diff --git a/.flatpak-builder/build/libxml b/.flatpak-builder/build/libxml new file mode 120000 index 0000000..7858edf --- /dev/null +++ b/.flatpak-builder/build/libxml @@ -0,0 +1 @@ +libxml-2 \ No newline at end of file diff --git a/.flatpak-builder/build/libxml-1 b/.flatpak-builder/build/libxml-1 new file mode 160000 index 0000000..2e9f786 --- /dev/null +++ b/.flatpak-builder/build/libxml-1 @@ -0,0 +1 @@ +Subproject commit 2e9f7860a9cb8be29eca90b7409ef0278d30ef10 diff --git a/.flatpak-builder/build/libxml-2 b/.flatpak-builder/build/libxml-2 new file mode 160000 index 0000000..2e9f786 --- /dev/null +++ b/.flatpak-builder/build/libxml-2 @@ -0,0 +1 @@ +Subproject commit 2e9f7860a9cb8be29eca90b7409ef0278d30ef10 diff --git a/.flatpak-builder/build/ligba b/.flatpak-builder/build/ligba new file mode 120000 index 0000000..03a66f0 --- /dev/null +++ b/.flatpak-builder/build/ligba @@ -0,0 +1 @@ +ligba-1 \ No newline at end of file diff --git a/.flatpak-builder/build/ligba-1 b/.flatpak-builder/build/ligba-1 new file mode 160000 index 0000000..5d23892 --- /dev/null +++ b/.flatpak-builder/build/ligba-1 @@ -0,0 +1 @@ +Subproject commit 5d23892e1c8abd931ad2a7bd24cd543b93ccb04c diff --git a/.flatpak-builder/build/ligda b/.flatpak-builder/build/ligda new file mode 120000 index 0000000..a225fae --- /dev/null +++ b/.flatpak-builder/build/ligda @@ -0,0 +1 @@ +ligda-1 \ No newline at end of file diff --git a/.flatpak-builder/build/ligda-1 b/.flatpak-builder/build/ligda-1 new file mode 160000 index 0000000..5d23892 --- /dev/null +++ b/.flatpak-builder/build/ligda-1 @@ -0,0 +1 @@ +Subproject commit 5d23892e1c8abd931ad2a7bd24cd543b93ccb04c diff --git a/.flatpak-builder/cache/.lock b/.flatpak-builder/cache/.lock new file mode 100644 index 0000000..e69de29 diff --git a/.flatpak-builder/cache/config b/.flatpak-builder/cache/config new file mode 100644 index 0000000..7dfbc01 --- /dev/null +++ b/.flatpak-builder/cache/config @@ -0,0 +1,4 @@ +[core] +repo_version=1 +mode=bare-user-only +min-free-space-percent=0 diff --git a/.flatpak-builder/cache/objects/00/0d8de4956378fa4281235b0972bdab09dcb5461675257533f9d1f021f7d29b.file b/.flatpak-builder/cache/objects/00/0d8de4956378fa4281235b0972bdab09dcb5461675257533f9d1f021f7d29b.file new file mode 100644 index 0000000..2cec47c Binary files /dev/null and b/.flatpak-builder/cache/objects/00/0d8de4956378fa4281235b0972bdab09dcb5461675257533f9d1f021f7d29b.file differ diff --git a/.flatpak-builder/cache/objects/00/21d8de059d757f9ca83864c4247e514f1d9712b842a2f62d8675b66d901ca3.file b/.flatpak-builder/cache/objects/00/21d8de059d757f9ca83864c4247e514f1d9712b842a2f62d8675b66d901ca3.file new file mode 100644 index 0000000..68a6db7 --- /dev/null +++ b/.flatpak-builder/cache/objects/00/21d8de059d757f9ca83864c4247e514f1d9712b842a2f62d8675b66d901ca3.file @@ -0,0 +1,773 @@ +/* + * Copyright (C) 2006 Bas Driessen + * Copyright (C) 2006 - 2014 Vivien Malerba + * Copyright (C) 2008 Murray Cumming + * Copyright (C) 2010 David King + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "gda-sqlite-ddl.h" +#include "gda-server-provider.h" +#include +#include + + +gchar * +_gda_sqlite_render_CREATE_TABLE (GdaServerProvider *provider, GdaConnection *cnc, + GdaServerOperation *op, GError **error) +{ + g_return_val_if_fail (provider, NULL); + g_return_val_if_fail (cnc, NULL); + g_return_val_if_fail (op, NULL); + g_return_val_if_fail (gda_server_operation_get_op_type (op) == GDA_SERVER_OPERATION_CREATE_TABLE, NULL); + + GString *string; + const GValue *value; + const GValue *value1; + gboolean allok = TRUE; + gboolean hasfields = FALSE; + gint nrows; + gint i; + gboolean first; + GSList *pkfields = NULL; /* list of GValue* composing the pkey */ + gint nbpkfields = 0; + gchar *sql = NULL; + gchar *conflict_algo = NULL; + gchar *tmp; + + /* CREATE TABLE */ + string = g_string_new ("CREATE "); + value = gda_server_operation_get_value_at (op, "/TABLE_DEF_P/TABLE_TEMP"); + if (value && G_VALUE_HOLDS (value, G_TYPE_BOOLEAN) && g_value_get_boolean (value)) + g_string_append (string, "TEMP "); + g_string_append (string, "TABLE "); + + value = gda_server_operation_get_value_at (op, "/TABLE_DEF_P/TABLE_IFNOTEXISTS"); + if (value && G_VALUE_HOLDS (value, G_TYPE_BOOLEAN) && g_value_get_boolean (value)) + g_string_append (string, "IF NOT EXISTS "); + + tmp = gda_connection_operation_get_sql_identifier_at (cnc, op, "/TABLE_DEF_P/TABLE_NAME", error); + if (!tmp) { + g_string_free (string, TRUE); + if (error != NULL) { + if (*error == NULL) { + g_warning (_("Internal error, creating table in SQLite provider")); + } + } + return NULL; + } + g_string_append (string, tmp); + g_free (tmp); + g_string_append (string, " ("); + + GdaServerOperationNode *node; + /* FIELDS */ + if (allok) { + + node = gda_server_operation_get_node_info (op, "/FIELDS_A"); + if (node == NULL) { + g_set_error (error, GDA_SERVER_OPERATION_ERROR, GDA_SERVER_OPERATION_INCORRECT_VALUE_ERROR, + "%s", _("No fields are defined for CREATE TABLE operation")); + return NULL; + } + + /* finding if there is a composed primary key */ + nrows = gda_data_model_get_n_rows (node->model); + for (i = 0; i < nrows; i++) { + value = gda_server_operation_get_value_at (op, "/FIELDS_A/@COLUMN_PKEY/%d", i); + if (value && G_VALUE_HOLDS (value, G_TYPE_BOOLEAN) && g_value_get_boolean (value)) { + tmp = gda_connection_operation_get_sql_identifier_at (cnc, op, + "/FIELDS_A/@COLUMN_NAME/%d", error, + i); + if (!tmp) { + g_string_free (string, TRUE); + g_assert (*error != NULL); + return NULL; + } + pkfields = g_slist_append (pkfields, tmp); + nbpkfields++; + } + } + + /* manually defined fields */ + first = TRUE; + for (i = 0; i < nrows; i++) { + gboolean pkautoinc = FALSE; + hasfields = TRUE; + if (first) + first = FALSE; + else + g_string_append (string, ", "); + + tmp = gda_connection_operation_get_sql_identifier_at (cnc, op, + "/FIELDS_A/@COLUMN_NAME/%d", error, i); + if (!tmp) { + g_string_free (string, TRUE); + g_assert (*error != NULL); + return NULL; + } + g_string_append (string, tmp); + g_free (tmp); + g_string_append_c (string, ' '); + + if (nbpkfields == 1) { + value = gda_server_operation_get_value_at (op, "/FIELDS_A/@COLUMN_AUTOINC/%d", i); + if (value && G_VALUE_HOLDS (value, G_TYPE_BOOLEAN) && g_value_get_boolean (value)) { + const gchar *tmp; + value = gda_server_operation_get_value_at (op, "/FIELDS_A/@COLUMN_TYPE/%d", i); + tmp = g_value_get_string (value); + if (!g_ascii_strcasecmp (tmp, "gint") || + !g_ascii_strcasecmp (tmp, "int")) { + g_string_append (string, "INTEGER PRIMARY KEY AUTOINCREMENT"); + pkautoinc = TRUE; + } + } + } + + if (!pkautoinc) { + value1 = gda_server_operation_get_value_at (op, "/FIELDS_A/@COLUMN_TYPE/%d", i); + GType gtype = g_type_from_name (g_value_get_string (value1)); + if (gtype == G_TYPE_INVALID) { + g_string_append (string, g_value_get_string (value1)); + } else { + g_string_append (string, + gda_server_provider_get_default_dbms_type (provider, + cnc, gtype)); + } + + value = gda_server_operation_get_value_at (op, "/FIELDS_A/@COLUMN_SIZE/%d", i); + if (value && G_VALUE_HOLDS (value, G_TYPE_UINT)) { + g_string_append_printf (string, "(%d", g_value_get_uint (value)); + + value = gda_server_operation_get_value_at (op, "/FIELDS_A/@COLUMN_SCALE/%d", i); + if (value && G_VALUE_HOLDS (value, G_TYPE_UINT)) + g_string_append_printf (string, ",%d)", g_value_get_uint (value)); + else + g_string_append (string, ")"); + } + + value = gda_server_operation_get_value_at (op, "/FIELDS_A/@COLUMN_DEFAULT/%d", i); + if (value && G_VALUE_HOLDS (value, G_TYPE_STRING)) { + const gchar *str = g_value_get_string (value); + if (str && *str) { + g_string_append (string, " DEFAULT "); + const gchar* valtmp = g_value_get_string (value1); + if (!g_ascii_strcasecmp (valtmp,"string") || + !g_ascii_strcasecmp (valtmp,"gchararray")) { + g_string_append_c (string,'\''); + g_string_append (string, str); + g_string_append_c (string,'\''); + } + else { + g_string_append (string, str); + } + } + } + + value = gda_server_operation_get_value_at (op, "/FIELDS_A/@COLUMN_NNUL/%d", i); + if (value && G_VALUE_HOLDS (value, G_TYPE_BOOLEAN) && g_value_get_boolean (value)) + g_string_append (string, " NOT NULL"); + + value = gda_server_operation_get_value_at (op, "/FIELDS_A/@COLUMN_UNIQUE/%d", i); + if (value && G_VALUE_HOLDS (value, G_TYPE_BOOLEAN) && g_value_get_boolean (value)) + g_string_append (string, " UNIQUE"); + + if (nbpkfields == 1) { + value = gda_server_operation_get_value_at (op, "/FIELDS_A/@COLUMN_PKEY/%d", i); + if (value && G_VALUE_HOLDS (value, G_TYPE_BOOLEAN) && g_value_get_boolean (value)) { + g_string_append (string, " PRIMARY KEY"); + + value = gda_server_operation_get_value_at (op, "/FIELDS_A/@COLUMN_CONFLICT/%d", i); + if (value && G_VALUE_HOLDS (value, G_TYPE_STRING)) { + const gchar *str = g_value_get_string (value); + if (str && *str) { + g_string_append (string, " ON CONFLICT "); + g_string_append (string, str); + } + + } + value = gda_server_operation_get_value_at (op, "/FIELDS_A/@COLUMN_AUTOINC/%d", i); + if (value && G_VALUE_HOLDS (value, G_TYPE_BOOLEAN) && g_value_get_boolean (value)) { + g_string_append (string, " AUTOINCREMENT"); + } + } + + } + else { + if (!conflict_algo) { + value = gda_server_operation_get_value_at (op, "/FIELDS_A/@COLUMN_CONFLICT/%d", i); + if (value && G_VALUE_HOLDS (value, G_TYPE_STRING)) { + const gchar *str = g_value_get_string (value); + if (str && *str) + conflict_algo = g_strdup (str); + } + } + } + + value = gda_server_operation_get_value_at (op, "/FIELDS_A/@COLUMN_CHECK/%d", i); + if (value && G_VALUE_HOLDS (value, G_TYPE_STRING)) { + const gchar *str = g_value_get_string (value); + if (str && *str) { + g_string_append (string, " CHECK ("); + g_string_append (string, str); + g_string_append_c (string, ')'); + } + } + + value = gda_server_operation_get_value_at (op, "/FIELDS_A/@COLUMN_COLLATE/%d", i); + if (value && G_VALUE_HOLDS (value, G_TYPE_STRING)) { + const gchar *str = g_value_get_string (value); + if (str && *str) { + g_string_append (string, " COLLATE "); + g_string_append (string, str); + } + } + } + } + } + + /* composed primary key */ + if (nbpkfields > 1) { + GSList *list; + + g_string_append (string, ", PRIMARY KEY ("); + for (list = pkfields; list; list = list->next) { + if (list != pkfields) + g_string_append (string, ", "); + g_string_append (string, (gchar *) list->data); + } + g_string_append_c (string, ')'); + + if (conflict_algo) { + g_string_append (string, " ON CONFLICT "); + g_string_append (string, conflict_algo); + } + } + g_slist_free_full (pkfields, (GDestroyNotify) g_free); + + node = gda_server_operation_get_node_info (op, "/FKEY_S"); + if (node) { + nrows = gda_server_operation_get_sequence_size (op, "/FKEY_S"); + for (i = 0; i < nrows; i++) { + gint nbfields = 0, j; + + g_string_append (string, ", FOREIGN KEY ("); + node = gda_server_operation_get_node_info (op, "/FKEY_S/%d/FKEY_FIELDS_A", i); + if (!node || ((nbfields = gda_data_model_get_n_rows (node->model)) == 0)) { + g_string_free (string, TRUE); + g_set_error (error, GDA_SERVER_OPERATION_ERROR, + GDA_SERVER_OPERATION_INCORRECT_VALUE_ERROR, + "%s", _("No field specified in foreign key constraint")); + return NULL; + } + else { + for (j = 0; j < nbfields; j++) { + if (j != 0) + g_string_append (string, ", "); + tmp = gda_connection_operation_get_sql_identifier_at (cnc, op, + "/FKEY_S/%d/FKEY_FIELDS_A/@FK_FIELD/%d", + error, i, j); + if (tmp) { + g_string_append (string, tmp); + g_free (tmp); + } + else { + g_string_free (string, TRUE); + return NULL; + } + } + } + g_string_append (string, ") REFERENCES "); + tmp = gda_connection_operation_get_sql_identifier_at (cnc, op, + "/FKEY_S/%d/FKEY_REF_TABLE", error, i); + if (tmp) { + g_string_append (string, tmp); + g_free (tmp); + } + else { + g_string_free (string, TRUE); + return NULL; + } + + g_string_append (string, " ("); + for (j = 0; j < nbfields; j++) { + if (j != 0) + g_string_append (string, ", "); + tmp = gda_connection_operation_get_sql_identifier_at (cnc, op, + "/FKEY_S/%d/FKEY_FIELDS_A/@FK_REF_PK_FIELD/%d", + error, i, j); + if (tmp) { + g_string_append (string, tmp); + g_free (tmp); + } + else { + g_string_free (string, TRUE); + return NULL; + } + } + g_string_append_c (string, ')'); + value = gda_server_operation_get_value_at (op, "/FKEY_S/%d/FKEY_MATCH_TYPE", i); + if (value && G_VALUE_HOLDS (value, G_TYPE_STRING) && g_value_get_string (value)) + g_string_append_printf (string, " %s", g_value_get_string (value)); + value = gda_server_operation_get_value_at (op, "/FKEY_S/%d/FKEY_ONUPDATE", i); + if (value && G_VALUE_HOLDS (value, G_TYPE_STRING) && g_value_get_string (value)) + g_string_append_printf (string, " ON UPDATE %s", g_value_get_string (value)); + value = gda_server_operation_get_value_at (op, "/FKEY_S/%d/FKEY_ONDELETE", i); + if (value && G_VALUE_HOLDS (value, G_TYPE_STRING) && g_value_get_string (value)) + g_string_append_printf (string, " ON DELETE %s", g_value_get_string (value)); + } + } + + /* CONSTRAINT can be inserted without specifying the keyword CONSTRAINT for sqlite. + * Here, we just insert what we have saved in the GdaServerOperation object. Since + * we are moving towards new implementation of how DDL operations should be handled, + * we don't need to put more effort here. This is just a temporary working solution + */ + node = gda_server_operation_get_node_info (op, "/TABLE_CONSTRAINTS_S"); + + if (node) + { + nrows = gda_server_operation_get_sequence_size (op, "/TABLE_CONSTRAINTS_S"); + + for (i = 0; i < nrows; i++) + { + g_string_append (string, ", "); + + const GValue *tval = gda_server_operation_get_value_at (op, "/TABLE_CONSTRAINTS_S/%d/CONSTRAINT_STRING", i); + + g_string_append (string, g_value_get_string (tval)); + } + } + + g_free (conflict_algo); + g_string_append (string, ")"); + + if (!hasfields) { + allok = FALSE; + g_set_error (error, GDA_SERVER_OPERATION_ERROR, + GDA_SERVER_OPERATION_INCORRECT_VALUE_ERROR, + "%s", _("Table to create must have at least one field")); + g_string_free (string, TRUE); + return NULL; + } + + sql = string->str; + g_string_free (string, FALSE); +#ifdef GDA_DEBUG + g_print ("Renderer SQL for SQLite: %s\n", sql); +#endif + return sql; +} + +gchar * +_gda_sqlite_render_DROP_TABLE (G_GNUC_UNUSED GdaServerProvider *provider, GdaConnection *cnc, + GdaServerOperation *op, GError **error) +{ + GString *string; + const GValue *value; + gchar *sql = NULL; + gchar *tmp; + + /* DROP TABLE */ + string = g_string_new ("DROP TABLE"); + + value = gda_server_operation_get_value_at (op, "/TABLE_DESC_P/TABLE_IFEXISTS"); + if (value && G_VALUE_HOLDS (value, G_TYPE_BOOLEAN) && g_value_get_boolean (value)) + g_string_append (string, " IF EXISTS"); + + tmp = gda_connection_operation_get_sql_identifier_at (cnc, op, "/TABLE_DESC_P/TABLE_NAME", error); + if (!tmp) { + g_string_free (string, TRUE); + return NULL; + } + g_string_append_c (string, ' '); + g_string_append (string, tmp); + g_free (tmp); + + sql = string->str; + g_string_free (string, FALSE); + + return sql; +} + +gchar * +_gda_sqlite_render_RENAME_TABLE (G_GNUC_UNUSED GdaServerProvider *provider, GdaConnection *cnc, + GdaServerOperation *op, GError **error) +{ + GString *string; + gchar *sql = NULL; + gchar *tmp; + + /* DROP TABLE */ + string = g_string_new ("ALTER TABLE "); + + tmp = gda_connection_operation_get_sql_identifier_at (cnc, op, "/TABLE_DESC_P/TABLE_NAME", error); + if (!tmp) { + g_string_free (string, TRUE); + return NULL; + } + g_string_append (string, tmp); + g_free (tmp); + + tmp = gda_connection_operation_get_sql_identifier_at (cnc, op, "/TABLE_DESC_P/TABLE_NEW_NAME", error); + if (!tmp) { + g_string_free (string, TRUE); + return NULL; + } + g_string_append (string, " RENAME TO "); + g_string_append (string, tmp); + g_free (tmp); + + sql = string->str; + g_string_free (string, FALSE); + + return sql; +} + +gchar * +_gda_sqlite_render_ADD_COLUMN (G_GNUC_UNUSED GdaServerProvider *provider, GdaConnection *cnc, + GdaServerOperation *op, G_GNUC_UNUSED GError **error) +{ + GString *string; + const GValue *value; + gchar *sql = NULL; + gchar *tmp; + + /* DROP TABLE */ + string = g_string_new ("ALTER TABLE "); + + tmp = gda_connection_operation_get_sql_identifier_at (cnc, op, "/COLUMN_DEF_P/TABLE_NAME", error); + if (!tmp) { + g_string_free (string, TRUE); + return NULL; + } + g_string_append (string, tmp); + g_free (tmp); + + g_string_append (string, " ADD COLUMN "); + + tmp = gda_connection_operation_get_sql_identifier_at (cnc, op, "/COLUMN_DEF_P/COLUMN_NAME", error); + if (!tmp) { + g_string_free (string, TRUE); + return NULL; + } + g_string_append (string, tmp); + g_free (tmp); + + value = gda_server_operation_get_value_at (op, "/COLUMN_DEF_P/COLUMN_TYPE"); + g_assert (value && G_VALUE_HOLDS (value, G_TYPE_STRING)); + g_string_append_c (string, ' '); + g_string_append (string, g_value_get_string (value)); + + value = gda_server_operation_get_value_at (op, "/COLUMN_DEF_P/COLUMN_SIZE"); + if (value && G_VALUE_HOLDS (value, G_TYPE_UINT)) { + g_string_append_printf (string, "(%d", g_value_get_uint (value)); + + value = gda_server_operation_get_value_at (op, "/COLUMN_DEF_P/COLUMN_SCALE"); + if (value && G_VALUE_HOLDS (value, G_TYPE_UINT)) + g_string_append_printf (string, ",%d)", g_value_get_uint (value)); + else + g_string_append (string, ")"); + } + + value = gda_server_operation_get_value_at (op, "/COLUMN_DEF_P/COLUMN_DEFAULT"); + if (value && G_VALUE_HOLDS (value, G_TYPE_STRING)) { + const gchar *str = g_value_get_string (value); + if (str && *str) { + g_string_append (string, " DEFAULT "); + g_string_append (string, str); + } + } + + value = gda_server_operation_get_value_at (op, "/COLUMN_DEF_P/COLUMN_NNUL"); + if (value && G_VALUE_HOLDS (value, G_TYPE_BOOLEAN) && g_value_get_boolean (value)) + g_string_append (string, " NOT NULL"); + + value = gda_server_operation_get_value_at (op, "/COLUMN_DEF_P/COLUMN_CHECK"); + if (value && G_VALUE_HOLDS (value, G_TYPE_STRING)) { + const gchar *str = g_value_get_string (value); + if (str && *str) { + g_string_append (string, " CHECK ("); + g_string_append (string, str); + g_string_append_c (string, ')'); + } + } + + sql = string->str; + g_string_free (string, FALSE); + + return sql; +} + + +gchar * +_gda_sqlite_render_CREATE_INDEX (G_GNUC_UNUSED GdaServerProvider *provider, GdaConnection *cnc, + GdaServerOperation *op, G_GNUC_UNUSED GError **error) +{ + GString *string; + const GValue *value; + gchar *sql = NULL; + GdaServerOperationNode *node; + gint nrows, i; + gchar *tmp; + + /* CREATE INDEX */ + string = g_string_new ("CREATE "); + + value = gda_server_operation_get_value_at (op, "/INDEX_DEF_P/INDEX_TYPE"); + if (value && G_VALUE_HOLDS (value, G_TYPE_STRING) && + g_value_get_string (value) && *g_value_get_string (value)) { + g_string_append (string, g_value_get_string (value)); + g_string_append_c (string, ' '); + } + + g_string_append (string, "INDEX "); + + value = gda_server_operation_get_value_at (op, "/INDEX_DEF_P/INDEX_IFNOTEXISTS"); + if (value && G_VALUE_HOLDS (value, G_TYPE_BOOLEAN) && g_value_get_boolean (value)) + g_string_append (string, " IF NOT EXISTS "); + + + tmp = gda_connection_operation_get_sql_identifier_at (cnc, op, "/INDEX_DEF_P/INDEX_NAME", error); + if (!tmp) { + g_string_free (string, TRUE); + return NULL; + } + g_string_append (string, tmp); + g_free (tmp); + + g_string_append (string, " ON "); + + tmp = gda_connection_operation_get_sql_identifier_at (cnc, op, "/INDEX_DEF_P/INDEX_ON_TABLE", error); + if (!tmp) { + g_string_free (string, TRUE); + return NULL; + } + g_string_append (string, tmp); + g_free (tmp); + + /* fields or expressions the index is on */ + g_string_append (string, " ("); + node = gda_server_operation_get_node_info (op, "/INDEX_FIELDS_S"); + g_assert (node); + nrows = gda_server_operation_get_sequence_size (op, "/INDEX_FIELDS_S"); + for (i = 0; i < nrows; i++) { + tmp = gda_connection_operation_get_sql_identifier_at (cnc, op, + "/INDEX_FIELDS_S/%d/INDEX_FIELD", error, i); + if (tmp) { + if (i != 0) + g_string_append (string, ", "); + g_string_append (string, tmp); + g_free (tmp); + + value = gda_server_operation_get_value_at (op, "/INDEX_FIELDS_S/%d/INDEX_COLLATE", i); + if (value && G_VALUE_HOLDS (value, G_TYPE_STRING)) { + const gchar *str = g_value_get_string (value); + if (str && *str) { + g_string_append (string, " COLLATE "); + g_string_append (string, str); + } + } + + + value = gda_server_operation_get_value_at (op, "/INDEX_FIELDS_S/%d/INDEX_SORT_ORDER", i); + if (value && G_VALUE_HOLDS (value, G_TYPE_STRING)) { + const gchar *str = g_value_get_string (value); + if (str && *str) { + g_string_append_c (string, ' '); + g_string_append (string, str); + } + } + } + else { + g_string_free (string, TRUE); + return NULL; + } + } + + g_string_append (string, ")"); + + sql = string->str; + g_string_free (string, FALSE); + + return sql; +} + +gchar * +_gda_sqlite_render_DROP_INDEX (G_GNUC_UNUSED GdaServerProvider *provider, GdaConnection *cnc, + GdaServerOperation *op, G_GNUC_UNUSED GError **error) +{ + GString *string; + const GValue *value; + gchar *sql = NULL; + gchar *tmp; + + /* DROP INDEX */ + string = g_string_new ("DROP INDEX "); + + value = gda_server_operation_get_value_at (op, "/INDEX_DESC_P/INDEX_IFEXISTS"); + if (value && G_VALUE_HOLDS (value, G_TYPE_BOOLEAN) && g_value_get_boolean (value)) + g_string_append (string, "IF EXISTS "); + + tmp = gda_connection_operation_get_sql_identifier_at (cnc, op, "/INDEX_DESC_P/INDEX_NAME", error); + if (!tmp) { + g_string_free (string, TRUE); + return NULL; + } + g_string_append (string, tmp); + g_free (tmp); + + sql = string->str; + g_string_free (string, FALSE); + + return sql; +} + +gchar * +_gda_sqlite_render_CREATE_VIEW (G_GNUC_UNUSED GdaServerProvider *provider, GdaConnection *cnc, + GdaServerOperation *op, G_GNUC_UNUSED GError **error) +{ + GString *string; + const GValue *value; + gboolean allok = TRUE; + gchar *sql = NULL; + gchar *tmp; + + string = g_string_new ("CREATE "); + value = gda_server_operation_get_value_at (op, "/VIEW_DEF_P/VIEW_TEMP"); + if (value && G_VALUE_HOLDS (value, G_TYPE_BOOLEAN) && g_value_get_boolean (value)) + g_string_append (string, "TEMP "); + + g_string_append (string, "VIEW "); + + value = gda_server_operation_get_value_at (op, "/VIEW_DEF_P/VIEW_IFNOTEXISTS"); + if (value && G_VALUE_HOLDS (value, G_TYPE_BOOLEAN) && g_value_get_boolean (value)) + g_string_append (string, "IF NOT EXISTS "); + + tmp = gda_connection_operation_get_sql_identifier_at (cnc, op, "/VIEW_DEF_P/VIEW_NAME", error); + if (!tmp) { + g_string_free (string, TRUE); + return NULL; + } + g_string_append (string, tmp); + g_free (tmp); + + if (allok) { + value = gda_server_operation_get_value_at (op, "/VIEW_DEF_P/VIEW_DEF"); + g_assert (value && G_VALUE_HOLDS (value, G_TYPE_STRING)); + g_string_append (string, " AS "); + g_string_append (string, g_value_get_string (value)); + } + + if (allok) { + sql = string->str; + g_string_free (string, FALSE); + } + else { + sql = NULL; + g_string_free (string, TRUE); + } + + return sql; +} + +gchar * +_gda_sqlite_render_DROP_VIEW (G_GNUC_UNUSED GdaServerProvider *provider, GdaConnection *cnc, + GdaServerOperation *op, G_GNUC_UNUSED GError **error) +{ + GString *string; + const GValue *value; + gchar *sql = NULL; + gchar *tmp; + + string = g_string_new ("DROP VIEW"); + + value = gda_server_operation_get_value_at (op, "/VIEW_DESC_P/VIEW_IFEXISTS"); + if (value && G_VALUE_HOLDS (value, G_TYPE_BOOLEAN) && g_value_get_boolean (value)) + g_string_append (string, " IF EXISTS"); + + tmp = gda_connection_operation_get_sql_identifier_at (cnc, op, "/VIEW_DESC_P/VIEW_NAME", error); + if (!tmp) { + g_string_free (string, TRUE); + return NULL; + } + g_string_append_c (string, ' '); + g_string_append (string, tmp); + g_free (tmp); + + sql = string->str; + g_string_free (string, FALSE); + + return sql; +} + +gchar * +_gda_sqlite_render_RENAME_COLUMN (GdaServerProvider *provider, + GdaConnection *cnc, + GdaServerOperation *op, + GError **error) +{ + gchar *sql = NULL; + + GString *string; + gchar *tmp; + + /* ALTER TABLE */ + string = g_string_new ("ALTER TABLE "); + + tmp = gda_connection_operation_get_sql_identifier_at (cnc, op, "/COLUMN_DEF_P/TABLE_NAME", error); + + if (!tmp) { + g_string_free (string, TRUE); + return NULL; + } + + g_string_append (string, tmp); + g_free (tmp); + + g_string_append (string, " RENAME COLUMN "); + + tmp = gda_connection_operation_get_sql_identifier_at(cnc, op, "/COLUMN_DEF_P/COLUMN_NAME", error); + if (!tmp) { + g_string_free(string, TRUE); + return NULL; + } + + g_string_append (string, tmp); + g_free (tmp); + + g_string_append (string, " TO "); + + tmp = gda_connection_operation_get_sql_identifier_at (cnc, op, "/COLUMN_DEF_P/COLUMN_NAME_NEW", error); + + if (!tmp) { + g_string_free (string, TRUE); + return NULL; + } + + g_string_append (string, tmp); + g_free (tmp); + + sql = string->str; + g_string_free (string, FALSE); + +#ifdef GDA_DEBUG + g_print ("Renderer SQL for SQLite: %s\n", sql); +#endif + + return sql; +} diff --git a/.flatpak-builder/cache/objects/00/393769f7119f69d711bd122f67d37fe33d44dfecb48b3fc750c04baf1d0873.file b/.flatpak-builder/cache/objects/00/393769f7119f69d711bd122f67d37fe33d44dfecb48b3fc750c04baf1d0873.file new file mode 100644 index 0000000..2bbe452 --- /dev/null +++ b/.flatpak-builder/cache/objects/00/393769f7119f69d711bd122f67d37fe33d44dfecb48b3fc750c04baf1d0873.file @@ -0,0 +1,1794 @@ +/* + * Copyright (C) 2008 - 2009 Bas Driessen + * Copyright (C) 2008 - 2012 Vivien Malerba + * Copyright (C) 2010 - 2011 Murray Cumming + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * + * Sql expression + * + */ + +GType +gda_sql_expr_get_type (void) +{ + static GType our_type = 0; + + if (our_type == 0) + our_type = g_boxed_type_register_static ("GdaSqlExpr", + (GBoxedCopyFunc) gda_sql_expr_copy, + (GBoxedFreeFunc) gda_sql_expr_free); + return our_type; +} + + +/** + * gda_sql_expr_new + * @parent: a #GdaSqlStatementInsert, #GdaSqlStatementUpdate, #GdaSqlSelectField, #GdaSqlSelectTarget, #GdaSqlOperation + * + * Creates a new #GdaSqlField structure, using @parent as its parent part. + * + * Returns: a new #GdaSqlField structure. + */ +GdaSqlExpr * +gda_sql_expr_new (GdaSqlAnyPart *parent) +{ + GdaSqlExpr *expr; + expr = g_new0 (GdaSqlExpr, 1); + GDA_SQL_ANY_PART(expr)->type = GDA_SQL_ANY_EXPR; + GDA_SQL_ANY_PART(expr)->parent = parent; + return expr; +} + +/** + * gda_sql_expr_free + * @expr: a #GdaSqlExpr to be freed. + * + * Frees a #GdaSqlExpr structure and its members. + * + */ +void +gda_sql_expr_free (GdaSqlExpr *expr) +{ + if (!expr) return; + + _gda_sql_expr_check_clean (expr); + gda_value_free (expr->value); + gda_sql_param_spec_free (expr->param_spec); + gda_sql_function_free (expr->func); + gda_sql_operation_free (expr->cond); + if (expr->select) { + if (GDA_SQL_ANY_PART (expr->select)->type == GDA_SQL_ANY_STMT_SELECT) + _gda_sql_statement_select_free (expr->select); + else if (GDA_SQL_ANY_PART (expr->select)->type == GDA_SQL_ANY_STMT_COMPOUND) + _gda_sql_statement_compound_free (expr->select); + else + g_assert_not_reached (); + } + gda_sql_case_free (expr->case_s); + g_free (expr->cast_as); + g_free (expr); +} + +/** + * gda_sql_expr_copy + * @expr: a #GdaSqlExpr + * + * Creates a new #GdaSqlExpr structure initiated with the values stored in @expr. + * + * Returns: a new #GdaSqlExpr structure. + */ +GdaSqlExpr * +gda_sql_expr_copy (GdaSqlExpr *expr) +{ + GdaSqlExpr *copy; + if (!expr) return NULL; + + copy = gda_sql_expr_new (NULL); + if (expr->value) { + GValue *value; + + value = g_new0 (GValue, 1); + g_value_init (value, G_VALUE_TYPE (expr->value)); + g_value_copy (expr->value, value); + copy->value = value; + } + copy->param_spec = gda_sql_param_spec_copy (expr->param_spec); + + copy->func = gda_sql_function_copy (expr->func); + gda_sql_any_part_set_parent (copy->func, copy); + + copy->cond = gda_sql_operation_copy (expr->cond); + gda_sql_any_part_set_parent (copy->cond, copy); + + if (expr->select) { + if (GDA_SQL_ANY_PART (expr->select)->type == GDA_SQL_ANY_STMT_SELECT) + copy->select = _gda_sql_statement_select_copy (expr->select); + else if (GDA_SQL_ANY_PART (expr->select)->type == GDA_SQL_ANY_STMT_COMPOUND) + copy->select = _gda_sql_statement_compound_copy (expr->select); + else + g_assert_not_reached (); + gda_sql_any_part_set_parent (copy->select, copy); + } + + copy->case_s = gda_sql_case_copy (expr->case_s); + gda_sql_any_part_set_parent (copy->case_s, copy); + + if (expr->cast_as) + copy->cast_as = g_strdup (expr->cast_as); + + copy->value_is_ident = expr->value_is_ident; + return copy; +} + +/** + * gda_sql_expr_serialize + * @expr: a #GdaSqlExpr structure + * + * Creates a new string representation of the SQL expression. You need to free the returned string + * using g_free(); + * + * Returns: a new string with the SQL expression or "null" in case @expr is invalid. + */ +gchar * +gda_sql_expr_serialize (GdaSqlExpr *expr) +{ + GString *string; + gchar *str, *tmp; + + if (!expr) + return g_strdup ("null"); + + string = g_string_new ("{"); + if (expr->cond) { + str = gda_sql_operation_serialize (expr->cond); + g_string_append_printf (string, "\"operation\":%s", str); + g_free (str); + } + else if (expr->func) { + str = gda_sql_function_serialize (expr->func); + g_string_append_printf (string, "\"func\":%s", str); + g_free (str); + } + else if (expr->select) { + if (GDA_SQL_ANY_PART (expr->select)->type == GDA_SQL_ANY_STMT_SELECT) + str = _gda_sql_statement_select_serialize (expr->select); + else if (GDA_SQL_ANY_PART (expr->select)->type == GDA_SQL_ANY_STMT_COMPOUND) + str = _gda_sql_statement_compound_serialize (expr->select); + else + g_assert_not_reached (); + g_string_append_printf (string, "\"select\":{%s}", str); + g_free (str); + } + else if (expr->case_s) { + str = gda_sql_case_serialize (expr->case_s); + g_string_append_printf (string, "\"case\":%s", str); + g_free (str); + } + else { + if (expr->value) { + tmp = gda_sql_value_stringify (expr->value); + str = _json_quote_string (tmp); + g_free (tmp); + g_string_append_printf (string, "\"value\":%s", str); + g_free (str); + } + else + g_string_append_printf (string, "\"value\":null"); + if (expr->param_spec) { + str = gda_sql_param_spec_serialize (expr->param_spec); + g_string_append_printf (string, ",\"param_spec\":%s", str); + g_free (str); + } + } + + if (expr->cast_as) { + str = _json_quote_string (expr->cast_as); + g_string_append_printf (string, ",\"cast\":%s", str); + g_free (str); + } + + if (expr->value_is_ident) { + str = _json_quote_string (expr->cast_as); + g_string_append (string, ",\"sqlident\":\"TRUE\""); + g_free (str); + } + + g_string_append_c (string, '}'); + str = string->str; + g_string_free (string, FALSE); + return str; +} + +/** + * gda_sql_expr_take_select + * @expr: a #GdaSqlExpr structure + * @stmt: a #GdaSqlStatement holding the #GdaSqlStatementSelect to take from + * + * Sets the expression's parent to the #GdaSqlStatementSelect held by @stmt. After + * calling this function @stmt is freed. + * + */ +void +gda_sql_expr_take_select (GdaSqlExpr *expr, GdaSqlStatement *stmt) +{ + if (stmt) { + GdaSqlAnyPart *part; + part = GDA_SQL_ANY_PART (stmt->contents); + stmt->contents = NULL; + gda_sql_statement_free (stmt); + expr->select = _gda_sql_statement_compound_reduce (part); + gda_sql_any_part_set_parent (expr->select, expr); + } +} + +/** + * gda_sql_field_new + * @parent: a #GdaSqlStatementSelect, #GdaSqlStatementInsert, #GdaSqlStatementDelete, #GdaSqlStatementUpdate + * + * Creates a new #GdaSqlField structure, using @parent as its parent part. + * + * Returns: a new #GdaSqlField structure. + */ +GdaSqlField * +gda_sql_field_new (GdaSqlAnyPart *parent) +{ + GdaSqlField *field; + field = g_new0 (GdaSqlField, 1); + GDA_SQL_ANY_PART(field)->type = GDA_SQL_ANY_SQL_FIELD; + GDA_SQL_ANY_PART(field)->parent = parent; + return field; +} + +/** + * gda_sql_field_free + * @field: a #GdaSqlField to be freed. + * + * Frees a #GdaSqlField structure and its members. + * + */ +void +gda_sql_field_free (GdaSqlField *field) +{ + if (!field) return; + + _gda_sql_field_check_clean (field); + g_free (field->field_name); + g_free (field); +} + +/** + * gda_sql_field_copy + * @field: a #GdaSqlAnyPart + * + * Creates a new GdaSqlField structure initiated with the values stored in @field. + * + * Returns: a new #GdaSqlField structure. + */ +GdaSqlField * +gda_sql_field_copy (GdaSqlField *field) +{ + GdaSqlField *copy; + if (!field) return NULL; + + copy = gda_sql_field_new (NULL); + if (field->field_name) + copy->field_name = g_strdup (field->field_name); + copy->validity_meta_table_column = field->validity_meta_table_column; + + return copy; +} + + +G_DEFINE_BOXED_TYPE(GdaSqlField, gda_sql_field, gda_sql_field_copy, gda_sql_field_free) + +/** + * gda_sql_field_serialize + * @field: a #GdaSqlField structure + * + * Creates a new string representing a field. You need to free the returned string + * using g_free(); + * + * Returns: a new string with the name of the field or "null" in case @field is invalid. + */ +gchar * +gda_sql_field_serialize (GdaSqlField *field) +{ + if (!field) + return g_strdup ("null"); + else + return _json_quote_string (field->field_name); +} + +/** + * gda_sql_field_take_name + * @field: a #GdaSqlField structure + * @value: a #GValue holding a string to take from + * + * Sets the field's name using the string held by @value. When call, @value is freed using + * #gda_value_free(). + * + */ +void +gda_sql_field_take_name (GdaSqlField *field, GValue *value) +{ + if (value) { + field->field_name = g_value_dup_string (value); + gda_value_free (value); + } +} + +/** + * gda_sql_table_new + * @parent: a #GdaSqlStatementSelect, #GdaSqlStatementInsert, #GdaSqlStatementDelete, #GdaSqlStatementUpdate + * + * Creates a new #GdaSqlTable structure, using @parent as its parent part. + * + * Returns: a new #GdaSqlTable structure. + */ +GdaSqlTable * +gda_sql_table_new (GdaSqlAnyPart *parent) +{ + GdaSqlTable *table; + table = g_new0 (GdaSqlTable, 1); + GDA_SQL_ANY_PART(table)->type = GDA_SQL_ANY_SQL_TABLE; + GDA_SQL_ANY_PART(table)->parent = parent; + return table; +} + +/** + * gda_sql_table_free + * @table: a #GdaSqlTable structure to be freed + * + * Frees a #GdaSqlTable structure and its members. + */ +void +gda_sql_table_free (GdaSqlTable *table) +{ + if (!table) return; + + _gda_sql_table_check_clean (table); + g_free (table->table_name); + g_free (table); +} + +/** + * gda_sql_table_copy + * @table: a #GdaSqlTable structure to be copied + * + * Creates a new #GdaSqlTable structure initiated with the values stored in @table. + * + * Returns: (transfer full): a new #GdaSqlTable structure. + */ +GdaSqlTable * +gda_sql_table_copy (GdaSqlTable *table) +{ + GdaSqlTable *copy; + if (!table) return NULL; + + copy = gda_sql_table_new (NULL); + if (table->table_name) + copy->table_name = g_strdup (table->table_name); + copy->validity_meta_object = table->validity_meta_object; + + return copy; +} + +G_DEFINE_BOXED_TYPE(GdaSqlTable, gda_sql_table, gda_sql_table_copy, gda_sql_table_free) + +/** + * gda_sql_table_serialize: + * @table: a #GdaSqlTable structure + * + * Creates a new string representing a table. You need to free the returned string + * using g_free(); + * + * Returns: (transfer full): a new string with the name of the field or "null" in case @table is invalid. + */ +gchar * +gda_sql_table_serialize (GdaSqlTable *table) +{ + if (!table) + return g_strdup ("null"); + else + return _json_quote_string (table->table_name); +} + +/** + * gda_sql_table_take_name: + * @table: a #GdaSqlTable structure + * @value: a #GValue holding a string to take from + * + * Sets the table's name using the string held by @value. When call, @value is freed using + * gda_value_free(). + * + */ +void +gda_sql_table_take_name (GdaSqlTable *table, GValue *value) +{ + if (value) { + table->table_name = g_value_dup_string (value); + gda_value_free (value); + } +} + +/** + * gda_sql_function_new + * @parent: a #GdaSqlAnyPart structure + * + * Creates a new #GdaSqlFunction structure initiated. + * + * Returns: a new #GdaSqlFunction structure. + */ +GdaSqlFunction * +gda_sql_function_new (GdaSqlAnyPart *parent) +{ + GdaSqlFunction *function; + function = g_new0 (GdaSqlFunction, 1); + GDA_SQL_ANY_PART(function)->type = GDA_SQL_ANY_SQL_FUNCTION; + GDA_SQL_ANY_PART(function)->parent = parent; + return function; +} + +/** + * gda_sql_function_free + * @function: a #GdaSqlFunction structure to be freed + * + * Frees a #GdaSqlFunction structure and its members. + */ +void +gda_sql_function_free (GdaSqlFunction *function) +{ + if (!function) return; + + g_free (function->function_name); + if (function->args_list) { + g_slist_free_full (function->args_list, (GDestroyNotify) gda_sql_expr_free); + } + g_free (function); +} + +/** + * gda_sql_function_copy + * @function: a #GdaSqlFunction structure to be copied + * + * Creates a new #GdaSqlFunction structure initiated with the values stored in @function. + * + * Returns: (transfer full): a new #GdaSqlFunction structure. + */ +GdaSqlFunction * +gda_sql_function_copy (GdaSqlFunction *function) +{ + GdaSqlFunction *copy; + + if (!function) return NULL; + + copy = gda_sql_function_new (NULL); + if (function->function_name) + copy->function_name = g_strdup (function->function_name); + + if (function->args_list) { + GSList *list; + for (list = function->args_list; list; list = list->next) { + copy->args_list = g_slist_prepend (copy->args_list, + gda_sql_expr_copy ((GdaSqlExpr *) list->data)); + gda_sql_any_part_set_parent (copy->args_list->data, copy); + } + copy->args_list = g_slist_reverse (copy->args_list); + } + + return copy; +} + + +G_DEFINE_BOXED_TYPE(GdaSqlFunction, gda_sql_function, gda_sql_function_copy, gda_sql_function_free) + +/** + * gda_sql_function_serialize + * @function: a #GdaSqlFunction structure + * + * Creates a new string representing a function. You need to free the returned string + * using g_free(); + * + * Returns: a new string with the description of the function or "null" in case @function is invalid. + */ +gchar * +gda_sql_function_serialize (GdaSqlFunction *function) +{ + if (!function) + return g_strdup ("null"); + else { + GString *string; + gchar *str; + + string = g_string_new ("{"); + + g_string_append (string, "\"function_name\":"); + str = _json_quote_string (function->function_name); + g_string_append (string, str); + g_free (str); + + g_string_append (string, ",\"function_args\":"); + if (function->args_list) { + GSList *list; + g_string_append_c (string, '['); + for (list = function->args_list; list; list = list->next) { + if (list != function->args_list) + g_string_append_c (string, ','); + str = gda_sql_expr_serialize ((GdaSqlExpr*) list->data); + g_string_append (string, str); + g_free (str); + } + g_string_append_c (string, ']'); + } + else + g_string_append (string, "null"); + g_string_append_c (string, '}'); + str = string->str; + g_string_free (string, FALSE); + return str; + } +} + +/** + * gda_sql_function_take_name + * @function: a #GdaSqlFunction structure + * @value: a #GValue holding a string to take from + * + * Sets the function's name using the string held by @value. When call, @value is freed using + * #gda_value_free(). + */ +void +gda_sql_function_take_name (GdaSqlFunction *function, GValue *value) +{ + if (value) { + function->function_name = g_value_dup_string (value); + gda_value_free (value); + } +} + +/** + * gda_sql_function_take_args_list + * @function: a #GdaSqlFunction structure + * @args: (element-type Gda.SqlExpr): a #GSList to take from + * + * Sets the function's arguments to point to @args, then sets the + * list's data elements' parent to @function. + * + */ +void +gda_sql_function_take_args_list (GdaSqlFunction *function, GSList *args) +{ + GSList *list; + function->args_list = args; + + for (list = args; list; list = list->next) + gda_sql_any_part_set_parent (list->data, function); +} + +/** + * gda_sql_operation_new + * @parent: a #GdaSqlAnyPart structure + * + * Creates a new #GdaSqlOperation structure and sets its parent to @parent. + * + * Returns: a new #GdaSqlOperation structure. + */ +GdaSqlOperation * +gda_sql_operation_new (GdaSqlAnyPart *parent) +{ + GdaSqlOperation *operation; + operation = g_new0 (GdaSqlOperation, 1); + GDA_SQL_ANY_PART(operation)->type = GDA_SQL_ANY_SQL_OPERATION; + GDA_SQL_ANY_PART(operation)->parent = parent; + return operation; +} + +/** + * gda_sql_operation_free + * @operation: a #GdaSqlOperation structure to be freed + * + * Frees a #GdaSqlOperation structure and its members. + */ +void +gda_sql_operation_free (GdaSqlOperation *operation) +{ + if (!operation) return; + + if (operation->operands) { + g_slist_free_full (operation->operands, (GDestroyNotify) gda_sql_expr_free); + } + g_free (operation); +} + +/** + * gda_sql_operation_copy + * @operation: a #GdaSqlOperation structure to be copied + * + * Creates a new #GdaSqlOperation structure initiated with the values stored in @operation. + * + * Returns: a new #GdaSqlOperation structure. + */ +GdaSqlOperation * +gda_sql_operation_copy (GdaSqlOperation *operation) +{ + GdaSqlOperation *copy; + GSList *list; + + if (!operation) return NULL; + + copy = gda_sql_operation_new (NULL); + copy->operator_type = operation->operator_type; + + for (list = operation->operands; list; list = list->next) { + copy->operands = g_slist_prepend (copy->operands, + gda_sql_expr_copy ((GdaSqlExpr*) list->data)); + gda_sql_any_part_set_parent (copy->operands->data, copy); + } + copy->operands = g_slist_reverse (copy->operands); + + return copy; +} + + +G_DEFINE_BOXED_TYPE(GdaSqlOperation, gda_sql_operation, gda_sql_operation_copy, gda_sql_operation_free) + +/** + * gda_sql_operation_serialize + * @operation: a #GdaSqlOperation structure + * + * Creates a new string representing an operator. You need to free the returned string + * using g_free(); + * + * Returns: a new string with the description of the operator or "null" in case @operation is invalid. + */ +gchar * +gda_sql_operation_serialize (GdaSqlOperation *operation) +{ + if (!operation) + return g_strdup ("null"); + else { + GString *string; + gchar *str; + GSList *list; + gint i = 0; + + string = g_string_new ("{"); + + g_string_append (string, "\"operator\":"); + str = _json_quote_string (gda_sql_operation_operator_to_string (operation->operator_type)); + g_string_append (string, str); + g_free (str); + + for (list = operation->operands; list; list = list->next) { + g_string_append_printf (string, ",\"operand%d\":", i++); + if (list->data) { + str = gda_sql_expr_serialize ((GdaSqlExpr*) list->data); + g_string_append (string, str); + g_free (str); + } + else + g_string_append (string, "null"); + } + + g_string_append_c (string, '}'); + str = string->str; + g_string_free (string, FALSE); + return str; + } +} + +/** + * gda_sql_operation_operator_to_string + * @op: a #GdaSqlOperation structure + * + * Returns a constant string representing a operator name. You don't need to free + * the returned string. + * + * Returns: a string with the operator's name or NULL in case @op is invalid. + */ +const gchar * +gda_sql_operation_operator_to_string (GdaSqlOperatorType op) +{ + switch (op) { + case GDA_SQL_OPERATOR_TYPE_AND: + return "AND"; + case GDA_SQL_OPERATOR_TYPE_OR: + return "OR"; + case GDA_SQL_OPERATOR_TYPE_NOT: + return "NOT"; + case GDA_SQL_OPERATOR_TYPE_EQ: + return "="; + case GDA_SQL_OPERATOR_TYPE_IS: + return "IS"; + case GDA_SQL_OPERATOR_TYPE_ISNULL: + return "IS NULL"; + case GDA_SQL_OPERATOR_TYPE_ISNOTNULL: + return "IS NOT NULL"; + case GDA_SQL_OPERATOR_TYPE_IN: + return "IN"; + case GDA_SQL_OPERATOR_TYPE_NOTIN: + return "NOT IN"; + case GDA_SQL_OPERATOR_TYPE_LIKE: + return "LIKE"; + /* ILIKE is a PostgreSQL extension for case-insensitive comparison. + * See http://developer.postgresql.org/pgdocs/postgres/functions-matching.html + */ + case GDA_SQL_OPERATOR_TYPE_ILIKE: + return "ILIKE"; + case GDA_SQL_OPERATOR_TYPE_BETWEEN: + return "BETWEEN"; + case GDA_SQL_OPERATOR_TYPE_GT: + return ">"; + case GDA_SQL_OPERATOR_TYPE_LT: + return "<"; + case GDA_SQL_OPERATOR_TYPE_GEQ: + return ">="; + case GDA_SQL_OPERATOR_TYPE_LEQ: + return "<="; + case GDA_SQL_OPERATOR_TYPE_DIFF: + return "!="; + case GDA_SQL_OPERATOR_TYPE_REGEXP: + return "RE"; + case GDA_SQL_OPERATOR_TYPE_REGEXP_CI: + return "CI_RE"; + case GDA_SQL_OPERATOR_TYPE_NOT_REGEXP: + return "!RE"; + case GDA_SQL_OPERATOR_TYPE_NOT_REGEXP_CI: + return "!CI_RE"; + case GDA_SQL_OPERATOR_TYPE_SIMILAR: + return "SIMILAR TO"; + case GDA_SQL_OPERATOR_TYPE_CONCAT: + return "||"; + case GDA_SQL_OPERATOR_TYPE_PLUS: + return "+"; + case GDA_SQL_OPERATOR_TYPE_MINUS: + return "-"; + case GDA_SQL_OPERATOR_TYPE_STAR: + return "*"; + case GDA_SQL_OPERATOR_TYPE_DIV: + return "/"; + case GDA_SQL_OPERATOR_TYPE_REM: + return "%"; + case GDA_SQL_OPERATOR_TYPE_BITAND: + return "&"; + case GDA_SQL_OPERATOR_TYPE_BITOR: + return "|"; + case GDA_SQL_OPERATOR_TYPE_BITNOT: + return "~"; + case GDA_SQL_OPERATOR_TYPE_NOTLIKE: + return "NOT LIKE"; + case GDA_SQL_OPERATOR_TYPE_NOTILIKE: + return "NOT ILIKE"; + default: + g_error ("Unhandled operator constant %d\n", op); + return NULL; + } +} + +/** + * gda_sql_operation_operator_from_string + * @op: a #GdaSqlOperation structure + * + * Returns #GdaSqlOperatorType that correspond with the string @op. + * + * Returns: #GdaSqlOperatorType + */ +GdaSqlOperatorType +gda_sql_operation_operator_from_string (const gchar *op) +{ + switch (g_ascii_toupper (*op)) { + case 'A': + return GDA_SQL_OPERATOR_TYPE_AND; + case 'O': + return GDA_SQL_OPERATOR_TYPE_OR; + case 'N': + return GDA_SQL_OPERATOR_TYPE_NOT; + case '=': + return GDA_SQL_OPERATOR_TYPE_EQ; + case 'I': + if (op[1] == 'S') + return GDA_SQL_OPERATOR_TYPE_IS; + else if (op[1] == 'N') + return GDA_SQL_OPERATOR_TYPE_IN; + else if (op[1] == 'L') + return GDA_SQL_OPERATOR_TYPE_ILIKE; + break; + case 'L': + return GDA_SQL_OPERATOR_TYPE_LIKE; + case 'B': + return GDA_SQL_OPERATOR_TYPE_BETWEEN; + case '>': + if (op[1] == '=') + return GDA_SQL_OPERATOR_TYPE_GEQ; + else if (op[1] == 0) + return GDA_SQL_OPERATOR_TYPE_GT; + break; + case '<': + if (op[1] == '=') + return GDA_SQL_OPERATOR_TYPE_LEQ; + else if (op[1] == 0) + return GDA_SQL_OPERATOR_TYPE_LT; + break; + case '!': + if (op[1] == '=') + return GDA_SQL_OPERATOR_TYPE_DIFF; + else if (op[1] == 'R') + return GDA_SQL_OPERATOR_TYPE_NOT_REGEXP; + else + return GDA_SQL_OPERATOR_TYPE_NOT_REGEXP_CI; + case 'R': + return GDA_SQL_OPERATOR_TYPE_REGEXP; + case 'C': + return GDA_SQL_OPERATOR_TYPE_REGEXP_CI; + case 'S': + return GDA_SQL_OPERATOR_TYPE_SIMILAR; + case '|': + if (op[1] == '|') + return GDA_SQL_OPERATOR_TYPE_CONCAT; + else + return GDA_SQL_OPERATOR_TYPE_BITOR; + case '+': + return GDA_SQL_OPERATOR_TYPE_PLUS; + case '-': + return GDA_SQL_OPERATOR_TYPE_MINUS; + case '*': + return GDA_SQL_OPERATOR_TYPE_STAR; + case '/': + return GDA_SQL_OPERATOR_TYPE_DIV; + case '%': + return GDA_SQL_OPERATOR_TYPE_REM; + case '&': + return GDA_SQL_OPERATOR_TYPE_BITAND; + } + g_error ("Unhandled operator named '%s'\n", op); + return 0; +} + +/** + * gda_sql_case_new + * @parent: a #GdaSqlAnyPart structure + * + * Creates a new #GdaSqlCase structure and sets its parent to @parent. + * + * Returns: a new #GdaSqlCase structure. + */ +GdaSqlCase * +gda_sql_case_new (GdaSqlAnyPart *parent) +{ + GdaSqlCase *sc; + sc = g_new0 (GdaSqlCase, 1); + GDA_SQL_ANY_PART(sc)->type = GDA_SQL_ANY_SQL_CASE; + GDA_SQL_ANY_PART(sc)->parent = parent; + return sc; +} + +/** + * gda_sql_case_free + * @sc: a #GdaSqlCase structure to be freed + * + * Frees a #GdaSqlCase structure and its members. + */ +void +gda_sql_case_free (GdaSqlCase *sc) +{ + if (!sc) return; + + gda_sql_expr_free (sc->base_expr); + gda_sql_expr_free (sc->else_expr); + if (sc->when_expr_list) { + g_slist_free_full (sc->when_expr_list, (GDestroyNotify) gda_sql_expr_free); + } + if (sc->then_expr_list) { + g_slist_free_full (sc->then_expr_list, (GDestroyNotify) gda_sql_expr_free); + } + g_free (sc); +} + +/** + * gda_sql_case_copy + * @sc: a #GdaSqlCase structure to be copied + * + * Creates a new #GdaSqlCase structure initiated with the values stored in @sc. + * + * Returns: a new #GdaSqlCase structure. + */ +GdaSqlCase * +gda_sql_case_copy (GdaSqlCase *sc) +{ + GdaSqlCase *copy; + GSList *list; + + if (!sc) return NULL; + + copy = gda_sql_case_new (NULL); + copy->base_expr = gda_sql_expr_copy (sc->base_expr); + gda_sql_any_part_set_parent (copy->base_expr, copy); + copy->else_expr = gda_sql_expr_copy (sc->else_expr); + gda_sql_any_part_set_parent (copy->else_expr, copy); + + for (list = sc->when_expr_list; list; list = list->next) { + copy->when_expr_list = g_slist_prepend (copy->when_expr_list, + gda_sql_expr_copy ((GdaSqlExpr*) list->data)); + gda_sql_any_part_set_parent (copy->when_expr_list->data, copy); + } + + copy->when_expr_list = g_slist_reverse (copy->when_expr_list); + for (list = sc->then_expr_list; list; list = list->next) { + copy->then_expr_list = g_slist_prepend (copy->then_expr_list, + gda_sql_expr_copy ((GdaSqlExpr*) list->data)); + gda_sql_any_part_set_parent (copy->then_expr_list->data, copy); + } + copy->then_expr_list = g_slist_reverse (copy->then_expr_list); + + return copy; +} + +G_DEFINE_BOXED_TYPE(GdaSqlCase, gda_sql_case, gda_sql_case_copy, gda_sql_case_free) + +/** + * gda_sql_case_serialize + * @sc: a #GdaSqlCase structure + * + * Creates a new string representing a CASE clause. You need to free the returned string + * using g_free(); + * + * Returns: a new string with the description of the CASE clause or "null" in case @sc is invalid. + */ +gchar * +gda_sql_case_serialize (GdaSqlCase *sc) +{ + if (!sc) + return g_strdup ("null"); + else { + GString *string; + gchar *str; + GSList *wlist, *tlist; + + string = g_string_new ("{"); + + g_string_append (string, "\"base_expr\":"); + str = gda_sql_expr_serialize (sc->base_expr); + g_string_append (string, str); + g_free (str); + + g_string_append (string, ",\"body\":["); + for (wlist = sc->when_expr_list, tlist = sc->then_expr_list; + wlist && tlist; wlist = wlist->next, tlist = tlist->next) { + if (wlist != sc->when_expr_list) + g_string_append_c (string, ','); + g_string_append_c (string, '{'); + g_string_append (string, "\"when\":"); + str = gda_sql_expr_serialize ((GdaSqlExpr*) wlist->data); + g_string_append (string, str); + g_free (str); + g_string_append (string, ",\"then\":"); + str = gda_sql_expr_serialize ((GdaSqlExpr*) tlist->data); + g_string_append (string, str); + g_free (str); + g_string_append_c (string, '}'); + } + g_string_append_c (string, ']'); + g_assert (!wlist && !tlist); + + g_string_append (string, ",\"else_expr\":"); + str = gda_sql_expr_serialize (sc->else_expr); + g_string_append (string, str); + g_free (str); + + g_string_append_c (string, '}'); + str = string->str; + g_string_free (string, FALSE); + return str; + } +} + +/** + * gda_sql_select_field_new + * @parent: a #GdaSqlStatementSelect structure + * + * Creates a new #GdaSqlSelectField structure and sets its parent to @parent. A + * #GdaSqlSelectField is any expression in SELECT statements before the FROM clause. + * + * Returns: a new #GdaSqlSelectField structure. + */ +GdaSqlSelectField * +gda_sql_select_field_new (GdaSqlAnyPart *parent) +{ + GdaSqlSelectField *field; + field = g_new0 (GdaSqlSelectField, 1); + GDA_SQL_ANY_PART(field)->type = GDA_SQL_ANY_SQL_SELECT_FIELD; + GDA_SQL_ANY_PART(field)->parent = parent; + return field; +} + +/** + * gda_sql_select_field_free + * @field: a #GdaSqlSelectField structure to be freed + * + * Frees a #GdaSqlSelectField structure and its members. + */ +void +gda_sql_select_field_free (GdaSqlSelectField *field) +{ + if (!field) return; + + _gda_sql_select_field_check_clean (field); + gda_sql_expr_free (field->expr); + g_free (field->field_name); + g_free (field->table_name); + g_free (field->as); + + g_free (field); +} + +/** + * gda_sql_select_field_copy + * @field: a #GdaSqlSelectField structure to be copied + * + * Creates a new #GdaSqlSelectField structure initiated with the values stored in @field. + * + * Returns: (transfer full): a new #GdaSqlSelectField structure. + */ +GdaSqlSelectField * +gda_sql_select_field_copy (GdaSqlSelectField *field) +{ + GdaSqlSelectField *copy; + + if (!field) return NULL; + + copy = gda_sql_select_field_new (NULL); + copy->expr = gda_sql_expr_copy (field->expr); + gda_sql_any_part_set_parent (copy->expr, copy); + + if (field->field_name) + copy->field_name = g_strdup (field->field_name); + if (field->table_name) + copy->table_name = g_strdup (field->table_name); + if (field->as) + copy->as = g_strdup (field->as); + + copy->validity_meta_object = field->validity_meta_object; + copy->validity_meta_table_column = field->validity_meta_table_column; + + return copy; +} + +G_DEFINE_BOXED_TYPE(GdaSqlSelectField, gda_sql_select_field, gda_sql_select_field_copy, gda_sql_select_field_free) + +/** + * gda_sql_select_field_serialize + * @field: a #GdaSqlSelectField structure + * + * Creates a new string representing an expression used as field in a SELECT statement + * before the FROM clause. + * + * Returns: a new string with the description of the expression or "null" in case @field is invalid. + */ +gchar * +gda_sql_select_field_serialize (GdaSqlSelectField *field) +{ + if (!field) + return g_strdup ("null"); + else { + GString *string; + gchar *str; + + string = g_string_new ("{"); + + g_string_append (string, "\"expr\":"); + str = gda_sql_expr_serialize (field->expr); + g_string_append (string, str); + g_free (str); + + if (field->field_name) { + g_string_append (string, ",\"field_name\":"); + str = _json_quote_string (field->field_name); + g_string_append (string, str); + g_free (str); + } + if (field->table_name) { + g_string_append (string, ",\"table_name\":"); + str = _json_quote_string (field->table_name); + g_string_append (string, str); + g_free (str); + } + if (field->as) { + g_string_append (string, ",\"as\":"); + str = _json_quote_string (field->as); + g_string_append (string, str); + g_free (str); + } + + g_string_append_c (string, '}'); + str = string->str; + g_string_free (string, FALSE); + return str; + } +} + +/** + * gda_sql_select_field_take_expr + * @field: a #GdaSqlSelectField structure + * @expr: a #GdaSqlExpr to take from + * + * Sets the expression field in the #GdaSqlSelectField structure to point to @expr + * and modify it to sets its parent to @field. + */ +void +gda_sql_select_field_take_expr (GdaSqlSelectField *field, GdaSqlExpr *expr) +{ + field->expr = expr; + g_assert (GDA_SQL_ANY_PART (expr)->type == GDA_SQL_ANY_EXPR); + gda_sql_any_part_set_parent (field->expr, field); + + if (expr && expr->value) { + const gchar *dup; + dup = g_value_get_string (expr->value); + if (dup && *dup) + _split_identifier_string (g_strdup (dup), &(field->table_name), &(field->field_name)); + } +} + +/** + * gda_sql_select_field_take_star_value + * @field: a #GdaSqlSelectField structure + * @value: a #GValue to take from + * + * Sets the expression field's value in the #GdaSqlSelectField structure to point to @value; + * after this @field is the owner of @value. + * + */ +void +gda_sql_select_field_take_star_value (GdaSqlSelectField *field, GValue *value) +{ + if (value) { + field->expr = gda_sql_expr_new (GDA_SQL_ANY_PART (field)); + field->expr->value = value; + } +} + +/** + * gda_sql_select_field_take_alias + * @field: a #GdaSqlSelectField structure + * @alias: a #GValue to take from + * + * Sets the 'as' field's string in the #GdaSqlSelectField structure. @alias is freed + * after call this function. + * + */ +void +gda_sql_select_field_take_alias (GdaSqlSelectField *field, GValue *alias) +{ + if (alias) { + field->as = g_value_dup_string (alias); + gda_value_free (alias); + } +} + +/** + * gda_sql_select_target_new + * @parent: a #GdaSqlSelectFrom + * + * Creates a new #GdaSqlSelectTarget structure and sets its parent to @parent. A + * #GdaSqlSelectTarget is the table in a SELECT statement. + * + * Returns: a new #GdaSqlSelectTarget structure. + */ +GdaSqlSelectTarget * +gda_sql_select_target_new (GdaSqlAnyPart *parent) +{ + GdaSqlSelectTarget *target; + target = g_new0 (GdaSqlSelectTarget, 1); + GDA_SQL_ANY_PART(target)->type = GDA_SQL_ANY_SQL_SELECT_TARGET; + GDA_SQL_ANY_PART(target)->parent = parent; + return target; +} + +/** + * gda_sql_select_target_free + * @target: a #GdaSqlSelectTarget structure to be freed + * + * Frees a #GdaSqlSelectTarget structure and its members. + */ +void +gda_sql_select_target_free (GdaSqlSelectTarget *target) +{ + if (!target) return; + + _gda_sql_select_target_check_clean (target); + gda_sql_expr_free (target->expr); + g_free (target->table_name); + g_free (target->as); + + g_free (target); +} + +/** + * gda_sql_select_target_copy + * @target: a #GdaSqlSelectTarget structure to be copied + * + * Creates a new #GdaSqlSelectTarget structure initiated with the values stored in @target. + * + * Returns: a new #GdaSqlSelectTarget structure. + */ +GdaSqlSelectTarget * +gda_sql_select_target_copy (GdaSqlSelectTarget *target) +{ + GdaSqlSelectTarget *copy; + + if (!target) return NULL; + + copy = gda_sql_select_target_new (NULL); + copy->expr = gda_sql_expr_copy (target->expr); + gda_sql_any_part_set_parent (copy->expr, copy); + + if (target->table_name) + copy->table_name = g_strdup (target->table_name); + if (target->as) + copy->as = g_strdup (target->as); + + copy->validity_meta_object = target->validity_meta_object; + + return copy; +} + +G_DEFINE_BOXED_TYPE(GdaSqlSelectTarget, gda_sql_select_target, gda_sql_select_target_copy, gda_sql_select_target_free) + +/** + * gda_sql_select_target_serialize + * @target: a #GdaSqlSelectTarget structure + * + * Creates a new string representing a target used in a SELECT statement + * after the FROM clause. + * + * Returns: a new string with the description of the expression or "null" in case @field is invalid. + */ +gchar * +gda_sql_select_target_serialize (GdaSqlSelectTarget *target) +{ + if (!target) + return g_strdup ("null"); + else { + GString *string; + gchar *str; + + string = g_string_new ("{"); + + g_string_append (string, "\"expr\":"); + str = gda_sql_expr_serialize (target->expr); + g_string_append (string, str); + g_free (str); + + if (target->table_name) { + g_string_append (string, ",\"table_name\":"); + str = _json_quote_string (target->table_name); + g_string_append (string, str); + g_free (str); + } + if (target->as) { + g_string_append (string, ",\"as\":"); + str = _json_quote_string (target->as); + g_string_append (string, str); + g_free (str); + } + + g_string_append_c (string, '}'); + str = string->str; + g_string_free (string, FALSE); + return str; + } +} + +/** + * gda_sql_select_target_take_table_name: + * @target: a #GdaSqlSelectTarget structure + * @value: a #GValue to take from + * + * Sets the target's name using the string stored in @value and the expression + * to set its value to point to value; after call this function the target owns + * @value, then you must not free it. + */ +void +gda_sql_select_target_take_table_name (GdaSqlSelectTarget *target, GValue *value) +{ + if (value) { + target->table_name = g_value_dup_string (value); + target->expr = gda_sql_expr_new (GDA_SQL_ANY_PART (target)); + target->expr->value = value; + } +} + +/** + * gda_sql_select_target_take_select: + * @target: a #GdaSqlSelectTarget structure + * @stmt: a #GValue to take from + * + * Sets the target to be a SELECT subquery setting target's expression to use + * @stmt; after call this function the target owns @stmt, then you must not free it. + */ +void +gda_sql_select_target_take_select (GdaSqlSelectTarget *target, GdaSqlStatement *stmt) +{ + if (stmt) { + target->expr = gda_sql_expr_new (GDA_SQL_ANY_PART (target)); + gda_sql_expr_take_select (target->expr, stmt); + } +} + +/** + * gda_sql_select_target_take_table_alias + * @target: a #GdaSqlSelectTarget structure + * @alias: a #GValue holding the alias string to take from + * + * Sets the target alias (AS) to the string held by @alias; after call + * this function @alias is freed. + */ +void +gda_sql_select_target_take_alias (GdaSqlSelectTarget *target, GValue *alias) +{ + if (alias) { + target->as = g_value_dup_string (alias); + gda_value_free (alias); + } +} + +/* + * Any JOIN ... in a SELECT statement + */ + +/** + * gda_sql_select_join_new + * @parent: a #GdaSqlSelectFrom + * + * Creates a new #GdaSqlSelectJoin structure and sets its parent to @parent. + * + * Returns: a new #GdaSqlSelectJoin structure + */ +GdaSqlSelectJoin * +gda_sql_select_join_new (GdaSqlAnyPart *parent) +{ + GdaSqlSelectJoin *join; + join = g_new0 (GdaSqlSelectJoin, 1); + GDA_SQL_ANY_PART(join)->type = GDA_SQL_ANY_SQL_SELECT_JOIN; + GDA_SQL_ANY_PART(join)->parent = parent; + return join; +} + +/** + * gda_sql_select_join_free + * @join: a #GdaSqlSelectJoin structure to be freed + * + * Frees a #GdaSqlSelectJoin structure and its members. + */ +void +gda_sql_select_join_free (GdaSqlSelectJoin *join) +{ + if (!join) return; + + gda_sql_expr_free (join->expr); + g_slist_free_full (join->use, (GDestroyNotify) gda_sql_field_free); + + g_free (join); +} + +/** + * gda_sql_select_join_copy + * @join: a #GdaSqlSelectJoin structure to be copied + * + * Creates a new #GdaSqlSelectJoin structure initiated with the values stored in @join. + * + * Returns: a new #GdaSqlSelectJoin structure. + */ +GdaSqlSelectJoin * +gda_sql_select_join_copy (GdaSqlSelectJoin *join) +{ + GdaSqlSelectJoin *copy; + GSList *list; + + if (!join) return NULL; + + copy = gda_sql_select_join_new (NULL); + copy->type = join->type; + copy->position = join->position; + + copy->expr = gda_sql_expr_copy (join->expr); + gda_sql_any_part_set_parent (copy->expr, copy); + + for (list = join->use; list; list = list->next) { + copy->use = g_slist_prepend (copy->use, + gda_sql_field_copy ((GdaSqlField*) list->data)); + gda_sql_any_part_set_parent (copy->use->data, copy); + } + copy->use = g_slist_reverse (copy->use); + + return copy; +} + +G_DEFINE_BOXED_TYPE(GdaSqlSelectJoin, gda_sql_select_join, gda_sql_select_join_copy, gda_sql_select_join_free) + +/** + * gda_sql_select_join_type_to_string + * @type: a #GdaSqlSelectJoinType structure to be copied + * + * Creates a new string representing the join type. + * + * Returns: a string representing the Join type. + */ +const gchar * +gda_sql_select_join_type_to_string (GdaSqlSelectJoinType type) +{ + switch (type) { + case GDA_SQL_SELECT_JOIN_CROSS: + return "CROSS"; + case GDA_SQL_SELECT_JOIN_NATURAL: + return "NATURAL"; + case GDA_SQL_SELECT_JOIN_INNER: + return "INNER"; + case GDA_SQL_SELECT_JOIN_LEFT: + return "LEFT"; + case GDA_SQL_SELECT_JOIN_RIGHT: + return "RIGHT"; + case GDA_SQL_SELECT_JOIN_FULL: + return "FULL"; + default: + g_error ("Unhandled join type constant %d\n", type); + return NULL; + } +} + +/** + * gda_sql_select_join_serialize + * @join: a #GdaSqlSelectJoin structure + * + * Creates a new string description of the join used in a SELECT statement. + * + * Returns: a new string with the description of the join or "null" in case @join is invalid. + */ +gchar * +gda_sql_select_join_serialize (GdaSqlSelectJoin *join) +{ + if (!join) + return g_strdup ("null"); + else { + GString *string; + gchar *str; + + string = g_string_new ("{"); + + g_string_append (string, "\"join_type\":"); + g_string_append_c (string, '"'); + g_string_append (string, gda_sql_select_join_type_to_string (join->type)); + g_string_append_c (string, '"'); + + g_string_append (string, ",\"join_pos\":"); + str = g_strdup_printf ("\"%d\"", join->position); + g_string_append (string, str); + g_free (str); + + if (join->expr) { + g_string_append (string, ",\"on_cond\":"); + str = gda_sql_expr_serialize (join->expr); + g_string_append (string, str); + g_free (str); + } + + if (join->use) { + GSList *list; + g_string_append (string, ",\"using\":"); + g_string_append_c (string, '['); + for (list = join->use; list; list = list->next) { + if (list != join->use) + g_string_append_c (string, ','); + str = gda_sql_field_serialize ((GdaSqlField*) list->data); + g_string_append (string, str); + g_free (str); + } + g_string_append_c (string, ']'); + } + + g_string_append_c (string, '}'); + str = string->str; + g_string_free (string, FALSE); + return str; + } +} + +/* + * Any FROM ... in a SELECT statement + */ + +/** + * gda_sql_select_from_new + * @parent: a #GdaSqlStatementSelect + * + * Creates a new #GdaSqlSelectFrom structure and sets its parent to @parent. + * + * Returns: a new #GdaSqlSelectFrom structure + */ +GdaSqlSelectFrom * +gda_sql_select_from_new (GdaSqlAnyPart *parent) +{ + GdaSqlSelectFrom *from; + from = g_new0 (GdaSqlSelectFrom, 1); + GDA_SQL_ANY_PART(from)->type = GDA_SQL_ANY_SQL_SELECT_FROM; + GDA_SQL_ANY_PART(from)->parent = parent; + return from; +} + +/** + * gda_sql_select_from_free + * @from: a #GdaSqlSelectFrom structure to be freed + * + * Frees a #GdaSqlSelectFrom structure and its members. + */ +void +gda_sql_select_from_free (GdaSqlSelectFrom *from) +{ + if (!from) return; + + if (from->targets) { + g_slist_free_full (from->targets, (GDestroyNotify) gda_sql_select_target_free); + } + if (from->joins) { + g_slist_free_full (from->joins, (GDestroyNotify) gda_sql_select_join_free); + } + + g_free (from); +} + +/** + * gda_sql_select_from_copy + * @from: a #GdaSqlSelectFrom structure to be copied + * + * Creates a new #GdaSqlSelectFrom structure initiated with the values stored in @from. + * + * Returns: a new #GdaSqlSelectFrom structure. + */ +GdaSqlSelectFrom * +gda_sql_select_from_copy (GdaSqlSelectFrom *from) +{ + GdaSqlSelectFrom *copy; + GSList *list; + + if (!from) return NULL; + + copy = gda_sql_select_from_new (NULL); + for (list = from->targets; list; list = list->next) { + copy->targets = g_slist_prepend (copy->targets, + gda_sql_select_target_copy ((GdaSqlSelectTarget *) list->data)); + gda_sql_any_part_set_parent (copy->targets->data, copy); + } + copy->targets = g_slist_reverse (copy->targets); + + for (list = from->joins; list; list = list->next) { + copy->joins = g_slist_prepend (copy->joins, + gda_sql_select_join_copy ((GdaSqlSelectJoin *) list->data)); + gda_sql_any_part_set_parent (copy->joins->data, copy); + } + copy->joins = g_slist_reverse (copy->joins); + + return copy; +} + +G_DEFINE_BOXED_TYPE(GdaSqlSelectFrom, gda_sql_select_from, gda_sql_select_from_copy, gda_sql_select_from_free) + + +/** + * gda_sql_select_from_serialize + * @from: a #GdaSqlSelectFrom structure + * + * Creates a new string description of the FROM clause used in a SELECT statement. + * + * Returns: a new string with the description of the FROM or "null" in case @from is invalid. + */ +gchar * +gda_sql_select_from_serialize (GdaSqlSelectFrom *from) +{ + if (!from) + return g_strdup ("null"); + else { + GString *string; + gchar *str; + GSList *list; + + string = g_string_new ("{"); + + g_string_append (string, "\"targets\":"); + if (from->targets) { + g_string_append_c (string, '['); + for (list = from->targets; list; list = list->next) { + if (list != from->targets) + g_string_append_c (string, ','); + str = gda_sql_select_target_serialize ((GdaSqlSelectTarget *) list->data); + g_string_append (string, str); + g_free (str); + } + g_string_append_c (string, ']'); + } + else + g_string_append (string, "null"); + + if (from->joins) { + g_string_append (string, ",\"joins\":"); + g_string_append_c (string, '['); + for (list = from->joins; list; list = list->next) { + if (list != from->joins) + g_string_append_c (string, ','); + str = gda_sql_select_join_serialize ((GdaSqlSelectJoin *) list->data); + g_string_append (string, str); + g_free (str); + } + g_string_append_c (string, ']'); + } + + g_string_append_c (string, '}'); + str = string->str; + g_string_free (string, FALSE); + return str; + } +} + +/** + * gda_sql_select_from_take_new_target + * @from: a #GdaSqlSelectFrom structure + * @target: a #GdaSqlSelectTarget to take from + * + * Append @target to the targets in the FROM clause and set @target's parent to + * @from; after call this function @from owns @target then you must not free it. + */ +void +gda_sql_select_from_take_new_target (GdaSqlSelectFrom *from, GdaSqlSelectTarget *target) +{ + from->targets = g_slist_append (from->targets, target); + gda_sql_any_part_set_parent (target, from); +} + +/** + * gda_sql_select_from_take_new_join + * @from: a #GdaSqlSelectFrom structure + * @join: a #GdaSqlSelectJoin to take from + * + * Append @join to the joins in the FROM clause and set @join's parent to + * @from; after call this function @from owns @join then you must not free it. + */ +void +gda_sql_select_from_take_new_join (GdaSqlSelectFrom *from, GdaSqlSelectJoin *join) +{ + from->joins = g_slist_append (from->joins, join); + gda_sql_any_part_set_parent (join, from); +} + +/* + * Any expression in a SELECT ... after the ORDER BY + */ + +/** + * gda_sql_select_order_new + * @parent: a #GdaSqlStatementSelect + * + * Creates a new #GdaSqlSelectOrder structure and sets its parent to @parent. + * + * Returns: a new #GdaSqlSelectOrder structure + */ +GdaSqlSelectOrder * +gda_sql_select_order_new (GdaSqlAnyPart *parent) +{ + GdaSqlSelectOrder *order; + order = g_new0 (GdaSqlSelectOrder, 1); + GDA_SQL_ANY_PART(order)->type = GDA_SQL_ANY_SQL_SELECT_ORDER; + GDA_SQL_ANY_PART(order)->parent = parent; + return order; +} + +/** + * gda_sql_select_order_free + * @order: a #GdaSqlSelectOrder structure to be freed + * + * Frees a #GdaSqlSelectOrder structure and its members. + */ +void +gda_sql_select_order_free (GdaSqlSelectOrder *order) +{ + if (!order) return; + + gda_sql_expr_free (order->expr); + g_free (order->collation_name); + + g_free (order); +} + +/** + * gda_sql_select_order_copy + * @order: a #GdaSqlSelectOrder structure to be copied + * + * Creates a new #GdaSqlSelectOrder structure initiated with the values stored in @order. + * + * Returns: a new #GdaSqlSelectOrder structure. + */ +GdaSqlSelectOrder * +gda_sql_select_order_copy (GdaSqlSelectOrder *order) +{ + GdaSqlSelectOrder *copy; + + if (!order) return NULL; + + copy = gda_sql_select_order_new (NULL); + + copy->expr = gda_sql_expr_copy (order->expr); + gda_sql_any_part_set_parent (copy->expr, copy); + + if (order->collation_name) + copy->collation_name = g_strdup (order->collation_name); + copy->asc = order->asc; + return copy; +} + +G_DEFINE_BOXED_TYPE(GdaSqlSelectOrder, gda_sql_select_order, gda_sql_select_order_copy, gda_sql_select_order_free) + +/** + * gda_sql_select_order_serialize + * @order: a #GdaSqlSelectOrder structure + * + * Creates a new string description of the ORDER BY clause used in a SELECT statement. + * + * Returns: a new string with the description of the ORDER BY or "null" in case @order is invalid. + */ +gchar * +gda_sql_select_order_serialize (GdaSqlSelectOrder *order) +{ + if (!order) + return g_strdup ("null"); + else { + GString *string; + gchar *str; + + string = g_string_new ("{"); + + g_string_append (string, "\"expr\":"); + str = gda_sql_expr_serialize (order->expr); + g_string_append (string, str); + g_free (str); + + g_string_append (string, ",\"sort\":"); + g_string_append (string, order->asc ? "\"ASC\"" : "\"DESC\""); + + if (order->collation_name) { + g_string_append (string, ",\"collation\":"); + str = _json_quote_string (order->collation_name); + g_string_append (string, str); + g_free (str); + } + + g_string_append_c (string, '}'); + str = string->str; + g_string_free (string, FALSE); + return str; + } +} diff --git a/.flatpak-builder/cache/objects/00/d835a2919d6cd9b37ad1ddfeef714c34473820ca8bfde3b7570cfafec58f5c.dirtree b/.flatpak-builder/cache/objects/00/d835a2919d6cd9b37ad1ddfeef714c34473820ca8bfde3b7570cfafec58f5c.dirtree new file mode 100644 index 0000000..f049120 Binary files /dev/null and b/.flatpak-builder/cache/objects/00/d835a2919d6cd9b37ad1ddfeef714c34473820ca8bfde3b7570cfafec58f5c.dirtree differ diff --git a/.flatpak-builder/cache/objects/01/bcedc268f7d3b5b3ba639526ffe478850c023976c99fa6f1f4905f198ea8d6.file b/.flatpak-builder/cache/objects/01/bcedc268f7d3b5b3ba639526ffe478850c023976c99fa6f1f4905f198ea8d6.file new file mode 100644 index 0000000..31fca3a Binary files /dev/null and b/.flatpak-builder/cache/objects/01/bcedc268f7d3b5b3ba639526ffe478850c023976c99fa6f1f4905f198ea8d6.file differ diff --git a/.flatpak-builder/cache/objects/02/1f9d83c3986c4be4eda7bafa258db7211627ac15f847ecfcf35243cd583e3e.dirtree b/.flatpak-builder/cache/objects/02/1f9d83c3986c4be4eda7bafa258db7211627ac15f847ecfcf35243cd583e3e.dirtree new file mode 100644 index 0000000..2d01def Binary files /dev/null and b/.flatpak-builder/cache/objects/02/1f9d83c3986c4be4eda7bafa258db7211627ac15f847ecfcf35243cd583e3e.dirtree differ diff --git a/.flatpak-builder/cache/objects/02/adc4288e2e9fce448eac67facb8d6b9793c63672198ae3f4dc27afbd686349.file b/.flatpak-builder/cache/objects/02/adc4288e2e9fce448eac67facb8d6b9793c63672198ae3f4dc27afbd686349.file new file mode 100644 index 0000000..f26dc43 Binary files /dev/null and b/.flatpak-builder/cache/objects/02/adc4288e2e9fce448eac67facb8d6b9793c63672198ae3f4dc27afbd686349.file differ diff --git a/.flatpak-builder/cache/objects/02/b74363ee6cc8e90e7cf6d95208facaf83221b115e0f64699b5584e531fb82e.file b/.flatpak-builder/cache/objects/02/b74363ee6cc8e90e7cf6d95208facaf83221b115e0f64699b5584e531fb82e.file new file mode 100644 index 0000000..f2ff8f1 Binary files /dev/null and b/.flatpak-builder/cache/objects/02/b74363ee6cc8e90e7cf6d95208facaf83221b115e0f64699b5584e531fb82e.file differ diff --git a/.flatpak-builder/cache/objects/03/5e548fa0f668693af0ffa44c88437b33f1f06d55e9c4b9e4a15b8ee919f5ae.dirtree b/.flatpak-builder/cache/objects/03/5e548fa0f668693af0ffa44c88437b33f1f06d55e9c4b9e4a15b8ee919f5ae.dirtree new file mode 100644 index 0000000..c8c0a4a Binary files /dev/null and b/.flatpak-builder/cache/objects/03/5e548fa0f668693af0ffa44c88437b33f1f06d55e9c4b9e4a15b8ee919f5ae.dirtree differ diff --git a/.flatpak-builder/cache/objects/03/68686429d0934a691fac484acebbcc480461e78bd96656df333590b1ac0fab.file b/.flatpak-builder/cache/objects/03/68686429d0934a691fac484acebbcc480461e78bd96656df333590b1ac0fab.file new file mode 100644 index 0000000..116a25a --- /dev/null +++ b/.flatpak-builder/cache/objects/03/68686429d0934a691fac484acebbcc480461e78bd96656df333590b1ac0fab.file @@ -0,0 +1,53 @@ +/*-*- Mode: C; c-basic-offset: 8 -*-*/ + +#ifndef foocanberracommonh +#define foocanberracommonh + +/*** + This file is part of libcanberra. + + Copyright 2008 Lennart Poettering + + libcanberra is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation, either version 2.1 of the + License, or (at your option) any later version. + + libcanberra is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with libcanberra. If not, see + . +***/ + +#include "canberra.h" +#include "macro.h" +#include "mutex.h" + +struct ca_context { + ca_bool_t opened; + ca_mutex *mutex; + + ca_proplist *props; + + char *driver; + char *device; + + void *private; +#ifdef HAVE_DSO + void *private_dso; +#endif +}; + +typedef enum ca_cache_control { + CA_CACHE_CONTROL_NEVER, + CA_CACHE_CONTROL_PERMANENT, + CA_CACHE_CONTROL_VOLATILE +} ca_cache_control_t; + +int ca_parse_cache_control(ca_cache_control_t *control, const char *c); + +#endif diff --git a/.flatpak-builder/cache/objects/03/d19b318015f476853eefd32e8390e3d9f2ed227d1bdeeed339bb59d4a9361d.dirtree b/.flatpak-builder/cache/objects/03/d19b318015f476853eefd32e8390e3d9f2ed227d1bdeeed339bb59d4a9361d.dirtree new file mode 100644 index 0000000..e6b0c66 Binary files /dev/null and b/.flatpak-builder/cache/objects/03/d19b318015f476853eefd32e8390e3d9f2ed227d1bdeeed339bb59d4a9361d.dirtree differ diff --git a/.flatpak-builder/cache/objects/04/17f9416c64a524ad28623bc97e77147f1dca763ee2b8238cdef13b06ee2b50.dirtree b/.flatpak-builder/cache/objects/04/17f9416c64a524ad28623bc97e77147f1dca763ee2b8238cdef13b06ee2b50.dirtree new file mode 100644 index 0000000..c5b6493 Binary files /dev/null and b/.flatpak-builder/cache/objects/04/17f9416c64a524ad28623bc97e77147f1dca763ee2b8238cdef13b06ee2b50.dirtree differ diff --git a/.flatpak-builder/cache/objects/04/3308ffa7df27518740c27e87322b1639e411ca1ca476699ca4cf755dacf5b7.dirtree b/.flatpak-builder/cache/objects/04/3308ffa7df27518740c27e87322b1639e411ca1ca476699ca4cf755dacf5b7.dirtree new file mode 100644 index 0000000..f70852d Binary files /dev/null and b/.flatpak-builder/cache/objects/04/3308ffa7df27518740c27e87322b1639e411ca1ca476699ca4cf755dacf5b7.dirtree differ diff --git a/.flatpak-builder/cache/objects/04/82ed9cbf588906c85f94f6078c8d8f7369d03132a7ac34286dee0508c8cf41.dirtree b/.flatpak-builder/cache/objects/04/82ed9cbf588906c85f94f6078c8d8f7369d03132a7ac34286dee0508c8cf41.dirtree new file mode 100644 index 0000000..2ce1ba0 Binary files /dev/null and b/.flatpak-builder/cache/objects/04/82ed9cbf588906c85f94f6078c8d8f7369d03132a7ac34286dee0508c8cf41.dirtree differ diff --git a/.flatpak-builder/cache/objects/04/bf37a2640918a9bbc9acc3ac4d7db520ba1d2da053eca5f05efa1e9d6044ba.file b/.flatpak-builder/cache/objects/04/bf37a2640918a9bbc9acc3ac4d7db520ba1d2da053eca5f05efa1e9d6044ba.file new file mode 100644 index 0000000..9a6ef92 --- /dev/null +++ b/.flatpak-builder/cache/objects/04/bf37a2640918a9bbc9acc3ac4d7db520ba1d2da053eca5f05efa1e9d6044ba.file @@ -0,0 +1,418 @@ +/* + * Copyright (C) 2008 - 2010 Murray Cumming + * Copyright (C) 2008 - 2012 Vivien Malerba + * Copyright (C) 2009 Bas Driessen + * Copyright (C) 2010 David King + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +static gpointer gda_sql_statement_insert_new (void); +static void gda_sql_statement_insert_free (gpointer stmt); +static gpointer gda_sql_statement_insert_copy (gpointer src); +static gchar *gda_sql_statement_insert_serialize (gpointer stmt); +static gboolean gda_sql_statement_insert_check_structure (GdaSqlAnyPart *stmt, gpointer data, GError **error); + +GdaSqlStatementContentsInfo insert_infos = { + GDA_SQL_STATEMENT_INSERT, + "INSERT", + gda_sql_statement_insert_new, + gda_sql_statement_insert_free, + gda_sql_statement_insert_copy, + gda_sql_statement_insert_serialize, + + gda_sql_statement_insert_check_structure, + NULL, + NULL, + NULL, + NULL, + NULL +}; + +GdaSqlStatementContentsInfo * +_gda_sql_statement_insert_get_infos (void) +{ + return &insert_infos; +} + +static gpointer +gda_sql_statement_insert_new (void) +{ + GdaSqlStatementInsert *stmt; + stmt = g_new0 (GdaSqlStatementInsert, 1); + GDA_SQL_ANY_PART (stmt)->type = GDA_SQL_ANY_STMT_INSERT; + return (gpointer) stmt; +} + +static void +gda_sql_statement_insert_free (gpointer stmt) +{ + GdaSqlStatementInsert *insert = (GdaSqlStatementInsert *) stmt; + GSList *list; + g_free (insert->on_conflict); + gda_sql_table_free (insert->table); + for (list = insert->values_list; list; list = list->next) { + if (list->data) { + g_slist_free_full ((GSList *) list->data, (GDestroyNotify) gda_sql_expr_free); + } + } + g_slist_free (insert->values_list); + + g_slist_free_full (insert->fields_list, (GDestroyNotify) gda_sql_field_free); + if (insert->select) { + if (GDA_SQL_ANY_PART (insert->select)->type == GDA_SQL_ANY_STMT_SELECT) + _gda_sql_statement_select_free (insert->select); + else if (GDA_SQL_ANY_PART (insert->select)->type == GDA_SQL_ANY_STMT_COMPOUND) + _gda_sql_statement_compound_free (insert->select); + else + g_assert_not_reached (); + } + + g_free (insert); +} + +static gpointer +gda_sql_statement_insert_copy (gpointer src) +{ + GdaSqlStatementInsert *dest; + GSList *list; + GdaSqlStatementInsert *insert = (GdaSqlStatementInsert *) src; + + dest = gda_sql_statement_insert_new (); + if (insert->on_conflict) + dest->on_conflict = g_strdup (insert->on_conflict); + + dest->table = gda_sql_table_copy (insert->table); + gda_sql_any_part_set_parent (dest->table, dest); + + for (list = insert->fields_list; list; list = list->next) { + dest->fields_list = g_slist_prepend (dest->fields_list, + gda_sql_field_copy ((GdaSqlField*) list->data)); + gda_sql_any_part_set_parent (dest->fields_list->data, dest); + } + dest->fields_list = g_slist_reverse (dest->fields_list); + + for (list = insert->values_list; list; list = list->next) { + GSList *vlist, *clist = NULL; + for (vlist = (GSList *) list->data; vlist; vlist = vlist->next) { + clist = g_slist_prepend (clist, + gda_sql_expr_copy ((GdaSqlExpr*) vlist->data)); + gda_sql_any_part_set_parent (clist->data, dest); + } + dest->values_list = g_slist_append (dest->values_list, g_slist_reverse (clist)); + } + if (insert->select) { + if (GDA_SQL_ANY_PART (insert->select)->type == GDA_SQL_ANY_STMT_SELECT) + dest->select = _gda_sql_statement_select_copy (insert->select); + else if (GDA_SQL_ANY_PART (insert->select)->type == GDA_SQL_ANY_STMT_COMPOUND) + dest->select = _gda_sql_statement_compound_copy (insert->select); + else + g_assert_not_reached (); + gda_sql_any_part_set_parent (dest->select, dest); + } + + return dest; +} + +static gchar * +gda_sql_statement_insert_serialize (gpointer stmt) +{ + GString *string; + gchar *str; + GSList *list; + GdaSqlStatementInsert *insert = (GdaSqlStatementInsert *) stmt; + + g_return_val_if_fail (stmt, NULL); + + string = g_string_new ("\"contents\":{"); + + /* table name */ + g_string_append (string, "\"table\":"); + str = gda_sql_table_serialize (insert->table); + g_string_append (string, str); + g_free (str); + + /* fields */ + g_string_append (string, ",\"fields\":"); + if (insert->fields_list) { + g_string_append_c (string, '['); + for (list = insert->fields_list; list; list = list->next) { + if (list != insert->fields_list) + g_string_append_c (string, ','); + str = gda_sql_field_serialize ((GdaSqlField*) list->data); + g_string_append (string, str); + g_free (str); + } + g_string_append_c (string, ']'); + } + else + g_string_append (string, "null"); + + /* values */ + if (insert->values_list) { + g_string_append (string, ",\"values\":["); + for (list = insert->values_list; list; list = list->next) { + if (list != insert->values_list) + g_string_append_c (string, ','); + if (list->data) { + GSList *vlist; + g_string_append_c (string, '['); + for (vlist = (GSList *) list->data; vlist; vlist = vlist->next) { + if (vlist != (GSList *) list->data) + g_string_append_c (string, ','); + str = gda_sql_expr_serialize ((GdaSqlExpr*) vlist->data); + g_string_append (string, str); + g_free (str); + } + g_string_append_c (string, ']'); + } + else + g_string_append (string, "null"); + } + g_string_append_c (string, ']'); + } + + /* select statement */ + if (insert->select) { + g_string_append (string, ",\"select\":{"); + if (GDA_SQL_ANY_PART (insert->select)->type == GDA_SQL_ANY_STMT_SELECT) + str = _gda_sql_statement_select_serialize (insert->select); + else if (GDA_SQL_ANY_PART (insert->select)->type == GDA_SQL_ANY_STMT_COMPOUND) + str = _gda_sql_statement_compound_serialize (insert->select); + else + g_assert_not_reached (); + + g_string_append (string, str); + g_free (str); + g_string_append_c (string, '}'); + } + + /* conflict clause */ + if (insert->on_conflict) { + g_string_append (string, ",\"on_conflict\":"); + str = _json_quote_string (insert->on_conflict); + g_string_append (string, str); + g_free (str); + } + g_string_append_c (string, '}'); + str = string->str; + g_string_free (string, FALSE); + return str; +} + +/** + * gda_sql_statement_insert_take_table_name + * @stmt: a #GdaSqlStatement pointer + * @value: name of the table to insert into, as a G_TYPE_STRING #GValue + * + * Sets the name of the table to insert into in @stmt. @value's ownership is transferred to + * @stmt (which means @stmt is then responsible for freeing it when no longer needed). + */ +void +gda_sql_statement_insert_take_table_name (GdaSqlStatement *stmt, GValue *value) +{ + GdaSqlStatementInsert *insert = (GdaSqlStatementInsert *) stmt->contents; + if (value) { + insert->table = gda_sql_table_new (GDA_SQL_ANY_PART (insert)); + gda_sql_table_take_name (insert->table, value); + } +} + +/** + * gda_sql_statement_insert_take_on_conflict + * @stmt: a #GdaSqlStatement pointer + * @value: name of the resolution conflict algorithm, as a G_TYPE_STRING #GValue + * + * Sets the name of the resolution conflict algorithm used by @stmt. @value's ownership is transferred to + * @stmt (which means @stmt is then responsible for freeing it when no longer needed). + */ +void +gda_sql_statement_insert_take_on_conflict (GdaSqlStatement *stmt, GValue *value) +{ + GdaSqlStatementInsert *insert = (GdaSqlStatementInsert *) stmt->contents; + if (value) { + insert->on_conflict = g_value_dup_string (value); + g_value_reset (value); + g_free (value); + } +} + +/** + * gda_sql_statement_insert_take_fields_list + * @stmt: a #GdaSqlStatement pointer + * @list: (element-type Gda.SqlField): a list of #GdaSqlField pointers + * + * Sets the list of fields for which values will be specified in @stmt. @list's + * ownership is transferred to + * @stmt (which means @stmt is then responsible for freeing it when no longer needed). + */ +void +gda_sql_statement_insert_take_fields_list (GdaSqlStatement *stmt, GSList *list) +{ + GSList *l; + GdaSqlStatementInsert *insert = (GdaSqlStatementInsert *) stmt->contents; + insert->fields_list = list; + + for (l = list; l; l = l->next) + gda_sql_any_part_set_parent (l->data, insert); +} + +/** + * gda_sql_statement_insert_take_1_values_list: + * @stmt: a #GdaSqlStatement pointer + * @list: (element-type Gda.SqlExpr): a list of #GdaSqlExpr pointers + * + * Sets a list of values to be inserted by @stmt. @list's + * ownership is transferred to + * @stmt (which means @stmt is then responsible for freeing it when no longer needed). + */ +void +gda_sql_statement_insert_take_1_values_list (GdaSqlStatement *stmt, GSList *list) +{ + GSList *l; + GdaSqlStatementInsert *insert = (GdaSqlStatementInsert *) stmt->contents; + + for (l = list; l; l = l->next) + gda_sql_any_part_set_parent (l->data, insert); + insert->values_list = g_slist_prepend (insert->values_list, list); +} + +/** + * gda_sql_statement_insert_take_extra_values_list: + * @stmt: a #GdaSqlStatement pointer + * @list: (element-type GdaSqlExpr): a list of #GSList of #GdaSqlExpr pointers + * + * Sets a list of list of values to be inserted by @stmt. @list's + * ownership is transferred to + * @stmt (which means @stmt is then responsible for freeing it when no longer needed). + */ +void +gda_sql_statement_insert_take_extra_values_list (GdaSqlStatement *stmt, GSList *list) +{ + GSList *l1, *l2; + GdaSqlStatementInsert *insert = (GdaSqlStatementInsert *) stmt->contents; + for (l1 = list; l1; l1 = l1->next) { + for (l2 = (GSList *) l1->data; l2; l2 = l2->next) + gda_sql_any_part_set_parent (l2->data, insert); + } + insert->values_list = g_slist_concat (insert->values_list, list); +} + + +/** + * gda_sql_statement_insert_take_select + * @stmt: a #GdaSqlStatement pointer + * @select: a SELECT or COMPOUND #GdaSqlStatement pointer + * + * Specifies a SELECT statement, the values inserted will be the result set of @select. @select's + * ownership is transferred to + * @stmt (which means @stmt is then responsible for freeing it when no longer needed). + */ +void +gda_sql_statement_insert_take_select (GdaSqlStatement *stmt, GdaSqlStatement *select) +{ + GdaSqlStatementInsert *insert = (GdaSqlStatementInsert *) stmt->contents; + GdaSqlAnyPart *part; + part = GDA_SQL_ANY_PART (select->contents); + select->contents = NULL; + gda_sql_statement_free (select); + insert->select = _gda_sql_statement_compound_reduce (part); + gda_sql_any_part_set_parent (insert->select, insert); +} + +static gboolean +gda_sql_statement_insert_check_structure (GdaSqlAnyPart *stmt, G_GNUC_UNUSED gpointer data, GError **error) +{ + GdaSqlStatementInsert *insert = (GdaSqlStatementInsert *) stmt; + guint nb_values; + GSList *list; + if (!stmt) return TRUE; + + nb_values = g_slist_length (insert->fields_list); /* may be 0 */ + if (!insert->table) { + g_set_error (error, GDA_SQL_ERROR, GDA_SQL_STRUCTURE_CONTENTS_ERROR, + "%s", _("INSERT statement needs a table to insert into")); + return FALSE; + } + if (insert->select) { + if (insert->values_list) { + g_set_error (error, GDA_SQL_ERROR, GDA_SQL_STRUCTURE_CONTENTS_ERROR, + "%s", _("Can't specify values to insert and SELECT statement in INSERT statement")); + return FALSE; + } + if (nb_values > 0) { + guint len; + if (GDA_SQL_ANY_PART (insert->select)->type == GDA_SQL_ANY_STMT_SELECT) { + GdaSqlStatementSelect *select = (GdaSqlStatementSelect*) insert->select; + len = g_slist_length (select->expr_list); + } + else if (GDA_SQL_ANY_PART (insert->select)->type == GDA_SQL_ANY_STMT_COMPOUND) { + gint compound_len; + GdaSqlStatementCompound *compound = (GdaSqlStatementCompound*) insert->select; + compound_len = _gda_sql_statement_compound_get_n_cols (compound, error); + len = compound_len; + if (compound_len < 0) + return FALSE; + } + else + g_assert_not_reached (); + if (len != nb_values) { + g_set_error (error, GDA_SQL_ERROR, GDA_SQL_STRUCTURE_CONTENTS_ERROR, + "%s", _("INSERT statement does not have the same number of target columns and expressions")); + return FALSE; + } + } + } + else { + /* using values list */ + if (!insert->values_list && (nb_values != 0)) { + g_set_error (error, GDA_SQL_ERROR, GDA_SQL_STRUCTURE_CONTENTS_ERROR, + "%s", _("Missing values to insert in INSERT statement")); + return FALSE; + } + + for (list = insert->values_list; list; list = list->next) { + if (nb_values == 0) { + nb_values = g_slist_length ((GSList *) list->data); + if (nb_values == 0) { + g_set_error (error, GDA_SQL_ERROR, GDA_SQL_STRUCTURE_CONTENTS_ERROR, + "%s", _("Missing values to insert in INSERT statement")); + return FALSE; + } + } + else + if (g_slist_length ((GSList *) list->data) != nb_values) { + if (insert->fields_list) + g_set_error (error, GDA_SQL_ERROR, GDA_SQL_STRUCTURE_CONTENTS_ERROR, + "%s", _("INSERT statement does not have the same number of target columns and expressions")); + else + g_set_error (error, GDA_SQL_ERROR, GDA_SQL_STRUCTURE_CONTENTS_ERROR, + "%s", _("VALUES lists must all be the same length in INSERT statement")); + return FALSE; + } + } + } + return TRUE; +} diff --git a/.flatpak-builder/cache/objects/05/57d7fd75eb89660a307e55f3eb59298b20e5a61c5219564960caaf559ba450.dirtree b/.flatpak-builder/cache/objects/05/57d7fd75eb89660a307e55f3eb59298b20e5a61c5219564960caaf559ba450.dirtree new file mode 100644 index 0000000..e464de8 Binary files /dev/null and b/.flatpak-builder/cache/objects/05/57d7fd75eb89660a307e55f3eb59298b20e5a61c5219564960caaf559ba450.dirtree differ diff --git a/.flatpak-builder/cache/objects/05/7d02e55942ae25e8771a85d7b77023bad09ab86b1c05a130cb9fedca238272.file b/.flatpak-builder/cache/objects/05/7d02e55942ae25e8771a85d7b77023bad09ab86b1c05a130cb9fedca238272.file new file mode 100644 index 0000000..65b9011 --- /dev/null +++ b/.flatpak-builder/cache/objects/05/7d02e55942ae25e8771a85d7b77023bad09ab86b1c05a130cb9fedca238272.file @@ -0,0 +1,243 @@ +/* + * Copyright (C) 2001 - 2004 Rodrigo Moya + * Copyright (C) 2002 Gonzalo Paniagua Javier + * Copyright (C) 2003 Laurent Sansonetti + * Copyright (C) 2005 Dan Winship + * Copyright (C) 2005 - 2014 Vivien Malerba + * Copyright (C) 2005 Álvaro Peña + * Copyright (C) 2007 Murray Cumming + * Copyright (C) 2011,2019 Daniel Espinosa + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GDA_DATA_MODEL_H__ +#define __GDA_DATA_MODEL_H__ + +#include +#include +#include +#include +#include +#include +#include +#include + +G_BEGIN_DECLS + +/* error reporting */ +extern GQuark gda_data_model_error_quark (void); +#define GDA_DATA_MODEL_ERROR gda_data_model_error_quark () + +typedef enum { + GDA_DATA_MODEL_ACCESS_RANDOM = 1 << 0, + GDA_DATA_MODEL_ACCESS_CURSOR_FORWARD = 1 << 1, + GDA_DATA_MODEL_ACCESS_CURSOR_BACKWARD = 1 << 2, + GDA_DATA_MODEL_ACCESS_CURSOR = GDA_DATA_MODEL_ACCESS_CURSOR_FORWARD | GDA_DATA_MODEL_ACCESS_CURSOR_BACKWARD, + GDA_DATA_MODEL_ACCESS_INSERT = 1 << 3, + GDA_DATA_MODEL_ACCESS_UPDATE = 1 << 4, + GDA_DATA_MODEL_ACCESS_DELETE = 1 << 5, + GDA_DATA_MODEL_ACCESS_WRITE = GDA_DATA_MODEL_ACCESS_INSERT | GDA_DATA_MODEL_ACCESS_UPDATE | + GDA_DATA_MODEL_ACCESS_DELETE +} GdaDataModelAccessFlags; + +typedef enum { + GDA_DATA_MODEL_HINT_START_BATCH_UPDATE, + GDA_DATA_MODEL_HINT_END_BATCH_UPDATE, + GDA_DATA_MODEL_HINT_REFRESH +} GdaDataModelHint; + +/** + * GdaDataModelIOFormat: + * @GDA_DATA_MODEL_IO_DATA_ARRAY_XML: data is exported as an XML structure + * @GDA_DATA_MODEL_IO_TEXT_SEPARATED: data is exported as CSV + * @GDA_DATA_MODEL_IO_TEXT_TABLE: data is exported as a human readable table + * + * Format to use when exporting a data model, see gda_data_model_export_to_string() and gda_data_model_export_to_file() + */ +typedef enum { + GDA_DATA_MODEL_IO_DATA_ARRAY_XML, + GDA_DATA_MODEL_IO_TEXT_SEPARATED, + GDA_DATA_MODEL_IO_TEXT_TABLE +} GdaDataModelIOFormat; + +typedef enum { + GDA_DATA_MODEL_ROW_OUT_OF_RANGE_ERROR, + GDA_DATA_MODEL_COLUMN_OUT_OF_RANGE_ERROR, + GDA_DATA_MODEL_VALUES_LIST_ERROR, + GDA_DATA_MODEL_VALUE_TYPE_ERROR, + GDA_DATA_MODEL_ROW_NOT_FOUND_ERROR, + GDA_DATA_MODEL_ACCESS_ERROR, + GDA_DATA_MODEL_FEATURE_NON_SUPPORTED_ERROR, + GDA_DATA_MODEL_FILE_EXIST_ERROR, + GDA_DATA_MODEL_XML_FORMAT_ERROR, + + GDA_DATA_MODEL_TRUNCATED_ERROR, + GDA_DATA_MODEL_INVALID, + GDA_DATA_MODEL_OTHER_ERROR +} GdaDataModelError; + + +#define GDA_TYPE_DATA_MODEL (gda_data_model_get_type()) +G_DECLARE_INTERFACE (GdaDataModel, gda_data_model, GDA, DATA_MODEL, GObject) + +/* struct for the interface */ +struct _GdaDataModelInterface { + GTypeInterface g_iface; + + /* virtual table */ + gint (* get_n_rows) (GdaDataModel *model); + gint (* get_n_columns) (GdaDataModel *model); + + GdaColumn *(* describe_column) (GdaDataModel *model, gint col); + GdaDataModelAccessFlags (* get_access_flags) (GdaDataModel *model); + + const GValue *(* get_value_at) (GdaDataModel *model, gint col, gint row, GError **error); + GdaValueAttribute (* get_attributes_at)(GdaDataModel *model, gint col, gint row); + GdaDataModelIter *(* create_iter) (GdaDataModel *model); + + gboolean (* set_value_at) (GdaDataModel *model, gint col, gint row, + const GValue *value, GError **error); + gboolean (* set_values) (GdaDataModel *model, gint row, GList *values, + GError **error); + gint (* append_values) (GdaDataModel *model, const GList *values, GError **error); + gint (* append_row) (GdaDataModel *model, GError **error); + gboolean (* remove_row) (GdaDataModel *model, gint row, GError **error); + gint (* find_row) (GdaDataModel *model, GSList *values, gint *cols_index); + + void (* freeze) (GdaDataModel *model); + void (* thaw) (GdaDataModel *model); + gboolean (* get_notify) (GdaDataModel *model); + void (* send_hint) (GdaDataModel *model, GdaDataModelHint hint, const GValue *hint_value); + + GError **(* get_exceptions) (GdaDataModel *model); + + /* signals */ + void (* row_inserted) (GdaDataModel *model, gint row); + void (* row_updated) (GdaDataModel *model, gint row); + void (* row_removed) (GdaDataModel *model, gint row); + void (* changed) (GdaDataModel *model); + void (* reset) (GdaDataModel *model); + void (* access_changed) (GdaDataModel *model); +}; + +/** + * SECTION:gda-data-model + * @short_description: Data model interface + * @title: GdaDataModel + * @stability: Stable + * @see_also: #GdaDataModelIter + * + * A #GdaDataModel represents an array of values organized in rows and columns. All the data in the same + * column have the same type, and all the data in each row have the same semantic meaning. The #GdaDataModel is + * actually an interface implemented by other objects to support various kinds of data storage and operations. + * + * When a SELECT statement is executed using an opened #GdaConnection, the returned value (if no error occurred) + * is a #GdaDataSelect object which implements the #GdaDataModel interface. Please see the #GdaDataSelect's + * documentation for more information. + * + * Depending on the real implementation, the contents of data models may be modified by the user using functions + * provided by the model. The actual operations a data model permits can be known using the + * gda_data_model_get_access_flags() method. + * + * Again, depending on the real implementation, data retrieving can be done either accessing direct random + * values located by their row and column, or using a cursor, or both. Use the gda_data_model_get_access_flags() + * method to know how the data model can be accessed. + * + * Random access to a data model's contents is done using gda_data_model_get_value_at(), or using + * one or more #GdaDataModelIter object(s); + * Cursor access to a data model's contents is done using a #GdaDataModelIter object. If this mode is + * the only supported, then only one #GdaDataModelIter object can be created and + * it is not possible to use gda_data_model_get_value_at() in this case. + * + * + * Random access data models are easier to use since picking a value is very simple using the gda_data_model_get_value_at(), + * but consume more memory since all the accessible values must generally be present in memory even if they are not used. + * Thus if a data model must handle large quantities of data, it is generally wiser to use a data model which can be + * only accessed using a cursor. + * + * As a side note there are also data models which wrap other data models such as: + * + * The #GdaDataProxy data model which stores temporary modifications and shows only some + * parts of the wrapped data model + * The #GdaDataAccessWrapper data model which offers a memory efficient random access on top of a + * wrapped cursor based access data model + * + * + * Also see the section about writing your own GdaDataModel + * + * Finally, the #GdaDataModel object implements its own locking mechanism and can be used simultaneously from several threads. + */ + +GdaDataModelAccessFlags gda_data_model_get_access_flags (GdaDataModel *model); + +gint gda_data_model_get_n_rows (GdaDataModel *model); +gint gda_data_model_get_n_columns (GdaDataModel *model); + +GdaColumn *gda_data_model_describe_column (GdaDataModel *model, gint col); +gint gda_data_model_get_column_index (GdaDataModel *model, const gchar *name); +const gchar *gda_data_model_get_column_name (GdaDataModel *model, gint col); +void gda_data_model_set_column_name (GdaDataModel *model, gint col, const gchar *name); +const gchar *gda_data_model_get_column_title (GdaDataModel *model, gint col); +void gda_data_model_set_column_title (GdaDataModel *model, gint col, const gchar *title); + +const GValue *gda_data_model_get_value_at (GdaDataModel *model, gint col, gint row, GError **error); +const GValue *gda_data_model_get_typed_value_at (GdaDataModel *model, gint col, gint row, + GType expected_type, gboolean nullok, GError **error); +GdaValueAttribute gda_data_model_get_attributes_at (GdaDataModel *model, gint col, gint row); +GdaDataModelIter *gda_data_model_create_iter (GdaDataModel *model); +void gda_data_model_freeze (GdaDataModel *model); +void gda_data_model_thaw (GdaDataModel *model); +gboolean gda_data_model_get_notify (GdaDataModel *model); +gboolean gda_data_model_set_value_at (GdaDataModel *model, gint col, gint row, + const GValue *value, GError **error); +gboolean gda_data_model_set_values (GdaDataModel *model, gint row, + GList *values, GError **error); +gint gda_data_model_append_row (GdaDataModel *model, GError **error); +gint gda_data_model_append_values (GdaDataModel *model, const GList *values, GError **error); +gboolean gda_data_model_remove_row (GdaDataModel *model, gint row, GError **error); +gint gda_data_model_get_row_from_values (GdaDataModel *model, GSList *values, gint *cols_index); + +void gda_data_model_send_hint (GdaDataModel *model, GdaDataModelHint hint, const GValue *hint_value); + +GError **gda_data_model_get_exceptions (GdaDataModel *model); + +/* contents saving and loading */ +gchar *gda_data_model_export_to_string (GdaDataModel *model, GdaDataModelIOFormat format, + const gint *cols, gint nb_cols, + const gint *rows, gint nb_rows, GdaSet *options); +gboolean gda_data_model_export_to_file (GdaDataModel *model, GdaDataModelIOFormat format, + const gchar *file, + const gint *cols, gint nb_cols, + const gint *rows, gint nb_rows, + GdaSet *options, GError **error); + +gboolean gda_data_model_import_from_model (GdaDataModel *to, GdaDataModel *from, gboolean overwrite, + GHashTable *cols_trans, GError **error); +gboolean gda_data_model_import_from_string (GdaDataModel *model, + const gchar *string, GHashTable *cols_trans, + GdaSet *options, GError **error); +gboolean gda_data_model_import_from_file (GdaDataModel *model, + const gchar *file, GHashTable *cols_trans, + GdaSet *options, GError **error); + +/* debug functions */ +void gda_data_model_dump (GdaDataModel *model, FILE *to_stream); +gchar *gda_data_model_dump_as_string (GdaDataModel *model); + +G_END_DECLS + +#endif diff --git a/.flatpak-builder/cache/objects/05/a6d5f9721d1b25357a3ab340e969333eb96f47d899c6706b357dde8669e2f7.file b/.flatpak-builder/cache/objects/05/a6d5f9721d1b25357a3ab340e969333eb96f47d899c6706b357dde8669e2f7.file new file mode 100644 index 0000000..20ee1ab --- /dev/null +++ b/.flatpak-builder/cache/objects/05/a6d5f9721d1b25357a3ab340e969333eb96f47d899c6706b357dde8669e2f7.file @@ -0,0 +1,54 @@ +/*-*- Mode: C; c-basic-offset: 8 -*-*/ + +/*** + This file is part of libcanberra. + + Copyright 2009 Lennart Poettering + + libcanberra is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation, either version 2.1 of the + License, or (at your option) any later version. + + libcanberra is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with libcanberra. If not, see + . +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include "fork-detect.h" + +int ca_detect_fork(void) { + static volatile pid_t pid = (pid_t) -1; + pid_t v, we; + + /* Some really stupid applications (Hey, vim, that means you!) + * love to fork after initializing gtk/libcanberra. This is really + * bad style. We however have to deal with this cleanly, so we try + * to detect the forks making sure all our calls fail cleanly + * after the fork. */ + + /* Ideally we'd use atomic operations here, but we don't have them + * and this is not exactly crucial, so we don't care */ + + v = pid; + we = getpid(); + + if (v == we || v == (pid_t) -1) { + pid = we; + return 0; + } + + return 1; +} diff --git a/.flatpak-builder/cache/objects/06/2ebfb75a2d9f51996bc768b7dd42a1482b0fd897168b88da4b1fbf16f836f6.dirtree b/.flatpak-builder/cache/objects/06/2ebfb75a2d9f51996bc768b7dd42a1482b0fd897168b88da4b1fbf16f836f6.dirtree new file mode 100644 index 0000000..9669382 Binary files /dev/null and b/.flatpak-builder/cache/objects/06/2ebfb75a2d9f51996bc768b7dd42a1482b0fd897168b88da4b1fbf16f836f6.dirtree differ diff --git a/.flatpak-builder/cache/objects/06/526cf0744dd69132bd20a0249ce05ad0cef5b8bc2bff620765b13f312603d0.dirtree b/.flatpak-builder/cache/objects/06/526cf0744dd69132bd20a0249ce05ad0cef5b8bc2bff620765b13f312603d0.dirtree new file mode 100644 index 0000000..506d750 Binary files /dev/null and b/.flatpak-builder/cache/objects/06/526cf0744dd69132bd20a0249ce05ad0cef5b8bc2bff620765b13f312603d0.dirtree differ diff --git a/.flatpak-builder/cache/objects/06/5ac6935133cc822f2e28f57f70b6c634c4ac29875a8b8dcd198c90d8eae9d0.dirtree b/.flatpak-builder/cache/objects/06/5ac6935133cc822f2e28f57f70b6c634c4ac29875a8b8dcd198c90d8eae9d0.dirtree new file mode 100644 index 0000000..6e6fc68 Binary files /dev/null and b/.flatpak-builder/cache/objects/06/5ac6935133cc822f2e28f57f70b6c634c4ac29875a8b8dcd198c90d8eae9d0.dirtree differ diff --git a/.flatpak-builder/cache/objects/07/34ebddcd1710953ae8fcb11de4055efd93ab2e4b73d9bb7290f82bcb19c4ce.file b/.flatpak-builder/cache/objects/07/34ebddcd1710953ae8fcb11de4055efd93ab2e4b73d9bb7290f82bcb19c4ce.file new file mode 100644 index 0000000..7bda3fd --- /dev/null +++ b/.flatpak-builder/cache/objects/07/34ebddcd1710953ae8fcb11de4055efd93ab2e4b73d9bb7290f82bcb19c4ce.file @@ -0,0 +1,11 @@ +prefix=/app +exec_prefix=/app/libexec +libdir=/app/lib +includedir=/app/include + +Name: libgda-6.0 +Description: GDA (GNOME Data Access) library +Requires: gobject-2.0 gthread-2.0 libxml-2.0 +Version: 6.0.0 +Libs: -L${libdir} -lgda-6.0 +Cflags: -I${includedir}/libgda-6.0 -I${includedir}/libgda-6.0/libgda diff --git a/.flatpak-builder/cache/objects/07/54ef32bddae7cef69aca84044503dfcdc16fff27bec4bde150163d29e23c7c.dirtree b/.flatpak-builder/cache/objects/07/54ef32bddae7cef69aca84044503dfcdc16fff27bec4bde150163d29e23c7c.dirtree new file mode 100644 index 0000000..03e6451 Binary files /dev/null and b/.flatpak-builder/cache/objects/07/54ef32bddae7cef69aca84044503dfcdc16fff27bec4bde150163d29e23c7c.dirtree differ diff --git a/.flatpak-builder/cache/objects/07/c7df5dcd52520fe88b1210736c79697ef065e3af3a946725bd16d17c1f8aaa.file b/.flatpak-builder/cache/objects/07/c7df5dcd52520fe88b1210736c79697ef065e3af3a946725bd16d17c1f8aaa.file new file mode 100644 index 0000000..56addbf --- /dev/null +++ b/.flatpak-builder/cache/objects/07/c7df5dcd52520fe88b1210736c79697ef065e3af3a946725bd16d17c1f8aaa.file @@ -0,0 +1,115 @@ +/* GDA common library + * Copyright (C) 2008 The GNOME Foundation. + * + * AUTHORS: + * Johannes Schmid + * Vivien Malerba + * + * This Library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This Library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this Library; see the file COPYING.LIB. If not, + * write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GDA_CUSTOM_MARSHAL_H__ +#define __GDA_CUSTOM_MARSHAL_H__ + +#include + +G_BEGIN_DECLS + +/* VOID:GTYPE,GTYPE */ +void +_gda_marshal_VOID__GTYPE_GTYPE (GClosure *closure, + GValue *return_value G_GNUC_UNUSED, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint G_GNUC_UNUSED, + gpointer marshal_data); + +/* ERROR:OBJECT,VALUE */ +void +_gda_marshal_ERROR__OBJECT_VALUE (GClosure *closure, + GValue *return_value G_GNUC_UNUSED, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint G_GNUC_UNUSED, + gpointer marshal_data); + +/* VOID:OBJECT,STRING,VALUE */ +void +_gda_marshal_VOID__OBJECT_STRING_VALUE (GClosure *closure, + GValue *return_value G_GNUC_UNUSED, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint G_GNUC_UNUSED, + gpointer marshal_data); + +/* ERROR:VOID */ +void +_gda_marshal_ERROR__VOID (GClosure *closure, + GValue *return_value G_GNUC_UNUSED, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint G_GNUC_UNUSED, + gpointer marshal_data); + + +/* VOID:STRING,VALUE */ +void +_gda_marshal_VOID__STRING_VALUE (GClosure *closure, + GValue *return_value G_GNUC_UNUSED, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint G_GNUC_UNUSED, + gpointer marshal_data); + +/* ERROR:VALUE */ +void +_gda_marshal_ERROR__VALUE (GClosure *closure, + GValue *return_value G_GNUC_UNUSED, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint G_GNUC_UNUSED, + gpointer marshal_data); + +/* ERROR:INT,INT */ +void +_gda_marshal_ERROR__INT_INT (GClosure *closure, + GValue *return_value G_GNUC_UNUSED, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint G_GNUC_UNUSED, + gpointer marshal_data); + +/* VOID:SLIST */ +void +_gda_marshal_VOID__SLIST (GClosure *closure, + GValue *return_value G_GNUC_UNUSED, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint G_GNUC_UNUSED, + gpointer marshal_data); + +/* ERROR:GdaMetaContext */ +void +_gda_marshal_ERROR__METACONTEXT (GClosure *closure, + GValue *return_value G_GNUC_UNUSED, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint G_GNUC_UNUSED, + gpointer marshal_data); + +G_END_DECLS + +#endif diff --git a/.flatpak-builder/cache/objects/08/162db4c263445c06b7445bf079713e7833858c90d205b2a2e3fd6220345945.dirtree b/.flatpak-builder/cache/objects/08/162db4c263445c06b7445bf079713e7833858c90d205b2a2e3fd6220345945.dirtree new file mode 100644 index 0000000..f84c714 Binary files /dev/null and b/.flatpak-builder/cache/objects/08/162db4c263445c06b7445bf079713e7833858c90d205b2a2e3fd6220345945.dirtree differ diff --git a/.flatpak-builder/cache/objects/08/2d831cd2d64544f92436570ba0ae1ee240d5fc1855f2b62c6827431351b27b.dirtree b/.flatpak-builder/cache/objects/08/2d831cd2d64544f92436570ba0ae1ee240d5fc1855f2b62c6827431351b27b.dirtree new file mode 100644 index 0000000..b3aa702 Binary files /dev/null and b/.flatpak-builder/cache/objects/08/2d831cd2d64544f92436570ba0ae1ee240d5fc1855f2b62c6827431351b27b.dirtree differ diff --git a/.flatpak-builder/cache/objects/08/aad6c0c8b63d234335206902aed3fd18b52efa89d5f62fe1aa18e316d78bcc.dirtree b/.flatpak-builder/cache/objects/08/aad6c0c8b63d234335206902aed3fd18b52efa89d5f62fe1aa18e316d78bcc.dirtree new file mode 100644 index 0000000..dcc7ec4 Binary files /dev/null and b/.flatpak-builder/cache/objects/08/aad6c0c8b63d234335206902aed3fd18b52efa89d5f62fe1aa18e316d78bcc.dirtree differ diff --git a/.flatpak-builder/cache/objects/08/ad19e3101dbcada77a935dcd3cd3720089dd33091e81b5513c1d77302749e0.file b/.flatpak-builder/cache/objects/08/ad19e3101dbcada77a935dcd3cd3720089dd33091e81b5513c1d77302749e0.file new file mode 120000 index 0000000..5776e00 --- /dev/null +++ b/.flatpak-builder/cache/objects/08/ad19e3101dbcada77a935dcd3cd3720089dd33091e81b5513c1d77302749e0.file @@ -0,0 +1 @@ +../../share/runtime/locale/rw/share/rw \ No newline at end of file diff --git a/.flatpak-builder/cache/objects/08/ad865a7307ee36e5c0c115f7cf70470bc36b32a82cedb6934f1e5d38564fb7.file b/.flatpak-builder/cache/objects/08/ad865a7307ee36e5c0c115f7cf70470bc36b32a82cedb6934f1e5d38564fb7.file new file mode 100644 index 0000000..82d5f44 --- /dev/null +++ b/.flatpak-builder/cache/objects/08/ad865a7307ee36e5c0c115f7cf70470bc36b32a82cedb6934f1e5d38564fb7.file @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2009 - 2012 Vivien Malerba + * Copyright (C) 2010 Robert Ancell + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GDA_TREE_MANAGER_H__ +#define __GDA_TREE_MANAGER_H__ + +#include +#include "gda-decl.h" + +G_BEGIN_DECLS + +#define GDA_TYPE_TREE_MANAGER (gda_tree_manager_get_type()) +G_DECLARE_DERIVABLE_TYPE (GdaTreeManager, gda_tree_manager, GDA, TREE_MANAGER, GObject) + +typedef GSList *(*GdaTreeManagerNodesFunc) (GdaTreeManager *manager, GdaTreeNode *node, + const GSList *children_nodes, + gboolean *out_error, GError **error); +typedef GdaTreeNode *(*GdaTreeManagerNodeFunc) (GdaTreeManager *manager, GdaTreeNode *parent, const gchar *name); + +/* error reporting */ +extern GQuark gda_tree_manager_error_quark (void); +#define GDA_TREE_MANAGER_ERROR gda_tree_manager_error_quark () + +typedef enum { + GDA_TREE_MANAGER_UNKNOWN_ERROR +} GdaTreeManagerError; + +struct _GdaTreeManagerClass { + GObjectClass parent_class; + + /* virtual methods */ + /** + * GdaTreeManager::update_children: + * + * Returns: NULL if an error occurred, and @out_error is set to TRUE + */ + GSList *(*update_children) (GdaTreeManager *manager, GdaTreeNode *node, + const GSList *children_nodes, + gboolean *out_error, GError **error); + + /*< private >*/ + /* Padding for future expansion */ + void (*_gda_reserved1) (void); + void (*_gda_reserved2) (void); + void (*_gda_reserved3) (void); + void (*_gda_reserved4) (void); +}; + +/** + * SECTION:gda-tree-manager + * @short_description: Base class for all the tree managers + * @title: GdaTreeManager + * @stability: Stable + * @see_also: + * + * A #GdaTreeManager object is responsible for creating nodes in the tree(s) for which it + * operates. + * + * When creating nodes, a #GdaTreeManager object can (depending on its implementation), get some + * named attributes from the node below which it has to create nodes, using the gda_tree_node_fetch_attribute() + * or gda_tree_node_get_node_attribute(). For example the #GdaTreeMgrColumns manager (which creates a node for each column + * of a table) needs the table name and the schema in which the table is; both can be specified using an + * object's property, or, if not specified that way, are fetched as attributes. + * + * The #GdaTreeManager itself is an abstract type (which can't be instantiated). Use an existing sub class or subclass + * it yourself. + */ + +GdaTreeManager *gda_tree_manager_new_with_func (GdaTreeManagerNodesFunc update_func); +void gda_tree_manager_add_manager (GdaTreeManager *manager, GdaTreeManager *sub); +const GSList *gda_tree_manager_get_managers (GdaTreeManager *manager); + +void gda_tree_manager_set_node_create_func (GdaTreeManager *manager, GdaTreeManagerNodeFunc func); +GdaTreeManagerNodeFunc gda_tree_manager_get_node_create_func (GdaTreeManager *manager); + +void gda_tree_manager_add_new_node_attribute (GdaTreeManager *manager, const gchar *attribute, const GValue *value); +GdaTreeNode *gda_tree_manager_create_node (GdaTreeManager *manager, GdaTreeNode *parent, const gchar *name); + +/* private */ +void _gda_tree_manager_update_children (GdaTreeManager *manager, GdaTreeNode *node, + const GSList *children_nodes, + gboolean *out_error, GError **error); + + +G_END_DECLS + +#endif diff --git a/.flatpak-builder/cache/objects/08/e000191ccb5262adc45dfe155bbccec0aa1806936f64f85e051c00c9bb4b60.file b/.flatpak-builder/cache/objects/08/e000191ccb5262adc45dfe155bbccec0aa1806936f64f85e051c00c9bb4b60.file new file mode 100644 index 0000000..1b3c663 Binary files /dev/null and b/.flatpak-builder/cache/objects/08/e000191ccb5262adc45dfe155bbccec0aa1806936f64f85e051c00c9bb4b60.file differ diff --git a/.flatpak-builder/cache/objects/09/7c36979cf84b2467e0471e730124dd7c1d7e153a9ab5e60b9ce404d7b69bd9.file b/.flatpak-builder/cache/objects/09/7c36979cf84b2467e0471e730124dd7c1d7e153a9ab5e60b9ce404d7b69bd9.file new file mode 100644 index 0000000..099f45a --- /dev/null +++ b/.flatpak-builder/cache/objects/09/7c36979cf84b2467e0471e730124dd7c1d7e153a9ab5e60b9ce404d7b69bd9.file @@ -0,0 +1,455 @@ +/* + * Copyright (C) 2018 Daniel Espinosa + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GDA_PROVIDER_META_H__ +#define __GDA_PROVIDER_META_H__ + +#include +#include +#include + +G_BEGIN_DECLS + +typedef enum { + GDA_PROVIDER_META_NO_CONNECTION_ERROR, + GDA_PROVIDER_META_QUERY_ERROR +} GdaProviderMetaError; + +extern GQuark gda_provider_meta_error_quark (void); +#define GDA_PROVIDER_META_ERROR gda_provider_meta_error_quark () + +#define GDA_TYPE_PROVIDER_META gda_provider_meta_get_type() + +G_DECLARE_INTERFACE(GdaProviderMeta, gda_provider_meta, GDA, PROVIDER_META, GObject) + +struct _GdaProviderMetaInterface +{ + GTypeInterface g_iface; + + /* _builtin_data_types */ + GdaDataModel *(*btypes) (GdaProviderMeta *prov, GError **error); + + /* _udt */ + GdaDataModel *(*udts) (GdaProviderMeta *prov, GError **error); + GdaRow *(*udt) (GdaProviderMeta *prov, + const gchar *udt_catalog, + const gchar *udt_schema, + GError **error); + + /* _udt_columns */ + GdaDataModel *(*udt_cols) (GdaProviderMeta *prov, GError **error); + GdaRow *(*udt_col) (GdaProviderMeta *prov, + const gchar *udt_catalog, + const gchar *udt_schema, + const gchar *udt_name, + GError **error); + + /* _enums */ + GdaDataModel *(*enums_type) (GdaProviderMeta *prov, GError **error); + GdaRow *(*enum_type) (GdaProviderMeta *prov, + const gchar *udt_catalog, + const gchar *udt_schema, + const gchar *udt_name, + GError **error); + + /* _domains */ + GdaDataModel *(*domains) (GdaProviderMeta *prov, GError **error); + GdaRow *(*domain) (GdaProviderMeta *prov, + const gchar *domain_catalog, + const gchar *domain_schema, + GError **error); + + /* _domain_constraints */ + GdaDataModel *(*domains_constraints) (GdaProviderMeta *prov, GError **error); + GdaDataModel *(*domain_constraints) (GdaProviderMeta *prov, + const gchar *domain_catalog, + const gchar *domain_schema, + const gchar *domain_name, + GError **error); + GdaRow *(*domain_constraint) (GdaProviderMeta *prov, + const gchar *domain_catalog, + const gchar *domain_schema, + const gchar *domain_name, + const gchar *constraint_name, + GError **error); + + /* _element_types */ + GdaDataModel *(*element_types) (GdaProviderMeta *prov, GError **error); + GdaRow *(*element_type) (GdaProviderMeta *prov, + const gchar *specific_name, GError **error); + + /* _collations */ + GdaDataModel *(*collations) (GdaProviderMeta *prov, GError **error); + GdaRow *(*collation) (GdaProviderMeta *prov, + const gchar *collation_catalog, + const gchar *collation_schema, + const gchar *collation_name_n, + GError **error); + + /* _character_sets */ + GdaDataModel *(*character_sets) (GdaProviderMeta *prov, GError **error); + GdaRow *(*character_set) (GdaProviderMeta *prov, + const gchar *chset_catalog, const gchar *chset_schema, const gchar *chset_name_n, GError **error); + + /* _schemata */ + GdaDataModel *(*schematas) (GdaProviderMeta *prov, GError **error); + GdaRow *(*schemata) (GdaProviderMeta *prov, + const gchar *catalog_name, + const gchar *schema_name_n, + GError **error); + + /* _tables or _views */ + GdaDataModel *(*tables_columns) (GdaProviderMeta *prov, GError **error); + GdaDataModel *(*tables) (GdaProviderMeta *prov, GError **error); + GdaRow *(*table) (GdaProviderMeta *prov, + const gchar *table_catalog, + const gchar *table_schema, + const gchar *table_name_n, GError **error); + GdaDataModel *(*views) (GdaProviderMeta *prov, GError **error); + GdaRow *(*view) (GdaProviderMeta *prov, + const gchar *view_catalog, + const gchar *view_schema, + const gchar *view_name_n, GError **error); + + /* _columns */ + GdaDataModel *(*columns) (GdaProviderMeta *prov, GError **error); + GdaDataModel *(*table_columns) (GdaProviderMeta *prov, + const gchar *table_catalog, + const gchar *table_schema, + const gchar *table_name, + GError **error); + GdaRow *(*table_column) (GdaProviderMeta *prov, + const gchar *table_catalog, + const gchar *table_schema, + const gchar *table_name, + const gchar *column_name, + GError **error); + + /* _view_column_usage */ + GdaDataModel *(*views_columns) (GdaProviderMeta *prov, GError **error); + GdaDataModel *(*view_columns) (GdaProviderMeta *prov, + const gchar *view_catalog, + const gchar *view_schema, + const gchar *view_name, GError **error); + GdaRow *(*view_column) (GdaProviderMeta *prov, + const gchar *view_catalog, + const gchar *view_schema, + const gchar *view_name, + const gchar *column_name, + GError **error); + + /* _table_constraints */ + GdaDataModel *(*constraints_tables) (GdaProviderMeta *prov, GError **error); + GdaDataModel *(*constraints_table) (GdaProviderMeta *prov, + const gchar *table_catalog, + const gchar *table_schema, const gchar *table_name, + GError **error); + GdaRow *(*constraint_table) (GdaProviderMeta *prov, + const gchar *table_catalog, + const gchar *table_schema, const gchar *table_name, + const gchar *constraint_name_n, GError **error); + + /* _referential_constraints */ + GdaDataModel *(*constraints_ref) (GdaProviderMeta *prov, GError **error); + GdaDataModel *(*constraints_ref_table) (GdaProviderMeta *prov, + const gchar *table_catalog, + const gchar *table_schema, + const gchar *table_name, + GError **error); + GdaRow *(*constraint_ref) (GdaProviderMeta *prov, + const gchar *table_catalog, + const gchar *table_schema, + const gchar *table_name, + const gchar *constraint_name, + GError **error); + + /* _key_column_usage */ + GdaDataModel *(*key_columns) (GdaProviderMeta *prov, GError **error); + GdaRow *(*key_column) (GdaProviderMeta *prov, + const gchar *table_catalog, const gchar *table_schema, + const gchar *table_name, + const gchar *constraint_name, GError **error); + + /* _check_column_usage */ + GdaDataModel *(*check_columns) (GdaProviderMeta *prov, GError **error); + GdaRow *(*check_column) (GdaProviderMeta *prov, + const gchar *table_catalog, const gchar *table_schema, + const gchar *table_name, + const gchar *constraint_name, GError **error); + + /* _triggers */ + GdaDataModel *(*triggers) (GdaProviderMeta *prov, GError **error); + GdaRow *(*trigger) (GdaProviderMeta *prov, + const gchar *table_catalog, + const gchar *table_schema, + const gchar *table_name, + GError **error); + + /* _routines */ + GdaDataModel *(*routines) (GdaProviderMeta *prov, GError **error); + GdaRow *(*routine) (GdaProviderMeta *prov, + const gchar *routine_catalog, + const gchar *routine_schema, + const gchar *routine_name_n, + GError **error); + + /* _routine_columns */ + GdaDataModel *(*routines_col) (GdaProviderMeta *prov, GError **error); + GdaRow *(*routine_col) (GdaProviderMeta *prov, + const gchar *rout_catalog, + const gchar *rout_schema, + const gchar *rout_name, GError **error); + + /* _parameters */ + GdaDataModel *(*routines_pars) (GdaProviderMeta *prov, GError **error); + GdaRow *(*routine_pars) (GdaProviderMeta *prov, + const gchar *rout_catalog, + const gchar *rout_schema, + const gchar *rout_name, GError **error); + /* _table_indexes */ + GdaDataModel *(*indexes_tables) (GdaProviderMeta *prov, GError **error); + GdaDataModel *(*indexes_table) (GdaProviderMeta *prov, + const gchar *table_catalog, + const gchar *table_schema, + const gchar *table_name, GError **error); + GdaRow *(*index_table) (GdaProviderMeta *prov, + const gchar *table_catalog, + const gchar *table_schema, + const gchar *table_name, + const gchar *index_name_n, GError **error); + + /* _index_column_usage */ + GdaDataModel *(*index_cols) (GdaProviderMeta *prov, GError **error); + GdaRow *(*index_col) (GdaProviderMeta *prov, + const gchar *table_catalog, + const gchar *table_schema, + const gchar *table_name, + const gchar *index_name, GError **error); + + /* Padding for future expansion */ + gpointer padding[12]; +}; + +GdaDataModel *gda_provider_meta_execute_query (GdaProviderMeta *prov, + const gchar *sql, + GdaSet *params, + GError **error); + +GdaRow *gda_provider_meta_execute_query_row (GdaProviderMeta *prov, + const gchar *sql, + GdaSet *params, + GError **error); + +GdaConnection *gda_provider_meta_get_connection (GdaProviderMeta *prov); + +/* _builtin_data_types */ +GdaDataModel *gda_provider_meta_btypes (GdaProviderMeta *prov, + GError **error); + +/* _udt */ +GdaDataModel *gda_provider_meta_udts (GdaProviderMeta *prov, + GError **error); +GdaRow *gda_provider_meta_udt (GdaProviderMeta *prov, + const gchar *udt_catalog, const gchar *udt_schema, + GError **error); + +/* _udt_columns */ +GdaDataModel *gda_provider_meta_udt_cols (GdaProviderMeta *prov, + GError **error); +GdaRow *gda_provider_meta_udt_col (GdaProviderMeta *prov, + const gchar *udt_catalog, const gchar *udt_schema, + const gchar *udt_name, GError **error); + +/* _enums */ +GdaDataModel *gda_provider_meta_enums_type (GdaProviderMeta *prov, + GError **error); +GdaRow *gda_provider_meta_enum_type (GdaProviderMeta *prov, + const gchar *udt_catalog, const gchar *udt_schema, const gchar *udt_name, GError **error); + +/* _domains */ +GdaDataModel *gda_provider_meta_domains (GdaProviderMeta *prov, + GError **error); +GdaRow *gda_provider_meta_domain (GdaProviderMeta *prov, + const gchar *domain_catalog, const gchar *domain_schema, GError **error); + +/* _domain_constraints */ +GdaDataModel *gda_provider_meta_domains_constraints (GdaProviderMeta *prov, + GError **error); +GdaDataModel *gda_provider_meta_domain_constraints (GdaProviderMeta *prov, + const gchar *domain_catalog, const gchar *domain_schema, + const gchar *domain_name, GError **error); +GdaRow *gda_provider_meta_domain_constraint (GdaProviderMeta *prov, + const gchar *domain_catalog, const gchar *domain_schema, + const gchar *domain_name, const gchar *contraint_name, + GError **error); + +/* _element_types */ +GdaDataModel *gda_provider_meta_element_types (GdaProviderMeta *prov, + GError **error); +GdaRow *gda_provider_meta_element_type (GdaProviderMeta *prov, + const gchar *specific_name, GError **error); + +/* _collations */ +GdaDataModel *gda_provider_meta_collations (GdaProviderMeta *prov, + GError **error); +GdaRow *gda_provider_meta_collation (GdaProviderMeta *prov, + const gchar *collation_catalog, const gchar *collation_schema, + const gchar *collation_name_n, GError **error); + +/* _character_sets */ +GdaDataModel *gda_provider_meta_character_sets (GdaProviderMeta *prov, + GError **error); +GdaRow *gda_provider_meta_character_set (GdaProviderMeta *prov, + const gchar *chset_catalog, const gchar *chset_schema, + const gchar *chset_name_n, GError **error); + +/* _schemata */ +GdaDataModel *gda_provider_meta_schematas (GdaProviderMeta *prov, + GError **error); +GdaRow *gda_provider_meta_schemata (GdaProviderMeta *prov, + const gchar *catalog_name, const gchar *schema_name_n, GError **error); + +/* _tables or _views */ +GdaDataModel *gda_provider_meta_tables (GdaProviderMeta *prov, + GError **error); +GdaRow *gda_provider_meta_table (GdaProviderMeta *prov, + const gchar *table_catalog, const gchar *table_schema, + const gchar *table_name_n, GError **error); +GdaDataModel *gda_provider_meta_views (GdaProviderMeta *prov, + GError **error); +GdaRow *gda_provider_meta_view (GdaProviderMeta *prov, + const gchar *view_catalog, const gchar *view_schema, + const gchar *view_name_n, GError **error); + +/* _columns */ +GdaDataModel *gda_provider_meta_columns (GdaProviderMeta *prov, + GError **error); +GdaDataModel *gda_provider_meta_tables_columns (GdaProviderMeta *prov, + GError **error); +GdaDataModel *gda_provider_meta_table_columns (GdaProviderMeta *prov, + const gchar *table_catalog, const gchar *table_schema, + const gchar *table_name, GError **error); +GdaRow *gda_provider_meta_table_column (GdaProviderMeta *prov, + const gchar *table_catalog, const gchar *table_schema, + const gchar *table_name, + const gchar *column_name, GError **error); + +/* _view_column_usage */ +GdaDataModel *gda_provider_meta_views_columns (GdaProviderMeta *prov, + GError **error); +GdaDataModel *gda_provider_meta_view_columns (GdaProviderMeta *prov, + const gchar *view_catalog, const gchar *view_schema, + const gchar *view_name, GError **error); +GdaRow *gda_provider_meta_view_column (GdaProviderMeta *prov, + const gchar *view_catalog, const gchar *view_schema, + const gchar *view_name, + const gchar *column_name, + GError **error); + +/* _table_constraints */ +GdaDataModel *gda_provider_meta_constraints_tables (GdaProviderMeta *prov, GError **error); +GdaDataModel *gda_provider_meta_constraints_table (GdaProviderMeta *prov, + const gchar *table_catalog, const gchar *table_schema, + const gchar *table_name, + GError **error); +GdaRow *gda_provider_meta_constraint_table (GdaProviderMeta *prov, + const gchar *table_catalog, const gchar *table_schema, + const gchar *table_name, + const gchar *constraint_name_n, GError **error); + +/* _referential_constraints */ +GdaDataModel *gda_provider_meta_constraints_ref (GdaProviderMeta *prov, + GError **error); +GdaDataModel *gda_provider_meta_constraints_ref_table (GdaProviderMeta *prov, + const gchar *table_catalog, + const gchar *table_schema, const gchar *table_name, + GError **error); +GdaRow *gda_provider_meta_constraint_ref (GdaProviderMeta *prov, + const gchar *table_catalog, + const gchar *table_schema, const gchar *table_name, + const gchar *constraint_name, GError **error); + +/* _key_column_usage */ +GdaDataModel *gda_provider_meta_key_columns (GdaProviderMeta *prov, + GError **error); +GdaRow *gda_provider_meta_key_column (GdaProviderMeta *prov, + const gchar *table_catalog, const gchar *table_schema, + const gchar *table_name, + const gchar *constraint_name, GError **error); + +/* _check_column_usage */ +GdaDataModel *gda_provider_meta_check_columns (GdaProviderMeta *prov, + GError **error); +GdaRow *gda_provider_meta_check_column (GdaProviderMeta *prov, + const gchar *table_catalog, + const gchar *table_schema, + const gchar *table_name, + const gchar *constraint_name, GError **error); + +/* _triggers */ +GdaDataModel *gda_provider_meta_triggers (GdaProviderMeta *prov, + GError **error); +GdaRow *gda_provider_meta_trigger (GdaProviderMeta *prov, + const gchar *table_catalog, + const gchar *table_schema, + const gchar *table_name, GError **error); + +/* _routines */ +GdaDataModel *gda_provider_meta_routines (GdaProviderMeta *prov, + GError **error); +GdaRow *gda_provider_meta_routine (GdaProviderMeta *prov, + const gchar *routine_catalog, const gchar *routine_schema, + const gchar *routine_name_n, GError **error); + +/* _routine_columns */ +GdaDataModel *gda_provider_meta_routines_col (GdaProviderMeta *prov, GError **error); +GdaRow *gda_provider_meta_routine_col (GdaProviderMeta *prov, + const gchar *rout_catalog, const gchar *rout_schema, + const gchar *rout_name, GError **error); + +/* _parameters */ +GdaDataModel *gda_provider_meta_routines_pars (GdaProviderMeta *prov, + GError **error); +GdaRow *gda_provider_meta_routine_pars (GdaProviderMeta *prov, + const gchar *rout_catalog, const gchar *rout_schema, + const gchar *rout_name, GError **error); +/* _table_indexes */ +GdaDataModel *gda_provider_meta_indexes_tables (GdaProviderMeta *prov, + GError **error); +GdaDataModel *gda_provider_meta_indexes_table (GdaProviderMeta *prov, + const gchar *table_catalog, const gchar *table_schema, + const gchar *table_name, GError **error); +GdaRow *gda_provider_meta_index_table (GdaProviderMeta *prov, + const gchar *table_catalog, + const gchar *table_schema, + const gchar *table_name, + const gchar *index_name_n, GError **error); + +/* _index_column_usage */ +GdaDataModel *gda_provider_meta_index_cols (GdaProviderMeta *prov, + GError **error); +GdaRow *gda_provider_meta_index_col (GdaProviderMeta *prov, + const gchar *table_catalog, + const gchar *table_schema, + const gchar *table_name, + const gchar *index_name, GError **error); + +G_END_DECLS + +#endif diff --git a/.flatpak-builder/cache/objects/09/9a8bee0011c2216884c94666cb19b636ee525dc3cc0181056b5a76458543b5.file b/.flatpak-builder/cache/objects/09/9a8bee0011c2216884c94666cb19b636ee525dc3cc0181056b5a76458543b5.file new file mode 100644 index 0000000..0a5c200 --- /dev/null +++ b/.flatpak-builder/cache/objects/09/9a8bee0011c2216884c94666cb19b636ee525dc3cc0181056b5a76458543b5.file @@ -0,0 +1,2334 @@ +/* + * Copyright (C) 2008 Bas Driessen + * Copyright (C) 2008 - 2011 Murray Cumming + * Copyright (C) 2008 - 2014 Vivien Malerba + * Copyright (C) 2010 David King + * Copyright (C) 2010 Jonh Wendell + * Copyright (C) 2017-2018 Daniel Espinosa + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#undef GDA_DISABLE_DEPRECATED + +#define G_LOG_DOMAIN "GDA-statement" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Main static functions + */ +static void gda_statement_dispose (GObject *object); + +static void gda_statement_set_property (GObject *object, + guint param_id, + const GValue *value, + GParamSpec *pspec); +static void gda_statement_get_property (GObject *object, + guint param_id, + GValue *value, + GParamSpec *pspec); + +typedef struct { + GdaSqlStatement *internal_struct; + GType *requested_types; +} GdaStatementPrivate; + +G_DEFINE_TYPE_WITH_PRIVATE (GdaStatement, gda_statement, G_TYPE_OBJECT) +/* signals */ +enum +{ + RESET, + CHECKED, + LAST_SIGNAL +}; + +static gint gda_statement_signals[LAST_SIGNAL] = { 0, 0 }; + +/* properties */ +enum +{ + PROP_0, + PROP_STRUCTURE +}; + +/* module error */ +GQuark gda_statement_error_quark (void) +{ + static GQuark quark; + if (!quark) + quark = g_quark_from_static_string ("gda_statement_error"); + return quark; +} + + +static void +gda_statement_class_init (GdaStatementClass * klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + /** + * GdaStatement::reset: + * @stmt: the #GdaStatement object + * + * Gets emitted whenever the @stmt has changed + */ + gda_statement_signals[RESET] = + g_signal_new ("reset", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (GdaStatementClass, reset), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, + 0); + /** + * GdaStatement::checked: + * @stmt: the #GdaStatement object + * @cnc: a #GdaConnection + * @checked: whether @stmt have been verified + * + * Gets emitted whenever the structure and contents + * of @stmt have been verified (emitted after gda_statement_check_validity()). + */ + gda_statement_signals[CHECKED] = + g_signal_new ("checked", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (GdaStatementClass, checked), + NULL, NULL, + _gda_marshal_VOID__OBJECT_BOOLEAN, G_TYPE_NONE, + 2, GDA_TYPE_CONNECTION, G_TYPE_BOOLEAN); + + klass->reset = NULL; + klass->checked = NULL; + + object_class->dispose = gda_statement_dispose; + + /* Properties */ + object_class->set_property = gda_statement_set_property; + object_class->get_property = gda_statement_get_property; + g_object_class_install_property (object_class, PROP_STRUCTURE, + g_param_spec_boxed ("structure", NULL, NULL, GDA_TYPE_SQL_STATEMENT, + G_PARAM_WRITABLE | G_PARAM_READABLE)); +} + +static void +gda_statement_init (GdaStatement * stmt) +{ + GdaStatementPrivate *priv = gda_statement_get_instance_private (stmt); + priv->internal_struct = NULL; + priv->requested_types = NULL; +} + +/** + * gda_statement_new: + * + * Creates a new #GdaStatement object + * + * Returns: the new object + */ +GdaStatement* +gda_statement_new (void) +{ + GObject *obj; + + obj = g_object_new (GDA_TYPE_STATEMENT, NULL); + return GDA_STATEMENT (obj); +} + +GdaSqlStatement * +_gda_statement_get_internal_struct (GdaStatement *stmt) +{ + g_return_val_if_fail (GDA_IS_STATEMENT (stmt), NULL); + GdaStatementPrivate *priv = gda_statement_get_instance_private (stmt); + return priv->internal_struct; +} + +/** + * gda_statement_copy: + * @orig: a #GdaStatement to make a copy of + * + * Copy constructor + * + * Returns: (transfer full): a the new copy of @orig + */ +GdaStatement * +gda_statement_copy (GdaStatement *orig) +{ + GObject *obj; + + g_return_val_if_fail (GDA_IS_STATEMENT (orig), NULL); + GdaStatementPrivate *priv = gda_statement_get_instance_private (orig); + + obj = g_object_new (GDA_TYPE_STATEMENT, "structure", priv->internal_struct, NULL); + return GDA_STATEMENT (obj); +} + +static void +gda_statement_dispose (GObject *object) +{ + GdaStatement *stmt; + + g_return_if_fail (object != NULL); + g_return_if_fail (GDA_IS_STATEMENT (object)); + stmt = GDA_STATEMENT (object); + GdaStatementPrivate *priv = gda_statement_get_instance_private (stmt); + + if (priv->requested_types != NULL) { + g_free (priv->requested_types); + priv->requested_types = NULL; + } + if (priv->internal_struct != NULL) { + gda_sql_statement_free (priv->internal_struct); + priv->internal_struct = NULL; + } + + /* parent class */ + G_OBJECT_CLASS (gda_statement_parent_class)->dispose (object); +} + +static void +gda_statement_set_property (GObject *object, + guint param_id, + const GValue *value, + GParamSpec *pspec) +{ + GdaStatement *stmt; + + stmt = GDA_STATEMENT (object); + GdaStatementPrivate *priv = gda_statement_get_instance_private (stmt); + switch (param_id) { + case PROP_STRUCTURE: + if (priv->internal_struct) { + gda_sql_statement_free (priv->internal_struct); + priv->internal_struct = NULL; + } + if (priv->requested_types) { + g_free (priv->requested_types); + priv->requested_types = NULL; + } + priv->internal_struct = g_value_dup_boxed (value); + g_signal_emit (stmt, gda_statement_signals [RESET], 0); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + break; + } +} + +static void +gda_statement_get_property (GObject *object, + guint param_id, + GValue *value, + GParamSpec *pspec) +{ + GdaStatement *stmt; + stmt = GDA_STATEMENT (object); + GdaStatementPrivate *priv = gda_statement_get_instance_private (stmt); + + switch (param_id) { + case PROP_STRUCTURE: + g_value_set_boxed (value, priv->internal_struct); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + break; + } +} + +/** + * gda_statement_get_statement_type: + * @stmt: a #GdaStatement object + * + * Get the type of statement held by @stmt. It returns GDA_SQL_STATEMENT_NONE if + * @stmt does not hold any statement + * + * Returns: (transfer none): the statement type + */ +GdaSqlStatementType +gda_statement_get_statement_type (GdaStatement *stmt) +{ + g_return_val_if_fail (stmt != NULL, GDA_SQL_STATEMENT_NONE); + g_return_val_if_fail (GDA_IS_STATEMENT (stmt), GDA_SQL_STATEMENT_NONE); + GdaStatementPrivate *priv = gda_statement_get_instance_private (stmt); + g_return_val_if_fail (priv, GDA_SQL_STATEMENT_NONE); + + if (priv->internal_struct) + return priv->internal_struct->stmt_type; + + return GDA_SQL_STATEMENT_NONE; +} + +/** + * gda_statement_is_useless: + * @stmt: a #GdaStatement object + * + * Tells if @stmt is composed only of spaces (that is it has no real SQL code), and is completely + * useless as such. + * + * Returns: TRUE if executing @stmt does nothing + */ +gboolean +gda_statement_is_useless (GdaStatement *stmt) +{ + g_return_val_if_fail (GDA_IS_STATEMENT (stmt), FALSE); + GdaStatementPrivate *priv = gda_statement_get_instance_private (stmt); + g_return_val_if_fail (priv, FALSE); + + if (priv->internal_struct && + priv->internal_struct->stmt_type == GDA_SQL_STATEMENT_UNKNOWN) { + GSList *list; + GdaSqlStatementUnknown *unknown; + unknown = (GdaSqlStatementUnknown*) priv->internal_struct->contents; + for (list = unknown->expressions; list; list = list->next) { + GdaSqlExpr *expr = (GdaSqlExpr *) list->data; + if (expr->param_spec) + return FALSE; + if (expr->value) { + if (G_VALUE_TYPE (expr->value) == G_TYPE_STRING) { + const gchar *str; + for (str = g_value_get_string (expr->value); + (*str == ' ') || (*str == '\t') || (*str == '\n') || + (*str == '\f') || (*str == '\r'); str++); + if (*str) + return FALSE; + } + else { + TO_IMPLEMENT; + return FALSE; + } + } + } + return TRUE; + } + return FALSE; +} + +/** + * gda_statement_check_structure: + * @stmt: a #GdaStatement object + * @error: a place to store errors, or %NULL + * + * Checks that @stmt's structure is correct. + * + * Returns: TRUE if @stmt's structure is correct + */ +gboolean +gda_statement_check_structure (GdaStatement *stmt, GError **error) +{ + g_return_val_if_fail (GDA_IS_STATEMENT (stmt), FALSE); + GdaStatementPrivate *priv = gda_statement_get_instance_private (stmt); + + return gda_sql_statement_check_structure (priv->internal_struct, error); +} + +/** + * gda_statement_check_validity: + * @stmt: a #GdaStatement object + * @cnc: (nullable): a #GdaConnection object, or %NULL + * @error: a place to store errors, or %NULL + * + * If @cnc is not %NULL then checks that every object (table, field, function) used in @stmt + * actually exists in @cnc's database + * + * If @cnc is %NULL, then cleans anything related to @cnc in @stmt. + * + * See gda_sql_statement_check_validity() for more information. + * + * Returns: TRUE if every object actually exists in @cnc's database + */ +gboolean +gda_statement_check_validity (GdaStatement *stmt, GdaConnection *cnc, GError **error) +{ + gboolean retval; + g_return_val_if_fail (GDA_IS_STATEMENT (stmt), FALSE); + GdaStatementPrivate *priv = gda_statement_get_instance_private (stmt); + g_return_val_if_fail (!cnc || GDA_IS_CONNECTION (cnc), FALSE); + + retval = gda_sql_statement_check_validity (priv->internal_struct, cnc, error); + g_signal_emit (stmt, gda_statement_signals [CHECKED], 0, cnc, retval); + + return retval; +} + +/** + * gda_statement_normalize: + * @stmt: a #GdaStatement object + * @cnc: a #GdaConnection object + * @error: a place to store errors, or %NULL + * + * "Normalizes" some parts of @stmt, see gda_sql_statement_normalize() for more + * information. + * + * Returns: TRUE if no error occurred + */ +gboolean +gda_statement_normalize (GdaStatement *stmt, GdaConnection *cnc, GError **error) +{ + g_return_val_if_fail (GDA_IS_STATEMENT (stmt), FALSE); + g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE); + GdaStatementPrivate *priv = gda_statement_get_instance_private (stmt); + + return gda_sql_statement_normalize (priv->internal_struct, cnc, error); +} + +/** + * gda_statement_serialize: + * @stmt: a #GdaStatement object + * + * Creates a string representing the contents of @stmt. + * + * Returns: a string containing the serialized version of @stmt + */ +gchar * +gda_statement_serialize (GdaStatement *stmt) +{ + gchar *str; + GString *string; + g_return_val_if_fail (GDA_IS_STATEMENT (stmt), NULL); + GdaStatementPrivate *priv = gda_statement_get_instance_private (stmt); + + string = g_string_new ("{"); + g_string_append (string, "\"statement\":"); + str = gda_sql_statement_serialize (priv->internal_struct); + if (str) { + g_string_append (string, str); + g_free (str); + } + else + g_string_append (string, "null"); + g_string_append_c (string, '}'); + + str = string->str; + g_string_free (string, FALSE); + return str; +} + +static gboolean +get_params_foreach_func (GdaSqlAnyPart *node, GdaSet **params, GError **error) +{ + GdaSqlParamSpec *pspec; + if (!node) return TRUE; + + if ((node->type == GDA_SQL_ANY_EXPR) && + (pspec = ((GdaSqlExpr*) node)->param_spec)) { + GdaHolder *h; + + if (pspec->g_type == GDA_TYPE_NULL) { + g_set_error (error, GDA_STATEMENT_ERROR, GDA_STATEMENT_PARAM_TYPE_ERROR, + _("Could not determine GType for parameter '%s'"), + pspec->name ? pspec->name : _("Unnamed")); + return FALSE; + } + if (!*params) + *params = gda_set_new (NULL); + h = gda_holder_new (pspec->g_type, pspec->name); + g_object_set (G_OBJECT (h), "name", pspec->name, + "description", pspec->descr, NULL); + gda_holder_set_not_null (h, ! pspec->nullok); + if (((GdaSqlExpr*) node)->value) { + /* Expr's value is "SQL encoded" => we need to convert it to a real value */ + GValue *evalue; + evalue = ((GdaSqlExpr*) node)->value; + if (G_VALUE_TYPE (evalue) == G_TYPE_STRING) { + GdaDataHandler *dh; + GValue *value; + dh = gda_data_handler_get_default (pspec->g_type); + if (!dh) { + g_set_error (error, GDA_STATEMENT_ERROR, GDA_STATEMENT_PARAM_TYPE_ERROR, + _("Can't handle default value of type '%s'"), + gda_g_type_to_string (pspec->g_type)); + g_object_unref (h); + return FALSE; + } + value = gda_data_handler_get_value_from_sql (dh, + g_value_get_string (evalue), + pspec->g_type); + g_object_unref (dh); + + if (!value) + value = gda_value_new_default (g_value_get_string (evalue)); + gda_holder_set_default_value (h, value); + gda_value_free (value); + } + else + gda_holder_set_default_value (h, ((GdaSqlExpr*) node)->value); + gda_holder_set_value_to_default (h); + } + gda_set_add_holder (*params, h); + g_object_unref (h); + } + return TRUE; +} + +/** + * gda_statement_get_parameters: + * @stmt: a #GdaStatement object + * @out_params: (out) (nullable) (transfer full): a place to store a new #GdaSet object, or %NULL + * @error: a place to store errors, or %NULL + * + * Get a new #GdaSet object which groups all the execution parameters + * which @stmt needs. This new object is returned though @out_params. + * + * Note that if @stmt does not need any parameter, then @out_params is set to %NULL. + * + * Returns: TRUE if no error occurred. + */ +gboolean +gda_statement_get_parameters (GdaStatement *stmt, GdaSet **out_params, GError **error) +{ + GdaSet *set = NULL; + g_return_val_if_fail (GDA_IS_STATEMENT (stmt), FALSE); + GdaStatementPrivate *priv = gda_statement_get_instance_private (stmt); + + if (out_params) + *out_params = NULL; + + if (!gda_sql_any_part_foreach (GDA_SQL_ANY_PART (priv->internal_struct->contents), + (GdaSqlForeachFunc) get_params_foreach_func, &set, error)) { + if (set) { + g_object_unref (set); + set = NULL; + } + return FALSE; + } + + if (out_params) + *out_params = set; + else + g_object_unref (set); + return TRUE; +} + +/* + * _gda_statement_get_requested_types: + * @stmt: a #GdaStatement + * + * Returns: a new #GType, suitable to use with gda_connection_statement_execute_select_full(), or %NULL + */ +const GType * +_gda_statement_get_requested_types (GdaStatement *stmt) +{ + g_return_val_if_fail (GDA_IS_STATEMENT (stmt), NULL); + GdaStatementPrivate *priv = gda_statement_get_instance_private (stmt); + if (! priv->internal_struct) + return NULL; + if (priv->requested_types) + return priv->requested_types; + if (priv->internal_struct->stmt_type != GDA_SQL_STATEMENT_SELECT) + return NULL; + + GdaSqlStatementSelect *selst; + GSList *list; + GArray *array = NULL; + rewind: + selst = (GdaSqlStatementSelect*) priv->internal_struct->contents; + for (list = selst->expr_list; list; list = list->next) { + GdaSqlExpr *expr; + GType type = G_TYPE_INVALID; + expr = ((GdaSqlSelectField*) list->data)->expr; + if (expr->cast_as && *expr->cast_as) + type = gda_g_type_from_string (expr->cast_as); + if (array) { + if (type == G_TYPE_INVALID) + type = 0; + g_array_append_val (array, type); + } + else if (type != G_TYPE_INVALID) { + array = g_array_new (TRUE, FALSE, sizeof (GType)); + goto rewind; + } + } + if (array) { + GType *retval; + guint len; + len = array->len; + retval = (GType*) g_array_free (array, FALSE); + retval [len] = G_TYPE_NONE; + priv->requested_types = retval; + return retval; + } + else + return NULL; +} + + +/* + * SQL rendering + */ +static gchar *default_render_value (const GValue *value, GdaSqlRenderingContext *context, GError **error); +static gchar *default_render_param_spec (GdaSqlParamSpec *pspec, GdaSqlExpr *expr, GdaSqlRenderingContext *context, + gboolean *is_default, gboolean *is_null, GError **error); + +static gchar *default_render_unknown (GdaSqlStatementUnknown *stmt, GdaSqlRenderingContext *context, GError **error); +static gchar *default_render_select (GdaSqlStatementSelect *stmt, GdaSqlRenderingContext *context, GError **error); +static gchar *default_render_insert (GdaSqlStatementInsert *stmt, GdaSqlRenderingContext *context, GError **error); +static gchar *default_render_delete (GdaSqlStatementDelete *stmt, GdaSqlRenderingContext *context, GError **error); +static gchar *default_render_update (GdaSqlStatementUpdate *stmt, GdaSqlRenderingContext *context, GError **error); +static gchar *default_render_compound (GdaSqlStatementCompound *stmt, GdaSqlRenderingContext *context, GError **error); + +static gchar *default_render_expr (GdaSqlExpr *expr, GdaSqlRenderingContext *context, + gboolean *is_default, gboolean *is_null, GError **error); +static gchar *default_render_table (GdaSqlTable *table, GdaSqlRenderingContext *context, GError **error); +static gchar *default_render_field (GdaSqlField *field, GdaSqlRenderingContext *context, GError **error); +static gchar *default_render_function (GdaSqlFunction *func, GdaSqlRenderingContext *context, GError **error); +static gchar *default_render_operation (GdaSqlOperation *op, GdaSqlRenderingContext *context, GError **error); +static gchar *default_render_case (GdaSqlCase *case_s, GdaSqlRenderingContext *context, GError **error); +static gchar *default_render_select_field (GdaSqlSelectField *field, GdaSqlRenderingContext *context, GError **error); +static gchar *default_render_select_target (GdaSqlSelectTarget *target, GdaSqlRenderingContext *context, GError **error); +static gchar *default_render_select_join (GdaSqlSelectJoin *join, GdaSqlRenderingContext *context, GError **error); +static gchar *default_render_select_from (GdaSqlSelectFrom *from, GdaSqlRenderingContext *context, GError **error); +static gchar *default_render_select_order (GdaSqlSelectOrder *order, GdaSqlRenderingContext *context, GError **error); +static gchar *default_render_distinct (GdaSqlStatementSelect *select, GdaSqlRenderingContext *context, GError **error); + +/** + * gda_statement_to_sql_real: + * @stmt: a #GdaStatement object + * @context: a #GdaSqlRenderingContext context + * @error: a place to store errors, or %NULL + * + * Renders @stmt to its SQL representation, using @context to specify how each part of @stmt must + * be rendered. This function is mainly used by database provider's implementations which require + * to specialize some aspects of SQL rendering to be adapted to the database,'s own SQL dialect + * (for example SQLite rewrites the 'FALSE' and 'TRUE' literals as '0' and 'NOT 0'). + * + * Returns: (transfer full): a new string, or %NULL if an error occurred + */ +gchar * +gda_statement_to_sql_real (GdaStatement *stmt, GdaSqlRenderingContext *context, GError **error) +{ + GdaSqlStatementContentsInfo *cinfo; + g_return_val_if_fail (GDA_IS_STATEMENT (stmt), NULL); + GdaStatementPrivate *priv = gda_statement_get_instance_private (stmt); + + if (!context->render_value) + context->render_value = default_render_value; + if (!context->render_param_spec) + context->render_param_spec = default_render_param_spec; + if (!context->render_expr) + context->render_expr = default_render_expr; + + if (!context->render_unknown) + context->render_unknown = (GdaSqlRenderingFunc) default_render_unknown; + if (!context->render_select) + context->render_select = (GdaSqlRenderingFunc) default_render_select; + if (!context->render_insert) + context->render_insert = (GdaSqlRenderingFunc) default_render_insert; + if (!context->render_delete) + context->render_delete = (GdaSqlRenderingFunc) default_render_delete; + if (!context->render_update) + context->render_update = (GdaSqlRenderingFunc) default_render_update; + if (!context->render_compound) + context->render_compound = (GdaSqlRenderingFunc) default_render_compound; + + if (!context->render_table) + context->render_table = (GdaSqlRenderingFunc) default_render_table; + if (!context->render_field) + context->render_field = (GdaSqlRenderingFunc) default_render_field; + if (!context->render_function) + context->render_function = (GdaSqlRenderingFunc) default_render_function; + if (!context->render_operation) + context->render_operation = (GdaSqlRenderingFunc) default_render_operation; + if (!context->render_case) + context->render_case = (GdaSqlRenderingFunc) default_render_case; + if (!context->render_select_field) + context->render_select_field = (GdaSqlRenderingFunc) default_render_select_field; + if (!context->render_select_target) + context->render_select_target = (GdaSqlRenderingFunc) default_render_select_target; + if (!context->render_select_join) + context->render_select_join = (GdaSqlRenderingFunc) default_render_select_join; + if (!context->render_select_from) + context->render_select_from = (GdaSqlRenderingFunc) default_render_select_from; + if (!context->render_select_order) + context->render_select_order = (GdaSqlRenderingFunc) default_render_select_order; + if (!context->render_distinct) + context->render_distinct = (GdaSqlRenderingFunc) default_render_distinct; + + cinfo = gda_sql_statement_get_contents_infos (priv->internal_struct->stmt_type); + if (cinfo->check_structure_func && !cinfo->check_structure_func (GDA_SQL_ANY_PART (priv->internal_struct->contents), + NULL, error)) + return NULL; + + switch (GDA_SQL_ANY_PART (priv->internal_struct->contents)->type) { + case GDA_SQL_ANY_STMT_UNKNOWN: + return context->render_unknown (GDA_SQL_ANY_PART (priv->internal_struct->contents), context, error); + case GDA_SQL_ANY_STMT_BEGIN: + if (context->render_begin) + return context->render_begin (GDA_SQL_ANY_PART (priv->internal_struct->contents), context, error); + break; + case GDA_SQL_ANY_STMT_ROLLBACK: + if (context->render_rollback) + return context->render_rollback (GDA_SQL_ANY_PART (priv->internal_struct->contents), context, error); + break; + case GDA_SQL_ANY_STMT_COMMIT: + if (context->render_commit) + return context->render_commit (GDA_SQL_ANY_PART (priv->internal_struct->contents), context, error); + break; + case GDA_SQL_ANY_STMT_SAVEPOINT: + if (context->render_savepoint) + return context->render_savepoint (GDA_SQL_ANY_PART (priv->internal_struct->contents), context, error); + break; + case GDA_SQL_ANY_STMT_ROLLBACK_SAVEPOINT: + if (context->render_rollback_savepoint) + return context->render_rollback_savepoint (GDA_SQL_ANY_PART (priv->internal_struct->contents), context, error); + break; + case GDA_SQL_ANY_STMT_DELETE_SAVEPOINT: + if (context->render_delete_savepoint) + return context->render_delete_savepoint (GDA_SQL_ANY_PART (priv->internal_struct->contents), context, error); + break; + case GDA_SQL_ANY_STMT_SELECT: + return context->render_select (GDA_SQL_ANY_PART (priv->internal_struct->contents), context, error); + case GDA_SQL_ANY_STMT_INSERT: + return context->render_insert (GDA_SQL_ANY_PART (priv->internal_struct->contents), context, error); + case GDA_SQL_ANY_STMT_DELETE: + return context->render_delete (GDA_SQL_ANY_PART (priv->internal_struct->contents), context, error); + case GDA_SQL_ANY_STMT_UPDATE: + return context->render_update (GDA_SQL_ANY_PART (priv->internal_struct->contents), context, error); + case GDA_SQL_ANY_STMT_COMPOUND: + return context->render_compound (GDA_SQL_ANY_PART (priv->internal_struct->contents), context, error); + default: + TO_IMPLEMENT; + return NULL; + break; + } + + /* default action is to use priv->internal_struct->sql */ + if (priv->internal_struct->sql) + return g_strdup (priv->internal_struct->sql); + else { + g_set_error (error, GDA_SQL_ERROR, GDA_SQL_STRUCTURE_CONTENTS_ERROR, + "%s", _("Missing SQL code")); + return NULL; + } +} + +static gchar * +default_render_value (const GValue *value, GdaSqlRenderingContext *context, GError **error) +{ + if (value && !gda_value_is_null (value)) { + GdaDataHandler *dh; + if (context->provider) { + dh = gda_server_provider_get_data_handler_g_type (context->provider, context->cnc, G_VALUE_TYPE (value)); + g_object_ref (dh); // dh here is not a full transfer. + } + else + dh = gda_data_handler_get_default (G_VALUE_TYPE (value)); + + if (!dh) { + if (g_type_is_a (G_VALUE_TYPE (value), GDA_TYPE_DEFAULT)) + return g_strdup ("DEFAULT"); + else { + g_set_error (error, GDA_SQL_ERROR, GDA_SQL_STRUCTURE_CONTENTS_ERROR, + _("No data handler for type '%s'"), + g_type_name (G_VALUE_TYPE (value))); + return NULL; + } + } + if (context->flags & GDA_STATEMENT_SQL_TIMEZONE_TO_GMT) { + if (g_type_is_a (G_VALUE_TYPE (value), GDA_TYPE_TIME)) { + GdaTime *t; + GdaTime *nt; + t = g_value_get_boxed (value); + + if (t != NULL) { + nt = gda_time_to_utc (t); + GValue v = {0}; + g_value_init (&v, GDA_TYPE_TIME); + g_value_take_boxed (&v, nt); + gchar *tmp; + tmp = gda_data_handler_get_sql_from_value (dh, &v); + g_value_reset (&v); + return tmp; + } + } + else if (g_type_is_a (G_VALUE_TYPE (value), G_TYPE_DATE_TIME)) { + GDateTime *nts; + nts = (GDateTime*) g_value_get_boxed (value); + if (nts != NULL) { + nts = (GDateTime*) g_date_time_to_utc ((GDateTime*) nts); + if (nts != NULL) { + GValue v = {0}; + g_value_init (&v, G_TYPE_DATE_TIME); + g_value_set_boxed (&v, nts); + gchar *tmp; + tmp = gda_data_handler_get_sql_from_value (dh, &v); + g_value_reset (&v); + return tmp; + } + } + } + } + + gchar *res; + + res = gda_data_handler_get_sql_from_value (dh, value); + g_object_unref (dh); + + return res; + } + else + return g_strdup ("NULL"); +} + +/** + * gda_statement_to_sql_extended: + * @stmt: a #GdaStatement object + * @cnc: (nullable): a #GdaConnection object, or %NULL + * @params: (nullable): parameters contained in a single #GdaSet object, or %NULL + * @flags: a set of flags to control the rendering + * @params_used: (element-type GdaHolder) (out) (transfer container) (nullable):a place to store the list of actual #GdaHolder objects in @params used to do the rendering, or %NULL + * @error: a place to store errors, or %NULL + * + * Renders @stmt as an SQL statement, with some control on how it is rendered. + * + * If @cnc is not %NULL, then the rendered SQL will better be suited to be used by @cnc (in particular + * it may include some SQL tweaks and/or proprietary extensions specific to the database engine used by @cnc): + * in this case the result is similar to calling gda_connection_statement_to_sql(). + * + * Returns: (transfer full): a new string if no error occurred + */ +gchar * +gda_statement_to_sql_extended (GdaStatement *stmt, GdaConnection *cnc, GdaSet *params, + GdaStatementSqlFlag flags, + GSList **params_used, GError **error) +{ + gchar *str; + GdaSqlRenderingContext context; + + g_return_val_if_fail (GDA_IS_STATEMENT (stmt), NULL); + + memset (&context, 0, sizeof (context)); + context.params = params; + context.flags = flags; + if (cnc) { + if (gda_connection_is_opened (cnc)) + return _gda_server_provider_statement_to_sql (gda_connection_get_provider (cnc), cnc, + stmt, params, flags, + params_used, error); + else + context.provider = gda_connection_get_provider (cnc); + } + + str = gda_statement_to_sql_real (stmt, &context, error); + + if (str) { + if (params_used) + *params_used = context.params_used; + else + g_slist_free (context.params_used); + } + else { + if (params_used) + *params_used = NULL; + g_slist_free (context.params_used); + } + return str; +} + +static gchar * +default_render_unknown (GdaSqlStatementUnknown *stmt, GdaSqlRenderingContext *context, GError **error) +{ + GString *string; + gchar *str; + GSList *list; + + g_return_val_if_fail (stmt, NULL); + g_return_val_if_fail (GDA_SQL_ANY_PART (stmt)->type == GDA_SQL_ANY_STMT_UNKNOWN, NULL); + + string = g_string_new (""); + for (list = stmt->expressions; list; list = list->next) { + str = context->render_expr ((GdaSqlExpr*) list->data, context, NULL, NULL, error); + if (!str) goto err; + g_string_append (string, str); + g_free (str); + } + + str = string->str; + g_string_free (string, FALSE); + return str; + + err: + g_string_free (string, TRUE); + return NULL; +} + +static gchar * +default_render_insert (GdaSqlStatementInsert *stmt, GdaSqlRenderingContext *context, GError **error) +{ + GString *string; + gchar *str; + GSList *list; + gboolean pretty = context->flags & GDA_STATEMENT_SQL_PRETTY; + + g_return_val_if_fail (stmt, NULL); + g_return_val_if_fail (GDA_SQL_ANY_PART (stmt)->type == GDA_SQL_ANY_STMT_INSERT, NULL); + + string = g_string_new ("INSERT "); + + /* conflict algo */ + if (stmt->on_conflict) + g_string_append_printf (string, "OR %s ", stmt->on_conflict); + + /* INTO */ + g_string_append (string, "INTO "); + str = context->render_table (GDA_SQL_ANY_PART (stmt->table), context, error); + if (!str) goto err; + g_string_append (string, str); + g_free (str); + + /* fields list */ + for (list = stmt->fields_list; list; list = list->next) { + if (list == stmt->fields_list) + g_string_append (string, " ("); + else + g_string_append (string, ", "); + str = context->render_field (GDA_SQL_ANY_PART (list->data), context, error); + if (!str) goto err; + g_string_append (string, str); + g_free (str); + } + if (stmt->fields_list) + g_string_append_c (string, ')'); + + /* values */ + if (stmt->select) { + if (pretty) + g_string_append_c (string, '\n'); + else + g_string_append_c (string, ' '); + str = context->render_select (GDA_SQL_ANY_PART (stmt->select), context, error); + if (!str) goto err; + g_string_append (string, str); + g_free (str); + } + else { + for (list = stmt->values_list; list; list = list->next) { + GSList *rlist; + if (list == stmt->values_list) { + if (pretty) + g_string_append (string, "\nVALUES"); + else + g_string_append (string, " VALUES"); + } + else + g_string_append_c (string, ','); + for (rlist = (GSList*) list->data; rlist; rlist = rlist->next) { + if (rlist == (GSList*) list->data) + g_string_append (string, " ("); + else + g_string_append (string, ", "); + str = context->render_expr ((GdaSqlExpr*) rlist->data, context, NULL, NULL, error); + if (!str) goto err; + if (pretty && (rlist != (GSList*) list->data)) + g_string_append (string, "\n\t"); + g_string_append (string, str); + g_free (str); + } + g_string_append_c (string, ')'); + } + + if (!stmt->fields_list && !stmt->values_list) + g_string_append (string, " DEFAULT VALUES"); + } + + str = string->str; + g_string_free (string, FALSE); + return str; + + err: + g_string_free (string, TRUE); + return NULL; +} + +static gchar * +default_render_delete (GdaSqlStatementDelete *stmt, GdaSqlRenderingContext *context, GError **error) +{ + GString *string; + gchar *str; + + g_return_val_if_fail (stmt, NULL); + g_return_val_if_fail (GDA_SQL_ANY_PART (stmt)->type == GDA_SQL_ANY_STMT_DELETE, NULL); + + string = g_string_new ("DELETE FROM "); + + /* FROM */ + str = context->render_table (GDA_SQL_ANY_PART (stmt->table), context, error); + if (!str) goto err; + g_string_append (string, str); + g_free (str); + + /* cond */ + if (stmt->cond) { + g_string_append (string, " WHERE "); + str = context->render_expr (stmt->cond, context, NULL, NULL, error); + if (!str) goto err; + g_string_append (string, str); + g_free (str); + } + + str = string->str; + g_string_free (string, FALSE); + return str; + + err: + g_string_free (string, TRUE); + return NULL; +} + +static gchar * +default_render_update (GdaSqlStatementUpdate *stmt, GdaSqlRenderingContext *context, GError **error) +{ + GString *string; + gchar *str; + GSList *flist, *elist; + gboolean pretty = context->flags & GDA_STATEMENT_SQL_PRETTY; + + g_return_val_if_fail (stmt, NULL); + g_return_val_if_fail (GDA_SQL_ANY_PART (stmt)->type == GDA_SQL_ANY_STMT_UPDATE, NULL); + + string = g_string_new ("UPDATE "); + /* conflict algo */ + if (stmt->on_conflict) + g_string_append_printf (string, "OR %s ", stmt->on_conflict); + + /* table */ + str = context->render_table (GDA_SQL_ANY_PART (stmt->table), context, error); + if (!str) goto err; + g_string_append (string, str); + g_free (str); + + /* columns set */ + if (pretty) + g_string_append (string, "\nSET "); + else + g_string_append (string, " SET "); + for (flist = stmt->fields_list, elist = stmt->expr_list; + flist && elist; + flist = flist->next, elist = elist->next) { + if (flist != stmt->fields_list) { + g_string_append (string, ", "); + if (pretty) + g_string_append (string, "\n\t"); + } + str = context->render_field (GDA_SQL_ANY_PART (flist->data), context, error); + if (!str) goto err; + g_string_append (string, str); + g_free (str); + g_string_append_c (string, '='); + str = context->render_expr ((GdaSqlExpr *) elist->data, context, NULL, NULL, error); + if (!str) goto err; + g_string_append (string, str); + g_free (str); + } + + /* cond */ + if (stmt->cond) { + if (pretty) + g_string_append (string, "\nWHERE "); + else + g_string_append (string, " WHERE "); + str = context->render_expr (stmt->cond, context, NULL, NULL, error); + if (!str) goto err; + g_string_append (string, str); + g_free (str); + } + + str = string->str; + g_string_free (string, FALSE); + return str; + + err: + g_string_free (string, TRUE); + return NULL; +} + +static gchar * +default_render_compound (GdaSqlStatementCompound *stmt, GdaSqlRenderingContext *context, GError **error) +{ + GString *string; + gchar *str; + GSList *list; + + g_return_val_if_fail (stmt, NULL); + g_return_val_if_fail (GDA_SQL_ANY_PART (stmt)->type == GDA_SQL_ANY_STMT_COMPOUND, NULL); + + string = g_string_new (""); + + for (list = stmt->stmt_list; list; list = list->next) { + GdaSqlStatement *sqlstmt = (GdaSqlStatement*) list->data; + if (list != stmt->stmt_list) { + switch (stmt->compound_type) { + case GDA_SQL_STATEMENT_COMPOUND_UNION: + g_string_append (string, " UNION "); + break; + case GDA_SQL_STATEMENT_COMPOUND_UNION_ALL: + g_string_append (string, " UNION ALL "); + break; + case GDA_SQL_STATEMENT_COMPOUND_INTERSECT: + g_string_append (string, " INTERSECT "); + break; + case GDA_SQL_STATEMENT_COMPOUND_INTERSECT_ALL: + g_string_append (string, " INTERSECT ALL "); + break; + case GDA_SQL_STATEMENT_COMPOUND_EXCEPT: + g_string_append (string, " EXCEPT "); + break; + case GDA_SQL_STATEMENT_COMPOUND_EXCEPT_ALL: + g_string_append (string, " EXCEPT ALL "); + break; + default: + g_assert_not_reached (); + } + } + switch (sqlstmt->stmt_type) { + case GDA_SQL_ANY_STMT_SELECT: + str = context->render_select (GDA_SQL_ANY_PART (sqlstmt->contents), context, error); + if (!str) goto err; + g_string_append_c (string, '('); + g_string_append (string, str); + g_string_append_c (string, ')'); + g_free (str); + break; + case GDA_SQL_ANY_STMT_COMPOUND: + str = context->render_compound (GDA_SQL_ANY_PART (sqlstmt->contents), context, error); + if (!str) goto err; + g_string_append_c (string, '('); + g_string_append (string, str); + g_string_append_c (string, ')'); + g_free (str); + break; + default: + g_assert_not_reached (); + } + } + + str = string->str; + g_string_free (string, FALSE); + return str; + + err: + g_string_free (string, TRUE); + return NULL; +} + +static gchar * +default_render_distinct (GdaSqlStatementSelect *stmt, GdaSqlRenderingContext *context, GError **error) +{ + gboolean pretty = context->flags & GDA_STATEMENT_SQL_PRETTY; + g_return_val_if_fail (stmt, NULL); + g_return_val_if_fail (GDA_SQL_ANY_PART (stmt)->type == GDA_SQL_ANY_STMT_SELECT, NULL); + + if (stmt->distinct) { + GString *string; + string = g_string_new ("DISTINCT"); + if (stmt->distinct_expr) { + gchar *str; + str = context->render_expr (stmt->distinct_expr, context, NULL, NULL, error); + if (!str) { + g_string_free (string, TRUE); + return NULL; + } + g_string_append (string, " ON ("); + g_string_append (string, str); + g_string_append (string, ") "); + g_free (str); + } + if (pretty) + g_string_append_c (string, '\n'); + return g_string_free (string, FALSE); + } + else + return NULL; +} + +static gchar * +default_render_select (GdaSqlStatementSelect *stmt, GdaSqlRenderingContext *context, GError **error) +{ + GString *string; + gchar *str; + GSList *list; + gboolean pretty = context->flags & GDA_STATEMENT_SQL_PRETTY; + + g_return_val_if_fail (stmt, NULL); + g_return_val_if_fail (GDA_SQL_ANY_PART (stmt)->type == GDA_SQL_ANY_STMT_SELECT, NULL); + + string = g_string_new ("SELECT "); + /* distinct */ + if (stmt->distinct) { + str = context->render_distinct (GDA_SQL_ANY_PART (stmt), context, error); + if (!str) goto err; + g_string_append (string, str); + g_string_append_c (string, ' '); + g_free (str); + } + + /* selected expressions */ + for (list = stmt->expr_list; list; list = list->next) { + str = context->render_select_field (GDA_SQL_ANY_PART (list->data), context, error); + if (!str) goto err; + if (list != stmt->expr_list) + g_string_append (string, ", "); + if (pretty) + g_string_append (string, "\n\t"); + g_string_append (string, str); + g_free (str); + } + + /* FROM */ + if (stmt->from) { + str = context->render_select_from (GDA_SQL_ANY_PART (stmt->from), context, error); + if (!str) goto err; + if (pretty) + g_string_append_c (string, '\n'); + else + g_string_append_c (string, ' '); + g_string_append (string, str); + g_free (str); + } + + /* WHERE */ + if (stmt->where_cond) { + if (pretty) + g_string_append (string, "\nWHERE "); + else + g_string_append (string, " WHERE "); + str = context->render_expr (stmt->where_cond, context, NULL, NULL, error); + if (!str) goto err; + g_string_append (string, str); + g_free (str); + } + + /* GROUP BY */ + for (list = stmt->group_by; list; list = list->next) { + str = context->render_expr (list->data, context, NULL, NULL, error); + if (!str) goto err; + if (list != stmt->group_by) + g_string_append (string, ", "); + else { + if (pretty) + g_string_append (string, "\nGROUP BY "); + else + g_string_append (string, " GROUP BY "); + } + g_string_append (string, str); + g_free (str); + } + + /* HAVING */ + if (stmt->having_cond) { + if (pretty) + g_string_append (string, "\nHAVING "); + else + g_string_append (string, " HAVING "); + str = context->render_expr (stmt->having_cond, context, NULL, NULL, error); + if (!str) goto err; + g_string_append (string, str); + g_free (str); + } + + /* ORDER BY */ + for (list = stmt->order_by; list; list = list->next) { + str = context->render_select_order (GDA_SQL_ANY_PART (list->data), context, error); + if (!str) goto err; + if (list != stmt->order_by) + g_string_append (string, ", "); + else { + if (pretty) + g_string_append (string, "\nORDER BY "); + else + g_string_append (string, " ORDER BY "); + } + g_string_append (string, str); + g_free (str); + } + + /* LIMIT */ + if (stmt->limit_count) { + g_string_append (string, " LIMIT "); + str = context->render_expr (stmt->limit_count, context, NULL, NULL, error); + if (!str) goto err; + g_string_append (string, str); + g_free (str); + if (stmt->limit_offset) { + g_string_append (string, " OFFSET "); + str = context->render_expr (stmt->limit_offset, context, NULL, NULL, error); + if (!str) goto err; + g_string_append (string, str); + g_free (str); + } + } + + str = string->str; + g_string_free (string, FALSE); + return str; + + err: + g_string_free (string, TRUE); + return NULL; +} + +/* + * Randers @pspec, and the default value stored in @expr->value if it exists + */ +static gchar * +default_render_param_spec (GdaSqlParamSpec *pspec, GdaSqlExpr *expr, GdaSqlRenderingContext *context, + gboolean *is_default, gboolean *is_null, GError **error) +{ + GString *string; + gchar *str; + GdaHolder *h = NULL; + gboolean render_pspec; /* if TRUE, then don't render parameter as its value but as a param specification */ + + g_return_val_if_fail (pspec, NULL); + + render_pspec = FALSE; + if (context->flags & (GDA_STATEMENT_SQL_PARAMS_LONG | + GDA_STATEMENT_SQL_PARAMS_SHORT | + GDA_STATEMENT_SQL_PARAMS_AS_COLON | + GDA_STATEMENT_SQL_PARAMS_AS_DOLLAR | + GDA_STATEMENT_SQL_PARAMS_AS_QMARK | + GDA_STATEMENT_SQL_PARAMS_AS_UQMARK)) + render_pspec = TRUE; + + if (is_default) + *is_default = FALSE; + if (is_null) + *is_null = FALSE; + + string = g_string_new (""); + + /* try to use a GdaHolder in context->params */ + if (context->params) { + h = gda_set_get_holder (context->params, pspec->name); + if (h && (gda_holder_get_g_type (h) != pspec->g_type)) { + g_set_error (error, GDA_STATEMENT_ERROR, GDA_STATEMENT_PARAM_ERROR, + _("Wrong parameter type for '%s': expected type '%s' and got '%s'"), + pspec->name, g_type_name (pspec->g_type), g_type_name (gda_holder_get_g_type (h))); + goto err; + } + } + if (!h && + (!render_pspec || + (context->flags & (GDA_STATEMENT_SQL_PARAMS_AS_DOLLAR | + GDA_STATEMENT_SQL_PARAMS_AS_QMARK | + GDA_STATEMENT_SQL_PARAMS_AS_UQMARK)))) { + /* a real value is needed or @context->params_used needs to be correct, and no GdaHolder found */ + g_set_error (error, GDA_STATEMENT_ERROR, GDA_STATEMENT_PARAM_ERROR, + _("Missing parameter '%s'"), pspec->name); + goto err; + } + if (h) { + /* keep track of the params used */ + context->params_used = g_slist_append (context->params_used, h); + + if (! render_pspec) { + const GValue *cvalue; + + if (!gda_holder_is_valid (h)) { + g_set_error (error, GDA_STATEMENT_ERROR, GDA_STATEMENT_PARAM_ERROR, + _("Parameter '%s' is invalid"), pspec->name); + goto err; + } + cvalue = gda_holder_get_value (h); + if (cvalue) { + str = context->render_value ((GValue*) cvalue, context, error); + if (!str) goto err; + g_string_append (string, str); + g_free (str); + if (is_null && gda_value_is_null (cvalue)) + *is_null = TRUE; + } + else { + /* @h is set to a default value */ + g_string_append (string, "DEFAULT"); + if (is_default) + *is_default = TRUE; + } + goto out; + } + } + + /* no parameter found in context->params => insert an SQL parameter */ + if (context->flags & GDA_STATEMENT_SQL_PARAMS_AS_COLON) { + gchar *str; + + str = gda_text_to_alphanum (pspec->name); + g_string_append_printf (string, ":%s", str); + g_free (str); + } + else if (context->flags & (GDA_STATEMENT_SQL_PARAMS_AS_DOLLAR | + GDA_STATEMENT_SQL_PARAMS_AS_QMARK | + GDA_STATEMENT_SQL_PARAMS_AS_UQMARK)) { + if (context->flags & GDA_STATEMENT_SQL_PARAMS_AS_DOLLAR) + g_string_append_printf (string, "$%d", g_slist_length (context->params_used)); + else if (context->flags & GDA_STATEMENT_SQL_PARAMS_AS_QMARK) + g_string_append_printf (string, "?%d", g_slist_length (context->params_used)); + else + g_string_append_c (string, '?'); + } + else { + GdaStatementSqlFlag flag = context->flags; + gchar *quoted_pname; + + if (! pspec->name) { + g_set_error (error, GDA_STATEMENT_ERROR, GDA_STATEMENT_PARAM_ERROR, + "%s", _("Unnamed parameter")); + goto err; + } + quoted_pname = gda_sql_identifier_force_quotes (pspec->name); + + if (! (flag & (GDA_STATEMENT_SQL_PARAMS_LONG | GDA_STATEMENT_SQL_PARAMS_SHORT))) { + if (!expr->value || gda_value_is_null (expr->value) || strcmp (quoted_pname, pspec->name)) + flag = GDA_STATEMENT_SQL_PARAMS_LONG; + else + flag = GDA_STATEMENT_SQL_PARAMS_SHORT; + } + + if (flag & GDA_STATEMENT_SQL_PARAMS_LONG) { + if (expr->value) { + if (G_VALUE_TYPE (expr->value) == G_TYPE_STRING) + str = g_value_dup_string (expr->value); + else + str = context->render_value (expr->value, context, error); + if (!str) { + g_free (quoted_pname); + goto err; + } + g_string_append (string, str); + g_free (str); + } + else + g_string_append (string, "##"); + + g_string_append (string, " /* "); + g_string_append_printf (string, "name:%s", quoted_pname); + if (pspec->g_type) { + str = gda_sql_identifier_force_quotes (gda_g_type_to_string (pspec->g_type)); + g_string_append_printf (string, " type:%s", str); + g_free (str); + } + if (pspec->descr) { + str = gda_sql_identifier_force_quotes (pspec->descr); + g_string_append_printf (string, " descr:%s", str); + g_free (str); + } + if (pspec->nullok) + g_string_append (string, " nullok:true"); + + g_string_append (string, " */"); + } + else { + g_string_append (string, "##"); + g_string_append (string, pspec->name); + if (pspec->g_type != GDA_TYPE_NULL) { + g_string_append (string, "::"); + g_string_append (string, gda_g_type_to_string (pspec->g_type)); + if (pspec->nullok) + g_string_append (string, "::NULL"); + } + } + + g_free (quoted_pname); + } + + out: + str = string->str; + g_string_free (string, FALSE); + return str; + + err: + g_string_free (string, TRUE); + return NULL; +} + +static gchar * +default_render_expr (GdaSqlExpr *expr, GdaSqlRenderingContext *context, gboolean *is_default, + gboolean *is_null, GError **error) +{ + GString *string; + gchar *str = NULL; + + g_return_val_if_fail (expr, NULL); + g_return_val_if_fail (GDA_SQL_ANY_PART (expr)->type == GDA_SQL_ANY_EXPR, NULL); + + if (is_default) + *is_default = FALSE; + if (is_null) + *is_null = FALSE; + + /* can't have: + * - expr->cast_as && expr->param_spec + */ + if (!gda_sql_any_part_check_structure (GDA_SQL_ANY_PART (expr), error)) return NULL; + + string = g_string_new (""); + if (expr->param_spec) { + str = context->render_param_spec (expr->param_spec, expr, context, is_default, is_null, error); + if (!str) goto err; + } + else if (expr->value) { + if (G_VALUE_TYPE (expr->value) == G_TYPE_STRING) { + /* specific treatment for strings, see documentation about GdaSqlExpr's value attribute */ + const gchar *vstr; + vstr = g_value_get_string (expr->value); + if (vstr) { + if (expr->value_is_ident) { + gchar **ids_array; + gint i; + GString *string = NULL; + GdaConnectionOptions cncoptions = 0; + if (context->cnc) + g_object_get (G_OBJECT (context->cnc), "options", &cncoptions, NULL); + ids_array = gda_sql_identifier_split (vstr); + if (!ids_array) + str = g_strdup (vstr); + else if (!(ids_array[0])) goto err; + else { + for (i = 0; ids_array[i]; i++) { + gchar *tmp; + if (!string) + string = g_string_new (""); + else + g_string_append_c (string, '.'); + tmp = gda_sql_identifier_quote (ids_array[i], context->cnc, + context->provider, FALSE, + cncoptions & GDA_CONNECTION_OPTIONS_SQL_IDENTIFIERS_CASE_SENSITIVE); + g_string_append (string, tmp); + g_free (tmp); + } + g_strfreev (ids_array); + str = g_string_free (string, FALSE); + } + } + else { + /* we don't have an identifier */ + if (!g_ascii_strcasecmp (vstr, "default")) { + if (is_default) + *is_default = TRUE; + str = g_strdup ("DEFAULT"); + } + else + str = g_strdup (vstr); + } + } + else { + str = g_strdup ("NULL"); + if (is_null) + *is_null = TRUE; + } + } + if (!str) { + /* use a GdaDataHandler to render the value as valid SQL */ + GdaDataHandler *dh; + if (context->cnc) { + GdaServerProvider *prov; + prov = gda_connection_get_provider (context->cnc); + dh = gda_server_provider_get_data_handler_g_type (prov, context->cnc, + G_VALUE_TYPE (expr->value)); + if (!dh) + goto err; + else + g_object_ref (dh); // We need this, since dh is not a full transfer + } + else + dh = gda_data_handler_get_default (G_VALUE_TYPE (expr->value)); + + if (dh) { + str = gda_data_handler_get_sql_from_value (dh, expr->value); + g_object_unref (dh); + } + else + str = gda_value_stringify (expr->value); + if (!str) goto err; + } + } + else if (expr->func) { + str = context->render_function (GDA_SQL_ANY_PART (expr->func), context, error); + if (!str) goto err; + } + else if (expr->cond) { + gchar *tmp; + tmp = context->render_operation (GDA_SQL_ANY_PART (expr->cond), context, error); + if (!tmp) goto err; + str = NULL; + if (GDA_SQL_ANY_PART (expr)->parent) { + if (GDA_SQL_ANY_PART (expr)->parent->type == GDA_SQL_ANY_STMT_SELECT) { + GdaSqlStatementSelect *selst; + selst = (GdaSqlStatementSelect*) (GDA_SQL_ANY_PART (expr)->parent); + if ((expr == selst->where_cond) || + (expr == selst->having_cond)) + str = tmp; + } + else if (GDA_SQL_ANY_PART (expr)->parent->type == GDA_SQL_ANY_STMT_DELETE) { + GdaSqlStatementDelete *delst; + delst = (GdaSqlStatementDelete*) (GDA_SQL_ANY_PART (expr)->parent); + if (expr == delst->cond) + str = tmp; + } + else if (GDA_SQL_ANY_PART (expr)->parent->type == GDA_SQL_ANY_STMT_UPDATE) { + GdaSqlStatementUpdate *updst; + updst = (GdaSqlStatementUpdate*) (GDA_SQL_ANY_PART (expr)->parent); + if (expr == updst->cond) + str = tmp; + } + } + + if (!str) { + str = g_strconcat ("(", tmp, ")", NULL); + g_free (tmp); + } + } + else if (expr->select) { + gchar *str1; + if (GDA_SQL_ANY_PART (expr->select)->type == GDA_SQL_ANY_STMT_SELECT) + str1 = context->render_select (GDA_SQL_ANY_PART (expr->select), context, error); + else if (GDA_SQL_ANY_PART (expr->select)->type == GDA_SQL_ANY_STMT_COMPOUND) + str1 = context->render_compound (GDA_SQL_ANY_PART (expr->select), context, error); + else + g_assert_not_reached (); + if (!str1) goto err; + + if (! GDA_SQL_ANY_PART (expr)->parent || + (GDA_SQL_ANY_PART (expr)->parent->type != GDA_SQL_ANY_SQL_FUNCTION)) { + str = g_strconcat ("(", str1, ")", NULL); + g_free (str1); + } + else + str = str1; + } + else if (expr->case_s) { + str = context->render_case (GDA_SQL_ANY_PART (expr->case_s), context, error); + if (!str) goto err; + } + else { + if (is_null) + *is_null = TRUE; + str = g_strdup ("NULL"); + } + + if (!str) goto err; + + if (expr->cast_as) + g_string_append_printf (string, "CAST (%s AS %s)", str, expr->cast_as); + else + g_string_append (string, str); + g_free (str); + + str = string->str; + g_string_free (string, FALSE); + return str; + + err: + g_string_free (string, TRUE); + return NULL; +} + +static gchar * +default_render_field (GdaSqlField *field, GdaSqlRenderingContext *context, GError **error) +{ + g_return_val_if_fail (field, NULL); + g_return_val_if_fail (GDA_SQL_ANY_PART (field)->type == GDA_SQL_ANY_SQL_FIELD, NULL); + + /* can't have: field->field_name not a valid SQL identifier */ + if (!gda_sql_any_part_check_structure (GDA_SQL_ANY_PART (field), error)) return NULL; + + GdaConnectionOptions cncoptions = 0; + if (context->cnc) + g_object_get (G_OBJECT (context->cnc), "options", &cncoptions, NULL); + return gda_sql_identifier_quote (field->field_name, context->cnc, context->provider, + FALSE, + cncoptions & GDA_CONNECTION_OPTIONS_SQL_IDENTIFIERS_CASE_SENSITIVE); +} + +static gchar * +default_render_table (GdaSqlTable *table, GdaSqlRenderingContext *context, GError **error) +{ + g_return_val_if_fail (table, NULL); + g_return_val_if_fail (GDA_SQL_ANY_PART (table)->type == GDA_SQL_ANY_SQL_TABLE, NULL); + + /* can't have: table->table_name not a valid SQL identifier */ + if (!gda_sql_any_part_check_structure (GDA_SQL_ANY_PART (table), error)) return NULL; + + gchar **ids_array; + ids_array = gda_sql_identifier_split (table->table_name); + if (!ids_array) { + g_set_error (error, GDA_SQL_ERROR, GDA_SQL_STRUCTURE_CONTENTS_ERROR, + "%s", _("Malformed table name")); + return NULL; + } + + gint i; + GString *string; + GdaConnectionOptions cncoptions = 0; + if (context->cnc) + g_object_get (G_OBJECT (context->cnc), "options", &cncoptions, NULL); + string = g_string_new (""); + for (i = 0; ids_array [i]; i++) { + gchar *tmp; + tmp = gda_sql_identifier_quote (ids_array [i], context->cnc, context->provider, + FALSE, + cncoptions & GDA_CONNECTION_OPTIONS_SQL_IDENTIFIERS_CASE_SENSITIVE); + g_free (ids_array [i]); + ids_array [i] = tmp; + if (i != 0) + g_string_append_c (string, '.'); + g_string_append (string, ids_array [i]); + } + g_strfreev (ids_array); + return g_string_free (string, FALSE); +} + +static gchar * +default_render_function (GdaSqlFunction *func, GdaSqlRenderingContext *context, GError **error) +{ + GString *string; + gchar *str; + GSList *list; + + g_return_val_if_fail (func, NULL); + g_return_val_if_fail (GDA_SQL_ANY_PART (func)->type == GDA_SQL_ANY_SQL_FUNCTION, NULL); + + /* can't have: func->function_name == NULL */ + if (!gda_sql_any_part_check_structure (GDA_SQL_ANY_PART (func), error)) return NULL; + + string = g_string_new (func->function_name); + g_string_append (string, " ("); + for (list = func->args_list; list; list = list->next) { + if (list != func->args_list) + g_string_append (string, ", "); + str = context->render_expr (list->data, context, NULL, NULL, error); + if (!str) goto err; + if (((GdaSqlExpr*) list->data)->select) + g_string_append_c (string, '('); + g_string_append (string, str); + if (((GdaSqlExpr*) list->data)->select) + g_string_append_c (string, ')'); + g_free (str); + } + g_string_append_c (string, ')'); + + str = string->str; + g_string_free (string, FALSE); + return str; + + err: + g_string_free (string, TRUE); + return NULL; +} + +static gchar * +default_render_operation (GdaSqlOperation *op, GdaSqlRenderingContext *context, GError **error) +{ + gchar *str; + GSList *list; + GSList *sql_list; /* list of SqlOperand */ + GString *string; + gchar *multi_op = NULL; + + typedef struct { + gchar *sql; + gboolean is_null; + gboolean is_default; + gboolean is_composed; + } SqlOperand; +#define SQL_OPERAND(x) ((SqlOperand*)(x)) + + g_return_val_if_fail (op, NULL); + g_return_val_if_fail (GDA_SQL_ANY_PART (op)->type == GDA_SQL_ANY_SQL_OPERATION, NULL); + + /* can't have: + * - op->operands == NULL + * - incorrect number of operands + */ + if (!gda_sql_any_part_check_structure (GDA_SQL_ANY_PART (op), error)) return NULL; + + /* render operands */ + for (list = op->operands, sql_list = NULL; list; list = list->next) { + SqlOperand *sqlop = g_new0 (SqlOperand, 1); + GdaSqlExpr *expr = (GdaSqlExpr*) list->data; + str = context->render_expr (expr, context, &(sqlop->is_default), &(sqlop->is_null), error); + if (!str) { + g_free (sqlop); + goto out; + } + sqlop->sql = str; + if (expr->case_s || expr->select) + sqlop->is_composed = TRUE; + sql_list = g_slist_prepend (sql_list, sqlop); + } + sql_list = g_slist_reverse (sql_list); + + str = NULL; + switch (op->operator_type) { + case GDA_SQL_OPERATOR_TYPE_EQ: + if (SQL_OPERAND (sql_list->next->data)->is_null) + str = g_strdup_printf ("%s IS NULL", SQL_OPERAND (sql_list->data)->sql); + else + str = g_strdup_printf ("%s = %s", SQL_OPERAND (sql_list->data)->sql, SQL_OPERAND (sql_list->next->data)->sql); + break; + case GDA_SQL_OPERATOR_TYPE_IS: + str = g_strdup_printf ("%s IS %s", SQL_OPERAND (sql_list->data)->sql, SQL_OPERAND (sql_list->next->data)->sql); + break; + case GDA_SQL_OPERATOR_TYPE_LIKE: + str = g_strdup_printf ("%s LIKE %s", SQL_OPERAND (sql_list->data)->sql, SQL_OPERAND (sql_list->next->data)->sql); + break; + case GDA_SQL_OPERATOR_TYPE_NOTLIKE: + str = g_strdup_printf ("%s NOT LIKE %s", SQL_OPERAND (sql_list->data)->sql, SQL_OPERAND (sql_list->next->data)->sql); + break; + case GDA_SQL_OPERATOR_TYPE_ILIKE: + str = g_strdup_printf ("%s ILIKE %s", SQL_OPERAND (sql_list->data)->sql, SQL_OPERAND (sql_list->next->data)->sql); + break; + case GDA_SQL_OPERATOR_TYPE_NOTILIKE: + str = g_strdup_printf ("%s NOT ILIKE %s", SQL_OPERAND (sql_list->data)->sql, SQL_OPERAND (sql_list->next->data)->sql); + break; + case GDA_SQL_OPERATOR_TYPE_GT: + str = g_strdup_printf ("%s > %s", SQL_OPERAND (sql_list->data)->sql, SQL_OPERAND (sql_list->next->data)->sql); + break; + case GDA_SQL_OPERATOR_TYPE_LT: + str = g_strdup_printf ("%s < %s", SQL_OPERAND (sql_list->data)->sql, SQL_OPERAND (sql_list->next->data)->sql); + break; + case GDA_SQL_OPERATOR_TYPE_GEQ: + str = g_strdup_printf ("%s >= %s", SQL_OPERAND (sql_list->data)->sql, SQL_OPERAND (sql_list->next->data)->sql); + break; + case GDA_SQL_OPERATOR_TYPE_LEQ: + str = g_strdup_printf ("%s <= %s", SQL_OPERAND (sql_list->data)->sql, SQL_OPERAND (sql_list->next->data)->sql); + break; + case GDA_SQL_OPERATOR_TYPE_DIFF: + str = g_strdup_printf ("%s != %s", SQL_OPERAND (sql_list->data)->sql, SQL_OPERAND (sql_list->next->data)->sql); + break; + case GDA_SQL_OPERATOR_TYPE_REGEXP: + str = g_strdup_printf ("%s ~ %s", SQL_OPERAND (sql_list->data)->sql, SQL_OPERAND (sql_list->next->data)->sql); + break; + case GDA_SQL_OPERATOR_TYPE_REGEXP_CI: + str = g_strdup_printf ("%s ~* %s", SQL_OPERAND (sql_list->data)->sql, SQL_OPERAND (sql_list->next->data)->sql); + break; + case GDA_SQL_OPERATOR_TYPE_NOT_REGEXP: + str = g_strdup_printf ("%s !~ %s", SQL_OPERAND (sql_list->data)->sql, SQL_OPERAND (sql_list->next->data)->sql); + break; + case GDA_SQL_OPERATOR_TYPE_NOT_REGEXP_CI: + str = g_strdup_printf ("%s !~* %s", SQL_OPERAND (sql_list->data)->sql, SQL_OPERAND (sql_list->next->data)->sql); + break; + case GDA_SQL_OPERATOR_TYPE_SIMILAR: + str = g_strdup_printf ("%s SIMILAR TO %s", SQL_OPERAND (sql_list->data)->sql, SQL_OPERAND (sql_list->next->data)->sql); + break; + case GDA_SQL_OPERATOR_TYPE_REM: + str = g_strdup_printf ("%s %% %s", SQL_OPERAND (sql_list->data)->sql, SQL_OPERAND (sql_list->next->data)->sql); + break; + case GDA_SQL_OPERATOR_TYPE_DIV: + str = g_strdup_printf ("%s / %s", SQL_OPERAND (sql_list->data)->sql, SQL_OPERAND (sql_list->next->data)->sql); + break; + case GDA_SQL_OPERATOR_TYPE_BITAND: + str = g_strdup_printf ("%s & %s", SQL_OPERAND (sql_list->data)->sql, SQL_OPERAND (sql_list->next->data)->sql); + break; + case GDA_SQL_OPERATOR_TYPE_BITOR: + str = g_strdup_printf ("%s | %s", SQL_OPERAND (sql_list->data)->sql, SQL_OPERAND (sql_list->next->data)->sql); + break; + case GDA_SQL_OPERATOR_TYPE_BETWEEN: + str = g_strdup_printf ("%s BETWEEN %s AND %s", SQL_OPERAND (sql_list->data)->sql, + SQL_OPERAND (sql_list->next->data)->sql, + SQL_OPERAND (sql_list->next->next->data)->sql); + break; + case GDA_SQL_OPERATOR_TYPE_ISNULL: + str = g_strdup_printf ("%s IS NULL", SQL_OPERAND (sql_list->data)->sql); + break; + case GDA_SQL_OPERATOR_TYPE_ISNOTNULL: + str = g_strdup_printf ("%s IS NOT NULL", SQL_OPERAND (sql_list->data)->sql); + break; + case GDA_SQL_OPERATOR_TYPE_BITNOT: + str = g_strdup_printf ("~ %s", SQL_OPERAND (sql_list->data)->sql); + break; + case GDA_SQL_OPERATOR_TYPE_NOT: + str = g_strdup_printf ("NOT %s", SQL_OPERAND (sql_list->data)->sql); + break; + case GDA_SQL_OPERATOR_TYPE_IN: + case GDA_SQL_OPERATOR_TYPE_NOTIN: { + gboolean add_p = TRUE; + if (sql_list->next && !(sql_list->next->next) && + *(SQL_OPERAND (sql_list->next->data)->sql)=='(') + add_p = FALSE; + + string = g_string_new (SQL_OPERAND (sql_list->data)->sql); + if (op->operator_type == GDA_SQL_OPERATOR_TYPE_IN) + g_string_append (string, " IN "); + else + g_string_append (string, " NOT IN "); + if (add_p) + g_string_append_c (string, '('); + for (list = sql_list->next; list; list = list->next) { + if (list != sql_list->next) + g_string_append (string, ", "); + g_string_append (string, SQL_OPERAND (list->data)->sql); + } + if (add_p) + g_string_append_c (string, ')'); + str = string->str; + g_string_free (string, FALSE); + break; + } + case GDA_SQL_OPERATOR_TYPE_CONCAT: + multi_op = "||"; + break; + case GDA_SQL_OPERATOR_TYPE_PLUS: + multi_op = "+"; + break; + case GDA_SQL_OPERATOR_TYPE_MINUS: + multi_op = "-"; + break; + case GDA_SQL_OPERATOR_TYPE_STAR: + multi_op = "*"; + break; + case GDA_SQL_OPERATOR_TYPE_AND: + multi_op = "AND"; + break; + case GDA_SQL_OPERATOR_TYPE_OR: + multi_op = "OR"; + break; + default: + g_assert_not_reached (); + break; + } + + if (multi_op) { + if (!sql_list->next) { + /* 1 operand only */ + string = g_string_new (""); + g_string_append_printf (string, "%s %s", multi_op, SQL_OPERAND (sql_list->data)->sql); + } + else { + /* 2 or more operands */ + if (SQL_OPERAND (sql_list->data)->is_composed) { + string = g_string_new ("("); + g_string_append (string, SQL_OPERAND (sql_list->data)->sql); + g_string_append_c (string, ')'); + } + else + string = g_string_new (SQL_OPERAND (sql_list->data)->sql); + for (list = sql_list->next; list; list = list->next) { + g_string_append_printf (string, " %s ", multi_op); + if (SQL_OPERAND (list->data)->is_composed) { + g_string_append_c (string, '('); + g_string_append (string, SQL_OPERAND (list->data)->sql); + g_string_append_c (string, ')'); + } + else + g_string_append (string, SQL_OPERAND (list->data)->sql); + } + } + str = string->str; + g_string_free (string, FALSE); + } + + out: + for (list = sql_list; list; list = list->next) { + g_free (((SqlOperand*)list->data)->sql); + g_free (list->data); + } + g_slist_free (sql_list); + + return str; +} + +static gchar * +default_render_case (GdaSqlCase *case_s, GdaSqlRenderingContext *context, GError **error) +{ + GString *string; + gchar *str; + GSList *wlist, *tlist; + + g_return_val_if_fail (case_s, NULL); + g_return_val_if_fail (GDA_SQL_ANY_PART (case_s)->type == GDA_SQL_ANY_SQL_CASE, NULL); + + /* can't have: + * - case_s->when_expr_list == NULL + * - g_slist_length (sc->when_expr_list) != g_slist_length (sc->then_expr_list) + */ + if (!gda_sql_any_part_check_structure (GDA_SQL_ANY_PART (case_s), error)) return NULL; + + string = g_string_new ("CASE"); + if (case_s->base_expr) { + g_string_append_c (string, ' '); + str = context->render_expr (case_s->base_expr, context, NULL, NULL, error); + if (!str) goto err; + g_string_append (string, str); + g_free (str); + } + + for (wlist = case_s->when_expr_list, tlist = case_s->then_expr_list; + wlist && tlist; + wlist = wlist->next, tlist = tlist->next) { + g_string_append (string, " WHEN "); + str = context->render_expr ((GdaSqlExpr*) wlist->data, context, NULL, NULL, error); + if (!str) goto err; + g_string_append (string, str); + g_free (str); + g_string_append (string, " THEN "); + str = context->render_expr ((GdaSqlExpr*) tlist->data, context, NULL, NULL, error); + if (!str) goto err; + g_string_append (string, str); + g_free (str); + } + + if (case_s->else_expr) { + g_string_append (string, " ELSE "); + str = context->render_expr (case_s->else_expr, context, NULL, NULL, error); + if (!str) goto err; + g_string_append (string, str); + g_free (str); + } + + g_string_append (string, " END"); + + str = string->str; + g_string_free (string, FALSE); + return str; + + err: + g_string_free (string, TRUE); + return NULL; +} + +static gboolean +alias_is_quoted (const gchar *alias) +{ + g_assert (alias); + if ((*alias == '\'') || (*alias == '"')) + return TRUE; + else + return FALSE; +} + +static gchar * +default_render_select_field (GdaSqlSelectField *field, GdaSqlRenderingContext *context, GError **error) +{ + GString *string; + gchar *str; + + g_return_val_if_fail (field, NULL); + g_return_val_if_fail (GDA_SQL_ANY_PART (field)->type == GDA_SQL_ANY_SQL_SELECT_FIELD, NULL); + + /* can't have: field->expr == NULL */ + if (!gda_sql_any_part_check_structure (GDA_SQL_ANY_PART (field), error)) return NULL; + + string = g_string_new (""); + str = context->render_expr (field->expr, context, NULL, NULL, error); + if (!str) goto err; + g_string_append (string, str); + g_free (str); + + if (field->as) { + if (! alias_is_quoted (field->as)) { + GdaConnectionOptions cncoptions = 0; + gchar *tmp; + if (context->cnc) + g_object_get (G_OBJECT (context->cnc), "options", &cncoptions, NULL); + tmp = gda_sql_identifier_quote (field->as, context->cnc, + context->provider, FALSE, + cncoptions & GDA_CONNECTION_OPTIONS_SQL_IDENTIFIERS_CASE_SENSITIVE); + g_string_append_printf (string, " AS %s", tmp); + g_free (tmp); + } + else + g_string_append_printf (string, " AS %s", field->as); + } + + str = string->str; + g_string_free (string, FALSE); + return str; + + err: + g_string_free (string, TRUE); + return NULL; +} + +static gchar * +default_render_select_target (GdaSqlSelectTarget *target, GdaSqlRenderingContext *context, GError **error) +{ + GString *string; + gchar *str; + + g_return_val_if_fail (target, NULL); + g_return_val_if_fail (GDA_SQL_ANY_PART (target)->type == GDA_SQL_ANY_SQL_SELECT_TARGET, NULL); + + /* can't have: target->expr == NULL */ + if (!gda_sql_any_part_check_structure (GDA_SQL_ANY_PART (target), error)) return NULL; + + if (! target->expr->value || (G_VALUE_TYPE (target->expr->value) != G_TYPE_STRING)) { + str = context->render_expr (target->expr, context, NULL, NULL, error); + if (!str) + return NULL; + string = g_string_new (str); + g_free (str); + } + else { + gboolean tmp; + tmp = target->expr->value_is_ident; + target->expr->value_is_ident = TRUE; + str = context->render_expr (target->expr, context, NULL, NULL, error); + target->expr->value_is_ident = tmp; + string = g_string_new (str); + g_free (str); + } + + if (target->as) { + if (! alias_is_quoted (target->as)) { + GdaConnectionOptions cncoptions = 0; + gchar *tmp; + if (context->cnc) + g_object_get (G_OBJECT (context->cnc), "options", &cncoptions, NULL); + tmp = gda_sql_identifier_quote (target->as, context->cnc, + context->provider, FALSE, + cncoptions & GDA_CONNECTION_OPTIONS_SQL_IDENTIFIERS_CASE_SENSITIVE); + g_string_append_printf (string, " AS %s", tmp); + g_free (tmp); + } + else + g_string_append_printf (string, " AS %s", target->as); + } + + str = string->str; + g_string_free (string, FALSE); + return str; +} + +static gchar * +default_render_select_join (GdaSqlSelectJoin *join, GdaSqlRenderingContext *context, GError **error) +{ + GString *string; + gchar *str; + gboolean pretty = context->flags & GDA_STATEMENT_SQL_PRETTY; + + g_return_val_if_fail (join, NULL); + g_return_val_if_fail (GDA_SQL_ANY_PART (join)->type == GDA_SQL_ANY_SQL_SELECT_JOIN, NULL); + + /* can't have: + * - join->expr && join->use + * - (join->type == GDA_SQL_SELECT_JOIN_CROSS) && (join->expr || join->use) + */ + if (!gda_sql_any_part_check_structure (GDA_SQL_ANY_PART (join), error)) return NULL; + + switch (join->type) { + case GDA_SQL_SELECT_JOIN_CROSS: + if (pretty) + string = g_string_new (",\n\t"); + else + string = g_string_new (","); + break; + case GDA_SQL_SELECT_JOIN_NATURAL: + if (pretty) + string = g_string_new ("\n\tNATURAL JOIN"); + else + string = g_string_new ("NATURAL JOIN"); + break; + case GDA_SQL_SELECT_JOIN_INNER: + if (pretty) + string = g_string_new ("\n\tINNER JOIN"); + else + string = g_string_new ("INNER JOIN"); + break; + case GDA_SQL_SELECT_JOIN_LEFT: + if (pretty) + string = g_string_new ("\n\tLEFT JOIN"); + else + string = g_string_new ("LEFT JOIN"); + break; + case GDA_SQL_SELECT_JOIN_RIGHT: + if (pretty) + string = g_string_new ("\n\tRIGHT JOIN"); + else + string = g_string_new ("RIGHT JOIN"); + break; + case GDA_SQL_SELECT_JOIN_FULL: + if (pretty) + string = g_string_new ("\n\tFULL JOIN"); + else + string = g_string_new ("FULL JOIN"); + break; + default: + g_assert_not_reached (); + } + + /* find joinned target */ + GdaSqlSelectFrom *from = (GdaSqlSelectFrom *) GDA_SQL_ANY_PART (join)->parent; + if (!from || (GDA_SQL_ANY_PART (from)->type != GDA_SQL_ANY_SQL_SELECT_FROM)) { + g_set_error (error, GDA_SQL_ERROR, GDA_SQL_STRUCTURE_CONTENTS_ERROR, + "%s", _("Join is not in a FROM statement")); + goto err; + } + GdaSqlSelectTarget *target; + target = g_slist_nth_data (from->targets, join->position); + if (!target || (GDA_SQL_ANY_PART (target)->type != GDA_SQL_ANY_SQL_SELECT_TARGET)) { + g_set_error (error, GDA_SQL_ERROR, GDA_SQL_STRUCTURE_CONTENTS_ERROR, + "%s", _("Could not find target the join is for")); + goto err; + } + str = context->render_select_target (GDA_SQL_ANY_PART (target), context, error); + if (!str) goto err; + + g_string_append_c (string, ' '); + g_string_append (string, str); + g_free (str); + + if (join->expr) { + g_string_append (string, " ON ("); + str = context->render_expr (join->expr, context, NULL, NULL, error); + if (!str) goto err; + g_string_append (string, str); + g_free (str); + g_string_append_c (string, ')'); + } + else if (join->use) { + GSList *list; + g_string_append (string, " USING ("); + for (list = join->use; list; list = list->next) { + if (list != join->use) + g_string_append (string, ", "); + str = context->render_field (GDA_SQL_ANY_PART (list->data), context, error); + if (!str) goto err; + g_string_append (string, str); + g_free (str); + } + g_string_append_c (string, ')'); + } + + str = string->str; + g_string_free (string, FALSE); + return str; + + err: + g_string_free (string, TRUE); + return NULL; +} + +static GdaSqlSelectJoin * +find_join_for_pos (GSList *joins_list, gint pos) +{ + GSList *list; + for (list = joins_list; list; list = list->next) { + if (((GdaSqlSelectJoin*) list->data)->position == pos) + return (GdaSqlSelectJoin*) list->data; + } + return NULL; +} + +static gchar * +default_render_select_from (GdaSqlSelectFrom *from, GdaSqlRenderingContext *context, GError **error) +{ + GString *string; + gchar *str; + GSList *tlist; + gint i; + gboolean pretty = context->flags & GDA_STATEMENT_SQL_PRETTY; + + g_return_val_if_fail (from, NULL); + g_return_val_if_fail (GDA_SQL_ANY_PART (from)->type == GDA_SQL_ANY_SQL_SELECT_FROM, NULL); + + /* can't have: from->targets == NULL */ + if (!gda_sql_any_part_check_structure (GDA_SQL_ANY_PART (from), error)) return NULL; + + string = g_string_new ("FROM "); + for (tlist = from->targets, i = 0; tlist; tlist = tlist->next, i++) { + GdaSqlSelectJoin *join = NULL; + if (tlist != from->targets) + join = find_join_for_pos (from->joins, i); + + if (join) { + str = context->render_select_join (GDA_SQL_ANY_PART (join), context, error); + if (!str) goto err; + if (!pretty) + g_string_append_c (string, ' '); + g_string_append (string, str); + g_free (str); + if (!pretty) + g_string_append_c (string, ' '); + } + else { + if (tlist != from->targets) { + if (pretty) + g_string_append (string, ",\n\t"); + else + g_string_append (string, ", "); + } + str = context->render_select_target (GDA_SQL_ANY_PART (tlist->data), context, error); + if (!str) goto err; + g_string_append (string, str); + g_free (str); + } + } + + str = string->str; + g_string_free (string, FALSE); + return str; + + err: + g_string_free (string, TRUE); + return NULL; +} + +static gchar * +default_render_select_order (GdaSqlSelectOrder *order, GdaSqlRenderingContext *context, GError **error) +{ + GString *string; + gchar *str; + + g_return_val_if_fail (order, NULL); + g_return_val_if_fail (GDA_SQL_ANY_PART (order)->type == GDA_SQL_ANY_SQL_SELECT_ORDER, NULL); + + /* can't have: order->expr == NULL */ + if (!gda_sql_any_part_check_structure (GDA_SQL_ANY_PART (order), error)) return NULL; + + string = g_string_new (""); + str = context->render_expr (order->expr, context, NULL, NULL, error); + if (!str) goto err; + g_string_append (string, str); + g_free (str); + + if (order->collation_name) + g_string_append_printf (string, " COLLATE %s", order->collation_name); + + if (order->asc) + g_string_append (string, " ASC"); + else + g_string_append (string, " DESC"); + + str = string->str; + g_string_free (string, FALSE); + return str; + + err: + g_string_free (string, TRUE); + return NULL; +} diff --git a/.flatpak-builder/cache/objects/09/a42652fb8cb464cb0f579ba22af64d0ced9427a0ea824308f87b4f2d9456d3.dirtree b/.flatpak-builder/cache/objects/09/a42652fb8cb464cb0f579ba22af64d0ced9427a0ea824308f87b4f2d9456d3.dirtree new file mode 100644 index 0000000..91cfda2 Binary files /dev/null and b/.flatpak-builder/cache/objects/09/a42652fb8cb464cb0f579ba22af64d0ced9427a0ea824308f87b4f2d9456d3.dirtree differ diff --git a/.flatpak-builder/cache/objects/09/cfaea057d5a01fc893c4472dd81e03c72e56807e52bd374c5a9a79ae01fca0.dirtree b/.flatpak-builder/cache/objects/09/cfaea057d5a01fc893c4472dd81e03c72e56807e52bd374c5a9a79ae01fca0.dirtree new file mode 100644 index 0000000..eab813f Binary files /dev/null and b/.flatpak-builder/cache/objects/09/cfaea057d5a01fc893c4472dd81e03c72e56807e52bd374c5a9a79ae01fca0.dirtree differ diff --git a/.flatpak-builder/cache/objects/09/e14a707f1f292d4bc922c7d733307f4dca87a0ef7ba891a202ba11f271f105.dirtree b/.flatpak-builder/cache/objects/09/e14a707f1f292d4bc922c7d733307f4dca87a0ef7ba891a202ba11f271f105.dirtree new file mode 100644 index 0000000..9f7e43b Binary files /dev/null and b/.flatpak-builder/cache/objects/09/e14a707f1f292d4bc922c7d733307f4dca87a0ef7ba891a202ba11f271f105.dirtree differ diff --git a/.flatpak-builder/cache/objects/0a/35d1234932ad4cd626a9e828036d057caf6921aa856478fb9acfd7d8a8f043.file b/.flatpak-builder/cache/objects/0a/35d1234932ad4cd626a9e828036d057caf6921aa856478fb9acfd7d8a8f043.file new file mode 100644 index 0000000..72afda2 --- /dev/null +++ b/.flatpak-builder/cache/objects/0a/35d1234932ad4cd626a9e828036d057caf6921aa856478fb9acfd7d8a8f043.file @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2007 - 2014 Vivien Malerba + * Copyright (C) 2010 David King + * Copyright (C) 2011 - 2014 Murray Cumming + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include +#include +#include +#include "gda-virtual-provider.h" +#include +#include + +G_DEFINE_TYPE (GdaVirtualProvider, gda_virtual_provider, GDA_TYPE_SQLITE_PROVIDER) + +/* + * GdaVirtualProvider class implementation + */ +static void +gda_virtual_provider_class_init (GdaVirtualProviderClass *klass) +{ + gda_server_provider_set_impl_functions (GDA_SERVER_PROVIDER_CLASS (klass), + GDA_SERVER_PROVIDER_FUNCTIONS_BASE, + (gpointer) NULL); +} + +static void +gda_virtual_provider_init (G_GNUC_UNUSED GdaVirtualProvider *vprov) +{ +} + diff --git a/.flatpak-builder/cache/objects/0a/83f7df35f73cb52c9c130b15cee844f40a273a31ef9560ea7e74707ed7dd0e.file b/.flatpak-builder/cache/objects/0a/83f7df35f73cb52c9c130b15cee844f40a273a31ef9560ea7e74707ed7dd0e.file new file mode 120000 index 0000000..c293e98 --- /dev/null +++ b/.flatpak-builder/cache/objects/0a/83f7df35f73cb52c9c130b15cee844f40a273a31ef9560ea7e74707ed7dd0e.file @@ -0,0 +1 @@ +../../share/runtime/locale/ca/share/ca \ No newline at end of file diff --git a/.flatpak-builder/cache/objects/0a/89c1f9a595f09814bd7994c153472cc428ff12ecb21d6029ed24f08d9b47b2.file b/.flatpak-builder/cache/objects/0a/89c1f9a595f09814bd7994c153472cc428ff12ecb21d6029ed24f08d9b47b2.file new file mode 100644 index 0000000..9582b00 --- /dev/null +++ b/.flatpak-builder/cache/objects/0a/89c1f9a595f09814bd7994c153472cc428ff12ecb21d6029ed24f08d9b47b2.file @@ -0,0 +1,587 @@ +/*-*- Mode: C; c-basic-offset: 8 -*-*/ + +/*** + This file is part of libcanberra. + + Copyright 2008 Nokia Corporation and/or its subsidiary(-ies). + + Author: Marc-Andre Lureau + + libcanberra is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation, either version 2.1 of the + License, or (at your option) any later version. + + libcanberra is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with libcanberra. If not, see + . +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "canberra.h" +#include "common.h" +#include "driver.h" +#include "llist.h" +#include "read-sound-file.h" +#include "sound-theme-spec.h" +#include "malloc.h" + +struct outstanding { + CA_LLIST_FIELDS(struct outstanding); + ca_bool_t dead; + uint32_t id; + int err; + ca_finish_callback_t callback; + void *userdata; + GstElement *pipeline; + struct ca_context *context; +}; + +struct private { + ca_theme_data *theme; + ca_bool_t signal_semaphore; + sem_t semaphore; + + GstBus *mgr_bus; + + /* Everything below protected by the outstanding_mutex */ + ca_mutex *outstanding_mutex; + ca_bool_t mgr_thread_running; + ca_bool_t semaphore_allocated; + CA_LLIST_HEAD(struct outstanding, outstanding); +}; + +#define PRIVATE(c) ((struct private *) ((c)->private)) + +static void* thread_func(void *userdata); +static void send_eos_msg(struct outstanding *out, int err); +static void send_mgr_exit_msg (struct private *p); + +static void outstanding_free(struct outstanding *o) { + GstBus *bus; + + ca_assert(o); + + if (o->pipeline) { + bus = gst_pipeline_get_bus(GST_PIPELINE (o->pipeline)); + if (bus != NULL) { + gst_bus_set_sync_handler(bus, NULL, NULL, NULL); + gst_object_unref(bus); + } + + gst_object_unref(GST_OBJECT(o->pipeline)); + } + + ca_free(o); +} + +int driver_open(ca_context *c) { + GError *error = NULL; + struct private *p; + pthread_t thread; + + ca_return_val_if_fail(c, CA_ERROR_INVALID); + ca_return_val_if_fail(!PRIVATE(c), CA_ERROR_INVALID); + ca_return_val_if_fail(!c->driver || ca_streq(c->driver, "gstreamer"), CA_ERROR_NODRIVER); + + gst_init_check(NULL, NULL, &error); + if (error != NULL) { + g_warning("gst_init: %s ", error->message); + g_error_free(error); + return CA_ERROR_INVALID; + } + + if (!(p = ca_new0(struct private, 1))) + return CA_ERROR_OOM; + c->private = p; + + if (!(p->outstanding_mutex = ca_mutex_new())) { + driver_destroy(c); + return CA_ERROR_OOM; + } + + if (sem_init(&p->semaphore, 0, 0) < 0) { + driver_destroy(c); + return CA_ERROR_OOM; + } + p->semaphore_allocated = TRUE; + + p->mgr_bus = gst_bus_new(); + if (p->mgr_bus == NULL) { + driver_destroy(c); + return CA_ERROR_OOM; + } + gst_bus_set_flushing(p->mgr_bus, FALSE); + + /* Give a reference to the bus to the mgr thread */ + if (pthread_create(&thread, NULL, thread_func, p) < 0) { + driver_destroy(c); + return CA_ERROR_OOM; + } + p->mgr_thread_running = TRUE; + + return CA_SUCCESS; +} + +int driver_destroy(ca_context *c) { + struct private *p; + struct outstanding *out; + + ca_return_val_if_fail(c, CA_ERROR_INVALID); + ca_return_val_if_fail(PRIVATE(c), CA_ERROR_STATE); + + p = PRIVATE(c); + + if (p->outstanding_mutex) { + ca_mutex_lock(p->outstanding_mutex); + + /* Tell all player threads to terminate */ + out = p->outstanding; + while (out) { + if (!out->dead) + send_eos_msg(out, CA_ERROR_DESTROYED); + out = out->next; + } + + /* Now that we've sent EOS for all pending players, append a + * message to wait for the mgr thread to exit */ + if (p->mgr_thread_running && p->semaphore_allocated) { + send_mgr_exit_msg(p); + + p->signal_semaphore = TRUE; + while (p->mgr_thread_running) { + ca_mutex_unlock(p->outstanding_mutex); + sem_wait(&p->semaphore); + ca_mutex_lock(p->outstanding_mutex); + } + } + + ca_mutex_unlock(p->outstanding_mutex); + ca_mutex_free(p->outstanding_mutex); + } + + if (p->mgr_bus) + g_object_unref(p->mgr_bus); + + if (p->theme) + ca_theme_data_free(p->theme); + + if (p->semaphore_allocated) + sem_destroy(&p->semaphore); + + ca_free(p); + + /* no gst_deinit(), see doc */ + + return CA_SUCCESS; +} + +int driver_change_device(ca_context *c, const char *device) { + ca_return_val_if_fail(c, CA_ERROR_INVALID); + ca_return_val_if_fail(PRIVATE(c), CA_ERROR_STATE); + + return CA_SUCCESS; +} + +int driver_change_props(ca_context *c, ca_proplist *changed, ca_proplist *merged) { + ca_return_val_if_fail(c, CA_ERROR_INVALID); + ca_return_val_if_fail(changed, CA_ERROR_INVALID); + ca_return_val_if_fail(merged, CA_ERROR_INVALID); + ca_return_val_if_fail(PRIVATE(c), CA_ERROR_STATE); + + return CA_SUCCESS; +} + +static void +send_eos_msg(struct outstanding *out, int err) { + struct private *p; + GstMessage *m; + GstStructure *s; + + out->dead = TRUE; + out->err = err; + + p = PRIVATE(out->context); + s = gst_structure_new("application/eos", "info", G_TYPE_POINTER, out, NULL); + m = gst_message_new_application (GST_OBJECT (out->pipeline), s); + + gst_bus_post (p->mgr_bus, m); +} + +static GstBusSyncReply +bus_cb(GstBus *bus, GstMessage *message, gpointer data) { + int err; + struct outstanding *out; + struct private *p; + + ca_return_val_if_fail(bus, GST_BUS_DROP); + ca_return_val_if_fail(message, GST_BUS_DROP); + ca_return_val_if_fail(data, GST_BUS_DROP); + + out = data; + p = PRIVATE(out->context); + + switch (GST_MESSAGE_TYPE(message)) { + /* for all elements */ + case GST_MESSAGE_ERROR: + err = CA_ERROR_SYSTEM; + break; + case GST_MESSAGE_EOS: + /* only respect EOS from the toplevel pipeline */ + if (GST_OBJECT(out->pipeline) != GST_MESSAGE_SRC(message)) + return GST_BUS_PASS; + + err = CA_SUCCESS; + break; + default: + return GST_BUS_PASS; + } + + /* Bin finished playback: ask the manager thread to shut it + * down, since we can't from the sync message handler */ + ca_mutex_lock(p->outstanding_mutex); + if (!out->dead) + send_eos_msg(out, err); + ca_mutex_unlock(p->outstanding_mutex); + + return GST_BUS_PASS; +} + +struct ca_sound_file { + GstElement *fdsrc; +}; + +static int ca_gst_sound_file_open(ca_sound_file **_f, const char *fn) { + int fd; + ca_sound_file *f; + + ca_return_val_if_fail(_f, CA_ERROR_INVALID); + ca_return_val_if_fail(fn, CA_ERROR_INVALID); + + if ((fd = open(fn, O_RDONLY)) == -1) + return errno == ENOENT ? CA_ERROR_NOTFOUND : CA_ERROR_SYSTEM; + + if (!(f = ca_new0(ca_sound_file, 1))) { + close(fd); + return CA_ERROR_OOM; + } + + if (!(f->fdsrc = gst_element_factory_make("fdsrc", NULL))) { + close(fd); + ca_free(f); + return CA_ERROR_OOM; + } + + g_object_set(GST_OBJECT(f->fdsrc), "fd", fd, NULL); + *_f = f; + + return CA_SUCCESS; +} + +static void on_pad_added(GstElement *element, GstPad *pad, gboolean arg1, gpointer data) +{ + GstStructure *structure; + GstElement *sinkelement; + GstCaps *caps; + GstPad *vpad; + const char *type; + + sinkelement = GST_ELEMENT(data); + + caps = gst_pad_query_caps(pad, NULL); + if (gst_caps_is_empty(caps) || gst_caps_is_any(caps)) { + gst_caps_unref(caps); + return; + } + + structure = gst_caps_get_structure(caps, 0); + type = gst_structure_get_name(structure); + if (g_str_has_prefix(type, "audio/x-raw") == TRUE) { + vpad = gst_element_get_static_pad(sinkelement, "sink"); + gst_pad_link(pad, vpad); + gst_object_unref(vpad); + } + gst_caps_unref(caps); +} + +static void +send_mgr_exit_msg (struct private *p) { + GstMessage *m; + GstStructure *s; + + s = gst_structure_new("application/mgr-exit", NULL); + m = gst_message_new_application (NULL, s); + + gst_bus_post (p->mgr_bus, m); +} + +/* Global manager thread that shuts down GStreamer pipelines when ordered */ +static void* thread_func(void *userdata) { + struct private *p = userdata; + GstBus *bus = g_object_ref(p->mgr_bus); + + pthread_detach(pthread_self()); + + /* Pop messages from the manager bus until we see an exit command */ + do { + GstMessage *m = gst_bus_timed_pop(bus, GST_CLOCK_TIME_NONE); + const GstStructure *s; + const GValue *v; + struct outstanding *out; + + if (m == NULL) + break; + if (GST_MESSAGE_TYPE(m) != GST_MESSAGE_APPLICATION) { + gst_message_unref (m); + break; + } + + s = gst_message_get_structure(m); + if (gst_structure_has_name(s, "application/mgr-exit")) { + gst_message_unref (m); + break; + } + + /* Otherwise, this must be an EOS message for an outstanding pipe */ + ca_assert(gst_structure_has_name(s, "application/eos")); + v = gst_structure_get_value(s, "info"); + ca_assert(v); + out = g_value_get_pointer(v); + ca_assert(out); + + /* Set pipeline back to NULL to close things. By the time this + * completes, we can be sure bus_cb won't be called */ + if (gst_element_set_state(out->pipeline, GST_STATE_NULL) == + GST_STATE_CHANGE_FAILURE) { + gst_message_unref (m); + break; + } + if (out->callback) + out->callback(out->context, out->id, out->err, out->userdata); + + ca_mutex_lock(p->outstanding_mutex); + CA_LLIST_REMOVE(struct outstanding, p->outstanding, out); + outstanding_free(out); + ca_mutex_unlock(p->outstanding_mutex); + + gst_message_unref(m); + } while (TRUE); + + /* Signal the semaphore and exit */ + ca_mutex_lock(p->outstanding_mutex); + if (p->signal_semaphore) + sem_post(&p->semaphore); + p->mgr_thread_running = FALSE; + ca_mutex_unlock(p->outstanding_mutex); + + gst_bus_set_flushing(bus, TRUE); + g_object_unref (bus); + return NULL; +} + + +int driver_play(ca_context *c, uint32_t id, ca_proplist *proplist, ca_finish_callback_t cb, void *userdata) { + struct private *p; + struct outstanding *out; + ca_sound_file *f; + GstElement *decodebin, *sink, *audioconvert, *audioresample, *abin; + GstBus *bus; + GstPad *audiopad; + int ret; + + ca_return_val_if_fail(c, CA_ERROR_INVALID); + ca_return_val_if_fail(proplist, CA_ERROR_INVALID); + ca_return_val_if_fail(!userdata || cb, CA_ERROR_INVALID); + + out = NULL; + f = NULL; + sink = NULL; + decodebin = NULL; + audioconvert = NULL; + audioresample = NULL; + abin = NULL; + p = PRIVATE(c); + + if ((ret = ca_lookup_sound_with_callback(&f, ca_gst_sound_file_open, NULL, &p->theme, c->props, proplist)) < 0) + goto fail; + + if (!(out = ca_new0(struct outstanding, 1))) + return CA_ERROR_OOM; + + out->id = id; + out->callback = cb; + out->userdata = userdata; + out->context = c; + + if (!(out->pipeline = gst_pipeline_new(NULL)) + || !(decodebin = gst_element_factory_make("decodebin2", NULL)) + || !(audioconvert = gst_element_factory_make("audioconvert", NULL)) + || !(audioresample = gst_element_factory_make("audioresample", NULL)) + || !(sink = gst_element_factory_make("autoaudiosink", NULL)) + || !(abin = gst_bin_new ("audiobin"))) { + + /* At this point, if there is a failure, free each plugin separately. */ + if (out->pipeline != NULL) + g_object_unref (out->pipeline); + if (decodebin != NULL) + g_object_unref(decodebin); + if (audioconvert != NULL) + g_object_unref(audioconvert); + if (audioresample != NULL) + g_object_unref(audioresample); + if (sink != NULL) + g_object_unref(sink); + if (abin != NULL) + g_object_unref(abin); + + ca_free(out); + + ret = CA_ERROR_OOM; + goto fail; + } + + bus = gst_pipeline_get_bus(GST_PIPELINE (out->pipeline)); + gst_bus_set_sync_handler(bus, bus_cb, out, NULL); + gst_object_unref(bus); + + g_signal_connect(decodebin, "new-decoded-pad", + G_CALLBACK (on_pad_added), abin); + gst_bin_add_many(GST_BIN (abin), audioconvert, audioresample, sink, NULL); + gst_element_link_many(audioconvert, audioresample, sink, NULL); + + audiopad = gst_element_get_static_pad(audioconvert, "sink"); + gst_element_add_pad(abin, gst_ghost_pad_new("sink", audiopad)); + gst_object_unref(audiopad); + + gst_bin_add_many(GST_BIN (out->pipeline), + f->fdsrc, decodebin, abin, NULL); + if (!gst_element_link(f->fdsrc, decodebin)) { + /* Bin now owns the fdsrc... */ + f->fdsrc = NULL; + + outstanding_free(out); + ret = CA_ERROR_OOM; + goto fail; + } + /* Bin now owns the fdsrc... */ + f->fdsrc = NULL; + + ca_free(f); + f = NULL; + + ca_mutex_lock(p->outstanding_mutex); + CA_LLIST_PREPEND(struct outstanding, p->outstanding, out); + ca_mutex_unlock(p->outstanding_mutex); + + if (gst_element_set_state(out->pipeline, + GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) { + ret = CA_ERROR_NOTAVAILABLE; + goto fail; + } + + return CA_SUCCESS; + +fail: + if (f && f->fdsrc) + gst_object_unref(f->fdsrc); + + if (f) + ca_free(f); + + return ret; +} + +int driver_cancel(ca_context *c, uint32_t id) { + struct private *p; + struct outstanding *out = NULL; + + ca_return_val_if_fail(c, CA_ERROR_INVALID); + ca_return_val_if_fail(PRIVATE(c), CA_ERROR_STATE); + + p = PRIVATE(c); + + ca_mutex_lock(p->outstanding_mutex); + + for (out = p->outstanding; out;/* out = out->next*/) { + struct outstanding *next; + + if (out->id != id || out->pipeline == NULL || out->dead == TRUE) { + out = out->next; + continue; + } + + if (gst_element_set_state(out->pipeline, GST_STATE_NULL) == + GST_STATE_CHANGE_FAILURE) + goto error; + + if (out->callback) + out->callback(c, out->id, CA_ERROR_CANCELED, out->userdata); + next = out->next; + CA_LLIST_REMOVE(struct outstanding, p->outstanding, out); + outstanding_free(out); + out = next; + } + + ca_mutex_unlock(p->outstanding_mutex); + + return CA_SUCCESS; + +error: + ca_mutex_unlock(p->outstanding_mutex); + return CA_ERROR_SYSTEM; +} + +int driver_cache(ca_context *c, ca_proplist *proplist) { + ca_return_val_if_fail(c, CA_ERROR_INVALID); + ca_return_val_if_fail(proplist, CA_ERROR_INVALID); + ca_return_val_if_fail(PRIVATE(c), CA_ERROR_STATE); + + return CA_ERROR_NOTSUPPORTED; +} + +int driver_playing(ca_context *c, uint32_t id, int *playing) { + struct private *p; + struct outstanding *out; + + ca_return_val_if_fail(c, CA_ERROR_INVALID); + ca_return_val_if_fail(c->private, CA_ERROR_STATE); + ca_return_val_if_fail(playing, CA_ERROR_INVALID); + + p = PRIVATE(c); + + *playing = 0; + + ca_mutex_lock(p->outstanding_mutex); + + for (out = p->outstanding; out; out = out->next) { + + if (out->id != id || out->pipeline == NULL || out->dead == TRUE) + continue; + + *playing = 1; + break; + } + + ca_mutex_unlock(p->outstanding_mutex); + + return CA_SUCCESS; +} diff --git a/.flatpak-builder/cache/objects/0a/9a3d41045781386266d859969ea5dd0414b52b7facf1763c035c2aabe1588a.file b/.flatpak-builder/cache/objects/0a/9a3d41045781386266d859969ea5dd0414b52b7facf1763c035c2aabe1588a.file new file mode 100644 index 0000000..a7c2c01 Binary files /dev/null and b/.flatpak-builder/cache/objects/0a/9a3d41045781386266d859969ea5dd0414b52b7facf1763c035c2aabe1588a.file differ diff --git a/.flatpak-builder/cache/objects/0a/a9cf71def0e65710d77d2bb91eec27275171232720fc693d99860d159df1c7.dirtree b/.flatpak-builder/cache/objects/0a/a9cf71def0e65710d77d2bb91eec27275171232720fc693d99860d159df1c7.dirtree new file mode 100644 index 0000000..e7a1d64 Binary files /dev/null and b/.flatpak-builder/cache/objects/0a/a9cf71def0e65710d77d2bb91eec27275171232720fc693d99860d159df1c7.dirtree differ diff --git a/.flatpak-builder/cache/objects/0b/0e4f80784bd6ed4db0a0766595012bed7c17bebf36ee128601ee7fbee226bb.file b/.flatpak-builder/cache/objects/0b/0e4f80784bd6ed4db0a0766595012bed7c17bebf36ee128601ee7fbee226bb.file new file mode 100644 index 0000000..f8222f7 Binary files /dev/null and b/.flatpak-builder/cache/objects/0b/0e4f80784bd6ed4db0a0766595012bed7c17bebf36ee128601ee7fbee226bb.file differ diff --git a/.flatpak-builder/cache/objects/0b/39b97022c77f8fa4161679af4f346dad9fe6382575b2d8a02ee399f2851a86.file b/.flatpak-builder/cache/objects/0b/39b97022c77f8fa4161679af4f346dad9fe6382575b2d8a02ee399f2851a86.file new file mode 100644 index 0000000..0c06e0f --- /dev/null +++ b/.flatpak-builder/cache/objects/0b/39b97022c77f8fa4161679af4f346dad9fe6382575b2d8a02ee399f2851a86.file @@ -0,0 +1,420 @@ +/* + * Copyright (C) 2006 - 2013 Vivien Malerba + * Copyright (C) 2007 Armin Burgmeier + * Copyright (C) 2010 David King + * Copyright (C) 2010 Jonh Wendell + * Copyright (C) 2018 Daniel Espinosa + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +#define G_LOG_DOMAIN "GDA-transaction-status" + +#include +#include +#include +#include +#include + +#define PARENT_TYPE G_TYPE_OBJECT + +typedef struct { + gchar *name; + GdaTransactionIsolation isolation_level; + GdaTransactionStatusState state; + GList *events; +} GdaTransactionStatusPrivate; + +G_DEFINE_TYPE_WITH_PRIVATE (GdaTransactionStatus, gda_transaction_status, G_TYPE_OBJECT) + +static void gda_transaction_status_finalize (GObject *object); + +/* + * GdaTransactionStatus class implementation + */ + +static void +gda_transaction_status_class_init (GdaTransactionStatusClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->finalize = gda_transaction_status_finalize; +} + +static void +gda_transaction_status_init (GdaTransactionStatus *tstatus) +{ + GdaTransactionStatusPrivate *priv = gda_transaction_status_get_instance_private (tstatus); + priv->name = NULL; + priv->isolation_level = GDA_TRANSACTION_ISOLATION_UNKNOWN; + priv->events = NULL; + priv->state = GDA_TRANSACTION_STATUS_STATE_OK; +} + +static void +event_free (GdaTransactionStatusEvent *event) +{ + switch (event->type) { + case GDA_TRANSACTION_STATUS_EVENT_SAVEPOINT: + g_free (event->pl.svp_name); + break; + case GDA_TRANSACTION_STATUS_EVENT_SQL: + g_free (event->pl.sql); + break; + case GDA_TRANSACTION_STATUS_EVENT_SUB_TRANSACTION: + g_object_unref (event->pl.sub_trans); + break; + default: + g_assert_not_reached (); + } + if (event->conn_event) + g_object_unref (event->conn_event); + + g_free (event); +} + +static void +gda_transaction_status_finalize (GObject *object) +{ + GdaTransactionStatus *tstatus = (GdaTransactionStatus *) object; + + g_return_if_fail (GDA_IS_TRANSACTION_STATUS (tstatus)); + + GdaTransactionStatusPrivate *priv = gda_transaction_status_get_instance_private (tstatus); + /* free memory */ + if (priv->name) { + g_free (priv->name); + priv->name = NULL; + } + + if (priv->events) { + g_list_free_full (priv->events, (GDestroyNotify) event_free); + priv->events = NULL; + } + + /* chain to parent class */ + G_OBJECT_CLASS (gda_transaction_status_parent_class)->finalize (object); +} + + +GdaTransactionStatusEvent * +gda_transaction_status_event_copy (GdaTransactionStatusEvent *src) { + GdaTransactionStatusEvent *cp = g_new0(GdaTransactionStatusEvent, 1); + cp->trans = src->trans; + cp->type = src->type; + cp->pl.svp_name = g_strdup (src->pl.svp_name); + cp->pl.sql = g_strdup (src->pl.sql); + cp->pl.sub_trans = src->pl.sub_trans; + cp->conn_event = src->conn_event; + return cp; +} +void +gda_transaction_status_event_free (GdaTransactionStatusEvent *te) { + g_free (te->pl.svp_name); + g_free (te->pl.sql); + g_free (te); +} + +G_DEFINE_BOXED_TYPE(GdaTransactionStatusEvent, gda_transaction_status_event, gda_transaction_status_event_copy, gda_transaction_status_event_free) + +/** + * gda_transaction_status_new: + * @name: name for the transaction + * + * Creates a new #GdaTransactionStatus object, which allows a fine-tune and + * full control of transactions to be used with providers. + * + * Returns: (transfer full): the newly created object. + */ +GdaTransactionStatus * +gda_transaction_status_new (const gchar *name) +{ + GdaTransactionStatus *tstatus; + + tstatus = g_object_new (GDA_TYPE_TRANSACTION_STATUS, NULL); + GdaTransactionStatusPrivate *priv = gda_transaction_status_get_instance_private (tstatus); + if (name) + priv->name = g_strdup (name); + + return tstatus; +} + +/** + * gda_transaction_status_add_event_svp: + * + */ +GdaTransactionStatusEvent * +gda_transaction_status_add_event_svp (GdaTransactionStatus *tstatus, const gchar *svp_name) +{ + GdaTransactionStatusEvent *ev; + + g_return_val_if_fail (GDA_IS_TRANSACTION_STATUS (tstatus), NULL); + g_return_val_if_fail (svp_name, NULL); + + GdaTransactionStatusPrivate *priv = gda_transaction_status_get_instance_private (tstatus); + + ev = g_new0 (GdaTransactionStatusEvent, 1); + ev->trans = tstatus; + ev->type = GDA_TRANSACTION_STATUS_EVENT_SAVEPOINT; + ev->pl.svp_name = g_strdup (svp_name); + priv->events = g_list_append (priv->events, ev); + + return ev; +} + +/** + * gda_transaction_status_add_event_sql: + * + */ +GdaTransactionStatusEvent * +gda_transaction_status_add_event_sql (GdaTransactionStatus *tstatus, const gchar *sql, GdaConnectionEvent *conn_event) +{ + GdaTransactionStatusEvent *ev; + + g_return_val_if_fail (GDA_IS_TRANSACTION_STATUS (tstatus), NULL); + g_return_val_if_fail (sql, NULL); + GdaTransactionStatusPrivate *priv = gda_transaction_status_get_instance_private (tstatus); + + ev = g_new0 (GdaTransactionStatusEvent, 1); + ev->trans = tstatus; + ev->type = GDA_TRANSACTION_STATUS_EVENT_SQL; + ev->pl.sql = g_strdup (sql); + if (conn_event) { + ev->conn_event = conn_event; + g_object_ref (conn_event); + } + priv->events = g_list_append (priv->events, ev); + + return ev; +} + +/** + * gda_transaction_status_add_event_sub: + * + */ +GdaTransactionStatusEvent * +gda_transaction_status_add_event_sub (GdaTransactionStatus *tstatus, GdaTransactionStatus *sub_trans) +{ + GdaTransactionStatusEvent *ev; + + g_return_val_if_fail (GDA_IS_TRANSACTION_STATUS (tstatus), NULL); + g_return_val_if_fail (GDA_IS_TRANSACTION_STATUS (sub_trans), NULL); + GdaTransactionStatusPrivate *priv = gda_transaction_status_get_instance_private (tstatus); + + ev = g_new0 (GdaTransactionStatusEvent, 1); + ev->trans = tstatus; + ev->type = GDA_TRANSACTION_STATUS_EVENT_SUB_TRANSACTION; + ev->pl.sub_trans = sub_trans; + g_object_ref (ev->pl.sub_trans); + priv->events = g_list_append (priv->events, ev); + + return ev; +} + +void +gda_transaction_status_free_events (GdaTransactionStatus *tstatus, GdaTransactionStatusEvent *event, + gboolean free_after) +{ + GList *node; + + g_return_if_fail (GDA_IS_TRANSACTION_STATUS (tstatus)); + GdaTransactionStatusPrivate *priv = gda_transaction_status_get_instance_private (tstatus); + node = g_list_find (priv->events, event); + g_return_if_fail (node); + + if (free_after) { + GList *list = g_list_last (priv->events); + GList *tmp; + while (list != node) { + event_free ((GdaTransactionStatusEvent *)(list->data)); + tmp = list->prev; + priv->events = g_list_delete_link (priv->events, list); + list = tmp; + } + } + event_free (event); + priv->events = g_list_delete_link (priv->events, node); +} + +/** + * gda_transaction_status_find: + * + * Returns: (transfer full) (nullable): + */ +GdaTransactionStatus * +gda_transaction_status_find (GdaTransactionStatus *tstatus, const gchar *str, GdaTransactionStatusEvent **destev) +{ + GdaTransactionStatus *trans = NULL; + GList *evlist; + + if (!tstatus) + return NULL; + + g_return_val_if_fail (GDA_IS_TRANSACTION_STATUS (tstatus), NULL); + GdaTransactionStatusPrivate *priv = gda_transaction_status_get_instance_private (tstatus); + if (destev) + *destev = NULL; + + if (!str) + return gda_transaction_status_find_current (tstatus, destev, FALSE); + + if (priv->name && !strcmp (priv->name, str)) + return tstatus; + + for (evlist = priv->events; evlist && !trans; evlist = evlist->next) { + GdaTransactionStatusEvent *ev = (GdaTransactionStatusEvent *)(evlist->data); + switch (ev->type) { + case GDA_TRANSACTION_STATUS_EVENT_SAVEPOINT: + if (!strcmp (ev->pl.svp_name, str)) + trans = tstatus; + break; + case GDA_TRANSACTION_STATUS_EVENT_SQL: + if (!strcmp (ev->pl.sql, str)) + trans = tstatus; + break; + case GDA_TRANSACTION_STATUS_EVENT_SUB_TRANSACTION: + trans = gda_transaction_status_find (ev->pl.sub_trans, str, NULL); + break; + default: + g_assert_not_reached (); + } + if (trans && destev) + *destev = ev; + } + + return trans; +} + +/** + * gda_transaction_status_find_current: + * + * Find a pointer to the "current" _unnamed_ transaction, which is the last + * transaction if there are several nested transactions + * + * Returns: (transfer full) (nullable): + */ +GdaTransactionStatus * +gda_transaction_status_find_current (GdaTransactionStatus *tstatus, GdaTransactionStatusEvent **destev, gboolean unnamed_only) +{ + GdaTransactionStatus *trans = NULL; + GList *evlist; + + if (!tstatus) + return NULL; + g_return_val_if_fail (GDA_IS_TRANSACTION_STATUS (tstatus), NULL); + GdaTransactionStatusPrivate *priv = gda_transaction_status_get_instance_private (tstatus); + if (destev) + *destev = NULL; + + for (evlist = priv->events; evlist && !trans; evlist = evlist->next) { + GdaTransactionStatusEvent *ev = (GdaTransactionStatusEvent *)(evlist->data); + if (ev->type == GDA_TRANSACTION_STATUS_EVENT_SUB_TRANSACTION) + trans = gda_transaction_status_find_current (ev->pl.sub_trans, destev, unnamed_only); + if (trans && destev && !(*destev)) + *destev = ev; + } + + if (!trans && ((unnamed_only && !priv->name) || !unnamed_only)) + trans = tstatus; + + return trans; +} + +/** + * gda_transaction_status_set_isolation_level: + */ +void +gda_transaction_status_set_isolation_level (GdaTransactionStatus *st, GdaTransactionIsolation il) +{ + g_return_if_fail (GDA_IS_TRANSACTION_STATUS (st)); + GdaTransactionStatusPrivate *priv = gda_transaction_status_get_instance_private (st); + priv->isolation_level = il; +} +/** + * gda_transaction_status_get_isolation_level: + */ +GdaTransactionIsolation +gda_transaction_status_get_isolation_level (GdaTransactionStatus *st) +{ + g_return_val_if_fail (GDA_IS_TRANSACTION_STATUS (st), GDA_TRANSACTION_ISOLATION_UNKNOWN); + GdaTransactionStatusPrivate *priv = gda_transaction_status_get_instance_private (st); + return priv->isolation_level; +} +/** + * gda_transaction_status_set_state: + */ +void +gda_transaction_status_set_state (GdaTransactionStatus *st, GdaTransactionStatusState state) +{ + g_return_if_fail (GDA_IS_TRANSACTION_STATUS (st)); + GdaTransactionStatusPrivate *priv = gda_transaction_status_get_instance_private (st); + priv->state = state; +} + +/** + * gda_transaction_status_get_state: + */ +GdaTransactionStatusState +gda_transaction_status_get_state (GdaTransactionStatus *st) +{ + g_return_val_if_fail (GDA_IS_TRANSACTION_STATUS (st), GDA_TRANSACTION_STATUS_STATE_FAILED); + GdaTransactionStatusPrivate *priv = gda_transaction_status_get_instance_private (st); + return priv->state; +} + +#ifdef GDA_DEBUG +void +gda_transaction_status_dump (GdaTransactionStatus *tstatus, guint offset) +{ + gchar *str; + GList *evlist; + gchar *levels[] = {"GDA_TRANSACTION_ISOLATION_UNKNOWN", + "GDA_TRANSACTION_ISOLATION_READ_COMMITTED", + "GDA_TRANSACTION_ISOLATION_READ_UNCOMMITTED", + "GDA_TRANSACTION_ISOLATION_REPEATABLE_READ", + "GDA_TRANSACTION_ISOLATION_SERIALIZABLE"}; +#define level_str(lev) ((lev < 4) ? levels[lev] : "UNKNOWN ISOLATION LEVEL") + + g_return_if_fail (GDA_IS_TRANSACTION_STATUS (tstatus)); + GdaTransactionStatusPrivate *priv = gda_transaction_status_get_instance_private (tstatus); + + str = g_new (gchar, offset+1); + memset (str, ' ', offset); + str [offset] = 0; + + g_print ("%sGdaTransactionStatus: %s (%s, %p)\n", str, priv->name ? priv->name : "(NONAME)", + level_str (priv->isolation_level), tstatus); + for (evlist = priv->events; evlist; evlist = evlist->next) { + GdaTransactionStatusEvent *ev = (GdaTransactionStatusEvent *) (evlist->data); + switch (ev->type) { + case GDA_TRANSACTION_STATUS_EVENT_SAVEPOINT: + g_print ("%s *SAVE POINT %s (%p)\n", str, ev->pl.svp_name, ev); + break; + case GDA_TRANSACTION_STATUS_EVENT_SQL: + g_print ("%s *SQL %s (%p): %s\n", str, ev->pl.sql, ev, + ev->conn_event ? gda_connection_event_get_description (ev->conn_event) : "_no event_"); + break; + case GDA_TRANSACTION_STATUS_EVENT_SUB_TRANSACTION: + g_print ("%s *SUB TRANSACTION (%p)\n", str, ev); + gda_transaction_status_dump (ev->pl.sub_trans, offset + 5); + break; + default: + g_assert_not_reached (); + } + } + + g_free (str); +} +#endif diff --git a/.flatpak-builder/cache/objects/0b/3d93f8b46fba97ac2f0155a2374b9aaf8e94e6e5b67f5a3e73620ba6e6aa76.file b/.flatpak-builder/cache/objects/0b/3d93f8b46fba97ac2f0155a2374b9aaf8e94e6e5b67f5a3e73620ba6e6aa76.file new file mode 100644 index 0000000..53d8855 --- /dev/null +++ b/.flatpak-builder/cache/objects/0b/3d93f8b46fba97ac2f0155a2374b9aaf8e94e6e5b67f5a3e73620ba6e6aa76.file @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.flatpak-builder/cache/objects/0b/53a6d15712fb3f1b3e6bcb8381a2b05284605a0329b636bf89971792aae942.file b/.flatpak-builder/cache/objects/0b/53a6d15712fb3f1b3e6bcb8381a2b05284605a0329b636bf89971792aae942.file new file mode 100644 index 0000000..d10999e --- /dev/null +++ b/.flatpak-builder/cache/objects/0b/53a6d15712fb3f1b3e6bcb8381a2b05284605a0329b636bf89971792aae942.file @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2008 - 2011 Vivien Malerba + * Copyright (C) 2010 Murray Cumming + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef _GDA_STATEMENT_STRUCT_H_ +#define _GDA_STATEMENT_STRUCT_H_ + +#include +#include +#include +#include + +G_BEGIN_DECLS + +/** + * GdaSqlStatement: + * @sql: + * @stmt_type: type of statement + * @contents: contents, cast it depending on @stmt_type (for example to a #GdaSqlStatementSelect). + * @validity_meta_struct: + * + * This structure is the top level structure encapsulating several type of statements. + */ +struct _GdaSqlStatement { + gchar *sql; + GdaSqlStatementType stmt_type; + gpointer contents; /* depends on stmt_type */ + GdaMetaStruct *validity_meta_struct; /* set when gda_sql_statement_check_validity() was last called */ + + /*< private >*/ + /* Padding for future expansion */ + gpointer _gda_reserved1; + gpointer _gda_reserved2; +}; + +#define GDA_TYPE_SQL_STATEMENT (gda_sql_statement_get_type()) + +GType gda_sql_statement_get_type (void) G_GNUC_CONST; +GdaSqlStatement *gda_sql_statement_new (GdaSqlStatementType type); +GdaSqlStatement *gda_sql_statement_copy (GdaSqlStatement *stmt); +void gda_sql_statement_free (GdaSqlStatement *stmt); +gchar *gda_sql_statement_serialize (GdaSqlStatement *stmt); + +const gchar *gda_sql_statement_type_to_string (GdaSqlStatementType type); +GdaSqlStatementType gda_sql_statement_string_to_type (const gchar *type); + +gboolean gda_sql_statement_check_structure (GdaSqlStatement *stmt, GError **error); +gboolean gda_sql_statement_check_validity (GdaSqlStatement *stmt, GdaConnection *cnc, GError **error); +gboolean gda_sql_statement_check_validity_m (GdaSqlStatement *stmt, + GdaMetaStruct *mstruct, + GError **error); + +void gda_sql_statement_check_clean (GdaSqlStatement *stmt); +gboolean gda_sql_statement_normalize (GdaSqlStatement *stmt, GdaConnection *cnc, GError **error); + +GdaSqlStatementContentsInfo *gda_sql_statement_get_contents_infos (GdaSqlStatementType type) ; + +G_END_DECLS + +#endif diff --git a/.flatpak-builder/cache/objects/0b/b77e07f1687bb1f754f47f511ebaeb152c3f8cbd18dfe4db3dfa6b0fc4fbed.dirtree b/.flatpak-builder/cache/objects/0b/b77e07f1687bb1f754f47f511ebaeb152c3f8cbd18dfe4db3dfa6b0fc4fbed.dirtree new file mode 100644 index 0000000..35255cb Binary files /dev/null and b/.flatpak-builder/cache/objects/0b/b77e07f1687bb1f754f47f511ebaeb152c3f8cbd18dfe4db3dfa6b0fc4fbed.dirtree differ diff --git a/.flatpak-builder/cache/objects/0b/e39b4ff7c90be7bd4b0de8c9cdc76e42a4c4bc46fb84dfd95221a7eaf9cc10.dirtree b/.flatpak-builder/cache/objects/0b/e39b4ff7c90be7bd4b0de8c9cdc76e42a4c4bc46fb84dfd95221a7eaf9cc10.dirtree new file mode 100644 index 0000000..1fed700 Binary files /dev/null and b/.flatpak-builder/cache/objects/0b/e39b4ff7c90be7bd4b0de8c9cdc76e42a4c4bc46fb84dfd95221a7eaf9cc10.dirtree differ diff --git a/.flatpak-builder/cache/objects/0c/76aca474e1a03baa2d6c8f72b53d4a44f0eb41d9a7f0592183c06f712ec55a.file b/.flatpak-builder/cache/objects/0c/76aca474e1a03baa2d6c8f72b53d4a44f0eb41d9a7f0592183c06f712ec55a.file new file mode 120000 index 0000000..7222c44 --- /dev/null +++ b/.flatpak-builder/cache/objects/0c/76aca474e1a03baa2d6c8f72b53d4a44f0eb41d9a7f0592183c06f712ec55a.file @@ -0,0 +1 @@ +../../share/runtime/locale/gl/share/gl \ No newline at end of file diff --git a/.flatpak-builder/cache/objects/0c/aec582e6f145e03885ee9a2ef25c47fe0cadbc27c1423f786a8b6d63fddc11.dirtree b/.flatpak-builder/cache/objects/0c/aec582e6f145e03885ee9a2ef25c47fe0cadbc27c1423f786a8b6d63fddc11.dirtree new file mode 100644 index 0000000..a98fc36 Binary files /dev/null and b/.flatpak-builder/cache/objects/0c/aec582e6f145e03885ee9a2ef25c47fe0cadbc27c1423f786a8b6d63fddc11.dirtree differ diff --git a/.flatpak-builder/cache/objects/0c/f0f76dd593eed9d5ef8dc8bd93f4071dcca7fc838a985ef2d200e249a9c3e0.file b/.flatpak-builder/cache/objects/0c/f0f76dd593eed9d5ef8dc8bd93f4071dcca7fc838a985ef2d200e249a9c3e0.file new file mode 100644 index 0000000..6336e91 Binary files /dev/null and b/.flatpak-builder/cache/objects/0c/f0f76dd593eed9d5ef8dc8bd93f4071dcca7fc838a985ef2d200e249a9c3e0.file differ diff --git a/.flatpak-builder/cache/objects/0d/0cd61d86b88027d22fc8c5bd6b0d09fffb8ad3445e3aa42b154a069c5d4cae.file b/.flatpak-builder/cache/objects/0d/0cd61d86b88027d22fc8c5bd6b0d09fffb8ad3445e3aa42b154a069c5d4cae.file new file mode 100644 index 0000000..5d8203a --- /dev/null +++ b/.flatpak-builder/cache/objects/0d/0cd61d86b88027d22fc8c5bd6b0d09fffb8ad3445e3aa42b154a069c5d4cae.file @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2005 - 2014 Vivien Malerba + * Copyright (C) 2006 - 2007 Murray Cumming + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GDA_BLOB_OP_IMPL_H__ +#define __GDA_BLOB_OP_IMPL_H__ + +#include +#include +#include +#include + +G_BEGIN_DECLS + + +/** + * GdaBlobOpFunctions: + */ +typedef struct { + /* Virtual methods */ + glong (* get_length) (GdaBlobOp *op); + glong (* read) (GdaBlobOp *op, GdaBlob *blob, glong offset, glong size); + glong (* write) (GdaBlobOp *op, GdaBlob *blob, glong offset); + gboolean (* write_all) (GdaBlobOp *op, GdaBlob *blob); +} GdaBlobOpFunctions; + +#define GDA_BLOB_OP_FUNCTIONS(x) ((GdaBlobOpFunctions*)(x)) + +G_END_DECLS + +#endif + diff --git a/.flatpak-builder/cache/objects/0d/1736214bad2cec525a021a624703f737215f3ace8cd0cba89fada551b62df4.file b/.flatpak-builder/cache/objects/0d/1736214bad2cec525a021a624703f737215f3ace8cd0cba89fada551b62df4.file new file mode 100644 index 0000000..22f7bbc --- /dev/null +++ b/.flatpak-builder/cache/objects/0d/1736214bad2cec525a021a624703f737215f3ace8cd0cba89fada551b62df4.file @@ -0,0 +1,377 @@ +/* + * Copyright (C) 2001 - 2002 Carlos Perelló Marín + * Copyright (C) 2001 - 2002 Rodrigo Moya + * Copyright (C) 2001 - 2012 Vivien Malerba + * Copyright (C) 2002 - 2003 Gonzalo Paniagua Javier + * Copyright (C) 2010 David King + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include +#include "gda-sqlite-util.h" +#include +#include +#include "gda-sqlite.h" +#include +#undef GDA_DISABLE_DEPRECATED +#include +#include "gda-sqlite-recordset.h" + +#include +#include "keywords_hash.code" /* this one is dynamically generated */ + +static guint +nocase_str_hash (gconstpointer v) +{ + guint ret; + gchar *up = g_ascii_strup ((gchar *) v, -1); + ret = g_str_hash ((gconstpointer) up); + g_free (up); + return ret; +} + +static gboolean +nocase_str_equal (gconstpointer v1, gconstpointer v2) +{ + return g_ascii_strcasecmp ((gchar *) v1, (gchar *) v2) == 0 ? TRUE : FALSE; +} + +void +_gda_sqlite_compute_types_hash (SqliteConnectionData *cdata) +{ + if (!cdata->types_hash) { + gint i; + GType type, *array; + GHashTable *hash; + cdata->types_hash = g_hash_table_new (nocase_str_hash, nocase_str_equal); + hash = cdata->types_hash; +#define NB_DECLARED_G_TYPES 14 + cdata->types_array = g_new (GType, NB_DECLARED_G_TYPES); + array = cdata->types_array; + + type = G_TYPE_INT; + i = 0; + array [i] = type; + g_hash_table_insert (hash, "integer", array + i); + g_hash_table_insert (hash, "int", array + i); + + type = G_TYPE_UINT; + i++; + array [i] = type; + g_hash_table_insert (hash, "unsigned integer", array + i); + g_hash_table_insert (hash, "unsigned int", array + i); + g_hash_table_insert (hash, "uint", array + i); + + type = G_TYPE_BOOLEAN; + i++; + array [i] = type; + g_hash_table_insert (hash, "boolean", array + i); + + type = G_TYPE_DATE; + i++; + array [i] = type; + g_hash_table_insert (hash, "date", array + i); + + type = GDA_TYPE_TIME; + i++; + array [i] = type; + g_hash_table_insert (hash, "time", array + i); + + type = G_TYPE_DATE_TIME; + i++; + array [i] = type; + g_hash_table_insert (hash, "timestamp", array + i); + + type = G_TYPE_DOUBLE; + i++; + array [i] = type; + g_hash_table_insert (hash, "real", array + i); + + type = G_TYPE_STRING; + i++; + array [i] = type; + g_hash_table_insert (hash, "text", array + i); + g_hash_table_insert (hash, "string", array + i); + g_hash_table_insert (hash, "varchar", array + i); + + type = GDA_TYPE_BINARY; + i++; + array [i] = type; + g_hash_table_insert (hash, "binary", array + i); + + type = GDA_TYPE_BLOB; + i++; + array [i] = type; + g_hash_table_insert (hash, "blob", array + i); + + type = G_TYPE_INT64; + i++; + array [i] = type; + g_hash_table_insert (hash, "int64", array + i); + g_hash_table_insert (hash, "bigint", array + i); + + type = G_TYPE_UINT64; + i++; + array [i] = type; + g_hash_table_insert (hash, "uint64", array + i); + + type = GDA_TYPE_SHORT; + i++; + array [i] = type; + g_hash_table_insert (hash, "short", array + i); + + type = GDA_TYPE_USHORT; + i++; + array [i] = type; + g_hash_table_insert (hash, "ushort", array + i); + g_hash_table_insert (hash, "unsigned short", array + i); + g_assert (i < NB_DECLARED_G_TYPES); + } +} + +GType +_gda_sqlite_compute_g_type (int sqlite_type) +{ + switch (sqlite_type) { + case SQLITE_INTEGER: + return G_TYPE_INT; + case SQLITE_FLOAT: + return G_TYPE_DOUBLE; + case 0: + case SQLITE_TEXT: + return G_TYPE_STRING; + case SQLITE_BLOB: + return GDA_TYPE_BLOB; + case SQLITE_NULL: + return GDA_TYPE_NULL; + default: + g_warning ("Unknown SQLite internal data type %d", sqlite_type); + return G_TYPE_STRING; + } +} + + + +GdaSqlReservedKeywordsFunc +_gda_sqlite_get_reserved_keyword_func (void) +{ +#ifdef GDA_DEBUG + test_keywords (); +#endif + return is_keyword; +} + +static gchar * +identifier_add_quotes (const gchar *str) +{ + gchar *retval, *rptr; + const gchar *sptr; + gint len; + + if (!str) + return NULL; + + len = strlen (str); + retval = g_new (gchar, 2*len + 3); + *retval = '"'; + for (rptr = retval+1, sptr = str; *sptr; sptr++, rptr++) { + if (*sptr == '"') { + *rptr = '"'; + rptr++; + *rptr = *sptr; + } + else + *rptr = *sptr; + } + *rptr = '"'; + rptr++; + *rptr = 0; + return retval; +} + +static gboolean +_sql_identifier_needs_quotes (const gchar *str) +{ + const gchar *ptr; + + g_return_val_if_fail (str, FALSE); + for (ptr = str; *ptr; ptr++) { + /* quote if 1st char is a number */ + if ((*ptr <= '9') && (*ptr >= '0')) { + if (ptr == str) + return TRUE; + continue; + } + if (((*ptr >= 'A') && (*ptr <= 'Z')) || + ((*ptr >= 'a') && (*ptr <= 'z'))) + continue; + + if ((*ptr != '$') && (*ptr != '_') && (*ptr != '#')) + return TRUE; + } + return FALSE; +} + +/* Returns: @str */ +static gchar * +sqlite_remove_quotes (gchar *str) +{ + glong total; + gchar *ptr; + glong offset = 0; + char delim; + + if (!str) + return NULL; + delim = *str; + if ((delim != '[') && (delim != '"') && (delim != '\'') && (delim != '`')) + return str; + + total = strlen (str); + if ((str[total-1] == delim) || ((delim == '[') && (str[total-1] == ']'))) { + /* string is correctly terminated */ + memmove (str, str+1, total-2); + total -=2; + } + else { + /* string is _not_ correctly terminated */ + memmove (str, str+1, total-1); + total -=1; + } + str[total] = 0; + + if ((delim == '"') || (delim == '\'')) { + ptr = (gchar *) str; + while (offset < total) { + /* we accept the "''" as a synonym of "\'" */ + if (*ptr == delim) { + if (*(ptr+1) == delim) { + memmove (ptr+1, ptr+2, total - offset); + offset += 2; + } + else { + *str = 0; + return str; + } + } + else if (*ptr == '"') { + if (*(ptr+1) == '"') { + memmove (ptr+1, ptr+2, total - offset); + offset += 2; + } + else { + *str = 0; + return str; + } + } + else if (*ptr == '\\') { + if (*(ptr+1) == '\\') { + memmove (ptr+1, ptr+2, total - offset); + offset += 2; + } + else { + if (*(ptr+1) == delim) { + *ptr = delim; + memmove (ptr+1, ptr+2, total - offset); + offset += 2; + } + else { + *str = 0; + return str; + } + } + } + else + offset ++; + + ptr++; + } + } + + return str; +} + +gchar * +_gda_sqlite_identifier_quote (G_GNUC_UNUSED GdaServerProvider *provider, GdaConnection *cnc, + const gchar *id, + gboolean for_meta_store, gboolean force_quotes) +{ + GdaSqlReservedKeywordsFunc kwfunc; + kwfunc = _gda_sqlite_get_reserved_keyword_func (); + + if (for_meta_store) { + gchar *tmp, *ptr; + tmp = sqlite_remove_quotes (g_strdup (id)); + if (kwfunc (tmp)) { + ptr = gda_sql_identifier_force_quotes (tmp); + g_free (tmp); + return ptr; + } + else { + /* if only alphanum => don't quote */ + for (ptr = tmp; *ptr; ptr++) { + if ((*ptr >= 'A') && (*ptr <= 'Z')) + *ptr += 'a' - 'A'; + if (((*ptr >= 'a') && (*ptr <= 'z')) || + ((*ptr >= '0') && (*ptr <= '9') && (ptr != tmp)) || + (*ptr >= '_')) + continue; + else { + ptr = gda_sql_identifier_force_quotes (tmp); + g_free (tmp); + return ptr; + } + } + return tmp; + } + } + else { + if (*id == '"') { + /* there are already some quotes */ + return g_strdup (id); + } + else if ((*id == '[') || (*id == '`')) { + /* there are already some quotes */ + gchar *tmp, *ptr; + tmp = sqlite_remove_quotes (g_strdup (id)); + ptr = gda_sql_identifier_force_quotes (tmp); + g_free (tmp); + return ptr; + } + if (kwfunc (id) || _sql_identifier_needs_quotes (id) || force_quotes) + return identifier_add_quotes (id); + + /* nothing to do */ + return g_strdup (id); + } +} + +gboolean +_gda_sqlite_check_transaction_started (GdaConnection *cnc, gboolean *out_started, GError **error) +{ + GdaTransactionStatus *trans; + + trans = gda_connection_get_transaction_status (cnc); + if (!trans) { + if (!gda_connection_begin_transaction (cnc, NULL, + GDA_TRANSACTION_ISOLATION_UNKNOWN, error)) + return FALSE; + else + *out_started = TRUE; + } + return TRUE; +} diff --git a/.flatpak-builder/cache/objects/0d/47fd2260ca67fa0856af12787ffe891156d7f67406a9dd093388e231d62368.file b/.flatpak-builder/cache/objects/0d/47fd2260ca67fa0856af12787ffe891156d7f67406a9dd093388e231d62368.file new file mode 100644 index 0000000..c7dbc24 Binary files /dev/null and b/.flatpak-builder/cache/objects/0d/47fd2260ca67fa0856af12787ffe891156d7f67406a9dd093388e231d62368.file differ diff --git a/.flatpak-builder/cache/objects/0e/0a8444cb829241598ffeb2c2488812aecf4bbc7102e140e650be94198d9d77.dirtree b/.flatpak-builder/cache/objects/0e/0a8444cb829241598ffeb2c2488812aecf4bbc7102e140e650be94198d9d77.dirtree new file mode 100644 index 0000000..15cab1b Binary files /dev/null and b/.flatpak-builder/cache/objects/0e/0a8444cb829241598ffeb2c2488812aecf4bbc7102e140e650be94198d9d77.dirtree differ diff --git a/.flatpak-builder/cache/objects/0e/6514edd67b43765a825ae93d1afdf4541d02cfc87b16b51e57c4cf540739a4.file b/.flatpak-builder/cache/objects/0e/6514edd67b43765a825ae93d1afdf4541d02cfc87b16b51e57c4cf540739a4.file new file mode 100755 index 0000000..02461a7 Binary files /dev/null and b/.flatpak-builder/cache/objects/0e/6514edd67b43765a825ae93d1afdf4541d02cfc87b16b51e57c4cf540739a4.file differ diff --git a/.flatpak-builder/cache/objects/0e/a33ce048b315e8b44ff7738dfa4e3fbb35bac33293485db49eb9da45b0be2d.dirtree b/.flatpak-builder/cache/objects/0e/a33ce048b315e8b44ff7738dfa4e3fbb35bac33293485db49eb9da45b0be2d.dirtree new file mode 100644 index 0000000..b3832f8 Binary files /dev/null and b/.flatpak-builder/cache/objects/0e/a33ce048b315e8b44ff7738dfa4e3fbb35bac33293485db49eb9da45b0be2d.dirtree differ diff --git a/.flatpak-builder/cache/objects/0f/06378a8004b4756cab1b7b16317f9cad2a58d244aa5902d531600f5ad92d84.dirtree b/.flatpak-builder/cache/objects/0f/06378a8004b4756cab1b7b16317f9cad2a58d244aa5902d531600f5ad92d84.dirtree new file mode 100644 index 0000000..b82ada2 Binary files /dev/null and b/.flatpak-builder/cache/objects/0f/06378a8004b4756cab1b7b16317f9cad2a58d244aa5902d531600f5ad92d84.dirtree differ diff --git a/.flatpak-builder/cache/objects/0f/259da148fc25760fb65df46b50374ae4f10168d2c8cfad898e1da443252ea4.dirtree b/.flatpak-builder/cache/objects/0f/259da148fc25760fb65df46b50374ae4f10168d2c8cfad898e1da443252ea4.dirtree new file mode 100644 index 0000000..bc45188 Binary files /dev/null and b/.flatpak-builder/cache/objects/0f/259da148fc25760fb65df46b50374ae4f10168d2c8cfad898e1da443252ea4.dirtree differ diff --git a/.flatpak-builder/cache/objects/0f/b7edd8252bfdd09c6b47b89e00fb40267843ca27cc9af2d053024994786c45.dirtree b/.flatpak-builder/cache/objects/0f/b7edd8252bfdd09c6b47b89e00fb40267843ca27cc9af2d053024994786c45.dirtree new file mode 100644 index 0000000..e6aab35 Binary files /dev/null and b/.flatpak-builder/cache/objects/0f/b7edd8252bfdd09c6b47b89e00fb40267843ca27cc9af2d053024994786c45.dirtree differ diff --git a/.flatpak-builder/cache/objects/0f/ef5c2f1f682bf248196044e4c8be393efd7c4654559d36a27bbd251324560a.dirtree b/.flatpak-builder/cache/objects/0f/ef5c2f1f682bf248196044e4c8be393efd7c4654559d36a27bbd251324560a.dirtree new file mode 100644 index 0000000..618c7ff Binary files /dev/null and b/.flatpak-builder/cache/objects/0f/ef5c2f1f682bf248196044e4c8be393efd7c4654559d36a27bbd251324560a.dirtree differ diff --git a/.flatpak-builder/cache/objects/0f/f9111ba3bb0682b60da90f4afbf99ec11a9f8ec0fddc12797b7c3c07fc599b.file b/.flatpak-builder/cache/objects/0f/f9111ba3bb0682b60da90f4afbf99ec11a9f8ec0fddc12797b7c3c07fc599b.file new file mode 100644 index 0000000..8ded843 --- /dev/null +++ b/.flatpak-builder/cache/objects/0f/f9111ba3bb0682b60da90f4afbf99ec11a9f8ec0fddc12797b7c3c07fc599b.file @@ -0,0 +1,109 @@ +// All token codes are small integers with #defines that begin with "TK_" +%token_prefix D_ + +// The type of the data attached to each token is GValue. This is also the +// default type for non-terminals. +// +%token_type {GValue *} +%default_type {GValue *} +%token_destructor {if ($$) { +#ifdef GDA_DEBUG_NO + gchar *str = gda_sql_value_stringify ($$); + g_print ("___ token destructor /%s/\n", str) + g_free (str); +#endif + g_value_unset ($$); g_free ($$);}} + +// The generated parser function takes a 4th argument as follows: +%extra_argument {GdaSqlParserIface *pdata} + +// This code runs whenever there is a syntax error +// +%syntax_error { + gda_sql_parser_set_syntax_error (pdata->parser); +} +%stack_overflow { + gda_sql_parser_set_overflow_error (pdata->parser); +} + +// The name of the generated procedure that implements the parser +// is as follows: +%name priv_gda_sql_delimiter + +// The following text is included near the beginning of the C source +// code file that implements the parser. +// +%include { +#include +#include +#include +#include +#include +#include +#include +#include +#include +} + +// The following directive causes tokens to +// fallback to RAWSTRING if they will not parse as their original value. +// However in this particular case, it serves to declare the LOOP,... tokens used by the +// GdaSqlParser object +%fallback RAWSTRING LOOP ENDLOOP DECLARE CREATE BLOB. + +// force the declaration of the ILLEGAL and SQLCOMMENT tokens +%nonassoc ILLEGAL. +%nonassoc SQLCOMMENT. + +// Input is a single SQL command +// A single statement +%type stmt {GdaSqlStatement *} +%destructor stmt {g_print ("Statement destroyed by parser: %p\n", $$); gda_sql_statement_free ($$);} +stmt ::= exprlist(L) SEMI. {pdata->parsed_statement = gda_sql_statement_new (GDA_SQL_STATEMENT_UNKNOWN); + /* FIXME: set SQL */ + gda_sql_statement_unknown_take_expressions (pdata->parsed_statement, g_slist_reverse (L)); +} +stmt ::= exprlist(L) END_OF_FILE. {pdata->parsed_statement = gda_sql_statement_new (GDA_SQL_STATEMENT_UNKNOWN); + /* FIXME: set SQL */ + gda_sql_statement_unknown_take_expressions (pdata->parsed_statement, g_slist_reverse (L)); +} + +// List of expressions +%type exprlist {GSList *} +%destructor exprlist {if ($$) {g_slist_free_full ($$, (GDestroyNotify) gda_sql_expr_free);}} +exprlist(L) ::= exprlist(E) expr(X). {L = g_slist_prepend (E, X);} +exprlist(L) ::= expr(E). {L = g_slist_append (NULL, E);} + +// A single expression +%type expr {GdaSqlExpr *} +%destructor expr {gda_sql_expr_free ($$);} +expr(E) ::= pvalue(V). {E = V;} +expr(E) ::= RAWSTRING(R). {E = gda_sql_expr_new (NULL); E->value = R;} +expr(E) ::= SPACE(S). {E =gda_sql_expr_new (NULL); E->value = S;} +expr(E) ::= value(V). {E =gda_sql_expr_new (NULL); E->value = V;} + +// Values: for all constants (G_TYPE_STRING GValue) +value(V) ::= STRING(S). {V = S;} +value(V) ::= TEXTUAL(T). {V = T;} +value(V) ::= INTEGER(I). {V = I;} +value(V) ::= FLOAT(F). {V = F;} + +// pvalue: values which are parameters (GdaSqlExpr) +%type pvalue {GdaSqlExpr *} +%destructor pvalue {gda_sql_expr_free ($$);} +pvalue(E) ::= UNSPECVAL LSBRACKET paramspec(P) RSBRACKET. {E = gda_sql_expr_new (NULL); E->param_spec = P;} +pvalue(E) ::= value(V) LSBRACKET paramspec(P) RSBRACKET. {E = gda_sql_expr_new (NULL); E->value = V; E->param_spec = P;} +pvalue(E) ::= SIMPLEPARAM(S). {E = gda_sql_expr_new (NULL); E->param_spec = gda_sql_param_spec_new (S);} + +// paramspec: parameter's specifications +%type paramspec {GdaSqlParamSpec *} +%destructor paramspec {gda_sql_param_spec_free ($$);} +paramspec(P) ::= . {P = NULL;} +paramspec(P) ::= paramspec(E) PNAME(N). {if (!E) P = gda_sql_param_spec_new (NULL); else P = E; + gda_sql_param_spec_take_name (P, N);} +paramspec(P) ::= paramspec(E) PDESCR(N). {if (!E) P = gda_sql_param_spec_new (NULL); else P = E; + gda_sql_param_spec_take_descr (P, N);} +paramspec(P) ::= paramspec(E) PTYPE(N). {if (!E) P = gda_sql_param_spec_new (NULL); else P = E; + gda_sql_param_spec_take_type (P, N);} +paramspec(P) ::= paramspec(E) PNULLOK(N). {if (!E) P = gda_sql_param_spec_new (NULL); else P = E; + gda_sql_param_spec_take_nullok (P, N);} diff --git a/.flatpak-builder/cache/objects/10/08a91a488ba3c7ea0f69450430301bd1fbfd44b5a813175901c28f34628ed9.file b/.flatpak-builder/cache/objects/10/08a91a488ba3c7ea0f69450430301bd1fbfd44b5a813175901c28f34628ed9.file new file mode 100644 index 0000000..8a57f7f --- /dev/null +++ b/.flatpak-builder/cache/objects/10/08a91a488ba3c7ea0f69450430301bd1fbfd44b5a813175901c28f34628ed9.file @@ -0,0 +1,1136 @@ +/* Driver template for the LEMON parser generator. +** The author disclaims copyright to this source code. +*/ +/* First off, code is included that follows the "include" declaration +** in the input grammar file. */ +#include +#line 36 "../libgda/sql-parser/delimiter.y" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#line 19 "/run/build/libgda/_flatpak_build/libgda/sql-parser/delimiter.c" +/* Next is all token values, in a form suitable for use by makeheaders. +** This section will be null unless lemon is run with the -m switch. +*/ +/* +** These constants (all generated automatically by the parser generator) +** specify the various kinds of tokens (terminals) that the parser +** understands. +** +** Each symbol here is a terminal symbol in the grammar. +*/ +/* Make sure the INTERFACE macro is defined. +*/ +#ifndef INTERFACE +# define INTERFACE 1 +#endif +/* The next thing included is series of defines which control +** various aspects of the generated parser. +** YYCODETYPE is the data type used for storing terminal +** and nonterminal numbers. "unsigned char" is +** used if there are fewer than 250 terminals +** and nonterminals. "int" is used otherwise. +** YYNOCODE is a number of type YYCODETYPE which corresponds +** to no legal terminal or nonterminal number. This +** number is used to fill in empty slots of the hash +** table. +** YYFALLBACK If defined, this indicates that one or more tokens +** have fall-back values which should be used if the +** original value of the token will not parse. +** YYACTIONTYPE is the data type used for storing terminal +** and nonterminal numbers. "unsigned char" is +** used if there are fewer than 250 rules and +** states combined. "int" is used otherwise. +** priv_gda_sql_delimiterTOKENTYPE is the data type used for minor tokens given +** directly to the parser from the tokenizer. +** YYMINORTYPE is the data type used for all minor tokens. +** This is typically a union of many types, one of +** which is priv_gda_sql_delimiterTOKENTYPE. The entry in the union +** for base tokens is called "yy0". +** YYSTACKDEPTH is the maximum depth of the parser's stack. If +** zero the stack is dynamically sized using realloc() +** priv_gda_sql_delimiterARG_SDECL A static variable declaration for the %extra_argument +** priv_gda_sql_delimiterARG_PDECL A parameter declaration for the %extra_argument +** priv_gda_sql_delimiterARG_STORE Code to store %extra_argument into yypParser +** priv_gda_sql_delimiterARG_FETCH Code to extract %extra_argument from yypParser +** YYNSTATE the combined number of states. +** YYNRULE the number of rules in the grammar +** YYERRORSYMBOL is the code number of the error symbol. If not +** defined, then do no error processing. +*/ +#define YYCODETYPE unsigned char +#define YYNOCODE 32 +#define YYACTIONTYPE unsigned char +#define priv_gda_sql_delimiterTOKENTYPE GValue * +typedef union { + int yyinit; + priv_gda_sql_delimiterTOKENTYPE yy0; + GdaSqlParamSpec * yy3; + GSList * yy27; + GdaSqlStatement * yy28; + GdaSqlExpr * yy54; +} YYMINORTYPE; +#ifndef YYSTACKDEPTH +#define YYSTACKDEPTH 100 +#endif +#define priv_gda_sql_delimiterARG_SDECL GdaSqlParserIface *pdata; +#define priv_gda_sql_delimiterARG_PDECL ,GdaSqlParserIface *pdata +#define priv_gda_sql_delimiterARG_FETCH GdaSqlParserIface *pdata = yypParser->pdata +#define priv_gda_sql_delimiterARG_STORE yypParser->pdata = pdata +#define YYNSTATE 26 +#define YYNRULE 20 +#define YYFALLBACK 1 +#define YY_NO_ACTION (YYNSTATE+YYNRULE+2) +#define YY_ACCEPT_ACTION (YYNSTATE+YYNRULE+1) +#define YY_ERROR_ACTION (YYNSTATE+YYNRULE) + +/* The yyzerominor constant is used to initialize instances of +** YYMINORTYPE objects to zero. */ +static const YYMINORTYPE yyzerominor = { 0 }; + +/* Define the yytestcase() macro to be a no-op if is not already defined +** otherwise. +** +** Applications can choose to define yytestcase() in the %include section +** to a macro that can assist in verifying code coverage. For production +** code the yytestcase() macro should be turned off. But it is useful +** for testing. +*/ +#ifndef yytestcase +# define yytestcase(X) +#endif + + +/* Next are the tables used to determine what action to take based on the +** current state and lookahead token. These tables are used to implement +** functions that take a state number and lookahead value and return an +** action integer. +** +** Suppose the action integer is N. Then the action is determined as +** follows +** +** 0 <= N < YYNSTATE Shift N. That is, push the lookahead +** token onto the stack and goto state N. +** +** YYNSTATE <= N < YYNSTATE+YYNRULE Reduce by rule N-YYNSTATE. +** +** N == YYNSTATE+YYNRULE A syntax error has occurred. +** +** N == YYNSTATE+YYNRULE+1 The parser accepts its input. +** +** N == YYNSTATE+YYNRULE+2 No such action. Denotes unused +** slots in the yy_action[] table. +** +** The action table is constructed as a single large table named yy_action[]. +** Given state S and lookahead X, the action is computed as +** +** yy_action[ yy_shift_ofst[S] + X ] +** +** If the index value yy_shift_ofst[S]+X is out of range or if the value +** yy_lookahead[yy_shift_ofst[S]+X] is not equal to X or if yy_shift_ofst[S] +** is equal to YY_SHIFT_USE_DFLT, it means that the action is not in the table +** and that yy_default[S] should be used instead. +** +** The formula above is for computing the action when the lookahead is +** a terminal symbol. If the lookahead is a non-terminal (as occurs after +** a reduce action) then the yy_reduce_ofst[] array is used in place of +** the yy_shift_ofst[] array and YY_REDUCE_USE_DFLT is used in place of +** YY_SHIFT_USE_DFLT. +** +** The following are the tables generated in this section: +** +** yy_action[] A single table containing all actions. +** yy_lookahead[] A table containing the lookahead for each entry in +** yy_action. Used to detect hash collisions. +** yy_shift_ofst[] For each state, the offset into yy_action for +** shifting terminals. +** yy_reduce_ofst[] For each state, the offset into yy_action for +** shifting non-terminals after a reduce. +** yy_default[] Default action for each state. +*/ +#define YY_ACTTAB_COUNT (45) +static const YYACTIONTYPE yy_action[] = { + /* 0 */ 23, 21, 26, 20, 19, 18, 17, 27, 9, 8, + /* 10 */ 22, 16, 15, 14, 13, 6, 23, 3, 11, 12, + /* 20 */ 2, 20, 19, 18, 17, 5, 22, 16, 15, 14, + /* 30 */ 13, 6, 48, 48, 11, 47, 1, 10, 24, 7, + /* 40 */ 25, 24, 7, 48, 4, +}; +static const YYCODETYPE yy_lookahead[] = { + /* 0 */ 1, 18, 0, 20, 21, 22, 23, 0, 9, 10, + /* 10 */ 11, 12, 13, 14, 15, 16, 1, 17, 19, 18, + /* 20 */ 17, 20, 21, 22, 23, 30, 11, 12, 13, 14, + /* 30 */ 15, 16, 31, 31, 19, 25, 26, 27, 28, 29, + /* 40 */ 27, 28, 29, 31, 30, +}; +#define YY_SHIFT_USE_DFLT (-18) +#define YY_SHIFT_COUNT (9) +#define YY_SHIFT_MIN (-17) +#define YY_SHIFT_MAX (15) +static const signed char yy_shift_ofst[] = { + /* 0 */ 15, -1, -18, -18, 1, -17, 3, 0, 7, 2, +}; +#define YY_REDUCE_USE_DFLT (-6) +#define YY_REDUCE_COUNT (3) +#define YY_REDUCE_MIN (-5) +#define YY_REDUCE_MAX (14) +static const signed char yy_reduce_ofst[] = { + /* 0 */ 10, 13, 14, -5, +}; +static const YYACTIONTYPE yy_default[] = { + /* 0 */ 46, 46, 41, 41, 46, 46, 46, 33, 46, 46, + /* 10 */ 29, 40, 38, 37, 36, 35, 34, 45, 44, 43, + /* 20 */ 42, 39, 32, 31, 30, 28, +}; + +/* The next table maps tokens into fallback tokens. If a construct +** like the following: +** +** %fallback ID X Y Z. +** +** appears in the grammar, then ID becomes a fallback token for X, Y, +** and Z. Whenever one of the tokens X, Y, or Z is input to the parser +** but it does not parse, the type of the token is changed to ID and +** the parse is retried before an error is thrown. +*/ +#ifdef YYFALLBACK +static const YYCODETYPE yyFallback[] = { + 0, /* $ => nothing */ + 0, /* RAWSTRING => nothing */ + 1, /* LOOP => RAWSTRING */ + 1, /* ENDLOOP => RAWSTRING */ + 1, /* DECLARE => RAWSTRING */ + 1, /* CREATE => RAWSTRING */ + 1, /* BLOB => RAWSTRING */ +}; +#endif /* YYFALLBACK */ + +/* The following structure represents a single element of the +** parser's stack. Information stored includes: +** +** + The state number for the parser at this level of the stack. +** +** + The value of the token stored at this level of the stack. +** (In other words, the "major" token.) +** +** + The semantic value stored at this level of the stack. This is +** the information used by the action routines in the grammar. +** It is sometimes called the "minor" token. +*/ +struct yyStackEntry { + YYACTIONTYPE stateno; /* The state-number */ + YYCODETYPE major; /* The major token value. This is the code + ** number for the token at this stack level */ + YYMINORTYPE minor; /* The user-supplied minor token value. This + ** is the value of the token */ +}; +typedef struct yyStackEntry yyStackEntry; + +/* The state of the parser is completely contained in an instance of +** the following structure */ +struct yyParser { + int yyidx; /* Index of top element in stack */ +#ifdef YYTRACKMAXSTACKDEPTH + int yyidxMax; /* Maximum value of yyidx */ +#endif + int yyerrcnt; /* Shifts left before out of the error */ + priv_gda_sql_delimiterARG_SDECL /* A place to hold %extra_argument */ +#if YYSTACKDEPTH<=0 + int yystksz; /* Current side of the stack */ + yyStackEntry *yystack; /* The parser's stack */ +#else + yyStackEntry yystack[YYSTACKDEPTH]; /* The parser's stack */ +#endif +}; +typedef struct yyParser yyParser; + +#ifndef NDEBUG +#include +static FILE *yyTraceFILE = 0; +static char *yyTracePrompt = 0; +#endif /* NDEBUG */ + +#ifndef NDEBUG +/* +** Turn parser tracing on by giving a stream to which to write the trace +** and a prompt to preface each trace message. Tracing is turned off +** by making either argument NULL +** +** Inputs: +**
    +**
  • A FILE* to which trace output should be written. +** If NULL, then tracing is turned off. +**
  • A prefix string written at the beginning of every +** line of trace output. If NULL, then tracing is +** turned off. +**
+** +** Outputs: +** None. +*/ +void priv_gda_sql_delimiterTrace(FILE *TraceFILE, char *zTracePrompt){ + yyTraceFILE = TraceFILE; + yyTracePrompt = zTracePrompt; + if( yyTraceFILE==0 ) yyTracePrompt = 0; + else if( yyTracePrompt==0 ) yyTraceFILE = 0; +} +#endif /* NDEBUG */ + +#ifndef NDEBUG +/* For tracing shifts, the names of all terminals and nonterminals +** are required. The following table supplies these names */ +static const char *const yyTokenName[] = { + "$", "RAWSTRING", "LOOP", "ENDLOOP", + "DECLARE", "CREATE", "BLOB", "ILLEGAL", + "SQLCOMMENT", "SEMI", "END_OF_FILE", "SPACE", + "STRING", "TEXTUAL", "INTEGER", "FLOAT", + "UNSPECVAL", "LSBRACKET", "RSBRACKET", "SIMPLEPARAM", + "PNAME", "PDESCR", "PTYPE", "PNULLOK", + "error", "stmt", "exprlist", "expr", + "pvalue", "value", "paramspec", +}; +#endif /* NDEBUG */ + +#ifndef NDEBUG +/* For tracing reduce actions, the names of all rules are required. +*/ +static const char *const yyRuleName[] = { + /* 0 */ "stmt ::= exprlist SEMI", + /* 1 */ "stmt ::= exprlist END_OF_FILE", + /* 2 */ "exprlist ::= exprlist expr", + /* 3 */ "exprlist ::= expr", + /* 4 */ "expr ::= pvalue", + /* 5 */ "expr ::= RAWSTRING", + /* 6 */ "expr ::= SPACE", + /* 7 */ "expr ::= value", + /* 8 */ "value ::= STRING", + /* 9 */ "value ::= TEXTUAL", + /* 10 */ "value ::= INTEGER", + /* 11 */ "value ::= FLOAT", + /* 12 */ "pvalue ::= UNSPECVAL LSBRACKET paramspec RSBRACKET", + /* 13 */ "pvalue ::= value LSBRACKET paramspec RSBRACKET", + /* 14 */ "pvalue ::= SIMPLEPARAM", + /* 15 */ "paramspec ::=", + /* 16 */ "paramspec ::= paramspec PNAME", + /* 17 */ "paramspec ::= paramspec PDESCR", + /* 18 */ "paramspec ::= paramspec PTYPE", + /* 19 */ "paramspec ::= paramspec PNULLOK", +}; +#endif /* NDEBUG */ + + +#if YYSTACKDEPTH<=0 +/* +** Try to increase the size of the parser stack. +*/ +static void yyGrowStack(yyParser *p){ + int newSize; + yyStackEntry *pNew; + + newSize = p->yystksz*2 + 100; + pNew = realloc(p->yystack, newSize*sizeof(pNew[0])); + if( pNew ){ + p->yystack = pNew; + p->yystksz = newSize; +#ifndef NDEBUG + if( yyTraceFILE ){ + fprintf(yyTraceFILE,"%sStack grows to %d entries!\n", + yyTracePrompt, p->yystksz); + } +#endif + } +} +#endif + +/* +** This function allocates a new parser. +** The only argument is a pointer to a function which works like +** malloc. +** +** Inputs: +** A pointer to the function used to allocate memory. +** +** Outputs: +** A pointer to a parser. This pointer is used in subsequent calls +** to priv_gda_sql_delimiter and priv_gda_sql_delimiterFree. +*/ +void *priv_gda_sql_delimiterAlloc(void *(*mallocProc)(size_t)){ + yyParser *pParser; + pParser = (yyParser*)(*mallocProc)( (size_t)sizeof(yyParser) ); + if( pParser ){ + pParser->yyidx = -1; +#ifdef YYTRACKMAXSTACKDEPTH + pParser->yyidxMax = 0; +#endif +#if YYSTACKDEPTH<=0 + pParser->yystack = NULL; + pParser->yystksz = 0; + yyGrowStack(pParser); +#endif + } + return pParser; +} + +/* The following function deletes the value associated with a +** symbol. The symbol can be either a terminal or nonterminal. +** "yymajor" is the symbol code, and "yypminor" is a pointer to +** the value. +*/ +static void yy_destructor( + yyParser *yypParser, /* The parser */ + YYCODETYPE yymajor, /* Type code for object to destroy */ + YYMINORTYPE *yypminor /* The object to be destroyed */ +){ + priv_gda_sql_delimiterARG_FETCH; + switch( yymajor ){ + /* Here is inserted the actions which take place when a + ** terminal or non-terminal is destroyed. This can happen + ** when the symbol is popped from the stack during a + ** reduce or during error processing or when a parser is + ** being destroyed before it is finished parsing. + ** + ** Note: during a reduce, the only symbols destroyed are those + ** which appear on the RHS of the rule, but which are not used + ** inside the C code. + */ + /* TERMINAL Destructor */ + case 1: /* RAWSTRING */ + case 2: /* LOOP */ + case 3: /* ENDLOOP */ + case 4: /* DECLARE */ + case 5: /* CREATE */ + case 6: /* BLOB */ + case 7: /* ILLEGAL */ + case 8: /* SQLCOMMENT */ + case 9: /* SEMI */ + case 10: /* END_OF_FILE */ + case 11: /* SPACE */ + case 12: /* STRING */ + case 13: /* TEXTUAL */ + case 14: /* INTEGER */ + case 15: /* FLOAT */ + case 16: /* UNSPECVAL */ + case 17: /* LSBRACKET */ + case 18: /* RSBRACKET */ + case 19: /* SIMPLEPARAM */ + case 20: /* PNAME */ + case 21: /* PDESCR */ + case 22: /* PTYPE */ + case 23: /* PNULLOK */ +{ +#line 9 "../libgda/sql-parser/delimiter.y" +if ((yypminor->yy0)) { +#ifdef GDA_DEBUG_NO + gchar *str = gda_sql_value_stringify ((yypminor->yy0)); + g_print ("___ token destructor /%s/\n", str) + g_free (str); +#endif + g_value_unset ((yypminor->yy0)); g_free ((yypminor->yy0));} +#line 437 "/run/build/libgda/_flatpak_build/libgda/sql-parser/delimiter.c" +} + break; + case 25: /* stmt */ +{ +#line 61 "../libgda/sql-parser/delimiter.y" +g_print ("Statement destroyed by parser: %p\n", (yypminor->yy28)); gda_sql_statement_free ((yypminor->yy28)); +#line 444 "/run/build/libgda/_flatpak_build/libgda/sql-parser/delimiter.c" +} + break; + case 26: /* exprlist */ +{ +#line 73 "../libgda/sql-parser/delimiter.y" +if ((yypminor->yy27)) {g_slist_free_full ((yypminor->yy27), (GDestroyNotify) gda_sql_expr_free);} +#line 451 "/run/build/libgda/_flatpak_build/libgda/sql-parser/delimiter.c" +} + break; + case 27: /* expr */ + case 28: /* pvalue */ +{ +#line 79 "../libgda/sql-parser/delimiter.y" +gda_sql_expr_free ((yypminor->yy54)); +#line 459 "/run/build/libgda/_flatpak_build/libgda/sql-parser/delimiter.c" +} + break; + case 30: /* paramspec */ +{ +#line 100 "../libgda/sql-parser/delimiter.y" +gda_sql_param_spec_free ((yypminor->yy3)); +#line 466 "/run/build/libgda/_flatpak_build/libgda/sql-parser/delimiter.c" +} + break; + default: break; /* If no destructor action specified: do nothing */ + } +} + +/* +** Pop the parser's stack once. +** +** If there is a destructor routine associated with the token which +** is popped from the stack, then call it. +** +** Return the major token number for the symbol popped. +*/ +static int yy_pop_parser_stack(yyParser *pParser){ + YYCODETYPE yymajor; + yyStackEntry *yytos; + + if( pParser->yyidx<0 ) return 0; + yytos = &pParser->yystack[pParser->yyidx]; +#ifndef NDEBUG + if( yyTraceFILE && pParser->yyidx>=0 ){ + fprintf(yyTraceFILE,"%sPopping %s\n", + yyTracePrompt, + yyTokenName[yytos->major]); + } +#endif + yymajor = yytos->major; + yy_destructor(pParser, yymajor, &yytos->minor); + pParser->yyidx--; + return yymajor; +} + +/* +** Deallocate and destroy a parser. Destructors are all called for +** all stack elements before shutting the parser down. +** +** Inputs: +**
    +**
  • A pointer to the parser. This should be a pointer +** obtained from priv_gda_sql_delimiterAlloc. +**
  • A pointer to a function used to reclaim memory obtained +** from malloc. +**
+*/ +void priv_gda_sql_delimiterFree( + void *p, /* The parser to be deleted */ + void (*freeProc)(void*) /* Function used to reclaim memory */ +){ + yyParser *pParser = (yyParser*)p; + if( pParser==0 ) return; + while( pParser->yyidx>=0 ) yy_pop_parser_stack(pParser); +#if YYSTACKDEPTH<=0 + free(pParser->yystack); +#endif + (*freeProc)((void*)pParser); +} + +/* +** Return the peak depth of the stack for a parser. +*/ +#ifdef YYTRACKMAXSTACKDEPTH +int priv_gda_sql_delimiterStackPeak(void *p){ + yyParser *pParser = (yyParser*)p; + return pParser->yyidxMax; +} +#endif + +/* +** Find the appropriate action for a parser given the terminal +** look-ahead token iLookAhead. +** +** If the look-ahead token is YYNOCODE, then check to see if the action is +** independent of the look-ahead. If it is, return the action, otherwise +** return YY_NO_ACTION. +*/ +static int yy_find_shift_action( + yyParser *pParser, /* The parser */ + YYCODETYPE iLookAhead /* The look-ahead token */ +){ + int i; + int stateno = pParser->yystack[pParser->yyidx].stateno; + + if( stateno>YY_SHIFT_COUNT + || (i = yy_shift_ofst[stateno])==YY_SHIFT_USE_DFLT ){ + return yy_default[stateno]; + } + assert( iLookAhead!=YYNOCODE ); + i += iLookAhead; + if( i<0 || i>=YY_ACTTAB_COUNT || yy_lookahead[i]!=iLookAhead ){ + if( iLookAhead>0 ){ +#ifdef YYFALLBACK + YYCODETYPE iFallback; /* Fallback token */ + if( iLookAhead %s\n", + yyTracePrompt, yyTokenName[iLookAhead], yyTokenName[iFallback]); + } +#endif + return yy_find_shift_action(pParser, iFallback); + } +#endif +#ifdef YYWILDCARD + { + int j = i - iLookAhead + YYWILDCARD; + if( +#if YY_SHIFT_MIN+YYWILDCARD<0 + j>=0 && +#endif +#if YY_SHIFT_MAX+YYWILDCARD>=YY_ACTTAB_COUNT + j %s\n", + yyTracePrompt, yyTokenName[iLookAhead], yyTokenName[YYWILDCARD]); + } +#endif /* NDEBUG */ + return yy_action[j]; + } + } +#endif /* YYWILDCARD */ + } + return yy_default[stateno]; + }else{ + return yy_action[i]; + } +} + +/* +** Find the appropriate action for a parser given the non-terminal +** look-ahead token iLookAhead. +** +** If the look-ahead token is YYNOCODE, then check to see if the action is +** independent of the look-ahead. If it is, return the action, otherwise +** return YY_NO_ACTION. +*/ +static int yy_find_reduce_action( + int stateno, /* Current state number */ + YYCODETYPE iLookAhead /* The look-ahead token */ +){ + int i; +#ifdef YYERRORSYMBOL + if( stateno>YY_REDUCE_COUNT ){ + return yy_default[stateno]; + } +#else + assert( stateno<=YY_REDUCE_COUNT ); +#endif + i = yy_reduce_ofst[stateno]; + assert( i!=YY_REDUCE_USE_DFLT ); + assert( iLookAhead!=YYNOCODE ); + i += iLookAhead; +#ifdef YYERRORSYMBOL + if( i<0 || i>=YY_ACTTAB_COUNT || yy_lookahead[i]!=iLookAhead ){ + return yy_default[stateno]; + } +#else + assert( i>=0 && iyyidx--; +#ifndef NDEBUG + if( yyTraceFILE ){ + fprintf(yyTraceFILE,"%sStack Overflow!\n",yyTracePrompt); + } +#endif + while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser); + /* Here code is inserted which will execute if the parser + ** stack every overflows */ +#line 25 "../libgda/sql-parser/delimiter.y" + + gda_sql_parser_set_overflow_error (pdata->parser); +#line 652 "/run/build/libgda/_flatpak_build/libgda/sql-parser/delimiter.c" + priv_gda_sql_delimiterARG_STORE; /* Suppress warning about unused %extra_argument var */ +} + +/* +** Perform a shift action. +*/ +static void yy_shift( + yyParser *yypParser, /* The parser to be shifted */ + int yyNewState, /* The new state to shift in */ + int yyMajor, /* The major token to shift in */ + YYMINORTYPE *yypMinor /* Pointer to the minor token to shift in */ +){ + yyStackEntry *yytos; + yypParser->yyidx++; +#ifdef YYTRACKMAXSTACKDEPTH + if( yypParser->yyidx>yypParser->yyidxMax ){ + yypParser->yyidxMax = yypParser->yyidx; + } +#endif +#if YYSTACKDEPTH>0 + if( yypParser->yyidx>=YYSTACKDEPTH ){ + yyStackOverflow(yypParser, yypMinor); + return; + } +#else + if( yypParser->yyidx>=yypParser->yystksz ){ + yyGrowStack(yypParser); + if( yypParser->yyidx>=yypParser->yystksz ){ + yyStackOverflow(yypParser, yypMinor); + return; + } + } +#endif + yytos = &yypParser->yystack[yypParser->yyidx]; + yytos->stateno = (YYACTIONTYPE)yyNewState; + yytos->major = (YYCODETYPE)yyMajor; + yytos->minor = *yypMinor; +#ifndef NDEBUG + if( yyTraceFILE && yypParser->yyidx>0 ){ + int i; + fprintf(yyTraceFILE,"%sShift %d\n",yyTracePrompt,yyNewState); + fprintf(yyTraceFILE,"%sStack:",yyTracePrompt); + for(i=1; i<=yypParser->yyidx; i++) + fprintf(yyTraceFILE," %s",yyTokenName[yypParser->yystack[i].major]); + fprintf(yyTraceFILE,"\n"); + } +#endif +} + +/* The following table contains information about every rule that +** is used during the reduce. +*/ +static const struct { + YYCODETYPE lhs; /* Symbol on the left-hand side of the rule */ + unsigned char nrhs; /* Number of right-hand side symbols in the rule */ +} yyRuleInfo[] = { + { 25, 2 }, + { 25, 2 }, + { 26, 2 }, + { 26, 1 }, + { 27, 1 }, + { 27, 1 }, + { 27, 1 }, + { 27, 1 }, + { 29, 1 }, + { 29, 1 }, + { 29, 1 }, + { 29, 1 }, + { 28, 4 }, + { 28, 4 }, + { 28, 1 }, + { 30, 0 }, + { 30, 2 }, + { 30, 2 }, + { 30, 2 }, + { 30, 2 }, +}; + +static void yy_accept(yyParser*); /* Forward Declaration */ + +/* +** Perform a reduce action and the shift that must immediately +** follow the reduce. +*/ +static void yy_reduce( + yyParser *yypParser, /* The parser */ + int yyruleno /* Number of the rule by which to reduce */ +){ + int yygoto; /* The next state */ + int yyact; /* The next action */ + YYMINORTYPE yygotominor; /* The LHS of the rule reduced */ + yyStackEntry *yymsp; /* The top of the parser's stack */ + int yysize; /* Amount to pop the stack */ + priv_gda_sql_delimiterARG_FETCH; + yymsp = &yypParser->yystack[yypParser->yyidx]; +#ifndef NDEBUG + if( yyTraceFILE && yyruleno>=0 + && yyruleno<(int)(sizeof(yyRuleName)/sizeof(yyRuleName[0])) ){ + fprintf(yyTraceFILE, "%sReduce [%s].\n", yyTracePrompt, + yyRuleName[yyruleno]); + } +#endif /* NDEBUG */ + + /* Silence complaints from purify about yygotominor being uninitialized + ** in some cases when it is copied into the stack after the following + ** switch. yygotominor is uninitialized when a rule reduces that does + ** not set the value of its left-hand side nonterminal. Leaving the + ** value of the nonterminal uninitialized is utterly harmless as long + ** as the value is never used. So really the only thing this code + ** accomplishes is to quieten purify. + ** + ** 2007-01-16: The wireshark project (www.wireshark.org) reports that + ** without this code, their parser segfaults. I'm not sure what there + ** parser is doing to make this happen. This is the second bug report + ** from wireshark this week. Clearly they are stressing Lemon in ways + ** that it has not been previously stressed... (SQLite ticket #2172) + */ + /*memset(&yygotominor, 0, sizeof(yygotominor));*/ + yygotominor = yyzerominor; + + + switch( yyruleno ){ + /* Beginning here are the reduction cases. A typical example + ** follows: + ** case 0: + ** #line + ** { ... } // User supplied code + ** #line + ** break; + */ + case 0: /* stmt ::= exprlist SEMI */ +#line 62 "../libgda/sql-parser/delimiter.y" +{pdata->parsed_statement = gda_sql_statement_new (GDA_SQL_STATEMENT_UNKNOWN); + /* FIXME: set SQL */ + gda_sql_statement_unknown_take_expressions (pdata->parsed_statement, g_slist_reverse (yymsp[-1].minor.yy27)); + yy_destructor(yypParser,9,&yymsp[0].minor); +} +#line 790 "/run/build/libgda/_flatpak_build/libgda/sql-parser/delimiter.c" + break; + case 1: /* stmt ::= exprlist END_OF_FILE */ +#line 66 "../libgda/sql-parser/delimiter.y" +{pdata->parsed_statement = gda_sql_statement_new (GDA_SQL_STATEMENT_UNKNOWN); + /* FIXME: set SQL */ + gda_sql_statement_unknown_take_expressions (pdata->parsed_statement, g_slist_reverse (yymsp[-1].minor.yy27)); + yy_destructor(yypParser,10,&yymsp[0].minor); +} +#line 799 "/run/build/libgda/_flatpak_build/libgda/sql-parser/delimiter.c" + break; + case 2: /* exprlist ::= exprlist expr */ +#line 74 "../libgda/sql-parser/delimiter.y" +{yygotominor.yy27 = g_slist_prepend (yymsp[-1].minor.yy27, yymsp[0].minor.yy54);} +#line 804 "/run/build/libgda/_flatpak_build/libgda/sql-parser/delimiter.c" + break; + case 3: /* exprlist ::= expr */ +#line 75 "../libgda/sql-parser/delimiter.y" +{yygotominor.yy27 = g_slist_append (NULL, yymsp[0].minor.yy54);} +#line 809 "/run/build/libgda/_flatpak_build/libgda/sql-parser/delimiter.c" + break; + case 4: /* expr ::= pvalue */ +#line 80 "../libgda/sql-parser/delimiter.y" +{yygotominor.yy54 = yymsp[0].minor.yy54;} +#line 814 "/run/build/libgda/_flatpak_build/libgda/sql-parser/delimiter.c" + break; + case 5: /* expr ::= RAWSTRING */ +#line 81 "../libgda/sql-parser/delimiter.y" +{yygotominor.yy54 = gda_sql_expr_new (NULL); yygotominor.yy54->value = yymsp[0].minor.yy0;} +#line 819 "/run/build/libgda/_flatpak_build/libgda/sql-parser/delimiter.c" + break; + case 6: /* expr ::= SPACE */ + case 7: /* expr ::= value */ yytestcase(yyruleno==7); +#line 82 "../libgda/sql-parser/delimiter.y" +{yygotominor.yy54 =gda_sql_expr_new (NULL); yygotominor.yy54->value = yymsp[0].minor.yy0;} +#line 825 "/run/build/libgda/_flatpak_build/libgda/sql-parser/delimiter.c" + break; + case 8: /* value ::= STRING */ + case 9: /* value ::= TEXTUAL */ yytestcase(yyruleno==9); + case 10: /* value ::= INTEGER */ yytestcase(yyruleno==10); + case 11: /* value ::= FLOAT */ yytestcase(yyruleno==11); +#line 86 "../libgda/sql-parser/delimiter.y" +{yygotominor.yy0 = yymsp[0].minor.yy0;} +#line 833 "/run/build/libgda/_flatpak_build/libgda/sql-parser/delimiter.c" + break; + case 12: /* pvalue ::= UNSPECVAL LSBRACKET paramspec RSBRACKET */ +#line 94 "../libgda/sql-parser/delimiter.y" +{yygotominor.yy54 = gda_sql_expr_new (NULL); yygotominor.yy54->param_spec = yymsp[-1].minor.yy3; yy_destructor(yypParser,16,&yymsp[-3].minor); + yy_destructor(yypParser,17,&yymsp[-2].minor); + yy_destructor(yypParser,18,&yymsp[0].minor); +} +#line 841 "/run/build/libgda/_flatpak_build/libgda/sql-parser/delimiter.c" + break; + case 13: /* pvalue ::= value LSBRACKET paramspec RSBRACKET */ +#line 95 "../libgda/sql-parser/delimiter.y" +{yygotominor.yy54 = gda_sql_expr_new (NULL); yygotominor.yy54->value = yymsp[-3].minor.yy0; yygotominor.yy54->param_spec = yymsp[-1].minor.yy3; yy_destructor(yypParser,17,&yymsp[-2].minor); + yy_destructor(yypParser,18,&yymsp[0].minor); +} +#line 848 "/run/build/libgda/_flatpak_build/libgda/sql-parser/delimiter.c" + break; + case 14: /* pvalue ::= SIMPLEPARAM */ +#line 96 "../libgda/sql-parser/delimiter.y" +{yygotominor.yy54 = gda_sql_expr_new (NULL); yygotominor.yy54->param_spec = gda_sql_param_spec_new (yymsp[0].minor.yy0);} +#line 853 "/run/build/libgda/_flatpak_build/libgda/sql-parser/delimiter.c" + break; + case 15: /* paramspec ::= */ +#line 101 "../libgda/sql-parser/delimiter.y" +{yygotominor.yy3 = NULL;} +#line 858 "/run/build/libgda/_flatpak_build/libgda/sql-parser/delimiter.c" + break; + case 16: /* paramspec ::= paramspec PNAME */ +#line 102 "../libgda/sql-parser/delimiter.y" +{if (!yymsp[-1].minor.yy3) yygotominor.yy3 = gda_sql_param_spec_new (NULL); else yygotominor.yy3 = yymsp[-1].minor.yy3; + gda_sql_param_spec_take_name (yygotominor.yy3, yymsp[0].minor.yy0);} +#line 864 "/run/build/libgda/_flatpak_build/libgda/sql-parser/delimiter.c" + break; + case 17: /* paramspec ::= paramspec PDESCR */ +#line 104 "../libgda/sql-parser/delimiter.y" +{if (!yymsp[-1].minor.yy3) yygotominor.yy3 = gda_sql_param_spec_new (NULL); else yygotominor.yy3 = yymsp[-1].minor.yy3; + gda_sql_param_spec_take_descr (yygotominor.yy3, yymsp[0].minor.yy0);} +#line 870 "/run/build/libgda/_flatpak_build/libgda/sql-parser/delimiter.c" + break; + case 18: /* paramspec ::= paramspec PTYPE */ +#line 106 "../libgda/sql-parser/delimiter.y" +{if (!yymsp[-1].minor.yy3) yygotominor.yy3 = gda_sql_param_spec_new (NULL); else yygotominor.yy3 = yymsp[-1].minor.yy3; + gda_sql_param_spec_take_type (yygotominor.yy3, yymsp[0].minor.yy0);} +#line 876 "/run/build/libgda/_flatpak_build/libgda/sql-parser/delimiter.c" + break; + case 19: /* paramspec ::= paramspec PNULLOK */ +#line 108 "../libgda/sql-parser/delimiter.y" +{if (!yymsp[-1].minor.yy3) yygotominor.yy3 = gda_sql_param_spec_new (NULL); else yygotominor.yy3 = yymsp[-1].minor.yy3; + gda_sql_param_spec_take_nullok (yygotominor.yy3, yymsp[0].minor.yy0);} +#line 882 "/run/build/libgda/_flatpak_build/libgda/sql-parser/delimiter.c" + break; + default: + break; + }; + yygoto = yyRuleInfo[yyruleno].lhs; + yysize = yyRuleInfo[yyruleno].nrhs; + yypParser->yyidx -= yysize; + yyact = yy_find_reduce_action(yymsp[-yysize].stateno,(YYCODETYPE)yygoto); + if( yyact < YYNSTATE ){ +#ifdef NDEBUG + /* If we are not debugging and the reduce action popped at least + ** one element off the stack, then we can push the new element back + ** onto the stack here, and skip the stack overflow test in yy_shift(). + ** That gives a significant speed improvement. */ + if( yysize ){ + yypParser->yyidx++; + yymsp -= yysize-1; + yymsp->stateno = (YYACTIONTYPE)yyact; + yymsp->major = (YYCODETYPE)yygoto; + yymsp->minor = yygotominor; + }else +#endif + { + yy_shift(yypParser,yyact,yygoto,&yygotominor); + } + }else{ + assert( yyact == YYNSTATE + YYNRULE + 1 ); + yy_accept(yypParser); + } +} + +/* +** The following code executes when the parse fails +*/ +#ifndef YYNOERRORRECOVERY +static void yy_parse_failed( + yyParser *yypParser /* The parser */ +){ + priv_gda_sql_delimiterARG_FETCH; +#ifndef NDEBUG + if( yyTraceFILE ){ + fprintf(yyTraceFILE,"%sFail!\n",yyTracePrompt); + } +#endif + while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser); + /* Here code is inserted which will be executed whenever the + ** parser fails */ + priv_gda_sql_delimiterARG_STORE; /* Suppress warning about unused %extra_argument variable */ +} +#endif /* YYNOERRORRECOVERY */ + +/* +** The following code executes when a syntax error first occurs. +*/ +static void yy_syntax_error( + yyParser *yypParser, /* The parser */ + int yymajor, /* The major type of the error token */ + YYMINORTYPE yyminor /* The minor type of the error token */ +){ + priv_gda_sql_delimiterARG_FETCH; +#define TOKEN (yyminor.yy0) +#line 22 "../libgda/sql-parser/delimiter.y" + + gda_sql_parser_set_syntax_error (pdata->parser); +#line 947 "/run/build/libgda/_flatpak_build/libgda/sql-parser/delimiter.c" + priv_gda_sql_delimiterARG_STORE; /* Suppress warning about unused %extra_argument variable */ +} + +/* +** The following is executed when the parser accepts +*/ +static void yy_accept( + yyParser *yypParser /* The parser */ +){ + priv_gda_sql_delimiterARG_FETCH; +#ifndef NDEBUG + if( yyTraceFILE ){ + fprintf(yyTraceFILE,"%sAccept!\n",yyTracePrompt); + } +#endif + while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser); + /* Here code is inserted which will be executed whenever the + ** parser accepts */ + priv_gda_sql_delimiterARG_STORE; /* Suppress warning about unused %extra_argument variable */ +} + +/* The main parser program. +** The first argument is a pointer to a structure obtained from +** "priv_gda_sql_delimiterAlloc" which describes the current state of the parser. +** The second argument is the major token number. The third is +** the minor token. The fourth optional argument is whatever the +** user wants (and specified in the grammar) and is available for +** use by the action routines. +** +** Inputs: +**
    +**
  • A pointer to the parser (an opaque structure.) +**
  • The major token number. +**
  • The minor token number. +**
  • An option argument of a grammar-specified type. +**
+** +** Outputs: +** None. +*/ +void priv_gda_sql_delimiter( + void *yyp, /* The parser */ + int yymajor, /* The major token code number */ + priv_gda_sql_delimiterTOKENTYPE yyminor /* The value for the token */ + priv_gda_sql_delimiterARG_PDECL /* Optional %extra_argument parameter */ +){ + YYMINORTYPE yyminorunion; + int yyact; /* The parser action. */ + int yyendofinput; /* True if we are at the end of input */ +#ifdef YYERRORSYMBOL + int yyerrorhit = 0; /* True if yymajor has invoked an error */ +#endif + yyParser *yypParser; /* The parser */ + + /* (re)initialize the parser, if necessary */ + yypParser = (yyParser*)yyp; + if( yypParser->yyidx<0 ){ +#if YYSTACKDEPTH<=0 + if( yypParser->yystksz <=0 ){ + /*memset(&yyminorunion, 0, sizeof(yyminorunion));*/ + yyminorunion = yyzerominor; + yyStackOverflow(yypParser, &yyminorunion); + return; + } +#endif + yypParser->yyidx = 0; + yypParser->yyerrcnt = -1; + yypParser->yystack[0].stateno = 0; + yypParser->yystack[0].major = 0; + } + yyminorunion.yy0 = yyminor; + yyendofinput = (yymajor==0); + priv_gda_sql_delimiterARG_STORE; + +#ifndef NDEBUG + if( yyTraceFILE ){ + fprintf(yyTraceFILE,"%sInput %s\n",yyTracePrompt,yyTokenName[yymajor]); + } +#endif + + do{ + yyact = yy_find_shift_action(yypParser,(YYCODETYPE)yymajor); + if( yyactyyerrcnt--; + yymajor = YYNOCODE; + }else if( yyact < YYNSTATE + YYNRULE ){ + yy_reduce(yypParser,yyact-YYNSTATE); + }else{ + assert( yyact == YY_ERROR_ACTION ); +#ifdef YYERRORSYMBOL + int yymx; +#endif +#ifndef NDEBUG + if( yyTraceFILE ){ + fprintf(yyTraceFILE,"%sSyntax Error!\n",yyTracePrompt); + } +#endif +#ifdef YYERRORSYMBOL + /* A syntax error has occurred. + ** The response to an error depends upon whether or not the + ** grammar defines an error token "ERROR". + ** + ** This is what we do if the grammar does define ERROR: + ** + ** * Call the %syntax_error function. + ** + ** * Begin popping the stack until we enter a state where + ** it is legal to shift the error symbol, then shift + ** the error symbol. + ** + ** * Set the error count to three. + ** + ** * Begin accepting and shifting new tokens. No new error + ** processing will occur until three tokens have been + ** shifted successfully. + ** + */ + if( yypParser->yyerrcnt<0 ){ + yy_syntax_error(yypParser,yymajor,yyminorunion); + } + yymx = yypParser->yystack[yypParser->yyidx].major; + if( yymx==YYERRORSYMBOL || yyerrorhit ){ +#ifndef NDEBUG + if( yyTraceFILE ){ + fprintf(yyTraceFILE,"%sDiscard input token %s\n", + yyTracePrompt,yyTokenName[yymajor]); + } +#endif + yy_destructor(yypParser, (YYCODETYPE)yymajor,&yyminorunion); + yymajor = YYNOCODE; + }else{ + while( + yypParser->yyidx >= 0 && + yymx != YYERRORSYMBOL && + (yyact = yy_find_reduce_action( + yypParser->yystack[yypParser->yyidx].stateno, + YYERRORSYMBOL)) >= YYNSTATE + ){ + yy_pop_parser_stack(yypParser); + } + if( yypParser->yyidx < 0 || yymajor==0 ){ + yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion); + yy_parse_failed(yypParser); + yymajor = YYNOCODE; + }else if( yymx!=YYERRORSYMBOL ){ + YYMINORTYPE u2; + u2.YYERRSYMDT = 0; + yy_shift(yypParser,yyact,YYERRORSYMBOL,&u2); + } + } + yypParser->yyerrcnt = 3; + yyerrorhit = 1; +#elif defined(YYNOERRORRECOVERY) + /* If the YYNOERRORRECOVERY macro is defined, then do not attempt to + ** do any kind of error recovery. Instead, simply invoke the syntax + ** error routine and continue going as if nothing had happened. + ** + ** Applications can set this macro (for example inside %include) if + ** they intend to abandon the parse upon the first syntax error seen. + */ + yy_syntax_error(yypParser,yymajor,yyminorunion); + yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion); + yymajor = YYNOCODE; + +#else /* YYERRORSYMBOL is not defined */ + /* This is what we do if the grammar does not define ERROR: + ** + ** * Report an error message, and throw away the input token. + ** + ** * If the input token is $, then fail the parse. + ** + ** As before, subsequent error messages are suppressed until + ** three input tokens have been successfully shifted. + */ + if( yypParser->yyerrcnt<=0 ){ + yy_syntax_error(yypParser,yymajor,yyminorunion); + } + yypParser->yyerrcnt = 3; + yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion); + if( yyendofinput ){ + yy_parse_failed(yypParser); + } + yymajor = YYNOCODE; +#endif + } + }while( yymajor!=YYNOCODE && yypParser->yyidx>=0 ); + return; +} diff --git a/.flatpak-builder/cache/objects/10/77466dc833b2a3be2fa806ab16ba16e4b449cfb1e35549c650fe94c0e3583f.file b/.flatpak-builder/cache/objects/10/77466dc833b2a3be2fa806ab16ba16e4b449cfb1e35549c650fe94c0e3583f.file new file mode 100644 index 0000000..6843b98 Binary files /dev/null and b/.flatpak-builder/cache/objects/10/77466dc833b2a3be2fa806ab16ba16e4b449cfb1e35549c650fe94c0e3583f.file differ diff --git a/.flatpak-builder/cache/objects/10/9f3534ab1169e085606300fcd00253e682be1e62be64e35f816b6d5dcfd529.file b/.flatpak-builder/cache/objects/10/9f3534ab1169e085606300fcd00253e682be1e62be64e35f816b6d5dcfd529.file new file mode 100644 index 0000000..09475a8 --- /dev/null +++ b/.flatpak-builder/cache/objects/10/9f3534ab1169e085606300fcd00253e682be1e62be64e35f816b6d5dcfd529.file @@ -0,0 +1,141 @@ +/* This file is generated by glib-genmarshal, do not modify it. This code is licensed under the same license as the containing project. Note that it links to GLib, so must comply with the LGPL linking clauses. */ +#pragma once + +#include + +G_BEGIN_DECLS + +/* VOID:VOID (../libgda/gda-marshal.list:25) */ +#define _gda_marshal_VOID__VOID g_cclosure_marshal_VOID__VOID + +/* VOID:POINTER (../libgda/gda-marshal.list:26) */ +#define _gda_marshal_VOID__POINTER g_cclosure_marshal_VOID__POINTER + +/* VOID:OBJECT (../libgda/gda-marshal.list:27) */ +#define _gda_marshal_VOID__OBJECT g_cclosure_marshal_VOID__OBJECT + +/* VOID:OBJECT,OBJECT (../libgda/gda-marshal.list:28) */ +extern +void _gda_marshal_VOID__OBJECT_OBJECT (GClosure *closure, + GValue *return_value, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint, + gpointer marshal_data); + +/* VOID:OBJECT,ENUM,OBJECT (../libgda/gda-marshal.list:29) */ +extern +void _gda_marshal_VOID__OBJECT_ENUM_OBJECT (GClosure *closure, + GValue *return_value, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint, + gpointer marshal_data); + +/* VOID:OBJECT,UINT (../libgda/gda-marshal.list:30) */ +extern +void _gda_marshal_VOID__OBJECT_UINT (GClosure *closure, + GValue *return_value, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint, + gpointer marshal_data); + +/* VOID:OBJECT,UINT,UINT (../libgda/gda-marshal.list:31) */ +extern +void _gda_marshal_VOID__OBJECT_UINT_UINT (GClosure *closure, + GValue *return_value, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint, + gpointer marshal_data); + +/* VOID:OBJECT,BOOLEAN (../libgda/gda-marshal.list:32) */ +extern +void _gda_marshal_VOID__OBJECT_BOOLEAN (GClosure *closure, + GValue *return_value, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint, + gpointer marshal_data); + +/* VOID:STRING,UINT,UINT (../libgda/gda-marshal.list:33) */ +extern +void _gda_marshal_VOID__STRING_UINT_UINT (GClosure *closure, + GValue *return_value, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint, + gpointer marshal_data); + +/* VOID:ENUM,OBJECT (../libgda/gda-marshal.list:34) */ +extern +void _gda_marshal_VOID__ENUM_OBJECT (GClosure *closure, + GValue *return_value, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint, + gpointer marshal_data); + +/* VOID:UINT,POINTER (../libgda/gda-marshal.list:35) */ +#define _gda_marshal_VOID__UINT_POINTER g_cclosure_marshal_VOID__UINT_POINTER + +/* VOID:INT,INT (../libgda/gda-marshal.list:36) */ +extern +void _gda_marshal_VOID__INT_INT (GClosure *closure, + GValue *return_value, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint, + gpointer marshal_data); + +/* VOID:INT,BOXED,BOXED (../libgda/gda-marshal.list:37) */ +extern +void _gda_marshal_VOID__INT_BOXED_BOXED (GClosure *closure, + GValue *return_value, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint, + gpointer marshal_data); + +/* VOID:INT,BOOLEAN (../libgda/gda-marshal.list:38) */ +extern +void _gda_marshal_VOID__INT_BOOLEAN (GClosure *closure, + GValue *return_value, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint, + gpointer marshal_data); + +/* VOID:STRING,INT (../libgda/gda-marshal.list:39) */ +extern +void _gda_marshal_VOID__STRING_INT (GClosure *closure, + GValue *return_value, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint, + gpointer marshal_data); + +/* POINTER:POINTER (../libgda/gda-marshal.list:40) */ +extern +void _gda_marshal_POINTER__POINTER (GClosure *closure, + GValue *return_value, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint, + gpointer marshal_data); + +/* BOOLEAN:POINTER (../libgda/gda-marshal.list:41) */ +extern +void _gda_marshal_BOOLEAN__POINTER (GClosure *closure, + GValue *return_value, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint, + gpointer marshal_data); + +/* VOID:ENUM (../libgda/gda-marshal.list:42) */ +#define _gda_marshal_VOID__ENUM g_cclosure_marshal_VOID__ENUM + + +G_END_DECLS diff --git a/.flatpak-builder/cache/objects/10/d428464e9cb27313095d1cdcd2232e0679cfe578384b0234f9480e4347676f.dirtree b/.flatpak-builder/cache/objects/10/d428464e9cb27313095d1cdcd2232e0679cfe578384b0234f9480e4347676f.dirtree new file mode 100644 index 0000000..1cf9e85 Binary files /dev/null and b/.flatpak-builder/cache/objects/10/d428464e9cb27313095d1cdcd2232e0679cfe578384b0234f9480e4347676f.dirtree differ diff --git a/.flatpak-builder/cache/objects/10/eea0f461137ce35765e9bd6ff285e3f54ee9ed5cc1f9616b7807932ab2e41d.file b/.flatpak-builder/cache/objects/10/eea0f461137ce35765e9bd6ff285e3f54ee9ed5cc1f9616b7807932ab2e41d.file new file mode 100644 index 0000000..c817434 --- /dev/null +++ b/.flatpak-builder/cache/objects/10/eea0f461137ce35765e9bd6ff285e3f54ee9ed5cc1f9616b7807932ab2e41d.file @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2005 - 2012 Vivien Malerba + * Copyright (C) 2006 - 2007 Murray Cumming + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GDA_DATA_MODEL_PRIVATE_H__ +#define __GDA_DATA_MODEL_PRIVATE_H__ + +#include +#include +#include +#include +#include +#include +#include + +G_BEGIN_DECLS + +gboolean gda_data_model_add_data_from_xml_node (GdaDataModel *model, xmlNodePtr node, GError **error); + +G_END_DECLS + +#endif diff --git a/.flatpak-builder/cache/objects/11/0a4e13c05b26d32a5e6d9fa12fbf8c8bf2ede4a6df0a9860e947a493d03a52.file b/.flatpak-builder/cache/objects/11/0a4e13c05b26d32a5e6d9fa12fbf8c8bf2ede4a6df0a9860e947a493d03a52.file new file mode 100644 index 0000000..f70f4e4 --- /dev/null +++ b/.flatpak-builder/cache/objects/11/0a4e13c05b26d32a5e6d9fa12fbf8c8bf2ede4a6df0a9860e947a493d03a52.file @@ -0,0 +1,288 @@ +/* + * Copyright (C) 2008 - 2012 Vivien Malerba + * Copyright (C) 2009 Murray Cumming + * Copyright (C) 2011 - 2013 Daniel Espinosa + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef _GDA_STATEMENT_STRUCT_DECL_H +#define _GDA_STATEMENT_STRUCT_DECL_H + +#include +#include +#include +#include +#include + +G_BEGIN_DECLS + +/* error reporting */ +extern GQuark gda_sql_error_quark (void); +#define GDA_SQL_ERROR gda_sql_error_quark () +/* + * GdaSqlError: + * + **/ +typedef enum { + GDA_SQL_STRUCTURE_CONTENTS_ERROR, + GDA_SQL_MALFORMED_IDENTIFIER_ERROR, + GDA_SQL_MISSING_IDENTIFIER_ERROR, + GDA_SQL_VALIDATION_ERROR +} GdaSqlError; + +/* + * Struct declarations + */ +/* + * GdaSqlAnyPart: + * + **/ +typedef struct _GdaSqlAnyPart GdaSqlAnyPart; +/* + * GdaSqlStatement: + * + **/ +typedef struct _GdaSqlStatement GdaSqlStatement; +/* + * GdaSqlStatementUnknown: + * + **/ +typedef struct _GdaSqlStatementUnknown GdaSqlStatementUnknown; +/* + * GdaSqlStatementTransaction: + * + **/ +typedef struct _GdaSqlStatementTransaction GdaSqlStatementTransaction; +/* + * GdaSqlStatementSelect: + * + **/ +typedef struct _GdaSqlStatementSelect GdaSqlStatementSelect; +/* + * GdaSqlStatementInsert: + * + **/ +typedef struct _GdaSqlStatementInsert GdaSqlStatementInsert; +/* + * GdaSqlStatementDelete: + * + **/ +typedef struct _GdaSqlStatementDelete GdaSqlStatementDelete; +/* + * GdaSqlStatementUpdate: + * + **/ +typedef struct _GdaSqlStatementUpdate GdaSqlStatementUpdate; +/* + * GdaSqlStatementCompound: + * + **/ +typedef struct _GdaSqlStatementCompound GdaSqlStatementCompound; + +/* + * Statement type + */ +/** + * GdaSqlStatementType: + * @GDA_SQL_STATEMENT_SELECT: a SELECT statement + * @GDA_SQL_STATEMENT_INSERT: an INSERT statement + * @GDA_SQL_STATEMENT_UPDATE: an UPDATE statement + * @GDA_SQL_STATEMENT_DELETE: a DELETE statement + * @GDA_SQL_STATEMENT_COMPOUND: a compound statement: multiple SELECT statements grouped together using an operator + * @GDA_SQL_STATEMENT_BEGIN: start of transaction statement + * @GDA_SQL_STATEMENT_ROLLBACK: transaction abort statement + * @GDA_SQL_STATEMENT_COMMIT: transaction commit statement + * @GDA_SQL_STATEMENT_SAVEPOINT: new savepoint definition statement + * @GDA_SQL_STATEMENT_ROLLBACK_SAVEPOINT: return to savepoint statement + * @GDA_SQL_STATEMENT_DELETE_SAVEPOINT: savepoint deletion statement + * @GDA_SQL_STATEMENT_UNKNOWN: unknown statement, only identifies variables + * @GDA_SQL_STATEMENT_NONE: not used + * + * Known types of statements + */ +typedef enum { + GDA_SQL_STATEMENT_SELECT, + GDA_SQL_STATEMENT_INSERT, + GDA_SQL_STATEMENT_UPDATE, + GDA_SQL_STATEMENT_DELETE, + GDA_SQL_STATEMENT_COMPOUND, + + GDA_SQL_STATEMENT_BEGIN, + GDA_SQL_STATEMENT_ROLLBACK, + GDA_SQL_STATEMENT_COMMIT, + + GDA_SQL_STATEMENT_SAVEPOINT, + GDA_SQL_STATEMENT_ROLLBACK_SAVEPOINT, + GDA_SQL_STATEMENT_DELETE_SAVEPOINT, + + GDA_SQL_STATEMENT_UNKNOWN, + GDA_SQL_STATEMENT_NONE +} GdaSqlStatementType; + + +/* + * Structures identification + */ +/** + * GdaSqlAnyPartType: + * @GDA_SQL_ANY_STMT_SELECT: structure is a #GdaSqlStatementSelect + * @GDA_SQL_ANY_STMT_INSERT: structure is a #GdaSqlStatementInsert + * @GDA_SQL_ANY_STMT_UPDATE: structure is a #GdaSqlStatementUpdate + * @GDA_SQL_ANY_STMT_DELETE: structure is a #GdaSqlStatementDelete + * @GDA_SQL_ANY_STMT_COMPOUND: structure is a #GdaSqlStatementCompound + * @GDA_SQL_ANY_STMT_BEGIN: structure is a #GdaSqlStatementTransaction + * @GDA_SQL_ANY_STMT_ROLLBACK: structure is a #GdaSqlStatementTransaction + * @GDA_SQL_ANY_STMT_COMMIT: structure is a #GdaSqlStatementTransaction + * @GDA_SQL_ANY_STMT_SAVEPOINT: structure is a #GdaSqlStatementTransaction + * @GDA_SQL_ANY_STMT_ROLLBACK_SAVEPOINT: structure is a #GdaSqlStatementTransaction + * @GDA_SQL_ANY_STMT_DELETE_SAVEPOINT: structure is a #GdaSqlStatementTransaction + * @GDA_SQL_ANY_STMT_UNKNOWN: structure is a #GdaSqlStatementUnknown + * @GDA_SQL_ANY_EXPR: structure is a #GdaSqlExpr + * @GDA_SQL_ANY_SQL_FIELD: structure is a #GdaSqlField + * @GDA_SQL_ANY_SQL_TABLE: structure is a #GdaSqlTable + * @GDA_SQL_ANY_SQL_FUNCTION: structure is a #GdaSqlFunction + * @GDA_SQL_ANY_SQL_OPERATION: structure is a #GdaSqlOperation + * @GDA_SQL_ANY_SQL_CASE: structure is a #GdaSqlCase + * @GDA_SQL_ANY_SQL_SELECT_FIELD: structure is a #GdaSqlSelectField + * @GDA_SQL_ANY_SQL_SELECT_TARGET: structure is a #GdaSqlSelectTarget + * @GDA_SQL_ANY_SQL_SELECT_JOIN: structure is a #GdaSqlSelectJoin + * @GDA_SQL_ANY_SQL_SELECT_FROM: structure is a #GdaSqlSelectFrom + * @GDA_SQL_ANY_SQL_SELECT_ORDER: structure is a #GdaSqlSelectOrder + * + * Type of part. + */ +typedef enum { + /* complete statements */ + GDA_SQL_ANY_STMT_SELECT = GDA_SQL_STATEMENT_SELECT, + GDA_SQL_ANY_STMT_INSERT = GDA_SQL_STATEMENT_INSERT, + GDA_SQL_ANY_STMT_UPDATE = GDA_SQL_STATEMENT_UPDATE, + GDA_SQL_ANY_STMT_DELETE = GDA_SQL_STATEMENT_DELETE, + GDA_SQL_ANY_STMT_COMPOUND = GDA_SQL_STATEMENT_COMPOUND, + GDA_SQL_ANY_STMT_BEGIN = GDA_SQL_STATEMENT_BEGIN, + GDA_SQL_ANY_STMT_ROLLBACK = GDA_SQL_STATEMENT_ROLLBACK, + GDA_SQL_ANY_STMT_COMMIT = GDA_SQL_STATEMENT_COMMIT, + GDA_SQL_ANY_STMT_SAVEPOINT = GDA_SQL_STATEMENT_SAVEPOINT, + GDA_SQL_ANY_STMT_ROLLBACK_SAVEPOINT = GDA_SQL_STATEMENT_ROLLBACK_SAVEPOINT, + GDA_SQL_ANY_STMT_DELETE_SAVEPOINT = GDA_SQL_STATEMENT_DELETE_SAVEPOINT, + GDA_SQL_ANY_STMT_UNKNOWN = GDA_SQL_STATEMENT_UNKNOWN, + + /* individual parts */ + GDA_SQL_ANY_EXPR = 500, + GDA_SQL_ANY_SQL_FIELD, + GDA_SQL_ANY_SQL_TABLE, + GDA_SQL_ANY_SQL_FUNCTION, + GDA_SQL_ANY_SQL_OPERATION, + GDA_SQL_ANY_SQL_CASE, + GDA_SQL_ANY_SQL_SELECT_FIELD, + GDA_SQL_ANY_SQL_SELECT_TARGET, + GDA_SQL_ANY_SQL_SELECT_JOIN, + GDA_SQL_ANY_SQL_SELECT_FROM, + GDA_SQL_ANY_SQL_SELECT_ORDER +} GdaSqlAnyPartType; + + +/** + * GdaSqlAnyPart: + * @type: type of structure, as a #GdaSqlAnyPartType enum. + * @parent: pointer to the parent #GdaSqlAnyPart structure + * + * Base structure of which all structures (except #GdaSqlStatement) "inherit". It identifies, for each structure, + * its type and its parent in the structure hierarchy. + */ +struct _GdaSqlAnyPart { + GdaSqlAnyPartType type; + GdaSqlAnyPart *parent; +}; + +#define GDA_SQL_ANY_PART(x) ((GdaSqlAnyPart*)(x)) +#define GDA_TYPE_SQL_ANY_PART gda_sql_any_part_get_type +GType gda_sql_any_part_get_type (void) G_GNUC_CONST; + +#define gda_sql_any_part_set_parent(a,p) \ + if (a) GDA_SQL_ANY_PART(a)->parent = GDA_SQL_ANY_PART(p) + +/* + * Iteration + */ + +/* returns FALSE if a recursive walking should be stopped (mandatory is @error is set) */ +/** + * GdaSqlForeachFunc: + * @part: the current #GdaSqlAnyPart node + * @data: user data passed to gda_sql_any_part_foreach(). + * @error: pointer to a place to store errors + * @Returns: FALSE if the gda_sql_any_part_foreach() should stop at this point and fail + * + * Specifies the type of functions passed to gda_sql_any_part_foreach(). + */ +typedef gboolean (*GdaSqlForeachFunc) (GdaSqlAnyPart *part, gpointer data, GError **error); + +gboolean gda_sql_any_part_foreach (GdaSqlAnyPart *node, GdaSqlForeachFunc func, gpointer data, GError **error); + +/* + * Structure validation + */ +gboolean gda_sql_any_part_check_structure (GdaSqlAnyPart *node, GError **error); + +/** + * GdaSqlStatementContentsInfo: + * + * Contents' infos + */ +typedef struct { + GdaSqlStatementType type; + gchar *name; + gpointer (*construct) (void); + void (*free) (gpointer stm); + gpointer (*copy) (gpointer stm); + gchar *(*serialize) (gpointer stm); + + /* augmenting information precision using a dictionary */ + GdaSqlForeachFunc check_structure_func; + GdaSqlForeachFunc check_validity_func; + + /*< private >*/ + /* Padding for future expansion */ + gpointer _gda_reserved1; + gpointer _gda_reserved2; + gpointer _gda_reserved3; + gpointer _gda_reserved4; +} GdaSqlStatementContentsInfo; +#define GDA_TYPE_SQL_STATEMENT_CONTENTS_INFO gda_sql_statement_contents_info_get_type() +GType gda_sql_statement_contents_info_get_type (void) G_GNUC_CONST; + +/** + * GdaSqlStatementCheckValidityData: + * + * Validation against a dictionary + */ +typedef struct { + GdaConnection *cnc; + GdaMetaStore *store; + GdaMetaStruct *mstruct; + + /*< private >*/ + /* Padding for future expansion */ + gpointer _gda_reserved1; + gpointer _gda_reserved2; + gpointer _gda_reserved3; + gpointer _gda_reserved4; +} GdaSqlStatementCheckValidityData; + +G_END_DECLS + +#endif diff --git a/.flatpak-builder/cache/objects/11/16216acb98227034976d999caffd071688c965e61e9b0d682e9d5c19ae4a8a.dirtree b/.flatpak-builder/cache/objects/11/16216acb98227034976d999caffd071688c965e61e9b0d682e9d5c19ae4a8a.dirtree new file mode 100644 index 0000000..40a89f5 Binary files /dev/null and b/.flatpak-builder/cache/objects/11/16216acb98227034976d999caffd071688c965e61e9b0d682e9d5c19ae4a8a.dirtree differ diff --git a/.flatpak-builder/cache/objects/11/9fb9726beb23fcaf6955f667ce6e936c6e5d14ef3a90c338323e3aef42ba8c.dirtree b/.flatpak-builder/cache/objects/11/9fb9726beb23fcaf6955f667ce6e936c6e5d14ef3a90c338323e3aef42ba8c.dirtree new file mode 100644 index 0000000..9b613a4 Binary files /dev/null and b/.flatpak-builder/cache/objects/11/9fb9726beb23fcaf6955f667ce6e936c6e5d14ef3a90c338323e3aef42ba8c.dirtree differ diff --git a/.flatpak-builder/cache/objects/11/bb5ea0692944994af46d8da2986b97458beb7c020a9074229c10b7a25c39e2.file b/.flatpak-builder/cache/objects/11/bb5ea0692944994af46d8da2986b97458beb7c020a9074229c10b7a25c39e2.file new file mode 100644 index 0000000..9e543ad --- /dev/null +++ b/.flatpak-builder/cache/objects/11/bb5ea0692944994af46d8da2986b97458beb7c020a9074229c10b7a25c39e2.file @@ -0,0 +1,154 @@ +/* + * Copyright (C) 2005 Dan Winship + * Copyright (C) 2005 - 2014 Vivien Malerba + * Copyright (C) 2005 Álvaro Peńa + * Copyright (C) 2007 Murray Cumming + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GDA_SERVER_PROVIDER_PRIVATE__ +#define __GDA_SERVER_PROVIDER_PRIVATE__ + +#include +#include + +/* + * Getting the GMainContext to use with the GdaWorker + */ +GMainContext *gda_server_provider_get_real_main_context (GdaConnection *cnc); + +/* + * GdaServerProvider's virtual functions access + */ +gpointer _gda_server_provider_get_impl_functions (GdaServerProvider *provider, GdaWorker *worker, + GdaServerProviderFunctionsType type); + +/* + * private API to access the provider's virtual methods, but only through the GdaWorker's prism + */ +GdaConnection * +_gda_server_provider_create_connection (GdaServerProvider *provider, const gchar *dsn_string, const gchar *cnc_string, + const gchar *auth_string, GdaConnectionOptions options); + +#define _gda_server_provider_open_connection_sync(p,c,pa,a,e) \ + _gda_server_provider_open_connection((p), (c), (pa), (a), NULL, NULL, NULL, (e)) +#define _gda_server_provider_open_connection_async(p,c,pa,a,f,d,ou,e) \ + _gda_server_provider_open_connection((p), (c), (pa), (a), (f), (d), (ou), (e)) + +gboolean +_gda_server_provider_open_connection (GdaServerProvider *provider, GdaConnection *cnc, + GdaQuarkList *params, GdaQuarkList *auth, + GdaConnectionOpenFunc cb_func, gpointer data, guint *out_job_id, + GError **error); +gboolean +_gda_server_provider_close_connection (GdaServerProvider *provider, GdaConnection *cnc, + GError **error); + +gboolean +_gda_server_provider_statement_prepare (GdaServerProvider *provider, GdaConnection *cnc, + GdaStatement *stmt, GError **error); + +gchar * +_gda_server_provider_statement_to_sql (GdaServerProvider *provider, GdaConnection *cnc, + GdaStatement *stmt, GdaSet *params, GdaStatementSqlFlag flags, + GSList **params_used, GError **error); + +gchar * +_gda_server_provider_identifier_quote (GdaServerProvider *provider, GdaConnection *cnc, + const gchar *id, gboolean for_meta_store, gboolean force_quotes); + +GObject * +_gda_server_provider_statement_execute (GdaServerProvider *provider, GdaConnection *cnc, + GdaStatement *stmt, GdaSet *params, + GdaStatementModelUsage model_usage, + GType *col_types, GdaSet **last_inserted_row, GError **error); +gboolean +_gda_server_provider_meta_0arg (GdaServerProvider *provider, GdaConnection *cnc, + GdaMetaStore *meta, GdaMetaContext *ctx, + GdaServerProviderMetaType type, GError **error); + +gboolean +_gda_server_provider_begin_transaction (GdaServerProvider *provider, GdaConnection *cnc, const gchar *name, GdaTransactionIsolation level, GError **error); +gboolean + +_gda_server_provider_commit_transaction (GdaServerProvider *provider, GdaConnection *cnc, const gchar *name, GError **error); + +gboolean +_gda_server_provider_rollback_transaction (GdaServerProvider *provider, GdaConnection *cnc, const gchar *name, GError **error); + +gboolean +_gda_server_provider_add_savepoint (GdaServerProvider *provider, GdaConnection *cnc, const gchar *name, GError **error); + +gboolean +_gda_server_provider_rollback_savepoint (GdaServerProvider *provider, GdaConnection *cnc, const gchar *name, GError **error); + +gboolean +_gda_server_provider_delete_savepoint (GdaServerProvider *provider, GdaConnection *cnc, const gchar *name, GError **error); + +typedef enum { + GDA_XA_START, + GDA_XA_END, + GDA_XA_PREPARE, + GDA_XA_COMMIT, + GDA_XA_ROLLBACK, + GDA_XA_RECOVER +} GdaXaType; + +gboolean +_gda_server_provider_xa (GdaServerProvider *provider, GdaConnection *cnc, const GdaXaTransactionId *trx, GdaXaType type, GError **error); +#define _gda_server_provider_xa_start(prov,cnc,trx,error) _gda_server_provider_xa((prov),(cnc),(trx),GDA_XA_START,(error)) +#define _gda_server_provider_xa_end(prov,cnc,trx,error) _gda_server_provider_xa((prov),(cnc),(trx),GDA_XA_END,(error)) +#define _gda_server_provider_xa_prepare(prov,cnc,trx,error) _gda_server_provider_xa((prov),(cnc),(trx),GDA_XA_PREPARE,(error)) +#define _gda_server_provider_xa_commit(prov,cnc,trx,error) _gda_server_provider_xa((prov),(cnc),(trx),GDA_XA_COMMIT,(error)) +#define _gda_server_provider_xa_rollback(prov,cnc,trx,error) _gda_server_provider_xa((prov),(cnc),(trx),GDA_XA_ROLLBACK,(error)) + +GList * +_gda_server_provider_xa_recover (GdaServerProvider *prov, GdaConnection *cnc, GError **error); + +gboolean +_gda_server_provider_meta_1arg (GdaServerProvider *provider, GdaConnection *cnc, + GdaMetaStore *meta, GdaMetaContext *ctx, + GdaServerProviderMetaType type, const GValue *value0, GError **error); + +gboolean +_gda_server_provider_meta_2arg (GdaServerProvider *provider, GdaConnection *cnc, + GdaMetaStore *meta, GdaMetaContext *ctx, + GdaServerProviderMetaType type, const GValue *value0, const GValue *value1, GError **error); + +gboolean +_gda_server_provider_meta_3arg (GdaServerProvider *provider, GdaConnection *cnc, + GdaMetaStore *meta, GdaMetaContext *ctx, + GdaServerProviderMetaType type, const GValue *value0, const GValue *value1, const GValue *value2, GError **error); + +gboolean +_gda_server_provider_meta_4arg (GdaServerProvider *provider, GdaConnection *cnc, + GdaMetaStore *meta, GdaMetaContext *ctx, + GdaServerProviderMetaType type, const GValue *value0, const GValue *value1, const GValue *value2, const GValue *value3, GError **error); + + +gboolean +_gda_server_provider_meta_5arg (GdaServerProvider *provider, GdaConnection *cnc, + GdaMetaStore *meta, GdaMetaContext *ctx, + GdaServerProviderMetaType type, const GValue *value0, const GValue *value1, const GValue *value2, const GValue *value3, const GValue *value4, GError **error); + + +G_END_DECLS + +#endif + + + diff --git a/.flatpak-builder/cache/objects/11/cc868798bcdb3176bbd5eb177e0a01f25bad7268aa190b1c3b81631f427f3d.file b/.flatpak-builder/cache/objects/11/cc868798bcdb3176bbd5eb177e0a01f25bad7268aa190b1c3b81631f427f3d.file new file mode 100644 index 0000000..47382e4 Binary files /dev/null and b/.flatpak-builder/cache/objects/11/cc868798bcdb3176bbd5eb177e0a01f25bad7268aa190b1c3b81631f427f3d.file differ diff --git a/.flatpak-builder/cache/objects/12/04a17ea6ad71688bd3f650380c38f370b5fdb3e8f998f8f8bf8bb1a8fdb06e.dirtree b/.flatpak-builder/cache/objects/12/04a17ea6ad71688bd3f650380c38f370b5fdb3e8f998f8f8bf8bb1a8fdb06e.dirtree new file mode 100644 index 0000000..dfea828 Binary files /dev/null and b/.flatpak-builder/cache/objects/12/04a17ea6ad71688bd3f650380c38f370b5fdb3e8f998f8f8bf8bb1a8fdb06e.dirtree differ diff --git a/.flatpak-builder/cache/objects/12/50f01c5a566ae0fd5a4f9ca8b31f9b9db36a7240cc07bf65dfdccc89730a6d.file b/.flatpak-builder/cache/objects/12/50f01c5a566ae0fd5a4f9ca8b31f9b9db36a7240cc07bf65dfdccc89730a6d.file new file mode 100644 index 0000000..f68f5a7 --- /dev/null +++ b/.flatpak-builder/cache/objects/12/50f01c5a566ae0fd5a4f9ca8b31f9b9db36a7240cc07bf65dfdccc89730a6d.file @@ -0,0 +1,103 @@ +# tokenizer.py +# +# Copyright 2021 James Westman +# +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation; either version 3 of the +# License, or (at your option) any later version. +# +# This file is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program. If not, see . +# +# SPDX-License-Identifier: LGPL-3.0-or-later + + +import typing as T +import re +from enum import Enum + +from .errors import CompileError, CompilerBugError + + +class TokenType(Enum): + EOF = 0 + IDENT = 1 + QUOTED = 2 + NUMBER = 3 + OP = 4 + WHITESPACE = 5 + COMMENT = 6 + PUNCTUATION = 7 + + +_tokens = [ + (TokenType.IDENT, r"[A-Za-z_][\d\w\-_]*"), + (TokenType.QUOTED, r'"(\\"|[^"\n])*"'), + (TokenType.QUOTED, r"'(\\'|[^'\n])*'"), + (TokenType.NUMBER, r"0x[A-Za-z0-9_]+"), + (TokenType.NUMBER, r"[\d_]+(\.[\d_]+)?"), + (TokenType.NUMBER, r"\.[\d_]+"), + (TokenType.WHITESPACE, r"\s+"), + (TokenType.COMMENT, r"\/\*[\s\S]*?\*\/"), + (TokenType.COMMENT, r"\/\/[^\n]*"), + (TokenType.OP, r"\$|<<|>>|=>|::|<|>|:=|\.|\|\||\||\+|\-|\*|=|:|/"), + (TokenType.PUNCTUATION, r"\(|\)|\{|\}|;|\[|\]|\,"), +] +_TOKENS = [(type, re.compile(regex)) for (type, regex) in _tokens] + + +class Token: + def __init__(self, type: TokenType, start: int, end: int, string: str): + self.type = type + self.start = start + self.end = end + self.string = string + + def __str__(self) -> str: + return self.string[self.start : self.end] + + def get_number(self) -> T.Union[int, float]: + if self.type != TokenType.NUMBER: + raise CompilerBugError() + + string = str(self).replace("_", "") + try: + if string.startswith("0x"): + return int(string, 16) + else: + return float(string) + except: + raise CompileError( + f"{str(self)} is not a valid number literal", self.start, self.end + ) + + +def _tokenize(ui_ml: str): + i = 0 + while i < len(ui_ml): + matched = False + for type, regex in _TOKENS: + match = regex.match(ui_ml, i) + + if match is not None: + yield Token(type, match.start(), match.end(), ui_ml) + i = match.end() + matched = True + break + + if not matched: + raise CompileError( + "Could not determine what kind of syntax is meant here", i, i + ) + + yield Token(TokenType.EOF, i, i, ui_ml) + + +def tokenize(data: str) -> T.List[Token]: + return list(_tokenize(data)) diff --git a/.flatpak-builder/cache/objects/12/7910892cb8a53ddd959656c35612b0d557cadc2e4d688c7f190b6b13193904.file b/.flatpak-builder/cache/objects/12/7910892cb8a53ddd959656c35612b0d557cadc2e4d688c7f190b6b13193904.file new file mode 100644 index 0000000..c5ad86b Binary files /dev/null and b/.flatpak-builder/cache/objects/12/7910892cb8a53ddd959656c35612b0d557cadc2e4d688c7f190b6b13193904.file differ diff --git a/.flatpak-builder/cache/objects/12/9523c34de168503ad355bdf92cf90f75012b4b4805a0018334a09c9950fca2.dirtree b/.flatpak-builder/cache/objects/12/9523c34de168503ad355bdf92cf90f75012b4b4805a0018334a09c9950fca2.dirtree new file mode 100644 index 0000000..58fa9e7 Binary files /dev/null and b/.flatpak-builder/cache/objects/12/9523c34de168503ad355bdf92cf90f75012b4b4805a0018334a09c9950fca2.dirtree differ diff --git a/.flatpak-builder/cache/objects/13/21a478a1888909396bb7b649d6201c874c8632be4331a4cc9d9572d2f0e9e2.dirtree b/.flatpak-builder/cache/objects/13/21a478a1888909396bb7b649d6201c874c8632be4331a4cc9d9572d2f0e9e2.dirtree new file mode 100644 index 0000000..e987b61 Binary files /dev/null and b/.flatpak-builder/cache/objects/13/21a478a1888909396bb7b649d6201c874c8632be4331a4cc9d9572d2f0e9e2.dirtree differ diff --git a/.flatpak-builder/cache/objects/13/43c54ad5c5f5221b3a71cef1aa997555f8788a8757a2ae9eefcbd12c02305e.file b/.flatpak-builder/cache/objects/13/43c54ad5c5f5221b3a71cef1aa997555f8788a8757a2ae9eefcbd12c02305e.file new file mode 120000 index 0000000..e232400 --- /dev/null +++ b/.flatpak-builder/cache/objects/13/43c54ad5c5f5221b3a71cef1aa997555f8788a8757a2ae9eefcbd12c02305e.file @@ -0,0 +1 @@ +../../share/runtime/locale/tg/share/tg \ No newline at end of file diff --git a/.flatpak-builder/cache/objects/13/57aae3b85c95c13479b9c03cdfa2f1a0363f6485e89fd56927f9be9fc6607f.file b/.flatpak-builder/cache/objects/13/57aae3b85c95c13479b9c03cdfa2f1a0363f6485e89fd56927f9be9fc6607f.file new file mode 120000 index 0000000..f8d263d --- /dev/null +++ b/.flatpak-builder/cache/objects/13/57aae3b85c95c13479b9c03cdfa2f1a0363f6485e89fd56927f9be9fc6607f.file @@ -0,0 +1 @@ +device-removed.oga \ No newline at end of file diff --git a/.flatpak-builder/cache/objects/13/7ab167cf070ba3ff7e71fce7200102b748c34ee816c6b16872ff4478ffd07e.dirtree b/.flatpak-builder/cache/objects/13/7ab167cf070ba3ff7e71fce7200102b748c34ee816c6b16872ff4478ffd07e.dirtree new file mode 100644 index 0000000..9a7db97 Binary files /dev/null and b/.flatpak-builder/cache/objects/13/7ab167cf070ba3ff7e71fce7200102b748c34ee816c6b16872ff4478ffd07e.dirtree differ diff --git a/.flatpak-builder/cache/objects/13/aa7257cb6c8fac94e9761b7109f754ba839d62e0d31a752f2c12340e6e1e75.file b/.flatpak-builder/cache/objects/13/aa7257cb6c8fac94e9761b7109f754ba839d62e0d31a752f2c12340e6e1e75.file new file mode 100644 index 0000000..dbf4ca7 --- /dev/null +++ b/.flatpak-builder/cache/objects/13/aa7257cb6c8fac94e9761b7109f754ba839d62e0d31a752f2c12340e6e1e75.file @@ -0,0 +1,47 @@ +/* + * This code has been copied from SQLite's mkkeywordhash.c file and modified. + * to read the SQL keywords from a file instead of static ones. + * + * Include it along with the generated keywork_hash.c file + */ + +#ifndef __KEYWORDS_HASH_H__ +#define __KEYWORDS_HASH_H__ + +#include + +#ifndef KEYWORDS_HASH_NO_STATIC +static +#endif +const unsigned char UpperToLower[] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, + 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, + 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, + 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 97, 98, 99,100,101,102,103, + 104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121, + 122, 91, 92, 93, 94, 95, 96, 97, 98, 99,100,101,102,103,104,105,106,107, + 108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125, + 126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, + 144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161, + 162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179, + 180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197, + 198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215, + 216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233, + 234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251, + 252,253,254,255 +}; +#define charMap(X) UpperToLower[(unsigned char)(X)] +#ifndef KEYWORDS_HASH_NO_STATIC +static +#endif +int +casecmp (const char *zLeft, const char *zRight, int N) +{ + register unsigned char *a, *b; + a = (unsigned char *)zLeft; + b = (unsigned char *)zRight; + while( N-- > 0 && *a!=0 && UpperToLower[*a]==UpperToLower[*b]){ a++; b++; } + return N<0 ? 0 : UpperToLower[*a] - UpperToLower[*b]; +} + +#endif diff --git a/.flatpak-builder/cache/objects/14/0b686ff648e2f830733d585301187d8fc84ea613f3b4ab6e7cc4a3907f1ef3.dirtree b/.flatpak-builder/cache/objects/14/0b686ff648e2f830733d585301187d8fc84ea613f3b4ab6e7cc4a3907f1ef3.dirtree new file mode 100644 index 0000000..d766a35 Binary files /dev/null and b/.flatpak-builder/cache/objects/14/0b686ff648e2f830733d585301187d8fc84ea613f3b4ab6e7cc4a3907f1ef3.dirtree differ diff --git a/.flatpak-builder/cache/objects/14/3a10217854d329c8baa03bc2a46b5e40381558abefccebcc3edf8c5dfddde9.dirtree b/.flatpak-builder/cache/objects/14/3a10217854d329c8baa03bc2a46b5e40381558abefccebcc3edf8c5dfddde9.dirtree new file mode 100644 index 0000000..7be0ffb Binary files /dev/null and b/.flatpak-builder/cache/objects/14/3a10217854d329c8baa03bc2a46b5e40381558abefccebcc3edf8c5dfddde9.dirtree differ diff --git a/.flatpak-builder/cache/objects/14/7b4f559abc1a26ae85fc06898e5e5d2fe4aa336edd5e25730c70130cc3fbb4.dirtree b/.flatpak-builder/cache/objects/14/7b4f559abc1a26ae85fc06898e5e5d2fe4aa336edd5e25730c70130cc3fbb4.dirtree new file mode 100644 index 0000000..f7f9beb Binary files /dev/null and b/.flatpak-builder/cache/objects/14/7b4f559abc1a26ae85fc06898e5e5d2fe4aa336edd5e25730c70130cc3fbb4.dirtree differ diff --git a/.flatpak-builder/cache/objects/14/e2551db5f48ca55a8e9e64529f7e9d70331153ee36ec1ec99b163f446cdcbf.file b/.flatpak-builder/cache/objects/14/e2551db5f48ca55a8e9e64529f7e9d70331153ee36ec1ec99b163f446cdcbf.file new file mode 100644 index 0000000..5c9f7bb --- /dev/null +++ b/.flatpak-builder/cache/objects/14/e2551db5f48ca55a8e9e64529f7e9d70331153ee36ec1ec99b163f446cdcbf.file @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2000 Reinhard Müller + * Copyright (C) 2000 - 2002 Rodrigo Moya + * Copyright (C) 2001 Carlos Perelló Marín + * Copyright (C) 2001 - 2012 Vivien Malerba + * Copyright (C) 2002 Gonzalo Paniagua Javier + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + + +#ifndef __GDA_DATA_MODEL_ITER_EXTRA_H_ +#define __GDA_DATA_MODEL_ITER_EXTRA_H_ + +#include "gda-data-model-iter.h" + +G_BEGIN_DECLS + +gboolean gda_data_model_iter_move_to_row_default (GdaDataModel *model, GdaDataModelIter *iter, gint row); +gboolean gda_data_model_iter_move_next_default (GdaDataModel *model, GdaDataModelIter *iter); +gboolean gda_data_model_iter_move_prev_default (GdaDataModel *model, GdaDataModelIter *iter); + +G_END_DECLS + +#endif diff --git a/.flatpak-builder/cache/objects/15/12acdd8f9ce15458e00ac06b17486913057de05c5c238aa217a7898355dc36.file b/.flatpak-builder/cache/objects/15/12acdd8f9ce15458e00ac06b17486913057de05c5c238aa217a7898355dc36.file new file mode 100644 index 0000000..fcd2c3b --- /dev/null +++ b/.flatpak-builder/cache/objects/15/12acdd8f9ce15458e00ac06b17486913057de05c5c238aa217a7898355dc36.file @@ -0,0 +1,221 @@ +# Makefile for program source directory in GNU NLS utilities package. +# Copyright (C) 1995, 1996, 1997 by Ulrich Drepper +# Copyright (C) 2004-2008 Rodney Dawes +# +# This file may be copied and used freely without restrictions. It may +# be used in projects which are not available under a GNU Public License, +# but which still want to provide support for the GNU gettext functionality. +# +# - Modified by Owen Taylor to use GETTEXT_PACKAGE +# instead of PACKAGE and to look for po2tbl in ./ not in intl/ +# +# - Modified by jacob berkman to install +# Makefile.in.in and po2tbl.sed.in for use with glib-gettextize +# +# - Modified by Rodney Dawes for use with intltool +# +# We have the following line for use by intltoolize: +# INTLTOOL_MAKEFILE + +GETTEXT_PACKAGE = @GETTEXT_PACKAGE@ +PACKAGE = @PACKAGE@ +VERSION = @VERSION@ + +SHELL = @SHELL@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +top_builddir = @top_builddir@ +VPATH = @srcdir@ + +prefix = @prefix@ +exec_prefix = @exec_prefix@ +datadir = @datadir@ +datarootdir = @datarootdir@ +libdir = @libdir@ +localedir = @localedir@ +subdir = po +install_sh = @install_sh@ +# Automake >= 1.8 provides @mkdir_p@. +# Until it can be supposed, use the safe fallback: +mkdir_p = $(install_sh) -d + +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ + +GMSGFMT = @GMSGFMT@ +MSGFMT = @MSGFMT@ +XGETTEXT = @XGETTEXT@ +INTLTOOL_UPDATE = @INTLTOOL_UPDATE@ +INTLTOOL_EXTRACT = @INTLTOOL_EXTRACT@ +MSGMERGE = INTLTOOL_EXTRACT="$(INTLTOOL_EXTRACT)" XGETTEXT="$(XGETTEXT)" srcdir=$(srcdir) $(INTLTOOL_UPDATE) --gettext-package $(GETTEXT_PACKAGE) --dist +GENPOT = INTLTOOL_EXTRACT="$(INTLTOOL_EXTRACT)" XGETTEXT="$(XGETTEXT)" srcdir=$(srcdir) $(INTLTOOL_UPDATE) --gettext-package $(GETTEXT_PACKAGE) --pot + +ALL_LINGUAS = @ALL_LINGUAS@ + +PO_LINGUAS=$(shell if test -r $(srcdir)/LINGUAS; then grep -v "^\#" $(srcdir)/LINGUAS; else echo "$(ALL_LINGUAS)"; fi) + +USER_LINGUAS=$(shell if test -n "$(LINGUAS)"; then LLINGUAS="$(LINGUAS)"; ALINGUAS="$(ALL_LINGUAS)"; for lang in $$LLINGUAS; do if test -n "`grep \^$$lang$$ $(srcdir)/LINGUAS 2>/dev/null`" -o -n "`echo $$ALINGUAS|tr ' ' '\n'|grep \^$$lang$$`"; then printf "$$lang "; fi; done; fi) + +USE_LINGUAS=$(shell if test -n "$(USER_LINGUAS)" -o -n "$(LINGUAS)"; then LLINGUAS="$(USER_LINGUAS)"; else if test -n "$(PO_LINGUAS)"; then LLINGUAS="$(PO_LINGUAS)"; else LLINGUAS="$(ALL_LINGUAS)"; fi; fi; for lang in $$LLINGUAS; do printf "$$lang "; done) + +POFILES=$(shell LINGUAS="$(PO_LINGUAS)"; for lang in $$LINGUAS; do printf "$$lang.po "; done) + +DISTFILES = Makefile.in.in POTFILES.in $(POFILES) +EXTRA_DISTFILES = ChangeLog POTFILES.skip Makevars LINGUAS + +POTFILES = \ +# This comment gets stripped out + +CATALOGS=$(shell LINGUAS="$(USE_LINGUAS)"; for lang in $$LINGUAS; do printf "$$lang.gmo "; done) + +.SUFFIXES: +.SUFFIXES: .po .pox .gmo .mo .msg .cat + +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +INTLTOOL_V_MSGFMT = $(INTLTOOL__v_MSGFMT_$(V)) +INTLTOOL__v_MSGFMT_= $(INTLTOOL__v_MSGFMT_$(AM_DEFAULT_VERBOSITY)) +INTLTOOL__v_MSGFMT_0 = @echo " MSGFMT" $@; + +.po.pox: + $(MAKE) $(GETTEXT_PACKAGE).pot + $(MSGMERGE) $* $(GETTEXT_PACKAGE).pot -o $*.pox + +.po.mo: + $(INTLTOOL_V_MSGFMT)$(MSGFMT) -o $@ $< + +.po.gmo: + $(INTLTOOL_V_MSGFMT)file=`echo $* | sed 's,.*/,,'`.gmo \ + && rm -f $$file && $(GMSGFMT) -o $$file $< + +.po.cat: + sed -f ../intl/po2msg.sed < $< > $*.msg \ + && rm -f $@ && gencat $@ $*.msg + + +all: all-@USE_NLS@ + +all-yes: $(CATALOGS) +all-no: + +$(GETTEXT_PACKAGE).pot: $(POTFILES) + $(GENPOT) + +install: install-data +install-data: install-data-@USE_NLS@ +install-data-no: all +install-data-yes: all + linguas="$(USE_LINGUAS)"; \ + for lang in $$linguas; do \ + dir=$(DESTDIR)$(localedir)/$$lang/LC_MESSAGES; \ + $(mkdir_p) $$dir; \ + if test -r $$lang.gmo; then \ + $(INSTALL_DATA) $$lang.gmo $$dir/$(GETTEXT_PACKAGE).mo; \ + echo "installing $$lang.gmo as $$dir/$(GETTEXT_PACKAGE).mo"; \ + else \ + $(INSTALL_DATA) $(srcdir)/$$lang.gmo $$dir/$(GETTEXT_PACKAGE).mo; \ + echo "installing $(srcdir)/$$lang.gmo as" \ + "$$dir/$(GETTEXT_PACKAGE).mo"; \ + fi; \ + if test -r $$lang.gmo.m; then \ + $(INSTALL_DATA) $$lang.gmo.m $$dir/$(GETTEXT_PACKAGE).mo.m; \ + echo "installing $$lang.gmo.m as $$dir/$(GETTEXT_PACKAGE).mo.m"; \ + else \ + if test -r $(srcdir)/$$lang.gmo.m ; then \ + $(INSTALL_DATA) $(srcdir)/$$lang.gmo.m \ + $$dir/$(GETTEXT_PACKAGE).mo.m; \ + echo "installing $(srcdir)/$$lang.gmo.m as" \ + "$$dir/$(GETTEXT_PACKAGE).mo.m"; \ + else \ + true; \ + fi; \ + fi; \ + done + +# Empty stubs to satisfy archaic automake needs +dvi info ctags tags CTAGS TAGS ID: + +# Define this as empty until I found a useful application. +install-exec installcheck: + +uninstall: + linguas="$(USE_LINGUAS)"; \ + for lang in $$linguas; do \ + rm -f $(DESTDIR)$(localedir)/$$lang/LC_MESSAGES/$(GETTEXT_PACKAGE).mo; \ + rm -f $(DESTDIR)$(localedir)/$$lang/LC_MESSAGES/$(GETTEXT_PACKAGE).mo.m; \ + done + +check: all $(GETTEXT_PACKAGE).pot + rm -f missing notexist + srcdir=$(srcdir) $(INTLTOOL_UPDATE) -m + if [ -r missing -o -r notexist ]; then \ + exit 1; \ + fi + +mostlyclean: + rm -f *.pox $(GETTEXT_PACKAGE).pot *.old.po cat-id-tbl.tmp + rm -f .intltool-merge-cache + +clean: mostlyclean + +distclean: clean + rm -f Makefile Makefile.in POTFILES stamp-it + rm -f *.mo *.msg *.cat *.cat.m *.gmo + +maintainer-clean: distclean + @echo "This command is intended for maintainers to use;" + @echo "it deletes files that may require special tools to rebuild." + rm -f Makefile.in.in + +distdir = ../$(PACKAGE)-$(VERSION)/$(subdir) +dist distdir: $(DISTFILES) + dists="$(DISTFILES)"; \ + extra_dists="$(EXTRA_DISTFILES)"; \ + for file in $$extra_dists; do \ + test -f $(srcdir)/$$file && dists="$$dists $(srcdir)/$$file"; \ + done; \ + for file in $$dists; do \ + test -f $$file || file="$(srcdir)/$$file"; \ + ln $$file $(distdir) 2> /dev/null \ + || cp -p $$file $(distdir); \ + done + +update-po: Makefile + $(MAKE) $(GETTEXT_PACKAGE).pot + tmpdir=`pwd`; \ + linguas="$(USE_LINGUAS)"; \ + for lang in $$linguas; do \ + echo "$$lang:"; \ + result="`$(MSGMERGE) -o $$tmpdir/$$lang.new.po $$lang`"; \ + if $$result; then \ + if cmp $(srcdir)/$$lang.po $$tmpdir/$$lang.new.po >/dev/null 2>&1; then \ + rm -f $$tmpdir/$$lang.new.po; \ + else \ + if mv -f $$tmpdir/$$lang.new.po $$lang.po; then \ + :; \ + else \ + echo "msgmerge for $$lang.po failed: cannot move $$tmpdir/$$lang.new.po to $$lang.po" 1>&2; \ + rm -f $$tmpdir/$$lang.new.po; \ + exit 1; \ + fi; \ + fi; \ + else \ + echo "msgmerge for $$lang.gmo failed!"; \ + rm -f $$tmpdir/$$lang.new.po; \ + fi; \ + done + +Makefile POTFILES: stamp-it + @if test ! -f $@; then \ + rm -f stamp-it; \ + $(MAKE) stamp-it; \ + fi + +stamp-it: Makefile.in.in $(top_builddir)/config.status POTFILES.in + cd $(top_builddir) \ + && CONFIG_FILES=$(subdir)/Makefile.in CONFIG_HEADERS= CONFIG_LINKS= \ + $(SHELL) ./config.status + +# Tell versions [3.59,3.63) of GNU make not to export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/.flatpak-builder/cache/objects/15/45213dc4b818c24b3f7afc0f68183f2e3edc86670dbe37275f60d1f2abf337.file b/.flatpak-builder/cache/objects/15/45213dc4b818c24b3f7afc0f68183f2e3edc86670dbe37275f60d1f2abf337.file new file mode 100644 index 0000000..e6bdd7a Binary files /dev/null and b/.flatpak-builder/cache/objects/15/45213dc4b818c24b3f7afc0f68183f2e3edc86670dbe37275f60d1f2abf337.file differ diff --git a/.flatpak-builder/cache/objects/15/57f8b7e045ccb8332dc48453dfb085196f2d7f79e6c3bb2bc5695fdbd45df0.dirtree b/.flatpak-builder/cache/objects/15/57f8b7e045ccb8332dc48453dfb085196f2d7f79e6c3bb2bc5695fdbd45df0.dirtree new file mode 100644 index 0000000..2287181 Binary files /dev/null and b/.flatpak-builder/cache/objects/15/57f8b7e045ccb8332dc48453dfb085196f2d7f79e6c3bb2bc5695fdbd45df0.dirtree differ diff --git a/.flatpak-builder/cache/objects/15/7c82ca03ad272cf645d5e81588a699b19ae7436a09180f1f649dc76dd64282.dirtree b/.flatpak-builder/cache/objects/15/7c82ca03ad272cf645d5e81588a699b19ae7436a09180f1f649dc76dd64282.dirtree new file mode 100644 index 0000000..febd6bb Binary files /dev/null and b/.flatpak-builder/cache/objects/15/7c82ca03ad272cf645d5e81588a699b19ae7436a09180f1f649dc76dd64282.dirtree differ diff --git a/.flatpak-builder/cache/objects/15/82d0a275689eaef514142d28976576fd0f279e4ffa542b8ef5faf9e8e90892.dirtree b/.flatpak-builder/cache/objects/15/82d0a275689eaef514142d28976576fd0f279e4ffa542b8ef5faf9e8e90892.dirtree new file mode 100644 index 0000000..73683aa Binary files /dev/null and b/.flatpak-builder/cache/objects/15/82d0a275689eaef514142d28976576fd0f279e4ffa542b8ef5faf9e8e90892.dirtree differ diff --git a/.flatpak-builder/cache/objects/15/99bad39e62c4f19635184b299ad65e62628ec14a892e04cd22b44d0cfe9a37.file b/.flatpak-builder/cache/objects/15/99bad39e62c4f19635184b299ad65e62628ec14a892e04cd22b44d0cfe9a37.file new file mode 100644 index 0000000..856feb8 --- /dev/null +++ b/.flatpak-builder/cache/objects/15/99bad39e62c4f19635184b299ad65e62628ec14a892e04cd22b44d0cfe9a37.file @@ -0,0 +1,9 @@ +[Desktop Entry] +Type=Application +Name=GNOME Login Sound +Comment=Plays a sound whenever you log in +Exec=/app/bin/canberra-gtk-play --id="desktop-login" --description="GNOME Login" +OnlyShowIn=GNOME; +AutostartCondition=GSettings org.gnome.desktop.sound event-sounds +X-GNOME-Autostart-Phase=Application +X-GNOME-Provides=login-sound diff --git a/.flatpak-builder/cache/objects/15/af5fc52d6bc247d1bc1c4dd2a9e717fe997bfa232305829f00c1cd835cabd7.file b/.flatpak-builder/cache/objects/15/af5fc52d6bc247d1bc1c4dd2a9e717fe997bfa232305829f00c1cd835cabd7.file new file mode 100644 index 0000000..293c071 --- /dev/null +++ b/.flatpak-builder/cache/objects/15/af5fc52d6bc247d1bc1c4dd2a9e717fe997bfa232305829f00c1cd835cabd7.file @@ -0,0 +1,251 @@ +/*-*- Mode: C; c-basic-offset: 8 -*-*/ + +#ifndef foocanberramacrohfoo +#define foocanberramacrohfoo + +/*** + This file is part of libcanberra. + + Copyright 2008 Lennart Poettering + + libcanberra is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation, either version 2.1 of the + License, or (at your option) any later version. + + libcanberra is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with libcanberra. If not, see + . +***/ + +#include +#include + +#ifndef PACKAGE +#error "Please include config.h before including this file!" +#endif + +#if defined (__GNUC__) && __GNUC__ >= 3 +#define CA_LIKELY(x) (__builtin_expect(!!(x),1)) +#define CA_UNLIKELY(x) (__builtin_expect((x),0)) +#else +#define CA_LIKELY(x) (x) +#define CA_UNLIKELY(x) (x) +#endif + +#ifdef __GNUC__ +#define CA_PRETTY_FUNCTION __PRETTY_FUNCTION__ +#else +#define CA_PRETTY_FUNCTION "" +#endif + +#define ca_return_if_fail(expr) \ + do { \ + if (CA_UNLIKELY(!(expr))) { \ + if (ca_debug()) \ + fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s().\n", #expr , __FILE__, __LINE__, CA_PRETTY_FUNCTION); \ + return; \ + } \ + } while(FALSE) + +#define ca_return_val_if_fail(expr, val) \ + do { \ + if (CA_UNLIKELY(!(expr))) { \ + if (ca_debug()) \ + fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s().\n", #expr , __FILE__, __LINE__, CA_PRETTY_FUNCTION); \ + return (val); \ + } \ + } while(FALSE) + +#define ca_return_null_if_fail(expr) ca_return_val_if_fail(expr, NULL) + +#define ca_return_if_fail_unlock(expr, mutex) \ + do { \ + if (CA_UNLIKELY(!(expr))) { \ + if (ca_debug()) \ + fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s().\n", #expr , __FILE__, __LINE__, CA_PRETTY_FUNCTION); \ + ca_mutex_unlock(mutex); \ + return; \ + } \ + } while(FALSE) + +#define ca_return_val_if_fail_unlock(expr, val, mutex) \ + do { \ + if (CA_UNLIKELY(!(expr))) { \ + if (ca_debug()) \ + fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s().\n", #expr , __FILE__, __LINE__, CA_PRETTY_FUNCTION); \ + ca_mutex_unlock(mutex); \ + return (val); \ + } \ + } while(FALSE) + +#define ca_return_null_if_fail_unlock(expr, mutex) ca_return_val_if_fail_unlock(expr, NULL, mutex) + +/* An assert which guarantees side effects of x, i.e. is never + * optimized away */ +#define ca_assert_se(expr) \ + do { \ + if (CA_UNLIKELY(!(expr))) { \ + fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s(). Aborting.\n", #expr , __FILE__, __LINE__, CA_PRETTY_FUNCTION); \ + abort(); \ + } \ + } while (FALSE) + +/* An assert that may be optimized away by defining NDEBUG */ +#ifdef NDEBUG +#define ca_assert(expr) do {} while (FALSE) +#else +#define ca_assert(expr) ca_assert_se(expr) +#endif + +#define ca_assert_not_reached() \ + do { \ + fprintf(stderr, "Code should not be reached at %s:%u, function %s(). Aborting.\n", __FILE__, __LINE__, CA_PRETTY_FUNCTION); \ + abort(); \ + } while (FALSE) + +#define CA_ELEMENTSOF(x) (sizeof(x)/sizeof((x)[0])) + +#ifdef __GNUC__ +#define CA_MAX(a,b) \ + __extension__ ({ typeof(a) _a = (a); \ + typeof(b) _b = (b); \ + _a > _b ? _a : _b; \ + }) +#else +#define CA_MAX(a, b) ((a) > (b) ? (a) : (b)) +#endif + +#ifdef __GNUC__ +#define CA_MIN(a,b) \ + __extension__ ({ typeof(a) _a = (a); \ + typeof(b) _b = (b); \ + _a < _b ? _a : _b; \ + }) +#else +#define CA_MIN(a, b) ((a) < (b) ? (a) : (b)) +#endif + +#ifdef __GNUC__ +#define CA_CLAMP(x, low, high) \ + __extension__ ({ typeof(x) _x = (x); \ + typeof(low) _low = (low); \ + typeof(high) _high = (high); \ + ((_x > _high) ? _high : ((_x < _low) ? _low : _x)); \ + }) +#else +#define CA_CLAMP(x, low, high) (((x) > (high)) ? (high) : (((x) < (low)) ? (low) : (x))) +#endif + +#ifndef FALSE +#define FALSE (0) +#endif + +#ifndef TRUE +#define TRUE (!FALSE) +#endif + +#define CA_PTR_TO_UINT(p) ((unsigned int) (unsigned long) (p)) +#define CA_UINT_TO_PTR(u) ((void*) (unsigned long) (u)) + +#define CA_PTR_TO_UINT32(p) ((uint32_t) CA_PTR_TO_UINT(p)) +#define CA_UINT32_TO_PTR(u) CA_UINT_TO_PTR((uint32_t) u) + +#define CA_PTR_TO_INT(p) ((int) CA_PTR_TO_UINT(p)) +#define CA_INT_TO_PTR(u) CA_UINT_TO_PTR((int) u) + +#define CA_PTR_TO_INT32(p) ((int32_t) CA_PTR_TO_UINT(p)) +#define CA_INT32_TO_PTR(u) CA_UINT_TO_PTR((int32_t) u) + +typedef int ca_bool_t; + +ca_bool_t ca_debug(void); + +static inline size_t ca_align(size_t l) { + return (((l + sizeof(void*) - 1) / sizeof(void*)) * sizeof(void*)); +} + +#define CA_ALIGN(x) (ca_align(x)) + +typedef void (*ca_free_cb_t)(void *); + +#ifdef HAVE_BYTESWAP_H +#include +#endif + +#ifdef HAVE_BYTESWAP_H + #define CA_INT16_SWAP(x) ((int16_t) bswap_16((uint16_t) x)) + #define CA_UINT16_SWAP(x) ((uint16_t) bswap_16((uint16_t) x)) + #define CA_INT32_SWAP(x) ((int32_t) bswap_32((uint32_t) x)) + #define CA_UINT32_SWAP(x) ((uint32_t) bswap_32((uint32_t) x)) +#else + #define CA_INT16_SWAP(x) ( (int16_t) ( ((uint16_t) x >> 8) | ((uint16_t) x << 8) ) ) + #define CA_UINT16_SWAP(x) ( (uint16_t) ( ((uint16_t) x >> 8) | ((uint16_t) x << 8) ) ) + #define CA_INT32_SWAP(x) ( (int32_t) ( ((uint32_t) x >> 24) | ((uint32_t) x << 24) | (((uint32_t) x & 0xFF00) << 8) | ((((uint32_t) x) >> 8) & 0xFF00) ) ) + #define CA_UINT32_SWAP(x) ( (uint32_t) ( ((uint32_t) x >> 24) | ((uint32_t) x << 24) | (((uint32_t) x & 0xFF00) << 8) | ((((uint32_t) x) >> 8) & 0xFF00) ) ) +#endif + +#ifdef WORDS_BIGENDIAN + #define CA_INT16_FROM_LE(x) CA_INT16_SWAP(x) + #define CA_INT16_FROM_BE(x) ((int16_t)(x)) + + #define CA_INT16_TO_LE(x) CA_INT16_SWAP(x) + #define CA_INT16_TO_BE(x) ((int16_t)(x)) + + #define CA_UINT16_FROM_LE(x) CA_UINT16_SWAP(x) + #define CA_UINT16_FROM_BE(x) ((uint16_t)(x)) + + #define CA_UINT16_TO_LE(x) CA_UINT16_SWAP(x) + #define CA_UINT16_TO_BE(x) ((uint16_t)(x)) + + #define CA_INT32_FROM_LE(x) CA_INT32_SWAP(x) + #define CA_INT32_FROM_BE(x) ((int32_t)(x)) + + #define CA_INT32_TO_LE(x) CA_INT32_SWAP(x) + #define CA_INT32_TO_BE(x) ((int32_t)(x)) + + #define CA_UINT32_FROM_LE(x) CA_UINT32_SWAP(x) + #define CA_UINT32_FROM_BE(x) ((uint32_t)(x)) + + #define CA_UINT32_TO_LE(x) CA_UINT32_SWAP(x) + #define CA_UINT32_TO_BE(x) ((uint32_t)(x)) +#else + #define CA_INT16_FROM_LE(x) ((int16_t)(x)) + #define CA_INT16_FROM_BE(x) CA_INT16_SWAP(x) + + #define CA_INT16_TO_LE(x) ((int16_t)(x)) + #define CA_INT16_TO_BE(x) CA_INT16_SWAP(x) + + #define CA_UINT16_FROM_LE(x) ((uint16_t)(x)) + #define CA_UINT16_FROM_BE(x) CA_UINT16_SWAP(x) + + #define CA_UINT16_TO_LE(x) ((uint16_t)(x)) + #define CA_UINT16_TO_BE(x) CA_UINT16_SWAP(x) + + #define CA_INT32_FROM_LE(x) ((int32_t)(x)) + #define CA_INT32_FROM_BE(x) CA_INT32_SWAP(x) + + #define CA_INT32_TO_LE(x) ((int32_t)(x)) + #define CA_INT32_TO_BE(x) CA_INT32_SWAP(x) + + #define CA_UINT32_FROM_LE(x) ((uint32_t)(x)) + #define CA_UINT32_FROM_BE(x) CA_UINT32_SWAP(x) + + #define CA_UINT32_TO_LE(x) ((uint32_t)(x)) + #define CA_UINT32_TO_BE(x) CA_UINT32_SWAP(x) +#endif + +#define ca_streq(a, b) (strcmp((a),(b)) == 0) + +#ifdef __GNUC__ +#define CA_GCC_DESTRUCTOR __attribute__ ((destructor)) +#else +#undef CA_GCC_DESTRUCTOR +#endif + +#endif diff --git a/.flatpak-builder/cache/objects/16/0eff30fb9031d0f04f843331f30aaf31dd75ac940fb79c03cca39be3b292c0.dirtree b/.flatpak-builder/cache/objects/16/0eff30fb9031d0f04f843331f30aaf31dd75ac940fb79c03cca39be3b292c0.dirtree new file mode 100644 index 0000000..66f3c19 Binary files /dev/null and b/.flatpak-builder/cache/objects/16/0eff30fb9031d0f04f843331f30aaf31dd75ac940fb79c03cca39be3b292c0.dirtree differ diff --git a/.flatpak-builder/cache/objects/16/263433b0c8ea210a980e26770b6be44bf73c932c4ebfddfdd07bf1dfe2881a.dirtree b/.flatpak-builder/cache/objects/16/263433b0c8ea210a980e26770b6be44bf73c932c4ebfddfdd07bf1dfe2881a.dirtree new file mode 100644 index 0000000..4329cea Binary files /dev/null and b/.flatpak-builder/cache/objects/16/263433b0c8ea210a980e26770b6be44bf73c932c4ebfddfdd07bf1dfe2881a.dirtree differ diff --git a/.flatpak-builder/cache/objects/16/34065eff50376b63f4ce0241d16fb104997392099ab17b39ef9b690c25bd09.dirtree b/.flatpak-builder/cache/objects/16/34065eff50376b63f4ce0241d16fb104997392099ab17b39ef9b690c25bd09.dirtree new file mode 100644 index 0000000..7fd3493 Binary files /dev/null and b/.flatpak-builder/cache/objects/16/34065eff50376b63f4ce0241d16fb104997392099ab17b39ef9b690c25bd09.dirtree differ diff --git a/.flatpak-builder/cache/objects/16/530d8f6517dd1e6cda885f8b56a36e9865b2061fb216a1a32d1692c20966de.file b/.flatpak-builder/cache/objects/16/530d8f6517dd1e6cda885f8b56a36e9865b2061fb216a1a32d1692c20966de.file new file mode 100644 index 0000000..01976e6 --- /dev/null +++ b/.flatpak-builder/cache/objects/16/530d8f6517dd1e6cda885f8b56a36e9865b2061fb216a1a32d1692c20966de.file @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2009 Bas Driessen + * Copyright (C) 2009 - 2012 Vivien Malerba + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GDA_DATA_META_WRAPPER_H__ +#define __GDA_DATA_META_WRAPPER_H__ + +#include +#include + +G_BEGIN_DECLS + +#define GDA_TYPE_DATA_META_WRAPPER (gda_data_meta_wrapper_get_type()) +G_DECLARE_DERIVABLE_TYPE(GdaDataMetaWrapper, gda_data_meta_wrapper, GDA, DATA_META_WRAPPER, GObject) + +struct _GdaDataMetaWrapperClass { + GObjectClass parent_class; + + /* Padding for future expansion */ + void (*_gda_reserved1) (void); + void (*_gda_reserved2) (void); + void (*_gda_reserved3) (void); + void (*_gda_reserved4) (void); +}; + +typedef enum { + GDA_DATA_META_WRAPPER_MODE_LC, /* quote identifier if there are some non lower case chars */ + GDA_DATA_META_WRAPPER_MODE_UC /* quote identifier if there are some non upper case chars */ +} GdaDataMetaWrapperMode; + + +GdaDataModel *_gda_data_meta_wrapper_new (GdaDataModel *model, gboolean reusable, + gint *cols, gint size, GdaSqlIdentifierStyle mode, + GdaSqlReservedKeywordsFunc reserved_keyword_func); + +GValue *_gda_data_meta_wrapper_compute_value (const GValue *value, GdaSqlIdentifierStyle mode, + GdaSqlReservedKeywordsFunc reserved_keyword_func); +G_END_DECLS + +#endif diff --git a/.flatpak-builder/cache/objects/16/7257bc91aedee4eae5f913188ac16faccdeadc1fbe70ce2463bafdc8791d5f.file b/.flatpak-builder/cache/objects/16/7257bc91aedee4eae5f913188ac16faccdeadc1fbe70ce2463bafdc8791d5f.file new file mode 100644 index 0000000..0fc953a Binary files /dev/null and b/.flatpak-builder/cache/objects/16/7257bc91aedee4eae5f913188ac16faccdeadc1fbe70ce2463bafdc8791d5f.file differ diff --git a/.flatpak-builder/cache/objects/16/c360b664f6ab39bcf34ccc08c8202157fd5b825eba486d26004c601bb3af29.file b/.flatpak-builder/cache/objects/16/c360b664f6ab39bcf34ccc08c8202157fd5b825eba486d26004c601bb3af29.file new file mode 100644 index 0000000..275327a --- /dev/null +++ b/.flatpak-builder/cache/objects/16/c360b664f6ab39bcf34ccc08c8202157fd5b825eba486d26004c601bb3af29.file @@ -0,0 +1,72 @@ +# gtk_combo_box_text.py +# +# Copyright 2021 James Westman +# +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation; either version 3 of the +# License, or (at your option) any later version. +# +# This file is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program. If not, see . +# +# SPDX-License-Identifier: LGPL-3.0-or-later + + +from .gobject_object import ObjectContent, validate_parent_type +from .common import * +from .contexts import ValueTypeCtx +from .values import StringValue + + +class Item(AstNode): + grammar = [ + Optional([UseIdent("name"), ":"]), + StringValue, + ] + + @property + def name(self) -> str: + return self.tokens["name"] + + @property + def value(self) -> StringValue: + return self.children[StringValue][0] + + @validate("name") + def unique_in_parent(self): + if self.name is not None: + self.validate_unique_in_parent( + f"Duplicate item '{self.name}'", lambda x: x.name == self.name + ) + + +class ExtComboBoxItems(AstNode): + grammar = [ + Keyword("items"), + "[", + Delimited(Item, ","), + "]", + ] + + @validate("items") + def container_is_combo_box_text(self): + validate_parent_type(self, "Gtk", "ComboBoxText", "combo box items") + + @validate("items") + def unique_in_parent(self): + self.validate_unique_in_parent("Duplicate items block") + + +@completer( + applies_in=[ObjectContent], + applies_in_subclass=("Gtk", "ComboBoxText"), + matches=new_statement_patterns, +) +def items_completer(ast_node, match_variables): + yield Completion("items", CompletionItemKind.Snippet, snippet="items [$0]") diff --git a/.flatpak-builder/cache/objects/16/d6d71ec7b8c0b385602550e267a27fd25c088a6690b4873b84887cb41a5919.dirtree b/.flatpak-builder/cache/objects/16/d6d71ec7b8c0b385602550e267a27fd25c088a6690b4873b84887cb41a5919.dirtree new file mode 100644 index 0000000..819d1ce Binary files /dev/null and b/.flatpak-builder/cache/objects/16/d6d71ec7b8c0b385602550e267a27fd25c088a6690b4873b84887cb41a5919.dirtree differ diff --git a/.flatpak-builder/cache/objects/17/533317178a990ecc364fb6b019a0d499944473b369205e6ec079d322e16944.file b/.flatpak-builder/cache/objects/17/533317178a990ecc364fb6b019a0d499944473b369205e6ec079d322e16944.file new file mode 100644 index 0000000..93de085 --- /dev/null +++ b/.flatpak-builder/cache/objects/17/533317178a990ecc364fb6b019a0d499944473b369205e6ec079d322e16944.file @@ -0,0 +1,636 @@ +/* + * Copyright (C) 2008 - 2011 Murray Cumming + * Copyright (C) 2008 - 2013 Vivien Malerba + * Copyright (C) 2009 Bas Driessen + * Copyright (C) 2010 David King + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +#define G_LOG_DOMAIN "GDA-data-comparator" + +#include +#include +#include "gda-data-comparator.h" +#include "gda-marshal.h" +#include "gda-data-model.h" + +/* + * Main static functions + */ +static void gda_data_comparator_class_init (GdaDataComparatorClass * class); +static void gda_data_comparator_init (GdaDataComparator *srv); +static void gda_data_comparator_dispose (GObject *object); + +static void gda_data_comparator_set_property (GObject *object, + guint param_id, + const GValue *value, + GParamSpec *pspec); +static void gda_data_comparator_get_property (GObject *object, + guint param_id, + GValue *value, + GParamSpec *pspec); + +static void gda_diff_free (GdaDiff *diff); + +/* signals */ +enum +{ + DIFF_COMPUTED, + LAST_SIGNAL +}; + +static gint gda_data_comparator_signals[LAST_SIGNAL] = { 0 }; + + +/* properties */ +enum +{ + PROP_0, + PROP_OLD_MODEL, + PROP_NEW_MODEL +}; + +typedef struct { + GdaDataModel *old_model; + GdaDataModel *new_model; + gint nb_key_columns; + gint *key_columns; + GArray *diffs; /* array of GdaDiff pointers */ +} GdaDataComparatorPrivate; + +G_DEFINE_TYPE_WITH_PRIVATE (GdaDataComparator, gda_data_comparator, G_TYPE_OBJECT) + + +/* module error */ +GQuark gda_data_comparator_error_quark (void) +{ + static GQuark quark; + if (!quark) + quark = g_quark_from_static_string ("gda_data_comparator_error"); + return quark; +} + +static gboolean +diff_computed_accumulator (G_GNUC_UNUSED GSignalInvocationHint *ihint, + GValue *return_accu, + const GValue *handler_return, + G_GNUC_UNUSED gpointer data) +{ + gboolean thisvalue; + + thisvalue = g_value_get_boolean (handler_return); + g_value_set_boolean (return_accu, thisvalue); + + return !thisvalue; /* stop signal if 'thisvalue' is FALSE */ +} + +static gboolean +m_diff_computed (G_GNUC_UNUSED GdaDataComparator *comparator, G_GNUC_UNUSED GdaDiff *diff) +{ + return FALSE; /* default is to allow differences computing to proceed (understand it as: FALSE => don't stop) */ +} + +static void +gda_data_comparator_class_init (GdaDataComparatorClass *class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (class); + + /* signals */ + + gda_data_comparator_signals [DIFF_COMPUTED] = + g_signal_new ("diff-computed", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GdaDataComparatorClass, diff_computed), + diff_computed_accumulator, NULL, + _gda_marshal_BOOLEAN__POINTER, G_TYPE_BOOLEAN, 1, G_TYPE_POINTER); + + class->diff_computed = m_diff_computed; + + /* virtual functions */ + object_class->dispose = gda_data_comparator_dispose; + + /* Properties */ + object_class->set_property = gda_data_comparator_set_property; + object_class->get_property = gda_data_comparator_get_property; + + g_object_class_install_property (object_class, PROP_OLD_MODEL, + g_param_spec_object ("old-model", _("Old data model"), NULL, + GDA_TYPE_DATA_MODEL, + (G_PARAM_READABLE | G_PARAM_WRITABLE))); + g_object_class_install_property (object_class, PROP_NEW_MODEL, + g_param_spec_object ("new-model", _("New data model"), NULL, + GDA_TYPE_DATA_MODEL, + (G_PARAM_READABLE | G_PARAM_WRITABLE))); +} + +static void +gda_data_comparator_init (GdaDataComparator *comparator) +{ + GdaDataComparatorPrivate *priv = gda_data_comparator_get_instance_private (comparator); + priv->diffs = g_array_new (FALSE, FALSE, sizeof (GdaDiff *)); +} + +/** + * gda_data_comparator_new: + * @old_model: Data model to which the modifications should be applied + * @new_model: Target data model. + * + * Creates a new comparator to compute the differences from @old_model to @new_model: if one applies + * all the computed differences (as #GdaDiff structures) to @old_model, the resulting data model + * should have the same contents as @new_model. + * + * Returns: (type GdaDataComparator) (transfer full): a new #GdaDataComparator object + */ +GObject * +gda_data_comparator_new (GdaDataModel *old_model, GdaDataModel *new_model) +{ + GObject *obj; + + g_return_val_if_fail (GDA_IS_DATA_MODEL (old_model), NULL); + g_return_val_if_fail (GDA_IS_DATA_MODEL (new_model), NULL); + + obj = g_object_new (GDA_TYPE_DATA_COMPARATOR, "old-model", old_model, "new-model", new_model, NULL); + + return obj; +} + +static void +clean_diff (GdaDataComparator *comparator) +{ + GdaDataComparatorPrivate *priv = gda_data_comparator_get_instance_private (comparator); + if (priv->diffs) { + gsize i; + for (i = 0; i < priv->diffs->len; i++) { + GdaDiff *diff = g_array_index (priv->diffs, GdaDiff *, i); + gda_diff_free (diff); + } + g_array_free (priv->diffs, TRUE); + } + priv->diffs = g_array_new (FALSE, FALSE, sizeof (GdaDiff *)); +} + +static void +gda_data_comparator_dispose (GObject *object) +{ + GdaDataComparator *comparator; + + g_return_if_fail (GDA_IS_DATA_COMPARATOR (object)); + + comparator = GDA_DATA_COMPARATOR (object); + GdaDataComparatorPrivate *priv = gda_data_comparator_get_instance_private (comparator); + if (priv->old_model) { + g_object_unref (priv->old_model); + priv->old_model = NULL; + } + if (priv->new_model) { + g_object_unref (priv->new_model); + priv->new_model = NULL; + } + clean_diff (comparator); + g_free (priv->key_columns); + g_array_free (priv->diffs, TRUE); + + /* parent class */ + G_OBJECT_CLASS (gda_data_comparator_parent_class)->dispose (object); +} + +static void +gda_data_comparator_set_property (GObject *object, + guint param_id, + const GValue *value, + GParamSpec *pspec) +{ + GdaDataComparator *comparator; + comparator = GDA_DATA_COMPARATOR (object); + GdaDataComparatorPrivate *priv = gda_data_comparator_get_instance_private (comparator); + if (priv) { + GdaDataModel *model; + + switch (param_id) { + case PROP_OLD_MODEL: + model = (GdaDataModel*) g_value_get_object (value); + if (priv->old_model && (priv->old_model != model)) { + /* re-init */ + clean_diff (comparator); + g_object_unref (priv->old_model); + g_free (priv->key_columns); + priv->key_columns = NULL; + } + priv->old_model = model; + if (model) + g_object_ref (model); + break; + case PROP_NEW_MODEL: + model = (GdaDataModel*) g_value_get_object (value); + if (priv->new_model && (priv->new_model != model)) { + /* re-init */ + clean_diff (comparator); + g_object_unref (priv->new_model); + g_free (priv->key_columns); + priv->key_columns = NULL; + } + priv->new_model = model; + if (model) + g_object_ref (model); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + break; + } + } +} + +static void +gda_data_comparator_get_property (GObject *object, + guint param_id, + GValue *value, + GParamSpec *pspec) +{ + GdaDataComparator *comparator; + + comparator = GDA_DATA_COMPARATOR (object); + GdaDataComparatorPrivate *priv = gda_data_comparator_get_instance_private (comparator); + if (priv) { + switch (param_id) { + case PROP_OLD_MODEL: + g_value_set_object (value, priv->old_model); + break; + case PROP_NEW_MODEL: + g_value_set_object (value, priv->new_model); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + break; + } + } +} + +static void +gda_diff_free (GdaDiff *diff) +{ + g_hash_table_destroy (diff->values); + g_free (diff); +} + +/** + * gda_data_comparator_set_key_columns: + * @comp: a #GdaDataComparator object + * @nb_cols: the size of the @col_numbers array + * @col_numbers: (array length=nb_cols): an array of @nb_cols values + * + * Defines the columns which will be used as a key when searching data. This is not mandatory but + * will speed things up as less data will be processed. + */ +void +gda_data_comparator_set_key_columns (GdaDataComparator *comp, const gint *col_numbers, gint nb_cols) +{ + g_return_if_fail (GDA_IS_DATA_COMPARATOR (comp)); + GdaDataComparatorPrivate *priv = gda_data_comparator_get_instance_private (comp); + + g_free (priv->key_columns); + priv->key_columns = NULL; + if (nb_cols > 0) { + priv->nb_key_columns = nb_cols; + priv->key_columns = g_new (gint, nb_cols); + memcpy (priv->key_columns, col_numbers, sizeof (gint) * nb_cols); /* Flawfinder: ignore */ + } +} + +/* + * Find the row in @priv->old_model from the values of @priv->new_model at line @row + * It is assumed that both data model have the same number of columns and of "compatible" types. + * + * Returns: + * -2 if an error occurred + * -1 if not found, + * >=0 if found (if changes need to be made, then @out_has_changed is set to TRUE). + */ +static gint +find_row_in_model (GdaDataComparator *comp, gint row, gboolean *out_has_changed, GError **error) +{ + gint i, erow; + gint ncols; + GSList *values = NULL; + GdaDataComparatorPrivate *priv = gda_data_comparator_get_instance_private (comp); + + *out_has_changed = FALSE; + ncols = gda_data_model_get_n_columns (priv->old_model); + if (!priv->key_columns) { + priv->nb_key_columns = ncols; + priv->key_columns = g_new (gint, ncols); + for (i = 0; i < ncols; i++) + priv->key_columns [i] = i; + } + + for (i = 0; i < priv->nb_key_columns; i++) { + const GValue *cvalue; + cvalue = gda_data_model_get_value_at (priv->new_model, priv->key_columns[i], row, error); + if (!cvalue) { + if (values) + g_slist_free (values); + return -2; + } + values = g_slist_append (values, (gpointer) cvalue); + } + + erow = gda_data_model_get_row_from_values (priv->old_model, values, priv->key_columns); + g_slist_free (values); + + if (erow >= 0) { + gboolean changed = FALSE; + for (i = 0; i < ncols; i++) { + const GValue *v1, *v2; + v1 = gda_data_model_get_value_at (priv->old_model, i, erow, error); + if (!v1) + return -2; + v2 = gda_data_model_get_value_at (priv->new_model, i, row, error); + if (!v2) + return -2; + if (gda_value_compare (v1, v2)) { + changed = TRUE; + break; + } + } + *out_has_changed = changed; + } + + return erow; +} + +/** + * gda_data_comparator_compute_diff: + * @comp: a #GdaDataComparator object + * @error: a place to store errors, or %NULL + * + * Actually computes the differences between the data models for which @comp is defined. + * + * For each difference computed, stored in a #GdaDiff structure, the "diff-computed" signal is emitted. + * If one connects to this signal and returns FALSE in the signal handler, then computing differences will be + * stopped and an error will be returned. + * + * Returns: TRUE if all the differences have been successfully computed, and FALSE if an error occurred + */ +gboolean +gda_data_comparator_compute_diff (GdaDataComparator *comp, GError **error) +{ + gint oncols, nncols, i; + gint onrows, nnrows; + gboolean *rows_to_del = NULL; + + g_return_val_if_fail (GDA_IS_DATA_COMPARATOR (comp), FALSE); + GdaDataComparatorPrivate *priv = gda_data_comparator_get_instance_private (comp); + + clean_diff (comp); + + /* check setup */ + if (!priv->old_model) { + g_set_error (error, GDA_DATA_COMPARATOR_ERROR, GDA_DATA_COMPARATOR_MISSING_DATA_MODEL_ERROR, + "%s", _("Missing original data model")); + return FALSE; + } + if (!priv->new_model) { + g_set_error (error, GDA_DATA_COMPARATOR_ERROR, GDA_DATA_COMPARATOR_MISSING_DATA_MODEL_ERROR, + "%s", _("Missing new data model")); + return FALSE; + } + if (! (gda_data_model_get_access_flags (priv->old_model) & GDA_DATA_MODEL_ACCESS_RANDOM) || + ! (gda_data_model_get_access_flags (priv->new_model) & GDA_DATA_MODEL_ACCESS_RANDOM)) { + g_set_error (error, GDA_DATA_COMPARATOR_ERROR, GDA_DATA_COMPARATOR_MODEL_ACCESS_ERROR, + "%s", _("Data models must support random access model")); + return FALSE; + } + + /* compare columns */ + oncols = gda_data_model_get_n_columns (priv->old_model); + nncols = gda_data_model_get_n_columns (priv->new_model); + if (oncols != nncols) { + g_set_error (error, GDA_DATA_COMPARATOR_ERROR, GDA_DATA_COMPARATOR_MISSING_DATA_MODEL_ERROR, + "%s", _("Data models to compare don't have the same number of columns")); + return FALSE; + } + + for (i = 0; i < oncols; i++) { + GdaColumn *ocol, *ncol; + ocol = gda_data_model_describe_column (priv->old_model, i); + ncol = gda_data_model_describe_column (priv->new_model, i); + if (gda_column_get_g_type (ocol) != gda_column_get_g_type (ncol)) { + g_set_error (error, GDA_DATA_COMPARATOR_ERROR, + GDA_DATA_COMPARATOR_COLUMN_TYPES_MISMATCH_ERROR, + _("Type mismatch for column %d: '%s' and '%s'"), i, + g_type_name (gda_column_get_g_type (ocol)), + g_type_name (gda_column_get_g_type (ncol))); + return FALSE; + } + } + + /* actual differences computations : rows to insert / update */ + onrows = gda_data_model_get_n_rows (priv->old_model); + if (onrows < 0) { + g_set_error (error, GDA_DATA_COMPARATOR_ERROR, GDA_DATA_COMPARATOR_MODEL_ACCESS_ERROR, + "%s", _("Can't get the number of rows of data model to compare from")); + return FALSE; + } + nnrows = gda_data_model_get_n_rows (priv->new_model); + if (nnrows < 0) { + g_set_error (error, GDA_DATA_COMPARATOR_ERROR, GDA_DATA_COMPARATOR_MODEL_ACCESS_ERROR, + "%s", _("Can't get the number of rows of data model to compare to")); + return FALSE; + } + if (onrows > 0) { + rows_to_del = g_new (gboolean, onrows); + memset (rows_to_del, TRUE, sizeof (gboolean) * onrows); + } + for (i = 0; i < nnrows; i++) { + gint erow = -1; + gboolean has_changed = FALSE; + GdaDiff *diff = NULL; + gboolean stop; + + erow = find_row_in_model (comp, i, &has_changed, error); + +#ifdef DEBUG_STORE_MODIFY + g_print ("FIND row %d returned row %d (%s)\n", i, erow, + has_changed ? "CHANGED" : "unchanged"); +#endif + if (erow == -1) { + gint j; + diff = g_new0 (GdaDiff, 1); + diff->type = GDA_DIFF_ADD_ROW; + diff->old_row = -1; + diff->new_row = i; + diff->values = g_hash_table_new_full (g_str_hash, g_str_equal, (GDestroyNotify) g_free, + (GDestroyNotify) gda_value_free); + for (j = 0; j < oncols; j++) { + const GValue *cvalue; + cvalue = gda_data_model_get_value_at (priv->new_model, j, i, error); + if (!cvalue) { + /* an error occurred */ + g_free (rows_to_del); + gda_diff_free (diff); + return FALSE; + } + g_hash_table_insert (diff->values, g_strdup_printf ("+%d", j), + gda_value_copy (cvalue)); + } + } + else if (erow < -1) { + /* an error occurred */ + g_free (rows_to_del); + return FALSE; + } + else if (has_changed) { + gint j; + diff = g_new0 (GdaDiff, 1); + diff->type = GDA_DIFF_MODIFY_ROW; + rows_to_del [erow] = FALSE; + diff->old_row = erow; + diff->new_row = i; + diff->values = g_hash_table_new_full (g_str_hash, g_str_equal, (GDestroyNotify) g_free, + (GDestroyNotify) gda_value_free); + for (j = 0; j < oncols; j++) { + const GValue *cvalue; + cvalue = gda_data_model_get_value_at (priv->new_model, j, i, error); + if (!cvalue) { + /* an error occurred */ + g_free (rows_to_del); + gda_diff_free (diff); + return FALSE; + } + g_hash_table_insert (diff->values, g_strdup_printf ("+%d", j), + gda_value_copy (cvalue)); + cvalue = gda_data_model_get_value_at (priv->old_model, j, i, error); + if (!cvalue) { + /* an error occurred */ + g_free (rows_to_del); + gda_diff_free (diff); + return FALSE; + } + g_hash_table_insert (diff->values, g_strdup_printf ("-%d", j), + gda_value_copy (cvalue)); + } + } + else + rows_to_del [erow] = FALSE; /* row has not been changed */ + + if (diff) { + g_array_append_val (priv->diffs, diff); + g_signal_emit (comp, gda_data_comparator_signals [DIFF_COMPUTED], 0, diff, &stop); + if (stop) { + g_set_error (error, GDA_DATA_COMPARATOR_ERROR, + GDA_DATA_COMPARATOR_USER_CANCELLED_ERROR, + "%s", _("Differences computation cancelled on signal handling")); + g_free (rows_to_del); + return FALSE; + } + } + } + + /* actual differences computations : rows to delete */ + for (i = 0; i < onrows; i++) { + GdaDiff *diff = NULL; + gboolean stop; + if (rows_to_del [i]) { + gint j; + diff = g_new0 (GdaDiff, 1); + diff->type = GDA_DIFF_REMOVE_ROW; + diff->old_row = i; + diff->new_row = -1; + diff->values = g_hash_table_new_full (g_str_hash, g_str_equal, (GDestroyNotify) g_free, + (GDestroyNotify) gda_value_free); + for (j = 0; j < oncols; j++) { + const GValue *cvalue; + cvalue = gda_data_model_get_value_at (priv->old_model, j, i, error); + if (!cvalue) { + /* an error occurred */ + g_free (rows_to_del); + gda_diff_free (diff); + return FALSE; + } + g_hash_table_insert (diff->values, g_strdup_printf ("-%d", j), + gda_value_copy (cvalue)); + } + g_array_append_val (priv->diffs, diff); + g_signal_emit (comp, gda_data_comparator_signals [DIFF_COMPUTED], 0, diff, &stop); + if (stop) { + g_set_error (error, GDA_DATA_COMPARATOR_ERROR, + GDA_DATA_COMPARATOR_USER_CANCELLED_ERROR, + "%s", _("Differences computation cancelled on signal handling")); + g_free (rows_to_del); + return FALSE; + } + } + } + + g_free (rows_to_del); + return TRUE; +} + +/** + * gda_data_comparator_get_n_diffs: + * @comp: a #GdaDataComparator object + * + * Get the number of differences as computed by the last time gda_data_comparator_compute_diff() was called. + * + * Returns: the number of computed differences + */ +gint +gda_data_comparator_get_n_diffs (GdaDataComparator *comp) +{ + g_return_val_if_fail (GDA_IS_DATA_COMPARATOR (comp), 0); + GdaDataComparatorPrivate *priv = gda_data_comparator_get_instance_private (comp); + + return priv->diffs->len; +} + +/** + * gda_data_comparator_get_diff: + * @comp: a #GdaDataComparator object + * @pos: the requested difference number (starting at 0) + * + * Get a pointer to the #GdaDiff structure representing the difference which number is @pos + * + * Returns: (transfer none): a pointer to a #GdaDiff, or %NULL if @pos is invalid + */ +const GdaDiff * +gda_data_comparator_get_diff (GdaDataComparator *comp, gint pos) +{ + g_return_val_if_fail (GDA_IS_DATA_COMPARATOR (comp), NULL); + GdaDataComparatorPrivate *priv = gda_data_comparator_get_instance_private (comp); + + return g_array_index (priv->diffs, GdaDiff*, pos); +} + +void +copy_hash (gpointer key, gpointer value, GdaDiff *dst) +{ + g_hash_table_insert (dst->values, g_strdup (key), gda_value_copy (value)); +} + +GdaDiff* +gda_diff_copy (GdaDiff *src) +{ + GdaDiff *dst = g_new0 (GdaDiff, 1); + dst->type = src->type; + dst->old_row = src->old_row; + dst->new_row = src->new_row; + dst->values = g_hash_table_new_full (g_str_hash, g_str_equal, (GDestroyNotify) g_free, + (GDestroyNotify) gda_value_free); + g_hash_table_foreach (src->values, (GHFunc)copy_hash, dst); + return dst; +} + +G_DEFINE_BOXED_TYPE (GdaDiff, gda_diff, gda_diff_copy, gda_diff_free) diff --git a/.flatpak-builder/cache/objects/17/6ba002d1a29f5c9b1a8094186d19bff793b2e4b5545359493432d101a7cc47.dirtree b/.flatpak-builder/cache/objects/17/6ba002d1a29f5c9b1a8094186d19bff793b2e4b5545359493432d101a7cc47.dirtree new file mode 100644 index 0000000..3d2c5cc Binary files /dev/null and b/.flatpak-builder/cache/objects/17/6ba002d1a29f5c9b1a8094186d19bff793b2e4b5545359493432d101a7cc47.dirtree differ diff --git a/.flatpak-builder/cache/objects/17/740ab418b8390fe837fba33c6df954d3fdfc568aced924861f45c12880ade5.file b/.flatpak-builder/cache/objects/17/740ab418b8390fe837fba33c6df954d3fdfc568aced924861f45c12880ade5.file new file mode 120000 index 0000000..388456e --- /dev/null +++ b/.flatpak-builder/cache/objects/17/740ab418b8390fe837fba33c6df954d3fdfc568aced924861f45c12880ade5.file @@ -0,0 +1 @@ +../../share/runtime/locale/fa/share/fa \ No newline at end of file diff --git a/.flatpak-builder/cache/objects/17/f7246644aaf12c7cfb5c85ef377eed37994b13852a1dd73c6f6116e451f5a1.dirtree b/.flatpak-builder/cache/objects/17/f7246644aaf12c7cfb5c85ef377eed37994b13852a1dd73c6f6116e451f5a1.dirtree new file mode 100644 index 0000000..7b28ceb Binary files /dev/null and b/.flatpak-builder/cache/objects/17/f7246644aaf12c7cfb5c85ef377eed37994b13852a1dd73c6f6116e451f5a1.dirtree differ diff --git a/.flatpak-builder/cache/objects/18/2b6df4445ffc389f4e4d79bd267dadef3a8b8595a9d659883c3e42e9e1245a.file b/.flatpak-builder/cache/objects/18/2b6df4445ffc389f4e4d79bd267dadef3a8b8595a9d659883c3e42e9e1245a.file new file mode 100644 index 0000000..3dd09a0 --- /dev/null +++ b/.flatpak-builder/cache/objects/18/2b6df4445ffc389f4e4d79bd267dadef3a8b8595a9d659883c3e42e9e1245a.file @@ -0,0 +1,79 @@ +# xml_emitter.py +# +# Copyright 2021 James Westman +# +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation; either version 3 of the +# License, or (at your option) any later version. +# +# This file is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program. If not, see . +# +# SPDX-License-Identifier: LGPL-3.0-or-later + +import typing as T + +from xml.sax import saxutils + +from blueprintcompiler.gir import GirType +from blueprintcompiler.language.types import ClassName + + +class XmlEmitter: + def __init__(self, indent=2): + self.indent = indent + self.result = '' + self._tag_stack = [] + self._needs_newline = False + + def start_tag(self, tag, **attrs: T.Union[str, GirType, ClassName, bool, None]): + self._indent() + self.result += f"<{tag}" + for key, val in attrs.items(): + if val is not None: + self.result += f' {key.replace("_", "-")}="{saxutils.escape(self._to_string(val))}"' + self.result += ">" + self._tag_stack.append(tag) + self._needs_newline = False + + def put_self_closing(self, tag, **attrs): + self._indent() + self.result += f"<{tag}" + for key, val in attrs.items(): + if val is not None: + self.result += f' {key.replace("_", "-")}="{saxutils.escape(self._to_string(val))}"' + self.result += "/>" + self._needs_newline = True + + def end_tag(self): + tag = self._tag_stack.pop() + if self._needs_newline: + self._indent() + self.result += f"" + self._needs_newline = True + + def put_text(self, text: T.Union[str, int, float]): + self.result += saxutils.escape(str(text)) + self._needs_newline = False + + def put_cdata(self, text: str): + self.result += f"" + self._needs_newline = False + + def _indent(self): + if self.indent is not None: + self.result += "\n" + " " * (self.indent * len(self._tag_stack)) + + def _to_string(self, val): + if isinstance(val, GirType): + return val.glib_type_name + elif isinstance(val, ClassName): + return val.glib_type_name + else: + return str(val) diff --git a/.flatpak-builder/cache/objects/18/30bb0d9c3e0e3c3d86cf64c5cf8fb2d9018cf397d682244bfcad03b342c671.dirtree b/.flatpak-builder/cache/objects/18/30bb0d9c3e0e3c3d86cf64c5cf8fb2d9018cf397d682244bfcad03b342c671.dirtree new file mode 100644 index 0000000..64344cd Binary files /dev/null and b/.flatpak-builder/cache/objects/18/30bb0d9c3e0e3c3d86cf64c5cf8fb2d9018cf397d682244bfcad03b342c671.dirtree differ diff --git a/.flatpak-builder/cache/objects/18/de0c81f5ee5024dbeeb6a8739b96a3abfaa5027504ded5032d071c89eee8f4.file b/.flatpak-builder/cache/objects/18/de0c81f5ee5024dbeeb6a8739b96a3abfaa5027504ded5032d071c89eee8f4.file new file mode 100644 index 0000000..62c96ec --- /dev/null +++ b/.flatpak-builder/cache/objects/18/de0c81f5ee5024dbeeb6a8739b96a3abfaa5027504ded5032d071c89eee8f4.file @@ -0,0 +1,40 @@ +/*-*- Mode: C; c-basic-offset: 8 -*-*/ + +#ifndef foocanberradriverhfoo +#define foocanberradriverhfoo + +/*** + This file is part of libcanberra. + + Copyright 2008 Lennart Poettering + + libcanberra is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation, either version 2.1 of the + License, or (at your option) any later version. + + libcanberra is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with libcanberra. If not, see + . +***/ + +#include "canberra.h" + +int driver_open(ca_context *c); +int driver_destroy(ca_context *c); + +int driver_change_device(ca_context *c, const char *device); +int driver_change_props(ca_context *c, ca_proplist *changed, ca_proplist *merged); + +int driver_play(ca_context *c, uint32_t id, ca_proplist *p, ca_finish_callback_t cb, void *userdata); +int driver_cancel(ca_context *c, uint32_t id); +int driver_cache(ca_context *c, ca_proplist *p); + +int driver_playing(ca_context *c, uint32_t id, int *playing); + +#endif diff --git a/.flatpak-builder/cache/objects/1a/8166f0fa0e924326b298e939b5b35c5a0365fca887943c29159d21b5ddf7cb.file b/.flatpak-builder/cache/objects/1a/8166f0fa0e924326b298e939b5b35c5a0365fca887943c29159d21b5ddf7cb.file new file mode 120000 index 0000000..706058c --- /dev/null +++ b/.flatpak-builder/cache/objects/1a/8166f0fa0e924326b298e939b5b35c5a0365fca887943c29159d21b5ddf7cb.file @@ -0,0 +1 @@ +../../share/runtime/locale/az/share/az \ No newline at end of file diff --git a/.flatpak-builder/cache/objects/1a/eb086d04ad79b4a41518bbb21bdb9b46ffd39884b2f720710173ed32f01c0b.dirtree b/.flatpak-builder/cache/objects/1a/eb086d04ad79b4a41518bbb21bdb9b46ffd39884b2f720710173ed32f01c0b.dirtree new file mode 100644 index 0000000..ecded52 Binary files /dev/null and b/.flatpak-builder/cache/objects/1a/eb086d04ad79b4a41518bbb21bdb9b46ffd39884b2f720710173ed32f01c0b.dirtree differ diff --git a/.flatpak-builder/cache/objects/1b/3666c4f47509c671bb9194c15b3873d728410c3af57110f4bf008c3b5bf9cc.file b/.flatpak-builder/cache/objects/1b/3666c4f47509c671bb9194c15b3873d728410c3af57110f4bf008c3b5bf9cc.file new file mode 100644 index 0000000..6854584 --- /dev/null +++ b/.flatpak-builder/cache/objects/1b/3666c4f47509c671bb9194c15b3873d728410c3af57110f4bf008c3b5bf9cc.file @@ -0,0 +1,564 @@ +/* + * Copyright (C) 2001 - 2003 Rodrigo Moya + * Copyright (C) 2001 - 2014 Vivien Malerba + * Copyright (C) 2002 Gonzalo Paniagua Javier + * Copyright (C) 2003 Laurent Sansonetti + * Copyright (C) 2006 Murray Cumming + * Copyright (C) 2008 Przemysław Grzegorczyk + * Copyright (C) 2010 Jonh Wendell + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +#define G_LOG_DOMAIN "GDA-quark-list" + +#include +#include +#include + +#ifdef USE_MLOCK +#include +#endif +#ifdef G_OS_WIN32 +#include +#include +#endif + +#define RANDOM_BLOB_SIZE 1024 +static gchar random_blob [RANDOM_BLOB_SIZE] = {0}; +static void ensure_static_blob_filled (void); + +typedef struct { + guint offset;/* offset in random_blob XOR from */ + gchar *pvalue; /* XORed value, not 0 terminated */ + gchar *cvalue; /* clear value, memory allocated with malloc() and mlock() */ +} ProtectedValue; + +static ProtectedValue *protected_value_new (gchar *cvalue); +static void protected_value_free (ProtectedValue *pvalue); +static void protected_value_xor (ProtectedValue *pvalue, gboolean to_clear); + +struct _GdaQuarkList { + GHashTable *hash_table; + GHashTable *hash_protected; +}; + +GType gda_quark_list_get_type (void) +{ + static GType our_type = 0; + + if (our_type == 0) + our_type = g_boxed_type_register_static ("GdaQuarkList", + (GBoxedCopyFunc) gda_quark_list_copy, + (GBoxedFreeFunc) gda_quark_list_free); + return our_type; +} + +/* + * Private functions + */ + +static void +ensure_static_blob_filled (void) +{ + if (random_blob [0] == 0) { + guint i; + for (i = 0; i < RANDOM_BLOB_SIZE; i++) { + random_blob [i] = g_random_int_range (1, 255); + /*g_print ("%02x ", (guchar) random_blob [i]);*/ + } +#ifdef G_OS_WIN32 + VirtualLock (random_blob, sizeof (gchar) * RANDOM_BLOB_SIZE); +#else +#ifdef USE_MLOCK + mlock (random_blob, sizeof (gchar) * RANDOM_BLOB_SIZE); +#endif +#endif + } +} + +static void +copy_hash_pair (gpointer key, gpointer value, gpointer user_data) +{ + g_hash_table_insert ((GHashTable *) user_data, + g_strdup ((const char *) key), + g_strdup ((const char *) value)); +} + +guint +protected_get_length (gchar *str, guint offset) +{ + gchar *ptr; + guint i; + ensure_static_blob_filled (); + for (i = 0, ptr = str; i < RANDOM_BLOB_SIZE - offset - 1; i++, ptr++) { + gchar c0, c1; + c0 = *ptr; + c1 = c0 ^ random_blob [offset + i]; + if (!c1) + break; + } + return i; +} + +static void +protected_value_xor (ProtectedValue *pvalue, gboolean to_clear) +{ + if (to_clear) { + if (! pvalue->cvalue) { + guint i, l; + ensure_static_blob_filled (); + l = protected_get_length (pvalue->pvalue, pvalue->offset); + pvalue->cvalue = malloc (sizeof (gchar) * (l + 1)); + for (i = 0; i < l; i++) + pvalue->cvalue [i] = pvalue->pvalue [i] ^ random_blob [pvalue->offset + i]; + pvalue->cvalue [l] = 0; +#ifdef G_OS_WIN32 + VirtualLock (pvalue->cvalue, sizeof (gchar) * (l + 1)); +#else +#ifdef USE_MLOCK + mlock (pvalue->cvalue, sizeof (gchar) * (l + 1)); +#endif +#endif + /*g_print ("Unmangled [%s]\n", pvalue->cvalue);*/ + } + } + else { + if (pvalue->cvalue) { + /*g_print ("Mangled [%s]\n", pvalue->cvalue);*/ + guint i; + for (i = 0; ; i++) { + gchar c; + c = pvalue->cvalue[i]; + pvalue->cvalue[i] = g_random_int_range (1, 255); + if (!c) + break; + } +#ifdef G_OS_WIN32 + VirtualUnlock (pvalue->cvalue, sizeof (gchar) * (i + 1)); +#else +#ifdef USE_MLOCK + munlock (pvalue->cvalue, sizeof (gchar) * (i + 1)); +#endif +#endif + free (pvalue->cvalue); + pvalue->cvalue = NULL; + } + } +} + +static void +copy_hash_pair_protected (gpointer key, gpointer value, gpointer user_data) +{ + ProtectedValue *p1, *p2; + guint l; + p1 = (ProtectedValue*) value; + p2 = g_new0 (ProtectedValue, 1); + l = protected_get_length (p1->pvalue, p1->offset); + p2->pvalue = g_new (gchar, l + 1); + memcpy (p2->pvalue, p1->pvalue, l + 1); + p2->offset = p1->offset; + p2->cvalue = NULL; + g_hash_table_insert ((GHashTable *) user_data, + g_strdup ((const char *) key), p2); +} + +static ProtectedValue * +protected_value_new (gchar *cvalue) +{ + ProtectedValue *pvalue; + guint i, l; + l = strlen (cvalue); + if (l >= RANDOM_BLOB_SIZE) { + g_warning ("Value too big to protect!"); + return NULL; + } + + /*g_print ("Initially mangled [%s]\n", cvalue);*/ + ensure_static_blob_filled (); + pvalue = g_new (ProtectedValue, 1); + pvalue->offset = g_random_int_range (0, RANDOM_BLOB_SIZE - l - 2); + pvalue->pvalue = g_new (gchar, l + 1); + pvalue->cvalue = NULL; + for (i = 0; i <= l; i++) { + pvalue->pvalue [i] = cvalue [i] ^ random_blob [pvalue->offset + i]; + cvalue [i] = g_random_int_range (0, 255); + } + return pvalue; +} + +static void +protected_value_free (ProtectedValue *pvalue) +{ + g_free (pvalue->pvalue); + if (pvalue->cvalue) + protected_value_xor (pvalue, FALSE); + g_free (pvalue); +} + +/** + * gda_quark_list_new: + * + * Creates a new #GdaQuarkList, which is a set of key->value pairs, + * very similar to GLib's GHashTable, but with the only purpose to + * make easier the parsing and creation of data source connection + * strings. + * + * Returns: (transfer full): the newly created #GdaQuarkList. + * + * Free-function: gda_quark_list_free + */ +GdaQuarkList * +gda_quark_list_new (void) +{ + GdaQuarkList *qlist; + + qlist = g_new0 (GdaQuarkList, 1); + qlist->hash_table = NULL; + qlist->hash_protected = NULL; + + return qlist; +} + +/** + * gda_quark_list_new_from_string: + * @string: a string. + * + * Creates a new #GdaQuarkList given a string. + * + * @string must be a semi-colon separated list of "<key>=<value>" strings (for example + * "DB_NAME=notes;USERNAME=alfred"). Each key and value must respect the RFC 1738 recommendations: the + * <>"#%{}|\^~[]'`;/?:@=& and space characters are replaced by + * "%%ab" where + * ab is the hexadecimal number corresponding to the character (for example the + * "DB_NAME=notes;USERNAME=al%%20fred" string will specify a username as "al fred"). If this formalism + * is not respected, then some unexpected results may occur. + * + * Returns: (transfer full): the newly created #GdaQuarkList. + * + * Free-function: gda_quark_list_free + */ +GdaQuarkList * +gda_quark_list_new_from_string (const gchar *string) +{ + GdaQuarkList *qlist; + + qlist = gda_quark_list_new (); + gda_quark_list_add_from_string (qlist, string, FALSE); + + return qlist; +} + +/** + * gda_quark_list_clear: + * @qlist: a #GdaQuarkList. + * + * Removes all strings in the given #GdaQuarkList. + */ +void +gda_quark_list_clear (GdaQuarkList *qlist) +{ + g_return_if_fail (qlist != NULL); + + if (qlist->hash_table) + g_hash_table_remove_all (qlist->hash_table); + if (qlist->hash_protected) + g_hash_table_remove_all (qlist->hash_protected); +} + +/** + * gda_quark_list_free: + * @qlist: (nullable): a #GdaQuarkList, or %NULL + * + * Releases all memory occupied by the given #GdaQuarkList. + */ +void +gda_quark_list_free (GdaQuarkList *qlist) +{ + if (qlist) { + if (qlist->hash_table) + g_hash_table_destroy (qlist->hash_table); + if (qlist->hash_protected) + g_hash_table_destroy (qlist->hash_protected); + g_free (qlist); + } +} + + +/** + * gda_quark_list_copy: + * @qlist: quark_list to get a copy from. + * + * Creates a new #GdaQuarkList from an existing one. + * + * Returns: a newly allocated #GdaQuarkList with a copy of the data in @qlist. + */ +GdaQuarkList * +gda_quark_list_copy (GdaQuarkList *qlist) +{ + GdaQuarkList *new_qlist; + + g_return_val_if_fail (qlist != NULL, NULL); + + new_qlist = gda_quark_list_new (); + if (qlist->hash_table) { + new_qlist->hash_table = g_hash_table_new_full (g_str_hash, + g_str_equal, + g_free, g_free); + g_hash_table_foreach (qlist->hash_table, copy_hash_pair, new_qlist->hash_table); + } + if (qlist->hash_protected) { + new_qlist->hash_protected = g_hash_table_new_full (g_str_hash, + g_str_equal, + g_free, + (GDestroyNotify) protected_value_free); + g_hash_table_foreach (qlist->hash_protected, copy_hash_pair_protected, + new_qlist->hash_protected); + } + return new_qlist; +} + +static gboolean +name_is_protected (const gchar *name) +{ + if (!g_ascii_strncasecmp (name, "pass", 4) || + !g_ascii_strncasecmp (name, "username", 8)) + return TRUE; + else + return FALSE; +} + +/** + * gda_quark_list_add_from_string: + * @qlist: a #GdaQuarkList. + * @string: a string. + * @cleanup: whether to cleanup the previous content or not. + * + * @string must be a semi-colon separated list of "<key>=<value>" strings (for example + * "DB_NAME=notes;USERNAME=alfred"). Each key and value must respect the RFC 1738 recommendations: the + * <>"#%{}|\^~[]'`;/?:@=& and space characters are replaced by + * "%%ab" where + * ab is the hexadecimal number corresponding to the character (for example the + * "DB_NAME=notes;USERNAME=al%%20fred" string will specify a username as "al fred"). If this formalism + * is not respected, then some unexpected results may occur. + * + * Some corner cases for any string part (delimited by the semi-colon): + * + * If it does not respect the "<key>=<value>" format then it will be ignored. + * Only the 1st equal character is used to separate the key from the value part (which means + * any other equal sign will be part of the value) + * + * + * + * Adds new key->value pairs from the given @string. If @cleanup is + * set to %TRUE, the previous contents will be discarded before adding + * the new pairs. + */ +void +gda_quark_list_add_from_string (GdaQuarkList *qlist, const gchar *string, gboolean cleanup) +{ + g_return_if_fail (qlist != NULL); + + gchar **arr; + + if (!string || !*string) + return; + + if (cleanup) + gda_quark_list_clear (qlist); + + arr = g_strsplit (string, ";", -1); + if (arr != NULL) { + guint n; + for (n = 0; arr[n] && (* (arr[n])); n++) { + gchar **pair; + gchar *tmp; + for (tmp = arr[n]; *tmp; tmp++) { + if (*tmp == '=') + break; + } + if (!*tmp) { + /* ignore this string since it does not contain the '=' char */ + continue; + } + + pair = (gchar **) g_strsplit (arr[n], "=", 2); + if (pair && pair[0]) { + gchar *name = pair[0]; + gchar *value = pair[1]; + g_strstrip (name); + gda_rfc1738_decode (name); + if (value) { + g_strstrip (value); + gda_rfc1738_decode (value); + } + + if (! name_is_protected (name)) { + if (!qlist->hash_table) + qlist->hash_table = g_hash_table_new_full (g_str_hash, + g_str_equal, + g_free, g_free); + g_hash_table_insert (qlist->hash_table, + (gpointer) name, (gpointer) value); + } + else { + ProtectedValue *pvalue; + pvalue = protected_value_new (value); + if (pvalue) { + if (!qlist->hash_protected) + qlist->hash_protected = g_hash_table_new_full (g_str_hash, + g_str_equal, + g_free, + (GDestroyNotify) protected_value_free); + g_hash_table_insert (qlist->hash_protected, + (gpointer) name, (gpointer) pvalue); + g_free (value); /* has been mangled */ + } + else { + if (!qlist->hash_table) + qlist->hash_table = g_hash_table_new_full (g_str_hash, + g_str_equal, + g_free, g_free); + g_hash_table_insert (qlist->hash_table, + (gpointer) name, (gpointer) value); + } + } + g_free (pair); + } + else + g_strfreev (pair); + } + g_strfreev (arr); + } +} + +/** + * gda_quark_list_find: + * @qlist: a #GdaQuarkList. + * @name: the name of the value to search for. + * + * Searches for the value identified by @name in the given #GdaQuarkList. For protected values + * (authentification data), don't forget to call gda_quark_list_protect_values() when you + * don't need them anymore (when needed again, they will be unmangled again). + * + * Returns: the value associated with the given key if found, or %NULL if not found. + */ +const gchar * +gda_quark_list_find (GdaQuarkList *qlist, const gchar *name) +{ + gchar *value = NULL; + g_return_val_if_fail (qlist, NULL); + g_return_val_if_fail (name, NULL); + + if (qlist->hash_table) + value = g_hash_table_lookup (qlist->hash_table, name); + if (value) + return value; + + ProtectedValue *pvalue = NULL; + if (qlist->hash_protected) + pvalue = g_hash_table_lookup (qlist->hash_protected, name); + if (pvalue) { + if (! pvalue->cvalue) + protected_value_xor (pvalue, TRUE); + return pvalue->cvalue; + } + else + return NULL; +} + +/** + * gda_quark_list_remove: + * @qlist: a #GdaQuarkList structure. + * @name: an entry name. + * + * Removes an entry from the #GdaQuarkList, given its name. + */ +void +gda_quark_list_remove (GdaQuarkList *qlist, const gchar *name) +{ + gboolean removed = FALSE; + g_return_if_fail (qlist != NULL); + g_return_if_fail (name != NULL); + + if (qlist->hash_table && g_hash_table_remove (qlist->hash_table, name)) + removed = TRUE; + if (!removed && qlist->hash_protected) + g_hash_table_remove (qlist->hash_protected, name); +} + +typedef struct { + gpointer user_data; + GHFunc func; +} PFuncData; + +static void +p_foreach (gchar *key, ProtectedValue *pvalue, PFuncData *data) +{ + if (pvalue->cvalue) + data->func ((gpointer) key, (gpointer) pvalue->cvalue, data->user_data); + else { + protected_value_xor (pvalue, TRUE); + data->func ((gpointer) key, (gpointer) pvalue->cvalue, data->user_data); + protected_value_xor (pvalue, FALSE); + } +} + +/** + * gda_quark_list_foreach: + * @qlist: a #GdaQuarkList structure. + * @func: (scope call): the function to call for each key/value pair + * @user_data: (closure): user data to pass to the function + * + * Calls the given function for each of the key/value pairs in @qlist. The function is passed the key and value + * of each pair, and the given user_data parameter. @qlist may not be modified while iterating over it. + */ +void +gda_quark_list_foreach (GdaQuarkList *qlist, GHFunc func, gpointer user_data) +{ + g_return_if_fail (qlist); + + if (qlist->hash_table) + g_hash_table_foreach (qlist->hash_table, func, user_data); + if (qlist->hash_protected) { + PFuncData pdata; + pdata.user_data = user_data; + pdata.func = func; + g_hash_table_foreach (qlist->hash_protected, (GHFunc) p_foreach, &pdata); + } +} + +static void +protect_foreach (G_GNUC_UNUSED gchar *key, ProtectedValue *pvalue, G_GNUC_UNUSED gpointer data) +{ + if (pvalue && pvalue->cvalue) + protected_value_xor (pvalue, FALSE); +} + +/** + * gda_quark_list_protect_values: + * @qlist: (nullable): a #GdaQuarkList, or %NULL + * + * Call this function to get rid of the clear version of all the values stored in @qlist. If @qlist is %NULL, + * then this function does nothing. + * + * Since: 5.2.0 + */ +void +gda_quark_list_protect_values (GdaQuarkList *qlist) +{ + if (qlist && qlist->hash_protected) + g_hash_table_foreach (qlist->hash_protected, (GHFunc) protect_foreach, NULL); +} diff --git a/.flatpak-builder/cache/objects/1b/483e677e03d117be8c8afb031abfc7f40d0958f844fe26d5fea5ec24c0791c.dirtree b/.flatpak-builder/cache/objects/1b/483e677e03d117be8c8afb031abfc7f40d0958f844fe26d5fea5ec24c0791c.dirtree new file mode 100644 index 0000000..e990773 Binary files /dev/null and b/.flatpak-builder/cache/objects/1b/483e677e03d117be8c8afb031abfc7f40d0958f844fe26d5fea5ec24c0791c.dirtree differ diff --git a/.flatpak-builder/cache/objects/1b/4c088a4f92c4500d26599f08ad0578e3244fbc997df65f74bf066a81b2a859.dirtree b/.flatpak-builder/cache/objects/1b/4c088a4f92c4500d26599f08ad0578e3244fbc997df65f74bf066a81b2a859.dirtree new file mode 100644 index 0000000..3933931 Binary files /dev/null and b/.flatpak-builder/cache/objects/1b/4c088a4f92c4500d26599f08ad0578e3244fbc997df65f74bf066a81b2a859.dirtree differ diff --git a/.flatpak-builder/cache/objects/1b/55ee4f417fb7e0407620d908057cd5d862bd68623804492b2649e756d51e5e.file b/.flatpak-builder/cache/objects/1b/55ee4f417fb7e0407620d908057cd5d862bd68623804492b2649e756d51e5e.file new file mode 100644 index 0000000..13f6eb1 --- /dev/null +++ b/.flatpak-builder/cache/objects/1b/55ee4f417fb7e0407620d908057cd5d862bd68623804492b2649e756d51e5e.file @@ -0,0 +1,284 @@ +# ast_utils.py +# +# Copyright 2021 James Westman +# +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation; either version 3 of the +# License, or (at your option) any later version. +# +# This file is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program. If not, see . +# +# SPDX-License-Identifier: LGPL-3.0-or-later + +from collections import ChainMap, defaultdict +from functools import cached_property +import typing as T + +from .errors import * +from .lsp_utils import SemanticToken + +TType = T.TypeVar("TType") + + +class Children: + """Allows accessing children by type using array syntax.""" + + def __init__(self, children): + self._children = children + + def __iter__(self) -> T.Iterator["AstNode"]: + return iter(self._children) + + @T.overload + def __getitem__(self, key: T.Type[TType]) -> T.List[TType]: + ... + + @T.overload + def __getitem__(self, key: int) -> "AstNode": + ... + + def __getitem__(self, key): + if isinstance(key, int): + if key >= len(self._children): + return None + else: + return self._children[key] + else: + return [child for child in self._children if isinstance(child, key)] + + +TCtx = T.TypeVar("TCtx") +TAttr = T.TypeVar("TAttr") + + +class Ctx: + """Allows accessing values from higher in the syntax tree.""" + + def __init__(self, node: "AstNode") -> None: + self.node = node + + def __getitem__(self, key: T.Type[TCtx]) -> T.Optional[TCtx]: + attrs = self.node._attrs_by_type(Context) + for name, attr in attrs: + if attr.type == key: + return getattr(self.node, name) + if self.node.parent is not None: + return self.node.parent.context[key] + else: + return None + + +class AstNode: + """Base class for nodes in the abstract syntax tree.""" + + completers: T.List = [] + attrs_by_type: T.Dict[T.Type, T.List] = {} + + def __init__(self, group, children, tokens, incomplete=False): + self.group = group + self.children = Children(children) + self.tokens = ChainMap(tokens, defaultdict(lambda: None)) + self.incomplete = incomplete + + self.parent = None + for child in self.children: + child.parent = self + + def __init_subclass__(cls): + cls.completers = [] + cls.validators = [ + getattr(cls, f) for f in dir(cls) if hasattr(getattr(cls, f), "_validator") + ] + cls.attrs_by_type = {} + + @cached_property + def context(self): + return Ctx(self) + + @cached_property + def root(self): + if self.parent is None: + return self + else: + return self.parent.root + + def parent_by_type(self, type: T.Type[TType]) -> TType: + if self.parent is None: + raise CompilerBugError() + elif isinstance(self.parent, type): + return self.parent + else: + return self.parent.parent_by_type(type) + + @cached_property + def errors(self): + return list( + error + for error in self._get_errors() + if not isinstance(error, CompileWarning) + ) + + @cached_property + def warnings(self): + return list( + warning + for warning in self._get_errors() + if isinstance(warning, CompileWarning) + ) + + def _get_errors(self): + for validator in self.validators: + try: + validator(self) + except CompileError as e: + yield e + if e.fatal: + return + + for child in self.children: + yield from child._get_errors() + + def _attrs_by_type(self, attr_type: T.Type[TAttr]) -> T.List[T.Tuple[str, TAttr]]: + if attr_type not in self.attrs_by_type: + self.attrs_by_type[attr_type] = [] + for name in dir(type(self)): + item = getattr(type(self), name) + if isinstance(item, attr_type): + self.attrs_by_type[attr_type].append((name, item)) + return self.attrs_by_type[attr_type] + + def get_docs(self, idx: int) -> T.Optional[str]: + for name, attr in self._attrs_by_type(Docs): + if attr.token_name: + token = self.group.tokens.get(attr.token_name) + if token and token.start <= idx < token.end: + return getattr(self, name) + else: + return getattr(self, name) + + for child in self.children: + if child.group.start <= idx < child.group.end: + docs = child.get_docs(idx) + if docs is not None: + return docs + + return None + + def get_semantic_tokens(self) -> T.Iterator[SemanticToken]: + for child in self.children: + yield from child.get_semantic_tokens() + + def validate_unique_in_parent( + self, error: str, check: T.Optional[T.Callable[["AstNode"], bool]] = None + ): + for child in self.parent.children: + if child is self: + break + + if type(child) is type(self): + if check is None or check(child): + raise CompileError( + error, + references=[ + ErrorReference( + child.group.start, + child.group.end, + "previous declaration was here", + ) + ], + ) + + +def validate(token_name=None, end_token_name=None, skip_incomplete=False): + """Decorator for functions that validate an AST node. Exceptions raised + during validation are marked with range information from the tokens.""" + + def decorator(func): + def inner(self): + if skip_incomplete and self.incomplete: + return + + try: + func(self) + except CompileError as e: + # If the node is only partially complete, then an error must + # have already been reported at the parsing stage + if self.incomplete: + return + + # This mess of code sets the error's start and end positions + # from the tokens passed to the decorator, if they have not + # already been set + if e.start is None: + if token := self.group.tokens.get(token_name): + e.start = token.start + else: + e.start = self.group.start + + if e.end is None: + if token := self.group.tokens.get(end_token_name): + e.end = token.end + elif token := self.group.tokens.get(token_name): + e.end = token.end + else: + e.end = self.group.end + + # Re-raise the exception + raise e + + inner._validator = True + return inner + + return decorator + + +class Docs: + def __init__(self, func, token_name=None): + self.func = func + self.token_name = token_name + + def __get__(self, instance, owner): + if instance is None: + return self + return self.func(instance) + + +def docs(*args, **kwargs): + """Decorator for functions that return documentation for tokens.""" + + def decorator(func): + return Docs(func, *args, **kwargs) + + return decorator + + +class Context: + def __init__(self, type: T.Type[TCtx], func: T.Callable[[AstNode], TCtx]) -> None: + self.type = type + self.func = func + + def __get__(self, instance, owner): + if instance is None: + return self + if ctx := getattr(instance, "_context_" + self.type.__name__, None): + return ctx + else: + ctx = self.func(instance) + setattr(instance, "_context_" + self.type.__name__, ctx) + return ctx + + +def context(type: T.Type[TCtx]): + """Decorator for functions that return a context object, which is passed down to .""" + + def decorator(func: T.Callable[[AstNode], TCtx]) -> Context: + return Context(type, func) + + return decorator diff --git a/.flatpak-builder/cache/objects/1c/01555a2aa570745efe945149caf00525cd542a287cad9d608edd1fb9f1a48a.file b/.flatpak-builder/cache/objects/1c/01555a2aa570745efe945149caf00525cd542a287cad9d608edd1fb9f1a48a.file new file mode 100644 index 0000000..46e60c4 --- /dev/null +++ b/.flatpak-builder/cache/objects/1c/01555a2aa570745efe945149caf00525cd542a287cad9d608edd1fb9f1a48a.file @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2000 Reinhard Müller + * Copyright (C) 2000 - 2002 Rodrigo Moya + * Copyright (C) 2001 Carlos Perelló Marín + * Copyright (C) 2001 - 2012 Vivien Malerba + * Copyright (C) 2002 Gonzalo Paniagua Javier + * Copyright (C) 2011 Murray Cumming + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GDA_SQL_STATEMENT_H__ +#define __GDA_SQL_STATEMENT_H__ + +G_BEGIN_DECLS + +/** + * SECTION:gda-sql-statement + * @short_description: SQL statement + * @title: GdaSqlStatement + * @stability: Stable + * @see_also: The #GdaSqlBuilder object which features some easy to use API to build #GdaSqlStatement structures or #GdaStatement objects without having to worry about the details of #GdaSqlStatement's contents. + * + * Use the #GdaSqlBuilder object to build #GdaSqlStatement structures. + * + * Every SQL statement can be decomposed in a #GdaSqlStatement structure. This is not a #GObject, but rather just a C structure + * which can be manipulated directly. The structure is a tree composed of several key structures which are show in the following diagram + * (even though it does not show, all structures "inherit" the #GdaSqlAnyPart structure which holds some basic information). + * + * + * + * + * + * + * Main parts of the #GdaSqlStatement structure. + * + * + * + * + * The examples/SqlParserConsole directory of &LIBGDA;'s sources contains a small utility + * to display statements' structures as a graph (using the GraphViz language). It has been used to + * provide the examples in this section of the documentation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +G_END_DECLS + +#endif diff --git a/.flatpak-builder/cache/objects/1c/b3d54fadebfd7ba824b14db00354eae69aced2d49e6fc55fdff93fda3f4d55.file b/.flatpak-builder/cache/objects/1c/b3d54fadebfd7ba824b14db00354eae69aced2d49e6fc55fdff93fda3f4d55.file new file mode 100644 index 0000000..1e7e4a2 --- /dev/null +++ b/.flatpak-builder/cache/objects/1c/b3d54fadebfd7ba824b14db00354eae69aced2d49e6fc55fdff93fda3f4d55.file @@ -0,0 +1,168 @@ +/* + * Copyright (C) 2009 - 2010 Murray Cumming + * Copyright (C) 2009 - 2011 Vivien Malerba + * Copyright (C) 2010 Jonh Wendell + * Copyright (C) 2011 Daniel Espinosa + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GDA_SQL_BUILDER_H_ +#define __GDA_SQL_BUILDER_H_ + +#include +#include +#include + +G_BEGIN_DECLS + +#define GDA_TYPE_SQL_BUILDER (gda_sql_builder_get_type()) +G_DECLARE_DERIVABLE_TYPE (GdaSqlBuilder,gda_sql_builder,GDA,SQL_BUILDER,GObject) + +/* error reporting */ +extern GQuark gda_sql_builder_error_quark (void); +#define GDA_SQL_BUILDER_ERROR gda_sql_builder_error_quark () + +typedef enum { + GDA_SQL_BUILDER_WRONG_TYPE_ERROR, + GDA_SQL_BUILDER_MISUSE_ERROR +} GdaSqlBuilderError; + + +/* struct for the object's data */ +/*struct _GdaSqlBuilder +{ + GObject object; + GdaSqlBuilderPrivate *priv; +}; +*/ +/* struct for the object's class */ +struct _GdaSqlBuilderClass +{ + GObjectClass parent_class; + + /*< private >*/ + /* Padding for future expansion */ + void (*_gda_reserved1) (void); + void (*_gda_reserved2) (void); + void (*_gda_reserved3) (void); + void (*_gda_reserved4) (void); +}; + +typedef guint GdaSqlBuilderId; + +/** + * SECTION:gda-sql-builder + * @short_description: Factory object for statements + * @title: GdaSqlBuilder + * @stability: Stable + * @see_also: #GdaSqlParser, #GdaSqlStatement and #GdaStatement + * + * The #GdaSqlBuilder can be used to build a #GdaStatement from its structural description, + * much in the same way a #GdaSqlParser can be used to build a #GdaStatement from an SQL + * string. + * + * The #GdaSqlBuilder internally constructs a #GdaSqlStatement and uses it when requested to produce + * a #GdaStatement (see gda_sql_builder_get_statement()), or a #GdaSqlStatement (see + * gda_sql_builder_get_sql_statement()). + * + * During the building process, some pieces of the statement are constructed, and assembled into the + * final statement. Each of these pieces can be reused anytime in the same #GdaSqlBuilder object, and each + * is identified using a single unsigned integer ID. That ID is dynamically allocated by the object. + * + * The following example builds the equivalent of the = ##ageparam::int"]]> expression: + * + * + * For more examples, see the Build statements without using a parser section. + */ + +GdaSqlBuilder *gda_sql_builder_new (GdaSqlStatementType stmt_type); +GdaStatement *gda_sql_builder_get_statement (GdaSqlBuilder *builder, GError **error); +GdaSqlStatement *gda_sql_builder_get_sql_statement (GdaSqlBuilder *builder); + +/* Expression API */ +GdaSqlBuilderId gda_sql_builder_add_id (GdaSqlBuilder *builder, const gchar *str); +GdaSqlBuilderId gda_sql_builder_add_field_id (GdaSqlBuilder *builder, const gchar *field_name, const gchar *table_name); +GdaSqlBuilderId gda_sql_builder_add_expr (GdaSqlBuilder *builder, GdaDataHandler *dh, GType type, ...); +GdaSqlBuilderId gda_sql_builder_add_expr_value (GdaSqlBuilder *builder, const GValue *value); +GdaSqlBuilderId gda_sql_builder_add_param (GdaSqlBuilder *builder, const gchar *param_name, GType type, gboolean nullok); + +GdaSqlBuilderId gda_sql_builder_add_cond (GdaSqlBuilder *builder, GdaSqlOperatorType op, + GdaSqlBuilderId op1, GdaSqlBuilderId op2, GdaSqlBuilderId op3); +GdaSqlBuilderId gda_sql_builder_add_cond_v (GdaSqlBuilder *builder, GdaSqlOperatorType op, + const GdaSqlBuilderId *op_ids, gint op_ids_size); +GdaSqlBuilderId gda_sql_builder_add_function (GdaSqlBuilder *builder, const gchar *func_name, ...); +GdaSqlBuilderId gda_sql_builder_add_function_v (GdaSqlBuilder *builder, const gchar *func_name, + const GdaSqlBuilderId *args, gint args_size); +GdaSqlBuilderId gda_sql_builder_add_sub_select (GdaSqlBuilder *builder, GdaSqlStatement *sqlst); +GdaSqlBuilderId gda_sql_builder_add_case (GdaSqlBuilder *builder, GdaSqlBuilderId test_expr, GdaSqlBuilderId else_expr, ...); +GdaSqlBuilderId gda_sql_builder_add_case_v (GdaSqlBuilder *builder, GdaSqlBuilderId test_expr, GdaSqlBuilderId else_expr, + const GdaSqlBuilderId *when_array, const GdaSqlBuilderId *then_array, gint args_size); + + +/* General Statement API */ +void gda_sql_builder_add_field_value (GdaSqlBuilder *builder, const gchar *field_name, GType type, ...); +void gda_sql_builder_add_field_value_as_gvalue (GdaSqlBuilder *builder, const gchar *field_name, + const GValue *value); +void gda_sql_builder_add_field_value_id (GdaSqlBuilder *builder, GdaSqlBuilderId field_id, GdaSqlBuilderId value_id); + +void gda_sql_builder_set_table (GdaSqlBuilder *builder, const gchar *table_name); +void gda_sql_builder_set_where (GdaSqlBuilder *builder, GdaSqlBuilderId cond_id); + +/* SELECT Statement API */ +GdaSqlBuilderId gda_sql_builder_select_add_field (GdaSqlBuilder *builder, const gchar *field_name, + const gchar *table_name, const gchar *alias); +GdaSqlBuilderId gda_sql_builder_select_add_target (GdaSqlBuilder *builder, const gchar *table_name, const gchar *alias); +GdaSqlBuilderId gda_sql_builder_select_add_target_id (GdaSqlBuilder *builder, GdaSqlBuilderId table_id, const gchar *alias); +GdaSqlBuilderId gda_sql_builder_select_join_targets (GdaSqlBuilder *builder, + GdaSqlBuilderId left_target_id, GdaSqlBuilderId right_target_id, + GdaSqlSelectJoinType join_type, + GdaSqlBuilderId join_expr); +void gda_sql_builder_join_add_field (GdaSqlBuilder *builder, GdaSqlBuilderId join_id, const gchar *field_name); +void gda_sql_builder_select_order_by (GdaSqlBuilder *builder, GdaSqlBuilderId expr_id, + gboolean asc, const gchar *collation_name); +void gda_sql_builder_select_set_distinct (GdaSqlBuilder *builder, + gboolean distinct, GdaSqlBuilderId expr_id); +void gda_sql_builder_select_set_limit (GdaSqlBuilder *builder, + GdaSqlBuilderId limit_count_expr_id, GdaSqlBuilderId limit_offset_expr_id); + +void gda_sql_builder_select_set_having (GdaSqlBuilder *builder, GdaSqlBuilderId cond_id); +void gda_sql_builder_select_group_by (GdaSqlBuilder *builder, GdaSqlBuilderId expr_id); + +/* COMPOUND SELECT Statement API */ +void gda_sql_builder_compound_set_type (GdaSqlBuilder *builder, GdaSqlStatementCompoundType compound_type); +void gda_sql_builder_compound_add_sub_select (GdaSqlBuilder *builder, GdaSqlStatement *sqlst); +void gda_sql_builder_compound_add_sub_select_from_builder (GdaSqlBuilder *builder, GdaSqlBuilder *subselect); + +/* import/Export API */ +GdaSqlExpr *gda_sql_builder_export_expression (GdaSqlBuilder *builder, GdaSqlBuilderId id); +GdaSqlBuilderId gda_sql_builder_import_expression (GdaSqlBuilder *builder, GdaSqlExpr *expr); +GdaSqlBuilderId gda_sql_builder_import_expression_from_builder (GdaSqlBuilder *builder, GdaSqlBuilder *query, GdaSqlBuilderId expr_id); + +G_END_DECLS + +#endif diff --git a/.flatpak-builder/cache/objects/1d/12b27a1160ad6b7740046147a15ea70f5674938bbfc488adfb7f5b95d64907.file b/.flatpak-builder/cache/objects/1d/12b27a1160ad6b7740046147a15ea70f5674938bbfc488adfb7f5b95d64907.file new file mode 100644 index 0000000..0f87619 --- /dev/null +++ b/.flatpak-builder/cache/objects/1d/12b27a1160ad6b7740046147a15ea70f5674938bbfc488adfb7f5b95d64907.file @@ -0,0 +1,2 @@ +libxml-2.0 +gio-2.0 \ No newline at end of file diff --git a/.flatpak-builder/cache/objects/1d/1cab58a200264340ae0fd44fb95c15f4688bf64a08ce1a525cf41b61455bd7.commit b/.flatpak-builder/cache/objects/1d/1cab58a200264340ae0fd44fb95c15f4688bf64a08ce1a525cf41b61455bd7.commit new file mode 100644 index 0000000..6ca64fd Binary files /dev/null and b/.flatpak-builder/cache/objects/1d/1cab58a200264340ae0fd44fb95c15f4688bf64a08ce1a525cf41b61455bd7.commit differ diff --git a/.flatpak-builder/cache/objects/1d/5aa6fe6eacbcacf81c2ca0d15ce119ee03af94821f3aec67286eed048ef415.dirtree b/.flatpak-builder/cache/objects/1d/5aa6fe6eacbcacf81c2ca0d15ce119ee03af94821f3aec67286eed048ef415.dirtree new file mode 100644 index 0000000..12f96a6 Binary files /dev/null and b/.flatpak-builder/cache/objects/1d/5aa6fe6eacbcacf81c2ca0d15ce119ee03af94821f3aec67286eed048ef415.dirtree differ diff --git a/.flatpak-builder/cache/objects/1d/b7fa46e709fdcc4cd0ee9b57711ec70d4873457c2980766be5c3a7ec4788f5.dirtree b/.flatpak-builder/cache/objects/1d/b7fa46e709fdcc4cd0ee9b57711ec70d4873457c2980766be5c3a7ec4788f5.dirtree new file mode 100644 index 0000000..ec7f012 Binary files /dev/null and b/.flatpak-builder/cache/objects/1d/b7fa46e709fdcc4cd0ee9b57711ec70d4873457c2980766be5c3a7ec4788f5.dirtree differ diff --git a/.flatpak-builder/cache/objects/1d/caf9e91f3b5210ab7db8659e23dc18ebfa797c0b3dbb6d663b21f160126215.file b/.flatpak-builder/cache/objects/1d/caf9e91f3b5210ab7db8659e23dc18ebfa797c0b3dbb6d663b21f160126215.file new file mode 100644 index 0000000..e34901c --- /dev/null +++ b/.flatpak-builder/cache/objects/1d/caf9e91f3b5210ab7db8659e23dc18ebfa797c0b3dbb6d663b21f160126215.file @@ -0,0 +1,96 @@ +# imports.py +# +# Copyright 2022 James Westman +# +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation; either version 3 of the +# License, or (at your option) any later version. +# +# This file is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program. If not, see . +# +# SPDX-License-Identifier: LGPL-3.0-or-later + + +from .. import gir +from .common import * + + +class GtkDirective(AstNode): + grammar = Statement( + Match("using").err( + 'File must start with a "using Gtk" directive (e.g. `using Gtk 4.0;`)' + ), + Match("Gtk").err( + 'File must start with a "using Gtk" directive (e.g. `using Gtk 4.0;`)' + ), + UseNumberText("version").expected("a version number for GTK"), + ) + + @validate("version") + def gtk_version(self): + version = self.tokens["version"] + if version not in ["4.0"]: + err = CompileError("Only GTK 4 is supported") + if version and version.startswith("4"): + err.hint( + "Expected the GIR version, not an exact version number. Use 'using Gtk 4.0;'." + ) + else: + err.hint("Expected 'using Gtk 4.0;'") + raise err + + try: + gir.get_namespace("Gtk", version) + except CompileError as e: + raise CompileError( + "Could not find GTK 4 introspection files. Is gobject-introspection installed?", + fatal=True, + # preserve the hints from the original error, because it contains + # useful debugging information + hints=e.hints, + ) + + @property + def gir_namespace(self): + # validate the GTK version first to make sure the more specific error + # message is emitted + self.gtk_version() + if self.tokens["version"] is not None: + return gir.get_namespace("Gtk", self.tokens["version"]) + else: + # For better error handling, just assume it's 4.0 + return gir.get_namespace("Gtk", "4.0") + + +class Import(AstNode): + grammar = Statement( + "using", + UseIdent("namespace").expected("a GIR namespace"), + UseNumberText("version").expected("a version number"), + ) + + @property + def namespace(self): + return self.tokens["namespace"] + + @property + def version(self): + return self.tokens["version"] + + @validate("namespace", "version") + def namespace_exists(self): + gir.get_namespace(self.tokens["namespace"], self.tokens["version"]) + + @property + def gir_namespace(self): + try: + return gir.get_namespace(self.tokens["namespace"], self.tokens["version"]) + except CompileError: + return None diff --git a/.flatpak-builder/cache/objects/1d/cf83b035b7e85cb37e757b2c53034787279f718debbd83f880b47aaff0351c.file b/.flatpak-builder/cache/objects/1d/cf83b035b7e85cb37e757b2c53034787279f718debbd83f880b47aaff0351c.file new file mode 100644 index 0000000..015002a --- /dev/null +++ b/.flatpak-builder/cache/objects/1d/cf83b035b7e85cb37e757b2c53034787279f718debbd83f880b47aaff0351c.file @@ -0,0 +1,313 @@ +/* + * Copyright (C) 2008 - 2010 Murray Cumming + * Copyright (C) 2008 - 2012 Vivien Malerba + * Copyright (C) 2009 Bas Driessen + * Copyright (C) 2010 David King + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include +#include +#include +#include +#include +#include + +static gpointer gda_sql_statement_compound_new (void); +static gboolean gda_sql_statement_compound_check_structure (GdaSqlAnyPart *stmt, gpointer data, GError **error); + +GdaSqlStatementContentsInfo compound_infos = { + GDA_SQL_STATEMENT_COMPOUND, + "COMPOUND", + gda_sql_statement_compound_new, + _gda_sql_statement_compound_free, + _gda_sql_statement_compound_copy, + _gda_sql_statement_compound_serialize, + + gda_sql_statement_compound_check_structure, + NULL, + NULL, + NULL, + NULL, + NULL +}; + +GdaSqlStatementContentsInfo * +_gda_sql_statement_compound_get_infos (void) +{ + return &compound_infos; +} + +static gpointer +gda_sql_statement_compound_new (void) +{ + GdaSqlStatementCompound *stmt; + stmt = g_new0 (GdaSqlStatementCompound, 1); + stmt->compound_type = -1; + GDA_SQL_ANY_PART (stmt)->type = GDA_SQL_ANY_STMT_COMPOUND; + return stmt; +} + +void +_gda_sql_statement_compound_free (gpointer stmt) +{ + GdaSqlStatementCompound *compound = (GdaSqlStatementCompound *) stmt; + + if (compound->stmt_list) { + g_slist_free_full (compound->stmt_list, (GDestroyNotify) gda_sql_statement_free); + } + g_free (compound); +} + +gpointer +_gda_sql_statement_compound_copy (gpointer src) +{ + GdaSqlStatementCompound *dest; + GdaSqlStatementCompound *compound = (GdaSqlStatementCompound *) src; + GSList *list; + + dest = gda_sql_statement_compound_new (); + dest->compound_type = compound->compound_type; + for (list = compound->stmt_list; list; list = list->next) { + GdaSqlStatement *sqlst; + sqlst = gda_sql_statement_copy ((GdaSqlStatement*) list->data); + gda_sql_any_part_set_parent (sqlst->contents, dest); + dest->stmt_list = g_slist_prepend (dest->stmt_list, sqlst); + } + dest->stmt_list = g_slist_reverse (dest->stmt_list); + + return dest; +} + +gchar * +_gda_sql_statement_compound_serialize (gpointer stmt) +{ + GString *string; + gchar *str; + GSList *list; + GdaSqlStatementCompound *compound = (GdaSqlStatementCompound *) stmt; + + g_return_val_if_fail (stmt, NULL); + + string = g_string_new ("\"contents\":{"); + g_string_append (string, "\"compount_type\":"); + switch (compound->compound_type) { + case GDA_SQL_STATEMENT_COMPOUND_UNION: + str = "UNION"; break; + case GDA_SQL_STATEMENT_COMPOUND_UNION_ALL: + str = "AUNION"; break; + case GDA_SQL_STATEMENT_COMPOUND_INTERSECT: + str = "INTERSECT"; break; + case GDA_SQL_STATEMENT_COMPOUND_INTERSECT_ALL: + str = "AINTERSECT"; break; + case GDA_SQL_STATEMENT_COMPOUND_EXCEPT: + str = "EXCEPT"; break; + case GDA_SQL_STATEMENT_COMPOUND_EXCEPT_ALL: + str = "AEXCEPT"; break; + default: + str = NULL; + g_assert_not_reached (); + } + g_string_append_printf (string, "\"%s\"", str); + + if (compound->stmt_list) { + g_string_append (string, ",\"select_stmts\":["); + for (list = compound->stmt_list; list; list = list->next) { + if (list != compound->stmt_list) + g_string_append_c (string, ','); + str = gda_sql_statement_serialize ((GdaSqlStatement*) list->data); + g_string_append (string, str); + g_free (str); + } + g_string_append_c (string, ']'); + } + + g_string_append_c (string, '}'); + str = string->str; + g_string_free (string, FALSE); + return str; +} + +/** + * gda_sql_statement_compound_take_stmt + * @stmt: a #GdaSqlStatement pointer + * @s: a #GdaSqlStatement pointer + * + * Adds the @s sub-statement to the @stmt compound statement. @s's reference is transferred to + * @stmt (which means @stmt is then responsible for freeing it when no longer needed). + */ +void +gda_sql_statement_compound_take_stmt (GdaSqlStatement *stmt, GdaSqlStatement *s) +{ + GdaSqlStatementCompound *compound = (GdaSqlStatementCompound *) stmt->contents; + + if (s->stmt_type == GDA_SQL_STATEMENT_COMPOUND) { + GdaSqlStatementCompound *scompound = (GdaSqlStatementCompound *) s->contents; + if (scompound->stmt_list) { + if (scompound->stmt_list->next) { + compound->stmt_list = g_slist_append (compound->stmt_list, s); + gda_sql_any_part_set_parent (s->contents, stmt); + } + else { + compound->stmt_list = g_slist_append (compound->stmt_list, scompound->stmt_list->data); + gda_sql_any_part_set_parent (((GdaSqlStatement*) scompound->stmt_list->data)->contents, stmt); + g_slist_free (scompound->stmt_list); + scompound->stmt_list = NULL; + gda_sql_statement_free (s); + } + } + else { + /* ignore @s */ + gda_sql_statement_free (s); + return; + } + } + else { + compound->stmt_list = g_slist_append (compound->stmt_list, s); + gda_sql_any_part_set_parent (s->contents, stmt); + } +} + +GdaSqlAnyPart * +_gda_sql_statement_compound_reduce (GdaSqlAnyPart *compound_or_select) +{ + GdaSqlAnyPart *part; + + part = compound_or_select; + if (part->type == GDA_SQL_ANY_STMT_COMPOUND) { + /* if only one child, then use that child instead */ + GdaSqlStatementCompound *compound = (GdaSqlStatementCompound*) part; + if (compound->stmt_list && !compound->stmt_list->next) { + GdaSqlAnyPart *rpart; + GdaSqlStatement *substmt; + substmt = (GdaSqlStatement *) compound->stmt_list->data; + + rpart = GDA_SQL_ANY_PART (substmt->contents); + substmt->contents = NULL; + gda_sql_statement_free (substmt); + + g_slist_free (compound->stmt_list); + compound->stmt_list = NULL; + _gda_sql_statement_compound_free (compound); + part = _gda_sql_statement_compound_reduce (rpart); + } + } + + return part; +} + + +/** + * gda_sql_statement_compound_set_type + * @stmt: a #GdaSqlStatement pointer + * @type: a #GdaSqlStatementCompoundType value + * + * Specifies @stmt's type of compound + */ +void +gda_sql_statement_compound_set_type (GdaSqlStatement *stmt, GdaSqlStatementCompoundType type) +{ + GdaSqlStatementCompound *compound = (GdaSqlStatementCompound *) stmt->contents; + compound->compound_type = type; +} + +gint +_gda_sql_statement_compound_get_n_cols (GdaSqlStatementCompound *compound, GError **error) +{ + if (!compound || !compound->stmt_list) { + g_set_error (error, GDA_SQL_ERROR, GDA_SQL_STRUCTURE_CONTENTS_ERROR, + "%s", _("COMPOUND statement contains an undefined COMPOUND statement")); + return -1; + } + + /* @compound's children */ + GdaSqlStatement *sqlstmt = (GdaSqlStatement*) compound->stmt_list->data; + if (sqlstmt->stmt_type == GDA_SQL_STATEMENT_SELECT) { + if (!sqlstmt->contents) { + g_set_error (error, GDA_SQL_ERROR, GDA_SQL_STRUCTURE_CONTENTS_ERROR, + "%s", _("COMPOUND statement contains an undefined SELECT statement")); + return -1; + } + return g_slist_length (((GdaSqlStatementSelect*) sqlstmt->contents)->expr_list); + } + else if (sqlstmt->stmt_type == GDA_SQL_STATEMENT_COMPOUND) + return _gda_sql_statement_compound_get_n_cols ((GdaSqlStatementCompound*) sqlstmt->contents, error); + else { + g_set_error (error, GDA_SQL_ERROR, GDA_SQL_STRUCTURE_CONTENTS_ERROR, + "%s", _("COMPOUND statement contains a non SELECT statement")); + return -1; + } +} + +static gboolean +gda_sql_statement_compound_check_structure (GdaSqlAnyPart *stmt, G_GNUC_UNUSED gpointer data, GError **error) +{ + GdaSqlStatementCompound *compound = (GdaSqlStatementCompound *) stmt; + gint nb_cols = -1; + GSList *list; + + if (!compound->stmt_list) { + g_set_error (error, GDA_SQL_ERROR, GDA_SQL_STRUCTURE_CONTENTS_ERROR, + "%s", _("COMPOUND statement does not contain any SELECT statement")); + return FALSE; + } + + if (!compound->stmt_list->next) { + g_set_error (error, GDA_SQL_ERROR, GDA_SQL_STRUCTURE_CONTENTS_ERROR, + "%s", _("COMPOUND statement only contains one SELECT statement")); + return FALSE; + } + + for (list = compound->stmt_list; list; list = list->next) { + GdaSqlStatement *sqlstmt = (GdaSqlStatement*) list->data; + gint nb; + if (sqlstmt->stmt_type == GDA_SQL_STATEMENT_SELECT) { + if (!sqlstmt->contents) { + g_set_error (error, GDA_SQL_ERROR, GDA_SQL_STRUCTURE_CONTENTS_ERROR, + "%s", _("COMPOUND statement contains an undefined SELECT statement")); + return FALSE; + } + nb = g_slist_length (((GdaSqlStatementSelect*) sqlstmt->contents)->expr_list); + } + else if (sqlstmt->stmt_type == GDA_SQL_STATEMENT_COMPOUND) { + nb = _gda_sql_statement_compound_get_n_cols ((GdaSqlStatementCompound*) sqlstmt->contents, error); + if (nb < 0) + return FALSE; + } + else { + g_set_error (error, GDA_SQL_ERROR, GDA_SQL_STRUCTURE_CONTENTS_ERROR, + "%s", _("COMPOUND statement contains a non SELECT statement")); + return FALSE; + } + + if (nb_cols == -1) { + nb_cols = nb; + if (nb == 0) { + g_set_error (error, GDA_SQL_ERROR, GDA_SQL_STRUCTURE_CONTENTS_ERROR, + "%s", _("COMPOUND statement contains an empty SELECT statement")); + return FALSE; + } + } + else if (nb != nb_cols) { + g_set_error (error, GDA_SQL_ERROR, GDA_SQL_STRUCTURE_CONTENTS_ERROR, + "%s", _("All statements in a COMPOUND must have the same number of columns")); + return FALSE; + } + } + + return TRUE; +} diff --git a/.flatpak-builder/cache/objects/1e/48579229e38eae99df4b43611f2ab19197c9533a40c32466bf9e42b5fc48ca.file b/.flatpak-builder/cache/objects/1e/48579229e38eae99df4b43611f2ab19197c9533a40c32466bf9e42b5fc48ca.file new file mode 100644 index 0000000..9c14e54 --- /dev/null +++ b/.flatpak-builder/cache/objects/1e/48579229e38eae99df4b43611f2ab19197c9533a40c32466bf9e42b5fc48ca.file @@ -0,0 +1,30 @@ +/* gda-db-column-private.h + * + * Copyright (C) 2020 Pavlo Solntsev + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef GDA_DB_COLUMN_PRIVATE_H +#define GDA_DB_COLUMN_PRIVATE_H + +#include "gda-meta-struct.h" +#include "gda-db-column.h" + +GdaDbColumn* gda_db_column_new_from_meta (GdaMetaTableColumn *column); + +#endif + diff --git a/.flatpak-builder/cache/objects/1e/6b1cf69091dc3212fb90d0f49148033c29ed8517fe147fb09f95a1d1d83267.file b/.flatpak-builder/cache/objects/1e/6b1cf69091dc3212fb90d0f49148033c29ed8517fe147fb09f95a1d1d83267.file new file mode 100644 index 0000000..e97cbaa --- /dev/null +++ b/.flatpak-builder/cache/objects/1e/6b1cf69091dc3212fb90d0f49148033c29ed8517fe147fb09f95a1d1d83267.file @@ -0,0 +1,1016 @@ +// All token codes are small integers with #defines that begin with "TK_" +%token_prefix T_ + +// The type of the data attached to each token is GValue. This is also the +// default type for non-terminals. +// +%token_type {GValue *} +%default_type {GValue *} +%token_destructor {if ($$) { +#ifdef GDA_DEBUG_NO + gchar *str = gda_sql_value_stringify ($$); + g_print ("___ token destructor /%s/\n", str) + g_free (str); +#endif + g_value_unset ($$); g_free ($$);}} + +// The generated parser function takes a 4th argument as follows: +%extra_argument {GdaSqlParserIface *pdata} + +// This code runs whenever there is a syntax error +// +%syntax_error { + gda_sql_parser_set_syntax_error (pdata->parser); +} +%stack_overflow { + gda_sql_parser_set_overflow_error (pdata->parser); +} + +// The name of the generated procedure that implements the parser +// is as follows: +%name priv_gda_sql_parser + +// The following text is included near the beginning of the C source +// code file that implements the parser. +// +%include { +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef struct { + GValue *fname; + GdaSqlExpr *expr; +} UpdateSet; + +typedef struct { + gboolean distinct; + GdaSqlExpr *expr; +} Distinct; + +typedef struct { + GdaSqlExpr *count; + GdaSqlExpr *offset; +} Limit; + +typedef struct { + GSList *when_list; + GSList *then_list; +} CaseBody; + +static GdaSqlOperatorType +sql_operation_string_to_operator (const gchar *op) +{ + switch (g_ascii_toupper (*op)) { + case 'A': + return GDA_SQL_OPERATOR_TYPE_AND; + case 'O': + return GDA_SQL_OPERATOR_TYPE_OR; + case 'N': + return GDA_SQL_OPERATOR_TYPE_NOT; + case '=': + return GDA_SQL_OPERATOR_TYPE_EQ; + case 'I': + if (op[1] == 'S') + return GDA_SQL_OPERATOR_TYPE_IS; + else if (op[1] == 'N') + return GDA_SQL_OPERATOR_TYPE_IN; + else if (op[1] == 'I') + return GDA_SQL_OPERATOR_TYPE_ILIKE; + break; + case 'L': + return GDA_SQL_OPERATOR_TYPE_LIKE; + case 'B': + return GDA_SQL_OPERATOR_TYPE_BETWEEN; + case '>': + if (op[1] == '=') + return GDA_SQL_OPERATOR_TYPE_GEQ; + else if (op[1] == 0) + return GDA_SQL_OPERATOR_TYPE_GT; + break; + case '<': + if (op[1] == '=') + return GDA_SQL_OPERATOR_TYPE_LEQ; + else if (op[1] == '>') + return GDA_SQL_OPERATOR_TYPE_DIFF; + else if (op[1] == 0) + return GDA_SQL_OPERATOR_TYPE_LT; + break; + case '!': + if (op[1] == '=') + return GDA_SQL_OPERATOR_TYPE_DIFF; + else if (op[1] == '~') { + if (op[2] == 0) + return GDA_SQL_OPERATOR_TYPE_NOT_REGEXP; + else if (op[2] == '*') + return GDA_SQL_OPERATOR_TYPE_NOT_REGEXP_CI; + } + break; + case '~': + if (op[1] == '*') + return GDA_SQL_OPERATOR_TYPE_REGEXP_CI; + else if (op[1] == 0) + return GDA_SQL_OPERATOR_TYPE_REGEXP; + break; + case 'S': + return GDA_SQL_OPERATOR_TYPE_SIMILAR; + case '|': + if (op[1] == '|') + return GDA_SQL_OPERATOR_TYPE_CONCAT; + else + return GDA_SQL_OPERATOR_TYPE_BITOR; + case '+': + return GDA_SQL_OPERATOR_TYPE_PLUS; + case '-': + return GDA_SQL_OPERATOR_TYPE_MINUS; + case '*': + return GDA_SQL_OPERATOR_TYPE_STAR; + case '/': + return GDA_SQL_OPERATOR_TYPE_DIV; + case '%': + return GDA_SQL_OPERATOR_TYPE_REM; + case '&': + return GDA_SQL_OPERATOR_TYPE_BITAND; + } + g_error ("Unhandled operator named '%s'\n", op); + return 0; +} + +static GdaSqlOperatorType +string_to_op_type (GValue *value) +{ + GdaSqlOperatorType op; + op = sql_operation_string_to_operator (g_value_get_string (value)); + g_value_reset (value); + g_free (value); + return op; +} + +static GdaSqlExpr * +compose_multiple_expr (GdaSqlOperatorType op, GdaSqlExpr *left, GdaSqlExpr *right) { + GdaSqlExpr *ret; + if (left->cond && (left->cond->operator_type == op)) { + ret = left; + ret->cond->operands = g_slist_append (ret->cond->operands, right); + } + else { + GdaSqlOperation *cond; + ret = gda_sql_expr_new (NULL); + cond = gda_sql_operation_new (GDA_SQL_ANY_PART (ret)); + ret->cond = cond; + cond->operator_type = op; + cond->operands = g_slist_prepend (NULL, right); + GDA_SQL_ANY_PART (right)->parent = GDA_SQL_ANY_PART (cond); + cond->operands = g_slist_prepend (cond->operands, left); + GDA_SQL_ANY_PART (left)->parent = GDA_SQL_ANY_PART (cond); + } + return ret; +} + +static GdaSqlExpr * +create_two_expr (GdaSqlOperatorType op, GdaSqlExpr *left, GdaSqlExpr *right) { + GdaSqlExpr *ret; + GdaSqlOperation *cond; + ret = gda_sql_expr_new (NULL); + cond = gda_sql_operation_new (GDA_SQL_ANY_PART (ret)); + ret->cond = cond; + cond->operator_type = op; + cond->operands = g_slist_prepend (NULL, right); + GDA_SQL_ANY_PART (right)->parent = GDA_SQL_ANY_PART (cond); + cond->operands = g_slist_prepend (cond->operands, left); + GDA_SQL_ANY_PART (left)->parent = GDA_SQL_ANY_PART (cond); + return ret; +} + +static GdaSqlExpr * +create_uni_expr (GdaSqlOperatorType op, GdaSqlExpr *expr) { + GdaSqlExpr *ret; + GdaSqlOperation *cond; + ret = gda_sql_expr_new (NULL); + cond = gda_sql_operation_new (GDA_SQL_ANY_PART (ret)); + ret->cond = cond; + cond->operator_type = op; + cond->operands = g_slist_prepend (NULL, expr); + GDA_SQL_ANY_PART (expr)->parent = GDA_SQL_ANY_PART (cond); + return ret; +} + +static GdaSqlStatement * +compose_multiple_compounds (GdaSqlStatementCompoundType ctype, GdaSqlStatement *left, GdaSqlStatement *right) { + GdaSqlStatement *ret = NULL; + GdaSqlStatementCompound *lc = (GdaSqlStatementCompound*) left->contents; + if (lc->compound_type == ctype) { + GdaSqlStatementCompound *rc = (GdaSqlStatementCompound*) right->contents; + if (!rc->stmt_list->next || rc->compound_type == ctype) { + GSList *list; + for (list = rc->stmt_list; list; list = list->next) + GDA_SQL_ANY_PART (((GdaSqlStatement*)list->data)->contents)->parent = GDA_SQL_ANY_PART (lc); + + ret = left; + lc->stmt_list = g_slist_concat (lc->stmt_list, rc->stmt_list); + rc->stmt_list = NULL; + gda_sql_statement_free (right); + } + } + else { + ret = gda_sql_statement_new (GDA_SQL_STATEMENT_COMPOUND); + gda_sql_statement_compound_set_type (ret, ctype); + gda_sql_statement_compound_take_stmt (ret, left); + gda_sql_statement_compound_take_stmt (ret, right); + } + return ret; +} + +} + +// The following directive causes tokens ABORT, AFTER, ASC, etc. to +// fallback to ID if they will not parse as their original value. +%fallback ID + ABORT AFTER ANALYZE ASC ATTACH BEFORE BEGIN CASCADE CAST CONFLICT + DATABASE DEFERRED DESC DETACH EACH END EXCLUSIVE EXPLAIN FAIL FOR + IGNORE IMMEDIATE INITIALLY INSTEAD LIKE ILIKE MATCH PLAN + QUERY KEY OF OFFSET PRAGMA RAISE REPLACE RESTRICT ROW + TEMP TRIGGER VACUUM VIEW VIRTUAL + REINDEX RENAME CTIME_KW IF + DELIMITER COMMIT ROLLBACK ISOLATION LEVEL SERIALIZABLE READ COMMITTED + UNCOMMITTED REPEATABLE WRITE ONLY SAVEPOINT RELEASE COMMENT FORCE WAIT NOWAIT BATCH. +%fallback TEXTUAL STRING. + +// Define operator precedence early so that this is the first occurance +// of the operator tokens in the grammer. Keeping the operators together +// causes them to be assigned integer values that are close together, +// which keeps parser tables smaller. +%left OR. +%left AND. +%right NOT. +%left IS MATCH NOTLIKE LIKE NOTILIKE ILIKE IN ISNULL NOTNULL DIFF EQ. +%left BETWEEN. +%left GT LEQ LT GEQ. +%left REGEXP REGEXP_CI NOT_REGEXP NOT_REGEXP_CI. +%left SIMILAR. +%right ESCAPE. +%left BITAND BITOR LSHIFT RSHIFT. +%left PLUS MINUS. +%left STAR SLASH REM. +%left CONCAT. +%left COLLATE. +%right UMINUS UPLUS BITNOT. +%left LP RP. +%left JOIN INNER NATURAL LEFT RIGHT FULL CROSS. +%left UNION EXCEPT INTERSECT. +%left PGCAST. + +// force the declaration of the ILLEGAL and SQLCOMMENT tokens +%nonassoc ILLEGAL. +%nonassoc SQLCOMMENT. + +// Input is a single SQL command +%type stmt {GdaSqlStatement *} +%destructor stmt {g_print ("Statement destroyed by parser: %p\n", $$); gda_sql_statement_free ($$);} +stmt ::= cmd(C) eos. {pdata->parsed_statement = C;} +stmt ::= compound(C) eos. { + GdaSqlStatementCompound *scompound = (GdaSqlStatementCompound *) C->contents; + if (scompound->stmt_list->next) + /* real compound (multiple statements) */ + pdata->parsed_statement = C; + else { + /* false compound (only 1 select) */ + pdata->parsed_statement = (GdaSqlStatement*) scompound->stmt_list->data; + GDA_SQL_ANY_PART (pdata->parsed_statement->contents)->parent = NULL; + g_slist_free (scompound->stmt_list); + scompound->stmt_list = NULL; + gda_sql_statement_free (C); + } +} +cmd(C) ::= LP cmd(E) RP. {C = E;} +compound(C) ::= LP compound(E) RP. {C = E;} + +eos ::= SEMI. +eos ::= END_OF_FILE. + +%type cmd {GdaSqlStatement *} +%destructor cmd {gda_sql_statement_free ($$);} + +// +// Transactions +// +cmd(C) ::= BEGIN. {C = gda_sql_statement_new (GDA_SQL_STATEMENT_BEGIN);} +cmd(C) ::= BEGIN TRANSACTION nm_opt(R). {C = gda_sql_statement_new (GDA_SQL_STATEMENT_BEGIN); + gda_sql_statement_trans_take_name (C, R); +} + +cmd(C) ::= BEGIN transtype(Y) TRANSACTION nm_opt(R). {C = gda_sql_statement_new (GDA_SQL_STATEMENT_BEGIN); + gda_sql_statement_trans_take_mode (C, Y); + gda_sql_statement_trans_take_name (C, R); +} + +cmd(C) ::= BEGIN transtype(Y) nm_opt(R). {C = gda_sql_statement_new (GDA_SQL_STATEMENT_BEGIN); + gda_sql_statement_trans_take_mode (C, Y); + gda_sql_statement_trans_take_name (C, R); +} + +cmd(C) ::= BEGIN transilev(L). {C = gda_sql_statement_new (GDA_SQL_STATEMENT_BEGIN); + gda_sql_statement_trans_set_isol_level (C, L); +} + +cmd(C) ::= BEGIN TRANSACTION transilev(L). {C = gda_sql_statement_new (GDA_SQL_STATEMENT_BEGIN); + gda_sql_statement_trans_set_isol_level (C, L); +} + +cmd(C) ::= BEGIN TRANSACTION transtype(Y). {C = gda_sql_statement_new (GDA_SQL_STATEMENT_BEGIN); + gda_sql_statement_trans_take_mode (C, Y); +} + +cmd(C) ::= BEGIN TRANSACTION transtype(Y) opt_comma transilev(L). {C = gda_sql_statement_new (GDA_SQL_STATEMENT_BEGIN); + gda_sql_statement_trans_take_mode (C, Y); + gda_sql_statement_trans_set_isol_level (C, L); +} + +cmd(C) ::= BEGIN TRANSACTION transilev(L) opt_comma transtype(Y). {C = gda_sql_statement_new (GDA_SQL_STATEMENT_BEGIN); + gda_sql_statement_trans_take_mode (C, Y); + gda_sql_statement_trans_set_isol_level (C, L); +} + +cmd(C) ::= BEGIN transtype(Y) opt_comma transilev(L). {C = gda_sql_statement_new (GDA_SQL_STATEMENT_BEGIN); + gda_sql_statement_trans_take_mode (C, Y); + gda_sql_statement_trans_set_isol_level (C, L); +} + +cmd(C) ::= BEGIN transilev(L) opt_comma transtype(Y). {C = gda_sql_statement_new (GDA_SQL_STATEMENT_BEGIN); + gda_sql_statement_trans_take_mode (C, Y); + gda_sql_statement_trans_set_isol_level (C, L); +} + +cmd(C) ::= END trans_opt_kw nm_opt(R). {C = gda_sql_statement_new (GDA_SQL_STATEMENT_COMMIT); + gda_sql_statement_trans_take_name (C, R); +} + +cmd(C) ::= COMMIT nm_opt(R). {C = gda_sql_statement_new (GDA_SQL_STATEMENT_COMMIT); + gda_sql_statement_trans_take_name (C, R); +} + +cmd(C) ::= COMMIT TRANSACTION nm_opt(R). {C = gda_sql_statement_new (GDA_SQL_STATEMENT_COMMIT); + gda_sql_statement_trans_take_name (C, R); +} + +cmd(C) ::= COMMIT FORCE STRING. {C = gda_sql_statement_new (GDA_SQL_STATEMENT_COMMIT);} +cmd(C) ::= COMMIT FORCE STRING COMMA INTEGER. {C = gda_sql_statement_new (GDA_SQL_STATEMENT_COMMIT);} +cmd(C) ::= COMMIT COMMENT STRING. {C = gda_sql_statement_new (GDA_SQL_STATEMENT_COMMIT);} +cmd(C) ::= COMMIT COMMENT STRING ora_commit_write. {C = gda_sql_statement_new (GDA_SQL_STATEMENT_COMMIT);} +cmd(C) ::= COMMIT ora_commit_write. {C = gda_sql_statement_new (GDA_SQL_STATEMENT_COMMIT);} + +cmd(C) ::= ROLLBACK trans_opt_kw nm_opt(R). {C = gda_sql_statement_new (GDA_SQL_STATEMENT_ROLLBACK); + gda_sql_statement_trans_take_name (C, R); +} + +ora_commit_write ::= WRITE IMMEDIATE. +ora_commit_write ::= WRITE BATCH. +ora_commit_write ::= WRITE WAIT. +ora_commit_write ::= WRITE NOWAIT. +ora_commit_write ::= WRITE IMMEDIATE WAIT. +ora_commit_write ::= WRITE IMMEDIATE NOWAIT. +ora_commit_write ::= WRITE BATCH WAIT. +ora_commit_write ::= WRITE BATCH NOWAIT. + +trans_opt_kw ::= . +trans_opt_kw ::= TRANSACTION. + +opt_comma ::= . +opt_comma ::= COMMA. + +%type transilev {GdaTransactionIsolation} +transilev(L) ::= ISOLATION LEVEL SERIALIZABLE. {L = GDA_TRANSACTION_ISOLATION_SERIALIZABLE;} +transilev(L) ::= ISOLATION LEVEL REPEATABLE READ. {L = GDA_TRANSACTION_ISOLATION_REPEATABLE_READ;} +transilev(L) ::= ISOLATION LEVEL READ COMMITTED. {L = GDA_TRANSACTION_ISOLATION_READ_COMMITTED;} +transilev(L) ::= ISOLATION LEVEL READ UNCOMMITTED. {L = GDA_TRANSACTION_ISOLATION_READ_UNCOMMITTED;} + +nm_opt(R) ::= . {R = NULL;} +nm_opt(R) ::= nm(N). {R = N;} + +transtype(A) ::= DEFERRED(X). {A = X;} +transtype(A) ::= IMMEDIATE(X). {A = X;} +transtype(A) ::= EXCLUSIVE(X). {A = X;} +transtype(A) ::= READ WRITE. {A = g_new0 (GValue, 1); + g_value_init (A, G_TYPE_STRING); + g_value_set_string (A, "READ_WRITE"); +} +transtype(A) ::= READ ONLY. {A = g_new0 (GValue, 1); + g_value_init (A, G_TYPE_STRING); + g_value_set_string (A, "READ_ONLY"); +} + +// +// Savepoints +// +cmd(C) ::= SAVEPOINT nm(R). {C = gda_sql_statement_new (GDA_SQL_STATEMENT_SAVEPOINT); + gda_sql_statement_trans_take_name (C, R); +} + +cmd(C) ::= RELEASE SAVEPOINT nm(R). {C = gda_sql_statement_new (GDA_SQL_STATEMENT_DELETE_SAVEPOINT); + gda_sql_statement_trans_take_name (C, R); +} + +cmd(C) ::= RELEASE nm(R). {C = gda_sql_statement_new (GDA_SQL_STATEMENT_DELETE_SAVEPOINT); + gda_sql_statement_trans_take_name (C, R); +} + +cmd(C) ::= ROLLBACK trans_opt_kw TO nm(R). {C = gda_sql_statement_new (GDA_SQL_STATEMENT_ROLLBACK_SAVEPOINT); + gda_sql_statement_trans_take_name (C, R); +} + +cmd(C) ::= ROLLBACK trans_opt_kw TO SAVEPOINT nm(R). {C = gda_sql_statement_new (GDA_SQL_STATEMENT_ROLLBACK_SAVEPOINT); + gda_sql_statement_trans_take_name (C, R); +} + +// +// INSERT +// +cmd(C) ::= INSERT opt_on_conflict(O) INTO fullname(X) inscollist_opt(F) VALUES LP rexprlist(Y) RP. { + C = gda_sql_statement_new (GDA_SQL_STATEMENT_INSERT); + gda_sql_statement_insert_take_table_name (C, X); + gda_sql_statement_insert_take_fields_list (C, F); + gda_sql_statement_insert_take_1_values_list (C, g_slist_reverse (Y)); + gda_sql_statement_insert_take_on_conflict (C, O); +} + +cmd(C) ::= INSERT opt_on_conflict(O) INTO fullname(X) inscollist_opt(F) VALUES LP rexprlist(Y) RP ins_extra_values(E). { + C = gda_sql_statement_new (GDA_SQL_STATEMENT_INSERT); + gda_sql_statement_insert_take_table_name (C, X); + gda_sql_statement_insert_take_fields_list (C, F); + gda_sql_statement_insert_take_1_values_list (C, g_slist_reverse (Y)); + gda_sql_statement_insert_take_extra_values_list (C, E); + gda_sql_statement_insert_take_on_conflict (C, O); +} + +cmd(C) ::= INSERT opt_on_conflict(O) INTO fullname(X) inscollist_opt(F) compound(S). { + C = gda_sql_statement_new (GDA_SQL_STATEMENT_INSERT); + gda_sql_statement_insert_take_table_name (C, X); + gda_sql_statement_insert_take_fields_list (C, F); + gda_sql_statement_insert_take_select (C, S); + gda_sql_statement_insert_take_on_conflict (C, O); +} + + +opt_on_conflict(O) ::= . {O = NULL;} +opt_on_conflict(O) ::= OR ID(V). {O = V;} + +%type ins_extra_values {GSList*} +%destructor ins_extra_values {GSList *list; + for (list = $$; list; list = list->next) { + g_slist_free_full ((GSList*) list->data, (GDestroyNotify) gda_sql_field_free); + } + g_slist_free ($$); +} +ins_extra_values(E) ::= ins_extra_values(A) COMMA LP rexprlist(L) RP. {E = g_slist_append (A, g_slist_reverse (L));} +ins_extra_values(E) ::= COMMA LP rexprlist(L) RP. {E = g_slist_append (NULL, g_slist_reverse (L));} + +%type inscollist_opt {GSList*} +%destructor inscollist_opt {if ($$) {g_slist_free_full ($$, (GDestroyNotify) gda_sql_field_free);}} +inscollist_opt(A) ::= . {A = NULL;} +inscollist_opt(A) ::= LP inscollist(X) RP. {A = X;} + +%type inscollist {GSList*} +%destructor inscollist {if ($$) {g_slist_free_full ($$, (GDestroyNotify) gda_sql_field_free);}} +inscollist(A) ::= inscollist(X) COMMA fullname(Y). {GdaSqlField *field; + field = gda_sql_field_new (NULL); + gda_sql_field_take_name (field, Y); + A = g_slist_append (X, field); +} +inscollist(A) ::= fullname(Y). {GdaSqlField *field = gda_sql_field_new (NULL); + gda_sql_field_take_name (field, Y); + A = g_slist_prepend (NULL, field); +} + +// DELETE +cmd(C) ::= DELETE FROM fullname(T) where_opt(X). {C = gda_sql_statement_new (GDA_SQL_STATEMENT_DELETE); + gda_sql_statement_delete_take_table_name (C, T); + gda_sql_statement_delete_take_condition (C, X);} + +%type where_opt {GdaSqlExpr *} +%destructor where_opt {gda_sql_expr_free ($$);} +where_opt(A) ::= . {A = NULL;} +where_opt(A) ::= WHERE expr(X). {A = X;} + +// UPDATE +cmd(C) ::= UPDATE opt_on_conflict(O) fullname(T) SET setlist(S) where_opt(X). { + GSList *list; + C = gda_sql_statement_new (GDA_SQL_STATEMENT_UPDATE); + gda_sql_statement_update_take_table_name (C, T); + gda_sql_statement_update_take_on_conflict (C, O); + gda_sql_statement_update_take_condition (C, X); + for (list = S; list; list = list->next) { + UpdateSet *set = (UpdateSet*) list->data; + gda_sql_statement_update_take_set_value (C, set->fname, set->expr); + g_free (set); + } + g_slist_free (S); +} + +%type setlist {GSList*} +%destructor setlist {GSList *list; + for (list = $$; list; list = list->next) { + UpdateSet *set = (UpdateSet*) list->data; + g_value_reset (set->fname); g_free (set->fname); + gda_sql_expr_free (set->expr); + g_free (set); + } + g_slist_free ($$); +} +setlist(A) ::= setlist(Z) COMMA fullname(X) EQ expr(Y). {UpdateSet *set; + set = g_new (UpdateSet, 1); + set->fname = X; + set->expr = Y; + A = g_slist_append (Z, set); +} +setlist(A) ::= fullname(X) EQ expr(Y). {UpdateSet *set; + set = g_new (UpdateSet, 1); + set->fname = X; + set->expr = Y; + A = g_slist_append (NULL, set); +} + +// COMPOUND SELECT +%type compound {GdaSqlStatement *} +%destructor compound {gda_sql_statement_free ($$);} +//compound(C) ::= LP compound(E) RP. {C = E;} +compound(C) ::= selectcmd(S). { + C = gda_sql_statement_new (GDA_SQL_STATEMENT_COMPOUND); + gda_sql_statement_compound_take_stmt (C, S); +} +compound(C) ::= compound(L) UNION opt_compound_all(A) compound(R). { + C = compose_multiple_compounds (A ? GDA_SQL_STATEMENT_COMPOUND_UNION_ALL : GDA_SQL_STATEMENT_COMPOUND_UNION, + L, R); +} + +compound(C) ::= compound(L) EXCEPT opt_compound_all(A) compound(R). { + C = compose_multiple_compounds (A ? GDA_SQL_STATEMENT_COMPOUND_EXCEPT_ALL : GDA_SQL_STATEMENT_COMPOUND_EXCEPT, + L, R); +} + +compound(C) ::= compound(L) INTERSECT opt_compound_all(A) compound(R). { + C = compose_multiple_compounds (A ? GDA_SQL_STATEMENT_COMPOUND_INTERSECT_ALL : GDA_SQL_STATEMENT_COMPOUND_INTERSECT, + L, R); +} + +%type opt_compound_all {gboolean} +opt_compound_all(A) ::= . {A = FALSE;} +opt_compound_all(A) ::= ALL. {A = TRUE;} + + +// SELECT +%type selectcmd {GdaSqlStatement *} +%destructor selectcmd {gda_sql_statement_free ($$);} +selectcmd(C) ::= SELECT distinct(D) selcollist(W) from(F) where_opt(Y) + groupby_opt(P) having_opt(Q) orderby_opt(Z) limit_opt(L). { + C = gda_sql_statement_new (GDA_SQL_STATEMENT_SELECT); + if (D) { + gda_sql_statement_select_take_distinct (C, D->distinct, D->expr); + g_free (D); + } + gda_sql_statement_select_take_expr_list (C, W); + gda_sql_statement_select_take_from (C, F); + gda_sql_statement_select_take_where_cond (C, Y); + gda_sql_statement_select_take_group_by (C, P); + gda_sql_statement_select_take_having_cond (C, Q); + gda_sql_statement_select_take_order_by (C, Z); + gda_sql_statement_select_take_limits (C, L.count, L.offset); +} + +%type limit_opt {Limit} +%destructor limit_opt {gda_sql_expr_free ($$.count); gda_sql_expr_free ($$.offset);} +limit_opt(A) ::= . {A.count = NULL; A.offset = NULL;} +limit_opt(A) ::= LIMIT expr(X). {A.count = X; A.offset = NULL;} +limit_opt(A) ::= LIMIT expr(X) OFFSET expr(Y). {A.count = X; A.offset = Y;} +limit_opt(A) ::= LIMIT expr(X) COMMA expr(Y). {A.count = X; A.offset = Y;} + +%type orderby_opt {GSList *} +%destructor orderby_opt {if ($$) {g_slist_free_full ($$, (GDestroyNotify) gda_sql_select_order_free);}} +orderby_opt(A) ::= . {A = 0;} +orderby_opt(A) ::= ORDER BY sortlist(X). {A = X;} + +%type sortlist {GSList *} +%destructor sortlist {if ($$) {g_slist_free_full ($$, (GDestroyNotify) gda_sql_select_order_free);}} +sortlist(A) ::= sortlist(X) COMMA expr(Y) sortorder(Z). {GdaSqlSelectOrder *order; + order = gda_sql_select_order_new (NULL); + order->expr = Y; + order->asc = Z; + A = g_slist_append (X, order); +} +sortlist(A) ::= expr(Y) sortorder(Z). {GdaSqlSelectOrder *order; + order = gda_sql_select_order_new (NULL); + order->expr = Y; + order->asc = Z; + A = g_slist_prepend (NULL, order); +} + +%type sortorder {gboolean} +sortorder(A) ::= ASC. {A = TRUE;} +sortorder(A) ::= DESC. {A = FALSE;} +sortorder(A) ::= . {A = TRUE;} + + +%type having_opt {GdaSqlExpr *} +%destructor having_opt {gda_sql_expr_free ($$);} +having_opt(A) ::= . {A = NULL;} +having_opt(A) ::= HAVING expr(X). {A = X;} + +%type groupby_opt {GSList*} +%destructor groupby_opt {if ($$) {g_slist_free_full ($$, (GDestroyNotify) gda_sql_expr_free);}} +groupby_opt(A) ::= . {A = 0;} +groupby_opt(A) ::= GROUP BY rnexprlist(X). {A = g_slist_reverse (X);} + +%type from {GdaSqlSelectFrom *} +%destructor from {gda_sql_select_from_free ($$);} +from(F) ::= . {F = NULL;} +from(F) ::= FROM seltablist(X). {F = X;} + +%type seltablist {GdaSqlSelectFrom *} +%destructor seltablist {gda_sql_select_from_free ($$);} +%type stl_prefix {GdaSqlSelectFrom *} +%destructor stl_prefix {gda_sql_select_from_free ($$);} + +seltablist(L) ::= stl_prefix(P) seltarget(T) on_cond(C) using_opt(U). { + GSList *last; + if (P) + L = P; + else + L = gda_sql_select_from_new (NULL); + gda_sql_select_from_take_new_target (L, T); + last = g_slist_last (L->joins); + if (last) { + GdaSqlSelectJoin *join = (GdaSqlSelectJoin *) (last->data); + join->expr = C; + join->position = g_slist_length (L->targets) - 1; + join->use = U; + } +} + +%type using_opt {GSList*} +%destructor using_opt {if ($$) {g_slist_free_full ($$, (GDestroyNotify) gda_sql_field_free);}} +using_opt(U) ::= USING LP inscollist(L) RP. {U = L;} +using_opt(U) ::= . {U = NULL;} + +stl_prefix(P) ::= . {P = NULL;} +stl_prefix(P) ::= seltablist(L) jointype(J). {GdaSqlSelectJoin *join; + P = L; + join = gda_sql_select_join_new (GDA_SQL_ANY_PART (P)); + join->type = J; + gda_sql_select_from_take_new_join (P, join); +} + + +%type on_cond {GdaSqlExpr *} +%destructor on_cond {gda_sql_expr_free ($$);} +on_cond(N) ::= ON expr(E). {N = E;} +on_cond(N) ::= . {N = NULL;} + +%type jointype {GdaSqlSelectJoinType} +jointype(J) ::= COMMA. {J = GDA_SQL_SELECT_JOIN_CROSS;} +jointype(J) ::= JOIN. {J = GDA_SQL_SELECT_JOIN_INNER;} +jointype(J) ::= CROSS JOIN. {J = GDA_SQL_SELECT_JOIN_CROSS;} +jointype(J) ::= INNER JOIN. {J = GDA_SQL_SELECT_JOIN_INNER;} +jointype(J) ::= NATURAL JOIN. {J = GDA_SQL_SELECT_JOIN_NATURAL;} +jointype(J) ::= LEFT JOIN. {J = GDA_SQL_SELECT_JOIN_LEFT;} +jointype(J) ::= LEFT OUTER JOIN. {J = GDA_SQL_SELECT_JOIN_LEFT;} +jointype(J) ::= RIGHT JOIN. {J = GDA_SQL_SELECT_JOIN_RIGHT;} +jointype(J) ::= RIGHT OUTER JOIN. {J = GDA_SQL_SELECT_JOIN_RIGHT;} +jointype(J) ::= FULL JOIN. {J = GDA_SQL_SELECT_JOIN_FULL;} +jointype(J) ::= FULL OUTER JOIN. {J = GDA_SQL_SELECT_JOIN_FULL;} + + +%type seltarget {GdaSqlSelectTarget *} +%destructor seltarget {gda_sql_select_target_free ($$);} +seltarget(T) ::= fullname(F) as(A). {T = gda_sql_select_target_new (NULL); + gda_sql_select_target_take_alias (T, A); + gda_sql_select_target_take_table_name (T, F); +} +seltarget(T) ::= fullname(F) ID(A). {T = gda_sql_select_target_new (NULL); + gda_sql_select_target_take_alias (T, A); + gda_sql_select_target_take_table_name (T, F); +} +seltarget(T) ::= LP compound(S) RP as(A). {T = gda_sql_select_target_new (NULL); + gda_sql_select_target_take_alias (T, A); + gda_sql_select_target_take_select (T, S); +} +seltarget(T) ::= LP compound(S) RP ID(A). {T = gda_sql_select_target_new (NULL); + gda_sql_select_target_take_alias (T, A); + gda_sql_select_target_take_select (T, S); +} +%type selcollist {GSList *} +%destructor selcollist {g_slist_free_full ($$, (GDestroyNotify) gda_sql_select_field_free);} + +%type sclp {GSList *} +%destructor sclp {g_slist_free_full ($$, (GDestroyNotify) gda_sql_select_field_free);} +sclp(A) ::= selcollist(X) COMMA. {A = X;} +sclp(A) ::= . {A = NULL;} + +selcollist(L) ::= sclp(E) expr(X) as(A). {GdaSqlSelectField *field; + field = gda_sql_select_field_new (NULL); + gda_sql_select_field_take_expr (field, X); + gda_sql_select_field_take_alias (field, A); + L = g_slist_append (E, field);} +selcollist(L) ::= sclp(E) starname(X). {GdaSqlSelectField *field; + field = gda_sql_select_field_new (NULL); + gda_sql_select_field_take_star_value (field, X); + L = g_slist_append (E, field);} + +starname(S) ::= STAR(X). {S = X;} +starname(A) ::= nm(S) DOT STAR(X). {gchar *str; + str = g_strdup_printf ("%s.%s", g_value_get_string (S), g_value_get_string (X)); + A = g_new0 (GValue, 1); + g_value_init (A, G_TYPE_STRING); + g_value_take_string (A, str); + g_value_reset (S); g_free (S); + g_value_reset (X); g_free (X); +} + +starname(A) ::= nm(C) DOT nm(S) DOT STAR(X). {gchar *str; + str = g_strdup_printf ("%s.%s.%s", g_value_get_string (C), + g_value_get_string (S), g_value_get_string (X)); + A = g_new0 (GValue, 1); + g_value_init (A, G_TYPE_STRING); + g_value_take_string (A, str); + g_value_reset (C); g_free (C); + g_value_reset (S); g_free (S); + g_value_reset (X); g_free (X); +} + +as(A) ::= AS fullname(F). {A = F;} +as(A) ::= AS value(F). {A = F;} +as(A) ::= . {A = NULL;} + +%type distinct {Distinct *} +%destructor distinct {if ($$) {if ($$->expr) gda_sql_expr_free ($$->expr); g_free ($$);}} +distinct(E) ::= . {E = NULL;} +distinct(E) ::= ALL. {E = NULL;} +distinct(E) ::= DISTINCT. {E = g_new0 (Distinct, 1); E->distinct = TRUE;} +distinct(E) ::= DISTINCT ON expr(X). [OR] {E = g_new0 (Distinct, 1); E->distinct = TRUE; E->expr = X;} + +// Non empty list of expressions +%type rnexprlist {GSList *} +%destructor rnexprlist {if ($$) {g_slist_free_full ($$, (GDestroyNotify) gda_sql_expr_free);}} +rnexprlist(L) ::= rnexprlist(E) COMMA expr(X). {L = g_slist_prepend (E, X);} +rnexprlist(L) ::= expr(E). {L = g_slist_append (NULL, E);} + +// List of expressions +%type rexprlist {GSList *} +%destructor rexprlist {if ($$) {g_slist_free_full ($$, (GDestroyNotify) gda_sql_expr_free);}} +rexprlist(L) ::= . {L = NULL;} +rexprlist(L) ::= rexprlist(E) COMMA expr(X). {L = g_slist_prepend (E, X);} +rexprlist(L) ::= expr(E). {L = g_slist_append (NULL, E);} + +// A single expression +%type expr {GdaSqlExpr *} +%destructor expr {gda_sql_expr_free ($$);} +expr(E) ::= pvalue(V). {E = V;} +expr(E) ::= value(V). {E = gda_sql_expr_new (NULL); E->value = V;} +expr(E) ::= LP expr(X) RP. {E = X;} +expr(E) ::= fullname(V). {E = gda_sql_expr_new (NULL); E->value = V;} +expr(E) ::= fullname(V) LP rexprlist(A) RP. {GdaSqlFunction *func; + E = gda_sql_expr_new (NULL); + func = gda_sql_function_new (GDA_SQL_ANY_PART (E)); + gda_sql_function_take_name (func, V); + gda_sql_function_take_args_list (func, g_slist_reverse (A)); + E->func = func;} +expr(E) ::= fullname(V) LP compound(S) RP. {GdaSqlFunction *func; + GdaSqlExpr *expr; + E = gda_sql_expr_new (NULL); + func = gda_sql_function_new (GDA_SQL_ANY_PART (E)); + gda_sql_function_take_name (func, V); + expr = gda_sql_expr_new (GDA_SQL_ANY_PART (func)); + gda_sql_expr_take_select (expr, S); + gda_sql_function_take_args_list (func, g_slist_prepend (NULL, expr)); + E->func = func;} +expr(E) ::= fullname(V) LP starname(A) RP. {GdaSqlFunction *func; + GdaSqlExpr *expr; + E = gda_sql_expr_new (NULL); + func = gda_sql_function_new (GDA_SQL_ANY_PART (E)); + gda_sql_function_take_name (func, V); + expr = gda_sql_expr_new (GDA_SQL_ANY_PART (func)); + expr->value = A; + gda_sql_function_take_args_list (func, g_slist_prepend (NULL, expr)); + E->func = func;} +expr(E) ::= CAST LP expr(A) AS fullname(T) RP. {E = A; + A->cast_as = g_value_dup_string (T); + g_value_reset (T); + g_free (T);} +expr(E) ::= expr(A) PGCAST fullname(T). {E = A; + A->cast_as = g_value_dup_string (T); + g_value_reset (T); + g_free (T);} + +expr(C) ::= expr(L) PLUS|MINUS(O) expr(R). {C = compose_multiple_expr (string_to_op_type (O), L, R);} +expr(C) ::= expr(L) STAR expr(R). {C = compose_multiple_expr (GDA_SQL_OPERATOR_TYPE_STAR, L, R);} +expr(C) ::= expr(L) SLASH|REM(O) expr(R). {C = create_two_expr (string_to_op_type (O), L, R);} +expr(C) ::= expr(L) BITAND|BITOR(O) expr(R). {C = create_two_expr (string_to_op_type (O), L, R);} + +expr(C) ::= MINUS expr(X). [UMINUS] {C = create_uni_expr (GDA_SQL_OPERATOR_TYPE_MINUS, X);} +expr(C) ::= PLUS expr(X). [UPLUS] {C = create_uni_expr (GDA_SQL_OPERATOR_TYPE_PLUS, X);} + +expr(C) ::= expr(L) AND expr(R). {C = compose_multiple_expr (GDA_SQL_OPERATOR_TYPE_AND, L, R);} +expr(C) ::= expr(L) OR expr(R). {C = compose_multiple_expr (GDA_SQL_OPERATOR_TYPE_OR, L, R);} +expr(C) ::= expr(L) CONCAT expr(R). {C = compose_multiple_expr (GDA_SQL_OPERATOR_TYPE_CONCAT, L, R);} + +expr(C) ::= expr(L) GT|LEQ|GEQ|LT(O) expr(R). {C = create_two_expr (string_to_op_type (O), L, R);} +expr(C) ::= expr(L) DIFF|EQ(O) expr(R). {C = create_two_expr (string_to_op_type (O), L, R);} +expr(C) ::= expr(L) LIKE expr(R). {C = create_two_expr (GDA_SQL_OPERATOR_TYPE_LIKE, L, R);} +expr(C) ::= expr(L) ILIKE expr(R). {C = create_two_expr (GDA_SQL_OPERATOR_TYPE_ILIKE, L, R);} +expr(C) ::= expr(L) NOTLIKE expr(R). {C = create_two_expr (GDA_SQL_OPERATOR_TYPE_NOTLIKE, L, R);} +expr(C) ::= expr(L) NOTILIKE expr(R). {C = create_two_expr (GDA_SQL_OPERATOR_TYPE_NOTILIKE, L, R);} +expr(C) ::= expr(L) REGEXP|REGEXP_CI|NOT_REGEXP|NOT_REGEXP_CI|SIMILAR(O) expr(R). {C = create_two_expr (string_to_op_type (O), L, R);} +expr(C) ::= expr(L) BETWEEN expr(R) AND expr(E). {GdaSqlOperation *cond; + C = gda_sql_expr_new (NULL); + cond = gda_sql_operation_new (GDA_SQL_ANY_PART (C)); + C->cond = cond; + cond->operator_type = GDA_SQL_OPERATOR_TYPE_BETWEEN; + cond->operands = g_slist_append (NULL, L); + GDA_SQL_ANY_PART (L)->parent = GDA_SQL_ANY_PART (cond); + cond->operands = g_slist_append (cond->operands, R); + GDA_SQL_ANY_PART (R)->parent = GDA_SQL_ANY_PART (cond); + cond->operands = g_slist_append (cond->operands, E); + GDA_SQL_ANY_PART (E)->parent = GDA_SQL_ANY_PART (cond); +} + +expr(C) ::= expr(L) NOT BETWEEN expr(R) AND expr(E). {GdaSqlOperation *cond; + GdaSqlExpr *expr; + expr = gda_sql_expr_new (NULL); + cond = gda_sql_operation_new (GDA_SQL_ANY_PART (expr)); + expr->cond = cond; + cond->operator_type = GDA_SQL_OPERATOR_TYPE_BETWEEN; + cond->operands = g_slist_append (NULL, L); + GDA_SQL_ANY_PART (L)->parent = GDA_SQL_ANY_PART (cond); + cond->operands = g_slist_append (cond->operands, R); + GDA_SQL_ANY_PART (R)->parent = GDA_SQL_ANY_PART (cond); + cond->operands = g_slist_append (cond->operands, E); + GDA_SQL_ANY_PART (E)->parent = GDA_SQL_ANY_PART (cond); + + C = gda_sql_expr_new (NULL); + cond = gda_sql_operation_new (GDA_SQL_ANY_PART (C)); + C->cond = cond; + cond->operator_type = GDA_SQL_OPERATOR_TYPE_NOT; + cond->operands = g_slist_prepend (NULL, expr); + GDA_SQL_ANY_PART (expr)->parent = GDA_SQL_ANY_PART (cond); +} + +expr(C) ::= NOT expr(R). {C = create_uni_expr (GDA_SQL_OPERATOR_TYPE_NOT, R);} +expr(C) ::= BITNOT expr(R). {C = create_uni_expr (GDA_SQL_OPERATOR_TYPE_BITNOT, R);} +expr(C) ::= expr(R) uni_op(O) . {C = create_uni_expr (O, R);} + +expr(C) ::= expr(L) IS expr(R). {C = create_two_expr (GDA_SQL_OPERATOR_TYPE_IS, L, R);} +expr(E) ::= LP compound(S) RP. {E = gda_sql_expr_new (NULL); gda_sql_expr_take_select (E, S);} +expr(E) ::= expr(R) IN LP rexprlist(L) RP. {GdaSqlOperation *cond; + GSList *list; + E = gda_sql_expr_new (NULL); + cond = gda_sql_operation_new (GDA_SQL_ANY_PART (E)); + E->cond = cond; + cond->operator_type = GDA_SQL_OPERATOR_TYPE_IN; + cond->operands = g_slist_prepend (g_slist_reverse (L), R); + for (list = cond->operands; list; list = list->next) + GDA_SQL_ANY_PART (list->data)->parent = GDA_SQL_ANY_PART (cond); +} +expr(E) ::= expr(R) IN LP compound(S) RP. {GdaSqlOperation *cond; + GdaSqlExpr *expr; + E = gda_sql_expr_new (NULL); + cond = gda_sql_operation_new (GDA_SQL_ANY_PART (E)); + E->cond = cond; + cond->operator_type = GDA_SQL_OPERATOR_TYPE_IN; + + expr = gda_sql_expr_new (GDA_SQL_ANY_PART (cond)); + gda_sql_expr_take_select (expr, S); + cond->operands = g_slist_prepend (NULL, expr); + cond->operands = g_slist_prepend (cond->operands, R); + GDA_SQL_ANY_PART (R)->parent = GDA_SQL_ANY_PART (cond); +} +expr(E) ::= expr(R) NOT IN LP rexprlist(L) RP. {GdaSqlOperation *cond; + GSList *list; + E = gda_sql_expr_new (NULL); + cond = gda_sql_operation_new (GDA_SQL_ANY_PART (E)); + E->cond = cond; + cond->operator_type = GDA_SQL_OPERATOR_TYPE_NOTIN; + cond->operands = g_slist_prepend (g_slist_reverse (L), R); + for (list = cond->operands; list; list = list->next) + GDA_SQL_ANY_PART (list->data)->parent = GDA_SQL_ANY_PART (cond); +} +expr(E) ::= expr(R) NOT IN LP compound(S) RP. {GdaSqlOperation *cond; + GdaSqlExpr *expr; + E = gda_sql_expr_new (NULL); + cond = gda_sql_operation_new (GDA_SQL_ANY_PART (E)); + E->cond = cond; + cond->operator_type = GDA_SQL_OPERATOR_TYPE_NOTIN; + + expr = gda_sql_expr_new (GDA_SQL_ANY_PART (cond)); + gda_sql_expr_take_select (expr, S); + cond->operands = g_slist_prepend (NULL, expr); + cond->operands = g_slist_prepend (cond->operands, R); + GDA_SQL_ANY_PART (R)->parent = GDA_SQL_ANY_PART (cond); +} +expr(A) ::= CASE case_operand(X) case_exprlist(Y) case_else(Z) END. { + GdaSqlCase *sc; + GSList *list; + A = gda_sql_expr_new (NULL); + sc = gda_sql_case_new (GDA_SQL_ANY_PART (A)); + sc->base_expr = X; + sc->else_expr = Z; + sc->when_expr_list = Y.when_list; + sc->then_expr_list = Y.then_list; + A->case_s = sc; + for (list = sc->when_expr_list; list; list = list->next) + GDA_SQL_ANY_PART (list->data)->parent = GDA_SQL_ANY_PART (sc); + for (list = sc->then_expr_list; list; list = list->next) + GDA_SQL_ANY_PART (list->data)->parent = GDA_SQL_ANY_PART (sc); +} + +%type case_operand {GdaSqlExpr*} +%destructor case_operand {gda_sql_expr_free ($$);} +case_operand(A) ::= expr(X). {A = X;} +case_operand(A) ::= . {A = NULL;} + +%type case_exprlist {CaseBody} +%destructor case_exprlist {g_slist_free_full ($$.when_list, (GDestroyNotify) gda_sql_expr_free); + g_slist_free_full ($$.then_list, (GDestroyNotify) gda_sql_expr_free);} + +case_exprlist(A) ::= case_exprlist(X) WHEN expr(Y) THEN expr(Z). { + A.when_list = g_slist_append (X.when_list, Y); + A.then_list = g_slist_append (X.then_list, Z); +} +case_exprlist(A) ::= WHEN expr(Y) THEN expr(Z). { + A.when_list = g_slist_prepend (NULL, Y); + A.then_list = g_slist_prepend (NULL, Z); +} + +%type case_else {GdaSqlExpr*} +%destructor case_else {gda_sql_expr_free ($$);} +case_else(A) ::= ELSE expr(X). {A = X;} +case_else(A) ::= . {A = NULL;} + +%type uni_op {GdaSqlOperatorType} +uni_op(O) ::= ISNULL. {O = GDA_SQL_OPERATOR_TYPE_ISNULL;} +uni_op(O) ::= IS NOTNULL. {O = GDA_SQL_OPERATOR_TYPE_ISNOTNULL;} + + +// Values: for all constants (G_TYPE_STRING GValue) +value(V) ::= NULL. {V = NULL;} +value(V) ::= STRING(S). {V = S;} +//value(V) ::= TEXTUAL(T). {V = T;} +value(V) ::= INTEGER(I). {V = I;} +value(V) ::= FLOAT(F). {V = F;} + +// pvalue: values which are parameters (GdaSqlExpr) +%type pvalue {GdaSqlExpr *} +%destructor pvalue {gda_sql_expr_free ($$);} +pvalue(E) ::= UNSPECVAL LSBRACKET paramspec(P) RSBRACKET. {E = gda_sql_expr_new (NULL); E->param_spec = P;} +pvalue(E) ::= value(V) LSBRACKET paramspec(P) RSBRACKET. {E = gda_sql_expr_new (NULL); E->value = V; E->param_spec = P;} +pvalue(E) ::= SIMPLEPARAM(S). {E = gda_sql_expr_new (NULL); E->param_spec = gda_sql_param_spec_new (S);} + +// paramspec: parameter's specifications +%type paramspec {GdaSqlParamSpec *} +%destructor paramspec {gda_sql_param_spec_free ($$);} +paramspec(P) ::= . {P = NULL;} +paramspec(P) ::= paramspec(E) PNAME(N). {if (!E) P = gda_sql_param_spec_new (NULL); else P = E; + gda_sql_param_spec_take_name (P, N);} +paramspec(P) ::= paramspec(E) PDESCR(N). {if (!E) P = gda_sql_param_spec_new (NULL); else P = E; + gda_sql_param_spec_take_descr (P, N);} +paramspec(P) ::= paramspec(E) PTYPE(N). {if (!E) P = gda_sql_param_spec_new (NULL); else P = E; + gda_sql_param_spec_take_type (P, N);} +paramspec(P) ::= paramspec(E) PNULLOK(N). {if (!E) P = gda_sql_param_spec_new (NULL); else P = E; + gda_sql_param_spec_take_nullok (P, N);} + +// The name of a column or table can be any of the following: +// +nm(A) ::= JOIN(X). {A = X;} +nm(A) ::= ID(X). {A = X;} +nm(A) ::= TEXTUAL(X). {A = X;} +nm(A) ::= LIMIT(X). {A = X;} + +// Fully qualified name +fullname(A) ::= nm(X). {A = X;} +fullname(A) ::= nm(S) DOT nm(X). {gchar *str; + str = g_strdup_printf ("%s.%s", g_value_get_string (S), g_value_get_string (X)); + A = g_new0 (GValue, 1); + g_value_init (A, G_TYPE_STRING); + g_value_take_string (A, str); + g_value_reset (S); g_free (S); + g_value_reset (X); g_free (X); +} + +fullname(A) ::= nm(C) DOT nm(S) DOT nm(X). {gchar *str; + str = g_strdup_printf ("%s.%s.%s", g_value_get_string (C), + g_value_get_string (S), g_value_get_string (X)); + A = g_new0 (GValue, 1); + g_value_init (A, G_TYPE_STRING); + g_value_take_string (A, str); + g_value_reset (C); g_free (C); + g_value_reset (S); g_free (S); + g_value_reset (X); g_free (X); +} diff --git a/.flatpak-builder/cache/objects/1e/821a5ed32b28b4042aa883607b8c8cba5194e80fc35e11b75fad379a6a4e9f.file b/.flatpak-builder/cache/objects/1e/821a5ed32b28b4042aa883607b8c8cba5194e80fc35e11b75fad379a6a4e9f.file new file mode 120000 index 0000000..bacfb57 --- /dev/null +++ b/.flatpak-builder/cache/objects/1e/821a5ed32b28b4042aa883607b8c8cba5194e80fc35e11b75fad379a6a4e9f.file @@ -0,0 +1 @@ +../../share/runtime/locale/eo/share/eo \ No newline at end of file diff --git a/.flatpak-builder/cache/objects/1e/ae87fc76505555a5f11a65e06e60f67e590fc9b0cebc19c1724ae20ca827e6.dirtree b/.flatpak-builder/cache/objects/1e/ae87fc76505555a5f11a65e06e60f67e590fc9b0cebc19c1724ae20ca827e6.dirtree new file mode 100644 index 0000000..936f28d Binary files /dev/null and b/.flatpak-builder/cache/objects/1e/ae87fc76505555a5f11a65e06e60f67e590fc9b0cebc19c1724ae20ca827e6.dirtree differ diff --git a/.flatpak-builder/cache/objects/1e/f575920d15e4802d8419046b233c31b767906027bd9c9e17b9d7cba5b61851.file b/.flatpak-builder/cache/objects/1e/f575920d15e4802d8419046b233c31b767906027bd9c9e17b9d7cba5b61851.file new file mode 100644 index 0000000..0e3ecc1 --- /dev/null +++ b/.flatpak-builder/cache/objects/1e/f575920d15e4802d8419046b233c31b767906027bd9c9e17b9d7cba5b61851.file @@ -0,0 +1,4 @@ +[Application] +name=io.gitlab.idevecore.Pomodoro +runtime=org.gnome.Platform/x86_64/44 +sdk=org.gnome.Sdk/x86_64/44 diff --git a/.flatpak-builder/cache/objects/1f/07e3e98721139713a69b62a8c67aba021f8308be3665482f266aad535e1167.dirtree b/.flatpak-builder/cache/objects/1f/07e3e98721139713a69b62a8c67aba021f8308be3665482f266aad535e1167.dirtree new file mode 100644 index 0000000..72dd7f0 Binary files /dev/null and b/.flatpak-builder/cache/objects/1f/07e3e98721139713a69b62a8c67aba021f8308be3665482f266aad535e1167.dirtree differ diff --git a/.flatpak-builder/cache/objects/1f/43263a296a7d2851a703b98fbf831aa13e40364ddfcf03dacd22b52c0e3963.file b/.flatpak-builder/cache/objects/1f/43263a296a7d2851a703b98fbf831aa13e40364ddfcf03dacd22b52c0e3963.file new file mode 100644 index 0000000..9a29c2a --- /dev/null +++ b/.flatpak-builder/cache/objects/1f/43263a296a7d2851a703b98fbf831aa13e40364ddfcf03dacd22b52c0e3963.file @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + diff --git a/.flatpak-builder/cache/objects/1f/621d4c7ea372f6298b2b447e5d36376b4a4bcabb1122176a6474a28a4eadfe.dirtree b/.flatpak-builder/cache/objects/1f/621d4c7ea372f6298b2b447e5d36376b4a4bcabb1122176a6474a28a4eadfe.dirtree new file mode 100644 index 0000000..d4c26f5 Binary files /dev/null and b/.flatpak-builder/cache/objects/1f/621d4c7ea372f6298b2b447e5d36376b4a4bcabb1122176a6474a28a4eadfe.dirtree differ diff --git a/.flatpak-builder/cache/objects/1f/c3119c6415d6d6b51e9ef5e502022f5b1fee98e6e8d871b84da0efa8b618b0.dirtree b/.flatpak-builder/cache/objects/1f/c3119c6415d6d6b51e9ef5e502022f5b1fee98e6e8d871b84da0efa8b618b0.dirtree new file mode 100644 index 0000000..6562754 Binary files /dev/null and b/.flatpak-builder/cache/objects/1f/c3119c6415d6d6b51e9ef5e502022f5b1fee98e6e8d871b84da0efa8b618b0.dirtree differ diff --git a/.flatpak-builder/cache/objects/1f/d4d89931b81b4d99a286c626095ea6634a9e9d734238e1bb7607b9ece07746.file b/.flatpak-builder/cache/objects/1f/d4d89931b81b4d99a286c626095ea6634a9e9d734238e1bb7607b9ece07746.file new file mode 100644 index 0000000..622a897 --- /dev/null +++ b/.flatpak-builder/cache/objects/1f/d4d89931b81b4d99a286c626095ea6634a9e9d734238e1bb7607b9ece07746.file @@ -0,0 +1,292 @@ + libcanberra 0.30 + + Copyright 2008-2012 Lennart Poettering + * [1]License + * [2]News + * [3]Overview + * [4]Current Status + * [5]Documentation + * [6]Requirements + * [7]Installation + * [8]Acknowledgements + * [9]Download + +License + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation, either version 2.1 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + General Public License for more details. + +News + + Tue 25 Sep 2012: + + [10]Version 0.30 released; Port to GStreamer 1.0. + + Tue 15 May 2012: + + [11]Version 0.29 released; A couple of bugfixes, drop GConf usage. + + Thu 24 Feb 2011: + + [12]Version 0.28 released; Hook properly into GNOME 3.0 sessions; this + drops support for GNOME 2.0 sessions, but not applications. + + Fri 18 Feb 2011: + + [13]Version 0.27 released; Gtk+ 3.x fixes; add new tool to implement + boot-up sounds when used with systemd; other fixes + + Mon 4 Oct 2010: + + [14]Version 0.26 released; Gtk+ 3.x fixes. + + Sun 13 Jun 2010: + + [15]Version 0.25 released; Optionally build with Gtk+ 3.x in addition + to Gtk+ 2.x. + + Mon 19 Apr 2010: + + [16]Version 0.24 released; GTK code is now fine with GSEAL. Minor fixes + in the PulseAudio backend, other fixes. + + Sat 20 Feb 2010: + + [17]Version 0.23 released; various minor fixes in the pulse and + gstreamer backends as well in the Vala API. Support for the recently + standardized Vorbis 6.1/7.1 multichannel modes. + + Tue 20 Oct 2009: + + [18]Version 0.22 released; small fix to make sure we don't dereference + a null pointer. + + Fri 16 Oct 2009: + + [19]Version 0.21 released; suppress casting warning + + Thu 15 Oct 2009: + + [20]Version 0.20 released; minor casting fix + + Wed 14 Oct 2009: + + [21]Version 0.19 released; some important fixes for the Gtk support + + Sun 20 Sep 2009: + + [22]Version 0.18 released; numerous updates for the Gtk support + + Fri 12 Sep 2009: + + [23]Version 0.17 released; add vala vapi file; numerous updates to Gtk + support + + Thu 27 Aug 2009: + + [24]Version 0.16 released; add new ca_context_playing() call + + Wed 5 Aug 2009: + + [25]Version 0.15 released; bug fixes + + Thu 2 Jul 2009: + + [26]Version 0.14 released; bug fixes + + Tue 23 Jun 2009: + + [27]Version 0.13 released; multichannel support; gtk multihead support; + bug fixes + + Mon 13 Apr 2009: + + [28]Version 0.12 released; changes include: various fixes and updates + for the PulseAudio backend; detect forks and return an error for all + functions in that case + + Wed 21 Jan 2009: + + [29]Version 0.11 released; changes include: major GStreamer backend + fixes; update to libtool 2.2; a few other fixes + + Mon 6 Oct 2008: + + [30]Version 0.10 released; changes include: install Gtk+ module using + GConf; a few other fixes + + Tue 9 Sep 2008: + + [31]Version 0.9 released; changes include: GStreamer fixes, include + (optional) libtdb based lookup cache. + + Thu 28 Aug 2008: + + [32]Version 0.8 released; changes include: new OSS and GStreamer + backend; portability fixes for FreeBSD/Solaris; the multi backend works + now + + Thu 14 Aug 2008: + + [33]Version 0.7 released; changes include: documentation updates; + various bug fixes; add this web site/README; allow playback of event + sounds with only a sound file path specified; other changes + +Overview + + libcanberra is an implementation of the [34]XDG Sound Theme and Name + Specifications, for generating event sounds on free desktops, such as + [35]GNOME. It comes with several backends ([36]ALSA, [37]PulseAudio, + OSS, [38]GStreamer, null) and is designed to be portable. It consists + of the following parts: + 1. libcanberra: the main library + 2. libcanberra-gtk: some glue code to make it easier to use + libcanberra from Gtk+ applications + 3. libcanberra-gtk-module: a Gtk+ module that uses libcanberra-gtk to + trigger input feedback event sounds + + For more information see [39]the original announcement. + +Current Status + + libcanberra is mostly feature complete. For now however it includes + backends only for ALSA, PulseAudio, OSS and GStreamer. + + libcanberra has been declared [40]a blessed GNOME dependency. + + The OSS driver is incomplete: only sound files that are in a format + natively understood by the sound card are supported. If the sample + type, channel map or sampling rate of the sound file are not supported + by the sound card no automatic conversion will take place and the file + will not be played. Also note that the OSS backend is most likely + incompatible with OSS4, due to subtle incompatibilities between OSS4 + and the OSS 3.x. + + It is recommended to always take the "shortest" path from libcanberra + to the audio device. I.e. don't use the GStreamer plugin if libcanberra + supports the final output target natively. Besides being more + resource-friendly and less error-prone, some advanced functionality + might get lost with each layer you add to your stack. For example: + while you could use libcanberra's Gstreamer backend to output to a + PulseAudio server this will not be able to make use of sample cacheing + or will be able to attach additional meta data to the sounds played, + which might be necessary for effects like positional event sounds. + +Documentation + + You may browse the [41]gtkdoc generated [42]programing documentation of + the API. + +Requirements + + Currently, libcanberra is tested on Linux only. + + libcanberra was developed and tested on Fedora Rawhide from August + 2008, it should work on most other Linux distributions (and maybe Unix + versions) since it uses GNU autoconf and GNU libtool for source code + configuration and shared library management. + + libcanberra has no dependencies besides the OGG Vorbis development + headers and whatever the selected backends require. Gtk+ support is + optional. An optional lookup cache can be used if Samba's tdb trivial + database is available. + +Installation + + As this package is made with the GNU autotools you should run + ./configure inside the distribution directory for configuring the + source tree. After that you should run make for compilation and make + install (as root) for installation of libcanberra. + +Acknowledgements + + Marc-André Lureau and Brian Cameron for the GStreamer backend. + + Joe Marcus Clarke for the OSS backend. + + Diego Elio Pettenò for various build system fixes. + +Download + + The newest release is always available from + [43]http://0pointer.de/lennart/projects/libcanberra/ + + The current release is [44]0.30 + + Get libcanberra's development sources from the [45]GIT [46]repository + ([47]gitweb): +git clone git://git.0pointer.de/libcanberra + + If you want to report bugs, have questions or want to be notified about + new releases, please join the [48]libcanberra-discuss mailing list. + + If you want to be notified about new git commits, please join the + [49]libcanberra-commits mailing list. + + libcanberra's bugs are tracked at [50]bugs.freedesktop.org. + __________________________________________________________________ + + + Lennart Poettering , September + 2012 + +References + + 1. README#license + 2. README#news + 3. README#overview + 4. README#status + 5. README#documentation + 6. README#requirements + 7. README#installation + 8. README#acks + 9. README#download + 10. http://0pointer.de/lennart/projects/libcanberra/libcanberra-0.30.tar.xz + 11. http://0pointer.de/lennart/projects/libcanberra/libcanberra-0.29.tar.xz + 12. http://0pointer.de/lennart/projects/libcanberra/libcanberra-0.28.tar.gz + 13. http://0pointer.de/lennart/projects/libcanberra/libcanberra-0.27.tar.gz + 14. http://0pointer.de/lennart/projects/libcanberra/libcanberra-0.26.tar.gz + 15. http://0pointer.de/lennart/projects/libcanberra/libcanberra-0.25.tar.gz + 16. http://0pointer.de/lennart/projects/libcanberra/libcanberra-0.24.tar.gz + 17. http://0pointer.de/lennart/projects/libcanberra/libcanberra-0.23.tar.gz + 18. http://0pointer.de/lennart/projects/libcanberra/libcanberra-0.22.tar.gz + 19. http://0pointer.de/lennart/projects/libcanberra/libcanberra-0.21.tar.gz + 20. http://0pointer.de/lennart/projects/libcanberra/libcanberra-0.20.tar.gz + 21. http://0pointer.de/lennart/projects/libcanberra/libcanberra-0.19.tar.gz + 22. http://0pointer.de/lennart/projects/libcanberra/libcanberra-0.18.tar.gz + 23. http://0pointer.de/lennart/projects/libcanberra/libcanberra-0.17.tar.gz + 24. http://0pointer.de/lennart/projects/libcanberra/libcanberra-0.16.tar.gz + 25. http://0pointer.de/lennart/projects/libcanberra/libcanberra-0.15.tar.gz + 26. http://0pointer.de/lennart/projects/libcanberra/libcanberra-0.14.tar.gz + 27. http://0pointer.de/lennart/projects/libcanberra/libcanberra-0.13.tar.gz + 28. http://0pointer.de/lennart/projects/libcanberra/libcanberra-0.12.tar.gz + 29. http://0pointer.de/lennart/projects/libcanberra/libcanberra-0.11.tar.gz + 30. http://0pointer.de/lennart/projects/libcanberra/libcanberra-0.10.tar.gz + 31. http://0pointer.de/lennart/projects/libcanberra/libcanberra-0.9.tar.gz + 32. http://0pointer.de/lennart/projects/libcanberra/libcanberra-0.8.tar.gz + 33. http://0pointer.de/lennart/projects/libcanberra/libcanberra-0.7.tar.gz + 34. http://freedesktop.org/wiki/Specifications/sound-theme-spec + 35. http://www.gnome.org/ + 36. http://alsa-project.org/ + 37. http://pulseaudio.org/ + 38. http://gstreamer.org/ + 39. http://0pointer.de/blog/projects/sixfold-announcement.html + 40. http://mail.gnome.org/archives/devel-announce-list/2008-August/msg00001.html + 41. http://www.gtk.org/gtk-doc/ + 42. http://0pointer.de/lennart/projects/libcanberra/gtkdoc/ + 43. http://0pointer.de/lennart/projects/libcanberra/ + 44. http://0pointer.de/lennart/projects/libcanberra/libcanberra-0.30.tar.xz + 45. http://git-scm.com/ + 46. git://git.0pointer.de/libcanberra + 47. http://git.0pointer.de/?p=libcanberra.git + 48. https://tango.0pointer.de/mailman/listinfo/libcanberra-discuss/ + 49. https://tango.0pointer.de/mailman/listinfo/libcanberra-commits/ + 50. http://bugs.freedesktop.org/buglist.cgi?bug_status=__open__&product=libcanberra diff --git a/.flatpak-builder/cache/objects/1f/d8d0097f3af4e70d208e58fbb543a095bbb789c8496f16c1a80ec24d982213.dirtree b/.flatpak-builder/cache/objects/1f/d8d0097f3af4e70d208e58fbb543a095bbb789c8496f16c1a80ec24d982213.dirtree new file mode 100644 index 0000000..92d993b Binary files /dev/null and b/.flatpak-builder/cache/objects/1f/d8d0097f3af4e70d208e58fbb543a095bbb789c8496f16c1a80ec24d982213.dirtree differ diff --git a/.flatpak-builder/cache/objects/20/1a96375fb60e681dd33f96b0592728c99ca8397efb0fe3bf7f1e8a0fe1c38f.file b/.flatpak-builder/cache/objects/20/1a96375fb60e681dd33f96b0592728c99ca8397efb0fe3bf7f1e8a0fe1c38f.file new file mode 100644 index 0000000..e0d9002 --- /dev/null +++ b/.flatpak-builder/cache/objects/20/1a96375fb60e681dd33f96b0592728c99ca8397efb0fe3bf7f1e8a0fe1c38f.file @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2007 - 2011 Vivien Malerba + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GDA_VPROVIDER_HUB_H__ +#define __GDA_VPROVIDER_HUB_H__ + +#include + +#define GDA_TYPE_VPROVIDER_HUB (gda_vprovider_hub_get_type()) + +G_BEGIN_DECLS + +G_DECLARE_DERIVABLE_TYPE (GdaVproviderHub, gda_vprovider_hub, GDA, VPROVIDER_HUB, GdaVproviderDataModel) + +struct _GdaVproviderHubClass { + GdaVproviderDataModelClass parent_class; + + /*< private >*/ + /* Padding for future expansion */ + void (*_gda_reserved1) (void); + void (*_gda_reserved2) (void); + void (*_gda_reserved3) (void); + void (*_gda_reserved4) (void); +}; + +/** + * SECTION:gda-vprovider-hub + * @short_description: Virtual provider for connections based on other connection + * @title: GdaVproviderHub + * @stability: Stable + * @see_also: See also the introduction to virtual connections + * + * This provider is used to create virtual connections which "incorporate" tables from other connections. This is typically + * used when one need to compare or migrate data from one database to the other by creating two connections for each database, + * and "binding" them into a third virtual connection using this provider. + * + * Using gda_virtual_connection_open() with this provider as argument + * will generate a #GdaVconnectionHub connection object, from which connections can be added. + */ + +GdaVirtualProvider *gda_vprovider_hub_new (void); + +G_END_DECLS + +#endif diff --git a/.flatpak-builder/cache/objects/20/2a5e284351db2ab2aa01df8c8d4bcd68122b752f2848a32c37269c6b81c8b0.file b/.flatpak-builder/cache/objects/20/2a5e284351db2ab2aa01df8c8d4bcd68122b752f2848a32c37269c6b81c8b0.file new file mode 100644 index 0000000..033e2ca --- /dev/null +++ b/.flatpak-builder/cache/objects/20/2a5e284351db2ab2aa01df8c8d4bcd68122b752f2848a32c37269c6b81c8b0.file @@ -0,0 +1,114 @@ +# ui.py +# +# Copyright 2022 James Westman +# +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation; either version 3 of the +# License, or (at your option) any later version. +# +# This file is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program. If not, see . +# +# SPDX-License-Identifier: LGPL-3.0-or-later + +from .. import gir +from .imports import GtkDirective, Import +from .gtkbuilder_template import Template +from .gobject_object import Object +from .gtk_menu import menu, Menu +from .common import * +from .contexts import ScopeCtx + + +class UI(AstNode): + """The AST node for the entire file""" + + grammar = [ + GtkDirective, + ZeroOrMore(Import), + Until( + AnyOf( + Template, + menu, + Object, + ), + Eof(), + ), + ] + + @property + def gir(self) -> gir.GirContext: + gir_ctx = gir.GirContext() + self._gir_errors = [] + + try: + if gtk := self.children[GtkDirective][0].gir_namespace: + gir_ctx.add_namespace(gtk) + except CompileError as e: + self._gir_errors.append(e) + + for i in self.children[Import]: + try: + if i.gir_namespace is not None: + gir_ctx.add_namespace(i.gir_namespace) + else: + gir_ctx.not_found_namespaces.add(i.namespace) + except CompileError as e: + e.start = i.group.tokens["namespace"].start + e.end = i.group.tokens["version"].end + self._gir_errors.append(e) + + return gir_ctx + + @property + def using(self) -> T.List[Import]: + return self.children[Import] + + @property + def gtk_decl(self) -> GtkDirective: + return self.children[GtkDirective][0] + + @property + def contents(self) -> T.List[T.Union[Object, Template, Menu]]: + return [ + child + for child in self.children + if isinstance(child, Object) + or isinstance(child, Template) + or isinstance(child, Menu) + ] + + @property + def template(self) -> T.Optional[Template]: + if len(self.children[Template]): + return self.children[Template][0] + else: + return None + + def is_legacy_template(self, id: str) -> bool: + return ( + id not in self.context[ScopeCtx].objects + and self.template is not None + and self.template.class_name.glib_type_name == id + ) + + @context(ScopeCtx) + def scope_ctx(self) -> ScopeCtx: + return ScopeCtx(node=self) + + @validate() + def gir_errors(self): + # make sure gir is loaded + self.gir + if len(self._gir_errors): + raise MultipleErrors(self._gir_errors) + + @validate() + def unique_ids(self): + self.context[ScopeCtx].validate_unique_ids() diff --git a/.flatpak-builder/cache/objects/20/7bdb44dc2291efb45d3f0629ac3e588ef58bc87dc6c27300ed76df938b4acc.dirtree b/.flatpak-builder/cache/objects/20/7bdb44dc2291efb45d3f0629ac3e588ef58bc87dc6c27300ed76df938b4acc.dirtree new file mode 100644 index 0000000..0b2279b Binary files /dev/null and b/.flatpak-builder/cache/objects/20/7bdb44dc2291efb45d3f0629ac3e588ef58bc87dc6c27300ed76df938b4acc.dirtree differ diff --git a/.flatpak-builder/cache/objects/21/339c491f5f7ab2ca45b122c59284a9ae58d79079460c15e44fb57de2710d6c.file b/.flatpak-builder/cache/objects/21/339c491f5f7ab2ca45b122c59284a9ae58d79079460c15e44fb57de2710d6c.file new file mode 100644 index 0000000..7c8e97e Binary files /dev/null and b/.flatpak-builder/cache/objects/21/339c491f5f7ab2ca45b122c59284a9ae58d79079460c15e44fb57de2710d6c.file differ diff --git a/.flatpak-builder/cache/objects/21/6d44bd2eb937fe660dee88f643607fb81c3fe7be6ff3407cf870fb11eaf29e.file b/.flatpak-builder/cache/objects/21/6d44bd2eb937fe660dee88f643607fb81c3fe7be6ff3407cf870fb11eaf29e.file new file mode 100644 index 0000000..1896185 Binary files /dev/null and b/.flatpak-builder/cache/objects/21/6d44bd2eb937fe660dee88f643607fb81c3fe7be6ff3407cf870fb11eaf29e.file differ diff --git a/.flatpak-builder/cache/objects/21/7461ff43c3d769ae9165da4e3fb0bd3c1e43ea5b88a76d3e6a1e9ee874e69f.file b/.flatpak-builder/cache/objects/21/7461ff43c3d769ae9165da4e3fb0bd3c1e43ea5b88a76d3e6a1e9ee874e69f.file new file mode 100644 index 0000000..4d72529 Binary files /dev/null and b/.flatpak-builder/cache/objects/21/7461ff43c3d769ae9165da4e3fb0bd3c1e43ea5b88a76d3e6a1e9ee874e69f.file differ diff --git a/.flatpak-builder/cache/objects/21/97358bfc75cbca39fbbccdb1ac631f25bed3f5407500871a37e4b68b08ba5f.dirtree b/.flatpak-builder/cache/objects/21/97358bfc75cbca39fbbccdb1ac631f25bed3f5407500871a37e4b68b08ba5f.dirtree new file mode 100644 index 0000000..7597018 Binary files /dev/null and b/.flatpak-builder/cache/objects/21/97358bfc75cbca39fbbccdb1ac631f25bed3f5407500871a37e4b68b08ba5f.dirtree differ diff --git a/.flatpak-builder/cache/objects/21/d625f19d8fe6e9dde7c71b815b50d0524f5d6458285ffa712d2f2c13578784.file b/.flatpak-builder/cache/objects/21/d625f19d8fe6e9dde7c71b815b50d0524f5d6458285ffa712d2f2c13578784.file new file mode 120000 index 0000000..2d395a5 --- /dev/null +++ b/.flatpak-builder/cache/objects/21/d625f19d8fe6e9dde7c71b815b50d0524f5d6458285ffa712d2f2c13578784.file @@ -0,0 +1 @@ +../../share/runtime/locale/sq/share/sq \ No newline at end of file diff --git a/.flatpak-builder/cache/objects/22/6b58723a448243a53779764084de38e4dfe0eb39ddc74e468b308772bb907a.file b/.flatpak-builder/cache/objects/22/6b58723a448243a53779764084de38e4dfe0eb39ddc74e468b308772bb907a.file new file mode 100644 index 0000000..29d95de --- /dev/null +++ b/.flatpak-builder/cache/objects/22/6b58723a448243a53779764084de38e4dfe0eb39ddc74e468b308772bb907a.file @@ -0,0 +1,81 @@ +# contexts.py +# +# Copyright 2023 James Westman +# +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation; either version 3 of the +# License, or (at your option) any later version. +# +# This file is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program. If not, see . +# +# SPDX-License-Identifier: LGPL-3.0-or-later + +import typing as T +from dataclasses import dataclass +from functools import cached_property + +from .common import * +from .gobject_object import Object +from .gtkbuilder_template import Template + + +@dataclass +class ValueTypeCtx: + value_type: T.Optional[GirType] + allow_null: bool = False + + +@dataclass +class ScopeCtx: + node: AstNode + + @cached_property + def template(self): + from .ui import UI + from .gtk_list_item_factory import ExtListItemFactory + + if isinstance(self.node, UI): + return self.node.template + elif isinstance(self.node, ExtListItemFactory): + return self.node + + @cached_property + def objects(self) -> T.Dict[str, Object]: + return { + obj.tokens["id"]: obj + for obj in self._iter_recursive(self.node) + if obj.tokens["id"] is not None + } + + def validate_unique_ids(self) -> None: + from .gtk_list_item_factory import ExtListItemFactory + + passed = {} + for obj in self._iter_recursive(self.node): + if obj.tokens["id"] is None: + continue + + if obj.tokens["id"] in passed: + token = obj.group.tokens["id"] + if not isinstance(obj, Template) and not isinstance( + obj, ExtListItemFactory + ): + raise CompileError( + f"Duplicate object ID '{obj.tokens['id']}'", + token.start, + token.end, + ) + passed[obj.tokens["id"]] = obj + + def _iter_recursive(self, node: AstNode): + yield node + for child in node.children: + if child.context[ScopeCtx] is self: + yield from self._iter_recursive(child) diff --git a/.flatpak-builder/cache/objects/22/a49967fa7002ca9ff4245025ef3f38267f59d7b3eb7922771454918b67c1b7.dirtree b/.flatpak-builder/cache/objects/22/a49967fa7002ca9ff4245025ef3f38267f59d7b3eb7922771454918b67c1b7.dirtree new file mode 100644 index 0000000..d350078 Binary files /dev/null and b/.flatpak-builder/cache/objects/22/a49967fa7002ca9ff4245025ef3f38267f59d7b3eb7922771454918b67c1b7.dirtree differ diff --git a/.flatpak-builder/cache/objects/22/cfdbcc21ec57b429fec6ec7bd2ecfd1cbb0a7ca350477452d8598c4192d16b.dirtree b/.flatpak-builder/cache/objects/22/cfdbcc21ec57b429fec6ec7bd2ecfd1cbb0a7ca350477452d8598c4192d16b.dirtree new file mode 100644 index 0000000..e889e51 Binary files /dev/null and b/.flatpak-builder/cache/objects/22/cfdbcc21ec57b429fec6ec7bd2ecfd1cbb0a7ca350477452d8598c4192d16b.dirtree differ diff --git a/.flatpak-builder/cache/objects/22/ef58d6401a8eec7412730315e884cb3cc9102b3489ea09517ca04fe4835c7e.dirtree b/.flatpak-builder/cache/objects/22/ef58d6401a8eec7412730315e884cb3cc9102b3489ea09517ca04fe4835c7e.dirtree new file mode 100644 index 0000000..6c94fc4 Binary files /dev/null and b/.flatpak-builder/cache/objects/22/ef58d6401a8eec7412730315e884cb3cc9102b3489ea09517ca04fe4835c7e.dirtree differ diff --git a/.flatpak-builder/cache/objects/24/0742c8ea368dd739631085b8f6b0ca85f332f34a79efb6242c384ac14008c2.file b/.flatpak-builder/cache/objects/24/0742c8ea368dd739631085b8f6b0ca85f332f34a79efb6242c384ac14008c2.file new file mode 100644 index 0000000..ef558bf --- /dev/null +++ b/.flatpak-builder/cache/objects/24/0742c8ea368dd739631085b8f6b0ca85f332f34a79efb6242c384ac14008c2.file @@ -0,0 +1,814 @@ +/* + * Copyright (C) 2008 Murray Cumming + * Copyright (C) 2008 - 2014 Vivien Malerba + * Copyright (C) 2009 Bas Driessen + * Copyright (C) 2009 Og B. Maciel + * Copyright (C) 2010 David King + * Copyright (C) 2010 Jonh Wendell + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +#define G_LOG_DOMAIN "GDA-xa-transaction" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static void gda_xa_transaction_class_init (GdaXaTransactionClass *klass); +static void gda_xa_transaction_init (GdaXaTransaction *xa_trans); +static void gda_xa_transaction_dispose (GObject *object); + +static void gda_xa_transaction_set_property (GObject *object, + guint param_id, + const GValue *value, + GParamSpec *pspec); +static void gda_xa_transaction_get_property (GObject *object, + guint param_id, + GValue *value, + GParamSpec *pspec); + + +typedef struct { + GdaXaTransactionId xid; + GHashTable *cnc_hash; /* key = cnc, value = branch qualifier as a GdaBinary */ + GList *cnc_list; + GdaConnection *non_xa_cnc; /* connection which does not support distributed transaction (also in @cnc_list) */ +} GdaXaTransactionPrivate; +G_DEFINE_TYPE_WITH_PRIVATE (GdaXaTransaction, gda_xa_transaction, G_TYPE_OBJECT) +/* properties */ +enum +{ + PROP_0, + PROP_FORMAT_ID, + PROP_TRANSACT_ID +}; + + +/* + * GdaXaTransaction class implementation + */ + +static void +gda_xa_transaction_class_init (GdaXaTransactionClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->dispose = gda_xa_transaction_dispose; + + + /* Properties */ + object_class->set_property = gda_xa_transaction_set_property; + object_class->get_property = gda_xa_transaction_get_property; + g_object_class_install_property (object_class, PROP_FORMAT_ID, + g_param_spec_uint ("format-id", NULL, NULL, + 0, G_MAXUINT32, 1, + G_PARAM_WRITABLE | G_PARAM_READABLE | + G_PARAM_CONSTRUCT_ONLY)); + g_object_class_install_property (object_class, PROP_TRANSACT_ID, + g_param_spec_string ("transaction-id", NULL, NULL, + NULL, + G_PARAM_WRITABLE | G_PARAM_READABLE | + G_PARAM_CONSTRUCT_ONLY)); +} + +static void +gda_xa_transaction_init (GdaXaTransaction *xa_trans) +{ + GdaXaTransactionPrivate *priv = gda_xa_transaction_get_instance_private (xa_trans); + priv->xid.format = 1; + priv->xid.gtrid_length = 0; + priv->xid.bqual_length = 0; + + priv->cnc_hash = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify)gda_binary_free); + priv->cnc_list = NULL; + priv->non_xa_cnc = NULL; +} + +static void +gda_xa_transaction_dispose (GObject *object) +{ + GdaXaTransaction *xa_trans = (GdaXaTransaction *) object; + + g_return_if_fail (GDA_IS_XA_TRANSACTION (xa_trans)); + GdaXaTransactionPrivate *priv = gda_xa_transaction_get_instance_private (xa_trans); + + if (priv->cnc_list) { + GList *list; + for (list = priv->cnc_list; list; list = list->next) { + g_object_set_data (G_OBJECT (list->data), "_gda_xa_transaction", NULL); + g_object_unref (G_OBJECT (list->data)); + } + g_list_free (priv->cnc_list); + priv->cnc_list = NULL; + } + if (priv->cnc_hash) { + g_hash_table_destroy (priv->cnc_hash); + priv->cnc_hash = NULL; + } + + /* chain to parent class */ + G_OBJECT_CLASS (gda_xa_transaction_parent_class)->dispose (object); +} + +static void +gda_xa_transaction_set_property (GObject *object, + guint param_id, + const GValue *value, + GParamSpec *pspec) +{ + GdaXaTransaction *xa_trans; + + xa_trans = GDA_XA_TRANSACTION (object); + GdaXaTransactionPrivate *priv = gda_xa_transaction_get_instance_private (xa_trans); + if (priv) { + switch (param_id) { + case PROP_FORMAT_ID: + priv->xid.format = g_value_get_uint (value); + break; + case PROP_TRANSACT_ID: { + const gchar *tmp; + gint len; + + tmp = g_value_get_string (value); + if (!tmp) { + gchar *dtmp; + dtmp = g_strdup_printf ("gda_global_transaction_%p", xa_trans); + len = strlen (dtmp); + g_assert (len <= 64); + priv->xid.gtrid_length = len; + memcpy (priv->xid.data, dtmp, len); /* Flawfinder: ignore */ + g_free (dtmp); + } + else { + len = strlen (tmp); + if (len > 64) + g_warning (_("Global transaction ID can not have more than 64 bytes")); + else { + priv->xid.gtrid_length = len; + memcpy (priv->xid.data, tmp, len); /* Flawfinder: ignore */ + } + } + break; + } + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + break; + } + } +} + +static void +gda_xa_transaction_get_property (GObject *object, + guint param_id, + GValue *value, + GParamSpec *pspec) +{ + GdaXaTransaction *xa_trans; + + xa_trans = GDA_XA_TRANSACTION (object); + GdaXaTransactionPrivate *priv = gda_xa_transaction_get_instance_private (xa_trans); + if (priv) { + switch (param_id) { + case PROP_FORMAT_ID: + g_value_set_uint (value, priv->xid.format); + break; + case PROP_TRANSACT_ID: { + gchar *tmp; + + tmp = g_new (gchar, priv->xid.gtrid_length + 1); + memcpy (tmp, priv->xid.data, priv->xid.gtrid_length); /* Flawfinder: ignore */ + tmp [priv->xid.gtrid_length] = 0; + g_value_take_string (value, tmp); + break; + } + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + break; + } + } +} + + +/* module error */ +GQuark gda_xa_transaction_error_quark (void) +{ + static GQuark quark; + if (!quark) + quark = g_quark_from_static_string ("gda_xa_transaction_error"); + return quark; +} + +/** + * gda_xa_transaction_new: + * @format: a format ID + * @global_transaction_id: the global transaction ID + * + * Creates a new #GdaXaTransaction object, which will control the process of + * performing a distributed transaction across several connections. + * + * Returns: (transfer full): the newly created object. + */ +GdaXaTransaction * +gda_xa_transaction_new (guint32 format, const gchar *global_transaction_id) +{ + g_return_val_if_fail (global_transaction_id && *global_transaction_id, NULL); + return (GdaXaTransaction*) g_object_new (GDA_TYPE_XA_TRANSACTION, "format", format, + "trans", global_transaction_id, NULL); +} + +/** + * gda_xa_transaction_register_connection: + * @xa_trans: a #GdaXaTransaction object + * @cnc: the connection to add to @xa_trans + * @branch: the branch qualifier + * @error: (nullable): a place to store errors, or %NULL + * + * Registers @cnc to be used by @xa_trans to create a distributed transaction. + * + * Note: any #GdaConnection object can only be registered with at most one #GdaXaTransaction object; also + * some connections may not be registered at all with a #GdaXaTransaction object because the database + * provider being used does not support it. + * + * Returns: %TRUE if no error occurred + */ +gboolean +gda_xa_transaction_register_connection (GdaXaTransaction *xa_trans, GdaConnection *cnc, + const gchar *branch, GError **error) +{ + GdaBinary *bin; + + g_return_val_if_fail (GDA_IS_XA_TRANSACTION (xa_trans), FALSE); + g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE); + g_return_val_if_fail (branch && *branch, FALSE); + GdaXaTransactionPrivate *priv = gda_xa_transaction_get_instance_private (xa_trans); + if (strlen (branch) >= 64) { + g_set_error (error, GDA_XA_TRANSACTION_ERROR, + GDA_XA_TRANSACTION_CONNECTION_BRANCH_LENGTH_ERROR, + "%s", _("Connection branch cannot exceed 63 bytes")); + return FALSE; + } + + const GdaBinary *ebranch = g_hash_table_lookup (priv->cnc_hash, cnc); + if (ebranch) { + bin = gda_binary_new (); + gda_binary_set_data (bin, (const guchar *)branch, strlen (branch) + 1); + g_hash_table_insert (priv->cnc_hash, cnc, bin); + return TRUE; + } + + /* check that @cnc is not already registered with another GdaXaTransaction object */ + if (g_object_get_data (G_OBJECT (cnc), "_gda_xa_transaction")) { + g_set_error (error, GDA_XA_TRANSACTION_ERROR, + GDA_XA_TRANSACTION_ALREADY_REGISTERED_ERROR, + "%s", _("Connection already registered with another GdaXaTransaction object")); + return FALSE; + } + + /* check that connection supports distributed transaction, only ONE connection in @xa_trans is allowed + * to not support them */ + GdaServerProvider *prov; + prov = gda_connection_get_provider (cnc); + + if (!gda_server_provider_supports_feature (prov, cnc, GDA_CONNECTION_FEATURE_XA_TRANSACTIONS)) { + /* if another connection does not support distributed transaction, then there is an error */ + if (priv->non_xa_cnc) { + g_set_error (error, GDA_XA_TRANSACTION_ERROR, + GDA_XA_TRANSACTION_DTP_NOT_SUPPORTED_ERROR, + "%s", _("Connection does not support distributed transaction")); + return FALSE; + } + else + priv->non_xa_cnc = cnc; + } + + bin = gda_binary_new (); + gda_binary_set_data (bin, (const guchar *)branch, strlen (branch) + 1); + priv->cnc_list = g_list_prepend (priv->cnc_list, cnc); + g_hash_table_insert (priv->cnc_hash, cnc, bin); + g_object_ref (cnc); + g_object_set_data (G_OBJECT (cnc), "_gda_xa_transaction", xa_trans); + + return TRUE; +} + +/** + * gda_xa_transaction_unregister_connection: + * @xa_trans: a #GdaXaTransaction object + * @cnc: the connection to add to @xa_trans + * + * Unregisters @cnc to be used by @xa_trans to create a distributed transaction. This is + * the opposite of gda_xa_transaction_register_connection(). + */ +void +gda_xa_transaction_unregister_connection (GdaXaTransaction *xa_trans, GdaConnection *cnc) +{ + g_return_if_fail (GDA_IS_XA_TRANSACTION (xa_trans)); + g_return_if_fail (GDA_IS_CONNECTION (cnc)); + GdaXaTransactionPrivate *priv = gda_xa_transaction_get_instance_private (xa_trans); + + if (!g_list_find (priv->cnc_list, cnc)) { + g_warning (_("Cannot unregister connection not registered with GdaXaTransaction object")); + return; + } + priv->cnc_list = g_list_remove (priv->cnc_list, cnc); + g_hash_table_remove (priv->cnc_hash, cnc); + g_object_set_data (G_OBJECT (cnc), "_gda_xa_transaction", NULL); + g_object_unref (cnc); +} + +/** + * gda_xa_transaction_begin: + * @xa_trans: a #GdaXaTransaction object + * @error: (nullable): a place to store errors, or %NULL + * + * Begins a distributed transaction (managed by @xa_trans). Please note that this phase may fail + * for some connections if a (normal) transaction is already started (this depends on the database + * provider being used), so it's better to avoid starting any (normal) transaction on any of the + * connections registered with @xa_trans. + * + * Returns: TRUE if no error occurred + */ +gboolean +gda_xa_transaction_begin (GdaXaTransaction *xa_trans, GError **error) +{ + GList *list; + g_return_val_if_fail (GDA_IS_XA_TRANSACTION (xa_trans), FALSE); + GdaXaTransactionPrivate *priv = gda_xa_transaction_get_instance_private (xa_trans); + + for (list = priv->cnc_list; list; list = list->next) { + GdaConnection *cnc; + GdaServerProvider *prov; + + cnc = GDA_CONNECTION (list->data); + prov = gda_connection_get_provider (cnc); + if (cnc != priv->non_xa_cnc) { + GdaBinary *branch; + branch = g_hash_table_lookup (priv->cnc_hash, cnc); + memcpy (priv->xid.data + priv->xid.gtrid_length, /* Flawfinder: ignore */ + gda_binary_get_data (branch), gda_binary_get_size (branch)); + if (! _gda_server_provider_xa_start (prov, cnc, &(priv->xid), error)) + break; + } + else { + /* do a simple BEGIN */ + if (! gda_connection_begin_transaction (cnc, NULL, GDA_TRANSACTION_ISOLATION_UNKNOWN, + error)) + break; + } + } + + if (list) { + /* something went wrong */ + for (; list; list = list->prev) { + GdaConnection *cnc; + GdaServerProvider *prov; + + cnc = GDA_CONNECTION (list->data); + prov = gda_connection_get_provider (cnc); + if (cnc != priv->non_xa_cnc) { + GdaBinary *branch; + branch = g_hash_table_lookup (priv->cnc_hash, cnc); + memcpy (priv->xid.data + priv->xid.gtrid_length, /* Flawfinder: ignore */ + gda_binary_get_data (branch), gda_binary_get_size (branch)); + _gda_server_provider_xa_rollback (prov, cnc, &(priv->xid), NULL); + } + else { + /* do a simple ROLLBACK */ + gda_connection_rollback_transaction (cnc, NULL, NULL); + } + } + return FALSE; + } + return TRUE; +} + +/** + * gda_xa_transaction_commit: + * @xa_trans: a #GdaXaTransaction object + * @cnc_to_recover: (nullable) (element-type Gda.Connection) (out callee-allocates): a place to store the list of connections for which the commit phase failed, or %NULL + * @error: a place to store errors, or %NULL + * + * Commits a distributed transaction (managed by @xa_trans). The commit is composed of two phases: + * + * a PREPARE phase where all the connections are required to store their transaction data to a + * permanent place (to be able to complete the commit should a problem occur afterwards) + * a COMMIT phase where the transaction data is actually written to the database + * + * + * If the PREPARE phase fails for any of the connection registered with @xa_trans, then the distributed commit + * fails and FALSE is returned. During the COMMIT phase, some commit may actually fail but the transaction can + * still be completed because the PREPARE phase succeeded (through the recover method). + * + * Returns: TRUE if no error occurred (there may be some connections to recover, though) + */ +gboolean +gda_xa_transaction_commit (GdaXaTransaction *xa_trans, GSList **cnc_to_recover, GError **error) +{ + GList *list; + if (cnc_to_recover) + *cnc_to_recover = NULL; + + g_return_val_if_fail (GDA_IS_XA_TRANSACTION (xa_trans), FALSE); + GdaXaTransactionPrivate *priv = gda_xa_transaction_get_instance_private (xa_trans); + + /* + * PREPARE phase + */ + for (list = priv->cnc_list; list; list = list->next) { + GdaConnection *cnc = NULL; + GdaServerProvider *prov; + GdaBinary *branch; + + if (cnc == priv->non_xa_cnc) + continue; + + cnc = GDA_CONNECTION (list->data); + prov = gda_connection_get_provider (cnc); + + branch = g_hash_table_lookup (priv->cnc_hash, cnc); + memcpy (priv->xid.data + priv->xid.gtrid_length, /* Flawfinder: ignore */ + gda_binary_get_data (branch), gda_binary_get_size (branch)); + + if (!_gda_server_provider_xa_end (prov, cnc, &(priv->xid), error)) + break; + + if (!_gda_server_provider_xa_prepare (prov, cnc, &(priv->xid), error)) + break; + } + if (list) { + /* something went wrong during the PREPARE phase => rollback everything */ + for (; list; list = list->prev) { + GdaConnection *cnc = NULL; + GdaServerProvider *prov; + + if (cnc == priv->non_xa_cnc) + gda_connection_rollback_transaction (cnc, NULL, NULL); + else { + GdaBinary *branch; + cnc = GDA_CONNECTION (list->data); + prov = gda_connection_get_provider (cnc); + branch = g_hash_table_lookup (priv->cnc_hash, cnc); + memcpy (priv->xid.data + priv->xid.gtrid_length, /* Flawfinder: ignore */ + gda_binary_get_data (branch), gda_binary_get_size (branch)); + _gda_server_provider_xa_rollback (prov, cnc, &(priv->xid), NULL); + } + } + return FALSE; + } + + /* + * COMMIT phase + */ + if (priv->non_xa_cnc && + ! gda_connection_commit_transaction (priv->non_xa_cnc, NULL, error)) { + /* something went wrong => rollback everything */ + for (list = priv->cnc_list; list; list = list->next) { + GdaConnection *cnc = NULL; + GdaServerProvider *prov; + + if (cnc == priv->non_xa_cnc) + gda_connection_rollback_transaction (cnc, NULL, NULL); + else { + GdaBinary *branch; + cnc = GDA_CONNECTION (list->data); + prov = gda_connection_get_provider (cnc); + branch = g_hash_table_lookup (priv->cnc_hash, cnc); + memcpy (priv->xid.data + priv->xid.gtrid_length, /* Flawfinder: ignore */ + gda_binary_get_data (branch), gda_binary_get_size (branch)); + _gda_server_provider_xa_rollback (prov, cnc, &(priv->xid), NULL); + } + } + return FALSE; + } + + for (list = priv->cnc_list; list; list = list->next) { + GdaConnection *cnc = NULL; + GdaServerProvider *prov; + GdaBinary *branch; + + if (cnc == priv->non_xa_cnc) + continue; + + cnc = GDA_CONNECTION (list->data); + prov = gda_connection_get_provider (cnc); + branch = g_hash_table_lookup (priv->cnc_hash, cnc); + memcpy (priv->xid.data + priv->xid.gtrid_length, /* Flawfinder: ignore */ + gda_binary_get_data (branch), gda_binary_get_size (branch)); + if (! _gda_server_provider_xa_commit (prov, cnc, &(priv->xid), error) && + cnc_to_recover) + *cnc_to_recover = g_slist_prepend (*cnc_to_recover, cnc); + } + + return TRUE; +} + +/** + * gda_xa_transaction_rollback: + * @xa_trans: a #GdaXaTransaction object + * @error: (nullable): a place to store errors, or %NULL + * + * Cancels a distributed transaction (managed by @xa_trans). + * + * Returns: %TRUE if no error occurred + */ +gboolean +gda_xa_transaction_rollback (GdaXaTransaction *xa_trans, GError **error) +{ + GList *list; + g_return_val_if_fail (GDA_IS_XA_TRANSACTION (xa_trans), FALSE); + GdaXaTransactionPrivate *priv = gda_xa_transaction_get_instance_private (xa_trans); + + for (list = priv->cnc_list; list; list = list->next) { + GdaConnection *cnc; + GdaServerProvider *prov; + + cnc = GDA_CONNECTION (list->data); + prov = gda_connection_get_provider (cnc); + + if (cnc == priv->non_xa_cnc) + gda_connection_rollback_transaction (cnc, NULL, NULL); + else { + GdaBinary *branch; + branch = g_hash_table_lookup (priv->cnc_hash, cnc); + memcpy (priv->xid.data + priv->xid.gtrid_length, /* Flawfinder: ignore */ + gda_binary_get_data (branch), gda_binary_get_size (branch)); + GError *lerror = NULL; + _gda_server_provider_xa_rollback (prov, cnc, &(priv->xid), &lerror); + if (error && !*error) + g_propagate_error (error, lerror); + else + g_clear_error (&lerror); + } + } + return TRUE; +} + +/** + * gda_xa_transaction_commit_recovered: + * @xa_trans: a #GdaXaTransaction object + * @cnc_to_recover: (nullable) (element-type Gda.Connection) (out callee-allocates): a place to store the list of connections for which the there were data to recover and which failed to be actually committed, or %NULL + * @error: (nullable): a place to store errors, or %NULL + * + * Tries to commit the data prepared but which failed to commit (see gda_xa_transaction_commit()). This + * method allows one to terminate a distributed transaction which succeeded but for which some + * connections needed to be recovered. + * + * Returns: %TRUE if all the data which was still uncommitted has been committed + */ +gboolean +gda_xa_transaction_commit_recovered (GdaXaTransaction *xa_trans, GSList **cnc_to_recover, GError **error) +{ + GList *list; + gboolean retval = TRUE; + + if (cnc_to_recover) + *cnc_to_recover = NULL; + g_return_val_if_fail (GDA_IS_XA_TRANSACTION (xa_trans), FALSE); + GdaXaTransactionPrivate *priv = gda_xa_transaction_get_instance_private (xa_trans); + + for (list = priv->cnc_list; list; list = list->next) { + GdaConnection *cnc; + GdaServerProvider *prov; + + cnc = GDA_CONNECTION (list->data); + prov = gda_connection_get_provider (cnc); + + if (cnc == priv->non_xa_cnc) + continue; + else { + GList *recov_xid_list; + + GdaBinary *branch; + GList *xlist; + gboolean commit_needed = FALSE; + + recov_xid_list = _gda_server_provider_xa_recover (prov, cnc, error); + if (!recov_xid_list) + continue; + + branch = g_hash_table_lookup (priv->cnc_hash, cnc); + memcpy (priv->xid.data + priv->xid.gtrid_length, /* Flawfinder: ignore */ + gda_binary_get_data (branch), gda_binary_get_size (branch)); + for (xlist = recov_xid_list; xlist; xlist = xlist->next) { + GdaXaTransactionId *xid = (GdaXaTransactionId*) xlist->data; + if (!xid) + /* ignore unknown XID format */ + continue; + + if (!commit_needed && + (xid->format == priv->xid.format) && + (xid->gtrid_length == priv->xid.gtrid_length) && + (xid->bqual_length == priv->xid.bqual_length) && + ! memcmp (priv->xid.data, xid->data, xid->bqual_length + xid->bqual_length)) + /* found a transaction to commit */ + commit_needed = TRUE; + + g_free (xid); + } + g_list_free (recov_xid_list); + + if (commit_needed) { + retval = _gda_server_provider_xa_commit (prov, cnc, &(priv->xid), error); + if (!retval) + if (cnc_to_recover) + *cnc_to_recover = g_slist_prepend (*cnc_to_recover, cnc); + } + } + } + return retval; +} + + +GdaXaTransactionId * +gda_xa_transaction_id_copy (GdaXaTransactionId *src) { + GdaXaTransactionId *cp = g_new0 (GdaXaTransactionId, 1); + cp->format = src->format; + cp->gtrid_length = src->gtrid_length; + cp->bqual_length = src->bqual_length; + for(int i = 0; i < 128; i++) { + cp->data[i] = src->data[i]; + } + return cp; +} +void +gda_xa_transaction_id_free (GdaXaTransactionId *tid) { + g_free (tid); +} + +G_DEFINE_BOXED_TYPE(GdaXaTransactionId, gda_xa_transaction_id, gda_xa_transaction_id_copy, gda_xa_transaction_id_free) + +/** + * gda_xa_transaction_id_to_string: + * @xid: a #GdaXaTransactionId pointer + * + * Creates a string representation of @xid, in the format <gtrid>,<bqual>,<formatID> the + * <gtrid> and <bqual> strings contain alphanumeric characters, and non alphanumeric characters + * are converted to "%ab" where ab is the hexadecimal representation of the character. + * + * Returns: (transfer full): a new string representation of @xid + */ +gchar * +gda_xa_transaction_id_to_string (const GdaXaTransactionId *xid) +{ +#define XID_SIZE (128 * 3 +15) + gchar *str = g_new0 (gchar, XID_SIZE); + int index = 0, i; + + g_return_val_if_fail (xid, NULL); + + /* global transaction ID */ + for (i = 0; i < xid->gtrid_length; i++) { + if (g_ascii_isalnum (xid->data[i])) { + str [index] = xid->data[i]; + index++; + } + else + index += sprintf (str+index, "%%%02x", xid->data[i]); /* Flawfinder: ignore */ + } + + /* branch qualifier */ + str [index++] = ','; + for (i = 0; i < xid->bqual_length; i++) { + if (g_ascii_isalnum (xid->data[xid->gtrid_length + i])) { + str [index] = xid->data[xid->gtrid_length + i]; + index++; + } + else + index += sprintf (str+index, "%%%02x", xid->data[xid->gtrid_length + i]); /* Flawfinder: ignore */ + } + + /* Format ID */ + str [index++] = ','; + sprintf (str, "%d", xid->format); /* Flawfinder: ignore */ + + return str; +} + +/** + * gda_xa_transaction_string_to_id: + * @str: a string representation of a #GdaXaTransactionId, in the "gtrid,bqual,formatID" format + * + * Creates a new #GdaXaTransactionId structure from its string representation, it's the opposite + * of gda_xa_transaction_id_to_string(). + * + * Returns: a new #GdaXaTransactionId structure, or %NULL in @str has a wrong format + * + * Free-function: g_free + */ +GdaXaTransactionId * +gda_xa_transaction_string_to_id (const gchar *str) +{ + GdaXaTransactionId *xid; + const gchar *ptr; + int index = 0; + + g_return_val_if_fail (str, NULL); + + xid = g_new0 (GdaXaTransactionId, 1); + + /* global transaction ID */ + for (ptr = str; *ptr && (*ptr != ','); ptr++, index++) { + if (index >= 64) + goto onerror; + + if (*ptr == '%') { + ptr++; + if (*ptr && (((*ptr >= 'a') && (*ptr <= 'f')) || + ((*ptr >= '0') && (*ptr <= '9')))) { + if ((*ptr >= 'a') && (*ptr <= 'f')) + xid->data [index] = (*ptr - 'a' + 10) * 16; + else + xid->data [index] = (*ptr - '0') * 16; + ptr++; + if (*ptr && (((*ptr >= 'a') && (*ptr <= 'f')) || + ((*ptr >= '0') && (*ptr <= '9')))) { + if ((*ptr >= 'a') && (*ptr <= 'f')) + xid->data [index] = (*ptr - 'a' + 10); + else + xid->data [index] = (*ptr - '0'); + } + else + goto onerror; + } + else + goto onerror; + } + else if (g_ascii_isalnum (*ptr)) + xid->data [index] = *ptr; + else + goto onerror; + } + xid->gtrid_length = index; + + /* branch qualifier */ + if (*ptr != ',') + goto onerror; + for (ptr++; *ptr && (*ptr != ','); ptr++, index++) { + if (index >= 128) + goto onerror; + + if (*ptr == '%') { + ptr++; + if (*ptr && (((*ptr >= 'a') && (*ptr <= 'f')) || + ((*ptr >= '0') && (*ptr <= '9')))) { + if ((*ptr >= 'a') && (*ptr <= 'f')) + xid->data [index] = (*ptr - 'a' + 10) * 16; + else + xid->data [index] = (*ptr - '0') * 16; + ptr++; + if (*ptr && (((*ptr >= 'a') && (*ptr <= 'f')) || + ((*ptr >= '0') && (*ptr <= '9')))) { + if ((*ptr >= 'a') && (*ptr <= 'f')) + xid->data [index] = (*ptr - 'a' + 10); + else + xid->data [index] = (*ptr - '0'); + } + else + goto onerror; + } + else + goto onerror; + } + else if (g_ascii_isalnum (*ptr)) + xid->data [index] = *ptr; + else + goto onerror; + } + xid->bqual_length = index - xid->gtrid_length; + + /* Format ID */ + if (*ptr != ',') + goto onerror; + ptr++; + gchar *endptr; + gint64 tmp = g_ascii_strtoll (ptr, &endptr, 10); + if (*endptr || (tmp < 0) || (tmp >= G_MAXUINT32)) + goto onerror; + + xid->format = (guint32) tmp; + + return xid; + + onerror: + g_free (xid); + return NULL; +} diff --git a/.flatpak-builder/cache/objects/24/27b3e601446d1b7a9a21b835a15f07e8a36e50b2ab69ef7827b42e07ff5304.file b/.flatpak-builder/cache/objects/24/27b3e601446d1b7a9a21b835a15f07e8a36e50b2ab69ef7827b42e07ff5304.file new file mode 100644 index 0000000..7959ff1 --- /dev/null +++ b/.flatpak-builder/cache/objects/24/27b3e601446d1b7a9a21b835a15f07e8a36e50b2ab69ef7827b42e07ff5304.file @@ -0,0 +1,230 @@ +/* gda-db-index-index.c + * + * Copyright (C) 2019 Pavlo Solntsev + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "gda-db-index-field.h" + +typedef struct +{ + GdaDbColumn *mColumn; + gchar *mCollate; + GdaDbIndexSortOrder mSortOrder; +} GdaDbIndexFieldPrivate; + + +/** + * SECTION:gda-db-index-field + * @short_description: Object to represent table index + * @see_also: #GdaDbTable, #GdaDbCatalog + * @stability: Stable + * @include: libgda/libgda.h + * + * This object is a container for information needed to create an index for a table. After + * population with information, it should be passed to the #GdaDbIndex instance. See #GdaDbIndex + * section for the example. + * + */ + +G_DEFINE_TYPE_WITH_PRIVATE(GdaDbIndexField, gda_db_index_field, G_TYPE_OBJECT) + +/** + * gda_db_index_field_new: + * + * Create a new instance of #GdaDbIndexField + * + * Returns: (transfer full): A new instance of #GdaDbIndexField + * + * Stability: Stable + * Since: 6.0 + */ +GdaDbIndexField * +gda_db_index_field_new (void) +{ + return g_object_new (GDA_TYPE_DB_INDEX_FIELD, NULL); +} +static void +gda_db_index_field_dispose (GObject *object) +{ + GdaDbIndexField *self = GDA_DB_INDEX_FIELD (object); + GdaDbIndexFieldPrivate *priv = gda_db_index_field_get_instance_private (self); + + g_object_unref (priv->mColumn); + + if (priv->mCollate) + g_free (priv->mCollate); + + G_OBJECT_CLASS (gda_db_index_field_parent_class)->dispose (object); +} + +static void +gda_db_index_field_class_init (GdaDbIndexFieldClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->dispose = gda_db_index_field_dispose; +} + +static void +gda_db_index_field_init (GdaDbIndexField *self) +{ + GdaDbIndexFieldPrivate *priv = gda_db_index_field_get_instance_private (self); + + priv->mColumn = NULL; + priv->mCollate = NULL; + priv->mSortOrder = GDA_DB_INDEX_SORT_ORDER_ASC; +} + +/** + * gda_db_index_field_set_column: + * @self: an instance of #GdaDbIndexField + * @column: column to add index to + * + * Only full name will be extracted from @column. The @column instance should be freed using + * g_object_unref(). The instance @self take a copy of the @column object by increasing its + * referecne count. + * + * Stability: Stable + * Since: 6.0 + */ +void +gda_db_index_field_set_column (GdaDbIndexField *self, + GdaDbColumn *column) +{ + GdaDbIndexFieldPrivate *priv = gda_db_index_field_get_instance_private (self); + + if (priv->mColumn) + g_object_unref (priv->mColumn); + + priv->mColumn = g_object_ref (column); +} + +/** + * gda_db_index_field_get_column: + * @self: a #GdaDbIndexField instance + * + * Returns an active column that was asigned to #GdaDbIndexField instance + * + * Returns: (transfer none): A #GdaDbColumn where index should be added + * + * Stability: Stable + * Since: 6.0 + */ +GdaDbColumn * +gda_db_index_field_get_column (GdaDbIndexField *self) +{ + GdaDbIndexFieldPrivate *priv = gda_db_index_field_get_instance_private (self); + return priv->mColumn; +} + +/** + * gda_db_index_field_set_collate: + * @self: instance of #GdaDbIndexField + * @collate: collate to set + * + * Unfortunately, collate can vary from provider to provider. This method accepts collate name as a + * string but user should provide valid values. For instance, SQLite3 accepts only "BINARY", + * "NOCASE", and "RTRIM" values. PostgreSQL, on the other hand expects a name of a callable object, + * e.g. function. + * + * Stability: Stable + * Since: 6.0 + */ +void +gda_db_index_field_set_collate (GdaDbIndexField *self, + const gchar *collate) +{ + GdaDbIndexFieldPrivate *priv = gda_db_index_field_get_instance_private (self); + + if (priv->mCollate) + g_free (priv->mCollate); + + priv->mCollate = g_strdup (collate); +} + +/** + * gda_db_index_field_get_collate: + * @self: instance of #GdaDbIndexField + * + * Returns: Collate value + * + * Stability: Stable + * Since: 6.0 + */ +const gchar * +gda_db_index_field_get_collate (GdaDbIndexField *self) +{ + GdaDbIndexFieldPrivate *priv = gda_db_index_field_get_instance_private (self); + return priv->mCollate; +} + +/** + * gda_db_index_field_set_sort_order: + * @self: object to use + * @sorder: sort order to set + * + * Stability: Stable + * Since: 6.0 + */ +void +gda_db_index_field_set_sort_order (GdaDbIndexField *self, + GdaDbIndexSortOrder sorder) +{ + GdaDbIndexFieldPrivate *priv = gda_db_index_field_get_instance_private (self); + priv->mSortOrder = sorder; +} + +/** + * gda_db_index_field_get_sort_order: + * @self: object to use + * + * Returns: sort order as a #GdaDbIndexSortOrder object + * + * Stability: Stable + * Since: 6.0 + */ +GdaDbIndexSortOrder +gda_db_index_field_get_sort_order (GdaDbIndexField *self) +{ + GdaDbIndexFieldPrivate *priv = gda_db_index_field_get_instance_private (self); + return priv->mSortOrder; +} + +/** + * gda_db_index_field_get_sort_order_str: + * @self: an instance of #GdaDbIndexField + * + * Returns: SORT ORDER string or %NULL + * + * Stability: Stable + * Since: 6.0 + */ +const gchar * +gda_db_index_field_get_sort_order_str (GdaDbIndexField *self) +{ + g_return_val_if_fail (GDA_IS_DB_INDEX_FIELD (self), NULL); + + GdaDbIndexSortOrder sorder = gda_db_index_field_get_sort_order (self); + + if (sorder == GDA_DB_INDEX_SORT_ORDER_ASC) + return "ASC"; + else if (sorder == GDA_DB_INDEX_SORT_ORDER_DESC) + return "DESC"; + else + return NULL; +} diff --git a/.flatpak-builder/cache/objects/24/71bdb8a0e1c92f5b01cb119bd1c2958d9ca38d2db932792ccc165e4d830e91.file b/.flatpak-builder/cache/objects/24/71bdb8a0e1c92f5b01cb119bd1c2958d9ca38d2db932792ccc165e4d830e91.file new file mode 100644 index 0000000..5e16455 Binary files /dev/null and b/.flatpak-builder/cache/objects/24/71bdb8a0e1c92f5b01cb119bd1c2958d9ca38d2db932792ccc165e4d830e91.file differ diff --git a/.flatpak-builder/cache/objects/24/874f732695a6b75b5bced544c9b62bbe803033183ed49d685625d367c99380.file b/.flatpak-builder/cache/objects/24/874f732695a6b75b5bced544c9b62bbe803033183ed49d685625d367c99380.file new file mode 100644 index 0000000..4de13f2 --- /dev/null +++ b/.flatpak-builder/cache/objects/24/874f732695a6b75b5bced544c9b62bbe803033183ed49d685625d367c99380.file @@ -0,0 +1,136 @@ +# gtkbuilder_child.py +# +# Copyright 2022 James Westman +# +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation; either version 3 of the +# License, or (at your option) any later version. +# +# This file is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program. If not, see . +# +# SPDX-License-Identifier: LGPL-3.0-or-later + + +from functools import cached_property + +from .gobject_object import Object +from .response_id import ExtResponse +from .common import * + +ALLOWED_PARENTS: T.List[T.Tuple[str, str]] = [ + ("Gtk", "Buildable"), + ("Gio", "ListStore"), +] + + +class ChildInternal(AstNode): + grammar = ["internal-child", UseIdent("internal_child")] + + @property + def internal_child(self) -> str: + return self.tokens["internal_child"] + + +class ChildType(AstNode): + grammar = UseIdent("child_type").expected("a child type") + + @property + def child_type(self) -> str: + return self.tokens["child_type"] + + +class ChildExtension(AstNode): + grammar = ExtResponse + + @property + def child(self) -> ExtResponse: + return self.children[0] + + +class ChildAnnotation(AstNode): + grammar = ["[", AnyOf(ChildInternal, ChildExtension, ChildType), "]"] + + @property + def child(self) -> T.Union[ChildInternal, ChildExtension, ChildType]: + return self.children[0] + + +class Child(AstNode): + grammar = [ + Optional(ChildAnnotation), + Object, + ] + + @property + def annotation(self) -> T.Optional[ChildAnnotation]: + annotations = self.children[ChildAnnotation] + return annotations[0] if len(annotations) else None + + @property + def object(self) -> Object: + return self.children[Object][0] + + @validate() + def parent_can_have_child(self): + if gir_class := self.parent.gir_class: + for namespace, name in ALLOWED_PARENTS: + parent_type = self.root.gir.get_type(name, namespace) + if gir_class.assignable_to(parent_type): + break + else: + hints = [ + "only Gio.ListStore or Gtk.Buildable implementors can have children" + ] + if "child" in gir_class.properties: + hints.append( + "did you mean to assign this object to the 'child' property?" + ) + raise CompileError( + f"{gir_class.full_name} doesn't have children", + hints=hints, + ) + + @cached_property + def response_id(self) -> T.Optional[ExtResponse]: + """Get action widget's response ID. + + If child is not action widget, returns `None`. + """ + if ( + self.annotation is not None + and isinstance(self.annotation.child, ChildExtension) + and isinstance(self.annotation.child.child, ExtResponse) + ): + return self.annotation.child.child + else: + return None + + @validate() + def internal_child_unique(self): + if self.annotation is not None: + if isinstance(self.annotation.child, ChildInternal): + internal_child = self.annotation.child.internal_child + self.validate_unique_in_parent( + f"Duplicate internal child '{internal_child}'", + lambda x: ( + x.annotation + and isinstance(x.annotation.child, ChildInternal) + and x.annotation.child.internal_child == internal_child + ), + ) + + +@decompiler("child") +def decompile_child(ctx, gir, type=None, internal_child=None): + if type is not None: + ctx.print(f"[{type}]") + elif internal_child is not None: + ctx.print(f"[internal-child {internal_child}]") + return gir diff --git a/.flatpak-builder/cache/objects/24/acbb915c6ac43f3ece67dedf1ad4c4500de87a4533b0a2090cb1c535560586.dirtree b/.flatpak-builder/cache/objects/24/acbb915c6ac43f3ece67dedf1ad4c4500de87a4533b0a2090cb1c535560586.dirtree new file mode 100644 index 0000000..ab50609 Binary files /dev/null and b/.flatpak-builder/cache/objects/24/acbb915c6ac43f3ece67dedf1ad4c4500de87a4533b0a2090cb1c535560586.dirtree differ diff --git a/.flatpak-builder/cache/objects/24/b81ae2a1dfd4df38cea4c0077b6ea1abfc4077f866dd5b762dee605649a8de.file b/.flatpak-builder/cache/objects/24/b81ae2a1dfd4df38cea4c0077b6ea1abfc4077f866dd5b762dee605649a8de.file new file mode 100644 index 0000000..f5f5a67 --- /dev/null +++ b/.flatpak-builder/cache/objects/24/b81ae2a1dfd4df38cea4c0077b6ea1abfc4077f866dd5b762dee605649a8de.file @@ -0,0 +1,410 @@ +/* + * Copyright (C) 2000 Reinhard Müller + * Copyright (C) 2000 - 2004 Rodrigo Moya + * Copyright (C) 2001 - 2014 Vivien Malerba + * Copyright (C) 2002 Cleber Rodrigues + * Copyright (C) 2002 - 2003 Gonzalo Paniagua Javier + * Copyright (C) 2003 Filip Van Raemdonck + * Copyright (C) 2004 - 2005 Alan Knowles + * Copyright (C) 2004 José María Casanova Crespo + * Copyright (C) 2005 - 2009 Bas Driessen + * Copyright (C) 2006 - 2008 Murray Cumming + * Copyright (C) 2007 Leonardo Boshell + * Copyright (C) 2010 David King + * Copyright (C) 2015 Gergely Polonkai + * Copyright (C) 2018 Daniel Espinosa + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GDA_CONNECTION_H__ +#define __GDA_CONNECTION_H__ + +#include "gda-decl.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +G_BEGIN_DECLS + +#define GDA_TYPE_CONNECTION (gda_connection_get_type()) + +G_DECLARE_DERIVABLE_TYPE (GdaConnection, gda_connection, GDA,CONNECTION, GObject) + +/* error reporting */ +extern GQuark gda_connection_error_quark (void); +#define GDA_CONNECTION_ERROR gda_connection_error_quark () + +typedef enum { + GDA_CONNECTION_DSN_NOT_FOUND_ERROR, + GDA_CONNECTION_PROVIDER_NOT_FOUND_ERROR, + GDA_CONNECTION_PROVIDER_ERROR, + GDA_CONNECTION_NO_CNC_SPEC_ERROR, + GDA_CONNECTION_NO_PROVIDER_SPEC_ERROR, + GDA_CONNECTION_OPEN_ERROR, + GDA_CONNECTION_ALREADY_OPENED_ERROR, + GDA_CONNECTION_STATEMENT_TYPE_ERROR, + GDA_CONNECTION_CANT_LOCK_ERROR, + GDA_CONNECTION_TASK_NOT_FOUND_ERROR, + GDA_CONNECTION_CLOSED_ERROR, + GDA_CONNECTION_META_DATA_CONTEXT_ERROR, + GDA_CONNECTION_NO_MAIN_CONTEXT_ERROR +} GdaConnectionError; + + +#define GDA_CONNECTION_NONEXIST_DSN_ERROR GDA_CONNECTION_DSN_NOT_FOUND_ERROR + +/** + * SECTION:gda-connection + * @short_description: A connection to a database + * @title: GdaConnection + * @stability: Stable + * + * Each connection to a database is represented by a #GdaConnection object. A connection is created + * using gda_connection_new_from_dsn() if a data source has been defined, or gda_connection_new_from_string() + * otherwise. It is not recommended to create a #GdaConnection object using g_object_new() as the results are + * unpredictable (some parts won't correctly be initialized). + * + * Once the connection has been created, it can be opened using gda_connection_open() or gda_connection_open_async(). + * By default these functions will block, unless you speficy a #GMainContext from which events will be processed + * while opening the connection using gda_connection_set_main_context(). + * + * The same gda_connection_set_main_context() allows the program to still handle events while a + * potentially blocking operation (such as executing a statement) is being carried out (this is a change compared to the + * #GdaConnection object in Libgda versions before 6.x, where asynchronous execution was featured + * using a set of specific functions like gda_connection_async_statement_execute()). + * + * The #GdaConnection object implements its own locking mechanism so it is thread-safe. If a #GMainContext has been + * specified using gda_connection_set_main_context(), then the events will continue to be processed while the + * lock on the connection is being acquired. + */ + +/** + * GdaConnectionStatus: + * @GDA_CONNECTION_STATUS_CLOSED: the connection is closed (default status upon creation) + * @GDA_CONNECTION_STATUS_OPENING: the connection is currently being opened + * @GDA_CONNECTION_STATUS_IDLE: the connection is opened but not currently used + * @GDA_CONNECTION_STATUS_BUSY: the connection is opened and currently being used + * + * Indicates the current status of a connection. The possible status and the transitions between those status + * are indicated in the diagram below: + * + * + * + * + * + * GdaConnection's status and transitions between different status + * + * + */ +typedef enum { + GDA_CONNECTION_STATUS_CLOSED, + GDA_CONNECTION_STATUS_OPENING, + GDA_CONNECTION_STATUS_IDLE, + GDA_CONNECTION_STATUS_BUSY +} GdaConnectionStatus; + +struct _GdaConnectionClass { + GObjectClass object_class; + + /* signals */ + void (*status_changed) (GdaConnection *obj, GdaConnectionStatus status); + void (*error) (GdaConnection *cnc, GdaConnectionEvent *error); + void (*opened) (GdaConnection *obj); + void (*closed) (GdaConnection *obj); + void (*dsn_changed) (GdaConnection *obj); + void (*transaction_status_changed)(GdaConnection *obj); + + + /*< private >*/ + /* Padding for future expansion */ + void (*_gda_reserved1) (void); + void (*_gda_reserved2) (void); + void (*_gda_reserved3) (void); + void (*_gda_reserved4) (void); +}; + +/** + * GdaConnectionOptions: + * @GDA_CONNECTION_OPTIONS_NONE: no specific aspect + * @GDA_CONNECTION_OPTIONS_READ_ONLY: this flag specifies that the connection to open should be in a read-only mode + * (this policy is not correctly enforced at the moment) + * @GDA_CONNECTION_OPTIONS_SQL_IDENTIFIERS_CASE_SENSITIVE: this flag specifies that SQL identifiers submitted as input + to Libgda have to keep their case sensitivity. + * @GDA_CONNECTION_OPTIONS_AUTO_META_DATA: this flags specifies that if a #GdaMetaStore has been associated + * to the connection, then it is kept up to date with the evolutions in the + * database's structure. Be aware however that there are some drawbacks + * explained below. + * + * Specifies some aspects of a connection when opening it. + * + * Additional information about the GDA_CONNECTION_OPTIONS_SQL_IDENTIFIERS_CASE_SENSITIVE flag: + * + * For example without this flag, if the table + * name specified in a #GdaServerOperation to create a table is + * MyTable, then usually the database will create a table named + * mytable, whereas with this flag, the table will be created + * as MyTable (note that in the end the database may still decide + * to name the table mytable or differently if it can't do + * otherwise). + * Libgda will not apply this rule when parsing SQL code, the SQL code being parsed + * has to be conform to the database it will be used with + * + * + * Note about the @GDA_CONNECTION_OPTIONS_AUTO_META_DATA flag: + * + * Every time a DDL statement is successfully executed, the associated meta data, if + defined, will be updated, which has a impact on performances + * If a transaction is started and some DDL statements are executed and the transaction + * is not rolled back or committed, then the meta data may end up being wrong + * + */ +typedef enum { + GDA_CONNECTION_OPTIONS_NONE = 0, + GDA_CONNECTION_OPTIONS_READ_ONLY = 1 << 0, + GDA_CONNECTION_OPTIONS_SQL_IDENTIFIERS_CASE_SENSITIVE = 1 << 1, + GDA_CONNECTION_OPTIONS_AUTO_META_DATA = 1 << 4 +} GdaConnectionOptions; + + +/** + * GdaConnectionFeature: + * @GDA_CONNECTION_FEATURE_AGGREGATES: test for aggregates support + * @GDA_CONNECTION_FEATURE_BLOBS: test for BLOBS (binary large objects) support + * @GDA_CONNECTION_FEATURE_INDEXES: test for indexes support + * @GDA_CONNECTION_FEATURE_INHERITANCE: test for tables inheritance support + * @GDA_CONNECTION_FEATURE_NAMESPACES: test for namespaces support + * @GDA_CONNECTION_FEATURE_PROCEDURES: test for functions support + * @GDA_CONNECTION_FEATURE_SEQUENCES: test for sequences support + * @GDA_CONNECTION_FEATURE_SQL: test for SQL language (even specific to the database) support + * @GDA_CONNECTION_FEATURE_TRANSACTIONS: test for transactions support + * @GDA_CONNECTION_FEATURE_SAVEPOINTS: test for savepoints within transactions support + * @GDA_CONNECTION_FEATURE_SAVEPOINTS_REMOVE: test if savepoints can be removed + * @GDA_CONNECTION_FEATURE_TRIGGERS: test for triggers support + * @GDA_CONNECTION_FEATURE_UPDATABLE_CURSOR: test for updatable cursors support + * @GDA_CONNECTION_FEATURE_USERS: test for users support + * @GDA_CONNECTION_FEATURE_VIEWS: test for views support + * @GDA_CONNECTION_FEATURE_TRANSACTION_ISOLATION_READ_COMMITTED: test for READ COMMITTED transaction isolation level + * @GDA_CONNECTION_FEATURE_TRANSACTION_ISOLATION_READ_UNCOMMITTED: test for READ UNCOMMITTED transaction isolation level + * @GDA_CONNECTION_FEATURE_TRANSACTION_ISOLATION_REPEATABLE_READ: test for REPEATABLE READ transaction isolation level + * @GDA_CONNECTION_FEATURE_TRANSACTION_ISOLATION_SERIALIZABLE: test for SERIALIZABLE transaction isolation level + * @GDA_CONNECTION_FEATURE_XA_TRANSACTIONS: test for distributed transactions support + * @GDA_CONNECTION_FEATURE_LAST: not used + * + * Used in gda_connection_supports_feature() and gda_server_provider_supports_feature() to test if a connection + * or a database provider supports some specific feature. + */ +typedef enum { + GDA_CONNECTION_FEATURE_AGGREGATES, + GDA_CONNECTION_FEATURE_BLOBS, + GDA_CONNECTION_FEATURE_INDEXES, + GDA_CONNECTION_FEATURE_INHERITANCE, + GDA_CONNECTION_FEATURE_NAMESPACES, + GDA_CONNECTION_FEATURE_PROCEDURES, + GDA_CONNECTION_FEATURE_SEQUENCES, + GDA_CONNECTION_FEATURE_SQL, + GDA_CONNECTION_FEATURE_TRANSACTIONS, + GDA_CONNECTION_FEATURE_SAVEPOINTS, + GDA_CONNECTION_FEATURE_SAVEPOINTS_REMOVE, + GDA_CONNECTION_FEATURE_TRIGGERS, + GDA_CONNECTION_FEATURE_UPDATABLE_CURSOR, + GDA_CONNECTION_FEATURE_USERS, + GDA_CONNECTION_FEATURE_VIEWS, + GDA_CONNECTION_FEATURE_TRANSACTION_ISOLATION_READ_COMMITTED, + GDA_CONNECTION_FEATURE_TRANSACTION_ISOLATION_READ_UNCOMMITTED, + GDA_CONNECTION_FEATURE_TRANSACTION_ISOLATION_REPEATABLE_READ, + GDA_CONNECTION_FEATURE_TRANSACTION_ISOLATION_SERIALIZABLE, + GDA_CONNECTION_FEATURE_XA_TRANSACTIONS, + + GDA_CONNECTION_FEATURE_LAST +} GdaConnectionFeature; + +/** + * GdaConnectionMetaType: + * @GDA_CONNECTION_META_NAMESPACES: lists the namespaces (or schemas for PostgreSQL) + * @GDA_CONNECTION_META_TYPES: lists the database types + * @GDA_CONNECTION_META_TABLES: lists the tables + * @GDA_CONNECTION_META_VIEWS: lists the views + * @GDA_CONNECTION_META_FIELDS: lists the table's or view's fields + * @GDA_CONNECTION_META_INDEXES: lists the table's indexes + * + * Used with gda_connection_get_meta_store_data() to describe what meta data to extract from + * a connection's associated #GdaMetaStore. + */ +typedef enum { + GDA_CONNECTION_META_NAMESPACES, + GDA_CONNECTION_META_TYPES, + GDA_CONNECTION_META_TABLES, + GDA_CONNECTION_META_VIEWS, + GDA_CONNECTION_META_FIELDS, + GDA_CONNECTION_META_INDEXES +} GdaConnectionMetaType; + + +GdaConnection *gda_connection_open_from_dsn_name (const gchar *dsn_name, + const gchar *auth_string, + GdaConnectionOptions options, + GError **error); + +GdaConnection *gda_connection_open_from_dsn (GdaDsnInfo *dsn, + const gchar *auth_string, + GdaConnectionOptions options, + GError **error); +GdaConnection *gda_connection_open_from_string (const gchar *provider_name, + const gchar *cnc_string, const gchar *auth_string, + GdaConnectionOptions options, GError **error); +GdaConnection *gda_connection_new_from_dsn_name (const gchar *dsn_name, + const gchar *auth_string, + GdaConnectionOptions options, + GError **error); + +GdaConnection *gda_connection_new_from_dsn (GdaDsnInfo *dsn, + const gchar *auth_string, + GdaConnectionOptions options, + GError **error); + +GdaConnection *gda_connection_new_from_string (const gchar *provider_name, + const gchar *cnc_string, const gchar *auth_string, + GdaConnectionOptions options, GError **error); + +gboolean gda_connection_open (GdaConnection *cnc, GError **error); +typedef void (*GdaConnectionOpenFunc) (GdaConnection *cnc, guint job_id, gboolean result, GError *error, gpointer data); +guint gda_connection_open_async (GdaConnection *cnc, GdaConnectionOpenFunc callback, gpointer data, GError **error); + +gboolean gda_connection_close (GdaConnection *cnc, GError **error); +gboolean gda_connection_is_opened (GdaConnection *cnc); +GdaConnectionStatus gda_connection_get_status (GdaConnection *cnc); + +GdaConnectionOptions gda_connection_get_options (GdaConnection *cnc); + +void gda_connection_set_main_context (GdaConnection *cnc, GThread *thread, GMainContext *context); +GMainContext *gda_connection_get_main_context (GdaConnection *cnc, GThread *thread); + +GdaServerProvider *gda_connection_get_provider (GdaConnection *cnc); +const gchar *gda_connection_get_provider_name (GdaConnection *cnc); + +GdaServerOperation *gda_connection_create_operation (GdaConnection *cnc, GdaServerOperationType type, + GdaSet *options, GError **error); + +gboolean gda_connection_perform_operation (GdaConnection *cnc, GdaServerOperation *op, GError **error); + +GdaServerOperation *gda_connection_prepare_operation_create_table_v (GdaConnection *cnc, const gchar *table_name, GError **error, ...); +GdaServerOperation *gda_connection_prepare_operation_create_table (GdaConnection *cnc, const gchar *table_name, GList *arguments, GError **error); +GdaServerOperation *gda_connection_prepare_operation_drop_table (GdaConnection *cnc, const gchar *table_name, GError **error); +gchar *gda_connection_operation_get_sql_identifier_at (GdaConnection *cnc, + GdaServerOperation *op, const gchar *path_format, GError **error, ...); +gchar *gda_connection_operation_get_sql_identifier_at_path (GdaConnection *cnc, GdaServerOperation *op, + const gchar *path, GError **error); +const gchar *gda_connection_get_dsn (GdaConnection *cnc); +const gchar *gda_connection_get_cnc_string (GdaConnection *cnc); +const gchar *gda_connection_get_authentication (GdaConnection *cnc); +gboolean gda_connection_get_date_format (GdaConnection *cnc, GDateDMY *out_first, + GDateDMY *out_second, GDateDMY *out_third, gchar *out_sep, + GError **error); + +GdaStatement *gda_connection_parse_sql_string (GdaConnection *cnc, const gchar *sql, GdaSet **params, + GError **error); + +/* + * Quick commands execution + */ +GdaDataModel* gda_connection_execute_select_command (GdaConnection *cnc, const gchar *sql, GError **error); +gint gda_connection_execute_non_select_command (GdaConnection *cnc, const gchar *sql, GError **error); + +/* + * Data in tables manipulation + */ +gboolean gda_connection_insert_row_into_table (GdaConnection *cnc, const gchar *table, GError **error, ...); +gboolean gda_connection_insert_row_into_table_v (GdaConnection *cnc, const gchar *table, + GSList *col_names, GSList *values, + GError **error); + +gboolean gda_connection_update_row_in_table (GdaConnection *cnc, const gchar *table, + const gchar *condition_column_name, + GValue *condition_value, GError **error, ...); +gboolean gda_connection_update_row_in_table_v (GdaConnection *cnc, const gchar *table, + const gchar *condition_column_name, + GValue *condition_value, + GSList *col_names, GSList *values, + GError **error); +gboolean gda_connection_delete_row_from_table (GdaConnection *cnc, const gchar *table, + const gchar *condition_column_name, + GValue *condition_value, GError **error); + +const GList *gda_connection_get_events (GdaConnection *cnc); + +GdaSqlParser *gda_connection_create_parser (GdaConnection *cnc); +GSList *gda_connection_batch_execute (GdaConnection *cnc, + GdaBatch *batch, GdaSet *params, + GdaStatementModelUsage model_usage, GError **error); + +gchar *gda_connection_quote_sql_identifier (GdaConnection *cnc, const gchar *id); +gchar *gda_connection_statement_to_sql (GdaConnection *cnc, + GdaStatement *stmt, GdaSet *params, GdaStatementSqlFlag flags, + GSList **params_used, GError **error); +/* synchronous execution */ +gboolean gda_connection_statement_prepare (GdaConnection *cnc, + GdaStatement *stmt, GError **error); +GObject *gda_connection_statement_execute (GdaConnection *cnc, GdaStatement *stmt, GdaSet *params, + GdaStatementModelUsage model_usage, GdaSet **last_insert_row, + GError **error); +GdaDataModel *gda_connection_statement_execute_select (GdaConnection *cnc, GdaStatement *stmt, + GdaSet *params, GError **error); +GdaDataModel *gda_connection_statement_execute_select_fullv (GdaConnection *cnc, GdaStatement *stmt, + GdaSet *params, GdaStatementModelUsage model_usage, + GError **error, ...); +GdaDataModel *gda_connection_statement_execute_select_full (GdaConnection *cnc, GdaStatement *stmt, + GdaSet *params, GdaStatementModelUsage model_usage, + GType *col_types, GError **error); +gint gda_connection_statement_execute_non_select (GdaConnection *cnc, GdaStatement *stmt, + GdaSet *params, GdaSet **last_insert_row, GError **error); + +/* repetitive statement */ +GSList *gda_connection_repetitive_statement_execute (GdaConnection *cnc, GdaRepetitiveStatement *rstmt, + GdaStatementModelUsage model_usage, GType *col_types, + gboolean stop_on_error, GError **error); + +/* transactions */ +gboolean gda_connection_begin_transaction (GdaConnection *cnc, const gchar *name, + GdaTransactionIsolation level, GError **error); +gboolean gda_connection_commit_transaction (GdaConnection *cnc, const gchar *name, GError **error); +gboolean gda_connection_rollback_transaction (GdaConnection *cnc, const gchar *name, GError **error); + +gboolean gda_connection_add_savepoint (GdaConnection *cnc, const gchar *name, GError **error); +gboolean gda_connection_rollback_savepoint (GdaConnection *cnc, const gchar *name, GError **error); +gboolean gda_connection_delete_savepoint (GdaConnection *cnc, const gchar *name, GError **error); + +GdaTransactionStatus *gda_connection_get_transaction_status (GdaConnection *cnc); + +gchar *gda_connection_value_to_sql_string (GdaConnection *cnc, GValue *from); + +gboolean gda_connection_supports_feature (GdaConnection *cnc, GdaConnectionFeature feature); +GdaMetaStore *gda_connection_get_meta_store (GdaConnection *cnc); +gboolean gda_connection_update_meta_store (GdaConnection *cnc, GdaMetaContext *context, GError **error); +GdaDataModel *gda_connection_get_meta_store_data (GdaConnection *cnc, GdaConnectionMetaType meta_type, + GError **error, gint nb_filters, ...); +GdaDataModel *gda_connection_get_meta_store_data_v(GdaConnection *cnc, GdaConnectionMetaType meta_type, + GList* filters, GError **error); +GdaDbCatalog *gda_connection_create_db_catalog (GdaConnection *cnc); +G_END_DECLS + +#endif diff --git a/.flatpak-builder/cache/objects/25/6f0b63269cbacd47ac0d6e690c920180fe9f40476f8d07cc6e0e4e5d6c15fe.dirtree b/.flatpak-builder/cache/objects/25/6f0b63269cbacd47ac0d6e690c920180fe9f40476f8d07cc6e0e4e5d6c15fe.dirtree new file mode 100644 index 0000000..6a7c456 Binary files /dev/null and b/.flatpak-builder/cache/objects/25/6f0b63269cbacd47ac0d6e690c920180fe9f40476f8d07cc6e0e4e5d6c15fe.dirtree differ diff --git a/.flatpak-builder/cache/objects/25/c21356174c19a302792656d5e1c1554856e03ca5eef6d8d5a4b2792fa4e3f4.file b/.flatpak-builder/cache/objects/25/c21356174c19a302792656d5e1c1554856e03ca5eef6d8d5a4b2792fa4e3f4.file new file mode 100644 index 0000000..a594b5f Binary files /dev/null and b/.flatpak-builder/cache/objects/25/c21356174c19a302792656d5e1c1554856e03ca5eef6d8d5a4b2792fa4e3f4.file differ diff --git a/.flatpak-builder/cache/objects/25/db02ada85dfe8b8eec62b458bae992fa0ea32ae11d810bee3c2724200a2161.file b/.flatpak-builder/cache/objects/25/db02ada85dfe8b8eec62b458bae992fa0ea32ae11d810bee3c2724200a2161.file new file mode 100644 index 0000000..285df10 --- /dev/null +++ b/.flatpak-builder/cache/objects/25/db02ada85dfe8b8eec62b458bae992fa0ea32ae11d810bee3c2724200a2161.file @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2008 - 2012 Vivien Malerba + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GDA_DATA_MODEL_SELECT_H__ +#define __GDA_DATA_MODEL_SELECT_H__ + +#include +#include + +G_BEGIN_DECLS + +#define GDA_TYPE_DATA_MODEL_SELECT (gda_data_model_select_get_type()) + +G_DECLARE_DERIVABLE_TYPE(GdaDataModelSelect, gda_data_model_select, GDA, DATA_MODEL_SELECT, GObject) + +struct _GdaDataModelSelectClass { + GObjectClass parent_class; + /* signals */ + void (* updated) (GdaDataModelSelect *model); +}; + +GdaDataModelSelect *gda_data_model_select_new (GdaConnection *cnc, GdaStatement *stm, GdaSet *params); +GdaDataModelSelect *gda_data_model_select_new_from_string (GdaConnection *cnc, const gchar *sql); +gboolean gda_data_model_select_is_valid (GdaDataModelSelect *model); +GdaSet *gda_data_model_select_get_parameters (GdaDataModelSelect *model); +void gda_data_model_select_set_parameters (GdaDataModelSelect *model, GdaSet *params); + +G_END_DECLS + +#endif diff --git a/.flatpak-builder/cache/objects/25/e32a0a8dca724b004cd0e9f3f6b0475dedb8c63802ff60ed1a4bd6d1d97fb4.file b/.flatpak-builder/cache/objects/25/e32a0a8dca724b004cd0e9f3f6b0475dedb8c63802ff60ed1a4bd6d1d97fb4.file new file mode 100644 index 0000000..b9b2732 --- /dev/null +++ b/.flatpak-builder/cache/objects/25/e32a0a8dca724b004cd0e9f3f6b0475dedb8c63802ff60ed1a4bd6d1d97fb4.file @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2008 - 2014 Vivien Malerba + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + + +#ifndef __GDA_SQL_PARSER_PRIV_H_ +#define __GDA_SQL_PARSER_PRIV_H_ + +#include +#include "gda-sql-parser.h" +#include "gda-statement-struct-pspec.h" + +G_BEGIN_DECLS + +typedef struct { + gint token_type; + gchar *next_token_start; + gchar *last_token_start; + gchar delimiter; + gboolean in_param_spec; + gint block_level; + gboolean ignore_semi; /* ignore any SEMI untill the next END statement where block_level==0 */ + + /* Padding for future expansion */ + gpointer _gda_reserved1; + gpointer _gda_reserved2; +} TokenizerContext; + +typedef struct { + GRecMutex mutex; + gchar *sql; + GSList *parsed_statements; + + /* parser */ + void *lemon_delimiter; + void *lemon_parser; + GArray *passed_tokens; /* array of token types (gint), spaces omitted, which have been given to the parser */ + + /* tokenizer contexts */ + TokenizerContext *context; + GSList *pushed_contexts; + + /* error reporting */ + GdaSqlParserError error_type; + gchar *error_msg; + gint error_line; /* (starts at 1) */ + gint error_col; /* (starts at 1) */ + gint error_pos; /* absolute count from start of message (starts at 1) */ + + /* modes */ + GdaSqlParserMode mode; + GdaSqlParserFlavour flavour; + + /* Padding for future expansion */ + gpointer _gda_reserved1; + gpointer _gda_reserved2; +} GdaSqlParserPrivate; + +G_END_DECLS + +#endif diff --git a/.flatpak-builder/cache/objects/26/45cf015e1ed26960ce55fd2850d8cdfba6a09636b9815750961302afdb5022.file b/.flatpak-builder/cache/objects/26/45cf015e1ed26960ce55fd2850d8cdfba6a09636b9815750961302afdb5022.file new file mode 100755 index 0000000..070e758 --- /dev/null +++ b/.flatpak-builder/cache/objects/26/45cf015e1ed26960ce55fd2850d8cdfba6a09636b9815750961302afdb5022.file @@ -0,0 +1,41 @@ +# libcanberra.la - a libtool library file +# Generated by libtool (GNU libtool) 2.4.2 +# +# Please DO NOT delete this file! +# It is necessary for linking the library. + +# The name that we can dlopen(3). +dlname='libcanberra.so.0' + +# Names of this library. +library_names='libcanberra.so.0.2.5 libcanberra.so.0 libcanberra.so' + +# The name of the static archive. +old_library='' + +# Linker flags that can not go in dependency_libs. +inherited_linker_flags='' + +# Libraries that this one depends upon. +dependency_libs=' -L/app/lib -lvorbisfile -lltdl -lm' + +# Names of additional weak libraries provided by this library +weak_library_names='' + +# Version information for libcanberra. +current=2 +age=2 +revision=5 + +# Is this an already installed library? +installed=yes + +# Should we warn about portability when linking against -modules? +shouldnotlink=no + +# Files to dlopen/dlpreopen +dlopen='' +dlpreopen='' + +# Directory that this library needs to be installed in: +libdir='/app/lib' diff --git a/.flatpak-builder/cache/objects/26/5986798752ecaf4bb5fe6bad030f8ad1d7c8c369b748a76c79e83c8b6f8d41.file b/.flatpak-builder/cache/objects/26/5986798752ecaf4bb5fe6bad030f8ad1d7c8c369b748a76c79e83c8b6f8d41.file new file mode 100644 index 0000000..b5dfb4e --- /dev/null +++ b/.flatpak-builder/cache/objects/26/5986798752ecaf4bb5fe6bad030f8ad1d7c8c369b748a76c79e83c8b6f8d41.file @@ -0,0 +1,2174 @@ +/* + * Copyright (C) 2011 Murray Cumming + * Copyright (C) 2011 - 2014 Vivien Malerba + * Copyright (C) 2019 Daniel Espinosa + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#undef GDA_DISABLE_DEPRECATED +#include "gda-data-pivot.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef struct { + GValue *value; + gint column_fields_index; + gint data_pos; /* index in priv->data_fields, or -1 if no index */ +} ColumnData; +static guint column_data_hash (gconstpointer key); +static gboolean column_data_equal (gconstpointer a, gconstpointer b); +static void column_data_free (ColumnData *cdata); + + +typedef struct { + gint row; + gint col; + GType gtype; + GArray *values; /* array of #GValue, none will be GDA_TYPE_NULL, and there is at least always 1 GValue */ + GdaDataPivotAggregate aggregate; + + gint nvalues; + GValue *data_value; + GError *error; +} CellData; +static guint cell_data_hash (gconstpointer key); +static gboolean cell_data_equal (gconstpointer a, gconstpointer b); +static void cell_data_free (CellData *cdata); +static void cell_data_compute_aggregate (CellData *cdata); + +static GValue *aggregate_get_empty_value (GdaDataPivotAggregate aggregate); +static gboolean aggregate_handle_new_value (CellData *cdata, const GValue *new_value); + + +#define TABLE_NAME "data" + +static void gda_data_pivot_class_init (GdaDataPivotClass *klass); +static void gda_data_pivot_init (GdaDataPivot *model); +static void gda_data_pivot_dispose (GObject *object); + +static void gda_data_pivot_set_property (GObject *object, + guint param_id, + const GValue *value, + GParamSpec *pspec); +static void gda_data_pivot_get_property (GObject *object, + guint param_id, + GValue *value, + GParamSpec *pspec); + +static guint _gda_value_hash (gconstpointer key); +static guint _gda_row_hash (gconstpointer key); +static gboolean _gda_row_equal (gconstpointer a, gconstpointer b); +static gboolean create_vcnc (GdaDataPivot *pivot, GError **error); +static gboolean bind_source_model (GdaDataPivot *pivot, GError **error); +static void clean_previous_population (GdaDataPivot *pivot); + +/* GdaDataModel interface */ +static void gda_data_pivot_data_model_init (GdaDataModelInterface *iface); +static gint gda_data_pivot_get_n_rows (GdaDataModel *model); +static gint gda_data_pivot_get_n_columns (GdaDataModel *model); +static GdaColumn *gda_data_pivot_describe_column (GdaDataModel *model, gint col); +static GdaDataModelAccessFlags gda_data_pivot_get_access_flags(GdaDataModel *model); +static const GValue *gda_data_pivot_get_value_at (GdaDataModel *model, gint col, gint row, GError **error); + +typedef struct { + GdaDataModel *model; /* data to analyse */ + + GdaConnection *vcnc; /* to use data in @model for row and column fields */ + + GArray *row_fields; /* array of (gchar *) field specifications */ + GArray *column_fields; /* array of (gchar *) field specifications */ + GArray *data_fields; /* array of (gchar *) field specifications */ + GArray *data_aggregates; /* array of GdaDataPivotAggregate, corresponding to @data_fields */ + + /* computed data */ + GArray *columns; /* Array of GdaColumn objects, for ALL columns! */ + GdaDataModel *results; +} GdaDataPivotPrivate; + +G_DEFINE_TYPE_WITH_CODE (GdaDataPivot, gda_data_pivot,G_TYPE_OBJECT, + G_ADD_PRIVATE (GdaDataPivot) + G_IMPLEMENT_INTERFACE(GDA_TYPE_DATA_MODEL,gda_data_pivot_data_model_init)) +/* properties */ +enum +{ + PROP_0, + PROP_MODEL, +}; + +static void +gda_data_pivot_class_init (GdaDataPivotClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + /* properties */ + object_class->set_property = gda_data_pivot_set_property; + object_class->get_property = gda_data_pivot_get_property; + g_object_class_install_property (object_class, PROP_MODEL, + g_param_spec_object ("model", NULL, "Data model from which data is analysed", + GDA_TYPE_DATA_MODEL, + G_PARAM_READABLE | G_PARAM_WRITABLE)); + + /* virtual functions */ + object_class->dispose = gda_data_pivot_dispose; +} + +static void +gda_data_pivot_data_model_init (GdaDataModelInterface *iface) +{ + iface->get_n_rows = gda_data_pivot_get_n_rows; + iface->get_n_columns = gda_data_pivot_get_n_columns; + iface->describe_column = gda_data_pivot_describe_column; + iface->get_access_flags = gda_data_pivot_get_access_flags; + iface->get_value_at = gda_data_pivot_get_value_at; + iface->get_attributes_at = NULL; + + iface->create_iter = NULL; + + iface->set_value_at = NULL; + iface->set_values = NULL; + iface->append_values = NULL; + iface->append_row = NULL; + iface->remove_row = NULL; + iface->find_row = NULL; + + iface->freeze = NULL; + iface->thaw = NULL; + iface->get_notify = NULL; + iface->send_hint = NULL; +} + +static void +gda_data_pivot_init (GdaDataPivot *model) +{ + GdaDataPivotPrivate *priv = gda_data_pivot_get_instance_private (model); + priv->model = NULL; +} + +static void +clean_previous_population (GdaDataPivot *pivot) +{ + GdaDataPivotPrivate *priv = gda_data_pivot_get_instance_private (pivot); + if (priv->results) { + g_object_unref ((GObject*) priv->results); + priv->results = NULL; + } + + if (priv->columns) { + guint i; + for (i = 0; i < priv->columns->len; i++) { + GObject *obj; + obj = g_array_index (priv->columns, GObject*, i); + g_object_unref (obj); + } + g_array_free (priv->columns, TRUE); + priv->columns = NULL; + } +} + +static void +gda_data_pivot_dispose (GObject *object) +{ + GdaDataPivot *model = (GdaDataPivot *) object; + GdaDataPivotPrivate *priv = gda_data_pivot_get_instance_private (model); + + g_return_if_fail (GDA_IS_DATA_PIVOT (model)); + + /* free memory */ + clean_previous_population (model); + + if (priv->row_fields) { + guint i; + for (i = 0; i < priv->row_fields->len; i++) { + gchar *tmp; + tmp = g_array_index (priv->row_fields, gchar*, i); + g_free (tmp); + } + g_array_free (priv->row_fields, TRUE); + priv->row_fields = NULL; + } + + if (priv->column_fields) { + guint i; + for (i = 0; i < priv->column_fields->len; i++) { + gchar *tmp; + tmp = g_array_index (priv->column_fields, gchar*, i); + g_free (tmp); + } + g_array_free (priv->column_fields, TRUE); + priv->column_fields = NULL; + } + + if (priv->data_fields) { + guint i; + for (i = 0; i < priv->data_fields->len; i++) { + gchar *tmp; + tmp = g_array_index (priv->data_fields, gchar*, i); + g_free (tmp); + } + g_array_free (priv->data_fields, TRUE); + priv->data_fields = NULL; + } + + if (priv->data_aggregates) { + g_array_free (priv->data_aggregates, TRUE); + priv->data_aggregates = NULL; + } + + if (priv->vcnc) { + g_object_unref (priv->vcnc); + priv->vcnc = NULL; + } + + if (priv->model) { + g_object_unref (priv->model); + priv->model = NULL; + } + + /* chain to parent class */ + G_OBJECT_CLASS (gda_data_pivot_parent_class)->dispose (object); +} + +/* module error */ +GQuark gda_data_pivot_error_quark (void) +{ + static GQuark quark; + if (!quark) + quark = g_quark_from_static_string ("gda_data_pivot_error"); + return quark; +} + +static void +gda_data_pivot_set_property (GObject *object, + guint param_id, + const GValue *value, + GParamSpec *pspec) +{ + GdaDataPivot *model; + + model = GDA_DATA_PIVOT (object); + GdaDataPivotPrivate *priv = gda_data_pivot_get_instance_private (model); + switch (param_id) { + case PROP_MODEL: { + GdaDataModel *mod = g_value_get_object (value); + + clean_previous_population (model); + + if (mod) { + g_return_if_fail (GDA_IS_DATA_MODEL (mod)); + + if (priv->model) { + if (priv->vcnc) + gda_vconnection_data_model_remove (GDA_VCONNECTION_DATA_MODEL (priv->vcnc), + TABLE_NAME, NULL); + g_object_unref (priv->model); + } + + priv->model = mod; + g_object_ref (mod); + } + break; + } + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + break; + } +} + +static void +gda_data_pivot_get_property (GObject *object, + guint param_id, + GValue *value, + GParamSpec *pspec) +{ + GdaDataPivot *model; + + model = GDA_DATA_PIVOT (object); + GdaDataPivotPrivate *priv = gda_data_pivot_get_instance_private (model); + switch (param_id) { + case PROP_MODEL: + g_value_set_object (value, G_OBJECT (priv->model)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + break; + } +} + +/** + * gda_data_pivot_new: + * @model: (nullable): a #GdaDataModel to analyse data from, or %NULL + * + * Creates a new #GdaDataModel which will contain analysed data from @model. + * + * Returns: (transfer full): a pointer to the newly created #GdaDataModel. + */ +GdaDataModel * +gda_data_pivot_new (GdaDataModel *model) +{ + GdaDataPivot *retmodel; + + g_return_val_if_fail (!model || GDA_IS_DATA_MODEL (model), NULL); + + retmodel = g_object_new (GDA_TYPE_DATA_PIVOT, + "model", model, NULL); + + return GDA_DATA_MODEL (retmodel); +} + +/* + * GdaDataModel interface implementation + */ +static gint +gda_data_pivot_get_n_rows (GdaDataModel *model) +{ + GdaDataPivot *pivot; + g_return_val_if_fail (GDA_IS_DATA_PIVOT (model), -1); + pivot = GDA_DATA_PIVOT (model); + GdaDataPivotPrivate *priv = gda_data_pivot_get_instance_private (pivot); + g_return_val_if_fail (priv, -1); + + if (priv->results) + return gda_data_model_get_n_rows (priv->results); + return -1; +} + +static gint +gda_data_pivot_get_n_columns (GdaDataModel *model) +{ + GdaDataPivot *pivot; + g_return_val_if_fail (GDA_IS_DATA_PIVOT (model), 0); + pivot = GDA_DATA_PIVOT (model); + GdaDataPivotPrivate *priv = gda_data_pivot_get_instance_private (pivot); + g_return_val_if_fail (priv, 0); + + if (priv->columns) + return (gint) priv->columns->len; + return 0; +} + +static GdaColumn * +gda_data_pivot_describe_column (GdaDataModel *model, gint col) +{ + GdaDataPivot *pivot; + GdaColumn *column = NULL; + g_return_val_if_fail (GDA_IS_DATA_PIVOT (model), NULL); + pivot = GDA_DATA_PIVOT (model); + GdaDataPivotPrivate *priv = gda_data_pivot_get_instance_private (pivot); + g_return_val_if_fail (priv, NULL); + + if (priv->columns && (col < (gint) priv->columns->len)) + column = g_array_index (priv->columns, GdaColumn*, col); + else { + if (priv->columns->len > 0) + g_warning ("Column %d out of range (0-%d)", col, + (gint) priv->columns->len); + else + g_warning ("No column defined"); + } + + return column; +} + +static GdaDataModelAccessFlags +gda_data_pivot_get_access_flags (GdaDataModel *model) +{ + GdaDataPivot *pivot; + + g_return_val_if_fail (GDA_IS_DATA_PIVOT (model), 0); + pivot = GDA_DATA_PIVOT (model); + GdaDataPivotPrivate *priv = gda_data_pivot_get_instance_private (pivot); + g_return_val_if_fail (priv, 0); + + return GDA_DATA_MODEL_ACCESS_RANDOM; +} + +static const GValue * +gda_data_pivot_get_value_at (GdaDataModel *model, gint col, gint row, GError **error) +{ + GdaDataPivot *pivot; + + g_return_val_if_fail (GDA_IS_DATA_PIVOT (model), NULL); + pivot = GDA_DATA_PIVOT (model); + GdaDataPivotPrivate *priv = gda_data_pivot_get_instance_private (pivot); + g_return_val_if_fail (priv, NULL); + g_return_val_if_fail (priv->model, NULL); + g_return_val_if_fail (row >= 0, NULL); + g_return_val_if_fail (col >= 0, NULL); + + if (! priv->results) { + g_set_error (error, GDA_DATA_PIVOT_ERROR, GDA_DATA_PIVOT_USAGE_ERROR, + "%s", _("Pivot model not populated")); + return NULL; + } + return gda_data_model_get_value_at (priv->results, col, row, error); +} + +static GValue * +aggregate_get_empty_value (GdaDataPivotAggregate aggregate) +{ + GValue *value; + switch (aggregate) { + case GDA_DATA_PIVOT_MIN: + case GDA_DATA_PIVOT_MAX: + case GDA_DATA_PIVOT_AVG: + case GDA_DATA_PIVOT_SUM: + return gda_value_new_null (); + case GDA_DATA_PIVOT_COUNT: + value = gda_value_new (G_TYPE_UINT); + g_value_set_uint (value, 0); + return value; + break; + default: + return gda_value_new_null (); + } +} + +static gboolean +aggregate_handle_gint (CellData *cdata, gint val) +{ + if (cdata->data_value) { + gint eval = 0; + if (G_VALUE_TYPE (cdata->data_value) == G_TYPE_INT) + eval = g_value_get_int (cdata->data_value); + switch (cdata->aggregate) { + case GDA_DATA_PIVOT_MIN: + if (eval > val) + g_value_set_int (cdata->data_value, val); + break; + case GDA_DATA_PIVOT_MAX: + if (eval < val) + g_value_set_int (cdata->data_value, val); + break; + case GDA_DATA_PIVOT_SUM: { + gint64 tmp; + tmp = eval + val; + if ((tmp > G_MAXINT) || (tmp < G_MININT)) + g_set_error (&(cdata->error), + GDA_DATA_PIVOT_ERROR, GDA_DATA_PIVOT_OVERFLOW_ERROR, + "%s", _("Integer overflow")); + else + g_value_set_int (cdata->data_value, (gint) tmp); + break; + } + case GDA_DATA_PIVOT_AVG: { + gint64 tmp; + tmp = g_value_get_int64 (cdata->data_value) + val; + if ((tmp > G_MAXINT64) || (tmp < G_MININT64)) + /* FIXME: how to handle overflow detection ? */ + g_set_error (&(cdata->error), + GDA_DATA_PIVOT_ERROR, GDA_DATA_PIVOT_OVERFLOW_ERROR, + "%s", _("Integer overflow")); + else + g_value_set_int64 (cdata->data_value, tmp); + break; + } + default: + return FALSE; + } + } + else { + /* new initial value */ + switch (cdata->aggregate) { + case GDA_DATA_PIVOT_MIN: + case GDA_DATA_PIVOT_MAX: + case GDA_DATA_PIVOT_SUM: + cdata->data_value = gda_value_new (G_TYPE_INT); + g_value_set_int (cdata->data_value, val); + break; + case GDA_DATA_PIVOT_AVG: + cdata->data_value = gda_value_new (G_TYPE_INT64); + g_value_set_int64 (cdata->data_value, (gint64) val); + break; + default: + return FALSE; + } + } + cdata->nvalues ++; + return TRUE; +} + +static gboolean +aggregate_handle_guint (CellData *cdata, guint val) +{ + if (cdata->data_value) { + guint eval = 0; + if (G_VALUE_TYPE (cdata->data_value) == G_TYPE_UINT) + eval = g_value_get_uint (cdata->data_value); + switch (cdata->aggregate) { + case GDA_DATA_PIVOT_MIN: + if (eval > val) + g_value_set_uint (cdata->data_value, val); + break; + case GDA_DATA_PIVOT_MAX: + if (eval < val) + g_value_set_uint (cdata->data_value, val); + break; + case GDA_DATA_PIVOT_SUM: { + guint64 tmp; + tmp = eval + val; + if (tmp > G_MAXUINT) + g_set_error (&(cdata->error), + GDA_DATA_PIVOT_ERROR, GDA_DATA_PIVOT_OVERFLOW_ERROR, + "%s", _("Integer overflow")); + else + g_value_set_uint (cdata->data_value, (guint) tmp); + break; + } + case GDA_DATA_PIVOT_AVG: { + guint64 tmp; + tmp = g_value_get_uint64 (cdata->data_value) + val; + if (tmp > G_MAXUINT64) + /* FIXME: how to handle overflow detection ? */ + g_set_error (&(cdata->error), + GDA_DATA_PIVOT_ERROR, GDA_DATA_PIVOT_OVERFLOW_ERROR, + "%s", _("Integer overflow")); + else + g_value_set_uint64 (cdata->data_value, tmp); + break; + } + default: + return FALSE; + } + } + else { + /* new initial value */ + switch (cdata->aggregate) { + case GDA_DATA_PIVOT_MIN: + case GDA_DATA_PIVOT_MAX: + case GDA_DATA_PIVOT_SUM: + cdata->data_value = gda_value_new (G_TYPE_UINT); + g_value_set_uint (cdata->data_value, val); + break; + case GDA_DATA_PIVOT_AVG: + cdata->data_value = gda_value_new (G_TYPE_UINT64); + g_value_set_uint64 (cdata->data_value, (guint64) val); + break; + default: + return FALSE; + } + } + cdata->nvalues ++; + return TRUE; +} + +static gboolean +aggregate_handle_gint64 (CellData *cdata, gint64 val) +{ + if (cdata->data_value) { + gint64 eval = 0; + if (G_VALUE_TYPE (cdata->data_value) == G_TYPE_INT64) + eval = g_value_get_int64 (cdata->data_value); + switch (cdata->aggregate) { + case GDA_DATA_PIVOT_MIN: + if (eval > val) + g_value_set_int64 (cdata->data_value, val); + break; + case GDA_DATA_PIVOT_MAX: + if (eval < val) + g_value_set_int64 (cdata->data_value, val); + break; + case GDA_DATA_PIVOT_SUM: + case GDA_DATA_PIVOT_AVG: { + gint64 tmp; + tmp = eval + val; + if ((tmp > G_MAXINT64) || (tmp < G_MININT64)) + /* FIXME: how to handle overflow detection ? */ + g_set_error (&(cdata->error), + GDA_DATA_PIVOT_ERROR, GDA_DATA_PIVOT_OVERFLOW_ERROR, + "%s", _("Integer overflow")); + else + g_value_set_int64 (cdata->data_value, (gint64) tmp); + break; + } + default: + return FALSE; + } + } + else { + /* new initial value */ + switch (cdata->aggregate) { + case GDA_DATA_PIVOT_MIN: + case GDA_DATA_PIVOT_MAX: + case GDA_DATA_PIVOT_SUM: + case GDA_DATA_PIVOT_AVG: + cdata->data_value = gda_value_new (G_TYPE_INT64); + g_value_set_int64 (cdata->data_value, val); + break; + default: + return FALSE; + } + } + cdata->nvalues ++; + return TRUE; +} + +static gboolean +aggregate_handle_guint64 (CellData *cdata, guint val) +{ + if (cdata->data_value) { + guint64 eval = 0; + if (G_VALUE_TYPE (cdata->data_value) == G_TYPE_UINT64) + eval = g_value_get_uint64 (cdata->data_value); + switch (cdata->aggregate) { + case GDA_DATA_PIVOT_MIN: + if (eval > val) + g_value_set_uint64 (cdata->data_value, val); + break; + case GDA_DATA_PIVOT_MAX: + if (eval < val) + g_value_set_uint64 (cdata->data_value, val); + break; + case GDA_DATA_PIVOT_SUM: + case GDA_DATA_PIVOT_AVG: { + guint64 tmp; + tmp = eval + val; + if (tmp > G_MAXUINT64) + /* FIXME: how to handle overflow detection ? */ + g_set_error (&(cdata->error), + GDA_DATA_PIVOT_ERROR, GDA_DATA_PIVOT_OVERFLOW_ERROR, + "%s", _("Integer overflow")); + else + g_value_set_uint64 (cdata->data_value, tmp); + break; + } + default: + return FALSE; + } + } + else { + /* new initial value */ + switch (cdata->aggregate) { + case GDA_DATA_PIVOT_MIN: + case GDA_DATA_PIVOT_MAX: + case GDA_DATA_PIVOT_SUM: + case GDA_DATA_PIVOT_AVG: + cdata->data_value = gda_value_new (G_TYPE_UINT64); + g_value_set_uint64 (cdata->data_value, val); + break; + default: + return FALSE; + } + } + cdata->nvalues ++; + return TRUE; +} + +static gboolean +aggregate_handle_float (CellData *cdata, gfloat val) +{ + if (cdata->data_value) { + gfloat eval = 0; + if (G_VALUE_TYPE (cdata->data_value) == G_TYPE_FLOAT) + eval = g_value_get_float (cdata->data_value); + switch (cdata->aggregate) { + case GDA_DATA_PIVOT_MIN: + if (eval > val) + g_value_set_float (cdata->data_value, val); + break; + case GDA_DATA_PIVOT_MAX: + if (eval < val) + g_value_set_float (cdata->data_value, val); + break; + case GDA_DATA_PIVOT_SUM: { + gdouble tmp; + tmp = eval + val; + if ((tmp > G_MAXDOUBLE) || (tmp < G_MINDOUBLE)) + g_set_error (&(cdata->error), + GDA_DATA_PIVOT_ERROR, GDA_DATA_PIVOT_OVERFLOW_ERROR, + "%s", _("Float value overflow")); + else + g_value_set_float (cdata->data_value, (gfloat) tmp); + break; + } + case GDA_DATA_PIVOT_AVG: { + gdouble tmp; + tmp = g_value_get_double (cdata->data_value) + val; + if ((tmp > G_MAXDOUBLE) || (tmp < G_MINDOUBLE)) + g_set_error (&(cdata->error), + GDA_DATA_PIVOT_ERROR, GDA_DATA_PIVOT_OVERFLOW_ERROR, + "%s", _("Float value overflow")); + else + g_value_set_double (cdata->data_value, tmp); + break; + } + default: + return FALSE; + } + } + else { + /* new initial value */ + switch (cdata->aggregate) { + case GDA_DATA_PIVOT_MIN: + case GDA_DATA_PIVOT_MAX: + case GDA_DATA_PIVOT_SUM: + cdata->data_value = gda_value_new (G_TYPE_FLOAT); + g_value_set_float (cdata->data_value, val); + break; + case GDA_DATA_PIVOT_AVG: + cdata->data_value = gda_value_new (G_TYPE_DOUBLE); + g_value_set_double (cdata->data_value, (gdouble) val); + break; + default: + return FALSE; + } + } + cdata->nvalues ++; + return TRUE; +} + +static gboolean +aggregate_handle_double (CellData *cdata, gdouble val) +{ + if (cdata->data_value) { + gdouble eval = 0; + if (G_VALUE_TYPE (cdata->data_value) == G_TYPE_DOUBLE) + eval = g_value_get_double (cdata->data_value); + switch (cdata->aggregate) { + case GDA_DATA_PIVOT_MIN: + if (eval > val) + g_value_set_double (cdata->data_value, val); + break; + case GDA_DATA_PIVOT_MAX: + if (eval < val) + g_value_set_double (cdata->data_value, val); + break; + case GDA_DATA_PIVOT_SUM: + case GDA_DATA_PIVOT_AVG: { + gdouble tmp; + tmp = eval + val; + if ((tmp > G_MAXDOUBLE) || (tmp < G_MINDOUBLE)) + /* FIXME: how to handle overflow detection ? */ + g_set_error (&(cdata->error), + GDA_DATA_PIVOT_ERROR, GDA_DATA_PIVOT_OVERFLOW_ERROR, + "%s", _("Double value overflow")); + else + g_value_set_double (cdata->data_value, (gdouble) tmp); + break; + } + default: + return FALSE; + } + } + else { + /* new initial value */ + switch (cdata->aggregate) { + case GDA_DATA_PIVOT_MIN: + case GDA_DATA_PIVOT_MAX: + case GDA_DATA_PIVOT_SUM: + case GDA_DATA_PIVOT_AVG: + cdata->data_value = gda_value_new (G_TYPE_DOUBLE); + g_value_set_double (cdata->data_value, val); + break; + default: + return FALSE; + } + } + cdata->nvalues ++; + return TRUE; +} + +static gboolean +aggregate_handle_char (CellData *cdata, + gint8 val + ) +{ + if (cdata->data_value) { + gint8 eval = 0; + if (G_VALUE_TYPE (cdata->data_value) == G_TYPE_CHAR) + eval = g_value_get_schar (cdata->data_value); + switch (cdata->aggregate) { + case GDA_DATA_PIVOT_MIN: + if (eval > val) + g_value_set_schar (cdata->data_value, val); + break; + case GDA_DATA_PIVOT_MAX: + if (eval < val) + g_value_set_schar (cdata->data_value, val); + break; + case GDA_DATA_PIVOT_SUM: { + gint tmp; + tmp = eval + val; + if ((tmp > G_MAXINT8) || (tmp < G_MININT8)) + g_set_error (&(cdata->error), + GDA_DATA_PIVOT_ERROR, GDA_DATA_PIVOT_OVERFLOW_ERROR, + "%s", _("Integer overflow")); + else + g_value_set_schar (cdata->data_value, (gint8) tmp); + break; + } + case GDA_DATA_PIVOT_AVG: { + gint64 tmp; + tmp = g_value_get_int64 (cdata->data_value) + val; + if ((tmp > G_MAXINT64) || (tmp < G_MININT64)) + /* FIXME: how to handle overflow detection ? */ + g_set_error (&(cdata->error), + GDA_DATA_PIVOT_ERROR, GDA_DATA_PIVOT_OVERFLOW_ERROR, + "%s", _("Integer overflow")); + else + g_value_set_int64 (cdata->data_value, tmp); + break; + } + default: + return FALSE; + } + } + else { + /* new initial value */ + switch (cdata->aggregate) { + case GDA_DATA_PIVOT_MIN: + case GDA_DATA_PIVOT_MAX: + case GDA_DATA_PIVOT_SUM: + cdata->data_value = gda_value_new (G_TYPE_CHAR); + g_value_set_schar (cdata->data_value, val); + break; + case GDA_DATA_PIVOT_AVG: + cdata->data_value = gda_value_new (G_TYPE_INT64); + g_value_set_int64 (cdata->data_value, (gint64) val); + break; + default: + return FALSE; + } + } + cdata->nvalues ++; + return TRUE; +} + +static gboolean +aggregate_handle_uchar (CellData *cdata, guchar val) +{ + if (cdata->data_value) { + guchar eval = 0; + if (G_VALUE_TYPE (cdata->data_value) == G_TYPE_UCHAR) + eval = g_value_get_uchar (cdata->data_value); + switch (cdata->aggregate) { + case GDA_DATA_PIVOT_MIN: + if (eval > val) + g_value_set_uchar (cdata->data_value, val); + break; + case GDA_DATA_PIVOT_MAX: + if (eval < val) + g_value_set_uchar (cdata->data_value, val); + break; + case GDA_DATA_PIVOT_SUM: { + guint tmp; + tmp = eval + val; + if (tmp > G_MAXUINT8) + g_set_error (&(cdata->error), + GDA_DATA_PIVOT_ERROR, GDA_DATA_PIVOT_OVERFLOW_ERROR, + "%s", _("Integer overflow")); + else + g_value_set_uchar (cdata->data_value, (guchar) tmp); + break; + } + case GDA_DATA_PIVOT_AVG: { + guint64 tmp; + tmp = g_value_get_uint64 (cdata->data_value) + val; + if (tmp > G_MAXUINT64) + /* FIXME: how to handle overflow detection ? */ + g_set_error (&(cdata->error), + GDA_DATA_PIVOT_ERROR, GDA_DATA_PIVOT_OVERFLOW_ERROR, + "%s", _("Integer overflow")); + else + g_value_set_uint64 (cdata->data_value, tmp); + break; + } + default: + return FALSE; + } + } + else { + /* new initial value */ + switch (cdata->aggregate) { + case GDA_DATA_PIVOT_MIN: + case GDA_DATA_PIVOT_MAX: + case GDA_DATA_PIVOT_SUM: + cdata->data_value = gda_value_new (G_TYPE_UCHAR); + g_value_set_uchar (cdata->data_value, val); + break; + case GDA_DATA_PIVOT_AVG: + cdata->data_value = gda_value_new (G_TYPE_UINT64); + g_value_set_uint64 (cdata->data_value, (guint64) val); + break; + default: + return FALSE; + } + } + cdata->nvalues ++; + return TRUE; +} + +static gboolean +aggregate_handle_short (CellData *cdata, gshort val) +{ + if (cdata->data_value) { + gshort eval = 0; + if (G_VALUE_TYPE (cdata->data_value) == GDA_TYPE_SHORT) + eval = gda_value_get_short (cdata->data_value); + switch (cdata->aggregate) { + case GDA_DATA_PIVOT_MIN: + if (eval > val) + gda_value_set_short (cdata->data_value, val); + break; + case GDA_DATA_PIVOT_MAX: + if (eval < val) + gda_value_set_short (cdata->data_value, val); + break; + case GDA_DATA_PIVOT_SUM: { + gint tmp; + tmp = eval + val; + if ((tmp > G_MAXSHORT) || (tmp < G_MINSHORT)) + g_set_error (&(cdata->error), + GDA_DATA_PIVOT_ERROR, GDA_DATA_PIVOT_OVERFLOW_ERROR, + "%s", _("Integer overflow")); + else + gda_value_set_short (cdata->data_value, (gshort) tmp); + break; + } + case GDA_DATA_PIVOT_AVG: { + gint64 tmp; + tmp = g_value_get_int64 (cdata->data_value) + val; + if ((tmp > G_MAXINT64) || (tmp < G_MININT64)) + /* FIXME: how to handle overflow detection ? */ + g_set_error (&(cdata->error), + GDA_DATA_PIVOT_ERROR, GDA_DATA_PIVOT_OVERFLOW_ERROR, + "%s", _("Integer overflow")); + else + g_value_set_int64 (cdata->data_value, tmp); + break; + } + default: + return FALSE; + } + } + else { + /* new initial value */ + switch (cdata->aggregate) { + case GDA_DATA_PIVOT_MIN: + case GDA_DATA_PIVOT_MAX: + case GDA_DATA_PIVOT_SUM: + cdata->data_value = gda_value_new (GDA_TYPE_SHORT); + gda_value_set_short (cdata->data_value, val); + break; + case GDA_DATA_PIVOT_AVG: + cdata->data_value = gda_value_new (G_TYPE_INT64); + g_value_set_int64 (cdata->data_value, (gint64) val); + break; + default: + return FALSE; + } + } + cdata->nvalues ++; + return TRUE; +} + +static gboolean +aggregate_handle_ushort (CellData *cdata, gushort val) +{ + if (cdata->data_value) { + gushort eval = 0; + if (G_VALUE_TYPE (cdata->data_value) == GDA_TYPE_USHORT) + eval = gda_value_get_ushort (cdata->data_value); + switch (cdata->aggregate) { + case GDA_DATA_PIVOT_MIN: + if (eval > val) + gda_value_set_ushort (cdata->data_value, val); + break; + case GDA_DATA_PIVOT_MAX: + if (eval < val) + gda_value_set_ushort (cdata->data_value, val); + break; + case GDA_DATA_PIVOT_SUM: { + guint tmp; + tmp = eval + val; + if (tmp > G_MAXUSHORT) + g_set_error (&(cdata->error), + GDA_DATA_PIVOT_ERROR, GDA_DATA_PIVOT_OVERFLOW_ERROR, + "%s", _("Integer overflow")); + else + gda_value_set_ushort (cdata->data_value, (gushort) tmp); + break; + } + case GDA_DATA_PIVOT_AVG: { + guint64 tmp; + tmp = g_value_get_uint64 (cdata->data_value) + val; + if (tmp > G_MAXUINT64) + /* FIXME: how to handle overflow detection ? */ + g_set_error (&(cdata->error), + GDA_DATA_PIVOT_ERROR, GDA_DATA_PIVOT_OVERFLOW_ERROR, + "%s", _("Integer overflow")); + else + g_value_set_uint64 (cdata->data_value, tmp); + break; + } + default: + return FALSE; + } + } + else { + /* new initial value */ + switch (cdata->aggregate) { + case GDA_DATA_PIVOT_MIN: + case GDA_DATA_PIVOT_MAX: + case GDA_DATA_PIVOT_SUM: + cdata->data_value = gda_value_new (GDA_TYPE_USHORT); + gda_value_set_ushort (cdata->data_value, val); + break; + case GDA_DATA_PIVOT_AVG: + cdata->data_value = gda_value_new (G_TYPE_UINT64); + g_value_set_uint64 (cdata->data_value, (guint64) val); + break; + default: + return FALSE; + } + } + cdata->nvalues ++; + return TRUE; +} + +/* + * Returns: %TRUE if @new_value_has been handled (even if it created cdata->error), + * or %FALSE if cdata's aggregate needs to store all the data + */ +static gboolean +aggregate_handle_new_value (CellData *cdata, const GValue *new_value) +{ + if (cdata->error) + return TRUE; + else if (cdata->values) + return FALSE; + + /* chack data type */ + if (G_VALUE_TYPE (new_value) != cdata->gtype) { + if (!cdata->error) + g_set_error (&(cdata->error), + GDA_DATA_PIVOT_ERROR, GDA_DATA_PIVOT_INTERNAL_ERROR, + "%s", _("Inconsistent data type")); + return TRUE; + } + + if (cdata->aggregate == GDA_DATA_PIVOT_COUNT) { + if (cdata->data_value) { + guint64 tmp; + tmp = g_value_get_uint (cdata->data_value) + 1; + if (tmp >= G_MAXUINT) + g_set_error (&(cdata->error), + GDA_DATA_PIVOT_ERROR, GDA_DATA_PIVOT_OVERFLOW_ERROR, + "%s", _("Integer overflow")); + else + g_value_set_uint (cdata->data_value, (guint) tmp); + } + else { + cdata->data_value = gda_value_new (G_TYPE_UINT); + g_value_set_uint (cdata->data_value, 1); + } + return TRUE; + } + else if (cdata->gtype == G_TYPE_INT) + return aggregate_handle_gint (cdata, g_value_get_int (new_value)); + else if (cdata->gtype == G_TYPE_UINT) + return aggregate_handle_guint (cdata, g_value_get_uint (new_value)); + else if (cdata->gtype == G_TYPE_INT64) + return aggregate_handle_gint64 (cdata, g_value_get_int64 (new_value)); + else if (cdata->gtype == G_TYPE_UINT64) + return aggregate_handle_guint64 (cdata, g_value_get_uint64 (new_value)); + else if (cdata->gtype == G_TYPE_FLOAT) + return aggregate_handle_float (cdata, g_value_get_float (new_value)); + else if (cdata->gtype == G_TYPE_DOUBLE) + return aggregate_handle_double (cdata, g_value_get_double (new_value)); + else if (cdata->gtype == G_TYPE_CHAR) + return aggregate_handle_char (cdata, g_value_get_schar (new_value)); + else if (cdata->gtype == G_TYPE_UCHAR) + return aggregate_handle_uchar (cdata, g_value_get_uchar (new_value)); + else if (cdata->gtype == GDA_TYPE_SHORT) + return aggregate_handle_short (cdata, gda_value_get_short (new_value)); + else if (cdata->gtype == GDA_TYPE_USHORT) + return aggregate_handle_ushort (cdata, gda_value_get_ushort (new_value)); + else { + /* incompatible data type for this kind of operation */ + if (!cdata->error) + g_set_error (&(cdata->error), + GDA_DATA_PIVOT_ERROR, GDA_DATA_PIVOT_INTERNAL_ERROR, + "%s", _("Data type does not support requested computation")); + return TRUE; + } +} + +/* + * Sets cdata->computed_value to a #GValue + * if an error occurs then cdata->computed_value is set to %NULL + * + * Also frees cdata->values. + */ +static void +cell_data_compute_aggregate (CellData *cdata) +{ + if (cdata->data_value) { + /* finish computation */ + if (cdata->error) { + gda_value_free (cdata->data_value); + cdata->data_value = NULL; + } + else if (cdata->aggregate == GDA_DATA_PIVOT_AVG) { + gdouble dval; + if ((cdata->gtype == G_TYPE_INT) || (cdata->gtype == G_TYPE_INT64) || + (cdata->gtype == G_TYPE_CHAR) || (cdata->gtype == GDA_TYPE_SHORT)) { + gint64 val; + g_assert (G_VALUE_TYPE (cdata->data_value) == G_TYPE_INT64); + val = g_value_get_int64 (cdata->data_value); + dval = val / (gdouble) cdata->nvalues; + } + else if ((cdata->gtype == G_TYPE_UINT) || (cdata->gtype == G_TYPE_UINT64) || + (cdata->gtype == G_TYPE_UCHAR) || (cdata->gtype == GDA_TYPE_USHORT)) { + guint64 val; + g_assert (G_VALUE_TYPE (cdata->data_value) == G_TYPE_UINT64); + val = g_value_get_uint64 (cdata->data_value); + dval = val / (gdouble) cdata->nvalues; + } + else if (cdata->gtype == G_TYPE_FLOAT) + dval = g_value_get_float (cdata->data_value) / (gdouble) cdata->nvalues; + else if (cdata->gtype == G_TYPE_DOUBLE) + dval = g_value_get_double (cdata->data_value) / (gdouble) cdata->nvalues; + else + g_assert_not_reached (); + + gda_value_free (cdata->data_value); + cdata->data_value = gda_value_new (G_TYPE_DOUBLE); + g_value_set_double (cdata->data_value, dval); + } + } + else if (cdata->values) { + TO_IMPLEMENT; + guint i; + for (i = 0; i < cdata->values->len; i++) { + GValue *value; + value = g_array_index (cdata->values, GValue*, i); + gda_value_free (value); + } + g_array_free (cdata->values, TRUE); + cdata->values = NULL; + } +} + +static GdaSqlStatement * +parse_field_spec (GdaDataPivot *pivot, const gchar *field, const gchar *alias, GError **error) +{ + GdaSqlParser *parser; + gchar *sql; + GdaStatement *stmt; + const gchar *remain; + GError *lerror = NULL; + GdaDataPivotPrivate *priv = gda_data_pivot_get_instance_private (pivot); + + g_return_val_if_fail (field, FALSE); + + if (! bind_source_model (pivot, error)) + return NULL; + + parser = gda_connection_create_parser (priv->vcnc); + g_assert (parser); + if (alias && *alias) { + gchar *tmp, *ptr; + tmp = g_strdup (alias); + for (ptr = tmp; *ptr; ptr++) { + if (g_ascii_isdigit (*ptr)) { + if (ptr == tmp) + *ptr = '_'; + } + else if (! g_ascii_isalpha (*ptr)) + *ptr = '_'; + } + sql = g_strdup_printf ("SELECT %s AS %s FROM " TABLE_NAME, field, tmp); + g_free (tmp); + } + else + sql = g_strdup_printf ("SELECT %s FROM " TABLE_NAME, field); + stmt = gda_sql_parser_parse_string (parser, sql, &remain, &lerror); + g_free (sql); + g_object_unref (parser); + if (!stmt || remain) { + g_set_error (error, GDA_DATA_PIVOT_ERROR, GDA_DATA_PIVOT_FIELD_FORMAT_ERROR, + _("Wrong field format error: %s"), + lerror && lerror->message ? lerror->message : _("No detail")); + g_clear_error (&lerror); + return NULL; + } + + /* test syntax: a valid SQL expression is required */ + GdaSqlStatement *sqlst = NULL; + g_object_get ((GObject*) stmt, "structure", &sqlst, NULL); + + if (sqlst->stmt_type != GDA_SQL_STATEMENT_SELECT) { + g_object_unref (stmt); + gda_sql_statement_free (sqlst); + g_set_error (error, GDA_DATA_PIVOT_ERROR, GDA_DATA_PIVOT_FIELD_FORMAT_ERROR, + "%s", _("Wrong field format")); + return NULL; + } + + /* + gchar *tmp = gda_sql_statement_serialize (sqlst); + g_print ("SQLST [%p, %s]\n", sqlst, tmp); + g_free (tmp); + */ + + /* further tests */ + GdaDataModel *model; + model = gda_connection_statement_execute_select (priv->vcnc, stmt, NULL, &lerror); + g_object_unref (stmt); + if (!model) { + g_set_error (error, GDA_DATA_PIVOT_ERROR, GDA_DATA_PIVOT_FIELD_FORMAT_ERROR, + _("Wrong field format error: %s"), + lerror && lerror->message ? lerror->message : _("No detail")); + g_clear_error (&lerror); + return NULL; + } + /* + g_print ("================= Pivot source:\n"); + gda_data_model_dump (model, NULL); + */ + + g_object_unref (model); + return sqlst; +} + +/** + * gda_data_pivot_add_field: + * @pivot: a #GdaDataPivot object + * @field_type: the type of field to add + * @field: the field description, see below + * @alias: (nullable): the field alias, or %NULL + * @error: (nullable): ta place to store errors, or %NULL + * + * Specifies that @field has to be included in the analysis. + * @field is a field specification with the following accepted syntaxes: + * + * a column name in the source data model (see gda_data_model_get_column_index()); or + * an SQL expression involving a column name in the source data model, for example: + * + * price + * firstname || ' ' || lastname + * nb BETWEEN 5 AND 10 + * + * + * + * It is also possible to specify several fields to be added, while separating them by a comma (in effect + * still forming a valid SQL syntax). + * + * Returns: %TRUE if no error occurred + * + * Since: 5.0 + */ +gboolean +gda_data_pivot_add_field (GdaDataPivot *pivot, GdaDataPivotFieldType field_type, + const gchar *field, const gchar *alias, GError **error) +{ + gchar *tmp; + GError *lerror = NULL; + + g_return_val_if_fail (GDA_IS_DATA_PIVOT (pivot), FALSE); + + GdaDataPivotPrivate *priv = gda_data_pivot_get_instance_private (pivot); + + g_return_val_if_fail (field, FALSE); + + GdaSqlStatement *sqlst; + sqlst = parse_field_spec (pivot, field, alias, error); + if (! sqlst) + return FALSE; + + GArray *array; + if (field_type == GDA_DATA_PIVOT_FIELD_ROW) { + if (! priv->row_fields) + priv->row_fields = g_array_new (FALSE, FALSE, sizeof (gchar*)); + array = priv->row_fields; + } + else { + if (! priv->column_fields) + priv->column_fields = g_array_new (FALSE, FALSE, sizeof (gchar*)); + array = priv->column_fields; + } + + GdaSqlStatementSelect *sel; + GSList *sf_list; + sel = (GdaSqlStatementSelect*) sqlst->contents; + for (sf_list = sel->expr_list; sf_list; sf_list = sf_list->next) { + GdaSqlBuilder *b; + GdaSqlBuilderId bid; + GdaSqlSelectField *sf; + sf = (GdaSqlSelectField*) sf_list->data; + b = gda_sql_builder_new (GDA_SQL_STATEMENT_SELECT); + gda_sql_builder_select_add_target_id (b, + gda_sql_builder_add_id (b, "T"), + NULL); + bid = gda_sql_builder_import_expression (b, sf->expr); + + if (bid == 0) { + g_set_error (error, GDA_DATA_PIVOT_ERROR, + GDA_DATA_PIVOT_FIELD_FORMAT_ERROR, + _("Wrong field format")); + gda_sql_statement_free (sqlst); + return FALSE; + } + gda_sql_builder_add_field_value_id (b, bid, 0); + gchar *sql; + GdaStatement *stmt; + stmt = gda_sql_builder_get_statement (b, &lerror); + g_object_unref (b); + if (!stmt) { + gda_sql_statement_free (sqlst); + g_set_error (error, GDA_DATA_PIVOT_ERROR, + GDA_DATA_PIVOT_FIELD_FORMAT_ERROR, + _("Wrong field format error: %s"), + lerror && lerror->message ? lerror->message : _("No detail")); + g_clear_error (&lerror); + return FALSE; + } + sql = gda_statement_to_sql (stmt, NULL, NULL); + g_object_unref (stmt); + if (!sql) { + g_set_error (error, GDA_DATA_PIVOT_ERROR, + GDA_DATA_PIVOT_FIELD_FORMAT_ERROR, + _("Wrong field format")); + gda_sql_statement_free (sqlst); + return FALSE; + } + /*g_print ("PART [%s][%s]\n", sql, sf->as);*/ + tmp = sql + 7; /* remove the "SELECT " start */ + tmp [strlen (tmp) - 7] = 0; /* remove the " FROM T" end */ + if (sf->as && *(sf->as)) { + gchar *tmp2; + tmp2 = g_strdup_printf ("%s AS %s", tmp, sf->as); + g_array_append_val (array, tmp2); + } + else { + tmp = g_strdup (tmp); + g_array_append_val (array, tmp); + } + g_free (sql); + } + + gda_sql_statement_free (sqlst); + + clean_previous_population (pivot); + + return TRUE; +} + +/** + * gda_data_pivot_add_data: + * @pivot: a #GdaDataPivot object + * @aggregate_type: the type of aggregate operation to perform + * @field: the field description, see below + * @alias: (nullable): the field alias, or %NULL + * @error: (nullable): ta place to store errors, or %NULL + * + * Specifies that @field has to be included in the analysis. + * @field is a field specification with the following accepted syntaxes: + * + * a column name in the source data model (see gda_data_model_get_column_index()); or + * an SQL expression involving a column name in the source data model, for examples: + * + * price + * firstname || ' ' || lastname + * nb BETWEEN 5 AND 10 + * + * + * + * It is also possible to specify several fields to be added, while separating them by a comma (in effect + * still forming a valid SQL syntax). + * + * Returns: %TRUE if no error occurred + * + * Since: 5.0 + */ +gboolean +gda_data_pivot_add_data (GdaDataPivot *pivot, GdaDataPivotAggregate aggregate_type, + const gchar *field, const gchar *alias, GError **error) +{ + gchar *tmp; + GError *lerror = NULL; + + g_return_val_if_fail (GDA_IS_DATA_PIVOT (pivot), FALSE); + g_return_val_if_fail (field, FALSE); + GdaDataPivotPrivate *priv = gda_data_pivot_get_instance_private (pivot); + + GdaSqlStatement *sqlst; + sqlst = parse_field_spec (pivot, field, alias, error); + if (! sqlst) + return FALSE; + + if (! priv->data_fields) + priv->data_fields = g_array_new (FALSE, FALSE, sizeof (gchar*)); + if (! priv->data_aggregates) + priv->data_aggregates = g_array_new (FALSE, FALSE, sizeof (GdaDataPivotAggregate)); + + GdaSqlStatementSelect *sel; + GSList *sf_list; + sel = (GdaSqlStatementSelect*) sqlst->contents; + for (sf_list = sel->expr_list; sf_list; sf_list = sf_list->next) { + GdaSqlBuilder *b; + GdaSqlBuilderId bid; + GdaSqlSelectField *sf; + sf = (GdaSqlSelectField*) sf_list->data; + b = gda_sql_builder_new (GDA_SQL_STATEMENT_SELECT); + gda_sql_builder_select_add_target_id (b, + gda_sql_builder_add_id (b, "T"), + NULL); + bid = gda_sql_builder_import_expression (b, sf->expr); + + if (bid == 0) { + g_set_error (error, GDA_DATA_PIVOT_ERROR, + GDA_DATA_PIVOT_FIELD_FORMAT_ERROR, + _("Wrong field format")); + gda_sql_statement_free (sqlst); + return FALSE; + } + gda_sql_builder_add_field_value_id (b, bid, 0); + gchar *sql; + GdaStatement *stmt; + stmt = gda_sql_builder_get_statement (b, &lerror); + g_object_unref (b); + if (!stmt) { + gda_sql_statement_free (sqlst); + g_set_error (error, GDA_DATA_PIVOT_ERROR, + GDA_DATA_PIVOT_FIELD_FORMAT_ERROR, + _("Wrong field format error: %s"), + lerror && lerror->message ? lerror->message : _("No detail")); + g_clear_error (&lerror); + return FALSE; + } + sql = gda_statement_to_sql (stmt, NULL, NULL); + g_object_unref (stmt); + if (!sql) { + g_set_error (error, GDA_DATA_PIVOT_ERROR, + GDA_DATA_PIVOT_FIELD_FORMAT_ERROR, + _("Wrong field format")); + gda_sql_statement_free (sqlst); + return FALSE; + } + /*g_print ("PART [%s][%s]\n", sql, sf->as);*/ + tmp = sql + 7; /* remove the "SELECT " start */ + tmp [strlen (tmp) - 7] = 0; /* remove the " FROM T" end */ + if (sf->as && *(sf->as)) { + gchar *tmp2; + tmp2 = g_strdup_printf ("%s AS %s", tmp, sf->as); + g_array_append_val (priv->data_fields, tmp2); + } + else { + tmp = g_strdup (tmp); + g_array_append_val (priv->data_fields, tmp); + } + g_array_append_val (priv->data_aggregates, aggregate_type); + g_free (sql); + } + + gda_sql_statement_free (sqlst); + + clean_previous_population (pivot); + + return TRUE; +} + +/** + * gda_data_pivot_populate: + * @pivot: a #GdaDataPivot object + * @error: (nullable): ta place to store errors, or %NULL + * + * Acutally populates @pivot by analysing the data from the provided data model. + * + * Returns: %TRUE if no error occurred. + * + * Since: 5.0 + */ +gboolean +gda_data_pivot_populate (GdaDataPivot *pivot, GError **error) +{ + gboolean retval = FALSE; + g_return_val_if_fail (GDA_IS_DATA_PIVOT (pivot), FALSE); + GdaDataPivotPrivate *priv = gda_data_pivot_get_instance_private (pivot); + + if (!priv->row_fields || (priv->row_fields->len == 0)) { + g_set_error (error, GDA_DATA_PIVOT_ERROR, GDA_DATA_PIVOT_USAGE_ERROR, + "%s", _("No row field defined")); + return FALSE; + } + + clean_previous_population (pivot); + + /* + * create data model extracted using the virtual connection. + * The resulting data model's columns are: + * - for priv->row_fields: 0 to priv->row_fields->len - 1 + * - for priv->column_fields: + * priv->row_fields->len to priv->row_fields->len + priv->column_fields->len - 1 + * - for priv->data_fields: priv->row_fields->len + priv->column_fields->len to priv->row_fields->len + priv->column_fields->len + priv->data_fields->len - 1 + */ + GString *string; + guint i; + string = g_string_new ("SELECT "); + for (i = 0; i < priv->row_fields->len; i++) { + gchar *part; + part = g_array_index (priv->row_fields, gchar *, i); + if (i != 0) + g_string_append (string, ", "); + g_string_append (string, part); + } + if (priv->column_fields) { + for (i = 0; i < priv->column_fields->len; i++) { + gchar *part; + part = g_array_index (priv->column_fields, gchar *, i); + g_string_append (string, ", "); + g_string_append (string, part); + } + } + if (priv->data_fields) { + for (i = 0; i < priv->data_fields->len; i++) { + gchar *part; + part = g_array_index (priv->data_fields, gchar *, i); + g_string_append (string, ", "); + g_string_append (string, part); + } + } + g_string_append (string, " FROM " TABLE_NAME); + + GdaStatement *stmt; + stmt = gda_connection_parse_sql_string (priv->vcnc, string->str, NULL, NULL); + g_string_free (string, TRUE); + if (!stmt) { + g_set_error (error, GDA_DATA_PIVOT_ERROR, GDA_DATA_PIVOT_INTERNAL_ERROR, + "%s", _("Could not get information from source data model")); + return FALSE; + } + + GdaDataModel *model; + model = gda_connection_statement_execute_select_full (priv->vcnc, stmt, NULL, + GDA_STATEMENT_MODEL_CURSOR_FORWARD, + //GDA_STATEMENT_MODEL_RANDOM_ACCESS, + NULL, NULL); + g_object_unref (stmt); + if (!model) { + g_set_error (error, GDA_DATA_PIVOT_ERROR, GDA_DATA_PIVOT_INTERNAL_ERROR, + "%s", _("Could not get information from source data model")); + return FALSE; + } + + /* + g_print ("========== Iterable data model\n"); + gda_data_model_dump (model, NULL); + */ + + /* iterate through the data model */ + GdaDataModelIter *iter; + gint col; + iter = gda_data_model_create_iter (model); + if (!iter) { + g_object_unref (model); + g_set_error (error, GDA_DATA_PIVOT_ERROR, GDA_DATA_PIVOT_INTERNAL_ERROR, + "%s", _("Could not get information from source data model")); + return FALSE; + } + + priv->columns = g_array_new (FALSE, FALSE, sizeof (GdaColumn*)); + for (col = 0; col < (gint) priv->row_fields->len; col++) { + GdaColumn *column; + GdaHolder *holder; + column = gda_column_new (); + holder = GDA_HOLDER (g_slist_nth_data (gda_set_get_holders (GDA_SET (iter)), col)); + + gda_column_set_name (column, gda_holder_get_id (holder)); + gda_column_set_description (column, gda_holder_get_id (holder)); + gda_column_set_g_type (column, gda_holder_get_g_type (holder)); + gda_column_set_position (column, col); + g_array_append_val (priv->columns, column); + } + + /* + * actual computation + */ + GHashTable *column_values_index; /* key = a #GValue (ref held in @column_values), + * value = pointer to a guint containing the position + * in @columns of the column */ + + GArray *first_rows; /* Array of GdaRow objects, the size of each GdaRow is + * the number of row fields defined */ + GHashTable *first_rows_index; /* key = a #GdaRow (ref held in @first_rows), + * value = pointer to a guint containing the position + * in @first_rows of the row. */ + GHashTable *data_hash; /* key = a CellData pointer, value = The CellData pointer + * as ref'ed in @data */ + + first_rows = g_array_new (FALSE, FALSE, sizeof (GdaRow*)); + first_rows_index = g_hash_table_new_full (_gda_row_hash, _gda_row_equal, NULL, g_free); + column_values_index = g_hash_table_new_full (column_data_hash, column_data_equal, + (GDestroyNotify) column_data_free, g_free); + data_hash = g_hash_table_new_full (cell_data_hash, cell_data_equal, + (GDestroyNotify) cell_data_free, NULL); + + for (;gda_data_model_iter_move_next (iter);) { + /* + * Row handling + */ + GdaRow *nrow; +#ifdef GDA_DEBUG_ROWS_HASH + g_print ("read from iter: "); +#endif + nrow = gda_row_new ((gint) priv->row_fields->len); + for (col = 0; col < (gint) priv->row_fields->len; col++) { + const GValue *ivalue; + GValue *rvalue; + GError *lerror = NULL; + ivalue = gda_data_model_iter_get_value_at_e (iter, col, &lerror); + if (!ivalue || lerror) { + clean_previous_population (pivot); + g_object_unref (nrow); + g_propagate_error (error, lerror); + goto out; + } + rvalue = gda_row_get_value (nrow, col); + gda_value_reset_with_type (rvalue, G_VALUE_TYPE (ivalue)); + g_value_copy (ivalue, rvalue); +#ifdef GDA_DEBUG_ROWS_HASH + gchar *tmp; + tmp = gda_value_stringify (rvalue); + g_print ("[%s]", tmp); + g_free (tmp); +#endif + } + + gint *rowindex; /* *rowindex will contain the actual row of the resulting data mode */ + rowindex = g_hash_table_lookup (first_rows_index, nrow); + if (rowindex) + g_object_unref (nrow); + else { + g_array_append_val (first_rows, nrow); + rowindex = g_new (gint, 1); + *rowindex = first_rows->len - 1; + g_hash_table_insert (first_rows_index, nrow, + rowindex); + } +#ifdef GDA_DEBUG_ROWS_HASH + g_print (" => @row %d\n", *rowindex); +#endif + + /* + * Column handling + */ + gint colsmax; + if (priv->column_fields) + colsmax = (gint) priv->column_fields->len; + else + colsmax = 1; + for (col = 0; col < colsmax; col++) { + const GValue *ivalue = NULL; + GError *lerror = NULL; + if (priv->column_fields) { + ivalue = gda_data_model_iter_get_value_at_e (iter, + col + priv->row_fields->len, + &lerror); + if (!ivalue || lerror) { + clean_previous_population (pivot); + g_propagate_error (error, lerror); + goto out; + } + } + + gint di, dimax; + if (priv->data_fields && priv->data_fields->len > 0) { + di = 0; + dimax = priv->data_fields->len; + } + else { + di = -1; + dimax = 0; + } + for (; di < dimax; di++) { + ColumnData coldata; + gint *colindex; + GdaDataPivotAggregate aggregate; + coldata.value = (GValue*) ivalue; + coldata.column_fields_index = col; + coldata.data_pos = di; + colindex = g_hash_table_lookup (column_values_index, &coldata); + if (di >= 0) + aggregate = g_array_index (priv->data_aggregates, + GdaDataPivotAggregate, di); + else + aggregate = GDA_DATA_PIVOT_SUM; + + if (!colindex) { + /* create new column */ + GdaColumn *column; + GString *name; + + name = g_string_new (""); + if (priv->column_fields && + priv->column_fields->len > 1) { + GdaColumn *column; + column = gda_data_model_describe_column (model, + priv->row_fields->len + col); + g_string_append_printf (name, "[%s]", + gda_column_get_name (column)); + } + if (ivalue) { + gchar *tmp; + tmp = gda_value_stringify (ivalue); + g_string_append (name, tmp); + g_free (tmp); + } + if ((di >= 0) && (dimax > 0)) { + GdaColumn *column; + gint vcol; + vcol = priv->row_fields->len + di; + if (priv->column_fields) + vcol += priv->column_fields->len; + column = gda_data_model_describe_column (model, vcol); + if (priv->column_fields) + g_string_append_printf (name, "[%s]", + gda_column_get_name (column)); + else + g_string_append (name, + gda_column_get_name (column)); + } + + column = gda_column_new (); + g_object_set_data ((GObject*) column, "agg", + GINT_TO_POINTER (aggregate)); + gda_column_set_name (column, name->str); + gda_column_set_description (column, name->str); + g_array_append_val (priv->columns, column); + gda_column_set_position (column, priv->columns->len - 1); + /* don't set the column's type now */ + /*g_print ("New column [%s] @real column %d, type %s\n", name->str, priv->columns->len - 1, gda_g_type_to_string (gda_column_get_g_type (column)));*/ + g_string_free (name, TRUE); + + ColumnData *ncoldata; + ncoldata = g_new (ColumnData, 1); + ncoldata->value = ivalue ? gda_value_copy ((GValue*) ivalue) : NULL; + ncoldata->column_fields_index = col; + ncoldata->data_pos = di; + colindex = g_new (gint, 1); + *colindex = priv->columns->len - 1; + g_hash_table_insert (column_values_index, ncoldata, + colindex); + } + + /* compute value to take into account */ + GValue *value = NULL; + if (di >= 0) { + const GValue *cvalue; + GError *lerror = NULL; + gint vcol; + vcol = priv->row_fields->len + di; + if (priv->column_fields) + vcol += priv->column_fields->len; + cvalue = gda_data_model_iter_get_value_at_e (iter, vcol, &lerror); + if (!cvalue || lerror) { + g_propagate_error (error, lerror); + goto out; + } + if (G_VALUE_TYPE (cvalue) != GDA_TYPE_NULL) + value = gda_value_copy (cvalue); + } + else { + value = gda_value_new (G_TYPE_INT); + g_value_set_int (value, 1); + } + + if (value) { + /* accumulate data */ + CellData ccdata, *pcdata; + ccdata.row = *rowindex; + ccdata.col = *colindex; + ccdata.values = NULL; + ccdata.data_value = NULL; + pcdata = g_hash_table_lookup (data_hash, &ccdata); + if (!pcdata) { + pcdata = g_new (CellData, 1); + pcdata->row = *rowindex; + pcdata->col = *colindex; + pcdata->error = NULL; + pcdata->values = NULL; + pcdata->gtype = G_VALUE_TYPE (value); + pcdata->nvalues = 0; + pcdata->data_value = NULL; + pcdata->aggregate = aggregate; + g_hash_table_insert (data_hash, pcdata, pcdata); + } + if (!aggregate_handle_new_value (pcdata, value)) { + if (!pcdata->values) + pcdata->values = g_array_new (FALSE, FALSE, + sizeof (GValue*)); + g_array_append_val (pcdata->values, value); + } + /*g_print ("row %d col %d => [%s]\n", pcdata->row, pcdata->col, + gda_value_stringify (value));*/ + } + } + } + } + if (gda_data_model_iter_get_row (iter) != -1) { + /* an error occurred! */ + goto out; + } + + /* compute real data model's values from all the collected data */ + GdaDataModel *results; + gint ncols, nrows; + ncols = priv->columns->len; + nrows = first_rows->len; + results = gda_data_model_array_new (ncols); + for (i = 0; i < priv->row_fields->len; i++) { + GdaColumn *acolumn, *ecolumn; + ecolumn = g_array_index (priv->columns, GdaColumn*, i); + acolumn = gda_data_model_describe_column (results, i); + gda_column_set_g_type (acolumn, gda_column_get_g_type (ecolumn)); + + gint j; + for (j = 0; j < nrows; j++) { + GdaRow *arow, *erow; + erow = g_array_index (first_rows, GdaRow*, j); + arow = gda_data_model_array_get_row ((GdaDataModelArray*) results, j, NULL); + if (!arow) { + g_assert (gda_data_model_append_row (results, NULL) == j); + arow = gda_data_model_array_get_row ((GdaDataModelArray*) results, j, + NULL); + g_assert (arow); + } + GValue *av, *ev; + av = gda_row_get_value (arow, i); + ev = gda_row_get_value (erow, i); + gda_value_reset_with_type (av, G_VALUE_TYPE (ev)); + g_value_copy (ev, av); + } + } + for (; i < (guint) ncols; i++) { + GdaColumn *ecolumn; + ecolumn = g_array_index (priv->columns, GdaColumn*, i); + + gint j; + for (j = 0; j < nrows; j++) { + GdaRow *arow; + GValue *av; + arow = gda_data_model_array_get_row ((GdaDataModelArray*) results, j, NULL); + av = gda_row_get_value (arow, i); + + CellData ccdata, *pcdata; + GType coltype = GDA_TYPE_NULL; + ccdata.row = j; + ccdata.col = i; + ccdata.values = NULL; + ccdata.data_value = NULL; + pcdata = g_hash_table_lookup (data_hash, &ccdata); + if (pcdata) { + cell_data_compute_aggregate (pcdata); + if (pcdata->data_value) { + coltype = G_VALUE_TYPE (pcdata->data_value); + gda_value_reset_with_type (av, coltype); + g_value_copy (pcdata->data_value, av); + } + else + gda_row_invalidate_value (arow, av); + } + else { + GValue *empty; + GdaDataPivotAggregate agg; + agg = GPOINTER_TO_INT (g_object_get_data ((GObject*) ecolumn, "agg")); + empty = aggregate_get_empty_value (agg); + coltype = G_VALUE_TYPE (empty); + gda_value_reset_with_type (av, coltype); + g_value_copy (empty, av); + } + if (coltype != GDA_TYPE_NULL) + gda_column_set_g_type (ecolumn, coltype); + } + } + priv->results = results; + + retval = TRUE; + + out: + if (!retval) + clean_previous_population (pivot); + + if (data_hash) + g_hash_table_destroy (data_hash); + + if (first_rows) { + guint i; + for (i = 0; i < first_rows->len; i++) { + GObject *obj; + obj = g_array_index (first_rows, GObject*, i); + if (obj) + g_object_unref (obj); + } + g_array_free (first_rows, TRUE); + } + + if (first_rows_index) + g_hash_table_destroy (first_rows_index); + + g_hash_table_destroy (column_values_index); + + g_object_unref (iter); + g_object_unref (model); + + return retval; +} + +static guint +_gda_value_hash (gconstpointer key) +{ + GValue *v; + GType vt; + guint res = 0; + v = (GValue *) key; + vt = G_VALUE_TYPE (v); + if ((vt == G_TYPE_BOOLEAN) || (vt == G_TYPE_INT) || (vt == G_TYPE_UINT) || + (vt == G_TYPE_FLOAT) || (vt == G_TYPE_DOUBLE) || + (vt == G_TYPE_INT64) || (vt == G_TYPE_INT64) || + (vt == GDA_TYPE_SHORT) || (vt == GDA_TYPE_USHORT) || + (vt == G_TYPE_CHAR) || (vt == G_TYPE_UCHAR) || + (vt == GDA_TYPE_NULL) || (vt == G_TYPE_GTYPE) || + (vt == G_TYPE_LONG) || (vt == G_TYPE_ULONG)) { + const signed char *p, *data; + data = (signed char*) v; + res = 5381; + for (p = data; p < data + sizeof (GValue); p++) + res = (res << 5) + res + *p; + } + else if (vt == G_TYPE_STRING) { + const gchar *tmp; + tmp = g_value_get_string (v); + if (tmp) + res += g_str_hash (tmp); + } + else if ((vt == GDA_TYPE_BINARY) || (vt == GDA_TYPE_BLOB)) { + GdaBinary *bin; + if (vt == GDA_TYPE_BLOB) { + GdaBlob *blob; + blob = (GdaBlob*) gda_value_get_blob ((GValue *) v); + bin = gda_blob_get_binary (blob); + if (gda_blob_get_op (blob) && + (gda_binary_get_size (bin) != gda_blob_op_get_length (gda_blob_get_op (blob)))) + gda_blob_op_read_all (gda_blob_get_op (blob), blob); + } + else + bin = gda_value_get_binary ((GValue *) v); + if (bin) { + glong l; + for (l = 0; l < gda_binary_get_size (bin); l++) { + guchar* p = gda_binary_get_data (bin); + res += (guint) p[l]; + } + } + } + else { + gchar *tmp; + tmp = gda_value_stringify (v); + res += g_str_hash (tmp); + g_free (tmp); + } + return res; +} + +static guint +_gda_row_hash (gconstpointer key) +{ + gint i, len; + GdaRow *r; + guint res = 0; + r = (GdaRow*) key; + len = gda_row_get_length (r); + for (i = 0; i < len ; i++) { + GValue *v; + v = gda_row_get_value (r, i); + res = (res << 5) + res + _gda_value_hash (v); + } + return res; +} + +static gboolean +_gda_row_equal (gconstpointer a, gconstpointer b) +{ + gint i, len; + GdaRow *ra, *rb; + ra = (GdaRow*) a; + rb = (GdaRow*) b; + len = gda_row_get_length (ra); + g_assert (len == gda_row_get_length (rb)); + for (i = 0; i < len ; i++) { + GValue *va, *vb; + va = gda_row_get_value (ra, i); + vb = gda_row_get_value (rb, i); + if (gda_value_differ (va, vb)) + return FALSE; + } + return TRUE; +} + +/* + * Create a new virtual connection for @pivot + */ +static gboolean +create_vcnc (GdaDataPivot *pivot, GError **error) +{ + GdaConnection *vcnc; + GError *lerror = NULL; + static GMutex provider_mutex; + static GdaVirtualProvider *virtual_provider; + GdaDataPivotPrivate * priv = gda_data_pivot_get_instance_private (pivot); + if (priv->vcnc) + return TRUE; + + g_mutex_lock (&provider_mutex); + if (!virtual_provider) + virtual_provider = gda_vprovider_data_model_new (); + g_mutex_unlock (&provider_mutex); + + vcnc = gda_virtual_connection_open (virtual_provider, GDA_CONNECTION_OPTIONS_NONE, &lerror); + if (! vcnc) { + g_print ("Virtual ERROR: %s\n", lerror && lerror->message ? lerror->message : "No detail"); + if (lerror) + g_error_free (lerror); + g_set_error (error, GDA_DATA_PIVOT_ERROR, GDA_DATA_PIVOT_INTERNAL_ERROR, + "%s", _("Could not create virtual connection")); + return FALSE; + } + + priv->vcnc = vcnc; + return TRUE; +} + +/* + * Bind @priv->model as a table named TABLE_NAME in @pivot's virtual connection + */ +static gboolean +bind_source_model (GdaDataPivot *pivot, GError **error) +{ + GdaDataPivotPrivate *priv = gda_data_pivot_get_instance_private (pivot); + if (! priv->model) { + g_set_error (error, GDA_DATA_PIVOT_ERROR, GDA_DATA_PIVOT_SOURCE_MODEL_ERROR, + "%s", _("No source defined")); + return FALSE; + } + if (! create_vcnc (pivot, error)) + return FALSE; + + if (gda_vconnection_data_model_get_model (GDA_VCONNECTION_DATA_MODEL (priv->vcnc), + TABLE_NAME) == priv->model) { + /* already bound */ + return TRUE; + } + + GError *lerror = NULL; + if (!gda_vconnection_data_model_add_model (GDA_VCONNECTION_DATA_MODEL (priv->vcnc), + priv->model, + TABLE_NAME, &lerror)) { + g_set_error (error, GDA_DATA_PIVOT_ERROR, GDA_DATA_PIVOT_SOURCE_MODEL_ERROR, + "%s", + _("Invalid source data model (may have incompatible column names)")); + g_clear_error (&lerror); + return FALSE; + } + + return TRUE; +} + +static +guint column_data_hash (gconstpointer key) +{ + ColumnData *cd; + cd = (ColumnData*) key; + if (cd->value) + return _gda_value_hash (cd->value) + cd->column_fields_index + cd->data_pos; + else + return cd->column_fields_index + cd->data_pos; +} + +static gboolean +column_data_equal (gconstpointer a, gconstpointer b) +{ + ColumnData *cda, *cdb; + cda = (ColumnData*) a; + cdb = (ColumnData*) b; + if ((cda->column_fields_index != cdb->column_fields_index) || + (cda->data_pos != cdb->data_pos)) + return FALSE; + if (cda->value && cdb->value) + return gda_value_differ (cda->value, cdb->value) ? FALSE : TRUE; + else if (cda->value || cdb->value) + return FALSE; + else + return TRUE; +} + +static void +column_data_free (ColumnData *cdata) +{ + gda_value_free (cdata->value); + g_free (cdata); +} + +static guint +cell_data_hash (gconstpointer key) +{ + CellData *cd; + cd = (CellData*) key; + return g_int_hash (&(cd->row)) + g_int_hash (&(cd->col)); +} + +static gboolean +cell_data_equal (gconstpointer a, gconstpointer b) +{ + CellData *cda, *cdb; + cda = (CellData*) a; + cdb = (CellData*) b; + if ((cda->row == cdb->row) && (cda->col == cdb->col)) + return TRUE; + else + return FALSE; +} + +static void +cell_data_free (CellData *cdata) +{ + if (cdata->values) { + guint i; + for (i = 0; i < cdata->values->len; i++) { + GValue *value; + value = g_array_index (cdata->values, GValue*, i); + gda_value_free (value); + } + g_array_free (cdata->values, TRUE); + } + gda_value_free (cdata->data_value); + g_free (cdata); +} diff --git a/.flatpak-builder/cache/objects/26/5dcc0b8858a90a492af2f104e918deb6fd10bc57a976c844748148bd040c5b.file b/.flatpak-builder/cache/objects/26/5dcc0b8858a90a492af2f104e918deb6fd10bc57a976c844748148bd040c5b.file new file mode 100644 index 0000000..85b3e2a Binary files /dev/null and b/.flatpak-builder/cache/objects/26/5dcc0b8858a90a492af2f104e918deb6fd10bc57a976c844748148bd040c5b.file differ diff --git a/.flatpak-builder/cache/objects/26/62e16af4fc5dec3b82649aba2bc94b3ad12eda850e822dd307cff42be7bba4.file b/.flatpak-builder/cache/objects/26/62e16af4fc5dec3b82649aba2bc94b3ad12eda850e822dd307cff42be7bba4.file new file mode 100644 index 0000000..3e10b92 --- /dev/null +++ b/.flatpak-builder/cache/objects/26/62e16af4fc5dec3b82649aba2bc94b3ad12eda850e822dd307cff42be7bba4.file @@ -0,0 +1,508 @@ +/* + * Copyright (C) 2014 Vivien Malerba + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +/* + * The "maintenance", or "background" thread is responsible to: + * - cache GdaWorker objects ready to be reused + * - join worker threads from GdaWorker + * + * - trim spare ITSignaler ? + */ + +#include "gda-worker.h" +#include "background.h" + +#define SPARE_WORKER_DELAY_MS 2000 +#define SPARE_ITS_DELAY_MS 2000 +#define MAKE_STATS +#undef MAKE_STATS + +#define DEBUG_BG +#undef DEBUG_BG + +#ifdef MAKE_STATS + #ifndef G_OS_WIN32 + #include + #include + #endif +#endif + +/* + * global data + */ +GMutex bg_mutex; /* protects: + * - the "background" thread creation, AND + * - the @spare_workers array + * - the @spare_its array */ + + +/* + * Job type: JOB_JOIN_THREAD + */ +typedef struct { + GThread *thread; +} JoinThreadData; + +static void +JoinThreadData_free (JoinThreadData *data) +{ + g_slice_free (JoinThreadData, data); +} + +/* + * Job type: JOB_SPARE_WORKER + */ +typedef struct { + GdaWorker *worker; + guint ms; +} WorkerSpareData; +static GArray *spare_workers = NULL; /* array of WorkerSpareData pointers (ref held), only used from within the "background" thread. + * the last entries have a higher value of @ms (because new elements are appended) */ +static void +WorkerSpareData_free (WorkerSpareData *data) +{ + if (data->worker) { +#ifdef DEBUG_BG + g_print ("[_gda_worker_bg_unref(%p)]\n", data->worker); +#endif + _gda_worker_bg_unref (data->worker); + } + g_slice_free (WorkerSpareData, data); +} + +/* + * Job type: JOB_SPARE_ITS + */ +typedef struct { + ITSignaler *its; + guint ms; +} ItsSpareData; +static GArray *spare_its = NULL; /* array of ItsSpareData pointers (ref held), only used from within the "background" thread. + * the last entries have a higher value of @ms (because new elements are appended) */ +static void +ItsSpareData_free (ItsSpareData *data) +{ + if (data->its) { +#ifdef DEBUG_BG + g_print ("[_its_bg_unref(%p)]\n", data->its); +#endif + _itsignaler_bg_unref (data->its); + } + g_slice_free (ItsSpareData, data); +} + +/* + * Job transmission through a GAsyncQueue + */ +static GAsyncQueue *bgqueue = NULL; /* vector to pass jobs to "background" thread */ +typedef enum { + JOB_JOIN_THREAD, + JOB_SPARE_WORKER, + JOB_SPARE_ITS +} JobType; + +typedef struct { + JobType type; + union { + JoinThreadData *u1; + WorkerSpareData *u2; + ItsSpareData *u3; + } u; +} Job; + +/* + * Utility + */ +static guint +compute_wait_delay (void) +{ + guint delay = 0; + + g_mutex_lock (&bg_mutex); + /* + guint i; + for (i = 0; i < spare_workers->len; i++) { + WorkerSpareData *data; + data = g_array_index (spare_workers, WorkerSpareData*, i); + if (i == 0) + delay = data->ms; + else + delay = MIN (delay, data->ms); + } + */ + if (spare_workers->len > 0) { /* we use here the fact that @spare_workers is ordered */ + WorkerSpareData *data; + data = g_array_index (spare_workers, WorkerSpareData*, 0); + delay = data->ms; + } + if (spare_its->len > 0) { /* we use here the fact that @spare_its is ordered */ + ItsSpareData *data; + data = g_array_index (spare_its, ItsSpareData*, 0); + if (delay == 0) + delay = data->ms; + else + delay = MIN (data->ms, delay); + } + g_mutex_unlock (&bg_mutex); + + return delay; +} + +/* + * MAIN part of the "background" thread + */ +static gpointer +background_main (G_GNUC_UNUSED gpointer data) +{ + GTimer *timer; + guint elapsed_ms = 0; + timer = g_timer_new (); + g_timer_stop (timer); + + while (1) { + /* honor delayed operations */ + g_mutex_lock (&bg_mutex); + guint i; + for (i = 0; i < spare_workers->len; ) { + WorkerSpareData *data; + data = g_array_index (spare_workers, WorkerSpareData*, i); + + if (data->ms <= elapsed_ms) { + g_array_remove_index (spare_workers, 0); + WorkerSpareData_free (data); + } + else { + data->ms -= elapsed_ms; + i++; + } + } + for (i = 0; i < spare_its->len; ) { + ItsSpareData *data; + data = g_array_index (spare_its, ItsSpareData*, i); + + if (data->ms <= elapsed_ms) { + g_array_remove_index (spare_its, 0); + ItsSpareData_free (data); + } + else { + data->ms -= elapsed_ms; + i++; + } + } + g_mutex_unlock (&bg_mutex); + + /* compute maximum time to wait */ + guint next_delay_ms; + next_delay_ms = compute_wait_delay (); + + /* fetch new job submissions from the queue */ + Job *job; + g_timer_start (timer); + if (next_delay_ms == 0) + job = g_async_queue_pop (bgqueue); + else + job = g_async_queue_timeout_pop (bgqueue, next_delay_ms * 1000); + g_timer_stop (timer); + elapsed_ms = (guint) (g_timer_elapsed (timer, NULL) * 1000.); + + if (job) { + switch (job->type) { + case JOB_SPARE_WORKER: + g_mutex_lock (&bg_mutex); + g_array_append_val (spare_workers, job->u.u2); +#ifdef DEBUG_BG + g_print ("[Cached GdaWorker %p]\n", job->u.u2->worker); +#endif + g_mutex_unlock (&bg_mutex); + break; + case JOB_SPARE_ITS: + g_mutex_lock (&bg_mutex); + g_array_append_val (spare_its, job->u.u3); +#ifdef DEBUG_BG + g_print ("[Cached ITS %p]\n", job->u.u3->its); +#endif + g_mutex_unlock (&bg_mutex); + break; + case JOB_JOIN_THREAD: { + JoinThreadData *data; + data = job->u.u1; +#ifdef DEBUG_BG + g_print ("[g_thread_join(%p)]\n", data->thread); +#endif + + bg_update_stats (BG_JOINED_THREADS); + + g_thread_join (data->thread); + JoinThreadData_free (data); + break; + } + default: + g_assert_not_reached (); + } + + g_slice_free (Job, job); /* free the Job "shell" */ + } + } + return NULL; +} + + +/** + * _bg_start: + * + * Have the "background" thread start. May be called several times. + */ +static void +_bg_start (void) +{ + static gboolean th_started = FALSE; + g_mutex_lock (&bg_mutex); + + if (!bgqueue) + bgqueue = g_async_queue_new (); + + if (!spare_its) + spare_its = g_array_new (FALSE, FALSE, sizeof (ItsSpareData*)); + + if (!spare_workers) + spare_workers = g_array_new (FALSE, FALSE, sizeof (WorkerSpareData*)); + + if (!th_started) { + GThread *th; + th = g_thread_new ("gdaBackground", background_main, NULL); + if (th) { + th_started = TRUE; + } + else + g_warning ("Failed to start Gda's background thread\n"); + } + + g_mutex_unlock (&bg_mutex); +} + +/** + * bg_join_thread: + * + * This function must be called by a thread right before it exits, it tells the "background" thread that + * it can call g_thread_join() without having the risk of blocking. It is called by worker threads right before + * they exit. + */ +void +bg_join_thread () +{ + _bg_start (); + + Job *job; + job = g_slice_new (Job); + job->type = JOB_JOIN_THREAD; + job->u.u1 = g_slice_new (JoinThreadData); + job->u.u1->thread = g_thread_self (); + + g_async_queue_push (bgqueue, job); +} + +/** + * bg_set_spare_gda_worker: + * @worker: a #GdaWorker + * + * This function requests that the "background" handle the caching or the destruction of @worker. It is intended to be called + * only from within the gda_worker_unref() method when the reference count is 0, but right before destroying it. + * + * The caller (the GdaWorker's code) must first set the reference count to 1 (and not destroy the object). + */ +void +bg_set_spare_gda_worker (GdaWorker *worker) +{ + g_return_if_fail (worker); + _bg_start (); + + Job *job; + job = g_slice_new (Job); + job->type = JOB_SPARE_WORKER; + job->u.u2 = g_slice_new (WorkerSpareData); + job->u.u2->worker = worker; + job->u.u2->ms = SPARE_WORKER_DELAY_MS; /* fixed delay => array is ordered, see compute_wait_delay() */ + + bg_update_stats (BG_CACHED_WORKER_REQUESTS); + + g_async_queue_push (bgqueue, job); +} + +/** + * bg_get_spare_gda_worker: + * + * Requests the "background" thread to provide a #GdaWorker which it has kept as a cache (see bg_set_spare_gda_worker()). + * The return value may be %NULL (if no #GdaWorker object is available), or a pointer to a #GdaWorker which refcount is 1 + * and which has a worker thread available immediately (no job pending or in process). + * + * Returns: (transfer full): a #GdaWorker, or %NULL + */ +GdaWorker * +bg_get_spare_gda_worker (void) +{ + GdaWorker *worker = NULL; + _bg_start (); + + g_mutex_lock (&bg_mutex); + if (spare_workers->len > 0) { + WorkerSpareData *data; + data = g_array_index (spare_workers, WorkerSpareData*, 0); + + worker = data->worker; + data->worker = NULL; + WorkerSpareData_free (data); + + g_array_remove_index (spare_workers, 0); +#ifdef DEBUG_BG + g_print ("[Fetched cached GdaWorker %p]\n", worker); +#endif + + bg_update_stats (BG_REUSED_WORKER_FROM_CACHE); + } + g_mutex_unlock (&bg_mutex); + + return worker; +} + +/* + * ITSignaler caching + */ +/** + * bg_set_spare_its: + * @its: a #ITSignaler + * + * This function requests that the "background" handle the caching or the destruction of @its. It is intended to be called + * only from within the itsignaler_unref() method when the reference count is 0, but right before destroying it. + * + * The caller (the ITSIgnaler's code) must first set the reference count to 1 (and not destroy the object). + */ +void +bg_set_spare_its (ITSignaler *its) +{ + g_return_if_fail (its); + _bg_start (); + + Job *job; + job = g_slice_new (Job); + job->type = JOB_SPARE_ITS; + job->u.u3 = g_slice_new (ItsSpareData); + job->u.u3->its = its; + job->u.u3->ms = SPARE_ITS_DELAY_MS; /* fixed delay => array is ordered, see compute_wait_delay() */ + + bg_update_stats (BG_CACHED_ITS_REQUESTS); + + g_async_queue_push (bgqueue, job); +} + +/** + * bg_get_spare_its: + * + * Requests the "background" thread to provide a #ITSignaler which it has kept as a cache (see bg_set_spare_its()). + * The return value may be %NULL (if no #ITSignaler object is available), or a pointer to a #ITSignaler which refcount is 1. + * + * Returns: (transfer full): a #ITSignaler, or %NULL + */ +ITSignaler * +bg_get_spare_its (void) +{ + ITSignaler *its = NULL; + _bg_start (); + + g_mutex_lock (&bg_mutex); + if (spare_its->len > 0) { + ItsSpareData *data; + data = g_array_index (spare_its, ItsSpareData*, 0); + + its = data->its; + data->its = NULL; + ItsSpareData_free (data); + + g_array_remove_index (spare_its, 0); +#ifdef DEBUG_BG + g_print ("[Fetched cached ITS %p]\n", its); +#endif + + bg_update_stats (BG_REUSED_ITS_FROM_CACHE); + } + g_mutex_unlock (&bg_mutex); + + return its; +} + + +/* + * Statistics + */ +#ifdef MAKE_STATS +guint stats [BG_STATS_MAX]; + +static void +write_stats (void) +{ + gchar *strings [] = { + "GdaWorker created", + "GdaWorker destroyed", + "GdaWorker cache requests", + "GdaWorker reused from cache", + + "Started threads", + "Joined threads", + + "ITS created", + "ITS destroyed", + "ITS cache requests", + "ITS reused from cache" + }; + BackgroundStats i; + GString *string; + string = g_string_new ("=== stats start ===\n"); + for (i = BG_STATS_MIN; i < BG_STATS_MAX; i++) + g_string_append_printf (string, "%s: %u\n", strings[i], stats [i]); + g_string_append (string, "=== stats end ===\n"); + + gchar *fname; +#ifndef G_OS_WIN32 + fname = g_strdup_printf ("gda_stats_%u", getpid ()); +#else + fname = g_strdup_printf ("gda_stats"); +#endif + g_file_set_contents (fname, string->str, -1, NULL); + g_free (fname); + g_string_free (string, TRUE); +} + +/** + * bg_update_stats: + */ +void +bg_update_stats (BackgroundStats type) +{ + g_assert ((type >= BG_STATS_MIN) && (type < BG_STATS_MAX)); + stats [type] ++; + if ((type == BG_CREATED_WORKER) || (type == BG_DESTROYED_WORKER) || + (type == BG_STARTED_THREADS) || (type == BG_JOINED_THREADS) || + (type == BG_CREATED_ITS) || (type == BG_DESTROYED_ITS)) + write_stats (); +} +#else +void +bg_update_stats (G_GNUC_UNUSED BackgroundStats type) +{ +} +#endif diff --git a/.flatpak-builder/cache/objects/27/9a4d199be3b03b218bcc7d851457d197e68bd7b019eab1608a3b94f0899a53.dirtree b/.flatpak-builder/cache/objects/27/9a4d199be3b03b218bcc7d851457d197e68bd7b019eab1608a3b94f0899a53.dirtree new file mode 100644 index 0000000..fddc05c Binary files /dev/null and b/.flatpak-builder/cache/objects/27/9a4d199be3b03b218bcc7d851457d197e68bd7b019eab1608a3b94f0899a53.dirtree differ diff --git a/.flatpak-builder/cache/objects/27/d88c4afeda7101410dbf2b12dd539ac38942445cd5238eae603fa81f73acda.file b/.flatpak-builder/cache/objects/27/d88c4afeda7101410dbf2b12dd539ac38942445cd5238eae603fa81f73acda.file new file mode 100644 index 0000000..e62e3f8 --- /dev/null +++ b/.flatpak-builder/cache/objects/27/d88c4afeda7101410dbf2b12dd539ac38942445cd5238eae603fa81f73acda.file @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2001 - 2004 Rodrigo Moya + * Copyright (C) 2002 - 2003 Gonzalo Paniagua Javier + * Copyright (C) 2004 - 2005 Alan Knowles + * Copyright (C) 2005 Bas Driessen + * Copyright (C) 2005 - 2014 Vivien Malerba + * Copyright (C) 2006 - 2008 Murray Cumming + * Copyright (C) 2007 Armin Burgmeier + * Copyright (C) 2013 Daniel Espinosa + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GDA_SERVER_PROVIDER_H__ +#define __GDA_SERVER_PROVIDER_H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +G_BEGIN_DECLS + +#define GDA_TYPE_SERVER_PROVIDER (gda_server_provider_get_type()) + +G_DECLARE_DERIVABLE_TYPE(GdaServerProvider, gda_server_provider, GDA, SERVER_PROVIDER, GObject) + +struct _GdaServerProviderClass { + GObjectClass parent_class; + gpointer functions_sets[8]; +}; + + +/* error reporting */ +extern GQuark gda_server_provider_error_quark (void); +#define GDA_SERVER_PROVIDER_ERROR gda_server_provider_error_quark () + +typedef enum +{ + GDA_SERVER_PROVIDER_METHOD_NON_IMPLEMENTED_ERROR, + GDA_SERVER_PROVIDER_PREPARE_STMT_ERROR, + GDA_SERVER_PROVIDER_EMPTY_STMT_ERROR, + GDA_SERVER_PROVIDER_MISSING_PARAM_ERROR, + GDA_SERVER_PROVIDER_STATEMENT_EXEC_ERROR, + GDA_SERVER_PROVIDER_OPERATION_ERROR, + GDA_SERVER_PROVIDER_INTERNAL_ERROR, + GDA_SERVER_PROVIDER_BUSY_ERROR, + GDA_SERVER_PROVIDER_NON_SUPPORTED_ERROR, + GDA_SERVER_PROVIDER_SERVER_VERSION_ERROR, + GDA_SERVER_PROVIDER_DATA_ERROR, + GDA_SERVER_PROVIDER_DEFAULT_VALUE_HANDLING_ERROR, + GDA_SERVER_PROVIDER_MISUSE_ERROR, + GDA_SERVER_PROVIDER_FILE_NOT_FOUND_ERROR +} GdaServerProviderError; + +/** + * SECTION:gda-server-provider + * @short_description: Base class for all the DBMS providers + * @title: GdaServerProvider + * @stability: Stable + * @see_also: #GdaConnection + * + * The #GdaServerProvider class is a virtual class which all the DBMS providers + * must inherit, and implement its virtual methods. + * + * See the Virtual methods for providers section for more information + * about how to implement the virtual methods. + */ + +/* provider information */ +const gchar *gda_server_provider_get_name (GdaServerProvider *provider); +const gchar *gda_server_provider_get_version (GdaServerProvider *provider); +const gchar *gda_server_provider_get_server_version (GdaServerProvider *provider, GdaConnection *cnc); +gboolean gda_server_provider_supports_feature (GdaServerProvider *provider, GdaConnection *cnc, + GdaConnectionFeature feature); + +/* types and values manipulation */ +GdaDataHandler *gda_server_provider_get_data_handler_g_type(GdaServerProvider *provider, + GdaConnection *cnc, + GType for_type); +GdaDataHandler *gda_server_provider_get_data_handler_dbms (GdaServerProvider *provider, + GdaConnection *cnc, + const gchar *for_type); +GValue *gda_server_provider_string_to_value (GdaServerProvider *provider, + GdaConnection *cnc, + const gchar *string, + GType preferred_type, + gchar **dbms_type); +gchar *gda_server_provider_value_to_sql_string (GdaServerProvider *provider, + GdaConnection *cnc, + GValue *from); +const gchar *gda_server_provider_get_default_dbms_type (GdaServerProvider *provider, + GdaConnection *cnc, + GType type); +gchar *gda_server_provider_escape_string (GdaServerProvider *provider, + GdaConnection *cnc, const gchar *str); +gchar *gda_server_provider_unescape_string (GdaServerProvider *provider, + GdaConnection *cnc, const gchar *str); + +/* actions with parameters */ +gboolean gda_server_provider_supports_operation (GdaServerProvider *provider, GdaConnection *cnc, + GdaServerOperationType type, GdaSet *options); +GdaServerOperation *gda_server_provider_create_operation (GdaServerProvider *provider, GdaConnection *cnc, + GdaServerOperationType type, + GdaSet *options, GError **error); +gchar *gda_server_provider_render_operation (GdaServerProvider *provider, GdaConnection *cnc, + GdaServerOperation *op, GError **error); +gboolean gda_server_provider_perform_operation (GdaServerProvider *provider, GdaConnection *cnc, + GdaServerOperation *op, GError **error); + +/* GdaStatement */ +GdaSqlParser *gda_server_provider_create_parser (GdaServerProvider *provider, GdaConnection *cnc); + +G_END_DECLS + +#endif diff --git a/.flatpak-builder/cache/objects/28/2d1507451faa76f88430f558c472a033df7671ec389fddf74fd52848323419.file b/.flatpak-builder/cache/objects/28/2d1507451faa76f88430f558c472a033df7671ec389fddf74fd52848323419.file new file mode 100644 index 0000000..52e3999 --- /dev/null +++ b/.flatpak-builder/cache/objects/28/2d1507451faa76f88430f558c472a033df7671ec389fddf74fd52848323419.file @@ -0,0 +1,97 @@ +/* gda-db-fkey.h + * + * Copyright (C) 2018 Pavlo Solntsev + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +#ifndef GDA_DB_FKEY_H +#define GDA_DB_FKEY_H + +#include +#include +#include +#include +#include +#include "gda-db-buildable.h" +#include "gda-server-operation.h" + +G_BEGIN_DECLS + +#define GDA_TYPE_DB_FKEY (gda_db_fkey_get_type()) + +G_DECLARE_DERIVABLE_TYPE (GdaDbFkey, gda_db_fkey, GDA, DB_FKEY, GObject) + +struct _GdaDbFkeyClass { + GObjectClass parent_class; +}; + +/** + * GdaDbFkeyReferenceAction: + * @GDA_DB_FKEY_NO_ACTION: Action is not specified. + * @GDA_DB_FKEY_SET_NULL: Action value is set to %NULL + * @GDA_DB_FKEY_RESTRICT: Value is set to "RESTRICT" + * @GDA_DB_FKEY_SET_DEFAULT: Value is set to default behavior + * @GDA_DB_FKEY_CASCADE: Value is set to cascade + * + * Specify numeric value for the actions, e.g. "ON DELETE" and "ON UPDATE" + */ +typedef enum { + GDA_DB_FKEY_NO_ACTION, + GDA_DB_FKEY_SET_NULL, + GDA_DB_FKEY_RESTRICT, + GDA_DB_FKEY_SET_DEFAULT, + GDA_DB_FKEY_CASCADE +} GdaDbFkeyReferenceAction; + + +GdaDbFkey* gda_db_fkey_new (void); + +const GList* gda_db_fkey_get_field_name (GdaDbFkey *self); +const GList* gda_db_fkey_get_ref_field (GdaDbFkey *self); + +void gda_db_fkey_set_field (GdaDbFkey *self, + const gchar *field, + const gchar *reffield); + +const gchar* gda_db_fkey_get_ref_table (GdaDbFkey *self); +void gda_db_fkey_set_ref_table (GdaDbFkey *self, + const gchar *rtable); + +const gchar* gda_db_fkey_get_ondelete (GdaDbFkey *self); + +GdaDbFkeyReferenceAction + gda_db_fkey_get_ondelete_id (GdaDbFkey *self); + +void gda_db_fkey_set_ondelete (GdaDbFkey *self, + GdaDbFkeyReferenceAction id); + +const gchar* gda_db_fkey_get_onupdate (GdaDbFkey *self); + +GdaDbFkeyReferenceAction + gda_db_fkey_get_onupdate_id (GdaDbFkey *self); + +void gda_db_fkey_set_onupdate (GdaDbFkey *self, + GdaDbFkeyReferenceAction id); + +gboolean gda_db_fkey_prepare_create (GdaDbFkey *self, + GdaServerOperation *op, + gint i, + GError **error); + +G_END_DECLS + +#endif /* GDA_DB_FKEY_H */ + diff --git a/.flatpak-builder/cache/objects/28/3ad0b2cf033bc398a6dd9ed1e2c39ea3c0756dfc732458e88758e753a68bc6.file b/.flatpak-builder/cache/objects/28/3ad0b2cf033bc398a6dd9ed1e2c39ea3c0756dfc732458e88758e753a68bc6.file new file mode 100644 index 0000000..b6b6426 --- /dev/null +++ b/.flatpak-builder/cache/objects/28/3ad0b2cf033bc398a6dd9ed1e2c39ea3c0756dfc732458e88758e753a68bc6.file @@ -0,0 +1,1511 @@ +/* + * Copyright (C) 2008 - 2009 Bas Driessen + * Copyright (C) 2008 - 2011 Murray Cumming + * Copyright (C) 2008 - 2013 Vivien Malerba + * Copyright (C) 2010 David King + * Copyright (C) 2010 Jonh Wendell + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Error reporting + */ +GQuark +gda_sql_error_quark (void) +{ + static GQuark quark; + if (!quark) + quark = g_quark_from_static_string ("gda_sql_error"); + return quark; +} + +GdaSqlStatementContentsInfo * +gda_sql_statement_contents_info_copy (GdaSqlStatementContentsInfo *src) { + GdaSqlStatementContentsInfo *cp = g_new0(GdaSqlStatementContentsInfo, 1); + cp->name = src->name; + cp->construct = src->construct; + cp->free = src->free; + cp->copy = src->copy; + cp->serialize = src->serialize; + + /* augmenting information precision using a dictionary */ + cp->check_structure_func = src->check_structure_func; + cp->check_validity_func = src->check_validity_func; + return cp; +} +void +gda_sql_statement_contents_info_free (GdaSqlStatementContentsInfo *cinfo) { + g_free (cinfo); +} + +G_DEFINE_BOXED_TYPE(GdaSqlStatementContentsInfo, gda_sql_statement_contents_info, gda_sql_statement_contents_info_copy, gda_sql_statement_contents_info_free) +/* + * statement's infos retrieval + */ +GdaSqlStatementContentsInfo * +gda_sql_statement_get_contents_infos (GdaSqlStatementType type) +{ + static GMutex mutex; + static GdaSqlStatementContentsInfo **contents = NULL; + + g_mutex_lock (&mutex); + if (!contents) { + contents = g_new0 (GdaSqlStatementContentsInfo *, GDA_SQL_STATEMENT_NONE); + + contents [GDA_SQL_STATEMENT_SELECT] = _gda_sql_statement_select_get_infos (); + contents [GDA_SQL_STATEMENT_INSERT] = _gda_sql_statement_insert_get_infos (); + contents [GDA_SQL_STATEMENT_DELETE] = _gda_sql_statement_delete_get_infos (); + contents [GDA_SQL_STATEMENT_UPDATE] = _gda_sql_statement_update_get_infos (); + contents [GDA_SQL_STATEMENT_BEGIN] = _gda_sql_statement_begin_get_infos (); + contents [GDA_SQL_STATEMENT_COMPOUND] = _gda_sql_statement_compound_get_infos (); + contents [GDA_SQL_STATEMENT_COMMIT] = _gda_sql_statement_commit_get_infos (); + contents [GDA_SQL_STATEMENT_ROLLBACK] = _gda_sql_statement_rollback_get_infos (); + contents [GDA_SQL_STATEMENT_UNKNOWN] = _gda_sql_statement_unknown_get_infos (); + contents [GDA_SQL_STATEMENT_SAVEPOINT] = _gda_sql_statement_savepoint_get_infos (); + contents [GDA_SQL_STATEMENT_ROLLBACK_SAVEPOINT] = _gda_sql_statement_rollback_savepoint_get_infos (); + contents [GDA_SQL_STATEMENT_DELETE_SAVEPOINT] = _gda_sql_statement_delete_savepoint_get_infos (); + } + g_mutex_unlock (&mutex); + + return contents[type]; +} + +G_DEFINE_BOXED_TYPE(GdaSqlStatement, gda_sql_statement, gda_sql_statement_copy, gda_sql_statement_free) + +/** + * gda_sql_statement_new + * @type: type of statement to create + * + * Use this function to create a #GdaSqlStatement of the specified @type type. + * + * Returns: a new #GdaSqlStatement + */ +GdaSqlStatement * +gda_sql_statement_new (GdaSqlStatementType type) +{ + GdaSqlStatement *stmt; + GdaSqlStatementContentsInfo *infos = gda_sql_statement_get_contents_infos (type); + + stmt = g_new0 (GdaSqlStatement, 1); + stmt->stmt_type = type; + if (infos && infos->construct) { + stmt->contents = infos->construct (); + GDA_SQL_ANY_PART (stmt->contents)->type = (GdaSqlAnyPartType) type; + } + else + TO_IMPLEMENT; + + return stmt; +} + +/** + * gda_sql_statement_copy + * @stmt: a #GdaSqlStatement pointer + * + * Creates a copy of @stmt. + * + * Returns: a new #GdaSqlStatement + */ +GdaSqlStatement * +gda_sql_statement_copy (GdaSqlStatement *stmt) +{ + GdaSqlStatement *copy; + GdaSqlStatementContentsInfo *infos; + + if (!stmt) + return NULL; + + infos = gda_sql_statement_get_contents_infos (stmt->stmt_type); + copy = g_new0 (GdaSqlStatement, 1); + copy->stmt_type = stmt->stmt_type; + + if (stmt->sql) + copy->sql = g_strdup (stmt->sql); + if (infos && infos->copy) { + copy->contents = infos->copy (stmt->contents); + GDA_SQL_ANY_PART (copy->contents)->type = GDA_SQL_ANY_PART (stmt->contents)->type; + } + else if (infos && infos->construct) { + copy->contents = infos->construct (); + GDA_SQL_ANY_PART (copy->contents)->type = (GdaSqlAnyPartType) stmt->stmt_type; + } + else + TO_IMPLEMENT; + if (stmt->validity_meta_struct) { + copy->validity_meta_struct = stmt->validity_meta_struct; + g_object_ref (copy->validity_meta_struct); + } + + return copy; +} + +/** + * gda_sql_statement_free + * @stmt: a #GdaSqlStatement pointer + * + * Releases any memory associated to @stmt. + */ +void +gda_sql_statement_free (GdaSqlStatement *stmt) +{ + GdaSqlStatementContentsInfo *infos; + + infos = gda_sql_statement_get_contents_infos (stmt->stmt_type); + g_free (stmt->sql); + + if (stmt->contents) { + if (infos && infos->free) + infos->free (stmt->contents); + else + TO_IMPLEMENT; + } + if (stmt->validity_meta_struct) + g_object_unref (stmt->validity_meta_struct); + + g_free (stmt); +} + +/** + * gda_sql_statement_type_to_string + * @type: a #GdaSqlStatementType value + * + * Converts a #GdaSqlStatementType to a string, see also gda_sql_statement_string_to_type() + * + * Returns: a constant string + */ +const gchar * +gda_sql_statement_type_to_string (GdaSqlStatementType type) +{ + GdaSqlStatementContentsInfo *infos; + infos = gda_sql_statement_get_contents_infos (type); + if (!infos) + return "NONE"; + else + return infos->name; +} + +/** + * gda_sql_statement_string_to_type + * @type: a string representing a #GdaSqlStatementType type + * + * Converts a string to a #GdaSqlStatementType value, see also gda_sql_statement_type_to_string() + * + * Returns: a #GdaSqlStatementType value + */ +GdaSqlStatementType +gda_sql_statement_string_to_type (const gchar *type) +{ + g_return_val_if_fail (type, GDA_SQL_STATEMENT_NONE); + + switch (*type) { + case 'B': + return GDA_SQL_STATEMENT_BEGIN; + case 'C': + if ((type[1] == 'O') && (type[2] == 'M') && (type[2] == 'P')) + return GDA_SQL_STATEMENT_COMPOUND; + else + return GDA_SQL_STATEMENT_COMMIT; + case 'D': + if (!strcmp (type, "DELETE")) + return GDA_SQL_STATEMENT_DELETE; + else + return GDA_SQL_STATEMENT_DELETE_SAVEPOINT; + case 'I': + return GDA_SQL_STATEMENT_INSERT; + case 'R': + if (!strcmp (type, "ROLLBACK")) + return GDA_SQL_STATEMENT_ROLLBACK; + else + return GDA_SQL_STATEMENT_ROLLBACK_SAVEPOINT; + case 'S': + if (type[1] == 'E') + return GDA_SQL_STATEMENT_SELECT; + else + return GDA_SQL_STATEMENT_SAVEPOINT; + case 'U': + if (type[1] == 'N') + return GDA_SQL_STATEMENT_UNKNOWN; + else + return GDA_SQL_STATEMENT_UPDATE; + default: + TO_IMPLEMENT; + return GDA_SQL_STATEMENT_NONE; + } +} + + +/** + * gda_sql_statement_serialize + * @stmt: a #GdaSqlStatement pointer + * + * Creates a string representation of @stmt. + * + * Returns: a new string + */ +gchar * +gda_sql_statement_serialize (GdaSqlStatement *stmt) +{ + GString *string; + gchar *str; + GdaSqlStatementContentsInfo *infos; + + if (!stmt) + return NULL; + + infos = gda_sql_statement_get_contents_infos (stmt->stmt_type); + string = g_string_new ("{"); + str = _json_quote_string (stmt->sql); + g_string_append_printf (string, "\"sql\":%s", str); + g_free (str); + g_string_append_printf (string, ",\"stmt_type\":\"%s\"", infos->name); + if (infos && infos->serialize) { + str = infos->serialize (stmt->contents); + g_string_append_c (string, ','); + g_string_append (string, str); + g_free (str); + } + else + TO_IMPLEMENT; + + g_string_append_c (string, '}'); + str = string->str; + g_string_free (string, FALSE); + return str; + +} + + +/* + * Check with dict data structure + */ +static gboolean foreach_check_clean (GdaSqlAnyPart *node, gpointer data, GError **error); + +static gboolean foreach_check_validity (GdaSqlAnyPart *node, GdaSqlStatementCheckValidityData *data, GError **error); +static gboolean gda_sql_expr_check_validity (GdaSqlExpr *expr, GdaSqlStatementCheckValidityData *data, GError **error); +static gboolean gda_sql_field_check_validity (GdaSqlField *field, GdaSqlStatementCheckValidityData *data, GError **error); +static gboolean gda_sql_table_check_validity (GdaSqlTable *table, GdaSqlStatementCheckValidityData *data, GError **error); +static gboolean gda_sql_select_field_check_validity (GdaSqlSelectField *field, GdaSqlStatementCheckValidityData *data, GError **error); +static gboolean gda_sql_select_target_check_validity (GdaSqlSelectTarget *target, GdaSqlStatementCheckValidityData *data, GError **error); + +/** + * gda_sql_statement_check_validity: + * @stmt: a #GdaSqlStatement pointer + * @cnc: (nullable): a #GdaConnection object, or %NULL + * @error: a place to store errors, or %NULL + * + * If @cnc is not %NULL, then checks that all the database objects referenced in the statement actually + * exist in the connection's database (for example the table being updated in a UPDATE statement must exist in the + * connection's database for the check to succeed). This method fills the @stmt->validity_meta_struct attribute. + * + * If @cnc is %NULL, then remove any information from a previous call to this method stored in @stmt. In this case, + * the @stmt->validity_meta_struct attribute is cleared. + * + * Also note that some parts of @stmt may be modified: for example leading and trailing spaces in aliases or + * objects names will be removed. + * + * Returns: TRUE if no error occurred + */ +gboolean +gda_sql_statement_check_validity (GdaSqlStatement *stmt, GdaConnection *cnc, GError **error) +{ + g_return_val_if_fail (stmt, FALSE); + g_return_val_if_fail (!cnc || GDA_IS_CONNECTION (cnc), FALSE); + + /* check the structure first */ + if (!gda_sql_statement_check_structure (stmt, error)) + return FALSE; + + /* clear any previous setting */ + gda_sql_statement_check_clean (stmt); + + if (cnc) { + GdaSqlStatementCheckValidityData data; + gboolean retval; + + /* prepare data */ + data.cnc = cnc; + data.store = gda_connection_get_meta_store (cnc); + data.mstruct = (GdaMetaStruct*) g_object_new (GDA_TYPE_META_STRUCT, "meta-store", data.store, "features", GDA_META_STRUCT_FEATURE_NONE, NULL); + + /* attach the GdaMetaStruct to @stmt */ + stmt->validity_meta_struct = data.mstruct; + retval = gda_sql_any_part_foreach (GDA_SQL_ANY_PART (stmt->contents), + (GdaSqlForeachFunc) foreach_check_validity, &data, error); + return retval; + } + else + return TRUE; +} + +/** + * gda_sql_statement_check_validity_m + * @stmt: a #GdaSqlStatement pointer + * @mstruct: (nullable): a #GdaMetaStruct object, or %NULL + * @error: a place to store errors, or %NULL + * + * If @mstruct is not %NULL, then checks that all the database objects referenced in the statement i + * actually referenced in @mstruct + * (for example the table being updated in a UPDATE statement must exist in the + * connection's database for the check to succeed). + * This method sets the @stmt->validity_meta_struct attribute to @mstruct. + * + * If @mstruct is %NULL, then remove any information from a previous call to this method stored in @stmt. In this case, + * the @stmt->validity_meta_struct attribute is cleared. + * + * Also note that some parts of @stmt may be modified: for example leading and trailing spaces in aliases or + * objects names will be removed. + * + * Returns: TRUE if no error occurred + * + * Since: 4.2 + */ +gboolean +gda_sql_statement_check_validity_m (GdaSqlStatement *stmt, GdaMetaStruct *mstruct, GError **error) +{ + g_return_val_if_fail (stmt, FALSE); + g_return_val_if_fail (!mstruct || GDA_IS_META_STRUCT (mstruct), FALSE); + + /* check the structure first */ + if (!gda_sql_statement_check_structure (stmt, error)) + return FALSE; + + /* clear any previous setting */ + gda_sql_statement_check_clean (stmt); + + if (mstruct) { + GdaSqlStatementCheckValidityData data; + gboolean retval; + + /* prepare data */ + data.cnc = NULL; + data.store = NULL; + data.mstruct = g_object_ref (mstruct); + + /* attach the GdaMetaStruct to @stmt */ + stmt->validity_meta_struct = data.mstruct; + retval = gda_sql_any_part_foreach (GDA_SQL_ANY_PART (stmt->contents), + (GdaSqlForeachFunc) foreach_check_validity, &data, error); + return retval; + } + else + return TRUE; +} + +static gboolean +foreach_check_validity (GdaSqlAnyPart *node, GdaSqlStatementCheckValidityData *data, GError **error) +{ + if (!node) return TRUE; + + switch (node->type) { + case GDA_SQL_ANY_STMT_SELECT: + case GDA_SQL_ANY_STMT_INSERT: + case GDA_SQL_ANY_STMT_UPDATE: + case GDA_SQL_ANY_STMT_DELETE: + case GDA_SQL_ANY_STMT_COMPOUND: + case GDA_SQL_ANY_STMT_BEGIN: + case GDA_SQL_ANY_STMT_ROLLBACK: + case GDA_SQL_ANY_STMT_COMMIT: + case GDA_SQL_ANY_STMT_SAVEPOINT: + case GDA_SQL_ANY_STMT_ROLLBACK_SAVEPOINT: + case GDA_SQL_ANY_STMT_DELETE_SAVEPOINT: + case GDA_SQL_ANY_STMT_UNKNOWN: { + GdaSqlStatementContentsInfo *cinfo; + cinfo = gda_sql_statement_get_contents_infos ((GdaSqlStatementType) node->type); + if (cinfo->check_validity_func) + return cinfo->check_validity_func (node, data, error); + break; + } + case GDA_SQL_ANY_EXPR: { + GdaSqlExpr *expr = (GdaSqlExpr *) node; + if (expr->cast_as) { + g_strchomp (expr->cast_as); + if (! *(expr->cast_as)) { + g_free (expr->cast_as); + expr->cast_as = NULL; + } + } + return gda_sql_expr_check_validity (expr, data, error); + } + case GDA_SQL_ANY_SQL_FIELD: { + GdaSqlField *field = (GdaSqlField*) node; + if (field->field_name) { + g_strchomp (field->field_name); + if (! *(field->field_name)) { + g_free (field->field_name); + field->field_name = NULL; + } + } + return gda_sql_field_check_validity (field, data, error); + } + case GDA_SQL_ANY_SQL_TABLE: { + GdaSqlTable *table = (GdaSqlTable*) node; + if (table->table_name) { + g_strchomp (table->table_name); + if (! *(table->table_name)) { + g_free (table->table_name); + table->table_name = NULL; + } + } + return gda_sql_table_check_validity (table, data, error); + } + case GDA_SQL_ANY_SQL_FUNCTION: { + GdaSqlFunction *function = (GdaSqlFunction*) node; + if (function->function_name) { + g_strchomp (function->function_name); + if (! *(function->function_name)) { + g_free (function->function_name); + function->function_name = NULL; + } + } + return TRUE; + } + case GDA_SQL_ANY_SQL_SELECT_FIELD: { + GdaSqlSelectField *field = (GdaSqlSelectField*) node; + if (field->as) { + g_strchomp (field->as); + if (! *(field->as)) { + g_free (field->as); + field->as = NULL; + } + } + + if (field->expr && field->expr->value && (G_VALUE_TYPE (field->expr->value) == G_TYPE_STRING)) { + g_free (field->field_name); + g_free (field->table_name); + _split_identifier_string (g_value_dup_string (field->expr->value), &(field->table_name), + &(field->field_name)); + } + if (field->table_name) { + g_strchomp (field->table_name); + if (! *(field->table_name)) { + g_free (field->table_name); + field->table_name = NULL; + } + } + if (field->field_name) { + g_strchomp (field->field_name); + if (! *(field->field_name)) { + g_free (field->field_name); + field->field_name = NULL; + } + } + return gda_sql_select_field_check_validity (field, data, error); + } + case GDA_SQL_ANY_SQL_SELECT_TARGET: { + GdaSqlSelectTarget *target = (GdaSqlSelectTarget*) node; + if (target->as) { + g_strchomp (target->as); + if (! *(target->as)) { + g_free (target->as); + target->as = NULL; + } + } + if (target->expr && target->expr->value && (G_VALUE_TYPE (target->expr->value) == G_TYPE_STRING)) { + g_free (target->table_name); + target->table_name = g_value_dup_string (target->expr->value); + } + if (target->table_name) { + g_strchomp (target->table_name); + if (! *(target->table_name)) { + g_free (target->table_name); + target->table_name = NULL; + } + } + return gda_sql_select_target_check_validity (target, data, error); + } + default: + break; + } + return TRUE; +} + +static gboolean +gda_sql_expr_check_validity (GdaSqlExpr *expr, G_GNUC_UNUSED GdaSqlStatementCheckValidityData *data, G_GNUC_UNUSED GError **error) +{ + if (!expr) return TRUE; + if (!expr->param_spec) return TRUE; + _gda_sql_expr_check_clean (expr); + + /* 2 checks to do here: + * - try to find the data type from expr->param_spec->type using data->mstruct (not yet possible) + * - if expr->param_spec->type is NULL, then try to identify it (and expr->param_spec->g_type) + * using @expr context, set expr->param_spec->validity_meta_dict. + */ + /*TO_IMPLEMENT;*/ + return TRUE; +} + +void +_gda_sql_expr_check_clean (GdaSqlExpr *expr) +{ + if (!expr) return; + if (expr->param_spec && expr->param_spec->validity_meta_dict) + TO_IMPLEMENT; +} + +static gboolean +gda_sql_field_check_validity (GdaSqlField *field, GdaSqlStatementCheckValidityData *data, GError **error) +{ + GdaSqlAnyPart *any; + GdaSqlTable *stable; + + if (!field) return TRUE; + _gda_sql_field_check_clean (field); + + for (any = GDA_SQL_ANY_PART(field)->parent; + any && (any->type != GDA_SQL_ANY_STMT_INSERT) && (any->type != GDA_SQL_ANY_STMT_UPDATE); + any = any->parent); + if (!any) { + g_set_error (error, GDA_SQL_ERROR, GDA_SQL_STRUCTURE_CONTENTS_ERROR, + "%s", _("GdaSqlField is not part of an INSERT or UPDATE statement")); + return FALSE; + } + + if (any->type == GDA_SQL_ANY_STMT_INSERT) + stable = ((GdaSqlStatementInsert*) any)->table; + else if (any->type == GDA_SQL_ANY_STMT_UPDATE) + stable = ((GdaSqlStatementUpdate*) any)->table; + else + g_assert_not_reached (); + + if (!stable) { + g_set_error (error, GDA_SQL_ERROR, GDA_SQL_VALIDATION_ERROR, + "%s", _("Missing table in statement")); + return FALSE; + } + if (!stable->validity_meta_object) { + if (! gda_sql_table_check_validity (stable, data, error)) + return FALSE; + } + + g_assert (stable->validity_meta_object); + GdaMetaTableColumn *tcol; + GValue value; + memset (&value, 0, sizeof (GValue)); + g_value_set_string (g_value_init (&value, G_TYPE_STRING), field->field_name); + tcol = gda_meta_struct_get_table_column (data->mstruct, + GDA_META_TABLE (stable->validity_meta_object), + &value); + g_value_unset (&value); + field->validity_meta_table_column = tcol; + if (!tcol) { + g_set_error (error, GDA_SQL_ERROR, GDA_SQL_VALIDATION_ERROR, + _("Column '%s' not found"), field->field_name); + return FALSE; + } + + return TRUE; +} + +void +_gda_sql_field_check_clean (GdaSqlField *field) +{ + if (!field) return; + field->validity_meta_table_column = NULL; +} + +/* For GdaSqlSelectTarget, GdaSqlSelectField and GdaSqlTable */ +static GdaMetaDbObject * +find_table_or_view (GdaSqlAnyPart *part, GdaSqlStatementCheckValidityData *data, const gchar *name, GError **error) +{ + GdaMetaDbObject *dbo; + GValue value; + GError *lerror = NULL; + + memset (&value, 0, sizeof (GValue)); + + /* use @name as the table or view's real name */ + g_value_set_string (g_value_init (&value, G_TYPE_STRING), name); + dbo = gda_meta_struct_complement (data->mstruct, GDA_META_DB_UNKNOWN, + NULL, NULL, &value, &lerror); + g_value_unset (&value); + if (!dbo && (*name == '"')) { + gchar *tmp; + g_clear_error (&lerror); + tmp = gda_sql_identifier_quote (name, data->cnc, NULL, TRUE, FALSE); + dbo = find_table_or_view (part, data, tmp, error); + g_free (tmp); + return dbo; + } + if (!dbo) { + /* use @name as a table alias in the statement */ + GdaSqlAnyPart *any; + + for (any = part->parent; + any && any->parent && (any->type != GDA_SQL_ANY_STMT_SELECT); + any = any->parent); + if (!any) + g_set_error (&lerror, GDA_SQL_ERROR, GDA_SQL_STRUCTURE_CONTENTS_ERROR, + "%s", _("GdaSqlSelectField is not part of a SELECT statement")); + else { + switch (any->type) { + case GDA_SQL_ANY_STMT_SELECT: { + GdaSqlStatementSelect *select = (GdaSqlStatementSelect*) any; + if (select->from) { + GSList *targets; + for (targets = select->from->targets; targets; targets = targets->next) { + GdaSqlSelectTarget *target = (GdaSqlSelectTarget*) targets->data; + if (!target->as || strcmp (target->as, name)) + continue; + g_value_set_string (g_value_init (&value, G_TYPE_STRING), + target->table_name); + dbo = gda_meta_struct_complement (data->mstruct, + GDA_META_DB_UNKNOWN, + NULL, NULL, &value, NULL); + g_value_unset (&value); + if (dbo) + break; + } + } + break; + } + case GDA_SQL_ANY_STMT_INSERT: + TO_IMPLEMENT; + break; + case GDA_SQL_ANY_STMT_UPDATE: + TO_IMPLEMENT; + break; + case GDA_SQL_ANY_STMT_DELETE: + TO_IMPLEMENT; + break; + case GDA_SQL_ANY_STMT_COMPOUND: + TO_IMPLEMENT; + break; + default: + g_assert_not_reached (); + break; + } + } + } + if (dbo) { + if (lerror) + g_error_free (lerror); + } + else { + if (lerror) + g_propagate_error (error, lerror); + } + + return dbo; +} + +static gboolean +gda_sql_table_check_validity (GdaSqlTable *table, GdaSqlStatementCheckValidityData *data, GError **error) +{ + GdaMetaDbObject *dbo; + + if (!table) return TRUE; + _gda_sql_table_check_clean (table); + + if (!table->table_name) { + g_set_error (error, GDA_SQL_ERROR, GDA_SQL_VALIDATION_ERROR, + "%s", _("Missing table name in statement")); + return FALSE; + } + + dbo = find_table_or_view ((GdaSqlAnyPart*) table, data, table->table_name, error); + if (dbo && ((dbo->obj_type != GDA_META_DB_TABLE) && + (dbo->obj_type != GDA_META_DB_VIEW))) { + g_set_error (error, GDA_SQL_ERROR, GDA_SQL_VALIDATION_ERROR, + _("Table '%s' not found"), table->table_name); + return FALSE; + } + table->validity_meta_object = dbo; + + return table->validity_meta_object ? TRUE : FALSE; +} + +void +_gda_sql_table_check_clean (GdaSqlTable *table) +{ + if (!table) return; + table->validity_meta_object = NULL; +} + +static gboolean +gda_sql_select_field_check_validity (GdaSqlSelectField *field, GdaSqlStatementCheckValidityData *data, GError **error) +{ + GValue value; + GdaMetaDbObject *dbo = NULL; + gboolean starred_field = FALSE; + + if (!field) return TRUE; + _gda_sql_select_field_check_clean (field); + + if (!field->field_name) + /* field is not a table.field */ + return TRUE; + + memset (&value, 0, sizeof (GValue)); + if (gda_identifier_equal (field->field_name, "*")) + starred_field = TRUE; + + if (!field->table_name) { + /* go through all the SELECT's targets to see if there is a table with the corresponding field */ + GdaSqlAnyPart *any; + GSList *targets; + GdaMetaTableColumn *tcol = NULL; + + for (any = GDA_SQL_ANY_PART(field)->parent; + any && (any->type != GDA_SQL_ANY_STMT_SELECT); + any = any->parent); + if (!any) { + g_set_error (error, GDA_SQL_ERROR, GDA_SQL_STRUCTURE_CONTENTS_ERROR, + "%s", _("GdaSqlSelectField is not part of a SELECT statement")); + return FALSE; + } + + if (((GdaSqlStatementSelect *)any)->from) { + for (targets = ((GdaSqlStatementSelect *)any)->from->targets; + targets; + targets = targets->next) { + GdaSqlSelectTarget *target = (GdaSqlSelectTarget *) targets->data; + if (!target->validity_meta_object && + !gda_sql_select_target_check_validity (target, data, error)) + return FALSE; + + g_value_set_string (g_value_init (&value, G_TYPE_STRING), field->field_name); + tcol = gda_meta_struct_get_table_column (data->mstruct, + GDA_META_TABLE (target->validity_meta_object), + &value); + g_value_unset (&value); + if (tcol) { + /* found a candidate */ + if (dbo) { + g_set_error (error, GDA_SQL_ERROR, GDA_SQL_VALIDATION_ERROR, + _("Could not identify table for field '%s'"), field->field_name); + return FALSE; + } + dbo = target->validity_meta_object; + } + } + if (!dbo) { + targets = ((GdaSqlStatementSelect *)any)->from->targets; + if (starred_field && targets && !targets->next) + /* only one target => it's the one */ + dbo = ((GdaSqlSelectTarget*) targets->data)->validity_meta_object; + } + } + if (!dbo) { + g_set_error (error, GDA_SQL_ERROR, GDA_SQL_VALIDATION_ERROR, + _("Could not identify table for field '%s'"), field->field_name); + return FALSE; + } + field->validity_meta_object = dbo; + field->validity_meta_table_column = tcol; + } + else { + /* table part */ + dbo = find_table_or_view ((GdaSqlAnyPart*) field, data, field->table_name, error); + if (dbo && (dbo->obj_type != GDA_META_DB_TABLE) && + (dbo->obj_type != GDA_META_DB_VIEW)) { + g_set_error (error, GDA_SQL_ERROR, GDA_SQL_VALIDATION_ERROR, + _("Table '%s' not found"), field->table_name); + return FALSE; + } + field->validity_meta_object = dbo; + if (!field->validity_meta_object) + return FALSE; + + /* field part */ + if (!gda_identifier_equal (field->field_name, "*")) { + GdaMetaTableColumn *tcol; + g_value_set_string (g_value_init (&value, G_TYPE_STRING), field->field_name); + tcol = gda_meta_struct_get_table_column (data->mstruct, + GDA_META_TABLE (field->validity_meta_object), + &value); + g_value_unset (&value); + field->validity_meta_table_column = tcol; + if (!tcol) { + g_set_error (error, GDA_SQL_ERROR, GDA_SQL_VALIDATION_ERROR, + _("Column '%s' not found"), field->field_name); + return FALSE; + } + } + } + return TRUE; +} + +void +_gda_sql_select_field_check_clean (GdaSqlSelectField *field) +{ + if (!field) return; + field->validity_meta_object = NULL; + field->validity_meta_table_column = NULL; +} + +static gboolean +gda_sql_select_target_check_validity (GdaSqlSelectTarget *target, GdaSqlStatementCheckValidityData *data, GError **error) +{ + GdaMetaDbObject *dbo; + if (!target || !target->table_name) + return TRUE; + + dbo = find_table_or_view ((GdaSqlAnyPart*) target, data, target->table_name, error); + if (dbo && (dbo->obj_type != GDA_META_DB_TABLE) && + (dbo->obj_type != GDA_META_DB_VIEW)) { + g_set_error (error, GDA_SQL_ERROR, GDA_SQL_VALIDATION_ERROR, + _("Table '%s' not found"), target->table_name); + return FALSE; + } + target->validity_meta_object = dbo; + return target->validity_meta_object ? TRUE : FALSE; +} + +void +_gda_sql_select_target_check_clean (GdaSqlSelectTarget *target) +{ + if (!target) return; + target->validity_meta_object = NULL; +} + + + +/** + * gda_sql_statement_check_clean + * @stmt: a pinter to a #GdaSqlStatement structure + * + * Cleans any data set by a previous call to gda_sql_statement_check_validity(). + */ +void +gda_sql_statement_check_clean (GdaSqlStatement *stmt) +{ + g_return_if_fail (stmt); + + if (stmt->validity_meta_struct) { + gda_sql_any_part_foreach (GDA_SQL_ANY_PART (stmt->contents), + (GdaSqlForeachFunc) foreach_check_clean, NULL, NULL); + g_object_unref (stmt->validity_meta_struct); + stmt->validity_meta_struct = NULL; + } +} + +static gboolean +foreach_check_clean (GdaSqlAnyPart *node, G_GNUC_UNUSED gpointer data, G_GNUC_UNUSED GError **error) +{ + if (!node) return TRUE; + + switch (node->type) { + case GDA_SQL_ANY_EXPR: + _gda_sql_expr_check_clean ((GdaSqlExpr*) node); + break; + case GDA_SQL_ANY_SQL_FIELD: + _gda_sql_field_check_clean ((GdaSqlField*) node); + break; + case GDA_SQL_ANY_SQL_TABLE: + _gda_sql_table_check_clean ((GdaSqlTable*) node); + break; + case GDA_SQL_ANY_SQL_SELECT_FIELD: + _gda_sql_select_field_check_clean ((GdaSqlSelectField*) node); + break; + case GDA_SQL_ANY_SQL_SELECT_TARGET: + _gda_sql_select_target_check_clean ((GdaSqlSelectTarget*) node); + break; + default: + break; + } + + return TRUE; +} + +static gboolean foreach_check_struct (GdaSqlAnyPart *node, gpointer data, GError **error); + +/** + * gda_sql_statement_check_structure + * @stmt: a #GdaSqlStatement pointer + * @error: a place to store errors, or %NULL + * + * Checks for any error in @stmt's structure to make sure the statement is valid + * (for example a SELECT statement must at least return a column, a DELETE statement must specify which table + * is targeted). + * + * Returns: TRUE if no error occurred + */ +gboolean +gda_sql_statement_check_structure (GdaSqlStatement *stmt, GError **error) +{ + g_return_val_if_fail (stmt, FALSE); + + return gda_sql_any_part_foreach (GDA_SQL_ANY_PART (stmt->contents), + (GdaSqlForeachFunc) foreach_check_struct, NULL, error); +} + +static gboolean +foreach_check_struct (GdaSqlAnyPart *node, G_GNUC_UNUSED gpointer data, GError **error) +{ + return gda_sql_any_part_check_structure (node, error); +} + +/** + * gda_sql_any_part_check_structure + * @node: a #GdaSqlAnyPart pointer + * @error: a place to store errors, or %NULL + * + * Checks for any error in @node's structure to make sure it is valid. This + * is the same as gda_sql_statement_check_structure() but for individual #GdaSqlAnyPart + * parts. This function is mainly for database provider's implementations + * + * Returns: TRUE if no error occurred + */ +gboolean +gda_sql_any_part_check_structure (GdaSqlAnyPart *node, GError **error) +{ + if (!node) return TRUE; + + switch (node->type) { + case GDA_SQL_ANY_STMT_SELECT: + case GDA_SQL_ANY_STMT_INSERT: + case GDA_SQL_ANY_STMT_UPDATE: + case GDA_SQL_ANY_STMT_DELETE: + case GDA_SQL_ANY_STMT_COMPOUND: + case GDA_SQL_ANY_STMT_BEGIN: + case GDA_SQL_ANY_STMT_ROLLBACK: + case GDA_SQL_ANY_STMT_COMMIT: + case GDA_SQL_ANY_STMT_SAVEPOINT: + case GDA_SQL_ANY_STMT_ROLLBACK_SAVEPOINT: + case GDA_SQL_ANY_STMT_DELETE_SAVEPOINT: + case GDA_SQL_ANY_STMT_UNKNOWN: { + GdaSqlStatementContentsInfo *cinfo; + cinfo = gda_sql_statement_get_contents_infos ((GdaSqlStatementType) node->type); + if (cinfo->check_structure_func) + return cinfo->check_structure_func (node, NULL, error); + break; + } + case GDA_SQL_ANY_EXPR: { + GdaSqlExpr *expr = (GdaSqlExpr*) node; + if (expr->cast_as && expr->param_spec) { + g_set_error (error, GDA_SQL_ERROR, GDA_SQL_STRUCTURE_CONTENTS_ERROR, + "%s", _("Expression can't have both a type cast and a parameter specification")); + return FALSE; + } + break; + } + case GDA_SQL_ANY_SQL_FIELD: { + GdaSqlField *field = (GdaSqlField*) node; + if (!_string_is_identifier (field->field_name)) { + if (field->field_name) + g_set_error (error, GDA_SQL_ERROR, GDA_SQL_MALFORMED_IDENTIFIER_ERROR, + _("'%s' is not a valid identifier"), field->field_name); + else + g_set_error (error, GDA_SQL_ERROR, GDA_SQL_MALFORMED_IDENTIFIER_ERROR, + "%s", _("Empty identifier")); + return FALSE; + } + break; + } + case GDA_SQL_ANY_SQL_TABLE: { + GdaSqlTable *table = (GdaSqlTable*) node; + if (!_string_is_identifier (table->table_name)) { + if (table->table_name) + g_set_error (error, GDA_SQL_ERROR, GDA_SQL_MALFORMED_IDENTIFIER_ERROR, + _("'%s' is not a valid identifier"), table->table_name); + else + g_set_error (error, GDA_SQL_ERROR, GDA_SQL_MALFORMED_IDENTIFIER_ERROR, + "%s", _("Empty identifier")); + return FALSE; + } + break; + } + case GDA_SQL_ANY_SQL_FUNCTION: { + GdaSqlFunction *function = (GdaSqlFunction*) node; + if (!_string_is_identifier (function->function_name)) { + if (function->function_name) + g_set_error (error, GDA_SQL_ERROR, GDA_SQL_MALFORMED_IDENTIFIER_ERROR, + _("'%s' is not a valid identifier"), function->function_name); + else + g_set_error (error, GDA_SQL_ERROR, GDA_SQL_MALFORMED_IDENTIFIER_ERROR, + "%s", _("Empty identifier")); + return FALSE; + } + break; + } + case GDA_SQL_ANY_SQL_OPERATION: { + GdaSqlOperation *operation = (GdaSqlOperation*) node; + if (!operation->operands) { + g_set_error (error, GDA_SQL_ERROR, GDA_SQL_STRUCTURE_CONTENTS_ERROR, + "%s", _("Operation has no operand")); + return FALSE; + } + switch (operation->operator_type) { + case GDA_SQL_OPERATOR_TYPE_EQ: + case GDA_SQL_OPERATOR_TYPE_IS: + case GDA_SQL_OPERATOR_TYPE_LIKE: + case GDA_SQL_OPERATOR_TYPE_NOTLIKE: + case GDA_SQL_OPERATOR_TYPE_ILIKE: + case GDA_SQL_OPERATOR_TYPE_NOTILIKE: + case GDA_SQL_OPERATOR_TYPE_GT: + case GDA_SQL_OPERATOR_TYPE_LT: + case GDA_SQL_OPERATOR_TYPE_GEQ: + case GDA_SQL_OPERATOR_TYPE_LEQ: + case GDA_SQL_OPERATOR_TYPE_DIFF: + case GDA_SQL_OPERATOR_TYPE_REGEXP: + case GDA_SQL_OPERATOR_TYPE_REGEXP_CI: + case GDA_SQL_OPERATOR_TYPE_NOT_REGEXP: + case GDA_SQL_OPERATOR_TYPE_NOT_REGEXP_CI: + case GDA_SQL_OPERATOR_TYPE_SIMILAR: + case GDA_SQL_OPERATOR_TYPE_REM: + case GDA_SQL_OPERATOR_TYPE_DIV: + case GDA_SQL_OPERATOR_TYPE_BITAND: + case GDA_SQL_OPERATOR_TYPE_BITOR: + if (g_slist_length (operation->operands) != 2) { + g_set_error (error, GDA_SQL_ERROR, GDA_SQL_STRUCTURE_CONTENTS_ERROR, + "%s", _("Wrong number of operands")); + return FALSE; + } + break; + case GDA_SQL_OPERATOR_TYPE_BETWEEN: + if (g_slist_length (operation->operands) != 3) { + g_set_error (error, GDA_SQL_ERROR, GDA_SQL_STRUCTURE_CONTENTS_ERROR, + "%s", _("Wrong number of operands")); + return FALSE; + } + break; + case GDA_SQL_OPERATOR_TYPE_BITNOT: + case GDA_SQL_OPERATOR_TYPE_ISNULL: + case GDA_SQL_OPERATOR_TYPE_ISNOTNULL: + case GDA_SQL_OPERATOR_TYPE_NOT: + if (g_slist_length (operation->operands) != 1) { + g_set_error (error, GDA_SQL_ERROR, GDA_SQL_STRUCTURE_CONTENTS_ERROR, + "%s", _("Wrong number of operands")); + return FALSE; + } + break; + case GDA_SQL_OPERATOR_TYPE_AND: + case GDA_SQL_OPERATOR_TYPE_OR: + case GDA_SQL_OPERATOR_TYPE_IN: + case GDA_SQL_OPERATOR_TYPE_NOTIN: + case GDA_SQL_OPERATOR_TYPE_CONCAT: + case GDA_SQL_OPERATOR_TYPE_STAR: + if (g_slist_length (operation->operands) < 2) { + g_set_error (error, GDA_SQL_ERROR, GDA_SQL_STRUCTURE_CONTENTS_ERROR, + "%s", _("Wrong number of operands")); + return FALSE; + } + break; + case GDA_SQL_OPERATOR_TYPE_MINUS: + case GDA_SQL_OPERATOR_TYPE_PLUS: + if (g_slist_length (operation->operands) == 0) { + g_set_error (error, GDA_SQL_ERROR, GDA_SQL_STRUCTURE_CONTENTS_ERROR, + "%s", _("Wrong number of operands")); + return FALSE; + } + break; + default: + g_set_error (error, GDA_SQL_ERROR, GDA_SQL_STRUCTURE_CONTENTS_ERROR, + _("Unknown operator %d"), operation->operator_type); + return FALSE; + } + break; + } + case GDA_SQL_ANY_SQL_CASE: { + GdaSqlCase *sc = (GdaSqlCase*) node; + if (g_slist_length (sc->when_expr_list) != g_slist_length (sc->then_expr_list)) { + g_set_error (error, GDA_SQL_ERROR, GDA_SQL_STRUCTURE_CONTENTS_ERROR, + "%s", "Number of WHEN is not the same as number of THEN in CASE expression"); + return FALSE; + } + if (!sc->when_expr_list) { + g_set_error (error, GDA_SQL_ERROR, GDA_SQL_STRUCTURE_CONTENTS_ERROR, + "%s", "CASE expression must have at least one WHEN ... THEN element"); + return FALSE; + } + break; + } + case GDA_SQL_ANY_SQL_SELECT_FIELD: { + GdaSqlSelectField *field = (GdaSqlSelectField*) node; + if (!field->expr) { + g_set_error (error, GDA_SQL_ERROR, GDA_SQL_STRUCTURE_CONTENTS_ERROR, + "%s", _("Missing expression in select field")); + return FALSE; + } + break; + } + case GDA_SQL_ANY_SQL_SELECT_TARGET: { + GdaSqlSelectTarget *target = (GdaSqlSelectTarget*) node; + if (!target->expr) { + g_set_error (error, GDA_SQL_ERROR, GDA_SQL_STRUCTURE_CONTENTS_ERROR, + "%s", _("Missing expression in select target")); + return FALSE; + } + break; + } + case GDA_SQL_ANY_SQL_SELECT_JOIN: { + GdaSqlSelectJoin *join = (GdaSqlSelectJoin*) node; + if (join->expr && join->use) { + g_set_error (error, GDA_SQL_ERROR, GDA_SQL_STRUCTURE_CONTENTS_ERROR, + "%s", _("Join can't at the same time specify a join condition and a list of fields to join on")); + return FALSE; + } + if ((join->type == GDA_SQL_SELECT_JOIN_CROSS) && (join->expr || join->use)) { + g_set_error (error, GDA_SQL_ERROR, GDA_SQL_STRUCTURE_CONTENTS_ERROR, + "%s", _("Cross join can't have a join condition or a list of fields to join on")); + return FALSE; + } + break; + } + case GDA_SQL_ANY_SQL_SELECT_FROM: { + GdaSqlSelectFrom *from = (GdaSqlSelectFrom*) node; + if (!from->targets) { + g_set_error (error, GDA_SQL_ERROR, GDA_SQL_STRUCTURE_CONTENTS_ERROR, + "%s", _("Empty FROM clause")); + return FALSE; + } + break; + } + case GDA_SQL_ANY_SQL_SELECT_ORDER: { + GdaSqlSelectOrder *order = (GdaSqlSelectOrder*) node; + if (!order->expr) { + g_set_error (error, GDA_SQL_ERROR, GDA_SQL_STRUCTURE_CONTENTS_ERROR, + "%s", "ORDER BY expression must have an expression"); + return FALSE; + } + break; + } + + default: + break; + } + + return TRUE; +} + +/** + * gda_sql_any_part_foreach: + * @node: the stat node + * @func: (scope call): function to call for each sub node + * @data: (closure): data to pass to @func each time it is called + * @error: a place to store errors, or %NULL (is also passed to @func) + * + * Calls a function for each element of a #GdaSqlAnyPart node + * + * Returns: TRUE if @func has been called for any sub node of @node and always returned TRUE, or FALSE + * otherwise. + */ +gboolean +gda_sql_any_part_foreach (GdaSqlAnyPart *node, GdaSqlForeachFunc func, gpointer data, GError **error) +{ + GSList *l; + if (!node) return TRUE; + + /* call @func for the node's contents */ + switch (node->type) { + case GDA_SQL_ANY_STMT_BEGIN: + case GDA_SQL_ANY_STMT_ROLLBACK: + case GDA_SQL_ANY_STMT_COMMIT: + case GDA_SQL_ANY_STMT_SAVEPOINT: + case GDA_SQL_ANY_STMT_ROLLBACK_SAVEPOINT: + case GDA_SQL_ANY_STMT_DELETE_SAVEPOINT: + case GDA_SQL_ANY_SQL_FIELD: + case GDA_SQL_ANY_SQL_TABLE: + /* nothing to do */ + break; + case GDA_SQL_ANY_STMT_SELECT: { + GdaSqlStatementSelect *stmt = (GdaSqlStatementSelect*) node; + if (!gda_sql_any_part_foreach (GDA_SQL_ANY_PART (stmt->distinct_expr), func, data, error)) + return FALSE; + for (l = stmt->expr_list; l; l = l->next) + if (!gda_sql_any_part_foreach (GDA_SQL_ANY_PART (l->data), func, data, error)) + return FALSE; + if (!gda_sql_any_part_foreach (GDA_SQL_ANY_PART (stmt->from), func, data, error)) + return FALSE; + if (!gda_sql_any_part_foreach (GDA_SQL_ANY_PART (stmt->where_cond), func, data, error)) + return FALSE; + for (l = stmt->group_by; l; l = l->next) + if (!gda_sql_any_part_foreach (GDA_SQL_ANY_PART (l->data), func, data, error)) + return FALSE; + if (!gda_sql_any_part_foreach (GDA_SQL_ANY_PART (stmt->having_cond), func, data, error)) + return FALSE; + for (l = stmt->order_by; l; l = l->next) + if (!gda_sql_any_part_foreach (GDA_SQL_ANY_PART (l->data), func, data, error)) + return FALSE; + if (!gda_sql_any_part_foreach (GDA_SQL_ANY_PART (stmt->limit_count), func, data, error)) + return FALSE; + if (!gda_sql_any_part_foreach (GDA_SQL_ANY_PART (stmt->limit_offset), func, data, error)) + return FALSE; + break; + } + case GDA_SQL_ANY_STMT_INSERT: { + GdaSqlStatementInsert *stmt = (GdaSqlStatementInsert*) node; + if (!gda_sql_any_part_foreach (GDA_SQL_ANY_PART (stmt->table), func, data, error)) + return FALSE; + for (l = stmt->fields_list; l; l = l->next) + if (!gda_sql_any_part_foreach (GDA_SQL_ANY_PART (l->data), func, data, error)) + return FALSE; + for (l = stmt->values_list; l; l = l->next) { + GSList *sl; + for (sl = (GSList *) l->data; sl; sl = sl->next) { + if (!gda_sql_any_part_foreach (GDA_SQL_ANY_PART (sl->data), func, data, error)) + return FALSE; + } + } + if (!gda_sql_any_part_foreach (GDA_SQL_ANY_PART (stmt->select), func, data, error)) + return FALSE; + break; + } + case GDA_SQL_ANY_STMT_UPDATE: { + GdaSqlStatementUpdate *stmt = (GdaSqlStatementUpdate*) node; + if (!gda_sql_any_part_foreach (GDA_SQL_ANY_PART (stmt->table), func, data, error)) + return FALSE; + for (l = stmt->fields_list; l; l = l->next) + if (!gda_sql_any_part_foreach (GDA_SQL_ANY_PART (l->data), func, data, error)) + return FALSE; + for (l = stmt->expr_list; l; l = l->next) + if (!gda_sql_any_part_foreach (GDA_SQL_ANY_PART (l->data), func, data, error)) + return FALSE; + if (!gda_sql_any_part_foreach (GDA_SQL_ANY_PART (stmt->cond), func, data, error)) + return FALSE; + break; + } + case GDA_SQL_ANY_STMT_DELETE: { + GdaSqlStatementDelete *stmt = (GdaSqlStatementDelete*) node; + if (!gda_sql_any_part_foreach (GDA_SQL_ANY_PART (stmt->table), func, data, error)) + return FALSE; + if (!gda_sql_any_part_foreach (GDA_SQL_ANY_PART (stmt->cond), func, data, error)) + return FALSE; + break; + } + case GDA_SQL_ANY_STMT_COMPOUND: { + GdaSqlStatementCompound *stmt = (GdaSqlStatementCompound*) node; + for (l = stmt->stmt_list; l; l = l->next) + if (!gda_sql_any_part_foreach (GDA_SQL_ANY_PART (((GdaSqlStatement*) l->data)->contents), + func, data, error)) + return FALSE; + break; + } + case GDA_SQL_ANY_STMT_UNKNOWN: { + GdaSqlStatementUnknown *stmt = (GdaSqlStatementUnknown*) node; + for (l = stmt->expressions; l; l = l->next) + if (!gda_sql_any_part_foreach (GDA_SQL_ANY_PART (l->data), func, data, error)) + return FALSE; + break; + } + + /* individual parts */ + case GDA_SQL_ANY_EXPR: { + GdaSqlExpr *expr = (GdaSqlExpr*) node; + if (!gda_sql_any_part_foreach (GDA_SQL_ANY_PART (expr->func), func, data, error)) + return FALSE; + if (!gda_sql_any_part_foreach (GDA_SQL_ANY_PART (expr->cond), func, data, error)) + return FALSE; + if (!gda_sql_any_part_foreach (GDA_SQL_ANY_PART (expr->select), func, data, error)) + return FALSE; + if (!gda_sql_any_part_foreach (GDA_SQL_ANY_PART (expr->case_s), func, data, error)) + return FALSE; + break; + } + case GDA_SQL_ANY_SQL_FUNCTION: { + GdaSqlFunction *function = (GdaSqlFunction *) node; + for (l = function->args_list; l; l = l->next) + if (!gda_sql_any_part_foreach (GDA_SQL_ANY_PART (l->data), func, data, error)) + return FALSE; + break; + } + case GDA_SQL_ANY_SQL_OPERATION: { + GdaSqlOperation *operation = (GdaSqlOperation *) node; + for (l = operation->operands; l; l = l->next) + if (!gda_sql_any_part_foreach (GDA_SQL_ANY_PART (l->data), func, data, error)) + return FALSE; + break; + } + case GDA_SQL_ANY_SQL_CASE: { + GdaSqlCase *sc = (GdaSqlCase*) node; + if (!gda_sql_any_part_foreach (GDA_SQL_ANY_PART (sc->base_expr), func, data, error)) + return FALSE; + for (l = sc->when_expr_list; l; l = l->next) + if (!gda_sql_any_part_foreach (GDA_SQL_ANY_PART (l->data), func, data, error)) + return FALSE; + for (l = sc->then_expr_list; l; l = l->next) + if (!gda_sql_any_part_foreach (GDA_SQL_ANY_PART (l->data), func, data, error)) + return FALSE; + if (!gda_sql_any_part_foreach (GDA_SQL_ANY_PART (sc->else_expr), func, data, error)) + return FALSE; + break; + } + case GDA_SQL_ANY_SQL_SELECT_FIELD: { + GdaSqlSelectField *field = (GdaSqlSelectField *) node; + if (!gda_sql_any_part_foreach (GDA_SQL_ANY_PART (field->expr), func, data, error)) + return FALSE; + break; + } + case GDA_SQL_ANY_SQL_SELECT_TARGET: { + GdaSqlSelectTarget *target = (GdaSqlSelectTarget *) node; + if (!gda_sql_any_part_foreach (GDA_SQL_ANY_PART (target->expr), func, data, error)) + return FALSE; + break; + } + case GDA_SQL_ANY_SQL_SELECT_JOIN: { + GdaSqlSelectJoin *join = (GdaSqlSelectJoin *) node; + if (!gda_sql_any_part_foreach (GDA_SQL_ANY_PART (join->expr), func, data, error)) + return FALSE; + for (l = join->use; l; l = l->next) + if (!gda_sql_any_part_foreach (GDA_SQL_ANY_PART (l->data), func, data, error)) + return FALSE; + break; + } + case GDA_SQL_ANY_SQL_SELECT_FROM: { + GdaSqlSelectFrom *from = (GdaSqlSelectFrom *) node; + for (l = from->targets; l; l = l->next) + if (!gda_sql_any_part_foreach (GDA_SQL_ANY_PART (l->data), func, data, error)) + return FALSE; + for (l = from->joins; l; l = l->next) + if (!gda_sql_any_part_foreach (GDA_SQL_ANY_PART (l->data), func, data, error)) + return FALSE; + break; + } + case GDA_SQL_ANY_SQL_SELECT_ORDER: { + GdaSqlSelectOrder *order = (GdaSqlSelectOrder *) node; + if (!gda_sql_any_part_foreach (GDA_SQL_ANY_PART (order->expr), func, data, error)) + return FALSE; + break; + } + default: + g_assert_not_reached (); + } + + /* finally call @func for this node */ + return func (node, data, error); +} + + +static gboolean foreach_normalize (GdaSqlAnyPart *node, GdaConnection *cnc, GError **error); + +/** + * gda_sql_statement_normalize: + * @stmt: a pointer to a #GdaSqlStatement structure + * @cnc: (nullable): a #GdaConnection object, or %NULL + * @error: a place to store errors, or %NULL + * + * "Normalizes" (in place) some parts of @stmt, which means @stmt may be modified. + * At the moment any "*" field in a SELECT statement will be replaced by one + * #GdaSqlSelectField structure for each field in the referenced table. + * + * Returns: TRUE if no error occurred + */ +gboolean +gda_sql_statement_normalize (GdaSqlStatement *stmt, GdaConnection *cnc, GError **error) +{ + gboolean retval; + g_return_val_if_fail (stmt, FALSE); + + if (!stmt->validity_meta_struct && !gda_sql_statement_check_validity (stmt, cnc, error)) + return FALSE; + + retval = gda_sql_any_part_foreach (GDA_SQL_ANY_PART (stmt->contents), + (GdaSqlForeachFunc) foreach_normalize, cnc, error); +#ifdef GDA_DEBUG + GError *lerror = NULL; + if (retval && !gda_sql_statement_check_validity (stmt, cnc, &lerror)) { + g_warning ("Internal error in %s(): statement is not valid anymore after: %s", __FUNCTION__, + lerror && lerror->message ? lerror->message : "No detail"); + if (lerror) + g_error_free (lerror); + } +#endif + return retval; +} + +static gboolean +foreach_normalize (GdaSqlAnyPart *node, G_GNUC_UNUSED GdaConnection *cnc, GError **error) +{ + if (!node) return TRUE; + + if (node->type == GDA_SQL_ANY_SQL_SELECT_FIELD) { + GdaSqlSelectField *field = (GdaSqlSelectField*) node; + if (((field->field_name && gda_identifier_equal (field->field_name, "*")) || + (field->expr && field->expr->value && (G_VALUE_TYPE (field->expr->value) == G_TYPE_STRING) && + gda_identifier_equal (g_value_get_string (field->expr->value), "*"))) && + field->validity_meta_object) { + /* expand * to all the fields */ + GdaMetaTable *mtable = GDA_META_TABLE (field->validity_meta_object); + GSList *list; + GdaSqlAnyPart *parent_node = ((GdaSqlAnyPart*) field)->parent; + gint nodepos = g_slist_index (((GdaSqlStatementSelect*) parent_node)->expr_list, node); + if (parent_node->type != GDA_SQL_ANY_STMT_SELECT) { + g_set_error (error, GDA_SQL_ERROR, GDA_SQL_STRUCTURE_CONTENTS_ERROR, + "%s", _("Select field is not in a SELECT statement")); + return FALSE; + } + for (list = mtable->columns; list; list = list->next) { + GdaSqlSelectField *nfield; + GdaMetaTableColumn *tcol = (GdaMetaTableColumn *) list->data; + + nfield = gda_sql_select_field_new (parent_node); + nfield->field_name = g_strdup (tcol->column_name); + if (field->table_name) + nfield->table_name = g_strdup (field->table_name); + nfield->validity_meta_object = field->validity_meta_object; + nfield->validity_meta_table_column = tcol; + nfield->expr = gda_sql_expr_new ((GdaSqlAnyPart*) nfield); + nfield->expr->value = gda_value_new (G_TYPE_STRING); + if (field->table_name) + g_value_take_string (nfield->expr->value, g_strdup_printf ("%s.%s", + nfield->table_name, + nfield->field_name)); + else + g_value_set_string (nfield->expr->value, nfield->field_name); + + /* insert nfield into expr_list */ + GSList *expr_list = ((GdaSqlStatementSelect*) parent_node)->expr_list; + if (list == mtable->columns) { + GSList *lnode = g_slist_nth (expr_list, nodepos); + lnode->data = nfield; + } + else + ((GdaSqlStatementSelect*) parent_node)->expr_list = + g_slist_insert (expr_list, nfield, ++nodepos); + } + /* get rid of @field */ + gda_sql_select_field_free (field); + } + } + + return TRUE; +} + +/* GdaSql* definitions */ + + +GdaSqlAnyPart* +gda_sql_any_part_copy (GdaSqlAnyPart *src) { + GdaSqlAnyPart *cp = g_new0(GdaSqlAnyPart, 1); + cp->type = src->type; + cp->parent = src->parent; + return cp; +} +void +gda_sql_any_part_free (GdaSqlAnyPart *anyp) { + g_free (anyp); +} + +G_DEFINE_BOXED_TYPE(GdaSqlAnyPart, gda_sql_any_part, gda_sql_any_part_copy, gda_sql_any_part_free) + diff --git a/.flatpak-builder/cache/objects/28/4b1c444d9ba36f8d3bdfe0cccd4c3a05d6adef589d669283aa27f77bf7cbd0.dirtree b/.flatpak-builder/cache/objects/28/4b1c444d9ba36f8d3bdfe0cccd4c3a05d6adef589d669283aa27f77bf7cbd0.dirtree new file mode 100644 index 0000000..4a8fecd Binary files /dev/null and b/.flatpak-builder/cache/objects/28/4b1c444d9ba36f8d3bdfe0cccd4c3a05d6adef589d669283aa27f77bf7cbd0.dirtree differ diff --git a/.flatpak-builder/cache/objects/28/97a1fad5f0e1d3ce00744b29771a59d8f2e42ed8d8c5c49fbe1e78e86aa900.dirtree b/.flatpak-builder/cache/objects/28/97a1fad5f0e1d3ce00744b29771a59d8f2e42ed8d8c5c49fbe1e78e86aa900.dirtree new file mode 100644 index 0000000..1d04d37 Binary files /dev/null and b/.flatpak-builder/cache/objects/28/97a1fad5f0e1d3ce00744b29771a59d8f2e42ed8d8c5c49fbe1e78e86aa900.dirtree differ diff --git a/.flatpak-builder/cache/objects/28/9b9c6782744afc6ce6c2a608fa334d52a67e80730872bb08768e6a77f8189c.dirtree b/.flatpak-builder/cache/objects/28/9b9c6782744afc6ce6c2a608fa334d52a67e80730872bb08768e6a77f8189c.dirtree new file mode 100644 index 0000000..fc3a5f4 Binary files /dev/null and b/.flatpak-builder/cache/objects/28/9b9c6782744afc6ce6c2a608fa334d52a67e80730872bb08768e6a77f8189c.dirtree differ diff --git a/.flatpak-builder/cache/objects/29/3f2c63e4a5c24ab2499cc1e979a1c83147870ef4bbdd919eec89abcc51ee58.file b/.flatpak-builder/cache/objects/29/3f2c63e4a5c24ab2499cc1e979a1c83147870ef4bbdd919eec89abcc51ee58.file new file mode 100644 index 0000000..ecc076d --- /dev/null +++ b/.flatpak-builder/cache/objects/29/3f2c63e4a5c24ab2499cc1e979a1c83147870ef4bbdd919eec89abcc51ee58.file @@ -0,0 +1,3 @@ +Name: blueprint-compiler +Description: Markup compiler for GTK user interface definitions +Version: 0.8.1 diff --git a/.flatpak-builder/cache/objects/29/dabb449e11a839f05f73708fccea24dcf50ae37d31a98665f8dfee7471b2fb.file b/.flatpak-builder/cache/objects/29/dabb449e11a839f05f73708fccea24dcf50ae37d31a98665f8dfee7471b2fb.file new file mode 100644 index 0000000..0acec19 --- /dev/null +++ b/.flatpak-builder/cache/objects/29/dabb449e11a839f05f73708fccea24dcf50ae37d31a98665f8dfee7471b2fb.file @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2008 - 2011 Vivien Malerba + * Copyright (C) 2009 Murray Cumming + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef _GDA_STATEMENT_STRUCT_INSERT_H_ +#define _GDA_STATEMENT_STRUCT_INSERT_H_ + +#include +#include +#include +#include +#include + +G_BEGIN_DECLS + +/* + * Structure definition + */ +/** + * GdaSqlStatementInsert: + * @any: inheritance structure + * @on_conflict: conflict resolution clause if there is one (such as "OR REPLACE") + * @table: name of the table to which data is inserted + * @fields_list: list of #GdaSqlField fields which are valued for insertion + * @values_list: list of list of #GdaSqlExpr expressions (this is a list of list, not a simple list) + * @select: a #GdaSqlStatementSelect or #GdaSqlStatementCompound structure representing the values to insert + * + * The statement is an INSERT statement, any kind of INSERT statement can be represented using this structure + * (if this is not the case + * then report a bug). + * + * + * + * + * + * + * Example of a #GdaSqlStatement having a #GdaSqlStatementInsert as its contents with 2 lists of values + * to insert. + * + * + * + * + * + * + * + * + * + * Another example of a #GdaSqlStatement having a #GdaSqlStatementInsert as its contents, using a SELECT + * to express the values to insert. + * + * + * + */ +struct _GdaSqlStatementInsert { + GdaSqlAnyPart any; + gchar *on_conflict; /* conflict resolution clause */ + GdaSqlTable *table; + GSList *fields_list; /* list of GdaSqlField structures */ + GSList *values_list; /* list of list of GdaSqlExpr */ + GdaSqlAnyPart *select; /* SELECT OR COMPOUND statements: GdaSqlStatementSelect or GdaSqlStatementCompound */ + + /*< private >*/ + /* Padding for future expansion */ + gpointer _gda_reserved1; + gpointer _gda_reserved2; +}; + +/* + * Common operations + */ +GdaSqlStatementContentsInfo *_gda_sql_statement_insert_get_infos (void); + +/* + * Functions used by the parser + */ +void gda_sql_statement_insert_take_table_name (GdaSqlStatement *stmt, GValue *value); +void gda_sql_statement_insert_take_on_conflict (GdaSqlStatement *stmt, GValue *value); +void gda_sql_statement_insert_take_fields_list (GdaSqlStatement *stmt, GSList *list); +void gda_sql_statement_insert_take_1_values_list (GdaSqlStatement *stmt, GSList *list); +void gda_sql_statement_insert_take_extra_values_list (GdaSqlStatement *stmt, GSList *list); + +void gda_sql_statement_insert_take_select (GdaSqlStatement *stmt, GdaSqlStatement *select); + +G_END_DECLS + +#endif diff --git a/.flatpak-builder/cache/objects/2a/426e8b9582aaba7a8f9acde9a96e345178a82168afaed4606027cb5dcc2307.file b/.flatpak-builder/cache/objects/2a/426e8b9582aaba7a8f9acde9a96e345178a82168afaed4606027cb5dcc2307.file new file mode 100644 index 0000000..3702847 --- /dev/null +++ b/.flatpak-builder/cache/objects/2a/426e8b9582aaba7a8f9acde9a96e345178a82168afaed4606027cb5dcc2307.file @@ -0,0 +1,28 @@ +/*-*- Mode: C; c-basic-offset: 8 -*-*/ + +#ifndef foocanberradriverorderhfoo +#define foocanberradriverorderhfoo + +/*** + This file is part of libcanberra. + + Copyright 2008 Lennart Poettering + + libcanberra is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation, either version 2.1 of the + License, or (at your option) any later version. + + libcanberra is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with libcanberra. If not, see + . +***/ + +extern const char* const ca_driver_order[]; + +#endif diff --git a/.flatpak-builder/cache/objects/2a/72b10ad7933c41dc473fabbc160e0780270fa56aaaa1d27eb625e68667db60.file b/.flatpak-builder/cache/objects/2a/72b10ad7933c41dc473fabbc160e0780270fa56aaaa1d27eb625e68667db60.file new file mode 100644 index 0000000..e511b59 --- /dev/null +++ b/.flatpak-builder/cache/objects/2a/72b10ad7933c41dc473fabbc160e0780270fa56aaaa1d27eb625e68667db60.file @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2014 Vivien Malerba + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GDA_CONNECT_H__ +#define __GDA_CONNECT_H__ + +#include + +G_BEGIN_DECLS + +/** + * SECTION:gda-connect + * @short_description: Inter thread signal propagation + * @title: GdaConnect + * @stability: Stable + * @see_also: + * + * The purpose of the gda_signal_connect() is to allow one to connect to a signal emitted by an object and be sure that + * the acutal signal handling will occur _only_ when running a specific #GMainContext. The gda_signal_handler_disconnect() actually + * disconnects the handler. + * + * Use these functions for exemple when you need to handle signals from objects which are emitted from within a thread + * which is not the main UI thread. + * + * These function implement their own locking mechanism and can safely be used from multiple + * threads at once without needing further locking. + */ + +gulong gda_signal_connect (gpointer instance, + const gchar *detailed_signal, + GCallback c_handler, + gpointer data, + GClosureNotify destroy_data, + GConnectFlags connect_flags, + GMainContext *context); + +void gda_signal_handler_disconnect (gpointer instance, + gulong handler_id); + +G_END_DECLS + +#endif diff --git a/.flatpak-builder/cache/objects/2a/b0631c63f1cf161ac757428eaa2fac9c07ab2bb5df23434677b17001f7705a.dirtree b/.flatpak-builder/cache/objects/2a/b0631c63f1cf161ac757428eaa2fac9c07ab2bb5df23434677b17001f7705a.dirtree new file mode 100644 index 0000000..13495b2 Binary files /dev/null and b/.flatpak-builder/cache/objects/2a/b0631c63f1cf161ac757428eaa2fac9c07ab2bb5df23434677b17001f7705a.dirtree differ diff --git a/.flatpak-builder/cache/objects/2a/da0464a675a477b65f54396e3260b02ce0a1f910d9620a2e30ebfa1bea7c0c.file b/.flatpak-builder/cache/objects/2a/da0464a675a477b65f54396e3260b02ce0a1f910d9620a2e30ebfa1bea7c0c.file new file mode 100644 index 0000000..e9fddab --- /dev/null +++ b/.flatpak-builder/cache/objects/2a/da0464a675a477b65f54396e3260b02ce0a1f910d9620a2e30ebfa1bea7c0c.file @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2019 Daniel Espinosa + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GDA_HANDLER_TEXT__ +#define __GDA_HANDLER_TEXT__ + +#include +#include + +G_BEGIN_DECLS + +/** + * SECTION:gda-handler-text + * @short_description: Default handler for large string values + * @title: GdaHanderText + * @stability: Stable + * @see_also: #GdaDataHandler interface + * + * You should normally not need to use this API, refer to the #GdaDataHandler + * interface documentation for more information. + */ + + +#define GDA_TYPE_HANDLER_TEXT (gda_handler_text_get_type()) + +G_DECLARE_DERIVABLE_TYPE(GdaHandlerText, gda_handler_text, GDA, HANDLER_TEXT, GObject) + +struct _GdaHandlerTextClass +{ + GObjectClass parent_class; +}; + +GdaDataHandler *gda_handler_text_new (void); +GdaDataHandler *gda_handler_text_new_with_connection (GdaConnection *cnc); + +G_END_DECLS + +#endif diff --git a/.flatpak-builder/cache/objects/2a/f18f4722c487bff8f0086bbe54134c73a36a43fdc6c1e2d7504cbda7ec193b.file b/.flatpak-builder/cache/objects/2a/f18f4722c487bff8f0086bbe54134c73a36a43fdc6c1e2d7504cbda7ec193b.file new file mode 100644 index 0000000..7e8c392 --- /dev/null +++ b/.flatpak-builder/cache/objects/2a/f18f4722c487bff8f0086bbe54134c73a36a43fdc6c1e2d7504cbda7ec193b.file @@ -0,0 +1,194 @@ +/* + * Copyright (C) 2008 - 2011 Vivien Malerba + * Copyright (C) 2013 Daniel Espinosa + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + + +#ifndef __GDA_SQL_PARSER_H_ +#define __GDA_SQL_PARSER_H_ + +#include +#include +#include +#include +#include + +G_BEGIN_DECLS + +/* error reporting */ +extern GQuark gda_sql_parser_error_quark (void); +#define GDA_SQL_PARSER_ERROR gda_sql_parser_error_quark () + +typedef enum +{ + GDA_SQL_PARSER_SYNTAX_ERROR, + GDA_SQL_PARSER_OVERFLOW_ERROR, + GDA_SQL_PARSER_EMPTY_SQL_ERROR +} GdaSqlParserError; + +typedef enum { + GDA_SQL_PARSER_MODE_PARSE, + GDA_SQL_PARSER_MODE_DELIMIT +} GdaSqlParserMode; + +typedef enum { + GDA_SQL_PARSER_FLAVOUR_STANDARD = 0, + GDA_SQL_PARSER_FLAVOUR_SQLITE = 1, + GDA_SQL_PARSER_FLAVOUR_MYSQL = 2, + GDA_SQL_PARSER_FLAVOUR_ORACLE = 3, + GDA_SQL_PARSER_FLAVOUR_POSTGRESQL = 4 +} GdaSqlParserFlavour; + +/* interface with the Lemon parser */ +typedef struct _GdaSqlParserIface +{ + GdaSqlParser *parser; + GdaSqlStatement *parsed_statement; + + /*< private >*/ + /* Padding for future expansion */ + gpointer _gda_reserved1; + gpointer _gda_reserved2; +} GdaSqlParserIface; + +#define GDA_TYPE_SQL_PARSER (gda_sql_parser_get_type()) +G_DECLARE_DERIVABLE_TYPE(GdaSqlParser, gda_sql_parser, GDA, SQL_PARSER, GObject) +/* struct for the object's class */ +struct _GdaSqlParserClass +{ + GObjectClass parent_class; + + /* virtual methods and data for sub classed parsers */ + void *(*delim_alloc) (void *(*f) (size_t s)); + void (*delim_free) (void *d, void(*f) (void *d)); + void (*delim_trace) (void *d, char *s); + void (*delim_parse) (void *d, int i, GValue *v, GdaSqlParserIface *iface); + gint *delim_tokens_trans; + + void *(*parser_alloc) (void *(*f)(size_t s)); + void (*parser_free) (void *p, void(*f)(void *p)); + void (*parser_trace) (void *p, char *s); + void (*parser_parse) (void *p, int i, GValue *v, GdaSqlParserIface *iface); + gint *parser_tokens_trans; + + /*< private >*/ + /* Padding for future expansion */ + void (*_gda_reserved1) (void); + void (*_gda_reserved2) (void); + void (*_gda_reserved3) (void); + void (*_gda_reserved4) (void); +}; + +/** + * SECTION:gda-sql-parser + * @short_description: SQL parser + * @title: GdaSqlParser + * @stability: Stable + * @see_also: #GdaSqlBuilder, #GdaSqlStatement and #GdaStatement + * + * The #GdaSqlParser is an object dedicated to creating #GdaStatement and #GdaBatch objects from SQL strings. The actual contents + * of the parsed statements is represented as #GdaSqlStatement structures (which can be obtained from any #GdaStatement through the + * "structure" property). + * + * #GdaSqlParser parsers can be created by calling gda_server_provider_create_parser() for a provider adapted SQL parser, or using + * gda_sql_parser_new() for a general purpose SQL parser. + * + * The #GdaSqlParser can either work in "parse" mode where it will try to parse the SQL string, or in "delimiter" mode where it will + * only attempt at delimiting SQL statements in a string which may contain several SQL statements (usually separated by a semi column). + * If operating in "parser" mode, and the parser can't correctly parse the string, then it will switch to the "delimiter" mode + * for the next statement in the string to parse (and create a GDA_SQL_STATEMENT_UNKNOWN statement). + * + * The #GdaSqlParser object parses and analyzes SQL statements and reports the following statement types: + * + * SELECT (and COMPOUND select), + * INSERT, UPDATE and DELETE SQL statements should be completely parsed. + * + * Transaction related statements (corresponding to the BEGIN, COMMIT, ROLLBACK, + * SAVEPOINT, ROLLBACK SAVEPOINT and DELETE SAVEPOINT) are parsed and a minimalist structure is created to + * extract some information (that structure is not enough per-se to re-create the complete SQL statement). + * + * Any other type of SQL statement (CREATE TABLE, ...) creates a #GdaStatement of type + * GDA_SQL_STATEMENT_UNKNOWN, and it only able to locate place holders (variables) and end of statement + * marks. + * + * + * NOTE: Any SQL of a type which should be parsed which but which creates a #GdaStatement of type GDA_SQL_STATEMENT_UNKNOWN + * (check with gda_statement_get_statement_type()) should be reported as a bug. + * + * The #GdaSqlParser object recognizes place holders (variables), which can later be queried and valued using + * gda_statement_get_parameters(). The following syntax are recognized (other syntaxes might be + * recognized for specific database providers if the #GdaSqlParser is created using gda_server_provider_create_parser() + * but for portability reasons it's better to avoid them): + * + * ##NAME[::TYPE[::NULL]]]: + * for a variable named NAME with the optional type TYPE (which can be a GType + * name or a custom database type name), and with the optional "::NULL" to instruct that the variable can + * be NULL. + * + * + * ## /* name:NAME [type:TYPE] [nullok:[TRUE|FALSE]] [descr:DESCR] */ + * for a variable named NAME with the optional type TYPE (which can be a GType + * name or a custom database type name), with the optional "nullok" attribute and an optional + * description DESCR. Note that the NAME, TYPE and DESCR literals here must be quoted (simple or double quotes) if + * they include non alphanumeric characters, and that there must always be at least a space between the + * and the opening and closing comments (C style). + * + * + * Note that the type string must be a type recognized by the + * gda_g_type_from_string() function (all valid GType names + * plus a few synonyms). Examples of correct place holders definitions are: + * + *## /* name:"+0" type:gchararray */ + *## /* name:'-5' type:string */ + *## /*name:myvar type:gint descr:ToBeDefined nullok:FALSE*/ + *## /*name:myvar type:int descr:"A long description"*/ + *##+0::gchararray + *##-5::timestamp + * + * + * Also note that variables should not be used when an SQL identifier is expected. For example the following + * examples should be avoided because they may not work properly (depending on the database being used): + * + *SELECT * FROM ##tablename::string; + *DELETE FROM mytable WHERE ##tcol::string = 5; + *ALTER GROUP mygroup ADD USER ##name::gchararray; + * + * + * The #GdaSqlParser object internally uses a LEMON generated parser (the same as the one used by SQLite). + * + * The #GdaSqlParser object implements its own locking mechanism so it is thread-safe. + */ + +GdaSqlParser *gda_sql_parser_new (void); + +GdaStatement *gda_sql_parser_parse_string (GdaSqlParser *parser, + const gchar *sql, const gchar **remain, + GError **error); +GdaBatch *gda_sql_parser_parse_string_as_batch (GdaSqlParser *parser, + const gchar *sql, const gchar **remain, + GError **error); +GdaBatch *gda_sql_parser_parse_file_as_batch (GdaSqlParser *parser, + const gchar *filename, GError **error); + +/* private API */ +void gda_sql_parser_set_syntax_error (GdaSqlParser *parser); +void gda_sql_parser_set_overflow_error (GdaSqlParser *parser); + +G_END_DECLS + +#endif diff --git a/.flatpak-builder/cache/objects/2b/3b7c120be6441e51b5f01a3ad764c2a67599685face359fb8de9f4cd1fea81.file b/.flatpak-builder/cache/objects/2b/3b7c120be6441e51b5f01a3ad764c2a67599685face359fb8de9f4cd1fea81.file new file mode 100644 index 0000000..a0ff221 Binary files /dev/null and b/.flatpak-builder/cache/objects/2b/3b7c120be6441e51b5f01a3ad764c2a67599685face359fb8de9f4cd1fea81.file differ diff --git a/.flatpak-builder/cache/objects/2b/437872c24ce37d9253d2d229e3dec84991de1a3a1afe847bff4e8b3dd532ab.dirtree b/.flatpak-builder/cache/objects/2b/437872c24ce37d9253d2d229e3dec84991de1a3a1afe847bff4e8b3dd532ab.dirtree new file mode 100644 index 0000000..9d19df6 Binary files /dev/null and b/.flatpak-builder/cache/objects/2b/437872c24ce37d9253d2d229e3dec84991de1a3a1afe847bff4e8b3dd532ab.dirtree differ diff --git a/.flatpak-builder/cache/objects/2b/dd4333881b7e6f36337123b5f48b9a3fde73ffa305808262e68e0a69d92743.dirtree b/.flatpak-builder/cache/objects/2b/dd4333881b7e6f36337123b5f48b9a3fde73ffa305808262e68e0a69d92743.dirtree new file mode 100644 index 0000000..fe671b7 Binary files /dev/null and b/.flatpak-builder/cache/objects/2b/dd4333881b7e6f36337123b5f48b9a3fde73ffa305808262e68e0a69d92743.dirtree differ diff --git a/.flatpak-builder/cache/objects/2c/00909b380d1b972a01e5fe831679ad340655c8d153ada016300ba79d8961b9.file b/.flatpak-builder/cache/objects/2c/00909b380d1b972a01e5fe831679ad340655c8d153ada016300ba79d8961b9.file new file mode 100644 index 0000000..8ffc13c Binary files /dev/null and b/.flatpak-builder/cache/objects/2c/00909b380d1b972a01e5fe831679ad340655c8d153ada016300ba79d8961b9.file differ diff --git a/.flatpak-builder/cache/objects/2c/06b1af66f0d4986e7470164626f61b2d4d3adf9a6792af5efa3129531e4420.file b/.flatpak-builder/cache/objects/2c/06b1af66f0d4986e7470164626f61b2d4d3adf9a6792af5efa3129531e4420.file new file mode 100644 index 0000000..cbb81bc --- /dev/null +++ b/.flatpak-builder/cache/objects/2c/06b1af66f0d4986e7470164626f61b2d4d3adf9a6792af5efa3129531e4420.file @@ -0,0 +1,544 @@ +/* This file is generated by glib-genmarshal, do not modify it. This code is licensed under the same license as the containing project. Note that it links to GLib, so must comply with the LGPL linking clauses. */ +#include "gda-marshal.h" + +#include + +#ifdef G_ENABLE_DEBUG +#define g_marshal_value_peek_boolean(v) g_value_get_boolean (v) +#define g_marshal_value_peek_char(v) g_value_get_schar (v) +#define g_marshal_value_peek_uchar(v) g_value_get_uchar (v) +#define g_marshal_value_peek_int(v) g_value_get_int (v) +#define g_marshal_value_peek_uint(v) g_value_get_uint (v) +#define g_marshal_value_peek_long(v) g_value_get_long (v) +#define g_marshal_value_peek_ulong(v) g_value_get_ulong (v) +#define g_marshal_value_peek_int64(v) g_value_get_int64 (v) +#define g_marshal_value_peek_uint64(v) g_value_get_uint64 (v) +#define g_marshal_value_peek_enum(v) g_value_get_enum (v) +#define g_marshal_value_peek_flags(v) g_value_get_flags (v) +#define g_marshal_value_peek_float(v) g_value_get_float (v) +#define g_marshal_value_peek_double(v) g_value_get_double (v) +#define g_marshal_value_peek_string(v) (char*) g_value_get_string (v) +#define g_marshal_value_peek_param(v) g_value_get_param (v) +#define g_marshal_value_peek_boxed(v) g_value_get_boxed (v) +#define g_marshal_value_peek_pointer(v) g_value_get_pointer (v) +#define g_marshal_value_peek_object(v) g_value_get_object (v) +#define g_marshal_value_peek_variant(v) g_value_get_variant (v) +#else /* !G_ENABLE_DEBUG */ +/* WARNING: This code accesses GValues directly, which is UNSUPPORTED API. + * Do not access GValues directly in your code. Instead, use the + * g_value_get_*() functions + */ +#define g_marshal_value_peek_boolean(v) (v)->data[0].v_int +#define g_marshal_value_peek_char(v) (v)->data[0].v_int +#define g_marshal_value_peek_uchar(v) (v)->data[0].v_uint +#define g_marshal_value_peek_int(v) (v)->data[0].v_int +#define g_marshal_value_peek_uint(v) (v)->data[0].v_uint +#define g_marshal_value_peek_long(v) (v)->data[0].v_long +#define g_marshal_value_peek_ulong(v) (v)->data[0].v_ulong +#define g_marshal_value_peek_int64(v) (v)->data[0].v_int64 +#define g_marshal_value_peek_uint64(v) (v)->data[0].v_uint64 +#define g_marshal_value_peek_enum(v) (v)->data[0].v_long +#define g_marshal_value_peek_flags(v) (v)->data[0].v_ulong +#define g_marshal_value_peek_float(v) (v)->data[0].v_float +#define g_marshal_value_peek_double(v) (v)->data[0].v_double +#define g_marshal_value_peek_string(v) (v)->data[0].v_pointer +#define g_marshal_value_peek_param(v) (v)->data[0].v_pointer +#define g_marshal_value_peek_boxed(v) (v)->data[0].v_pointer +#define g_marshal_value_peek_pointer(v) (v)->data[0].v_pointer +#define g_marshal_value_peek_object(v) (v)->data[0].v_pointer +#define g_marshal_value_peek_variant(v) (v)->data[0].v_pointer +#endif /* !G_ENABLE_DEBUG */ + +/* VOID:OBJECT,OBJECT (../libgda/gda-marshal.list:28) */ +void +_gda_marshal_VOID__OBJECT_OBJECT (GClosure *closure, + GValue *return_value G_GNUC_UNUSED, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint G_GNUC_UNUSED, + gpointer marshal_data) +{ + typedef void (*GMarshalFunc_VOID__OBJECT_OBJECT) (gpointer data1, + gpointer arg1, + gpointer arg2, + gpointer data2); + GCClosure *cc = (GCClosure *) closure; + gpointer data1, data2; + GMarshalFunc_VOID__OBJECT_OBJECT callback; + + g_return_if_fail (n_param_values == 3); + + if (G_CCLOSURE_SWAP_DATA (closure)) + { + data1 = closure->data; + data2 = g_value_peek_pointer (param_values + 0); + } + else + { + data1 = g_value_peek_pointer (param_values + 0); + data2 = closure->data; + } + callback = (GMarshalFunc_VOID__OBJECT_OBJECT) (marshal_data ? marshal_data : cc->callback); + + callback (data1, + g_marshal_value_peek_object (param_values + 1), + g_marshal_value_peek_object (param_values + 2), + data2); +} + +/* VOID:OBJECT,ENUM,OBJECT (../libgda/gda-marshal.list:29) */ +void +_gda_marshal_VOID__OBJECT_ENUM_OBJECT (GClosure *closure, + GValue *return_value G_GNUC_UNUSED, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint G_GNUC_UNUSED, + gpointer marshal_data) +{ + typedef void (*GMarshalFunc_VOID__OBJECT_ENUM_OBJECT) (gpointer data1, + gpointer arg1, + gint arg2, + gpointer arg3, + gpointer data2); + GCClosure *cc = (GCClosure *) closure; + gpointer data1, data2; + GMarshalFunc_VOID__OBJECT_ENUM_OBJECT callback; + + g_return_if_fail (n_param_values == 4); + + if (G_CCLOSURE_SWAP_DATA (closure)) + { + data1 = closure->data; + data2 = g_value_peek_pointer (param_values + 0); + } + else + { + data1 = g_value_peek_pointer (param_values + 0); + data2 = closure->data; + } + callback = (GMarshalFunc_VOID__OBJECT_ENUM_OBJECT) (marshal_data ? marshal_data : cc->callback); + + callback (data1, + g_marshal_value_peek_object (param_values + 1), + g_marshal_value_peek_enum (param_values + 2), + g_marshal_value_peek_object (param_values + 3), + data2); +} + +/* VOID:OBJECT,UINT (../libgda/gda-marshal.list:30) */ +void +_gda_marshal_VOID__OBJECT_UINT (GClosure *closure, + GValue *return_value G_GNUC_UNUSED, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint G_GNUC_UNUSED, + gpointer marshal_data) +{ + typedef void (*GMarshalFunc_VOID__OBJECT_UINT) (gpointer data1, + gpointer arg1, + guint arg2, + gpointer data2); + GCClosure *cc = (GCClosure *) closure; + gpointer data1, data2; + GMarshalFunc_VOID__OBJECT_UINT callback; + + g_return_if_fail (n_param_values == 3); + + if (G_CCLOSURE_SWAP_DATA (closure)) + { + data1 = closure->data; + data2 = g_value_peek_pointer (param_values + 0); + } + else + { + data1 = g_value_peek_pointer (param_values + 0); + data2 = closure->data; + } + callback = (GMarshalFunc_VOID__OBJECT_UINT) (marshal_data ? marshal_data : cc->callback); + + callback (data1, + g_marshal_value_peek_object (param_values + 1), + g_marshal_value_peek_uint (param_values + 2), + data2); +} + +/* VOID:OBJECT,UINT,UINT (../libgda/gda-marshal.list:31) */ +void +_gda_marshal_VOID__OBJECT_UINT_UINT (GClosure *closure, + GValue *return_value G_GNUC_UNUSED, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint G_GNUC_UNUSED, + gpointer marshal_data) +{ + typedef void (*GMarshalFunc_VOID__OBJECT_UINT_UINT) (gpointer data1, + gpointer arg1, + guint arg2, + guint arg3, + gpointer data2); + GCClosure *cc = (GCClosure *) closure; + gpointer data1, data2; + GMarshalFunc_VOID__OBJECT_UINT_UINT callback; + + g_return_if_fail (n_param_values == 4); + + if (G_CCLOSURE_SWAP_DATA (closure)) + { + data1 = closure->data; + data2 = g_value_peek_pointer (param_values + 0); + } + else + { + data1 = g_value_peek_pointer (param_values + 0); + data2 = closure->data; + } + callback = (GMarshalFunc_VOID__OBJECT_UINT_UINT) (marshal_data ? marshal_data : cc->callback); + + callback (data1, + g_marshal_value_peek_object (param_values + 1), + g_marshal_value_peek_uint (param_values + 2), + g_marshal_value_peek_uint (param_values + 3), + data2); +} + +/* VOID:OBJECT,BOOLEAN (../libgda/gda-marshal.list:32) */ +void +_gda_marshal_VOID__OBJECT_BOOLEAN (GClosure *closure, + GValue *return_value G_GNUC_UNUSED, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint G_GNUC_UNUSED, + gpointer marshal_data) +{ + typedef void (*GMarshalFunc_VOID__OBJECT_BOOLEAN) (gpointer data1, + gpointer arg1, + gboolean arg2, + gpointer data2); + GCClosure *cc = (GCClosure *) closure; + gpointer data1, data2; + GMarshalFunc_VOID__OBJECT_BOOLEAN callback; + + g_return_if_fail (n_param_values == 3); + + if (G_CCLOSURE_SWAP_DATA (closure)) + { + data1 = closure->data; + data2 = g_value_peek_pointer (param_values + 0); + } + else + { + data1 = g_value_peek_pointer (param_values + 0); + data2 = closure->data; + } + callback = (GMarshalFunc_VOID__OBJECT_BOOLEAN) (marshal_data ? marshal_data : cc->callback); + + callback (data1, + g_marshal_value_peek_object (param_values + 1), + g_marshal_value_peek_boolean (param_values + 2), + data2); +} + +/* VOID:STRING,UINT,UINT (../libgda/gda-marshal.list:33) */ +void +_gda_marshal_VOID__STRING_UINT_UINT (GClosure *closure, + GValue *return_value G_GNUC_UNUSED, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint G_GNUC_UNUSED, + gpointer marshal_data) +{ + typedef void (*GMarshalFunc_VOID__STRING_UINT_UINT) (gpointer data1, + gpointer arg1, + guint arg2, + guint arg3, + gpointer data2); + GCClosure *cc = (GCClosure *) closure; + gpointer data1, data2; + GMarshalFunc_VOID__STRING_UINT_UINT callback; + + g_return_if_fail (n_param_values == 4); + + if (G_CCLOSURE_SWAP_DATA (closure)) + { + data1 = closure->data; + data2 = g_value_peek_pointer (param_values + 0); + } + else + { + data1 = g_value_peek_pointer (param_values + 0); + data2 = closure->data; + } + callback = (GMarshalFunc_VOID__STRING_UINT_UINT) (marshal_data ? marshal_data : cc->callback); + + callback (data1, + g_marshal_value_peek_string (param_values + 1), + g_marshal_value_peek_uint (param_values + 2), + g_marshal_value_peek_uint (param_values + 3), + data2); +} + +/* VOID:ENUM,OBJECT (../libgda/gda-marshal.list:34) */ +void +_gda_marshal_VOID__ENUM_OBJECT (GClosure *closure, + GValue *return_value G_GNUC_UNUSED, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint G_GNUC_UNUSED, + gpointer marshal_data) +{ + typedef void (*GMarshalFunc_VOID__ENUM_OBJECT) (gpointer data1, + gint arg1, + gpointer arg2, + gpointer data2); + GCClosure *cc = (GCClosure *) closure; + gpointer data1, data2; + GMarshalFunc_VOID__ENUM_OBJECT callback; + + g_return_if_fail (n_param_values == 3); + + if (G_CCLOSURE_SWAP_DATA (closure)) + { + data1 = closure->data; + data2 = g_value_peek_pointer (param_values + 0); + } + else + { + data1 = g_value_peek_pointer (param_values + 0); + data2 = closure->data; + } + callback = (GMarshalFunc_VOID__ENUM_OBJECT) (marshal_data ? marshal_data : cc->callback); + + callback (data1, + g_marshal_value_peek_enum (param_values + 1), + g_marshal_value_peek_object (param_values + 2), + data2); +} + +/* VOID:INT,INT (../libgda/gda-marshal.list:36) */ +void +_gda_marshal_VOID__INT_INT (GClosure *closure, + GValue *return_value G_GNUC_UNUSED, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint G_GNUC_UNUSED, + gpointer marshal_data) +{ + typedef void (*GMarshalFunc_VOID__INT_INT) (gpointer data1, + gint arg1, + gint arg2, + gpointer data2); + GCClosure *cc = (GCClosure *) closure; + gpointer data1, data2; + GMarshalFunc_VOID__INT_INT callback; + + g_return_if_fail (n_param_values == 3); + + if (G_CCLOSURE_SWAP_DATA (closure)) + { + data1 = closure->data; + data2 = g_value_peek_pointer (param_values + 0); + } + else + { + data1 = g_value_peek_pointer (param_values + 0); + data2 = closure->data; + } + callback = (GMarshalFunc_VOID__INT_INT) (marshal_data ? marshal_data : cc->callback); + + callback (data1, + g_marshal_value_peek_int (param_values + 1), + g_marshal_value_peek_int (param_values + 2), + data2); +} + +/* VOID:INT,BOXED,BOXED (../libgda/gda-marshal.list:37) */ +void +_gda_marshal_VOID__INT_BOXED_BOXED (GClosure *closure, + GValue *return_value G_GNUC_UNUSED, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint G_GNUC_UNUSED, + gpointer marshal_data) +{ + typedef void (*GMarshalFunc_VOID__INT_BOXED_BOXED) (gpointer data1, + gint arg1, + gpointer arg2, + gpointer arg3, + gpointer data2); + GCClosure *cc = (GCClosure *) closure; + gpointer data1, data2; + GMarshalFunc_VOID__INT_BOXED_BOXED callback; + + g_return_if_fail (n_param_values == 4); + + if (G_CCLOSURE_SWAP_DATA (closure)) + { + data1 = closure->data; + data2 = g_value_peek_pointer (param_values + 0); + } + else + { + data1 = g_value_peek_pointer (param_values + 0); + data2 = closure->data; + } + callback = (GMarshalFunc_VOID__INT_BOXED_BOXED) (marshal_data ? marshal_data : cc->callback); + + callback (data1, + g_marshal_value_peek_int (param_values + 1), + g_marshal_value_peek_boxed (param_values + 2), + g_marshal_value_peek_boxed (param_values + 3), + data2); +} + +/* VOID:INT,BOOLEAN (../libgda/gda-marshal.list:38) */ +void +_gda_marshal_VOID__INT_BOOLEAN (GClosure *closure, + GValue *return_value G_GNUC_UNUSED, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint G_GNUC_UNUSED, + gpointer marshal_data) +{ + typedef void (*GMarshalFunc_VOID__INT_BOOLEAN) (gpointer data1, + gint arg1, + gboolean arg2, + gpointer data2); + GCClosure *cc = (GCClosure *) closure; + gpointer data1, data2; + GMarshalFunc_VOID__INT_BOOLEAN callback; + + g_return_if_fail (n_param_values == 3); + + if (G_CCLOSURE_SWAP_DATA (closure)) + { + data1 = closure->data; + data2 = g_value_peek_pointer (param_values + 0); + } + else + { + data1 = g_value_peek_pointer (param_values + 0); + data2 = closure->data; + } + callback = (GMarshalFunc_VOID__INT_BOOLEAN) (marshal_data ? marshal_data : cc->callback); + + callback (data1, + g_marshal_value_peek_int (param_values + 1), + g_marshal_value_peek_boolean (param_values + 2), + data2); +} + +/* VOID:STRING,INT (../libgda/gda-marshal.list:39) */ +void +_gda_marshal_VOID__STRING_INT (GClosure *closure, + GValue *return_value G_GNUC_UNUSED, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint G_GNUC_UNUSED, + gpointer marshal_data) +{ + typedef void (*GMarshalFunc_VOID__STRING_INT) (gpointer data1, + gpointer arg1, + gint arg2, + gpointer data2); + GCClosure *cc = (GCClosure *) closure; + gpointer data1, data2; + GMarshalFunc_VOID__STRING_INT callback; + + g_return_if_fail (n_param_values == 3); + + if (G_CCLOSURE_SWAP_DATA (closure)) + { + data1 = closure->data; + data2 = g_value_peek_pointer (param_values + 0); + } + else + { + data1 = g_value_peek_pointer (param_values + 0); + data2 = closure->data; + } + callback = (GMarshalFunc_VOID__STRING_INT) (marshal_data ? marshal_data : cc->callback); + + callback (data1, + g_marshal_value_peek_string (param_values + 1), + g_marshal_value_peek_int (param_values + 2), + data2); +} + +/* POINTER:POINTER (../libgda/gda-marshal.list:40) */ +void +_gda_marshal_POINTER__POINTER (GClosure *closure, + GValue *return_value, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint G_GNUC_UNUSED, + gpointer marshal_data) +{ + typedef gpointer (*GMarshalFunc_POINTER__POINTER) (gpointer data1, + gpointer arg1, + gpointer data2); + GCClosure *cc = (GCClosure *) closure; + gpointer data1, data2; + GMarshalFunc_POINTER__POINTER callback; + gpointer v_return; + + g_return_if_fail (return_value != NULL); + g_return_if_fail (n_param_values == 2); + + if (G_CCLOSURE_SWAP_DATA (closure)) + { + data1 = closure->data; + data2 = g_value_peek_pointer (param_values + 0); + } + else + { + data1 = g_value_peek_pointer (param_values + 0); + data2 = closure->data; + } + callback = (GMarshalFunc_POINTER__POINTER) (marshal_data ? marshal_data : cc->callback); + + v_return = callback (data1, + g_marshal_value_peek_pointer (param_values + 1), + data2); + + g_value_set_pointer (return_value, v_return); +} + +/* BOOLEAN:POINTER (../libgda/gda-marshal.list:41) */ +void +_gda_marshal_BOOLEAN__POINTER (GClosure *closure, + GValue *return_value, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint G_GNUC_UNUSED, + gpointer marshal_data) +{ + typedef gboolean (*GMarshalFunc_BOOLEAN__POINTER) (gpointer data1, + gpointer arg1, + gpointer data2); + GCClosure *cc = (GCClosure *) closure; + gpointer data1, data2; + GMarshalFunc_BOOLEAN__POINTER callback; + gboolean v_return; + + g_return_if_fail (return_value != NULL); + g_return_if_fail (n_param_values == 2); + + if (G_CCLOSURE_SWAP_DATA (closure)) + { + data1 = closure->data; + data2 = g_value_peek_pointer (param_values + 0); + } + else + { + data1 = g_value_peek_pointer (param_values + 0); + data2 = closure->data; + } + callback = (GMarshalFunc_BOOLEAN__POINTER) (marshal_data ? marshal_data : cc->callback); + + v_return = callback (data1, + g_marshal_value_peek_pointer (param_values + 1), + data2); + + g_value_set_boolean (return_value, v_return); +} + diff --git a/.flatpak-builder/cache/objects/2c/162b1c88552ef6fbd493865c1535e6243f017dc7ba65b39abeec2294a6f253.dirtree b/.flatpak-builder/cache/objects/2c/162b1c88552ef6fbd493865c1535e6243f017dc7ba65b39abeec2294a6f253.dirtree new file mode 100644 index 0000000..bc4d4c6 Binary files /dev/null and b/.flatpak-builder/cache/objects/2c/162b1c88552ef6fbd493865c1535e6243f017dc7ba65b39abeec2294a6f253.dirtree differ diff --git a/.flatpak-builder/cache/objects/2c/36d952804a534d3caa8766486ec99d5371483226e375db5ed6ab3f9376231f.dirtree b/.flatpak-builder/cache/objects/2c/36d952804a534d3caa8766486ec99d5371483226e375db5ed6ab3f9376231f.dirtree new file mode 100644 index 0000000..2dca295 Binary files /dev/null and b/.flatpak-builder/cache/objects/2c/36d952804a534d3caa8766486ec99d5371483226e375db5ed6ab3f9376231f.dirtree differ diff --git a/.flatpak-builder/cache/objects/2c/dc5c1ef72d904fdc1c3fb1c67d7b1023d1f7cb1c020c2262d71769f978f841.file b/.flatpak-builder/cache/objects/2c/dc5c1ef72d904fdc1c3fb1c67d7b1023d1f7cb1c020c2262d71769f978f841.file new file mode 100644 index 0000000..c61242c --- /dev/null +++ b/.flatpak-builder/cache/objects/2c/dc5c1ef72d904fdc1c3fb1c67d7b1023d1f7cb1c020c2262d71769f978f841.file @@ -0,0 +1,179 @@ +/* + * Copyright (C) 2009 - 2013 Vivien Malerba + * Copyright (C) 2010 David King + * Copyright (C) 2018 Daniel Espinosa + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +#define G_LOG_DOMAIN "GDA-tree-mgr-label" + +#include +#include +#include +#include "gda-tree-mgr-label.h" +#include "gda-tree-node.h" + +typedef struct { + gchar *label; /* imposed upon construction */ +} GdaTreeMgrLabelPrivate; + +G_DEFINE_TYPE_WITH_PRIVATE (GdaTreeMgrLabel, gda_tree_mgr_label, GDA_TYPE_TREE_MANAGER) + +static void gda_tree_mgr_label_dispose (GObject *object); +static void gda_tree_mgr_label_set_property (GObject *object, + guint param_id, + const GValue *value, + GParamSpec *pspec); +static void gda_tree_mgr_label_get_property (GObject *object, + guint param_id, + GValue *value, + GParamSpec *pspec); + +/* virtual methods */ +static GSList *gda_tree_mgr_label_update_children (GdaTreeManager *manager, GdaTreeNode *node, const GSList *children_nodes, + gboolean *out_error, GError **error); + +static GObjectClass *parent_class = NULL; + +/* properties */ +enum { + PROP_0, + PROP_LABEL +}; + +/* + * GdaTreeMgrLabel class implementation + * @klass: + */ +static void +gda_tree_mgr_label_class_init (GdaTreeMgrLabelClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + /* virtual methods */ + ((GdaTreeManagerClass*) klass)->update_children = gda_tree_mgr_label_update_children; + + /* Properties */ + object_class->set_property = gda_tree_mgr_label_set_property; + object_class->get_property = gda_tree_mgr_label_get_property; + + g_object_class_install_property (object_class, PROP_LABEL, + g_param_spec_string ("label", NULL, + "Label for the node", + NULL, G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)); + + object_class->dispose = gda_tree_mgr_label_dispose; +} + +static void +gda_tree_mgr_label_init (GdaTreeMgrLabel *mgr) {} + +static void +gda_tree_mgr_label_dispose (GObject *object) +{ + GdaTreeMgrLabel *mgr = (GdaTreeMgrLabel *) object; + + g_return_if_fail (GDA_IS_TREE_MGR_LABEL (mgr)); + GdaTreeMgrLabelPrivate *priv = gda_tree_mgr_label_get_instance_private (mgr); + + g_free (priv->label); + priv->label = NULL; + + /* chain to parent class */ + parent_class->dispose (object); +} + +static void +gda_tree_mgr_label_set_property (GObject *object, + guint param_id, + const GValue *value, + GParamSpec *pspec) +{ + GdaTreeMgrLabel *mgr; + + mgr = GDA_TREE_MGR_LABEL (object); + GdaTreeMgrLabelPrivate *priv = gda_tree_mgr_label_get_instance_private (mgr); + switch (param_id) { + case PROP_LABEL: + priv->label = g_value_dup_string (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + break; + } +} + +static void +gda_tree_mgr_label_get_property (GObject *object, + guint param_id, + GValue *value, + GParamSpec *pspec) +{ + GdaTreeMgrLabel *mgr; + + mgr = GDA_TREE_MGR_LABEL (object); + GdaTreeMgrLabelPrivate *priv = gda_tree_mgr_label_get_instance_private (mgr); + switch (param_id) { + case PROP_LABEL: + g_value_set_string (value, priv->label); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + break; + } +} + +/** + * gda_tree_mgr_label_new: + * @label: a label string + * + * Creates a new #GdaTreeManager object which will add one tree node labelled @label + * + * Returns: (transfer full): a new #GdaTreeManager object + * + * Since: 4.2 + */ +GdaTreeManager* +gda_tree_mgr_label_new (const gchar *label) +{ + GdaTreeMgrLabel *mgr; + mgr = (GdaTreeMgrLabel*) g_object_new (GDA_TYPE_TREE_MGR_LABEL, + "label", label, NULL); + return (GdaTreeManager*) mgr; +} + +void ref_elements (GObject *object, G_GNUC_UNUSED gpointer user_data) +{ + g_object_ref (object); +} + +static GSList * +gda_tree_mgr_label_update_children (GdaTreeManager *manager, GdaTreeNode *node, const GSList *children_nodes, + G_GNUC_UNUSED gboolean *out_error, G_GNUC_UNUSED GError **error) +{ + if (children_nodes) { + GSList *list = g_slist_copy ((GSList*) children_nodes); + g_slist_foreach (list, (GFunc) ref_elements, NULL); + return list; + } + + GdaTreeMgrLabel *mgr = GDA_TREE_MGR_LABEL (manager); + GdaTreeNode *snode; + GdaTreeMgrLabelPrivate *priv = gda_tree_mgr_label_get_instance_private (mgr); + + snode = gda_tree_manager_create_node (manager, node, priv->label ? priv->label : _("No name")); + return g_slist_prepend (NULL, snode); +} diff --git a/.flatpak-builder/cache/objects/2d/47d70628cca9fa16574ef4041c3761c05b5d1bdf79982c5b50df59f53f3de1.file b/.flatpak-builder/cache/objects/2d/47d70628cca9fa16574ef4041c3761c05b5d1bdf79982c5b50df59f53f3de1.file new file mode 100644 index 0000000..76d95fa --- /dev/null +++ b/.flatpak-builder/cache/objects/2d/47d70628cca9fa16574ef4041c3761c05b5d1bdf79982c5b50df59f53f3de1.file @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2000 Reinhard Müller + * Copyright (C) 2000 - 2003 Rodrigo Moya + * Copyright (C) 2001 - 2011 Vivien Malerba + * Copyright (C) 2002 Gonzalo Paniagua Javier + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + + +#ifndef __GDA_BATCH_H_ +#define __GDA_BATCH_H_ + +#include +#include + +G_BEGIN_DECLS + +#define GDA_TYPE_BATCH (gda_batch_get_type()) +G_DECLARE_DERIVABLE_TYPE(GdaBatch, gda_batch, GDA, BATCH, GObject) + +/* error reporting */ +extern GQuark gda_batch_error_quark (void); +#define GDA_BATCH_ERROR gda_batch_error_quark () + +typedef enum { + GDA_BATCH_CONFLICTING_PARAMETER_ERROR +} GdaBatchError; + +/* struct for the object's class */ +struct _GdaBatchClass +{ + GObjectClass parent_class; + + /* signals */ + void (*changed) (GdaBatch *batch, GdaStatement *changed_stmt); + + /*< private >*/ + /* Padding for future expansion */ + void (*_gda_reserved1) (void); + void (*_gda_reserved2) (void); + void (*_gda_reserved3) (void); + void (*_gda_reserved4) (void); +}; + +/** + * SECTION:gda-batch + * @short_description: Multiple SQL statements grouped together. + * @title: GdaBatch + * @stability: Stable + * @see_also: #GdaStatement + * + * The #GdaBatch object represents one or more SQL statements (as #GdaStatement objects) in a single object. + * + * A #GdaBatch can either be built "manually" by assembling together several #GdaStatement objects, + * or from an SQL string using a #GdaSqlParser object. + */ + +GdaBatch *gda_batch_new (void); +GdaBatch *gda_batch_copy (GdaBatch *orig); +void gda_batch_add_statement (GdaBatch *batch, GdaStatement *stmt); +void gda_batch_remove_statement (GdaBatch *batch, GdaStatement *stmt); + +gchar *gda_batch_serialize (GdaBatch *batch); +const GSList *gda_batch_get_statements (GdaBatch *batch); +gboolean gda_batch_get_parameters (GdaBatch *batch, GdaSet **out_params, GError **error); + +G_END_DECLS + +#endif diff --git a/.flatpak-builder/cache/objects/2d/5b6371fc0a75faaa465d0f1e838889f0539cd3260ca35b877cfad6e2226e00.file b/.flatpak-builder/cache/objects/2d/5b6371fc0a75faaa465d0f1e838889f0539cd3260ca35b877cfad6e2226e00.file new file mode 100644 index 0000000..20001a6 --- /dev/null +++ b/.flatpak-builder/cache/objects/2d/5b6371fc0a75faaa465d0f1e838889f0539cd3260ca35b877cfad6e2226e00.file @@ -0,0 +1,312 @@ +/* + * Copyright (C) 2008 - 2012 Vivien Malerba + * Copyright (C) 2009 Bas Driessen + * Copyright (C) 2010 David King + * Copyright (C) 2010 Murray Cumming + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include +#include +#include +#include +#include + +static gpointer gda_sql_statement_trans_new (void); +static void gda_sql_statement_trans_free (gpointer stmt); +static gpointer gda_sql_statement_trans_copy (gpointer src); +static gchar *gda_sql_statement_trans_serialize (gpointer stmt); + +/* BEGIN */ +GdaSqlStatementContentsInfo begin_infos = { + GDA_SQL_STATEMENT_BEGIN, + "BEGIN", + gda_sql_statement_trans_new, + gda_sql_statement_trans_free, + gda_sql_statement_trans_copy, + gda_sql_statement_trans_serialize, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL +}; + +GdaSqlStatementContentsInfo * +_gda_sql_statement_begin_get_infos (void) +{ + return &begin_infos; +} + +/* COMMIT */ +GdaSqlStatementContentsInfo commit_infos = { + GDA_SQL_STATEMENT_COMMIT, + "COMMIT", + gda_sql_statement_trans_new, + gda_sql_statement_trans_free, + gda_sql_statement_trans_copy, + gda_sql_statement_trans_serialize, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL +}; + +GdaSqlStatementContentsInfo * +_gda_sql_statement_commit_get_infos (void) +{ + return &commit_infos; +} + +/* ROLLBACK */ +GdaSqlStatementContentsInfo rollback_infos = { + GDA_SQL_STATEMENT_ROLLBACK, + "ROLLBACK", + gda_sql_statement_trans_new, + gda_sql_statement_trans_free, + gda_sql_statement_trans_copy, + gda_sql_statement_trans_serialize, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL +}; + +GdaSqlStatementContentsInfo * +_gda_sql_statement_rollback_get_infos (void) +{ + return &rollback_infos; +} + +/* SAVEPOINT */ +GdaSqlStatementContentsInfo svp_infos = { + GDA_SQL_STATEMENT_SAVEPOINT, + "SAVEPOINT", + gda_sql_statement_trans_new, + gda_sql_statement_trans_free, + gda_sql_statement_trans_copy, + gda_sql_statement_trans_serialize, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL +}; + +GdaSqlStatementContentsInfo * +_gda_sql_statement_savepoint_get_infos (void) +{ + return &svp_infos; +} + +/* ROLLBACK SAVEPOINT */ +GdaSqlStatementContentsInfo rollback_svp_infos = { + GDA_SQL_STATEMENT_ROLLBACK_SAVEPOINT, + "ROLLBACK_SAVEPOINT", + gda_sql_statement_trans_new, + gda_sql_statement_trans_free, + gda_sql_statement_trans_copy, + gda_sql_statement_trans_serialize, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL +}; + +GdaSqlStatementContentsInfo * +_gda_sql_statement_rollback_savepoint_get_infos (void) +{ + return &rollback_svp_infos; +} + +/* DELETE SAVEPOINT */ +GdaSqlStatementContentsInfo delete_svp_infos = { + GDA_SQL_STATEMENT_DELETE_SAVEPOINT, + "DELETE_SAVEPOINT", + gda_sql_statement_trans_new, + gda_sql_statement_trans_free, + gda_sql_statement_trans_copy, + gda_sql_statement_trans_serialize, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL +}; + +GdaSqlStatementContentsInfo * +_gda_sql_statement_delete_savepoint_get_infos (void) +{ + return &delete_svp_infos; +} + + +static gpointer +gda_sql_statement_trans_new (void) +{ + GdaSqlStatementTransaction *trans; + trans = g_new0 (GdaSqlStatementTransaction, 1); + trans->isolation_level = GDA_TRANSACTION_ISOLATION_UNKNOWN; + return trans; +} + +static void +gda_sql_statement_trans_free (gpointer stmt) +{ + GdaSqlStatementTransaction *trans = (GdaSqlStatementTransaction *) stmt; + g_free (trans->trans_mode); + g_free (trans->trans_name); + g_free (trans); +} + +static gpointer +gda_sql_statement_trans_copy (gpointer src) +{ + GdaSqlStatementTransaction *dest; + GdaSqlStatementTransaction *trans = (GdaSqlStatementTransaction *) src; + + dest = g_new0 (GdaSqlStatementTransaction, 1); + if (trans->trans_mode) + dest->trans_mode = g_strdup (trans->trans_mode); + if (trans->trans_name) + dest->trans_name = g_strdup (trans->trans_name); + dest->isolation_level = trans->isolation_level; + + return dest; +} + +static gchar * +gda_sql_statement_trans_serialize (gpointer stmt) +{ + GString *string; + gchar *str; + GdaSqlStatementTransaction *trans = (GdaSqlStatementTransaction *) stmt; + + g_return_val_if_fail (stmt, NULL); + + string = g_string_new ("\"contents\":{"); + g_string_append (string, "\"trans_mode\":"); + + str = _json_quote_string (trans->trans_mode); + g_string_append (string, str); + g_free (str); + + g_string_append (string, ",\"trans_name\":"); + str = _json_quote_string (trans->trans_name); + g_string_append (string, str); + g_free (str); + + g_string_append (string, ",\"isol_level\":"); + switch (trans->isolation_level) { + default: + case GDA_TRANSACTION_ISOLATION_UNKNOWN: + str = NULL; + break; + case GDA_TRANSACTION_ISOLATION_READ_COMMITTED: + str = "COMMITTED_READ"; + break; + case GDA_TRANSACTION_ISOLATION_READ_UNCOMMITTED: + str = "UNCOMMITTED_READ"; + break; + case GDA_TRANSACTION_ISOLATION_REPEATABLE_READ: + str = "REPEATABLE_READ"; + break; + case GDA_TRANSACTION_ISOLATION_SERIALIZABLE: + str = "SERIALIZABLE"; + break; + } + if (str) + g_string_append_printf (string, "\"%s\"", str); + else + g_string_append (string, "null"); + + g_string_append_c (string, '}'); + str = string->str; + g_string_free (string, FALSE); + return str; +} + +/** + * gda_sql_statement_trans_take_name + * @stmt: a #GdaSqlStatement pointer + * @value: (transfer full): a G_TYPE_STRING value + * + * Sets the name of the transaction + * + * @value's ownership is transferred to + * @stmt (which means @stmt is then responsible for freeing it when no longer needed). + */ +void +gda_sql_statement_trans_take_name (GdaSqlStatement *stmt, GValue *value) +{ + GdaSqlStatementTransaction *trans = (GdaSqlStatementTransaction *) stmt->contents; + if (trans->trans_name) { + g_free (trans->trans_name); + trans->trans_name = NULL; + } + if (value) { + trans->trans_name = g_value_dup_string (value); + gda_value_free (value); + } +} + +/** + * gda_sql_statement_trans_take_mode + * @stmt: a #GdaSqlStatement pointer + * @value: (transfer full): a G_TYPE_STRING value + * + * Sets the model of the transaction + * + * @value's ownership is transferred to + * @stmt (which means @stmt is then responsible for freeing it when no longer needed). + */ +void +gda_sql_statement_trans_take_mode (GdaSqlStatement *stmt, GValue *value) +{ + GdaSqlStatementTransaction *trans = (GdaSqlStatementTransaction *) stmt->contents; + if (trans->trans_mode) { + g_free (trans->trans_mode); + trans->trans_mode = NULL; + } + if (value) { + trans->trans_mode = g_value_dup_string (value); + gda_value_free (value); + } +} + +/** + * gda_sql_statement_set_isol_level + * @stmt: a #GdaSqlStatement pointer + * @level: the transacion level + * + * Sets the transaction level of the transaction + */ +void +gda_sql_statement_trans_set_isol_level (GdaSqlStatement *stmt, GdaTransactionIsolation level) +{ + GdaSqlStatementTransaction *trans = (GdaSqlStatementTransaction *) stmt->contents; + trans->isolation_level = level; +} diff --git a/.flatpak-builder/cache/objects/2d/6bdeabd72a7f6661497efcbc533d96064b4aff317fd90717bc0e40976e371e.file b/.flatpak-builder/cache/objects/2d/6bdeabd72a7f6661497efcbc533d96064b4aff317fd90717bc0e40976e371e.file new file mode 100644 index 0000000..0ad5be1 --- /dev/null +++ b/.flatpak-builder/cache/objects/2d/6bdeabd72a7f6661497efcbc533d96064b4aff317fd90717bc0e40976e371e.file @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2001 - 2003 Rodrigo Moya + * Copyright (C) 2001 - 2011 Vivien Malerba + * Copyright (C) 2002 Gonzalo Paniagua Javier + * Copyright (C) 2003 Laurent Sansonetti + * Copyright (C) 2003 Xabier Rodríguez Calvar + * Copyright (C) 2004 Paisa Seeluangsawat + * Copyright (C) 2005 Bas Driessen + * Copyright (C) 2005 Álvaro Peńa + * Copyright (C) 2018 Daniel Espinosa + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GDA_ROW_H__ +#define __GDA_ROW_H__ + +#include +#include + +G_BEGIN_DECLS + +#define GDA_TYPE_ROW (gda_row_get_type()) +G_DECLARE_DERIVABLE_TYPE(GdaRow, gda_row, GDA, ROW, GObject) +struct _GdaRowClass { + GObjectClass parent_class; + + /*< private >*/ + /* Padding for future expansion */ + void (*_gda_reserved1) (void); + void (*_gda_reserved2) (void); + void (*_gda_reserved3) (void); + void (*_gda_reserved4) (void); +}; + +/** + * SECTION:gda-row + * @short_description: Individual row of a #GdaDataModelArray object + * @title: GdaRow + * @stability: Stable + * @see_also: #GdaDataModelArray + * + * The #GdaDataModelArray object uses #GdaRow to store each row of data. Each #GdaRow has the same + * number of #GValue values (equal to the number of columns of the data model). + * + * As a side note, the #GdaRow object is also used internally by the implementation of the data models returned + * when executing a SELECT statement. + */ + +GdaRow *gda_row_new (gint count); +GdaRow *gda_row_new_from_data_model (GdaDataModel *model, guint row); +gint gda_row_get_length (GdaRow *row); +GValue *gda_row_get_value (GdaRow *row, gint num); + +/* for database providers mainly */ +void gda_row_invalidate_value (GdaRow *row, GValue *value); +void gda_row_invalidate_value_e (GdaRow *row, GValue *value, GError *error); +gboolean gda_row_value_is_valid (GdaRow *row, GValue *value); +gboolean gda_row_value_is_valid_e (GdaRow *row, GValue *value, GError **error); + +G_END_DECLS + +#endif diff --git a/.flatpak-builder/cache/objects/2d/98609105a9f9fd970e04149a577d411507f7f454ba4e1d2318dbeafc71f5ce.file b/.flatpak-builder/cache/objects/2d/98609105a9f9fd970e04149a577d411507f7f454ba4e1d2318dbeafc71f5ce.file new file mode 100644 index 0000000..fbdba30 --- /dev/null +++ b/.flatpak-builder/cache/objects/2d/98609105a9f9fd970e04149a577d411507f7f454ba4e1d2318dbeafc71f5ce.file @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2001 - 2002 Gonzalo Paniagua Javier + * Copyright (C) 2001 - 2002 Rodrigo Moya + * Copyright (C) 2003 Danilo Schoeneberg + * Copyright (C) 2003 Laurent Sansonetti + * Copyright (C) 2005 - 2012 Vivien Malerba + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GDA_SQLITE_DDL_H__ +#define __GDA_SQLITE_DDL_H__ + +#include + +G_BEGIN_DECLS + +gchar *_gda_sqlite_render_CREATE_TABLE (GdaServerProvider *provider, GdaConnection *cnc, + GdaServerOperation *op, GError **error); +gchar *_gda_sqlite_render_DROP_TABLE (GdaServerProvider *provider, GdaConnection *cnc, + GdaServerOperation *op, GError **error); +gchar *_gda_sqlite_render_RENAME_TABLE (GdaServerProvider *provider, GdaConnection *cnc, + GdaServerOperation *op, GError **error); +gchar *_gda_sqlite_render_ADD_COLUMN (GdaServerProvider *provider, GdaConnection *cnc, + GdaServerOperation *op, GError **error); +gchar *_gda_sqlite_render_DROP_COLUMN (GdaServerProvider *provider, GdaConnection *cnc, + GdaServerOperation *op, GError **error); +gchar *_gda_sqlite_render_RENAME_COLUMN (GdaServerProvider *provider, GdaConnection *cnc, + GdaServerOperation *op, GError **error); +gchar *_gda_sqlite_render_CREATE_INDEX (GdaServerProvider *provider, GdaConnection *cnc, + GdaServerOperation *op, GError **error); +gchar *_gda_sqlite_render_DROP_INDEX (GdaServerProvider *provider, GdaConnection *cnc, + GdaServerOperation *op, GError **error); +gchar *_gda_sqlite_render_CREATE_VIEW (GdaServerProvider *provider, GdaConnection *cnc, + GdaServerOperation *op, GError **error); +gchar *_gda_sqlite_render_DROP_VIEW (GdaServerProvider *provider, GdaConnection *cnc, + GdaServerOperation *op, GError **error); + +G_END_DECLS + +#endif + diff --git a/.flatpak-builder/cache/objects/2d/e33e4449d4fb565ff9078987671208bf4bca83baace16016daf5e03a39025f.file b/.flatpak-builder/cache/objects/2d/e33e4449d4fb565ff9078987671208bf4bca83baace16016daf5e03a39025f.file new file mode 120000 index 0000000..e70323c --- /dev/null +++ b/.flatpak-builder/cache/objects/2d/e33e4449d4fb565ff9078987671208bf4bca83baace16016daf5e03a39025f.file @@ -0,0 +1 @@ +../../share/runtime/locale/nl/share/nl \ No newline at end of file diff --git a/.flatpak-builder/cache/objects/2d/f39fcd6682d48ef87bbfb1ffa8a0ca2cd1d96dbd5466124f24cca0d511abc0.file b/.flatpak-builder/cache/objects/2d/f39fcd6682d48ef87bbfb1ffa8a0ca2cd1d96dbd5466124f24cca0d511abc0.file new file mode 100644 index 0000000..2ff823b --- /dev/null +++ b/.flatpak-builder/cache/objects/2d/f39fcd6682d48ef87bbfb1ffa8a0ca2cd1d96dbd5466124f24cca0d511abc0.file @@ -0,0 +1,412 @@ +/* + * Copyright (C) 2000 - 2003 Rodrigo Moya + * Copyright (C) 2001 Cleber Rodrigues + * Copyright (C) 2002 Gonzalo Paniagua Javier + * Copyright (C) 2003 Laurent Sansonetti + * Copyright (C) 2003 Paisa Seeluangsawat + * Copyright (C) 2003 Xabier Rodríguez Calvar + * Copyright (C) 2004 Paisa Seeluangsawat + * Copyright (C) 2004 Szalai Ferenc + * Copyright (C) 2005 - 2013 Vivien Malerba + * Copyright (C) 2006 - 2008 Murray Cumming + * Copyright (C) 2007 Leonardo Boshell + * Copyright (C) 2010 David King + * Copyright (C) 2011, 2018 Daniel Espinosa + * Copyright (C) 2015 Corentin Noël + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +#define G_LOG_DOMAIN "GDA-row" + +#include "gda-row.h" +#include +#include +#include "gda-data-model.h" + +#define PARENT_TYPE G_TYPE_OBJECT + +typedef struct { + GdaDataModel *model; /* can be NULL */ + guint model_row; + + GValue *fields; /* GValues */ + GError **errors; /* GError for each invalid value at the same position */ + guint nfields; +} GdaRowPrivate; +G_DEFINE_TYPE_WITH_PRIVATE (GdaRow, gda_row, G_TYPE_OBJECT) + +/* properties */ +enum +{ + PROP_NB_VALUES = 1, + PROP_MODEL, + PROP_MODEL_ROW +}; + +static void gda_row_finalize (GObject *object); +static void gda_row_dispose (GObject *object); + +static void gda_row_set_property (GObject *object, + guint param_id, + const GValue *value, + GParamSpec *pspec); +static void gda_row_get_property (GObject *object, + guint param_id, + GValue *value, + GParamSpec *pspec); + +static void +gda_row_class_init (GdaRowClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->finalize = gda_row_finalize; + object_class->dispose = gda_row_dispose; + + /* Properties */ + object_class->set_property = gda_row_set_property; + object_class->get_property = gda_row_get_property; + + g_object_class_install_property (object_class, PROP_NB_VALUES, + g_param_spec_int ("nb-values", "NumValues", "Number of values in the row", + 1, G_MAXINT, 1, + G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE)); + + g_object_class_install_property (object_class, PROP_MODEL, + g_param_spec_object ("model", "Model", "Data model used to get values from", + GDA_TYPE_DATA_MODEL, + G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE)); + + g_object_class_install_property (object_class, PROP_MODEL_ROW, + g_param_spec_int ("model-row", "ModelRow", "Row number in data model to get data from", + 0, G_MAXINT, 0, + G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE)); +} + +static void +gda_row_init (GdaRow *row) +{ + g_return_if_fail (GDA_IS_ROW (row)); + + GdaRowPrivate *priv = gda_row_get_instance_private (row); + priv->model = NULL; + priv->model_row = 0; + priv->fields = NULL; + priv->errors = NULL; + priv->nfields = 0; +} + +static void +gda_row_dispose (GObject *object) +{ + GdaRow *row = (GdaRow *) object; + + g_return_if_fail (GDA_IS_ROW (row)); + + G_OBJECT_CLASS (gda_row_parent_class)->dispose (object); +} + +static void +gda_row_finalize (GObject *object) +{ + GdaRow *row = (GdaRow *) object; + + g_return_if_fail (GDA_IS_ROW (row)); + GdaRowPrivate *priv = gda_row_get_instance_private (row); + + if (priv->model == NULL) { + guint i; + + for (i = 0; i < priv->nfields; i++) { + gda_value_set_null (&(priv->fields [i])); + if (priv->errors && priv->errors [i]) + g_error_free (priv->errors [i]); + } + g_free (priv->fields); + g_free (priv->errors); + + } else { + g_object_unref (priv->model); + priv->model = NULL; + } + + G_OBJECT_CLASS (gda_row_parent_class)->finalize (object); +} + +static void +gda_row_set_property (GObject *object, + guint param_id, + const GValue *value, + GParamSpec *pspec) +{ + GdaRow *row; + + row = GDA_ROW (object); + GdaRowPrivate *priv = gda_row_get_instance_private (row); + switch (param_id) { + case PROP_NB_VALUES: + if (priv->model != NULL) { + g_warning (_("Can't set a number of values, because a data model is in use")); + break; + } + guint i; + g_return_if_fail (!priv->fields); + + priv->nfields = (guint) g_value_get_int (value); + priv->fields = g_new0 (GValue, priv->nfields); + for (i = 0; i < priv->nfields; i++) + gda_value_set_null (& (priv->fields [i])); + break; + case PROP_MODEL: + if (priv->nfields != 0) { + break; + } + priv->model = GDA_DATA_MODEL(g_object_ref (g_value_get_object (value))); + break; + case PROP_MODEL_ROW: + if (priv->nfields != 0) { + break; + } + priv->model_row = g_value_get_uint (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + break; + } +} + +static void +gda_row_get_property (GObject *object, + guint param_id, + GValue *value, + GParamSpec *pspec) +{ + GdaRow *row; + + row = GDA_ROW (object); + GdaRowPrivate *priv = gda_row_get_instance_private (row); + switch (param_id) { + case PROP_NB_VALUES: + g_value_set_int (value, priv->nfields); + break; + case PROP_MODEL: + g_value_set_object (value, priv->model); + break; + case PROP_MODEL_ROW: + g_value_set_uint (value, priv->model_row); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + break; + } +} + +/** + * gda_row_new: + * @count: number of #GValue in the new #GdaRow. + * + * Creates a #GdaRow which can hold @count #GValue values. + * + * Returns: a newly allocated #GdaRow object. + */ +GdaRow * +gda_row_new (gint count) +{ + g_return_val_if_fail (count > 0, NULL); + return (GdaRow*) g_object_new (GDA_TYPE_ROW, "nb-values", count, NULL); +} + +/** + * gda_row_new_from_data_model: + * @model: a #GdaDataModel to get data from. + * @row: row at #GdaDataModel to get data from + * + * Creates a #GdaRow which represent a row in a #GdaDataModel + * + * Returns: (transfer full):a newly allocated #GdaRow object. + */ +GdaRow * +gda_row_new_from_data_model (GdaDataModel *model, guint row) +{ + g_return_val_if_fail (model, NULL); + g_return_val_if_fail (GDA_IS_DATA_MODEL (model), NULL); + return (GdaRow*) g_object_new (GDA_TYPE_ROW, "model", model, "model-row", row, NULL); +} + +/** + * gda_row_get_value: + * @row: a #GdaRow + * @num: field index. + * + * Gets a pointer to a #GValue stored in a #GdaRow. + * + * This is a pointer to the internal array of values. Don't try to free + * or modify it (modifying is reserved to database provider's implementations). + * + * Returns: (nullable) (transfer none): a pointer to the #GValue in the position @num of @row. + */ +GValue * +gda_row_get_value (GdaRow *row, gint num) +{ + g_return_val_if_fail (GDA_IS_ROW (row), NULL); + GdaRowPrivate *priv = gda_row_get_instance_private (row); + if (priv->model == NULL) { + g_return_val_if_fail ((num >= 0) && ((guint) num < priv->nfields), NULL); + return & (priv->fields[num]); + } else { + GError *error = NULL; + const GValue *value = NULL; + g_return_val_if_fail ((num >= 0) && (num < gda_data_model_get_n_columns (priv->model)), NULL); + value = gda_data_model_get_value_at (priv->model, num, priv->model_row, &error); + if (value == NULL) { + g_warning (_("No value can be retrieved from data model's row: %s"), + error ? (error->message ? error->message : _("No Detail")) : _("No error was set")); + } + } + return NULL; +} + +/** + * gda_row_invalidate_value: + * @row: a #GdaRow + * @value: a #GValue belonging to @row (obtained with gda_row_get_value()). + * + * Marks @value as being invalid. This method is mainly used by database + * providers' implementations to report any error while reading a value from the database. + */ +void +gda_row_invalidate_value (G_GNUC_UNUSED GdaRow *row, GValue *value) +{ + return gda_row_invalidate_value_e (row, value, NULL); +} + +/** + * gda_row_invalidate_value_e: + * @row: a #GdaRow + * @value: a #GValue belonging to @row (obtained with gda_row_get_value()). + * @error: (nullable) (transfer full): the error which lead to the invalidation + * + * Marks @value as being invalid. This method is mainly used by database + * providers' implementations to report any error while reading a value from the database. + * + * Since: 4.2.10 + */ +void +gda_row_invalidate_value_e (GdaRow *row, GValue *value, GError *error) +{ + gda_value_set_null (value); + G_VALUE_TYPE (value) = G_TYPE_INVALID; + GdaRowPrivate *priv = gda_row_get_instance_private (row); + if (error) { + guint i; + if (! priv->errors) + priv->errors = g_new0 (GError*, priv->nfields); + for (i = 0; i < priv->nfields; i++) { + if (& (priv->fields[i]) == value) { + if (priv->errors [i]) + g_error_free (priv->errors [i]); + priv->errors [i] = error; + break; + } + } + if (i == priv->nfields) { + g_error_free (error); + g_warning (_("Value not found in row!")); + } + } + else if (priv->errors) { + guint i; + for (i = 0; i < priv->nfields; i++) { + if (& (priv->fields[i]) == value) { + if (priv->errors [i]) { + g_error_free (priv->errors [i]); + priv->errors [i] = NULL; + } + break; + } + } + if (i == priv->nfields) + g_warning (_("Value not found in row!")); + } +} + +/** + * gda_row_value_is_valid: + * @row: a #GdaRow. + * @value: a #GValue belonging to @row (obtained with gda_row_get_value()). + * + * Tells if @value has been marked as being invalid by gda_row_invalidate_value(). + * This method is mainly used by database + * providers' implementations to report any error while reading a value from the database. + * + * Returns: %TRUE if @value is valid + */ +gboolean +gda_row_value_is_valid (GdaRow *row, GValue *value) +{ + return gda_row_value_is_valid_e (row, value, NULL); +} + +/** + * gda_row_value_is_valid_e: + * @row: a #GdaRow. + * @value: a #GValue belonging to @row (obtained with gda_row_get_value()). + * @error: (nullable): a place to store the invalid error, or %NULL + * + * Tells if @value has been marked as being invalid by gda_row_invalidate_value(). + * This method is mainly used by database + * providers' implementations to report any error while reading a value from the database. + * + * Returns: %TRUE if @value is valid + * + * Since: 4.2.10 + */ +gboolean +gda_row_value_is_valid_e (GdaRow *row, GValue *value, GError **error) +{ + gboolean valid; + valid = (G_VALUE_TYPE (value) == G_TYPE_INVALID) ? FALSE : TRUE; + GdaRowPrivate *priv = gda_row_get_instance_private (row); + if (!valid && priv->errors && error) { + guint i; + for (i = 0; i < priv->nfields; i++) { + if (& (priv->fields[i]) == value) { + if (priv->errors [i]) + g_propagate_error (error, g_error_copy (priv->errors [i])); + break; + } + } + if (i == priv->nfields) + g_warning (_("Value not found in row!")); + } + return valid; +} + +/** + * gda_row_get_length: + * @row: a #GdaRow. + * + * Returns: the number of columns that the @row has. + */ +gint +gda_row_get_length (GdaRow *row) +{ + g_return_val_if_fail (GDA_IS_ROW (row), 0); + GdaRowPrivate *priv = gda_row_get_instance_private (row); + if (priv->model == NULL) + return priv->nfields; + return gda_data_model_get_n_columns (priv->model); +} diff --git a/.flatpak-builder/cache/objects/2e/9d3e807c9c7f6447dafd47b40191b4b27b85dadacdb194a205540859e9d713.file b/.flatpak-builder/cache/objects/2e/9d3e807c9c7f6447dafd47b40191b4b27b85dadacdb194a205540859e9d713.file new file mode 100644 index 0000000..0b99836 --- /dev/null +++ b/.flatpak-builder/cache/objects/2e/9d3e807c9c7f6447dafd47b40191b4b27b85dadacdb194a205540859e9d713.file @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2001 Carlos Perelló Marín + * Copyright (C) 2001 - 2003 Rodrigo Moya + * Copyright (C) 2001 - 2012 Vivien Malerba + * Copyright (C) 2002 - 2003 Gonzalo Paniagua Javier + * Copyright (C) 2005 Cygwin Ports Maintainer + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GDA_DATA_MODEL_EXTRA_H__ +#define __GDA_DATA_MODEL_EXTRA_H__ + +#include +#include + +G_BEGIN_DECLS + +void gda_data_model_row_inserted (GdaDataModel *model, gint row); +void gda_data_model_row_updated (GdaDataModel *model, gint row); +void gda_data_model_row_removed (GdaDataModel *model, gint row); +void gda_data_model_reset (GdaDataModel *model); + +G_END_DECLS + +#endif diff --git a/.flatpak-builder/cache/objects/2f/adcf20adb6539d0f566b720cd1b202a604d300096c2f75de410e3ef4f6c19c.file b/.flatpak-builder/cache/objects/2f/adcf20adb6539d0f566b720cd1b202a604d300096c2f75de410e3ef4f6c19c.file new file mode 100644 index 0000000..c702406 --- /dev/null +++ b/.flatpak-builder/cache/objects/2f/adcf20adb6539d0f566b720cd1b202a604d300096c2f75de410e3ef4f6c19c.file @@ -0,0 +1,9 @@ +[Desktop Entry] +Type=Application +Name=GNOME System Ready Sound +Comment=Plays a sound whenever your system is ready for login +Exec=/app/bin/canberra-gtk-play --id="system-ready" --description="GNOME System Ready" +OnlyShowIn=GNOME; +AutostartCondition=GSettings org.gnome.desktop.sound event-sounds +X-GNOME-Autostart-Phase=Application +X-GNOME-Provides=login-sound diff --git a/.flatpak-builder/cache/objects/2f/f80c4863baae154d000b7d7747e2b7922df4b81e1be0706816d5cfc7d49386.dirtree b/.flatpak-builder/cache/objects/2f/f80c4863baae154d000b7d7747e2b7922df4b81e1be0706816d5cfc7d49386.dirtree new file mode 100644 index 0000000..89003c0 Binary files /dev/null and b/.flatpak-builder/cache/objects/2f/f80c4863baae154d000b7d7747e2b7922df4b81e1be0706816d5cfc7d49386.dirtree differ diff --git a/.flatpak-builder/cache/objects/30/38fa8e823b94bcccb2214a1d3a737e07386fe8073c307241d2990845ae31c3.file b/.flatpak-builder/cache/objects/30/38fa8e823b94bcccb2214a1d3a737e07386fe8073c307241d2990845ae31c3.file new file mode 100644 index 0000000..1321b6e --- /dev/null +++ b/.flatpak-builder/cache/objects/30/38fa8e823b94bcccb2214a1d3a737e07386fe8073c307241d2990845ae31c3.file @@ -0,0 +1,159 @@ +/* + * Copyright (C) 2001 - 2002 Carlos Perelló Marín + * Copyright (C) 2001 - 2002 Rodrigo Moya + * Copyright (C) 2001 - 2014 Vivien Malerba + * Copyright (C) 2002 Gonzalo Paniagua Javier + * Copyright (C) 2005 Denis Fortin + * Copyright (C) 2008 Przemysław Grzegorczyk + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GDA_SQLITE_H__ +#define __GDA_SQLITE_H__ + +#include +#include +#include +#include +#include + +#ifdef WITH_BDBSQLITE + #include + #include "gda-symbols-util.h" + #define SQLITE3_CALL(x) (s3r->x) +#else + #include + #define SQLITE3_CALL(p,x) (((Sqlite3ApiRoutines*) gda_sqlite_provider_get_api(p))->x) + #if (SQLITE_VERSION_NUMBER < 3005000) + typedef sqlite_int64 sqlite3_int64; + #endif +#endif + +/* + * Provider's specific connection data + */ +typedef struct { + GdaServerProviderConnectionData parent; + sqlite3 *connection; + GWeakRef provider; + gchar *file; + GHashTable *types_hash; /* key = type name, value = pointer to a GType */ + GType *types_array;/* holds GType values, pointed by @types_hash */ +} SqliteConnectionData; + +extern GHashTable *error_blobs_hash; + + +/** + * API interface to SQLite derived providers + */ +typedef struct { + int (*sqlite3_bind_blob)(sqlite3_stmt*,int,const void*,int n,void(*)(void*)); + int (*sqlite3_bind_double)(sqlite3_stmt*,int,double); + int (*sqlite3_bind_int)(sqlite3_stmt*,int,int); + int (*sqlite3_bind_int64)(sqlite3_stmt*,int,sqlite_int64); + int (*sqlite3_bind_null)(sqlite3_stmt*,int); + int (*sqlite3_bind_text)(sqlite3_stmt*,int,const char*,int n,void(*)(void*)); + int (*sqlite3_bind_zeroblob)(sqlite3_stmt*,int,int); + int (*sqlite3_blob_bytes)(sqlite3_blob*); + int (*sqlite3_blob_close)(sqlite3_blob*); + int (*sqlite3_blob_open)(sqlite3*,const char*,const char*,const char*,sqlite3_int64,int,sqlite3_blob**); + int (*sqlite3_blob_read)(sqlite3_blob*,void*,int,int); + int (*sqlite3_blob_write)(sqlite3_blob*,const void*,int,int); + + int (*sqlite3_busy_timeout)(sqlite3*,int ms); + int (*sqlite3_changes)(sqlite3*); + int (*sqlite3_clear_bindings)(sqlite3_stmt*); + int (*sqlite3_close)(sqlite3*); + int (*sqlite3_close_v2)(sqlite3*); + + const void * (*sqlite3_column_blob)(sqlite3_stmt*,int iCol); + int (*sqlite3_column_bytes)(sqlite3_stmt*,int iCol); + int (*sqlite3_column_count)(sqlite3_stmt*pStmt); + const char * (*sqlite3_column_database_name)(sqlite3_stmt*,int); + const char * (*sqlite3_column_decltype)(sqlite3_stmt*,int i); + double (*sqlite3_column_double)(sqlite3_stmt*,int iCol); + int (*sqlite3_column_int)(sqlite3_stmt*,int iCol); + sqlite_int64 (*sqlite3_column_int64)(sqlite3_stmt*,int iCol); + const char * (*sqlite3_column_name)(sqlite3_stmt*,int); + const char * (*sqlite3_column_origin_name)(sqlite3_stmt*,int); + const char * (*sqlite3_column_table_name)(sqlite3_stmt*,int); + const unsigned char * (*sqlite3_column_text)(sqlite3_stmt*,int iCol); + int (*sqlite3_column_type)(sqlite3_stmt*,int iCol); + + int (*sqlite3_config) (int, ...); + + int (*sqlite3_create_function)(sqlite3*,const char*,int,int,void*,void (*xFunc)(sqlite3_context*,int,sqlite3_value**),void (*xStep)(sqlite3_context*,int,sqlite3_value**),void (*xFinal)(sqlite3_context*)); + int (*sqlite3_create_function_v2)(sqlite3*,const char*,int,int,void*,void (*xFunc)(sqlite3_context*,int,sqlite3_value**),void (*xStep)(sqlite3_context*,int,sqlite3_value**),void (*xFinal)(sqlite3_context*),void(*xDestroy)(void*)); + int (*sqlite3_create_module)(sqlite3*,const char*,const sqlite3_module*,void*); + sqlite3 * (*sqlite3_db_handle)(sqlite3_stmt*); + int (*sqlite3_declare_vtab)(sqlite3*,const char*); + + int (*sqlite3_errcode)(sqlite3*db); + const char * (*sqlite3_errmsg)(sqlite3*); + + int (*sqlite3_exec)(sqlite3*,const char*,sqlite3_callback,void*,char**); + int (*sqlite3_extended_result_codes)(sqlite3*,int); + int (*sqlite3_finalize)(sqlite3_stmt*pStmt); + void (*sqlite3_free)(void*); + void (*sqlite3_free_table)(char**result); + int (*sqlite3_get_table)(sqlite3*,const char*,char***,int*,int*,char**); + sqlite_int64 (*sqlite3_last_insert_rowid)(sqlite3*); + + void *(*sqlite3_malloc)(int); + char * (*sqlite3_mprintf)(const char*,...); + int (*sqlite3_open)(const char*,sqlite3**); + int (*sqlite3_open_v2)(const char *filename, sqlite3 **ppDb, int flags, const char *zVfs); + int (*sqlite3_prepare)(sqlite3*,const char*,int,sqlite3_stmt**,const char**); + int (*sqlite3_prepare_v2)(sqlite3*,const char*,int,sqlite3_stmt**,const char**); + + int (*sqlite3_reset)(sqlite3_stmt*pStmt); + void (*sqlite3_result_blob)(sqlite3_context*,const void*,int,void(*)(void*)); + void (*sqlite3_result_double)(sqlite3_context*,double); + void (*sqlite3_result_error)(sqlite3_context*,const char*,int); + void (*sqlite3_result_int)(sqlite3_context*,int); + void (*sqlite3_result_int64)(sqlite3_context*,sqlite_int64); + void (*sqlite3_result_null)(sqlite3_context*); + void (*sqlite3_result_text)(sqlite3_context*,const char*,int,void(*)(void*)); + + int (*sqlite3_step)(sqlite3_stmt*); + int (*sqlite3_table_column_metadata)(sqlite3*,const char*,const char*,const char*,char const**,char const**,int*,int*,int*); + int (*sqlite3_threadsafe)(void); + + const void * (*sqlite3_value_blob)(sqlite3_value*); + int (*sqlite3_value_bytes)(sqlite3_value*); + int (*sqlite3_value_int)(sqlite3_value*); + double (*sqlite3_value_double)(sqlite3_value*); + sqlite3_int64 (*sqlite3_value_int64)(sqlite3_value*); + const unsigned char * (*sqlite3_value_text)(sqlite3_value*); + int (*sqlite3_value_type)(sqlite3_value*); + + int (*sqlite3_key)(sqlite3 *, const void *, int); + int (*sqlite3_key_v2)(sqlite3 *, const char *, const void *, int); + int (*sqlite3_rekey)(sqlite3 *, const void *, int); + + int (*sqlite3_create_collation) (sqlite3*, const char *, int, void*, int(*xCompare)(void*,int,const void*,int,const void*)); + + int (*sqlite3_enable_load_extension) (sqlite3 *, int); +} Sqlite3ApiRoutines; + +extern Sqlite3ApiRoutines *s3r; + +GModule *gda_sqlite_find_library (const gchar *name_part); +void gda_sqlite_load_symbols (GModule *module, Sqlite3ApiRoutines **apilib); + +#endif diff --git a/.flatpak-builder/cache/objects/30/434cb7875cbd0e25defa5f534fa0a55e393c4c2d6b9b2e2b3f0b70ecb1c7aa.dirtree b/.flatpak-builder/cache/objects/30/434cb7875cbd0e25defa5f534fa0a55e393c4c2d6b9b2e2b3f0b70ecb1c7aa.dirtree new file mode 100644 index 0000000..fdbfea6 Binary files /dev/null and b/.flatpak-builder/cache/objects/30/434cb7875cbd0e25defa5f534fa0a55e393c4c2d6b9b2e2b3f0b70ecb1c7aa.dirtree differ diff --git a/.flatpak-builder/cache/objects/30/6995f415ed5cae5da4cdc109be6602d2cd9ffbeb5d7a5287aa6ae706ca5bef.dirtree b/.flatpak-builder/cache/objects/30/6995f415ed5cae5da4cdc109be6602d2cd9ffbeb5d7a5287aa6ae706ca5bef.dirtree new file mode 100644 index 0000000..b2c1f67 Binary files /dev/null and b/.flatpak-builder/cache/objects/30/6995f415ed5cae5da4cdc109be6602d2cd9ffbeb5d7a5287aa6ae706ca5bef.dirtree differ diff --git a/.flatpak-builder/cache/objects/30/c2f21ba219d7566918f21ac56cde1413f288d7e4f3bb8dfba31adc2bb6c438.file b/.flatpak-builder/cache/objects/30/c2f21ba219d7566918f21ac56cde1413f288d7e4f3bb8dfba31adc2bb6c438.file new file mode 120000 index 0000000..f97f468 --- /dev/null +++ b/.flatpak-builder/cache/objects/30/c2f21ba219d7566918f21ac56cde1413f288d7e4f3bb8dfba31adc2bb6c438.file @@ -0,0 +1 @@ +camera-shutter.oga \ No newline at end of file diff --git a/.flatpak-builder/cache/objects/30/fc2a3ea8c3d1b52ba48abb18a558bde40c3fbe9b67dd382c54330c6e83f9ac.file b/.flatpak-builder/cache/objects/30/fc2a3ea8c3d1b52ba48abb18a558bde40c3fbe9b67dd382c54330c6e83f9ac.file new file mode 100644 index 0000000..2a38548 --- /dev/null +++ b/.flatpak-builder/cache/objects/30/fc2a3ea8c3d1b52ba48abb18a558bde40c3fbe9b67dd382c54330c6e83f9ac.file @@ -0,0 +1,3640 @@ +/* + * Copyright (C) 2001 - 2003 Rodrigo Moya + * Copyright (C) 2002 - 2003 Gonzalo Paniagua Javier + * Copyright (C) 2002 Holger Thon + * Copyright (C) 2002 - 2016 Vivien Malerba + * Copyright (C) 2002 Zbigniew Chyla + * Copyright (C) 2003 Akira TAGOH + * Copyright (C) 2003 Danilo Schoeneberg + * Copyright (C) 2003 Laurent Sansonetti + * Copyright (C) 2003 Philippe CHARLIER + * Copyright (C) 2004 Andrew Hill + * Copyright (C) 2004 Dani Baeyens + * Copyright (C) 2004 - 2011 Murray Cumming + * Copyright (C) 2004 Paisa Seeluangsawat + * Copyright (C) 2004 Szalai Ferenc + * Copyright (C) 2007 Armin Burgmeier + * Copyright (C) 2007 Leonardo Boshell + * Copyright (C) 2008 Przemysław Grzegorczyk + * Copyright (C) 2009 Bas Driessen + * Copyright (C) 2010 David King + * Copyright (C) 2010 Jonh Wendell + * Copyright (C) 2011 - 2019 Daniel Espinosa + * Copyright (C) 2013 Miguel Angel Cabrera Moya + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +#define G_LOG_DOMAIN "GDA-value" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#define __GDA_INTERNAL__ +#include "dir-blob-op.h" + +#define l_g_value_unset(val) G_STMT_START{ if (G_IS_VALUE (val)) g_value_unset (val); }G_STMT_END +#ifdef G_OS_WIN32 +#define bcmp(s1, s2, n) memcmp ((s1), (s2), (n)) +#endif + +/** + * GdaNumeric: (set-value-func gda_value_set_numeric) (get-value-func gda_value_get_numeric) + * @number: a string representing a number + * @precision: precision to use when @number is converted (not implemented jet) + * @width: not implemented jet + * + * Holds numbers represented as strings. + * + * This struct must be considered as opaque. Any access to its members must use its + * accessors added since version 5.0.2. + */ +struct _GdaNumeric { + gchar* number; /* stored in the "C" locale, never NULL */ + glong precision; + glong width; + + /*< private >*/ + gpointer reserved; /* reserved for future usage with GMP (http://gmplib.org/) */ +}; + + + +static gboolean +set_from_string (GValue *value, const gchar *as_string) +{ + gboolean retval; + gchar *endptr [1]; + gdouble dvalue; + glong lvalue; + gulong ulvalue; + GType type; + + g_return_val_if_fail (value, FALSE); + if (! G_IS_VALUE (value)) { + g_warning ("Can't set value for a G_TYPE_INVALID GValue"); + return FALSE; + } + else if (GDA_VALUE_HOLDS_NULL (value)) { + g_warning ("Can't set value for a NULL GValue"); + return FALSE; + } + + type = G_VALUE_TYPE (value); + g_value_reset (value); + + /* custom transform function */ + retval = FALSE; + if (type == G_TYPE_BOOLEAN) { + if ((as_string[0] == 't') || (as_string[0] == 'T')) { + g_value_set_boolean (value, TRUE); + retval = TRUE; + } + else if ((as_string[0] == 'f') || (as_string[0] == 'F')) { + g_value_set_boolean (value, FALSE); + retval = TRUE; + } + else { + gint i; + i = atoi (as_string); /* Flawfinder: ignore */ + g_value_set_boolean (value, i ? TRUE : FALSE); + retval = TRUE; + } + } + else if (type == G_TYPE_INT64) { + gint64 i64; + i64 = g_ascii_strtoll (as_string, endptr, 10); + if (*as_string != '\0' && **endptr == '\0'){ + g_value_set_int64 (value, i64); + retval = TRUE; + } + } + else if (type == G_TYPE_UINT64) { + guint64 ui64; + ui64 = g_ascii_strtoull (as_string, endptr, 10); + if (*as_string != '\0' && **endptr == '\0'){ + g_value_set_uint64 (value, ui64); + retval = TRUE; + } + } + else if (type == G_TYPE_INT) { + lvalue = strtol (as_string, endptr, 10); + if (*as_string != '\0' && **endptr == '\0'){ + g_value_set_int (value, (gint32) lvalue); + retval = TRUE; + } + } + else if (type == G_TYPE_UINT) { + ulvalue = strtoul (as_string, endptr, 10); + if (*as_string!=0 && **endptr==0) { + g_value_set_uint(value,(guint32)ulvalue); + retval = TRUE; + } + } + else if (type == GDA_TYPE_SHORT) { + lvalue = strtol (as_string, endptr, 10); + if (*as_string != '\0' && **endptr == '\0'){ + gda_value_set_short (value, (gint16) lvalue); + retval = TRUE; + } + } + else if (type == GDA_TYPE_USHORT) { + ulvalue = strtoul (as_string, endptr, 10); + if (*as_string!=0 && **endptr==0) { + gda_value_set_ushort(value,(guint16)ulvalue); + retval = TRUE; + } + } + else if (type == G_TYPE_CHAR) { + lvalue = strtol (as_string, endptr, 10); + if (*as_string!=0 && **endptr==0) { + g_value_set_schar(value,(gint)lvalue); + retval = TRUE; + } + } + else if (type == G_TYPE_UCHAR) { + ulvalue = strtoul (as_string,endptr, 10); + if (*as_string!=0 && **endptr==0) { + g_value_set_uchar(value,(guchar)ulvalue); + retval = TRUE; + } + } + else if (type == G_TYPE_FLOAT) { + dvalue = g_ascii_strtod (as_string, endptr); + if (*as_string != '\0' && **endptr == '\0'){ + g_value_set_float (value, (gfloat) dvalue); + retval = TRUE; + } + } + else if (type == G_TYPE_DOUBLE) { + dvalue = g_ascii_strtod (as_string, endptr); + if (*as_string != '\0' && **endptr == '\0'){ + g_value_set_double (value, dvalue); + retval = TRUE; + } + } + else if (type == GDA_TYPE_NUMERIC) { + GdaNumeric *numeric = gda_numeric_new (); + gda_numeric_set_from_string (numeric, as_string); + gda_value_set_numeric (value, numeric); + gda_numeric_free (numeric); + retval = TRUE; + } + else if (type == G_TYPE_DATE) { + GDate *gdate; + gdate = g_date_new (); + + if (gda_parse_iso8601_date (gdate, as_string)) { + g_value_take_boxed (value, gdate); + retval = TRUE; + } + else + g_date_free (gdate); + } + else if (type == GDA_TYPE_TIME) { + GdaTime* timegda = gda_parse_iso8601_time (as_string); + if (timegda != NULL) { + g_value_take_boxed (value, timegda); + retval = TRUE; + } + } + else if (g_type_is_a (type, G_TYPE_DATE_TIME)) { + GTimeZone *tz = g_time_zone_new_utc (); + GDateTime* timestamp = g_date_time_new_from_iso8601 (as_string,tz); + if (timestamp) { + g_value_set_boxed (value, timestamp); + retval = TRUE; + g_date_time_unref (timestamp); + } + g_time_zone_unref (tz); + } + else if (type == GDA_TYPE_NULL) { + gda_value_set_null (value); + retval = TRUE; + } + else if (type == G_TYPE_GTYPE) { + GType gt; + gt = gda_g_type_from_string (as_string); + if (gt != G_TYPE_INVALID) { + g_value_set_gtype (value, gt); + retval = TRUE; + } + } + else if (type == G_TYPE_ULONG) + { + gulong ulvalue; + + ulvalue = strtoul (as_string, endptr, 10); + if (*as_string!=0 && **endptr==0) { + g_value_set_ulong (value, ulvalue); + retval = TRUE; + } + } + else if (type == G_TYPE_LONG) + { + glong lvalue; + + lvalue = strtol (as_string, endptr, 10); + if (*as_string!=0 && **endptr==0) { + g_value_set_long (value, lvalue); + retval = TRUE; + } + } + else if (type == GDA_TYPE_BINARY) { + GdaBinary *bin; + bin = gda_string_to_binary (as_string); + if (bin) { + gda_value_take_binary (value, bin); + retval = TRUE; + } + } + else if (type == GDA_TYPE_BLOB) { + GdaBlob *blob; + blob = gda_string_to_blob (as_string); + if (blob) { + gda_value_take_blob (value, blob); + retval = TRUE; + } + } + else if (g_value_type_transformable (G_TYPE_STRING, type)) { + /* use the GLib type transformation function */ + GValue *string; + + string = g_new0 (GValue, 1); + g_value_init (string, G_TYPE_STRING); + g_value_set_string (string, as_string); + + g_value_transform (string, value); + gda_value_free (string); + + retval = TRUE; + } + + return retval; +} + +/* + * Register the NULL type in the GType system + */ + +static gpointer +gda_null_copy (G_GNUC_UNUSED gpointer boxed) +{ + return (gpointer) NULL; +} + +static void +gda_null_free (G_GNUC_UNUSED gpointer boxed) +{ +} + +GType +gda_null_get_type (void) +{ + static GType type = 0; + + if (G_UNLIKELY (type == 0)) { + type = g_boxed_type_register_static ("GdaNull", + (GBoxedCopyFunc) gda_null_copy, + (GBoxedFreeFunc) gda_null_free); + } + + return type; +} + +/* + * Register the DEFAULT type in the GType system + */ +static void +string_to_default (const GValue *src, GValue *dest) +{ + g_return_if_fail (G_VALUE_HOLDS_STRING (src) && GDA_VALUE_HOLDS_DEFAULT (dest)); + g_value_set_boxed (dest, g_value_get_string (src)); +} + +static void +default_to_string (const GValue *src, GValue *dest) +{ + gchar *str; + g_return_if_fail (G_VALUE_HOLDS_STRING (dest) && GDA_VALUE_HOLDS_DEFAULT (src)); + str = (gchar*) g_value_get_boxed (src); + g_value_set_string (dest, str); +} + +static gpointer +gda_default_copy (G_GNUC_UNUSED gpointer boxed) +{ + if (boxed) + return (gpointer) g_strdup (boxed); + else + return (gpointer) NULL; +} + +static void +gda_default_free (G_GNUC_UNUSED gpointer boxed) +{ + g_free (boxed); +} + +GType +gda_default_get_type (void) +{ + static GType type = 0; + + if (G_UNLIKELY (type == 0)) { + type = g_boxed_type_register_static ("GdaDefault", + (GBoxedCopyFunc) gda_default_copy, + (GBoxedFreeFunc) gda_default_free); + + g_value_register_transform_func (G_TYPE_STRING, + type, + string_to_default); + + g_value_register_transform_func (type, + G_TYPE_STRING, + default_to_string); + } + + return type; +} + +// Declare GDA_TYPE_TEXT + +struct _GdaText { + gchar *str; +}; + +/** + * gda_text_new: + * + * Creates a new #GdaText object, initialy with no string. + * Use #gda_text_set_string() to set a string to. + * + * Returns: (transfer full): a new #GdaText object + */ +GdaText* +gda_text_new () { + GdaText *t = g_new0 (GdaText, 1); + t->str = NULL; + return t; +} + + +/** + * gda_text_free: + * @text: a #GdaText object + * + * Free resources on #GdaText object. + */ +void +gda_text_free (GdaText *text) +{ + g_return_if_fail (text); + if (text->str != NULL) { + g_free (text->str); + } + g_free (text); +} + +/** + * gda_text_get_string: + * @text: a #GdaText object + * + * Returns: (transfer none): a string represented by #GdaText + */ +const gchar* +gda_text_get_string (GdaText *text) { + g_return_val_if_fail (text != NULL, NULL); + + return (const gchar*) text->str; +} + +/** + * gda_text_set_string: + * @text: a #GdaText object + * @str: a string to set from + * + * Set string. The string is duplicated. + */ +void +gda_text_set_string (GdaText *text, const gchar *str) { + g_return_if_fail (text); + if (text->str != NULL) { + g_free (text->str); + } + if (str != NULL) { + text->str = g_strdup (str); + } else { + text->str = NULL; + } +} + +/** + * gda_text_take_string: + * @text: a #GdaText object + * @str: a string to take ownership on + * + * Takes ownership on a given string, so you don't need to free it. + */ +void +gda_text_take_string (GdaText *text, gchar *str) { + g_return_if_fail (text); + if (text->str != NULL) { + g_free (text->str); + } + text->str = str; +} +static void +string_to_text (const GValue *src, GValue *dest) +{ + GdaText *t; + + g_return_if_fail (G_VALUE_HOLDS_STRING (src) && GDA_VALUE_HOLDS_TEXT (dest)); + + t = gda_text_new (); + if (t->str) { + g_free (t->str); + } + gda_text_set_string (t, g_value_get_string (src)); + g_value_take_boxed (dest, t); +} + +static void +text_to_string (const GValue *src, GValue *dest) +{ + g_return_if_fail (G_VALUE_HOLDS_STRING (dest) && GDA_VALUE_HOLDS_TEXT (src)); + + GdaText *text; + + text = (GdaText*) g_value_get_boxed (src); + if (text != NULL) { + g_value_set_string (dest, gda_text_get_string (text)); + } else { + g_value_set_string (dest, NULL); + } +} + +static GdaText* +gda_text_copy (GdaText *boxed) +{ + GdaText *t = gda_text_new (); + if (boxed->str != NULL) { + t->str = g_strdup (boxed->str); + } else { + t->str = NULL; + } + return t; +} + +static void +register_transformation_func (GType type) { + g_value_register_transform_func (G_TYPE_STRING, + type, + string_to_text); + g_value_register_transform_func (type, + G_TYPE_STRING, + text_to_string); +} + +G_DEFINE_BOXED_TYPE_WITH_CODE(GdaText, gda_text, gda_text_copy, gda_text_free, + register_transformation_func(g_define_type_id)) + +// GdaBinary + +struct _GdaBinary { + guchar *data; + glong binary_length; +}; + +/* + * Register the GdaBinary type in the GType system + */ + +/* Transform a String GValue to a GdaBinary*/ +static void +string_to_binary (const GValue *src, GValue *dest) +{ + GdaBinary *bin; + const gchar *as_string; + + g_return_if_fail (G_VALUE_HOLDS_STRING (src) && + GDA_VALUE_HOLDS_BINARY (dest)); + + as_string = g_value_get_string (src); + + bin = gda_string_to_binary (as_string); + g_return_if_fail (bin); + gda_value_take_binary (dest, bin); +} + +static void +binary_to_string (const GValue *src, GValue *dest) +{ + gchar *str; + + g_return_if_fail (G_VALUE_HOLDS_STRING (dest) && + GDA_VALUE_HOLDS_BINARY (src)); + + str = gda_binary_to_string (gda_value_get_binary (src), 0); + + g_value_take_string (dest, str); +} + +GType +gda_binary_get_type (void) +{ + static GType type = 0; + + if (G_UNLIKELY (type == 0)) { + type = g_boxed_type_register_static ("GdaBinary", + (GBoxedCopyFunc) gda_binary_copy, + (GBoxedFreeFunc) gda_binary_free); + + g_value_register_transform_func (G_TYPE_STRING, + type, + string_to_binary); + + g_value_register_transform_func (type, + G_TYPE_STRING, + binary_to_string); + } + + return type; +} + + +/* + * Register the GdaBlob type in the GType system + */ +/* Transform a String GValue to a GdaBlob*/ +static void +string_to_blob (const GValue *src, GValue *dest) +{ + GdaBlob *blob; + const gchar *as_string; + + g_return_if_fail (G_VALUE_HOLDS_STRING (src) && + GDA_VALUE_HOLDS_BLOB (dest)); + + as_string = g_value_get_string (src); + + blob = gda_string_to_blob (as_string); + g_return_if_fail (blob); + gda_value_take_blob (dest, blob); +} + +static void +blob_to_string (const GValue *src, GValue *dest) +{ + gchar *str; + + g_return_if_fail (G_VALUE_HOLDS_STRING (dest) && + GDA_VALUE_HOLDS_BLOB (src)); + + str = gda_blob_to_string ((GdaBlob *) gda_value_get_blob ((GValue *) src), 0); + + g_value_take_string (dest, str); +} + +/** + * gda_binary_new: + * + * Creates a new #GdaBinary coping data. + * + * Returns: (transfer full): the newly created #GdaBinary. + * + * Since: 6.0 + */ +GdaBinary* +gda_binary_new (void) +{ + GdaBinary *binary = g_new0 (GdaBinary, 1); + + binary->data = NULL; + binary->binary_length = 0; + + return (GdaBinary*) binary; +} + +/** + * gda_binary_set_data: + * @binary: a #GdaBinary pointer + * @val: (array length=size) (element-type guint8): value to be copied by #GdaBinary. + * @size: the size of the memory pool pointer to by @val. + * + * Set binary data to a #GdaBinary, holding a copy of the data. + * + * Since: 6.0 + */ +void +gda_binary_set_data (GdaBinary *binary, const guchar *val, glong size) +{ + g_return_if_fail (binary); + g_return_if_fail (val); + if (binary->data) + g_free (binary->data); + binary->data = g_memdup (val, size); + binary->binary_length = size; +} + +/** + * gda_binary_take_data: + * @val: (array length=size) (element-type guint8): value to be taken by #GdaBinary. + * @size: the size of the memory pool pointer to by @val. + * + * Set binary data to a #GdaBinary, directly holding @val (no copy made). + */ +void +gda_binary_take_data (GdaBinary *binary, guchar *val, glong size) +{ + g_return_if_fail (binary); + g_return_if_fail (val); + if (binary->data) + g_free (binary->data); + binary->data = val; + binary->binary_length = size; +} + + +/** + * gda_binary_get_data: + * @binary: a #GdaBinary pointer + * + * Returns: (transfer none): associated data to #GdaBinary. + * + * Since: 6.0 + */ +gpointer +gda_binary_get_data (GdaBinary *binary) +{ + g_return_val_if_fail (binary, NULL); + + return binary->data; +} + + + +/** + * gda_binary_reset_data: + * @binary: a #GdaBinary pointer + * + * Frees data referenced by #GdaBinary + * + * Since: 6.0 + */ +void +gda_binary_reset_data (GdaBinary *binary) +{ + g_return_if_fail (binary); + + if (binary->data != NULL) + g_free (binary->data); + binary->data = NULL; + binary->binary_length = 0; +} + + +/** + * gda_binary_get_size: + * + * Returns: size of associated data to #GdaBinary or -1 in case of error. + * + * Since: 6.0 + */ +glong +gda_binary_get_size (const GdaBinary *binary) +{ + g_return_val_if_fail (binary, -1); + + return binary->binary_length; +} + + +/** + * gda_binary_copy: + * @src: source to get a copy from. + * + * Creates a new #GdaBinary structure from an existing one. + + * Returns: (transfer full): a newly allocated #GdaBinary which contains a copy of information in @boxed. + * + */ +GdaBinary* +gda_binary_copy (GdaBinary *src) +{ + GdaBinary *copy = NULL; + + g_return_val_if_fail (src, NULL); + + copy = g_new0 (GdaBinary, 1); + copy->data = g_memdup (src->data, src->binary_length); + copy->binary_length = src->binary_length; + + return copy; +} + +/** + * gda_binary_free: + * @binary: (transfer full): #GdaBinary to free. + * + * Deallocates all memory associated to the given #GdaBinary. + */ +void +gda_binary_free (GdaBinary *binary) +{ + g_return_if_fail (binary); + + if (binary->data) + g_free (binary->data); + g_free (binary); +} + +/** + * gda_value_new_binary: + * @val: (transfer full): value to set for the new #GValue. + * @size: the size of the memory pool pointer to by @val. + * + * Makes a new #GValue of type #GDA_TYPE_BINARY with value @val. + * + * Returns: (transfer full): the newly created #GValue. + * + * Free-function: gda_value_free + */ +GValue * +gda_value_new_binary (const guchar *val, glong size) +{ + GValue *value; + GdaBinary binary; + + /* We use the const on the function parameter to make this clearer, + * but it would be awkward to keep the const in the struct. + */ + binary.data = (guchar*) val; + binary.binary_length = size; + + value = g_new0 (GValue, 1); + gda_value_set_binary (value, &binary); + + return value; +} + + + +// GdaBlob + +struct _GdaBlob { + GdaBinary *data; + GdaBlobOp *op; +}; + + +GType +gda_blob_get_type (void) +{ + static GType type = 0; + + if (G_UNLIKELY (type == 0)) { + type = g_boxed_type_register_static ("GdaBlob", + (GBoxedCopyFunc) gda_blob_copy, + (GBoxedFreeFunc) gda_blob_free); + + g_value_register_transform_func (G_TYPE_STRING, + type, + string_to_blob); + + g_value_register_transform_func (type, + G_TYPE_STRING, + blob_to_string); + } + + return type; +} + +/** + * gda_blob_new: + * + * Creates a new #GdaBlob. + * + * Returns: (transfer full): a newly allocated #GdaBlob. + * + * Since: 6.0 + */ +GdaBlob* +gda_blob_new (void) +{ + GdaBlob* blob = g_new0 (GdaBlob, 1); + blob->data = gda_binary_new (); + + return (GdaBlob*) blob; +} + +/** + * gda_blob_get_binary: + * @blob: a #GdaBlob pointer + * + * Returns: (transfer none): associated #GdaBinary. + * + * Since: 6.0 + */ +GdaBinary* +gda_blob_get_binary (GdaBlob *blob) +{ + g_return_val_if_fail (blob, NULL); + + return blob->data; +} + +/** + * gda_blob_get_op: + * @blob: a #GdaBlob pointer + * + * Returns: (transfer none): associated #GdaBlobOp. + * + * Since: 6.0 + */ +GdaBlobOp* +gda_blob_get_op (GdaBlob *blob) +{ + g_return_val_if_fail (blob, NULL); + + return blob->op; +} + + +/** + * gda_blob_copy: + * @src: source to get a copy from. + * + * Creates a new #GdaBlob structure from an existing one. + + * Returns: (transfer full): a newly allocated #GdaBlob which contains a copy of information in @boxed. + * + */ +GdaBlob* +gda_blob_copy (GdaBlob *src) +{ + GdaBlob *copy = NULL; + + g_return_val_if_fail (src != NULL, NULL); + + copy = g_new0 (GdaBlob, 1); + copy->data = gda_binary_new (); + if (! src->data) + return copy; + + if (src->data->data) + gda_binary_set_data (copy->data, + gda_binary_get_data (src->data), + gda_binary_get_size (src->data)); + gda_blob_set_op (copy, src->op); + + return (GdaBlob*) copy; +} + +/** + * gda_blob_free: + * @blob: (transfer full): #GdaBlob to free. + * + * Deallocates all memory associated to the given #GdaBlob. + */ +void +gda_blob_free (GdaBlob *blob) +{ + g_return_if_fail (blob); + + if (blob->op) { + g_object_unref (blob->op); + blob->op = NULL; + } + gda_binary_free (blob->data); + g_free (blob); +} + +/** + * gda_blob_set_op: + * @blob: a #GdaBlob value + * @op: (nullable): a #GdaBlobOp object, or %NULL + * + * Correctly assigns @op to @blob (increases @op's reference count) + */ +void +gda_blob_set_op (GdaBlob *blob, GdaBlobOp *op) +{ + g_return_if_fail (blob); + + if (blob->op) { + g_object_unref (blob->op); + blob->op = NULL; + } + if (op) { + g_return_if_fail (GDA_IS_BLOB_OP (op)); + blob->op = g_object_ref (op); + } +} + +/** + * GdaGeometricPoint: + * @x: + * @y: + */ +struct _GdaGeometricPoint { + gdouble x; + gdouble y; +}; + +/* + * Register the GdaGeometricPoint type in the GType system + */ +static void +geometric_point_to_string (const GValue *src, GValue *dest) +{ + GdaGeometricPoint *point; + gchar *str; + g_return_if_fail (G_VALUE_HOLDS_STRING (dest) && + GDA_VALUE_HOLDS_GEOMETRIC_POINT (src)); + + point = (GdaGeometricPoint *) gda_value_get_geometric_point ((GValue *) src); + if (point) + str = g_strdup_printf ("(%.*g,%.*g)", DBL_DIG, point->x, + DBL_DIG, point->y); + else + str = g_strdup_printf ("(%.*g,%.*g)", + DBL_DIG, 0., + DBL_DIG, 0.); + g_value_take_string (dest, str); +} + +/* Transform a String GValue to a GdaGeometricPoint from a string like "(3.2,5.6)" */ +static void +string_to_geometric_point (const GValue *src, GValue *dest) +{ + GdaGeometricPoint *point; + const gchar *as_string; + + g_return_if_fail (G_VALUE_HOLDS_STRING (src) && + GDA_VALUE_HOLDS_GEOMETRIC_POINT (dest)); + + as_string = g_value_get_string (src); + point = g_new0 (GdaGeometricPoint, 1); + + as_string++; + point->x = atof (as_string); + as_string = strchr (as_string, ','); + as_string++; + point->y = atof (as_string); + + gda_value_set_geometric_point (dest, point); + g_free (point); +} + +GType +gda_geometric_point_get_type (void) +{ + static GType type = 0; + + if (G_UNLIKELY (type == 0)) { + type = g_boxed_type_register_static ("GdaGeometricPoint", + (GBoxedCopyFunc) gda_geometric_point_copy, + (GBoxedFreeFunc) gda_geometric_point_free); + + g_value_register_transform_func (G_TYPE_STRING, + type, + string_to_geometric_point); + + g_value_register_transform_func (type, + G_TYPE_STRING, + geometric_point_to_string); + } + + return type; +} + +/** + * gda_geometric_point_copy: + * + * Returns: (transfer full): + */ +GdaGeometricPoint* +gda_geometric_point_copy (GdaGeometricPoint *gp) +{ + GdaGeometricPoint *copy; + + g_return_val_if_fail (gp, NULL); + + copy = g_new0 (GdaGeometricPoint, 1); + copy->x = gp->x; + copy->y = gp->y; + + return copy; +} + +void +gda_geometric_point_free (GdaGeometricPoint *gp) +{ + g_free (gp); +} + + +/** + * gda_geometric_point_new: + * + * Returns: (transfer full): a new #GdaGeometricPoint + */ +GdaGeometricPoint* +gda_geometric_point_new (void) +{ + return g_new0 (GdaGeometricPoint, 1); +} +/** + * gda_geometric_point_get_x: + * + */ +gdouble +gda_geometric_point_get_x (GdaGeometricPoint* gp) +{ + g_return_val_if_fail (gp != NULL, 0); + return gp->x; +} +/** + * gda_geometric_point_set_x: + * + */ +void +gda_geometric_point_set_x (GdaGeometricPoint* gp, double x) +{ + g_return_if_fail (gp != NULL); + gp->x = x; +} +/** + * gda_geometric_point_get_y: + * + */ +gdouble +gda_geometric_point_get_y (GdaGeometricPoint* gp) +{ + g_return_val_if_fail (gp != NULL, 0); + return gp->y; +} +/** + * gda_geometric_point_set_y: + * + */ +void +gda_geometric_point_set_y (GdaGeometricPoint* gp, double y) +{ + g_return_if_fail (gp != NULL); + gp->y = y; +} + + +/* + * Register the GdaNumeric type in the GType system + */ +static void +numeric_to_string (const GValue *src, GValue *dest) +{ + const GdaNumeric *numeric; + + g_return_if_fail (G_VALUE_HOLDS_STRING (dest) && + GDA_VALUE_HOLDS_NUMERIC (src)); + + numeric = gda_value_get_numeric (src); + if (numeric) + g_value_set_string (dest, numeric->number); + else + g_value_set_string (dest, "0.0"); +} + +static void +numeric_to_int (const GValue *src, GValue *dest) +{ + const GdaNumeric *numeric; + + g_return_if_fail (G_VALUE_HOLDS_INT (dest) && + GDA_VALUE_HOLDS_NUMERIC (src)); + + numeric = gda_value_get_numeric (src); + if (numeric) { + glong tmp; + tmp = atol (numeric->number); /* Flawfinder: ignore */ + if ((tmp < G_MININT) || (tmp > G_MAXINT)) + g_warning ("Integer overflow for value %ld", tmp); + g_value_set_int (dest, tmp); + } + else + g_value_set_int (dest, 0); +} + +static void +numeric_to_uint (const GValue *src, GValue *dest) +{ + const GdaNumeric *numeric; + + g_return_if_fail (G_VALUE_HOLDS_UINT (dest) && + GDA_VALUE_HOLDS_NUMERIC (src)); + + numeric = gda_value_get_numeric (src); + if (numeric) { + glong tmp; + tmp = atol (numeric->number); /* Flawfinder: ignore */ + if ((tmp < 0) || (tmp > (glong)G_MAXUINT)) + g_warning ("Unsigned integer overflow for value %ld", tmp); + g_value_set_uint (dest, tmp); + } + else + g_value_set_uint (dest, 0); +} + +static void +numeric_to_boolean (const GValue *src, GValue *dest) +{ + const GdaNumeric *numeric; + + g_return_if_fail (G_VALUE_HOLDS_BOOLEAN (dest) && + GDA_VALUE_HOLDS_NUMERIC (src)); + + numeric = gda_value_get_numeric (src); + if (numeric) + g_value_set_boolean (dest, atoi (numeric->number)); /* Flawfinder: ignore */ + else + g_value_set_boolean (dest, 0); +} + +static void +numeric_to_double (const GValue *src, GValue *dest) +{ + const GdaNumeric *numeric; + + g_return_if_fail (G_VALUE_HOLDS_DOUBLE (dest) && + GDA_VALUE_HOLDS_NUMERIC (src)); + + numeric = gda_value_get_numeric (src); + if (numeric) + g_value_set_double (dest, gda_numeric_get_double (numeric)); + else + g_value_set_double (dest, 0.0); +} + +static void +numeric_to_float (const GValue *src, GValue *dest) +{ + const GdaNumeric *numeric; + + g_return_if_fail (G_VALUE_HOLDS_FLOAT (dest) && + GDA_VALUE_HOLDS_NUMERIC (src)); + + numeric = gda_value_get_numeric (src); + if (numeric) + g_value_set_float (dest, (float) gda_numeric_get_double (numeric)); + else + g_value_set_float (dest, 0.0); +} + +GType +gda_numeric_get_type (void) +{ + static GType type = 0; + + if (G_UNLIKELY (type == 0)) { + type = g_boxed_type_register_static ("GdaNumeric", + (GBoxedCopyFunc) gda_numeric_copy, + (GBoxedFreeFunc) gda_numeric_free); + + /* FIXME: No function to Transform String to from GdaNumeric */ + + g_value_register_transform_func (type, G_TYPE_STRING, numeric_to_string); + g_value_register_transform_func (type, G_TYPE_INT, numeric_to_int); + g_value_register_transform_func (type, G_TYPE_UINT, numeric_to_uint); + g_value_register_transform_func (type, G_TYPE_BOOLEAN, numeric_to_boolean); + g_value_register_transform_func (type, G_TYPE_DOUBLE, numeric_to_double); + g_value_register_transform_func (type, G_TYPE_FLOAT, numeric_to_float); + } + + return type; +} + + +/** + * gda_numeric_copy: + * @src: source to get a copy from. + * + * Creates a new #GdaNumeric structure from an existing one. + + * Returns: (transfer full): a newly allocated #GdaNumeric which contains a copy of information in @boxed. + * + * Free-function: gda_numeric_free + */ + +GdaNumeric* +gda_numeric_copy (GdaNumeric *src) +{ + GdaNumeric *copy; + gchar *str; + + g_return_val_if_fail (src, NULL); + + copy = gda_numeric_new (); + + str = gda_numeric_get_string (src); + gda_numeric_set_from_string (copy, str); + g_free (str); + + gda_numeric_set_width (copy, gda_numeric_get_width (src)); + gda_numeric_set_precision (copy, gda_numeric_get_precision (src)); + + return copy; +} + +/** + * gda_numeric_free: + * @numeric: (transfer full): a #GdaNumeric pointer + * + * Deallocates all memory associated to the given @boxed + */ +void +gda_numeric_free (GdaNumeric *numeric) +{ + g_return_if_fail (numeric); + + g_free (numeric->number); + g_free (numeric); +} + +static gchar* +gda_dtostr_dup (const double value) +{ + char buffer[G_ASCII_DTOSTR_BUF_SIZE]; + g_ascii_dtostr (buffer, sizeof (buffer), value); + return g_strdup (buffer); +} + +/** + * gda_numeric_new: + * + * Creates a new #GdaNumeric with defaults. + * + * Returns: (transfer full): a new #GdaNumeric. + * Since: 5.0.2 + */ +GdaNumeric* +gda_numeric_new (void) +{ + GdaNumeric *n = g_new0 (GdaNumeric, 1); + n->number = gda_dtostr_dup (0.0); + return n; +} + +/** + * gda_numeric_set_from_string: + * @numeric: a #GdaNumeric + * @str: a string representing a number, in the C locale format + * + * Sets @numeric with a number represented by @str, in the C locale format (dot as a fraction separator). + * + * Since: 5.0.2 + */ +void +gda_numeric_set_from_string (GdaNumeric *numeric, const gchar* str) +{ + g_return_if_fail (numeric); + g_return_if_fail (str); + g_free (numeric->number); + + gdouble number; + gchar *endptr = NULL; + number = g_ascii_strtod (str, &endptr); + if (*endptr) + numeric->number = gda_dtostr_dup (number); + else + numeric->number = g_strdup (str); +} + +/** + * gda_numeric_set_double: + * @numeric: a #GdaNumeric + * @number: a #gdouble + * + * Sets @numeric using a #gdouble represented by @number. + * + * Since: 5.0.2 + */ +void +gda_numeric_set_double (GdaNumeric *numeric, gdouble number) +{ + g_return_if_fail (numeric); + g_free (numeric->number); + numeric->number = gda_dtostr_dup (number); +} + +/** + * gda_numeric_get_double: + * @numeric: a #GdaNumeric + * + * Returns: a #gdouble representation of @numeric + * Since: 5.0.2 + */ +gdouble +gda_numeric_get_double (const GdaNumeric *numeric) +{ + g_return_val_if_fail (numeric, 0.0); + return g_ascii_strtod (numeric->number, NULL); +} + +/** + * gda_numeric_set_width: + * @numeric: a #GdaNumeric + * @width: a #glong + * + * Sets the width of a #GdaNumeric. (Not yet implemented). + * + * Since: 5.0.2 + */ +void +gda_numeric_set_width (GdaNumeric *numeric, glong width) +{ + g_return_if_fail (numeric); + numeric->width = width; +} + +/** + * gda_numeric_get_width: + * @numeric: a #GdaNumeric + * + * Gets the width of a #GdaNumeric. (Not yet implemented). + * + * Returns: an integer with the width of a #GdaNumeric. (Not jet implemented). + * + * Since: 5.0.2 + */ +glong +gda_numeric_get_width (const GdaNumeric *numeric) +{ + g_return_val_if_fail (numeric, 0.0); + return numeric->width; +} + +/** + * gda_numeric_set_precision: + * @numeric: a #GdaNumeric + * @precision: a #glong + * + * Sets the precision of a #GdaNumeric. + * + * Since: 5.0.2 + */ +void +gda_numeric_set_precision (GdaNumeric *numeric, glong precision) +{ + g_return_if_fail (numeric); + numeric->precision = precision; +} + +/** + * gda_numeric_get_precision: + * @numeric: a #GdaNumeric + * + * Gets the precision of a #GdaNumeric. + * + * Returns: an integer with the precision of a #GdaNumeric. + * + * Since: 5.0.2 + */ +glong +gda_numeric_get_precision (const GdaNumeric *numeric) +{ + g_return_val_if_fail (numeric, -1); + return numeric->precision; +} +/** + * gda_numeric_get_string: + * @numeric: a #GdaNumeric + * + * Get the string representation of @numeric, in the C locale format (dot as a fraction separator). + * + * Returns: (transfer full) (nullable): a new string representing the stored valued in @numeric + * + * Since: 5.0.2 + */ +gchar* +gda_numeric_get_string (const GdaNumeric *numeric) +{ + if (numeric) + return g_strdup (numeric->number); + else + return NULL; +} + +/* + * Register the GdaTime type in the GType system + */ + +static void +time_to_string (const GValue *src, GValue *dest) +{ + gchar *str = gda_value_stringify (src); + if (g_strcmp0 ("", str) == 0) { + g_value_set_string (dest, "00:00:00+0"); + } else { + g_value_set_string (dest, str); + } + g_free (str); +} + +/* Transform a String GValue to a GdaTime from a string like "12:30:15+01" */ +static void +string_to_time (const GValue *src, GValue *dest) +{ + const gchar *str = g_value_get_string (src); + GdaTime *time = gda_parse_iso8601_time (str); + if (time != NULL) { + g_value_take_boxed (dest, time); + } +} + +/** + * gda_time_copy: + * @time: an instance of #GdaTime to copy + * + * Create a copy of #GdaTime + * + * Returns: (transfer full): a pointer to a new #GdaTime struct + */ +GdaTime* +gda_time_copy (const GdaTime* time) +{ + GdaTime* c; + c = (GdaTime*) g_date_time_add_days ((GDateTime*) time, 0); + return c; +} + +/** + * gda_time_free: + * @time: a #GdaTime to free + * + * Free resources holded by the #GdaTime instance + * + * Since: 6.0 + */ +void +gda_time_free (GdaTime* time) +{ + g_date_time_unref ((GDateTime*) time); +} + +static void +gda_time_register_transform_func (GType typeid) +{ + g_value_register_transform_func (G_TYPE_STRING, typeid, string_to_time); + g_value_register_transform_func (typeid, G_TYPE_STRING, time_to_string); +} + +G_DEFINE_BOXED_TYPE_WITH_CODE (GdaTime, gda_time, gda_time_copy, gda_time_free, + gda_time_register_transform_func (g_define_type_id)) +/** + * gda_value_take_time: + * @value: a #GValue that will store @val. + * @time: (transfer full): a #GdaTime structure with the time to be stored in @value. + * + * Stores @val into @value, but on the contrary to gda_value_set_data(), the @time + * argument is not copied, but used as-is and it should be considered owned by @value. + */ +void +gda_value_take_time (GValue *value, GdaTime *time) +{ + g_return_if_fail (value); + g_return_if_fail (time != NULL); + + l_g_value_unset (value); + g_value_init (value, GDA_TYPE_TIME); + g_value_take_boxed (value, time); +} + + +/** + * gda_time_new: + * + * Creates a new #GdaTime with time now local. + * + * Returns: (transfer full): a new #GdaTime structure + */ +GdaTime* +gda_time_new (void) +{ + GdaTime *t; + t = (GdaTime*) g_date_time_new_now_local (); + return t; +} + + +/** + * gda_time_to_string: + * @time: #GdaTime instance to convert to string + * + * Creates a string representation of a #GdaTime in local time + * with the timezone designation. + * + * Returns: (transfer full): a new string + * Since: 6.0 + */ +gchar* +gda_time_to_string (GdaTime *time) +{ + gchar *str; + str = g_date_time_format ((GDateTime*) time, "%H:%M:%S%:::z"); + return str; +} + +/** + * gda_time_to_string_local: + * @time: #GdaTime instance to convert to string + * + * Creates a string representation of a #GdaTime in local time + * without timezone designation. + * + * Returns: (transfer full): a new string + * Since: 6.0 + */ +gchar* +gda_time_to_string_local (GdaTime *time) +{ + gchar *str; + GDateTime *ndt = g_date_time_to_local ((GDateTime*) time); + str = g_date_time_format (ndt, "%H:%M:%S"); + g_date_time_unref (ndt); + return str; +} + +/** + * gda_time_to_string_utc: + * @time: #GdaTime instance to convert to string + * + * Creates a string representation of a #GdaTime in UTC time + * with time zone indication. + * + * Returns: (transfer full): a new string + * Since: 6.0 + */ +gchar* +gda_time_to_string_utc (GdaTime *time) +{ + GDateTime *ndt = g_date_time_to_utc ((GDateTime*) time); + gchar *str; + str = g_date_time_format (ndt, "%H:%M:%S%:::z"); + g_date_time_unref (ndt); + return str; +} +/** + * gda_time_to_utc: + * @time: a #GdaTime + * + * Change time zone to UTC. + */ +GdaTime* +gda_time_to_utc (GdaTime *time) +{ + return (GdaTime*) g_date_time_to_utc ((GDateTime*) time); +} + +/** + * gda_time_new_from_values: + * @hour: hours + * @minute: minutes + * @second: seconds + * @fraction: fraction of seconds + * @timezone: timezone in seconds added to UTC + * + * Create new instance of #GdaTime from the provided values. + * + * Returns: (transfer full): the a new value storing a time + */ +GdaTime* +gda_time_new_from_values (gushort hour, gushort minute, gushort second, gulong fraction, glong timezone) +{ + gdouble seconds = 0.0; + gchar *sec = g_strdup_printf ("%d.%lu", second, fraction); + seconds = g_ascii_strtod (sec, NULL); + g_free (sec); + GTimeZone *tz = g_time_zone_new_offset (timezone); + + GdaTime* time = (GdaTime*) g_date_time_new (tz, + 1970, + 1, + 1, + (gint) hour, + (gint) minute, + seconds); + g_time_zone_unref (tz); + + return time; +} + +/** + * gda_time_new_from_date_time: + * @dt: a #GDateTime to get time from + * + * Creates new instcne of #GdaTime from #GDateTime. + * + * Returns: (transfer full): the a new value storing a time + * Since: 6.0 + */ +GdaTime* +gda_time_new_from_date_time (GDateTime *dt) +{ + return (GdaTime*) g_date_time_add_days (dt, 0); +} + +/** + * gda_time_get_hour: + * @time: a #GdaTime value to get hours from + * + * Get hours from the #GdaTime instance + * + * Since: 6.0 + */ +gushort +gda_time_get_hour (const GdaTime* time) +{ + g_return_val_if_fail (time != NULL, 0); + return (gushort) g_date_time_get_hour ((GDateTime*) time); +} +/** + * gda_time_set_hour: + * @time: a #GdaTime value to set hours to + * @hour: new hours to set to + * + * Set hour component to the #GdaTime instance. + * + * Since: 6.0 + */ +void +gda_time_set_hour (GdaTime* time, gushort hour) +{ + g_return_if_fail (time != NULL); + time = gda_time_new_from_values (hour, + gda_time_get_minute (time), + gda_time_get_second (time), + gda_time_get_fraction (time), + gda_time_get_timezone (time)); +} +/** + * gda_time_get_minute: + * @time: a #GdaTime value to get minutes from + * + * Get minutes from the #GdaTime instance + * + * Since: 6.0 + */ +gushort +gda_time_get_minute (const GdaTime* time) +{ + g_return_val_if_fail (time != NULL, 0); + return (gushort) g_date_time_get_minute ((GDateTime*) time); +} +/** + * gda_time_set_minute: + * @time: a #GdaTime value to set hours to + * @minute: new minutes to set to + * + * Set minutes to the #GdaTime instance + * + * Since: 6.0 + */ +void +gda_time_set_minute (GdaTime* time, gushort minute) +{ + g_return_if_fail (time != NULL); + time = gda_time_new_from_values (gda_time_get_hour (time), + minute, + gda_time_get_second (time), + gda_time_get_fraction (time), + gda_time_get_timezone (time)); +} +/** + * gda_time_get_second: + * @time: a #GdaTime value to get seconds from + * + * Get second component from #GdaTime + * + * Since: 6.0 + */ +gushort +gda_time_get_second (const GdaTime* time) +{ + g_return_val_if_fail (time != NULL, 0); + return (gushort) g_date_time_get_second ((GDateTime*) time); +} +/** + * gda_time_set_second: + * @time: a #GdaTime value to set hours to + * @second: new seconds to set to + * + * Set second component + * + * Since: 6.0 + */ +void +gda_time_set_second (GdaTime* time, gushort second) +{ + g_return_if_fail (time != NULL); + time = gda_time_new_from_values (gda_time_get_hour (time), + gda_time_get_minute (time), + second, + gda_time_get_fraction (time), + gda_time_get_timezone (time)); +} +/** + * gda_time_get_fraction: + * @time: a #GdaTime value to get fraction of seconds from + * + * Extract fraction of seconds from the instance of #GdaTime + * + * Returns: fraction of seconds + * + * Since: 6.0 + */ +gulong +gda_time_get_fraction (const GdaTime* time) +{ + g_return_val_if_fail (time != NULL, 0); + gdouble v = g_date_time_get_seconds ((GDateTime*) time) - g_date_time_get_second ((GDateTime*) time); + gchar *str = g_strdup_printf ("%0.6f", v); + for (int i = 0; i < 2; i++) { + str[i] = ' '; + } + gulong f = (gulong) g_ascii_strtoll ((const gchar*) str, NULL, 10); + g_free (str); + return f; +} +/** + * gda_time_set_fraction: + * @time: a #GdaTime value to set hours to + * @fraction: new second fraction to set to. + * + * Set new value for the second fraction + * + * Since: 6.0 + */ +void +gda_time_set_fraction (GdaTime* time, gulong fraction) +{ + g_return_if_fail (time != NULL); + time = gda_time_new_from_values (gda_time_get_hour (time), + gda_time_get_minute (time), + gda_time_get_second (time), + fraction, + gda_time_get_timezone (time)); +} +/** + * gda_time_get_timezone: + * @time: a #GdaTime value to get time zone from + * + * Returns number of seconds to be added to UTC time. + * + * Since: 6.0 + */ +glong +gda_time_get_timezone (const GdaTime* time) +{ + g_return_val_if_fail (time != NULL, 0); + return g_date_time_get_utc_offset ((GDateTime*) time) / 1000000; +} +/** + * gda_time_get_tz: + * @time: a #GdaTime value to get time zone from + * + * Returns a #GTimeZone in use in this @time. + * + * Since: 6.0 + */ +GTimeZone* +gda_time_get_tz (const GdaTime* time) +{ + g_return_val_if_fail (time != NULL, 0); + const gchar *stz = g_date_time_get_timezone_abbreviation ((GDateTime*)time); + GTimeZone *tz = g_time_zone_new (stz); + return tz; +} + +/** + * gda_time_set_timezone: + * @time: a #GdaTime value to set time zone to + * @timezone: new time zone to set to. See #gda_time_change_timezone + * + * Set timezone component for the instance of #GdaTime + * + * Since: 6.0 + */ +void +gda_time_set_timezone (GdaTime* time, glong timezone) +{ + g_return_if_fail (time != NULL); + time = gda_time_new_from_values (gda_time_get_hour (time), + gda_time_get_minute (time), + gda_time_get_second (time), + gda_time_get_fraction (time), + timezone); +} + +/** + * gda_time_valid: + * @time: a #GdaTime value to check if it is valid + * + * A time is always valid, so this method has been deprecated. + * + * Returns: #TRUE if #GdaTime is valid; %FALSE otherwise. + * + * Deprecated: 6.0 + * Since: 4.2 + */ +gboolean +gda_time_valid (const GdaTime *time) +{ + g_return_val_if_fail (time, FALSE); + + return TRUE; +} + +/** + * gda_time_to_timezone: + * @time: a valid #GdaTime + * @ntz: a new #GTimeZone to use + * + * Translate @time's to give timezone + * + * Since: 6.0 + */ +GdaTime* +gda_time_to_timezone (GdaTime *time, GTimeZone *ntz) +{ + g_return_val_if_fail (time, NULL); + return (GdaTime*) g_date_time_to_timezone ((GDateTime*) time, ntz); +} + +/** + * gda_date_time_copy: + * + * Returns: (transfer full): + */ +GDateTime* +gda_date_time_copy (GDateTime *ts) +{ + g_return_val_if_fail(ts != NULL, NULL); + + GTimeZone *tz; + + tz = g_time_zone_new (g_date_time_get_timezone_abbreviation (ts)); + + return g_date_time_new (tz, + g_date_time_get_year (ts), + g_date_time_get_month (ts), + g_date_time_get_day_of_month (ts), + g_date_time_get_hour (ts), + g_date_time_get_minute (ts), + g_date_time_get_seconds (ts)); +} + +/** + * gda_value_new: + * @type: the new value type. + * + * Creates a new #GValue of type @type, left in the same state as when g_value_init() is called. + * + * Returns: (transfer full): the newly created #GValue with the specified @type. You need to set the value in the returned GValue. + * + * Free-function: gda_value_free + */ +GValue * +gda_value_new (GType type) +{ + GValue *value; + + value = g_new0 (GValue, 1); + g_value_init (value, type); + + return value; +} + +/** + * gda_value_new_null: + * + * Creates a new #GValue initiated to a #GdaNull structure with a #GDA_TYPE_NULL, to + * represent a NULL in the database. + * + * Returns: (transfer full): a new #GValue of the type #GDA_TYPE_NULL + */ +GValue* +gda_value_new_null (void) +{ + return gda_value_new (GDA_TYPE_NULL); +} + +/** + * gda_value_new_default: + * @default_val: (nullable): the default value as a string, or %NULL + * + * Creates a new default value. + * + * Returns: (transfer full): a new #GValue of the type #GDA_TYPE_DEFAULT + * + * Since: 4.2.9 + */ +GValue * +gda_value_new_default (const gchar *default_val) +{ + GValue *value; + value = gda_value_new (GDA_TYPE_DEFAULT); + g_value_set_boxed (value, default_val); + return value; +} + + + +/** + * gda_value_new_blob: + * @val: value to set for the new #GValue. + * @size: the size of the memory pool pointer to by @val. + * + * Makes a new #GValue of type #GDA_TYPE_BLOB with the data contained by @val. + * + * Returns: (transfer full): the newly created #GValue. + * + * Free-function: gda_value_free + */ +GValue * +gda_value_new_blob (const guchar *val, glong size) +{ + GValue *value; + GdaBlob *blob; + GdaBinary *bin; + + blob = gda_blob_new (); + bin = gda_blob_get_binary (blob); + gda_binary_set_data (bin, val, size); + value = g_new0 (GValue, 1); + g_value_init (value, GDA_TYPE_BLOB); + g_value_take_boxed (value, blob); + + return value; +} + +/** + * gda_value_new_blob_from_file: + * @filename: name of the file to manipulate + * + * Makes a new #GValue of type #GDA_TYPE_BLOB interfacing with the contents of the file + * named @filename + * + * Returns: (transfer full): the newly created #GValue. + * + * Free-function: gda_value_free + */ +GValue * +gda_value_new_blob_from_file (const gchar *filename) +{ + GValue *value; + GdaBlob *blob; + + blob = g_new0 (GdaBlob, 1); + blob->op = _gda_dir_blob_op_new (filename); + + value = g_new0 (GValue, 1); + g_value_init (value, GDA_TYPE_BLOB); + g_value_take_boxed (value, blob); + + return value; +} + +/** + * gda_value_new_date_time: + * + * Makes a new #GValue of type #G_TYPE_DATE_TIME + * + * Returns: (transfer full): the newly created #GValue, or %NULL in case of error + * + * Free-function: gda_value_free + */ +GValue * +gda_value_new_date_time (GDateTime *dt) +{ + if (!dt) + return NULL; + + GValue *value; + + value = g_new0 (GValue, 1); + g_value_init (value, G_TYPE_DATE_TIME); + g_value_set_boxed (value, dt); + + return value; +} + +/** + * gda_value_new_date_time_from_timet: + * @val: value to set for the new #GValue. + * + * Makes a new #GValue of type #G_TYPE_DATE_TIME with value @val + * (of type time_t). The returned timestamp's value is relative to the current + * timezone (i.e. is localtime). + * + * For example, to get a time stamp representing the current date and time, use: + * + * + * ts = gda_value_new_date_time_from_timet (time (NULL)); + * + * + * Returns: (transfer full): the newly created #GValue, or %NULL in case of error + * + * Free-function: gda_value_free + */ +GValue * +gda_value_new_date_time_from_timet (time_t val) +{ + GValue *value; + GDateTime* tstamp = g_date_time_new_from_unix_utc ((gint64)val); + + value = g_new0 (GValue, 1); + g_value_init (value, G_TYPE_DATE_TIME); + g_value_set_boxed (value, tstamp); + g_date_time_unref (tstamp); + + return value; +} +/** + * gda_value_new_time_from_timet: + * @val: value to set for the new #GValue. + * + * Makes a new #GValue of type #GDA_TYPE_TIME with value @val + * (of type time_t). The returned times's value is relative to the current + * timezone (i.e. is localtime). + * + * For example, to get a time representing the current time, use: + * + * + * ts = gda_value_new_time_from_timet (time (NULL)); + * + * + * Returns: (transfer full): the newly created #GValue, or %NULL in case of error + * + * Free-function: gda_value_free + * + * Since: 6.0 + */ +GValue * +gda_value_new_time_from_timet (time_t val) +{ + GValue *value = gda_value_new (GDA_TYPE_TIME); + GDateTime *dt = g_date_time_new_from_unix_local (val); + GdaTime *t = gda_time_new_from_date_time (dt); + g_date_time_unref (dt); + g_value_take_boxed (value, t); + + return value; +} + +/** + * gda_value_new_from_string: + * @as_string: stringified representation of the value. + * @type: the new value type. + * + * Makes a new #GValue of type @type from its string representation. + * + * For more information + * about the string format, see the gda_value_set_from_string() function. + * This function is typically used when reading configuration files or other non-user input that should be locale + * independent. + * + * Returns: (transfer full): the newly created #GValue or %NULL if the string representation cannot be converted to the specified @type. + * + * Free-function: gda_value_free + */ +GValue * +gda_value_new_from_string (const gchar *as_string, GType type) +{ + GValue *value; + + g_return_val_if_fail (as_string, NULL); + + value = gda_value_new (type); + if (set_from_string (value, as_string)) + return value; + else { + gda_value_free (value); + return NULL; + } +} + +/** + * gda_value_new_from_xml: + * @node: an XML node representing the value. + * + * Creates a GValue from an XML representation of it. That XML + * node corresponds to the following string representation: + * <value type="gdatype">value</value> + * + * For more information + * about the string format, see the gda_value_set_from_string() function. + * This function is typically used when reading configuration files or other non-user input that should be locale + * independent. + * + * Returns: (transfer full): the newly created #GValue. + * + * Free-function: gda_value_free + */ +GValue * +gda_value_new_from_xml (const xmlNodePtr node) +{ + GValue *value; + xmlChar *prop; + + g_return_val_if_fail (node, NULL); + + /* parse the XML */ + if (!node || !(node->name) || (node && strcmp ((gchar*)node->name, "value"))) + return NULL; + + value = g_new0 (GValue, 1); + prop = xmlGetProp (node, (xmlChar*) "gdatype"); + if (prop && !gda_value_set_from_string (value, + (gchar*)xmlNodeGetContent (node), + gda_g_type_from_string ((gchar*) prop))) { + g_free (value); + value = NULL; + } + if (prop) + xmlFree (prop); + + return value; +} + +/** + * gda_value_free: + * @value: (transfer full) (nullable): the resource to free (or %NULL) + * + * Deallocates all memory associated to a #GValue. + */ +void +gda_value_free (GValue *value) +{ + if (!value) + return; + l_g_value_unset (value); + g_free (value); +} + +/** + * gda_value_reset_with_type: + * @value: the #GValue to be reseted + * @type: the #GType to set to + * + * Resets the #GValue and set a new type to #GType. +*/ +void +gda_value_reset_with_type (GValue *value, GType type) +{ + g_return_if_fail (value); + + if (G_IS_VALUE (value) && (G_VALUE_TYPE (value) == type)) + g_value_reset (value); + else { + l_g_value_unset (value); + if (type == G_TYPE_INVALID) + return; + else + g_value_init (value, type); + } +} + + + +/** + * gda_value_is_null: + * @value: value to test. + * + * Tests if a given @value is of type #GDA_TYPE_NULL. + * + * Returns: a boolean that says whether or not @value is of type #GDA_TYPE_NULL. + */ +gboolean +gda_value_is_null (const GValue *value) +{ + g_return_val_if_fail (value, FALSE); + return gda_value_isa (value, GDA_TYPE_NULL); +} + +/** + * gda_value_is_number: + * @value: a #GValue. + * + * Gets whether the value stored in the given #GValue is of numeric type or not. + * + * Returns: %TRUE if a number, %FALSE otherwise. + */ +gboolean +gda_value_is_number (const GValue *value) +{ + g_return_val_if_fail (value, FALSE); + if(G_VALUE_HOLDS_INT(value) || + G_VALUE_HOLDS_INT64(value) || + G_VALUE_HOLDS_UINT(value) || + G_VALUE_HOLDS_UINT64(value) || + G_VALUE_HOLDS_CHAR(value) || + G_VALUE_HOLDS_UCHAR(value)) + return TRUE; + else + return FALSE; +} + +/** + * gda_value_copy: + * @value: value to get a copy from. + * + * Creates a new #GValue from an existing one. + * + * Returns: (transfer full): a newly allocated #GValue with a copy of the data in @value. + * + * Free-function: gda_value_free + */ +GValue * +gda_value_copy (const GValue *value) +{ + GValue *copy; + + g_return_val_if_fail (value, NULL); + + copy = g_new0 (GValue, 1); + + if (G_IS_VALUE (value)) { + g_value_init (copy, G_VALUE_TYPE (value)); + g_value_copy (value, copy); + } + + return copy; +} + +/** + * gda_value_get_binary: + * @value: a #GValue whose value we want to get. + * + * Returns: (transfer none): the value stored in @value. + */ +GdaBinary * +gda_value_get_binary (const GValue *value) +{ + GdaBinary *val; + + g_return_val_if_fail (value, NULL); + g_return_val_if_fail (gda_value_isa (value, GDA_TYPE_BINARY), NULL); + + val = (GdaBinary*) g_value_get_boxed (value); + + return val; +} + + +/** + * gda_value_set_binary: + * @value: a #GValue that will store @val. + * @binary: a #GdaBinary structure with the data and its size to be stored in @value. + * + * Stores @val into @value. + */ +void +gda_value_set_binary (GValue *value, GdaBinary *binary) +{ + g_return_if_fail (value); + + l_g_value_unset (value); + g_value_init (value, GDA_TYPE_BINARY); + if (binary) + g_value_set_boxed (value, binary); + else + g_value_set_boxed (value, gda_binary_new ()); +} + +/** + * gda_value_take_binary: + * @value: a #GValue that will store @val. + * @binary: (transfer full): a #GdaBinary structure with the data and its size to be stored in @value. + * + * Stores @val into @value, but on the contrary to gda_value_set_binary(), the @binary + * argument is not copied, but used as-is and it should be considered owned by @value. + */ +void +gda_value_take_binary (GValue *value, GdaBinary *binary) +{ + g_return_if_fail (value); + g_return_if_fail (binary); + + l_g_value_unset (value); + g_value_init (value, GDA_TYPE_BINARY); + g_value_take_boxed (value, binary); +} + +/** + * gda_value_set_blob: + * @value: a #GValue that will store @val. + * @blob: a #GdaBlob structure with the data and its size to be stored in @value. + * + * Stores @val into @value. + */ +void +gda_value_set_blob (GValue *value, const GdaBlob *blob) +{ + g_return_if_fail (value); + g_return_if_fail (blob); + + l_g_value_unset (value); + g_value_init (value, GDA_TYPE_BLOB); + g_value_set_boxed (value, blob); +} + +/** + * gda_value_get_blob: + * @value: a #GValue whose value we want to get. + * + * Returns: (transfer none): the value stored in @value. + */ +const GdaBlob * +gda_value_get_blob (const GValue *value) +{ + GdaBlob *val; + + g_return_val_if_fail (value, NULL); + g_return_val_if_fail (gda_value_isa (value, GDA_TYPE_BLOB), NULL); + + val = (GdaBlob*) g_value_get_boxed (value); + + return val; +} + +/** + * gda_value_take_blob: + * @value: a #GValue that will store @val. + * @blob: (transfer full): a #GdaBlob structure with the data and its size to be stored in @value. + * + * Stores @val into @value, but on the contrary to gda_value_set_blob(), the @blob + * argument is not copied, but used as-is and it should be considered owned by @value. + */ +void +gda_value_take_blob (GValue *value, GdaBlob *blob) +{ + g_return_if_fail (value); + g_return_if_fail (blob); + + l_g_value_unset (value); + g_value_init (value, GDA_TYPE_BLOB); + g_value_take_boxed (value, blob); +} + +/** + * gda_value_get_geometric_point: + * @value: a #GValue whose value we want to get. + * + * Returns: (transfer none): the value stored in @value. + */ +const GdaGeometricPoint * +gda_value_get_geometric_point (const GValue *value) +{ + g_return_val_if_fail (value, NULL); + g_return_val_if_fail (gda_value_isa (value, GDA_TYPE_GEOMETRIC_POINT), NULL); + return (const GdaGeometricPoint *) g_value_get_boxed(value); +} + +/** + * gda_value_set_geometric_point: + * @value: a #GValue that will store @val. + * @val: value to be stored in @value. + * + * Stores @val into @value. + */ +void +gda_value_set_geometric_point (GValue *value, const GdaGeometricPoint *val) +{ + g_return_if_fail (value); + g_return_if_fail (val); + + l_g_value_unset (value); + g_value_init (value, GDA_TYPE_GEOMETRIC_POINT); + g_value_set_boxed (value, val); +} + +/** + * gda_value_set_null: + * @value: a #GValue that will store a value of type #GDA_TYPE_NULL. + * + * Sets the type of @value to #GDA_TYPE_NULL. + */ +void +gda_value_set_null (GValue *value) +{ + g_return_if_fail (value); + gda_value_reset_with_type (value, GDA_TYPE_NULL); +} + +/** + * gda_value_get_numeric: + * @value: a #GValue whose value we want to get. + * + * Returns: (transfer none): the value stored in @value. + */ +const GdaNumeric * +gda_value_get_numeric (const GValue *value) +{ + g_return_val_if_fail (value, NULL); + g_return_val_if_fail (gda_value_isa (value, GDA_TYPE_NUMERIC), NULL); + return (const GdaNumeric *) g_value_get_boxed(value); +} + +/** + * gda_value_set_numeric: + * @value: a #GValue that will store @val. + * @val: value to be stored in @value. + * + * Stores @val into @value. + */ +void +gda_value_set_numeric (GValue *value, const GdaNumeric *val) +{ + g_return_if_fail (value); + g_return_if_fail (val); + + l_g_value_unset (value); + g_value_init (value, GDA_TYPE_NUMERIC); + g_value_set_boxed (value, val); +} + +/** + * gda_value_get_short: + * @value: a #GValue whose value we want to get. + * + * Returns: the value stored in @value. + */ +gshort +gda_value_get_short (const GValue *value) +{ + g_return_val_if_fail (value, -1); + g_return_val_if_fail (gda_value_isa (value, GDA_TYPE_SHORT), -1); + return (gshort) value->data[0].v_int; +} + +/** + * gda_value_set_short: + * @value: a #GValue that will store @val. + * @val: value to be stored in @value. + * + * Stores @val into @value. + */ +void +gda_value_set_short (GValue *value, gshort val) +{ + g_return_if_fail (value); + + l_g_value_unset (value); + g_value_init (value, GDA_TYPE_SHORT); + value->data[0].v_int = val; +} + +/** + * gda_value_get_ushort: + * @value: a #GValue whose value we want to get. + * + * Returns: the value stored in @value. + */ +gushort +gda_value_get_ushort (const GValue *value) +{ + g_return_val_if_fail (value, -1); + g_return_val_if_fail (gda_value_isa (value, GDA_TYPE_USHORT), -1); + return (gushort) value->data[0].v_uint; +} + +/** + * gda_value_set_ushort: + * @value: a #GValue that will store @val. + * @val: value to be stored in @value. + * + * Stores @val into @value. + */ +void +gda_value_set_ushort (GValue *value, gushort val) +{ + g_return_if_fail (value); + + l_g_value_unset (value); + g_value_init (value, GDA_TYPE_USHORT); + value->data[0].v_uint = val; +} + + +/** + * gda_value_get_time: + * @value: a #GValue whose value we want to get. + * + * Returns: (transfer none): the value stored in @value. + */ +const GdaTime * +gda_value_get_time (const GValue *value) +{ + g_return_val_if_fail (value, NULL); + g_return_val_if_fail (gda_value_isa (value, GDA_TYPE_TIME), NULL); + return (const GdaTime *) g_value_get_boxed(value); +} + +/** + * gda_value_set_time: + * @value: a #GValue that will store @val. + * @val: value to be stored in @value. + * + * Stores @val into @value. + */ +void +gda_value_set_time (GValue *value, const GdaTime *val) +{ + g_return_if_fail (value); + g_return_if_fail (val); + + l_g_value_unset (value); + g_value_init (value, GDA_TYPE_TIME); + g_value_set_boxed (value, val); +} + +/** + * gda_value_get_timestamp: + * @value: a #GValue whose value we want to get. + * + * Returns: (transfer none): the value stored in @value. + */ +const GDateTime * +gda_value_get_timestamp (const GValue *value) +{ + g_return_val_if_fail (value, NULL); + g_return_val_if_fail (gda_value_isa (value, G_TYPE_DATE_TIME), NULL); + return (const GDateTime *) g_value_get_boxed(value); +} + +/** + * gda_value_set_timestamp: + * @value: a #GValue that will store @val. + * @val: value to be stored in @value. + * + * Stores @val into @value. + */ +void +gda_value_set_timestamp (GValue *value, const GDateTime *val) +{ + g_return_if_fail (value); + g_return_if_fail (val); + + l_g_value_unset (value); + g_value_init (value, G_TYPE_DATE_TIME); + g_value_set_boxed (value, val); +} + +/** + * gda_value_set_from_string: + * @value: a #GValue that will store @val. + * @as_string: the stringified representation of the value. + * @type: the type of the value + * + * Stores the value data from its string representation as @type. + * + * The accepted formats are: + * + * G_TYPE_BOOLEAN: a caseless comparison is made with "true" or "false" + * numerical types: C locale format (dot as a fraction separator) + * G_TYPE_DATE: see gda_parse_iso8601_date() + * GDA_TYPE_TIME: see gda_parse_iso8601_time() + * GDA_TYPE_TIMESTAMP: see g_date_time_new_from_iso8601() + * + * + * This function is typically used when reading configuration files or other non-user input that should be locale + * independent. + * + * Returns: %TRUE if the value has been converted to @type from + * its string representation; it not means that the value is converted + * successfully, just that the transformation is available. %FALSE otherwise. + */ +gboolean +gda_value_set_from_string (GValue *value, + const gchar *as_string, + GType type) +{ + g_return_val_if_fail (value, FALSE); + g_return_val_if_fail (as_string, FALSE); + + /* REM: glib does not register any transform function from G_TYPE_STRING to any other + * type except to a G_TYPE_STRING, so we can't use g_value_type_transformable (G_TYPE_STRING, type) */ + gda_value_reset_with_type (value, type); + return set_from_string (value, as_string); +} + +/** + * gda_value_set_from_value: + * @value: a #GValue. + * @from: the value to copy from. + * + * Sets the value of a #GValue from another #GValue. This + * is different from #gda_value_copy, which creates a new #GValue. + * #gda_value_set_from_value, on the other hand, copies the contents + * of @copy into @value, which must already be allocated. + * + * If values are incompatible (see @g_value_type_compatible) then @value is set to a + * #GDA_TYPE_NULL, and %FALSE is returned. + * + * Returns: %TRUE if successful, %FALSE otherwise. + */ +gboolean +gda_value_set_from_value (GValue *value, const GValue *from) +{ + g_return_val_if_fail (value, FALSE); + g_return_val_if_fail (from, FALSE); + + if (G_IS_VALUE (from)) { + if (g_value_type_compatible (G_VALUE_TYPE (from), G_VALUE_TYPE (value))) { + g_value_reset (value); + g_value_copy (from, value); + return TRUE; + } + else { + gda_value_set_null (value); + return FALSE; + } + } + else { + l_g_value_unset (value); + return TRUE; + } +} + +/** + * gda_value_stringify: + * @value: a #GValue. + * + * Converts a GValue to its string representation which is a human readable value. Note that the + * returned string does not take into account the current locale of the user (on the contrary to the + * #GdaDataHandler objects). Using this function should be limited to debugging and values serialization + * purposes. + * + * Output is in the "C" locale for numbers, and dates are converted in a YYYY-MM-DD format. + * + * Returns: (transfer full): a new string, or %NULL if the conversion cannot be done. Free the value with a g_free() when you've finished using it. + */ +gchar * +gda_value_stringify (const GValue *value) +{ + if (!value) + return g_strdup ("NULL"); + + GType type = G_VALUE_TYPE (value); + if (type == G_TYPE_FLOAT) { + char buffer[G_ASCII_DTOSTR_BUF_SIZE]; + g_ascii_formatd (buffer, sizeof (buffer), "%f", g_value_get_float (value)); + return g_strdup (buffer); + } + else if (type == G_TYPE_DOUBLE) { + char buffer[G_ASCII_DTOSTR_BUF_SIZE]; + g_ascii_formatd (buffer, sizeof (buffer), "%f", g_value_get_double (value)); + return g_strdup (buffer); + } + else if (type == GDA_TYPE_NUMERIC) + return gda_numeric_get_string (gda_value_get_numeric (value)); + else if (type == G_TYPE_DATE) { + GDate *date; + date = (GDate *) g_value_get_boxed (value); + if (date) { + if (g_date_valid (date)) + return g_strdup_printf ("%04u-%02u-%02u", + g_date_get_year (date), + g_date_get_month (date), + g_date_get_day (date)); + else + return g_strdup_printf ("%04u-%02u-%02u", + date->year, date->month, date->day); + } + else + return g_strdup ("NULL"); + } + else if (g_type_is_a (type, GDA_TYPE_TIME)) { + GdaTime *gts; + gts = (GdaTime*) g_value_get_boxed (value); + if (gts != NULL) { + return gda_time_to_string_utc (gts); + } else { + return "NULL"; + } + } + else if (g_type_is_a (type, G_TYPE_DATE_TIME)) { + GDateTime *ts; + ts = (GDateTime*) g_value_get_boxed (value); + return g_date_time_format (ts, "%FT%H:%M:%S%:::z"); + } + else if (g_type_is_a (type, GDA_TYPE_NULL)) { + return g_strdup ("NULL"); + } + else if (g_type_is_a (type, GDA_TYPE_TEXT)) { + GdaText *text; + text = (GdaText*) g_value_get_boxed (value); + return g_strdup (gda_text_get_string (text)); + } + else if (g_value_type_transformable (G_VALUE_TYPE (value), G_TYPE_STRING)) { + GValue *string; + gchar *str; + + string = g_value_init (g_new0 (GValue, 1), G_TYPE_STRING); + g_value_transform (value, string); + str = g_value_dup_string (string); + gda_value_free (string); + return str; + } + else if (G_TYPE_IS_OBJECT (type)) { + GObject *obj; + obj = g_value_get_object (value); + return g_strdup_printf ("%p (%s)", obj, G_OBJECT_TYPE_NAME (obj)); + } + else + return g_strdup (""); +} + +/** + * gda_value_differ: + * @value1: a #GValue to compare. + * @value2: the other #GValue to be compared to @value1. + * + * Tells if two values are equal or not, by comparing memory representations. Unlike gda_value_compare(), + * the returned value is boolean, and gives no idea about ordering. + * + * The two values must be of the same type, with the exception that a value of any type can be + * compared to a GDA_TYPE_NULL value, specifically: + * + * if @value1 and @value2 are both GDA_TYPE_NULL values then the returned value is 0 + * if @value1 is a GDA_TYPE_NULL value and @value2 is of another type then the returned value is 1 + * if @value1 is of another type and @value2 is a GDA_TYPE_NULL value then the returned value is 1 + * in all other cases, @value1 and @value2 must be of the same type and their values are compared + * + * + * Returns: a non 0 value if @value1 and @value2 differ, and 0 if they are equal + */ +gint +gda_value_differ (const GValue *value1, const GValue *value2) +{ + GType type; + g_return_val_if_fail (value1 && value2, FALSE); + + /* blind value comparison */ + type = G_VALUE_TYPE (value1); + if (!bcmp (value1, value2, sizeof (GValue))) + return 0; + + /* handle GDA_TYPE_NULL comparisons with other types */ + else if (type == GDA_TYPE_NULL) { + if (G_VALUE_TYPE (value2) == GDA_TYPE_NULL) + return 0; + else + return 1; + } + + else if (G_VALUE_TYPE (value2) == GDA_TYPE_NULL) + return 1; + + g_return_val_if_fail (G_VALUE_TYPE (value1) == G_VALUE_TYPE (value2), 1); + + /* general case */ + if (type == GDA_TYPE_BINARY) { + const GdaBinary *binary1 = gda_value_get_binary ((GValue*) value1); + const GdaBinary *binary2 = gda_value_get_binary ((GValue*) value2); + if (binary1 && binary2 && (binary1->binary_length == binary2->binary_length)) + return bcmp (binary1->data, binary2->data, binary1->binary_length); + else + return 1; + } + + else if (type == GDA_TYPE_BLOB) { + const GdaBlob *blob1 = gda_value_get_blob (value1); + const GdaBlob *blob2 = gda_value_get_blob (value2); + if (blob1 && blob2 && (((GdaBinary *)blob1)->binary_length == ((GdaBinary *)blob2)->binary_length)) { + if (blob1->op == blob2->op) + return bcmp (((GdaBinary *)blob1)->data, ((GdaBinary *)blob2)->data, + ((GdaBinary *)blob1)->binary_length); + } + return 1; + } + + else if (type == G_TYPE_DATE) { + GDate *d1, *d2; + + d1 = (GDate *) g_value_get_boxed (value1); + d2 = (GDate *) g_value_get_boxed (value2); + if (d1 && d2) + return g_date_compare (d1, d2); + return 1; + } + + else if (type == GDA_TYPE_GEOMETRIC_POINT) { + const GdaGeometricPoint *p1, *p2; + p1 = gda_value_get_geometric_point (value1); + p2 = gda_value_get_geometric_point (value2); + if (p1 && p2) + return bcmp (p1, p2, sizeof (GdaGeometricPoint)); + return 1; + } + + else if (type == G_TYPE_OBJECT) { + if (g_value_get_object (value1) == g_value_get_object (value2)) + return 0; + else + return -1; + } + + else if (type == GDA_TYPE_NUMERIC) { + const GdaNumeric *num1, *num2; + num1= gda_value_get_numeric (value1); + num2 = gda_value_get_numeric (value2); + if (num1 && num2) + return strcmp (num1->number, num2->number); + return 1; + } + + else if (type == G_TYPE_STRING) { + const gchar *str1, *str2; + str1 = g_value_get_string (value1); + str2 = g_value_get_string (value2); + if (str1 && str2) + return g_strcmp0 (str1, str2); + return 1; + } + + else if (type == GDA_TYPE_TEXT) { + GdaText *t1, *t2; + const gchar *str1, *str2; + t1 = g_value_get_boxed (value1); + t2 = g_value_get_boxed (value2); + str1 = gda_text_get_string (t1); + str2 = gda_text_get_string (t2); + if (str1 && str2) + return g_strcmp0 (str1, str2); + return 1; + } + + else if (type == GDA_TYPE_TIME) { + const GdaTime *t1, *t2; + t1 = gda_value_get_time (value1); + t2 = gda_value_get_time (value2); + if (t1 && t2) { + return g_date_time_difference ((GDateTime*) t1,(GDateTime*) t2) != 0 ? 1 : 0; + } + return 1; + } + + else if (g_type_is_a (type, G_TYPE_DATE_TIME)) { + GDateTime *ts1, *ts2; + ts1 = (GDateTime*) g_value_get_boxed (value1); + ts2 = (GDateTime*) g_value_get_boxed (value2); + if (ts1 && ts2) + return (gint) g_date_time_difference (ts1, ts2); + return 1; + } + + else if ((type == G_TYPE_INT) || + (type == G_TYPE_UINT) || + (type == G_TYPE_INT64) || + (type == G_TYPE_UINT64) || + (type == GDA_TYPE_SHORT) || + (type == GDA_TYPE_USHORT) || + (type == G_TYPE_FLOAT) || + (type == G_TYPE_DOUBLE) || + (type == G_TYPE_BOOLEAN) || + (type == G_TYPE_CHAR) || + (type == G_TYPE_UCHAR) || + (type == G_TYPE_LONG) || + (type == G_TYPE_ULONG) || + (type == G_TYPE_GTYPE)) + /* values here ARE different because otherwise the bcmp() at the beginning would + * already have retruned */ + return 1; + + else if (g_type_is_a (type, G_TYPE_OBJECT)) { + if (g_value_get_object (value1) == g_value_get_object (value2)) + return 0; + else + return -1; + } + + g_warning ("%s() cannot handle values of type %s", __FUNCTION__, g_type_name (G_VALUE_TYPE (value1))); + + return 1; +} + +/** + * gda_value_compare: + * @value1: a #GValue to compare (not %NULL) + * @value2: the other #GValue to be compared to @value1 (not %NULL) + * + * Compares two values of the same type, with the exception that a value of any type can be + * compared to a GDA_TYPE_NULL value, specifically: + * + * if @value1 and @value2 are both GDA_TYPE_NULL values then the returned value is 0 + * if @value1 is a GDA_TYPE_NULL value and @value2 is of another type then the returned value is -1 + * if @value1 is of another type and @value2 is a GDA_TYPE_NULL value then the returned value is 1 + * in all other cases, @value1 and @value2 must be of the same type and their values are compared + * + * + * Returns: if both values have the same type, returns 0 if both contain + * the same value, an integer less than 0 if @value1 is less than @value2 or + * an integer greater than 0 if @value1 is greater than @value2. + */ +gint +gda_value_compare (const GValue *value1, const GValue *value2) +{ + gint retval; + GType type; + + g_return_val_if_fail (value1 && value2, -1); + + type = G_VALUE_TYPE (value1); + + if (value1 == value2) { + return 0; + } + else if (type == GDA_TYPE_NULL) { + /* handle GDA_TYPE_NULL comparisons with other types */ + if (G_VALUE_TYPE (value2) == GDA_TYPE_NULL) + return 0; + else + return -1; + } + else if (G_VALUE_TYPE (value2) == GDA_TYPE_NULL) { + return 1; + } + /* GdaText vs. string */ + if (G_VALUE_TYPE (value1) == GDA_TYPE_TEXT && G_VALUE_TYPE (value2) == G_TYPE_STRING) { + GdaText *text1, *text2; + GValue *v2; + text1 = g_value_get_boxed (value1); + v2 = gda_value_new (GDA_TYPE_TEXT); + g_value_transform (value2, v2); + text2 = g_value_get_boxed (v2); + if (text2 == NULL) { + retval = -1; + } else { + retval = g_strcmp0 (gda_text_get_string (text1), gda_text_get_string (text2)); + } + gda_value_free (v2); + return retval; + } + /* general case */ + g_return_val_if_fail (G_VALUE_TYPE (value1) == G_VALUE_TYPE (value2), -1); + + if (type == G_TYPE_INT64) { + gint64 i1 = g_value_get_int64 (value1); + gint64 i2 = g_value_get_int64 (value2); + return (i1 > i2) ? 1 : ((i1 == i2) ? 0 : -1); + } + + else if (type == G_TYPE_UINT64) { + guint64 i1 = g_value_get_uint64 (value1); + guint64 i2 = g_value_get_uint64 (value2); + return (i1 > i2) ? 1 : ((i1 == i2) ? 0 : -1); + } + + else if (type == GDA_TYPE_BINARY) { + const GdaBinary *binary1 = gda_value_get_binary (value1); + const GdaBinary *binary2 = gda_value_get_binary (value2); + if (binary1 && binary2 && (binary1->binary_length == binary2->binary_length)) + return memcmp (binary1->data, binary2->data, binary1->binary_length) ; + else + return -1; + } + + else if (type == G_TYPE_BOOLEAN) + return g_value_get_boolean (value1) - g_value_get_boolean (value2); + + else if (type == GDA_TYPE_BLOB) { + const GdaBlob *blob1 = gda_value_get_blob (value1); + const GdaBlob *blob2 = gda_value_get_blob (value2); + if (blob1 && blob2 && (((GdaBinary *)blob1)->binary_length == ((GdaBinary *)blob2)->binary_length)) { + if (blob1->op == blob2->op) + return memcmp (((GdaBinary *)blob1)->data, ((GdaBinary *)blob2)->data, + ((GdaBinary *)blob1)->binary_length); + else + return -1; + } + else + return -1; + } + + else if (type == G_TYPE_DATE) { + GDate *d1, *d2; + + d1 = (GDate *) g_value_get_boxed (value1); + d2 = (GDate *) g_value_get_boxed (value2); + if (d1 && d2) + return g_date_compare (d1, d2); + else { + if (d1) + return 1; + else { + if (d2) + return -1; + else + return 0; + } + } + } + + else if (type == G_TYPE_DOUBLE) { + gdouble v1, v2; + + v1 = g_value_get_double (value1); + v2 = g_value_get_double (value2); + + if (v1 == v2) + return 0; + else + return (v1 > v2) ? 1 : -1; + } + + else if (type == GDA_TYPE_GEOMETRIC_POINT) { + const GdaGeometricPoint *p1, *p2; + p1 = gda_value_get_geometric_point (value1); + p2 = gda_value_get_geometric_point (value2); + if (p1 && p2) + return memcmp (p1, p2, sizeof (GdaGeometricPoint)); + else if (p1) + return 1; + else if (p2) + return -1; + else + return 0; + } + + else if (type == G_TYPE_OBJECT) { + if (g_value_get_object (value1) == g_value_get_object (value2)) + return 0; + else + return -1; + } + + else if (type == G_TYPE_INT) + return g_value_get_int (value1) - g_value_get_int (value2); + + else if (type == GDA_TYPE_NUMERIC) { + const GdaNumeric *num1, *num2; + num1= gda_value_get_numeric (value1); + num2 = gda_value_get_numeric (value2); + if (num1) { + if (num2) + retval = strcmp (num1->number, num2->number); + else + retval = 1; + } + else + retval = -1; + return retval; + } + + else if (type == G_TYPE_FLOAT) { + gfloat f1 = g_value_get_float (value1); + gfloat f2 = g_value_get_float (value2); + return (f1 > f2) ? 1 : ((f1 == f2) ? 0 : -1); + } + + else if (type == GDA_TYPE_SHORT) { + gshort i1 = gda_value_get_short (value1); + gshort i2 = gda_value_get_short (value2); + return (i1 > i2) ? 1 : ((i1 == i2) ? 0 : -1); + } + + else if (type == G_TYPE_ULONG) { + gulong i1 = g_value_get_ulong (value1); + gulong i2 = g_value_get_ulong (value2); + return (i1 > i2) ? 1 : ((i1 == i2) ? 0 : -1); + } + + else if (type == G_TYPE_LONG) { + glong i1 = g_value_get_long (value1); + glong i2 = g_value_get_long (value2); + return (i1 > i2) ? 1 : ((i1 == i2) ? 0 : -1); + } + + else if (type == GDA_TYPE_USHORT) { + gushort i1 = gda_value_get_ushort (value1); + gushort i2 = gda_value_get_ushort (value2); + return (i1 > i2) ? 1 : ((i1 == i2) ? 0 : -1); + } + + else if (type == G_TYPE_STRING) { + const gchar *str1, *str2; + str1 = g_value_get_string (value1); + str2 = g_value_get_string (value2); + if (str1 && str2) + retval = g_strcmp0 (str1, str2); + else { + if (str1) + return 1; + else { + if (str2) + return -1; + else + return 0; + } + } + + return retval; + } + + else if (type == GDA_TYPE_TEXT) { + GdaText *t1, *t2; + t1 = g_value_get_boxed (value1); + t2 = g_value_get_boxed (value2); + const gchar *str1, *str2; + str1 = gda_text_get_string (t1); + str2 = gda_text_get_string (t2); + if (str1 && str2) + retval = g_strcmp0 (str1, str2); + else { + if (str1) + return 1; + else { + if (str2) + return -1; + else + return 0; + } + } + + return retval; + } + + else if (type == GDA_TYPE_TIME) { + const GdaTime *t1, *t2; + t1 = gda_value_get_time (value1); + t2 = gda_value_get_time (value2); + if (t1 && t2) + return g_date_time_compare ((GDateTime*) t1, (GDateTime*) t2); + } + + else if (type == G_TYPE_DATE_TIME) { + const GDateTime *ts1, *ts2; + ts1 = g_value_get_boxed (value1); + ts2 = g_value_get_boxed (value2); + if (ts1 && ts2) + return g_date_time_compare ((GDateTime*) ts1, (GDateTime*) ts2); + else if (ts1) + return 1; + else if (ts2) + return -1; + else + return 0; + } + + else if (type == G_TYPE_CHAR) { + gint8 c1 = g_value_get_schar (value1); + gint8 c2 = g_value_get_schar (value2); + return (c1 > c2) ? 1 : ((c1 == c2) ? 0 : -1); + } + + else if (type == G_TYPE_UCHAR) { + guchar c1 = g_value_get_uchar (value1); + guchar c2 = g_value_get_uchar (value2); + return (c1 > c2) ? 1 : ((c1 == c2) ? 0 : -1); + } + + else if (type == G_TYPE_UINT) { + guint i1 = g_value_get_uint (value1); + guint i2 = g_value_get_uint (value2); + return (i1 > i2) ? 1 : ((i1 == i2) ? 0 : -1); + } + + else if (type == G_TYPE_GTYPE) { + GType t1 = g_value_get_gtype (value1); + GType t2 = g_value_get_gtype (value2); + return (t1 > t2) ? 1 : ((t1 == t2) ? 0: -1); + } + + else if (g_type_is_a (type, G_TYPE_OBJECT)) { + if (g_value_get_object (value1) == g_value_get_object (value2)) + return 0; + else + return -1; + } + + g_warning ("%s() cannot handle values of type %s", __FUNCTION__, g_type_name (G_VALUE_TYPE (value1))); + + return 0; +} + +/* + * to_string + * + * The exact reverse process of set_from_string(), almost the same as gda_value_stingify () + * because of some localization with gda_value_stingify (). + */ +static gchar * +to_string (const GValue *value) +{ + gchar *retval = NULL; + + g_return_val_if_fail (value, NULL); + + if (G_VALUE_TYPE (value) == G_TYPE_BOOLEAN) { + if (g_value_get_boolean (value)) + retval = g_strdup ("true"); + else + retval = g_strdup ("false"); + } + else + retval = gda_value_stringify (value); + + return retval; +} + + +/** + * gda_value_to_xml: (skip) + * @value: a #GValue. + * + * Serializes the given #GValue to an XML node string. + * + * Returns: (transfer full): the XML node. Once not needed anymore, you should free it. + */ +xmlNodePtr +gda_value_to_xml (const GValue *value) +{ + gchar *valstr; + xmlNodePtr retval; + + g_return_val_if_fail (value, NULL); + + valstr = to_string (value); + + retval = xmlNewNode (NULL, (xmlChar*)"value"); + xmlSetProp(retval, (xmlChar*)"type", (xmlChar*)g_type_name (G_VALUE_TYPE (value))); + xmlNodeSetContent (retval, (xmlChar*)valstr); + + g_free (valstr); + + return retval; +} + +/** + * gda_value_to_xml_string: + * @value: a #GValue to convert to string + * + * This methods creates an XML string representation of a #GValue + * + * Returns: (transfer full): an string representing a #GValue in XML format + */ +gchar* +gda_value_to_xml_string (const GValue *value) { + g_return_val_if_fail (value != NULL, NULL); + + xmlNodePtr node; + xmlBufferPtr buff; + gchar *str = NULL; + + node = gda_value_to_xml (value); + buff = xmlBufferCreate (); + xmlNodeDump (buff, node->doc, node, 0, 0); + str = g_strdup ((gchar*) buff->content); + xmlBufferFree (buff); + xmlFreeNode (node); + return str; +} + + +/* Register the GDA Types */ + +/* Gda gshort type */ +/* Transform a String GValue to a gshort*/ +static void +string_to_short(const GValue *src, GValue *dest) +{ + + const gchar *as_string; + long int lvalue; + gchar *endptr; + + g_return_if_fail (G_VALUE_HOLDS_STRING (src) && + (GDA_VALUE_HOLDS_SHORT (dest) || GDA_VALUE_HOLDS_USHORT (dest))); + + as_string = g_value_get_string ((GValue *) src); + + lvalue = strtol (as_string, &endptr, 10); + + if (*as_string != '\0' && *endptr == '\0') { + if (GDA_VALUE_HOLDS_SHORT (dest)) + gda_value_set_short (dest, (gshort) lvalue); + else + gda_value_set_ushort (dest, (gushort) lvalue); + } +} + +static void +short_to_string (const GValue *src, GValue *dest) +{ + gchar *str; + + g_return_if_fail (G_VALUE_HOLDS_STRING (dest) && + (GDA_VALUE_HOLDS_SHORT (src) || GDA_VALUE_HOLDS_USHORT (src))); + + if (GDA_VALUE_HOLDS_SHORT (src)) + str = g_strdup_printf ("%d", gda_value_get_short ((GValue *) src)); + else + str = g_strdup_printf ("%d", gda_value_get_ushort ((GValue *) src)); + + g_value_take_string (dest, str); +} + + +GType +gda_short_get_type (void) +{ + static GType type = 0; + + if (G_UNLIKELY (type == 0)) { + static const GTypeInfo type_info = { + 0, /* class_size */ + NULL, /* base_init */ + NULL, /* base_finalize */ + NULL, /* class_init */ + NULL, /* class_finalize */ + NULL, /* class_data */ + 0, /* instance_size */ + 0, /* n_preallocs */ + NULL, /* instance_init */ + NULL /* value_table */ + }; + + type = g_type_register_static (G_TYPE_INT, "GdaShort", &type_info, 0); + + g_value_register_transform_func(G_TYPE_STRING, + type, + string_to_short); + + g_value_register_transform_func(type, + G_TYPE_STRING, + short_to_string); + } + + + + return type; +} + +GType +gda_ushort_get_type (void) { + static GType type = 0; + + if (G_UNLIKELY (type == 0)) { + static const GTypeInfo type_info = { + 0, /* class_size */ + NULL, /* base_init */ + NULL, /* base_finalize */ + NULL, /* class_init */ + NULL, /* class_finalize */ + NULL, /* class_data */ + 0, /* instance_size */ + 0, /* n_preallocs */ + NULL, /* instance_init */ + NULL /* value_table */ + }; + + type = g_type_register_static (G_TYPE_UINT, "GdaUShort", &type_info, 0); + + g_value_register_transform_func (G_TYPE_STRING, + type, + string_to_short); + + g_value_register_transform_func (type, + G_TYPE_STRING, + short_to_string); + } + + return type; +} + + + +#define MYMIN(a,b) (((b) > 0) ? ((a) < (b) ? (a) : (b)) : (a)) + +/** + * gda_binary_to_string: + * @bin: a correctly filled @GdaBinary structure + * @maxlen: a maximum len used to truncate, or %0 for no maximum length + * + * Converts all the non printable characters of bin->data into the "\xyz" representation + * where "xyz" is the octal representation of the byte, and the '\' (backslash) character + * is converted to "\\". Printable characters (defined by g_ascii_isprint()) as well as newline + * character are not converted. + * + * Note that the backslash and newline characters are considered as printable characters and + * will not be represented by the "\xyz" representation. + * + * Use this function to get a representation as much readable by humans as possible of a binary + * chunk. Note that this function is internally called when transforming a binary value to + * a string for example when using g_value_transform() or gda_value_stringify(). + * + * Returns: (transfer full): a new string from @bin + */ +gchar * +gda_binary_to_string (const GdaBinary *bin, guint maxlen) +{ + gint nb_rewrites = 0; + gchar *sptr, *rptr; + gulong realsize = MYMIN ((gulong)(bin->binary_length), maxlen); + + gchar *retval; + gulong offset = 0; + + if (!bin->data || (bin->binary_length == 0)) + return g_strdup (""); + + /* compute number of char rewrites */ + for (offset = 0, sptr = (gchar*) bin->data; + offset < realsize; + offset ++, sptr++) { + if ((*sptr != '\n') && ((*sptr == '\\') || !g_ascii_isprint (*sptr))) + nb_rewrites++; + } + + /* mem allocation and copy */ + retval = g_malloc0 (realsize + nb_rewrites * 4 + 1); + rptr = retval; + sptr = (gchar*) bin->data; + offset = 0; + while (offset < realsize) { + /* g_print (">%x<\n", (guchar) *ptr); */ + if ((*sptr == '\n') || ((*sptr != '\\') && g_ascii_isprint (*sptr))) { + *rptr = *sptr; + rptr ++; + } + else { + if (*sptr == '\\') { + *rptr = '\\'; + rptr++; + *rptr = '\\'; + rptr++; + } + else { + guchar val = *sptr; + + *rptr = '\\'; + rptr++; + + *rptr = val / 64 + '0'; + rptr++; + val = val % 64; + + *rptr = val / 8 + '0'; + val = val % 8; + rptr++; + + *rptr = val + '0'; + rptr++; + } + } + + sptr++; + offset ++; + } + + return retval; +} + +/** + * gda_string_to_binary: + * @str: (nullable): a string to convert, or %NULL + * + * Performs the reverse of gda_binary_to_string() (note that for any "\xyz" succession + * of 4 characters where "xyz" represents a valid octal value, the resulting read value will + * be modulo 256). + * + * I @str is %NULL, then an empty (i.e. where the @data part is %NULL) #GdaBinary is created and returned. + * + * Returns: (transfer full): a new #GdaBinary if no error were found in @str, or %NULL otherwise + */ +GdaBinary * +gda_string_to_binary (const gchar *str) +{ + GdaBinary *bin; + glong len = 0, total; + const guchar *sptr; + guchar *rptr, *retval; + + if (!str) { + bin = g_new0 (GdaBinary, 1); + bin->data = NULL; + bin->binary_length = 0; + return bin; + } + + total = strlen (str); + retval = g_new0 (guchar, total + 1); + sptr = (guchar*) str; + rptr = retval; + + while (*sptr) { + if (*sptr == '\\') { + if (*(sptr+1) == '\\') { + *rptr = '\\'; + sptr += 2; + } + else { + guint tmp; + if ((*(sptr+1) >= '0') && (*(sptr+1) <= '7') && + (*(sptr+2) >= '0') && (*(sptr+2) <= '7') && + (*(sptr+3) >= '0') && (*(sptr+3) <= '7')) { + tmp = (*(sptr+1) - '0') * 64 + + (*(sptr+2) - '0') * 8 + + (*(sptr+3) - '0'); + sptr += 4; + *rptr = tmp % 256; + } + else { + g_free (retval); + return NULL; + } + } + } + else { + *rptr = *sptr; + sptr++; + } + + rptr++; + len ++; + } + + bin = g_new0 (GdaBinary, 1); + bin->data = retval; + bin->binary_length = len; + + return bin; +} + +/** + * gda_blob_to_string: + * @blob: a correctly filled @GdaBlob structure + * @maxlen: a maximum len used to truncate, or 0 for no maximum length + * + * Converts all the non printable characters of blob->data into the \xxx representation + * where xxx is the octal representation of the byte, and the '\' (backslash) character + * is converted to "\\". + * + * Returns: (transfer full): a new string from @blob + */ +gchar * +gda_blob_to_string (GdaBlob *blob, guint maxlen) +{ + if (!((GdaBinary *)blob)->data && blob->op) { + /* fetch some data first (limited amount of data) */ + gda_blob_op_read (blob->op, blob, 0, 40); + } + return gda_binary_to_string ((GdaBinary*) blob, maxlen); +} + +/** + * gda_string_to_blob: + * @str: a string to convert + * + * Performs the reverse of gda_blob_to_string(). + * + * Returns: (transfer full): a new #gdaBlob if no error were found in @str, or NULL otherwise + */ +GdaBlob * +gda_string_to_blob (const gchar *str) +{ + GdaBinary *bin; + bin = gda_string_to_binary (str); + if (bin) { + GdaBlob *blob; + blob = g_new0 (GdaBlob, 1); + ((GdaBinary*) blob)->data = bin->data; + ((GdaBinary*) blob)->binary_length = bin->binary_length; + blob->op = NULL; + g_free (bin); + return blob; + } + else + return NULL; +} + diff --git a/.flatpak-builder/cache/objects/31/3b6c31565cf54e4e27a046f4a42821b4d40c02e03654a7498a7561245f8d4b.file b/.flatpak-builder/cache/objects/31/3b6c31565cf54e4e27a046f4a42821b4d40c02e03654a7498a7561245f8d4b.file new file mode 100755 index 0000000..2bfa80d Binary files /dev/null and b/.flatpak-builder/cache/objects/31/3b6c31565cf54e4e27a046f4a42821b4d40c02e03654a7498a7561245f8d4b.file differ diff --git a/.flatpak-builder/cache/objects/32/333151ff38b96a480fa897b93f360e1ae15a1f14ec167e5d4ac7584d50b76e.dirtree b/.flatpak-builder/cache/objects/32/333151ff38b96a480fa897b93f360e1ae15a1f14ec167e5d4ac7584d50b76e.dirtree new file mode 100644 index 0000000..170a1cb Binary files /dev/null and b/.flatpak-builder/cache/objects/32/333151ff38b96a480fa897b93f360e1ae15a1f14ec167e5d4ac7584d50b76e.dirtree differ diff --git a/.flatpak-builder/cache/objects/32/581173bcd500e4ccc2353c6cdf1f98c2a680c25f8b5b83605c779eaea4b757.file b/.flatpak-builder/cache/objects/32/581173bcd500e4ccc2353c6cdf1f98c2a680c25f8b5b83605c779eaea4b757.file new file mode 100644 index 0000000..1ec4248 --- /dev/null +++ b/.flatpak-builder/cache/objects/32/581173bcd500e4ccc2353c6cdf1f98c2a680c25f8b5b83605c779eaea4b757.file @@ -0,0 +1,2316 @@ +/* + * Copyright (C) 2000 Akira Tagoh + * Copyright (C) 2000 Reinhard Müller + * Copyright (C) 2000 - 2005 Rodrigo Moya + * Copyright (C) 2001 - 2015 Vivien Malerba + * Copyright (C) 2002 - 2003 Gonzalo Paniagua Javier + * Copyright (C) 2002 Zbigniew Chyla + * Copyright (C) 2003 Akira TAGOH + * Copyright (C) 2003 - 2004 Laurent Sansonetti + * Copyright (C) 2003 - 2010 Murray Cumming + * Copyright (C) 2004 Alan Knowles + * Copyright (C) 2004 Dani Baeyens + * Copyright (C) 2005 Stanislav Brabec + * Copyright (C) 2008 Przemysław Grzegorczyk + * Copyright (C) 2009 Bas Driessen + * Copyright (C) 2010 David King + * Copyright (C) 2010 Jonh Wendell + * Copyright (C) 2013, 2018 Daniel Espinosa + * Copyright (C) 2013 Miguel Angel Cabrera Moya + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +#define G_LOG_DOMAIN "GDA-config" + +#include +#include +#include +#include +#include +#include +#include "gda-marshal.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_GIO + #include +#else +#endif +#ifdef G_OS_WIN32 +#include +#endif + +#ifdef HAVE_LIBSECRET + #include + const SecretSchema *_gda_secret_get_schema (void) G_GNUC_CONST; + #define GDA_SECRET_SCHEMA _gda_secret_get_schema () + #define SECRET_LABEL "DSN" + const SecretSchema * + _gda_secret_get_schema (void) + { + static const SecretSchema the_schema = { + "org.gnome-db.DSN", SECRET_SCHEMA_NONE, + { + { "DSN", SECRET_SCHEMA_ATTRIBUTE_STRING }, + { "NULL", 0 }, + } + }; + return &the_schema; + } +#else + #ifdef HAVE_GNOME_KEYRING + #include + #define SECRET_LABEL "server" + #endif +#endif + +/* + Register GdaDsnInfo type +*/ +GType +gda_dsn_info_get_type (void) +{ + static GType type = 0; + + if (G_UNLIKELY (type == 0)) { + if (type == 0) + type = g_boxed_type_register_static ("GdaDsnInfo", + (GBoxedCopyFunc) gda_dsn_info_copy, + (GBoxedFreeFunc) gda_dsn_info_free); + } + + return type; +} + +/** + * gda_dsn_info_new: + * + * Creates a new empty #GdaDsnInfo struct. + * + * Returns: (transfer full): a new #GdaDsnInfo struct. + * + * Since: 5.2 + */ +GdaDsnInfo* +gda_dsn_info_new (void) +{ + GdaDsnInfo *dsn = g_new0 (GdaDsnInfo, 1); + dsn->name = NULL; + dsn->provider = NULL; + dsn->description = NULL; + dsn->cnc_string = NULL; + dsn->auth_string = NULL; + dsn->is_system = FALSE; + return dsn; +} + +/** + * gda_dsn_info_copy: + * @source: a #GdaDsnInfo to copy from + * + * Copy constructor. + * + * Returns: (transfer full): a new #GdaDsnInfo + * + * Since: 5.2 + */ +GdaDsnInfo * +gda_dsn_info_copy (const GdaDsnInfo *source) +{ + GdaDsnInfo *n; + g_return_val_if_fail (source, NULL); + n = gda_dsn_info_new (); + n->name = source->name ? g_strdup (source->name) : NULL; + n->provider = source->provider ? g_strdup (source->provider) : NULL; + n->description = source->description ? g_strdup (source->description) : NULL; + n->cnc_string = source->cnc_string ? g_strdup (source->cnc_string) : NULL; + n->auth_string = source->auth_string ? g_strdup (source->auth_string) : NULL; + n->is_system = source->is_system; + return n; +} + +/** + * gda_dsn_info_free: + * @dsn: (nullable): a #GdaDsnInfo struct to free + * + * Frees any resources taken by @dsn struct. If @dsn is %NULL, then nothing happens. + * + * Since: 5.2 + */ +void +gda_dsn_info_free (GdaDsnInfo *dsn) +{ + if (dsn) { + g_free (dsn->name); + g_free (dsn->provider); + g_free (dsn->description); + g_free (dsn->cnc_string); + g_free (dsn->auth_string); + g_free (dsn); + } +} + +static +gboolean string_equal (const gchar *s1, const gchar *s2) +{ + if (s1) { + if (s2) + return !strcmp (s1, s2); + else + return FALSE; + } + else + return s2 ? FALSE : TRUE; +} + +static void gda_quark_process (gpointer key, + gpointer value, + gpointer string) +{ + gchar *evalue; + + g_string_append_c ((GString *)string, ','); + evalue = gda_rfc1738_encode ((const gchar *)value); + g_string_append_printf ((GString *)string, ",%s=%s", (gchar *)key, evalue); + g_free (evalue); +} + +static gchar * +make_cmp_string (const gchar *key_values_string) +{ + if (!key_values_string) + return NULL; + + GdaQuarkList *ql; + GSList *list, *sorted_list = NULL; + GString *string = g_string_new(""); + ql = gda_quark_list_new_from_string (key_values_string); + gda_quark_list_foreach (ql, gda_quark_process, string); + gda_quark_list_free (ql); + if (string) + return g_string_free (string, FALSE); + else + return NULL; +} + +/** + * gda_dsn_info_equal: + * @dsn1: (nullable): a #GdaDsnInfo + * @dsn2: (nullable): a #GdaDsnInfo + * + * Compares @dsn1 and @dsn2. + * + * If both @dsn1 and @dsn2 are %NULL, then the function returns %TRUE. + * If only one of @dsn1 or @dsn2 is %NULL, then the function return %FALSE. + * + * Returns: %TRUE if they are equal. + */ +gboolean +gda_dsn_info_equal (const GdaDsnInfo *dsn1, const GdaDsnInfo *dsn2) +{ + if (dsn1) { + if (dsn2) { + if ((dsn1->is_system == dsn2->is_system) && + string_equal (dsn1->name, dsn2->name) && + string_equal (dsn1->provider, dsn2->provider) && + string_equal (dsn1->description, dsn2->description)) { + gboolean eq; + gchar *s1, *s2; + s1 = make_cmp_string (dsn1->cnc_string); + s2 = make_cmp_string (dsn2->cnc_string); + eq = string_equal (s1, s2); + g_free (s1); + g_free (s2); + if (eq) { + s1 = make_cmp_string (dsn1->auth_string); + s2 = make_cmp_string (dsn2->auth_string); + eq = string_equal (s1, s2); + g_free (s1); + g_free (s2); + } + return eq; + } + else + return FALSE; + } + else + return FALSE; + } + else + return dsn2 ? FALSE : TRUE; +} + +/* GdaProviderInfo definitions */ +GdaProviderInfo* +gda_provider_info_copy (GdaProviderInfo *src) +{ + GdaProviderInfo *dst = g_new0(GdaProviderInfo, 1); + dst->id = g_strdup (src->id); + dst->location = g_strdup (src->location); + dst->description = g_strdup (src->description); + dst->dsn_params = gda_set_copy (src->dsn_params); + dst->auth_params = gda_set_copy (src->auth_params); + dst->icon_id = g_strdup (src->icon_id); + return dst; +} + +void +gda_provider_info_free (GdaProviderInfo *info) +{ + g_free (info->id); + g_free (info->location); + g_free (info->description); + g_object_unref (info->dsn_params); + g_object_unref (info->auth_params); + g_free (info->icon_id); + g_free (info); +} + +G_DEFINE_BOXED_TYPE (GdaProviderInfo, gda_provider_info, gda_provider_info_copy, gda_provider_info_free) + +/* GdaInternalProvider */ +typedef struct { + GdaProviderInfo pinfo; + GModule *handle; + GdaServerProvider *instance; +} InternalProvider; + +typedef struct { + gchar *user_file; + gchar *system_file; + gboolean system_config_allowed; + GSList *dsn_list; /* list of GdaDsnInfo structures */ + GSList *prov_list; /* list of InternalProvider structures */ + gboolean providers_loaded; /* TRUE if providers list has already been scanned */ + + gboolean emit_signals; +} GdaConfigPrivate; + +G_DEFINE_TYPE_WITH_PRIVATE (GdaConfig, gda_config, G_TYPE_OBJECT) + +static GObject *gda_config_constructor (GType type, + guint n_construct_properties, + GObjectConstructParam *construct_properties); +static void gda_config_dispose (GObject *object); +static void gda_config_set_property (GObject *object, + guint param_id, + const GValue *value, + GParamSpec *pspec); +static void gda_config_get_property (GObject *object, + guint param_id, + GValue *value, + GParamSpec *pspec); +static GdaConfig *unique_instance = NULL; +#ifdef HAVE_LIBSECRET +static gboolean sync_keyring = FALSE; +#else + #ifdef HAVE_GNOME_KEYRING +static gboolean sync_keyring = FALSE; + #endif +#endif + +static gint data_source_info_compare (GdaDsnInfo *infoa, GdaDsnInfo *infob); +static void internal_provider_free (InternalProvider *ip); +static void load_config_file (const gchar *file, gboolean is_system); +static void save_config_file (gboolean is_system); +static void load_all_providers (void); +static void reload_dsn_configuration (void); + + +enum { + DSN_ADDED, + DSN_TO_BE_REMOVED, + DSN_REMOVED, + DSN_CHANGED, + LAST_SIGNAL +}; + +static gint gda_config_signals[LAST_SIGNAL] = { 0, 0, 0, 0 }; + +/* properties */ +enum { + PROP_0, + PROP_USER_FILE, + PROP_SYSTEM_FILE +}; + +#ifdef HAVE_GIO +/* + * GIO static variables + */ +static GFileMonitor *mon_conf_user = NULL; +static GFileMonitor *mon_conf_global = NULL; +gulong user_notify_changes = 0; +gulong global_notify_changes = 0; + +static void conf_file_changed (GFileMonitor *mon, GFile *file, GFile *other_file, + GFileMonitorEvent event_type, gpointer data); +static void lock_notify_changes (void); +static void unlock_notify_changes (void); +#endif + +static GRecMutex gda_rmutex; +#define GDA_CONFIG_LOCK() g_rec_mutex_lock(&gda_rmutex) +#define GDA_CONFIG_UNLOCK() g_rec_mutex_unlock(&gda_rmutex) + +/* GdaServerProvider for SQLite as a shortcut, available + * even if the SQLite provider is not installed + */ +GdaServerProvider *_gda_config_sqlite_provider = NULL; + +/* + * GdaConfig class implementation + * @klass: + */ +static void +gda_config_class_init (GdaConfigClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + /** + * GdaConfig::dsn-added: + * @conf: the #GdaConfig object + * @new_dsn: a #GdaDsnInfo + * + * Gets emitted whenever a new DSN has been defined + */ + gda_config_signals[DSN_ADDED] = + g_signal_new ("dsn-added", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (GdaConfigClass, dsn_added), + NULL, NULL, + _gda_marshal_VOID__POINTER, + G_TYPE_NONE, 1, G_TYPE_POINTER); + /** + * GdaConfig::dsn-to-be-removed: + * @conf: the #GdaConfig object + * @old_dsn: a #GdaDsnInfo + * + * Gets emitted whenever a DSN is about to be removed + */ + gda_config_signals[DSN_TO_BE_REMOVED] = + g_signal_new ("dsn-to-be-removed", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (GdaConfigClass, dsn_to_be_removed), + NULL, NULL, + _gda_marshal_VOID__POINTER, + G_TYPE_NONE, 1, G_TYPE_POINTER); + /** + * GdaConfig::dsn-removed: + * @conf: the #GdaConfig object + * @old_dsn: a #GdaDsnInfo + * + * Gets emitted whenever a DSN has been removed + */ + gda_config_signals[DSN_REMOVED] = + g_signal_new ("dsn-removed", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (GdaConfigClass, dsn_removed), + NULL, NULL, + _gda_marshal_VOID__POINTER, + G_TYPE_NONE, 1, G_TYPE_POINTER); + /** + * GdaConfig::dsn-changed: + * @conf: the #GdaConfig object + * @dsn: a #GdaDsnInfo + * + * Gets emitted whenever a DSN's definition has been changed + */ + gda_config_signals[DSN_CHANGED] = + g_signal_new ("dsn-changed", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (GdaConfigClass, dsn_changed), + NULL, NULL, + _gda_marshal_VOID__POINTER, + G_TYPE_NONE, 1, G_TYPE_POINTER); + + /* Properties */ + object_class->set_property = gda_config_set_property; + object_class->get_property = gda_config_get_property; + + /** + * GdaConfig:user-filename: + * + * File to use for per-user DSN list. When changed, the whole list of DSN will be reloaded. + */ + /* To translators: DSN stands for Data Source Name, it's a named connection string defined in $XDG_DATA_HOME/libgda/config */ + g_object_class_install_property (object_class, PROP_USER_FILE, + g_param_spec_string ("user-filename", NULL, + "File to use for per-user DSN list", + NULL, + (G_PARAM_READABLE | G_PARAM_WRITABLE))); + /** + * GdaConfig:system-filename: + * + * File to use for system-wide DSN list. When changed, the whole list of DSN will be reloaded. + */ + /* To translators: DSN stands for Data Source Name, it's a named connection string defined in $PREFIX/etc/libgda-6.0/config */ + g_object_class_install_property (object_class, PROP_SYSTEM_FILE, + g_param_spec_string ("system-filename", NULL, + "File to use for system-wide DSN list", + NULL, + (G_PARAM_READABLE | G_PARAM_WRITABLE))); + + object_class->constructor = gda_config_constructor; + object_class->dispose = gda_config_dispose; +} + +static void +gda_config_init (GdaConfig *conf) +{ + g_return_if_fail (GDA_IS_CONFIG (conf)); + GdaConfigPrivate *priv = gda_config_get_instance_private (conf); + priv->user_file = NULL; + priv->system_file = NULL; + priv->system_config_allowed = FALSE; + priv->prov_list = NULL; + priv->dsn_list = NULL; + priv->providers_loaded = FALSE; + priv->emit_signals = TRUE; +} + +#ifdef HAVE_LIBSECRET +static void +secret_password_found_cb (GObject *source_object, GAsyncResult *res, gchar *dsnname) +{ + gchar *auth; + GError *error = NULL; + auth = secret_password_lookup_finish (res, &error); + GdaConfigPrivate *priv = gda_config_get_instance_private (unique_instance); + if (auth) { + GdaDsnInfo *dsn; + dsn = gda_config_get_dsn_info (dsnname); + if (dsn) { + if (dsn->auth_string && auth && !strcmp (dsn->auth_string, auth)) + return; + + g_free (dsn->auth_string); + dsn->auth_string = g_strdup (auth); + } + /*g_print ("Loaded auth info for '%s'\n", dsnname);*/ + if (priv->emit_signals) + g_signal_emit (unique_instance, gda_config_signals [DSN_CHANGED], 0, dsn); + g_free (auth); + } + else if (error) { + gda_log_message (_("Error loading authentication information for '%s' DSN: %s"), + dsnname, error->message ? error->message : _("No detail")); + g_clear_error (&error); + } + g_free (dsnname); +} +#else + #ifdef HAVE_GNOME_KEYRING +static void +password_found_cb (GnomeKeyringResult res, const gchar *password, const gchar *dsnname) +{ + if (res == GNOME_KEYRING_RESULT_OK) { + GdaDsnInfo *dsn; + dsn = gda_config_get_dsn_info (dsnname); + if (dsn) { + if (dsn->auth_string && password && !strcmp (dsn->auth_string, password)) + return; + + g_free (dsn->auth_string); + dsn->auth_string = g_strdup (password); + } + /*g_print ("Loaded auth info for '%s'\n", dsnname);*/ + if (priv->emit_signals) + g_signal_emit (unique_instance, gda_config_signals [DSN_CHANGED], 0, dsn); + } + else if (res != GNOME_KEYRING_RESULT_NO_MATCH) + gda_log_message (_("Error loading authentication information for '%s' DSN: %s"), + dsnname, gnome_keyring_result_to_message (res)); +} + #endif +#endif + +static void +load_config_file (const gchar *file, gboolean is_system) +{ + xmlDocPtr doc; + xmlNodePtr root; + GdaConfigPrivate *priv = gda_config_get_instance_private (unique_instance); + + if (!g_file_test (file, G_FILE_TEST_EXISTS)) + return; + + doc = xmlParseFile (file); + if (!doc) + return; + + root = xmlDocGetRootElement (doc); + if (root) { + xmlNodePtr node; + for (node = root->children; node; node = node->next) { /* iter over the
tags */ + if (strcmp ((gchar *) node->name, "section")) + continue; + + xmlChar *prop; + gchar *ptr; + GdaDsnInfo *info; + gboolean is_new = FALSE; + xmlNodePtr entry; + + prop = xmlGetProp (node, BAD_CAST "path"); + if (!prop) + continue; + for (ptr = ((gchar *) prop) + strlen ((gchar *) prop) - 1; ptr >= (gchar *) prop; ptr--) { + if (*ptr == '/') { + ptr++; + break; + } + } + info = gda_config_get_dsn_info (ptr); + if (!info) { + info = g_new0 (GdaDsnInfo, 1); + info->name = g_strdup (ptr); + is_new = TRUE; + } + else { + g_free (info->provider); info->provider = NULL; + g_free (info->cnc_string); info->cnc_string = NULL; + g_free (info->description); info->description = NULL; + g_free (info->auth_string); info->auth_string = NULL; + } + info->is_system = is_system; + xmlFree (prop); + + gchar *username = NULL, *password = NULL; + for (entry = node->children; entry; entry = entry->next) { /* iter over the tags */ + xmlChar *value; + if (strcmp ((gchar *)entry->name, "entry")) + continue; + prop = xmlGetProp (entry, BAD_CAST "name"); + if (!prop) + continue; + value = xmlGetProp (entry, BAD_CAST "value"); + if (!value) { + xmlFree (prop); + continue; + } + if (!strcmp ((gchar *) prop, "DSN")) + info->cnc_string = g_strdup ((gchar *)value); + else if (!strcmp ((gchar *) prop, "Provider")) { + GdaProviderInfo *pinfo; + pinfo = gda_config_get_provider_info ((gchar *)value); + if (pinfo) + info->provider = g_strdup (pinfo->id); + else + info->provider = g_strdup ((gchar *)value); + } + else if (!strcmp ((gchar *) prop, "Description")) + info->description = g_strdup ((gchar *)value); + if (!strcmp ((gchar *) prop, "Auth")) + info->auth_string = g_strdup ((gchar *)value); + else if (!strcmp ((gchar *) prop, "Username")) + username = g_strdup ((gchar*) value); + else if (!strcmp ((gchar *) prop, "Password")) + password = g_strdup ((gchar*) value); + xmlFree (prop); + xmlFree (value); + } + + if (username && *username) { + if (!info->auth_string) { + /* migrate username/password to auth_string */ + gchar *s1; + s1 = gda_rfc1738_encode (username); + if (password) { + gchar *s2; + s2 = gda_rfc1738_encode (password); + info->auth_string = g_strdup_printf ("USERNAME=%s;PASSWORD=%s", s1, s2); + g_free (s2); + } + else + info->auth_string = g_strdup_printf ("USERNAME=%s", s1); + g_free (s1); + } + } + g_free (username); + g_free (password); + +#ifdef HAVE_LIBSECRET + if (! is_system) { + if (sync_keyring) { + GError *error = NULL; + gchar *auth = NULL; + auth = secret_password_lookup_sync (GDA_SECRET_SCHEMA, + NULL, &error, + SECRET_LABEL, info->name, NULL); + if (auth) { + /*g_print ("Loaded sync. auth info for '%s': %s\n", info->name, auth);*/ + info->auth_string = g_strdup (auth); + g_free (auth); + } + else if (error) { + gda_log_message (_("Error loading authentication information for '%s' DSN: %s"), + info->name, error->message ? error->message : _("No detail")); + g_clear_error (&error); + } + } + else { + secret_password_lookup (GDA_SECRET_SCHEMA, + NULL, (GAsyncReadyCallback) secret_password_found_cb, + g_strdup (info->name), + SECRET_LABEL, info->name, NULL); + } + } +#else + #ifdef HAVE_GNOME_KEYRING + if (! is_system) { + if (sync_keyring) { + GnomeKeyringResult res; + gchar *auth = NULL; + res = gnome_keyring_find_password_sync (GNOME_KEYRING_NETWORK_PASSWORD, &auth, + SECRET_LABEL, info->name, NULL); + if (res == GNOME_KEYRING_RESULT_OK) { + /*g_print ("Loaded sync. auth info for '%s': %s\n", info->name, auth);*/ + info->auth_string = g_strdup (auth); + } + else if (res != GNOME_KEYRING_RESULT_NO_MATCH) + gda_log_message (_("Error loading authentication information for '%s' DSN: %s"), + info->name, gnome_keyring_result_to_message (res)); + if (auth) + gnome_keyring_free_password (auth); + } + else { + gchar *tmp = g_strdup (info->name); + gnome_keyring_find_password (GNOME_KEYRING_NETWORK_PASSWORD, + (GnomeKeyringOperationGetStringCallback) password_found_cb, + tmp, g_free, + SECRET_LABEL, tmp, NULL); + } + } + #endif +#endif + /* signals */ + if (is_new) { + priv->dsn_list = g_slist_insert_sorted (priv->dsn_list, info, + (GCompareFunc) data_source_info_compare); + if (priv->emit_signals) + g_signal_emit (unique_instance, gda_config_signals[DSN_ADDED], 0, info); + } + else if (priv->emit_signals) + g_signal_emit (unique_instance, gda_config_signals[DSN_CHANGED], 0, info); + } + } + xmlFreeDoc (doc); +} + +static void +save_config_file (gboolean is_system) +{ + xmlDocPtr doc; + xmlNodePtr root; + GSList *list; + + if (!unique_instance) + gda_config_get (); + GdaConfigPrivate *priv = gda_config_get_instance_private (unique_instance); + + if ((!is_system && !priv->user_file) || + (is_system && !priv->system_file)) { + return; + } + + doc = xmlNewDoc (BAD_CAST "1.0"); + root = xmlNewDocNode (doc, NULL, BAD_CAST "libgda-config", NULL); + xmlDocSetRootElement (doc, root); + for (list = priv->dsn_list; list; list = list->next) { + GdaDsnInfo *info = (GdaDsnInfo*) list->data; + if (info->is_system != is_system) + continue; + + xmlNodePtr section, entry; + gchar *prop; + section = xmlNewChild (root, NULL, BAD_CAST "section", NULL); + prop = g_strdup_printf ("/apps/libgda/Datasources/%s", info->name); + xmlSetProp (section, BAD_CAST "path", BAD_CAST prop); + g_free (prop); + + /* provider */ + entry = xmlNewChild (section, NULL, BAD_CAST "entry", NULL); + xmlSetProp (entry, BAD_CAST "name", BAD_CAST "Provider"); + xmlSetProp (entry, BAD_CAST "type", BAD_CAST "string"); + xmlSetProp (entry, BAD_CAST "value", BAD_CAST (info->provider)); + + /* DSN */ + entry = xmlNewChild (section, NULL, BAD_CAST "entry", NULL); + xmlSetProp (entry, BAD_CAST "name", BAD_CAST "DSN"); + xmlSetProp (entry, BAD_CAST "type", BAD_CAST "string"); + xmlSetProp (entry, BAD_CAST "value", BAD_CAST (info->cnc_string)); + +#if !defined (HAVE_GNOME_KEYRING) && !defined (HAVE_LIBSECRET) + if (! is_system) { + /* auth */ + entry = xmlNewChild (section, NULL, BAD_CAST "entry", NULL); + xmlSetProp (entry, BAD_CAST "name", BAD_CAST "Auth"); + xmlSetProp (entry, BAD_CAST "type", BAD_CAST "string"); + xmlSetProp (entry, BAD_CAST "value", BAD_CAST (info->auth_string)); + } +#endif + + /* description */ + entry = xmlNewChild (section, NULL, BAD_CAST "entry", NULL); + xmlSetProp (entry, BAD_CAST "name", BAD_CAST "Description"); + xmlSetProp (entry, BAD_CAST "type", BAD_CAST "string"); + xmlSetProp (entry, BAD_CAST "value", BAD_CAST (info->description)); + } + +#ifdef HAVE_GIO + lock_notify_changes (); +#endif + if (!is_system && priv->user_file) { + if (xmlSaveFormatFile (priv->user_file, doc, TRUE) == -1) + gda_log_error ("Error saving config data to '%s'", priv->user_file); + } + else if (is_system && priv->system_file) { + if (xmlSaveFormatFile (priv->system_file, doc, TRUE) == -1) + gda_log_error ("Error saving config data to '%s'", priv->system_file); + } + fflush (NULL); +#ifdef HAVE_GIO + unlock_notify_changes (); +#endif + xmlFreeDoc (doc); +} + +static GObject * +gda_config_constructor (GType type, + guint n_construct_properties, + GObjectConstructParam *construct_properties) +{ + GObject *object; + + if (!unique_instance) { +#if defined(HAVE_LIBSECRET) || defined(HAVE_GNOME_KEYRING) + if (g_getenv ("GDA_CONFIG_SYNCHRONOUS")) + sync_keyring = TRUE; +#endif + + guint i; + gboolean user_file_set = FALSE, system_file_set = FALSE; + + object = G_OBJECT_CLASS (gda_config_parent_class)->constructor (type, + n_construct_properties, + construct_properties); + for (i = 0; i< n_construct_properties; i++) { + GObjectConstructParam *prop = &(construct_properties[i]); + if (!strcmp (g_param_spec_get_name (prop->pspec), "user-filename")) { + user_file_set = TRUE; + /*g_print ("GdaConfig user dir set\n");*/ + } + else if (!strcmp (g_param_spec_get_name (prop->pspec), "system-filename")) { + system_file_set = TRUE; + /*g_print ("GdaConfig system dir set\n");*/ + } + } + + unique_instance = GDA_CONFIG (object); + GdaConfigPrivate *priv = gda_config_get_instance_private (unique_instance); + g_object_ref (object); /* keep one reference for the library */ + + /* define user and system dirs. if not already defined */ + if (!user_file_set) { + gchar *confdir, *conffile; + gboolean setup_ok = TRUE; + confdir = g_build_path (G_DIR_SEPARATOR_S, g_get_user_data_dir (), "libgda", NULL); + conffile = g_build_filename (confdir, "config", NULL); + + if (!g_file_test (confdir, G_FILE_TEST_EXISTS)) { + gchar *old_path; + old_path = g_build_path (G_DIR_SEPARATOR_S, g_get_home_dir (), ".libgda", NULL); /* Flawfinder: ignore */ + if (g_file_test (old_path, G_FILE_TEST_EXISTS)) { + /* using $HOME/.libgda because it exists */ + g_free (confdir); + confdir = old_path; + g_free (conffile); + conffile = g_build_filename (confdir, "config", NULL); + } + else { + g_free (old_path); + if (g_mkdir_with_parents (confdir, 0700)) { + setup_ok = FALSE; + gda_log_error (_("Error creating user specific " + "configuration directory '%s'"), + confdir); + } + if (setup_ok) { + gchar *str; + gchar *full_file; + gsize len; +#define DB_FILE "sales_test.db" +#define DEFAULT_CONFIG \ +"\n" \ +"\n" \ +"
\n" \ +" \n" \ +" \n" \ +" \n" \ +"
\n" \ +"
\n" +#define DEFAULT_CONFIG_EMPTY \ +"\n" \ +"\n" \ +" \n" \ +"\n" + + str = gda_gbr_get_file_path (GDA_ETC_DIR, + LIBGDA_ABI_NAME, DB_FILE, NULL); + if (g_file_get_contents (str, &full_file, &len, NULL)) { + gchar *dbfile; + + /* copy the Sales test database */ + dbfile = g_build_filename (confdir, DB_FILE, NULL); + if (g_file_set_contents (dbfile, full_file, len, NULL)) { + gchar *str2; + str2 = g_strdup_printf (DEFAULT_CONFIG, confdir); + g_file_set_contents (conffile, str2, -1, NULL); + g_free (str2); + } + else + g_file_set_contents (conffile, DEFAULT_CONFIG_EMPTY, -1, NULL); + g_free (dbfile); + g_free (full_file); + } + else + g_file_set_contents (conffile, DEFAULT_CONFIG_EMPTY, -1, NULL); + g_free (str); + } + } + if (setup_ok && !g_file_test (confdir, G_FILE_TEST_IS_DIR)) { + setup_ok = FALSE; + gda_log_message (_("User specific " + "configuration directory '%s' exists and is not a directory"), + confdir); + } + g_free (confdir); + + if (setup_ok) + priv->user_file = conffile; + else + g_free (conffile); + } + else { + if (!g_file_test (confdir, G_FILE_TEST_IS_DIR)) { + gda_log_message (_("User specific " + "configuration directory '%s' exists and is not a directory"), + confdir); + g_free (conffile); + } + else + priv->user_file = conffile; + g_free (confdir); + } + } + if (!system_file_set) + priv->system_file = gda_gbr_get_file_path (GDA_ETC_DIR, + LIBGDA_ABI_NAME, "config", NULL); + priv->system_config_allowed = FALSE; + if (priv->system_file) { +#ifdef G_OS_WIN32 + + FILE *file; + file = fopen (priv->system_file, "a"); /* Flawfinder: ignore */ + if (file) { + priv->system_config_allowed = TRUE; + fclose (file); + } +#else + struct stat stbuf; + if (stat (priv->system_file, &stbuf) == 0) { + /* use effective user and group IDs */ + uid_t euid; + gid_t egid; + euid = geteuid (); + egid = getegid (); + if (euid == stbuf.st_uid) { + if ((stbuf.st_mode & S_IWUSR) && (stbuf.st_mode & S_IRUSR)) + priv->system_config_allowed = TRUE; + } + else if (egid == stbuf.st_gid) { + if ((stbuf.st_mode & S_IWGRP) && (stbuf.st_mode & S_IRGRP)) + priv->system_config_allowed = TRUE; + } + else if ((stbuf.st_mode & S_IWOTH) && (stbuf.st_mode & S_IROTH)) + priv->system_config_allowed = TRUE; + } +#endif + } + + /* Setup file monitoring */ +#ifdef HAVE_GIO + if (priv->user_file) { + GFile *gf; + gf = g_file_new_for_path (priv->user_file); + mon_conf_user = g_file_monitor_file (gf, G_FILE_MONITOR_NONE, NULL, NULL); + if (mon_conf_user) + g_signal_connect (G_OBJECT (mon_conf_user), "changed", + G_CALLBACK (conf_file_changed), NULL); + g_object_unref (gf); + } + + if (priv->system_file) { + GFile *gf; + gf = g_file_new_for_path (priv->system_file); + mon_conf_global = g_file_monitor_file (gf, G_FILE_MONITOR_NONE, NULL, NULL); + if (mon_conf_user) + g_signal_connect (G_OBJECT (mon_conf_global), "changed", + G_CALLBACK (conf_file_changed), NULL); + g_object_unref (gf); + } +#endif + /* load existing DSN definitions */ + if (priv->system_file) + load_config_file (priv->system_file, TRUE); + if (priv->user_file) + load_config_file (priv->user_file, FALSE); + } + else + object = g_object_ref (G_OBJECT (unique_instance)); + + return object; +} + +static void +gda_config_dispose (GObject *object) +{ + GdaConfig *conf = (GdaConfig *) object; + + g_return_if_fail (GDA_IS_CONFIG (conf)); + GdaConfigPrivate *priv = gda_config_get_instance_private (conf); + + if (priv) { + if (priv->user_file) { + g_free (priv->user_file); + priv->user_file = NULL; + } + if (priv->system_file) { + g_free (priv->system_file); + priv->system_file = NULL; + } + + if (priv->dsn_list) { + g_slist_free_full (priv->dsn_list, (GDestroyNotify) gda_dsn_info_free); + priv->dsn_list = NULL; + } + if (priv->prov_list) { + g_slist_free_full (priv->prov_list, (GDestroyNotify) internal_provider_free); + priv->prov_list = NULL; + } + } + + /* chain to parent class */ + G_OBJECT_CLASS (gda_config_parent_class)->dispose (object); +} + + +/* module error */ +GQuark gda_config_error_quark (void) +{ + static GQuark quark; + if (!quark) + quark = g_quark_from_static_string ("gda_config_error"); + return quark; +} + + +static void +gda_config_set_property (GObject *object, + guint param_id, + const GValue *value, + GParamSpec *pspec) +{ + GdaConfig *conf; + const gchar *cstr; + + conf = GDA_CONFIG (object); + GdaConfigPrivate *priv = gda_config_get_instance_private (conf); + switch (param_id) { + case PROP_USER_FILE: + cstr = g_value_get_string (value); + if ((cstr && priv->user_file && + !strcmp (cstr, priv->user_file)) || + (! cstr && !priv->user_file)) { + /* nothing to do */ + break; + } + g_free (priv->user_file); + priv->user_file = NULL; + if (g_value_get_string (value)) + priv->user_file = g_strdup (cstr); + reload_dsn_configuration (); + break; + case PROP_SYSTEM_FILE: + cstr = g_value_get_string (value); + if ((cstr && priv->system_file && + !strcmp (cstr, priv->system_file)) || + (! cstr && !priv->system_file)) { + /* nothing to do */ + break; + } + g_free (priv->system_file); + priv->system_file = NULL; + if (g_value_get_string (value)) + priv->system_file = g_strdup (cstr); + reload_dsn_configuration (); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + break; + } +} + +static void +gda_config_get_property (GObject *object, + guint param_id, + GValue *value, + GParamSpec *pspec) +{ + GdaConfig *conf; + + conf = GDA_CONFIG (object); + GdaConfigPrivate *priv = gda_config_get_instance_private (conf); + switch (param_id) { + case PROP_USER_FILE: + g_value_set_string (value, priv->user_file); + break; + case PROP_SYSTEM_FILE: + g_value_set_string (value, priv->system_file); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + break; + } +} + +/** + * gda_config_get: + * + * Get a pointer to the global (unique) #GdaConfig object. This functions increments + * the reference count of the object, so you need to call g_object_unref() on it once finished. + * + * Returns: (transfer full): a non %NULL pointer to the unique #GdaConfig + */ +GdaConfig* +gda_config_get (void) +{ + GDA_CONFIG_LOCK (); + g_object_new (GDA_TYPE_CONFIG, NULL); + g_assert (unique_instance); + GDA_CONFIG_UNLOCK (); + return unique_instance; +} + +/** + * gda_config_get_dsn_info: + * @dsn_name: the name of the DSN to look for + * + * Get information about the DSN named @dsn_name. + * + * @dsn_name's format is "[<username>[:<password>]@]<DSN>" (if <username> + * and optionally <password> are provided, they are ignored). Also see the gda_dsn_split() utility + * function. + * + * Returns: (transfer none): a pointer to read-only #GdaDsnInfo structure, or %NULL if not found + */ +GdaDsnInfo * +gda_config_get_dsn_info (const gchar *dsn_name) +{ + GSList *list; + + g_return_val_if_fail (dsn_name, NULL); + + gchar *user, *pass, *real_dsn; + gda_dsn_split (dsn_name, &real_dsn, &user, &pass); + g_free (user); + g_free (pass); + if (!real_dsn) { + gda_log_message (_("Malformed data source name '%s'"), dsn_name); + return NULL; + } + + GDA_CONFIG_LOCK (); + if (!unique_instance) + gda_config_get (); + GdaConfigPrivate *priv = gda_config_get_instance_private (unique_instance); + + for (list = priv->dsn_list; list; list = list->next) + if (!strcmp (((GdaDsnInfo*) list->data)->name, real_dsn)) { + GDA_CONFIG_UNLOCK (); + g_free (real_dsn); + return (GdaDsnInfo*) list->data; + } + GDA_CONFIG_UNLOCK (); + g_free (real_dsn); + return NULL; +} + +#ifdef HAVE_LIBSECRET +static void +secret_password_stored_cb (GObject *source_object, GAsyncResult *res, gchar *dsnname) +{ + GError *error = NULL; + if (! secret_password_store_finish (res, &error)) { + gda_log_error (_("Couldn't save authentication information for DSN '%s': %s"), + dsnname, error && error->message ? error->message : _("No detail")); + g_clear_error (&error); + } + g_free (dsnname); +} +#else + #ifdef HAVE_GNOME_KEYRING +static void +password_stored_cb (GnomeKeyringResult res, const gchar *dsnname) +{ + if (res != GNOME_KEYRING_RESULT_OK) + gda_log_error (_("Couldn't save authentication information for DSN '%s': %s"), dsnname, + gnome_keyring_result_to_message (res)); +} + #endif +#endif + +/** + * gda_config_define_dsn: + * @info: a pointer to a filled GdaDsnInfo structure + * @error: a place to store errors, or %NULL + * + * Add or update a DSN from the definition in @info. + * + * This method may fail with a %GDA_CONFIG_ERROR domain error (see the #GdaConfigError error codes). + * + * Returns: TRUE if no error occurred + */ +gboolean +gda_config_define_dsn (const GdaDsnInfo *info, GError **error) +{ + GdaDsnInfo *einfo; + gboolean save_user = FALSE; + gboolean save_system = FALSE; + + g_return_val_if_fail (info, FALSE); + g_return_val_if_fail (info->name, FALSE); + + GDA_CONFIG_LOCK (); + if (!unique_instance) + gda_config_get (); + GdaConfigPrivate *priv = gda_config_get_instance_private (unique_instance); + + if (info->is_system && !priv->system_config_allowed) { + g_set_error (error, GDA_CONFIG_ERROR, GDA_CONFIG_PERMISSION_ERROR, + "%s", _("Can't manage system-wide configuration")); + GDA_CONFIG_UNLOCK (); + return FALSE; + } + + if (info->is_system) + save_system = TRUE; + else + save_user = TRUE; + einfo = gda_config_get_dsn_info (info->name); + if (einfo) { + g_free (einfo->provider); einfo->provider = NULL; + g_free (einfo->cnc_string); einfo->cnc_string = NULL; + g_free (einfo->description); einfo->description = NULL; + g_free (einfo->auth_string); einfo->auth_string = NULL; + if (info->provider) + einfo->provider = g_strdup (info->provider); + if (info->cnc_string) + einfo->cnc_string = g_strdup (info->cnc_string); + if (info->description) + einfo->description = g_strdup (info->description); + if (info->auth_string) + einfo->auth_string = g_strdup (info->auth_string); + + if (info->is_system != einfo->is_system) { + save_system = TRUE; + save_user = TRUE; + einfo->is_system = info->is_system ? TRUE : FALSE; + } + if (priv->emit_signals) + g_signal_emit (unique_instance, gda_config_signals[DSN_CHANGED], 0, einfo); + } + else { + einfo = g_new0 (GdaDsnInfo, 1); + einfo->name = g_strdup (info->name); + if (info->provider) + einfo->provider = g_strdup (info->provider); + if (info->cnc_string) + einfo->cnc_string = g_strdup (info->cnc_string); + if (info->description) + einfo->description = g_strdup (info->description); + if (info->auth_string) + einfo->auth_string = g_strdup (info->auth_string); + einfo->is_system = info->is_system ? TRUE : FALSE; + + priv->dsn_list = g_slist_insert_sorted (priv->dsn_list, einfo, + (GCompareFunc) data_source_info_compare); + if (priv->emit_signals) + g_signal_emit (unique_instance, gda_config_signals[DSN_ADDED], 0, einfo); + } + +#ifdef HAVE_LIBSECRET + if (! info->is_system && info->auth_string) { + /* save to keyring */ + gchar *tmp; + tmp = g_strdup_printf (_("Gnome-DB: authentication for the '%s' DSN"), info->name); + if (sync_keyring) { + gboolean res; + GError *error = NULL; + res = secret_password_store_sync (GDA_SECRET_SCHEMA, + SECRET_COLLECTION_DEFAULT, + tmp, info->auth_string, + NULL, &error, + SECRET_LABEL, info->name, NULL); + if (!res) { + gda_log_error (_("Couldn't save authentication information for DSN '%s': %s"), + info->name, + error && error->message ? error->message : _("No detail")); + g_clear_error (&error); + } + } + else { + secret_password_store (GDA_SECRET_SCHEMA, + SECRET_COLLECTION_DEFAULT, + tmp, info->auth_string, + NULL, + (GAsyncReadyCallback) secret_password_stored_cb, + g_strdup (info->name), + SECRET_LABEL, info->name, NULL); + } + g_free (tmp); + } +#else + #ifdef HAVE_GNOME_KEYRING + if (! info->is_system && info->auth_string) { + /* save to keyring */ + gchar *tmp; + tmp = g_strdup_printf (_("Gnome-DB: authentication for the '%s' DSN"), info->name); + if (sync_keyring) { + GnomeKeyringResult res; + res = gnome_keyring_store_password_sync (GNOME_KEYRING_NETWORK_PASSWORD, GNOME_KEYRING_DEFAULT, + tmp, info->auth_string, + SECRET_LABEL, info->name, NULL); + password_stored_cb (res, info->name); + } + else { + gchar *tmp1; + tmp1 = g_strdup (info->name); + gnome_keyring_store_password (GNOME_KEYRING_NETWORK_PASSWORD, + GNOME_KEYRING_DEFAULT, + tmp, info->auth_string, + (GnomeKeyringOperationDoneCallback) password_stored_cb, tmp1, g_free, + SECRET_LABEL, info->name, NULL); + } + g_free (tmp); + } + #endif +#endif + + if (save_system) + save_config_file (TRUE); + if (save_user) + save_config_file (FALSE); + + GDA_CONFIG_UNLOCK (); + return TRUE; +} + +#ifdef HAVE_LIBSECRET +static void +secret_password_deleted_cb (GObject *source_object, GAsyncResult *res, gchar *dsnname) +{ + GError *error = NULL; + if (! secret_password_clear_finish (res, &error)) { + gda_log_error (_("Couldn't delete authentication information for DSN '%s': %s"), dsnname, + error && error->message ? error->message : _("No detail")); + g_clear_error (&error); + } + g_free (dsnname); +} +#else + #ifdef HAVE_GNOME_KEYRING +static void +password_deleted_cb (GnomeKeyringResult res, const gchar *dsnname) +{ + if (res != GNOME_KEYRING_RESULT_OK) + gda_log_error (_("Couldn't delete authentication information for DSN '%s': %s"), dsnname, + gnome_keyring_result_to_message (res)); +} + #endif +#endif + +/** + * gda_config_remove_dsn: + * @dsn_name: the name of the DSN to remove + * @error: a place to store errors, or %NULL + * + * Remove the DSN named @dsn_name. + * + * This method may fail with a %GDA_CONFIG_ERROR domain error (see the #GdaConfigError error codes). + * + * Returns: TRUE if no error occurred + */ +gboolean +gda_config_remove_dsn (const gchar *dsn_name, GError **error) +{ + GdaDsnInfo *info; + gboolean save_user = FALSE; + gboolean save_system = FALSE; + + g_return_val_if_fail (dsn_name, FALSE); + GdaConfigPrivate *priv = gda_config_get_instance_private (unique_instance); + + GDA_CONFIG_LOCK (); + if (!unique_instance) + gda_config_get (); + + info = gda_config_get_dsn_info (dsn_name); + if (!info) { + g_set_error (error, GDA_CONFIG_ERROR, GDA_CONFIG_DSN_NOT_FOUND_ERROR, + _("Unknown DSN '%s'"), dsn_name); + GDA_CONFIG_UNLOCK (); + return FALSE; + } + if (info->is_system && !priv->system_config_allowed) { + g_set_error (error, GDA_CONFIG_ERROR, GDA_CONFIG_PERMISSION_ERROR, + "%s", _("Can't manage system-wide configuration")); + GDA_CONFIG_UNLOCK (); + return FALSE; + } + + if (info->is_system) + save_system = TRUE; + else + save_user = TRUE; + + if (priv->emit_signals) + g_signal_emit (unique_instance, gda_config_signals[DSN_TO_BE_REMOVED], 0, info); + priv->dsn_list = g_slist_remove (priv->dsn_list, info); + if (priv->emit_signals) + g_signal_emit (unique_instance, gda_config_signals[DSN_REMOVED], 0, info); + +#ifdef HAVE_LIBSECRET + if (! info->is_system) { + /* remove from keyring */ + if (sync_keyring) { + GError *error = NULL; + if (! secret_password_clear_sync (GDA_SECRET_SCHEMA, + NULL, &error, + SECRET_LABEL, info->name, NULL)) { + gda_log_error (_("Couldn't delete authentication information for DSN '%s': %s"), + info->name, + error && error->message ? error->message : _("No detail")); + g_clear_error (&error); + } + } + else { + secret_password_clear (GDA_SECRET_SCHEMA, + NULL, (GAsyncReadyCallback) secret_password_deleted_cb, + g_strdup (info->name), + SECRET_LABEL, info->name, NULL); + } + } +#else + #ifdef HAVE_GNOME_KEYRING + if (! info->is_system) { + /* remove from keyring */ + if (sync_keyring) { + GnomeKeyringResult res; + res = gnome_keyring_delete_password_sync (GNOME_KEYRING_NETWORK_PASSWORD, GNOME_KEYRING_DEFAULT, + SECRET_LABEL, info->name, NULL); + password_deleted_cb (res, info->name); + } + else { + gchar *tmp; + tmp = g_strdup (dsn_name); + gnome_keyring_delete_password (GNOME_KEYRING_NETWORK_PASSWORD, + (GnomeKeyringOperationDoneCallback) password_deleted_cb, + tmp, g_free, + SECRET_LABEL, info->name, NULL); + } + } + #endif +#endif + gda_dsn_info_free (info); + + if (save_system) + save_config_file (TRUE); + if (save_user) + save_config_file (FALSE); + + GDA_CONFIG_UNLOCK (); + return TRUE; +} + +/** + * gda_config_dsn_needs_authentication: + * @dsn_name: the name of a DSN, in the "[<username>[:<password>]@]<DSN>" format + * + * Tells if the data source identified as @dsn_name needs any authentication. If a <username> + * and optionally a <password> are specified, they are ignored. + * + * Returns: TRUE if an authentication is needed + */ +gboolean +gda_config_dsn_needs_authentication (const gchar *dsn_name) +{ + GdaDsnInfo *info; + GdaProviderInfo *pinfo; + + info = gda_config_get_dsn_info (dsn_name); + if (!info) + return FALSE; + pinfo = gda_config_get_provider_info (info->provider); + if (!pinfo) { + gda_log_message (_("Provider '%s' not found"), info->provider); + return FALSE; + } + if (pinfo->auth_params && gda_set_get_holders (pinfo->auth_params)) + return TRUE; + else + return FALSE; +} + +/** + * gda_config_list_dsn: + * + * Get a #GdaDataModel representing all the configured DSN, and keeping itself up to date with + * the changes in the declared DSN. + * + * The returned data model is composed of the following columns: + * + * DSN name + * Provider name + * Description + * Connection string + * Username if it exists + * + * + * Returns: (transfer full): a new #GdaDataModel + */ +GdaDataModel * +gda_config_list_dsn (void) +{ + GdaDataModel *model; + GDA_CONFIG_LOCK (); + if (!unique_instance) + gda_config_get (); + + model = GDA_DATA_MODEL (g_object_new (GDA_TYPE_DATA_MODEL_DSN_LIST, NULL)); + GDA_CONFIG_UNLOCK (); + return model; +} + +/** + * gda_config_get_nb_dsn: + * + * Get the number of defined DSN + * + * Returns: the number of defined DSN + */ +gint +gda_config_get_nb_dsn (void) +{ + gint ret; + GDA_CONFIG_LOCK (); + if (!unique_instance) + gda_config_get (); + GdaConfigPrivate *priv = gda_config_get_instance_private (unique_instance); + + ret = g_slist_length (priv->dsn_list); + GDA_CONFIG_UNLOCK (); + return ret; +} + +/** + * gda_config_get_dsn_info_index: + * @dsn_name: a DSN + * + * Get the index (starting at 0) of the DSN named @dsn_name + * + * Returns: the index or -1 if not found + */ +gint +gda_config_get_dsn_info_index (const gchar *dsn_name) +{ + GdaDsnInfo *info; + gint ret = -1; + + g_return_val_if_fail (dsn_name, -1); + GDA_CONFIG_LOCK (); + if (!unique_instance) + gda_config_get (); + GdaConfigPrivate *priv = gda_config_get_instance_private (unique_instance); + + info = gda_config_get_dsn_info (dsn_name); + if (info) + ret = g_slist_index (priv->dsn_list, info); + + GDA_CONFIG_UNLOCK (); + return ret; +} + +/** + * gda_config_get_dsn_info_at_index: + * @index: an index + * + * Get a pointer to a read-only #GdaDsnInfo at the @index position + * + * Returns: (transfer none):the pointer or %NULL if no DSN exists at position @index + */ +GdaDsnInfo * +gda_config_get_dsn_info_at_index (gint index) +{ + GdaDsnInfo *ret; + GDA_CONFIG_LOCK (); + if (!unique_instance) + gda_config_get (); + GdaConfigPrivate *priv = gda_config_get_instance_private (unique_instance); + ret = g_slist_nth_data (priv->dsn_list, index); + GDA_CONFIG_UNLOCK (); + return ret; +} + +/** + * gda_config_can_modify_system_config: + * + * Tells if the global (system) configuration can be modified (considering + * system permissions and settings) + * + * Returns: TRUE if system-wide configuration can be modified + */ +gboolean +gda_config_can_modify_system_config (void) +{ + gboolean retval; + GDA_CONFIG_LOCK (); + if (!unique_instance) + gda_config_get (); + GdaConfigPrivate *priv = gda_config_get_instance_private (unique_instance); + retval = priv->system_config_allowed; + GDA_CONFIG_UNLOCK (); + return retval; +} + +/** + * gda_config_get_provider_info: + * @provider_name: a database provider + * + * Get some information about the a database provider (adapter) named + * + * Returns: (transfer none): a pointer to read-only #GdaProviderInfo structure, or %NULL if not found + */ +GdaProviderInfo * +gda_config_get_provider_info (const gchar *provider_name) +{ + GSList *list; + g_return_val_if_fail (provider_name, NULL); + GDA_CONFIG_LOCK (); + if (!unique_instance) + gda_config_get (); + GdaConfigPrivate *priv = gda_config_get_instance_private (unique_instance); + + if (!priv->providers_loaded) + load_all_providers (); + + if (!g_ascii_strcasecmp (provider_name, "MS Access")) { + GDA_CONFIG_UNLOCK (); + return gda_config_get_provider_info ("MSAccess"); + } + + for (list = priv->prov_list; list; list = list->next) + if (!g_ascii_strcasecmp (((GdaProviderInfo*) list->data)->id, provider_name)) { + GDA_CONFIG_UNLOCK (); + return (GdaProviderInfo*) list->data; + } + GDA_CONFIG_UNLOCK (); + return NULL; +} + +/** + * gda_config_get_provider: + * @provider_name: a database provider + * @error: a place to store errors, or %NULL + * + * Get a pointer to the session-wide #GdaServerProvider for the + * provider named @provider_name. The caller must not call g_object_unref() on the + * returned object. + * + * This method may fail with a %GDA_CONFIG_ERROR domain error (see the #GdaConfigError error codes). + * + * Returns: (transfer none): a pointer to the #GdaServerProvider, or %NULL if an error occurred + */ +GdaServerProvider * +gda_config_get_provider (const gchar *provider_name, GError **error) +{ + InternalProvider *ip; + GdaServerProvider *(*plugin_create_provider) (void); + GdaServerProvider *(*plugin_create_sub_provider) (const gchar *provider_name); + + g_return_val_if_fail (provider_name, NULL); + GDA_CONFIG_LOCK (); + ip = (InternalProvider *) gda_config_get_provider_info (provider_name); + if (!ip) { + g_set_error (error, GDA_CONFIG_ERROR, GDA_CONFIG_PROVIDER_NOT_FOUND_ERROR, + _("No provider '%s' installed"), provider_name); + GDA_CONFIG_UNLOCK (); + return NULL; + } + if (ip->instance) { + GDA_CONFIG_UNLOCK (); + return ip->instance; + } + /* need to actually create the provider object */ + if (!ip->handle) { + GdaProviderInfo *info = (GdaProviderInfo*) ip; + ip->handle = g_module_open (info->location, G_MODULE_BIND_LAZY); + if (!ip->handle) { + g_set_error (error, GDA_CONFIG_ERROR, GDA_CONFIG_PROVIDER_CREATION_ERROR, + _("Can't load provider: %s"), g_module_error ()); + return NULL; + } + + void (*plugin_init) (void); + if (g_module_symbol (ip->handle, "plugin_init", (gpointer *) &plugin_init)) { + plugin_init (); + } + } + + g_module_symbol (ip->handle, "plugin_create_provider", (gpointer) &plugin_create_provider); + if (plugin_create_provider) { + ip->instance = plugin_create_provider (); + } else { + g_module_symbol (ip->handle, "plugin_create_sub_provider", (gpointer) &plugin_create_sub_provider); + if (plugin_create_sub_provider) + ip->instance = plugin_create_sub_provider (provider_name); + } + + if (!ip->instance) { + g_set_error (error, GDA_CONFIG_ERROR, GDA_CONFIG_PROVIDER_CREATION_ERROR, + _("Can't instantiate provider '%s'"), provider_name); + GDA_CONFIG_UNLOCK (); + return NULL; + } + + GDA_CONFIG_UNLOCK (); + return ip->instance; +} + +/** + * gda_config_list_providers: + * + * Get a #GdaDataModel representing all the installed database providers. + * + * The returned data model is composed of the following columns: + * + * Provider name + * Description + * DSN parameters + * Authentication parameters + * File name of the plugin + * + * + * Returns: (transfer full): a new #GdaDataModel + */ +GdaDataModel * +gda_config_list_providers (void) +{ + GSList *list; + GdaDataModel *model; + + GDA_CONFIG_LOCK (); + if (!unique_instance) + gda_config_get (); + GdaConfigPrivate *priv = gda_config_get_instance_private (unique_instance); + + if (!priv->providers_loaded) + load_all_providers (); + + model = gda_data_model_array_new_with_g_types (5, + G_TYPE_STRING, + G_TYPE_STRING, + G_TYPE_STRING, + G_TYPE_STRING, + G_TYPE_STRING); + gda_data_model_set_column_title (model, 0, _("Provider")); + gda_data_model_set_column_title (model, 1, _("Description")); + gda_data_model_set_column_title (model, 2, _("DSN parameters")); + gda_data_model_set_column_title (model, 3, _("Authentication")); + gda_data_model_set_column_title (model, 4, _("File")); + g_object_set_data (G_OBJECT (model), "name", _("List of installed providers")); + + for (list = priv->prov_list; list; list = list->next) { + GdaProviderInfo *info = (GdaProviderInfo *) list->data; + GValue *value; + gint row; + + row = gda_data_model_append_row (model, NULL); + + value = gda_value_new_from_string (info->id, G_TYPE_STRING); + gda_data_model_set_value_at (model, 0, row, value, NULL); + gda_value_free (value); + + if (info->description) + value = gda_value_new_from_string (info->description, G_TYPE_STRING); + else + value = gda_value_new_null (); + gda_data_model_set_value_at (model, 1, row, value, NULL); + gda_value_free (value); + + if (info->dsn_params) { + GSList *params; + GString *string = g_string_new (""); + for (params = gda_set_get_holders (info->dsn_params); + params; params = params->next) { + const gchar *id; + + id = gda_holder_get_id (GDA_HOLDER (params->data)); + if (params != gda_set_get_holders (info->dsn_params)) + g_string_append (string, ",\n"); + g_string_append (string, id); + } + value = gda_value_new_from_string (string->str, G_TYPE_STRING); + g_string_free (string, TRUE); + gda_data_model_set_value_at (model, 2, row, value, NULL); + gda_value_free (value); + } + + if (info->auth_params) { + GSList *params; + GString *string = g_string_new (""); + for (params = gda_set_get_holders (info->auth_params); + params; params = params->next) { + const gchar *id; + + id = gda_holder_get_id (GDA_HOLDER (params->data)); + if (params != gda_set_get_holders (info->auth_params)) + g_string_append (string, ",\n"); + g_string_append (string, id); + } + value = gda_value_new_from_string (string->str, G_TYPE_STRING); + g_string_free (string, TRUE); + gda_data_model_set_value_at (model, 3, row, value, NULL); + gda_value_free (value); + } + + value = gda_value_new_from_string (info->location, G_TYPE_STRING); + gda_data_model_set_value_at (model, 4, row, value, NULL); + gda_value_free (value); + } + g_object_set (G_OBJECT (model), "read-only", TRUE, NULL); + + GDA_CONFIG_UNLOCK (); + return model; +} + +static gint +internal_provider_sort_func (InternalProvider *a, InternalProvider *b) +{ + return strcmp (a->pinfo.id, b->pinfo.id); +} + +static void load_providers_from_dir (const gchar *dirname, gboolean recurs); +static void +load_all_providers (void) +{ + const gchar *dirname; + g_assert (unique_instance); + GdaConfigPrivate *priv = gda_config_get_instance_private (unique_instance); + GError *error = NULL; + + dirname = g_getenv ("GDA_TOP_BUILD_DIR"); + if (dirname) { + gchar *pdir; + pdir = g_build_path (G_DIR_SEPARATOR_S, dirname, "providers", NULL); + load_providers_from_dir (pdir, TRUE); + g_free (pdir); + } + else { + gchar *str; + str = gda_gbr_get_file_path (GDA_LIB_DIR, LIBGDA_ABI_NAME, "providers", NULL); + load_providers_from_dir (str, FALSE); + g_free (str); + } + priv->providers_loaded = TRUE; + + /* find SQLite provider, and instantiate it if not installed */ + _gda_config_sqlite_provider = gda_config_get_provider ("SQLite", &error); + if (!_gda_config_sqlite_provider) { + g_message (_("No default SQLite Provider Trying to create a new one. Error was: %s"), + error && error->message ? error->message: _("No detail")); + g_clear_error (&error); + _gda_config_sqlite_provider = (GdaServerProvider*) + g_object_new (GDA_TYPE_SQLITE_PROVIDER, NULL); + } + + /* sort providers by name */ + priv->prov_list = g_slist_sort (priv->prov_list, + (GCompareFunc) internal_provider_sort_func); +} + +static InternalProvider * +create_internal_provider (const gchar *path, + const gchar *prov_name, const gchar *prov_descr, + gchar *dsn_spec, gchar *auth_spec, const gchar *icon_id) +{ + g_return_val_if_fail (prov_name, NULL); + + InternalProvider *ip; + GdaProviderInfo *info; + + ip = g_new0 (InternalProvider, 1); + ip->handle = NULL; + info = (GdaProviderInfo*) ip; + info->location = g_strdup (path); + + info->id = g_strdup (prov_name); + info->description = g_strdup (prov_descr); + + /* DSN parameters */ + info->dsn_params = NULL; + if (dsn_spec) { + GError *error = NULL; + info->dsn_params = gda_set_new_from_spec_string (dsn_spec, &error); + if (!info->dsn_params) { + g_warning ("Invalid format for provider '%s' DSN spec : %s", + info->id, + error ? error->message : "Unknown error"); + g_clear_error (&error); +#ifdef GDA_DEBUG + g_print ("Dump DSN spec:\n%s\n", dsn_spec); +#endif + + /* there may be traces of the provider installed but some parts are missing, + forget about that provider... */ + internal_provider_free (ip); + g_free (dsn_spec); + return NULL; + } + g_free (dsn_spec); + } + else + gda_log_message ("Provider '%s' does not provide a DSN spec", info->id); + + /* Authentication parameters */ + info->auth_params = NULL; + if (auth_spec) { + GError *error = NULL; + + info->auth_params = gda_set_new_from_spec_string (auth_spec, &error); + if (!info->auth_params) { + g_warning ("Invalid format for provider '%s' AUTH spec : %s", + info->id, + error ? error->message : "Unknown error"); + if (error) + g_error_free (error); + } + + if (!info->auth_params) { + /* there may be traces of the provider installed but some parts are missing, + forget about that provider... */ + internal_provider_free (ip); + g_free (auth_spec); + return NULL; + } + g_free (auth_spec); + } + else { + /* default to username/password */ + GdaHolder *h; + info->auth_params = gda_set_new_inline (2, "USERNAME", G_TYPE_STRING, NULL, + "PASSWORD", G_TYPE_STRING, NULL); + h = gda_set_get_holder (info->auth_params, "USERNAME"); + g_object_set (G_OBJECT (h), "name", _("Username"), "not-null", TRUE, NULL); + h = gda_set_get_holder (info->auth_params, "PASSWORD"); + g_object_set (G_OBJECT (h), "name", _("Password"), "not-null", TRUE, NULL); + + GValue *value; +#define GDAUI_ATTRIBUTE_PLUGIN "__gdaui_attr_plugin" + value = gda_value_new_from_string ("string:HIDDEN=true", G_TYPE_STRING); + g_object_set (h, "plugin", value, NULL); + gda_value_free (value); + } + + info->icon_id = icon_id ? g_strdup (icon_id) : g_strdup (prov_name); + + return ip; +} + +static void +load_providers_from_dir (const gchar *dirname, gboolean recurs) +{ + GDir *dir; + GError *err = NULL; + const gchar *name; + + GDA_CONFIG_LOCK (); + if (!unique_instance) + gda_config_get (); + GdaConfigPrivate *priv = gda_config_get_instance_private (unique_instance); + /* read the plugin directory */ +#ifdef GDA_DEBUG + g_print ("Loading providers in %s\n", dirname); +#endif + dir = g_dir_open (dirname, 0, &err); + if (err) { + gda_log_error (err->message); + g_error_free (err); + return; + } + + while ((name = g_dir_read_name (dir))) { + GModule *handle; + gchar *path; + + /* initialization method */ + void (*plugin_init) (const gchar *); + + /* methods for shared libraries which provide only one type of provider */ + const gchar * (* plugin_get_name) (void); + const gchar * (* plugin_get_description) (void); + gchar * (* plugin_get_dsn_spec) (void); + gchar * (* plugin_get_auth_spec) (void); + const gchar * (*plugin_get_icon_id) (void); + + /* methods for shared libraries which provide several types of providers (ODBC, JDBC, ...) */ + const gchar ** (* plugin_get_sub_names) (void); + const gchar * (* plugin_get_sub_description) (const gchar *name); + gchar * (* plugin_get_sub_dsn_spec) (const gchar *name); + gchar * (* plugin_get_sub_auth_spec) (const gchar *name); + const gchar * (*plugin_get_sub_icon_id) (const gchar *name); + + if (recurs) { + gchar *cname; + cname = g_build_filename (dirname, name, NULL); + if (g_file_test (cname, G_FILE_TEST_IS_DIR)) + load_providers_from_dir (cname, TRUE); + g_free (cname); + } + if (!g_str_has_suffix (name, "." G_MODULE_SUFFIX)) + continue; +#ifdef G_WITH_CYGWIN + if (!g_str_has_prefix (name, "cyggda")) +#else + if (!g_str_has_prefix (name, "libgda")) +#endif + continue; + +#ifdef GDA_DEBUG + g_print ("File's name checking for provider: %s\n", name); +#endif + path = g_build_path (G_DIR_SEPARATOR_S, dirname, name, NULL); + handle = g_module_open (path, G_MODULE_BIND_LAZY); + if (!handle) { + if (g_getenv ("GDA_SHOW_PROVIDER_LOADING_ERROR")) + gda_log_message (_("Error loading provider '%s': %s"), path, g_module_error ()); +#ifdef GDA_DEBUG + g_print ("Error loading provider's module: %s : %s\n", path, g_module_error ()); +#endif + g_free (path); + continue; + } + + if (g_module_symbol (handle, "plugin_init", (gpointer *) &plugin_init)) { + plugin_init (dirname); + } + else { + g_module_close (handle); + g_free (path); + continue; + } + g_module_symbol (handle, "plugin_get_name", + (gpointer *) &plugin_get_name); + g_module_symbol (handle, "plugin_get_description", + (gpointer *) &plugin_get_description); + g_module_symbol (handle, "plugin_get_dsn_spec", + (gpointer *) &plugin_get_dsn_spec); + g_module_symbol (handle, "plugin_get_auth_spec", + (gpointer *) &plugin_get_auth_spec); + g_module_symbol (handle, "plugin_get_icon_id", + (gpointer *) &plugin_get_icon_id); + g_module_symbol (handle, "plugin_get_sub_names", + (gpointer *) &plugin_get_sub_names); + g_module_symbol (handle, "plugin_get_sub_description", + (gpointer *) &plugin_get_sub_description); + g_module_symbol (handle, "plugin_get_sub_dsn_spec", + (gpointer *) &plugin_get_sub_dsn_spec); + g_module_symbol (handle, "plugin_get_sub_auth_spec", + (gpointer *) &plugin_get_sub_auth_spec); + g_module_symbol (handle, "plugin_get_sub_icon_id", + (gpointer *) &plugin_get_sub_icon_id); + + if (plugin_get_sub_names) { + const gchar **subnames = plugin_get_sub_names (); + const gchar **ptr; + for (ptr = subnames; ptr && *ptr; ptr++) { + InternalProvider *ip; + + ip = create_internal_provider (path, *ptr, + plugin_get_sub_description ? + plugin_get_sub_description (*ptr) : NULL, + plugin_get_sub_dsn_spec ? + plugin_get_sub_dsn_spec (*ptr) : NULL, + plugin_get_sub_auth_spec ? + plugin_get_sub_auth_spec (*ptr) : NULL, + plugin_get_sub_icon_id ? + plugin_get_sub_icon_id (*ptr) : NULL); + if (ip) { + priv->prov_list = + g_slist_prepend (priv->prov_list, ip); +#ifdef GDA_DEBUG + g_print ("Loaded '%s' sub-provider\n", ((GdaProviderInfo*) ip)->id); +#endif + } +#ifdef GDA_DEBUG + else { + g_print ("Error Loading sub-provider\n"); + } +#endif + } + } + else { + InternalProvider *ip; + ip = create_internal_provider (path, + plugin_get_name ? plugin_get_name () : name, + plugin_get_description ? plugin_get_description () : NULL, + plugin_get_dsn_spec ? plugin_get_dsn_spec () : NULL, + plugin_get_auth_spec ? plugin_get_auth_spec () : NULL, + plugin_get_icon_id ? plugin_get_icon_id () : NULL); + if (ip) { + priv->prov_list = + g_slist_prepend (priv->prov_list, ip); +#ifdef GDA_DEBUG + g_print ("Loaded '%s' provider\n", ((GdaProviderInfo*) ip)->id); +#endif + } +#ifdef GDA_DEBUG + else { + g_print ("Error Loading provider\n"); + } +#endif + } + g_free (path); + g_module_close (handle); + } + + /* free memory */ + g_dir_close (dir); + GDA_CONFIG_UNLOCK (); +} + + + +/* sorting function */ +static gint +data_source_info_compare (GdaDsnInfo *infoa, GdaDsnInfo *infob) +{ + if (!infoa && !infob) + return 0; + if (infoa) { + if (!infob) + return 1; + else { + gchar *u8a, *u8b; + gint res; + u8a = g_utf8_casefold (infoa->name, -1); + u8b = g_utf8_casefold (infob->name, -1); + res = strcmp (u8a, u8b); + g_free (u8a); + g_free (u8b); + return res; + } + } + else + return -1; +} + +static void +internal_provider_free (InternalProvider *ip) +{ + GdaProviderInfo *info = (GdaProviderInfo*) ip; + if (ip->instance) + g_object_unref (ip->instance); + if (ip->handle) + g_module_close (ip->handle); + + g_free (info->id); + g_free (info->location); + g_free (info->description); + if (info->dsn_params) + g_object_unref (info->dsn_params); + g_free (ip); +} + +static gboolean +str_equal (const gchar *str1, const gchar *str2) +{ + if (str1 && str2) { + if (!strcmp (str1, str2)) + return TRUE; + else + return FALSE; + } + else if (!str1 && !str2) + return TRUE; + return FALSE; +} + +static void +reload_dsn_configuration (void) +{ + GSList *list, *current_dsn_list, *new_dsn_list; + if (!unique_instance) { + /* object not yet created */ + return; + } + GdaConfigPrivate *priv = gda_config_get_instance_private (unique_instance); + + GDA_CONFIG_LOCK (); +#ifdef GDA_DEBUG_NO + gboolean is_system = (mon == mon_conf_global) ? TRUE : FALSE; + g_print ("Reloading config files (%s config has changed)\n", is_system ? "global" : "user"); + for (list = priv->dsn_list; list; list = list->next) { + GdaDsnInfo *info = (GdaDsnInfo *) list->data; + g_print ("[info %p]: %s/%s\n", info, info->provider, info->name); + } +#endif + current_dsn_list = priv->dsn_list; + priv->dsn_list = NULL; + + priv->emit_signals = FALSE; +#ifdef HAVE_GIO + lock_notify_changes (); +#endif + if (priv->system_file) + load_config_file (priv->system_file, TRUE); + if (priv->user_file) + load_config_file (priv->user_file, FALSE); +#ifdef HAVE_GIO + unlock_notify_changes (); +#endif + priv->emit_signals = TRUE; + + new_dsn_list = priv->dsn_list; + priv->dsn_list = current_dsn_list; + current_dsn_list = NULL; + + /* handle new or updated DSN */ + GHashTable *hash = g_hash_table_new (g_str_hash, g_str_equal); + for (list = new_dsn_list; list; list = list->next) { + GdaDsnInfo *ninfo, *oinfo; + ninfo = (GdaDsnInfo *) list->data; + oinfo = gda_config_get_dsn_info (ninfo->name); + if (!oinfo) { + /* add ninfo */ + priv->dsn_list = g_slist_insert_sorted (priv->dsn_list, ninfo, + (GCompareFunc) data_source_info_compare); + if (priv->emit_signals) + g_signal_emit (unique_instance, gda_config_signals[DSN_ADDED], 0, ninfo); + g_hash_table_insert (hash, ninfo->name, (gpointer) 0x1); + } + else { + /* signal changed if updated */ + if (str_equal (oinfo->provider, ninfo->provider) && + str_equal (oinfo->description, ninfo->description) && + str_equal (oinfo->cnc_string, ninfo->cnc_string) && +#if !defined (HAVE_GNOME_KEYRING) && !defined (HAVE_LIBSECRET) + str_equal (oinfo->auth_string, ninfo->auth_string) && +#endif + (oinfo->is_system == ninfo->is_system)) { + /* no change for this DSN */ + gda_dsn_info_free (ninfo); + } + else { + GdaDsnInfo tmp; + tmp = *oinfo; + *oinfo = *ninfo; + *ninfo = tmp; + if (priv->emit_signals) + g_signal_emit (unique_instance, gda_config_signals[DSN_CHANGED], 0, oinfo); + gda_dsn_info_free (ninfo); + } + g_hash_table_insert (hash, oinfo->name, (gpointer) 0x1); + } + } + g_slist_free (new_dsn_list); + + /* remove old DSN */ + for (list = priv->dsn_list; list; ) { + GdaDsnInfo *info; + info = (GdaDsnInfo *) list->data; + list = list->next; + if (g_hash_table_lookup (hash, info->name)) + continue; + + if (priv->emit_signals) + g_signal_emit (unique_instance, gda_config_signals[DSN_TO_BE_REMOVED], 0, info); + priv->dsn_list = g_slist_remove (priv->dsn_list, info); + if (priv->emit_signals) + g_signal_emit (unique_instance, gda_config_signals[DSN_REMOVED], 0, info); + gda_dsn_info_free (info); + } + g_hash_table_destroy (hash); + + GDA_CONFIG_UNLOCK (); +} + +/* + * File monitoring actions + */ +#ifdef HAVE_GIO + +static void +conf_file_changed (G_GNUC_UNUSED GFileMonitor *mon, G_GNUC_UNUSED GFile *file, + G_GNUC_UNUSED GFile *other_file, GFileMonitorEvent event_type, + G_GNUC_UNUSED gpointer data) +{ + if (event_type != G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT) + return; + reload_dsn_configuration (); +} + +static void +lock_notify_changes (void) +{ + if (user_notify_changes != 0) + g_signal_handler_block (mon_conf_user, user_notify_changes); + if (global_notify_changes != 0) + g_signal_handler_block (mon_conf_global, global_notify_changes); +} + +static void +unlock_notify_changes (void) +{ + if (user_notify_changes != 0) + g_signal_handler_unblock (mon_conf_user, user_notify_changes); + if (global_notify_changes != 0) + g_signal_handler_unblock (mon_conf_global, global_notify_changes); +} + +#endif diff --git a/.flatpak-builder/cache/objects/32/80741d2707ff6522d40cd24943850b56182071c368802e5d3ac9be591ba898.file b/.flatpak-builder/cache/objects/32/80741d2707ff6522d40cd24943850b56182071c368802e5d3ac9be591ba898.file new file mode 100644 index 0000000..7f396a0 Binary files /dev/null and b/.flatpak-builder/cache/objects/32/80741d2707ff6522d40cd24943850b56182071c368802e5d3ac9be591ba898.file differ diff --git a/.flatpak-builder/cache/objects/33/4c36de78c88ef42cc60ecdc73abd6af9aab75abd18fd9e2f3882884929067d.dirtree b/.flatpak-builder/cache/objects/33/4c36de78c88ef42cc60ecdc73abd6af9aab75abd18fd9e2f3882884929067d.dirtree new file mode 100644 index 0000000..94abde9 Binary files /dev/null and b/.flatpak-builder/cache/objects/33/4c36de78c88ef42cc60ecdc73abd6af9aab75abd18fd9e2f3882884929067d.dirtree differ diff --git a/.flatpak-builder/cache/objects/33/6edcfe43bae4fb93c7d1f9df4d39ccabb700072ce99042642d7a16d861c08d.file b/.flatpak-builder/cache/objects/33/6edcfe43bae4fb93c7d1f9df4d39ccabb700072ce99042642d7a16d861c08d.file new file mode 100644 index 0000000..f5ba04d --- /dev/null +++ b/.flatpak-builder/cache/objects/33/6edcfe43bae4fb93c7d1f9df4d39ccabb700072ce99042642d7a16d861c08d.file @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2008 - 2011 Vivien Malerba + * Copyright (C) 2009 Murray Cumming + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef _GDA_STATEMENT_STRUCT_UPDATE_H_ +#define _GDA_STATEMENT_STRUCT_UPDATE_H_ + +#include +#include +#include +#include +#include + +G_BEGIN_DECLS + +/* + * Structure definition + */ +/** + * GdaSqlStatementUpdate: + * @any: + * @on_conflict: + * @table: + * @fields_list: + * @expr_list: + * @cond: + */ +struct _GdaSqlStatementUpdate { + GdaSqlAnyPart any; + gchar *on_conflict; /* conflict resolution clause */ + GdaSqlTable *table; + GSList *fields_list; /* list of GdaSqlField pointers */ + GSList *expr_list; /* list of GdaSqlExpr pointers */ + GdaSqlExpr *cond; + + /*< private >*/ + /* Padding for future expansion */ + gpointer _gda_reserved1; + gpointer _gda_reserved2; +}; + +/* + * Common operations + */ +GdaSqlStatementContentsInfo *_gda_sql_statement_update_get_infos (void); + +/* + * Functions used by the parser + */ +void gda_sql_statement_update_take_table_name (GdaSqlStatement *stmt, GValue *value); +void gda_sql_statement_update_take_on_conflict (GdaSqlStatement *stmt, GValue *value); +void gda_sql_statement_update_take_condition (GdaSqlStatement *stmt, GdaSqlExpr *cond); +void gda_sql_statement_update_take_set_value (GdaSqlStatement *stmt, GValue *fname, GdaSqlExpr *expr); + +G_END_DECLS + +#endif diff --git a/.flatpak-builder/cache/objects/33/d76ca239bba7aac9d043efbac581dc39df775d24171a97436347ec0589dd90.dirtree b/.flatpak-builder/cache/objects/33/d76ca239bba7aac9d043efbac581dc39df775d24171a97436347ec0589dd90.dirtree new file mode 100644 index 0000000..3e2446d Binary files /dev/null and b/.flatpak-builder/cache/objects/33/d76ca239bba7aac9d043efbac581dc39df775d24171a97436347ec0589dd90.dirtree differ diff --git a/.flatpak-builder/cache/objects/34/65061cb139f74cfaec6ff7a85597f8197ab9f7a54f75e39d16cfced027cf40.file b/.flatpak-builder/cache/objects/34/65061cb139f74cfaec6ff7a85597f8197ab9f7a54f75e39d16cfced027cf40.file new file mode 100644 index 0000000..f3545ad --- /dev/null +++ b/.flatpak-builder/cache/objects/34/65061cb139f74cfaec6ff7a85597f8197ab9f7a54f75e39d16cfced027cf40.file @@ -0,0 +1,161 @@ +/* + * Copyright (C) 2007 - 2015 Vivien Malerba + * Copyright (C) 2008 Murray Cumming + * Copyright (C) 2010 David King + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include +#include +#include "gda-virtual-connection.h" +#include +#include +#include +#include + +static void gda_virtual_connection_dispose (GObject *object); + +typedef struct { + gpointer v_provider_data; + GDestroyNotify v_provider_data_destroy_func; +} GdaVirtualConnectionPrivate; + +G_DEFINE_TYPE_WITH_PRIVATE (GdaVirtualConnection, gda_virtual_connection, GDA_TYPE_CONNECTION) + +/* + * GdaVirtualConnection class implementation + */ +static void +conn_closed_cb (GdaVirtualConnection *vcnc) +{ + GdaVirtualConnectionPrivate *priv = gda_virtual_connection_get_instance_private (vcnc); + if (priv->v_provider_data) { + if (priv->v_provider_data_destroy_func) + priv->v_provider_data_destroy_func (priv->v_provider_data); + else + g_warning ("Provider did not clean its connection data"); + priv->v_provider_data = NULL; + } +} + +static void +gda_virtual_connection_class_init (GdaVirtualConnectionClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + /* virtual methods */ + object_class->dispose = gda_virtual_connection_dispose; + GDA_CONNECTION_CLASS (klass)->closed = (void (*) (GdaConnection*)) conn_closed_cb; +} + +static void +gda_virtual_connection_init (GdaVirtualConnection *vcnc) +{ + GdaVirtualConnectionPrivate *priv = gda_virtual_connection_get_instance_private (vcnc); + priv->v_provider_data = NULL; + priv->v_provider_data_destroy_func = NULL; +} + +static void +gda_virtual_connection_dispose (GObject *object) +{ + GdaVirtualConnection *vcnc = (GdaVirtualConnection *) object; + + g_return_if_fail (GDA_IS_VIRTUAL_CONNECTION (vcnc)); + GdaVirtualConnectionPrivate *priv = gda_virtual_connection_get_instance_private (vcnc); + + if (priv->v_provider_data) { + if (priv->v_provider_data_destroy_func) + priv->v_provider_data_destroy_func (priv->v_provider_data); + else + g_warning (_("Provider did not clean its connection data")); + priv->v_provider_data = NULL; + priv->v_provider_data_destroy_func = NULL; + } + + /* chain to parent class */ + G_OBJECT_CLASS (gda_virtual_connection_parent_class)->finalize (object); +} + +/** + * gda_virtual_connection_open + * @virtual_provider: a #GdaVirtualProvider object + * @options: some options + * @error: a place to store errors, or %NULL + * + * Creates and opens a new virtual connection using the @virtual_provider provider. The returned value + * is a new #GdaVirtualConnection which needs to be used to actually add some contents to the virtual connection. + * + * Returns: a new #GdaConnection object, or %NULL if an error occurred + */ +GdaConnection * +gda_virtual_connection_open (GdaVirtualProvider *virtual_provider, GdaConnectionOptions options, GError **error) +{ + g_return_val_if_fail (GDA_IS_VIRTUAL_PROVIDER (virtual_provider), NULL); + + GdaConnection *cnc = NULL; + cnc = _gda_server_provider_create_connection (GDA_SERVER_PROVIDER (virtual_provider), NULL, NULL, + NULL, options); + if (!GDA_IS_CONNECTION (cnc)) { + g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_PROVIDER_ERROR, + _("Internal error: virtual provider does not implement the create_operation() virtual method")); + return NULL; + } + + if (!gda_connection_open (cnc, error)) { + g_object_unref (cnc); + cnc = NULL; + } + return cnc; +} + +/** + * gda_virtual_connection_internal_set_provider_data + * @vcnc: a #GdaConnection object + * @data: an opaque structure, known only to the provider for which @vcnc is opened + * @destroy_func: function to call when the connection closes and @data needs to be destroyed + * + * Note: calling this function more than once will not make it call @destroy_func on any previously + * set opaque @data, you'll have to do it yourself. + */ +void +gda_virtual_connection_internal_set_provider_data (GdaVirtualConnection *vcnc, gpointer data, GDestroyNotify destroy_func) +{ + g_return_if_fail (GDA_IS_VIRTUAL_CONNECTION (vcnc)); + GdaVirtualConnectionPrivate *priv = gda_virtual_connection_get_instance_private (vcnc); + priv->v_provider_data = data; + priv->v_provider_data_destroy_func = destroy_func; +} + +/** + * gda_virtual_connection_internal_get_provider_data + * @vcnc: a #GdaConnection object + * + * Get the opaque pointer previously set using gda_virtual_connection_internal_set_provider_data(). + * If it's not set, then add a connection event and returns %NULL + * + * Returns: the pointer to the opaque structure set using gda_virtual_connection_internal_set_provider_data() + */ +gpointer +gda_virtual_connection_internal_get_provider_data (GdaVirtualConnection *vcnc) +{ + g_return_val_if_fail (GDA_IS_VIRTUAL_CONNECTION (vcnc), NULL); + GdaVirtualConnectionPrivate *priv = gda_virtual_connection_get_instance_private (vcnc); + if (! priv->v_provider_data) + gda_connection_add_event_string (GDA_CONNECTION (vcnc), _("Internal error: invalid provider handle")); + return priv->v_provider_data; +} diff --git a/.flatpak-builder/cache/objects/34/915d0b4a1024c29c86f38a0763f30ed3d2a387fa82e26c7e37e51b0e9828a9.dirtree b/.flatpak-builder/cache/objects/34/915d0b4a1024c29c86f38a0763f30ed3d2a387fa82e26c7e37e51b0e9828a9.dirtree new file mode 100644 index 0000000..89fc870 Binary files /dev/null and b/.flatpak-builder/cache/objects/34/915d0b4a1024c29c86f38a0763f30ed3d2a387fa82e26c7e37e51b0e9828a9.dirtree differ diff --git a/.flatpak-builder/cache/objects/34/ec52f49d52a566358178d3900381b92d690652fd14ccc17badf181d6faba8a.file b/.flatpak-builder/cache/objects/34/ec52f49d52a566358178d3900381b92d690652fd14ccc17badf181d6faba8a.file new file mode 100644 index 0000000..762d689 --- /dev/null +++ b/.flatpak-builder/cache/objects/34/ec52f49d52a566358178d3900381b92d690652fd14ccc17badf181d6faba8a.file @@ -0,0 +1,187 @@ +/* + * Copyright (C) 2008 - 2013 Vivien Malerba + * Copyright (C) 2010 David King + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include +#include "gda-sqlite-pstmt.h" +#include "gda-sqlite.h" +#include + +static void _gda_sqlite_pstmt_dispose (GObject *object); + +typedef struct { + GWeakRef provider; + sqlite3_stmt *sqlite_stmt; + gboolean stmt_used; /* TRUE if a recorset already uses this prepared statement, + * necessary because only one recordset can use sqlite_stmt at a time */ + GHashTable *rowid_hash; + gint nb_rowid_columns; +} GdaSqlitePStmtPrivate; + +G_DEFINE_TYPE_WITH_PRIVATE (GdaSqlitePStmt, _gda_sqlite_pstmt, GDA_TYPE_PSTMT) + +static void +_gda_sqlite_pstmt_class_init (GdaSqlitePStmtClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + /* virtual functions */ + object_class->finalize = _gda_sqlite_pstmt_dispose; +} + +static void +_gda_sqlite_pstmt_init (GdaSqlitePStmt *pstmt) +{ + GdaSqlitePStmtPrivate *priv = _gda_sqlite_pstmt_get_instance_private (pstmt); + priv->sqlite_stmt = NULL; + priv->stmt_used = FALSE; + priv->rowid_hash = NULL; + priv->nb_rowid_columns = 0; + g_weak_ref_init (&priv->provider, NULL); +} + +static void +_gda_sqlite_pstmt_dispose (GObject *object) +{ + GdaSqlitePStmt *pstmt = (GdaSqlitePStmt *) object; + GdaSqlitePStmtPrivate *priv = _gda_sqlite_pstmt_get_instance_private (pstmt); + + g_return_if_fail (GDA_IS_PSTMT (pstmt)); + + /* free memory */ + if (priv->sqlite_stmt != NULL) { + GdaSqliteProvider *prov = g_weak_ref_get (&priv->provider); + if (prov != NULL) { + SQLITE3_CALL (prov, sqlite3_finalize) (priv->sqlite_stmt); + g_object_unref (prov); + } + priv->sqlite_stmt = NULL; + } + + if (priv->rowid_hash != NULL) { + g_hash_table_destroy (priv->rowid_hash); + priv->rowid_hash = NULL; + } + g_weak_ref_clear (&priv->provider); + + /* chain to parent class */ + G_OBJECT_CLASS (_gda_sqlite_pstmt_parent_class)->finalize (object); +} + +GdaSqlitePStmt * +_gda_sqlite_pstmt_new (GdaSqliteProvider *provider, sqlite3_stmt *sqlite_stmt) +{ + GdaSqlitePStmt *pstmt; + + pstmt = (GdaSqlitePStmt*) g_object_new (GDA_TYPE_SQLITE_PSTMT, NULL); + + GdaSqlitePStmtPrivate *priv = _gda_sqlite_pstmt_get_instance_private (pstmt); + + priv->sqlite_stmt = sqlite_stmt; + g_weak_ref_set (&priv->provider, provider); + return pstmt; +} + +/** + * Returns: (transfer full): current #GdaSqliteProvider + */ +GdaSqliteProvider* +_gda_sqlite_pstmt_get_provider (GdaSqlitePStmt *pstmt) +{ + g_return_val_if_fail (pstmt != NULL, NULL); + g_return_val_if_fail (GDA_IS_SQLITE_PSTMT (pstmt), NULL); + GdaSqlitePStmtPrivate *priv = _gda_sqlite_pstmt_get_instance_private (pstmt); + + return g_weak_ref_get (&priv->provider); +} +sqlite3_stmt* +_gda_sqlite_pstmt_get_stmt (GdaSqlitePStmt *pstmt) +{ + g_return_val_if_fail (pstmt != NULL, NULL); + g_return_val_if_fail (GDA_IS_SQLITE_PSTMT (pstmt), NULL); + GdaSqlitePStmtPrivate *priv = _gda_sqlite_pstmt_get_instance_private (pstmt); + + return priv->sqlite_stmt; +} +gboolean +_gda_sqlite_pstmt_get_is_used (GdaSqlitePStmt *pstmt) +{ + g_return_val_if_fail (pstmt != NULL, FALSE); + g_return_val_if_fail (GDA_IS_SQLITE_PSTMT (pstmt), FALSE); + GdaSqlitePStmtPrivate *priv = _gda_sqlite_pstmt_get_instance_private (pstmt); + + return priv->stmt_used; +} +void +_gda_sqlite_pstmt_set_is_used (GdaSqlitePStmt *pstmt, + gboolean used) +{ + g_return_if_fail (pstmt != NULL); + g_return_if_fail (GDA_IS_SQLITE_PSTMT (pstmt)); + GdaSqlitePStmtPrivate *priv = _gda_sqlite_pstmt_get_instance_private (pstmt); + priv->stmt_used = used; +} + +GHashTable* +_gda_sqlite_pstmt_get_rowid_hash (GdaSqlitePStmt *pstmt) +{ + g_return_val_if_fail (pstmt != NULL, NULL); + g_return_val_if_fail (GDA_IS_SQLITE_PSTMT (pstmt), NULL); + GdaSqlitePStmtPrivate *priv = _gda_sqlite_pstmt_get_instance_private (pstmt); + + return priv->rowid_hash; +} +void +_gda_sqlite_pstmt_set_rowid_hash (GdaSqlitePStmt *pstmt, + GHashTable *hash) +{ + g_return_if_fail (pstmt != NULL); + g_return_if_fail (GDA_IS_SQLITE_PSTMT (pstmt)); + GdaSqlitePStmtPrivate *priv = _gda_sqlite_pstmt_get_instance_private (pstmt); + + if (priv->rowid_hash != NULL) { + g_hash_table_unref (priv->rowid_hash); + priv->rowid_hash = NULL; + } + if (hash != NULL) { + priv->rowid_hash = g_hash_table_ref (hash); + } else { + priv->rowid_hash = NULL; + } +} +gint +_gda_sqlite_pstmt_get_nb_rowid_columns (GdaSqlitePStmt *pstmt) +{ + g_return_val_if_fail (pstmt != NULL, -1); + g_return_val_if_fail (GDA_IS_SQLITE_PSTMT (pstmt), -1); + GdaSqlitePStmtPrivate *priv = _gda_sqlite_pstmt_get_instance_private (pstmt); + + return priv->nb_rowid_columns; +} +void +_gda_sqlite_pstmt_set_nb_rowid_columns (GdaSqlitePStmt *pstmt, + gint nb) +{ + g_return_if_fail (pstmt != NULL); + g_return_if_fail (GDA_IS_SQLITE_PSTMT (pstmt)); + GdaSqlitePStmtPrivate *priv = _gda_sqlite_pstmt_get_instance_private (pstmt); + + priv->nb_rowid_columns = nb; +} + diff --git a/.flatpak-builder/cache/objects/35/1dff2c990372ea1d9234b1a9ea4499dfdec0c75785ad203e7328c6d053bc25.dirtree b/.flatpak-builder/cache/objects/35/1dff2c990372ea1d9234b1a9ea4499dfdec0c75785ad203e7328c6d053bc25.dirtree new file mode 100644 index 0000000..c2fefe4 Binary files /dev/null and b/.flatpak-builder/cache/objects/35/1dff2c990372ea1d9234b1a9ea4499dfdec0c75785ad203e7328c6d053bc25.dirtree differ diff --git a/.flatpak-builder/cache/objects/35/4fc52168746e8c3d0a6e370b21d0c2b775a043caa10deadddafd8ad8ba5d84.file b/.flatpak-builder/cache/objects/35/4fc52168746e8c3d0a6e370b21d0c2b775a043caa10deadddafd8ad8ba5d84.file new file mode 100644 index 0000000..370c747 --- /dev/null +++ b/.flatpak-builder/cache/objects/35/4fc52168746e8c3d0a6e370b21d0c2b775a043caa10deadddafd8ad8ba5d84.file @@ -0,0 +1,73 @@ +/* + * BinReloc - a library for creating relocatable executables + * Written by: Hongli Lai + * http://autopackage.org/ + * + * This source code is public domain. You can relicense this code + * under whatever license you want. + * + * See http://autopackage.org/docs/binreloc/ for + * more information and how to use this. + */ + +/* + * To avoid name clashes with other libraries which might also use BinReloc, all the API + * has been prefixed with _gda + */ + +#ifndef __BINRELOC_H__ +#define __BINRELOC_H__ + +#include + +G_BEGIN_DECLS + + +/** These error codes can be returned by br_init(), br_init_lib(), gbr_init() or gbr_init_lib(). */ +typedef enum { + /** Cannot allocate memory. */ + _GDA_GBR_INIT_ERROR_NOMEM, + /** Unable to open /proc/self/maps; see errno for details. */ + _GDA_GBR_INIT_ERROR_OPEN_MAPS, + /** Unable to read from /proc/self/maps; see errno for details. */ + _GDA_GBR_INIT_ERROR_READ_MAPS, + /** The file format of /proc/self/maps is invalid; kernel bug? */ + _GDA_GBR_INIT_ERROR_INVALID_MAPS, + /** BinReloc is disabled (the ENABLE_BINRELOC macro is not defined). */ + _GDA_GBR_INIT_ERROR_DISABLED +} GbrInitError; + + +#ifndef BINRELOC_RUNNING_DOXYGEN +/* Mangle symbol names to avoid symbol collisions with other ELF objects. */ + #define _gda_gbr_find_exe fnYM49765777344607__gda_gbr_find_exe + #define _gda_gbr_find_exe_dir fnYM49765777344607__gda_gbr_find_exe_dir + #define _gda_gbr_find_prefix fnYM49765777344607__gda_gbr_find_prefix + #define _gda_gbr_find_bin_dir fnYM49765777344607__gda_gbr_find_bin_dir + #define _gda_gbr_find_sbin_dir fnYM49765777344607__gda_gbr_find_sbin_dir + #define _gda_gbr_find_data_dir fnYM49765777344607__gda_gbr_find_data_dir + #define _gda_gbr_find_locale_dir fnYM49765777344607__gda_gbr_find_locale_dir + #define _gda_gbr_find_lib_dir fnYM49765777344607__gda_gbr_find_lib_dir + #define _gda_gbr_find_libexec_dir fnYM49765777344607__gda_gbr_find_libexec_dir + #define _gda_gbr_find_etc_dir fnYM49765777344607__gda_gbr_find_etc_dir + + +#endif +gboolean _gda_gbr_init (GError **error); +gboolean _gda_gbr_init_lib (GError **error); + +gchar *_gda_gbr_find_exe (const gchar *default_exe); +gchar *_gda_gbr_find_exe_dir (const gchar *default_dir); +gchar *_gda_gbr_find_prefix (const gchar *default_prefix); +gchar *_gda_gbr_find_bin_dir (const gchar *default_bin_dir); +gchar *_gda_gbr_find_sbin_dir (const gchar *default_sbin_dir); +gchar *_gda_gbr_find_data_dir (const gchar *default_data_dir); +gchar *_gda_gbr_find_locale_dir (const gchar *default_locale_dir); +gchar *_gda_gbr_find_lib_dir (const gchar *default_lib_dir); +gchar *_gda_gbr_find_libexec_dir (const gchar *default_libexec_dir); +gchar *_gda_gbr_find_etc_dir (const gchar *default_etc_dir); + + +G_END_DECLS + +#endif /* __BINRELOC_H__ */ diff --git a/.flatpak-builder/cache/objects/35/bd0504af5dec71f6973269db36339616491745095f16824fea0424394be1fa.file b/.flatpak-builder/cache/objects/35/bd0504af5dec71f6973269db36339616491745095f16824fea0424394be1fa.file new file mode 100644 index 0000000..5ba4325 --- /dev/null +++ b/.flatpak-builder/cache/objects/35/bd0504af5dec71f6973269db36339616491745095f16824fea0424394be1fa.file @@ -0,0 +1,80 @@ +# gtk_size_group.py +# +# Copyright 2021 James Westman +# +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation; either version 3 of the +# License, or (at your option) any later version. +# +# This file is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program. If not, see . +# +# SPDX-License-Identifier: LGPL-3.0-or-later + + +from .gobject_object import ObjectContent, validate_parent_type +from .common import * +from .contexts import ScopeCtx + + +class Widget(AstNode): + grammar = UseIdent("name") + + @property + def name(self) -> str: + return self.tokens["name"] + + @validate("name") + def obj_widget(self): + object = self.context[ScopeCtx].objects.get(self.tokens["name"]) + type = self.root.gir.get_type("Widget", "Gtk") + if object is None: + raise CompileError( + f"Could not find object with ID {self.tokens['name']}", + did_you_mean=( + self.tokens["name"], + self.context[ScopeCtx].objects.keys(), + ), + ) + elif object.gir_class and not object.gir_class.assignable_to(type): + raise CompileError( + f"Cannot assign {object.gir_class.full_name} to {type.full_name}" + ) + + @validate("name") + def unique_in_parent(self): + self.validate_unique_in_parent( + f"Object '{self.name}' is listed twice", lambda x: x.name == self.name + ) + + +class ExtSizeGroupWidgets(AstNode): + grammar = [ + Keyword("widgets"), + "[", + Delimited(Widget, ","), + "]", + ] + + @validate("widgets") + def container_is_size_group(self): + validate_parent_type(self, "Gtk", "SizeGroup", "size group properties") + + @validate("widgets") + def unique_in_parent(self): + self.validate_unique_in_parent("Duplicate widgets block") + + +@completer( + applies_in=[ObjectContent], + applies_in_subclass=("Gtk", "SizeGroup"), + matches=new_statement_patterns, +) +def size_group_completer(ast_node, match_variables): + yield Completion("widgets", CompletionItemKind.Snippet, snippet="widgets [$0]") diff --git a/.flatpak-builder/cache/objects/35/d649cd4dcbb9516cb9a6101aa6bf55b0cf195a35b3cc770066d2a0ddba4d26.file b/.flatpak-builder/cache/objects/35/d649cd4dcbb9516cb9a6101aa6bf55b0cf195a35b3cc770066d2a0ddba4d26.file new file mode 100755 index 0000000..5ef08c3 --- /dev/null +++ b/.flatpak-builder/cache/objects/35/d649cd4dcbb9516cb9a6101aa6bf55b0cf195a35b3cc770066d2a0ddba4d26.file @@ -0,0 +1,1108 @@ +#!/usr/bin/perl -w +# -*- Mode: perl; indent-tabs-mode: nil; c-basic-offset: 4 -*- + +# +# The Intltool Message Extractor +# +# Copyright (C) 2000-2001, 2003 Free Software Foundation. +# +# Intltool is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of the +# License, or (at your option) any later version. +# +# Intltool is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. +# +# Authors: Kenneth Christiansen +# Darin Adler +# + +## Release information +my $PROGRAM = "intltool-extract"; +my $PACKAGE = "intltool"; +my $VERSION = "0.51.0"; + +## Loaded modules +use strict; +use File::Basename; +use Getopt::Long; + +## Scalars used by the option stuff +my $TYPE_ARG = "0"; +my $LOCAL_ARG = "0"; +my $HELP_ARG = "0"; +my $VERSION_ARG = "0"; +my $UPDATE_ARG = "0"; +my $QUIET_ARG = "0"; +my $SRCDIR_ARG = "."; +my $NOMSGCTXT_ARG = "0"; + +my $FILE; +my $OUTFILE; + +my $gettext_type = ""; +my $input; +my %messages = (); +my @messages_sorted = (); +my %loc = (); +my %count = (); +my %comments = (); +my $strcount = 0; + +my $XMLCOMMENT = ""; + +## Use this instead of \w for XML files to handle more possible characters. +my $w = "[-A-Za-z0-9._:]"; + +## Always print first +$| = 1; + +## Handle options +GetOptions ( + "type=s" => \$TYPE_ARG, + "local|l" => \$LOCAL_ARG, + "help|h" => \$HELP_ARG, + "version|v" => \$VERSION_ARG, + "update" => \$UPDATE_ARG, + "quiet|q" => \$QUIET_ARG, + "srcdir=s" => \$SRCDIR_ARG, + "nomsgctxt" => \$NOMSGCTXT_ARG, + ) or &error; + +&split_on_argument; + + +## Check for options. +## This section will check for the different options. + +sub split_on_argument { + + if ($VERSION_ARG) { + &version; + + } elsif ($HELP_ARG) { + &help; + + } elsif ($LOCAL_ARG) { + &place_local; + &extract; + + } elsif ($UPDATE_ARG) { + &place_normal; + &extract; + + } elsif (@ARGV > 0) { + &place_normal; + &message; + &extract; + + } else { + &help; + + } +} + +sub place_normal { + $FILE = $ARGV[0]; + $OUTFILE = "$FILE.h"; + + my $dirname = dirname ($OUTFILE); + if (! -d "$dirname" && $dirname ne "") { + system ("mkdir -p $dirname"); + } +} + +sub place_local { + $FILE = $ARGV[0]; + $OUTFILE = fileparse($FILE, ()); + if (!-e "tmp/") { + system("mkdir tmp/"); + } + $OUTFILE = "./tmp/$OUTFILE.h" +} + +sub determine_type { + if ($TYPE_ARG =~ /^gettext\/(.*)/) { + $gettext_type=$1 + } +} + +## Sub for printing release information +sub version{ + print <<_EOF_; +${PROGRAM} (${PACKAGE}) $VERSION +Copyright (C) 2000, 2003 Free Software Foundation, Inc. +Written by Kenneth Christiansen, 2000. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +_EOF_ + exit; +} + +## Sub for printing usage information +sub help { + print <<_EOF_; +Usage: ${PROGRAM} [OPTION]... [FILENAME] +Generates a header file from an XML source file. + +It grabs all strings between <_translatable_node> and its end tag in +XML files. Read manpage (man ${PROGRAM}) for more info. + + --type=TYPE Specify the file type of FILENAME. Currently supports: + "gettext/glade", "gettext/ini", "gettext/keys" + "gettext/rfc822deb", "gettext/schemas", + "gettext/gsettings", "gettext/xml", "gettext/quoted", + "gettext/quotedxml", "gettext/tlk", "gettext/qtdesigner" + -l, --local Writes output into current working directory + (conflicts with --update) + --update Writes output into the same directory the source file + reside (conflicts with --local) + --srcdir Root of the source tree + -v, --version Output version information and exit + -h, --help Display this help and exit + -q, --quiet Quiet mode + +Report bugs to http://bugs.launchpad.net/intltool +_EOF_ + exit; +} + +## Sub for printing error messages +sub error{ + print STDERR "Try `${PROGRAM} --help' for more information.\n"; + exit; +} + +sub message { + print "Generating C format header file for translation.\n" unless $QUIET_ARG; +} + +sub extract { + &determine_type; + + &convert; + + open OUT, ">$OUTFILE"; + binmode (OUT) if $^O eq 'MSWin32'; + &msg_write; + close OUT; + + print "Wrote $OUTFILE\n" unless $QUIET_ARG; +} + +sub convert { + + ## Reading the file + { + local (*IN); + local $/; #slurp mode + open (IN, "<$SRCDIR_ARG/$FILE") || die "can't open $SRCDIR_ARG/$FILE: $!"; + binmode (IN); + $input = ; + close IN; + } + + &type_ini if $gettext_type eq "ini"; + &type_keys if $gettext_type eq "keys"; + &type_xml if $gettext_type eq "xml"; + &type_glade if $gettext_type eq "glade"; + &type_gsettings if $gettext_type eq "gsettings"; + &type_schemas if $gettext_type eq "schemas"; + &type_rfc822deb if $gettext_type eq "rfc822deb"; + &type_quoted if $gettext_type eq "quoted"; + &type_quotedxml if $gettext_type eq "quotedxml"; + &type_tlk if $gettext_type eq "tlk"; + &type_qtdesigner if $gettext_type eq "qtdesigner"; +} + +sub entity_decode_minimal +{ + local ($_) = @_; + + s/'/'/g; # ' + s/"/"/g; # " + s/&/&/g; + + return $_; +} + +sub entity_decode +{ + local ($_) = @_; + + s/'/'/g; # ' + s/"/"/g; # " + s/<//g; + s/&/&/g; + + return $_; +} + +sub escape_char +{ + return '\"' if $_ eq '"'; + return '\n' if $_ eq "\n"; + return '\\\\' if $_ eq '\\'; + + return $_; +} + +sub escape +{ + my ($string) = @_; + return join "", map &escape_char, split //, $string; +} + +sub add_message +{ + my ($string) = @_; + push @messages_sorted, $string if !defined $messages{$string}; + $messages{$string} = []; +} + +sub type_ini { + ### For generic translatable desktop files ### + while ($input =~ /^(#(.+)\n)?^_[A-Za-z0-9\-]+\s*=\s*(.*)$/mg) { + if (defined($2)) { + $comments{$3} = $2; + } + add_message($3); + } +} + +sub type_keys { + ### For generic translatable mime/keys files ### + while ($input =~ /^\s*_\w+=(.*)$/mg) { + add_message($1); + } +} + +sub type_xml { + ### For generic translatable XML files ### + my $tree = readXml($input); + parseTree(0, $tree); +} + +sub print_var { + my $var = shift; + my $vartype = ref $var; + + if ($vartype =~ /ARRAY/) { + my @arr = @{$var}; + print "[ "; + foreach my $el (@arr) { + print_var($el); + print ", "; + } + print "] "; + } elsif ($vartype =~ /HASH/) { + my %hash = %{$var}; + print "{ "; + foreach my $key (keys %hash) { + print "$key => "; + print_var($hash{$key}); + print ", "; + } + print "} "; + } else { + print $var; + } +} + +# Same syntax as getAttributeString in intltool-merge.in.in, similar logic (look for ## differences comment) +sub getAttributeString +{ + my $sub = shift; + my $do_translate = shift || 1; + my $language = shift || ""; + my $translate = shift; + my $result = ""; + foreach my $e (reverse(sort(keys %{ $sub }))) { + my $key = $e; + my $string = $sub->{$e}; + my $quote = '"'; + + $string =~ s/^[\s]+//; + $string =~ s/[\s]+$//; + + if ($string =~ /^'.*'$/) + { + $quote = "'"; + } + $string =~ s/^['"]//g; + $string =~ s/['"]$//g; + + ## differences from intltool-merge.in.in + if ($key =~ /^_/) { + $comments{entity_decode($string)} = $XMLCOMMENT if $XMLCOMMENT; + add_message(entity_decode($string)); + $$translate = 2; + } + ## differences end here from intltool-merge.in.in + $result .= " $key=$quote$string$quote"; + } + return $result; +} + +# Verbatim copy from intltool-merge.in.in +sub getXMLstring +{ + my $ref = shift; + my $spacepreserve = shift || 0; + my @list = @{ $ref }; + my $result = ""; + + my $count = scalar(@list); + my $attrs = $list[0]; + my $index = 1; + + $spacepreserve = 1 if ((exists $attrs->{"xml:space"}) && ($attrs->{"xml:space"} =~ /^["']?preserve["']?$/)); + $spacepreserve = 0 if ((exists $attrs->{"xml:space"}) && ($attrs->{"xml:space"} =~ /^["']?default["']?$/)); + + while ($index < $count) { + my $type = $list[$index]; + my $content = $list[$index+1]; + if (! $type ) { + # We've got CDATA + if ($content) { + # lets strip the whitespace here, and *ONLY* here + $content =~ s/\s+/ /gs if (!$spacepreserve); + $result .= $content; + } + } elsif ( "$type" ne "1" ) { + # We've got another element + $result .= "<$type"; + $result .= getAttributeString(@{$content}[0], 0); # no nested translatable elements + if ($content) { + my $subresult = getXMLstring($content, $spacepreserve); + if ($subresult) { + $result .= ">".$subresult . ""; + } else { + $result .= "/>"; + } + } else { + $result .= "/>"; + } + } + $index += 2; + } + return $result; +} + +# Verbatim copy from intltool-merge.in.in, except for MULTIPLE_OUTPUT handling removed +# Translate list of nodes if necessary +sub translate_subnodes +{ + my $fh = shift; + my $content = shift; + my $language = shift || ""; + my $singlelang = shift || 0; + my $spacepreserve = shift || 0; + + my @nodes = @{ $content }; + + my $count = scalar(@nodes); + my $index = 0; + while ($index < $count) { + my $type = $nodes[$index]; + my $rest = $nodes[$index+1]; + traverse($fh, $type, $rest, $language, $spacepreserve); + $index += 2; + } +} + +# Based on traverse() in intltool-merge.in.in +sub traverse +{ + my $fh = shift; # unused, to allow us to sync code between -merge and -extract + my $nodename = shift; + my $content = shift; + my $language = shift || ""; + my $spacepreserve = shift || 0; + + if ($nodename && "$nodename" eq "1") { + $XMLCOMMENT = $content; + } elsif ($nodename) { + # element + my @all = @{ $content }; + my $attrs = shift @all; + my $translate = 0; + my $outattr = getAttributeString($attrs, 1, $language, \$translate); + + if ($nodename =~ /^_/) { + $translate = 1; + $nodename =~ s/^_//; + } + my $lookup = ''; + + $spacepreserve = 0 if ((exists $attrs->{"xml:space"}) && ($attrs->{"xml:space"} =~ /^["']?default["']?$/)); + $spacepreserve = 1 if ((exists $attrs->{"xml:space"}) && ($attrs->{"xml:space"} =~ /^["']?preserve["']?$/)); + + if ($translate) { + $lookup = getXMLstring($content, $spacepreserve); + if (!$spacepreserve) { + $lookup =~ s/^\s+//s; + $lookup =~ s/\s+$//s; + } + if (exists $attrs->{"msgctxt"}) { + my $context = entity_decode ($attrs->{"msgctxt"}); + $context =~ s/^["'](.*)["']/$1/; + $lookup = "$context\004$lookup"; + } + + if ($lookup && $translate != 2) { + $comments{$lookup} = $XMLCOMMENT if $XMLCOMMENT; + add_message($lookup); + } elsif ($translate == 2) { + translate_subnodes($fh, \@all, $language, 1, $spacepreserve); + } + } else { + $XMLCOMMENT = ""; + my $count = scalar(@all); + if ($count > 0) { + my $index = 0; + while ($index < $count) { + my $type = $all[$index]; + my $rest = $all[$index+1]; + traverse($fh, $type, $rest, $language, $spacepreserve); + $index += 2; + } + } + } + $XMLCOMMENT = ""; + } +} + + +# Verbatim copy from intltool-merge.in.in, $fh for compatibility +sub parseTree +{ + my $fh = shift; + my $ref = shift; + my $language = shift || ""; + + my $name = shift @{ $ref }; + my $cont = shift @{ $ref }; + + while (!$name || "$name" eq "1") { + $name = shift @{ $ref }; + $cont = shift @{ $ref }; + } + + my $spacepreserve = 0; + my $attrs = @{$cont}[0]; + $spacepreserve = 1 if ((exists $attrs->{"xml:space"}) && ($attrs->{"xml:space"} =~ /^["']?preserve["']?$/)); + + traverse($fh, $name, $cont, $language, $spacepreserve); +} + +# Verbatim copy from intltool-merge.in.in +sub intltool_tree_comment +{ + my $expat = shift; + my $data = $expat->original_string(); + my $clist = $expat->{Curlist}; + my $pos = $#$clist; + + $data =~ s/^$//s; + push @$clist, 1 => $data; +} + +# Verbatim copy from intltool-merge.in.in +sub intltool_tree_cdatastart +{ + my $expat = shift; + my $clist = $expat->{Curlist}; + my $pos = $#$clist; + + push @$clist, 0 => $expat->original_string(); +} + +# Verbatim copy from intltool-merge.in.in +sub intltool_tree_cdataend +{ + my $expat = shift; + my $clist = $expat->{Curlist}; + my $pos = $#$clist; + + $clist->[$pos] .= $expat->original_string(); +} + +# Verbatim copy from intltool-merge.in.in +sub intltool_tree_char +{ + my $expat = shift; + my $text = shift; + my $clist = $expat->{Curlist}; + my $pos = $#$clist; + + # Use original_string so that we retain escaped entities + # in CDATA sections. + # + if ($pos > 0 and $clist->[$pos - 1] eq '0') { + $clist->[$pos] .= $expat->original_string(); + } else { + push @$clist, 0 => $expat->original_string(); + } +} + +# Verbatim copy from intltool-merge.in.in +sub intltool_tree_start +{ + my $expat = shift; + my $tag = shift; + my @origlist = (); + + # Use original_string so that we retain escaped entities + # in attribute values. We must convert the string to an + # @origlist array to conform to the structure of the Tree + # Style. + # + my @original_array = split /\x/, $expat->original_string(); + my $source = $expat->original_string(); + + # Remove leading tag. + # + $source =~ s|^\s*<\s*(\S+)||s; + + # Grab attribute key/value pairs and push onto @origlist array. + # + while ($source) + { + if ($source =~ /^\s*([\w:-]+)\s*[=]\s*["]/) + { + $source =~ s|^\s*([\w:-]+)\s*[=]\s*["]([^"]*)["]||s; + push @origlist, $1; + push @origlist, '"' . $2 . '"'; + } + elsif ($source =~ /^\s*([\w:-]+)\s*[=]\s*[']/) + { + $source =~ s|^\s*([\w:-]+)\s*[=]\s*[']([^']*)[']||s; + push @origlist, $1; + push @origlist, "'" . $2 . "'"; + } + else + { + last; + } + } + + my $ol = [ { @origlist } ]; + + push @{ $expat->{Lists} }, $expat->{Curlist}; + push @{ $expat->{Curlist} }, $tag => $ol; + $expat->{Curlist} = $ol; +} + +# Copied from intltool-merge.in.in and added comment handler. +sub readXml +{ + my $xmldoc = shift || return; + my $ret = eval 'require XML::Parser'; + if(!$ret) { + die "You must have XML::Parser installed to run $0\n\n"; + } + my $xp = new XML::Parser(Style => 'Tree'); + $xp->setHandlers(Char => \&intltool_tree_char); + $xp->setHandlers(Start => \&intltool_tree_start); + $xp->setHandlers(CdataStart => \&intltool_tree_cdatastart); + $xp->setHandlers(CdataEnd => \&intltool_tree_cdataend); + + ## differences from intltool-merge.in.in + $xp->setHandlers(Comment => \&intltool_tree_comment); + ## differences end here from intltool-merge.in.in + + my $tree = $xp->parse($xmldoc); + +# Hello thereHowdydo +# would be: +# [foo, [{}, 1, "comment", head, [{id => "a"}, 0, "Hello ", em, [{}, 0, "there"]], bar, +# [{}, 0, "Howdy", ref, [{}]], 0, "do" ] ] + + return $tree; +} + +sub type_schemas { + ### For schemas XML files ### + + # FIXME: We should handle escaped < (less than) + while ($input =~ / + \s* + (\s*(?:\s*)?(.*?)\s*<\/default>\s*)? + (\s*(?:\s*)?(.*?)\s*<\/short>\s*)? + (\s*(?:\s*)?(.*?)\s*<\/long>\s*)? + <\/locale> + /sgx) { + my @totranslate = ($3,$6,$9); + my @eachcomment = ($2,$5,$8); + foreach (@totranslate) { + my $currentcomment = shift @eachcomment; + next if !$_; + s/\s+/ /g; + add_message(entity_decode_minimal($_)); + $comments{entity_decode_minimal($_)} = $currentcomment if (defined($currentcomment)); + } + } +} + +# Parse the tree as returned by readXml() for gschema.xml files. +sub traverse_gsettings { + sub cleanup { + s/^\s+//; + s/\s+$//; + s/\s+/ /g; + return $_; + } + + my $nodename = shift; + my $content = shift; + my $comment = shift || 0; + my @list = @{ $content }; + my $attrs_ref = shift @list; + my %attrs = %{ $attrs_ref }; + if (($nodename eq 'default' and $attrs{'l10n'}) or + ($nodename eq 'summary') or ($nodename eq 'description')) { + # preserve whitespace. deal with it ourselves, below. + my $message = getXMLstring($content, 1); + + if ($nodename eq 'default') { + # for we strip leading and trailing whitespace but + # preserve (possibly quoted) whitespace within + $message =~ s/^\s+//; + $message =~ s/\s+$//; + } else { + # for and , we normalise all + # whitespace while preserving paragraph boundaries + $message = join "\n\n", map &cleanup, split/\n\s*\n+/, $message; + } + + my $context = $attrs{'context'}; + $context =~ s/^["'](.*)["']/$1/ if $context; + $message = $context . "\004" . $message if $context; + add_message($message); + $comments{$message} = $comment if $comment; + } else { + my $index = 0; + my $comment; + while (scalar(@list) > 1) { + my $type = shift @list; + my $content = shift @list; + if (!$type || "$type" eq "1") { + if ($type == 1) { + $comment = $content; + } + next; + } else { + traverse_gsettings($type, $content, $comment); + $comment = 0; + } + } + } +} + +sub type_gsettings { + my $tree = readXml($input); + my @tree_nodes = @{ $tree }; + my $node = shift @tree_nodes; + while (!$node || "$node" eq "1") { + shift @tree_nodes; + $node = shift @tree_nodes; + } + my $content = shift @tree_nodes; + traverse_gsettings($node, $content); +} + +sub type_rfc822deb { + ### For rfc822-style Debian configuration files ### + + my $lineno = 1; + my $type = ''; + while ($input =~ /\G(.*?)(^|\n)(_+)([^:]+):[ \t]*(.*?)(?=\n\S|$)/sg) + { + my ($pre, $newline, $underscore, $tag, $text) = ($1, $2, $3, $4, $5); + while ($pre =~ m/\n/g) + { + $lineno ++; + } + $lineno += length($newline); + my @str_list = rfc822deb_split(length($underscore), $text); + for my $str (@str_list) + { + $strcount++; + add_message($str); + $loc{$str} = $lineno; + $count{$str} = $strcount; + my $usercomment = ''; + while($pre =~ s/(^|\n)#([^\n]*)$//s) + { + $usercomment = "\n" . $2 . $usercomment; + } + $comments{$str} = $tag . $usercomment; + } + $lineno += ($text =~ s/\n//g); + } +} + +sub rfc822deb_split { + # Debian defines a special way to deal with rfc822-style files: + # when a value contain newlines, it consists of + # 1. a short form (first line) + # 2. a long description, all lines begin with a space, + # and paragraphs are separated by a single dot on a line + # This routine returns an array of all paragraphs, and reformat + # them. + # When first argument is 2, the string is a comma separated list of + # values. + my $type = shift; + my $text = shift; + $text =~ s/^[ \t]//mg; + return (split(/, */, $text, 0)) if $type ne 1; + return ($text) if $text !~ /\n/; + + $text =~ s/([^\n]*)\n//; + my @list = ($1); + my $str = ''; + for my $line (split (/\n/, $text)) + { + chomp $line; + if ($line =~ /^\.\s*$/) + { + # New paragraph + $str =~ s/\s*$//; + push(@list, $str); + $str = ''; + } + elsif ($line =~ /^\s/) + { + # Line which must not be reformatted + $str .= "\n" if length ($str) && $str !~ /\n$/; + $line =~ s/\s+$//; + $str .= $line."\n"; + } + else + { + # Continuation line, remove newline + $str .= " " if length ($str) && $str !~ /\n$/; + $str .= $line; + } + } + $str =~ s/\s*$//; + push(@list, $str) if length ($str); + return @list; +} + +sub type_quoted { + while ($input =~ /\"(([^\"]|\\\")*[^\\\"])\"/g) { + my $message = $1; + my $before = $`; + $message =~ s/\\\"/\"/g; + $before =~ s/[^\n]//g; + add_message($message); + $loc{$message} = length ($before) + 2; + } +} + +sub type_quotedxml { + while ($input =~ /\"(([^\"]|\\\")*[^\\\"])\"/g) { + my $message = $1; + my $before = $`; + $message =~ s/\\\"/\"/g; + $message = entity_decode($message); + $before =~ s/[^\n]//g; + add_message($message); + $loc{$message} = length ($before) + 2; + } +} + +# Parse the tree as returned by readXml() for Qt Designer .ui files. +sub traverse_qtdesigner { + my $nodename = shift; + my $content = shift; + my @list = @{ $content }; + my $attrs_ref = shift @list; + my %attrs = %{ $attrs_ref }; + if ($nodename eq 'string' and !exists $attrs{"notr"}) { + # Preserve whitespace. Deal with it ourselves, below. + my $message = getXMLstring($content, 1); + + # We strip leading and trailing whitespace but + # preserve whitespace within (e.g. newlines) + $message =~ s/^\s+//; + $message =~ s/\s+$//; + + my $context = $attrs{'comment'}; + # Remove enclosing quotes from msgctxt + $context =~ s/^["'](.*)["']/$1/ if $context; + $message = $context . "\004" . $message if $context; + add_message($message); + my $comment = $attrs{'extracomment'}; + # Remove enclosing quotes from developer comments + $comment =~ s/^["'](.*)["']/$1/ if $comment; + $comments{$message} = $comment if $comment; + } else { + my $index = 0; + while (scalar(@list) > 1) { + my $type = shift @list; + my $content = shift @list; + if (!$type || "$type" eq "1") { + next; + } else { + traverse_qtdesigner($type, $content); + } + } + } +} + +sub type_qtdesigner { + ### For translatable Qt Designer XML files ### + # + # Specs: + # + # - http://qt-project.org/doc/qt-5.0/qtlinguist/linguist-ts-file-format.html + # - http://qt-project.org/doc/qt-5.0/qtdesigner/designer-ui-file-format.html + # + # tag attributes: + # + # notr="true" means the string is not translatable + # extracomment maps to a developer comment in gettext + # comment corresponds to "disambiguation" in the Qt Linguist API, and maps + # to msgctxt in gettext + # + # Example: + # + # Ok + + my $tree = readXml($input); + my @tree_nodes = @{ $tree }; + my $node = shift @tree_nodes; + while (!$node || "$node" eq "1") { + shift @tree_nodes; + $node = shift @tree_nodes; + } + my $content = shift @tree_nodes; + traverse_qtdesigner($node, $content); + +} + +sub type_glade { + ### For translatable Glade XML files ### + + my $tags = "label|title|text|format|copyright|comments|preview_text|tooltip|message"; + + while ($input =~ /<($tags)>([^<]+)<\/($tags)>/sg) { + # Glade sometimes uses tags that normally mark translatable things for + # little bits of non-translatable content. We work around this by not + # translating strings that only includes something like label4 or window1. + add_message(entity_decode($2)) unless $2 =~ /^(window|label|dialog)[0-9]+$/; + } + + while ($input =~ /(..[^<]*)<\/items>/sg) { + for my $item (split (/\n/, $1)) { + add_message(entity_decode($item)); + } + } + + ## handle new glade files + while ($input =~ /<(\w+)\s+[^>]*translatable\s*=\s*["']yes["'](?:\s+[^>]*context\s*=\s*["']([^"']*)["'])?(?:\s+[^>]*comments\s*=\s*["']([^"']*)["'])?[^>]*>([^<]+)<\/\1>/sg) { + if (!($4 =~ /^(window|label)[0-9]+$/)) { + my $message = entity_decode($4); + if (defined($2)) { + $message = entity_decode($2) . "\004" . $message; + } + add_message($message); + if (defined($3)) { + $comments{$message} = entity_decode($3) ; + } + } + } + while ($input =~ /]*)"\s+description="([^>]+)"\/>/sg) { + add_message(entity_decode_minimal($2)); + } +} + +sub type_tlk { + my ($ftype, $fvers, $langid, $strcount, $stroff); + my $count = 0; + my $pos = 0; + my @inputa = split (//, $input, 21); + my $foo; + my $strdata; + + $ftype = substr ($input, 0, 3); + $fvers = substr ($input, 4, 7); + $langid = unpack ("L", $inputa[8] . $inputa[9] . + $inputa[10] . $inputa[11]); + $strcount = unpack ("L", $inputa[12] . $inputa[13] . + $inputa[14] . $inputa[15]); + $stroff = unpack ("L", $inputa[16] . $inputa[17] . + $inputa[18] . $inputa[19]); + + use bytes; + $strdata = bytes::substr ($input, $stroff); + + my $sinpos = 20; + + $foo = $inputa[$sinpos]; + $sinpos = 40 * 2000; + @inputa = split (//, $foo, $sinpos + 1); + + $pos = 0; + while ($count < $strcount) { + my ($flags, $soundref, $volvar, $pitch, $offset, $strsize, $sndlen) = 0; + + if ($count > 0 && $count % 2000 == 0) { + $foo = $inputa[$sinpos]; + my $numleft = ($strcount - $count); + if ($numleft > 2000) { + $sinpos = 40 * 2000; + } else { + $sinpos = 40 * $numleft; + } + @inputa = split (//, $foo, $sinpos + 1); + my $numbytes = @inputa; + $pos = 0; + } + + + $flags = unpack ("L", $inputa[$pos] . $inputa[$pos + 1] . + $inputa[$pos + 2] . $inputa[$pos + 3]); + $pos += 4; + if ($flags & 0x0002) { + $soundref = join ('', @inputa[$pos..$pos + 15]); + $soundref =~ s/\0//g; + } + $pos += 16; +# According to the Bioware Aurora Talk Table Format documentation +# the VolumeVariance and PitchVariance DWORDs are not used +# We increment the pos counter, but do not read the data, here +# $volvar = unpack ("L", $inputa[$pos] . $inputa[$pos + 1] . +# $inputa[$pos + 2] . $inputa[$pos + 3]); + $pos += 4; +# $pitch = unpack ("L", $inputa[$pos] . $inputa[$pos + 1] . +# $inputa[$pos + 2] . $inputa[$pos + 3]); + $pos += 4; + $offset = unpack ("L", $inputa[$pos] . $inputa[$pos + 1] . + $inputa[$pos + 2] . $inputa[$pos + 3]) + if ($flags & 0x0001); + $pos += 4; + $strsize = unpack ("L", $inputa[$pos] . $inputa[$pos + 1] . + $inputa[$pos + 2] . $inputa[$pos + 3]) + if ($flags & 0x0001); + $pos += 4; + $sndlen = unpack ("d", $inputa[$pos] . $inputa[$pos + 1] . + $inputa[$pos + 2] . $inputa[$pos + 3]) + if ($flags & 0x0004); + $pos += 4; + + if (defined $strsize && $strsize > 0) { + my $message = substr ($strdata, $offset, $strsize); + if (defined $message) { + use Encode; + Encode::from_to ($message, "iso-8859-1", "UTF-8"); + add_message($message); + if ($message =~ /^Bad Strref$/ ) { + $comments{$message} = "DO NOT Translate this Entry."; + $comments{$message} .= "\nTLK:position=$count"; + } else { + $comments{$message} = "TLK:position=$count"; + $comments{$message} .= "; TLK:sndresref=$soundref" + if (defined $soundref && $soundref ne ""); + $comments{$message} .= "; TLK:sndlen=$sndlen" + if (defined $sndlen && $sndlen != 0); + } + } else { + print STDERR "Missing message? ID: $count\n"; + } + } + $count++; + } +} + +sub msg_write { + my @msgids; + if (%count) + { + @msgids = sort { $count{$a} <=> $count{$b} } keys %count; + } + else + { + @msgids = @messages_sorted; + } + for my $message (@msgids) + { + my $offsetlines = 1; + my $context = undef; + $offsetlines++ if $message =~ /%/; + if (defined ($comments{$message})) + { + while ($comments{$message} =~ m/\n/g) + { + $offsetlines++; + } + } + print OUT "# ".($loc{$message} - $offsetlines). " \"$FILE\"\n" + if defined $loc{$message}; + print OUT "/* ".$comments{$message}." */\n" + if defined $comments{$message}; + print OUT "/* xgettext:no-c-format */\n" if $message =~ /%/; + + if ($message =~ /(.*)\004(.*)/s) { + $context = $1; + $message = $2; + } + my @lines = split (/\n/, $message, -1); + for (my $n = 0; $n < @lines; $n++) + { + if ($n == 0) + { + if (defined $context) + { + if ($NOMSGCTXT_ARG) + { + print OUT "char *s = N_(\"", $context, "|"; + } + else + { + print OUT "char *s = C_(\"", $context, "\", \""; + } + } + else + { + print OUT "char *s = N_(\""; + } + } + else + { + print OUT " \""; + } + + print OUT escape($lines[$n]); + + if ($n < @lines - 1) + { + print OUT "\\n\"\n"; + } + else + { + print OUT "\");\n"; + } + } + } +} + diff --git a/.flatpak-builder/cache/objects/36/2239ff322bdeebe222da8e7d23233f8c972d6c9f22ccbb3693ee25f6b2225f.dirtree b/.flatpak-builder/cache/objects/36/2239ff322bdeebe222da8e7d23233f8c972d6c9f22ccbb3693ee25f6b2225f.dirtree new file mode 100644 index 0000000..f687058 Binary files /dev/null and b/.flatpak-builder/cache/objects/36/2239ff322bdeebe222da8e7d23233f8c972d6c9f22ccbb3693ee25f6b2225f.dirtree differ diff --git a/.flatpak-builder/cache/objects/36/2fe1fb0adc76f787e858284a23507b8c47bf83844300ed14bd1403d2199185.file b/.flatpak-builder/cache/objects/36/2fe1fb0adc76f787e858284a23507b8c47bf83844300ed14bd1403d2199185.file new file mode 100644 index 0000000..6ee06a9 --- /dev/null +++ b/.flatpak-builder/cache/objects/36/2fe1fb0adc76f787e858284a23507b8c47bf83844300ed14bd1403d2199185.file @@ -0,0 +1,363 @@ +/*-*- Mode: C; c-basic-offset: 8 -*-*/ + +/*** + This file is part of libcanberra. + + Copyright 2008 Lennart Poettering + + libcanberra is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation, either version 2.1 of the + License, or (at your option) any later version. + + libcanberra is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with libcanberra. If not, see + . +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "driver.h" +#include "llist.h" +#include "malloc.h" +#include "common.h" +#include "driver-order.h" + +struct backend { + CA_LLIST_FIELDS(struct backend); + ca_context *context; +}; + +struct private { + ca_context *context; + CA_LLIST_HEAD(struct backend, backends); +}; + +#define PRIVATE(c) ((struct private *) ((c)->private)) + +static int add_backend(struct private *p, const char *name) { + struct backend *b, *last; + int ret; + + ca_assert(p); + ca_assert(name); + + if (ca_streq(name, "multi")) + return CA_ERROR_NOTAVAILABLE; + + for (b = p->backends; b; b = b->next) + if (ca_streq(b->context->driver, name)) + return CA_ERROR_NOTAVAILABLE; + + if (!(b = ca_new0(struct backend, 1))) + return CA_ERROR_OOM; + + if ((ret = ca_context_create(&b->context)) < 0) + goto fail; + + if ((ret = ca_context_change_props_full(b->context, p->context->props)) < 0) + goto fail; + + if ((ret = ca_context_set_driver(b->context, name)) < 0) + goto fail; + + if ((ret = ca_context_open(b->context)) < 0) + goto fail; + + for (last = p->backends; last; last = last->next) + if (!last->next) + break; + + CA_LLIST_INSERT_AFTER(struct backend, p->backends, last, b); + + return CA_SUCCESS; + +fail: + + if (b->context) + ca_context_destroy(b->context); + + ca_free(b); + + return ret; +} + +static int remove_backend(struct private *p, struct backend *b) { + int ret; + + ca_assert(p); + ca_assert(b); + + ret = ca_context_destroy(b->context); + CA_LLIST_REMOVE(struct backend, p->backends, b); + ca_free(b); + + return ret; +} + +int driver_open(ca_context *c) { + struct private *p; + int ret = CA_SUCCESS; + + ca_return_val_if_fail(c, CA_ERROR_INVALID); + ca_return_val_if_fail(c->driver, CA_ERROR_NODRIVER); + ca_return_val_if_fail(!strncmp(c->driver, "multi", 5), CA_ERROR_NODRIVER); + ca_return_val_if_fail(!PRIVATE(c), CA_ERROR_STATE); + + if (!(c->private = p = ca_new0(struct private, 1))) + return CA_ERROR_OOM; + + p->context = c; + + if (c->driver) { + char *e, *k; + + if (!(e = ca_strdup(c->driver))) { + driver_destroy(c); + return CA_ERROR_OOM; + } + + k = e; + for (;;) { + size_t n; + ca_bool_t last; + + n = strcspn(k, ",:"); + last = k[n] == 0; + k[n] = 0; + + if (n > 0) { + int r; + + r = add_backend(p, k); + + if (ret == CA_SUCCESS) + ret = r; + } + + if (last) + break; + + k += n+1 ; + } + + ca_free(e); + + } else { + + const char *const *e; + + for (e = ca_driver_order; *e; e++) { + int r; + + r = add_backend(p, *e); + + /* We return the error code of the first module that fails only */ + if (ret == CA_SUCCESS) + ret = r; + } + } + + if (!p->backends) { + driver_destroy(c); + return ret == CA_SUCCESS ? CA_ERROR_NODRIVER : ret; + } + + return CA_SUCCESS; +} + + +int driver_destroy(ca_context *c) { + int ret = CA_SUCCESS; + struct private *p; + + ca_return_val_if_fail(c, CA_ERROR_INVALID); + ca_return_val_if_fail(c->private, CA_ERROR_STATE); + + p = PRIVATE(c); + + while (p->backends) { + int r; + + r = remove_backend(p, p->backends); + + if (ret == CA_SUCCESS) + ret = r; + } + + ca_free(p); + + c->private = NULL; + + return ret; +} + +int driver_change_device(ca_context *c, const char *device) { + ca_return_val_if_fail(c, CA_ERROR_INVALID); + ca_return_val_if_fail(c->private, CA_ERROR_STATE); + + return CA_ERROR_NOTSUPPORTED; +} + +int driver_change_props(ca_context *c, ca_proplist *changed, ca_proplist *merged) { + int ret = CA_SUCCESS; + struct private *p; + struct backend *b; + + ca_return_val_if_fail(c, CA_ERROR_INVALID); + ca_return_val_if_fail(changed, CA_ERROR_INVALID); + ca_return_val_if_fail(merged, CA_ERROR_INVALID); + ca_return_val_if_fail(c->private, CA_ERROR_STATE); + + p = PRIVATE(c); + + for (b = p->backends; b; b = b->next) { + int r; + + r = ca_context_change_props_full(b->context, changed); + + /* We only return the first failure */ + if (ret == CA_SUCCESS) + ret = r; + } + + return ret; +} + +struct closure { + ca_context *context; + ca_finish_callback_t callback; + void *userdata; +}; + +static void call_closure(ca_context *c, uint32_t id, int error_code, void *userdata) { + struct closure *closure = userdata; + + closure->callback(closure->context, id, error_code, closure->userdata); + ca_free(closure); +} + +int driver_play(ca_context *c, uint32_t id, ca_proplist *proplist, ca_finish_callback_t cb, void *userdata) { + int ret = CA_SUCCESS; + struct private *p; + struct backend *b; + struct closure *closure; + + ca_return_val_if_fail(c, CA_ERROR_INVALID); + ca_return_val_if_fail(proplist, CA_ERROR_INVALID); + ca_return_val_if_fail(!userdata || cb, CA_ERROR_INVALID); + ca_return_val_if_fail(c->private, CA_ERROR_STATE); + + p = PRIVATE(c); + + if (cb) { + if (!(closure = ca_new(struct closure, 1))) + return CA_ERROR_OOM; + + closure->context = c; + closure->callback = cb; + closure->userdata = userdata; + } else + closure = NULL; + + /* The first backend that can play this, takes it */ + for (b = p->backends; b; b = b->next) { + int r; + + if ((r = ca_context_play_full(b->context, id, proplist, closure ? call_closure : NULL, closure)) == CA_SUCCESS) + return r; + + /* We only return the first failure */ + if (ret == CA_SUCCESS) + ret = r; + } + + ca_free(closure); + + return ret; +} + +int driver_cancel(ca_context *c, uint32_t id) { + int ret = CA_SUCCESS; + struct private *p; + struct backend *b; + + ca_return_val_if_fail(c, CA_ERROR_INVALID); + ca_return_val_if_fail(c->private, CA_ERROR_STATE); + + p = PRIVATE(c); + + for (b = p->backends; b; b = b->next) { + int r; + + r = ca_context_cancel(b->context, id); + + /* We only return the first failure */ + if (ret == CA_SUCCESS) + ret = r; + } + + return ret; +} + +int driver_cache(ca_context *c, ca_proplist *proplist) { + int ret = CA_SUCCESS; + struct private *p; + struct backend *b; + + ca_return_val_if_fail(c, CA_ERROR_INVALID); + ca_return_val_if_fail(proplist, CA_ERROR_INVALID); + ca_return_val_if_fail(c->private, CA_ERROR_STATE); + + p = PRIVATE(c); + + /* The first backend that can cache this, takes it */ + for (b = p->backends; b; b = b->next) { + int r; + + if ((r = ca_context_cache_full(b->context, proplist)) == CA_SUCCESS) + return r; + + /* We only return the first failure */ + if (ret == CA_SUCCESS) + ret = r; + } + + return ret; +} + +int driver_playing(ca_context *c, uint32_t id, int *playing) { + int ret = CA_SUCCESS; + struct private *p; + struct backend *b; + + ca_return_val_if_fail(c, CA_ERROR_INVALID); + ca_return_val_if_fail(playing, CA_ERROR_INVALID); + ca_return_val_if_fail(c->private, CA_ERROR_STATE); + + p = PRIVATE(c); + + *playing = 0; + + for (b = p->backends; b; b = b->next) { + int r, _playing = 0; + + r = ca_context_playing(b->context, id, &_playing); + + /* We only return the first failure */ + if (ret == CA_SUCCESS) + ret = r; + + if (_playing) + *playing = 1; + } + + return ret; +} diff --git a/.flatpak-builder/cache/objects/36/4305195f4ae2b1b96f411bc11aaf595b1b6255f4634085ece2c48704fb0465.file b/.flatpak-builder/cache/objects/36/4305195f4ae2b1b96f411bc11aaf595b1b6255f4634085ece2c48704fb0465.file new file mode 100644 index 0000000..e62fc5a --- /dev/null +++ b/.flatpak-builder/cache/objects/36/4305195f4ae2b1b96f411bc11aaf595b1b6255f4634085ece2c48704fb0465.file @@ -0,0 +1,172 @@ +/* + * Copyright (C) 2008 - 2010 Murray Cumming + * Copyright (C) 2008 - 2012 Vivien Malerba + * Copyright (C) 2009 Bas Driessen + * Copyright (C) 2010 David King + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include +#include +#include +#include +#include +#include +#include + +static gpointer gda_sql_statement_delete_new (void); +static void gda_sql_statement_delete_free (gpointer stmt); +static gpointer gda_sql_statement_delete_copy (gpointer src); +static gchar *gda_sql_statement_delete_serialize (gpointer stmt); +static gboolean gda_sql_statement_delete_check_structure (GdaSqlAnyPart *stmt, gpointer data, GError **error); + +GdaSqlStatementContentsInfo delete_infos = { + GDA_SQL_STATEMENT_DELETE, + "DELETE", + gda_sql_statement_delete_new, + gda_sql_statement_delete_free, + gda_sql_statement_delete_copy, + gda_sql_statement_delete_serialize, + + gda_sql_statement_delete_check_structure, + NULL, + NULL, + NULL, + NULL, + NULL +}; + +GdaSqlStatementContentsInfo * +_gda_sql_statement_delete_get_infos (void) +{ + return &delete_infos; +} + +static gpointer +gda_sql_statement_delete_new (void) +{ + GdaSqlStatementDelete *stmt; + stmt = g_new0 (GdaSqlStatementDelete, 1); + GDA_SQL_ANY_PART (stmt)->type = GDA_SQL_ANY_STMT_DELETE; + return (gpointer) stmt; +} + +static void +gda_sql_statement_delete_free (gpointer stmt) +{ + GdaSqlStatementDelete *delete = (GdaSqlStatementDelete *) stmt; + + if (delete->table) + gda_sql_table_free (delete->table); + if (delete->cond) + gda_sql_expr_free (delete->cond); + g_free (delete); +} + +static gpointer +gda_sql_statement_delete_copy (gpointer src) +{ + GdaSqlStatementDelete *dest; + GdaSqlStatementDelete *delete = (GdaSqlStatementDelete *) src; + + dest = gda_sql_statement_delete_new (); + + dest->table = gda_sql_table_copy (delete->table); + gda_sql_any_part_set_parent (dest->table, dest); + + dest->cond = gda_sql_expr_copy (delete->cond); + gda_sql_any_part_set_parent (dest->cond, dest); + + return dest; +} + +static gchar * +gda_sql_statement_delete_serialize (gpointer stmt) +{ + GString *string; + gchar *str; + GdaSqlStatementDelete *delete = (GdaSqlStatementDelete *) stmt; + + g_return_val_if_fail (stmt, NULL); + + string = g_string_new ("\"contents\":{"); + + /* table name */ + g_string_append (string, "\"table\":"); + str = gda_sql_table_serialize (delete->table); + g_string_append (string, str); + g_free (str); + + /* condition */ + if (delete->cond) { + g_string_append (string, ",\"condition\":"); + str = gda_sql_expr_serialize (delete->cond); + g_string_append (string, str); + g_free (str); + } + g_string_append_c (string, '}'); + str = string->str; + g_string_free (string, FALSE); + return str; +} + +/** + * gda_sql_statement_delete_take_table_name + * @stmt: a #GdaSqlStatement pointer + * @value: a table name as a G_TYPE_STRING #GValue + * + * Sets the name of the table to delete from in @stmt. @value's ownership is transferred to + * @stmt (which means @stmt is then responsible for freeing it when no longer needed). + */ +void +gda_sql_statement_delete_take_table_name (GdaSqlStatement *stmt, GValue *value) +{ + GdaSqlStatementDelete *delete = (GdaSqlStatementDelete *) stmt->contents; + if (value) { + delete->table = gda_sql_table_new (GDA_SQL_ANY_PART (stmt)); + gda_sql_table_take_name (delete->table, value); + } +} + +/** + * gda_sql_statement_delete_take_condition + * @stmt: a #GdaSqlStatement pointer + * @cond: the WHERE condition of the DELETE statement, as a #GdaSqlExpr + * + * Sets the WHERE condition of @stmt. @cond's ownership is transferred to + * @stmt (which means @stmt is then responsible for freeing it when no longer needed). + */ +void +gda_sql_statement_delete_take_condition (GdaSqlStatement *stmt, GdaSqlExpr *cond) +{ + GdaSqlStatementDelete *delete = (GdaSqlStatementDelete *) stmt->contents; + delete->cond = cond; + gda_sql_any_part_set_parent (delete->cond, delete); +} + +static gboolean +gda_sql_statement_delete_check_structure (GdaSqlAnyPart *stmt, G_GNUC_UNUSED gpointer data, GError **error) +{ + GdaSqlStatementDelete *delete = (GdaSqlStatementDelete *) stmt; + if (!delete->table) { + g_set_error (error, GDA_SQL_ERROR, GDA_SQL_STRUCTURE_CONTENTS_ERROR, + "%s", _("DELETE statement needs a table to delete from")); + return FALSE; + } + + return TRUE; +} diff --git a/.flatpak-builder/cache/objects/36/661094b2455207be7f824bcfc57c3461a535c7341c9b3ba2c7c056d3501334.file b/.flatpak-builder/cache/objects/36/661094b2455207be7f824bcfc57c3461a535c7341c9b3ba2c7c056d3501334.file new file mode 120000 index 0000000..5b793d3 --- /dev/null +++ b/.flatpak-builder/cache/objects/36/661094b2455207be7f824bcfc57c3461a535c7341c9b3ba2c7c056d3501334.file @@ -0,0 +1 @@ +../../share/runtime/locale/sv/share/sv \ No newline at end of file diff --git a/.flatpak-builder/cache/objects/36/9ba4d2a6e1506c4899f0b59ea4b37416f9def4109d6ac18c716d32a1baadb4.file b/.flatpak-builder/cache/objects/36/9ba4d2a6e1506c4899f0b59ea4b37416f9def4109d6ac18c716d32a1baadb4.file new file mode 120000 index 0000000..84b7cc1 --- /dev/null +++ b/.flatpak-builder/cache/objects/36/9ba4d2a6e1506c4899f0b59ea4b37416f9def4109d6ac18c716d32a1baadb4.file @@ -0,0 +1 @@ +../../share/runtime/locale/zh/share/zh_CN \ No newline at end of file diff --git a/.flatpak-builder/cache/objects/36/a969a00db086543cad24c4de83cef69093dee36e7fa6c81af9b78d9a4d0537.commit b/.flatpak-builder/cache/objects/36/a969a00db086543cad24c4de83cef69093dee36e7fa6c81af9b78d9a4d0537.commit new file mode 100644 index 0000000..9834bcb Binary files /dev/null and b/.flatpak-builder/cache/objects/36/a969a00db086543cad24c4de83cef69093dee36e7fa6c81af9b78d9a4d0537.commit differ diff --git a/.flatpak-builder/cache/objects/36/f58b2c809dc5a7d74962ec9bc1859817b3fc15a39531563a29a3790d25c3a5.file b/.flatpak-builder/cache/objects/36/f58b2c809dc5a7d74962ec9bc1859817b3fc15a39531563a29a3790d25c3a5.file new file mode 100644 index 0000000..563c986 Binary files /dev/null and b/.flatpak-builder/cache/objects/36/f58b2c809dc5a7d74962ec9bc1859817b3fc15a39531563a29a3790d25c3a5.file differ diff --git a/.flatpak-builder/cache/objects/37/a1abc65cab71e694e43b2ac97de368a628a03f2561a6f8e5e9d43569a418d9.file b/.flatpak-builder/cache/objects/37/a1abc65cab71e694e43b2ac97de368a628a03f2561a6f8e5e9d43569a418d9.file new file mode 100644 index 0000000..681e6a6 --- /dev/null +++ b/.flatpak-builder/cache/objects/37/a1abc65cab71e694e43b2ac97de368a628a03f2561a6f8e5e9d43569a418d9.file @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2008 - 2012 Vivien Malerba + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GDA_STATEMENT_PRIV__ +#define __GDA_STATEMENT_PRIV__ + + +G_BEGIN_DECLS + +GdaSqlStatement *_gda_statement_get_internal_struct (GdaStatement *stmt); +const GType *_gda_statement_get_requested_types (GdaStatement *stmt); + +G_END_DECLS + +#endif + + + diff --git a/.flatpak-builder/cache/objects/37/ac0d238a29b253ec9db712629241c9e4886fe922123b77882c4c5437425695.file b/.flatpak-builder/cache/objects/37/ac0d238a29b253ec9db712629241c9e4886fe922123b77882c4c5437425695.file new file mode 100644 index 0000000..730a98d --- /dev/null +++ b/.flatpak-builder/cache/objects/37/ac0d238a29b253ec9db712629241c9e4886fe922123b77882c4c5437425695.file @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2007 - 2014 Vivien Malerba + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GDA_VIRTUAL_CONNECTION_H__ +#define __GDA_VIRTUAL_CONNECTION_H__ + +#include +#include "gda-virtual-provider.h" + +#define GDA_TYPE_VIRTUAL_CONNECTION (gda_virtual_connection_get_type()) + +G_BEGIN_DECLS + +G_DECLARE_DERIVABLE_TYPE (GdaVirtualConnection, gda_virtual_connection, GDA, VIRTUAL_CONNECTION, GdaConnection) + +struct _GdaVirtualConnectionClass { + GdaConnectionClass parent_class; + + /*< private >*/ + /* Padding for future expansion */ + void (*_gda_reserved1) (void); + void (*_gda_reserved2) (void); + void (*_gda_reserved3) (void); + void (*_gda_reserved4) (void); +}; + +/** + * SECTION:gda-virtual-connection + * @short_description: Base class for all virtual connection objects + * @title: GdaVirtualConnection + * @stability: Stable + * @see_also: + * + * This is a base virtual class for all virtual connection implementations. + */ + +GType gda_virtual_connection_get_type (void) G_GNUC_CONST; +GdaConnection *gda_virtual_connection_open (GdaVirtualProvider *virtual_provider, GdaConnectionOptions options, + GError **error); +void gda_virtual_connection_internal_set_provider_data (GdaVirtualConnection *vcnc, + gpointer data, GDestroyNotify destroy_func); +gpointer gda_virtual_connection_internal_get_provider_data (GdaVirtualConnection *vcnc); + +G_END_DECLS + +#endif diff --git a/.flatpak-builder/cache/objects/37/bb9cd2211573b7993972a4d6444c8a996d94d42de008acee3e2e123e8645d5.dirtree b/.flatpak-builder/cache/objects/37/bb9cd2211573b7993972a4d6444c8a996d94d42de008acee3e2e123e8645d5.dirtree new file mode 100644 index 0000000..0d4980b Binary files /dev/null and b/.flatpak-builder/cache/objects/37/bb9cd2211573b7993972a4d6444c8a996d94d42de008acee3e2e123e8645d5.dirtree differ diff --git a/.flatpak-builder/cache/objects/38/2dcdebb9a1fd0db6966e43fe23bafb78a4a5431800430e304630eeacccccc5.file b/.flatpak-builder/cache/objects/38/2dcdebb9a1fd0db6966e43fe23bafb78a4a5431800430e304630eeacccccc5.file new file mode 120000 index 0000000..791e143 --- /dev/null +++ b/.flatpak-builder/cache/objects/38/2dcdebb9a1fd0db6966e43fe23bafb78a4a5431800430e304630eeacccccc5.file @@ -0,0 +1 @@ +../../share/runtime/locale/ja/share/ja \ No newline at end of file diff --git a/.flatpak-builder/cache/objects/38/c6c5b4d2fdd11af7e6aa3f02f6c80b1bca28a47f6fcd8a92800393a665733c.dirtree b/.flatpak-builder/cache/objects/38/c6c5b4d2fdd11af7e6aa3f02f6c80b1bca28a47f6fcd8a92800393a665733c.dirtree new file mode 100644 index 0000000..59f72e3 Binary files /dev/null and b/.flatpak-builder/cache/objects/38/c6c5b4d2fdd11af7e6aa3f02f6c80b1bca28a47f6fcd8a92800393a665733c.dirtree differ diff --git a/.flatpak-builder/cache/objects/39/2acd966969b027f4c9d3778dc6327e885b45b913a13228d0a73bce5009d3b0.file b/.flatpak-builder/cache/objects/39/2acd966969b027f4c9d3778dc6327e885b45b913a13228d0a73bce5009d3b0.file new file mode 100644 index 0000000..e85190b --- /dev/null +++ b/.flatpak-builder/cache/objects/39/2acd966969b027f4c9d3778dc6327e885b45b913a13228d0a73bce5009d3b0.file @@ -0,0 +1,866 @@ +# gir.py +# +# Copyright 2021 James Westman +# +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation; either version 3 of the +# License, or (at your option) any later version. +# +# This file is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program. If not, see . +# +# SPDX-License-Identifier: LGPL-3.0-or-later + +from functools import cached_property +import typing as T +import os, sys + +import gi # type: ignore + +gi.require_version("GIRepository", "2.0") +from gi.repository import GIRepository # type: ignore + +from .errors import CompileError, CompilerBugError +from . import typelib, xml_reader + +_namespace_cache: T.Dict[str, "Namespace"] = {} +_xml_cache = {} + +_user_search_paths = [] + + +def add_typelib_search_path(path: str): + _user_search_paths.append(path) + + +def get_namespace(namespace: str, version: str) -> "Namespace": + search_paths = [*GIRepository.Repository.get_search_path(), *_user_search_paths] + + filename = f"{namespace}-{version}.typelib" + + if filename not in _namespace_cache: + for search_path in search_paths: + path = os.path.join(search_path, filename) + + if os.path.exists(path) and os.path.isfile(path): + tl = typelib.load_typelib(path) + repository = Repository(tl) + + _namespace_cache[filename] = repository.namespace + break + + if filename not in _namespace_cache: + raise CompileError( + f"Namespace {namespace}-{version} could not be found", + hints=["search path: " + os.pathsep.join(search_paths)], + ) + + return _namespace_cache[filename] + + +def get_xml(namespace: str, version: str): + search_paths = [] + + if data_paths := os.environ.get("XDG_DATA_DIRS"): + search_paths += [ + os.path.join(path, "gir-1.0") for path in data_paths.split(os.pathsep) + ] + + filename = f"{namespace}-{version}.gir" + + if filename not in _xml_cache: + for search_path in search_paths: + path = os.path.join(search_path, filename) + + if os.path.exists(path) and os.path.isfile(path): + _xml_cache[filename] = xml_reader.parse(path) + break + + if filename not in _xml_cache: + raise CompileError( + f"GObject introspection file '{namespace}-{version}.gir' could not be found", + hints=["search path: " + os.pathsep.join(search_paths)], + ) + + return _xml_cache[filename] + + +class GirType: + @property + def doc(self) -> T.Optional[str]: + return None + + def assignable_to(self, other: "GirType") -> bool: + raise NotImplementedError() + + @property + def name(self) -> str: + """The GIR name of the type, not including the namespace""" + raise NotImplementedError() + + @property + def full_name(self) -> str: + """The GIR name of the type to use in diagnostics""" + raise NotImplementedError() + + @property + def glib_type_name(self) -> str: + """The name of the type in the GObject type system, suitable to pass to `g_type_from_name()`.""" + raise NotImplementedError() + + @property + def incomplete(self) -> bool: + return False + + +class ExternType(GirType): + def __init__(self, name: str) -> None: + super().__init__() + self._name = name + + def assignable_to(self, other: GirType) -> bool: + return True + + @property + def full_name(self) -> str: + return self._name + + @property + def glib_type_name(self) -> str: + return self._name + + @property + def incomplete(self) -> bool: + return True + + +class ArrayType(GirType): + def __init__(self, inner: GirType) -> None: + self._inner = inner + + def assignable_to(self, other: GirType) -> bool: + return isinstance(other, ArrayType) and self._inner.assignable_to(other._inner) + + @property + def name(self) -> str: + return self._inner.name + "[]" + + @property + def full_name(self) -> str: + return self._inner.full_name + "[]" + + +class BasicType(GirType): + name: str = "unknown type" + + @property + def full_name(self) -> str: + return self.name + + +class BoolType(BasicType): + name = "bool" + glib_type_name: str = "gboolean" + + def assignable_to(self, other: GirType) -> bool: + return isinstance(other, BoolType) + + +class IntType(BasicType): + name = "int" + glib_type_name: str = "gint" + + def assignable_to(self, other: GirType) -> bool: + return ( + isinstance(other, IntType) + or isinstance(other, UIntType) + or isinstance(other, FloatType) + ) + + +class UIntType(BasicType): + name = "uint" + glib_type_name: str = "guint" + + def assignable_to(self, other: GirType) -> bool: + return ( + isinstance(other, IntType) + or isinstance(other, UIntType) + or isinstance(other, FloatType) + ) + + +class FloatType(BasicType): + name = "float" + glib_type_name: str = "gfloat" + + def assignable_to(self, other: GirType) -> bool: + return isinstance(other, FloatType) + + +class StringType(BasicType): + name = "string" + glib_type_name: str = "gchararray" + + def assignable_to(self, other: GirType) -> bool: + return isinstance(other, StringType) + + +class TypeType(BasicType): + name = "GType" + glib_type_name: str = "GType" + + def assignable_to(self, other: GirType) -> bool: + return isinstance(other, TypeType) + + +_BASIC_TYPES = { + "bool": BoolType, + "string": StringType, + "int": IntType, + "uint": UIntType, + "float": FloatType, + "double": FloatType, + "type": TypeType, +} + + +TNode = T.TypeVar("TNode", bound="GirNode") + + +class GirNode: + def __init__(self, container: T.Optional["GirNode"], tl: typelib.Typelib) -> None: + self.container = container + self.tl = tl + + def get_containing(self, container_type: T.Type[TNode]) -> TNode: + if self.container is None: + raise CompilerBugError() + elif isinstance(self.container, container_type): + return self.container + else: + return self.container.get_containing(container_type) + + @cached_property + def xml(self): + for el in self.container.xml.children: + if el.attrs.get("name") == self.name: + return el + + @cached_property + def glib_type_name(self) -> str: + return self.tl.OBJ_GTYPE_NAME + + @cached_property + def full_name(self) -> str: + if self.container is None: + return self.name + else: + return f"{self.container.name}.{self.name}" + + @cached_property + def name(self) -> str: + return self.tl.BLOB_NAME + + @cached_property + def cname(self) -> str: + return self.tl.OBJ_GTYPE_NAME + + @cached_property + def available_in(self) -> str: + return self.xml.get("version") + + @cached_property + def doc(self) -> T.Optional[str]: + sections = [] + + if self.signature: + sections.append("```\n" + self.signature + "\n```") + + try: + el = self.xml.get_elements("doc") + if len(el) == 1: + sections.append(el[0].cdata.strip()) + except: + # Not a huge deal, but if you want docs in the language server you + # should ensure .gir files are installed + pass + + return "\n\n---\n\n".join(sections) + + @property + def signature(self) -> T.Optional[str]: + return None + + @property + def type(self) -> GirType: + raise NotImplementedError() + + +class Property(GirNode): + def __init__(self, klass: T.Union["Class", "Interface"], tl: typelib.Typelib): + super().__init__(klass, tl) + + @cached_property + def name(self) -> str: + return self.tl.PROP_NAME + + @cached_property + def type(self): + return self.get_containing(Repository)._resolve_type_id(self.tl.PROP_TYPE) + + @cached_property + def signature(self): + return f"{self.full_name} {self.container.name}.{self.name}" + + @property + def writable(self) -> bool: + return self.tl.PROP_WRITABLE == 1 + + @property + def construct_only(self) -> bool: + return self.tl.PROP_CONSTRUCT_ONLY == 1 + + +class Parameter(GirNode): + def __init__(self, container: GirNode, tl: typelib.Typelib) -> None: + super().__init__(container, tl) + + +class Signal(GirNode): + def __init__( + self, klass: T.Union["Class", "Interface"], tl: typelib.Typelib + ) -> None: + super().__init__(klass, tl) + # if parameters := xml.get_elements('parameters'): + # self.params = [Parameter(self, child) for child in parameters[0].get_elements('parameter')] + # else: + # self.params = [] + + @property + def signature(self): + # TODO: fix + # args = ", ".join([f"{p.type_name} {p.name}" for p in self.params]) + args = "" + return f"signal {self.container.name}.{self.name} ({args})" + + +class Interface(GirNode, GirType): + def __init__(self, ns: "Namespace", tl: typelib.Typelib): + super().__init__(ns, tl) + + @cached_property + def properties(self) -> T.Mapping[str, Property]: + n_prerequisites = self.tl.INTERFACE_N_PREREQUISITES + offset = self.tl.header.HEADER_INTERFACE_BLOB_SIZE + offset += (n_prerequisites + n_prerequisites % 2) * 2 + n_properties = self.tl.INTERFACE_N_PROPERTIES + property_size = self.tl.header.HEADER_PROPERTY_BLOB_SIZE + result = {} + for i in range(n_properties): + property = Property(self, self.tl[offset + i * property_size]) + result[property.name] = property + return result + + @cached_property + def signals(self) -> T.Mapping[str, Signal]: + n_prerequisites = self.tl.INTERFACE_N_PREREQUISITES + offset = self.tl.header.HEADER_INTERFACE_BLOB_SIZE + offset += (n_prerequisites + n_prerequisites % 2) * 2 + offset += ( + self.tl.INTERFACE_N_PROPERTIES * self.tl.header.HEADER_PROPERTY_BLOB_SIZE + ) + offset += self.tl.INTERFACE_N_METHODS * self.tl.header.HEADER_FUNCTION_BLOB_SIZE + n_signals = self.tl.INTERFACE_N_SIGNALS + property_size = self.tl.header.HEADER_SIGNAL_BLOB_SIZE + result = {} + for i in range(n_signals): + signal = Signal(self, self.tl[offset + i * property_size]) + result[signal.name] = signal + return result + + @cached_property + def prerequisites(self) -> T.List["Interface"]: + n_prerequisites = self.tl.INTERFACE_N_PREREQUISITES + result = [] + for i in range(n_prerequisites): + entry = self.tl.INTERFACE_PREREQUISITES[i * 2].AS_DIR_ENTRY + result.append(self.get_containing(Repository)._resolve_dir_entry(entry)) + return result + + def assignable_to(self, other: GirType) -> bool: + if self == other: + return True + for pre in self.prerequisites: + if pre.assignable_to(other): + return True + return False + + +class Class(GirNode, GirType): + def __init__(self, ns: "Namespace", tl: typelib.Typelib) -> None: + super().__init__(ns, tl) + + @property + def abstract(self) -> bool: + return self.tl.OBJ_ABSTRACT == 1 + + @cached_property + def implements(self) -> T.List[Interface]: + n_interfaces = self.tl.OBJ_N_INTERFACES + result = [] + for i in range(n_interfaces): + entry = self.tl[self.tl.header.HEADER_OBJECT_BLOB_SIZE + i * 2].AS_DIR_ENTRY + result.append(self.get_containing(Repository)._resolve_dir_entry(entry)) + return result + + @cached_property + def own_properties(self) -> T.Mapping[str, Property]: + n_interfaces = self.tl.OBJ_N_INTERFACES + offset = self.tl.header.HEADER_OBJECT_BLOB_SIZE + offset += (n_interfaces + n_interfaces % 2) * 2 + offset += self.tl.OBJ_N_FIELDS * self.tl.header.HEADER_FIELD_BLOB_SIZE + offset += ( + self.tl.OBJ_N_FIELD_CALLBACKS * self.tl.header.HEADER_CALLBACK_BLOB_SIZE + ) + n_properties = self.tl.OBJ_N_PROPERTIES + property_size = self.tl.header.HEADER_PROPERTY_BLOB_SIZE + result = {} + for i in range(n_properties): + property = Property(self, self.tl[offset + i * property_size]) + result[property.name] = property + return result + + @cached_property + def own_signals(self) -> T.Mapping[str, Signal]: + n_interfaces = self.tl.OBJ_N_INTERFACES + offset = self.tl.header.HEADER_OBJECT_BLOB_SIZE + offset += (n_interfaces + n_interfaces % 2) * 2 + offset += self.tl.OBJ_N_FIELDS * self.tl.header.HEADER_FIELD_BLOB_SIZE + offset += ( + self.tl.OBJ_N_FIELD_CALLBACKS * self.tl.header.HEADER_CALLBACK_BLOB_SIZE + ) + offset += self.tl.OBJ_N_PROPERTIES * self.tl.header.HEADER_PROPERTY_BLOB_SIZE + offset += self.tl.OBJ_N_METHODS * self.tl.header.HEADER_FUNCTION_BLOB_SIZE + n_signals = self.tl.OBJ_N_SIGNALS + signal_size = self.tl.header.HEADER_SIGNAL_BLOB_SIZE + result = {} + for i in range(n_signals): + signal = Signal(self, self.tl[offset][i * signal_size]) + result[signal.name] = signal + return result + + @cached_property + def parent(self) -> T.Optional["Class"]: + if entry := self.tl.OBJ_PARENT: + return self.get_containing(Repository)._resolve_dir_entry(entry) + else: + return None + + @cached_property + def signature(self) -> str: + assert self.container is not None + result = f"class {self.container.name}.{self.name}" + if self.parent is not None: + assert self.parent.container is not None + result += f" : {self.parent.container.name}.{self.parent.name}" + if len(self.implements): + result += " implements " + ", ".join( + [impl.full_name for impl in self.implements] + ) + return result + + @cached_property + def properties(self) -> T.Mapping[str, Property]: + return {p.name: p for p in self._enum_properties()} + + @cached_property + def signals(self) -> T.Mapping[str, Signal]: + return {s.name: s for s in self._enum_signals()} + + def assignable_to(self, other: GirType) -> bool: + if self == other: + return True + elif self.parent and self.parent.assignable_to(other): + return True + else: + for iface in self.implements: + if iface.assignable_to(other): + return True + + return False + + def _enum_properties(self) -> T.Iterable[Property]: + yield from self.own_properties.values() + + if self.parent is not None: + yield from self.parent.properties.values() + + for impl in self.implements: + yield from impl.properties.values() + + def _enum_signals(self) -> T.Iterable[Signal]: + yield from self.own_signals.values() + + if self.parent is not None: + yield from self.parent.signals.values() + + for impl in self.implements: + yield from impl.signals.values() + + +class TemplateType(GirType): + def __init__(self, name: str, parent: T.Optional[GirType]): + self._name = name + self.parent = parent + + @property + def name(self) -> str: + return self._name + + @property + def full_name(self) -> str: + return self._name + + @property + def glib_type_name(self) -> str: + return self._name + + @cached_property + def properties(self) -> T.Mapping[str, Property]: + if not (isinstance(self.parent, Class) or isinstance(self.parent, Interface)): + return {} + else: + return self.parent.properties + + @cached_property + def signals(self) -> T.Mapping[str, Signal]: + if not (isinstance(self.parent, Class) or isinstance(self.parent, Interface)): + return {} + else: + return self.parent.signals + + def assignable_to(self, other: "GirType") -> bool: + if self == other: + return True + elif isinstance(other, Interface): + # we don't know the template type's interfaces, assume yes + return True + elif self.parent is None or isinstance(self.parent, ExternType): + return isinstance(other, Class) + else: + return self.parent.assignable_to(other) + + @cached_property + def signature(self) -> str: + if self.parent is None: + return f"template {self.name}" + else: + return f"template {self.name} : {self.parent.full_name}" + + @property + def incomplete(self) -> bool: + return True + + +class EnumMember(GirNode): + def __init__(self, enum: "Enumeration", tl: typelib.Typelib) -> None: + super().__init__(enum, tl) + + @property + def value(self) -> int: + return self.tl.VALUE_VALUE + + @cached_property + def name(self) -> str: + return self.tl.VALUE_NAME + + @cached_property + def nick(self) -> str: + return self.name.replace("_", "-") + + @property + def c_ident(self) -> str: + return self.tl.attr("c:identifier") + + @property + def signature(self) -> str: + return f"enum member {self.full_name} = {self.value}" + + +class Enumeration(GirNode, GirType): + def __init__(self, ns: "Namespace", tl: typelib.Typelib) -> None: + super().__init__(ns, tl) + + @cached_property + def members(self) -> T.Dict[str, EnumMember]: + members = {} + n_values = self.tl.ENUM_N_VALUES + values = self.tl.ENUM_VALUES + value_size = self.tl.header.HEADER_VALUE_BLOB_SIZE + for i in range(n_values): + member = EnumMember(self, values[i * value_size]) + members[member.name] = member + return members + + @property + def signature(self) -> str: + return f"enum {self.full_name}" + + def assignable_to(self, type: GirType) -> bool: + return type == self + + +class Boxed(GirNode, GirType): + def __init__(self, ns: "Namespace", tl: typelib.Typelib) -> None: + super().__init__(ns, tl) + + @property + def signature(self) -> str: + return f"boxed {self.full_name}" + + def assignable_to(self, type) -> bool: + return type == self + + +class Bitfield(Enumeration): + def __init__(self, ns: "Namespace", tl: typelib.Typelib) -> None: + super().__init__(ns, tl) + + +class Namespace(GirNode): + def __init__(self, repo: "Repository", tl: typelib.Typelib) -> None: + super().__init__(repo, tl) + + self.entries: T.Dict[str, GirType] = {} + + n_local_entries: int = tl.HEADER_N_ENTRIES + directory: typelib.Typelib = tl.HEADER_DIRECTORY + for i in range(n_local_entries): + entry = directory[i * tl.HEADER_ENTRY_BLOB_SIZE] + entry_name: str = entry.DIR_ENTRY_NAME + entry_type: int = entry.DIR_ENTRY_BLOB_TYPE + entry_blob: typelib.Typelib = entry.DIR_ENTRY_OFFSET + + if entry_type == typelib.BLOB_TYPE_ENUM: + self.entries[entry_name] = Enumeration(self, entry_blob) + elif entry_type == typelib.BLOB_TYPE_FLAGS: + self.entries[entry_name] = Bitfield(self, entry_blob) + elif entry_type == typelib.BLOB_TYPE_OBJECT: + self.entries[entry_name] = Class(self, entry_blob) + elif entry_type == typelib.BLOB_TYPE_INTERFACE: + self.entries[entry_name] = Interface(self, entry_blob) + elif ( + entry_type == typelib.BLOB_TYPE_BOXED + or entry_type == typelib.BLOB_TYPE_STRUCT + ): + self.entries[entry_name] = Boxed(self, entry_blob) + + @cached_property + def xml(self): + return get_xml(self.name, self.version).get_elements("namespace")[0] + + @cached_property + def name(self) -> str: + return self.tl.HEADER_NAMESPACE + + @cached_property + def version(self) -> str: + return self.tl.HEADER_NSVERSION + + @property + def signature(self) -> str: + return f"namespace {self.name} {self.version}" + + @cached_property + def classes(self) -> T.Mapping[str, Class]: + return { + name: entry + for name, entry in self.entries.items() + if isinstance(entry, Class) + } + + @cached_property + def interfaces(self) -> T.Mapping[str, Interface]: + return { + name: entry + for name, entry in self.entries.items() + if isinstance(entry, Interface) + } + + def get_type(self, name) -> T.Optional[GirType]: + """Gets a type (class, interface, enum, etc.) from this namespace.""" + return self.entries.get(name) + + def get_type_by_cname(self, cname: str) -> T.Optional[GirType]: + """Gets a type from this namespace by its C name.""" + for item in self.entries.values(): + if hasattr(item, "cname") and item.cname == cname: + return item + return None + + def lookup_type(self, type_name: str) -> T.Optional[GirType]: + """Looks up a type in the scope of this namespace (including in the + namespace's dependencies).""" + + if type_name in _BASIC_TYPES: + return _BASIC_TYPES[type_name]() + elif "." in type_name: + ns, name = type_name.split(".", 1) + return self.get_containing(Repository).get_type(name, ns) + else: + return self.get_type(type_name) + + +class Repository(GirNode): + def __init__(self, tl: typelib.Typelib) -> None: + super().__init__(None, tl) + + self.namespace = Namespace(self, tl) + + if dependencies := tl[0x24].string: + deps = [tuple(dep.split("-", 1)) for dep in dependencies.split("|")] + try: + self.includes = { + name: get_namespace(name, version) for name, version in deps + } + except: + raise CompilerBugError(f"Failed to load dependencies.") + else: + self.includes = {} + + def get_type(self, name: str, ns: str) -> T.Optional[GirType]: + return self.lookup_namespace(ns).get_type(name) + + def get_type_by_cname(self, name: str) -> T.Optional[GirType]: + for ns in [self.namespace, *self.includes.values()]: + if type := ns.get_type_by_cname(name): + return type + return None + + def lookup_namespace(self, ns: str): + """Finds a namespace among this namespace's dependencies.""" + if ns == self.namespace.name: + return self.namespace + else: + for include in self.includes.values(): + if namespace := include.get_containing(Repository).lookup_namespace(ns): + return namespace + + def _resolve_dir_entry(self, dir_entry: typelib.Typelib): + if dir_entry.DIR_ENTRY_LOCAL: + return self.namespace.get_type(dir_entry.DIR_ENTRY_NAME) + else: + ns = dir_entry.DIR_ENTRY_NAMESPACE + return self.lookup_namespace(ns).get_type(dir_entry.DIR_ENTRY_NAME) + + def _resolve_type_id(self, type_id: int) -> GirType: + if type_id & 0xFFFFFF == 0: + type_id = (type_id >> 27) & 0x1F + # simple type + if type_id == typelib.TYPE_BOOLEAN: + return BoolType() + elif type_id in [typelib.TYPE_FLOAT, typelib.TYPE_DOUBLE]: + return FloatType() + elif type_id in [ + typelib.TYPE_INT8, + typelib.TYPE_INT16, + typelib.TYPE_INT32, + typelib.TYPE_INT64, + ]: + return IntType() + elif type_id in [ + typelib.TYPE_UINT8, + typelib.TYPE_UINT16, + typelib.TYPE_UINT32, + typelib.TYPE_UINT64, + ]: + return UIntType() + elif type_id == typelib.TYPE_UTF8: + return StringType() + elif type_id == typelib.TYPE_GTYPE: + return TypeType() + else: + raise CompilerBugError("Unknown type ID", type_id) + else: + blob = self.tl.header[type_id] + if blob.TYPE_BLOB_TAG == typelib.TYPE_INTERFACE: + return self._resolve_dir_entry( + self.tl.header[type_id].TYPE_BLOB_INTERFACE + ) + elif blob.TYPE_BLOB_TAG == typelib.TYPE_ARRAY: + return ArrayType(self._resolve_type_id(blob.TYPE_BLOB_ARRAY_INNER)) + else: + raise CompilerBugError(f"{blob.TYPE_BLOB_TAG}") + + +class GirContext: + def __init__(self): + self.namespaces = {} + self.not_found_namespaces: T.Set[str] = set() + + def add_namespace(self, namespace: Namespace): + other = self.namespaces.get(namespace.name) + if other is not None and other.version != namespace.version: + raise CompileError( + f"Namespace {namespace.name}-{namespace.version} can't be imported because version {other.version} was imported earlier" + ) + + self.namespaces[namespace.name] = namespace + + def get_type_by_cname(self, name: str) -> T.Optional[GirType]: + for ns in self.namespaces.values(): + if type := ns.get_type_by_cname(name): + return type + return None + + def get_type(self, name: str, ns: str) -> T.Optional[GirType]: + if ns is None and name in _BASIC_TYPES: + return _BASIC_TYPES[name]() + + ns = ns or "Gtk" + + if ns not in self.namespaces: + return None + + return self.namespaces[ns].get_type(name) + + def get_class(self, name: str, ns: str) -> T.Optional[Class]: + type = self.get_type(name, ns) + if isinstance(type, Class): + return type + else: + return None + + def validate_ns(self, ns: str) -> None: + """Raises an exception if there is a problem looking up the given + namespace.""" + + ns = ns or "Gtk" + + if ns not in self.namespaces and ns not in self.not_found_namespaces: + raise CompileError( + f"Namespace {ns} was not imported", + did_you_mean=(ns, self.namespaces.keys()), + ) + + def validate_type(self, name: str, ns: str) -> None: + """Raises an exception if there is a problem looking up the given type.""" + + self.validate_ns(ns) + + type = self.get_type(name, ns) + + ns = ns or "Gtk" + + if type is None: + raise CompileError( + f"Namespace {ns} does not contain a type called {name}", + did_you_mean=(name, self.namespaces[ns].classes.keys()), + ) diff --git a/.flatpak-builder/cache/objects/39/5fced77fcd6aaa21616ac01df2db2356b094b33e32fc9a8f0a6c64a8381c54.file b/.flatpak-builder/cache/objects/39/5fced77fcd6aaa21616ac01df2db2356b094b33e32fc9a8f0a6c64a8381c54.file new file mode 100644 index 0000000..183ad8e --- /dev/null +++ b/.flatpak-builder/cache/objects/39/5fced77fcd6aaa21616ac01df2db2356b094b33e32fc9a8f0a6c64a8381c54.file @@ -0,0 +1,106 @@ +# gobject_object.py +# +# Copyright 2022 James Westman +# +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation; either version 3 of the +# License, or (at your option) any later version. +# +# This file is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program. If not, see . +# +# SPDX-License-Identifier: LGPL-3.0-or-later + + +import typing as T +from functools import cached_property + +from .common import * +from .response_id import ExtResponse +from .types import ClassName, ConcreteClassName + + +RESERVED_IDS = {"this", "self", "template", "true", "false", "null", "none"} + + +class ObjectContent(AstNode): + grammar = ["{", Until(OBJECT_CONTENT_HOOKS, "}")] + + @property + def gir_class(self): + return self.parent.gir_class + + +class Object(AstNode): + grammar: T.Any = [ + ConcreteClassName, + Optional(UseIdent("id")), + ObjectContent, + ] + + @property + def id(self) -> str: + return self.tokens["id"] + + @property + def class_name(self) -> ClassName: + return self.children[ClassName][0] + + @property + def content(self) -> ObjectContent: + return self.children[ObjectContent][0] + + @property + def gir_class(self) -> GirType: + if self.class_name is None: + raise CompilerBugError() + return self.class_name.gir_type + + @cached_property + def action_widgets(self) -> T.List[ExtResponse]: + """Get list of widget's action widgets. + + Empty if object doesn't have action widgets. + """ + from .gtkbuilder_child import Child + + return [ + child.response_id + for child in self.content.children[Child] + if child.response_id + ] + + @validate("id") + def object_id_not_reserved(self): + from .gtkbuilder_template import Template + + if not isinstance(self, Template) and self.id in RESERVED_IDS: + raise CompileWarning(f"{self.id} may be a confusing object ID") + + +def validate_parent_type(node, ns: str, name: str, err_msg: str): + parent = node.root.gir.get_type(name, ns) + container_type = node.parent_by_type(Object).gir_class + if container_type and not container_type.assignable_to(parent): + raise CompileError( + f"{container_type.full_name} is not a {parent.full_name}, so it doesn't have {err_msg}" + ) + + +@decompiler("object") +def decompile_object(ctx, gir, klass, id=None): + gir_class = ctx.type_by_cname(klass) + klass_name = ( + decompile.full_name(gir_class) if gir_class is not None else "$" + klass + ) + if id is None: + ctx.print(f"{klass_name} {{") + else: + ctx.print(f"{klass_name} {id} {{") + return gir_class diff --git a/.flatpak-builder/cache/objects/39/741efefb7e39c766799d24a7a1beddd4c00bc709c6c630c21992699efddae3.file b/.flatpak-builder/cache/objects/39/741efefb7e39c766799d24a7a1beddd4c00bc709c6c630c21992699efddae3.file new file mode 100755 index 0000000..b2efabf Binary files /dev/null and b/.flatpak-builder/cache/objects/39/741efefb7e39c766799d24a7a1beddd4c00bc709c6c630c21992699efddae3.file differ diff --git a/.flatpak-builder/cache/objects/39/88db6545d4758ae05a624bb42ffa67b5606c4a6414d652edfafba71a7cf188.file b/.flatpak-builder/cache/objects/39/88db6545d4758ae05a624bb42ffa67b5606c4a6414d652edfafba71a7cf188.file new file mode 120000 index 0000000..23eeced --- /dev/null +++ b/.flatpak-builder/cache/objects/39/88db6545d4758ae05a624bb42ffa67b5606c4a6414d652edfafba71a7cf188.file @@ -0,0 +1 @@ +libcanberra.so.0.2.5 \ No newline at end of file diff --git a/.flatpak-builder/cache/objects/39/9df962366c831c6af1662cfac320df6be253bd02b4d8d7a5fabdf4bebb7974.file b/.flatpak-builder/cache/objects/39/9df962366c831c6af1662cfac320df6be253bd02b4d8d7a5fabdf4bebb7974.file new file mode 100644 index 0000000..80a087b --- /dev/null +++ b/.flatpak-builder/cache/objects/39/9df962366c831c6af1662cfac320df6be253bd02b4d8d7a5fabdf4bebb7974.file @@ -0,0 +1,6 @@ +[GTK Module] +Name=canberra-gtk-module +Description=Event Sound Module +X-GTK-Module-Name=canberra-gtk-module +X-GTK-Module-Enabled-Schema=org.gnome.desktop.sound +X-GTK-Module-Enabled-Key=event-sounds diff --git a/.flatpak-builder/cache/objects/3a/0a57155bee94229d8a5fc5beae27cd7ea9074eacdd2058ab07ce1ce150fcb3.file b/.flatpak-builder/cache/objects/3a/0a57155bee94229d8a5fc5beae27cd7ea9074eacdd2058ab07ce1ce150fcb3.file new file mode 100644 index 0000000..e67c75b --- /dev/null +++ b/.flatpak-builder/cache/objects/3a/0a57155bee94229d8a5fc5beae27cd7ea9074eacdd2058ab07ce1ce150fcb3.file @@ -0,0 +1,956 @@ +/* + * Copyright (C) 2014 Vivien Malerba + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifdef FORCE_NO_EVENTFD + /* for testing purposes */ + #undef HAVE_EVENTFD +#endif + +#define DEBUG_NOTIFICATION +#undef DEBUG_NOTIFICATION + +#ifdef __GNUC__ +#define likely(x) __builtin_expect(!!(x), 1) +#define unlikely(x) __builtin_expect(!!(x), 0) +#else +#define likely(x) (x) +#define unlikely(x) (x) +#endif + +#include "itsignaler.h" +#ifndef NOBG + #include "background.h" +#endif +#include +#include +#include +#include +#include +#include + +/* optimizations */ +static guint created_objects = 0; /* counter of all the ITSignaler objects ever created */ + +#ifdef G_OS_WIN32 + #define INVALID_SOCK INVALID_SOCKET + #define SIGNALER_PORT 5906 +#else + #define _GNU_SOURCE + #include + #include + #ifdef HAVE_EVENTFD + #include + #else + + #endif + #define INVALID_SOCK -1 + #include +#endif + +typedef struct { + gpointer data; + GDestroyNotify destroy_func; +} NotificationData; + +/* + * Threads synchronization with notifications + * + * Use a GAsyncQueue to pass notifications from one thread to the other. + * + * Windows specific implementation: + * Use a client/server pair of sockets, waiting can be done on the reading socket + * + * Unix specific implementation: + * If HAVE_EVENTFD is defined (Linux extension), then use eventfd(), else use a pair of file descriptors obtained + * using pipe() + * + */ +struct _ITSignaler { + guint8 broken; /* TRUE if the object has suffered an unrecoverable error */ + +#ifdef HAVE_FORK + /* detect forked process */ + pid_t pid; +#endif + + /* data queue */ + GAsyncQueue *data_queue; + + /* signaling mechanism */ +#ifdef G_OS_WIN32 + SOCKET socks[2]; /* [0] for reading and [1] for writing */ +#else + #ifdef HAVE_EVENTFD + int event_fd; + #else + int fds[2]; /* [0] for reading and [1] for writing */ + GIOChannel *ioc; + #endif +#endif + + /* reference count, thread safe */ + guint ref_count; + GMutex mutex; +}; + +#define itsignaler_lock(x) g_mutex_lock(& (((ITSignaler*)x)->mutex)) +#define itsignaler_unlock(x) g_mutex_unlock(& (((ITSignaler*)x)->mutex)) + +/** + * itsignaler_ref: + * @its: (nullable): a #ITSignaler object + * + * Increases the reference count of @its. If @its is %NULL, then nothing happens. + * + * This function can be called from any thread. + * + * Returns: @its + */ +ITSignaler * +itsignaler_ref (ITSignaler *its) +{ + if (its) { + itsignaler_lock (its); + its->ref_count++; +#ifdef DEBUG_NOTIFICATION + g_print ("[I] ITSignaler %p ++: %u\n", its, its->ref_count); +#endif + itsignaler_unlock (its); + } + return its; +} + +static void +cleanup_signaling (ITSignaler *its) +{ +#ifdef G_OS_WIN32 + int rc; + if (its->socks[1] != INVALID_SOCKET) { + struct linger so_linger = { 1, 0 }; + rc = setsockopt (its->socks[1], SOL_SOCKET, SO_LINGER, + (char *)&so_linger, sizeof (so_linger)); + g_assert (rc != SOCKET_ERROR); + rc = closesocket (its->socks[1]); + g_assert (rc != SOCKET_ERROR); + its->socks [1] = INVALID_SOCKET; + } + if (its->socks[0] != INVALID_SOCKET) { + rc = closesocket (its->socks[0]); + g_assert (rc != SOCKET_ERROR); + its->socks [0] = INVALID_SOCKET; + } +#else + #ifdef HAVE_EVENTFD + if (its->event_fd != INVALID_SOCK) { + g_assert (close (its->event_fd) == 0); + its->event_fd = INVALID_SOCK; + } + #else + if (its->fds[0] != INVALID_SOCK) { + g_assert (close (its->fds[0]) == 0); + its->fds[0] = INVALID_SOCK; + } + if (its->fds[1] != INVALID_SOCK) { + g_assert (close (its->fds[1]) == 0); + its->fds[1] = INVALID_SOCK; + } + #endif +#endif +} + +#ifndef NOBG +static void +itsignaler_reset (ITSignaler *its) +{ + g_assert (its->ref_count == 0); +#ifdef G_OS_WIN32 + guint8 value; + ssize_t nr; + for (nr = recv (its->socks[0], (char*) &value, sizeof (value), 0); + nr >= 0; + nr = recv (its->socks[0], (char*) &value, sizeof (value), 0)); + g_assert (nr == -1); +#else + #ifdef HAVE_EVENTFD + guint64 nbnotif; + ssize_t nr = read (its->event_fd, &nbnotif, sizeof (nbnotif)); + nr = read (its->event_fd, &nbnotif, sizeof (nbnotif)); + g_assert (nr == -1); + #else + guint8 value; + ssize_t nr; + for (nr = read (its->fds[0], &value, sizeof (value)); + nr >= 0; + nr = read (its->fds[0], &value, sizeof (value))); + g_assert (nr == -1); + #endif +#endif + NotificationData *nd; + for (nd = g_async_queue_try_pop (its->data_queue); + nd; + nd = g_async_queue_try_pop (its->data_queue)) { + if (nd->data && nd->destroy_func) + nd->destroy_func (nd->data); + } +} +#endif + +/* + * This function requires that @its be locked using itsignaler_lock() + */ +static void +itsignaler_free (ITSignaler *its) +{ + /* destroy @its */ + GMutex *m = &(its->mutex); + cleanup_signaling (its); + + /* clear queue's contents */ + g_async_queue_unref (its->data_queue); + +#ifdef DEBUG_NOTIFICATION + g_print ("[I] Destroyed ITSignaler %p\n", its); +#endif + g_mutex_unlock (m); + g_mutex_clear (m); +#ifndef NOBG + bg_update_stats (BG_DESTROYED_ITS); +#endif + + g_free (its); +} + +void +_itsignaler_unref (ITSignaler *its, gboolean give_to_bg) +{ + g_assert (its); + + itsignaler_lock (its); + its->ref_count--; +#ifdef DEBUG_NOTIFICATION + g_print ("[I] ITSignaler %p --: %u\n", its, its->ref_count); +#endif + if (its->ref_count == 0) { +#ifndef NOBG + /* destroy or store as spare */ + if (!its->broken && give_to_bg) { + itsignaler_reset (its); + its->ref_count++; + bg_set_spare_its (its); + itsignaler_unlock (its); + } + else + itsignaler_free (its); +#else + itsignaler_free (its); +#endif + } + else + itsignaler_unlock (its); +} + +/** + * itsignaler_unref: + * @its: (nullable): a #ITSignaler object + * + * Decrease the reference count of @its; when the rerefence count reaches zero, the object + * is freed. If @its is %NULL, then nothing happens. + * + * This function can be called from any thread. + */ +void +itsignaler_unref (ITSignaler *its) +{ + if (its) + _itsignaler_unref (its, TRUE); +} + +void +_itsignaler_bg_unref (ITSignaler *its) +{ + g_assert (its); + g_assert (its->ref_count == 1); + + _itsignaler_unref (its, FALSE); +} + +static void +notification_data_free (NotificationData *nd) +{ + if (nd->data && nd->destroy_func) + nd->destroy_func (nd->data); + g_free (nd); +} + +/** + * itsignaler_new: + * + * Creates a new #ITSignaler object. + * + * Returns: a new #ITSignaler, or %NULL if an error occurred. Use itsignaler_unref() when not needed anymore. + */ +ITSignaler * +itsignaler_new (void) +{ + ITSignaler *its; +#ifndef NOBG + its = bg_get_spare_its (); + if (its) + return its; +#endif + + gboolean err = FALSE; + its = g_new0 (ITSignaler, 1); + its->ref_count = 1; + its->broken = FALSE; + +#ifdef G_OS_WIN32 + SECURITY_DESCRIPTOR sd; + SECURITY_ATTRIBUTES sa; + memset (&sd, 0, sizeof (sd)); + memset (&sa, 0, sizeof (sa)); + + InitializeSecurityDescriptor (&sd, SECURITY_DESCRIPTOR_REVISION); + SetSecurityDescriptorDacl (&sd, TRUE, 0, FALSE); + + sa.nLength = sizeof (SECURITY_ATTRIBUTES); + sa.lpSecurityDescriptor = &sd; + + DWORD dwrc; + HANDLE sync = CreateEvent (&sa, FALSE, TRUE, TEXT ("Global\\gda-signaler-port")); + if (!sync && (GetLastError () == ERROR_ACCESS_DENIED)) + sync = OpenEvent (SYNCHRONIZE | EVENT_MODIFY_STATE, FALSE, TEXT ("Global\\gda-signaler-port")); + if (!sync || + ((dwrc = WaitForSingleObject (sync, INFINITE)) != WAIT_OBJECT_0)) { + err = TRUE; + goto next; + } + + /* Windows has no 'socketpair' function. CreatePipe is no good as pipe + * handles cannot be polled on. Here we create the socketpair by hand + */ + its->socks [0] = INVALID_SOCKET; + its->socks [1] = INVALID_SOCKET; + + /* Initialize sockets */ + static gboolean init_done = FALSE; + if (!init_done) { + WORD version_requested = MAKEWORD (2, 2); + WSADATA wsa_data; + int rc = WSAStartup (version_requested, &wsa_data); // FIXME: call WSACleanup() somehow... + if ((rc != 0) || (LOBYTE (wsa_data.wVersion) != 2) || (HIBYTE (wsa_data.wVersion) != 2)) { + err = TRUE; + goto next; + } + init_done = TRUE; + } + + /* Create listening socket */ + SOCKET listener; + listener = socket (AF_INET, SOCK_STREAM, 0); + if (listener == INVALID_SOCKET) { + err = TRUE; + goto next; + } + + /* preventing sockets to be inherited by child processes */ + BOOL brc = SetHandleInformation ((HANDLE) listener, HANDLE_FLAG_INHERIT, 0); + if (!brc) { + closesocket (listener); + err = TRUE; + goto next; + } + + /* Set SO_REUSEADDR and TCP_NODELAY on listening socket */ + BOOL so_reuseaddr = 1; + int rc = setsockopt (listener, SOL_SOCKET, SO_REUSEADDR, + (char *)&so_reuseaddr, sizeof (so_reuseaddr)); + if (rc == SOCKET_ERROR) { + closesocket (listener); + err = TRUE; + goto next; + } + + BOOL tcp_nodelay = 1; + rc = setsockopt (listener, IPPROTO_TCP, TCP_NODELAY, + (char *)&tcp_nodelay, sizeof (tcp_nodelay)); + if (rc == SOCKET_ERROR) { + closesocket (listener); + err = TRUE; + goto next; + } + + /* Bind listening socket to signaler port */ + struct sockaddr_in addr; + memset (&addr, 0, sizeof (addr)); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = htonl (INADDR_LOOPBACK); + addr.sin_port = htons (SIGNALER_PORT); + rc = bind (listener, (const struct sockaddr*) &addr, sizeof (addr)); + if (rc == SOCKET_ERROR) { + closesocket (listener); + err = TRUE; + goto next; + } + + /* Listen for incomming connections */ + rc = listen (listener, 1); + if (rc == SOCKET_ERROR) { + closesocket (listener); + err = TRUE; + goto next; + } + + /* Create the writer socket */ + its->socks[1] = WSASocket (AF_INET, SOCK_STREAM, 0, NULL, 0, 0); + if (its->socks[1] == INVALID_SOCKET) { + err = TRUE; + goto next; + } + + /* Preventing sockets to be inherited by child processes */ + brc = SetHandleInformation ((HANDLE) its->socks[1], HANDLE_FLAG_INHERIT, 0); + if (!brc) { + err = TRUE; + goto next; + } + + /* Set TCP_NODELAY on writer socket */ + rc = setsockopt (its->socks[1], IPPROTO_TCP, TCP_NODELAY, + (char *)&tcp_nodelay, sizeof (tcp_nodelay)); + if (rc == SOCKET_ERROR) { + err = TRUE; + goto next; + } + + /* Connect writer to the listener */ + rc = connect (its->socks[1], (struct sockaddr*) &addr, sizeof (addr)); + + /* Accept connection from writer */ + its->socks[0] = accept (listener, NULL, NULL); + + /* We don't need the listening socket anymore. Close it */ + rc = closesocket (listener); + if (rc == SOCKET_ERROR) { + err = TRUE; + goto next; + } + + /* Exit the critical section */ + brc = SetEvent (sync); + if (!brc) { + err = TRUE; + goto next; + } + + if (its->socks[0] == INVALID_SOCKET) { + err = TRUE; + closesocket (its->socks[1]); + its->socks[1] = INVALID_SOCKET; + goto next; + } + + /* Set non blocking mode */ + u_long nonblock = 1; + rc = ioctlsocket (its->socks[0], FIONBIO, &nonblock); + if (rc == SOCKET_ERROR) { + err = TRUE; + goto next; + } + + /* Preventing sockets to be inherited by child processes */ + brc = SetHandleInformation ((HANDLE) its->socks[0], HANDLE_FLAG_INHERIT, 0); + if (!brc) { + err = TRUE; + goto next; + } +#else + #ifdef HAVE_EVENTFD + its->event_fd = eventfd (0, EFD_NONBLOCK | EFD_CLOEXEC); + if (its->event_fd == INVALID_SOCK) { + err = TRUE; + goto next; + } + #else /* HAVE_EVENTFD */ + if (pipe (its->fds) != 0) { + err = TRUE; + goto next; + } + + /* set read to non blocking */ + int flags; + flags = fcntl (its->fds[0], F_GETFL, 0); + if (flags < 0) + err = TRUE; + else { + flags = flags | O_NONBLOCK; + #ifdef HAVE_FD_CLOEXEC + flags = flags | FD_CLOEXEC; + #endif + if (fcntl (its->fds[0], F_SETFL, flags) < 0) + err = TRUE; + } + #endif /* HAVE_EVENTFD */ +#endif /* G_OS_WIN32 */ + + next: + if (err) { + cleanup_signaling (its); + g_free (its); + return NULL; + } + + /* finish init */ + its->data_queue = g_async_queue_new_full ((GDestroyNotify) notification_data_free); + g_mutex_init (&(its->mutex)); + +#ifdef HAVE_FORK + its->pid = getpid (); +#endif + + if (err) { + its->broken = TRUE; + itsignaler_unref (its); + return NULL; + } + +#ifdef DEBUG_NOTIFICATION + g_print ("[I] Created ITSignaler %p\n", its); +#endif + + created_objects++; +#ifndef NOBG + bg_update_stats (BG_CREATED_ITS); +#endif + return its; +} + +#ifdef G_OS_WIN32 +/** + * itsignaler_windows_get_poll_fd: + * @its: a #ITSignaler object + * + * Get the socket descriptor associated to @its. + * + * Returns: the file descriptor number, or -1 on error + */ +SOCKET +itsignaler_windows_get_poll_fd (ITSignaler *its) +{ + g_return_val_if_fail (its, -1); + return its->socks[0]; +} + +#else + +/** + * itsignaler_unix_get_poll_fd: + * @its: a #ITSignaler object + * + * Get the file descriptor associated to @its. + * + * Returns: the file descriptor number, or -1 on error + */ +int +itsignaler_unix_get_poll_fd (ITSignaler *its) +{ + g_return_val_if_fail (its, -1); + +#ifdef HAVE_EVENTFD + return its->event_fd; +#else + return its->fds[0]; +#endif +} +#endif /* G_OS_WIN32 */ + +/** + * itsignaler_push_notification: + * @its: a #ITSignaler pointer + * @data: a pointer to some data. + * @destroy_func: (nullable): a function to be called to free @data, or %NULL + * + * Use this function to push a notification. + * + * Note that @data will be passes AS-IS to the thread which calls itsignaler_pop_notification(), any memory allocation + * must be handled correctly by the caller. However, in case itsignaler_unref() is called while there are still some + * undelivered notifications, each notification's data will be freed using the @destroy_func which was specified when + * itsignaler_push_notification() was called (note that no warning of any sort will be shown if @destroy_func is %NULL + * and some notification data should have been freed). + * + * Returns: %TRUE if no error occurred + */ +gboolean +itsignaler_push_notification (ITSignaler *its, gpointer data, GDestroyNotify destroy_func) +{ + g_return_val_if_fail (its, FALSE); + g_return_val_if_fail (data, FALSE); + + if (its->broken) + return FALSE; + +#ifdef HAVE_FORK + if (unlikely (its->pid != getpid ())) + return FALSE; +#endif + +#ifdef DEBUG_NOTIFICATION_FORCE + /* force an error */ + static guint c = 0; + c++; + if (c == 4) + goto onerror; +#endif + + /* push notification to queue */ + NotificationData *nd; + nd = g_new (NotificationData, 1); + nd->data = data; + nd->destroy_func = destroy_func; + g_async_queue_lock (its->data_queue); + g_async_queue_push_unlocked (its->data_queue, nd); + g_async_queue_unlock (its->data_queue); + + /* actual notification */ +#ifdef G_OS_WIN32 + const guint8 value = 1; + ssize_t nw; + nw = send (its->socks[1], (char*) &value, sizeof (value), 0); + if (nw != sizeof (value)) + goto onerror; /* Error */ +#else + #ifdef HAVE_EVENTFD + const uint64_t inc = 1; + ssize_t nw; + nw = write (its->event_fd, &inc, sizeof (inc)); + if (nw != sizeof (inc)) + goto onerror; /* Error */ + #else + const guint8 value = 1; + ssize_t nw; + nw = write (its->fds[1], &value, sizeof (value)); + if (nw != sizeof (value)) + goto onerror; /* Error */ + #endif +#endif + + return TRUE; + + onerror: + its->broken = TRUE; + cleanup_signaling (its); + +#ifdef DEBUG_NOTIFICATION + g_print ("[I] %s(): returned FALSE\n", __FUNCTION__); + g_print ("[I] ITSignaler will not be useable anymore\n"); +#endif + return FALSE; +} + +static gpointer +itsignaler_pop_notification_non_block (ITSignaler *its) +{ + g_return_val_if_fail (its != NULL, NULL); + +#ifdef G_OS_WIN32 + guint8 value; + ssize_t nr = recv (its->socks[0], (char*) &value, sizeof (value), 0); + if (nr == -1) + return NULL; /* nothing to read */ + else + g_assert (nr == sizeof (value)); +#else + #ifdef HAVE_EVENTFD + guint64 nbnotif; + ssize_t nr = read (its->event_fd, &nbnotif, sizeof (nbnotif)); + if (nr == -1) { + return NULL; /* nothing to read */ + } + else + g_assert (nr == sizeof (nbnotif)); + nbnotif --; + + if (nbnotif > 0) { + /* some other notifications need to be processed */ + ssize_t nw; + nw = write (its->event_fd, &nbnotif, sizeof (nbnotif)); + if (nw != sizeof (nbnotif)) { + close (its->event_fd); + its->event_fd = INVALID_SOCK; + its->broken = TRUE; + } + } + #else + guint8 value; + ssize_t nr = read (its->fds[0], &value, sizeof (value)); + if (nr == -1) + return NULL; /* nothing to read */ + else + g_assert (nr == sizeof (value)); + #endif +#endif + + /* actual notification contents */ + NotificationData *nd; + g_async_queue_lock (its->data_queue); + nd = (NotificationData*) g_async_queue_pop_unlocked (its->data_queue); + g_async_queue_unlock (its->data_queue); + if (nd) { + gpointer retval; + retval = nd->data; + g_free (nd); + return retval; + } + else + return NULL; +} + +/** + * itsignaler_pop_notification: + * @its: a #ITSignaler object + * @timeout_ms: if set to %0, then the function returns immediately if there is no notification, if set to a negative value, then this function blocks until a notification becomes available, otherwise maximum number of miliseconds to wait for a notification. + * + * Use this function from the thread to be signaled, to fetch any pending notification. If no notification is available, + * then this function returns immediately %NULL. It's up to the caller to free the returned data. + * + * Returns: a pointer to some data which has been pushed by the notifying thread using itsignaler_push_notification(), or %NULL + * if no notification is present. + */ +gpointer +itsignaler_pop_notification (ITSignaler *its, gint timeout_ms) +{ + g_return_val_if_fail (its, NULL); + + if (timeout_ms == 0) + return itsignaler_pop_notification_non_block (its); + +#ifdef G_OS_WIN32 + struct timeval *timeout_ptr = NULL; + fd_set fds; + SOCKET sock; + + if (timeout_ms > 0) { + struct timeval timeout; + timeout.tv_sec = timeout_ms / 1000; + timeout.tv_usec = (timeout_ms - (timeout.tv_sec * 1000)) * 1000; + timeout_ptr = &timeout; + } + sock = itsignaler_windows_get_poll_fd (its); + FD_ZERO (&fds); + FD_SET (sock, &fds); + + int res; + res = select (1, &fds, 0, 0, timeout_ptr); + if (res == SOCKET_ERROR) + return NULL; + else if (res > 0) + return itsignaler_pop_notification_non_block (its); +#else + struct pollfd fds[1]; + fds[0].fd = itsignaler_unix_get_poll_fd (its); + fds[0].events = POLLIN; + fds[0].revents = 0; + + int res; + res = poll (fds, 1, timeout_ms); + if (res == -1) + return NULL; + else if (res > 0) { + if (fds[0].revents | POLLIN) + return itsignaler_pop_notification_non_block (its); + else + return NULL; + } +#endif + + return NULL; +} + +/* + * GSource integration + */ +typedef struct { + GSource source; + ITSignaler *its; /* reference held */ +#ifndef G_OS_WIN32 + GPollFD pollfd; +#endif +} ITSSource; + +static gboolean its_source_prepare (GSource *source, gint *timeout_); +static gboolean its_source_check (GSource *source); +static gboolean its_source_dispatch (GSource *source, GSourceFunc callback, gpointer user_data); +static void its_source_finalize (GSource *source); + +GSourceFuncs funcs = { + its_source_prepare, + its_source_check, + its_source_dispatch, + its_source_finalize, + NULL, + NULL +}; + +/** + * itsignaler_create_source: + * @its: a #ITSignaler object + * + * Create a new #GSource for @its. + * + * The source will not initially be associated with any #GMainContext and must be added to one + * with g_source_attach() before it will be executed. + * + * Returns: a new #GSource. + */ +GSource * +itsignaler_create_source (ITSignaler *its) +{ + g_return_val_if_fail (its, NULL); + + GSource *source; + ITSSource *isource; + source = g_source_new (&funcs, sizeof (ITSSource)); + isource = (ITSSource*) source; + isource->its = itsignaler_ref (its); + +#ifdef G_OS_WIN32 + SOCKET sock; + GIOChannel *channel; + sock = itsignaler_windows_get_poll_fd (its); + channel = g_io_channel_win32_new_socket (sock); + GSource *child_source; + child_source = g_io_create_watch (channel, G_IO_IN | G_IO_HUP | G_IO_ERR); + g_source_add_child_source (source, child_source); + g_source_set_dummy_callback (child_source); + g_io_channel_unref (channel); + g_source_unref (child_source); +#else + isource->pollfd.fd = itsignaler_unix_get_poll_fd (its); + isource->pollfd.events = G_IO_IN | G_IO_HUP | G_IO_ERR; + isource->pollfd.revents = 0; + g_source_add_poll (source, &(isource->pollfd)); +#endif + + return source; +} + +static gboolean +its_source_prepare (G_GNUC_UNUSED GSource *source, gint *timeout_) +{ + *timeout_ = -1; + return FALSE; +} + +static gboolean +its_source_check (GSource *source) +{ + ITSSource *isource = (ITSSource*) source; + +#ifndef G_OS_WIN32 + if (isource->pollfd.revents & G_IO_IN) + return TRUE; + + if (isource->pollfd.revents & (G_IO_HUP | G_IO_ERR)) { + g_source_remove_poll (source, &(isource->pollfd)); + isource->its->broken = TRUE; + cleanup_signaling (isource->its); + g_warning ("ITSignaler %p: ERROR HUP or ERR!\n", isource->its); + } +#endif + return FALSE; +} + +static gboolean +its_source_dispatch (GSource *source, GSourceFunc callback, gpointer user_data) +{ + ITSSource *isource = (ITSSource*) source; + ITSignalerFunc func; + func = (ITSignalerFunc) callback; + + gboolean retval; + itsignaler_ref (isource->its); + retval = func (user_data); + itsignaler_unref (isource->its); + return retval; +} + +static +void its_source_finalize (GSource *source) +{ + ITSSource *isource = (ITSSource*) source; + + itsignaler_unref (isource->its); +} + +/** + * itsignaler_add: + * @its: a #ITSignaler object + * @context: (nullable): a GMainContext (if %NULL, the default context will be used). + * @func: callback function to be called when a notification is ready + * @data: data to pass to @func + * @notify: (nullable): a function to call when data is no longer in use, or NULL. + * + * Have @its call @func (with @data) in the context of @context. Remove using itsignaler_remove(). This function + * is similar to itsignaler_create_source() but is packaged for easier usage. + * + * Use itsignaler_remove() to undo this function. + * + * Returns: the ID (greater than 0) for the source within the #GMainContext. + */ +guint +itsignaler_add (ITSignaler *its, GMainContext *context, ITSignalerFunc func, gpointer data, GDestroyNotify notify) +{ + GSource *source; + guint id; + + g_return_val_if_fail (its, 0); + + source = itsignaler_create_source (its); + if (!source) + return 0; + + g_source_set_callback (source, G_SOURCE_FUNC (func), data, notify); + id = g_source_attach (source, context); + g_source_unref (source); + + return id; +} + +/** + * itsignaler_remove: + * @its: a #ITSignaler object + * @context: (nullable): a GMainContext (if NULL, the default context will be used). + * @id: the ID of the source as returned by itsignaler_add() + * + * Does the reverse of itsignaler_add(). + * + * Returns: %TRUE if the source has been removed + */ +gboolean +itsignaler_remove (G_GNUC_UNUSED ITSignaler *its, GMainContext *context, guint id) +{ + GSource *source; + source = g_main_context_find_source_by_id (context, id); + if (source) { + g_source_destroy (source); + return TRUE; + } + else + return FALSE; +} diff --git a/.flatpak-builder/cache/objects/3a/866b15ea0cc581821ed41e7493dd70251e11a252d8424633fc5496afc19960.commit b/.flatpak-builder/cache/objects/3a/866b15ea0cc581821ed41e7493dd70251e11a252d8424633fc5496afc19960.commit new file mode 100644 index 0000000..1360bc9 Binary files /dev/null and b/.flatpak-builder/cache/objects/3a/866b15ea0cc581821ed41e7493dd70251e11a252d8424633fc5496afc19960.commit differ diff --git a/.flatpak-builder/cache/objects/3a/f85e97f76bcd0bbe1d5e669fe0dff35778fc7774bdd1e8ba9ee415f950283c.file b/.flatpak-builder/cache/objects/3a/f85e97f76bcd0bbe1d5e669fe0dff35778fc7774bdd1e8ba9ee415f950283c.file new file mode 100644 index 0000000..4c31ab6 --- /dev/null +++ b/.flatpak-builder/cache/objects/3a/f85e97f76bcd0bbe1d5e669fe0dff35778fc7774bdd1e8ba9ee415f950283c.file @@ -0,0 +1,219 @@ +/* + * Copyright (C) 2006 - 2007 Murray Cumming + * Copyright (C) 2006 - 2012 Vivien Malerba + * Copyright (C) 2018 Daniel Espinosa + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + + +#ifndef __GDA_DATA_PROXY_H_ +#define __GDA_DATA_PROXY_H_ + +#include "gda-decl.h" +#include +#include +#include + + +G_BEGIN_DECLS + +#define GDA_TYPE_DATA_PROXY (gda_data_proxy_get_type()) + +G_DECLARE_DERIVABLE_TYPE(GdaDataProxy, gda_data_proxy, GDA, DATA_PROXY, GObject) + +/* error reporting */ +extern GQuark gda_data_proxy_error_quark (void); +#define GDA_DATA_PROXY_ERROR gda_data_proxy_error_quark () + +typedef enum { + GDA_DATA_PROXY_COMMIT_ERROR, + GDA_DATA_PROXY_COMMIT_CANCELLED, + GDA_DATA_PROXY_READ_ONLY_VALUE, + GDA_DATA_PROXY_READ_ONLY_ROW, + GDA_DATA_PROXY_FILTER_ERROR +} GdaDataProxyError; + +/* struct for the object's class */ +struct _GdaDataProxyClass +{ + GObjectClass parent_class; + + void (* row_delete_changed) (GdaDataProxy *proxy, gint row, gboolean to_be_deleted); + + void (* sample_size_changed) (GdaDataProxy *proxy, gint sample_size); + void (* sample_changed) (GdaDataProxy *proxy, gint sample_start, gint sample_end); + + GError *(* validate_row_changes) (GdaDataProxy *proxy, gint row, gint proxied_row); + void (* row_changes_applied) (GdaDataProxy *proxy, gint row, gint proxied_row); + + void (* filter_changed) (GdaDataProxy *proxy); + + /*< private >*/ + /* Padding for future expansion */ + void (*_gda_reserved1) (void); + void (*_gda_reserved2) (void); + void (*_gda_reserved3) (void); + void (*_gda_reserved4) (void); +}; + +/** + * SECTION:gda-data-proxy + * @short_description: Proxy to hold modifications for any #GdaDataModel, providing the #GdaDataModel interface itself + * @title: GdaDataProxy + * @stability: Stable + * @see_also: #GdaDataModel + * + * This object stores modifications to be made to a #GdaDataModel object which is proxied until the modifications are actually + * written to the #GdaDataModel, it can also filter the proxied data model to show only a subset (a defined number of continuous + * rows or by a filter to apply). + * + * Specifically, for a proxied data model having nb_cols columns and nb_rows rows, + * the #GdaDataProxy object has the following attributes: + * + * + * 2 * nb_cols columns: + * + * the first (>= 0) nb_cols columns are the current values stored in the + * proxy (which correspond to the values of the proxied data model if the considered row has not been + * changed). The associated values are writable. + * the last nb_cols columns are the values stored in the proxied data model, + * at column col - nb_cols + * + * + * + * a variable number of rows depending on the following attributes: + * + * if the proxy is configured to have an empty row as the first row + * if the proxy only displays parts of the proxied data model + * if new rows have been added to the proxy + * + * + * Any #GdaDataModelIter iterator created will only make appear the colmuns as present in the proxied + * data model, not any of the other columns + * + * This situation is illustrated in the following schema, where there is a direct mapping between the proxy's + * rows and the proxied data model's rows: + * + * + * + * + * + * GdaDataProxy's values mapping regarding the proxied data model + * + * + * + * Note that unless explicitly mentioned, the columns are read-only. + * + * The following figures illustrate row mappings between the data proxy and the proxied data model in + * several situations (which can be combined, but are shown alone for simplicity): + * + * situation where rows 1 and 5 have been marked as deleted from the data proxy, using + * gda_data_proxy_delete() method, the data + * proxy has 2 rows less than the proxied data model: + * + * + * + * + * + * GdaDataProxy with 2 rows marked as deleted + * + * + * + * situation where the data proxy only shows a sample of the proxied data model + * at any given time, using the + * gda_data_proxy_set_sample_size() method + * (the sample here is 4 rows wide, and starts at row 3): + * + * + * + * + * + * GdaDataProxy with a sample size of 4 + * + * + * + * situation where the data proxy shows a row of NULL values, using the + * "prepend-null-entry" property: + * + * + * + * + * + * GdaDataProxy with an extra row of NULL values + * + * + * + * situation where a row has been added to the data proxy, using for example the + * gda_data_model_append_row() method: + * + * + * + * + * + * GdaDataProxy where a row has been added + * + * + * + * + * + * The #GdaDataProxy objects are thread safe, which means any proxy object can be used from + * any thread at the same time as they implement their own locking mechanisms. + */ + +GObject *gda_data_proxy_new (GdaDataModel *model); +GdaDataProxy *gda_data_proxy_new_with_data_model (GdaDataModel *model); + +GdaDataModel *gda_data_proxy_get_proxied_model (GdaDataProxy *proxy); +gint gda_data_proxy_get_proxied_model_n_cols (GdaDataProxy *proxy); +gint gda_data_proxy_get_proxied_model_n_rows (GdaDataProxy *proxy); +gboolean gda_data_proxy_is_read_only (GdaDataProxy *proxy); +GSList *gda_data_proxy_get_values (GdaDataProxy *proxy, gint proxy_row, + gint *cols_index, gint n_cols); +GdaValueAttribute gda_data_proxy_get_value_attributes (GdaDataProxy *proxy, gint proxy_row, gint col); +void gda_data_proxy_alter_value_attributes (GdaDataProxy *proxy, gint proxy_row, gint col, GdaValueAttribute alter_flags); +gint gda_data_proxy_get_proxied_model_row (GdaDataProxy *proxy, gint proxy_row); + +void gda_data_proxy_delete (GdaDataProxy *proxy, gint proxy_row); +void gda_data_proxy_undelete (GdaDataProxy *proxy, gint proxy_row); +gboolean gda_data_proxy_row_is_deleted (GdaDataProxy *proxy, gint proxy_row); +gboolean gda_data_proxy_row_is_inserted (GdaDataProxy *proxy, gint proxy_row); + +gboolean gda_data_proxy_row_has_changed (GdaDataProxy *proxy, gint proxy_row); +gboolean gda_data_proxy_has_changed (GdaDataProxy *proxy); +gint gda_data_proxy_get_n_new_rows (GdaDataProxy *proxy); +gint gda_data_proxy_get_n_modified_rows (GdaDataProxy *proxy); + +gboolean gda_data_proxy_apply_row_changes (GdaDataProxy *proxy, gint proxy_row, GError **error); +void gda_data_proxy_cancel_row_changes (GdaDataProxy *proxy, gint proxy_row, gint col); + +gboolean gda_data_proxy_apply_all_changes (GdaDataProxy *proxy, GError **error); +gboolean gda_data_proxy_cancel_all_changes (GdaDataProxy *proxy); + +void gda_data_proxy_set_sample_size (GdaDataProxy *proxy, gint sample_size); +gint gda_data_proxy_get_sample_size (GdaDataProxy *proxy); +void gda_data_proxy_set_sample_start (GdaDataProxy *proxy, gint sample_start); +gint gda_data_proxy_get_sample_start (GdaDataProxy *proxy); +gint gda_data_proxy_get_sample_end (GdaDataProxy *proxy); + +gboolean gda_data_proxy_set_filter_expr (GdaDataProxy *proxy, const gchar *filter_expr, GError **error); +const gchar *gda_data_proxy_get_filter_expr (GdaDataProxy *proxy); +gboolean gda_data_proxy_set_ordering_column (GdaDataProxy *proxy, gint col, GError **error); +gint gda_data_proxy_get_filtered_n_rows (GdaDataProxy *proxy); + +G_END_DECLS + +#endif diff --git a/.flatpak-builder/cache/objects/3b/b2cca34c9b51265aa9dbb7778bc41d4ab30da1726dba9d00aa1a2120c7e9e9.file b/.flatpak-builder/cache/objects/3b/b2cca34c9b51265aa9dbb7778bc41d4ab30da1726dba9d00aa1a2120c7e9e9.file new file mode 100755 index 0000000..fc5e46f Binary files /dev/null and b/.flatpak-builder/cache/objects/3b/b2cca34c9b51265aa9dbb7778bc41d4ab30da1726dba9d00aa1a2120c7e9e9.file differ diff --git a/.flatpak-builder/cache/objects/3b/b789aa985183ec31394ab3cf5c1a720d5690395c0d0dba0bb0366efe3395b5.file b/.flatpak-builder/cache/objects/3b/b789aa985183ec31394ab3cf5c1a720d5690395c0d0dba0bb0366efe3395b5.file new file mode 100644 index 0000000..7d931b7 Binary files /dev/null and b/.flatpak-builder/cache/objects/3b/b789aa985183ec31394ab3cf5c1a720d5690395c0d0dba0bb0366efe3395b5.file differ diff --git a/.flatpak-builder/cache/objects/3c/0a11128f82a1a8942fa7288fbf401e23dbb16912b9863e2377c95beb8559dc.file b/.flatpak-builder/cache/objects/3c/0a11128f82a1a8942fa7288fbf401e23dbb16912b9863e2377c95beb8559dc.file new file mode 100644 index 0000000..b2d579b --- /dev/null +++ b/.flatpak-builder/cache/objects/3c/0a11128f82a1a8942fa7288fbf401e23dbb16912b9863e2377c95beb8559dc.file @@ -0,0 +1,100 @@ +# xml_reader.py +# +# Copyright 2021 James Westman +# +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation; either version 3 of the +# License, or (at your option) any later version. +# +# This file is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program. If not, see . +# +# SPDX-License-Identifier: LGPL-3.0-or-later + + +from collections import defaultdict +from functools import cached_property +import typing as T +from xml import sax + + +# To speed up parsing, we ignore all tags except these +PARSE_GIR = set( + [ + "repository", + "namespace", + "class", + "interface", + "property", + "glib:signal", + "include", + "implements", + "type", + "parameter", + "parameters", + "enumeration", + "member", + "bitfield", + ] +) + + +class Element: + def __init__(self, tag: str, attrs: T.Dict[str, str]): + self.tag = tag + self.attrs = attrs + self.children: T.List["Element"] = [] + self.cdata_chunks: T.List[str] = [] + + @cached_property + def cdata(self): + return "".join(self.cdata_chunks) + + def get_elements(self, name: str) -> T.List["Element"]: + return [child for child in self.children if child.tag == name] + + def __getitem__(self, key: str): + return self.attrs.get(key) + + +class Handler(sax.handler.ContentHandler): + def __init__(self): + self.root = None + self.stack = [] + + def startElement(self, name, attrs): + element = Element(name, attrs.copy()) + + if len(self.stack): + last = self.stack[-1] + last.children.append(element) + else: + self.root = element + + self.stack.append(element) + + def endElement(self, name): + self.stack.pop() + + def characters(self, content): + self.stack[-1].cdata_chunks.append(content) + + +def parse(filename): + parser = sax.make_parser() + handler = Handler() + parser.setContentHandler(handler) + parser.parse(filename) + return handler.root + + +def parse_string(xml): + handler = Handler() + parser = sax.parseString(xml, handler) + return handler.root diff --git a/.flatpak-builder/cache/objects/3c/37e3322f827e4743fd098255b22e962feb85be2bda36f6d090b92b02ad075f.dirtree b/.flatpak-builder/cache/objects/3c/37e3322f827e4743fd098255b22e962feb85be2bda36f6d090b92b02ad075f.dirtree new file mode 100644 index 0000000..5cc0c55 Binary files /dev/null and b/.flatpak-builder/cache/objects/3c/37e3322f827e4743fd098255b22e962feb85be2bda36f6d090b92b02ad075f.dirtree differ diff --git a/.flatpak-builder/cache/objects/3d/20dd70718b8ee8c46a89b62e61d9f5e92d2440d62348ce496fba65cfb5b2cd.dirtree b/.flatpak-builder/cache/objects/3d/20dd70718b8ee8c46a89b62e61d9f5e92d2440d62348ce496fba65cfb5b2cd.dirtree new file mode 100644 index 0000000..af76255 Binary files /dev/null and b/.flatpak-builder/cache/objects/3d/20dd70718b8ee8c46a89b62e61d9f5e92d2440d62348ce496fba65cfb5b2cd.dirtree differ diff --git a/.flatpak-builder/cache/objects/3d/4553529b1474d5a4b2ce180ecaae21a6e310eef1b2b4168fad8e8a33cbc85e.dirtree b/.flatpak-builder/cache/objects/3d/4553529b1474d5a4b2ce180ecaae21a6e310eef1b2b4168fad8e8a33cbc85e.dirtree new file mode 100644 index 0000000..747f134 Binary files /dev/null and b/.flatpak-builder/cache/objects/3d/4553529b1474d5a4b2ce180ecaae21a6e310eef1b2b4168fad8e8a33cbc85e.dirtree differ diff --git a/.flatpak-builder/cache/objects/3d/67e040c7c29ceaa4e547740c570c645f326a27c0579733bc6892a9aabae200.commit b/.flatpak-builder/cache/objects/3d/67e040c7c29ceaa4e547740c570c645f326a27c0579733bc6892a9aabae200.commit new file mode 100644 index 0000000..7358ac2 Binary files /dev/null and b/.flatpak-builder/cache/objects/3d/67e040c7c29ceaa4e547740c570c645f326a27c0579733bc6892a9aabae200.commit differ diff --git a/.flatpak-builder/cache/objects/3e/72d8a777a5696c64813b824b57ada460dfec6649bf7bcd0397c1f228a8edb9.dirtree b/.flatpak-builder/cache/objects/3e/72d8a777a5696c64813b824b57ada460dfec6649bf7bcd0397c1f228a8edb9.dirtree new file mode 100644 index 0000000..3f4e9b1 Binary files /dev/null and b/.flatpak-builder/cache/objects/3e/72d8a777a5696c64813b824b57ada460dfec6649bf7bcd0397c1f228a8edb9.dirtree differ diff --git a/.flatpak-builder/cache/objects/3e/86000257be09ac41ed467ac5b11cde619929b44f17ffbe0c5ab5f9f1aefe36.file b/.flatpak-builder/cache/objects/3e/86000257be09ac41ed467ac5b11cde619929b44f17ffbe0c5ab5f9f1aefe36.file new file mode 100644 index 0000000..3ce6d1f --- /dev/null +++ b/.flatpak-builder/cache/objects/3e/86000257be09ac41ed467ac5b11cde619929b44f17ffbe0c5ab5f9f1aefe36.file @@ -0,0 +1,2107 @@ +/* + * Copyright (C) 2006 - 2014 Murray Cumming + * Copyright (C) 2006 - 2014 Vivien Malerba + * Copyright (C) 2007 Brecht Sanders + * Copyright (C) 2009 Bas Driessen + * Copyright (C) 2010 David King + * Copyright (C) 2010 Jonh Wendell + * Copyright (C) 2013, 2018-2019 Daniel Espinosa + * Copyright (C) 2013 Miguel Angel Cabrera Moya + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +#define G_LOG_DOMAIN "GDA-data-model-import" + +#include "gda-data-model-import.h" +#include +#ifndef G_OS_WIN32 + #include +#else + #include +#endif +#include +#include +#include +#include +#include +#ifdef HAVE_LOCALE_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* For gda_data_model_add_data_from_xml_node() */ +#include +#include + +#include +#include "csv.h" + +typedef enum { + FORMAT_XML_DATA, + FORMAT_CSV, + FORMAT_XML_NODE +} InternalFormat; + +typedef struct { + gint nb_cols; + GdaDataModelImport *model; + + gint field_next_col; + GSList *fields; /* list of GValue */ +} CsvParserData; + + +/* GdaDataModel interface */ +static void gda_data_model_import_data_model_init (GdaDataModelInterface *iface); +static gint gda_data_model_import_get_n_rows (GdaDataModel *model); +static gint gda_data_model_import_get_n_columns (GdaDataModel *model); +static GdaColumn *gda_data_model_import_describe_column (GdaDataModel *model, gint col); +static GdaDataModelAccessFlags gda_data_model_import_get_access_flags(GdaDataModel *model); +static const GValue *gda_data_model_import_get_value_at (GdaDataModel *model, gint col, gint row, GError **error); +static GdaValueAttribute gda_data_model_import_get_attributes_at (GdaDataModel *model, gint col, gint row); +static GdaDataModelIter *gda_data_model_import_create_iter (GdaDataModel *model); +static gboolean gda_data_model_import_iter_next (GdaDataModel *model, GdaDataModelIter *iter); +static gboolean gda_data_model_import_iter_prev (GdaDataModel *model, GdaDataModelIter *iter); + + +typedef struct { + /* data access specific variables */ + gboolean is_mapped; /* TRUE if a file has been mapped */ + union { + /* mapped file */ + struct { + gchar *filename; + int fd; + gpointer start; + size_t length; + } mapped; + + /* data as a string */ + gchar *string; + } src; + gchar *data_start; + guint data_length; + + /* extraction format specific variables */ + InternalFormat format; + union { + struct { + struct csv_parser *parser; + gchar *encoding; + gchar delimiter; + gchar quote; + + gboolean ignore_first_line; + GArray *rows_read; + + gchar *start_pos; + gboolean initializing; + guint text_line; /* line number of the current last line */ + + CsvParserData *pdata; + } csv; + struct { + xmlTextReaderPtr reader; + } xml; + struct { + xmlNodePtr node; + } node; + } extract; + GSList *cursor_values; /* list of GValues for the current row + * (might be shorter than the number of columns in the data model)*/ + + /* general data */ + gboolean random_access; + GSList *columns; + GdaDataModel *random_access_model; /* data is imported into this model if random access is required */ + GSList *errors; /* list of errors as GError structures */ + GdaSet *options; + + gint iter_row; + gboolean init_done; + gboolean strict; +} GdaDataModelImportPrivate; + +G_DEFINE_TYPE_WITH_CODE (GdaDataModelImport, gda_data_model_import, G_TYPE_OBJECT, + G_ADD_PRIVATE (GdaDataModelImport) + G_IMPLEMENT_INTERFACE (GDA_TYPE_DATA_MODEL, gda_data_model_import_data_model_init)) + +/* properties */ +enum +{ + PROP_0, + PROP_RANDOM_ACCESS, + PROP_FILENAME, + PROP_DATA_STRING, + PROP_XML_NODE, + PROP_OPTIONS, + PROP_STRICT +}; + +#define CSV_TITLE_BUFFER_SIZE 255 +#define CSV_DATA_BUFFER_SIZE 2048 + +static GObject *gda_data_model_import_constructor (GType type, + guint n_construct_properties, + GObjectConstructParam *construct_properties); +static void gda_data_model_import_dispose (GObject *object); +static void gda_data_model_import_finalize (GObject *object); + +static void gda_data_model_import_set_property (GObject *object, + guint param_id, + const GValue *value, + GParamSpec *pspec); +static void gda_data_model_import_get_property (GObject *object, + guint param_id, + GValue *value, + GParamSpec *pspec); + +static const gchar *find_option_as_string (GdaDataModelImport *model, const gchar *pname); +static gboolean find_option_as_boolean (GdaDataModelImport *model, const gchar *pname, gboolean defaults); +static void add_error (GdaDataModelImport *model, const gchar *err); + +G_DEFINE_TYPE(GdaDataModelImportIter, gda_data_model_import_iter, GDA_TYPE_DATA_MODEL_ITER) + +static gboolean gda_data_model_import_iter_move_next (GdaDataModelIter *iter); +static gboolean gda_data_model_import_iter_move_prev (GdaDataModelIter *iter); + +static void gda_data_model_import_iter_init (GdaDataModelImportIter *iter) {} +static void gda_data_model_import_iter_class_init (GdaDataModelImportIterClass *klass) { + GdaDataModelIterClass *model_iter_class = GDA_DATA_MODEL_ITER_CLASS (klass); + model_iter_class->move_next = gda_data_model_import_iter_move_next; + model_iter_class->move_prev = gda_data_model_import_iter_move_prev; +} + +static gboolean +gda_data_model_import_iter_move_next (GdaDataModelIter *iter) { + GdaDataModel *model; + g_object_get (G_OBJECT (iter), "data-model", &model, NULL); + g_return_val_if_fail (model, FALSE); + return gda_data_model_import_iter_next (model, iter); +} + +static gboolean +gda_data_model_import_iter_move_prev (GdaDataModelIter *iter) { + GdaDataModel *model; + g_object_get (G_OBJECT (iter), "data-model", &model, NULL); + g_return_val_if_fail (model, FALSE); + return gda_data_model_import_iter_prev (model, iter); +} + + +static void +gda_data_model_import_class_init (GdaDataModelImportClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + /* properties */ + object_class->set_property = gda_data_model_import_set_property; + object_class->get_property = gda_data_model_import_get_property; + /** + * GdaDataModelImport:random-access: + * + * Defines if the data model will be accessed randomly or through a cursor. If set to %FALSE, + * access will have to be done using a cursor. + */ + g_object_class_install_property (object_class, PROP_RANDOM_ACCESS, + g_param_spec_boolean ("random-access", NULL, "Random access to the data model " + "is possible", + FALSE, + G_PARAM_READABLE | G_PARAM_WRITABLE | + G_PARAM_CONSTRUCT_ONLY)); + /** + * GdaDataModelImport:filename: + * + * Name of the file to import. + */ + g_object_class_install_property (object_class, PROP_FILENAME, + g_param_spec_string ("filename", NULL, "File to import", NULL, + G_PARAM_READABLE | G_PARAM_WRITABLE | + G_PARAM_CONSTRUCT_ONLY)); + /** + * GdaDataModelImport:data-string: + * + * Data to import, as a string. + */ + g_object_class_install_property (object_class, PROP_DATA_STRING, + g_param_spec_string ("data-string", NULL, "String to import", NULL, + G_PARAM_READABLE | G_PARAM_WRITABLE | + G_PARAM_CONSTRUCT_ONLY)); + /** + * GdaDataModelImport:xml-node: + * + * Data to import, as a pointer to an XML node (a #xmlNodePtr). + */ + g_object_class_install_property (object_class, PROP_XML_NODE, + g_param_spec_pointer ("xml-node", NULL, "XML node to import from", + G_PARAM_READABLE | G_PARAM_WRITABLE | + G_PARAM_CONSTRUCT_ONLY)); + /** + * GdaDataModelImport:options: + * + * Data model options. + */ + g_object_class_install_property (object_class, PROP_OPTIONS, + g_param_spec_object ("options", NULL, "Options to configure the import", + GDA_TYPE_SET, + G_PARAM_READABLE | G_PARAM_WRITABLE | + G_PARAM_CONSTRUCT_ONLY)); + /** + * GdaDataModelImport:strict: + * + * Defines the behaviour in case the imported data contains recoverable errors (usually too + * many or too few data per row). If set to %TRUE, an error will be reported and the import + * will stop, and if set to %FALSE, then the error will be reported but the import will not stop. + * + * Since: 4.2.1 + */ + g_object_class_install_property (object_class, PROP_STRICT, + g_param_spec_boolean ("strict", NULL, "Consider missing or too much values an error", + FALSE, + G_PARAM_READABLE | G_PARAM_WRITABLE | + G_PARAM_CONSTRUCT)); + + /* virtual functions */ + object_class->constructor = gda_data_model_import_constructor; + object_class->dispose = gda_data_model_import_dispose; + object_class->finalize = gda_data_model_import_finalize; +} + +static void +gda_data_model_import_data_model_init (GdaDataModelInterface *iface) +{ + iface->get_n_rows = gda_data_model_import_get_n_rows; + iface->get_n_columns = gda_data_model_import_get_n_columns; + iface->describe_column = gda_data_model_import_describe_column; + iface->get_access_flags = gda_data_model_import_get_access_flags; + iface->get_value_at = gda_data_model_import_get_value_at; + iface->get_attributes_at = gda_data_model_import_get_attributes_at; + + iface->create_iter = gda_data_model_import_create_iter; + + iface->set_value_at = NULL; + iface->set_values = NULL; + iface->append_values = NULL; + iface->append_row = NULL; + iface->remove_row = NULL; + iface->find_row = NULL; + + iface->freeze = NULL; + iface->thaw = NULL; + iface->get_notify = NULL; + iface->send_hint = NULL; +} + +static void +gda_data_model_import_init (GdaDataModelImport *model) +{ + GdaDataModelImportPrivate *priv = gda_data_model_import_get_instance_private (model); + priv->random_access = FALSE; /* cursor mode is the default */ + priv->columns = NULL; + priv->random_access_model = NULL; + priv->errors = NULL; + priv->cursor_values = NULL; + + priv->is_mapped = TRUE; + priv->src.mapped.filename = NULL; + priv->src.mapped.fd = -1; + priv->src.mapped.start = NULL; + + priv->format = FORMAT_CSV; + priv->data_start = NULL; + priv->data_length = 0; + + priv->iter_row = -1; + priv->init_done = FALSE; + priv->strict = FALSE; +} + +static void init_csv_import (GdaDataModelImport *model); +static void init_xml_import (GdaDataModelImport *model); +static void init_node_import (GdaDataModelImport *model); + +static GObject * +gda_data_model_import_constructor (GType type, + guint n_construct_properties, + GObjectConstructParam *construct_properties) +{ + GObject *object; + + /* construct parent */ + object = G_OBJECT_CLASS (gda_data_model_import_parent_class)->constructor (type, + n_construct_properties, + construct_properties); + + /* parse construct properties */ + GdaDataModelImport *model; + guint i; + model = GDA_DATA_MODEL_IMPORT (object); + GdaDataModelImportPrivate *priv = gda_data_model_import_get_instance_private (model); + for (i = 0; i< n_construct_properties; i++) { + GObjectConstructParam *prop = &(construct_properties[i]); + if (!strcmp (g_param_spec_get_name (prop->pspec), "random-access")) { + priv->random_access = g_value_get_boolean (prop->value); + if (priv->format == FORMAT_XML_NODE) + priv->random_access = TRUE; + } + else if (!strcmp (g_param_spec_get_name (prop->pspec), "filename")) { + const gchar *string; + string = g_value_get_string (prop->value); + if (!string) + continue; + + priv->is_mapped = TRUE; + priv->src.mapped.filename = g_strdup (g_value_get_string (prop->value)); + + /* file opening */ + priv->src.mapped.fd = open (priv->src.mapped.filename, O_RDONLY); /* Flawfinder: ignore */ + if (priv->src.mapped.fd < 0) { + /* error */ + add_error (model, strerror(errno)); + continue; + } + + /* file mmaping */ + struct stat _stat; + + if (fstat (priv->src.mapped.fd, &_stat) < 0) { + /* error */ + add_error (model, strerror(errno)); + continue; + } + priv->src.mapped.length = _stat.st_size; +#ifndef G_OS_WIN32 + priv->src.mapped.start = mmap (NULL, priv->src.mapped.length, + PROT_READ, MAP_PRIVATE, + priv->src.mapped.fd, 0); + if (priv->src.mapped.start == MAP_FAILED) { + /* error */ + add_error (model, strerror(errno)); + priv->src.mapped.start = NULL; + continue; + } +#else + HANDLE hFile = CreateFile (priv->src.mapped.filename, + GENERIC_READ, + FILE_SHARE_READ, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL); + if (!hFile) { + LPVOID lpMsgBuf; + DWORD dw = GetLastError(); + FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + dw, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPTSTR) &lpMsgBuf, + 0, NULL); + add_error (model, (gchar *)lpMsgBuf); + continue; + } + HANDLE view = CreateFileMapping(hFile, + NULL, PAGE_READONLY|SEC_COMMIT, 0,0 , NULL); + if (!view) { + /* error */ + LPVOID lpMsgBuf; + DWORD dw = GetLastError(); + FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + dw, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPTSTR) &lpMsgBuf, + 0, NULL); + add_error (model, (gchar *)lpMsgBuf); + continue; + } + priv->src.mapped.start = MapViewOfFile(view, FILE_MAP_READ, 0, 0, + priv->src.mapped.length); + if (!priv->src.mapped.start) { + /* error */ + LPVOID lpMsgBuf; + DWORD dw = GetLastError(); + FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + dw, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPTSTR) &lpMsgBuf, + 0, NULL); + add_error (model, (gchar *)lpMsgBuf); + continue; + } +#endif + priv->data_start = priv->src.mapped.start; + priv->data_length = priv->src.mapped.length; + } + else if (!strcmp (g_param_spec_get_name (prop->pspec), "data-string")) { + const gchar *string; + string = g_value_get_string (prop->value); + if (!string) + continue; + priv->is_mapped = FALSE; + priv->src.string = g_strdup (g_value_get_string (prop->value)); + priv->data_start = priv->src.string; + priv->data_length = strlen (priv->src.string); + } + else if (!strcmp (g_param_spec_get_name (prop->pspec), "xml-node")) { + gpointer data = g_value_get_pointer (prop->value); + if (!data) + continue; + priv->format = FORMAT_XML_NODE; + priv->extract.node.node = data; + } + else if (!strcmp (g_param_spec_get_name (prop->pspec), "options")) { + if (priv->options) + g_object_unref(priv->options); + + priv->options = g_value_get_object (prop->value); + if (priv->options) { + if (!GDA_IS_SET (priv->options)) { + g_warning (_("\"options\" property is not a GdaSet object")); + priv->options = NULL; + } + else + g_object_ref (priv->options); + } + } + else if (!strcmp (g_param_spec_get_name (prop->pspec), "strict")) { + priv->strict = g_value_get_boolean (prop->value); + } + } + + if (priv->errors) + return object; + + /* finish construction */ + /* determine the real kind of data (CVS text of XML) */ + if (priv->format != FORMAT_XML_NODE + && priv->data_start) { + if (!strncmp (priv->data_start, "format = FORMAT_XML_DATA; + else + priv->format = FORMAT_CSV; + } + + /* analyze common options and init */ + if (! priv->init_done) { + priv->init_done = TRUE; + switch (priv->format) { + case FORMAT_XML_DATA: + init_xml_import (model); + break; + + case FORMAT_CSV: + priv->extract.csv.quote = '"'; + if (priv->options) { + const gchar *option; + option = find_option_as_string (model, "ENCODING"); + if (option) + priv->extract.csv.encoding = g_strdup (option); + option = find_option_as_string (model, "SEPARATOR"); + if (option) + priv->extract.csv.delimiter = *option; + priv->extract.csv.quote = '"'; + option = find_option_as_string (model, "QUOTE"); + if (option) + priv->extract.csv.quote = *option; + } + init_csv_import (model); + break; + + case FORMAT_XML_NODE: + priv->random_access = TRUE; + init_node_import (model); + break; + default: + g_assert_not_reached (); + } + + /* for random access, create a new GdaDataModelArray model and copy the contents + from this model */ + if (priv->random_access && priv->columns && !priv->random_access_model) { + GdaDataModel *ramodel; + + ramodel = gda_data_access_wrapper_new ((GdaDataModel *) model); + priv->random_access_model = ramodel; + } + } + + return object; +} + + +static void +csv_free_stored_rows (GdaDataModelImport *model) +{ + GdaDataModelImportPrivate *priv = gda_data_model_import_get_instance_private (model); + gsize i; + g_assert (priv->format == FORMAT_CSV); + for (i = 0; i < priv->extract.csv.rows_read->len; i++) { + GSList *list = g_array_index (priv->extract.csv.rows_read, + GSList *, i); + g_slist_free_full (list, (GDestroyNotify) gda_value_free); + } + + if (priv->extract.csv.pdata) { + if (priv->extract.csv.pdata->fields) { + g_slist_free_full (priv->extract.csv.pdata->fields, (GDestroyNotify) gda_value_free); + } + g_free (priv->extract.csv.pdata); + } + + g_array_free (priv->extract.csv.rows_read, FALSE); + priv->extract.csv.rows_read = NULL; +} + +static void +gda_data_model_import_dispose (GObject *object) +{ + GdaDataModelImport *model = (GdaDataModelImport *) object; + + g_return_if_fail (GDA_IS_DATA_MODEL_IMPORT (model)); + GdaDataModelImportPrivate *priv = gda_data_model_import_get_instance_private (model); + + /* free memory */ + if (priv->options) { + g_object_unref (priv->options); + priv->options = NULL; + } + + if (priv->columns) { + g_slist_free_full (priv->columns, (GDestroyNotify) g_object_unref); + priv->columns = NULL; + } + + /* data access mem free */ + if (priv->is_mapped) { + if (priv->src.mapped.start) { +#ifndef G_OS_WIN32 + munmap (priv->src.mapped.start, priv->src.mapped.length); +#else + UnmapViewOfFile (priv->src.mapped.start); +#endif + priv->src.mapped.start = NULL; + } + + g_free (priv->src.mapped.filename); + if (priv->src.mapped.fd >= 0) { + close (priv->src.mapped.fd); + priv->src.mapped.fd = -1; + } + } + else { + g_free (priv->src.string); + priv->src.string = NULL; + } + + /* extraction data free */ + switch (priv->format) { + case FORMAT_XML_DATA: + if (priv->extract.xml.reader) { + xmlFreeTextReader (priv->extract.xml.reader); + priv->extract.xml.reader = NULL; + } + break; + case FORMAT_CSV: + if (priv->extract.csv.parser) { + csv_fini (priv->extract.csv.parser, NULL, NULL, NULL); + priv->extract.csv.parser = NULL; + } + if (priv->extract.csv.rows_read) + csv_free_stored_rows (model); + if (priv->extract.csv.encoding) { + g_free (priv->extract.csv.encoding); + priv->extract.csv.encoding = NULL; + } + break; + case FORMAT_XML_NODE: + break; + default: + g_assert_not_reached (); + break; + } + + /* random access model free */ + if (priv->random_access_model) { + g_object_unref (priv->random_access_model); + priv->random_access_model = NULL; + } + + /* chain to parent class */ + G_OBJECT_CLASS (gda_data_model_import_parent_class)->dispose (object); +} + +static void +gda_data_model_import_finalize (GObject *object) +{ + GdaDataModelImport *model = (GdaDataModelImport *) object; + + g_return_if_fail (GDA_IS_DATA_MODEL_IMPORT (model)); + GdaDataModelImportPrivate *priv = gda_data_model_import_get_instance_private (model); + + /* free memory */ + if (priv->errors) { + g_slist_free_full (priv->errors, (GDestroyNotify) g_error_free); + priv->errors = NULL; + } + + if (priv->cursor_values) { + g_slist_free_full (priv->cursor_values, (GDestroyNotify) gda_value_free); + priv->cursor_values = NULL; + } + + + /* chain to parent class */ + G_OBJECT_CLASS (gda_data_model_import_parent_class)->finalize (object); +} + + +static const gchar * +find_option_as_string (GdaDataModelImport *model, const gchar *pname) +{ + GdaDataModelImportPrivate *priv = gda_data_model_import_get_instance_private (model); + const GValue *value; + + value = gda_set_get_holder_value (priv->options, pname); + if (value && !gda_value_is_null ((GValue *) value)) { + if (!gda_value_isa ((GValue *) value, G_TYPE_STRING)) + g_warning (_("The %s option must hold a string value, ignored."), pname); + else + return g_value_get_string ((GValue *) value); + } + return NULL; +} + +static gboolean +find_option_as_boolean (GdaDataModelImport *model, const gchar *pname, gboolean defaults) +{ + GdaDataModelImportPrivate *priv = gda_data_model_import_get_instance_private (model); + const GValue *value; + + value = gda_set_get_holder_value (priv->options, pname); + if (value && !gda_value_is_null ((GValue *) value)) { + if (!gda_value_isa ((GValue *) value, G_TYPE_BOOLEAN)) + g_warning (_("The '%s' option must hold a " + "boolean value, ignored."), pname); + else + return g_value_get_boolean ((GValue *) value); + } + + return defaults; +} + +static void +gda_data_model_import_set_property (GObject *object, + guint param_id, + const GValue *value, + GParamSpec *pspec) +{ + GdaDataModelImport *model; + + model = GDA_DATA_MODEL_IMPORT (object); + GdaDataModelImportPrivate *priv = gda_data_model_import_get_instance_private (model); + switch (param_id) { + case PROP_OPTIONS: + case PROP_XML_NODE: + case PROP_DATA_STRING: + case PROP_FILENAME: + case PROP_RANDOM_ACCESS: + /* handled in the constructor */ + break; + case PROP_STRICT: + priv->strict = g_value_get_boolean (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + break; + } +} + +static void +gda_data_model_import_get_property (GObject *object, + guint param_id, + GValue *value, + GParamSpec *pspec) +{ + GdaDataModelImport *model; + + model = GDA_DATA_MODEL_IMPORT (object); + GdaDataModelImportPrivate *priv = gda_data_model_import_get_instance_private (model); + switch (param_id) { + case PROP_RANDOM_ACCESS: + g_value_set_boolean (value, priv->random_access); + break; + case PROP_FILENAME: + if (priv->is_mapped) + g_value_set_string (value, priv->src.mapped.filename); + else + g_value_set_string (value, NULL); + break; + case PROP_DATA_STRING: + if (priv->is_mapped) + g_value_set_string (value, NULL); + else + g_value_set_string (value, priv->src.string); + break; + case PROP_STRICT: + g_value_set_boolean (value, priv->strict); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + break; + } +} + +/** + * gda_data_model_import_new_file: + * @filename: the file to import data from + * @random_access: TRUE if random access will be required + * @options: (transfer none) (nullable): importing options + * + * Creates a new #GdaDataModel object which contains the data stored within the @filename file. + * + * The options are the following ones: + * + * For the CSV format: + * + * ENCODING (string): specifies the encoding of the data in the file + * SEPARATOR (string): specifies the CSV separator (comma as default) + * QUOTE (string): specifies the character used as quote (double quote as default) + * NAMES_ON_FIRST_LINE (boolean): consider that the first line of the file contains columns' titles (note that the TITLE_AS_FIRST_LINE option is also accepted as a synonym) + * G_TYPE_<column number> (GType): specifies the type of value expected in column <column number> + * + * + * Other formats: no option + * + * + * Note: after the creation, please use gda_data_model_import_get_errors() to check any error. + * + * Returns: (transfer full): a pointer to the newly created #GdaDataModel. + */ +GdaDataModel * +gda_data_model_import_new_file (const gchar *filename, gboolean random_access, GdaSet *options) +{ + GdaDataModelImport *model; + + g_return_val_if_fail (filename, NULL); + + model = g_object_new (GDA_TYPE_DATA_MODEL_IMPORT, + "random-access", random_access, + "options", options, + "filename", filename, NULL); + + return GDA_DATA_MODEL (model); +} + +/** + * gda_data_model_import_new_mem: + * @data: a string containing the data to import + * @random_access: TRUE if random access will be required + * @options: (transfer none) (nullable): importing options, see gda_data_model_import_new_file() for more information + * + * Creates a new #GdaDataModel object which contains the data stored in the @data string. + * + * Important note: the @data string is not copied for memory efficiency reasons and should not + * therefore be altered in any way as long as the returned data model exists. + * + * Returns: (transfer full): a pointer to the newly created #GdaDataModel. + */ +GdaDataModel * +gda_data_model_import_new_mem (const gchar *data, gboolean random_access, GdaSet *options) +{ + GdaDataModelImport *model; + + model = g_object_new (GDA_TYPE_DATA_MODEL_IMPORT, + "random-access", random_access, + "options", options, + "data-string", data, NULL); + + return GDA_DATA_MODEL (model); +} + +/** + * gda_data_model_import_new_xml_node: + * @node: (transfer none): an XML node corresponding to a <data-array> tag + * + * Creates a new #GdaDataModel and loads the data in @node. The resulting data model + * can be accessed in a random way. + * + * Returns: (transfer full): a pointer to the newly created #GdaDataModel. + */ +GdaDataModel * +gda_data_model_import_new_xml_node (xmlNodePtr node) +{ + GdaDataModelImport *model; + + model = g_object_new (GDA_TYPE_DATA_MODEL_IMPORT, + "xml-node", node, NULL); + + return GDA_DATA_MODEL (model); +} + + +/* + * + * CSV treatments + * + */ + +static gboolean csv_init_csv_parser (GdaDataModelImport *model); +static gboolean csv_fetch_some_lines (GdaDataModelImport *model); + +static void +init_csv_import (GdaDataModelImport *model) +{ + GdaDataModelImportPrivate *priv = gda_data_model_import_get_instance_private (model); + gboolean title_first_line = FALSE; + gint nbcols; + + if (priv->options) + title_first_line = find_option_as_boolean (model, "NAMES_ON_FIRST_LINE", FALSE) || + find_option_as_boolean (model, "TITLE_AS_FIRST_LINE", FALSE); + + g_assert (priv->format == FORMAT_CSV); + + if (!priv->extract.csv.delimiter) + priv->extract.csv.delimiter = ','; + + priv->extract.csv.ignore_first_line = FALSE; + priv->extract.csv.start_pos = priv->data_start; + priv->extract.csv.text_line = 1; /* start line numbering at 1 */ + priv->extract.csv.rows_read = g_array_new (FALSE, TRUE, sizeof (GSList *)); + + /* parser init */ + if (!csv_init_csv_parser (model)) + return; + + /* set parser parameters */ + csv_set_delim (priv->extract.csv.parser, priv->extract.csv.delimiter); + csv_set_quote (priv->extract.csv.parser, priv->extract.csv.quote); + + /* fill in at least a row to determine the number of columns */ + priv->extract.csv.initializing = TRUE; + csv_fetch_some_lines (model); + priv->extract.csv.initializing = FALSE; + + /* computing columns */ + if (priv->extract.csv.rows_read->len == 0) + return; + + GSList *row; + gint col; + const GValue *cvalue; + + row = g_array_index (priv->extract.csv.rows_read, GSList *, 0); + g_assert (row); + nbcols = g_slist_length (row); + + for (col = 0; col < nbcols; col++) { + GdaColumn *column; + gchar *str = NULL; + + column = gda_column_new (); + priv->columns = g_slist_append (priv->columns, + column); + if (title_first_line) { + cvalue = g_slist_nth_data (row, col); + if (cvalue && !gda_value_is_null (cvalue)) + str = gda_value_stringify (cvalue); + } + if (!str) + str = g_strdup_printf ("column_%d", col); + gda_column_set_name (column, str); + gda_column_set_description (column, str); + g_free (str); + + gda_column_set_g_type (column, G_TYPE_STRING); + if (priv->options) { + gchar *pname; + const GValue *value; + + pname = g_strdup_printf ("G_TYPE_%d", col); + value = gda_set_get_holder_value (priv->options, pname); + if (value && !gda_value_is_null ((GValue *) value)) { + if (!gda_value_isa ((GValue *) value, G_TYPE_GTYPE)) + g_warning (_("The '%s' option must hold a " + "GType value, ignored."), pname); + else { + GType gtype; + + gtype = g_value_get_gtype ((GValue *) value); + gda_column_set_g_type (column, gtype); + } + } + g_free (pname); + } + } + + /* reset */ + /*g_print ("CSV parser RESET...................................................\n");*/ + csv_free_stored_rows (model); + csv_fini (priv->extract.csv.parser, NULL, NULL, NULL); + csv_init_csv_parser (model); + + priv->extract.csv.start_pos = priv->data_start; + priv->extract.csv.text_line = 1; /* start line numbering at 1 */ + priv->extract.csv.rows_read = g_array_new (FALSE, TRUE, sizeof (GSList *)); + if (title_first_line) + priv->extract.csv.ignore_first_line = TRUE; + csv_fetch_some_lines (model); +} + +static gboolean +csv_init_csv_parser (GdaDataModelImport *model) +{ + GdaDataModelImportPrivate *priv = gda_data_model_import_get_instance_private (model); + if (csv_init (&(priv->extract.csv.parser), 0) != 0) { + priv->extract.csv.parser = NULL; + return FALSE; + } + + priv->extract.csv.pdata = g_new0 (CsvParserData, 1); + priv->extract.csv.pdata->nb_cols = gda_data_model_get_n_columns ((GdaDataModel*) model); + priv->extract.csv.pdata->model = model; + priv->extract.csv.pdata->field_next_col = 0; + priv->extract.csv.pdata->fields = NULL; + + csv_set_delim (priv->extract.csv.parser, priv->extract.csv.delimiter); + csv_set_quote (priv->extract.csv.parser, priv->extract.csv.quote); + return TRUE; +} + +static void +csv_parser_field_read_cb (char *s, size_t len, void *data) +{ + CsvParserData *pdata = (CsvParserData* ) data; + GdaDataModelImport *model = pdata->model; + GValue *value = NULL; + GdaColumn *column; + GType type = GDA_TYPE_NULL; + gchar *copy; + GdaDataModelImportPrivate *priv = gda_data_model_import_get_instance_private (pdata->model); + + if (priv->extract.csv.ignore_first_line) + return; + + /* convert to correct encoding */ + if (priv->extract.csv.encoding) { + GError *error = NULL; + copy = g_convert (s, len, "UTF-8", priv->extract.csv.encoding, + NULL, NULL, &error); + if (!copy) { + gchar *str; + str = g_strdup_printf (_("Character conversion at line %d, error: %s"), + priv->extract.csv.text_line, + error && error->message ? error->message: + _("no detail")); + add_error (model, str); + g_free (str); + g_error_free (error); + } + } + else + copy = g_locale_to_utf8 (s, len, NULL, NULL, NULL); + if (!copy) + copy = g_strndup (s, len); + /*g_print ("FIELD: #%s# ", copy);*/ + + /* compute column's type */ + if (! priv->extract.csv.initializing) { + if (pdata->field_next_col >= pdata->nb_cols) { + /* ignore extra fields */ + g_free (copy); + return; + } + column = gda_data_model_describe_column ((GdaDataModel *) model, + pdata->field_next_col); + pdata->field_next_col++; + + if (!column) { + g_free (copy); + return; + } + type = gda_column_get_g_type (column); + } + else + type = G_TYPE_STRING; + + /* create a GValue */ + if (type != GDA_TYPE_BINARY) { + if (! g_ascii_strcasecmp (copy, "NULL")) + value = gda_value_new_null (); + else { + value = gda_value_new_from_string (copy, type); + if (!value) { + gchar *str; + str = g_strdup_printf (_("Could not convert string '%s' to a '%s' value"), copy, + g_type_name (type)); + add_error (model, str); + g_free (str); + } + } + } + else + value = gda_value_new_binary ((guchar*) s, len); + g_free (copy); + pdata->fields = g_slist_prepend (pdata->fields, value); + pdata->nb_cols ++; + /*g_print ("=> %p (cols so far: %d)\n", value, g_slist_length (pdata->fields));*/ +} + +static void +csv_parser_row_read_cb (G_GNUC_UNUSED char c, void *data) +{ + CsvParserData *pdata = (CsvParserData* ) data; + GSList *row; + gint size; + GdaDataModelImportPrivate *priv = gda_data_model_import_get_instance_private (pdata->model); + + if (priv->extract.csv.ignore_first_line) + priv->extract.csv.ignore_first_line = FALSE; + else { + row = g_slist_reverse (pdata->fields); + pdata->fields = NULL; + pdata->field_next_col = 0; + + size = g_slist_length (row); + g_assert (size <= pdata->nb_cols); + /*g_print ("===========ROW %d (%d cols)===========\n", priv->extract.csv.text_line, size);*/ + + g_array_append_val (priv->extract.csv.rows_read, row); + priv->extract.csv.text_line ++; + } +} + +static gboolean +csv_fetch_some_lines (GdaDataModelImport *model) +{ + size_t size; + GdaDataModelImportPrivate *priv = gda_data_model_import_get_instance_private (model); + + if (!priv->extract.csv.initializing) + size = MIN (CSV_TITLE_BUFFER_SIZE, + priv->data_start + priv->data_length - + priv->extract.csv.start_pos); + else + size = MIN (CSV_DATA_BUFFER_SIZE, + priv->data_start + priv->data_length - + priv->extract.csv.start_pos); + + if (csv_parse (priv->extract.csv.parser, + priv->extract.csv.start_pos, size, + csv_parser_field_read_cb, + csv_parser_row_read_cb, priv->extract.csv.pdata) != size) { + gchar *str = g_strdup_printf (_("Error while parsing CSV file: %s"), + csv_strerror (csv_error (priv->extract.csv.parser))); + add_error (model, str); + g_free (str); + priv->extract.csv.start_pos = priv->data_start + priv->data_length; + return FALSE; + } + else { + priv->extract.csv.start_pos += size; + + /* try to finish the line if it has not been read entirely */ + if (priv->extract.csv.rows_read->len == 0) { + if ((priv->extract.csv.start_pos != + priv->data_start + priv->data_length)) + return csv_fetch_some_lines (model); + else { + /* end of data */ + csv_fini (priv->extract.csv.parser, + csv_parser_field_read_cb, + csv_parser_row_read_cb, priv->extract.csv.pdata); + return TRUE; + } + } + else + return TRUE; + } +} + + +/* + * + * XML treatments + * + */ + +static gint xml_fetch_next_xml_node (xmlTextReaderPtr reader); +static void xml_fetch_next_row (GdaDataModelImport *model); + +typedef struct { + xmlChar *id; + xmlChar *name; + xmlChar *title; + xmlChar *caption; + xmlChar *dbms_type; + GType gdatype; + gint size; + gint scale; + gboolean pkey; + gboolean unique; + gboolean nullok; + gboolean autoinc; + xmlChar *table; + xmlChar *ref; +} XmlColumnSpec; + +static void +clean_field_specs (GSList *fields) +{ + GSList *list; + XmlColumnSpec *spec; + + for (list = fields; list; list = list->next) { + spec = (XmlColumnSpec*)(list->data); + xmlFree (spec->id); + xmlFree (spec->name); + xmlFree (spec->title); + xmlFree (spec->caption); + xmlFree (spec->dbms_type); + xmlFree (spec->table); + xmlFree (spec->ref); + xmlFree (spec); + } + g_slist_free (fields); +} + +static void +init_xml_import (GdaDataModelImport *model) +{ + int ret; + xmlTextReaderPtr reader; + GdaDataModelImportPrivate *priv = gda_data_model_import_get_instance_private (model); + + g_assert (priv->format == FORMAT_XML_DATA); + + /* init extraction specific variables */ + reader = xmlReaderForMemory (priv->data_start, + priv->data_length, + NULL, NULL, 0); + priv->extract.xml.reader = reader; + + if (! reader) { + /* error, try to switch to csv */ + priv->format = FORMAT_CSV; + init_csv_import (model); + return; + } + + /* create columns */ + ret = xmlTextReaderRead (reader); + if (ret < 0) { + /* error */ + add_error (model, _("Failed to read node in XML file")); + xmlFreeTextReader (reader); + priv->extract.xml.reader = NULL; + } + else { + const xmlChar *name; + xmlNodePtr node; + gchar *prop; + GSList *list, *fields = NULL; + gint pos, nbfields = 0; + + if (ret == 0) + return; + + name = xmlTextReaderConstName (reader); + if (strcmp ((gchar*)name, "gda_array")) { + /* error */ + gchar *str; + + str = g_strdup_printf (_("Expected node in XML file, got <%s>"), name); + add_error (model, str); + g_free (str); + xmlFreeTextReader (reader); + priv->extract.xml.reader = NULL; + return; + } + node = xmlTextReaderCurrentNode (reader); + + prop = (gchar*)xmlGetProp (node, (xmlChar*)"id"); + if (prop) + g_object_set_data_full (G_OBJECT (model), "id", prop, xmlFree); + prop = (gchar*)xmlGetProp (node, (xmlChar*)"name"); + if (prop) + g_object_set_data_full (G_OBJECT (model), "name", prop, xmlFree); + + prop = (gchar*)xmlGetProp (node, (xmlChar*)"descr"); + if (prop) + g_object_set_data_full (G_OBJECT (model), "descr", prop, xmlFree); + + /* compute fields */ + ret = xml_fetch_next_xml_node (reader); + name = (ret > 0) ? xmlTextReaderConstName (reader) : NULL; + while (name && !strcmp ((char*)name, "gda_array_field")) { + XmlColumnSpec *spec; + gchar *str; + + spec = g_new0 (XmlColumnSpec, 1); + fields = g_slist_append (fields, spec); + + spec->id = xmlTextReaderGetAttribute (reader, (xmlChar*)"id"); + spec->name = xmlTextReaderGetAttribute (reader, (xmlChar*)"name"); + spec->title = xmlTextReaderGetAttribute (reader, (xmlChar*)"title"); + if (!spec->title && spec->name) + spec->title = xmlStrdup (spec->name); + + spec->caption = xmlTextReaderGetAttribute (reader, (xmlChar*)"caption"); + spec->dbms_type = xmlTextReaderGetAttribute (reader, (xmlChar*)"dbms_type"); + str = (gchar*)xmlTextReaderGetAttribute (reader, (xmlChar*)"gdatype"); + if (str) { + spec->gdatype = gda_g_type_from_string (str); + xmlFree (str); + if (spec->gdatype == G_TYPE_INVALID) + spec->gdatype = GDA_TYPE_NULL; + } + else { + add_error (model, _("No \"gdatype\" attribute specified in ")); + clean_field_specs (fields); + xmlFreeTextReader (reader); + priv->extract.xml.reader = NULL; + return; + } + str = (gchar*)xmlTextReaderGetAttribute (reader, (xmlChar*)"size"); + if (str) { + spec->size = atoi (str); /* Flawfinder: ignore */ + if (spec->size < 0) + spec->size = 0; + xmlFree (str); + } + str = (gchar*)xmlTextReaderGetAttribute (reader, (xmlChar*)"scale"); + if (str) { + spec->scale = atoi (str); /* Flawfinder: ignore */ + if (spec->scale < 0) + spec->scale = 0; + xmlFree (str); + } + str = (gchar*)xmlTextReaderGetAttribute (reader, (xmlChar*)"pkey"); + if (str) { + spec->pkey = ((*str == 't') || (*str == 'T')) ? TRUE : FALSE; + xmlFree (str); + } + str = (gchar*)xmlTextReaderGetAttribute (reader, (xmlChar*)"unique"); + if (str) { + spec->unique = ((*str == 't') || (*str == 'T')) ? TRUE : FALSE; + xmlFree (str); + } + str = (gchar*)xmlTextReaderGetAttribute (reader, (xmlChar*)"nullok"); + spec->nullok = FALSE; + if (str) { + spec->nullok = ((*str == 't') || (*str == 'T')) ? TRUE : FALSE; + xmlFree (str); + } + str = (gchar*)xmlTextReaderGetAttribute (reader, (xmlChar*)"auto_increment"); + if (str) { + spec->autoinc = ((*str == 't') || (*str == 'T')) ? TRUE : FALSE; + xmlFree (str); + } + spec->table = xmlTextReaderGetAttribute (reader, (xmlChar*)"table"); + spec->ref = xmlTextReaderGetAttribute (reader, (xmlChar*)"ref"); + + nbfields ++; + + ret = xml_fetch_next_xml_node (reader); + name = (ret > 0) ? xmlTextReaderConstName (reader) : NULL; + } + + if (nbfields == 0) { + add_error (model, _("Expected in ")); + clean_field_specs (fields); + xmlFreeTextReader (reader); + priv->extract.xml.reader = NULL; + return; + } + + for (list = fields, pos = 0; + list; + list = list->next, pos++) { + GdaColumn *column; + XmlColumnSpec *spec; + + spec = (XmlColumnSpec *)(list->data); + column = gda_column_new (); + priv->columns = g_slist_append (priv->columns, column); + g_object_set (G_OBJECT (column), "id", spec->id, NULL); + gda_column_set_description (column, (gchar*)spec->title); + gda_column_set_name (column, (gchar*)spec->name); + gda_column_set_dbms_type (column, (gchar*)spec->dbms_type); + gda_column_set_g_type (column, spec->gdatype); + gda_column_set_allow_null (column, spec->nullok); + } + clean_field_specs (fields); + + /* move to find the tag */ + name = (ret > 0) ? xmlTextReaderConstName (reader) : NULL; + if (!name || strcmp ((gchar*)name, "gda_array_data")) { + gchar *str; + + if (name) + str = g_strdup_printf (_("Expected in , got <%s>"), name); + else + str = g_strdup (_("Expected in ")); + add_error (model, str); + g_free (str); + + xmlFreeTextReader (reader); + priv->extract.xml.reader = NULL; + return; + } + + /* get ready for the data reading */ + ret = xml_fetch_next_xml_node (reader); + if (ret <= 0) { + add_error (model, _("Can't read the contents of the node")); + xmlFreeTextReader (reader); + priv->extract.xml.reader = NULL; + return; + } + } +} + +static gint +xml_fetch_next_xml_node (xmlTextReaderPtr reader) +{ + gint ret; + + ret = xmlTextReaderRead (reader); + while ((ret > 0) && (xmlTextReaderNodeType (reader) != XML_ELEMENT_NODE)) { + ret = xmlTextReaderRead (reader); + } + + return ret; +} + +static void +xml_fetch_next_row (GdaDataModelImport *model) +{ + GdaDataModelImportPrivate *priv = gda_data_model_import_get_instance_private (model); + xmlTextReaderPtr reader; + const xmlChar *name; + gint ret; + + const gchar *lang = setlocale(LC_ALL, NULL); + + GSList *columns = priv->columns; + GdaColumn *last_column = NULL; + GSList *values = NULL; + + if (priv->cursor_values) { + g_slist_free_full (priv->cursor_values, (GDestroyNotify) gda_value_free); + priv->cursor_values = NULL; + } + + reader = priv->extract.xml.reader; + if (!reader) + return; + + /* we must now have a tag */ + name = xmlTextReaderConstName (reader); + if (!name || strcmp ((gchar*)name, "gda_array_row")) { + gchar *str; + + str = g_strdup_printf (_("Expected in , got <%s>"), name); + add_error (model, str); + g_free (str); + xmlFreeTextReader (reader); + priv->extract.xml.reader = NULL; + return; + } + + /* compute values */ + ret = xml_fetch_next_xml_node (reader); + name = (ret > 0) ? xmlTextReaderConstName (reader) : NULL; + while (name && !strcmp ((gchar*)name, "gda_value")) { + /* ignore this if the "lang" is there and is not the user locale */ + xmlChar *this_lang; + this_lang = xmlTextReaderGetAttribute (reader, (xmlChar*)"xml:lang"); + if (this_lang && strncmp ((gchar*)this_lang, (gchar*)lang, strlen ((gchar*)this_lang))) { + xmlFree (this_lang); + ret = xml_fetch_next_xml_node (reader); + name = (ret > 0) ? xmlTextReaderConstName (reader) : NULL; + continue; + } + + /* use this */ + if (!columns) + add_error (model, _("Row has too many values (which are ignored)")); + else { + gboolean value_is_null = FALSE; + xmlChar *isnull; + GdaColumn *column; + + isnull = xmlTextReaderGetAttribute (reader, (xmlChar*)"isnull"); + if (isnull) { + if ((*isnull == 't') || (*isnull == 'T')) + value_is_null = TRUE; + xmlFree (isnull); + } + + if (this_lang) + column = last_column; + else { + column = (GdaColumn *) columns->data; + last_column = column; + columns = g_slist_next (columns); + } + + if (value_is_null) { + values = g_slist_prepend (values, gda_value_new_null ()); + ret = -1; + } + else { + ret = xmlTextReaderRead (reader); + if (ret > 0) { + GValue *value; + GType gtype; + + ret = -1; + + gtype = gda_column_get_g_type (column); + /*g_print ("TYPE: %s\n", xmlTextReaderConstName (reader));*/ + if (xmlTextReaderNodeType (reader) == XML_TEXT_NODE) { + const xmlChar *xmlstr; + + xmlstr = xmlTextReaderConstValue (reader); + value = gda_value_new_from_string ((gchar *) xmlstr, gtype); + /*g_print ("Convert #%s# (type:%s) => %s (type:%s)\n", (gchar *) xmlstr, + gda_g_type_to_string (gtype), + gda_value_stringify (value), + value ? gda_g_type_to_string (G_VALUE_TYPE (value)) : "no type");*/ + if (!value) { + gchar *str; + + str = g_strdup_printf (_("Could not convert '%s' to a value of type %s"), + (gchar *) xmlstr, gda_g_type_to_string (gtype)); + add_error (model, str); + g_free (str); + value = gda_value_new_null (); + } + } + else { + if (xmlTextReaderNodeType (reader) == XML_ELEMENT_NODE) + ret = 1; /* don't read another node in the next loop, + use the current one */ + if (value_is_null) + value = gda_value_new_null (); + else + value = gda_value_new_from_string ("", gtype); + } + + if (this_lang) { + /* replace the last value (which did not have any "lang" attribute */ + gda_value_free ((GValue *) values->data); + values->data = value; + xmlFree (this_lang); + } + else + values = g_slist_prepend (values, value); + } + } + } + if (ret < 0) /* read another node ? */ + ret = xml_fetch_next_xml_node (reader); + name = (ret > 0) ? xmlTextReaderConstName (reader) : NULL; + } + + if (values) + priv->cursor_values = g_slist_reverse (values); +#ifdef GDA_DEBUG_NO + GSList *l; + gint c; + + g_print ("======== GdaDataModelImport => next XML row ========\n"); + for (c = 0, l = priv->cursor_values; l; l = l->next, c++) { + GValue *val = (GValue*)(l->data); + g_print ("#%d %s (type:%s)\n", c, gda_value_stringify (val), + val ? g_type_name (G_VALUE_TYPE (val)) : "no type"); + } +#endif + + if (ret <= 0) { + /* destroy the reader, nothing to read anymore */ + xmlFreeTextReader (reader); + priv->extract.xml.reader = NULL; + } +} + +static void +init_node_import (GdaDataModelImport *model) +{ + GdaDataModelImportPrivate *priv = gda_data_model_import_get_instance_private (model); + GdaDataModel *ramodel; + xmlNodePtr node, cur; + gint nbfields = 0; + GSList *fields = NULL; + GSList *list; + gint pos; + gchar *str; + + node = priv->extract.node.node; + if (!node) + return; + + if (strcmp ((gchar*)node->name, "gda_array")) { + gchar *str; + + str = g_strdup_printf (_("Expected node but got <%s>"), node->name); + add_error (model, str); + g_free (str); + + node = priv->extract.node.node = NULL; + return; + } + + for (cur = node->children; cur; cur=cur->next) { + if (xmlNodeIsText (cur)) + continue; + if (!strcmp ((gchar*)cur->name, "gda_array_field")) { + XmlColumnSpec *spec; + + spec = g_new0 (XmlColumnSpec, 1); + fields = g_slist_append (fields, spec); + + spec->id = xmlGetProp (cur, (xmlChar*)"id"); + spec->name = xmlGetProp (cur, (xmlChar*)"name"); + spec->title = xmlGetProp (cur, (xmlChar*)"title"); + if (!spec->title && spec->name) + spec->title = xmlStrdup (spec->name); + + spec->caption = xmlGetProp (cur, (xmlChar*)"caption"); + spec->dbms_type = xmlGetProp (cur, (xmlChar*)"dbms_type"); + str = (gchar*)xmlGetProp (cur, (xmlChar*)"gdatype"); + if (str) { + spec->gdatype = gda_g_type_from_string (str); + xmlFree (str); + if (spec->gdatype == G_TYPE_INVALID) + spec->gdatype = GDA_TYPE_NULL; + } + else { + add_error (model, _("No \"gdatype\" attribute specified in ")); + clean_field_specs (fields); + node = priv->extract.node.node = NULL; + return; + } + str = (gchar*)xmlGetProp (cur, (xmlChar*)"size"); + if (str) { + spec->size = atoi (str); /* Flawfinder: ignore */ + if (spec->size < 0) + spec->size = 0; + xmlFree (str); + } + str = (gchar*)xmlGetProp (cur, (xmlChar*)"scale"); + if (str) { + spec->scale = atoi (str); /* Flawfinder: ignore */ + if (spec->scale < 0) + spec->scale = 0; + xmlFree (str); + } + str = (gchar*)xmlGetProp (cur, (xmlChar*)"pkey"); + if (str) { + spec->pkey = ((*str == 't') || (*str == 'T')) ? TRUE : FALSE; + xmlFree (str); + } + str = (gchar*)xmlGetProp (cur, (xmlChar*)"unique"); + if (str) { + spec->unique = ((*str == 't') || (*str == 'T')) ? TRUE : FALSE; + xmlFree (str); + } + str = (gchar*)xmlGetProp (cur, (xmlChar*)"nullok"); + spec->nullok = FALSE; + if (str) { + spec->nullok = ((*str == 't') || (*str == 'T')) ? TRUE : FALSE; + xmlFree (str); + } + str = (gchar*)xmlGetProp (cur, (xmlChar*)"auto_increment"); + if (str) { + spec->autoinc = ((*str == 't') || (*str == 'T')) ? TRUE : FALSE; + xmlFree (str); + } + spec->table = xmlGetProp (cur, (xmlChar*)"table"); + spec->ref = xmlGetProp (cur, (xmlChar*)"ref"); + + nbfields ++; + continue; + } + if (!strcmp ((gchar*)cur->name, "gda_array_data")) + break; + } + + if (nbfields == 0) { + add_error (model, _("No specified in ")); + node = priv->extract.node.node = NULL; + clean_field_specs (fields); + return; + } + + /* random access model creation */ + ramodel = gda_data_model_array_new (nbfields); + priv->random_access_model = ramodel; + str = (gchar*)xmlGetProp (node, (xmlChar*)"id"); + if (str) + g_object_set_data_full (G_OBJECT (model), "id", str, xmlFree); + str = (gchar*)xmlGetProp (node, (xmlChar*)"name"); + if (str) + g_object_set_data_full (G_OBJECT (model), "name", str, xmlFree); + + str = (gchar*)xmlGetProp (node, (xmlChar*)"descr"); + if (str) + g_object_set_data_full (G_OBJECT (model), "descr", str, xmlFree); + + for (list = fields, pos = 0; + list; + list = list->next, pos++) { + GdaColumn *column; + XmlColumnSpec *spec; + + spec = (XmlColumnSpec *)(list->data); + column = gda_data_model_describe_column (ramodel, pos); + g_object_set (G_OBJECT (column), "id", spec->id, NULL); + gda_column_set_description (column, (gchar*)spec->title); + gda_column_set_name (column, (gchar*)spec->name); + gda_column_set_dbms_type (column, (gchar*)spec->dbms_type); + gda_column_set_g_type (column, spec->gdatype); + gda_column_set_allow_null (column, spec->nullok); + + priv->columns = g_slist_prepend (priv->columns, gda_column_copy (column)); + } + clean_field_specs (fields); + priv->columns = g_slist_reverse (priv->columns); + + GError *error = NULL; + if (cur && ! gda_data_model_add_data_from_xml_node (ramodel, cur, &error)) { + add_error (model, error && error->message ? error->message : _("No detail")); + g_clear_error (&error); + } +} + + + +static void +add_error (GdaDataModelImport *model, const gchar *err) +{ + GdaDataModelImportPrivate *priv = gda_data_model_import_get_instance_private (model); + GError *error = NULL; + + g_set_error (&error, GDA_DATA_MODEL_ERROR, GDA_DATA_MODEL_ACCESS_ERROR, "%s", err); + priv->errors = g_slist_append (priv->errors, error); +} + +/** + * gda_data_model_import_get_errors: + * @model: a #GdaDataModelImport object + * + * Get the list of errors which @model has to report. The returned list is a list of + * #GError structures, and must not be modified + * + * Returns: (transfer none) (element-type GLib.Error): the list of errors (which must not be modified), or %NULL + */ +GSList * +gda_data_model_import_get_errors (GdaDataModelImport *model) +{ + g_return_val_if_fail (GDA_IS_DATA_MODEL_IMPORT (model), NULL); + GdaDataModelImportPrivate *priv = gda_data_model_import_get_instance_private (model); + + return priv->errors; +} + +/** + * gda_data_model_import_clean_errors: + * @model: a #GdaDataModelImport object + * + * Clears the history of errors @model has to report + */ +void +gda_data_model_import_clean_errors (GdaDataModelImport *model) +{ + g_return_if_fail (GDA_IS_DATA_MODEL_IMPORT (model)); + GdaDataModelImportPrivate *priv = gda_data_model_import_get_instance_private (model); + + g_slist_free_full (priv->errors, (GDestroyNotify) g_error_free); + priv->errors = NULL; +} + + + +/* + * GdaDataModel interface implementation + */ +static gint +gda_data_model_import_get_n_rows (GdaDataModel *model) +{ + GdaDataModelImport *imodel; + g_return_val_if_fail (GDA_IS_DATA_MODEL_IMPORT (model), 0); + imodel = GDA_DATA_MODEL_IMPORT (model); + GdaDataModelImportPrivate *priv = gda_data_model_import_get_instance_private (imodel); + + if (!priv->random_access) + return -1; + else { + if (priv->random_access_model) + return gda_data_model_get_n_rows (priv->random_access_model); + else + /* number of rows is not known */ + return -1; + } +} + +static gint +gda_data_model_import_get_n_columns (GdaDataModel *model) +{ + GdaDataModelImport *imodel; + g_return_val_if_fail (GDA_IS_DATA_MODEL_IMPORT (model), 0); + imodel = GDA_DATA_MODEL_IMPORT (model); + GdaDataModelImportPrivate *priv = gda_data_model_import_get_instance_private (imodel); + + if (priv->columns) + return g_slist_length (priv->columns); + else + return 0; +} + +static GdaColumn * +gda_data_model_import_describe_column (GdaDataModel *model, gint col) +{ + GdaDataModelImport *imodel; + g_return_val_if_fail (GDA_IS_DATA_MODEL_IMPORT (model), NULL); + imodel = GDA_DATA_MODEL_IMPORT (model); + GdaDataModelImportPrivate *priv = gda_data_model_import_get_instance_private (imodel); + + if (priv->columns) + return g_slist_nth_data (priv->columns, col); + else + return NULL; +} + +static GdaDataModelAccessFlags +gda_data_model_import_get_access_flags (GdaDataModel *model) +{ + GdaDataModelImport *imodel; + GdaDataModelAccessFlags flags = GDA_DATA_MODEL_ACCESS_CURSOR_FORWARD; + + g_return_val_if_fail (GDA_IS_DATA_MODEL_IMPORT (model), 0); + imodel = GDA_DATA_MODEL_IMPORT (model); + GdaDataModelImportPrivate *priv = gda_data_model_import_get_instance_private (imodel); + + if (priv->format == FORMAT_CSV) { + /*flags |= GDA_DATA_MODEL_ACCESS_CURSOR_BACKWARD*/; + } + + if (priv->random_access && priv->random_access_model) + flags |= GDA_DATA_MODEL_ACCESS_RANDOM; + + return flags; +} + +static const GValue * +gda_data_model_import_get_value_at (GdaDataModel *model, gint col, gint row, GError **error) +{ + GdaDataModelImport *imodel; + g_return_val_if_fail (GDA_IS_DATA_MODEL_IMPORT (model), NULL); + imodel = GDA_DATA_MODEL_IMPORT (model); + GdaDataModelImportPrivate *priv = gda_data_model_import_get_instance_private (imodel); + + if (priv->random_access_model) + /* if there is a random access model, then use it */ + return gda_data_model_get_value_at (priv->random_access_model, col, row, error); + else { + /* otherwise, bail out */ + g_set_error (error, GDA_DATA_MODEL_ERROR, GDA_DATA_MODEL_ACCESS_ERROR, + "%s", _("Data model does not support random access")); + return NULL; + } +} + +static GdaValueAttribute +gda_data_model_import_get_attributes_at (GdaDataModel *model, gint col, G_GNUC_UNUSED gint row) +{ + GdaValueAttribute flags = 0; + GdaDataModelImport *imodel; + GdaColumn *column; + + g_return_val_if_fail (GDA_IS_DATA_MODEL_IMPORT (model), 0); + imodel = (GdaDataModelImport *) model; + GdaDataModelImportPrivate *priv = gda_data_model_import_get_instance_private (imodel); + g_return_val_if_fail (priv, 0); + + flags = GDA_VALUE_ATTR_NO_MODIF; + column = gda_data_model_describe_column (model, col); + if (gda_column_get_allow_null (column)) + flags |= GDA_VALUE_ATTR_CAN_BE_NULL; + + return flags; +} + +static GdaDataModelIter * +gda_data_model_import_create_iter (GdaDataModel *model) +{ + GdaDataModelImport *imodel; + GdaDataModelIter *iter; + + g_return_val_if_fail (GDA_IS_DATA_MODEL_IMPORT (model), NULL); + imodel = (GdaDataModelImport *) model; + GdaDataModelImportPrivate *priv = gda_data_model_import_get_instance_private (imodel); + g_return_val_if_fail (priv, NULL); + + if (priv->random_access_model) { + iter = gda_data_model_create_iter (priv->random_access_model); + /* REM: don't do: + * g_object_set (G_OBJECT (iter), "forced-model", model, NULL); + * because otherwise data fetch will come back on @model, which is not what is wanted. + * However the problem is that getting the "model" property from the returned iterator will + * give a pointer to priv->random_access_model and not @model... + */ + } + else + iter = (GdaDataModelIter *) g_object_new (GDA_TYPE_DATA_MODEL_IMPORT_ITER, + "data-model", model, NULL); + return iter; +} + +static void +add_error_too_few_values (GdaDataModelImport *model) +{ + gchar *str; + GdaDataModelImportPrivate *priv = gda_data_model_import_get_instance_private (model); + + switch (priv->format){ + case FORMAT_CSV: + if (priv->strict) + str = g_strdup_printf (_("Row at line %d does not have enough values"), + priv->extract.csv.text_line > 1 ? + priv->extract.csv.text_line - 1 : + priv->extract.csv.text_line); + else + str = g_strdup_printf (_("Row at line %d does not have enough values, " + "completed with NULL values"), + priv->extract.csv.text_line > 1 ? + priv->extract.csv.text_line - 1 : + priv->extract.csv.text_line); + add_error (model, str); + g_free (str); + break; + default: + if (priv->strict) + add_error (model, ("Row does not have enough values")); + else + add_error (model, ("Row does not have enough values, " + "completed with NULL values")); + break; + } +} + +static void +add_error_too_many_values (GdaDataModelImport *model) +{ + GdaDataModelImportPrivate *priv = gda_data_model_import_get_instance_private (model); + gchar *str; + + switch (priv->format){ + case FORMAT_CSV: + str = g_strdup_printf (_("Row at line %d does not have enough values " + "(which are thus ignored)"), + priv->extract.csv.text_line); + add_error (model, str); + g_free (str); + break; + default: + add_error (model, ("Row does not have enough values (which are thus ignored)")); + break; + } +} + +static gboolean +gda_data_model_import_iter_next (GdaDataModel *model, GdaDataModelIter *iter) +{ + GdaDataModelImport *imodel; + GSList *next_values = NULL; + + g_return_val_if_fail (GDA_IS_DATA_MODEL_IMPORT (model), FALSE); + imodel = (GdaDataModelImport *) model; + GdaDataModelImportPrivate *priv = gda_data_model_import_get_instance_private (imodel); + + /* if there is a random access model, then use it */ + if (priv->format == FORMAT_XML_NODE) + return gda_data_model_iter_move_next_default (model, iter); + + /* fetch the next row if necessary */ + switch (priv->format) { + case FORMAT_XML_DATA: + xml_fetch_next_row (imodel); + next_values = priv->cursor_values; + break; + + case FORMAT_CSV: + if (! priv->extract.csv.rows_read) { + gda_data_model_iter_invalidate_contents (iter); + return FALSE; + } + + if (gda_data_model_iter_is_valid (iter) && + (priv->extract.csv.rows_read->len > 0)) { + /* get rid of row pointer by iter */ + GSList *list = g_array_index (priv->extract.csv.rows_read, + GSList *, 0); + g_assert (list); + g_slist_free_full (list, (GDestroyNotify) gda_value_free); + g_array_remove_index (priv->extract.csv.rows_read, 0); + } + + /* fetch some more rows if necessary */ + if (priv->extract.csv.rows_read->len == 0) + csv_fetch_some_lines (imodel); + if (priv->extract.csv.rows_read->len != 0) + next_values = g_array_index (priv->extract.csv.rows_read, + GSList *, 0); + break; + default: + g_assert_not_reached (); + } + + /* set values in iter */ + if (next_values) { + GSList *plist; + GSList *vlist; + gboolean update_model; + + g_object_get (G_OBJECT (iter), "update-model", &update_model, NULL); + g_object_set (G_OBJECT (iter), "update-model", FALSE, NULL); + for (plist = gda_set_get_holders (((GdaSet *) iter)), vlist = next_values; + plist && vlist; + plist = plist->next, vlist = vlist->next) { + GError *lerror = NULL; + if (! gda_holder_take_value ((GdaHolder*) plist->data, + (GValue *) vlist->data, &lerror)) + gda_holder_force_invalid_e (GDA_HOLDER (plist->data), lerror); + vlist->data = NULL; + } + if (plist || vlist) { + if (plist) { + add_error_too_few_values (imodel); + for (; plist; plist = plist->next) { + if (priv->strict) + gda_holder_force_invalid (GDA_HOLDER (plist->data)); + else + gda_holder_set_value (GDA_HOLDER (plist->data), NULL, NULL); + } + } + else + add_error_too_many_values (imodel); + } + if (gda_data_model_iter_is_valid (iter)) + priv->iter_row ++; + else + priv->iter_row = 0; + + g_object_set (G_OBJECT (iter), "current-row", priv->iter_row, + "update-model", update_model, NULL); + + return TRUE; + } + else { + gda_data_model_iter_invalidate_contents (iter); + g_object_set (G_OBJECT (iter), "current-row", -1, NULL); + g_signal_emit_by_name (iter, "end-of-data"); + return FALSE; + } +} + +static gboolean +gda_data_model_import_iter_prev (GdaDataModel *model, GdaDataModelIter *iter) +{ + GdaDataModelImport *imodel; + + g_return_val_if_fail (GDA_IS_DATA_MODEL_IMPORT (model), FALSE); + imodel = (GdaDataModelImport *) model; + GdaDataModelImportPrivate *priv = gda_data_model_import_get_instance_private (imodel); + + if (priv->format == FORMAT_XML_DATA) + return FALSE; + + /* if there is a random access model, then use it */ + if (priv->format == FORMAT_XML_NODE) + return gda_data_model_iter_move_prev_default (model, iter); + + /* fetch the previous row if necessary */ + switch (priv->format) { + case FORMAT_CSV: + default: + g_assert_not_reached (); + } + + /* set values in iter */ + if (priv->cursor_values) { + GSList *plist; + GSList *vlist; + gboolean update_model; + + g_object_get (G_OBJECT (iter), "update-model", &update_model, NULL); + g_object_set (G_OBJECT (iter), "update-model", FALSE, NULL); + for (plist = gda_set_get_holders (((GdaSet *) iter)), vlist = priv->cursor_values; + plist && vlist; + plist = plist->next, vlist = vlist->next) { + GError *lerror = NULL; + if (! gda_holder_set_value ((GdaHolder*) plist->data, + (GValue *) vlist->data, &lerror)) + gda_holder_force_invalid_e (GDA_HOLDER (plist->data), lerror); + } + if (plist || vlist) { + if (plist) { + add_error_too_few_values (imodel); + for (; plist; plist = plist->next) { + if (priv->strict) + gda_holder_force_invalid (GDA_HOLDER (plist->data)); + else + gda_holder_set_value (GDA_HOLDER (plist->data), NULL, NULL); + } + } + else + add_error_too_many_values (imodel); + } + + if (gda_data_model_iter_is_valid (iter)) + priv->iter_row --; + + g_assert (priv->iter_row >= 0); + g_object_set (G_OBJECT (iter), "current-row", priv->iter_row, + "update-model", update_model, NULL); + return TRUE; + } + else { + gda_data_model_iter_invalidate_contents (iter); + g_object_set (G_OBJECT (iter), "current-row", -1, NULL); + return FALSE; + } +} diff --git a/.flatpak-builder/cache/objects/3e/8ffb01dec892e1361b88e00ce846a1a0512e179ba3df67b4ae48a226c2443e.file b/.flatpak-builder/cache/objects/3e/8ffb01dec892e1361b88e00ce846a1a0512e179ba3df67b4ae48a226c2443e.file new file mode 100644 index 0000000..c32e921 --- /dev/null +++ b/.flatpak-builder/cache/objects/3e/8ffb01dec892e1361b88e00ce846a1a0512e179ba3df67b4ae48a226c2443e.file @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2006 - 2011 Vivien Malerba + * Copyright (C) 2007 Murray Cumming + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GDA_HANDLER_NUMERICAL__ +#define __GDA_HANDLER_NUMERICAL__ + +#include +#include + +G_BEGIN_DECLS + +#define GDA_TYPE_HANDLER_NUMERICAL (gda_handler_numerical_get_type()) +G_DECLARE_FINAL_TYPE (GdaHandlerNumerical, gda_handler_numerical, GDA, HANDLER_NUMERICAL, GObject) + +/** + * SECTION:gda-handler-numerical + * @short_description: Default handler for numeric values + * @title: GdaHanderNumerical + * @stability: Stable + * @see_also: #GdaDataHandler interface + * + * You should normally not need to use this API, refer to the #GdaDataHandler + * interface documentation for more information. + */ + +GdaDataHandler *gda_handler_numerical_new (void); + +G_END_DECLS + +#endif diff --git a/.flatpak-builder/cache/objects/3e/a2fd097da651bd037199e0907a4425379e9d92dd4cc95cfd8cd010b4dbdfe9.dirtree b/.flatpak-builder/cache/objects/3e/a2fd097da651bd037199e0907a4425379e9d92dd4cc95cfd8cd010b4dbdfe9.dirtree new file mode 100644 index 0000000..e0d77f1 Binary files /dev/null and b/.flatpak-builder/cache/objects/3e/a2fd097da651bd037199e0907a4425379e9d92dd4cc95cfd8cd010b4dbdfe9.dirtree differ diff --git a/.flatpak-builder/cache/objects/3e/e3d32597938b9389c38701762a694ae56ae6683f8a8c4efd81857360580f4b.dirtree b/.flatpak-builder/cache/objects/3e/e3d32597938b9389c38701762a694ae56ae6683f8a8c4efd81857360580f4b.dirtree new file mode 100644 index 0000000..7d7ca87 Binary files /dev/null and b/.flatpak-builder/cache/objects/3e/e3d32597938b9389c38701762a694ae56ae6683f8a8c4efd81857360580f4b.dirtree differ diff --git a/.flatpak-builder/cache/objects/3f/0ff3d63ba57273848e19eaa708590f8232835dae375f278ed822d6e90473fe.dirtree b/.flatpak-builder/cache/objects/3f/0ff3d63ba57273848e19eaa708590f8232835dae375f278ed822d6e90473fe.dirtree new file mode 100644 index 0000000..eac01fc Binary files /dev/null and b/.flatpak-builder/cache/objects/3f/0ff3d63ba57273848e19eaa708590f8232835dae375f278ed822d6e90473fe.dirtree differ diff --git a/.flatpak-builder/cache/objects/3f/7f5322dd69ba7ba80ea7b02aed10e42ce9ca564cfe078bacb67bfd028d1046.file b/.flatpak-builder/cache/objects/3f/7f5322dd69ba7ba80ea7b02aed10e42ce9ca564cfe078bacb67bfd028d1046.file new file mode 100644 index 0000000..d4db059 --- /dev/null +++ b/.flatpak-builder/cache/objects/3f/7f5322dd69ba7ba80ea7b02aed10e42ce9ca564cfe078bacb67bfd028d1046.file @@ -0,0 +1,2 @@ +gobject-2.0 +gio-2.0 diff --git a/.flatpak-builder/cache/objects/3f/f9fe30c56c6f1a0a0847164204b0f77d400b8be323f78a64d62a2dbd0f2923.commit b/.flatpak-builder/cache/objects/3f/f9fe30c56c6f1a0a0847164204b0f77d400b8be323f78a64d62a2dbd0f2923.commit new file mode 100644 index 0000000..1543281 Binary files /dev/null and b/.flatpak-builder/cache/objects/3f/f9fe30c56c6f1a0a0847164204b0f77d400b8be323f78a64d62a2dbd0f2923.commit differ diff --git a/.flatpak-builder/cache/objects/40/5f203e5b56ef569fe4d37343e1dcbf202ae5f9baa9d16957597a0e59c1db88.dirtree b/.flatpak-builder/cache/objects/40/5f203e5b56ef569fe4d37343e1dcbf202ae5f9baa9d16957597a0e59c1db88.dirtree new file mode 100644 index 0000000..c3a90d2 Binary files /dev/null and b/.flatpak-builder/cache/objects/40/5f203e5b56ef569fe4d37343e1dcbf202ae5f9baa9d16957597a0e59c1db88.dirtree differ diff --git a/.flatpak-builder/cache/objects/40/8879b9998434df08c009612d54397bccf60410bf12f5ee792fcd7a641febc1.dirtree b/.flatpak-builder/cache/objects/40/8879b9998434df08c009612d54397bccf60410bf12f5ee792fcd7a641febc1.dirtree new file mode 100644 index 0000000..33f544d Binary files /dev/null and b/.flatpak-builder/cache/objects/40/8879b9998434df08c009612d54397bccf60410bf12f5ee792fcd7a641febc1.dirtree differ diff --git a/.flatpak-builder/cache/objects/41/0b6b677af2e56c461d47b0ebdd6539d3fc022df431bb793a91390ecd53c1b9.file b/.flatpak-builder/cache/objects/41/0b6b677af2e56c461d47b0ebdd6539d3fc022df431bb793a91390ecd53c1b9.file new file mode 100644 index 0000000..67791f0 --- /dev/null +++ b/.flatpak-builder/cache/objects/41/0b6b677af2e56c461d47b0ebdd6539d3fc022df431bb793a91390ecd53c1b9.file @@ -0,0 +1,990 @@ +/*-*- Mode: C; c-basic-offset: 8 -*-*/ + +/*** + This file is part of libcanberra. + + Copyright 2008 Lennart Poettering + + libcanberra is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation, either version 2.1 of the + License, or (at your option) any later version. + + libcanberra is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with libcanberra. If not, see + . +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#include "canberra-gtk.h" + +typedef struct { + guint signal_id; + gboolean arg1_is_set; + GObject *object; + GValue arg1; + GdkEvent *event; +} SoundEventData; + +/* + We generate these sounds: + + dialog-error + dialog-warning + dialog-information + dialog-question + window-new + window-close + window-minimized + window-unminimized + window-maximized + window-unmaximized + notebook-tab-changed + dialog-ok + dialog-cancel + item-selected + link-pressed + link-released + button-pressed + button-released + menu-click + button-toggle-on + button-toggle-off + menu-popup + menu-popdown + menu-replace + tooltip-popup + tooltip-popdown + drag-start + drag-accept + drag-fail + expander-toggle-on + expander-toggle-off + + TODO: + scroll-xxx + window-switch + window-resize-xxx + window-move-xxx + +*/ + +static gboolean disabled = FALSE; + +static GQueue sound_event_queue = G_QUEUE_INIT; + +static guint idle_id = 0; + +static guint + signal_id_dialog_response, + signal_id_widget_show, + signal_id_widget_hide, + signal_id_check_menu_item_toggled, + signal_id_menu_item_activate, + signal_id_toggle_button_toggled, + signal_id_button_pressed, + signal_id_button_released, + signal_id_widget_window_state_event, + signal_id_notebook_switch_page, + signal_id_tree_view_cursor_changed, + signal_id_icon_view_selection_changed, + signal_id_widget_drag_begin, + signal_id_widget_drag_failed, + signal_id_widget_drag_drop, + signal_id_expander_activate; + +static GQuark + disable_sound_quark, + was_iconized_quark, + is_xembed_quark; + +/* Make sure GCC doesn't warn us about a missing prototype for this + * exported function */ +void gtk_module_init(gint *argc, gchar ***argv[]); + +static const char *translate_message_tye(GtkMessageType mt) { + static const char *const message_type_table[] = { + [GTK_MESSAGE_INFO] = "dialog-information", + [GTK_MESSAGE_WARNING] = "dialog-warning", + [GTK_MESSAGE_QUESTION] = "dialog-question", + [GTK_MESSAGE_ERROR] = "dialog-error", + [GTK_MESSAGE_OTHER] = NULL + }; + + if (mt >= G_N_ELEMENTS(message_type_table)) + return NULL; + + return message_type_table[mt]; +} + +static const char *translate_response(int response) { + static const char *const response_table[] = { + [-GTK_RESPONSE_NONE] = NULL, + [-GTK_RESPONSE_REJECT] = "dialog-cancel", + [-GTK_RESPONSE_DELETE_EVENT] = "dialog-cancel", + [-GTK_RESPONSE_ACCEPT] = "dialog-ok", + [-GTK_RESPONSE_OK] = "dialog-ok", + [-GTK_RESPONSE_CANCEL] = "dialog-cancel", + [-GTK_RESPONSE_CLOSE] = "dialog-ok", + [-GTK_RESPONSE_YES] = "dialog-ok", + [-GTK_RESPONSE_NO] = "dialog-cancel", + [-GTK_RESPONSE_APPLY] = "dialog-ok", + [-GTK_RESPONSE_HELP] = NULL, + }; + + if (response >= 0) + return NULL; + + if ((unsigned) -response >= G_N_ELEMENTS(response_table)) + return NULL; + + return response_table[-response]; +} + +static gboolean is_child_of_combo_box(GtkWidget *w) { + + while (w) { + + if (GTK_IS_COMBO_BOX(w)) + return TRUE; + + w = gtk_widget_get_parent(w); + } + + return FALSE; +} + +static GtkDialog* find_parent_dialog(GtkWidget *w) { + + while (w) { + + if (GTK_IS_DIALOG(w)) + return GTK_DIALOG(w); + + w = gtk_widget_get_parent(w); + } + + return NULL; +} + +static void free_sound_event(SoundEventData *d) { + + g_object_unref(d->object); + + if (d->arg1_is_set) + g_value_unset(&d->arg1); + + if (d->event) + gdk_event_free(d->event); + + g_slice_free(SoundEventData, d); +} + +static gboolean is_menu_hint(GdkWindowTypeHint hint) { + return + hint == GDK_WINDOW_TYPE_HINT_POPUP_MENU || + hint == GDK_WINDOW_TYPE_HINT_DROPDOWN_MENU || + hint == GDK_WINDOW_TYPE_HINT_MENU; +} + +static SoundEventData* filter_sound_event(SoundEventData *d) { + GList *i, *n; + + do { + + for (i = sound_event_queue.head; i; i = n) { + SoundEventData *j; + + j = i->data; + n = i->next; + + if (d->object == j->object) { + + /* Let's drop a show event immediately followed by a + * hide event */ + + if (d->signal_id == signal_id_widget_show && + j->signal_id == signal_id_widget_hide) { + + free_sound_event(d); + free_sound_event(j); + g_queue_delete_link(&sound_event_queue, i); + + return NULL; + } + + /* Let's drop widget hide events in favour of dialog + * response. + * + * Let's drop widget window state events in favour of + * widget hide/show. + * + * Let's drop double events */ + + if ((d->signal_id == signal_id_widget_hide && + j->signal_id == signal_id_dialog_response) || + + (d->signal_id == signal_id_widget_window_state_event && + j->signal_id == signal_id_widget_hide) || + + (d->signal_id == signal_id_widget_window_state_event && + j->signal_id == signal_id_widget_show)) { + + free_sound_event(d); + d = j; + g_queue_delete_link(&sound_event_queue, i); + break; + } + + if ((d->signal_id == signal_id_dialog_response && + j->signal_id == signal_id_widget_hide) || + + (d->signal_id == signal_id_widget_show && + j->signal_id == signal_id_widget_window_state_event) || + + (d->signal_id == signal_id_widget_hide && + j->signal_id == signal_id_widget_window_state_event) || + + (d->signal_id == j->signal_id)) { + + free_sound_event(j); + g_queue_delete_link(&sound_event_queue, i); + } + + } else if (GTK_IS_WINDOW(d->object) && GTK_IS_WINDOW(j->object)) { + + GdkWindowTypeHint dhint, jhint; + + dhint = gtk_window_get_type_hint(GTK_WINDOW(d->object)); + jhint = gtk_window_get_type_hint(GTK_WINDOW(j->object)); + + if (is_menu_hint(dhint) && is_menu_hint(jhint)) { + + if (d->signal_id == signal_id_widget_hide && + j->signal_id == signal_id_widget_show) { + free_sound_event(d); + d = j; + g_queue_delete_link(&sound_event_queue, i); + break; + } + + if (d->signal_id == signal_id_widget_show && + j->signal_id == signal_id_widget_hide) { + + free_sound_event(j); + g_queue_delete_link(&sound_event_queue, i); + } + } + } + } + + /* If we exited the iteration early, let's retry. */ + + } while (i); + + /* FIXME: Filter menu hide on menu show */ + + return d; +} + +static gint window_get_desktop(GdkDisplay *d, GdkWindow *w) { + Atom type_return; + gint format_return; + gulong nitems_return; + gulong bytes_after_return; + guchar *data = NULL; + gint ret = -1; + + if (XGetWindowProperty(GDK_DISPLAY_XDISPLAY(d), GDK_WINDOW_XID(w), + gdk_x11_get_xatom_by_name_for_display(d, "_NET_WM_DESKTOP"), + 0, G_MAXLONG, False, XA_CARDINAL, &type_return, + &format_return, &nitems_return, &bytes_after_return, + &data) != Success) + return -1; + + if (type_return == XA_CARDINAL && format_return == 32 && data) { + guint32 desktop = *(guint32*) data; + + if (desktop != 0xFFFFFFFF) + ret = (gint) desktop; + } + + if (type_return != None && data != NULL) + XFree(data); + + return ret; +} + +static gint display_get_desktop(GdkDisplay *d) { + Atom type_return; + gint format_return; + gulong nitems_return; + gulong bytes_after_return; + guchar *data = NULL; + gint ret = -1; + + if (XGetWindowProperty(GDK_DISPLAY_XDISPLAY(d), DefaultRootWindow(GDK_DISPLAY_XDISPLAY(d)), + gdk_x11_get_xatom_by_name_for_display(d, "_NET_CURRENT_DESKTOP"), + 0, G_MAXLONG, False, XA_CARDINAL, &type_return, + &format_return, &nitems_return, &bytes_after_return, + &data) != Success) + return -1; + + if (type_return == XA_CARDINAL && format_return == 32 && data) { + + guint32 desktop = *(guint32*) data; + + if (desktop != 0xFFFFFFFF) + ret = (gint) desktop; + } + + if (type_return != None && data != NULL) + XFree(data); + + return ret; +} + +static gboolean window_is_xembed(GdkDisplay *d, GdkWindow *w) { + Atom type_return; + gint format_return; + gulong nitems_return; + gulong bytes_after_return; + guchar *data = NULL; + gboolean ret = FALSE; + Atom xembed; + + /* Gnome Panel applets are XEMBED windows. We need to make sure we + * ignore them */ + + xembed = gdk_x11_get_xatom_by_name_for_display(d, "_XEMBED_INFO"); + + /* be robust against not existing XIDs (LP: #834403) */ + gdk_error_trap_push(); + if (XGetWindowProperty(GDK_DISPLAY_XDISPLAY(d), GDK_WINDOW_XID(w), + xembed, + 0, 2, False, xembed, &type_return, + &format_return, &nitems_return, &bytes_after_return, + &data) != Success) { + return FALSE; + } + +#if GTK_CHECK_VERSION(3,0,0) + gdk_error_trap_pop_ignored(); +#else + gdk_flush(); + gdk_error_trap_pop(); +#endif + + if (type_return == xembed && format_return == 32 && data) + ret = TRUE; + + if (type_return != None && data != NULL) + XFree(data); + + return ret; +} + +static void dispatch_sound_event(SoundEventData *d) { + int ret = CA_SUCCESS; + static gboolean menu_is_popped_up = FALSE; + + if (g_object_get_qdata(d->object, disable_sound_quark)) + return; + + /* The GdkWindow of the the widget might have changed while this + * event was queued for us. Make sure to update it from the + * current one if necessary. */ + if (d->event && d->event->any.window) { + GdkWindow *window; + + g_object_unref(G_OBJECT(d->event->any.window)); + + if ((window = gtk_widget_get_window(GTK_WIDGET(d->object)))) + d->event->any.window = GDK_WINDOW(g_object_ref(G_OBJECT(window))); + else + d->event->any.window = NULL; + } + + if (d->signal_id == signal_id_widget_show) { + GdkWindowTypeHint hint; + + /* Show/hide signals for non-windows have already been filtered out + * by the emission hook! */ + + hint = gtk_window_get_type_hint(GTK_WINDOW(d->object)); + + if (is_menu_hint(hint)) { + + if (!menu_is_popped_up) { + + ret = ca_gtk_play_for_widget(GTK_WIDGET(d->object), 0, + CA_PROP_EVENT_ID, "menu-popup", + CA_PROP_EVENT_DESCRIPTION, "Menu popped up", + CA_PROP_CANBERRA_CACHE_CONTROL, "permanent", + NULL); + } else { + ret = ca_gtk_play_for_widget(GTK_WIDGET(d->object), 0, + CA_PROP_EVENT_ID, "menu-replace", + CA_PROP_EVENT_DESCRIPTION, "Menu replaced", + CA_PROP_CANBERRA_CACHE_CONTROL, "permanent", + NULL); + } + + menu_is_popped_up = TRUE; + + } else if (hint == GDK_WINDOW_TYPE_HINT_TOOLTIP) { + + ret = ca_gtk_play_for_widget(GTK_WIDGET(d->object), 0, + CA_PROP_EVENT_ID, "tooltip-popup", + CA_PROP_EVENT_DESCRIPTION, "Tooltip popped up", + CA_PROP_CANBERRA_CACHE_CONTROL, "permanent", + NULL); + + } else if (hint == GDK_WINDOW_TYPE_HINT_NORMAL || + hint == GDK_WINDOW_TYPE_HINT_DIALOG) { + + gboolean played_sound = FALSE; + gboolean is_xembed; + + is_xembed = + gtk_widget_get_realized(GTK_WIDGET(d->object)) && + window_is_xembed( + gtk_widget_get_display(GTK_WIDGET(d->object)), + gtk_widget_get_window(GTK_WIDGET(d->object))); + + g_object_set_qdata(d->object, is_xembed_quark, GINT_TO_POINTER(is_xembed)); + + if (GTK_IS_MESSAGE_DIALOG(d->object)) { + GtkMessageType mt; + const char *id; + + g_object_get(d->object, "message_type", &mt, NULL); + + if ((id = translate_message_tye(mt))) { + + ret = ca_gtk_play_for_widget(GTK_WIDGET(d->object), 0, + CA_PROP_EVENT_ID, id, + CA_PROP_EVENT_DESCRIPTION, "Message dialog shown", + CA_PROP_CANBERRA_CACHE_CONTROL, "permanent", + NULL); + played_sound = TRUE; + } + + } + + if (!played_sound && + !is_xembed && + gtk_window_get_decorated(GTK_WINDOW(d->object))) { + + ret = ca_gtk_play_for_widget(GTK_WIDGET(d->object), 0, + CA_PROP_EVENT_ID, "window-new", + CA_PROP_EVENT_DESCRIPTION, "Window shown", + CA_PROP_CANBERRA_CACHE_CONTROL, "permanent", + NULL); + + } + } + } + + if (GTK_IS_DIALOG(d->object) && d->signal_id == signal_id_dialog_response) { + + int response; + const char *id; + + response = g_value_get_int(&d->arg1); + + if ((id = translate_response(response))) { + + ret = ca_gtk_play_for_widget(GTK_WIDGET(d->object), 0, + CA_PROP_EVENT_ID, id, + CA_PROP_EVENT_DESCRIPTION, "Dialog closed", + CA_PROP_CANBERRA_CACHE_CONTROL, "permanent", + NULL); + } else { + ret = ca_gtk_play_for_widget(GTK_WIDGET(d->object), 0, + CA_PROP_EVENT_ID, "window-close", + CA_PROP_EVENT_DESCRIPTION, "Window closed", + CA_PROP_CANBERRA_CACHE_CONTROL, "permanent", + NULL); + } + + } else if (d->signal_id == signal_id_widget_hide) { + GdkWindowTypeHint hint; + + hint = gtk_window_get_type_hint(GTK_WINDOW(d->object)); + + if (is_menu_hint(hint)) { + + if (GTK_IS_MENU(gtk_bin_get_child(GTK_BIN(d->object)))) { + + ret = ca_gtk_play_for_widget(GTK_WIDGET(d->object), 0, + CA_PROP_EVENT_ID, "menu-popdown", + CA_PROP_EVENT_DESCRIPTION, "Menu popped down", + CA_PROP_CANBERRA_CACHE_CONTROL, "permanent", + NULL); + } + + menu_is_popped_up = FALSE; + + } else if (hint == GDK_WINDOW_TYPE_HINT_TOOLTIP) { + + ret = ca_gtk_play_for_widget(GTK_WIDGET(d->object), 0, + CA_PROP_EVENT_ID, "tooltip-popdown", + CA_PROP_EVENT_DESCRIPTION, "Tooltip popped down", + CA_PROP_CANBERRA_CACHE_CONTROL, "permanent", + NULL); + + } else if ((hint == GDK_WINDOW_TYPE_HINT_NORMAL || + hint == GDK_WINDOW_TYPE_HINT_DIALOG)) { + + gboolean is_xembed; + + is_xembed = !!g_object_get_qdata(d->object, is_xembed_quark); + + if (!is_xembed && + gtk_window_get_decorated(GTK_WINDOW(d->object))) + ret = ca_gtk_play_for_widget(GTK_WIDGET(d->object), 0, + CA_PROP_EVENT_ID, "window-close", + CA_PROP_EVENT_DESCRIPTION, "Window closed", + CA_PROP_CANBERRA_CACHE_CONTROL, "permanent", + NULL); + } + } + + if (GTK_IS_WINDOW(d->object) && d->signal_id == signal_id_widget_window_state_event) { + GdkEventWindowState *e; + gint w_desktop = -1, c_desktop = -1; + + e = (GdkEventWindowState*) d->event; + + /* Unfortunately GDK_WINDOW_STATE_ICONIFIED is used both for + * proper minimizing and when a window becomes invisible + * because the desktop was switched. To handle this we check + * if the window becoming invisible is actually on the current + * desktop, and only if that's the case we assume it is being + * minimized. We then store this information, so that we know + * later on when the window is unminimized again. */ + + if (gtk_widget_get_realized(GTK_WIDGET(d->object))) { + GdkDisplay *display; + + display = gtk_widget_get_display(GTK_WIDGET(d->object)); + w_desktop = window_get_desktop(display, gtk_widget_get_window(GTK_WIDGET(d->object))); + c_desktop = display_get_desktop(display); + } + + if ((e->changed_mask & GDK_WINDOW_STATE_ICONIFIED) && + (e->new_window_state & GDK_WINDOW_STATE_ICONIFIED) && + (w_desktop == c_desktop || w_desktop < 0)) { + + ret = ca_gtk_play_for_widget(GTK_WIDGET(d->object), 0, + CA_PROP_EVENT_ID, "window-minimized", + CA_PROP_EVENT_DESCRIPTION, "Window minimized", + CA_PROP_CANBERRA_CACHE_CONTROL, "permanent", + NULL); + + g_object_set_qdata(d->object, was_iconized_quark, GINT_TO_POINTER(1)); + + } else if ((e->changed_mask & (GDK_WINDOW_STATE_MAXIMIZED|GDK_WINDOW_STATE_FULLSCREEN)) && + (e->new_window_state & (GDK_WINDOW_STATE_MAXIMIZED|GDK_WINDOW_STATE_FULLSCREEN))) { + + ret = ca_gtk_play_for_widget(GTK_WIDGET(d->object), 0, + CA_PROP_EVENT_ID, "window-maximized", + CA_PROP_EVENT_DESCRIPTION, "Window maximized", + CA_PROP_CANBERRA_CACHE_CONTROL, "permanent", + NULL); + + g_object_set_qdata(d->object, was_iconized_quark, GINT_TO_POINTER(0)); + + } else if ((e->changed_mask & GDK_WINDOW_STATE_ICONIFIED) && + !(e->new_window_state & GDK_WINDOW_STATE_ICONIFIED) && + g_object_get_qdata(d->object, was_iconized_quark)) { + + ret = ca_gtk_play_for_widget(GTK_WIDGET(d->object), 0, + CA_PROP_EVENT_ID, "window-unminimized", + CA_PROP_EVENT_DESCRIPTION, "Window unminimized", + CA_PROP_CANBERRA_CACHE_CONTROL, "permanent", + NULL); + + g_object_set_qdata(d->object, was_iconized_quark, GINT_TO_POINTER(0)); + + } else if ((e->changed_mask & (GDK_WINDOW_STATE_MAXIMIZED|GDK_WINDOW_STATE_FULLSCREEN)) && + !(e->new_window_state & (GDK_WINDOW_STATE_MAXIMIZED|GDK_WINDOW_STATE_FULLSCREEN))) { + + ret = ca_gtk_play_for_widget(GTK_WIDGET(d->object), 0, + CA_PROP_EVENT_ID, "window-unmaximized", + CA_PROP_EVENT_DESCRIPTION, "Window unmaximized", + CA_PROP_CANBERRA_CACHE_CONTROL, "permanent", + NULL); + } + } + + if (GTK_IS_CHECK_MENU_ITEM(d->object) && d->signal_id == signal_id_check_menu_item_toggled) { + + if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(d->object))) + ret = ca_gtk_play_for_event(d->event, 0, + CA_PROP_EVENT_ID, "button-toggle-on", + CA_PROP_EVENT_DESCRIPTION, "Check menu item checked", + CA_PROP_CANBERRA_CACHE_CONTROL, "permanent", + NULL); + else + ret = ca_gtk_play_for_event(d->event, 0, + CA_PROP_EVENT_ID, "button-toggle-off", + CA_PROP_EVENT_DESCRIPTION, "Check menu item unchecked", + CA_PROP_CANBERRA_CACHE_CONTROL, "permanent", + NULL); + + } else if (GTK_IS_MENU_ITEM(d->object) && d->signal_id == signal_id_menu_item_activate) { + + if (!gtk_menu_item_get_submenu(GTK_MENU_ITEM(d->object))) + ret = ca_gtk_play_for_event(d->event, 0, + CA_PROP_EVENT_ID, "menu-click", + CA_PROP_EVENT_DESCRIPTION, "Menu item clicked", + CA_PROP_CANBERRA_CACHE_CONTROL, "permanent", + NULL); + } + + if (GTK_IS_TOGGLE_BUTTON(d->object)) { + + if (d->signal_id == signal_id_toggle_button_toggled) { + + if (!is_child_of_combo_box(GTK_WIDGET(d->object))) { + + /* We don't want to play this sound if this is a toggle + * button belonging to combo box. */ + + if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(d->object))) + ret = ca_gtk_play_for_event(d->event, 0, + CA_PROP_EVENT_ID, "button-toggle-on", + CA_PROP_EVENT_DESCRIPTION, "Toggle button checked", + CA_PROP_CANBERRA_CACHE_CONTROL, "permanent", + NULL); + else + ret = ca_gtk_play_for_event(d->event, 0, + CA_PROP_EVENT_ID, "button-toggle-off", + CA_PROP_EVENT_DESCRIPTION, "Toggle button unchecked", + CA_PROP_CANBERRA_CACHE_CONTROL, "permanent", + NULL); + } + } + + } else if (GTK_IS_LINK_BUTTON(d->object)) { + + if (d->signal_id == signal_id_button_pressed) { + ret = ca_gtk_play_for_event(d->event, 0, + CA_PROP_EVENT_ID, "link-pressed", + CA_PROP_EVENT_DESCRIPTION, "Link pressed", + CA_PROP_CANBERRA_CACHE_CONTROL, "permanent", + NULL); + + } else if (d->signal_id == signal_id_button_released) { + + ret = ca_gtk_play_for_event(d->event, 0, + CA_PROP_EVENT_ID, "link-released", + CA_PROP_EVENT_DESCRIPTION, "Link released", + CA_PROP_CANBERRA_CACHE_CONTROL, "permanent", + NULL); + } + + } else if (GTK_IS_BUTTON(d->object) && !GTK_IS_TOGGLE_BUTTON(d->object)) { + + if (d->signal_id == signal_id_button_pressed) { + ret = ca_gtk_play_for_event(d->event, 0, + CA_PROP_EVENT_ID, "button-pressed", + CA_PROP_EVENT_DESCRIPTION, "Button pressed", + CA_PROP_CANBERRA_CACHE_CONTROL, "permanent", + NULL); + + } else if (d->signal_id == signal_id_button_released) { + GtkDialog *dialog; + gboolean dont_play = FALSE; + + if ((dialog = find_parent_dialog(GTK_WIDGET(d->object)))) { + int response; + + /* Don't play the click sound if this is a response widget + * we will generate a dialog-xxx event sound anyway. */ + + response = gtk_dialog_get_response_for_widget(dialog, GTK_WIDGET(d->object)); + dont_play = !!translate_response(response); + } + + if (!dont_play) + ret = ca_gtk_play_for_event(d->event, 0, + CA_PROP_EVENT_ID, "button-released", + CA_PROP_EVENT_DESCRIPTION, "Button released", + CA_PROP_CANBERRA_CACHE_CONTROL, "permanent", + NULL); + } + } + + if (GTK_IS_NOTEBOOK(d->object) && d->signal_id == signal_id_notebook_switch_page) { + ret = ca_gtk_play_for_event(d->event, 0, + CA_PROP_EVENT_ID, "notebook-tab-changed", + CA_PROP_EVENT_DESCRIPTION, "Tab changed", + CA_PROP_CANBERRA_CACHE_CONTROL, "permanent", + NULL); + goto finish; + } + + if (GTK_IS_TREE_VIEW(d->object) && d->signal_id == signal_id_tree_view_cursor_changed) { + ret = ca_gtk_play_for_event(d->event, 0, + CA_PROP_EVENT_ID, "item-selected", + CA_PROP_EVENT_DESCRIPTION, "Item selected", + CA_PROP_CANBERRA_CACHE_CONTROL, "permanent", + NULL); + goto finish; + } + + if (GTK_IS_ICON_VIEW(d->object) && d->signal_id == signal_id_icon_view_selection_changed) { + ret = ca_gtk_play_for_event(d->event, 0, + CA_PROP_EVENT_ID, "item-selected", + CA_PROP_EVENT_DESCRIPTION, "Item selected", + CA_PROP_CANBERRA_CACHE_CONTROL, "permanent", + NULL); + goto finish; + } + + if (GTK_IS_EXPANDER(d->object) && d->signal_id == signal_id_expander_activate) { + + if (gtk_expander_get_expanded(GTK_EXPANDER(d->object))) + ret = ca_gtk_play_for_event(d->event, 0, + CA_PROP_EVENT_ID, "expander-toggle-on", + CA_PROP_EVENT_DESCRIPTION, "Expander expanded", + CA_PROP_CANBERRA_CACHE_CONTROL, "permanent", + NULL); + else + ret = ca_gtk_play_for_event(d->event, 0, + CA_PROP_EVENT_ID, "expander-toggle-off", + CA_PROP_EVENT_DESCRIPTION, "Expander unexpanded", + CA_PROP_CANBERRA_CACHE_CONTROL, "permanent", + NULL); + + goto finish; + } + + if (GTK_IS_WIDGET(d->object)) { + + if (d->signal_id == signal_id_widget_drag_begin) { + + ret = ca_gtk_play_for_event(d->event, 0, + CA_PROP_EVENT_ID, "drag-start", + CA_PROP_EVENT_DESCRIPTION, "Drag started", + CA_PROP_CANBERRA_CACHE_CONTROL, "permanent", + NULL); + goto finish; + + } else if (d->signal_id == signal_id_widget_drag_drop) { + + ret = ca_gtk_play_for_event(d->event, 0, + CA_PROP_EVENT_ID, "drag-accept", + CA_PROP_EVENT_DESCRIPTION, "Drag accepted", + CA_PROP_CANBERRA_CACHE_CONTROL, "permanent", + NULL); + goto finish; + + } else if (d->signal_id == signal_id_widget_drag_failed) { + + ret = ca_gtk_play_for_event(d->event, 0, + CA_PROP_EVENT_ID, "drag-fail", + CA_PROP_EVENT_DESCRIPTION, "Drag failed", + CA_PROP_CANBERRA_CACHE_CONTROL, "permanent", + NULL); + goto finish; + } + } + +finish: + + ; + /* if (ret != CA_SUCCESS) */ + /* g_warning("Failed to play event sound: %s", ca_strerror(ret)); */ +} + +static void dispatch_queue(void) { + SoundEventData *d; + + while ((d = g_queue_pop_head(&sound_event_queue))) { + + if (!(d = filter_sound_event(d))) + continue; + + dispatch_sound_event(d); + free_sound_event(d); + } +} + +static gboolean idle_cb(void *userdata) { + idle_id = 0; + + dispatch_queue(); + + return FALSE; +} + +static void connect_settings(void); + +static gboolean emission_hook_cb(GSignalInvocationHint *hint, guint n_param_values, const GValue *param_values, gpointer data) { + static SoundEventData *d = NULL; + GdkEvent *e; + GObject *object; + + connect_settings(); + + if (disabled) + return TRUE; + + object = g_value_get_object(¶m_values[0]); + + /* g_message("signal '%s' on object of type '%s' with name '%s'", */ + /* g_signal_name(hint->signal_id), */ + /* G_OBJECT_TYPE_NAME(object), */ + /* gtk_widget_get_name(GTK_WIDGET(object))); */ + + /* if (GTK_IS_WINDOW(object)) */ + /* g_message("window role='%s' title='%s' type='%u'", */ + /* gtk_window_get_role(GTK_WINDOW(object)), */ + /* gtk_window_get_title(GTK_WINDOW(object)), */ + /* gtk_window_get_type_hint(GTK_WINDOW(object))); */ + + /* Filter a few very often occuring signals as quickly as possible */ + if ((hint->signal_id == signal_id_widget_hide || + hint->signal_id == signal_id_widget_show || + hint->signal_id == signal_id_widget_window_state_event) && + !GTK_IS_WINDOW(object)) + return TRUE; + + if (hint->signal_id != signal_id_widget_hide && + hint->signal_id != signal_id_dialog_response && + !gtk_widget_is_drawable(GTK_WIDGET (object))) + return TRUE; + + d = g_slice_new0(SoundEventData); + + d->object = g_object_ref(object); + + d->signal_id = hint->signal_id; + + if (d->signal_id == signal_id_widget_window_state_event) { + d->event = gdk_event_copy(g_value_peek_pointer(¶m_values[1])); + } else if ((e = gtk_get_current_event())) + d->event = gdk_event_copy(e); + + if (n_param_values > 1) { + g_value_init(&d->arg1, G_VALUE_TYPE(¶m_values[1])); + g_value_copy(¶m_values[1], &d->arg1); + d->arg1_is_set = TRUE; + } + + g_queue_push_tail(&sound_event_queue, d); + + if (idle_id == 0) + idle_id = gdk_threads_add_idle_full(GDK_PRIORITY_REDRAW-1, (GSourceFunc) idle_cb, NULL, NULL); + + return TRUE; +} + +static void install_hook(GType type, const char *sig, guint *sn) { + GTypeClass *type_class; + + type_class = g_type_class_ref(type); + + *sn = g_signal_lookup(sig, type); + g_signal_add_emission_hook(*sn, 0, emission_hook_cb, NULL, NULL); + + g_type_class_unref(type_class); +} + +static void read_enable_input_feedback_sounds(GtkSettings *s) { + gboolean enabled = !disabled; + + if (g_getenv("CANBERRA_FORCE_INPUT_FEEDBACK_SOUNDS")) + disabled = FALSE; + else { + g_object_get(G_OBJECT(s), "gtk-enable-input-feedback-sounds", &enabled, NULL); + disabled = !enabled; + } +} + +static void enable_input_feedback_sounds_changed(GtkSettings *s, GParamSpec *arg1, gpointer userdata) { + read_enable_input_feedback_sounds(s); +} + +static void connect_settings(void) { + GtkSettings *s; + static gboolean connected = FALSE; + + if (connected) + return; + + if (!(s = gtk_settings_get_default())) + return; + + if (g_object_class_find_property(G_OBJECT_GET_CLASS(s), "gtk-enable-input-feedback-sounds")) { + g_signal_connect(G_OBJECT(s), "notify::gtk-enable-input-feedback-sounds", G_CALLBACK(enable_input_feedback_sounds_changed), NULL); + read_enable_input_feedback_sounds(s); + } else + g_debug("This Gtk+ version doesn't have the GtkSettings::gtk-enable-input-feedback-sounds property."); + + connected = TRUE; +} + +#if GTK_CHECK_VERSION(3,0,0) +#warning "We really need a quit handler in Gtk 3.0, https://bugzilla.gnome.org/show_bug.cgi?id=639770" +#else +static gboolean quit_handler(gpointer data) { + dispatch_queue(); + return FALSE; +} +#endif + +G_MODULE_EXPORT void gtk_module_init(gint *argc, gchar ***argv[]) { + + /* This is the same quark libgnomeui uses! */ + disable_sound_quark = g_quark_from_string("gnome_disable_sound_events"); + was_iconized_quark = g_quark_from_string("canberra_was_iconized"); + is_xembed_quark = g_quark_from_string("canberra_is_xembed"); + + /* Hook up the gtk setting */ + connect_settings(); + + install_hook(GTK_TYPE_WINDOW, "show", &signal_id_widget_show); + install_hook(GTK_TYPE_WINDOW, "hide", &signal_id_widget_hide); + install_hook(GTK_TYPE_DIALOG, "response", &signal_id_dialog_response); + install_hook(GTK_TYPE_MENU_ITEM, "activate", &signal_id_menu_item_activate); + install_hook(GTK_TYPE_CHECK_MENU_ITEM, "toggled", &signal_id_check_menu_item_toggled); + install_hook(GTK_TYPE_TOGGLE_BUTTON, "toggled", &signal_id_toggle_button_toggled); + install_hook(GTK_TYPE_BUTTON, "pressed", &signal_id_button_pressed); + install_hook(GTK_TYPE_BUTTON, "released", &signal_id_button_released); + install_hook(GTK_TYPE_WIDGET, "window-state-event", &signal_id_widget_window_state_event); + install_hook(GTK_TYPE_NOTEBOOK, "switch-page", &signal_id_notebook_switch_page); + install_hook(GTK_TYPE_TREE_VIEW, "cursor-changed", &signal_id_tree_view_cursor_changed); + install_hook(GTK_TYPE_ICON_VIEW, "selection-changed", &signal_id_icon_view_selection_changed); + install_hook(GTK_TYPE_WIDGET, "drag-begin", &signal_id_widget_drag_begin); + install_hook(GTK_TYPE_WIDGET, "drag-drop", &signal_id_widget_drag_drop); + install_hook(GTK_TYPE_WIDGET, "drag-failed", &signal_id_widget_drag_failed); + install_hook(GTK_TYPE_EXPANDER, "activate", &signal_id_expander_activate); + +#if !GTK_CHECK_VERSION(3,0,0) + gtk_quit_add(1, quit_handler, NULL); +#endif +} + +G_MODULE_EXPORT gchar* g_module_check_init(GModule *module); + +G_MODULE_EXPORT gchar* g_module_check_init(GModule *module) { + g_module_make_resident(module); + return NULL; +} diff --git a/.flatpak-builder/cache/objects/41/19bc893b550fc25e4b40c12553981a8fb500ad2b359fc6e19e8dbb53b6c177.dirtree b/.flatpak-builder/cache/objects/41/19bc893b550fc25e4b40c12553981a8fb500ad2b359fc6e19e8dbb53b6c177.dirtree new file mode 100644 index 0000000..b7f2ead Binary files /dev/null and b/.flatpak-builder/cache/objects/41/19bc893b550fc25e4b40c12553981a8fb500ad2b359fc6e19e8dbb53b6c177.dirtree differ diff --git a/.flatpak-builder/cache/objects/41/8ccd4067ae839e89f2cabea39320f8b1aed004b50ae44b3a6b687f8113f849.file b/.flatpak-builder/cache/objects/41/8ccd4067ae839e89f2cabea39320f8b1aed004b50ae44b3a6b687f8113f849.file new file mode 100644 index 0000000..86f9363 --- /dev/null +++ b/.flatpak-builder/cache/objects/41/8ccd4067ae839e89f2cabea39320f8b1aed004b50ae44b3a6b687f8113f849.file @@ -0,0 +1,239 @@ +/* + * Copyright (C) 2006 - 2013 Vivien Malerba + * Copyright (C) 2007 Armin Burgmeier + * Copyright (C) 2007 Murray Cumming + * Copyright (C) 2009 Bas Driessen + * Copyright (C) 2010 David King + * Copyright (C) 2010 Jonh Wendell + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "gda-handler-bin.h" +#include +#include +#include +#include +#include + +struct _GdaHandlerBin +{ + GObject parent_instance; + + guint nb_g_types; + GType *valid_g_types; +}; + +static void data_handler_iface_init (GdaDataHandlerInterface *iface); + +G_DEFINE_TYPE_EXTENDED (GdaHandlerBin, gda_handler_bin, G_TYPE_OBJECT, 0, + G_IMPLEMENT_INTERFACE (GDA_TYPE_DATA_HANDLER, data_handler_iface_init)) + +/** + * gda_handler_bin_new: + * + * Creates a data handler for binary values + * + * Returns: (type GdaHandlerBin) (transfer full): the new object + */ +GdaDataHandler * +gda_handler_bin_new (void) +{ + GObject *obj; + + obj = g_object_new (GDA_TYPE_HANDLER_BIN, NULL); + + return (GdaDataHandler *) obj; +} + + +static gchar * +gda_handler_bin_get_sql_from_value (G_GNUC_UNUSED GdaDataHandler *iface, const GValue *value) +{ + g_assert (value); + + gchar *retval; + if (gda_value_isa ((GValue *) value, GDA_TYPE_BINARY)) { + gchar *str, *str2; + str = gda_binary_to_string (gda_value_get_binary ((GValue *) value), 0); + str2 = gda_default_escape_string (str); + g_free (str); + retval = g_strdup_printf ("'%s'", str2); + g_free (str2); + } + else { + GdaBlob *blob; + GdaBinary *bin; + blob = (GdaBlob*) gda_value_get_blob ((GValue *) value); + bin = (GdaBinary *) blob; + if (gda_blob_get_op (blob) && + (gda_binary_get_size (bin) != gda_blob_op_get_length (gda_blob_get_op (blob)))) + gda_blob_op_read_all (gda_blob_get_op (blob), blob); + + gchar *str, *str2; + str = gda_binary_to_string (bin, 0); + str2 = gda_default_escape_string (str); + g_free (str); + retval = g_strdup_printf ("'%s'", str2); + g_free (str2); + } + + return retval; +} + +static gchar * +gda_handler_bin_get_str_from_value (G_GNUC_UNUSED GdaDataHandler *iface, const GValue *value) +{ + g_assert (value); + + gchar *retval = NULL; + if (value) { + if (gda_value_isa ((GValue *) value, GDA_TYPE_BINARY)) + retval = gda_binary_to_string (gda_value_get_binary ((GValue *) value), 0); + else { + GdaBlob *blob; + blob = (GdaBlob*) gda_value_get_blob ((GValue *) value); + if (gda_blob_get_op (blob)) + gda_blob_op_read_all (gda_blob_get_op (blob), blob); + retval = gda_binary_to_string ((GdaBinary *) blob, 0); + } + } + + return retval; +} + +static GValue * +gda_handler_bin_get_value_from_str (G_GNUC_UNUSED GdaDataHandler *iface, const gchar *str, GType type) +{ + g_assert (str); + + GValue *value = NULL; + if (type == GDA_TYPE_BINARY) { + GdaBinary *bin; + bin = gda_string_to_binary (str); + if (bin) { + value = gda_value_new (GDA_TYPE_BINARY); + gda_value_take_binary (value, bin); + } + } + else { + GdaBlob *blob; + blob = gda_string_to_blob (str); + if (blob) { + value = gda_value_new (GDA_TYPE_BLOB); + gda_value_take_blob (value, blob); + } + } + + return value; +} + +static GValue * +gda_handler_bin_get_value_from_sql (G_GNUC_UNUSED GdaDataHandler *iface, const gchar *sql, GType type) +{ + g_assert (sql); + + GValue *value = NULL; + if (*sql) { + gint i = strlen (sql); + if ((i>=2) && (*sql=='\'') && (sql[i-1]=='\'')) { + gchar *str = g_strdup (sql); + gchar *unstr; + + str[i-1] = 0; + unstr = gda_default_unescape_string (str+1); + if (unstr) { + value = gda_handler_bin_get_value_from_str (iface, unstr, type); + g_free (unstr); + } + g_free (str); + } + } + + return value; +} + +static gboolean +gda_handler_bin_accepts_g_type (GdaDataHandler *iface, GType type) +{ + GdaHandlerBin *hdl; + guint i; + + g_assert (iface); + hdl = (GdaHandlerBin*) (iface); + + for (i = 0; i < hdl->nb_g_types; i++) { + if (hdl->valid_g_types [i] == type) + return TRUE; + } + + return FALSE; +} + +static const gchar * +gda_handler_bin_get_descr (GdaDataHandler *iface) +{ + g_return_val_if_fail (GDA_IS_HANDLER_BIN (iface), NULL); + return g_object_get_data (G_OBJECT (iface), "descr"); +} + +static void +gda_handler_bin_init (GdaHandlerBin * hdl) +{ + hdl->nb_g_types = 2; + hdl->valid_g_types = g_new0 (GType, hdl->nb_g_types); + hdl->valid_g_types[0] = GDA_TYPE_BINARY; + hdl->valid_g_types[1] = GDA_TYPE_BLOB; + + g_object_set_data (G_OBJECT (hdl), "name", "InternalBin"); + g_object_set_data (G_OBJECT (hdl), "descr", _("Binary representation")); +} + +static void +gda_handler_bin_dispose (GObject * object) +{ + GdaHandlerBin *hdl; + + g_return_if_fail (object != NULL); + g_return_if_fail (GDA_IS_HANDLER_BIN (object)); + + hdl = GDA_HANDLER_BIN (object); + + g_clear_pointer (&hdl->valid_g_types, g_free); + + /* for the parent class */ + G_OBJECT_CLASS (gda_handler_bin_parent_class)->dispose (object); +} + +static void +data_handler_iface_init (GdaDataHandlerInterface *iface) +{ + iface->get_sql_from_value = gda_handler_bin_get_sql_from_value; + iface->get_str_from_value = gda_handler_bin_get_str_from_value; + iface->get_value_from_sql = gda_handler_bin_get_value_from_sql; + iface->get_value_from_str = gda_handler_bin_get_value_from_str; + iface->get_sane_init_value = NULL; + iface->accepts_g_type = gda_handler_bin_accepts_g_type; + iface->get_descr = gda_handler_bin_get_descr; +} + +static void +gda_handler_bin_class_init (GdaHandlerBinClass * class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (class); + + object_class->dispose = gda_handler_bin_dispose; +} diff --git a/.flatpak-builder/cache/objects/41/d8bb3f8ca32c35040d3ebbf983ee69e68f80552332ffc937ddc41636942770.file b/.flatpak-builder/cache/objects/41/d8bb3f8ca32c35040d3ebbf983ee69e68f80552332ffc937ddc41636942770.file new file mode 100644 index 0000000..440d3ea --- /dev/null +++ b/.flatpak-builder/cache/objects/41/d8bb3f8ca32c35040d3ebbf983ee69e68f80552332ffc937ddc41636942770.file @@ -0,0 +1,296 @@ +/* + * Copyright (C) 2001 - 2003 Rodrigo Moya + * Copyright (C) 2002 - 2003 Gonzalo Paniagua Javier + * Copyright (C) 2002 - 2015 Vivien Malerba + * Copyright (C) 2003 Akira TAGOH + * Copyright (C) 2003 Danilo Schoeneberg + * Copyright (C) 2003 Laurent Sansonetti + * Copyright (C) 2004 - 2011 Murray Cumming + * Copyright (C) 2004 Paisa Seeluangsawat + * Copyright (C) 2008 Przemysław Grzegorczyk + * Copyright (C) 2009 Bas Driessen + * Copyright (C) 2011 - 2017 Daniel Espinosa + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GDA_VALUE_H__ +#define __GDA_VALUE_H__ + +#include +#include +#include +#include +#include + +G_BEGIN_DECLS + +#define GDA_TIMEZONE_INVALID (2*12*60*60) + +/* Definition of the GType's values used in GValue*/ +#define GDA_TYPE_NULL (gda_null_get_type()) +#define GDA_TYPE_DEFAULT (gda_default_get_type()) +#define GDA_TYPE_BLOB (gda_blob_get_type()) +#define GDA_TYPE_GEOMETRIC_POINT (gda_geometric_point_get_type()) +#define GDA_TYPE_SHORT (gda_short_get_type()) +#define GDA_TYPE_USHORT (gda_ushort_get_type()) +#define GDA_TYPE_TIME (gda_time_get_type()) +#define GDA_TYPE_TEXT (gda_text_get_type()) + +/* Definition of the GDA_VALUE_HOLDS macros */ +#define GDA_VALUE_HOLDS_NULL(value) G_VALUE_HOLDS(value, GDA_TYPE_NULL) +#define GDA_VALUE_HOLDS_DEFAULT(value) G_VALUE_HOLDS(value, GDA_TYPE_DEFAULT) +#define GDA_VALUE_HOLDS_BLOB(value) G_VALUE_HOLDS(value, GDA_TYPE_BLOB) +#define GDA_VALUE_HOLDS_GEOMETRIC_POINT(value) G_VALUE_HOLDS(value, GDA_TYPE_GEOMETRIC_POINT) +#define GDA_VALUE_HOLDS_SHORT(value) G_VALUE_HOLDS(value, GDA_TYPE_SHORT) +#define GDA_VALUE_HOLDS_USHORT(value) G_VALUE_HOLDS(value, GDA_TYPE_USHORT) +#define GDA_VALUE_HOLDS_TIME(value) G_VALUE_HOLDS(value, GDA_TYPE_TIME) +#define GDA_VALUE_HOLDS_TEXT(value) G_VALUE_HOLDS(value, GDA_TYPE_TEXT) + +/* GdaText */ + +typedef struct _GdaText GdaText; + +GType gda_text_get_type (void) G_GNUC_CONST; +GdaText *gda_text_new (); +void gda_text_free (GdaText *text); +const gchar *gda_text_get_string (GdaText *text); +void gda_text_set_string (GdaText *text, const gchar *str); +void gda_text_take_string (GdaText *text, gchar *str); + +/* GdaNumeric */ +typedef struct _GdaNumeric GdaNumeric; + +#define GDA_TYPE_NUMERIC (gda_numeric_get_type()) +#define GDA_VALUE_HOLDS_NUMERIC(value) G_VALUE_HOLDS(value, GDA_TYPE_NUMERIC) + +GType gda_numeric_get_type (void) G_GNUC_CONST; +GdaNumeric* gda_numeric_new (void); +GdaNumeric* gda_numeric_copy (GdaNumeric *src); +void gda_numeric_set_from_string (GdaNumeric *numeric, const gchar* str); +void gda_numeric_set_double (GdaNumeric *numeric, gdouble number); +gdouble gda_numeric_get_double (const GdaNumeric *numeric); +void gda_numeric_set_precision (GdaNumeric *numeric, glong precision); +glong gda_numeric_get_precision (const GdaNumeric *numeric); +void gda_numeric_set_width (GdaNumeric *numeric, glong width); +glong gda_numeric_get_width (const GdaNumeric *numeric); +gchar* gda_numeric_get_string (const GdaNumeric *numeric); +void gda_numeric_free (GdaNumeric *numeric); + +/** + * GdaTime: + * + * Represents a time information. + */ +typedef struct _GDateTime GdaTime; + +GType gda_time_get_type (void) G_GNUC_CONST; +GdaTime* gda_time_new (void); +GdaTime* gda_time_new_from_date_time (GDateTime *dt); +GdaTime* gda_time_new_from_values (gushort hour, gushort minute, gushort second, gulong fraction, glong timezone); +GdaTime* gda_time_copy (const GdaTime* time); +void gda_time_free (GdaTime* time); + +gushort gda_time_get_hour (const GdaTime* time); +void gda_time_set_hour (GdaTime* time, gushort hour); +gushort gda_time_get_minute (const GdaTime* time); +void gda_time_set_minute (GdaTime* time, gushort minute); +gushort gda_time_get_second (const GdaTime* time); +void gda_time_set_second (GdaTime* time, gushort second); +gulong gda_time_get_fraction (const GdaTime *time); +void gda_time_set_fraction (GdaTime* time, gulong fraction); +GTimeZone* gda_time_get_tz (const GdaTime *time); +glong gda_time_get_timezone (const GdaTime *time); + +G_DEPRECATED +gboolean gda_time_valid (const GdaTime *time); +GdaTime *gda_time_to_timezone (GdaTime *time, GTimeZone *ntz); +GdaTime *gda_time_to_utc (GdaTime *time); +gchar* gda_time_to_string (GdaTime *time); +gchar* gda_time_to_string_local (GdaTime *time); +gchar* gda_time_to_string_utc (GdaTime *time); + +/** + * GdaBinary: (ref-func gda_binary_new) (unref-func gda_binary_free) (get-value-func gda_value_get_binary) (set-value-func gda_value_set_binary) + */ +typedef struct _GdaBinary GdaBinary; + +#define GDA_TYPE_BINARY (gda_binary_get_type ()) +#define GDA_VALUE_HOLDS_BINARY(value) G_VALUE_HOLDS(value, GDA_TYPE_BINARY) + +GValue* gda_value_new_binary (const guchar *val, glong size); +GdaBinary* gda_value_get_binary (const GValue *value); +void gda_value_set_binary (GValue *value, GdaBinary *binary); +void gda_value_take_binary (GValue *value, GdaBinary *binary); + + +GType gda_binary_get_type (void) G_GNUC_CONST; +GdaBinary* gda_binary_new (void); +glong gda_binary_get_size (const GdaBinary* binary); +gpointer gda_binary_get_data (GdaBinary* binary); +void gda_binary_reset_data (GdaBinary* binary); +void gda_binary_set_data (GdaBinary *binary, const guchar *val, glong size); +void gda_binary_take_data (GdaBinary *binary, guchar *val, glong size); +GdaBinary* gda_binary_copy (GdaBinary *src); +void gda_binary_free (GdaBinary *binary); + +/** + * GdaBlob: + * @data: data buffer, as a #GdaBinary + * @op: (nullable): a pointer to a #GdaBlopOp, or %NULL + * + * Represents some binary data, accessed through a #GdaBlobOp object. + * @op is generally set up by database providers when giving access to an existing BLOB in + * a database, but can be modified if needed using gda_blob_set_op(). + */ +typedef struct _GdaBlob GdaBlob; + + +GType gda_blob_get_type (void) G_GNUC_CONST; +GdaBlob* gda_blob_new (void); +GdaBinary* gda_blob_get_binary (GdaBlob *blob); +GdaBlobOp* gda_blob_get_op (GdaBlob *blob); +GdaBlob* gda_blob_copy (GdaBlob *src); +void gda_blob_free (GdaBlob *blob); +void gda_blob_set_op (GdaBlob *blob, GdaBlobOp *op); + + +#define gda_value_isa(value, type) (G_VALUE_HOLDS(value, type)) + +/** + * SECTION:gda-value + * @short_description: Assorted functions for dealing with single #GValue values + * @title: GdaValue + * @stability: Stable + * @see_also: #GValue and #GdaBlobOp + * + * &LIBGDA; manages each individual value within an opaque #GValue structure. Any GValue type can be used, + * and &LIBGDA; adds a few more data types usually found in DBMS such as NUMERIC, TIME, TIMESTAMP, GEOMETRIC POINT, BINARY and BLOB. + * + * Libgda makes a distinction between binary and blob types + * + * binary data can be inserted into an SQL statement using a + * (DBMS dependent) syntax, such as "X'ABCD'" syntax for SQLite or the binary strings syntax for PostgreSQL. Binary data + * is manipulated using a #GdaBinary structure (which is basically a bytes buffer and a length attribute). + * + * blob data are a special feature that some DBMS have which requires some non SQL code to manipulate them. + * Usually only a reference is stored in each table containing a blob, and the actual blob data resides somewhere on the disk + * (while still being managed transparently by the database). For example PotsgreSQL stores blobs as files on the disk and + * references them using object identifiers (Oid). Blob data + * is manipulated using a #GdaBlob structure which encapsulates a #GdaBinary structure and adds a reference to a + * #GdaBlobOp object used to read and write data from and to the blob. + * + * + * Please note that is distinction between binary data and blobs is Libgda only and does not reflect the DBMS's documentations; + * for instance MySQL has several BLOB types but Libgda interprets them as binary types. + * + * Each provider or connection can be queried about its blob support using the gda_server_provider_supports_feature() or + * gda_connection_supports_feature() methods. + * + * There are two special value types which are: + * + * the GDA_TYPE_NULL value which never changes and acutally represents an SQL NULL value + * the GDA_TYPE_DEFAULT value which represents a default value which &LIBGDA; does not interpret (such as when a table column's default value is a function call) + * + */ + +GValue *gda_value_new (GType type); + +GValue *gda_value_new_null (void); +GValue *gda_value_new_default (const gchar *default_val); +GValue *gda_value_new_blob (const guchar *val, glong size); +GValue *gda_value_new_blob_from_file (const gchar *filename); +GValue *gda_value_new_time_from_timet (time_t val); +GValue *gda_value_new_date_time_from_timet (time_t val); + +GValue *gda_value_new_from_string (const gchar *as_string, GType type); +GValue *gda_value_new_from_xml (const xmlNodePtr node); + +void gda_value_free (GValue *value); +void gda_value_reset_with_type (GValue *value, GType type); + +gboolean gda_value_is_null (const GValue *value); +gboolean gda_value_is_number (const GValue *value); +GValue *gda_value_copy (const GValue *value); + + +const GdaBlob *gda_value_get_blob (const GValue *value); +void gda_value_set_blob (GValue *value, const GdaBlob *blob); +void gda_value_take_blob (GValue *value, GdaBlob *blob); + +typedef struct _GdaGeometricPoint GdaGeometricPoint; +GType gda_geometric_point_get_type (void) G_GNUC_CONST; +GdaGeometricPoint *gda_geometric_point_new (void); +gdouble gda_geometric_point_get_x (GdaGeometricPoint* gp); +void gda_geometric_point_set_x (GdaGeometricPoint* gp, double x); +gdouble gda_geometric_point_get_y (GdaGeometricPoint* gp); +void gda_geometric_point_set_y (GdaGeometricPoint* gp, double y); +GdaGeometricPoint *gda_geometric_point_copy (GdaGeometricPoint *gp); +void gda_geometric_point_free (GdaGeometricPoint *gp); +const GdaGeometricPoint *gda_value_get_geometric_point (const GValue *value); +void gda_value_set_geometric_point (GValue *value, const GdaGeometricPoint *val); + +void gda_value_set_null (GValue *value); + +const GdaNumeric *gda_value_get_numeric (const GValue *value); +void gda_value_set_numeric (GValue *value, const GdaNumeric *val); +gshort gda_value_get_short (const GValue *value); +void gda_value_set_short (GValue *value, const gshort val); +gushort gda_value_get_ushort (const GValue *value); +void gda_value_set_ushort (GValue *value, const gushort val); +const GdaTime *gda_value_get_time (const GValue *value); +void gda_value_set_time (GValue *value, const GdaTime *val); +void gda_time_set_timezone (GdaTime* time, glong timezone); + + + + +gboolean gda_value_set_from_string (GValue *value, + const gchar *as_string, + GType type); +gboolean gda_value_set_from_value (GValue *value, const GValue *from); + +gint gda_value_differ (const GValue *value1, const GValue *value2); +gint gda_value_compare (const GValue *value1, const GValue *value2); +gchar *gda_value_stringify (const GValue *value); +xmlNodePtr gda_value_to_xml (const GValue *value); +gchar* gda_value_to_xml_string (const GValue *value); + +gchar *gda_binary_to_string (const GdaBinary *bin, guint maxlen); +GdaBinary *gda_string_to_binary (const gchar *str); + +gchar *gda_blob_to_string (GdaBlob *blob, guint maxlen); +GdaBlob *gda_string_to_blob (const gchar *str); + +/* Custom data types */ + +GType gda_null_get_type (void) G_GNUC_CONST; +GType gda_default_get_type (void) G_GNUC_CONST; + + + + + +/* Timestamp based on GDateTime */ + +GDateTime *gda_date_time_copy (GDateTime *ts); + +GType gda_short_get_type (void) G_GNUC_CONST; +GType gda_ushort_get_type (void) G_GNUC_CONST; + +G_END_DECLS + +#endif diff --git a/.flatpak-builder/cache/objects/41/f9ebb9c6a29dd6b4751ace4abbf14af75ebd0c935d4b118bff00c70cf6ea62.dirtree b/.flatpak-builder/cache/objects/41/f9ebb9c6a29dd6b4751ace4abbf14af75ebd0c935d4b118bff00c70cf6ea62.dirtree new file mode 100644 index 0000000..b27d000 Binary files /dev/null and b/.flatpak-builder/cache/objects/41/f9ebb9c6a29dd6b4751ace4abbf14af75ebd0c935d4b118bff00c70cf6ea62.dirtree differ diff --git a/.flatpak-builder/cache/objects/41/fcb86ffa9338ce92f0bf1f7687706a2e061098262a1e0a3fca75a8d6895f54.file b/.flatpak-builder/cache/objects/41/fcb86ffa9338ce92f0bf1f7687706a2e061098262a1e0a3fca75a8d6895f54.file new file mode 100644 index 0000000..51266c6 Binary files /dev/null and b/.flatpak-builder/cache/objects/41/fcb86ffa9338ce92f0bf1f7687706a2e061098262a1e0a3fca75a8d6895f54.file differ diff --git a/.flatpak-builder/cache/objects/42/357b9daa811462153a4d5bfec8ac5c495b3de37b58b73d6479f1d32d393ecc.dirtree b/.flatpak-builder/cache/objects/42/357b9daa811462153a4d5bfec8ac5c495b3de37b58b73d6479f1d32d393ecc.dirtree new file mode 100644 index 0000000..9f609c3 Binary files /dev/null and b/.flatpak-builder/cache/objects/42/357b9daa811462153a4d5bfec8ac5c495b3de37b58b73d6479f1d32d393ecc.dirtree differ diff --git a/.flatpak-builder/cache/objects/42/3cbbe9ff0d8f8d232568c8e818ddc5d903e895839c2d43f13578a0f5faae3a.dirtree b/.flatpak-builder/cache/objects/42/3cbbe9ff0d8f8d232568c8e818ddc5d903e895839c2d43f13578a0f5faae3a.dirtree new file mode 100644 index 0000000..b2488b6 Binary files /dev/null and b/.flatpak-builder/cache/objects/42/3cbbe9ff0d8f8d232568c8e818ddc5d903e895839c2d43f13578a0f5faae3a.dirtree differ diff --git a/.flatpak-builder/cache/objects/42/608701cd776ca7b2794844ccf63377389c9053ceebdd6eab83478169aa8231.dirtree b/.flatpak-builder/cache/objects/42/608701cd776ca7b2794844ccf63377389c9053ceebdd6eab83478169aa8231.dirtree new file mode 100644 index 0000000..4c0c872 Binary files /dev/null and b/.flatpak-builder/cache/objects/42/608701cd776ca7b2794844ccf63377389c9053ceebdd6eab83478169aa8231.dirtree differ diff --git a/.flatpak-builder/cache/objects/42/b5d52efe1957843d139f607b9fe18731ceedd1664ebf8a2ec18c8bd91ab60a.file b/.flatpak-builder/cache/objects/42/b5d52efe1957843d139f607b9fe18731ceedd1664ebf8a2ec18c8bd91ab60a.file new file mode 100644 index 0000000..7bbf449 --- /dev/null +++ b/.flatpak-builder/cache/objects/42/b5d52efe1957843d139f607b9fe18731ceedd1664ebf8a2ec18c8bd91ab60a.file @@ -0,0 +1,416 @@ +/* + * Copyright (C) 2000 - 2001 Reinhard Müller + * Copyright (C) 2000 - 2003 Rodrigo Moya + * Copyright (C) 2001 - 2013 Vivien Malerba + * Copyright (C) 2002 - 2003 Gonzalo Paniagua Javier + * Copyright (C) 2010 David King + * Copyright (C) 2010 Jonh Wendell + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +#define G_LOG_DOMAIN "GDA-batch" + +#include +#include +#include +#include +#include + +/* + * Main static functions + */ +static void gda_batch_dispose (GObject *object); + +static void gda_batch_set_property (GObject *object, + guint param_id, + const GValue *value, + GParamSpec *pspec); +static void gda_batch_get_property (GObject *object, + guint param_id, + GValue *value, + GParamSpec *pspec); + +typedef struct { + GSList *statements; /* list of GdaStatement objects */ +} GdaBatchPrivate; +G_DEFINE_TYPE_WITH_PRIVATE (GdaBatch, gda_batch, G_TYPE_OBJECT) +/* signals */ +enum +{ + CHANGED, + LAST_SIGNAL +}; + +static gint gda_batch_signals[LAST_SIGNAL] = { 0 }; + +/* properties */ +enum +{ + PROP_0, +}; + +/* module error */ +GQuark gda_batch_error_quark (void) +{ + static GQuark quark; + if (!quark) + quark = g_quark_from_static_string ("gda_batch_error"); + return quark; +} + +static void m_changed_cb (GdaBatch *batch, GdaStatement *changed_stmt); +static void +gda_batch_class_init (GdaBatchClass * klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + /** + * GdaBatch::changed: + * @batch: the #GdaBatch object + * @changed_stmt: the statement which has been changed + * + * Gets emitted whenever a #GdaStatement in the @batch object changes + */ + gda_batch_signals[CHANGED] = + g_signal_new ("changed", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (GdaBatchClass, changed), + NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, + 1, G_TYPE_OBJECT); + + klass->changed = m_changed_cb; + + object_class->dispose = gda_batch_dispose; + + /* Properties */ + object_class->set_property = gda_batch_set_property; + object_class->get_property = gda_batch_get_property; +} + +static void +m_changed_cb (G_GNUC_UNUSED GdaBatch *batch, G_GNUC_UNUSED GdaStatement *changed_stmt) +{ + +} + + +static void +gda_batch_init (GdaBatch * batch) +{ + GdaBatchPrivate *priv = gda_batch_get_instance_private (batch); + priv->statements = NULL; +} + +/** + * gda_batch_new: + * + * Creates a new #GdaBatch object + * + * Returns: the new object + */ +GdaBatch* +gda_batch_new (void) +{ + GObject *obj; + + obj = g_object_new (GDA_TYPE_BATCH, NULL); + return GDA_BATCH (obj); +} + + +/** + * gda_batch_copy: + * @orig: a #GdaBatch to make a copy of + * + * Copy constructor + * + * Returns: (transfer full): a the new copy of @orig + */ +GdaBatch * +gda_batch_copy (GdaBatch *orig) +{ + GObject *obj; + GdaBatch *batch; + GSList *list; + + g_return_val_if_fail (GDA_IS_BATCH (orig), NULL); + GdaBatchPrivate *opriv = gda_batch_get_instance_private (orig); + + obj = g_object_new (GDA_TYPE_BATCH, NULL); + batch = (GdaBatch *) obj; + GdaBatchPrivate *priv = gda_batch_get_instance_private (batch); + for (list = opriv->statements; list; list = list->next) { + GdaStatement *copy; + + copy = gda_statement_copy (GDA_STATEMENT (list->data)); + priv->statements = g_slist_prepend (priv->statements, copy); + } + priv->statements = g_slist_reverse (priv->statements); + + return batch; +} + +static void +gda_batch_dispose (GObject *object) +{ + GdaBatch *batch; + + g_return_if_fail (object != NULL); + g_return_if_fail (GDA_IS_BATCH (object)); + + batch = GDA_BATCH (object); + GdaBatchPrivate *priv = gda_batch_get_instance_private (batch); + if (priv->statements) { + g_slist_free_full (priv->statements, (GDestroyNotify) g_object_unref); + priv->statements = NULL; + } + + /* parent class */ + G_OBJECT_CLASS (gda_batch_parent_class)->dispose (object); +} + +static void +gda_batch_set_property (GObject *object, + guint param_id, + G_GNUC_UNUSED const GValue *value, + GParamSpec *pspec) +{ + GdaBatch *batch; + + batch = GDA_BATCH (object); + GdaBatchPrivate *priv = gda_batch_get_instance_private (batch); + if (priv) { + switch (param_id) { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + break; + } + } +} + +static void +gda_batch_get_property (GObject *object, + guint param_id, + G_GNUC_UNUSED GValue *value, + GParamSpec *pspec) +{ + GdaBatch *batch; + batch = GDA_BATCH (object); + GdaBatchPrivate *priv = gda_batch_get_instance_private (batch); + + if (priv) { + switch (param_id) { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + break; + } + } +} + +static void +stmt_reset_cb (GdaStatement *stmt, GdaBatch *batch) +{ + g_signal_emit (batch, gda_batch_signals [CHANGED], 0, stmt); +} + +/** + * gda_batch_add_statement: + * @batch: a #GdaBatch object + * @stmt: (transfer full): a statement to add to @batch's statements list + * + * Add @stmt to the list of statements managed by @batch. A #GdaStatement object can be + * added multiple times to a #GdaBatch object. The @batch increases reference count for @stmt and + * the @stmt instance can be freed using g_object_unref(). + */ +void +gda_batch_add_statement (GdaBatch *batch, GdaStatement *stmt) +{ + g_return_if_fail (GDA_IS_BATCH (batch)); + g_return_if_fail (GDA_IS_STATEMENT (stmt)); + GdaBatchPrivate *priv = gda_batch_get_instance_private (batch); + + g_signal_connect (G_OBJECT (stmt), "reset", + G_CALLBACK (stmt_reset_cb), batch); + + priv->statements = g_slist_append (priv->statements, stmt); + g_object_ref (stmt); +} + +/** + * gda_batch_remove_statement: + * @batch: a #GdaBatch object + * @stmt: a statement to remove from @batch's statements list + * + * Removes @stmt from the list of statements managed by @batch. If @stmt is present several + * times in @batch's statements' list, then only the first one is removed. + */ +void +gda_batch_remove_statement (GdaBatch *batch, GdaStatement *stmt) +{ + g_return_if_fail (GDA_IS_BATCH (batch)); + g_return_if_fail (GDA_IS_STATEMENT (stmt)); + GdaBatchPrivate *priv = gda_batch_get_instance_private (batch); + + if (g_slist_index (priv->statements, stmt) < 0) { + g_warning (_("Statement could not be found in batch's statements")); + return; + } + + priv->statements = g_slist_remove (priv->statements, stmt); + if (g_slist_index (priv->statements, stmt) < 0) + /* @stmt is no more in @batch's list */ + g_signal_handlers_disconnect_by_func (G_OBJECT (stmt), + G_CALLBACK (stmt_reset_cb), batch); + g_object_unref (stmt); +} + + +/** + * gda_batch_serialize: + * @batch: a #GdaBatch object + * + * Creates a string representing the contents of @batch. + * + * Returns: (transfer full): a string containing the serialized version of @batch + */ +gchar * +gda_batch_serialize (GdaBatch *batch) +{ + GSList *list; + GString *string; + gchar *str; + + g_return_val_if_fail (GDA_IS_BATCH (batch), NULL); + GdaBatchPrivate *priv = gda_batch_get_instance_private (batch); + + string = g_string_new ("{"); + g_string_append (string, "\"statements\":"); + if (priv->statements) { + g_string_append_c (string, '['); + for (list = priv->statements; list; list = list->next) { + str = gda_statement_serialize (GDA_STATEMENT (list->data)); + if (list != priv->statements) + g_string_append_c (string, ','); + g_string_append (string, str); + g_free (str); + } + g_string_append_c (string, ']'); + } + else + g_string_append (string, "null"); + g_string_append_c (string, '}'); + + str = string->str; + g_string_free (string, FALSE); + return str; +} + +/** + * gda_batch_get_statements: + * @batch: a #GdaBatch object + * + * Get a list of the #GdaStatement objects contained in @batch + * + * Returns: (element-type GdaStatement) (transfer none): a list of #GdaStatement which should not be modified. + */ +const GSList * +gda_batch_get_statements (GdaBatch *batch) +{ + g_return_val_if_fail (GDA_IS_BATCH (batch), NULL); + GdaBatchPrivate *priv = gda_batch_get_instance_private (batch); + + return priv->statements; +} + +/** + * gda_batch_get_parameters: + * @batch: a #GdaBatch object + * @out_params: (out) (transfer full) (nullable): a place to store a new #GdaSet object, or %NULL + * @error: a place to store errors, or %NULL + * + * Get a new #GdaSet object which groups all the execution parameters + * which @batch needs for all the statements it includes. + * This new object is returned though @out_params. + * + * Note that if @batch does not need any parameter, then @out_params is set to %NULL. + * + * Returns: TRUE if no error occurred. + */ +gboolean +gda_batch_get_parameters (GdaBatch *batch, GdaSet **out_params, GError **error) +{ + GdaSet *set = NULL; + GSList *list; + + g_return_val_if_fail (GDA_IS_BATCH (batch), FALSE); + + GdaBatchPrivate *priv = gda_batch_get_instance_private (batch); + + if (out_params) + *out_params = NULL; + + if (!priv->statements) + return TRUE; + + for (list = priv->statements; list; list = list->next) { + GdaSet *tmpset = NULL; + if (!gda_statement_get_parameters (GDA_STATEMENT (list->data), out_params ? &tmpset : NULL, error)) { + if (tmpset) + g_object_unref (tmpset); + if (set) + g_object_unref (set); + return FALSE; + } + + if (tmpset && gda_set_get_holders (tmpset)) { + if (!set) { + set = tmpset; + tmpset = NULL; + } + else { + /* merge @set and @tmp_set */ + GSList *holders; + for (holders = gda_set_get_holders (tmpset); holders; holders = holders->next) { + GdaHolder *holder = (GdaHolder *) holders->data; + if (! gda_set_add_holder (set, holder)) { + GdaHolder *eholder = gda_set_get_holder (set, gda_holder_get_id (holder)); + if (!eholder || + (gda_holder_get_g_type (eholder) != (gda_holder_get_g_type (holder)))) { + /* error */ + g_set_error (error, GDA_BATCH_ERROR, GDA_BATCH_CONFLICTING_PARAMETER_ERROR, + _("Conflicting parameter '%s'"), gda_holder_get_id (holder)); + g_object_unref (tmpset); + g_object_unref (set); + return FALSE; + } + } + } + } + } + if (tmpset) + g_object_unref (tmpset); + } + + if (set) { + if (out_params) + *out_params = set; + else + g_object_unref (set); + } + return TRUE; +} diff --git a/.flatpak-builder/cache/objects/42/c030178049a3611c7d205bfde96604a46125f9ceb3e4232f1eb325f57f3bb5.dirtree b/.flatpak-builder/cache/objects/42/c030178049a3611c7d205bfde96604a46125f9ceb3e4232f1eb325f57f3bb5.dirtree new file mode 100644 index 0000000..0844ce4 Binary files /dev/null and b/.flatpak-builder/cache/objects/42/c030178049a3611c7d205bfde96604a46125f9ceb3e4232f1eb325f57f3bb5.dirtree differ diff --git a/.flatpak-builder/cache/objects/43/449f1b617f11daa4e293e45e8ef61b6a28fa8f0a1e4a1d131fea6223559c1d.dirtree b/.flatpak-builder/cache/objects/43/449f1b617f11daa4e293e45e8ef61b6a28fa8f0a1e4a1d131fea6223559c1d.dirtree new file mode 100644 index 0000000..4e44c93 Binary files /dev/null and b/.flatpak-builder/cache/objects/43/449f1b617f11daa4e293e45e8ef61b6a28fa8f0a1e4a1d131fea6223559c1d.dirtree differ diff --git a/.flatpak-builder/cache/objects/43/7b4d156de99165bce4b44d574ce74f01ffddc14dd156b4dbf5cf51a16fcc2b.dirtree b/.flatpak-builder/cache/objects/43/7b4d156de99165bce4b44d574ce74f01ffddc14dd156b4dbf5cf51a16fcc2b.dirtree new file mode 100644 index 0000000..f630a14 Binary files /dev/null and b/.flatpak-builder/cache/objects/43/7b4d156de99165bce4b44d574ce74f01ffddc14dd156b4dbf5cf51a16fcc2b.dirtree differ diff --git a/.flatpak-builder/cache/objects/43/88d281896c90a035e201d0436029ee6b5329885ac452479f487b7dfc6dbcb1.dirtree b/.flatpak-builder/cache/objects/43/88d281896c90a035e201d0436029ee6b5329885ac452479f487b7dfc6dbcb1.dirtree new file mode 100644 index 0000000..4c8cf0f Binary files /dev/null and b/.flatpak-builder/cache/objects/43/88d281896c90a035e201d0436029ee6b5329885ac452479f487b7dfc6dbcb1.dirtree differ diff --git a/.flatpak-builder/cache/objects/43/88e67c5dd300f3b05d435ace38f1e072f931c37f4e7717114698b01f4c708d.dirtree b/.flatpak-builder/cache/objects/43/88e67c5dd300f3b05d435ace38f1e072f931c37f4e7717114698b01f4c708d.dirtree new file mode 100644 index 0000000..56e4af7 Binary files /dev/null and b/.flatpak-builder/cache/objects/43/88e67c5dd300f3b05d435ace38f1e072f931c37f4e7717114698b01f4c708d.dirtree differ diff --git a/.flatpak-builder/cache/objects/43/8966c390c22e06217b4ad1919539fe6d2bd2b740416ab19376b34807dfd4eb.file b/.flatpak-builder/cache/objects/43/8966c390c22e06217b4ad1919539fe6d2bd2b740416ab19376b34807dfd4eb.file new file mode 120000 index 0000000..d1ef17c --- /dev/null +++ b/.flatpak-builder/cache/objects/43/8966c390c22e06217b4ad1919539fe6d2bd2b740416ab19376b34807dfd4eb.file @@ -0,0 +1 @@ +libcanberra-gtk3.so.0.1.9 \ No newline at end of file diff --git a/.flatpak-builder/cache/objects/43/b0e8015144d0c5d0efb78484c224a3c98ef58dc86e37cd7bd457fd85316227.file b/.flatpak-builder/cache/objects/43/b0e8015144d0c5d0efb78484c224a3c98ef58dc86e37cd7bd457fd85316227.file new file mode 100644 index 0000000..49757e7 --- /dev/null +++ b/.flatpak-builder/cache/objects/43/b0e8015144d0c5d0efb78484c224a3c98ef58dc86e37cd7bd457fd85316227.file @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2006 - 2011 Vivien Malerba + * Copyright (C) 2007 Armin Burgmeier + * Copyright (C) 2007 Murray Cumming + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GDA_HANDLER_STRING__ +#define __GDA_HANDLER_STRING__ + +#include +#include + +G_BEGIN_DECLS + +#define GDA_TYPE_HANDLER_STRING (gda_handler_string_get_type()) +G_DECLARE_FINAL_TYPE (GdaHandlerString, gda_handler_string, GDA, HANDLER_STRING, GObject) + +/** + * SECTION:gda-handler-string + * @short_description: Default handler for string values + * @title: GdaHanderString + * @stability: Stable + * @see_also: #GdaDataHandler interface + * + * You should normally not need to use this API, refer to the #GdaDataHandler + * interface documentation for more information. + */ + +GdaDataHandler *gda_handler_string_new (void); +GdaDataHandler *gda_handler_string_new_with_provider (GdaServerProvider *prov, GdaConnection *cnc); + +G_END_DECLS + +#endif diff --git a/.flatpak-builder/cache/objects/43/e5bcc29f08abb7e1f276e78bd587ad0ebe48b0f9a5187e5cd4f3f1ae3435a4.file b/.flatpak-builder/cache/objects/43/e5bcc29f08abb7e1f276e78bd587ad0ebe48b0f9a5187e5cd4f3f1ae3435a4.file new file mode 100644 index 0000000..b59735b --- /dev/null +++ b/.flatpak-builder/cache/objects/43/e5bcc29f08abb7e1f276e78bd587ad0ebe48b0f9a5187e5cd4f3f1ae3435a4.file @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2006 - 2011 Vivien Malerba + * Copyright (C) 2007 Murray Cumming + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GDA_HANDLER_BOOLEAN__ +#define __GDA_HANDLER_BOOLEAN__ + +#include +#include + +G_BEGIN_DECLS + +#define GDA_TYPE_HANDLER_BOOLEAN (gda_handler_boolean_get_type()) +G_DECLARE_FINAL_TYPE (GdaHandlerBoolean, gda_handler_boolean, GDA, HANDLER_BOOLEAN, GObject) + +/** + * SECTION:gda-handler-boolean + * @short_description: Default handler for boolean values + * @title: GdaHanderBoolean + * @stability: Stable + * @see_also: #GdaDataHandler interface + * + * You should normally not need to use this API, refer to the #GdaDataHandler + * interface documentation for more information. + */ + +GdaDataHandler *gda_handler_boolean_new (void); + +G_END_DECLS + +#endif diff --git a/.flatpak-builder/cache/objects/44/203152da35eb2eb353848f8e69c028ca37e702d09f4a6aca761a5ebc596309.file b/.flatpak-builder/cache/objects/44/203152da35eb2eb353848f8e69c028ca37e702d09f4a6aca761a5ebc596309.file new file mode 100644 index 0000000..a807447 --- /dev/null +++ b/.flatpak-builder/cache/objects/44/203152da35eb2eb353848f8e69c028ca37e702d09f4a6aca761a5ebc596309.file @@ -0,0 +1,736 @@ +/* gda-db-view.c + * + * Copyright (C) 2018-2019 Pavlo Solntsev + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +#define G_LOG_DOMAIN "GDA-db-view" + +#include +#include "gda-db-view.h" +#include "gda-db-buildable.h" +#include "gda-db-base.h" +#include "gda-lockable.h" +#include "gda-server-provider.h" +#include "gda-ddl-modifiable.h" + +typedef struct +{ + gchar *mp_defstring; + gboolean m_istemp; + gboolean m_ifnoexist; + gboolean m_replace; +} GdaDbViewPrivate; + +/** + * SECTION:gda-db-view + * @short_description: Object to represent view database object + * @see_also: #GdaDbTable, #GdaDbCatalog + * @stability: Stable + * @include: libgda/libgda.h + * + * This object represents a view of a database. The view can be constracted manually + * using API or generated from xml file together with other databse objects. See #GdaDbCatalog. + * #GdaDbView implements #GdaDbBuildable interface for parsing xml file. This is typical example + * how #GdaDbView can be used + * + * |[ + * + * GdaDbView *myview = gda_db_view_new (); + * gda_db_base_set_name (GDA_DB_BASE (myview), "MyView"); + * gda_db_view_set_istemp (myview, FALSE); + * gda_db_view_set_defstring (myview, "SELECT name, project_id FROM NewEmployee"); + * + * res = gda_db_view_create (myview, fixture->cnc, TRUE, &error); + * + * if (!res) + * GDA_PGSQL_ERROR_HANDLE (error); + * ]| + */ + +static void gda_db_view_buildable_interface_init (GdaDbBuildableInterface *iface); +static void gda_ddl_modifiable_interface_init (GdaDdlModifiableInterface *iface); + +static gboolean gda_db_view_create (GdaDdlModifiable *self, GdaConnection *cnc, + gpointer user_data, GError **error); +static gboolean gda_db_view_drop (GdaDdlModifiable *self, GdaConnection *cnc, + gpointer user_data, GError **error); +static gboolean gda_db_view_rename (GdaDdlModifiable *old_name, GdaConnection *cnc, + gpointer new_name, GError **error); + +G_DEFINE_TYPE_WITH_CODE (GdaDbView, gda_db_view, GDA_TYPE_DB_BASE, + G_ADD_PRIVATE (GdaDbView) + G_IMPLEMENT_INTERFACE (GDA_TYPE_DB_BUILDABLE, + gda_db_view_buildable_interface_init) + G_IMPLEMENT_INTERFACE (GDA_TYPE_DDL_MODIFIABLE, + gda_ddl_modifiable_interface_init)) + +/* This is convenient way to name all nodes from xml file */ +enum { + GDA_DB_VIEW_NODE, + GDA_DB_VIEW_IFNOEXIST, + GDA_DB_VIEW_TEMP, + GDA_DB_VIEW_REPLACE, + GDA_DB_VIEW_NAME, + GDA_DB_VIEW_DEFSTR, + GDA_DB_VIEW_N_NODES +}; + +static const gchar *gdadbviewnodes[GDA_DB_VIEW_N_NODES] = { + "view", + "ifnoexist", + "temp", + "replace", + "name", + "definition" +}; + +enum { + PROP_0, + PROP_VIEW_TEMP, + PROP_VIEW_REPLACE, + PROP_VIEW_IFNOEXIST, + PROP_VIEW_DEFSTR, + N_PROPS +}; + +static GParamSpec *properties [N_PROPS] = {NULL}; + +/** + * gda_db_view_new: + * + * Returns: (transfer full): A new instance of #GdaDbView. + * + * Stability: Stable + * Since: 6.0 + */ +GdaDbView* +gda_db_view_new (void) +{ + return g_object_new (GDA_TYPE_DB_VIEW, NULL); +} + +static void +gda_db_view_finalize (GObject *object) +{ + GdaDbView *self = GDA_DB_VIEW(object); + GdaDbViewPrivate *priv = gda_db_view_get_instance_private (self); + + g_free (priv->mp_defstring); + + G_OBJECT_CLASS (gda_db_view_parent_class)->finalize (object); +} + +static void +gda_db_view_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + GdaDbView *self = GDA_DB_VIEW (object); + GdaDbViewPrivate *priv = gda_db_view_get_instance_private (self); + + switch (prop_id) + { + case PROP_VIEW_TEMP: + g_value_set_boolean (value,priv->m_istemp); + break; + case PROP_VIEW_REPLACE: + g_value_set_boolean (value,priv->m_replace); + break; + case PROP_VIEW_IFNOEXIST: + g_value_set_boolean (value,priv->m_ifnoexist); + break; + case PROP_VIEW_DEFSTR: + g_value_set_string (value,priv->mp_defstring); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gda_db_view_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + GdaDbView *self = GDA_DB_VIEW (object); + GdaDbViewPrivate *priv = gda_db_view_get_instance_private (self); + + switch (prop_id) + { + case PROP_VIEW_TEMP: + priv->m_istemp = g_value_get_boolean (value); + break; + case PROP_VIEW_REPLACE: + priv->m_replace = g_value_get_boolean (value); + break; + case PROP_VIEW_IFNOEXIST: + priv->m_ifnoexist = g_value_get_boolean (value); + break; + case PROP_VIEW_DEFSTR: + g_free (priv->mp_defstring); + priv->mp_defstring = g_value_dup_string (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gda_db_view_class_init (GdaDbViewClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->finalize = gda_db_view_finalize; + object_class->get_property = gda_db_view_get_property; + object_class->set_property = gda_db_view_set_property; + + properties[PROP_VIEW_TEMP] = + g_param_spec_boolean ("istemp", + "IsTemp", + "Set if view is temp", + FALSE, + G_PARAM_READWRITE); + properties[PROP_VIEW_REPLACE] = + g_param_spec_boolean ("replace", + "Replace", + "Set if view should be repalced", + TRUE, + G_PARAM_READWRITE); + properties[PROP_VIEW_IFNOEXIST] = + g_param_spec_boolean ("ifnoexist", + "IfNoExist", + "Create view if it doesn't exist", + FALSE, + G_PARAM_READWRITE); + properties[PROP_VIEW_DEFSTR] = + g_param_spec_string ("defstring", + "Definition", + "Define view", + FALSE, + G_PARAM_READWRITE); + + g_object_class_install_properties (object_class, N_PROPS, properties); +} + +static void +gda_db_view_init (GdaDbView *self) +{ + GdaDbViewPrivate *priv = gda_db_view_get_instance_private (self); + + priv->mp_defstring = NULL; + priv->mp_defstring = NULL; + priv->m_istemp = TRUE; +} + +static gboolean +gda_db_view_parse_node (GdaDbBuildable *buildable, + xmlNodePtr node, + GError **error) +{ + g_return_val_if_fail (node, FALSE); + g_return_val_if_fail (node, FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + GdaDbView *self = GDA_DB_VIEW (buildable); + +/* + * + * SELECT id,name FROM CUSTOMER + * + */ + + xmlChar *prop = NULL; + + prop = xmlGetProp (node, (xmlChar *)gdadbviewnodes[GDA_DB_VIEW_NAME]); + g_assert (prop); /* Bug with xml valdation */ + + gda_db_base_set_name (GDA_DB_BASE(self), (gchar*)prop); + xmlFree (prop); + prop = NULL; + + prop = xmlGetProp (node, (xmlChar *)gdadbviewnodes[GDA_DB_VIEW_REPLACE]); + if (prop) + g_object_set (G_OBJECT(self), "replace", *prop == 't' || *prop == 'T' ? TRUE : FALSE, NULL); + + xmlFree (prop); + prop = NULL; + + prop = xmlGetProp (node, (xmlChar *)gdadbviewnodes[GDA_DB_VIEW_TEMP]); + if (prop) + g_object_set (G_OBJECT(self), "istemp", *prop == 't' || *prop == 'T' ? TRUE : FALSE, NULL); + + xmlFree (prop); + prop = NULL; + + prop = xmlGetProp (node, (xmlChar *)gdadbviewnodes[GDA_DB_VIEW_IFNOEXIST]); + if (prop) + g_object_set (G_OBJECT(self), "ifnoexist", *prop == 't' || *prop == 'T' ? TRUE : FALSE, NULL); + + xmlFree (prop); + prop = NULL; +/* Loop here is for the following expension if we need to add more children + * nodes it will be easy to add + */ + for (xmlNodePtr it = node->children; it ; it = it->next) + { + if (!g_strcmp0 ((char *)it->name,gdadbviewnodes[GDA_DB_VIEW_DEFSTR])) + { + xmlChar *def = xmlNodeGetContent (it); + gda_db_view_set_defstring (self, (gchar*)def); + xmlFree (def); + } + } + + return TRUE; +} + +static gboolean +gda_db_view_write_node (GdaDbBuildable *buildable, + xmlNodePtr rootnode, + GError **error) +{ + g_return_val_if_fail (buildable, FALSE); + g_return_val_if_fail (rootnode, FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + GdaDbView *self = GDA_DB_VIEW (buildable); + GdaDbViewPrivate *priv = gda_db_view_get_instance_private (self); + + xmlNodePtr node = NULL; + node = xmlNewChild (rootnode, + NULL, + BAD_CAST gdadbviewnodes[GDA_DB_VIEW_NODE], + NULL); + + xmlNewProp (node, + BAD_CAST gdadbviewnodes[GDA_DB_VIEW_NODE], + BAD_CAST gda_db_base_get_name (GDA_DB_BASE(self))); + + xmlNewProp (node, + BAD_CAST gdadbviewnodes[GDA_DB_VIEW_REPLACE], + BAD_CAST GDA_BOOL_TO_STR(priv->m_replace)); + + xmlNewProp (node, + BAD_CAST gdadbviewnodes[GDA_DB_VIEW_TEMP], + BAD_CAST GDA_BOOL_TO_STR(priv->m_istemp)); + + xmlNewProp (node, + BAD_CAST gdadbviewnodes[GDA_DB_VIEW_IFNOEXIST], + BAD_CAST GDA_BOOL_TO_STR(priv->m_ifnoexist)); + + xmlNewChild (node, + NULL, + BAD_CAST gdadbviewnodes[GDA_DB_VIEW_DEFSTR], + BAD_CAST priv->mp_defstring); + + return TRUE; +} + +static void +gda_db_view_buildable_interface_init (GdaDbBuildableInterface *iface) +{ + iface->parse_node = gda_db_view_parse_node; + iface->write_node = gda_db_view_write_node; +} + +static void gda_ddl_modifiable_interface_init (GdaDdlModifiableInterface *iface) +{ + iface->create = gda_db_view_create; + iface->drop = gda_db_view_drop; + iface->rename = gda_db_view_rename; +} +/** + * gda_db_view_get_istemp: + * @self: a #GdaDbView object + * + * Returns: %TRUE if the view is temporary, %FALSE otherwise + * + * Stability: Stable + * Since: 6.0 + */ +gboolean +gda_db_view_get_istemp (GdaDbView *self) +{ + g_return_val_if_fail (self, FALSE); + GdaDbViewPrivate *priv = gda_db_view_get_instance_private (self); + return priv->m_istemp; +} + +/** + * gda_db_view_set_istemp: + * @self: a #GdaDbView object + * @temp: value to set + * + * Stability: Stable + * Since: 6.0 + */ +void +gda_db_view_set_istemp (GdaDbView *self, + gboolean temp) +{ + g_return_if_fail (self); + GdaDbViewPrivate *priv = gda_db_view_get_instance_private (self); + priv->m_istemp = temp; +} + +/** + * gda_db_view_get_ifnoexist: + * @self: a #GdaDbView object + * + * Returns: %TRUE if th view should be created with "IF NOT EXISTS" key, %FALSE + * otherwise + * + * Stability: Stable + * Since: 6.0 + */ +gboolean +gda_db_view_get_ifnoexist (GdaDbView *self) +{ + g_return_val_if_fail (self, FALSE); + GdaDbViewPrivate *priv = gda_db_view_get_instance_private (self); + return priv->m_ifnoexist; +} + +/** + * gda_db_view_set_ifnoexist: + * @self: a #GdaDbView object + * @noexist: a value to set + * + * Stability: Stable + * Since: 6.0 + */ +void +gda_db_view_set_ifnoexist (GdaDbView *self, + gboolean noexist) +{ + g_return_if_fail (self); + GdaDbViewPrivate *priv = gda_db_view_get_instance_private (self); + priv->m_ifnoexist = noexist; +} + +/** + * gda_db_view_get_defstring: + * @self: a #GdaDbView object + * + * Returns: view definition string + * + * Stability: Stable + * Since: 6.0 + */ +const gchar* +gda_db_view_get_defstring (GdaDbView *self) +{ + g_return_val_if_fail (self, FALSE); + GdaDbViewPrivate *priv = gda_db_view_get_instance_private (self); + return priv->mp_defstring; +} + +/** + * gda_db_view_set_defstring: + * @self: a #GdaDbView object + * @str: view definition string to set. Should be valid SQL string + * + * Stability: Stable + * Since: 6.0 + */ +void +gda_db_view_set_defstring (GdaDbView *self, + const gchar *str) +{ + g_return_if_fail (self); + GdaDbViewPrivate *priv = gda_db_view_get_instance_private (self); + g_free (priv->mp_defstring); + priv->mp_defstring = g_strdup (str); +} + +/** + * gda_db_view_get_replace: + * @self: a #GdaDbView object + * + * Returns: %TRUE if the current view should replace the existing one in the + * database, %FALSE otherwise. + * + * Stability: Stable + * Since: 6.0 + */ +gboolean +gda_db_view_get_replace (GdaDbView *self) +{ + g_return_val_if_fail (self, FALSE); + GdaDbViewPrivate *priv = gda_db_view_get_instance_private (self); + + return priv->m_replace; +} + +/** + * gda_db_view_set_replace: + * @self: a #GdaDbView object + * @replace: a value to set + * + * Stability: Stable + * Since: 6.0 + */ +void +gda_db_view_set_replace (GdaDbView *self, + gboolean replace) +{ + g_return_if_fail (self); + GdaDbViewPrivate *priv = gda_db_view_get_instance_private (self); + + priv->m_replace = replace; +} + +/** + * gda_db_view_create: + * @self: a #GdaDbView instance + * @cnc: open connection for the operation + * @ifnotexists: if set to %TRUE, the view will be created using IF NOT EXISTS flag + * @error: error container + * + * This method performs CREATE_VIEW operation over @cnc using data stored in @self + * It is a convenient method to perform operation. See gda_db_view_prepare_create() if better + * flexibility is needed. + * + * For convenience, @ifnotexists should be used to specify if the view should be created if exist. + * The internal property "ifnoexists" will be ignored. + * + * Returns: %TRUE if no error, %FASLE otherwise + * + * Stability: Stable + * Since: 6.0 + */ +static gboolean +gda_db_view_create (GdaDdlModifiable *self, + GdaConnection *cnc, + gpointer user_data, + GError **error) +{ + GdaServerProvider *provider = NULL; + GdaServerOperation *op = NULL; + GdaDbView *view = GDA_DB_VIEW (self); + + gda_lockable_lock ((GdaLockable*)cnc); + + provider = gda_connection_get_provider (cnc); + GdaDbViewPrivate *priv = gda_db_view_get_instance_private (view); + + if (!gda_db_base_get_name (GDA_DB_BASE (view))) + { + g_set_error (error, GDA_DDL_MODIFIABLE_ERROR, GDA_DDL_MODIFIABLE_MISSED_DATA, + _("View name is not set")); + return FALSE; + } + + if (!priv->mp_defstring) + { + g_set_error (error, GDA_DDL_MODIFIABLE_ERROR, GDA_DDL_MODIFIABLE_MISSED_DATA, + _("View definition is not set")); + return FALSE; + } + + op = gda_server_provider_create_operation (provider, + cnc, + GDA_SERVER_OPERATION_CREATE_VIEW, + NULL, + error); + if (!op) + goto on_error; + + if (!gda_server_operation_set_value_at (op, + gda_db_base_get_name (GDA_DB_BASE(self)), + error, + "/VIEW_DEF_P/VIEW_NAME")) + goto on_error; + + if (!gda_server_operation_set_value_at (op, + GDA_BOOL_TO_STR(priv->m_replace), + error, + "/VIEW_DEF_P/VIEW_OR_REPLACE")) + goto on_error; + + if (!gda_server_operation_set_value_at (op, + GDA_BOOL_TO_STR(priv->m_istemp), + error, + "/VIEW_DEF_P/VIEW_TEMP")) + goto on_error; + + if (!gda_server_operation_set_value_at (op, + priv->mp_defstring, + error, + "/VIEW_DEF_P/VIEW_DEF")) + goto on_error; + + if(!gda_server_provider_perform_operation (provider, cnc, op, error)) + goto on_error; + + g_object_unref (op); + gda_lockable_unlock ((GdaLockable*)cnc); + return TRUE; + +on_error: + if (op) g_object_unref (op); + gda_lockable_unlock ((GdaLockable*)cnc); + return FALSE; +} + +/** + * gda_db_view_prepare_create: + * @self: a #GdaDbView instance + * @op: #GdaServerOperation instance to populate + * @error: error container + * + * Populate @op with information needed to perform CREATE_VIEW operation. This method was desgned + * for internal use and will be obsolete in the future. Do not use it for the new code. + * + * Stability: Stable + * Returns: %TRUE if succeeded and %FALSE otherwise. + */ +gboolean +gda_db_view_prepare_create (GdaDbView *self, + GdaServerOperation *op, + GError **error) +{ + g_return_val_if_fail (self, FALSE); + g_return_val_if_fail (op, FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + GdaDbViewPrivate *priv = gda_db_view_get_instance_private (self); + + if (!gda_server_operation_set_value_at (op, + gda_db_base_get_name (GDA_DB_BASE(self)), + error, + "/VIEW_DEF_P/VIEW_NAME")) + return FALSE; + + if (!gda_server_operation_set_value_at (op, + GDA_BOOL_TO_STR(priv->m_replace), + error, + "/VIEW_DEF_P/VIEW_OR_REPLACE")) + return FALSE; + + + if (!gda_server_operation_set_value_at (op, + GDA_BOOL_TO_STR(priv->m_istemp), + error, + "/VIEW_DEF_P/VIEW_TEMP")) + return FALSE; + + if (!gda_server_operation_set_value_at (op, + priv->mp_defstring, + error, + "/VIEW_DEF_P/VIEW_DEF")) + return FALSE; + + return TRUE; +} + +/** + * gda_db_view_drop: + * @self: #GdaDbView instance to drop form the database + * @cnc: Connection to the database to perform the operation + * @ifexists: if %TRUE IF NOT EXISTS will be added to the SQL command + * @action: actions for referencing objecrs. See #GdaDbViewRefAction + * @error: instance of #GError to place the error + * + * This method call DDL comands to drop the view. + * + * Returns: %TRUE if everything is ok and %FALSE otherwise. + * + * Stability: Stable + * Since: 6.0 + */ +static gboolean +gda_db_view_drop (GdaDdlModifiable *self, + GdaConnection *cnc, + gpointer user_data, + GError **error) +{ + gda_lockable_lock ((GdaLockable*)cnc); + + GdaServerProvider *provider = NULL; + GdaServerOperation *op = NULL; + gchar *action_str = NULL; + GdaDbViewRefAction *action = (GdaDbViewRefAction*)user_data; + + provider = gda_connection_get_provider (cnc); + + op = gda_server_provider_create_operation (provider, + cnc, + GDA_SERVER_OPERATION_DROP_VIEW, + NULL, + error); + if (!op) + goto on_error; + + if (!gda_server_operation_set_value_at (op, + gda_db_base_get_full_name (GDA_DB_BASE (self)), + error, + "/VIEW_DESC_P/VIEW_NAME")) + goto on_error; + + if (!gda_server_operation_set_value_at (op, GDA_BOOL_TO_STR(TRUE), error, + "/VIEW_DESC_P/VIEW_IFEXISTS")) + goto on_error; + + switch (*action) + { + case GDA_DB_VIEW_RESTRICT: + action_str = g_strdup ("RESTRICT"); + break; + case GDA_DB_VIEW_CASCADE: + action_str = g_strdup ("CASCADE"); + break; + default: + g_debug("Wrong value for action. It is %d\n", *action); + break; + } + + if (!gda_server_operation_set_value_at (op, action_str, error, + "/VIEW_DESC_P/REFERENCED_ACTION")) + goto on_error; + + if (!gda_server_provider_perform_operation (provider, cnc, op, error)) + goto on_error; + + g_object_unref (op); + g_free (action_str); + gda_lockable_unlock ((GdaLockable*)cnc); + + return TRUE; + +on_error: + if (op) g_object_unref (op); + gda_lockable_unlock ((GdaLockable*)cnc); + g_free (action_str); + return FALSE; +} + +static gboolean +gda_db_view_rename (GdaDdlModifiable *old_name, + GdaConnection *cnc, + gpointer new_name, + GError **error) +{ + g_set_error (error, GDA_DDL_MODIFIABLE_ERROR, + GDA_DDL_MODIFIABLE_NOT_IMPLEMENTED, + _("Operation is not implemented for the used provider")); + return FALSE; +} diff --git a/.flatpak-builder/cache/objects/44/6a0ef11b7cc167f3b603e585c7eeeeb675faa412d5ec73f62988eb0b6c5488.dirmeta b/.flatpak-builder/cache/objects/44/6a0ef11b7cc167f3b603e585c7eeeeb675faa412d5ec73f62988eb0b6c5488.dirmeta new file mode 100644 index 0000000..6757a41 Binary files /dev/null and b/.flatpak-builder/cache/objects/44/6a0ef11b7cc167f3b603e585c7eeeeb675faa412d5ec73f62988eb0b6c5488.dirmeta differ diff --git a/.flatpak-builder/cache/objects/44/b91e79061cd9ab47ce498828f630a6df7052185a0ac2fb49b41b5c146ff1ea.file b/.flatpak-builder/cache/objects/44/b91e79061cd9ab47ce498828f630a6df7052185a0ac2fb49b41b5c146ff1ea.file new file mode 120000 index 0000000..22e1f93 --- /dev/null +++ b/.flatpak-builder/cache/objects/44/b91e79061cd9ab47ce498828f630a6df7052185a0ac2fb49b41b5c146ff1ea.file @@ -0,0 +1 @@ +dialog-warning.oga \ No newline at end of file diff --git a/.flatpak-builder/cache/objects/44/bf12903404aab6b14d73a146e6dd8b00cae24aa7ec215fb4557b8f9f168a21.dirtree b/.flatpak-builder/cache/objects/44/bf12903404aab6b14d73a146e6dd8b00cae24aa7ec215fb4557b8f9f168a21.dirtree new file mode 100644 index 0000000..04c698a Binary files /dev/null and b/.flatpak-builder/cache/objects/44/bf12903404aab6b14d73a146e6dd8b00cae24aa7ec215fb4557b8f9f168a21.dirtree differ diff --git a/.flatpak-builder/cache/objects/44/efc591aa1bcac741f6c0cc6ccd552ba61840e78c4a4de4910005612cd17794.dirtree b/.flatpak-builder/cache/objects/44/efc591aa1bcac741f6c0cc6ccd552ba61840e78c4a4de4910005612cd17794.dirtree new file mode 100644 index 0000000..f2e6efe Binary files /dev/null and b/.flatpak-builder/cache/objects/44/efc591aa1bcac741f6c0cc6ccd552ba61840e78c4a4de4910005612cd17794.dirtree differ diff --git a/.flatpak-builder/cache/objects/45/1c61e446d926047afc0bf2df959a1af2001b834fcea773edc6d5866d755154.dirtree b/.flatpak-builder/cache/objects/45/1c61e446d926047afc0bf2df959a1af2001b834fcea773edc6d5866d755154.dirtree new file mode 100644 index 0000000..16f8afd Binary files /dev/null and b/.flatpak-builder/cache/objects/45/1c61e446d926047afc0bf2df959a1af2001b834fcea773edc6d5866d755154.dirtree differ diff --git a/.flatpak-builder/cache/objects/45/4f77d15acdbefa1faf025c2b6f5216138f57773886ea55a2cb5d3e41acab0b.dirtree b/.flatpak-builder/cache/objects/45/4f77d15acdbefa1faf025c2b6f5216138f57773886ea55a2cb5d3e41acab0b.dirtree new file mode 100644 index 0000000..483819c Binary files /dev/null and b/.flatpak-builder/cache/objects/45/4f77d15acdbefa1faf025c2b6f5216138f57773886ea55a2cb5d3e41acab0b.dirtree differ diff --git a/.flatpak-builder/cache/objects/45/5443ebf710b7c37d01a810227f11e695d604d7f900f673436942227f1b1613.file b/.flatpak-builder/cache/objects/45/5443ebf710b7c37d01a810227f11e695d604d7f900f673436942227f1b1613.file new file mode 100644 index 0000000..17ac234 --- /dev/null +++ b/.flatpak-builder/cache/objects/45/5443ebf710b7c37d01a810227f11e695d604d7f900f673436942227f1b1613.file @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2006 - 2011 Vivien Malerba + * Copyright (C) 2007 Armin Burgmeier + * Copyright (C) 2007 Murray Cumming + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GDA_HANDLER_BIN__ +#define __GDA_HANDLER_BIN__ + +#include +#include + +G_BEGIN_DECLS + +#define GDA_TYPE_HANDLER_BIN (gda_handler_bin_get_type()) +G_DECLARE_FINAL_TYPE (GdaHandlerBin, gda_handler_bin, GDA, HANDLER_BIN, GObject) + +/** + * SECTION:gda-handler-bin + * @short_description: Default handler for binary values + * @title: GdaHanderBin + * @stability: Stable + * @see_also: #GdaDataHandler interface + * + * You should normally not need to use this API, refer to the #GdaDataHandler + * interface documentation for more information. + */ + +GdaDataHandler *gda_handler_bin_new (void); + +G_END_DECLS + +#endif diff --git a/.flatpak-builder/cache/objects/45/d235a64d4e1bce1a2b0f4ed8dd1ea605cc1b027596be25b1ff496260b7abcc.dirtree b/.flatpak-builder/cache/objects/45/d235a64d4e1bce1a2b0f4ed8dd1ea605cc1b027596be25b1ff496260b7abcc.dirtree new file mode 100644 index 0000000..62083ee Binary files /dev/null and b/.flatpak-builder/cache/objects/45/d235a64d4e1bce1a2b0f4ed8dd1ea605cc1b027596be25b1ff496260b7abcc.dirtree differ diff --git a/.flatpak-builder/cache/objects/46/6b706b7ce85bcab5b371497bd3df78deec5f3cce61ea201dfab33e5f16cbab.file b/.flatpak-builder/cache/objects/46/6b706b7ce85bcab5b371497bd3df78deec5f3cce61ea201dfab33e5f16cbab.file new file mode 100644 index 0000000..5d61fc8 --- /dev/null +++ b/.flatpak-builder/cache/objects/46/6b706b7ce85bcab5b371497bd3df78deec5f3cce61ea201dfab33e5f16cbab.file @@ -0,0 +1,513 @@ +/* + * Copyright (C) 2009 - 2013 Vivien Malerba + * Copyright (C) 2010 David King + * Copyright (C) 2010 Jonh Wendell + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +#define G_LOG_DOMAIN "GDA-tree-manager" + +#include "gda-tree-manager.h" +#include "gda-tree-node.h" +#include "gda-value.h" +#include + +/** + * GdaTreeManagerNodesFunc: + * @manager: a #GdaTreeManager + * @node: (nullable): a #GdaTreeNode object, or %NULL + * @children_nodes: (element-type GdaTreeNode): a list of #GdaTreeNode nodes which have previously been created by a similar call and + * need to be updated ore moved + * @out_error: (out) (nullable): a boolean to store if there was an error (can be %NULL) + * @error: a place to store errors, or %NULL + * + * Returns: (transfer container) (element-type GdaTreeNode): a new list of #GdaTreeNode objects. + */ + +/** + * GdaTreeManagerNodeFunc: + * @manager: a #GdaTreeManager + * @parent: (nullable): the parent the new node may have, or %NULL + * @name: (nullable): name given to the new node, or %NULL + * + * Returns: (transfer full): a new #GdaTreeNode + */ + +typedef struct { + gchar *att_name; + GValue *value; +} AddedAttribute; + +typedef struct { + GSList *sub_managers; /* list of GdaTreeManager structures, no ref held */ + GSList *ref_managers; /* list of GdaTreeManager structures, ref held */ + gboolean recursive; + + GdaTreeManagerNodeFunc node_create_func; + GdaTreeManagerNodesFunc update_func; + + GSList *added_attributes; /* list of #AddedAttribute pointers, managed here */ +} GdaTreeManagerPrivate; + +G_DEFINE_TYPE_WITH_PRIVATE (GdaTreeManager, gda_tree_manager, G_TYPE_OBJECT) + +static void gda_tree_manager_dispose (GObject *object); +static void gda_tree_manager_set_property (GObject *object, + guint param_id, + const GValue *value, + GParamSpec *pspec); +static void gda_tree_manager_get_property (GObject *object, + guint param_id, + GValue *value, + GParamSpec *pspec); + +/* properties */ +enum { + PROP_0, + PROP_RECURS, + PROP_FUNC, + LAST_PROP +}; + +static GParamSpec *properties [LAST_PROP]; + +static void +gda_tree_manager_class_init (GdaTreeManagerClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + /* virtual methods */ + klass->update_children = NULL; + + /* Properties */ + object_class->set_property = gda_tree_manager_set_property; + object_class->get_property = gda_tree_manager_get_property; + object_class->dispose = gda_tree_manager_dispose; + + /** + * GdaTreeManager:recursive: + * + * This property specifies if, when initially creating nodes or updating the list of nodes, + * the tree manager shoud also request that each node it has created or updated also + * initially create or update their children. + * + * This property can typically set to FALSE if the process of creating children nodes is lenghty + * and needs to be postponed while an event occurs. + */ + properties [PROP_RECURS] = + g_param_spec_boolean ("recursive", + NULL, + "Recursive building/updating of children", + TRUE, + G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT); + + /** + * GdaTreeManager:func: (type GdaTreeManagerNodesFunc) + * + * This property specifies the function which needs to be called when the list of #GdaTreeNode nodes + * managed has to be updated + */ + properties [PROP_FUNC] = + g_param_spec_pointer ("func", + NULL, + "Function called when building/updating of children", + G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT); + + g_object_class_install_properties (object_class, LAST_PROP, properties); +} + +static void +gda_tree_manager_init (GdaTreeManager *manager) +{ + GdaTreeManagerPrivate *priv; + + g_return_if_fail (GDA_IS_TREE_MANAGER (manager)); + + priv = gda_tree_manager_get_instance_private (manager); + priv->sub_managers = NULL; + priv->ref_managers = NULL; + priv->added_attributes = NULL; +} + +static void +gda_tree_manager_dispose (GObject *object) +{ + GdaTreeManager *manager = (GdaTreeManager *) object; + GdaTreeManagerPrivate *priv; + + g_return_if_fail (GDA_IS_TREE_MANAGER (manager)); + + priv = gda_tree_manager_get_instance_private (manager); + g_clear_pointer (&priv->sub_managers, g_slist_free); + g_clear_object (&priv->ref_managers); + if (priv->added_attributes) { + GSList *list; + for (list = priv->added_attributes; list; list = list->next) { + AddedAttribute *aa = (AddedAttribute*) list->data; + g_free (aa->att_name); + if (aa->value) + gda_value_free (aa->value); + g_free (aa); + } + } + + g_clear_pointer (&priv->added_attributes, g_slist_free); + + /* chain to parent class */ + G_OBJECT_CLASS (gda_tree_manager_parent_class)->dispose (object); +} + + +/* module error */ +GQuark gda_tree_manager_error_quark (void) +{ + static GQuark quark; + if (!quark) + quark = g_quark_from_static_string ("gda_tree_manager_error"); + return quark; +} + +static void +gda_tree_manager_set_property (GObject *object, + guint param_id, + const GValue *value, + GParamSpec *pspec) +{ + GdaTreeManager *manager = GDA_TREE_MANAGER (object); + GdaTreeManagerPrivate *priv = gda_tree_manager_get_instance_private (manager); + + switch (param_id) { + case PROP_RECURS: + priv->recursive = g_value_get_boolean (value); + break; + case PROP_FUNC: + priv->update_func = g_value_get_pointer (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + break; + } +} + +static void +gda_tree_manager_get_property (GObject *object, + guint param_id, + GValue *value, + GParamSpec *pspec) +{ + GdaTreeManager *manager = GDA_TREE_MANAGER (object); + GdaTreeManagerPrivate *priv = gda_tree_manager_get_instance_private (manager); + + switch (param_id) { + case PROP_RECURS: + g_value_set_boolean (value, priv->recursive); + break; + case PROP_FUNC: + g_value_set_pointer (value, priv->update_func); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + break; + } +} + +/* + * @manager: a #GdaTreeManager object + * @node: (nullable): a #GdaTreeNode object, or %NULL + * @children_nodes: (element-type GdaTreeNode): a list of #GdaTreeNode nodes which have previously been created by a similar call and + * need to be updated ore moved + * @out_error: (out) (nullable): a boolean to store if there was an error (can be %NULL) + * @error: a place to store errors, or %NULL + * + * Creates (or updates) the list of #GdaTreeNode objects which are placed as children of @node. The returned + * list will completely replace the existing list of nodes managed by @manager (as children of @node). + * + * If a node is already present in @children_nodes and needs to be kept in the new list, then it should be added + * to the returned list and its reference count should be increased by one. + * + * Since: 4.2 + */ +void +_gda_tree_manager_update_children (GdaTreeManager *manager, GdaTreeNode *node, const GSList *children_nodes, + gboolean *out_error, GError **error) +{ + GSList *nodes_list = NULL; + GdaTreeManagerPrivate *priv; + + g_return_if_fail (GDA_IS_TREE_MANAGER (manager)); + g_return_if_fail (GDA_IS_TREE_NODE (node)); + + priv = gda_tree_manager_get_instance_private (manager); + + if (out_error) + *out_error = FALSE; + if (priv->update_func) + nodes_list = priv->update_func (manager, node, children_nodes, out_error, error); + else { + GdaTreeManagerClass *klass = GDA_TREE_MANAGER_GET_CLASS (manager); + if (klass->update_children) + nodes_list = klass->update_children (manager, node, children_nodes, out_error, error); + } + _gda_tree_node_add_children (node, manager, nodes_list); + + /* calling sub managers for each new node */ + GSList *list; + for (list = nodes_list; list; list = list->next) { + GSList *sl; + for (sl = priv->sub_managers; sl; sl = sl->next) { + if (priv->recursive) { + gboolean lout_error = FALSE; + GdaTreeNode *parent = GDA_TREE_NODE (list->data); + GdaTreeManager *mgr = GDA_TREE_MANAGER (sl->data); + _gda_tree_manager_update_children (mgr, parent, + _gda_tree_node_get_children_for_manager (parent, mgr), + &lout_error, error); + if (lout_error) { + if (out_error) + *out_error = TRUE; + return; + } + } + else + _gda_tree_node_add_children (GDA_TREE_NODE (list->data), GDA_TREE_MANAGER (sl->data), NULL); + } + } + if (nodes_list) + g_slist_free (nodes_list); +} + + +/** + * gda_tree_manager_new_with_func: + * @update_func: (scope call): the function to call when the manager object is requested to create or update its list of + * #GdaTreeNode nodes + * + * Use this method to create a new #GdaTreeManager if it's more convenient than subclassing; all is needed + * is the @update_func function which is responsible for creating or updating the children nodes of a specified #GdaTreeNode. + * + * Returns: (transfer full): a new #GdaTreeManager + * + * Since: 4.2 + */ +GdaTreeManager * +gda_tree_manager_new_with_func (GdaTreeManagerNodesFunc update_func) +{ + g_return_val_if_fail (update_func, NULL); + + return (GdaTreeManager*) g_object_new (GDA_TYPE_TREE_MANAGER, + "func", update_func, + NULL); +} + +/** + * gda_tree_manager_add_new_node_attribute: + * @manager: a #GdaTreeManager + * @attribute: an attribute name + * @value: (nullable): the attribute's value, or %NULL + * + * Requests that for any new node managed (eg. created) by @manager, a new attribute will be set. This allows + * one to customize the attributes of new nodes created by an existing #GdaTreeManager. + * + * As a side effect, if @value is %NULL, then the corresponding attribute, if it was set, is unset. + * + * Since: 4.2 + */ +void +gda_tree_manager_add_new_node_attribute (GdaTreeManager *manager, const gchar *attribute, const GValue *value) +{ + AddedAttribute *aa = NULL; + GSList *list; + GdaTreeManagerPrivate *priv; + + g_return_if_fail (GDA_IS_TREE_MANAGER (manager)); + g_return_if_fail (attribute && *attribute); + + priv = gda_tree_manager_get_instance_private (manager); + for (list = priv->added_attributes; list; list = list->next) { + if (!strcmp (((AddedAttribute *) list->data)->att_name, attribute)) { + aa = (AddedAttribute *) list->data; + break; + } + } + if (!aa) { + aa = g_new0 (AddedAttribute, 1); + aa->att_name = g_strdup (attribute); + priv->added_attributes = g_slist_append (priv->added_attributes, aa); + } + else if (aa->value) { + gda_value_free (aa->value); + aa->value = NULL; + } + if (value) + aa->value = gda_value_copy (value); + +} + +/** + * gda_tree_manager_create_node: + * @manager: a #GdaTreeManager + * @parent: (nullable): the parent the new node may have, or %NULL + * @name: (nullable): name given to the new node, or %NULL + * + * Requests that @manager creates a new #GdaTreeNode. The new node is not in any + * way linked to @manager yet, consider this method as a #GdaTreeNode factory. + * + * This method is usually used when implementing a #GdaTreeManagerNodesFunc function (to create nodes), + * or when subclassing the #GdaTreeManager. + * + * Returns: (transfer full): a new #GdaTreeNode + * + * Since: 4.2 + */ +GdaTreeNode * +gda_tree_manager_create_node (GdaTreeManager *manager, GdaTreeNode *parent, const gchar *name) +{ + GdaTreeNode *node; + GSList *list; + GdaTreeManagerPrivate *priv; + + g_return_val_if_fail (GDA_IS_TREE_MANAGER (manager), NULL); + + priv = gda_tree_manager_get_instance_private (manager); + if (priv->node_create_func) + node = priv->node_create_func (manager, parent, name); + else + node = gda_tree_node_new (name); + + for (list = priv->added_attributes; list; list = list->next) { + AddedAttribute *aa = (AddedAttribute*) list->data; + gda_tree_node_set_node_attribute (node, aa->att_name, aa->value, NULL); + } + + return node; +} + +static gboolean +manager_is_sub_manager_of (GdaTreeManager *mgr, GdaTreeManager *sub) +{ + GdaTreeManagerPrivate *priv; + + priv = gda_tree_manager_get_instance_private (mgr); + if (g_slist_find (priv->ref_managers, sub)) + return TRUE; + + GSList *list; + for (list = priv->sub_managers; list; list = list->next) { + if (manager_is_sub_manager_of (GDA_TREE_MANAGER (list->data), sub)) + return TRUE; + } + + return FALSE; +} + +/** + * gda_tree_manager_add_manager: + * @manager: a #GdaTreeManager object + * @sub: a #GdaTreeManager object to add + * + * Adds a sub manager to @manager. Use this method to create the skeleton structure + * of a #GdaTree. Note that a single #GdaTreeManager can be used by several #GdaTree objects + * or several times in the same #GdaTree's structure. + * + * Please note that it's possible for @mgr and @sub to be the same object, but beware of the possible + * infinite recursive behaviour in this case when creating children nodes + * (depending on the actual implementation of the #GdaTreeManager). + * + * Since: 4.2 + */ +void +gda_tree_manager_add_manager (GdaTreeManager *manager, GdaTreeManager *sub) +{ + GdaTreeManagerPrivate *priv; + g_return_if_fail (GDA_IS_TREE_MANAGER (manager)); + g_return_if_fail (GDA_IS_TREE_MANAGER (sub)); + + priv = gda_tree_manager_get_instance_private (manager); + priv->sub_managers = g_slist_append (priv->sub_managers, sub); + + /* determine if @sub should be ref'ed or not to avoid circular dependencies */ + if ((sub != manager) && !manager_is_sub_manager_of (sub, manager)) { + priv->ref_managers = g_slist_prepend (priv->ref_managers, sub); + g_object_ref (sub); + } +} + + +/** + * gda_tree_manager_get_managers: + * @manager: a #GdaTreeManager object + * + * Get the list of sub managers which have already been added using gda_tree_manager_add_manager() + * + * Returns: (transfer none) (element-type Gda.TreeManager): a list of #GdaTreeMenager which should not be modified. + * + * Since: 4.2 + */ +const GSList * +gda_tree_manager_get_managers (GdaTreeManager *manager) +{ + GdaTreeManagerPrivate *priv; + + g_return_val_if_fail (GDA_IS_TREE_MANAGER (manager), NULL); + + priv = gda_tree_manager_get_instance_private (manager); + return priv->sub_managers; +} + +/** + * gda_tree_manager_set_node_create_func: + * @manager: a #GdaTreeManager tree manager object + * @func: (nullable) (scope call): a #GdaTreeManagerNodeFunc function pointer, or %NULL + * + * Sets the function to be called when a new node is being created by @manager. If @func is %NULL + * then each created node will be a #GdaTreeNode object. + * + * Specifying a custom #GdaTreeManagerNodeFunc function for example allows one to use + * specialized sub-classed #GdaTreeNode objects. + * + * Since: 4.2 + */ +void +gda_tree_manager_set_node_create_func (GdaTreeManager *manager, GdaTreeManagerNodeFunc func) +{ + GdaTreeManagerPrivate *priv; + + g_return_if_fail (GDA_IS_TREE_MANAGER (manager)); + + priv = gda_tree_manager_get_instance_private (manager); + priv->node_create_func = func; +} + +/** + * gda_tree_manager_get_node_create_func: (skip) + * @manager: a #GdaTreeManager tree manager object + * + * Get the function used by @manager when creating new #GdaTreeNode nodes + * + * Returns: the #GdaTreeManagerNodeFunc function, or %NULL if the default function is used + * + * Since: 4.2 + */ +GdaTreeManagerNodeFunc +gda_tree_manager_get_node_create_func (GdaTreeManager *manager) +{ + GdaTreeManagerPrivate *priv; + + g_return_val_if_fail (GDA_IS_TREE_MANAGER (manager), NULL); + + priv = gda_tree_manager_get_instance_private (manager); + return priv->node_create_func; +} diff --git a/.flatpak-builder/cache/objects/46/cba4098f371be36e8b18b652b794904fe509c7b5c2554e47fdea4c39ee387c.dirtree b/.flatpak-builder/cache/objects/46/cba4098f371be36e8b18b652b794904fe509c7b5c2554e47fdea4c39ee387c.dirtree new file mode 100644 index 0000000..55e4f1a Binary files /dev/null and b/.flatpak-builder/cache/objects/46/cba4098f371be36e8b18b652b794904fe509c7b5c2554e47fdea4c39ee387c.dirtree differ diff --git a/.flatpak-builder/cache/objects/46/dada94159b6acd0e467222e53f9da68237847ef7ca98827188f2f049115fda.file b/.flatpak-builder/cache/objects/46/dada94159b6acd0e467222e53f9da68237847ef7ca98827188f2f049115fda.file new file mode 100644 index 0000000..c378927 --- /dev/null +++ b/.flatpak-builder/cache/objects/46/dada94159b6acd0e467222e53f9da68237847ef7ca98827188f2f049115fda.file @@ -0,0 +1,219 @@ +# gtk_a11y.py +# +# Copyright 2021 James Westman +# +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation; either version 3 of the +# License, or (at your option) any later version. +# +# This file is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program. If not, see . +# +# SPDX-License-Identifier: LGPL-3.0-or-later + +from .gobject_object import ObjectContent, validate_parent_type +from .attributes import BaseAttribute +from .values import Value +from .common import * +from .contexts import ValueTypeCtx +from ..decompiler import escape_quote + + +def get_property_types(gir): + # from + return { + "autocomplete": gir.get_type("AccessibleAutocomplete", "Gtk"), + "description": StringType(), + "has-popup": BoolType(), + "key-shortcuts": StringType(), + "label": StringType(), + "level": IntType(), + "modal": BoolType(), + "multi-line": BoolType(), + "multi-selectable": BoolType(), + "orientation": gir.get_type("Orientation", "Gtk"), + "placeholder": StringType(), + "read-only": BoolType(), + "required": BoolType(), + "role-description": StringType(), + "sort": gir.get_type("AccessibleSort", "Gtk"), + "value-max": FloatType(), + "value-min": FloatType(), + "value-now": FloatType(), + "value-text": StringType(), + } + + +def get_relation_types(gir): + # from + widget = gir.get_type("Widget", "Gtk") + return { + "active-descendant": widget, + "col-count": IntType(), + "col-index": IntType(), + "col-index-text": StringType(), + "col-span": IntType(), + "controls": widget, + "described-by": widget, + "details": widget, + "error-message": widget, + "flow-to": widget, + "labelled-by": widget, + "owns": widget, + "pos-in-set": IntType(), + "row-count": IntType(), + "row-index": IntType(), + "row-index-text": StringType(), + "row-span": IntType(), + "set-size": IntType(), + } + + +def get_state_types(gir): + # from + return { + "busy": BoolType(), + "checked": gir.get_type("AccessibleTristate", "Gtk"), + "disabled": BoolType(), + "expanded": BoolType(), + "hidden": BoolType(), + "invalid": gir.get_type("AccessibleInvalidState", "Gtk"), + "pressed": gir.get_type("AccessibleTristate", "Gtk"), + "selected": BoolType(), + } + + +def get_types(gir): + return { + **get_property_types(gir), + **get_relation_types(gir), + **get_state_types(gir), + } + + +def _get_docs(gir, name): + if gir_type := ( + gir.get_type("AccessibleProperty", "Gtk").members.get(name) + or gir.get_type("AccessibleRelation", "Gtk").members.get(name) + or gir.get_type("AccessibleState", "Gtk").members.get(name) + ): + return gir_type.doc + + +class A11yProperty(BaseAttribute): + grammar = Statement( + UseIdent("name"), + ":", + Value, + ) + + @property + def tag_name(self): + name = self.tokens["name"] + gir = self.root.gir + if name in get_property_types(gir): + return "property" + elif name in get_relation_types(gir): + return "relation" + elif name in get_state_types(gir): + return "state" + else: + raise CompilerBugError() + + @property + def name(self): + return self.tokens["name"].replace("_", "-") + + @property + def value(self) -> Value: + return self.children[0] + + @context(ValueTypeCtx) + def value_type(self) -> ValueTypeCtx: + return ValueTypeCtx(get_types(self.root.gir).get(self.tokens["name"])) + + @validate("name") + def is_valid_property(self): + types = get_types(self.root.gir) + if self.tokens["name"] not in types: + raise CompileError( + f"'{self.tokens['name']}' is not an accessibility property, relation, or state", + did_you_mean=(self.tokens["name"], types.keys()), + ) + + @validate("name") + def unique_in_parent(self): + self.validate_unique_in_parent( + f"Duplicate accessibility attribute '{self.tokens['name']}'", + check=lambda child: child.tokens["name"] == self.tokens["name"], + ) + + @docs("name") + def prop_docs(self): + if self.tokens["name"] in get_types(self.root.gir): + return _get_docs(self.root.gir, self.tokens["name"]) + + +class ExtAccessibility(AstNode): + grammar = [ + Keyword("accessibility"), + "{", + Until(A11yProperty, "}"), + ] + + @property + def properties(self) -> T.List[A11yProperty]: + return self.children[A11yProperty] + + @validate("accessibility") + def container_is_widget(self): + validate_parent_type(self, "Gtk", "Widget", "accessibility properties") + + @validate("accessibility") + def unique_in_parent(self): + self.validate_unique_in_parent("Duplicate accessibility block") + + +@completer( + applies_in=[ObjectContent], + matches=new_statement_patterns, +) +def a11y_completer(ast_node, match_variables): + yield Completion( + "accessibility", CompletionItemKind.Snippet, snippet="accessibility {\n $0\n}" + ) + + +@completer( + applies_in=[ExtAccessibility], + matches=new_statement_patterns, +) +def a11y_name_completer(ast_node, match_variables): + for name, type in get_types(ast_node.root.gir).items(): + yield Completion( + name, CompletionItemKind.Property, docs=_get_docs(ast_node.root.gir, type) + ) + + +@decompiler("relation", cdata=True) +def decompile_relation(ctx, gir, name, cdata): + ctx.print_attribute(name, cdata, get_types(ctx.gir).get(name)) + + +@decompiler("state", cdata=True) +def decompile_state(ctx, gir, name, cdata, translatable="false"): + if decompile.truthy(translatable): + ctx.print(f'{name}: _("{escape_quote(cdata)}");') + else: + ctx.print_attribute(name, cdata, get_types(ctx.gir).get(name)) + + +@decompiler("accessibility") +def decompile_accessibility(ctx, gir): + ctx.print("accessibility {") diff --git a/.flatpak-builder/cache/objects/47/bca67e23e7f6d79ac41d56f8122b8cc16b23f99fc82d403c985b057b5b54b4.file b/.flatpak-builder/cache/objects/47/bca67e23e7f6d79ac41d56f8122b8cc16b23f99fc82d403c985b057b5b54b4.file new file mode 100644 index 0000000..5548a68 --- /dev/null +++ b/.flatpak-builder/cache/objects/47/bca67e23e7f6d79ac41d56f8122b8cc16b23f99fc82d403c985b057b5b54b4.file @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2006 - 2008 Murray Cumming + * Copyright (C) 2006 Rodrigo Moya + * Copyright (C) 2006 - 2015 Vivien Malerba + * Copyright (C) 2007 Armin Burgmeier + * Copyright (C) 2007 Daniel Espinosa + * Copyright (C) 2010 David King + * Copyright (C) 2010 Jonh Wendell + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +#define G_LOG_DOMAIN "GDA-server-provider-extra" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +/* Moved to gda-server-provider.c */ diff --git a/.flatpak-builder/cache/objects/49/9f9a27885f2e84bd485156b3ef1510822904babb8bf15081fe3b52d1c56c9c.dirtree b/.flatpak-builder/cache/objects/49/9f9a27885f2e84bd485156b3ef1510822904babb8bf15081fe3b52d1c56c9c.dirtree new file mode 100644 index 0000000..733bc04 Binary files /dev/null and b/.flatpak-builder/cache/objects/49/9f9a27885f2e84bd485156b3ef1510822904babb8bf15081fe3b52d1c56c9c.dirtree differ diff --git a/.flatpak-builder/cache/objects/4a/14851c2d76b0e3800e70097d97a6f7d3e43e99f01d5dbce8479793eb34dcb0.dirtree b/.flatpak-builder/cache/objects/4a/14851c2d76b0e3800e70097d97a6f7d3e43e99f01d5dbce8479793eb34dcb0.dirtree new file mode 100644 index 0000000..160d894 Binary files /dev/null and b/.flatpak-builder/cache/objects/4a/14851c2d76b0e3800e70097d97a6f7d3e43e99f01d5dbce8479793eb34dcb0.dirtree differ diff --git a/.flatpak-builder/cache/objects/4a/16d3e8ba076efdf8411dd6893c587c5057023f7ce63028ef6092510539c9ff.dirtree b/.flatpak-builder/cache/objects/4a/16d3e8ba076efdf8411dd6893c587c5057023f7ce63028ef6092510539c9ff.dirtree new file mode 100644 index 0000000..263d55c Binary files /dev/null and b/.flatpak-builder/cache/objects/4a/16d3e8ba076efdf8411dd6893c587c5057023f7ce63028ef6092510539c9ff.dirtree differ diff --git a/.flatpak-builder/cache/objects/4a/3066d3722b691c99b8d83392b2809502e10b2cf3988a9a43fb16380903a72b.file b/.flatpak-builder/cache/objects/4a/3066d3722b691c99b8d83392b2809502e10b2cf3988a9a43fb16380903a72b.file new file mode 100644 index 0000000..939dda9 --- /dev/null +++ b/.flatpak-builder/cache/objects/4a/3066d3722b691c99b8d83392b2809502e10b2cf3988a9a43fb16380903a72b.file @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2009 - 2011 Vivien Malerba + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GDA_TREE_MGR_TABLES_H__ +#define __GDA_TREE_MGR_TABLES_H__ + +#include +#include "gda-tree-manager.h" + +G_BEGIN_DECLS + +#define GDA_TYPE_TREE_MGR_TABLES (gda_tree_mgr_tables_get_type()) +G_DECLARE_DERIVABLE_TYPE (GdaTreeMgrTables, gda_tree_mgr_tables, GDA, TREE_MGR_TABLES, GdaTreeManager) + +struct _GdaTreeMgrTablesClass { + GdaTreeManagerClass object_class; +}; + +/** + * SECTION:gda-tree-mgr-tables + * @short_description: A tree manager which creates a node for each table in a schema + * @title: GdaTreeMgrTables + * @stability: Stable + * @see_also: + * + * The #GdaTreeMgrTables is a #GdaTreeManager object which creates a node for + * each table in a database schema. + * + * It uses the #GdaMetaStore associated to a #GdaConnection to get the tables list + * in database schema; it's up to the + * caller to make sure the data in the #GdaMetaStore is up to date. + * + * The #GdaConnection to be used needs to be specified when the object is created. The + * schema can however be specified when the object is created, and if not, is + * fetched from the #GdaTreeNode below which the nodes will be placed (using + * gda_tree_node_fetch_attribute()). + */ + +GdaTreeManager* gda_tree_mgr_tables_new (GdaConnection *cnc, const gchar *schema); + +G_END_DECLS + +#endif diff --git a/.flatpak-builder/cache/objects/4a/42b268ab8f3aa650d8dac6e93df15e135f5b4d620dcb6172fb5f8a584f36c8.dirtree b/.flatpak-builder/cache/objects/4a/42b268ab8f3aa650d8dac6e93df15e135f5b4d620dcb6172fb5f8a584f36c8.dirtree new file mode 100644 index 0000000..47a7a7d Binary files /dev/null and b/.flatpak-builder/cache/objects/4a/42b268ab8f3aa650d8dac6e93df15e135f5b4d620dcb6172fb5f8a584f36c8.dirtree differ diff --git a/.flatpak-builder/cache/objects/4a/51eaebd942ca8cc408c6627bc48bd3296418392c9e00c6a1c4f06582d025ba.dirtree b/.flatpak-builder/cache/objects/4a/51eaebd942ca8cc408c6627bc48bd3296418392c9e00c6a1c4f06582d025ba.dirtree new file mode 100644 index 0000000..8e7a362 Binary files /dev/null and b/.flatpak-builder/cache/objects/4a/51eaebd942ca8cc408c6627bc48bd3296418392c9e00c6a1c4f06582d025ba.dirtree differ diff --git a/.flatpak-builder/cache/objects/4a/978554439c02e7d46720fe528036e34fb03a227e63dc53dcff3f0737801b93.file b/.flatpak-builder/cache/objects/4a/978554439c02e7d46720fe528036e34fb03a227e63dc53dcff3f0737801b93.file new file mode 100755 index 0000000..13740be Binary files /dev/null and b/.flatpak-builder/cache/objects/4a/978554439c02e7d46720fe528036e34fb03a227e63dc53dcff3f0737801b93.file differ diff --git a/.flatpak-builder/cache/objects/4a/bd7e37c7b30b76ddda0edbed87ebc6df50857afd01a85fca90506eafa048a5.file b/.flatpak-builder/cache/objects/4a/bd7e37c7b30b76ddda0edbed87ebc6df50857afd01a85fca90506eafa048a5.file new file mode 120000 index 0000000..c3362f4 --- /dev/null +++ b/.flatpak-builder/cache/objects/4a/bd7e37c7b30b76ddda0edbed87ebc6df50857afd01a85fca90506eafa048a5.file @@ -0,0 +1 @@ +../../share/runtime/locale/pt/share/pt_BR \ No newline at end of file diff --git a/.flatpak-builder/cache/objects/4a/f50596deb6d16b5421e07de117fd688ffb1d3d161a2b5cecc87e1ddbe2cf59.dirtree b/.flatpak-builder/cache/objects/4a/f50596deb6d16b5421e07de117fd688ffb1d3d161a2b5cecc87e1ddbe2cf59.dirtree new file mode 100644 index 0000000..83de1e7 Binary files /dev/null and b/.flatpak-builder/cache/objects/4a/f50596deb6d16b5421e07de117fd688ffb1d3d161a2b5cecc87e1ddbe2cf59.dirtree differ diff --git a/.flatpak-builder/cache/objects/4b/069f870b2cba39f20dc55d6ff45a57dff1c3ebf97787682ebd4f6a28f55a27.dirtree b/.flatpak-builder/cache/objects/4b/069f870b2cba39f20dc55d6ff45a57dff1c3ebf97787682ebd4f6a28f55a27.dirtree new file mode 100644 index 0000000..6ca1b94 Binary files /dev/null and b/.flatpak-builder/cache/objects/4b/069f870b2cba39f20dc55d6ff45a57dff1c3ebf97787682ebd4f6a28f55a27.dirtree differ diff --git a/.flatpak-builder/cache/objects/4b/28b8417c7f8d1f07d6dd390f84eb7e6826e5442626e5d0137da2a28ac4c827.file b/.flatpak-builder/cache/objects/4b/28b8417c7f8d1f07d6dd390f84eb7e6826e5442626e5d0137da2a28ac4c827.file new file mode 100644 index 0000000..bfdd9e6 --- /dev/null +++ b/.flatpak-builder/cache/objects/4b/28b8417c7f8d1f07d6dd390f84eb7e6826e5442626e5d0137da2a28ac4c827.file @@ -0,0 +1,193 @@ + +/* This file is generated by glib-mkenums, do not modify it. This code is licensed under the same license as the containing project. Note that it links to GLib, so must comply with the LGPL linking clauses. */ + +#include "gda-enum-types.h" +#include "gda-connection.h" +#include "gda-enums.h" + +#define C_ENUM(v) ((gint) v) +#define C_FLAGS(v) ((guint) v) + +/* enumerations from "gda-connection.h" */ + +GType +gda_connection_error_get_type (void) +{ +static gsize gtype_id = 0; +static const GEnumValue values[] = { + { C_ENUM(GDA_CONNECTION_DSN_NOT_FOUND_ERROR), "GDA_CONNECTION_DSN_NOT_FOUND_ERROR", "dsn-not-found-error" }, + { C_ENUM(GDA_CONNECTION_PROVIDER_NOT_FOUND_ERROR), "GDA_CONNECTION_PROVIDER_NOT_FOUND_ERROR", "provider-not-found-error" }, + { C_ENUM(GDA_CONNECTION_PROVIDER_ERROR), "GDA_CONNECTION_PROVIDER_ERROR", "provider-error" }, + { C_ENUM(GDA_CONNECTION_NO_CNC_SPEC_ERROR), "GDA_CONNECTION_NO_CNC_SPEC_ERROR", "no-cnc-spec-error" }, + { C_ENUM(GDA_CONNECTION_NO_PROVIDER_SPEC_ERROR), "GDA_CONNECTION_NO_PROVIDER_SPEC_ERROR", "no-provider-spec-error" }, + { C_ENUM(GDA_CONNECTION_OPEN_ERROR), "GDA_CONNECTION_OPEN_ERROR", "open-error" }, + { C_ENUM(GDA_CONNECTION_ALREADY_OPENED_ERROR), "GDA_CONNECTION_ALREADY_OPENED_ERROR", "already-opened-error" }, + { C_ENUM(GDA_CONNECTION_STATEMENT_TYPE_ERROR), "GDA_CONNECTION_STATEMENT_TYPE_ERROR", "statement-type-error" }, + { C_ENUM(GDA_CONNECTION_CANT_LOCK_ERROR), "GDA_CONNECTION_CANT_LOCK_ERROR", "cant-lock-error" }, + { C_ENUM(GDA_CONNECTION_TASK_NOT_FOUND_ERROR), "GDA_CONNECTION_TASK_NOT_FOUND_ERROR", "task-not-found-error" }, + { C_ENUM(GDA_CONNECTION_CLOSED_ERROR), "GDA_CONNECTION_CLOSED_ERROR", "closed-error" }, + { C_ENUM(GDA_CONNECTION_META_DATA_CONTEXT_ERROR), "GDA_CONNECTION_META_DATA_CONTEXT_ERROR", "meta-data-context-error" }, + { C_ENUM(GDA_CONNECTION_NO_MAIN_CONTEXT_ERROR), "GDA_CONNECTION_NO_MAIN_CONTEXT_ERROR", "no-main-context-error" }, +{ 0, NULL, NULL } + }; + if (g_once_init_enter (>ype_id)) { + GType new_type = g_enum_register_static (g_intern_static_string ("GdaConnectionError"), values); + g_once_init_leave (>ype_id, new_type); + } + return (GType) gtype_id; + } + +GType +gda_connection_status_get_type (void) +{ +static gsize gtype_id = 0; +static const GEnumValue values[] = { + { C_ENUM(GDA_CONNECTION_STATUS_CLOSED), "GDA_CONNECTION_STATUS_CLOSED", "closed" }, + { C_ENUM(GDA_CONNECTION_STATUS_OPENING), "GDA_CONNECTION_STATUS_OPENING", "opening" }, + { C_ENUM(GDA_CONNECTION_STATUS_IDLE), "GDA_CONNECTION_STATUS_IDLE", "idle" }, + { C_ENUM(GDA_CONNECTION_STATUS_BUSY), "GDA_CONNECTION_STATUS_BUSY", "busy" }, +{ 0, NULL, NULL } + }; + if (g_once_init_enter (>ype_id)) { + GType new_type = g_enum_register_static (g_intern_static_string ("GdaConnectionStatus"), values); + g_once_init_leave (>ype_id, new_type); + } + return (GType) gtype_id; + } + +GType +gda_connection_options_get_type (void) +{ +static gsize gtype_id = 0; +static const GFlagsValue values[] = { + { C_FLAGS(GDA_CONNECTION_OPTIONS_NONE), "GDA_CONNECTION_OPTIONS_NONE", "none" }, + { C_FLAGS(GDA_CONNECTION_OPTIONS_READ_ONLY), "GDA_CONNECTION_OPTIONS_READ_ONLY", "read-only" }, + { C_FLAGS(GDA_CONNECTION_OPTIONS_SQL_IDENTIFIERS_CASE_SENSITIVE), "GDA_CONNECTION_OPTIONS_SQL_IDENTIFIERS_CASE_SENSITIVE", "sql-identifiers-case-sensitive" }, + { C_FLAGS(GDA_CONNECTION_OPTIONS_AUTO_META_DATA), "GDA_CONNECTION_OPTIONS_AUTO_META_DATA", "auto-meta-data" }, +{ 0, NULL, NULL } + }; + if (g_once_init_enter (>ype_id)) { + GType new_type = g_flags_register_static (g_intern_static_string ("GdaConnectionOptions"), values); + g_once_init_leave (>ype_id, new_type); + } + return (GType) gtype_id; + } + +GType +gda_connection_feature_get_type (void) +{ +static gsize gtype_id = 0; +static const GEnumValue values[] = { + { C_ENUM(GDA_CONNECTION_FEATURE_AGGREGATES), "GDA_CONNECTION_FEATURE_AGGREGATES", "aggregates" }, + { C_ENUM(GDA_CONNECTION_FEATURE_BLOBS), "GDA_CONNECTION_FEATURE_BLOBS", "blobs" }, + { C_ENUM(GDA_CONNECTION_FEATURE_INDEXES), "GDA_CONNECTION_FEATURE_INDEXES", "indexes" }, + { C_ENUM(GDA_CONNECTION_FEATURE_INHERITANCE), "GDA_CONNECTION_FEATURE_INHERITANCE", "inheritance" }, + { C_ENUM(GDA_CONNECTION_FEATURE_NAMESPACES), "GDA_CONNECTION_FEATURE_NAMESPACES", "namespaces" }, + { C_ENUM(GDA_CONNECTION_FEATURE_PROCEDURES), "GDA_CONNECTION_FEATURE_PROCEDURES", "procedures" }, + { C_ENUM(GDA_CONNECTION_FEATURE_SEQUENCES), "GDA_CONNECTION_FEATURE_SEQUENCES", "sequences" }, + { C_ENUM(GDA_CONNECTION_FEATURE_SQL), "GDA_CONNECTION_FEATURE_SQL", "sql" }, + { C_ENUM(GDA_CONNECTION_FEATURE_TRANSACTIONS), "GDA_CONNECTION_FEATURE_TRANSACTIONS", "transactions" }, + { C_ENUM(GDA_CONNECTION_FEATURE_SAVEPOINTS), "GDA_CONNECTION_FEATURE_SAVEPOINTS", "savepoints" }, + { C_ENUM(GDA_CONNECTION_FEATURE_SAVEPOINTS_REMOVE), "GDA_CONNECTION_FEATURE_SAVEPOINTS_REMOVE", "savepoints-remove" }, + { C_ENUM(GDA_CONNECTION_FEATURE_TRIGGERS), "GDA_CONNECTION_FEATURE_TRIGGERS", "triggers" }, + { C_ENUM(GDA_CONNECTION_FEATURE_UPDATABLE_CURSOR), "GDA_CONNECTION_FEATURE_UPDATABLE_CURSOR", "updatable-cursor" }, + { C_ENUM(GDA_CONNECTION_FEATURE_USERS), "GDA_CONNECTION_FEATURE_USERS", "users" }, + { C_ENUM(GDA_CONNECTION_FEATURE_VIEWS), "GDA_CONNECTION_FEATURE_VIEWS", "views" }, + { C_ENUM(GDA_CONNECTION_FEATURE_TRANSACTION_ISOLATION_READ_COMMITTED), "GDA_CONNECTION_FEATURE_TRANSACTION_ISOLATION_READ_COMMITTED", "transaction-isolation-read-committed" }, + { C_ENUM(GDA_CONNECTION_FEATURE_TRANSACTION_ISOLATION_READ_UNCOMMITTED), "GDA_CONNECTION_FEATURE_TRANSACTION_ISOLATION_READ_UNCOMMITTED", "transaction-isolation-read-uncommitted" }, + { C_ENUM(GDA_CONNECTION_FEATURE_TRANSACTION_ISOLATION_REPEATABLE_READ), "GDA_CONNECTION_FEATURE_TRANSACTION_ISOLATION_REPEATABLE_READ", "transaction-isolation-repeatable-read" }, + { C_ENUM(GDA_CONNECTION_FEATURE_TRANSACTION_ISOLATION_SERIALIZABLE), "GDA_CONNECTION_FEATURE_TRANSACTION_ISOLATION_SERIALIZABLE", "transaction-isolation-serializable" }, + { C_ENUM(GDA_CONNECTION_FEATURE_XA_TRANSACTIONS), "GDA_CONNECTION_FEATURE_XA_TRANSACTIONS", "xa-transactions" }, + { C_ENUM(GDA_CONNECTION_FEATURE_LAST), "GDA_CONNECTION_FEATURE_LAST", "last" }, +{ 0, NULL, NULL } + }; + if (g_once_init_enter (>ype_id)) { + GType new_type = g_enum_register_static (g_intern_static_string ("GdaConnectionFeature"), values); + g_once_init_leave (>ype_id, new_type); + } + return (GType) gtype_id; + } + +GType +gda_connection_meta_type_get_type (void) +{ +static gsize gtype_id = 0; +static const GEnumValue values[] = { + { C_ENUM(GDA_CONNECTION_META_NAMESPACES), "GDA_CONNECTION_META_NAMESPACES", "namespaces" }, + { C_ENUM(GDA_CONNECTION_META_TYPES), "GDA_CONNECTION_META_TYPES", "types" }, + { C_ENUM(GDA_CONNECTION_META_TABLES), "GDA_CONNECTION_META_TABLES", "tables" }, + { C_ENUM(GDA_CONNECTION_META_VIEWS), "GDA_CONNECTION_META_VIEWS", "views" }, + { C_ENUM(GDA_CONNECTION_META_FIELDS), "GDA_CONNECTION_META_FIELDS", "fields" }, + { C_ENUM(GDA_CONNECTION_META_INDEXES), "GDA_CONNECTION_META_INDEXES", "indexes" }, +{ 0, NULL, NULL } + }; + if (g_once_init_enter (>ype_id)) { + GType new_type = g_enum_register_static (g_intern_static_string ("GdaConnectionMetaType"), values); + g_once_init_leave (>ype_id, new_type); + } + return (GType) gtype_id; + } + +/* enumerations from "gda-enums.h" */ + +GType +gda_transaction_isolation_get_type (void) +{ +static gsize gtype_id = 0; +static const GEnumValue values[] = { + { C_ENUM(GDA_TRANSACTION_ISOLATION_SERVER_DEFAULT), "GDA_TRANSACTION_ISOLATION_SERVER_DEFAULT", "server-default" }, + { C_ENUM(GDA_TRANSACTION_ISOLATION_READ_COMMITTED), "GDA_TRANSACTION_ISOLATION_READ_COMMITTED", "read-committed" }, + { C_ENUM(GDA_TRANSACTION_ISOLATION_READ_UNCOMMITTED), "GDA_TRANSACTION_ISOLATION_READ_UNCOMMITTED", "read-uncommitted" }, + { C_ENUM(GDA_TRANSACTION_ISOLATION_REPEATABLE_READ), "GDA_TRANSACTION_ISOLATION_REPEATABLE_READ", "repeatable-read" }, + { C_ENUM(GDA_TRANSACTION_ISOLATION_SERIALIZABLE), "GDA_TRANSACTION_ISOLATION_SERIALIZABLE", "serializable" }, +{ 0, NULL, NULL } + }; + if (g_once_init_enter (>ype_id)) { + GType new_type = g_enum_register_static (g_intern_static_string ("GdaTransactionIsolation"), values); + g_once_init_leave (>ype_id, new_type); + } + return (GType) gtype_id; + } + +GType +gda_value_attribute_get_type (void) +{ +static gsize gtype_id = 0; +static const GFlagsValue values[] = { + { C_FLAGS(GDA_VALUE_ATTR_NONE), "GDA_VALUE_ATTR_NONE", "none" }, + { C_FLAGS(GDA_VALUE_ATTR_IS_NULL), "GDA_VALUE_ATTR_IS_NULL", "is-null" }, + { C_FLAGS(GDA_VALUE_ATTR_CAN_BE_NULL), "GDA_VALUE_ATTR_CAN_BE_NULL", "can-be-null" }, + { C_FLAGS(GDA_VALUE_ATTR_IS_DEFAULT), "GDA_VALUE_ATTR_IS_DEFAULT", "is-default" }, + { C_FLAGS(GDA_VALUE_ATTR_CAN_BE_DEFAULT), "GDA_VALUE_ATTR_CAN_BE_DEFAULT", "can-be-default" }, + { C_FLAGS(GDA_VALUE_ATTR_IS_UNCHANGED), "GDA_VALUE_ATTR_IS_UNCHANGED", "is-unchanged" }, + { C_FLAGS(GDA_VALUE_ATTR_DATA_NON_VALID), "GDA_VALUE_ATTR_DATA_NON_VALID", "data-non-valid" }, + { C_FLAGS(GDA_VALUE_ATTR_HAS_VALUE_ORIG), "GDA_VALUE_ATTR_HAS_VALUE_ORIG", "has-value-orig" }, + { C_FLAGS(GDA_VALUE_ATTR_NO_MODIF), "GDA_VALUE_ATTR_NO_MODIF", "no-modif" }, + { C_FLAGS(GDA_VALUE_ATTR_READ_ONLY), "GDA_VALUE_ATTR_READ_ONLY", "read-only" }, +{ 0, NULL, NULL } + }; + if (g_once_init_enter (>ype_id)) { + GType new_type = g_flags_register_static (g_intern_static_string ("GdaValueAttribute"), values); + g_once_init_leave (>ype_id, new_type); + } + return (GType) gtype_id; + } + +GType +gda_sql_identifier_style_get_type (void) +{ +static gsize gtype_id = 0; +static const GFlagsValue values[] = { + { C_FLAGS(GDA_SQL_IDENTIFIERS_LOWER_CASE), "GDA_SQL_IDENTIFIERS_LOWER_CASE", "lower-case" }, + { C_FLAGS(GDA_SQL_IDENTIFIERS_UPPER_CASE), "GDA_SQL_IDENTIFIERS_UPPER_CASE", "upper-case" }, +{ 0, NULL, NULL } + }; + if (g_once_init_enter (>ype_id)) { + GType new_type = g_flags_register_static (g_intern_static_string ("GdaSqlIdentifierStyle"), values); + g_once_init_leave (>ype_id, new_type); + } + return (GType) gtype_id; + } + +/* Generated data ends here */ + diff --git a/.flatpak-builder/cache/objects/4b/e594ed9240a7b64aee57922450b86edb4a4b243556d254976bdc3491245922.dirtree b/.flatpak-builder/cache/objects/4b/e594ed9240a7b64aee57922450b86edb4a4b243556d254976bdc3491245922.dirtree new file mode 100644 index 0000000..0dddddb Binary files /dev/null and b/.flatpak-builder/cache/objects/4b/e594ed9240a7b64aee57922450b86edb4a4b243556d254976bdc3491245922.dirtree differ diff --git a/.flatpak-builder/cache/objects/4c/47d325c0abc95889128878ae3a7cd93d6b82698c8433043659430829a250bb.file b/.flatpak-builder/cache/objects/4c/47d325c0abc95889128878ae3a7cd93d6b82698c8433043659430829a250bb.file new file mode 100644 index 0000000..975ce0a --- /dev/null +++ b/.flatpak-builder/cache/objects/4c/47d325c0abc95889128878ae3a7cd93d6b82698c8433043659430829a250bb.file @@ -0,0 +1,2454 @@ +/* + * Copyright (C) 2008 - 2013 Vivien Malerba + * Copyright (C) 2010 David King + * Copyright (C) 2012 Daniel Espinosa + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include +#include "gda-sqlite.h" +#include "gda-sqlite-meta.h" +#include "gda-sqlite-util.h" +#include "gda-sqlite-provider.h" +#include +#include +#include +#include +#include +#include +#include + +static gboolean append_a_row (GdaDataModel *to_model, GError **error, gint nb, ...); + +/* + * predefined statements' IDs + */ +typedef enum { + I_PRAGMA_DATABASE_LIST, + I_PRAGMA_TABLE_INFO, + I_PRAGMA_INDEX_LIST, + I_PRAGMA_INDEX_INFO, + I_PRAGMA_FK_LIST, + I_PRAGMA_PROCLIST, + I_PRAGMA_FK_ENFORCED +} InternalStatementItem; + + +/* + * predefined statements' SQL + */ +static gchar *internal_sql[] = { + /* I_PRAGMA_DATABASE_LIST */ + "PRAGMA database_list", + + /* I_PRAGMA_TABLE_INFO */ + /* warning: this can return an error as "no such function XXX" if a view has been + * defined using a function not native of SQLite (and thus not available in Libgda) */ + "PRAGMA table_info (##tblname::string)", + + /* I_PRAGMA_INDEX_LIST */ + "PRAGMA index_list (##tblname::string)", + + /* I_PRAGMA_INDEX_INFO */ + "PRAGMA index_info (##idxname::string)", + + /* I_PRAGMA_FK_LIST */ + "PRAGMA foreign_key_list (##tblname::string)", + + /* I_PRAGMA_PROCLIST */ + "PRAGMA proc_list", + + /* I_PRAGMA_FK_ENFORCED */ + "PRAGMA foreign_keys" +}; +/* name of the temporary database we don't want */ +#define TMP_DATABASE_NAME "temp" +/* SQL statement where we can't use a prepared statement since the table to select from is the variable */ +#define SELECT_TABLES_VIEWS "SELECT tbl_name, type, sql FROM %s.sqlite_master where type='table' OR type='view'" + +/* + * predefined statements' GdaStatement + */ +static GMutex init_mutex; +static GdaStatement **internal_stmt = NULL; +static GdaSet *internal_params = NULL; + +/* + * global static values + */ +static GdaSqlParser *internal_parser = NULL; +static GValue *catalog_value = NULL; +static GValue *table_type_value = NULL; +static GValue *view_type_value = NULL; +static GValue *view_check_option = NULL; +static GValue *false_value = NULL; +static GValue *true_value = NULL; +static GValue *zero_value = NULL; +static GValue *rule_value_none = NULL; +static GValue *rule_value_action = NULL; +static GdaSet *pragma_set = NULL; + +static GValue * +new_caseless_value (const GValue *cvalue) +{ + GValue *newvalue; + gchar *str, *ptr; + str = g_value_dup_string (cvalue); + for (ptr = str; *ptr; ptr++) { + if ((*ptr >= 'A') && (*ptr <= 'Z')) + *ptr += 'a' - 'A'; + if (((*ptr >= 'a') && (*ptr <= 'z')) || + ((*ptr >= '0') && (*ptr <= '9')) || + (*ptr >= '_')) + continue; + else { + g_free (str); + newvalue = gda_value_new (G_TYPE_STRING); + g_value_set_string (newvalue, g_value_get_string (cvalue)); + return newvalue; + } + } + newvalue = gda_value_new (G_TYPE_STRING); + g_value_take_string (newvalue, str); + return newvalue; +} + +/* + * Returns: @string + */ +static gchar * +to_caseless_string (gchar *string) +{ + gchar *ptr; + for (ptr = string; *ptr; ptr++) { + if ((*ptr >= 'A') && (*ptr <= 'Z')) + *ptr += 'a' - 'A'; + if (((*ptr >= 'a') && (*ptr <= 'z')) || + ((*ptr >= '0') && (*ptr <= '9')) || + (*ptr >= '_')) + continue; + else + return string; + } + return string; +} + +/* + * Meta initialization + */ +void +_gda_sqlite_provider_meta_init (GdaServerProvider *provider) +{ + g_mutex_lock (&init_mutex); + + if (!internal_stmt) { + InternalStatementItem i; + internal_parser = gda_server_provider_internal_get_parser (provider); + internal_params = gda_set_new (NULL); + + internal_stmt = g_new0 (GdaStatement *, sizeof (internal_sql) / sizeof (gchar*)); + for (i = I_PRAGMA_DATABASE_LIST; i < sizeof (internal_sql) / sizeof (gchar*); i++) { + GdaSet *set; + internal_stmt[i] = gda_sql_parser_parse_string (internal_parser, internal_sql[i], NULL, NULL); + if (!internal_stmt[i]) + g_error ("Could not parse internal statement: %s\n", internal_sql[i]); + g_assert (gda_statement_get_parameters (internal_stmt[i], &set, NULL)); + if (set) { + gda_set_merge_with_set (internal_params, set); + g_object_unref (set); + } + } + + g_value_set_string ((catalog_value = gda_value_new (G_TYPE_STRING)), "main"); + g_value_set_string ((table_type_value = gda_value_new (G_TYPE_STRING)), "BASE TABLE"); + g_value_set_string ((view_type_value = gda_value_new (G_TYPE_STRING)), "VIEW"); + g_value_set_string ((view_check_option = gda_value_new (G_TYPE_STRING)), "NONE"); + g_value_set_boolean ((false_value = gda_value_new (G_TYPE_BOOLEAN)), FALSE); + g_value_set_boolean ((true_value = gda_value_new (G_TYPE_BOOLEAN)), TRUE); + g_value_set_int ((zero_value = gda_value_new (G_TYPE_INT)), 0); + rule_value_none = view_check_option; + g_value_set_string ((rule_value_action = gda_value_new (G_TYPE_STRING)), "NO ACTION"); + + pragma_set = gda_set_new_inline (2, "tblname", G_TYPE_STRING, "", + "idxname", G_TYPE_STRING, ""); + } + + g_mutex_unlock (&init_mutex); +} + +static GdaStatement * +get_statement (InternalStatementItem type, const gchar *schema_name, const gchar *obj_name, GError **error) +{ + GdaStatement *stmt; + if (strcmp (schema_name, "main")) { + gchar *str, *qschema; + + qschema = _gda_sqlite_identifier_quote (NULL, NULL, schema_name, FALSE, FALSE); + switch (type) { + case I_PRAGMA_TABLE_INFO: + str = g_strdup_printf ("PRAGMA %s.table_info ('%s')", qschema, obj_name); + break; + case I_PRAGMA_INDEX_LIST: + str = g_strdup_printf ("PRAGMA %s.index_list ('%s')", qschema, obj_name); + break; + case I_PRAGMA_INDEX_INFO: + str = g_strdup_printf ("PRAGMA %s.index_info ('%s')", qschema, obj_name); + break; + case I_PRAGMA_FK_LIST: + str = g_strdup_printf ("PRAGMA %s.foreign_key_list ('%s')", qschema, obj_name); + break; + default: + g_assert_not_reached (); + } + + stmt = gda_sql_parser_parse_string (internal_parser, str, NULL, NULL); + g_free (str); + g_free (qschema); + g_assert (stmt); + } + else { + switch (type) { + case I_PRAGMA_TABLE_INFO: + case I_PRAGMA_INDEX_LIST: + case I_PRAGMA_FK_LIST: + if (! gda_set_set_holder_value (pragma_set, error, "tblname", obj_name)) + return NULL; + break; + case I_PRAGMA_INDEX_INFO: + if (! gda_set_set_holder_value (pragma_set, error, "idxname", obj_name)) + return NULL; + break; + default: + g_assert_not_reached (); + } + + stmt = g_object_ref (internal_stmt [type]); + } + + return stmt; +} + +gboolean +_gda_sqlite_meta__info (G_GNUC_UNUSED GdaServerProvider *prov, G_GNUC_UNUSED GdaConnection *cnc, + GdaMetaStore *store, GdaMetaContext *context, GError **error) +{ + GdaDataModel *model; + gboolean retval = TRUE; + + model = gda_meta_store_create_modify_data_model (store, context->table_name); + g_assert (model); + + retval = append_a_row (model, error, 1, FALSE, catalog_value); + if (retval) { + gda_meta_store_set_reserved_keywords_func (store, _gda_sqlite_get_reserved_keyword_func()); + retval = gda_meta_store_modify (store, context->table_name, model, NULL, error, NULL); + } + g_object_unref (model); + return retval; +} + +gboolean +_gda_sqlite_meta__btypes (G_GNUC_UNUSED GdaServerProvider *prov, G_GNUC_UNUSED GdaConnection *cnc, + GdaMetaStore *store, GdaMetaContext *context, GError **error) +{ + GdaDataModel *mod_model; + gboolean retval = TRUE; + gsize i; + typedef struct { + gchar *tname; + gchar *gtype; + gchar *comments; + gchar *synonyms; + } InternalType; + + InternalType internal_types[] = { + {"integer", "gint", "Signed integer, stored in 1, 2, 3, 4, 6, or 8 bytes depending on the magnitude of the value", "int"}, + {"real", "gdouble", "Floating point value, stored as an 8-byte IEEE floating point number", NULL}, + {"text", "string", "Text string, stored using the database encoding", "string"}, + {"blob", "GdaBlob", "Blob of data, stored exactly as it was input", NULL}, + {"timestamp", "GDateTime", "Time stamp, stored as 'YYYY-MM-DDTHH:MM:SS.SSS[TZ]'", NULL}, + {"time", "GdaTime", "Time, stored as 'HH:MM:SS.SSS'", NULL}, + {"date", "GDate", "Date, stored as 'YYYY-MM-DD'", NULL}, + {"boolean", "gboolean", "Boolean value", "bool"} + }; + + mod_model = gda_meta_store_create_modify_data_model (store, context->table_name); + g_assert (mod_model); + + for (i = 0; i < sizeof (internal_types) / sizeof (InternalType); i++) { + GValue *v1, *v2, *v3, *v4; + InternalType *it = &(internal_types[i]); + + g_value_set_string (v1 = gda_value_new (G_TYPE_STRING), it->tname); + g_value_set_string (v2 = gda_value_new (G_TYPE_STRING), it->gtype); + g_value_set_string (v3 = gda_value_new (G_TYPE_STRING), it->comments); + if (it->synonyms) + g_value_set_string (v4 = gda_value_new (G_TYPE_STRING), it->synonyms); + else + v4 = NULL; + + if (!append_a_row (mod_model, error, 6, + FALSE, v1, /* short_type_name */ + TRUE, v1, /* full_type_name */ + TRUE, v2, /* gtype */ + TRUE, v3, /* comments */ + TRUE, v4, /* synonyms */ + FALSE, false_value /* internal */)) { + retval = FALSE; + break; + } + } + if (retval) { + gda_meta_store_set_reserved_keywords_func (store, _gda_sqlite_get_reserved_keyword_func()); + retval = gda_meta_store_modify (store, context->table_name, mod_model, NULL, error, NULL); + } + g_object_unref (mod_model); + + return retval; +} + +/* + * copied from SQLite's sources to determine column affinity + */ +static gint +get_affinity (const gchar *type) +{ + guint32 h = 0; + gint aff = SQLITE_TEXT; + const unsigned char *ptr = (unsigned char *) type; + + while( *ptr ){ + h = (h<<8) + g_ascii_tolower(*ptr); + ptr++; + if( h==(('c'<<24)+('h'<<16)+('a'<<8)+'r') ){ /* CHAR */ + aff = SQLITE_TEXT; + }else if( h==(('c'<<24)+('l'<<16)+('o'<<8)+'b') ){ /* CLOB */ + aff = SQLITE_TEXT; + }else if( h==(('t'<<24)+('e'<<16)+('x'<<8)+'t') ){ /* TEXT */ + aff = SQLITE_TEXT; + }else if( h==(('b'<<24)+('l'<<16)+('o'<<8)+'b') /* BLOB */ + && (aff==SQLITE_INTEGER || aff==SQLITE_FLOAT) ){ + aff = 0; + }else if( h==(('r'<<24)+('e'<<16)+('a'<<8)+'l') /* REAL */ + && aff==SQLITE_INTEGER ){ + aff = SQLITE_FLOAT; + }else if( h==(('f'<<24)+('l'<<16)+('o'<<8)+'a') /* FLOA */ + && aff==SQLITE_INTEGER ){ + aff = SQLITE_FLOAT; + }else if( h==(('d'<<24)+('o'<<16)+('u'<<8)+'b') /* DOUB */ + && aff==SQLITE_INTEGER ){ + aff = SQLITE_FLOAT; + }else if( (h&0x00FFFFFF)==(('i'<<16)+('n'<<8)+'t') ){ /* INT */ + aff = SQLITE_INTEGER; + break; + } + } + + return aff; +} + +static gboolean +fill_udt_model (GdaSqliteProvider *prov, SqliteConnectionData *cdata, GHashTable *added_hash, + GdaDataModel *mod_model, const GValue *p_udt_schema, GError **error) +{ + gint status; + sqlite3_stmt *tables_stmt = NULL; + gchar *str; + const gchar *cstr; + gboolean retval = TRUE; + + cstr = g_value_get_string (p_udt_schema); + str = g_strdup_printf ("SELECT name FROM %s.sqlite_master WHERE type='table' AND name not like 'sqlite_%%'", cstr); + status = SQLITE3_CALL (prov, sqlite3_prepare_v2) (cdata->connection, str, -1, &tables_stmt, NULL); + g_free (str); + if ((status != SQLITE_OK) || !tables_stmt) + return FALSE; + + if (!cdata->types_hash) + _gda_sqlite_compute_types_hash (cdata); + + for (status = SQLITE3_CALL (prov, sqlite3_step) (tables_stmt); + status == SQLITE_ROW; + status = SQLITE3_CALL (prov, sqlite3_step) (tables_stmt)) { + gchar *sql; + sqlite3_stmt *fields_stmt; + gint fields_status; + + if (strcmp (cstr, "main")) + sql = g_strdup_printf ("PRAGMA %s.table_info(%s);", cstr, + SQLITE3_CALL (prov, sqlite3_column_text) (tables_stmt, 0)); + else + sql = g_strdup_printf ("PRAGMA table_info('%s');", + SQLITE3_CALL (prov, sqlite3_column_text) (tables_stmt, 0)); + fields_status = SQLITE3_CALL (prov, sqlite3_prepare_v2) (cdata->connection, sql, + -1, &fields_stmt, NULL); + g_free (sql); + if ((fields_status != SQLITE_OK) || !fields_stmt) + break; + + for (fields_status = SQLITE3_CALL (prov, sqlite3_step) (fields_stmt); + fields_status == SQLITE_ROW; + fields_status = SQLITE3_CALL (prov, sqlite3_step) (fields_stmt)) { + GType gtype; + GType *pg; + const gchar *typname = (gchar *) SQLITE3_CALL (prov, sqlite3_column_text) (fields_stmt, 2); + if (!typname || !(*typname)) + continue; + + pg = g_hash_table_lookup (cdata->types_hash, typname); + gtype = pg ? *pg : GDA_TYPE_NULL; + if ((gtype == GDA_TYPE_NULL) && !g_hash_table_lookup (added_hash, typname)) { + GValue *vname, *vgtyp; + + gtype = _gda_sqlite_compute_g_type (get_affinity (typname)); + g_value_take_string ((vname = gda_value_new (G_TYPE_STRING)), + to_caseless_string (g_strdup (typname))); + g_value_set_string ((vgtyp = gda_value_new (G_TYPE_STRING)), g_type_name (gtype)); + + if (!append_a_row (mod_model, error, 9, + FALSE, catalog_value, /* udt_catalog */ + FALSE, p_udt_schema, /* udt_schema */ + FALSE, vname, /* udt_name */ + TRUE, vgtyp, /* udt_gtype */ + TRUE, NULL, /* udt_comments */ + FALSE, vname, /* udt_short_name */ + TRUE, vname, /* udt_full_name */ + FALSE, false_value, /* udt_internal */ + FALSE, NULL /* udt_owner */)) { + retval = FALSE; + break; + } + g_hash_table_insert (added_hash, g_strdup (typname), GINT_TO_POINTER (1)); + } + } + SQLITE3_CALL (prov, sqlite3_finalize) (fields_stmt); + } + SQLITE3_CALL (prov, sqlite3_finalize) (tables_stmt); + + return retval; +} + +static guint +nocase_str_hash (gconstpointer v) +{ + guint ret; + gchar *up = g_ascii_strup ((gchar *) v, -1); + ret = g_str_hash ((gconstpointer) up); + g_free (up); + return ret; +} + +static gboolean +nocase_str_equal (gconstpointer v1, gconstpointer v2) +{ + return g_ascii_strcasecmp ((gchar *) v1, (gchar *) v2) == 0 ? TRUE : FALSE; +} + +gboolean +_gda_sqlite_meta__udt (GdaServerProvider *prov, GdaConnection *cnc, + GdaMetaStore *store, GdaMetaContext *context, GError **error) +{ + SqliteConnectionData *cdata; + GdaDataModel *mod_model = NULL; + gboolean retval = TRUE; + + GHashTable *added_hash; + GdaDataModel *tmpmodel; + gint i, nrows; + + /* get connection's private data */ + cdata = (SqliteConnectionData*) gda_connection_internal_get_provider_data_error (cnc, error); + if (!cdata) + return FALSE; + + /* get list of schemas */ + tmpmodel = (GdaDataModel *) gda_connection_statement_execute (cnc, internal_stmt[I_PRAGMA_DATABASE_LIST], + NULL, GDA_STATEMENT_MODEL_RANDOM_ACCESS, NULL, error); + if (!tmpmodel) + return FALSE; + + /* prepare modification model */ + added_hash = g_hash_table_new_full (nocase_str_hash, nocase_str_equal, g_free, NULL); + mod_model = gda_meta_store_create_modify_data_model (store, context->table_name); + g_assert (mod_model); + + nrows = gda_data_model_get_n_rows (tmpmodel); + for (i = 0; i < nrows; i++) { + /* iterate through the schemas */ + const GValue *cvalue = gda_data_model_get_value_at (tmpmodel, 1, i, error); + if (!cvalue) { + retval = FALSE; + break; + } + if (!strcmp (g_value_get_string (cvalue), TMP_DATABASE_NAME)) + continue; /* nothing to do */ + if (! fill_udt_model (GDA_SQLITE_PROVIDER (prov), cdata, added_hash, mod_model, cvalue, error)) { + retval = FALSE; + break; + } + } + g_object_unref (tmpmodel); + g_hash_table_destroy (added_hash); + + /* actually use mod_model */ + if (retval) { + gda_meta_store_set_reserved_keywords_func (store, _gda_sqlite_get_reserved_keyword_func()); + retval = gda_meta_store_modify (store, context->table_name, mod_model, NULL, error, NULL); + } + g_object_unref (mod_model); + + return retval; +} + +gboolean +_gda_sqlite_meta_udt (GdaServerProvider *prov, GdaConnection *cnc, + GdaMetaStore *store, GdaMetaContext *context, GError **error, + G_GNUC_UNUSED const GValue *udt_catalog, const GValue *udt_schema) +{ + SqliteConnectionData *cdata; + GdaDataModel *mod_model = NULL; + gboolean retval = TRUE; + + GHashTable *added_hash; + + /* get connection's private data */ + cdata = (SqliteConnectionData*) gda_connection_internal_get_provider_data_error (cnc, error); + if (!cdata) + return FALSE; + + /* prepare modification model */ + added_hash = g_hash_table_new_full (nocase_str_hash, nocase_str_equal, g_free, NULL); + mod_model = gda_meta_store_create_modify_data_model (store, context->table_name); + g_assert (mod_model); + + if (! fill_udt_model (GDA_SQLITE_PROVIDER (prov), cdata, added_hash, mod_model, udt_schema, error)) + retval = FALSE; + + g_hash_table_destroy (added_hash); + + /* actually use mod_model */ + if (retval) { + gda_meta_store_set_reserved_keywords_func (store, _gda_sqlite_get_reserved_keyword_func()); + retval = gda_meta_store_modify (store, context->table_name, mod_model, NULL, error, NULL); + } + g_object_unref (mod_model); + + return retval; +} + +gboolean +_gda_sqlite_meta__udt_cols (G_GNUC_UNUSED GdaServerProvider *prov, G_GNUC_UNUSED GdaConnection *cnc, + G_GNUC_UNUSED GdaMetaStore *store, G_GNUC_UNUSED GdaMetaContext *context, + G_GNUC_UNUSED GError **error) +{ + /* feature not supported by SQLite */ + return TRUE; +} + +gboolean +_gda_sqlite_meta_udt_cols (G_GNUC_UNUSED GdaServerProvider *prov, G_GNUC_UNUSED GdaConnection *cnc, + G_GNUC_UNUSED GdaMetaStore *store, G_GNUC_UNUSED GdaMetaContext *context, + G_GNUC_UNUSED GError **error, G_GNUC_UNUSED const GValue *udt_catalog, + G_GNUC_UNUSED const GValue *udt_schema, G_GNUC_UNUSED const GValue *udt_name) +{ + /* feature not supported by SQLite */ + return TRUE; +} + +gboolean +_gda_sqlite_meta__enums (G_GNUC_UNUSED GdaServerProvider *prov, G_GNUC_UNUSED GdaConnection *cnc, + G_GNUC_UNUSED GdaMetaStore *store, G_GNUC_UNUSED GdaMetaContext *context, + G_GNUC_UNUSED GError **error) +{ + /* feature not supported by SQLite */ + return TRUE; +} + +gboolean +_gda_sqlite_meta_enums (G_GNUC_UNUSED GdaServerProvider *prov, G_GNUC_UNUSED GdaConnection *cnc, + G_GNUC_UNUSED GdaMetaStore *store, G_GNUC_UNUSED GdaMetaContext *context, + G_GNUC_UNUSED GError **error, G_GNUC_UNUSED const GValue *udt_catalog, + G_GNUC_UNUSED const GValue *udt_schema, G_GNUC_UNUSED const GValue *udt_name) +{ + /* feature not supported by SQLite */ + return TRUE; +} + +gboolean +_gda_sqlite_meta__domains (G_GNUC_UNUSED GdaServerProvider *prov, G_GNUC_UNUSED GdaConnection *cnc, + G_GNUC_UNUSED GdaMetaStore *store, G_GNUC_UNUSED GdaMetaContext *context, + G_GNUC_UNUSED GError **error) +{ + /* feature not supported by SQLite */ + return TRUE; +} + +gboolean +_gda_sqlite_meta_domains (G_GNUC_UNUSED GdaServerProvider *prov, G_GNUC_UNUSED GdaConnection *cnc, + G_GNUC_UNUSED GdaMetaStore *store, G_GNUC_UNUSED GdaMetaContext *context, + G_GNUC_UNUSED GError **error, G_GNUC_UNUSED const GValue *domain_catalog, + G_GNUC_UNUSED const GValue *domain_schema) +{ + /* feature not supported by SQLite */ + return TRUE; +} + +gboolean +_gda_sqlite_meta__constraints_dom (G_GNUC_UNUSED GdaServerProvider *prov, G_GNUC_UNUSED GdaConnection *cnc, + G_GNUC_UNUSED GdaMetaStore *store, G_GNUC_UNUSED GdaMetaContext *context, + G_GNUC_UNUSED GError **error) +{ + /* feature not supported by SQLite */ + return TRUE; +} + +gboolean +_gda_sqlite_meta_constraints_dom (G_GNUC_UNUSED GdaServerProvider *prov, G_GNUC_UNUSED GdaConnection *cnc, + G_GNUC_UNUSED GdaMetaStore *store, G_GNUC_UNUSED GdaMetaContext *context, + G_GNUC_UNUSED GError **error, G_GNUC_UNUSED const GValue *domain_catalog, + G_GNUC_UNUSED const GValue *domain_schema, + G_GNUC_UNUSED const GValue *domain_name) +{ + /* feature not supported by SQLite */ + return TRUE; +} + +gboolean +_gda_sqlite_meta__el_types (G_GNUC_UNUSED GdaServerProvider *prov, G_GNUC_UNUSED GdaConnection *cnc, + G_GNUC_UNUSED GdaMetaStore *store, G_GNUC_UNUSED GdaMetaContext *context, + G_GNUC_UNUSED GError **error) +{ + /* feature not supported by SQLite */ + return TRUE; +} + +gboolean +_gda_sqlite_meta_el_types (G_GNUC_UNUSED GdaServerProvider *prov, G_GNUC_UNUSED GdaConnection *cnc, + G_GNUC_UNUSED GdaMetaStore *store, G_GNUC_UNUSED GdaMetaContext *context, + G_GNUC_UNUSED GError **error, G_GNUC_UNUSED const GValue *specific_name) +{ + /* feature not supported by SQLite */ + return TRUE; +} + +gboolean +_gda_sqlite_meta__collations (G_GNUC_UNUSED GdaServerProvider *prov, G_GNUC_UNUSED GdaConnection *cnc, + G_GNUC_UNUSED GdaMetaStore *store, G_GNUC_UNUSED GdaMetaContext *context, + G_GNUC_UNUSED GError **error) +{ + /* FIXME: We need to do something similar to what's done with + * functions and aggregates as there is no pragma or API */ + return TRUE; +} + +gboolean +_gda_sqlite_meta_collations (G_GNUC_UNUSED GdaServerProvider *prov, G_GNUC_UNUSED GdaConnection *cnc, + G_GNUC_UNUSED GdaMetaStore *store, G_GNUC_UNUSED GdaMetaContext *context, + G_GNUC_UNUSED GError **error, G_GNUC_UNUSED const GValue *collation_catalog, + G_GNUC_UNUSED const GValue *collation_schema, + G_GNUC_UNUSED const GValue *collation_name_n) +{ + /* FIXME: We need to do something similar to what's done with + * functions and aggregates as there is no pragma or API */ + return TRUE; +} + +gboolean +_gda_sqlite_meta__character_sets (G_GNUC_UNUSED GdaServerProvider *prov, G_GNUC_UNUSED GdaConnection *cnc, + G_GNUC_UNUSED GdaMetaStore *store, G_GNUC_UNUSED GdaMetaContext *context, G_GNUC_UNUSED GError **error) +{ + /* FIXME: We need to do something similar to what's done with + * functions and aggregates as there is no pragma or API */ + return TRUE; +} + +gboolean +_gda_sqlite_meta_character_sets (G_GNUC_UNUSED GdaServerProvider *prov, G_GNUC_UNUSED GdaConnection *cnc, + G_GNUC_UNUSED GdaMetaStore *store, G_GNUC_UNUSED GdaMetaContext *context, G_GNUC_UNUSED GError **error, + G_GNUC_UNUSED const GValue *chset_catalog, G_GNUC_UNUSED const GValue *chset_schema, + G_GNUC_UNUSED const GValue *chset_name_n) +{ + /* FIXME: We need to do something similar to what's done with + * functions and aggregates as there is no pragma or API */ + return TRUE; +} + +gboolean +_gda_sqlite_meta__schemata (GdaServerProvider *prov, GdaConnection *cnc, + GdaMetaStore *store, GdaMetaContext *context, GError **error) +{ + return _gda_sqlite_meta_schemata (prov, cnc, store, context, error, + NULL, NULL); +} + +gboolean +_gda_sqlite_meta_schemata (G_GNUC_UNUSED GdaServerProvider *prov, GdaConnection *cnc, + GdaMetaStore *store, GdaMetaContext *context, GError **error, + G_GNUC_UNUSED const GValue *catalog_name, const GValue *schema_name_n) +{ + GdaDataModel *model, *tmpmodel; + gboolean retval = TRUE; + gint nrows, i; + tmpmodel = (GdaDataModel *) gda_connection_statement_execute (cnc, internal_stmt[I_PRAGMA_DATABASE_LIST], + NULL, GDA_STATEMENT_MODEL_RANDOM_ACCESS, NULL, error); + if (!tmpmodel) + return FALSE; + + model = gda_meta_store_create_modify_data_model (store, context->table_name); + g_assert (model); + + nrows = gda_data_model_get_n_rows (tmpmodel); + for (i = 0; (i < nrows) && retval; i++) { + const GValue *cvalue; + + cvalue = gda_data_model_get_value_at (tmpmodel, 1, i, error); + if (!cvalue) { + retval = FALSE; + break; + } + if (!schema_name_n || + !gda_value_compare (schema_name_n, cvalue)) { + const gchar *cstr; + GValue *v1, *v2; + + cstr = g_value_get_string (cvalue); /* VMA */ + if (!cstr || !strncmp (cstr, TMP_DATABASE_NAME, 4)) + continue; + + g_value_set_boolean ((v1 = gda_value_new (G_TYPE_BOOLEAN)), FALSE); + g_value_set_boolean ((v2 = gda_value_new (G_TYPE_BOOLEAN)), TRUE); + retval = append_a_row (model, error, 5, + FALSE, catalog_value, + TRUE, new_caseless_value (cvalue), + FALSE, NULL, + TRUE, v1, + TRUE, v2); + } + } + g_object_unref (tmpmodel); + if (retval){ + gda_meta_store_set_reserved_keywords_func (store, _gda_sqlite_get_reserved_keyword_func()); + retval = gda_meta_store_modify_with_context (store, context, model, error); + } + g_object_unref (model); + + return retval; +} + +/* + * Warning: this is a hack where it is assumed that the GValue values from SQLite's SELECT execution are available + * event _after_ several calls to gda_data_model_get_value_at(), which might not be TRUE in all the cases. + * + * For this purpose, the @models list contains the list of data models which then have to be destroyed. + */ +static gboolean +fill_tables_views_model (GdaConnection *cnc, + GdaDataModel *to_tables_model, GdaDataModel *to_views_model, + const GValue *p_table_schema, const GValue *p_table_name, + GError **error) +{ + gchar *str; + GdaDataModel *tmpmodel; + gboolean retval = TRUE; + gint nrows, i; + GdaStatement *stmt; + GType col_types[] = {G_TYPE_STRING, G_TYPE_STRING, G_TYPE_NONE}; + const gchar *schema_name = TMP_DATABASE_NAME; + if (p_table_schema != NULL) { + schema_name = g_value_get_string (p_table_schema); + } + + if (!g_strcmp0 (schema_name, TMP_DATABASE_NAME)) + return TRUE; /* nothing to do */ + + str = g_strdup_printf (SELECT_TABLES_VIEWS, schema_name); + stmt = gda_sql_parser_parse_string (internal_parser, str, NULL, NULL); + g_free (str); + g_assert (stmt); + tmpmodel = gda_connection_statement_execute_select_full (cnc, stmt, NULL, + GDA_STATEMENT_MODEL_RANDOM_ACCESS, + col_types, error); + g_object_unref (stmt); + if (!tmpmodel) + return FALSE; + + nrows = gda_data_model_get_n_rows (tmpmodel); + for (i = 0; (i < nrows) && retval; i++) { + const GValue *cvalue; + GValue *ncvalue; + + cvalue = gda_data_model_get_value_at (tmpmodel, 0, i, error); + if (!cvalue) { + retval = FALSE; + break; + } + ncvalue = new_caseless_value (cvalue); + + if (!p_table_name || + !gda_value_compare (p_table_name, ncvalue)) { + GValue *v1, *v2 = NULL; + const GValue *tvalue; + const GValue *dvalue; + gboolean is_view = FALSE; + const gchar *this_table_name; + GValue *ntable_schema; + + this_table_name = g_value_get_string (ncvalue); + g_assert (this_table_name); + if (!strcmp (this_table_name, "sqlite_sequence")) { + gda_value_free (ncvalue); + continue; /* ignore that table */ + } + + tvalue = gda_data_model_get_value_at (tmpmodel, 1, i, error); + if (!tvalue) { + retval = FALSE; + gda_value_free (ncvalue); + break; + } + dvalue = gda_data_model_get_value_at (tmpmodel, 2, i, error); + if (!dvalue) { + retval = FALSE; + gda_value_free (ncvalue); + break; + } + ntable_schema = new_caseless_value (p_table_schema); + if (*(g_value_get_string (tvalue)) == 'v') + is_view = TRUE; + g_value_set_boolean ((v1 = gda_value_new (G_TYPE_BOOLEAN)), TRUE); + + str = g_strdup_printf ("%s.%s", + g_value_get_string (ntable_schema), + g_value_get_string (ncvalue)); + g_value_take_string ((v2 = gda_value_new (G_TYPE_STRING)), str); + + if (is_view && ! append_a_row (to_views_model, error, 6, + FALSE, catalog_value, + FALSE, ntable_schema, + FALSE, ncvalue, + FALSE, dvalue, + FALSE, view_check_option, + FALSE, false_value)) + retval = FALSE; + if (! append_a_row (to_tables_model, error, 9, + FALSE, catalog_value, /* table_catalog */ + TRUE, ntable_schema, /* table_schema */ + TRUE, ncvalue, /* table_name */ + FALSE, is_view ? view_type_value : table_type_value, /* table_type */ + TRUE, v1, /* is_insertable_into */ + FALSE, NULL, /* table_comments */ + FALSE, strcmp (schema_name, "main") ? v2 : ncvalue, /* table_short_name */ + TRUE, v2, /* table_full_name */ + FALSE, NULL)) /* table_owner */ + retval = FALSE; + } + else + gda_value_free (ncvalue); + } + g_object_unref (tmpmodel); + + return retval; +} + +gboolean +_gda_sqlite_meta__tables_views (G_GNUC_UNUSED GdaServerProvider *prov, GdaConnection *cnc, + GdaMetaStore *store, GdaMetaContext *context, GError **error) +{ + GdaDataModel *tmpmodel; + GdaDataModel *tables_model, *views_model; + gboolean retval = TRUE; + gint i, nrows; + + tmpmodel = (GdaDataModel *) gda_connection_statement_execute (cnc, internal_stmt[I_PRAGMA_DATABASE_LIST], + NULL, GDA_STATEMENT_MODEL_RANDOM_ACCESS, NULL, error); + if (!tmpmodel) + return FALSE; + + tables_model = gda_meta_store_create_modify_data_model (store, "_tables"); + g_assert (tables_model); + views_model = gda_meta_store_create_modify_data_model (store, "_views"); + g_assert (views_model); + + nrows = gda_data_model_get_n_rows (tmpmodel); + for (i = 0; i < nrows; i++) { + /* iterate through the schemas */ + const GValue *cvalue = gda_data_model_get_value_at (tmpmodel, 1, i, error); + if (!cvalue) { + retval = FALSE; + break; + } + if (!strcmp (g_value_get_string (cvalue), TMP_DATABASE_NAME)) + continue; /* nothing to do */ + + if (! fill_tables_views_model (cnc, tables_model, views_model, + cvalue, NULL, error)) { + retval = FALSE; + break; + } + } + + GdaMetaContext c2; + c2 = *context; /* copy contents, just because we need to modify @context->table_name */ + if (retval) { + c2.table_name = "_tables"; + gda_meta_store_set_reserved_keywords_func (store, _gda_sqlite_get_reserved_keyword_func()); + retval = gda_meta_store_modify_with_context (store, &c2, tables_model, error); + } + if (retval) { + c2.table_name = "_views"; + gda_meta_store_set_reserved_keywords_func (store, _gda_sqlite_get_reserved_keyword_func()); + retval = gda_meta_store_modify_with_context (store, &c2, views_model, error); + } + g_object_unref (views_model); + g_object_unref (tables_model); + + g_object_unref (tmpmodel); + return retval; +} + +gboolean +_gda_sqlite_meta_tables_views (G_GNUC_UNUSED GdaServerProvider *prov, GdaConnection *cnc, + GdaMetaStore *store, GdaMetaContext *context, GError **error, + G_GNUC_UNUSED const GValue *table_catalog, const GValue *table_schema, const GValue *table_name_n) +{ + GdaDataModel *tables_model, *views_model; + gboolean retval = TRUE; + tables_model = gda_meta_store_create_modify_data_model (store, "_tables"); + g_assert (tables_model); + views_model = gda_meta_store_create_modify_data_model (store, "_views"); + g_assert (views_model); + + if (! fill_tables_views_model (cnc, tables_model, views_model, table_schema, table_name_n, error)) + retval = FALSE; + + GdaMetaContext c2; + c2 = *context; /* copy contents, just because we need to modify @context->table_name */ + if (retval) { + c2.table_name = "_tables"; + gda_meta_store_set_reserved_keywords_func (store, _gda_sqlite_get_reserved_keyword_func()); + retval = gda_meta_store_modify_with_context (store, &c2, tables_model, error); + } + if (retval) { + c2.table_name = "_views"; + gda_meta_store_set_reserved_keywords_func (store, _gda_sqlite_get_reserved_keyword_func()); + retval = gda_meta_store_modify_with_context (store, &c2, views_model, error); + } + g_object_unref (tables_model); + g_object_unref (views_model); + + return retval; +} + +static gboolean +fill_columns_model (GdaConnection *cnc, SqliteConnectionData *cdata, + GdaDataModel *mod_model, + const GValue *p_table_schema, const GValue *p_table_name, + GError **error) +{ + GdaDataModel *tmpmodel; + gboolean retval = TRUE; + gint nrows; + const gchar *schema_name; + gint i; + GType col_types[] = {G_TYPE_INT, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INT, + G_TYPE_STRING, G_TYPE_BOOLEAN, G_TYPE_NONE}; + GdaStatement *stmt; + GError *lerror = NULL; + GdaSqliteProvider *prov = GDA_SQLITE_PROVIDER (gda_connection_get_provider (GDA_CONNECTION (cnc))); + + schema_name = g_value_get_string (p_table_schema); + stmt = get_statement (I_PRAGMA_TABLE_INFO, schema_name, g_value_get_string (p_table_name), NULL); + tmpmodel = gda_connection_statement_execute_select_full (cnc, stmt, pragma_set, + GDA_STATEMENT_MODEL_RANDOM_ACCESS, + col_types, &lerror); + g_object_unref (stmt); + if (!tmpmodel) { + if (lerror && lerror->message && !strstr (lerror->message, "no such function")) { + g_propagate_error (error, lerror); + return FALSE; + } + else + return TRUE; + } + + nrows = gda_data_model_get_n_rows (tmpmodel); + for (i = 0; i < nrows; i++) { + GValue *v1, *v2, *v3, *v4, *v5 = NULL, *v6; + char const *pzDataType; /* Declared data type */ + char const *pzCollSeq; /* Collation sequence name */ + int pNotNull; /* True if NOT NULL constraint exists */ + int pPrimaryKey; /* True if column part of PK */ + int pAutoinc; /* True if column is auto-increment */ + const gchar *this_table_name; + const gchar *this_col_name; + const GValue *this_col_pname; + GValue *nthis_col_pname = NULL; + GType gtype = GDA_TYPE_NULL; + const GValue *cvalue; + + this_col_pname = gda_data_model_get_value_at (tmpmodel, 1, i, error); + if (!this_col_pname) { + retval = FALSE; + break; + } + nthis_col_pname = new_caseless_value (this_col_pname); + + this_table_name = g_value_get_string (p_table_name); + g_assert (this_table_name); + if (!strcmp (this_table_name, "sqlite_sequence")) { + gda_value_free (nthis_col_pname); + continue; /* ignore that table */ + } + + this_col_name = g_value_get_string (nthis_col_pname); + if (SQLITE3_CALL (prov, sqlite3_table_column_metadata) (cdata->connection, + g_value_get_string (p_table_schema), + this_table_name, this_col_name, + &pzDataType, &pzCollSeq, + &pNotNull, &pPrimaryKey, &pAutoinc) + != SQLITE_OK) { + /* may fail because we have a view and not a table => use @tmpmodel to fetch info. */ + cvalue = gda_data_model_get_value_at (tmpmodel, 2, i, error); + if (!cvalue) { + retval = FALSE; + gda_value_free (nthis_col_pname); + break; + } + pzDataType = g_value_get_string (cvalue); + pzCollSeq = NULL; + cvalue = gda_data_model_get_value_at (tmpmodel, 3, i, error); + if (!cvalue) { + retval = FALSE; + gda_value_free (nthis_col_pname); + break; + } + pNotNull = g_value_get_int (cvalue); + cvalue = gda_data_model_get_value_at (tmpmodel, 5, i, error); + if (!cvalue) { + retval = FALSE; + gda_value_free (nthis_col_pname); + break; + } + pPrimaryKey = g_value_get_boolean (cvalue); + pAutoinc = 0; + } + + cvalue = gda_data_model_get_value_at (tmpmodel, 0, i, error); + if (!cvalue) { + retval = FALSE; + gda_value_free (nthis_col_pname); + break; + } + v1 = gda_value_copy (cvalue); + g_value_set_string ((v2 = gda_value_new (G_TYPE_STRING)), pzDataType); + g_value_set_boolean ((v3 = gda_value_new (G_TYPE_BOOLEAN)), pNotNull ? FALSE : TRUE); + if (pzCollSeq) + g_value_take_string ((v4 = gda_value_new (G_TYPE_STRING)), + to_caseless_string (g_strdup (pzCollSeq))); + else + v4 = NULL; + if (pAutoinc) + g_value_set_string ((v5 = gda_value_new (G_TYPE_STRING)), GDA_EXTRA_AUTO_INCREMENT); + g_value_set_int (v1, g_value_get_int (v1) + 1); + + if (pzDataType) { + gchar *tmp = g_strdup (pzDataType); + gchar *ptr; + GType *pg; + for (ptr = tmp; *ptr && (*ptr != '(') && (*ptr != '['); ptr++); + if (*ptr) + *ptr = 0; + pg = g_hash_table_lookup (cdata->types_hash, tmp); + gtype = pg ? (GType) *pg : GDA_TYPE_NULL; + g_free (tmp); + } + if (gtype == GDA_TYPE_NULL) + /* default to string if nothing else */ + g_value_set_string ((v6 = gda_value_new (G_TYPE_STRING)), "string"); + else + g_value_set_string ((v6 = gda_value_new (G_TYPE_STRING)), g_type_name (gtype)); + cvalue = gda_data_model_get_value_at (tmpmodel, 4, i, error); + if (!cvalue) { + gda_value_free (nthis_col_pname); + retval = FALSE; + break; + } + if (! append_a_row (mod_model, error, 24, + FALSE, catalog_value, /* table_catalog */ + TRUE, new_caseless_value (p_table_schema), /* table_schema */ + TRUE, new_caseless_value (p_table_name), /* table_name */ + TRUE, nthis_col_pname, /* column name */ + TRUE, v1, /* ordinal_position */ + FALSE, cvalue, /* column default */ + TRUE, v3, /* is_nullable */ + TRUE, v2, /* data_type */ + FALSE, NULL, /* array_spec */ + TRUE, v6, /* gtype */ + FALSE, NULL, /* character_maximum_length */ + FALSE, NULL, /* character_octet_length */ + FALSE, NULL, /* numeric_precision */ + FALSE, NULL, /* numeric_scale */ + FALSE, NULL, /* datetime_precision */ + FALSE, NULL, /* character_set_catalog */ + FALSE, NULL, /* character_set_schema */ + FALSE, NULL, /* character_set_name */ + FALSE, catalog_value, /* collation_catalog */ + FALSE, catalog_value, /* collation_schema */ + TRUE, v4, /* collation_name */ + v5 ? TRUE : FALSE, v5, /* extra */ + FALSE, NULL, /* is_updatable */ + FALSE, NULL /* column_comments */)) + retval = FALSE; + + } + + g_object_unref (tmpmodel); + return retval; +} + +gboolean +_gda_sqlite_meta__columns (G_GNUC_UNUSED GdaServerProvider *prov, GdaConnection *cnc, + GdaMetaStore *store, GdaMetaContext *context, GError **error) +{ + GdaDataModel *mod_model, *tmpmodel; + gboolean retval = TRUE; + gint i, nrows; + SqliteConnectionData *cdata; + + cdata = (SqliteConnectionData*) gda_connection_internal_get_provider_data_error (cnc, error); + if (!cdata) + return FALSE; + + tmpmodel = (GdaDataModel *) gda_connection_statement_execute (cnc, internal_stmt[I_PRAGMA_DATABASE_LIST], + NULL, GDA_STATEMENT_MODEL_RANDOM_ACCESS, NULL, error); + if (!tmpmodel) + return FALSE; + + mod_model = gda_meta_store_create_modify_data_model (store, context->table_name); + g_assert (mod_model); + + nrows = gda_data_model_get_n_rows (tmpmodel); + for (i = 0; i < nrows; i++) { + /* iterate through the schemas */ + GdaDataModel *tables_model; + const gchar *schema_name; + const GValue *cvalue = gda_data_model_get_value_at (tmpmodel, 1, i, error); + if (!cvalue) { + retval = FALSE; + break; + } + schema_name = g_value_get_string (cvalue); + if (!strcmp (schema_name, TMP_DATABASE_NAME)) + continue; /* nothing to do */ + + gchar *str; + GType col_types[] = {G_TYPE_STRING, G_TYPE_STRING, G_TYPE_NONE}; + GdaStatement *stmt; + + str = g_strdup_printf (SELECT_TABLES_VIEWS, schema_name); + stmt = gda_sql_parser_parse_string (internal_parser, str, NULL, NULL); + g_free (str); + g_assert (stmt); + tables_model = gda_connection_statement_execute_select_full (cnc, stmt, NULL, + GDA_STATEMENT_MODEL_RANDOM_ACCESS, + col_types, error); + g_object_unref (stmt); + if (!tables_model) { + retval = FALSE; + break; + } + + gint tnrows, ti; + tnrows = gda_data_model_get_n_rows (tables_model); + for (ti = 0; ti < tnrows; ti++) { + /* iterate through the tables */ + const GValue *cv; + cv = gda_data_model_get_value_at (tables_model, 0, ti, error); + if (!cv) { + retval = FALSE; + break; + } + if (!fill_columns_model (cnc, cdata, mod_model, cvalue, cv, error)) { + retval = FALSE; + break; + } + } + g_object_unref (tables_model); + if (!retval) + break; + } + g_object_unref (tmpmodel); + + if (retval) { + gda_meta_store_set_reserved_keywords_func (store, _gda_sqlite_get_reserved_keyword_func()); + retval = gda_meta_store_modify_with_context (store, context, mod_model, error); + } + g_object_unref (mod_model); + + return retval; +} + +gboolean +_gda_sqlite_meta_columns (G_GNUC_UNUSED GdaServerProvider *prov, GdaConnection *cnc, + GdaMetaStore *store, GdaMetaContext *context, GError **error, + G_GNUC_UNUSED const GValue *table_catalog, const GValue *table_schema, const GValue *table_name) +{ + gboolean retval = TRUE; + GdaDataModel *mod_model = NULL; + SqliteConnectionData *cdata; + + cdata = (SqliteConnectionData*) gda_connection_internal_get_provider_data_error (cnc, error); + if (!cdata) + return FALSE; + + mod_model = gda_meta_store_create_modify_data_model (store, context->table_name); + g_assert (mod_model); + + retval = fill_columns_model (cnc, cdata, mod_model, table_schema, table_name, error); + if (retval) { + gda_meta_store_set_reserved_keywords_func (store, _gda_sqlite_get_reserved_keyword_func()); + retval = gda_meta_store_modify_with_context (store, context, mod_model, error); + } + g_object_unref (mod_model); + + return retval; +} + +gboolean +_gda_sqlite_meta__view_cols (G_GNUC_UNUSED GdaServerProvider *prov, G_GNUC_UNUSED GdaConnection *cnc, + G_GNUC_UNUSED GdaMetaStore *store, G_GNUC_UNUSED GdaMetaContext *context, G_GNUC_UNUSED GError **error) +{ + /* FIXME: feature not natively supported by SQLite => parse view's definition ? */ + return TRUE; +} + +gboolean +_gda_sqlite_meta_view_cols (G_GNUC_UNUSED GdaServerProvider *prov, G_GNUC_UNUSED GdaConnection *cnc, + G_GNUC_UNUSED GdaMetaStore *store, G_GNUC_UNUSED GdaMetaContext *context, + G_GNUC_UNUSED GError **error, G_GNUC_UNUSED const GValue *view_catalog, + G_GNUC_UNUSED const GValue *view_schema, G_GNUC_UNUSED const GValue *view_name) +{ + /* FIXME: feature not natively supported by SQLite => parse view's definition ? */ + return TRUE; +} + +static gboolean +fill_constraints_tab_model (GdaConnection *cnc, SqliteConnectionData *cdata, GdaDataModel *mod_model, + const GValue *p_table_schema, const GValue *p_table_name, const GValue *constraint_name_n, + GError **error) +{ + GdaDataModel *tmpmodel; + gboolean retval = TRUE; + gint nrows; + const gchar *schema_name; + gint i; + GdaStatement *stmt; + GError *lerror = NULL; + GdaSqliteProvider *prov = GDA_SQLITE_PROVIDER (gda_connection_get_provider (GDA_CONNECTION (cnc))); + + + schema_name = g_value_get_string (p_table_schema); + + /* + * PRIMARY KEY + * + * SQLite only allows 1 primary key to be defined per table. + */ + GType pk_col_types[] = {G_TYPE_INT, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INT, + G_TYPE_STRING, G_TYPE_BOOLEAN, G_TYPE_NONE}; + gboolean has_pk = FALSE; + + stmt = get_statement (I_PRAGMA_TABLE_INFO, schema_name, g_value_get_string (p_table_name), NULL); + tmpmodel = gda_connection_statement_execute_select_full (cnc, stmt, pragma_set, + GDA_STATEMENT_MODEL_RANDOM_ACCESS, + pk_col_types, &lerror); + g_object_unref (stmt); + if (!tmpmodel) { + if (lerror && lerror->message && !strstr (lerror->message, "no such function")) { + g_propagate_error (error, lerror); + return FALSE; + } + else + return TRUE; + } + + nrows = gda_data_model_get_n_rows (tmpmodel); + for (i = 0; i < nrows; i++) { + char const *pzDataType; /* Declared data type */ + char const *pzCollSeq; /* Collation sequence name */ + int pNotNull; /* True if NOT NULL constraint exists */ + int pPrimaryKey; /* True if column part of PK */ + int pAutoinc; /* True if column is auto-increment */ + const gchar *this_table_name; + const gchar *this_col_name; + const GValue *this_col_pname, *cvalue; + + this_col_pname = gda_data_model_get_value_at (tmpmodel, 1, i, error); + if (!this_col_pname) { + retval = FALSE; + break; + } + this_table_name = g_value_get_string (p_table_name); + g_assert (this_table_name); + if (!strcmp (this_table_name, "sqlite_sequence")) + continue; /* ignore that table */ + + this_col_name = g_value_get_string (this_col_pname); + if (SQLITE3_CALL (prov, sqlite3_table_column_metadata) (cdata->connection, + g_value_get_string (p_table_schema), + this_table_name, this_col_name, + &pzDataType, &pzCollSeq, + &pNotNull, &pPrimaryKey, &pAutoinc) + != SQLITE_OK) { + /* may fail because we have a view and not a table => use @tmpmodel to fetch info. */ + cvalue = gda_data_model_get_value_at (tmpmodel, 5, i, error); + if (!cvalue) { + retval = FALSE; + break; + } + pPrimaryKey = g_value_get_boolean (cvalue); + } + + if (pPrimaryKey) { + has_pk = TRUE; + break; + } + } + + if (retval && has_pk) { + if (!constraint_name_n || ! strcmp (g_value_get_string (constraint_name_n), "primary_key")) { + GValue *v1, *v2, *v3; + g_value_set_string ((v1 = gda_value_new (G_TYPE_STRING)), "primary_key"); + g_value_set_string ((v2 = gda_value_new (G_TYPE_STRING)), "PRIMARY KEY"); + v3 = new_caseless_value (p_table_schema); + + if (! append_a_row (mod_model, error, 10, + FALSE, catalog_value, /* constraint_catalog */ + FALSE, v3, /* constraint_schema */ + TRUE, v1, /* constraint_name */ + FALSE, catalog_value, /* table_catalog */ + TRUE, v3, /* table_schema */ + TRUE, new_caseless_value (p_table_name), /* table_name */ + TRUE, v2, /* constraint_type */ + FALSE, NULL, /* check_clause */ + FALSE, NULL, /* is_deferrable */ + FALSE, NULL /* initially_deferred */)) + retval = FALSE; + } + } + + g_object_unref (tmpmodel); + if (!retval) + return FALSE; + + /* + * UNIQUE + */ + GType unique_col_types[] = {G_TYPE_INT, G_TYPE_STRING, G_TYPE_INT, G_TYPE_NONE}; + + stmt = get_statement (I_PRAGMA_INDEX_LIST, schema_name, g_value_get_string (p_table_name), error); + tmpmodel = gda_connection_statement_execute_select_full (cnc, stmt, pragma_set, + GDA_STATEMENT_MODEL_RANDOM_ACCESS, + unique_col_types, error); + g_object_unref (stmt); + if (!tmpmodel) + return FALSE; + + nrows = gda_data_model_get_n_rows (tmpmodel); + for (i = 0; i < nrows; i++) { + const GValue *cvalue; + GValue *v2; + + cvalue = gda_data_model_get_value_at (tmpmodel, 2, i, error); + if (!cvalue) { + retval = FALSE; + break; + } + if (!g_value_get_int (cvalue)) + continue; + + cvalue = gda_data_model_get_value_at (tmpmodel, 1, i, error); + if (!cvalue) { + retval = FALSE; + break; + } + if (constraint_name_n && strcmp (g_value_get_string (constraint_name_n), g_value_get_string (cvalue))) + continue; + + g_value_set_string ((v2 = gda_value_new (G_TYPE_STRING)), "UNIQUE"); + + if (! append_a_row (mod_model, error, 10, + FALSE, catalog_value, /* constraint_catalog */ + TRUE, new_caseless_value (p_table_schema), /* constraint_schema */ + TRUE, new_caseless_value (cvalue), /* constraint_name */ + FALSE, catalog_value, /* table_catalog */ + TRUE, new_caseless_value (p_table_schema), /* table_schema */ + TRUE, new_caseless_value (p_table_name), /* table_name */ + TRUE, v2, /* constraint_type */ + FALSE, NULL, /* check_clause */ + FALSE, NULL, /* is_deferrable */ + FALSE, NULL /* initially_deferred */)) + retval = FALSE; + } + g_object_unref (tmpmodel); + if (!retval) + return FALSE; + + /* + * FOREIGN KEYS + */ + GType fk_col_types[] = {G_TYPE_INT, G_TYPE_INT, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_NONE}; + gint fkid = -1; + stmt = get_statement (I_PRAGMA_FK_LIST, schema_name, g_value_get_string (p_table_name), error); + tmpmodel = gda_connection_statement_execute_select_full (cnc, stmt, pragma_set, + GDA_STATEMENT_MODEL_RANDOM_ACCESS, + fk_col_types, error); + g_object_unref (stmt); + if (!tmpmodel) + return FALSE; + + nrows = gda_data_model_get_n_rows (tmpmodel); + for (i = 0; i < nrows; i++) { + const GValue *cvalue; + + cvalue = gda_data_model_get_value_at (tmpmodel, 0, i, error); + if (!cvalue) { + retval = FALSE; + break; + } + if ((fkid == -1) || (fkid != g_value_get_int (cvalue))) { + gchar *constname; + GValue *v1, *v2; + + fkid = g_value_get_int (cvalue); + + cvalue = gda_data_model_get_value_at (tmpmodel, 2, i, error); + if (!cvalue) { + retval = FALSE; + break; + } + constname = g_strdup_printf ("fk%d_%s", fkid, g_value_get_string (cvalue)); + if (constraint_name_n && strcmp (g_value_get_string (constraint_name_n), constname)) { + g_free (constname); + continue; + } + + g_value_take_string ((v1 = gda_value_new (G_TYPE_STRING)), constname); + g_value_set_string ((v2 = gda_value_new (G_TYPE_STRING)), "FOREIGN KEY"); + + if (! append_a_row (mod_model, error, 10, + FALSE, catalog_value, /* constraint_catalog */ + TRUE, new_caseless_value (p_table_schema), /* constraint_schema */ + TRUE, v1, /* constraint_name */ + FALSE, catalog_value, /* table_catalog */ + TRUE, new_caseless_value (p_table_schema), /* table_schema */ + TRUE, new_caseless_value (p_table_name), /* table_name */ + TRUE, v2, /* constraint_type */ + FALSE, NULL, /* check_clause */ + FALSE, NULL, /* is_deferrable */ + FALSE, NULL /* initially_deferred */)) + retval = FALSE; + } + } + g_object_unref (tmpmodel); + + /* + * CHECK constraint + * FIXME: how to get that information? + */ + + return retval; +} + +gboolean +_gda_sqlite_meta__constraints_tab (G_GNUC_UNUSED GdaServerProvider *prov, GdaConnection *cnc, + GdaMetaStore *store, GdaMetaContext *context, GError **error) +{ + GdaDataModel *mod_model, *tmpmodel; + gboolean retval = TRUE; + gint i, nrows; + SqliteConnectionData *cdata; + + cdata = (SqliteConnectionData*) gda_connection_internal_get_provider_data_error (cnc, error); + if (!cdata) + return FALSE; + + tmpmodel = (GdaDataModel *) gda_connection_statement_execute (cnc, internal_stmt[I_PRAGMA_DATABASE_LIST], + NULL, GDA_STATEMENT_MODEL_RANDOM_ACCESS, NULL, error); + if (!tmpmodel) + return FALSE; + + mod_model = gda_meta_store_create_modify_data_model (store, context->table_name); + g_assert (mod_model); + + nrows = gda_data_model_get_n_rows (tmpmodel); + for (i = 0; i < nrows; i++) { + /* iterate through the schemas */ + GdaDataModel *tables_model; + const gchar *schema_name; + const GValue *cvalue = gda_data_model_get_value_at (tmpmodel, 1, i, error); + if (!cvalue) { + retval = FALSE; + break; + } + schema_name = g_value_get_string (cvalue); + if (!strcmp (schema_name, TMP_DATABASE_NAME)) + continue; /* nothing to do */ + + gchar *str; + GType col_types[] = {G_TYPE_STRING, G_TYPE_STRING, G_TYPE_NONE}; + GdaStatement *stmt; + + str = g_strdup_printf (SELECT_TABLES_VIEWS, schema_name); + stmt = gda_sql_parser_parse_string (internal_parser, str, NULL, NULL); + g_free (str); + g_assert (stmt); + tables_model = gda_connection_statement_execute_select_full (cnc, stmt, NULL, + GDA_STATEMENT_MODEL_RANDOM_ACCESS, + col_types, error); + g_object_unref (stmt); + if (!tables_model) { + retval = FALSE; + break; + } + + gint tnrows, ti; + tnrows = gda_data_model_get_n_rows (tables_model); + for (ti = 0; ti < tnrows; ti++) { + /* iterate through the tables */ + const GValue *cv = gda_data_model_get_value_at (tables_model, 0, ti, error); + if (!cv) { + retval = FALSE; + break; + } + if (!fill_constraints_tab_model (cnc, cdata, mod_model, cvalue, cv, NULL, error)) { + retval = FALSE; + break; + } + } + g_object_unref (tables_model); + if (!retval) + break; + } + g_object_unref (tmpmodel); + + if (retval) { + gda_meta_store_set_reserved_keywords_func (store, _gda_sqlite_get_reserved_keyword_func()); + retval = gda_meta_store_modify_with_context (store, context, mod_model, error); + } + g_object_unref (mod_model); + + return retval; +} + +gboolean +_gda_sqlite_meta_constraints_tab (G_GNUC_UNUSED GdaServerProvider *prov, GdaConnection *cnc, + GdaMetaStore *store, GdaMetaContext *context, GError **error, + G_GNUC_UNUSED const GValue *table_catalog, const GValue *table_schema, + const GValue *table_name, const GValue *constraint_name_n) +{ + gboolean retval = TRUE; + GdaDataModel *mod_model = NULL; + SqliteConnectionData *cdata; + + cdata = (SqliteConnectionData*) gda_connection_internal_get_provider_data_error (cnc, error); + if (!cdata) + return FALSE; + + mod_model = gda_meta_store_create_modify_data_model (store, context->table_name); + g_assert (mod_model); + + retval = fill_constraints_tab_model (cnc, cdata, mod_model, table_schema, table_name, constraint_name_n, error); + if (retval) { + gda_meta_store_set_reserved_keywords_func (store, _gda_sqlite_get_reserved_keyword_func()); + retval = gda_meta_store_modify_with_context (store, context, mod_model, error); + } + g_object_unref (mod_model); + + return retval; +} + +static gboolean +fill_constraints_ref_model (GdaConnection *cnc, G_GNUC_UNUSED SqliteConnectionData *cdata, + GdaDataModel *mod_model, const GValue *p_table_schema, const GValue *p_table_name, + const GValue *constraint_name_n, gint fk_enforced, GError **error) +{ + GdaDataModel *tmpmodel; + gboolean retval = TRUE; + gint nrows; + const gchar *schema_name; + gint i; + GdaStatement *stmt; + + /* + * Setup stmt to execute + */ + schema_name = g_value_get_string (p_table_schema); + + GType fk_col_types[] = {G_TYPE_INT, G_TYPE_INT, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_NONE}; + gint fkid = -1; + stmt = get_statement (I_PRAGMA_FK_LIST, schema_name, g_value_get_string (p_table_name), error); + tmpmodel = gda_connection_statement_execute_select_full (cnc, stmt, pragma_set, + GDA_STATEMENT_MODEL_RANDOM_ACCESS, + fk_col_types, error); + g_object_unref (stmt); + if (!tmpmodel) + return FALSE; + + nrows = gda_data_model_get_n_rows (tmpmodel); + for (i = 0; i < nrows; i++) { + const GValue *cvalue; + + cvalue = gda_data_model_get_value_at (tmpmodel, 0, i, error); + if (!cvalue) { + retval = FALSE; + break; + } + if ((fkid == -1) || (fkid != g_value_get_int (cvalue))) { + gchar *constname; + //GValue *v2; + GValue *v3, *v4, *v5 = NULL; + const GValue *cv6, *cv7; + + fkid = g_value_get_int (cvalue); + + cvalue = gda_data_model_get_value_at (tmpmodel, 2, i, error); + cv6 = gda_data_model_get_value_at (tmpmodel, 5, i, error); + cv7 = gda_data_model_get_value_at (tmpmodel, 6, i, error); + if (!cvalue || !cv6 || !cv7) { + retval = FALSE; + break; + } + + constname = g_strdup_printf ("fk%d_%s", fkid, g_value_get_string (cvalue)); + if (constraint_name_n && strcmp (g_value_get_string (constraint_name_n), constname)) { + g_free (constname); + continue; + } + + //g_value_set_string ((v2 = gda_value_new (G_TYPE_STRING)), "FOREIGN KEY"); + g_value_set_string ((v3 = gda_value_new (G_TYPE_STRING)), g_value_get_string (cvalue)); + g_value_set_string ((v4 = gda_value_new (G_TYPE_STRING)), "primary_key"); + if (!constraint_name_n) + g_value_take_string ((v5 = gda_value_new (G_TYPE_STRING)), constname); + + if ((fk_enforced && + ! append_a_row (mod_model, error, 11, + FALSE, catalog_value, /* table_catalog */ + TRUE, new_caseless_value (p_table_schema), /* table_schema */ + TRUE, new_caseless_value (p_table_name), /* table_name */ + constraint_name_n ? FALSE: TRUE, + constraint_name_n ? constraint_name_n : v5, /* constraint_name */ + FALSE, catalog_value, /* ref_table_catalog */ + TRUE, new_caseless_value (p_table_schema), /* ref_table_schema */ + TRUE, v3, /* ref_table_name */ + TRUE, v4, /* ref_constraint_name */ + FALSE, NULL, /* match_option */ + FALSE, cv6, /* update_rule */ + FALSE, cv7 /* delete_rule */)) || + (! fk_enforced && + ! append_a_row (mod_model, error, 11, + FALSE, catalog_value, /* table_catalog */ + TRUE, new_caseless_value (p_table_schema), /* table_schema */ + TRUE, new_caseless_value (p_table_name), /* table_name */ + constraint_name_n ? FALSE: TRUE, + constraint_name_n ? constraint_name_n : v5, /* constraint_name */ + FALSE, catalog_value, /* ref_table_catalog */ + TRUE, new_caseless_value (p_table_schema), /* ref_table_schema */ + TRUE, v3, /* ref_table_name */ + TRUE, v4, /* ref_constraint_name */ + FALSE, NULL, /* match_option */ + FALSE, rule_value_none, /* update_rule */ + FALSE, rule_value_none /* delete_rule */))) + retval = FALSE; + if (constraint_name_n) + g_free (constname); + } + } + g_object_unref (tmpmodel); + + return retval; +} + +gboolean +_gda_sqlite_meta__constraints_ref (G_GNUC_UNUSED GdaServerProvider *prov, GdaConnection *cnc, + GdaMetaStore *store, GdaMetaContext *context, GError **error) +{ + GdaDataModel *mod_model, *tmpmodel; + gboolean retval = TRUE; + gint i, nrows; + SqliteConnectionData *cdata; + gint fk_enforced = -1; + + cdata = (SqliteConnectionData*) gda_connection_internal_get_provider_data_error (cnc, error); + if (!cdata) + return FALSE; + + tmpmodel = (GdaDataModel *) gda_connection_statement_execute (cnc, internal_stmt[I_PRAGMA_DATABASE_LIST], + NULL, GDA_STATEMENT_MODEL_RANDOM_ACCESS, NULL, error); + if (!tmpmodel) + return FALSE; + + mod_model = gda_meta_store_create_modify_data_model (store, context->table_name); + g_assert (mod_model); + + nrows = gda_data_model_get_n_rows (tmpmodel); + for (i = 0; i < nrows; i++) { + /* iterate through the schemas */ + GdaDataModel *tables_model; + const gchar *schema_name; + const GValue *cvalue = gda_data_model_get_value_at (tmpmodel, 1, i, error); + if (!cvalue) { + retval = FALSE; + break; + } + schema_name = g_value_get_string (cvalue); + if (!strcmp (schema_name, TMP_DATABASE_NAME)) + continue; /* nothing to do */ + + gchar *str; + GType col_types[] = {G_TYPE_STRING, G_TYPE_STRING, G_TYPE_NONE}; + GdaStatement *stmt; + + str = g_strdup_printf (SELECT_TABLES_VIEWS, schema_name); + stmt = gda_sql_parser_parse_string (internal_parser, str, NULL, NULL); + g_free (str); + g_assert (stmt); + tables_model = gda_connection_statement_execute_select_full (cnc, stmt, NULL, + GDA_STATEMENT_MODEL_RANDOM_ACCESS, + col_types, error); + g_object_unref (stmt); + if (!tables_model) { + retval = FALSE; + break; + } + + gint tnrows, ti; + tnrows = gda_data_model_get_n_rows (tables_model); + for (ti = 0; ti < tnrows; ti++) { + + /* iterate through the tables */ + const GValue *cv = gda_data_model_get_value_at (tables_model, 0, ti, error); + if (!cv) { + retval = FALSE; + break; + } + + if (fk_enforced < 0) { + GdaDataModel *pmodel; + fk_enforced = 0; + pmodel = (GdaDataModel *) gda_connection_statement_execute (cnc, + internal_stmt[I_PRAGMA_FK_ENFORCED], + NULL, GDA_STATEMENT_MODEL_RANDOM_ACCESS, + NULL, NULL); + if (pmodel) { + const GValue *pv; + pv = gda_data_model_get_value_at (pmodel, 0, 0, NULL); + if (pv && (G_VALUE_TYPE (pv) == G_TYPE_INT)) + fk_enforced = g_value_get_int (pv) ? 1 : 0; + g_object_unref (pmodel); + } + } + if (!fill_constraints_ref_model (cnc, cdata, mod_model, cvalue, cv, NULL, + fk_enforced, error)) { + retval = FALSE; + break; + } + } + g_object_unref (tables_model); + if (!retval) + break; + } + g_object_unref (tmpmodel); + + if (retval) { + gda_meta_store_set_reserved_keywords_func (store, _gda_sqlite_get_reserved_keyword_func()); + retval = gda_meta_store_modify_with_context (store, context, mod_model, error); + } + g_object_unref (mod_model); + + return retval; +} + +gboolean +_gda_sqlite_meta_constraints_ref (G_GNUC_UNUSED GdaServerProvider *prov, GdaConnection *cnc, + GdaMetaStore *store, GdaMetaContext *context, GError **error, + G_GNUC_UNUSED const GValue *table_catalog, const GValue *table_schema, const GValue *table_name, + const GValue *constraint_name) +{ + gboolean retval = TRUE; + GdaDataModel *mod_model = NULL; + SqliteConnectionData *cdata; + + cdata = (SqliteConnectionData*) gda_connection_internal_get_provider_data_error (cnc, error); + if (!cdata) + return FALSE; + + mod_model = gda_meta_store_create_modify_data_model (store, context->table_name); + g_assert (mod_model); + + GdaDataModel *pmodel; + gint fk_enforced = 0; + pmodel = (GdaDataModel *) gda_connection_statement_execute (cnc, + internal_stmt[I_PRAGMA_FK_ENFORCED], + NULL, GDA_STATEMENT_MODEL_RANDOM_ACCESS, + NULL, NULL); + if (pmodel) { + const GValue *pv; + pv = gda_data_model_get_value_at (pmodel, 0, 0, NULL); + if (pv && (G_VALUE_TYPE (pv) == G_TYPE_INT)) + fk_enforced = g_value_get_int (pv) ? 1 : 0; + g_object_unref (pmodel); + } + + retval = fill_constraints_ref_model (cnc, cdata, mod_model, table_schema, table_name, constraint_name, + fk_enforced, error); + if (retval) { + gda_meta_store_set_reserved_keywords_func (store, _gda_sqlite_get_reserved_keyword_func()); + retval = gda_meta_store_modify_with_context (store, context, mod_model, error); + } + g_object_unref (mod_model); + + return retval; +} + +static gboolean +fill_key_columns_model (GdaConnection *cnc, SqliteConnectionData *cdata, GdaDataModel *mod_model, + const GValue *p_table_schema, const GValue *p_table_name, const GValue *constraint_name, + GError **error) +{ + GdaDataModel *tmpmodel; + gboolean retval = TRUE; + gint nrows; + const gchar *schema_name, *const_name; + gint i; + GdaStatement *stmt; + GdaSqliteProvider *prov = GDA_SQLITE_PROVIDER (gda_connection_get_provider (cnc)); + + schema_name = g_value_get_string (p_table_schema); + const_name = g_value_get_string (constraint_name); + if (!strcmp (const_name, "primary_key")) { + /* + * PRIMARY KEY columns + */ + GType pk_col_types[] = {G_TYPE_INT, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INT, + G_TYPE_STRING, G_TYPE_BOOLEAN, G_TYPE_NONE}; + gint ord_pos = 1; + GError *lerror = NULL; + stmt = get_statement (I_PRAGMA_TABLE_INFO, schema_name, g_value_get_string (p_table_name), NULL); + tmpmodel = gda_connection_statement_execute_select_full (cnc, stmt, pragma_set, + GDA_STATEMENT_MODEL_RANDOM_ACCESS, + pk_col_types, &lerror); + g_object_unref (stmt); + if (!tmpmodel) { + if (lerror && lerror->message && !strstr (lerror->message, "no such function")) { + g_propagate_error (error, lerror); + return FALSE; + } + else + return TRUE; + } + + nrows = gda_data_model_get_n_rows (tmpmodel); + for (i = 0; i < nrows; i++) { + char const *pzDataType; /* Declared data type */ + char const *pzCollSeq; /* Collation sequence name */ + int pNotNull; /* True if NOT NULL constraint exists */ + int pPrimaryKey; /* True if column part of PK */ + int pAutoinc; /* True if column is auto-increment */ + const gchar *this_table_name; + const gchar *this_col_name; + const GValue *this_col_pname, *cvalue; + GValue *v1; + + this_col_pname = gda_data_model_get_value_at (tmpmodel, 1, i, error); + if (!this_col_pname) { + retval = FALSE; + break; + } + this_table_name = g_value_get_string (p_table_name); + g_assert (this_table_name); + if (!strcmp (this_table_name, "sqlite_sequence")) + continue; /* ignore that table */ + + this_col_name = g_value_get_string (this_col_pname); + if (SQLITE3_CALL (prov, sqlite3_table_column_metadata) (cdata->connection, g_value_get_string (p_table_schema), + this_table_name, this_col_name, + &pzDataType, &pzCollSeq, + &pNotNull, &pPrimaryKey, &pAutoinc) + != SQLITE_OK) { + /* may fail because we have a view and not a table => use @tmpmodel to fetch info. */ + cvalue = gda_data_model_get_value_at (tmpmodel, 5, i, error); + if (!cvalue) { + retval = FALSE; + break; + } + pPrimaryKey = g_value_get_boolean (cvalue); + } + if (pPrimaryKey) { + cvalue = gda_data_model_get_value_at (tmpmodel, 1, i, error); + if (!cvalue) { + retval = FALSE; + break; + } + g_value_set_int ((v1 = gda_value_new (G_TYPE_INT)), ord_pos++); + if (! append_a_row (mod_model, error, 6, + FALSE, catalog_value, /* table_catalog */ + TRUE, new_caseless_value (p_table_schema), /* table_schema */ + TRUE, new_caseless_value (p_table_name), /* table_name */ + TRUE, new_caseless_value (constraint_name), /* constraint_name */ + TRUE, new_caseless_value (cvalue), /* column_name */ + TRUE, v1 /* ordinal_position */)) { + retval = FALSE; + break; + } + } + } + g_object_unref (tmpmodel); + } + else if ((*const_name == 'f') && (const_name[1] == 'k')) { + /* + * FOREIGN key columns + */ + GType fk_col_types[] = {G_TYPE_INT, G_TYPE_INT, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_NONE}; + gint fkid = -1; + gint ord_pos = 1; + stmt = get_statement (I_PRAGMA_FK_LIST, schema_name, g_value_get_string (p_table_name), error); + tmpmodel = gda_connection_statement_execute_select_full (cnc, stmt, pragma_set, + GDA_STATEMENT_MODEL_RANDOM_ACCESS, + fk_col_types, error); + g_object_unref (stmt); + if (!tmpmodel) + return FALSE; + + nrows = gda_data_model_get_n_rows (tmpmodel); + for (i = 0; i < nrows; i++) { + const GValue *cvalue; + GValue *v1; + + cvalue = gda_data_model_get_value_at (tmpmodel, 0, i, error); + if (!cvalue) { + retval = FALSE; + break; + } + if ((fkid == -1) || (fkid != g_value_get_int (cvalue))) { + gchar *constname; + + fkid = g_value_get_int (cvalue); + + cvalue = gda_data_model_get_value_at (tmpmodel, 2, i, error); + if (!cvalue) { + retval = FALSE; + break; + } + constname = g_strdup_printf ("fk%d_%s", fkid, g_value_get_string (cvalue)); + if (strcmp (const_name, constname)) { + fkid = -1; + g_free (constname); + continue; + } + ord_pos = 1; + } + + g_value_set_int ((v1 = gda_value_new (G_TYPE_INT)), ord_pos++); + cvalue = gda_data_model_get_value_at (tmpmodel, 3, i, error); + if (!cvalue) { + retval = FALSE; + break; + } + if (! append_a_row (mod_model, error, 6, + FALSE, catalog_value, /* table_catalog */ + TRUE, new_caseless_value (p_table_schema), /* table_schema */ + TRUE, new_caseless_value (p_table_name), /* table_name */ + TRUE, new_caseless_value (constraint_name), /* constraint_name */ + TRUE, new_caseless_value (cvalue), /* column_name */ + TRUE, v1 /* ordinal_position */)) + retval = FALSE; + } + g_object_unref (tmpmodel); + } + else { + /* + * UNIQUE columns + */ + GType unique_col_types[] = {G_TYPE_INT, G_TYPE_INT, G_TYPE_STRING, G_TYPE_NONE}; + + stmt = get_statement (I_PRAGMA_INDEX_INFO, schema_name, g_value_get_string (constraint_name), + error); + tmpmodel = gda_connection_statement_execute_select_full (cnc, stmt, pragma_set, + GDA_STATEMENT_MODEL_RANDOM_ACCESS, + unique_col_types, error); + g_object_unref (stmt); + if (!tmpmodel) + return FALSE; + + nrows = gda_data_model_get_n_rows (tmpmodel); + for (i = 0; i < nrows; i++) { + GValue *v1; + const GValue *cvalue; + cvalue = gda_data_model_get_value_at (tmpmodel, 1, i, error); + if (!cvalue) { + retval = FALSE; + break; + } + g_value_set_int ((v1 = gda_value_new (G_TYPE_INT)), g_value_get_int (cvalue) + 1); + cvalue = gda_data_model_get_value_at (tmpmodel, 2, i, error); + if (!cvalue) { + retval = FALSE; + break; + } + if (! append_a_row (mod_model, error, 6, + FALSE, catalog_value, /* table_catalog */ + TRUE, new_caseless_value (p_table_schema), /* table_schema */ + TRUE, new_caseless_value (p_table_name), /* table_name */ + TRUE, new_caseless_value (constraint_name), /* constraint_name */ + TRUE, new_caseless_value (cvalue), /* column_name */ + TRUE, v1 /* ordinal_position */)) + retval = FALSE; + } + g_object_unref (tmpmodel); + } + + return retval; +} + +gboolean +_gda_sqlite_meta__key_columns (G_GNUC_UNUSED GdaServerProvider *prov, GdaConnection *cnc, + GdaMetaStore *store, GdaMetaContext *context, GError **error) +{ + /* iterate through the tables, and each time call fill_constraints_tab_model() + * to get the list of table constraints. + * Then iterate through that data model and call fill_key_columns_model() + * for each row */ + + GdaDataModel *const_model, *tmpmodel; + gboolean retval = TRUE; + gint i, nrows; + SqliteConnectionData *cdata; + + cdata = (SqliteConnectionData*) gda_connection_internal_get_provider_data_error (cnc, error); + if (!cdata) + return FALSE; + + tmpmodel = (GdaDataModel *) gda_connection_statement_execute (cnc, internal_stmt[I_PRAGMA_DATABASE_LIST], + NULL, GDA_STATEMENT_MODEL_RANDOM_ACCESS, NULL, error); + if (!tmpmodel) + return FALSE; + + const_model = gda_meta_store_create_modify_data_model (store, "_table_constraints"); + g_assert (const_model); + + nrows = gda_data_model_get_n_rows (tmpmodel); + for (i = 0; i < nrows; i++) { + /* iterate through the schemas */ + GdaDataModel *tables_model; + const gchar *schema_name; + const GValue *cvalue = gda_data_model_get_value_at (tmpmodel, 1, i, error); + + if (!cvalue) { + retval = FALSE; + break; + } + schema_name = g_value_get_string (cvalue); + if (!strcmp (schema_name, TMP_DATABASE_NAME)) + continue; /* nothing to do */ + + gchar *str; + GType col_types[] = {G_TYPE_STRING, G_TYPE_STRING, G_TYPE_NONE}; + GdaStatement *stmt; + + str = g_strdup_printf (SELECT_TABLES_VIEWS, schema_name); + stmt = gda_sql_parser_parse_string (internal_parser, str, NULL, NULL); + g_free (str); + g_assert (stmt); + tables_model = gda_connection_statement_execute_select_full (cnc, stmt, NULL, + GDA_STATEMENT_MODEL_RANDOM_ACCESS, + col_types, error); + g_object_unref (stmt); + if (!tables_model) { + retval = FALSE; + break; + } + + gint tnrows, ti; + tnrows = gda_data_model_get_n_rows (tables_model); + for (ti = 0; ti < tnrows; ti++) { + /* iterate through the tables */ + const GValue *cv = gda_data_model_get_value_at (tables_model, 0, ti, error); + if (!cv) { + retval = FALSE; + break; + } + if (!fill_constraints_tab_model (cnc, cdata, const_model, cvalue, cv, NULL, error)) { + retval = FALSE; + break; + } + } + g_object_unref (tables_model); + if (!retval) + break; + } + g_object_unref (tmpmodel); + if (!retval) { + g_object_unref (const_model); + return FALSE; + } + + GdaDataModel *mod_model; + mod_model = gda_meta_store_create_modify_data_model (store, context->table_name); + g_assert (mod_model); + + nrows = gda_data_model_get_n_rows (const_model); + for (i = 0; i < nrows; i++) { + const GValue *v2, *v4, *v5; + v2 = gda_data_model_get_value_at (const_model, 2, i, error); + if (!v2) { + retval = FALSE; + break; + } + v4 = gda_data_model_get_value_at (const_model, 4, i, error); + if (!v4) { + retval = FALSE; + break; + } + v5 = gda_data_model_get_value_at (const_model, 5, i, error); + if (!v5) { + retval = FALSE; + break; + } + if (!fill_key_columns_model (cnc, cdata, mod_model, v4, v5, v2, error)) { + retval = FALSE; + break; + } + } + g_object_unref (const_model); + + if (retval) { + gda_meta_store_set_reserved_keywords_func (store, _gda_sqlite_get_reserved_keyword_func()); + retval = gda_meta_store_modify_with_context (store, context, mod_model, error); + } + g_object_unref (mod_model); + + return retval; +} + +gboolean +_gda_sqlite_meta_key_columns (G_GNUC_UNUSED GdaServerProvider *prov, GdaConnection *cnc, + GdaMetaStore *store, GdaMetaContext *context, GError **error, + G_GNUC_UNUSED const GValue *table_catalog, const GValue *table_schema, const GValue *table_name, + const GValue *constraint_name) +{ + gboolean retval = TRUE; + GdaDataModel *mod_model = NULL; + SqliteConnectionData *cdata; + + cdata = (SqliteConnectionData*) gda_connection_internal_get_provider_data_error (cnc, error); + if (!cdata) + return FALSE; + + mod_model = gda_meta_store_create_modify_data_model (store, context->table_name); + g_assert (mod_model); + + retval = fill_key_columns_model (cnc, cdata, mod_model, table_schema, table_name, constraint_name, error); + if (retval) { + gda_meta_store_set_reserved_keywords_func (store, _gda_sqlite_get_reserved_keyword_func()); + retval = gda_meta_store_modify_with_context (store, context, mod_model, error); + } + g_object_unref (mod_model); + + return retval; +} + +gboolean +_gda_sqlite_meta__check_columns (G_GNUC_UNUSED GdaServerProvider *prov, G_GNUC_UNUSED GdaConnection *cnc, + G_GNUC_UNUSED GdaMetaStore *store, G_GNUC_UNUSED GdaMetaContext *context, G_GNUC_UNUSED GError **error) +{ + /* FIXME: How to get this ? */ + return TRUE; +} + +gboolean +_gda_sqlite_meta_check_columns (G_GNUC_UNUSED GdaServerProvider *prov, G_GNUC_UNUSED GdaConnection *cnc, + G_GNUC_UNUSED GdaMetaStore *store, G_GNUC_UNUSED GdaMetaContext *context, + G_GNUC_UNUSED GError **error, G_GNUC_UNUSED const GValue *table_catalog, + G_GNUC_UNUSED const GValue *table_schema, + G_GNUC_UNUSED const GValue *table_name, + G_GNUC_UNUSED const GValue *constraint_name) +{ + /* FIXME: How to get this ? */ + return TRUE; +} + +gboolean +_gda_sqlite_meta__triggers (G_GNUC_UNUSED GdaServerProvider *prov, G_GNUC_UNUSED GdaConnection *cnc, + G_GNUC_UNUSED GdaMetaStore *store, G_GNUC_UNUSED GdaMetaContext *context, + G_GNUC_UNUSED GError **error) +{ + /* FIXME: How to get this ? */ + return TRUE; +} + +gboolean +_gda_sqlite_meta_triggers (G_GNUC_UNUSED GdaServerProvider *prov, G_GNUC_UNUSED GdaConnection *cnc, + G_GNUC_UNUSED GdaMetaStore *store, G_GNUC_UNUSED GdaMetaContext *context, + G_GNUC_UNUSED GError **error, G_GNUC_UNUSED const GValue *table_catalog, + G_GNUC_UNUSED const GValue *table_schema, G_GNUC_UNUSED const GValue *table_name) +{ + /* FIXME: How to get this ? */ + return TRUE; +} + + +gboolean +_gda_sqlite_meta__routines (GdaServerProvider *prov, GdaConnection *cnc, + GdaMetaStore *store, GdaMetaContext *context, GError **error) +{ + return _gda_sqlite_meta_routines (prov, cnc, store, context, error, NULL, NULL, NULL); +} + +#ifndef HAVE_SQLITE +static gboolean +fill_routines (GdaDataModel *mod_model, + const GValue *rname, const GValue *is_agg, const GValue *rnargs, const GValue *sname, + GError **error) +{ + GValue *v0; + gboolean retval = TRUE; + + if (g_value_get_int (is_agg) == 0) + g_value_set_string ((v0 = gda_value_new (G_TYPE_STRING)), "FUNCTION"); + else + g_value_set_string ((v0 = gda_value_new (G_TYPE_STRING)), "AGGREGATE"); + if (!append_a_row (mod_model, error, 22, + FALSE, catalog_value, /* specific_catalog */ + FALSE, catalog_value, /* specific_schema */ + FALSE, sname, /* specific_name */ + FALSE, NULL, /* routine_catalog */ + FALSE, NULL, /* routine_schema */ + TRUE, new_caseless_value (rname), /* routine_name */ + TRUE, v0, /* routine_type */ + FALSE, NULL, /* return_type */ + FALSE, false_value, /* returns_set */ + FALSE, rnargs, /* nb_args */ + FALSE, NULL, /* routine_body */ + FALSE, NULL, /* routine_definition */ + FALSE, NULL, /* external_name */ + FALSE, NULL, /* external_language */ + FALSE, NULL, /* parameter_style */ + FALSE, NULL, /* is_deterministic */ + FALSE, NULL, /* sql_data_access */ + FALSE, NULL, /* is_null_call */ + FALSE, NULL, /* routine_comments */ + TRUE, new_caseless_value (rname), /* routine_short_name */ + TRUE, new_caseless_value (rname), /* routine_full_name */ + FALSE, NULL /* routine_owner */)) { + retval = FALSE; + } + + return retval; +} +#endif + +gboolean +_gda_sqlite_meta_routines (G_GNUC_UNUSED GdaServerProvider *prov, G_GNUC_UNUSED GdaConnection *cnc, + G_GNUC_UNUSED GdaMetaStore *store, G_GNUC_UNUSED GdaMetaContext *context, G_GNUC_UNUSED GError **error, + G_GNUC_UNUSED const GValue *routine_catalog, + G_GNUC_UNUSED const GValue *routine_schema, G_GNUC_UNUSED const GValue *routine_name_n) +{ + gboolean retval = TRUE; + +#ifndef HAVE_SQLITE + /* get list of procedures */ + SqliteConnectionData *cdata; + GdaDataModel *tmpmodel, *mod_model; + gint i, nrows; + + cdata = (SqliteConnectionData*) gda_connection_internal_get_provider_data_error (cnc, error); + if (!cdata) + return FALSE; + + tmpmodel = (GdaDataModel *) gda_connection_statement_execute (cnc, internal_stmt[I_PRAGMA_PROCLIST], + NULL, GDA_STATEMENT_MODEL_RANDOM_ACCESS, + NULL, error); + if (!tmpmodel) + return FALSE; + + mod_model = gda_meta_store_create_modify_data_model (store, context->table_name); + g_assert (mod_model); + + nrows = gda_data_model_get_n_rows (tmpmodel); + for (i = 0; i < nrows; i++) { + const GValue *cv0, *cv1, *cv2, *cv3; + cv0 = gda_data_model_get_value_at (tmpmodel, 0, i, error); + if (!cv0) { + retval = FALSE; + break; + } + cv1 = gda_data_model_get_value_at (tmpmodel, 1, i, error); + if (!cv1) { + retval = FALSE; + break; + } + cv2 = gda_data_model_get_value_at (tmpmodel, 2, i, error); + if (!cv2) { + retval = FALSE; + break; + } + cv3 = gda_data_model_get_value_at (tmpmodel, 3, i, error); + if (!cv3) { + retval = FALSE; + break; + } + if ((!routine_name_n || (routine_name_n && !gda_value_compare (routine_name_n, cv0))) + && ! fill_routines (mod_model, cv0, cv1, cv2, cv3, error)) { + retval = FALSE; + break; + } + } + + if (retval) { + gda_meta_store_set_reserved_keywords_func (store, _gda_sqlite_get_reserved_keyword_func()); + retval = gda_meta_store_modify_with_context (store, context, mod_model, error); + } + g_object_unref (mod_model); + g_object_unref (tmpmodel); +#endif + + return retval; +} + +gboolean +_gda_sqlite_meta__routine_col (G_GNUC_UNUSED GdaServerProvider *prov, G_GNUC_UNUSED GdaConnection *cnc, + G_GNUC_UNUSED GdaMetaStore *store, G_GNUC_UNUSED GdaMetaContext *context, + G_GNUC_UNUSED GError **error) +{ + /* feature not available in SQLite */ + return TRUE; +} + +gboolean +_gda_sqlite_meta_routine_col (G_GNUC_UNUSED GdaServerProvider *prov, G_GNUC_UNUSED GdaConnection *cnc, + G_GNUC_UNUSED GdaMetaStore *store, G_GNUC_UNUSED GdaMetaContext *context, + G_GNUC_UNUSED GError **error, G_GNUC_UNUSED const GValue *rout_catalog, + G_GNUC_UNUSED const GValue *rout_schema, G_GNUC_UNUSED const GValue *rout_name, + G_GNUC_UNUSED const GValue *col_name, G_GNUC_UNUSED const GValue *ordinal_position) +{ + /* feature not available in SQLite */ + return TRUE; +} + +gboolean +_gda_sqlite_meta__routine_par (G_GNUC_UNUSED GdaServerProvider *prov, G_GNUC_UNUSED GdaConnection *cnc, + G_GNUC_UNUSED GdaMetaStore *store, G_GNUC_UNUSED GdaMetaContext *context, + G_GNUC_UNUSED GError **error) +{ + /* Routines in SQLite accept any type of value => nothing to do */ + return TRUE; +} + +gboolean +_gda_sqlite_meta_routine_par (G_GNUC_UNUSED GdaServerProvider *prov, G_GNUC_UNUSED GdaConnection *cnc, + G_GNUC_UNUSED GdaMetaStore *store, G_GNUC_UNUSED GdaMetaContext *context, + G_GNUC_UNUSED GError **error, G_GNUC_UNUSED const GValue *rout_catalog, + G_GNUC_UNUSED const GValue *rout_schema, G_GNUC_UNUSED const GValue *rout_name) +{ + /* Routines in SQLite accept any type of value => nothing to do */ + return TRUE; +} + +gboolean +_gda_sqlite_meta__indexes_tab (G_GNUC_UNUSED GdaServerProvider *prov, G_GNUC_UNUSED GdaConnection *cnc, + G_GNUC_UNUSED GdaMetaStore *store, G_GNUC_UNUSED GdaMetaContext *context, + G_GNUC_UNUSED GError **error) +{ + //TO_IMPLEMENT; + return TRUE; +} + +gboolean +_gda_sqlite_meta_indexes_tab (G_GNUC_UNUSED GdaServerProvider *prov, G_GNUC_UNUSED GdaConnection *cnc, + G_GNUC_UNUSED GdaMetaStore *store, G_GNUC_UNUSED GdaMetaContext *context, + G_GNUC_UNUSED GError **error, G_GNUC_UNUSED const GValue *table_catalog, + G_GNUC_UNUSED const GValue *table_schema, + G_GNUC_UNUSED const GValue *table_name, + G_GNUC_UNUSED const GValue *index_name_n) +{ + //TO_IMPLEMENT; + return TRUE; +} + +gboolean +_gda_sqlite_meta__index_cols (G_GNUC_UNUSED GdaServerProvider *prov, G_GNUC_UNUSED GdaConnection *cnc, + G_GNUC_UNUSED GdaMetaStore *store, G_GNUC_UNUSED GdaMetaContext *context, + G_GNUC_UNUSED GError **error) +{ + //TO_IMPLEMENT; + return TRUE; +} + +gboolean +_gda_sqlite_meta_index_cols (G_GNUC_UNUSED GdaServerProvider *prov, G_GNUC_UNUSED GdaConnection *cnc, + G_GNUC_UNUSED GdaMetaStore *store, G_GNUC_UNUSED GdaMetaContext *context, + G_GNUC_UNUSED GError **error, G_GNUC_UNUSED const GValue *table_catalog, + G_GNUC_UNUSED const GValue *table_schema, G_GNUC_UNUSED const GValue *table_name, + G_GNUC_UNUSED const GValue *index_name) +{ + //TO_IMPLEMENT; + return TRUE; +} + +/* + * @...: a list of TRUE/FALSE, GValue* -- if TRUE then the following GValue will be freed by + * this function + */ +static gboolean +append_a_row (GdaDataModel *to_model, GError **error, gint nb, ...) +{ + va_list ap; + GList *values = NULL; + gint i; + GValue **free_array; + gboolean retval = TRUE; + + /* compute list of values */ + free_array = g_new0 (GValue *, nb); + va_start (ap, nb); + for (i = 0; i < nb; i++) { + gboolean to_free; + GValue *value; + to_free = va_arg (ap, gboolean); + value = va_arg (ap, GValue *); + if (to_free) + free_array[i] = value; + values = g_list_prepend (values, value); + } + va_end (ap); + values = g_list_reverse (values); + + /* add to model */ + if (gda_data_model_append_values (to_model, values, error) < 0) + retval = FALSE; + + /* memory free */ + g_list_free (values); + for (i = 0; i < nb; i++) { + if (free_array[i]) + gda_value_free (free_array[i]); + } + g_free (free_array); + return retval; +} diff --git a/.flatpak-builder/cache/objects/4c/a2bb8ce20031787b4ebb0919af8a0e655a38c1f441065c7be1d28940b2b042.file b/.flatpak-builder/cache/objects/4c/a2bb8ce20031787b4ebb0919af8a0e655a38c1f441065c7be1d28940b2b042.file new file mode 100644 index 0000000..15b1f3b --- /dev/null +++ b/.flatpak-builder/cache/objects/4c/a2bb8ce20031787b4ebb0919af8a0e655a38c1f441065c7be1d28940b2b042.file @@ -0,0 +1,248 @@ +/* + * Copyright (C) 2007 - 2014 Vivien Malerba + * Copyright (C) 2010 David King + * Copyright (C) 2018 Daniel Espinosa + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +#define G_LOG_DOMAIN "GDA-dir-blob-op" + +#include +#define __GDA_INTERNAL__ +#include "dir-blob-op.h" +#include +#include +#include +#include +#include +#include + +/* module error */ +GQuark gda_dir_blob_op_error_quark (void) +{ + static GQuark quark; + if (!quark) + quark = g_quark_from_static_string ("gda_dir_blob_op_error"); + return quark; +} + + +typedef struct { + gchar *complete_filename; +} GdaDirBlobOpPrivate; + +G_DEFINE_TYPE_WITH_PRIVATE (GdaDirBlobOp, gda_dir_blob_op, GDA_TYPE_BLOB_OP) + +static void gda_dir_blob_op_dispose (GObject *object); + +static glong gda_dir_blob_op_get_length (GdaBlobOp *op); +static glong gda_dir_blob_op_read (GdaBlobOp *op, GdaBlob *blob, glong offset, glong size); +static glong gda_dir_blob_op_write (GdaBlobOp *op, GdaBlob *blob, glong offset); + +static void +gda_dir_blob_op_init (GdaDirBlobOp *op) +{ + g_return_if_fail (GDA_IS_DIR_BLOB_OP (op)); + GdaDirBlobOpPrivate *priv = gda_dir_blob_op_get_instance_private (op); + + priv->complete_filename = NULL; +} + +static void +gda_dir_blob_op_class_init (GdaDirBlobOpClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GdaBlobOpClass *blob_class = GDA_BLOB_OP_CLASS (klass); + object_class->dispose = gda_dir_blob_op_dispose; + + GDA_BLOB_OP_FUNCTIONS (blob_class->functions)->get_length = gda_dir_blob_op_get_length; + GDA_BLOB_OP_FUNCTIONS (blob_class->functions)->read = gda_dir_blob_op_read; + GDA_BLOB_OP_FUNCTIONS (blob_class->functions)->write = gda_dir_blob_op_write; +} +static void +gda_dir_blob_op_dispose (GObject *object) +{ + GdaDirBlobOp *op = GDA_DIR_BLOB_OP (object); + GdaDirBlobOpPrivate *priv = gda_dir_blob_op_get_instance_private (op); + if (priv->complete_filename) { + g_free (priv->complete_filename); + priv->complete_filename = NULL; + } +} +/** + * _gda_dir_blob_op_new + */ +GdaBlobOp * +_gda_dir_blob_op_new (const gchar *complete_filename) +{ + GdaDirBlobOp *pgop; + + g_return_val_if_fail (complete_filename, NULL); + + pgop = g_object_new (GDA_TYPE_DIR_BLOB_OP, NULL); + GdaDirBlobOpPrivate *priv = gda_dir_blob_op_get_instance_private (pgop); + priv->complete_filename = g_strdup (complete_filename); + + return GDA_BLOB_OP (pgop); +} + +/** + * _gda_dir_blob_set_filename + */ +void +_gda_dir_blob_set_filename (GdaDirBlobOp *blob, const gchar *complete_filename) +{ + g_return_if_fail (GDA_IS_DIR_BLOB_OP (blob)); + g_return_if_fail (complete_filename); + GdaDirBlobOpPrivate *priv = gda_dir_blob_op_get_instance_private (blob); + + g_free (priv->complete_filename); + priv->complete_filename = g_strdup (complete_filename); +} + +/** + * _gda_dir_blob_get_filename + */ +const gchar * +_gda_dir_blob_get_filename (GdaDirBlobOp *blob) +{ + g_return_val_if_fail (GDA_IS_DIR_BLOB_OP (blob), NULL); + GdaDirBlobOpPrivate *priv = gda_dir_blob_op_get_instance_private (blob); + + return priv->complete_filename; +} + +/* + * Virtual functions + */ +static glong +gda_dir_blob_op_get_length (GdaBlobOp *op) +{ + GdaDirBlobOp *dirop; + struct stat filestat; + + g_return_val_if_fail (GDA_IS_DIR_BLOB_OP (op), -1); + dirop = GDA_DIR_BLOB_OP (op); + GdaDirBlobOpPrivate *priv = gda_dir_blob_op_get_instance_private (dirop); + + if (! g_stat (priv->complete_filename, &filestat)) + return filestat.st_size; + return -1; +} + +static glong +gda_dir_blob_op_read (GdaBlobOp *op, GdaBlob *blob, glong offset, glong size) +{ + GdaDirBlobOp *dirop; + GdaBinary *bin; + FILE *file; + size_t nread; + guchar *buffer; + + g_return_val_if_fail (GDA_IS_DIR_BLOB_OP (op), -1); + dirop = GDA_DIR_BLOB_OP (op); + GdaDirBlobOpPrivate *priv = gda_dir_blob_op_get_instance_private (dirop); + if (offset >= G_MAXINT) + return -1; + g_return_val_if_fail (blob, -1); + + /* open file */ + file = fopen (priv->complete_filename, "rb"); /* Flawfinder: ignore */ + if (!file) + return -1; + + /* go to offset */ + if (fseek (file, offset, SEEK_SET) != 0) { + fclose (file); + return -1; + } + + bin = gda_blob_get_binary (blob); + gda_binary_reset_data (bin); + buffer = g_new0 (guchar, size); + nread = fread ((char *) (buffer), 1, size, file); + gda_binary_take_data (bin, buffer, nread); + fclose (file); + + return nread; +} + +static glong +gda_dir_blob_op_write (GdaBlobOp *op, GdaBlob *blob, glong offset) +{ + GdaDirBlobOp *dirop; + GdaBinary *bin; + FILE *file; + glong nbwritten; + + g_return_val_if_fail (GDA_IS_DIR_BLOB_OP (op), -1); + dirop = GDA_DIR_BLOB_OP (op); + GdaDirBlobOpPrivate *priv = gda_dir_blob_op_get_instance_private (dirop); + if (offset >= G_MAXINT) + return -1; + g_return_val_if_fail (blob, -1); + + /* open file */ + file = fopen (priv->complete_filename, "w+b"); /* Flawfinder: ignore */ + if (!file) + return -1; + + /* go to offset */ + if (offset > 0) { + if (fseek (file, offset, SEEK_SET) != 0) { + fclose (file); + return -1; + } + } + + if (gda_blob_get_op (blob) && (gda_blob_get_op (blob) != op)) { + /* use data through blob->op */ +#define buf_size 16384 + gint nread = 0; + GdaBlob *tmpblob = gda_blob_new (); + gda_blob_set_op (tmpblob, gda_blob_get_op (blob)); + + nbwritten = 0; + + for (nread = gda_blob_op_read (gda_blob_get_op (tmpblob), tmpblob, 0, buf_size); + nread > 0; + nread = gda_blob_op_read (gda_blob_get_op (tmpblob), tmpblob, nbwritten, buf_size)) { + GdaBinary *bin = gda_blob_get_binary (tmpblob); + glong tmp_written; + tmp_written = fwrite ((char *) gda_binary_get_data (bin), sizeof (guchar), gda_binary_get_size (bin), file); + if (tmp_written < gda_binary_get_size (bin)) { + /* error writing stream */ + fclose (file); + gda_blob_free (tmpblob); + return -1; + } + nbwritten += tmp_written; + if (nread < buf_size) + /* nothing more to read */ + break; + } + + fclose (file); + gda_blob_free (tmpblob); + } + else { + bin = (GdaBinary *) blob; + nbwritten = fwrite ((char *) (gda_binary_get_data (bin)), 1, gda_binary_get_size (bin), file); + fclose (file); + } + + return (nbwritten >= 0) ? nbwritten : -1; +} diff --git a/.flatpak-builder/cache/objects/4d/4eb1eb0514b4edd5c314d99af754658bdb22858d6c3b02518d89189911b158.file b/.flatpak-builder/cache/objects/4d/4eb1eb0514b4edd5c314d99af754658bdb22858d6c3b02518d89189911b158.file new file mode 100644 index 0000000..50a6560 Binary files /dev/null and b/.flatpak-builder/cache/objects/4d/4eb1eb0514b4edd5c314d99af754658bdb22858d6c3b02518d89189911b158.file differ diff --git a/.flatpak-builder/cache/objects/4d/92def83a84f78ed689cad3a022259e37e94e098b6ddfd8264b74bb651e7883.dirtree b/.flatpak-builder/cache/objects/4d/92def83a84f78ed689cad3a022259e37e94e098b6ddfd8264b74bb651e7883.dirtree new file mode 100644 index 0000000..0b4f774 Binary files /dev/null and b/.flatpak-builder/cache/objects/4d/92def83a84f78ed689cad3a022259e37e94e098b6ddfd8264b74bb651e7883.dirtree differ diff --git a/.flatpak-builder/cache/objects/4d/f321129b21ffe59e016e5f761771eab77fd3d1ed952f32be37faac93d83813.dirtree b/.flatpak-builder/cache/objects/4d/f321129b21ffe59e016e5f761771eab77fd3d1ed952f32be37faac93d83813.dirtree new file mode 100644 index 0000000..44cf8f7 Binary files /dev/null and b/.flatpak-builder/cache/objects/4d/f321129b21ffe59e016e5f761771eab77fd3d1ed952f32be37faac93d83813.dirtree differ diff --git a/.flatpak-builder/cache/objects/4e/2fd8a430b306e7276c6f041abfc30e19762164c15687b53e7466f11d24a1fa.file b/.flatpak-builder/cache/objects/4e/2fd8a430b306e7276c6f041abfc30e19762164c15687b53e7466f11d24a1fa.file new file mode 120000 index 0000000..b3a2eaa --- /dev/null +++ b/.flatpak-builder/cache/objects/4e/2fd8a430b306e7276c6f041abfc30e19762164c15687b53e7466f11d24a1fa.file @@ -0,0 +1 @@ +../../share/runtime/locale/oc/share/oc \ No newline at end of file diff --git a/.flatpak-builder/cache/objects/4e/8cc29c5b524fc000621f03f6f9c4a1c6db4ecf16b6af046326b586ecce5bdd.file b/.flatpak-builder/cache/objects/4e/8cc29c5b524fc000621f03f6f9c4a1c6db4ecf16b6af046326b586ecce5bdd.file new file mode 100644 index 0000000..a3beb7c --- /dev/null +++ b/.flatpak-builder/cache/objects/4e/8cc29c5b524fc000621f03f6f9c4a1c6db4ecf16b6af046326b586ecce5bdd.file @@ -0,0 +1,155 @@ +.TH INTLTOOL-UPDATE 8 "2003-08-02" "intltool" + +.SH NAME +intltool-update \- updates PO template file and merge translations with it + +.SH SYNOPSIS +.BI intltool-update " [option]..." +.br +.BI intltool-update " LANGCODE" + +.SH DESCRIPTION +.B intltool-update +generates new po file templates from source code, and merges existing +translations with these new po templates. +.PP +You must change working directory to the subdirectory containing translations +(usually "\fIpo/\fR") before running \fBintltool-update\fR. + +.SH OPTIONS +When executing +.B intltool-update +, only one mode of operation is allowed each time. +.\" ------------------------------------------------------- +.SS "Mode of operation" +.\" ------------------------------------------------------- +.IP "\fB\-p\fR" 4 +.PD 0 +.IP "\fB\-\-pot\fR" 4 +.PD +Generate po template (.pot) only. +.IP "\fB\-s\fR" 4 +.PD 0 +.IP "\fB\-\-headers\fR" 4 +.PD +Executes \fBintltool-extract\fR(8) to extract strings inside XML/INI +style files listed in \fBPOTFILES.in\fR, and writes the extracted +strings into header files, so that the strings can be recognised +by \fBxgettext\fR(1). +.IP "\fB\-m\fR" 4 +.PD 0 +.IP "\fB\-\-maintain\fR" 4 +.PD +Search for left out files, which should have been listed in +.B POTFILES.in +or +.BR POTFILES.skip "." +A list of all these files are written into another file called +"\fBmissing\fR". +.IP "\fB\-r\fR" 4 +.PD 0 +.IP "\fB\-\-report\fR" 4 +.PD +Display a status report for all translations in the software. +.IP "\fB\-d \fILANGCODE\fR" 4 +.PD 0 +.IP "\fB\-\-dist \fILANGCODE\fR" 4 +.PD +Merge +.BR LANGCODE .po +with existing PO template. +.\" ------------------------------------------------------- +.SS "Other options" +.\" ------------------------------------------------------- +. +.IP "\fB\-g \fINAME\fR" 4 +.PD 0 +.IP "\fB\-\-gettext-package\fR=\fINAME\fR" 4 +.PD +Manually specify PO template file name, instead of determining the +name automatically from source. Useful with +.BR \-p / \-\-pot +option. This option has an additional effect: the name of current working +directory is no more limited to "po" or "po-*". +.IP "\fB\-o \fIFILENAME\fR" 4 +.PD 0 +.IP "\fB\-\-output-file\fR=\fIFILENAME\fR" 4 +.PD +Manually specify output \fIFILENAME\fR after merging old translation with +PO template. Useful either with +.BR \-d / \-\-dist +option or without any option. +.IP "\fB\-x\fR" 4 +.PD 0 +.IP "\fB\-\-verbose\fR" 4 +.PD +Display lots of feedback. +.IP "\fB\-\-version\fR" 4 +Show version information. +.IP "\fB\-\-help\fR" 4 +Show usage and basic help information. + +.SH EXAMPLES +Creates a new PO template from source code, and name it foo.pot: +.PP +.RS 2 +.nf +.ft CW +.ne 1 +intltool-update \-\-pot \-\-gettext-package=foo +.ft R +.fi +.RE +.PP +Updates translation file xy.po using existing po template called +"bar.pot", and writes output into "xy1.po": +.PP +.RS 2 +.nf +.ft CW +.ne 1 +intltool-update \-\-dist \-\-gettext-package=bar \-\-output-file=xy1.po xy +.ft R +.fi +.RE +.PP +Creates new PO template and updates translation file xy.po +(xy.po is overwritten with new content): +.PP +.RS 2 +.nf +.ft CW +.ne 1 +intltool-update xy +.ft R +.fi +(same as \fBintltool-update \-\-pot && intltool-update \-\-dist xy\fR) +.RE + +.SH FILES +.IP "\fBpo/POTFILES.in\fR" +Contains list of source files which contain translatable strings, +one file per line. +.IP "\fBpo/POTFILES.skip\fR" +.PD 0 +.IP "\fBpo/POTFILES.ignore\fR (obsolete)" +.PD +Contains list of source files which should be ignored when searching +for translatable strings. + +.SH REPORTING BUGS +Report bugs to http://bugs.launchpad.net/intltool + +.SH AUTHOR +Darin Adler +.br +Kenneth Christiansen +.br +Maciej Stachowiak + +.SH SEE ALSO +.BR intltoolize (8), +.BR intltool-prepare (8), +.BR intltool-extract (8), +.BR intltool-merge (8), +.BR xgettext (1) diff --git a/.flatpak-builder/cache/objects/4e/8daf41df5e397e80edd19b5289c724c229026fd97c73ccbf7a3af9df285a87.file b/.flatpak-builder/cache/objects/4e/8daf41df5e397e80edd19b5289c724c229026fd97c73ccbf7a3af9df285a87.file new file mode 100644 index 0000000..a253702 Binary files /dev/null and b/.flatpak-builder/cache/objects/4e/8daf41df5e397e80edd19b5289c724c229026fd97c73ccbf7a3af9df285a87.file differ diff --git a/.flatpak-builder/cache/objects/4e/e7568670af29934e31ff26500fb6978ae01c199cd22e0acee86ba1cad35dc1.file b/.flatpak-builder/cache/objects/4e/e7568670af29934e31ff26500fb6978ae01c199cd22e0acee86ba1cad35dc1.file new file mode 100644 index 0000000..f2e1b45 Binary files /dev/null and b/.flatpak-builder/cache/objects/4e/e7568670af29934e31ff26500fb6978ae01c199cd22e0acee86ba1cad35dc1.file differ diff --git a/.flatpak-builder/cache/objects/4f/61316c935cec0f68770871876a68e88d03cb51f50bf17e3a62375d6c3d5b67.dirtree b/.flatpak-builder/cache/objects/4f/61316c935cec0f68770871876a68e88d03cb51f50bf17e3a62375d6c3d5b67.dirtree new file mode 100644 index 0000000..fb36de6 Binary files /dev/null and b/.flatpak-builder/cache/objects/4f/61316c935cec0f68770871876a68e88d03cb51f50bf17e3a62375d6c3d5b67.dirtree differ diff --git a/.flatpak-builder/cache/objects/4f/6dabac8e84fb82def6d57c84d8c7624aaf1b0710a7d18e85cc23b438b6f9a8.file b/.flatpak-builder/cache/objects/4f/6dabac8e84fb82def6d57c84d8c7624aaf1b0710a7d18e85cc23b438b6f9a8.file new file mode 100644 index 0000000..c6632fd --- /dev/null +++ b/.flatpak-builder/cache/objects/4f/6dabac8e84fb82def6d57c84d8c7624aaf1b0710a7d18e85cc23b438b6f9a8.file @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2005 - 2011 Vivien Malerba + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GDA_CONNECTION_EVENT_H__ +#define __GDA_CONNECTION_EVENT_H__ + +#include +#include + +G_BEGIN_DECLS + +#define GDA_TYPE_CONNECTION_EVENT (gda_connection_event_get_type()) +G_DECLARE_DERIVABLE_TYPE (GdaConnectionEvent, gda_connection_event, GDA, CONNECTION_EVENT, GObject) + +struct _GdaConnectionEventClass { + GObjectClass parent_class; + + gpointer padding[12]; +}; + +typedef enum { + GDA_CONNECTION_EVENT_NOTICE, + GDA_CONNECTION_EVENT_WARNING, + GDA_CONNECTION_EVENT_ERROR, + GDA_CONNECTION_EVENT_COMMAND + +} GdaConnectionEventType; + +typedef enum +{ + GDA_CONNECTION_EVENT_CODE_CONSTRAINT_VIOLATION, + GDA_CONNECTION_EVENT_CODE_RESTRICT_VIOLATION, + GDA_CONNECTION_EVENT_CODE_NOT_NULL_VIOLATION, + GDA_CONNECTION_EVENT_CODE_FOREIGN_KEY_VIOLATION, + GDA_CONNECTION_EVENT_CODE_UNIQUE_VIOLATION, + GDA_CONNECTION_EVENT_CODE_CHECK_VIOLATION, + GDA_CONNECTION_EVENT_CODE_INSUFFICIENT_PRIVILEGES, + GDA_CONNECTION_EVENT_CODE_UNDEFINED_COLUMN, + GDA_CONNECTION_EVENT_CODE_UNDEFINED_FUNCTION, + GDA_CONNECTION_EVENT_CODE_UNDEFINED_TABLE, + GDA_CONNECTION_EVENT_CODE_DUPLICATE_COLUMN, + GDA_CONNECTION_EVENT_CODE_DUPLICATE_DATABASE, + GDA_CONNECTION_EVENT_CODE_DUPLICATE_FUNCTION, + GDA_CONNECTION_EVENT_CODE_DUPLICATE_SCHEMA, + GDA_CONNECTION_EVENT_CODE_DUPLICATE_TABLE, + GDA_CONNECTION_EVENT_CODE_DUPLICATE_ALIAS, + GDA_CONNECTION_EVENT_CODE_DUPLICATE_OBJECT, + GDA_CONNECTION_EVENT_CODE_SYNTAX_ERROR, + GDA_CONNECTION_EVENT_CODE_UNKNOWN +} GdaConnectionEventCode; + +#define GDA_SQLSTATE_NO_ERROR "00000" +#define GDA_SQLSTATE_GENERAL_ERROR "HY000" + +/** + * SECTION:gda-connection-event + * @short_description: Any event which has occurred on a #GdaConnection + * @title: GdaConnectionEvent + * @stability: Stable + * @see_also: #GdaConnection + * + * Events occurring on a connection are each represented as a #GdaConnectionEvent object. Each #GdaConnection + * is responsible for keeping a list of past events; that list can be consulted using the + * gda_connection_get_events() function. + */ + +void gda_connection_event_set_event_type (GdaConnectionEvent *event, GdaConnectionEventType type); +GdaConnectionEventType gda_connection_event_get_event_type (GdaConnectionEvent *event); + +const gchar *gda_connection_event_get_description (GdaConnectionEvent *event); +void gda_connection_event_set_description (GdaConnectionEvent *event, const gchar *description); +glong gda_connection_event_get_code (GdaConnectionEvent *event); +void gda_connection_event_set_code (GdaConnectionEvent *event, glong code); +GdaConnectionEventCode gda_connection_event_get_gda_code (GdaConnectionEvent *event); +void gda_connection_event_set_gda_code (GdaConnectionEvent *event, GdaConnectionEventCode code); +const gchar *gda_connection_event_get_source (GdaConnectionEvent *event); +void gda_connection_event_set_source (GdaConnectionEvent *event, const gchar *source); +const gchar *gda_connection_event_get_sqlstate (GdaConnectionEvent *event); +void gda_connection_event_set_sqlstate (GdaConnectionEvent *event, const gchar *sqlstate); + +G_END_DECLS + +#endif diff --git a/.flatpak-builder/cache/objects/4f/934690c3ed8c91a0e56ea85e0842bdd07681722892916ba13995db01026f61.dirtree b/.flatpak-builder/cache/objects/4f/934690c3ed8c91a0e56ea85e0842bdd07681722892916ba13995db01026f61.dirtree new file mode 100644 index 0000000..13483ba Binary files /dev/null and b/.flatpak-builder/cache/objects/4f/934690c3ed8c91a0e56ea85e0842bdd07681722892916ba13995db01026f61.dirtree differ diff --git a/.flatpak-builder/cache/objects/4f/a090a6016413ca20a5c95a31a1fface7125d2b3290286889dc546da9c947cc.file b/.flatpak-builder/cache/objects/4f/a090a6016413ca20a5c95a31a1fface7125d2b3290286889dc546da9c947cc.file new file mode 100644 index 0000000..d0021cc --- /dev/null +++ b/.flatpak-builder/cache/objects/4f/a090a6016413ca20a5c95a31a1fface7125d2b3290286889dc546da9c947cc.file @@ -0,0 +1,1051 @@ +/* gda-db-table.c + * + * Copyright (C) 2018-2019 Pavlo Solntsev + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +#define G_LOG_DOMAIN "GDA-db-table" + +#include "gda-db-table.h" +#include "gda-db-fkey.h" +#include "gda-db-column.h" +#include +#include +#include "gda-server-provider.h" +#include "gda-connection.h" +#include "gda-meta-struct.h" +#include "gda-ddl-modifiable.h" +#include + +G_DEFINE_QUARK (gda_db_table_error, gda_db_table_error) + +typedef struct +{ + gchar *mp_comment; + + gboolean m_istemp; + GList *mp_columns; /* Type GdaDbColumn*/ + GList *mp_fkeys; /* List of all fkeys, GdaDbFkey */ + GSList *mp_constraint; /* A list of constraints for the table as strings, a la gchar* */ +} GdaDbTablePrivate; + +/** + * SECTION:gda-db-table + * @title: GdaDbTable + * @short_description: Object to represent table database object + * @see_also: #GdaDbView, #GdaDbCatalog + * @stability: Stable + * @include: libgda/libgda.h + * + * This object represents a table of a database. The table view can be constracted manually + * using API or generated from xml file together with other databse objects. See #GdaDbCatalog. + * #GdaDbTable implements #GdaDbBuildable interface for parsing xml file. + * + * #GdaDbTable can be used as a container to hold other objects, e.g. #GdaDbColumn, #GdaDbFkey and + * as soon as populated with all needed objects the table can be created using + * gda_ddl_modifiable_create(), + * + * To delete the table a method gda_ddl_modifiable_drop() can be called. + * + * A simple example of how to create a table with 3 columns being the last column of the foreign key. + * + * |[ + * + * GdaConnection *cnc; + * //Open connection here + * + * GError *error = NULL; + * + * GdaDbTable *tproject = gda_db_table_new (); + * gda_db_base_set_name (GDA_DB_BASE (tproject), "Project"); + * + * GdaDbColumn *pid = gda_db_column_new (); + * GdaDbColumn *pname = gda_db_column_new (); + * GdaDbColumn *pfkey = gda_db_column_new (); + * GdaDbFkey *fkey = gda_db_fkey_new (); + * + * gda_db_column_set_name (pid, "id"); + * gda_db_column_set_type (pid, G_TYPE_INT); + * gda_db_column_set_nnul (pid, TRUE); + * gda_db_column_set_autoinc (pid, TRUE); + * gda_db_column_set_unique (pid, TRUE); + * gda_db_column_set_pkey (pid, TRUE); + * + * gda_db_column_set_name (pname, "name"); + * gda_db_column_set_type (pname, G_TYPE_STRING); + * gda_db_column_set_size (pname, 30); + * gda_db_column_set_nnul (pname, TRUE); + * gda_db_column_set_unique (pname, TRUE); + * + * gda_db_column_set_name (pfkey, "fkey"); + * gda_db_column_set_type (pfkey, G_TYPE_INT); + * gda_db_column_set_nnul (pfkey, TRUE); + * + * gda_db_fkey_set_ref_table (fkey, "AnotherTable"); + * gda_db_fkey_set_ondelete (fkey, GDA_DB_FKEY_RESTRICT); + * gda_db_fkey_set_onupdate (fkey, GDA_DB_FKEY_RESTRICT); + * gda_db_fkey_set_field (fkey, "fkey", "another_table_id"); + * + * gda_db_table_append_column (tproject, pid); + * g_object_unref (pid); + * + * gda_db_table_append_column (tproject, pname); + * g_object_unref (pname); + * + * gda_db_table_append_column (tproject, pfkey); + * g_object_unref (pfkey); + * + * gda_db_table_append_fkey (tproject, fkey); + * g_object_unref (fkey); + * + * if (!gda_ddl_modifiable_create (GDA_DDL_MODIFIABLE (tproject), cnc, NULL, &error)) + * { + * g_error ("It was not possible to create the table in the database: %s\n", + * error && error->message ? error->message : "No detail"); + * } + * + * g_object_unref (tproject); + * + * ]| + + */ + +static void gda_db_table_buildable_interface_init (GdaDbBuildableInterface *iface); +static void gda_ddl_modifiable_interface_init (GdaDdlModifiableInterface *iface); + +static gboolean gda_db_table_create (GdaDdlModifiable *self, GdaConnection *cnc, + gpointer user_data, GError **error); +static gboolean gda_db_table_drop (GdaDdlModifiable *self, GdaConnection *cnc, + gpointer user_data, GError **error); +static gboolean gda_db_table_rename (GdaDdlModifiable *old_name, GdaConnection *cnc, + gpointer new_name, GError **error); + +G_DEFINE_TYPE_WITH_CODE (GdaDbTable, gda_db_table, GDA_TYPE_DB_BASE, + G_ADD_PRIVATE (GdaDbTable) + G_IMPLEMENT_INTERFACE (GDA_TYPE_DB_BUILDABLE, + gda_db_table_buildable_interface_init) + G_IMPLEMENT_INTERFACE (GDA_TYPE_DDL_MODIFIABLE, + gda_ddl_modifiable_interface_init)) + +enum { + PROP_0, + PROP_COMMENT, + PROP_ISTEMP, + /* */ + N_PROPS +}; + +static GParamSpec *properties [N_PROPS] = {NULL}; + +/* This is a convenient way to name all nodes from xml file */ +enum { + GDA_DB_TABLE_NODE, + GDA_DB_TABLE_NAME, + GDA_DB_TABLE_TEMP, + GDA_DB_TABLE_SPACE, + GDA_DB_TABLE_COMMENT, + GDA_DB_TABLE_CONSTRAINT, + + GDA_DB_TABLE_N_NODES +}; + +static const gchar *gdadbtablenodes[GDA_DB_TABLE_N_NODES] = { + "table", + "name", + "temptable", + "space", + "comment", + "constraint" +}; + +/** + * gda_db_table_new: + * + * Returns: New instance of #GdaDbTable, to free with g_object_unref () once not needed anymore + * + * Stability: Stable + * Since: 6.0 + */ +GdaDbTable * +gda_db_table_new (void) +{ + G_DEBUG_HERE(); + return g_object_new (GDA_TYPE_DB_TABLE, NULL); +} + +static void +gda_db_table_finalize (GObject *object) +{ + G_DEBUG_HERE(); + GdaDbTable *self = (GdaDbTable *)object; + GdaDbTablePrivate *priv = gda_db_table_get_instance_private (self); + + g_free (priv->mp_comment); + + G_OBJECT_CLASS (gda_db_table_parent_class)->finalize (object); +} + +static void +gda_db_table_dispose (GObject *object) +{ + GdaDbTable *self = (GdaDbTable *)object; + GdaDbTablePrivate *priv = gda_db_table_get_instance_private (self); + + if (priv->mp_fkeys) + g_list_free_full (priv->mp_fkeys, (GDestroyNotify) g_object_unref); + if (priv->mp_columns) + g_list_free_full (priv->mp_columns, (GDestroyNotify)g_object_unref); + if (priv->mp_constraint) + g_slist_free_full (priv->mp_constraint, (GDestroyNotify)g_free); + + G_OBJECT_CLASS (gda_db_table_parent_class)->dispose (object); +} + +static void +gda_db_table_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + GdaDbTable *self = GDA_DB_TABLE (object); + GdaDbTablePrivate *priv = gda_db_table_get_instance_private (self); + + switch (prop_id) { + case PROP_COMMENT: + g_value_set_string (value, priv->mp_comment); + break; + case PROP_ISTEMP: + g_value_set_boolean (value, priv->m_istemp); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +gda_db_table_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + GdaDbTable *self = GDA_DB_TABLE (object); + GdaDbTablePrivate *priv = gda_db_table_get_instance_private (self); + + switch (prop_id) { + case PROP_COMMENT: + g_free (priv->mp_comment); + priv->mp_comment = g_value_dup_string (value); + break; + case PROP_ISTEMP: + priv->m_istemp = g_value_get_boolean (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +gda_db_table_class_init (GdaDbTableClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->finalize = gda_db_table_finalize; + object_class->dispose = gda_db_table_dispose; + object_class->get_property = gda_db_table_get_property; + object_class->set_property = gda_db_table_set_property; + + properties[PROP_COMMENT] = g_param_spec_string ("comment", + "Comment", + "Table comment", + NULL, + G_PARAM_READWRITE); + properties[PROP_ISTEMP] = g_param_spec_string ("istemp", + "temporary-table", + "Is table temporary", + NULL, + G_PARAM_READWRITE); + + g_object_class_install_properties (object_class, N_PROPS, properties); +} + +static void +gda_db_table_init (GdaDbTable *self) +{ + GdaDbTablePrivate *priv = gda_db_table_get_instance_private (self); + + priv->mp_columns = NULL; + priv->m_istemp = FALSE; + priv->mp_comment = NULL; + priv->mp_fkeys = NULL; + priv->mp_constraint = NULL; +} + +/** + * gda_db_table_parse_node: + * @self: a #GdaDbTable object + * @node: instance of #xmlNodePtr to parse + * @error: #GError to handle an error + * + * Parse @node wich should point to the node + * + * Returns: %TRUE if no error, %FALSE otherwise + * + * Since: 6.0 + */ +static gboolean +gda_db_table_parse_node (GdaDbBuildable *buildable, + xmlNodePtr node, + GError **error) +{ + G_DEBUG_HERE(); + g_return_val_if_fail (buildable, FALSE); + g_return_val_if_fail (node, FALSE); + + GdaDbTable *self = GDA_DB_TABLE (buildable); + + GdaDbTablePrivate *priv = gda_db_table_get_instance_private (self); + + xmlChar *name = NULL; + name = xmlGetProp (node, (xmlChar *)gdadbtablenodes[GDA_DB_TABLE_NAME]); + g_assert (name); /* If here bug with xml validation */ + gda_db_base_set_name(GDA_DB_BASE(self), (gchar*)name); + xmlFree(name); + + xmlChar *tempt = xmlGetProp (node, (xmlChar*)gdadbtablenodes[GDA_DB_TABLE_TEMP]); + + if (tempt) + { + if (*tempt == 't' || *tempt == 't') + g_object_set (G_OBJECT(self), "istemp", TRUE, NULL); + + xmlFree (tempt); + } + + for (xmlNodePtr it = node->children; it ; it = it->next) + { + if (!g_strcmp0 ((gchar *) it->name, gdadbtablenodes[GDA_DB_TABLE_COMMENT])) + { + xmlChar *comment = xmlNodeGetContent (it); + + if (comment) + { + g_object_set (G_OBJECT(self), "comment", (char*)comment, NULL); + xmlFree (comment); + } + } + else if (!g_strcmp0 ((gchar *)it->name, "column")) + { + GdaDbColumn *column = gda_db_column_new (); + + if (!gda_db_buildable_parse_node(GDA_DB_BUILDABLE (column), it, error)) + { + g_object_unref(column); + return FALSE; + } + else + priv->mp_columns = g_list_append (priv->mp_columns, column); + } + else if (!g_strcmp0 ((gchar*)it->name, "fkey")) + { + GdaDbFkey *fkey; + fkey = gda_db_fkey_new (); + + if (!gda_db_buildable_parse_node (GDA_DB_BUILDABLE(fkey), it, error)) + { + g_object_unref (fkey); + return FALSE; + } + else + priv->mp_fkeys = g_list_append (priv->mp_fkeys, fkey); + } + else if (!g_strcmp0((gchar*)it->name, gdadbtablenodes[GDA_DB_TABLE_CONSTRAINT])) + { + xmlChar *constraint = xmlNodeGetContent (it); + + if (constraint) + { + gda_db_table_append_constraint(self, (gchar*)constraint); + xmlFree (constraint); + } + + } /* end of else if */ + } /* End of for loop */ + return TRUE; +} /* End of gda_db_column_parse_node */ + +static gboolean +gda_db_table_write_node (GdaDbBuildable *buildable, + xmlNodePtr rootnode, + GError **error) +{ + G_DEBUG_HERE(); + g_return_val_if_fail (buildable, FALSE); + g_return_val_if_fail (rootnode, FALSE); + + GdaDbTable *self = GDA_DB_TABLE (buildable); + GdaDbTablePrivate *priv = gda_db_table_get_instance_private (self); + + xmlNodePtr node = NULL; + node = xmlNewChild (rootnode, NULL, (xmlChar*)gdadbtablenodes[GDA_DB_TABLE_NODE], NULL); + xmlNewProp (node, BAD_CAST gdadbtablenodes[GDA_DB_TABLE_NAME], + BAD_CAST gda_db_base_get_name (GDA_DB_BASE(self))); + + xmlNewProp (node, BAD_CAST gdadbtablenodes[GDA_DB_TABLE_TEMP], + BAD_CAST GDA_BOOL_TO_STR (priv->m_istemp)); + + xmlNewChild (node, NULL, + (xmlChar*)gdadbtablenodes[GDA_DB_TABLE_COMMENT], + (xmlChar*)priv->mp_comment); + + GList *it = NULL; + + for (it = priv->mp_columns; it; it=it->next) + if(!gda_db_buildable_write_node (GDA_DB_BUILDABLE(GDA_DB_COLUMN(it->data)), node,error)) + return FALSE; + + return TRUE; +} + +static void +gda_db_table_buildable_interface_init (GdaDbBuildableInterface *iface) +{ + iface->parse_node = gda_db_table_parse_node; + iface->write_node = gda_db_table_write_node; +} + +static void +gda_ddl_modifiable_interface_init (GdaDdlModifiableInterface *iface) +{ + iface->create = gda_db_table_create; + iface->drop = gda_db_table_drop; + iface->rename = gda_db_table_rename; +} +/** + * gda_db_table_set_comment: + * @self: an #GdaDbTable object + * @tablecomment: Comment to set as a string + * + * If @tablecomment is %NULL nothing is happened. @tablecomment will not be set + * to %NULL. + * + * Stability: Stable + * Since: 6.0 + */ +void +gda_db_table_set_comment (GdaDbTable *self, + const char *tablecomment) +{ + G_DEBUG_HERE(); + g_return_if_fail (self); + + if (tablecomment) + { + GdaDbTablePrivate *priv = gda_db_table_get_instance_private (self); + g_free (priv->mp_comment); + priv->mp_comment = g_utf8_strup (tablecomment, g_utf8_strlen (tablecomment, -1)); + } +} + +/** + * gda_db_table_set_is_temp: + * @self: a #GdaDbTable object + * @istemp: Set if the table should be temporary + * + * Set if the table should be temporary or not. %FALSE is set by default. + * + * Stability: Stable + * Since: 6.0 + */ +void +gda_db_table_set_is_temp (GdaDbTable *self, + gboolean istemp) +{ + G_DEBUG_HERE(); + g_return_if_fail (self); + GdaDbTablePrivate *priv = gda_db_table_get_instance_private (self); + priv->m_istemp = istemp; +} + +/** + * gda_db_table_get_comment: + * @self: a #GdaDbTable object + * + * Returns: A comment string or %NULL if comment wasn't set. + * + * Stability: Stable + * Since: 6.0 + */ +const char* +gda_db_table_get_comment (GdaDbTable *self) +{ + G_DEBUG_HERE(); + g_return_val_if_fail (self, NULL); + GdaDbTablePrivate *priv = gda_db_table_get_instance_private (self); + return priv->mp_comment; +} + +/** + * gda_db_table_get_temp: + * @self: a #GdaDbTable object + * + * Returns temp key. If %TRUE table should be temporary, %FALSE otherwise. + * If @self is %NULL, this function aborts. So check @self before calling this + * method. + * + * Stability: Stable + * Since: 6.0 + */ +gboolean +gda_db_table_get_temp (GdaDbTable *self) +{ + G_DEBUG_HERE(); + g_return_val_if_fail (self, FALSE); + + GdaDbTablePrivate *priv = gda_db_table_get_instance_private (self); + return priv->m_istemp; +} + +/** + * gda_db_table_is_valid: + * @self: a #GdaDbTable instance + * + * This method returns %TRUE if at least one column is added to the table. It ruturns %FALSE if the + * table has no columns. + * + * Returns: %TRUE or %FALSE + * + * Stability: Stable + * Since: 6.0 + */ +gboolean +gda_db_table_is_valid (GdaDbTable *self) +{ + G_DEBUG_HERE(); + g_return_val_if_fail (self, FALSE); + + GdaDbTablePrivate *priv = gda_db_table_get_instance_private (self); + +/* TODO: It may be worthwhile to have the same method for all children elements and + * call this method on each children member to make sure whole table is valid + * */ + if (priv->mp_columns) + return TRUE; + else + return FALSE; +} + +/** + * gda_db_table_get_columns: + * @self: an #GdaDbTable object + * + * Use this method to obtain internal list of all columns. The internal list + * should not be freed. + * + * Returns: (element-type Gda.DbColumn) (transfer none): A list of #GdaDbColumn objects or %NULL + * if the internal list is not set or if %NULL is passed. + * + * Stability: Stable + * Since: 6.0 + * + */ +GList* +gda_db_table_get_columns (GdaDbTable *self) +{ + G_DEBUG_HERE(); + g_return_val_if_fail (self, NULL); + GdaDbTablePrivate *priv = gda_db_table_get_instance_private (self); + + return priv->mp_columns; +} + +/** + * gda_db_table_get_fkeys: + * @self: A #GdaDbTable object + * + * Use this method to obtain internal list of all fkeys. The internal list + * should not be freed. + * + * Returns: (transfer none) (element-type Gda.DbFkey): A list of #GdaDbFkey objects or %NULL if + * the internal list is not set or %NULL is passed + * + * Stability: Stable + * Since: 6.0 + */ +GList* +gda_db_table_get_fkeys (GdaDbTable *self) +{ + G_DEBUG_HERE(); + g_return_val_if_fail (self, NULL); + GdaDbTablePrivate *priv = gda_db_table_get_instance_private (self); + + return priv->mp_fkeys; +} + +/** + * gda_db_table_is_temp: + * @self: a #GdaDbTable object + * + * Checks if the table is temporary + * + * Returns: %TRUE if table is temporary, %FALSE otherwise. + * + * Stability: Stable + * Since: 6.0 + */ +gboolean +gda_db_table_get_is_temp (GdaDbTable *self) +{ + G_DEBUG_HERE(); + g_return_val_if_fail (GDA_IS_DB_TABLE(self), FALSE); + + GdaDbTablePrivate *priv = gda_db_table_get_instance_private (self); + return priv->m_istemp; +} + +/** + * gda_db_table_prepare_create: + * @self: a #GdaDbTable instance + * @op: an instance of #GdaServerOperation to populate. + * @ifnotexists: Set it to TRUE if "IF NOT EXISTS" should be added + * @error: error container + * + * Populate @op with information stored in @self. This method sets @op to execute CREATE_TABLE + * operation. + * + * Returns: %TRUE if no error occured and %FALSE otherwise. + * + * Stability: Stable + * Since: 6.0 + */ +gboolean +gda_db_table_prepare_create (GdaDbTable *self, + GdaServerOperation *op, + gboolean ifnotexists, + GError **error) +{ + G_DEBUG_HERE(); + g_return_val_if_fail(GDA_IS_DB_TABLE(self), FALSE); + g_return_val_if_fail(GDA_IS_SERVER_OPERATION(op), FALSE); + g_return_val_if_fail(error == NULL || *error == NULL, FALSE); + + GdaDbTablePrivate *priv = gda_db_table_get_instance_private (self); + + if (!gda_server_operation_set_value_at (op, + gda_db_base_get_name (GDA_DB_BASE(self)), + error, + "/TABLE_DEF_P/TABLE_NAME")) + return FALSE; + + if (!gda_server_operation_set_value_at (op, + GDA_BOOL_TO_STR(priv->m_istemp), + error, + "/TABLE_DEF_P/TABLE_TEMP")) + return FALSE; + + if (!gda_server_operation_set_value_at (op, + priv->mp_comment, + error, + "/TABLE_DEF_P/TABLE_COMMENT")) + return FALSE; + + if (!gda_server_operation_set_value_at (op, + GDA_BOOL_TO_STR (ifnotexists), + error, + "/TABLE_DEF_P/TABLE_IFNOTEXISTS")) + return FALSE; + + GSList *jt = NULL; + int indexsec = 0; /* Index for sequence */ + + for (jt = priv->mp_constraint; jt != NULL; jt = jt->next, indexsec++) + { + if (!gda_server_operation_set_value_at (op, + (const gchar *)jt->data, + error, + "/TABLE_CONSTRAINTS_S/%d/CONSTRAINT_STRING", indexsec)) + return FALSE; + } + + GList *it = NULL; + gint i = 0; /* column order counter */ + + for (it = priv->mp_columns;it;it=it->next) + if(!gda_db_column_prepare_create (GDA_DB_COLUMN (it->data), op, i++, error)) + return FALSE; + + i = 0; + for (it = priv->mp_fkeys;it;it=it->next) + if(!gda_db_fkey_prepare_create (GDA_DB_FKEY(it->data), op, i++, error)) + return FALSE; + + return TRUE; +} + +static gint +_gda_db_compare_column_meta (GdaMetaTableColumn *a, + GdaDbColumn *b) +{ + if (a && !b) + return 1; + else if (!a && b) + return -1; + else if (!a && !b) + return 0; + + const gchar *namea = a->column_name; + const gchar *nameb = gda_db_column_get_name (b); + + g_debug("Checking %s and %s\n", namea, nameb); + return g_strcmp0 (namea,nameb); +} + +/** + * gda_db_table_update: + * @self: a #GdaDbTable instance + * @obj: The corresponding meta object to take data from + * @cnc: opened connection + * @error: error container + * + * With this method object @obj in the database available through @cnc will be updated using + * ADD_COLUMN operation with information stored in @self. This method is designed for internal use + * only and should not be used for the new code. It will be obsolete. + * + * Returns: %TRUE if no error and %FALSE otherwise + */ +gboolean +gda_db_table_update (GdaDbTable *self, + GdaMetaTable *obj, + GdaConnection *cnc, + GError **error) +{ + g_return_val_if_fail (GDA_IS_DB_TABLE(self), FALSE); + g_return_val_if_fail (obj, FALSE); + g_return_val_if_fail (GDA_IS_CONNECTION(cnc), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + if (!gda_connection_is_opened (cnc)) + { + g_set_error (error, GDA_DB_TABLE_ERROR, GDA_DB_TABLE_CONNECTION_NOT_OPENED, + _("Connection is not opened")); + return FALSE; + } + + GdaDbTablePrivate *priv = gda_db_table_get_instance_private (self); + + if (!obj->columns) + { + g_set_error (error, GDA_DB_TABLE_ERROR, GDA_DB_TABLE_COLUMN_EMPTY, _("Empty column list")); + return FALSE; + } + + GSList *dbcolumns = NULL; + GList *it = NULL; + + GdaServerProvider *provider = NULL; + GdaServerOperation *op = NULL; + + dbcolumns = obj->columns; + + gda_lockable_lock ((GdaLockable*)cnc); + + provider = gda_connection_get_provider (cnc); + + op = gda_server_provider_create_operation (provider, + cnc, + GDA_SERVER_OPERATION_ADD_COLUMN, + NULL, + error); + if (!op) + goto on_error; + + if(!gda_server_operation_set_value_at (op, + gda_db_base_get_full_name (GDA_DB_BASE(self)), + error, + "/COLUMN_DEF_P/TABLE_NAME")) + goto on_error; + + gint newcolumncount = 0; + for (it = priv->mp_columns;it;it=it->next) + { + GSList *res = g_slist_find_custom (dbcolumns, + it->data, + (GCompareFunc)_gda_db_compare_column_meta); + + if (res) /* If object is present we need go to next element */ + continue; + else + newcolumncount++; /* We need to count new column. See below */ + + if(!gda_db_column_prepare_add (GDA_DB_COLUMN(it->data), op, error)) + { + g_slist_free (res); + goto on_error; + } + } + + if (newcolumncount != 0) /* Run operation only if at least on column is present*/ + if(!gda_server_provider_perform_operation (provider, cnc, op, error)) + goto on_error; + + g_object_unref(op); + gda_lockable_unlock ((GdaLockable*)cnc); + return TRUE; + +on_error: + g_object_unref(op); + gda_lockable_unlock ((GdaLockable*)cnc); + return FALSE; +} + +/* + * @self: a #GdaDbTable object + * @cnc: a #GdaConnection object + * @ifnotexists: Set to %TRUE if table should be created with "IFNOTEXISTS" option + * @error: container for error storage + * + */ +static gboolean +gda_db_table_create (GdaDdlModifiable *self, + GdaConnection *cnc, + gpointer user_data, + GError **error) +{ + g_return_val_if_fail (GDA_IS_DB_TABLE (self), FALSE); + + gda_lockable_lock (GDA_LOCKABLE(cnc)); + + GdaServerProvider *provider = NULL; + GdaServerOperation *op = NULL; + gboolean res = FALSE; + + GdaDbTable *table = GDA_DB_TABLE (self); + + provider = gda_connection_get_provider (cnc); + + op = gda_server_provider_create_operation (provider, + cnc, + GDA_SERVER_OPERATION_CREATE_TABLE, + NULL, + error); + if (op) + { + g_object_set_data_full (G_OBJECT (op), "connection", g_object_ref (cnc), g_object_unref); + + if (gda_db_table_prepare_create (table, op, TRUE, error)) + { +#ifdef GDA_DEBUG + gchar* str = gda_server_operation_render (op, error); + g_message ("Operation: %s", str); + g_free (str); +#endif + res = gda_server_provider_perform_operation (provider, cnc, op, error); + } + g_object_unref (op); + } + gda_lockable_unlock (GDA_LOCKABLE(cnc)); + + return res; +} + +/** + * gda_db_table_append_column: + * @self: a #GdaDbTable instance + * @column: column to add + * + * Append @column to the internal list of columns + * + * Stability: Stable + * Since: 6.0 + */ +void +gda_db_table_append_column (GdaDbTable *self, + GdaDbColumn *column) +{ + g_return_if_fail (self); + g_return_if_fail (column); + + GdaDbTablePrivate *priv = gda_db_table_get_instance_private (self); + + g_object_set (column, "table", self, NULL); + priv->mp_columns = g_list_append (priv->mp_columns, g_object_ref (column)); +} + +/** + * gda_db_table_append_fkey: + * @self: a #GdaDbTable instance + * @fkey: fkry to add + * + * Append @fkey to the internal list of columns + * + * Stability: Stable + * Since: 6.0 + */ +void +gda_db_table_append_fkey (GdaDbTable *self, + GdaDbFkey *fkey) +{ + g_return_if_fail (self); + + GdaDbTablePrivate *priv = gda_db_table_get_instance_private (self); + + priv->mp_fkeys = g_list_append (priv->mp_fkeys, g_object_ref (fkey)); +} + +/* + * @old_name: The originam table to rename. + * @new_name: The new table to rename to + * @cnc: Connection to use + * @error: An error holder + * + * This method performs rename operation on the table + * + * Stability: Stable + * Since: 6.0 + */ +static gboolean +gda_db_table_rename (GdaDdlModifiable *old_name, + GdaConnection *cnc, + gpointer new_name, + GError **error) +{ + G_DEBUG_HERE(); + GdaServerOperation *op = NULL; + GdaServerProvider *provider = NULL; + GdaDbTable *new_name_table = NULL; + + g_return_val_if_fail(GDA_IS_DB_TABLE (old_name), FALSE); + g_return_val_if_fail(new_name, FALSE); + + new_name_table = GDA_DB_TABLE (new_name); + + gda_lockable_lock (GDA_LOCKABLE (cnc)); + provider = gda_connection_get_provider (cnc); + + op = gda_server_provider_create_operation (provider, cnc, GDA_SERVER_OPERATION_RENAME_TABLE, + NULL, error); + + if (!op) + goto on_error; + + if (!gda_server_operation_set_value_at (op, gda_db_base_get_full_name (GDA_DB_BASE (old_name)), + error, "/TABLE_DESC_P/TABLE_NAME")) + goto on_error; + + if (!gda_server_operation_set_value_at (op, gda_db_base_get_full_name (GDA_DB_BASE (new_name_table)), + error, "/TABLE_DESC_P/TABLE_NEW_NAME")) + goto on_error; + + if (!gda_server_provider_perform_operation (provider, cnc, op, error)) + goto on_error; + + g_object_unref (op); + + gda_lockable_unlock (GDA_LOCKABLE (cnc)); + + return TRUE; + +on_error: + if (op) + g_object_unref (op); + + gda_lockable_unlock (GDA_LOCKABLE (cnc)); + + return FALSE; +} + +/* + * @self: An instance of GdaDbTable + * @cnc: Open connection to use for the operation + * @ifexists: Set to %TRUE if the flag "IF EXISTS" should be added. + * @error: A place to store the error + * + * Drop table from the database. This mehod will call "DROP TABLE ..." SQL command. + * + * Returns: %TRUE if no error and %FALSE otherwise. + * + * Stability: Stable + * Since: 6.0 + */ +static gboolean +gda_db_table_drop (GdaDdlModifiable *self, + GdaConnection *cnc, + gpointer user_data, + GError **error) +{ + G_DEBUG_HERE(); + GdaServerProvider *provider = NULL; + GdaServerOperation *op = NULL; + + g_return_val_if_fail (GDA_IS_DB_TABLE (self), FALSE); + + gda_lockable_lock (GDA_LOCKABLE (cnc)); + + provider = gda_connection_get_provider (cnc); + + op = gda_server_provider_create_operation (provider, cnc, GDA_SERVER_OPERATION_DROP_TABLE, + NULL, error); + + if (!op) + { + g_warning("ServerOperation is NULL\n"); + goto on_error; + } + + if (!gda_server_operation_set_value_at (op, gda_db_base_get_full_name(GDA_DB_BASE(self)), error, + "/TABLE_DESC_P/TABLE_NAME")) + goto on_error; + + if (!gda_server_operation_set_value_at (op, GDA_BOOL_TO_STR (TRUE), error, + "/TABLE_DESC_P/TABLE_IFEXISTS")) + goto on_error; + + if (!gda_server_provider_perform_operation (provider, cnc, op, error)) + goto on_error; + + g_object_unref (op); + + gda_lockable_unlock (GDA_LOCKABLE (cnc)); + + return TRUE; + +on_error: + if (op) g_object_unref (op); + + gda_lockable_unlock (GDA_LOCKABLE (cnc)); + + return FALSE; +} + +/** + * gda_db_table_append_constraint: + * @self: a #GdaDbTable instance + * @constr: a constraint string to append + * + * Adds global table constraint. It will be added to the sql string by the provider implementation + * if it supports it. Usually, table constraint is very complex and the current method just append + * a list of constraints to the sql string. + * + * Stability: Stable + * Since: 6.0 + */ +void +gda_db_table_append_constraint (GdaDbTable *self, + const gchar *constr) +{ + GdaDbTablePrivate *priv = gda_db_table_get_instance_private (self); + + priv->mp_constraint = g_slist_append (priv->mp_constraint, g_strdup (constr)); +} diff --git a/.flatpak-builder/cache/objects/50/272749a56c27422cc82d8d9d589bdcf634a3beb5a7dbb68ae23307269ee727.dirtree b/.flatpak-builder/cache/objects/50/272749a56c27422cc82d8d9d589bdcf634a3beb5a7dbb68ae23307269ee727.dirtree new file mode 100644 index 0000000..f477eb3 Binary files /dev/null and b/.flatpak-builder/cache/objects/50/272749a56c27422cc82d8d9d589bdcf634a3beb5a7dbb68ae23307269ee727.dirtree differ diff --git a/.flatpak-builder/cache/objects/50/36edec243889f9c9c77fe558c8ca1444cb8a60645055c21e2f8b65e1c513f7.file b/.flatpak-builder/cache/objects/50/36edec243889f9c9c77fe558c8ca1444cb8a60645055c21e2f8b65e1c513f7.file new file mode 100644 index 0000000..80488da --- /dev/null +++ b/.flatpak-builder/cache/objects/50/36edec243889f9c9c77fe558c8ca1444cb8a60645055c21e2f8b65e1c513f7.file @@ -0,0 +1,244 @@ +/* + * Copyright (C) 2006 - 2013 Vivien Malerba + * Copyright (C) 2007 Armin Burgmeier + * Copyright (C) 2007 Murray Cumming + * Copyright (C) 2009 Bas Driessen + * Copyright (C) 2010 David King + * Copyright (C) 2010 Jonh Wendell + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "gda-handler-string.h" +#include +#include +#include +#include + +struct _GdaHandlerString +{ + GObject parent_instance; + + GdaServerProvider *prov; + GdaConnection *cnc; +}; + +static void data_handler_iface_init (GdaDataHandlerInterface *iface); + +G_DEFINE_TYPE_EXTENDED (GdaHandlerString, gda_handler_string, G_TYPE_OBJECT, 0, + G_IMPLEMENT_INTERFACE (GDA_TYPE_DATA_HANDLER, data_handler_iface_init)) + +/** + * gda_handler_string_new: + * + * Creates a data handler for strings + * + * Returns: (type GdaHandlerString) (transfer full): the new object + */ +GdaDataHandler * +gda_handler_string_new (void) +{ + GObject *obj; + + obj = g_object_new (GDA_TYPE_HANDLER_STRING, NULL); + + return (GdaDataHandler *) obj; +} + +/** + * gda_handler_string_new_with_provider: + * @prov: a #GdaServerProvider object + * @cnc: (nullable): a #GdaConnection object, or %NULL + * + * Creates a data handler for strings, which will use some specific methods implemented + * by the @prov object (possibly also @cnc). + * + * Returns: (type GdaHandlerString) (transfer full): the new object + */ +GdaDataHandler * +gda_handler_string_new_with_provider (GdaServerProvider *prov, GdaConnection *cnc) +{ + GObject *obj; + GdaHandlerString *dh; + + g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (prov), NULL); + g_return_val_if_fail (!cnc || GDA_IS_CONNECTION (cnc), NULL); + + obj = g_object_new (GDA_TYPE_HANDLER_STRING, NULL); + dh = (GdaHandlerString*) obj; + + dh->prov = prov; + if (cnc) + dh->cnc = cnc; + + g_object_add_weak_pointer (G_OBJECT (prov), (gpointer) &(dh->prov)); + if (cnc) + g_object_add_weak_pointer (G_OBJECT (cnc), (gpointer) &(dh->cnc)); + + return (GdaDataHandler *) obj; +} + +static gchar * +gda_handler_string_get_sql_from_value (GdaDataHandler *iface, const GValue *value) +{ + g_assert (value); + + gchar *str, *retval; + GdaHandlerString *hdl; + + g_return_val_if_fail (GDA_IS_HANDLER_STRING (iface), NULL); + hdl = (GdaHandlerString*) (iface); + + str = gda_value_stringify ((GValue *) value); + if (str) { + gchar *str2; + if (hdl->prov) + str2 = gda_server_provider_escape_string (hdl->prov, hdl->cnc, str); + else + str2 = gda_default_escape_string (str); + retval = g_strdup_printf ("'%s'", str2); + g_free (str2); + g_free (str); + } + else + retval = g_strdup ("NULL"); + + return retval; +} + +static gchar * +gda_handler_string_get_str_from_value (G_GNUC_UNUSED GdaDataHandler *iface, const GValue *value) +{ + g_assert (value); + return gda_value_stringify ((GValue *) value); +} + +static GValue * +gda_handler_string_get_value_from_sql (GdaDataHandler *iface, const gchar *sql, G_GNUC_UNUSED GType type) +{ + g_assert (sql); + + GdaHandlerString *hdl; + GValue *value = NULL; + + g_return_val_if_fail (GDA_IS_HANDLER_STRING (iface), NULL); + hdl = (GdaHandlerString*) (iface); + + if (*sql) { + gint i = strlen (sql); + if ((i>=2) && (*sql=='\'') && (sql[i-1]=='\'')) { + gchar *str = g_strdup (sql); + gchar *unstr; + + str[i-1] = 0; + if (hdl->prov) + unstr = gda_server_provider_unescape_string (hdl->prov, hdl->cnc, str+1); + else + unstr = gda_default_unescape_string (str+1); + if (unstr) { + value = g_value_init (g_new0 (GValue, 1), G_TYPE_STRING); + g_value_take_string (value, unstr); + } + g_free (str); + } + } + else + value = gda_value_new_null (); + + return value; +} + +static GValue * +gda_handler_string_get_value_from_str (G_GNUC_UNUSED GdaDataHandler *iface, const gchar *str, G_GNUC_UNUSED GType type) +{ + g_assert (str); + + GValue *value; + value = g_value_init (g_new0 (GValue, 1), G_TYPE_STRING); + g_value_set_string (value, str); + return value; +} + +static GValue * +gda_handler_string_get_sane_init_value (G_GNUC_UNUSED GdaDataHandler *iface, G_GNUC_UNUSED GType type) +{ + GValue *value; + + value = g_value_init (g_new0 (GValue, 1), G_TYPE_STRING); + g_value_set_string (value, ""); + return value; +} + +static gboolean +gda_handler_string_accepts_g_type (GdaDataHandler *iface, GType type) +{ + g_assert (iface); + return type == G_TYPE_STRING ? TRUE : FALSE; +} + +static const gchar * +gda_handler_string_get_descr (GdaDataHandler *iface) +{ + g_return_val_if_fail (GDA_IS_HANDLER_STRING (iface), NULL); + return g_object_get_data (G_OBJECT (iface), "descr"); +} + +static void +gda_handler_string_init (GdaHandlerString * hdl) +{ + /* Private structure */ + g_object_set_data (G_OBJECT (hdl), "name", "InternalString"); + g_object_set_data (G_OBJECT (hdl), "descr", _("Strings representation")); +} + +static void +gda_handler_string_dispose (GObject *object) +{ + GdaHandlerString *hdl = (GdaHandlerString *)object; + + g_return_if_fail (object != NULL); + g_return_if_fail (GDA_IS_HANDLER_STRING (object)); + + hdl = GDA_HANDLER_STRING (object); + + if (hdl->prov) + g_object_remove_weak_pointer (G_OBJECT (hdl->prov), (gpointer) &(hdl->prov)); + if (hdl->cnc) + g_object_remove_weak_pointer (G_OBJECT (hdl->cnc), (gpointer) &(hdl->cnc)); + + /* for the parent class */ + G_OBJECT_CLASS (gda_handler_string_parent_class)->dispose (object); +} + +static void +data_handler_iface_init (GdaDataHandlerInterface *iface) +{ + iface->get_sql_from_value = gda_handler_string_get_sql_from_value; + iface->get_str_from_value = gda_handler_string_get_str_from_value; + iface->get_value_from_sql = gda_handler_string_get_value_from_sql; + iface->get_value_from_str = gda_handler_string_get_value_from_str; + iface->get_sane_init_value = gda_handler_string_get_sane_init_value; + iface->accepts_g_type = gda_handler_string_accepts_g_type; + iface->get_descr = gda_handler_string_get_descr; +} + +static void +gda_handler_string_class_init (GdaHandlerStringClass * class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (class); + + object_class->dispose = gda_handler_string_dispose; +} diff --git a/.flatpak-builder/cache/objects/50/38516854bdfd036b9a22d13b9dddb3ebe3e8d647b1e2edcbe39fcfdb0fbbdb.file b/.flatpak-builder/cache/objects/50/38516854bdfd036b9a22d13b9dddb3ebe3e8d647b1e2edcbe39fcfdb0fbbdb.file new file mode 120000 index 0000000..72f6c41 --- /dev/null +++ b/.flatpak-builder/cache/objects/50/38516854bdfd036b9a22d13b9dddb3ebe3e8d647b1e2edcbe39fcfdb0fbbdb.file @@ -0,0 +1 @@ +../../share/runtime/locale/fi/share/fi \ No newline at end of file diff --git a/.flatpak-builder/cache/objects/50/4225db4c82d1e0fc1da5b761052dfb9803778aac06a5b6d73d4bf9863188e2.dirtree b/.flatpak-builder/cache/objects/50/4225db4c82d1e0fc1da5b761052dfb9803778aac06a5b6d73d4bf9863188e2.dirtree new file mode 100644 index 0000000..8b9d713 Binary files /dev/null and b/.flatpak-builder/cache/objects/50/4225db4c82d1e0fc1da5b761052dfb9803778aac06a5b6d73d4bf9863188e2.dirtree differ diff --git a/.flatpak-builder/cache/objects/50/8ac74d10e7bc17b2e1b4de6494d133ffc21b487ad38a5ac76ed4b9d2ed7c3c.dirtree b/.flatpak-builder/cache/objects/50/8ac74d10e7bc17b2e1b4de6494d133ffc21b487ad38a5ac76ed4b9d2ed7c3c.dirtree new file mode 100644 index 0000000..b084c13 Binary files /dev/null and b/.flatpak-builder/cache/objects/50/8ac74d10e7bc17b2e1b4de6494d133ffc21b487ad38a5ac76ed4b9d2ed7c3c.dirtree differ diff --git a/.flatpak-builder/cache/objects/51/28956335fe0029455bae01beed061a0c72e2835df07d168d632307d3ea034b.file b/.flatpak-builder/cache/objects/51/28956335fe0029455bae01beed061a0c72e2835df07d168d632307d3ea034b.file new file mode 100644 index 0000000..a69f380 --- /dev/null +++ b/.flatpak-builder/cache/objects/51/28956335fe0029455bae01beed061a0c72e2835df07d168d632307d3ea034b.file @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2006 - 2012 Vivien Malerba + * Copyright (C) 2018 Daniel Espinosa + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GDA_DATA_ACCESS_WRAPPER_H__ +#define __GDA_DATA_ACCESS_WRAPPER_H__ + +#include + +G_BEGIN_DECLS + +#define GDA_TYPE_DATA_ACCESS_WRAPPER (gda_data_access_wrapper_get_type()) +G_DECLARE_DERIVABLE_TYPE(GdaDataAccessWrapper, gda_data_access_wrapper, GDA, DATA_ACCESS_WRAPPER, GObject) + +struct _GdaDataAccessWrapperClass { + GObjectClass parent_class; + + /*< private >*/ + /* Padding for future expansion */ + /*< private >*/ + void (*_gda_reserved1) (void); + void (*_gda_reserved2) (void); + void (*_gda_reserved3) (void); + void (*_gda_reserved4) (void); +}; + +/** + * SECTION:gda-data-access-wrapper + * @short_description: Offers a random access on top of a cursor-only access data model + * @title: GdaDataAccessWrapper + * @stability: Stable + * @see_also: #GdaDataModel + * + * The #GdaDataAccessWrapper object simply wraps another #GdaDataModel data model object + * and allows data to be accessed in a random way while remaining memory efficient as much as possible. + */ + +GdaDataModel *gda_data_access_wrapper_new (GdaDataModel *model); +gboolean gda_data_access_wrapper_set_mapping (GdaDataAccessWrapper *wrapper, + const gint *mapping, gint mapping_size); + +G_END_DECLS + +#endif diff --git a/.flatpak-builder/cache/objects/51/3150f72d317ddeeb0655dc4131302bcdffe2220ef8ad4b5eb3afce4f28b35b.file b/.flatpak-builder/cache/objects/51/3150f72d317ddeeb0655dc4131302bcdffe2220ef8ad4b5eb3afce4f28b35b.file new file mode 100755 index 0000000..43314b4 --- /dev/null +++ b/.flatpak-builder/cache/objects/51/3150f72d317ddeeb0655dc4131302bcdffe2220ef8ad4b5eb3afce4f28b35b.file @@ -0,0 +1,3 @@ +#!/bin/sh + +/app/bin/canberra-gtk-play --id="desktop-logout" --description="GNOME Logout" diff --git a/.flatpak-builder/cache/objects/52/01573677d56ec43eaab28177afb4bbb06bfe893cd9d59c6ae4247e0b16f44d.file b/.flatpak-builder/cache/objects/52/01573677d56ec43eaab28177afb4bbb06bfe893cd9d59c6ae4247e0b16f44d.file new file mode 100644 index 0000000..eb2f76b --- /dev/null +++ b/.flatpak-builder/cache/objects/52/01573677d56ec43eaab28177afb4bbb06bfe893cd9d59c6ae4247e0b16f44d.file @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2001 Cleber Rodrigues + * Copyright (C) 2001 - 2002 Rodrigo Moya + * Copyright (C) 2002 Gonzalo Paniagua Javier + * Copyright (C) 2005 - 2012 Vivien Malerba + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GDA_DATA_MODEL_ARRAY_H__ +#define __GDA_DATA_MODEL_ARRAY_H__ + +#include +#include + +G_BEGIN_DECLS + +#define GDA_TYPE_DATA_MODEL_ARRAY (gda_data_model_array_get_type()) +G_DECLARE_DERIVABLE_TYPE(GdaDataModelArray, gda_data_model_array, GDA, DATA_MODEL_ARRAY, GObject) +struct _GdaDataModelArrayClass { + GObjectClass parent_class; + + /*< private >*/ + /* Padding for future expansion */ + void (*_gda_reserved1) (void); + void (*_gda_reserved2) (void); + void (*_gda_reserved3) (void); + void (*_gda_reserved4) (void); +}; + +/** + * SECTION:gda-data-model-array + * @short_description: An implementation of #GdaDataModel based on a #GArray + * @title: GdaDataModelArray + * @stability: Stable + * @see_also: #GdaDataModel + * + * The #GdaDataModelArray object is a data model which internally uses a #GArray to index all its rows (represented + * as #GdaRow objects). In this data model, all the data is stored in memory, which can be a memory limitation if the number + * of rows is huge. + * This type of data model is easy to use to store some temporary data, and has a random access mode (any value can be accessed + * at any time without the need for an iterator). + */ + +GdaDataModel *gda_data_model_array_new_with_g_types (gint cols, ...); +GdaDataModel *gda_data_model_array_new_with_g_types_v (gint cols, GType *types); +GdaDataModel *gda_data_model_array_new (gint cols); +GdaDataModelArray *gda_data_model_array_copy_model (GdaDataModel *src, GError **error); +GdaDataModelArray *gda_data_model_array_copy_model_ext (GdaDataModel *src, + gint ncols, gint *cols, GError **error); + +GdaRow *gda_data_model_array_get_row (GdaDataModelArray *model, gint row, GError **error); +void gda_data_model_array_set_n_columns (GdaDataModelArray *model, gint cols); +void gda_data_model_array_clear (GdaDataModelArray *model); + +G_END_DECLS + +#endif diff --git a/.flatpak-builder/cache/objects/52/1e625555efcc126738b6d7493be914301a1d9d1a07d12ada56ebb03dbda926.file b/.flatpak-builder/cache/objects/52/1e625555efcc126738b6d7493be914301a1d9d1a07d12ada56ebb03dbda926.file new file mode 100644 index 0000000..1b89fdd --- /dev/null +++ b/.flatpak-builder/cache/objects/52/1e625555efcc126738b6d7493be914301a1d9d1a07d12ada56ebb03dbda926.file @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2008 - 2012 Vivien Malerba + * Copyright (C) 2009 Murray Cumming + * Copyright (C) 2011 Daniel Espinosa + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef _GDA_STATEMENT_STRUCT_COMPOUND_H_ +#define _GDA_STATEMENT_STRUCT_COMPOUND_H_ + +#include +#include +#include +#include + +G_BEGIN_DECLS + +/* + * Kinds + */ +/** + * GdaSqlStatementCompoundType: + * @GDA_SQL_STATEMENT_COMPOUND_UNION: + * @GDA_SQL_STATEMENT_COMPOUND_UNION_ALL: + * @GDA_SQL_STATEMENT_COMPOUND_INTERSECT: + * @GDA_SQL_STATEMENT_COMPOUND_INTERSECT_ALL: + * @GDA_SQL_STATEMENT_COMPOUND_EXCEPT: + * @GDA_SQL_STATEMENT_COMPOUND_EXCEPT_ALL: + */ +typedef enum { + GDA_SQL_STATEMENT_COMPOUND_UNION, + GDA_SQL_STATEMENT_COMPOUND_UNION_ALL, + GDA_SQL_STATEMENT_COMPOUND_INTERSECT, + GDA_SQL_STATEMENT_COMPOUND_INTERSECT_ALL, + GDA_SQL_STATEMENT_COMPOUND_EXCEPT, + GDA_SQL_STATEMENT_COMPOUND_EXCEPT_ALL +} GdaSqlStatementCompoundType; + +/* + * Structure definition + */ +/** + * GdaSqlStatementCompound: + * @any: + * @compound_type: + * @stmt_list: + */ +struct _GdaSqlStatementCompound { + GdaSqlAnyPart any; + GdaSqlStatementCompoundType compound_type; + GSList *stmt_list; /* list of SELECT or COMPOUND statements */ + + /*< private >*/ + /* Padding for future expansion */ + gpointer _gda_reserved1; + gpointer _gda_reserved2; +}; + +/* + * Common operations + */ +gpointer _gda_sql_statement_compound_copy (gpointer src); +void _gda_sql_statement_compound_free (gpointer stmt); +gchar *_gda_sql_statement_compound_serialize (gpointer stmt); +GdaSqlStatementContentsInfo *_gda_sql_statement_compound_get_infos (void); + +/* + * compound specific operations + */ +gint _gda_sql_statement_compound_get_n_cols (GdaSqlStatementCompound *compound, GError **error); +GdaSqlAnyPart * _gda_sql_statement_compound_reduce (GdaSqlAnyPart *compound_or_select); + +/* + * Functions used by the parser + */ +void gda_sql_statement_compound_set_type (GdaSqlStatement *stmt, GdaSqlStatementCompoundType type); +void gda_sql_statement_compound_take_stmt (GdaSqlStatement *stmt, GdaSqlStatement *s); + +G_END_DECLS + +#endif diff --git a/.flatpak-builder/cache/objects/52/5ab9bcfaca65f75c7d58dede754178496c2efa026bac44be1c39a62e392c75.commit b/.flatpak-builder/cache/objects/52/5ab9bcfaca65f75c7d58dede754178496c2efa026bac44be1c39a62e392c75.commit new file mode 100644 index 0000000..b29ebbb Binary files /dev/null and b/.flatpak-builder/cache/objects/52/5ab9bcfaca65f75c7d58dede754178496c2efa026bac44be1c39a62e392c75.commit differ diff --git a/.flatpak-builder/cache/objects/52/5f5d1d43447474e1067cc0f210c6c4a71475b59e48a66680670bf6aa58addd.file b/.flatpak-builder/cache/objects/52/5f5d1d43447474e1067cc0f210c6c4a71475b59e48a66680670bf6aa58addd.file new file mode 100644 index 0000000..8155605 --- /dev/null +++ b/.flatpak-builder/cache/objects/52/5f5d1d43447474e1067cc0f210c6c4a71475b59e48a66680670bf6aa58addd.file @@ -0,0 +1,6 @@ +[Sound Theme] +Name=Default +Directories=stereo + +[stereo] +OutputProfile=stereo diff --git a/.flatpak-builder/cache/objects/52/63ae876e11fe680f62b458ddb395813826b43615c181640927c6976a53a1d0.file b/.flatpak-builder/cache/objects/52/63ae876e11fe680f62b458ddb395813826b43615c181640927c6976a53a1d0.file new file mode 100644 index 0000000..e96c3a1 Binary files /dev/null and b/.flatpak-builder/cache/objects/52/63ae876e11fe680f62b458ddb395813826b43615c181640927c6976a53a1d0.file differ diff --git a/.flatpak-builder/cache/objects/52/ccb0068dd8da111ac64547635855b17bd7e197d0412e97ac50df6fec1d118c.dirtree b/.flatpak-builder/cache/objects/52/ccb0068dd8da111ac64547635855b17bd7e197d0412e97ac50df6fec1d118c.dirtree new file mode 100644 index 0000000..24262d7 Binary files /dev/null and b/.flatpak-builder/cache/objects/52/ccb0068dd8da111ac64547635855b17bd7e197d0412e97ac50df6fec1d118c.dirtree differ diff --git a/.flatpak-builder/cache/objects/53/003f038b7ba738438d166242999f9bd446674adb7c9ff4fac6bacba97b4e51.file b/.flatpak-builder/cache/objects/53/003f038b7ba738438d166242999f9bd446674adb7c9ff4fac6bacba97b4e51.file new file mode 100644 index 0000000..cceb6c6 --- /dev/null +++ b/.flatpak-builder/cache/objects/53/003f038b7ba738438d166242999f9bd446674adb7c9ff4fac6bacba97b4e51.file @@ -0,0 +1,79 @@ +# gtk_layout.py +# +# Copyright 2021 James Westman +# +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation; either version 3 of the +# License, or (at your option) any later version. +# +# This file is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program. If not, see . +# +# SPDX-License-Identifier: LGPL-3.0-or-later + + +from .gobject_object import ObjectContent, validate_parent_type +from .common import * +from .contexts import ValueTypeCtx +from .values import Value + + +class LayoutProperty(AstNode): + grammar = Statement(UseIdent("name"), ":", Err(Value, "Expected a value")) + tag_name = "property" + + @property + def name(self) -> str: + return self.tokens["name"] + + @property + def value(self) -> Value: + return self.children[Value][0] + + @context(ValueTypeCtx) + def value_type(self) -> ValueTypeCtx: + # there isn't really a way to validate these + return ValueTypeCtx(None) + + @validate("name") + def unique_in_parent(self): + self.validate_unique_in_parent( + f"Duplicate layout property '{self.name}'", + check=lambda child: child.name == self.name, + ) + + +class ExtLayout(AstNode): + grammar = Sequence( + Keyword("layout"), + "{", + Until(LayoutProperty, "}"), + ) + + @validate("layout") + def container_is_widget(self): + validate_parent_type(self, "Gtk", "Widget", "layout properties") + + @validate("layout") + def unique_in_parent(self): + self.validate_unique_in_parent("Duplicate layout block") + + +@completer( + applies_in=[ObjectContent], + applies_in_subclass=("Gtk", "Widget"), + matches=new_statement_patterns, +) +def layout_completer(ast_node, match_variables): + yield Completion("layout", CompletionItemKind.Snippet, snippet="layout {\n $0\n}") + + +@decompiler("layout") +def decompile_layout(ctx, gir): + ctx.print("layout {") diff --git a/.flatpak-builder/cache/objects/53/43f64efb5e777f07fff48818de14341ba887de586fa0eddcc81e37f6be0a08.dirtree b/.flatpak-builder/cache/objects/53/43f64efb5e777f07fff48818de14341ba887de586fa0eddcc81e37f6be0a08.dirtree new file mode 100644 index 0000000..3630a84 Binary files /dev/null and b/.flatpak-builder/cache/objects/53/43f64efb5e777f07fff48818de14341ba887de586fa0eddcc81e37f6be0a08.dirtree differ diff --git a/.flatpak-builder/cache/objects/53/6f843bab718bc875f73d08c420db9087f9177981ac47b6c1fe7e18270a0dcd.dirtree b/.flatpak-builder/cache/objects/53/6f843bab718bc875f73d08c420db9087f9177981ac47b6c1fe7e18270a0dcd.dirtree new file mode 100644 index 0000000..5aeda2e Binary files /dev/null and b/.flatpak-builder/cache/objects/53/6f843bab718bc875f73d08c420db9087f9177981ac47b6c1fe7e18270a0dcd.dirtree differ diff --git a/.flatpak-builder/cache/objects/53/ed0210722202239c38257089f833499217367d69b749e16f0b804922fe4826.file b/.flatpak-builder/cache/objects/53/ed0210722202239c38257089f833499217367d69b749e16f0b804922fe4826.file new file mode 100644 index 0000000..99a94df --- /dev/null +++ b/.flatpak-builder/cache/objects/53/ed0210722202239c38257089f833499217367d69b749e16f0b804922fe4826.file @@ -0,0 +1,2477 @@ +/* + * Copyright (C) 2008 - 2011 Murray Cumming + * Copyright (C) 2008 - 2014 Vivien Malerba + * Copyright (C) 2009 Bas Driessen + * Copyright (C) 2010 David King + * Copyright (C) 2013 Daniel Espinosa + * Copyright (C) 2015 Corentin Noël + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +#define G_LOG_DOMAIN "GDA-set" + +#include +#include +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#include +#ifdef HAVE_LOCALE_H +#include +#endif +#include "gda-set.h" +#include "gda-marshal.h" +#include "gda-data-model.h" +#include "gda-data-model-import.h" +#include "gda-holder.h" +#include "gda-connection.h" +#include "gda-server-provider.h" +#include "gda-util.h" +#include +#include + +/** + * GdaSetGroup: + * @nodes: (element-type Gda.SetNode): list of GdaSetNode, at least one entry + * @nodes_source: (nullable): if NULL, then @nodes contains exactly one entry + * + * Since 5.2, you must consider this struct as opaque. Any access to its internal must use public API. + * Don't try to use #gda_set_group_free on a struct that was created manually. + */ +struct _GdaSetGroup { + GSList *nodes; /* list of GdaSetNode, at least one entry */ + GdaSetSource *nodes_source; /* if NULL, then @nodes contains exactly one entry */ + + /*< private >*/ + /* Padding for future expansion */ + gpointer _gda_reserved1; + gpointer _gda_reserved2; +}; +/* + Register GdaSetGroup type +*/ +GType +gda_set_group_get_type (void) +{ + static GType type = 0; + + if (G_UNLIKELY (type == 0)) { + if (type == 0) + type = g_boxed_type_register_static ("GdaSetGroup", + (GBoxedCopyFunc) gda_set_group_copy, + (GBoxedFreeFunc) gda_set_group_free); + } + + return type; +} + +/** + * gda_set_group_new: + * @node: a #GdaSetNode struct + * + * Creates a new #GdaSetGroup struct. If @source is %NULL then new group contains + * just one #GdaSetNode. + * + * Return: (transfer full): a new #GdaSetGroup struct. + * + * Since: 5.2 + */ +GdaSetGroup* +gda_set_group_new (GdaSetNode *node) +{ + GdaSetGroup *sg; + + g_return_val_if_fail (node, NULL); + + sg = g_new0 (GdaSetGroup, 1); + sg->nodes_source = NULL; + sg->nodes = NULL; + sg->nodes = g_slist_append (sg->nodes, node); + return sg; +} + +/** + * gda_set_group_copy: + * @sg: a #GdaSetGroup + * + * Copy constructor. + * + * Returns: a new #GdaSetGroup + * + * Since: 5.2 + */ +GdaSetGroup * +gda_set_group_copy (GdaSetGroup *sg) +{ + g_return_val_if_fail (sg, NULL); + + GdaSetGroup *n; + n = g_new0 (GdaSetGroup, 1); + n->nodes_source = sg->nodes_source; + n->nodes = g_slist_copy (sg->nodes); + return n; +} + +/** + * gda_set_group_free: + * @sg: (nullable): a #GdaSetGroup struct to free + * + * Frees any resources taken by @sg struct. If @sg is %NULL, then nothing happens. + * + * Since: 5.2 + */ +void +gda_set_group_free (GdaSetGroup *sg) +{ + g_return_if_fail(sg); + g_slist_free (sg->nodes); + g_free (sg); +} + +/** + * gda_set_group_set_source: + * @sg: a #GdaSetGroup + * @source: a #GdaSetSource to set + * + * Since: 5.2 + */ +void +gda_set_group_set_source (GdaSetGroup *sg, GdaSetSource *source) +{ + g_return_if_fail (sg); + sg->nodes_source = source; +} + +/** + * gda_set_group_get_source: + * @sg: a #GdaSetGroup + * + * Returns: a #GdaSetSource. If %NULL then @sg contains just one element. + * + * Since: 5.2 + */ +GdaSetSource* +gda_set_group_get_source (GdaSetGroup *sg) +{ + g_return_val_if_fail (sg, NULL); + return sg->nodes_source; +} + +/** + * gda_set_group_add_node: + * @sg: a #GdaSetGroup + * @node: a #GdaSetNode to set + * + * Since: 5.2 + */ +void +gda_set_group_add_node (GdaSetGroup *sg, GdaSetNode *node) +{ + g_return_if_fail (sg); + g_return_if_fail (node); + sg->nodes = g_slist_append (sg->nodes, node); +} + +/** + * gda_set_group_get_node: + * @sg: a #GdaSetGroup + * + * This method always return first #GdaSetNode in @sg. + * + * Returns: first #GdaSetNode in @sg. + * + * Since: 5.2 + */ +GdaSetNode* +gda_set_group_get_node (GdaSetGroup *sg) +{ + g_return_val_if_fail (sg, NULL); + g_return_val_if_fail (sg->nodes, NULL); + return GDA_SET_NODE (sg->nodes->data); +} + +/** + * gda_set_group_get_nodes: + * @sg: a #GdaSetGroup + * + * Returns a #GSList with the #GdaSetNode grouped by @sg. You must use + * #g_slist_free on returned list. + * + * Returns: (transfer none) (element-type Gda.SetNode): a #GSList with all nodes in @sg. + * + * Since: 5.2 + */ +GSList* +gda_set_group_get_nodes (GdaSetGroup *sg) +{ + g_return_val_if_fail (sg, NULL); + g_return_val_if_fail (sg->nodes, NULL); + return sg->nodes; +} + +/** + * gda_set_group_get_n_nodes: + * @sg: a #GdaSetGroup + * + * Returns: number of nodes in @sg. + * + * Since: 5.2 + */ +gint +gda_set_group_get_n_nodes (GdaSetGroup *sg) +{ + g_return_val_if_fail (sg, -1); + return g_slist_length (sg->nodes); +} + +/** + * GdaSetSource: + * @data_model: Can't be NULL + * @nodes: (element-type Gda.SetNode): list of #GdaSetNode for which source_model == @data_model + * + * Since 5.2, you must consider this struct as opaque. Any access to its internal must use public API. + * Don't try to use #gda_set_source_free on a struct that was created manually. + **/ +struct _GdaSetSource { + GdaDataModel *data_model; /* Can't be NULL */ + GSList *nodes; /* list of #GdaSetNode for which source_model == @data_model */ + + /*< private >*/ + /* Padding for future expansion */ + gpointer _gda_reserved1; + gpointer _gda_reserved2; + gpointer _gda_reserved3; + gpointer _gda_reserved4; +}; + +/* + Register GdaSetSource type +*/ +GType +gda_set_source_get_type (void) +{ + static GType type = 0; + + if (G_UNLIKELY (type == 0)) { + if (type == 0) + type = g_boxed_type_register_static ("GdaSetSource", + (GBoxedCopyFunc) gda_set_source_copy, + (GBoxedFreeFunc) gda_set_source_free); + } + + return type; +} + +/** + * gda_set_source_new: + * @model: a #GdaDataModel + * + * Creates a new #GdaSetSource struct. + * + * Return: (transfer full): a new #GdaSetSource struct. + * + * Since: 5.2 + */ +GdaSetSource* +gda_set_source_new (GdaDataModel *model) +{ + g_return_val_if_fail (model != NULL && GDA_IS_DATA_MODEL (model), NULL); + GdaSetSource *s = g_new0 (GdaSetSource, 1); + s->nodes = NULL; + s->data_model = g_object_ref (model); + + return s; +} + +/** + * gda_set_source_copy: + * @s: a #GdaSetGroup + * + * Copy constructor. + * + * Returns: a new #GdaSetSource + * + * Since: 5.2 + */ +GdaSetSource * +gda_set_source_copy (GdaSetSource *s) +{ + GdaSetSource *n; + g_return_val_if_fail (s, NULL); + n = gda_set_source_new (gda_set_source_get_data_model (s)); + n->nodes = g_slist_copy (s->nodes); + return n; +} + +/** + * gda_set_source_free: + * @s: (nullable): a #GdaSetSource struct to free + * + * Frees any resources taken by @s struct. If @s is %NULL, then nothing happens. + * + * Since: 5.2 + */ +void +gda_set_source_free (GdaSetSource *s) +{ + g_return_if_fail(s); + g_object_unref (s->data_model); + g_slist_free (s->nodes); /* FIXME: A source must own its nodes, then they must be freed here + this leaves to others responsability free nodes BEFORE + to free this source */ + g_free (s); +} + +/** + * gda_set_source_get_data_model: + * @s: a #GdaSetSource + * + * Returns: (transfer none): a #GdaDataModel used by @s + * + * Since: 5.2 + */ +GdaDataModel* +gda_set_source_get_data_model (GdaSetSource *s) +{ + g_return_val_if_fail (s, NULL); + return s->data_model; +} + +/** + * gda_set_source_set_data_model: + * @s: a #GdaSetSource struct to free + * @model: a #GdaDataModel + * + * Set a #GdaDataModel + * + * Since: 5.2 + */ +void +gda_set_source_set_data_model (GdaSetSource *s, GdaDataModel *model) +{ + g_return_if_fail (s); + g_return_if_fail (GDA_IS_DATA_MODEL (model)); + s->data_model = g_object_ref (model); +} + +/** + * gda_set_source_add_node: + * @s: a #GdaSetSource + * @node: a #GdaSetNode to add + * + * Set a #GdaDataModel + * + * Since: 5.2 + */ +void +gda_set_source_add_node (GdaSetSource *s, GdaSetNode *node) +{ + g_return_if_fail (s); + g_return_if_fail (node); + s->nodes = g_slist_append (s->nodes, node); +} + +/** + * gda_set_source_get_nodes: + * @s: a #GdaSetSource + * + * Returns: (transfer none) (element-type Gda.SetNode): a list of #GdaSetNode structs + * + * Since: 5.2 + */ +GSList* +gda_set_source_get_nodes (GdaSetSource *s) +{ + g_return_val_if_fail (s, NULL); + g_return_val_if_fail (s->nodes, NULL); + return s->nodes; +} + +/** + * gda_set_source_get_n_nodes: + * @s: a #GdaSetSource + * + * Returns: number of nodes in @sg. + * + * Since: 5.2 + */ +gint +gda_set_source_get_n_nodes (GdaSetSource *s) +{ + g_return_val_if_fail (s, -1); + return g_slist_length (s->nodes); +} +/** + * GdaSetNode: + * @holder: a #GdaHolder. It can't be NULL + * @source_model: a #GdaDataModel. It could be NULL + * @source_column: a #gint with the number of column in @source_model + * + * Since 5.2, you must consider this struct as opaque. Any access to its internal must use public API. + * Don't try to use #gda_set_node_free on a struct that was created manually. + */ +struct _GdaSetNode { + GdaHolder *holder; /* Can't be NULL */ + GdaDataModel *source_model; /* may be NULL */ + gint source_column; /* unused if @source_model is NULL */ + + /*< private >*/ + /* Padding for future expansion */ + gpointer _gda_reserved1; + gpointer _gda_reserved2; +}; +/* + Register GdaSetNode type +*/ +GType +gda_set_node_get_type (void) +{ + static GType type = 0; + + if (G_UNLIKELY (type == 0)) { + if (type == 0) + type = g_boxed_type_register_static ("GdaSetNode", + (GBoxedCopyFunc) gda_set_node_copy, + (GBoxedFreeFunc) gda_set_node_free); + } + + return type; +} + +/** + * gda_set_node_new: + * @holder: a #GdaHolder to used by new #GdaSetNode + * + * Creates a new #GdaSetNode struct. + * + * Return: (transfer full): a new #GdaSetNode struct. + * + * Since: 5.2 + */ +GdaSetNode* +gda_set_node_new (GdaHolder *holder) +{ + g_return_val_if_fail (GDA_IS_HOLDER (holder), NULL); + GdaSetNode *n = g_new0 (GdaSetNode, 1); + n->holder = holder; + n->source_model = NULL; + return n; +} + +/** + * gda_set_node_copy: + * @node: a #GdaSetNode to copy from + * + * Copy constructor. + * + * Returns: a new #GdaSetNode + * + * Since: 5.2 + */ +GdaSetNode * +gda_set_node_copy (GdaSetNode *node) +{ + g_return_val_if_fail (node, NULL); + + GdaSetNode *n; + n = gda_set_node_new (gda_set_node_get_holder (node)); + gda_set_node_set_source_column (n, gda_set_node_get_source_column (node)); + gda_set_node_set_holder (n, gda_set_node_get_holder (node)); + gda_set_node_set_data_model (n, gda_set_node_get_data_model (node)); + return n; +} + +/** + * gda_set_node_free: + * @node: (nullable): a #GdaSetNode struct to free + * + * Frees any resources taken by @node struct. If @node is %NULL, then nothing happens. + * + * Since: 5.2 + */ +void +gda_set_node_free (GdaSetNode *node) +{ + if (node == NULL) + return; + g_free (node); +} + +/** + * gda_set_node_get_holder: + * @node: a #GdaSetNode struct to get holder from + * + * Returns: (transfer none): the #GdaHolder used by @node + * + * Since: 5.2 + */ +GdaHolder* +gda_set_node_get_holder (GdaSetNode *node) +{ + g_return_val_if_fail (node, NULL); + return node->holder; +} + +/** + * gda_set_node_set_holder: + * @node: a #GdaSetNode struct to set holder to + * + * Set a #GdaHolder to @node. + * + * Since: 5.2 + */ +void +gda_set_node_set_holder (GdaSetNode *node, GdaHolder *holder) +{ + g_return_if_fail (node); + g_return_if_fail (GDA_IS_HOLDER (holder)); + node->holder = holder; +} + +/** + * gda_set_node_get_data_model: + * @node: a #GdaSetNode struct to get holder from + * + * Returns: (transfer none): the #GdaDataModel used by @node + * + * Since: 5.2 + */ +GdaDataModel* +gda_set_node_get_data_model (GdaSetNode *node) +{ + g_return_val_if_fail (node, NULL); + return node->source_model; +} + +/** + * gda_set_node_set_data_model: + * @node: a #GdaSetNode struct to set data model to + * @model: (nullable): a #GdaDataModel to be used by @node + * + * Set a #GdaDataModel to be used by @node. @model increment its reference + * counting when set. Internally referenced column number is set to first column + * in @model. + * + * Since: 5.2 + */ +void +gda_set_node_set_data_model (GdaSetNode *node, GdaDataModel *model) +{ + g_return_if_fail (node); + if (GDA_IS_DATA_MODEL (model)) { + node->source_model = model; + node->source_column = 0; + } + else { + node->source_model = NULL; + node->source_column = -1; + } +} + +/** + * gda_set_node_get_source_column: + * @node: a #GdaSetNode struct to get column source from + * + * Returns: the number of column referenced in a given #GdaDataModel. If negative + * no column is referenced or no #GdaDataModel is used by @node. + * + * Since: 5.2 + */ +gint +gda_set_node_get_source_column (GdaSetNode *node) +{ + g_return_val_if_fail (node, -1); + return node->source_column; +} + +/** + * gda_set_node_set_source_column: + * @node: a #GdaSetNode struct to set column source to, from an used data model + * + * Set column number in the #GdaDataModel used @node. If no #GdaDataModel is set + * then column is set to invalid (-1); + * + * Since: 5.2 + */ +void +gda_set_node_set_source_column (GdaSetNode *node, gint column) +{ + g_return_if_fail (column >= 0); + if (GDA_IS_DATA_MODEL (node->source_model)) { + if (column < gda_data_model_get_n_columns (node->source_model)) + node->source_column = column; + } +} + +/* + * Main static functions + */ + +/* private structure */ +typedef struct +{ + gchar *id; + gchar *name; + gchar *descr; + GHashTable *holders_hash; /* key = GdaHoler ID, value = GdaHolder */ + GPtrArray *holders_array; + gboolean read_only; + gboolean validate_changes; + + GSList *holders; /* list of GdaHolder objects */ + GSList *nodes_list; /* list of GdaSetNode */ + GSList *sources_list; /* list of GdaSetSource */ + GSList *groups_list; /* list of GdaSetGroup */ +} GdaSetPrivate; + + +G_DEFINE_TYPE_WITH_PRIVATE(GdaSet, gda_set, G_TYPE_OBJECT) + +static void gda_set_dispose (GObject *object); +static void gda_set_finalize (GObject *object); + +static void set_remove_node (GdaSet *set, GdaSetNode *node); +static void set_remove_source (GdaSet *set, GdaSetSource *source); + +static void holder_to_default_cb (GdaHolder *holder, GdaSet *dataset); +static void changed_holder_cb (GdaHolder *holder, GdaSet *dataset); +static GError *validate_change_holder_cb (GdaHolder *holder, const GValue *value, GdaSet *dataset); +static void source_changed_holder_cb (GdaHolder *holder, GdaSet *dataset); +static void holder_notify_cb (GdaHolder *holder, GParamSpec *pspec, GdaSet *dataset); + + +static void compute_public_data (GdaSet *set); +static gboolean gda_set_real_add_holder (GdaSet *set, GdaHolder *holder); + +/* properties */ +enum +{ + PROP_0, + PROP_ID, + PROP_NAME, + PROP_DESCR, + PROP_HOLDERS, + PROP_VALIDATE_CHANGES +}; + +/* signals */ +enum +{ + HOLDER_CHANGED, + PUBLIC_DATA_CHANGED, + HOLDER_ATTR_CHANGED, + VALIDATE_HOLDER_CHANGE, + VALIDATE_SET, + HOLDER_TYPE_SET, + SOURCE_MODEL_CHANGED, + LAST_SIGNAL +}; + +static gint gda_set_signals[LAST_SIGNAL] = { 0, 0, 0, 0, 0, 0 }; + +static void +gda_set_set_property (GObject *object, + guint param_id, + const GValue *value, + GParamSpec *pspec) +{ + GdaSet* set; + set = GDA_SET (object); + GdaSetPrivate *priv = gda_set_get_instance_private (set); + + switch (param_id) { + case PROP_ID: + if (priv->id != NULL) { + g_free (priv->id); + } + priv->id = g_value_dup_string (value); + break; + case PROP_NAME: + if (priv->name != NULL) { + g_free (priv->name); + } + priv->name = g_value_dup_string (value); + break; + case PROP_DESCR: + if (priv->descr) { + g_free (priv->descr); + } + priv->descr = g_value_dup_string (value); + break; + case PROP_HOLDERS: { + /* add the holders */ + GSList* holders; + for (holders = (GSList*) g_value_get_pointer (value); holders; holders = holders->next) + gda_set_real_add_holder (set, GDA_HOLDER (holders->data)); + compute_public_data (set); + break; + } + case PROP_VALIDATE_CHANGES: + if (priv->validate_changes != g_value_get_boolean (value)) { + GSList *list; + priv->validate_changes = g_value_get_boolean (value); + for (list = priv->holders; list; list = list->next) { + GdaHolder *holder = (GdaHolder*) list->data; + g_object_set ((GObject*) holder, "validate-changes", + priv->validate_changes, NULL); + if (priv->validate_changes) + g_signal_connect ((GObject*) holder, "validate-change", + G_CALLBACK (validate_change_holder_cb), set); + else + g_signal_handlers_disconnect_by_func ((GObject*) holder, + G_CALLBACK (validate_change_holder_cb), + set); + } + } + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + break; + } +} + +static void +gda_set_get_property (GObject *object, + guint param_id, + GValue *value, + GParamSpec *pspec) +{ + GdaSet* set; + set = GDA_SET (object); + GdaSetPrivate *priv = gda_set_get_instance_private (set); + + switch (param_id) { + case PROP_ID: + g_value_set_string (value, priv->id); + break; + case PROP_NAME: + if (priv->name) + g_value_set_string (value, priv->name); + else + g_value_set_string (value, priv->id); + break; + case PROP_DESCR: + g_value_set_string (value, priv->descr); + break; + case PROP_VALIDATE_CHANGES: + g_value_set_boolean (value, priv->validate_changes); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + break; + } +} + +/* module error */ +GQuark gda_set_error_quark (void) +{ + static GQuark quark; + if (!quark) + quark = g_quark_from_static_string ("gda_set_error"); + return quark; +} + +static gboolean +validate_accumulator (G_GNUC_UNUSED GSignalInvocationHint *ihint, + GValue *return_accu, + const GValue *handler_return, + G_GNUC_UNUSED gpointer data) +{ + GError *error; + + error = g_value_get_boxed (handler_return); + g_value_set_boxed (return_accu, error); + + return error ? FALSE : TRUE; /* stop signal if an error has been set */ +} + +static GError * +m_validate_holder_change (G_GNUC_UNUSED GdaSet *set, G_GNUC_UNUSED GdaHolder *holder, + G_GNUC_UNUSED const GValue *new_value) +{ + return NULL; +} + +static GError* +m_validate_set (G_GNUC_UNUSED GdaSet *set) +{ + return NULL; +} + +static void +gda_set_class_init (GdaSetClass *class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (class); + + gda_set_parent_class = g_type_class_peek_parent (class); + + gda_set_signals[HOLDER_CHANGED] = + g_signal_new ("holder-changed", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (GdaSetClass, holder_changed), + NULL, NULL, + _gda_marshal_VOID__OBJECT, G_TYPE_NONE, 1, + GDA_TYPE_HOLDER); + + /** + * GdaSet::validate-holder-change: + * @set: the #GdaSet + * @holder: the #GdaHolder which is going to change + * @new_value: the proposed new value for @holder + * + * Gets emitted when a #GdaHolder's in @set is going to change its value. One can connect to + * this signal to control which values @holder can have (for example to implement some business rules) + * + * Returns: NULL if @holder is allowed to change its value to @new_value, or a #GError + * otherwise. + */ + gda_set_signals[VALIDATE_HOLDER_CHANGE] = + g_signal_new ("validate-holder-change", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GdaSetClass, validate_holder_change), + validate_accumulator, NULL, + _gda_marshal_ERROR__OBJECT_VALUE, G_TYPE_ERROR, 2, + GDA_TYPE_HOLDER, G_TYPE_VALUE); + /** + * GdaSet::validate-set: + * @set: the #GdaSet + * + * Gets emitted when gda_set_is_valid() is called, use + * this signal to control which combination of values @set's holder can have (for example to implement some business rules) + * + * Returns: NULL if @set's contents has been validated, or a #GError + * otherwise. + */ + gda_set_signals[VALIDATE_SET] = + g_signal_new ("validate-set", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GdaSetClass, validate_set), + validate_accumulator, NULL, + _gda_marshal_ERROR__VOID, G_TYPE_ERROR, 0); + /** + * GdaSet::holder-attr-changed: + * @set: the #GdaSet + * @holder: the GdaHolder for which an attribute changed + * @attr_name: attribute's name + * @attr_value: attribute's value + * + * Gets emitted when an attribute for any of the #GdaHolder objects managed by @set has changed + */ + gda_set_signals[HOLDER_ATTR_CHANGED] = + g_signal_new ("holder-attr-changed", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (GdaSetClass, holder_attr_changed), + NULL, NULL, + _gda_marshal_VOID__OBJECT_STRING_VALUE, G_TYPE_NONE, 3, + GDA_TYPE_HOLDER, G_TYPE_STRING, G_TYPE_VALUE); + /** + * GdaSet::public-data-changed: + * @set: the #GdaSet + * + * Gets emitted when @set's public data (#GdaSetNode, #GdaSetGroup or #GdaSetSource values) have changed + */ + gda_set_signals[PUBLIC_DATA_CHANGED] = + g_signal_new ("public-data-changed", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (GdaSetClass, public_data_changed), + NULL, NULL, + _gda_marshal_VOID__VOID, G_TYPE_NONE, 0); + + /** + * GdaSet::holder-type-set: + * @set: the #GdaSet + * @holder: the #GdaHolder for which the #GType has been set + * + * Gets emitted when @holder in @set has its type finally set, in case + * it was #GDA_TYPE_NULL + * + * Since: 4.2 + */ + gda_set_signals[HOLDER_TYPE_SET] = + g_signal_new ("holder-type-set", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (GdaSetClass, holder_type_set), + NULL, NULL, + _gda_marshal_VOID__OBJECT, G_TYPE_NONE, 1, + GDA_TYPE_HOLDER); + + /** + * GdaSet::source-model-changed: + * @set: the #GdaSet + * @source: the #GdaSetSource for which the @data_model attribute has changed + * + * Gets emitted when the data model in @source has changed + * + * Since: 4.2 + */ + gda_set_signals[SOURCE_MODEL_CHANGED] = + g_signal_new ("source-model-changed", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (GdaSetClass, source_model_changed), + NULL, NULL, + _gda_marshal_VOID__POINTER, G_TYPE_NONE, 1, + G_TYPE_POINTER); + + + class->holder_changed = NULL; + class->validate_holder_change = m_validate_holder_change; + class->validate_set = m_validate_set; + class->holder_attr_changed = NULL; + class->public_data_changed = NULL; + class->holder_type_set = NULL; + class->source_model_changed = NULL; + + /* Properties */ + object_class->set_property = gda_set_set_property; + object_class->get_property = gda_set_get_property; + g_object_class_install_property (object_class, PROP_ID, + g_param_spec_string ("id", NULL, "Id", NULL, + (G_PARAM_READABLE | G_PARAM_WRITABLE))); + g_object_class_install_property (object_class, PROP_NAME, + g_param_spec_string ("name", NULL, "Name", NULL, + (G_PARAM_READABLE | G_PARAM_WRITABLE))); + g_object_class_install_property (object_class, PROP_DESCR, + g_param_spec_string ("description", NULL, "Description", NULL, + (G_PARAM_READABLE | G_PARAM_WRITABLE))); + g_object_class_install_property (object_class, PROP_HOLDERS, + g_param_spec_pointer ("holders", "GSList of GdaHolders", + "GdaHolder objects the set should contain", ( + G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY))); + /** + * GdaSet:validate-changes: + * + * Defines if the "validate-set" signal gets emitted when + * any holder in the data set changes. This property also affects the + * GdaHolder:validate-changes property. + * + * Since: 5.2.0 + */ + g_object_class_install_property (object_class, PROP_VALIDATE_CHANGES, + g_param_spec_boolean ("validate-changes", NULL, "Defines if the validate-set signal is emitted", TRUE, + (G_PARAM_READABLE | G_PARAM_WRITABLE))); + object_class->dispose = gda_set_dispose; + object_class->finalize = gda_set_finalize; +} + +static void +gda_set_init (GdaSet *set) +{ + GdaSetPrivate *priv = gda_set_get_instance_private (set); + priv->holders = NULL; + priv->nodes_list = NULL; + priv->sources_list = NULL; + priv->groups_list = NULL; + priv->holders_hash = g_hash_table_new (g_str_hash, g_str_equal); + priv->holders_array = NULL; + priv->read_only = FALSE; + priv->validate_changes = TRUE; +} + + +/** + * gda_set_new: + * @holders: (element-type Gda.Holder) (transfer none): a list of #GdaHolder objects + * + * Creates a new #GdaSet object, and populates it with the list given as argument. + * The list can then be freed as it is copied. All the value holders in @holders are referenced counted + * and modified, so they should not be used anymore afterwards. + * + * Returns: a new #GdaSet object + */ +GdaSet * +gda_set_new (GSList *holders) +{ + GObject *obj; + + obj = g_object_new (GDA_TYPE_SET, NULL); + for (; holders; holders = holders->next) + gda_set_real_add_holder ((GdaSet*) obj, GDA_HOLDER (holders->data)); + compute_public_data ((GdaSet*) obj); + + return (GdaSet*) obj; +} + +/** + * gda_set_new_read_only: + * @holders: (element-type Gda.Holder) (transfer none): a list of #GdaHolder objects + * + * Creates a new #GdaSet like gda_set_new(), but does not allow modifications to any of the #GdaHolder + * object in @holders. This function is used for Libgda's database providers' implementation. + * + * Returns: a new #GdaSet object + * + * Since: 4.2 + */ +GdaSet * +gda_set_new_read_only (GSList *holders) +{ + GObject *obj; + + obj = g_object_new (GDA_TYPE_SET, NULL); + + GdaSetPrivate *priv = gda_set_get_instance_private (GDA_SET(obj)); + + priv->read_only = TRUE; + for (; holders; holders = holders->next) + gda_set_real_add_holder ((GdaSet*) obj, GDA_HOLDER (holders->data)); + compute_public_data ((GdaSet*) obj); + + return (GdaSet*) obj; +} + +/** + * gda_set_copy: + * @set: a #GdaSet object + * + * Creates a new #GdaSet object, copy of @set + * + * Returns: (transfer full): a new #GdaSet object + */ +GdaSet * +gda_set_copy (GdaSet *set) +{ + GdaSet *copy; + GSList *list, *holders = NULL; + g_return_val_if_fail (GDA_IS_SET (set), NULL); + GdaSetPrivate *priv = gda_set_get_instance_private (set); + + for (list = priv->holders; list; list = list->next) + holders = g_slist_prepend (holders, gda_holder_copy (GDA_HOLDER (list->data))); + holders = g_slist_reverse (holders); + + copy = g_object_new (GDA_TYPE_SET, "holders", holders, NULL); + g_slist_free_full (holders, (GDestroyNotify) g_object_unref); + + return copy; +} + +/** + * gda_set_new_inline: + * @nb: the number of value holders which will be contained in the new #GdaSet + * @...: a serie of a (const gchar*) id, (GType) type, and value + * + * Creates a new #GdaSet containing holders defined by each triplet in ... + * For each triplet (id, Glib type and value), + * the value must be of the correct type (gchar * if type is G_STRING, ...) + * + * Note that this function is a utility function and that only a limited set of types are supported. Trying + * to use an unsupported type will result in a warning, and the returned value holder holding a safe default + * value. + * + * Returns: (transfer full): a new #GdaSet object + */ +GdaSet * +gda_set_new_inline (gint nb, ...) +{ + GdaSet *set = NULL; + GSList *holders = NULL; + va_list ap; + gchar *id; + gint i; + gboolean allok = TRUE; + + /* build the list of holders */ + va_start (ap, nb); + for (i = 0; i < nb; i++) { + GType type; + GdaHolder *holder; + GValue *value; + GError *lerror = NULL; + + id = va_arg (ap, char *); + type = va_arg (ap, GType); + holder = gda_holder_new (type, id); + + value = gda_value_new (type); + if (g_type_is_a (type, G_TYPE_BOOLEAN)) + g_value_set_boolean (value, va_arg (ap, int)); + else if (g_type_is_a (type, G_TYPE_STRING)) + g_value_set_string (value, va_arg (ap, gchar *)); + else if (g_type_is_a (type, G_TYPE_OBJECT)) + g_value_set_object (value, va_arg (ap, gpointer)); + else if (g_type_is_a (type, G_TYPE_INT)) + g_value_set_int (value, va_arg (ap, gint)); + else if (g_type_is_a (type, G_TYPE_UINT)) + g_value_set_uint (value, va_arg (ap, guint)); + else if (g_type_is_a (type, GDA_TYPE_BINARY)) + gda_value_set_binary (value, va_arg (ap, GdaBinary *)); + else if (g_type_is_a (type, G_TYPE_INT64)) + g_value_set_int64 (value, va_arg (ap, gint64)); + else if (g_type_is_a (type, G_TYPE_UINT64)) + g_value_set_uint64 (value, va_arg (ap, guint64)); + else if (g_type_is_a (type, GDA_TYPE_SHORT)) + gda_value_set_short (value, va_arg (ap, int)); + else if (g_type_is_a (type, GDA_TYPE_USHORT)) + gda_value_set_ushort (value, va_arg (ap, guint)); + else if (g_type_is_a (type, G_TYPE_CHAR)) + g_value_set_schar (value, va_arg (ap, gint)); + else if (g_type_is_a (type, G_TYPE_UCHAR)) + g_value_set_uchar (value, va_arg (ap, guint)); + else if (g_type_is_a (type, G_TYPE_FLOAT)) + g_value_set_float (value, va_arg (ap, double)); + else if (g_type_is_a (type, G_TYPE_DOUBLE)) + g_value_set_double (value, va_arg (ap, gdouble)); + else if (g_type_is_a (type, GDA_TYPE_NUMERIC)) + gda_value_set_numeric (value, va_arg (ap, GdaNumeric *)); + else if (g_type_is_a (type, G_TYPE_DATE)) + g_value_set_boxed (value, va_arg (ap, GDate *)); + else if (g_type_is_a (type, G_TYPE_LONG)) + g_value_set_long (value, va_arg (ap, glong)); + else if (g_type_is_a (type, G_TYPE_ULONG)) + g_value_set_ulong (value, va_arg (ap, gulong)); + else if (g_type_is_a (type, G_TYPE_GTYPE)) + g_value_set_gtype (value, va_arg(ap, GType)); + else if (g_type_is_a (type, G_TYPE_DATE_TIME)) + g_value_set_boxed (value, va_arg(ap, GDateTime *)); + else if (g_type_is_a (type, GDA_TYPE_TIME)) + gda_value_set_time (value, va_arg(ap, GdaTime *)); + else { + g_warning (_("%s() does not handle values of type '%s'."), + __FUNCTION__, g_type_name (type)); + g_object_unref (holder); + allok = FALSE; + break; + } + + if (!gda_holder_take_value (holder, value, &lerror)) { + g_warning (_("Unable to set holder's value: %s"), + lerror && lerror->message ? lerror->message : _("No detail")); + if (lerror) + g_error_free (lerror); + g_object_unref (holder); + allok = FALSE; + break; + } + holders = g_slist_append (holders, holder); + } + va_end (ap); + + /* create the set */ + if (allok) + set = gda_set_new (holders); + if (holders) { + g_slist_free_full (holders, (GDestroyNotify) g_object_unref); + } + return set; +} + +/** + * gda_set_set_holder_value: + * @set: a #GdaSet object + * @error: (nullable): a place to store errors, or %NULL + * @holder_id: the ID of the holder to set the value + * @...: value, of the correct type, depending on the requested holder's type (not NULL) + * + * Set the value of the #GdaHolder which ID is @holder_id to a specified value + * + * Returns: %TRUE if no error occurred and the value was set correctly + */ +gboolean +gda_set_set_holder_value (GdaSet *set, GError **error, const gchar *holder_id, ...) +{ + GdaHolder *holder; + va_list ap; + GValue *value; + GType type; + GdaSetPrivate *priv = gda_set_get_instance_private (set); + + g_return_val_if_fail (GDA_IS_SET (set), FALSE); + g_return_val_if_fail (priv, FALSE); + + holder = gda_set_get_holder (set, holder_id); + if (!holder) { + g_set_error (error, GDA_SET_ERROR, GDA_SET_HOLDER_NOT_FOUND_ERROR, + _("GdaHolder with ID '%s' not found in set"), holder_id); + return FALSE; + } + type = gda_holder_get_g_type (holder); + va_start (ap, holder_id); + value = gda_value_new (type); + if (g_type_is_a (type, G_TYPE_BOOLEAN)) + g_value_set_boolean (value, va_arg (ap, int)); + else if (g_type_is_a (type, G_TYPE_STRING)) + g_value_set_string (value, va_arg (ap, gchar *)); + else if (g_type_is_a (type, G_TYPE_OBJECT)) + g_value_set_object (value, va_arg (ap, gpointer)); + else if (g_type_is_a (type, G_TYPE_INT)) + g_value_set_int (value, va_arg (ap, gint)); + else if (g_type_is_a (type, G_TYPE_UINT)) + g_value_set_uint (value, va_arg (ap, guint)); + else if (g_type_is_a (type, GDA_TYPE_BINARY)) + gda_value_set_binary (value, va_arg (ap, GdaBinary *)); + else if (g_type_is_a (type, G_TYPE_INT64)) + g_value_set_int64 (value, va_arg (ap, gint64)); + else if (g_type_is_a (type, G_TYPE_UINT64)) + g_value_set_uint64 (value, va_arg (ap, guint64)); + else if (g_type_is_a (type, GDA_TYPE_SHORT)) + gda_value_set_short (value, va_arg (ap, int)); + else if (g_type_is_a (type, GDA_TYPE_USHORT)) + gda_value_set_ushort (value, va_arg (ap, guint)); + else if (g_type_is_a (type, G_TYPE_CHAR)) + g_value_set_schar (value, va_arg (ap, gint)); + else if (g_type_is_a (type, G_TYPE_UCHAR)) + g_value_set_uchar (value, va_arg (ap, guint)); + else if (g_type_is_a (type, G_TYPE_FLOAT)) + g_value_set_float (value, va_arg (ap, double)); + else if (g_type_is_a (type, G_TYPE_DOUBLE)) + g_value_set_double (value, va_arg (ap, gdouble)); + else if (g_type_is_a (type, GDA_TYPE_NUMERIC)) + gda_value_set_numeric (value, va_arg (ap, GdaNumeric *)); + else if (g_type_is_a (type, G_TYPE_DATE)) + g_value_set_boxed (value, va_arg (ap, GDate *)); + else if (g_type_is_a (type, G_TYPE_DATE_TIME)) + g_value_set_boxed (value, va_arg (ap, GDateTime*)); + else if (g_type_is_a (type, GDA_TYPE_TIME)) + gda_value_set_time (value, va_arg (ap, GdaTime*)); + else if (g_type_is_a (type, G_TYPE_LONG)) + g_value_set_long (value, va_arg (ap, glong)); + else if (g_type_is_a (type, G_TYPE_ULONG)) + g_value_set_ulong (value, va_arg (ap, gulong)); + else if (g_type_is_a (type, G_TYPE_GTYPE)) + g_value_set_gtype (value, va_arg (ap, GType)); + else { + g_set_error (error, GDA_SET_ERROR, GDA_SET_IMPLEMENTATION_ERROR, + _("%s() does not handle values of type '%s'."), + __FUNCTION__, g_type_name (type)); + va_end (ap); + return FALSE; + } + + va_end (ap); + return gda_holder_take_value (holder, value, error); +} + +/** + * gda_set_get_holder_value: + * @set: a #GdaSet object + * @holder_id: the ID of the holder to set the value + * + * Get the value of the #GdaHolder which ID is @holder_id + * + * Returns: (nullable) (transfer none): the requested GValue, or %NULL (see gda_holder_get_value()) + */ +const GValue * +gda_set_get_holder_value (GdaSet *set, const gchar *holder_id) +{ + GdaHolder *holder; + + g_return_val_if_fail (GDA_IS_SET (set), NULL); + + GdaSetPrivate *priv = gda_set_get_instance_private (set); + + g_return_val_if_fail (priv, NULL); + + holder = gda_set_get_holder (set, holder_id); + if (holder) + return gda_holder_get_value (holder); + else + return NULL; +} + +static void +xml_validity_error_func (void *ctx, const char *msg, ...) +{ + va_list args; + gchar *str, *str2, *newerr; + + va_start (args, msg); + str = g_strdup_vprintf (msg, args); + va_end (args); + + str2 = *((gchar **) ctx); + + if (str2) { + newerr = g_strdup_printf ("%s\n%s", str2, str); + g_free (str2); + } + else + newerr = g_strdup (str); + g_free (str); + + *((gchar **) ctx) = newerr; +} + +/** + * gda_set_new_from_spec_string: + * @xml_spec: a string + * @error: (nullable): a place to store the error, or %NULL + * + * Creates a new #GdaSet object from the @xml_spec + * specifications + * + * Returns: (transfer full): a new object, or %NULL if an error occurred + */ +GdaSet * +gda_set_new_from_spec_string (const gchar *xml_spec, GError **error) +{ + xmlDocPtr doc; + xmlNodePtr root; + GdaSet *set; + + /* string parsing */ + doc = xmlParseMemory (xml_spec, strlen (xml_spec)); + if (!doc) + return NULL; + + { + /* doc validation */ + xmlValidCtxtPtr validc; + int xmlcheck; + gchar *err_str = NULL; + xmlDtdPtr old_dtd = NULL; + xmlDtdPtr gda_paramlist_dtd = NULL; + GFile *file; + gchar *path; + + validc = g_new0 (xmlValidCtxt, 1); + validc->userData = &err_str; + validc->error = xml_validity_error_func; + validc->warning = NULL; + + xmlcheck = xmlDoValidityCheckingDefaultValue; + xmlDoValidityCheckingDefaultValue = 1; + + /* replace the DTD with ours */ + /* paramlist DTD */ + path = gda_gbr_get_file_path (GDA_DATA_DIR, LIBGDA_ABI_NAME, "dtd", "libgda-paramlist.dtd", NULL); + file = g_file_new_for_path (path); + if (g_file_query_exists (file, NULL)) { + gda_paramlist_dtd = xmlParseDTD (NULL, (xmlChar*) path); + } + + if (!gda_paramlist_dtd) { + if (g_getenv ("GDA_TOP_SRC_DIR")) { + gchar *ipath; + + ipath = g_build_filename (g_getenv ("GDA_TOP_SRC_DIR"), "libgda", "libgda-paramlist.dtd", NULL); + gda_paramlist_dtd = xmlParseDTD (NULL, (xmlChar*) ipath); + g_free (ipath); + } + if (!gda_paramlist_dtd) + g_message (_("Could not parse '%s': XML data import validation will not be performed (some weird errors may occur)"), + path); + } + g_free (path); + g_object_unref (file); + if (gda_paramlist_dtd != NULL) { + gda_paramlist_dtd->name = xmlStrdup((xmlChar*) "data-set-spec"); + old_dtd = doc->intSubset; + doc->intSubset = gda_paramlist_dtd; + } + +#ifndef G_OS_WIN32 + if (doc->intSubset && !xmlValidateDocument (validc, doc)) { + if (gda_paramlist_dtd) + doc->intSubset = old_dtd; + xmlFreeDoc (doc); + g_free (validc); + + if (err_str) { + g_set_error (error, + GDA_SET_ERROR, + GDA_SET_XML_SPEC_ERROR, + "XML spec. does not conform to DTD:\n%s", err_str); + g_free (err_str); + } + else + g_set_error (error, + GDA_SET_ERROR, + GDA_SET_XML_SPEC_ERROR, + "%s", "XML spec. does not conform to DTD"); + + xmlDoValidityCheckingDefaultValue = xmlcheck; + return NULL; + } +#endif + if (gda_paramlist_dtd != NULL) { + doc->intSubset = old_dtd; + xmlFreeDtd (gda_paramlist_dtd); + gda_paramlist_dtd = NULL; + } + xmlDoValidityCheckingDefaultValue = xmlcheck; + g_free (validc); + } + + /* doc is now non NULL */ + root = xmlDocGetRootElement (doc); + if (strcmp ((gchar*)root->name, "data-set-spec") != 0){ + g_set_error (error, GDA_SET_ERROR, GDA_SET_XML_SPEC_ERROR, + _("Spec's root node != 'data-set-spec': '%s'"), root->name); + return NULL; + } + + /* creating holders */ + root = root->xmlChildrenNode; + while (xmlNodeIsText (root)) + root = root->next; + + set = gda_set_new_from_spec_node (root, error); + xmlFreeDoc(doc); + return set; +} + + +/** + * gda_set_new_from_spec_node: + * @xml_spec: a #xmlNodePtr for a <parameters> tag + * @error: (nullable): a place to store the error, or %NULL + * + * Creates a new #GdaSet object from the @xml_spec + * specifications + * + * Returns: (transfer full): a new object, or %NULL if an error occurred + */ +GdaSet * +gda_set_new_from_spec_node (xmlNodePtr xml_spec, GError **error) +{ + GdaSet *set = NULL; + GSList *holders = NULL, *sources = NULL; + GSList *list; + const gchar *lang = setlocale(LC_ALL, NULL); + + xmlNodePtr cur; + gboolean allok = TRUE; + gchar *str; + + if (strcmp ((gchar*)xml_spec->name, "parameters") != 0){ + g_set_error (error, GDA_SET_ERROR, GDA_SET_XML_SPEC_ERROR, + _("Missing node : '%s'"), xml_spec->name); + return NULL; + } + + /* Holders' sources, not mandatory: makes the @sources list */ + cur = xml_spec->next; + while (cur && (xmlNodeIsText (cur) || strcmp ((gchar*)cur->name, "sources"))) + cur = cur->next; + if (allok && cur && !strcmp ((gchar*)cur->name, "sources")){ + for (cur = cur->xmlChildrenNode; (cur != NULL) && allok; cur = cur->next) { + if (xmlNodeIsText (cur)) + continue; + + if (!strcmp ((gchar*)cur->name, "gda_array")) { + GdaDataModel *model; + GSList *errors; + + model = gda_data_model_import_new_xml_node (cur); + errors = gda_data_model_import_get_errors (GDA_DATA_MODEL_IMPORT (model)); + if (errors) { + GError *err = (GError *) errors->data; + g_set_error (error, GDA_SET_ERROR, GDA_SET_XML_SPEC_ERROR, + "%s", err->message); + g_object_unref (model); + model = NULL; + allok = FALSE; + } + else { + sources = g_slist_prepend (sources, model); + str = (gchar*)xmlGetProp(cur, (xmlChar*) "name"); + if (str) + g_object_set_data_full (G_OBJECT (model), "name", str, xmlFree); + } + } + } + } + + /* holders */ + for (cur = xml_spec->xmlChildrenNode; cur && allok; cur = cur->next) { + if (xmlNodeIsText (cur)) + continue; + + if (!strcmp ((gchar*)cur->name, "parameter")) { + GdaHolder *holder = NULL; + gchar *str, *id; + xmlChar *this_lang; + xmlChar *gdatype; + + /* don't care about entries for the wrong locale */ + this_lang = xmlGetProp(cur, (xmlChar*)"lang"); + if (this_lang && strncmp ((gchar*)this_lang, lang, strlen ((gchar*)this_lang))) { + g_free (this_lang); + continue; + } + + /* find if there is already a holder with the same ID */ + id = (gchar*)xmlGetProp(cur, (xmlChar*)"id"); + for (list = holders; list && !holder; list = list->next) { + str = (gchar *) gda_holder_get_id ((GdaHolder *) list->data); + if (str && id && !strcmp (str, id)) + holder = (GdaHolder *) list->data; + } + if (id) + xmlFree (id); + + if (holder && !this_lang) { + xmlFree (this_lang); + continue; + } + g_free (this_lang); + + + /* find data type and create GdaHolder */ + gdatype = xmlGetProp (cur, BAD_CAST "gdatype"); + + if (!holder) { + GType gt; + gt = gdatype ? gda_g_type_from_string ((gchar *) gdatype) : G_TYPE_STRING; + if (gt == G_TYPE_INVALID) + gt = GDA_TYPE_NULL; + holder = (GdaHolder*) (g_object_new (GDA_TYPE_HOLDER, + "g-type", gt, + NULL)); + holders = g_slist_append (holders, holder); + } + if (gdatype) + xmlFree (gdatype); + + /* set holder's attributes */ + if (! gda_utility_holder_load_attributes (holder, cur, sources, error)) + allok = FALSE; + } + } + + /* setting prepared new names from sources (models) */ + for (list = sources; list; list = list->next) { + str = g_object_get_data (G_OBJECT (list->data), "newname"); + if (str) { + g_object_set_data_full (G_OBJECT (list->data), "name", g_strdup (str), g_free); + g_object_set_data (G_OBJECT (list->data), "newname", NULL); + } + str = g_object_get_data (G_OBJECT (list->data), "newdescr"); + if (str) { + g_object_set_data_full (G_OBJECT (list->data), "descr", g_strdup (str), g_free); + g_object_set_data (G_OBJECT (list->data), "newdescr", NULL); + } + } + + /* holders' values, constraints: TODO */ + + /* GdaSet creation */ + if (allok) { + xmlChar *prop;; + set = gda_set_new (holders); + + GdaSetPrivate *priv = gda_set_get_instance_private (set); + + prop = xmlGetProp(xml_spec, (xmlChar*)"id"); + if (prop) { + priv->id = g_strdup ((gchar*)prop); + xmlFree (prop); + } + prop = xmlGetProp(xml_spec, (xmlChar*)"name"); + if (prop) { + priv->name = g_strdup ((gchar*)prop); + xmlFree (prop); + } + prop = xmlGetProp(xml_spec, (xmlChar*)"descr"); + if (prop) { + priv->descr = g_strdup ((gchar*)prop); + xmlFree (prop); + } + } + + g_slist_free_full (holders, (GDestroyNotify) g_object_unref); + g_slist_free_full (sources, (GDestroyNotify) g_object_unref); + + return set; +} + +/** + * gda_set_remove_holder: + * @set: a #GdaSet object + * @holder: the #GdaHolder to remove from @set + * + * Removes a #GdaHolder from the list of holders managed by @set + */ +void +gda_set_remove_holder (GdaSet *set, GdaHolder *holder) +{ + GdaSetNode *node; + GdaDataModel *model; + + g_return_if_fail (GDA_IS_SET (set)); + + GdaSetPrivate *priv = gda_set_get_instance_private (set); + + g_return_if_fail (priv); + g_return_if_fail (g_slist_find (priv->holders, holder)); + + if (priv->validate_changes) + g_signal_handlers_disconnect_by_func (G_OBJECT (holder), + G_CALLBACK (validate_change_holder_cb), set); + if (! priv->read_only) { + g_signal_handlers_disconnect_by_func (G_OBJECT (holder), + G_CALLBACK (changed_holder_cb), set); + g_signal_handlers_disconnect_by_func (G_OBJECT (holder), + G_CALLBACK (source_changed_holder_cb), set); + } + g_signal_handlers_disconnect_by_func (holder, + G_CALLBACK (holder_notify_cb), set); + g_signal_handlers_disconnect_by_func (holder, + G_CALLBACK (holder_to_default_cb), set); + + /* now destroy the GdaSetNode and the GdaSetSource if necessary */ + node = gda_set_get_node (set, holder); + g_assert (node); + model = gda_set_node_get_data_model (node); + if (GDA_IS_DATA_MODEL (model)) { + GdaSetSource *source; + GSList *nodes; + + source = gda_set_get_source_for_model (set, model); + g_assert (source); + nodes = gda_set_source_get_nodes (source); + g_assert (nodes); + if (! nodes->next) + set_remove_source (set, source); + } + set_remove_node (set, node); + + priv->holders = g_slist_remove (priv->holders, holder); + g_hash_table_remove (priv->holders_hash, gda_holder_get_id (holder)); + if (priv->holders_array) { + g_ptr_array_free (priv->holders_array, TRUE); + priv->holders_array = NULL; + } + g_object_unref (G_OBJECT (holder)); +} + +static void +source_changed_holder_cb (G_GNUC_UNUSED GdaHolder *holder, GdaSet *set) +{ + compute_public_data (set); +} + + +static GError * +validate_change_holder_cb (GdaHolder *holder, const GValue *value, GdaSet *set) +{ + g_return_val_if_fail (GDA_IS_SET (set), NULL); + GdaSetPrivate *priv = gda_set_get_instance_private (set); + /* signal the holder validate-change */ + GError *error = NULL; + if (priv->read_only) + g_set_error (&error, GDA_SET_ERROR, GDA_SET_READ_ONLY_ERROR, "%s", _("Data set does not allow modifications")); + else { +#ifdef GDA_DEBUG_signal + g_print (">> 'VALIDATE_HOLDER_CHANGE' from %s\n", __FUNCTION__); +#endif + g_signal_emit (G_OBJECT (set), gda_set_signals[VALIDATE_HOLDER_CHANGE], 0, holder, value, &error); +#ifdef GDA_DEBUG_signal + g_print ("<< 'VALIDATE_HOLDER_CHANGED' from %s\n", __FUNCTION__); +#endif + } + return error; +} + +static void +changed_holder_cb (GdaHolder *holder, GdaSet *set) +{ + /* signal the holder change */ +#ifdef GDA_DEBUG_signal + g_print (">> 'HOLDER_CHANGED' from %s\n", __FUNCTION__); +#endif + g_signal_emit (G_OBJECT (set), gda_set_signals[HOLDER_CHANGED], 0, holder); +#ifdef GDA_DEBUG_signal + g_print ("<< 'HOLDER_CHANGED' from %s\n", __FUNCTION__); +#endif +} + +static void +group_free (GdaSetGroup *group, G_GNUC_UNUSED gpointer data) +{ + gda_set_group_free (group); +} + +static void +gda_set_dispose (GObject *object) +{ + GdaSet *set; + GSList *list; + + g_return_if_fail (object != NULL); + g_return_if_fail (GDA_IS_SET (object)); + + set = GDA_SET (object); + + GdaSetPrivate *priv = gda_set_get_instance_private (set); + + /* free the holders list */ + if (priv->holders) { + for (list = priv->holders; list; list = list->next) { + if (priv->validate_changes) + g_signal_handlers_disconnect_by_func (G_OBJECT (list->data), + G_CALLBACK (validate_change_holder_cb), set); + if (! priv->read_only) { + g_signal_handlers_disconnect_by_func (G_OBJECT (list->data), + G_CALLBACK (changed_holder_cb), set); + g_signal_handlers_disconnect_by_func (G_OBJECT (list->data), + G_CALLBACK (source_changed_holder_cb), set); + } + g_object_unref (list->data); + } + g_slist_free (priv->holders); + } + if (priv->holders_hash) { + g_hash_table_destroy (priv->holders_hash); + priv->holders_hash = NULL; + } + if (priv->holders_array) { + g_ptr_array_free (priv->holders_array, TRUE); + priv->holders_array = NULL; + } + + /* free the nodes if there are some */ + while (priv->nodes_list) + set_remove_node (set, GDA_SET_NODE (priv->nodes_list->data)); + while (priv->sources_list) + set_remove_source (set, GDA_SET_SOURCE (priv->sources_list->data)); + + g_slist_foreach (priv->groups_list, (GFunc) group_free, NULL); + g_slist_free (priv->groups_list); + priv->groups_list = NULL; + + /* parent class */ + G_OBJECT_CLASS(gda_set_parent_class)->dispose (object); +} + +static void +gda_set_finalize (GObject *object) +{ + GdaSet *set; + + g_return_if_fail (object != NULL); + g_return_if_fail (GDA_IS_SET (object)); + + set = GDA_SET (object); + + GdaSetPrivate *priv = gda_set_get_instance_private (set); + + if (priv) { + g_free (priv->id); + g_free (priv->name); + g_free (priv->descr); + } + + /* parent class */ + G_OBJECT_CLASS(gda_set_parent_class)->finalize (object); +} + +/* + * Resets and computes set->nodes, and if some nodes already exist, they are previously discarded + */ +static void +compute_public_data (GdaSet *set) +{ + GSList *list; + GdaSetNode *node; + GdaSetSource *source; + GdaSetGroup *group; + GHashTable *groups = NULL; + + g_return_if_fail (GDA_IS_SET (set)); + GdaSetPrivate *priv = gda_set_get_instance_private (set); + + /* + * Get rid of all the previous structures + */ + while (priv->nodes_list) + set_remove_node (set, GDA_SET_NODE (priv->nodes_list->data)); + while (priv->sources_list) + set_remove_source (set, GDA_SET_SOURCE (priv->sources_list->data)); + + g_slist_foreach (priv->groups_list, (GFunc) group_free, NULL); + g_slist_free (priv->groups_list); + priv->groups_list = NULL; + + /* + * Creation of the GdaSetNode structures + */ + for (list = priv->holders; list; list = list->next) { + GdaHolder *holder = GDA_HOLDER (list->data); + gint col; + node = gda_set_node_new (holder); + gda_set_node_set_data_model (node, gda_holder_get_source_model (holder, &col)); + gda_set_node_set_source_column (node, col); + priv->nodes_list = g_slist_prepend (priv->nodes_list, node); + } + priv->nodes_list = g_slist_reverse (priv->nodes_list); + + /* + * Creation of the GdaSetSource and GdaSetGroup structures + */ + for (list = priv->nodes_list; list;list = list->next) { + node = GDA_SET_NODE (list->data); + + /* source */ + source = NULL; + if (gda_set_node_get_data_model (node)) { + source = gda_set_get_source_for_model (set, gda_set_node_get_data_model (node)); + if (source) + gda_set_source_add_node (source, node); + else { + source = gda_set_source_new (gda_set_node_get_data_model (node)); + gda_set_source_add_node (source, node); + priv->sources_list = g_slist_prepend (priv->sources_list, source); + } + } + + /* group */ + group = NULL; + if (gda_set_node_get_data_model (node) && groups) + group = g_hash_table_lookup (groups, gda_set_node_get_data_model (node)); + if (group) + gda_set_group_add_node (group, node); + else { + group = gda_set_group_new (node); + gda_set_group_set_source (group, source); + priv->groups_list = g_slist_prepend (priv->groups_list, group); + if (gda_set_node_get_data_model (node)) { + if (!groups) + groups = g_hash_table_new (NULL, NULL); /* key = source model, + value = GdaSetGroup */ + g_hash_table_insert (groups, gda_set_node_get_data_model (node), group); + } + } + } + priv->groups_list = g_slist_reverse (priv->groups_list); + if (groups) + g_hash_table_destroy (groups); + +#ifdef GDA_DEBUG_signal + g_print (">> 'PUBLIC_DATA_CHANGED' from %p\n", set); +#endif + g_signal_emit (set, gda_set_signals[PUBLIC_DATA_CHANGED], 0); +#ifdef GDA_DEBUG_signal + g_print ("<< 'PUBLIC_DATA_CHANGED' from %p\n", set); +#endif +} + +/** + * gda_set_add_holder: + * @set: a #GdaSet object + * @holder: (transfer none): a #GdaHolder object + * + * Adds @holder to the list of holders managed within @set. + * + * NOTE: if @set already has a #GdaHolder with the same ID as @holder, then @holder + * will not be added to the set (even if @holder's type or value is not the same as the + * one already in @set). + * + * Returns: %TRUE if @holder has been added to @set (and FALSE if it has not been added because there is another #GdaHolder + * with the same ID) + */ +gboolean +gda_set_add_holder (GdaSet *set, GdaHolder *holder) +{ + gboolean added; + g_return_val_if_fail (GDA_IS_SET (set), FALSE); + g_return_val_if_fail (GDA_IS_HOLDER (holder), FALSE); + + added = gda_set_real_add_holder (set, holder); + if (added) + compute_public_data (set); + return added; +} + +static void +holder_to_default_cb (GdaHolder *holder, GdaSet *dataset) { + g_signal_emit (G_OBJECT (dataset), gda_set_signals[HOLDER_ATTR_CHANGED], 0, holder, + "to-default", gda_holder_get_value (holder)); +} + +static void +holder_notify_cb (GdaHolder *holder, GParamSpec *pspec, GdaSet *dataset) +{ + g_return_if_fail (GDA_IS_SET (dataset)); + GType gtype; + gtype = gda_holder_get_g_type (holder); + if (!strcmp (pspec->name, "g-type")) { + if (gtype == GDA_TYPE_NULL) { + return; + } + g_signal_emit (dataset, gda_set_signals[HOLDER_TYPE_SET], 0, holder); + } + else if (!strcmp (pspec->name, "name")) { + GValue *name = gda_value_new (G_TYPE_STRING); + g_object_get_property (G_OBJECT (dataset), "name", name); + g_signal_emit (G_OBJECT (dataset), gda_set_signals[HOLDER_ATTR_CHANGED], 0, holder, + "name", name); + gda_value_free (name); + } + else if (!strcmp (pspec->name, "description")) { + GValue *desc = gda_value_new (G_TYPE_STRING); + g_object_get_property (G_OBJECT (dataset), "description", desc); + g_signal_emit (G_OBJECT (dataset), gda_set_signals[HOLDER_ATTR_CHANGED], 0, holder, + "description", desc); + gda_value_free (desc); + } + else if (!strcmp (pspec->name, "plugin")) { + GValue *plugin = gda_value_new (G_TYPE_STRING); + g_object_get_property (G_OBJECT (holder), "plugin", plugin); + g_signal_emit (G_OBJECT (dataset), gda_set_signals[HOLDER_ATTR_CHANGED], 0, holder, + "plugin", plugin); + gda_value_free (plugin); + } +} + +static gboolean +gda_set_real_add_holder (GdaSet *set, GdaHolder *holder) +{ + GdaHolder *similar; + const gchar *hid; + + g_return_val_if_fail (GDA_IS_SET (set), FALSE); + GdaSetPrivate *priv = gda_set_get_instance_private (set); + + /* + * try to find a similar holder in the priv->holders: + * a holder B is similar to a holder A if it has the same ID + */ + hid = gda_holder_get_id (holder); + if (hid == NULL) { + g_warning (_("GdaHolder needs to have an ID")); + return FALSE; + } + + similar = (GdaHolder*) g_hash_table_lookup (priv->holders_hash, hid); + if (!similar) { + /* really add @holder to the set */ + priv->holders = g_slist_append (priv->holders, holder); + g_hash_table_insert (priv->holders_hash, (gchar*) hid, holder); + if (priv->holders_array) { + g_ptr_array_free (priv->holders_array, TRUE); + priv->holders_array = NULL; + } + g_object_ref (holder); + if (priv->validate_changes) + g_signal_connect (G_OBJECT (holder), "validate-change", + G_CALLBACK (validate_change_holder_cb), set); + if (! priv->read_only) { + g_signal_connect (G_OBJECT (holder), "changed", + G_CALLBACK (changed_holder_cb), set); + g_signal_connect (G_OBJECT (holder), "source-changed", + G_CALLBACK (source_changed_holder_cb), set); + } + g_signal_connect (G_OBJECT (holder), "notify", + G_CALLBACK (holder_notify_cb), set); + g_signal_connect (G_OBJECT (holder), "to-default", + G_CALLBACK (holder_to_default_cb), set); + return TRUE; + } + else if (similar == holder) + return FALSE; + else { +#ifdef GDA_DEBUG_NO + g_print ("In Set %p, Holder %p and %p are similar, keeping %p only\n", set, similar, holder, similar); +#endif + return FALSE; + } +} + + +/** + * gda_set_merge_with_set: + * @set: a #GdaSet object + * @set_to_merge: a #GdaSet object + * + * Add to @set all the holders of @set_to_merge. + * Note1: only the #GdaHolder of @set_to_merge for which no holder in @set has the same ID are merged + * Note2: all the #GdaHolder merged in @set are still used by @set_to_merge. + */ +void +gda_set_merge_with_set (GdaSet *set, GdaSet *set_to_merge) +{ + GSList *holders; + g_return_if_fail (GDA_IS_SET (set)); + g_return_if_fail (set_to_merge && GDA_IS_SET (set_to_merge)); + GdaSetPrivate *priv = gda_set_get_instance_private (set_to_merge); + + for (holders = priv->holders; holders; holders = holders->next) + gda_set_real_add_holder (set, GDA_HOLDER (holders->data)); + compute_public_data (set); +} + +static void +set_remove_node (GdaSet *set, GdaSetNode *node) +{ + g_return_if_fail (GDA_IS_SET (set)); + GdaSetPrivate *priv = gda_set_get_instance_private (set); + gda_set_node_free (node); + priv->nodes_list = g_slist_remove (priv->nodes_list, node); +} + +static void +set_remove_source (GdaSet *set, GdaSetSource *source) +{ + g_return_if_fail (GDA_IS_SET (set)); + GdaSetPrivate *priv = gda_set_get_instance_private (set); + + g_return_if_fail (g_slist_find (priv->sources_list, source)); + gda_set_source_free (source); + priv->sources_list = g_slist_remove (priv->sources_list, source); +} + +/** + * gda_set_is_valid: + * @set: a #GdaSet object + * @error: (nullable): a place to store validation errors, or %NULL + * + * This method tells if all @set's #GdaHolder objects are valid, and if + * they represent a valid combination of values, as defined by rules + * external to Libgda: the "validate-set" signal is emitted and if none of the signal handlers return an + * error, then the returned value is TRUE, otherwise the return value is FALSE as soon as a signal handler + * returns an error. + * + * Returns: TRUE if the set is valid + */ +gboolean +gda_set_is_valid (GdaSet *set, GError **error) +{ + GSList *holders; + + g_return_val_if_fail (GDA_IS_SET (set), FALSE); + + GdaSetPrivate *priv = gda_set_get_instance_private (set); + + g_return_val_if_fail (priv, FALSE); + + for (holders = priv->holders; holders; holders = holders->next) { + if (!gda_holder_is_valid (GDA_HOLDER (holders->data))) { + g_set_error (error, GDA_SET_ERROR, GDA_SET_INVALID_ERROR, + "%s", _("One or more values are invalid")); + return FALSE; + } + } + + return _gda_set_validate (set, error); +} + +gboolean +_gda_set_validate (GdaSet *set, GError **error) +{ + /* signal the holder validate-set */ + GError *lerror = NULL; +#ifdef GDA_DEBUG_signal + g_print (">> 'VALIDATE_SET' from %s\n", __FUNCTION__); +#endif + g_signal_emit (G_OBJECT (set), gda_set_signals[VALIDATE_SET], 0, &lerror); +#ifdef GDA_DEBUG_signal + g_print ("<< 'VALIDATE_SET' from %s\n", __FUNCTION__); +#endif + if (lerror) { + g_propagate_error (error, lerror); + return FALSE; + } + return TRUE; +} + + +/** + * gda_set_get_holder: + * @set: a #GdaSet object + * @holder_id: the ID of the requested value holder + * + * Finds a #GdaHolder using its ID + * + * Returns: (transfer none): the requested #GdaHolder or %NULL + */ +GdaHolder * +gda_set_get_holder (GdaSet *set, const gchar *holder_id) +{ + g_return_val_if_fail (GDA_IS_SET (set), NULL); + g_return_val_if_fail (holder_id, NULL); + + GdaSetPrivate *priv = gda_set_get_instance_private (set); + + return (GdaHolder *) g_hash_table_lookup (priv->holders_hash, holder_id); +} + +/** + * gda_set_get_nth_holder: + * @set: a #GdaSet object + * @pos: the position of the requested #GdaHolder, starting at %0 + * + * Finds a #GdaHolder using its position + * + * Returns: (transfer none): the requested #GdaHolder or %NULL + * + * Since: 4.2 + */ +GdaHolder * +gda_set_get_nth_holder (GdaSet *set, gint pos) +{ + g_return_val_if_fail (GDA_IS_SET (set), NULL); + g_return_val_if_fail (pos >= 0, NULL); + GdaSetPrivate *priv = gda_set_get_instance_private (set); + + if (priv->holders_array == NULL) { + GSList *list; + priv->holders_array = g_ptr_array_new_full (g_slist_length (priv->holders), + (GDestroyNotify) g_object_unref); + for (list = priv->holders; list; list = list->next) { + g_ptr_array_insert (priv->holders_array, -1, + g_object_ref ((GObject*) list->data)); + } + } + if ((guint)pos >= priv->holders_array->len) + return NULL; + else + return g_ptr_array_index (priv->holders_array, pos); +} + +/** + * gda_set_get_holders: + * + * Returns: (transfer none) (element-type Gda.Holder): a list of #GdaHolder objects in the set + */ +GSList* +gda_set_get_holders (GdaSet *set) { + g_return_val_if_fail (set != NULL, NULL); + g_return_val_if_fail (GDA_IS_SET(set), NULL); + + GdaSetPrivate *priv = gda_set_get_instance_private (set); + + return priv->holders; +} +/** + * gda_set_get_nodes: + * + * Returns: (transfer none) (element-type Gda.SetNode): a list of #GdaSetNode objects in the set + */ +GSList* +gda_set_get_nodes (GdaSet *set) { + g_return_val_if_fail (GDA_IS_SET(set), NULL); + + GdaSetPrivate *priv = gda_set_get_instance_private (set); + + return priv->nodes_list; +} + +/** + * gda_set_get_sources: + * + * Returns: (transfer none) (element-type Gda.SetSource): a list of #GdaSetSource objects in the set + */ +GSList* +gda_set_get_sources (GdaSet *set) { + g_return_val_if_fail (GDA_IS_SET(set), NULL); + + GdaSetPrivate *priv = gda_set_get_instance_private (set); + + return priv->sources_list; +} + +/** + * gda_set_get_groups: + * + * Returns: (transfer none) (element-type Gda.SetGroup): a list of #GdaSetGroup objects in the set + */ +GSList* +gda_set_get_groups (GdaSet *set) { + g_return_val_if_fail (GDA_IS_SET(set), NULL); + + GdaSetPrivate *priv = gda_set_get_instance_private (set); + + return priv->groups_list; +} +/** + * gda_set_get_node: + * @set: a #GdaSet object + * @holder: a #GdaHolder object + * + * Finds a #GdaSetNode holding information for @holder, don't modify the returned structure + * + * Returns: (transfer none): the requested #GdaSetNode or %NULL + */ +GdaSetNode * +gda_set_get_node (GdaSet *set, GdaHolder *holder) +{ + GdaSetNode *retval = NULL; + GSList *list; + + g_return_val_if_fail (GDA_IS_SET (set), NULL); + + GdaSetPrivate *priv = gda_set_get_instance_private (set); + + g_return_val_if_fail (priv, NULL); + g_return_val_if_fail (GDA_IS_HOLDER (holder), NULL); + /* FIXME: May is better to use holder's hash for better performance */ + g_return_val_if_fail (g_slist_find (priv->holders, holder), NULL); + + for (list = priv->nodes_list; list && !retval; list = list->next) { + GdaHolder *node_holder; + retval = GDA_SET_NODE (list->data); + node_holder = gda_set_node_get_holder (retval); + if (node_holder == holder) /* FIXME: May is better to compare holders ID */ + break; + else + retval = NULL; + } + return retval; +} + +/** + * gda_set_get_source: + * @set: a #GdaSet object + * @holder: a #GdaHolder object + * + * Finds a #GdaSetSource which contains the #GdaDataModel restricting the possible values of + * @holder, don't modify the returned structure. + * + * Returns: (transfer none): the requested #GdaSetSource or %NULL + */ +GdaSetSource * +gda_set_get_source (GdaSet *set, GdaHolder *holder) +{ + GdaSetNode *node; + GdaDataModel *node_model; + + node = gda_set_get_node (set, holder); + node_model = gda_set_node_get_data_model (node); + if (node && GDA_IS_DATA_MODEL (node_model)) + return gda_set_get_source_for_model (set, node_model); + else + return NULL; +} + +/** + * gda_set_get_group: + * @set: a #GdaSet object + * @holder: a #GdaHolder object + * + * Finds a #GdaSetGroup which lists a #GdaSetNode containing @holder, + * don't modify the returned structure. + * + * Returns: (transfer none): the requested #GdaSetGroup or %NULL + */ +GdaSetGroup * +gda_set_get_group (GdaSet *set, GdaHolder *holder) +{ + GdaSetNode *node; + GdaSetGroup *retval = NULL; + GSList *list; + + g_return_val_if_fail (GDA_IS_SET (set), NULL); + + GdaSetPrivate *priv = gda_set_get_instance_private (set); + + g_return_val_if_fail (priv, NULL); + g_return_val_if_fail (GDA_IS_HOLDER (holder), NULL); + g_return_val_if_fail (g_slist_find (priv->holders, holder), NULL); + + for (list = priv->groups_list; list; list = list->next) { + retval = GDA_SET_GROUP (list->data); + GSList *sublist; + for (sublist = gda_set_group_get_nodes (retval); sublist; sublist = sublist->next) { + node = GDA_SET_NODE (sublist->data); + if (node) { + GdaHolder *node_holder; + node_holder = gda_set_node_get_holder (node); + if (node_holder == holder) /* FIXME: May is better to compare holders ID */ + break; + } + } + if (sublist) + break; + } + return list ? retval : NULL; +} + + +/** + * gda_set_get_source_for_model: + * @set: a #GdaSet object + * @model: a #GdaDataModel object + * + * Finds the #GdaSetSource structure used in @set for which @model is a + * the data model (the returned structure should not be modified). + * + * Returns: (transfer none): the requested #GdaSetSource pointer or %NULL. + */ +GdaSetSource * +gda_set_get_source_for_model (GdaSet *set, GdaDataModel *model) +{ + GdaSetSource *retval = NULL; + GdaDataModel *source_model; + GSList *list; + + g_return_val_if_fail (GDA_IS_SET (set), NULL); + + GdaSetPrivate *priv = gda_set_get_instance_private (set); + + g_return_val_if_fail (priv, NULL); + g_return_val_if_fail (GDA_IS_DATA_MODEL (model), NULL); + + list = priv->sources_list; + while (list && !retval) { + retval = GDA_SET_SOURCE (list->data); + source_model = gda_set_source_get_data_model (retval); + if (GDA_IS_DATA_MODEL (source_model)) { + if (source_model == model) + break; + else + retval = NULL; + } + list = g_slist_next (list); + } + + return retval; +} + +/** + * gda_set_replace_source_model: + * @set: a #GdaSet object + * @source: a pointer to a #GdaSetSource in @set + * @model: a #GdaDataModel + * + * Replaces @source->data_model with @model, which must have the same + * characteristics as @source->data_model (same column types) + * + * Also for each #GdaHolder for which @source->data_model is a source model, + * this method calls gda_holder_set_source_model() with @model to replace + * the source by the new model + * + * Since: 4.2 + */ +void +gda_set_replace_source_model (GdaSet *set, GdaSetSource *source, GdaDataModel *model) +{ + GdaDataModel *source_model; + + g_return_if_fail (GDA_IS_SET (set)); + g_return_if_fail (source); + + GdaSetPrivate *priv = gda_set_get_instance_private (set); + + g_return_if_fail (g_slist_find (priv->sources_list, source)); + g_return_if_fail (GDA_IS_DATA_MODEL (model)); + + /* compare models */ + gint ncols, i; + + source_model = gda_set_source_get_data_model (source); + if (GDA_IS_DATA_MODEL (source_model)) { + ncols = gda_data_model_get_n_columns (source_model); + /* FIXME: This way to compare two Data Models could be useful as a function + * gda_data_model_compare (GdaDataModel) + **/ + if (ncols != gda_data_model_get_n_columns (model)) { + g_warning (_("Replacing data model must have the same characteristics as the " + "data model it replaces")); + return; + } + for (i = 0; i < ncols; i++) { + GdaColumn *c1, *c2; + GType t1, t2; + c1 = gda_data_model_describe_column (source->data_model, i); + c2 = gda_data_model_describe_column (model, i); + t1 = gda_column_get_g_type (c1); + t2 = gda_column_get_g_type (c2); + + if ((t1 != GDA_TYPE_NULL) && (t2 != GDA_TYPE_NULL) && (t1 != t2)) { + g_warning (_("Replacing data model must have the same characteristics as the " + "data model it replaces")); + return; + } + } + } + + /* actually swap the models */ + GSList *list; + gda_set_source_set_data_model (source, model); + for (list = gda_set_source_get_nodes (source); list; list = list->next) { + GdaSetNode *node = GDA_SET_NODE (list->data); + gda_set_node_set_data_model (node, model); + g_signal_handlers_block_by_func (G_OBJECT (node->holder), + G_CALLBACK (source_changed_holder_cb), set); + gda_holder_set_source_model (GDA_HOLDER (node->holder), model, node->source_column, + NULL); + g_signal_handlers_unblock_by_func (G_OBJECT (node->holder), + G_CALLBACK (source_changed_holder_cb), set); + + } +#ifdef GDA_DEBUG_signal + g_print (">> 'SOURCE_MODEL_CHANGED' from %s\n", __FUNCTION__); +#endif + g_signal_emit (G_OBJECT (set), gda_set_signals[SOURCE_MODEL_CHANGED], 0, source); +#ifdef GDA_DEBUG_signal + g_print ("<< 'SOURCE_MODEL_CHANGED' from %s\n", __FUNCTION__); +#endif +} + +#ifdef GDA_DEBUG_NO +static void holder_dump (GdaHolder *holder); +static void set_node_dump (GdaSetNode *node); +static void set_source_dump (GdaSetSource *source); +static void set_group_dump (GdaSetGroup *group); + +static void +holder_dump (GdaHolder *holder) +{ + g_print (" GdaHolder %p (%s)\n", holder, holder ? gda_holder_get_id (holder) : "---"); +} + +static void +set_source_dump (GdaSetSource *source) +{ + g_print (" GdaSetSource %p\n", source); + if (source) { + g_print (" - data_model: %p\n", source->data_model); + GSList *list; + for (list = source->nodes; list; list = list->next) + g_print (" - node: %p\n", list->data); + } +} + +static void +set_group_dump (GdaSetGroup *group) +{ + g_print (" GdaSetGroup %p\n", group); + if (group) { + GSList *list; + for (list = gda_set_group_get_nodes (group); list; list = list->next) + g_print (" - node: %p\n", list->data); + g_print (" - GdaSetSource: %p\n", group->nodes_source); + } +} + +static void +set_node_dump (GdaSetNode *node) +{ + g_print (" GdaSetNode: %p\n", node); + g_print (" - holder: %p (%s)\n", node->holder, node->holder ? gda_holder_get_id (node->holder) : "ERROR : no GdaHolder!"); + g_print (" - source_model: %p\n", node->source_model); + g_print (" - source_column: %d\n", node->source_column); +} + +void +gda_set_dump (GdaSet *set) +{ + g_print ("=== GdaSet %p ===\n", set); + g_slist_foreach (priv->holders, (GFunc) holder_dump, NULL); + g_slist_foreach (priv->nodes_list, (GFunc) set_node_dump, NULL); + g_slist_foreach (priv->sources_list, (GFunc) set_source_dump, NULL); + g_slist_foreach (priv->groups_list, (GFunc) set_group_dump, NULL); + g_print ("=== GdaSet %p END ===\n", set); +} +#endif diff --git a/.flatpak-builder/cache/objects/54/0b065be1a13b83df6026b98e0747d7982720e29186a182f0330ae8f2c5533c.file b/.flatpak-builder/cache/objects/54/0b065be1a13b83df6026b98e0747d7982720e29186a182f0330ae8f2c5533c.file new file mode 100644 index 0000000..5544188 --- /dev/null +++ b/.flatpak-builder/cache/objects/54/0b065be1a13b83df6026b98e0747d7982720e29186a182f0330ae8f2c5533c.file @@ -0,0 +1,217 @@ +/*-*- Mode: C; c-basic-offset: 8 -*-*/ + +/*** + This file is part of libcanberra. + + Copyright 2008 Lennart Poettering + + libcanberra is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation, either version 2.1 of the + License, or (at your option) any later version. + + libcanberra is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with libcanberra. If not, see + . +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include "read-sound-file.h" +#include "read-wav.h" +#include "read-vorbis.h" +#include "macro.h" +#include "malloc.h" +#include "canberra.h" + +struct ca_sound_file { + ca_wav *wav; + ca_vorbis *vorbis; + char *filename; + + unsigned nchannels; + unsigned rate; + ca_sample_type_t type; +}; + +int ca_sound_file_open(ca_sound_file **_f, const char *fn) { + FILE *file; + ca_sound_file *f; + int ret; + + ca_return_val_if_fail(_f, CA_ERROR_INVALID); + ca_return_val_if_fail(fn, CA_ERROR_INVALID); + + if (!(f = ca_new0(ca_sound_file, 1))) + return CA_ERROR_OOM; + + if (!(f->filename = ca_strdup(fn))) { + ret = CA_ERROR_OOM; + goto fail; + } + + if (!(file = fopen(fn, "r"))) { + ret = errno == ENOENT ? CA_ERROR_NOTFOUND : CA_ERROR_SYSTEM; + goto fail; + } + + if ((ret = ca_wav_open(&f->wav, file)) == CA_SUCCESS) { + f->nchannels = ca_wav_get_nchannels(f->wav); + f->rate = ca_wav_get_rate(f->wav); + f->type = ca_wav_get_sample_type(f->wav); + *_f = f; + return CA_SUCCESS; + } + + if (ret == CA_ERROR_CORRUPT) { + + if (fseek(file, 0, SEEK_SET) < 0) { + ret = CA_ERROR_SYSTEM; + goto fail; + } + + if ((ret = ca_vorbis_open(&f->vorbis, file)) == CA_SUCCESS) { + f->nchannels = ca_vorbis_get_nchannels(f->vorbis); + f->rate = ca_vorbis_get_rate(f->vorbis); + f->type = CA_SAMPLE_S16NE; + *_f = f; + return CA_SUCCESS; + } + } + +fail: + + ca_free(f->filename); + ca_free(f); + + return ret; +} + +void ca_sound_file_close(ca_sound_file *f) { + ca_assert(f); + + if (f->wav) + ca_wav_close(f->wav); + if (f->vorbis) + ca_vorbis_close(f->vorbis); + + ca_free(f->filename); + ca_free(f); +} + +unsigned ca_sound_file_get_nchannels(ca_sound_file *f) { + ca_assert(f); + return f->nchannels; +} + +unsigned ca_sound_file_get_rate(ca_sound_file *f) { + ca_assert(f); + return f->rate; +} + +ca_sample_type_t ca_sound_file_get_sample_type(ca_sound_file *f) { + ca_assert(f); + return f->type; +} + +const ca_channel_position_t* ca_sound_file_get_channel_map(ca_sound_file *f) { + ca_assert(f); + + if (f->wav) + return ca_wav_get_channel_map(f->wav); + else + return ca_vorbis_get_channel_map(f->vorbis); +} + +int ca_sound_file_read_int16(ca_sound_file *f, int16_t *d, size_t *n) { + ca_return_val_if_fail(f, CA_ERROR_INVALID); + ca_return_val_if_fail(d, CA_ERROR_INVALID); + ca_return_val_if_fail(n, CA_ERROR_INVALID); + ca_return_val_if_fail(*n > 0, CA_ERROR_INVALID); + ca_return_val_if_fail(f->wav || f->vorbis, CA_ERROR_STATE); + ca_return_val_if_fail(f->type == CA_SAMPLE_S16NE || f->type == CA_SAMPLE_S16RE, CA_ERROR_STATE); + + if (f->wav) + return ca_wav_read_s16le(f->wav, d, n); + else + return ca_vorbis_read_s16ne(f->vorbis, d, n); +} + +int ca_sound_file_read_uint8(ca_sound_file *f, uint8_t *d, size_t *n) { + ca_return_val_if_fail(f, CA_ERROR_INVALID); + ca_return_val_if_fail(d, CA_ERROR_INVALID); + ca_return_val_if_fail(n, CA_ERROR_INVALID); + ca_return_val_if_fail(*n > 0, CA_ERROR_INVALID); + ca_return_val_if_fail(f->wav && !f->vorbis, CA_ERROR_STATE); + ca_return_val_if_fail(f->type == CA_SAMPLE_U8, CA_ERROR_STATE); + + if (f->wav) + return ca_wav_read_u8(f->wav, d, n); + + return CA_ERROR_STATE; +} + +int ca_sound_file_read_arbitrary(ca_sound_file *f, void *d, size_t *n) { + int ret; + + ca_return_val_if_fail(f, CA_ERROR_INVALID); + ca_return_val_if_fail(d, CA_ERROR_INVALID); + ca_return_val_if_fail(n, CA_ERROR_INVALID); + ca_return_val_if_fail(*n > 0, CA_ERROR_INVALID); + + switch (f->type) { + case CA_SAMPLE_S16NE: + case CA_SAMPLE_S16RE: { + size_t k; + + k = *n / sizeof(int16_t); + if ((ret = ca_sound_file_read_int16(f, d, &k)) == CA_SUCCESS) + *n = k * sizeof(int16_t); + + break; + } + + case CA_SAMPLE_U8: { + size_t k; + + k = *n; + if ((ret = ca_sound_file_read_uint8(f, d, &k)) == CA_SUCCESS) + *n = k; + + break; + } + + default: + ca_assert_not_reached(); + } + + return ret; +} + +off_t ca_sound_file_get_size(ca_sound_file *f) { + ca_return_val_if_fail(f, (off_t) -1); + + if (f->wav) + return ca_wav_get_size(f->wav); + else + return ca_vorbis_get_size(f->vorbis); +} + +size_t ca_sound_file_frame_size(ca_sound_file *f) { + unsigned c; + + ca_assert(f); + + c = ca_sound_file_get_nchannels(f); + + return c * (ca_sound_file_get_sample_type(f) == CA_SAMPLE_U8 ? 1U : 2U); +} diff --git a/.flatpak-builder/cache/objects/54/2b14975bb28ba3a0b02b1145c19f9a4ee911e95e586e3b6897687530139e5f.file b/.flatpak-builder/cache/objects/54/2b14975bb28ba3a0b02b1145c19f9a4ee911e95e586e3b6897687530139e5f.file new file mode 120000 index 0000000..f35003d --- /dev/null +++ b/.flatpak-builder/cache/objects/54/2b14975bb28ba3a0b02b1145c19f9a4ee911e95e586e3b6897687530139e5f.file @@ -0,0 +1 @@ +/run \ No newline at end of file diff --git a/.flatpak-builder/cache/objects/55/7b632616bee0acffe8d49513645fc59d5adfe21a796f926795276c95789b3c.file b/.flatpak-builder/cache/objects/55/7b632616bee0acffe8d49513645fc59d5adfe21a796f926795276c95789b3c.file new file mode 100644 index 0000000..235e257 --- /dev/null +++ b/.flatpak-builder/cache/objects/55/7b632616bee0acffe8d49513645fc59d5adfe21a796f926795276c95789b3c.file @@ -0,0 +1,24 @@ +/* gsound.h + * + * Copyright (C) 2014 Tristan Brindle + * + * This file is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of the + * License, or (at your option) any later version. + * + * This file is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef GSOUND_H +#define GSOUND_H + +#include "gsound-context.h" + +#endif /* GSOUND_H */ diff --git a/.flatpak-builder/cache/objects/55/9bb70c18c57d49c2dac9cfdc91c4ebbb306685e5428db2dde3746ebca511a3.file b/.flatpak-builder/cache/objects/55/9bb70c18c57d49c2dac9cfdc91c4ebbb306685e5428db2dde3746ebca511a3.file new file mode 100644 index 0000000..f77b0e4 --- /dev/null +++ b/.flatpak-builder/cache/objects/55/9bb70c18c57d49c2dac9cfdc91c4ebbb306685e5428db2dde3746ebca511a3.file @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2007 - 2011 Vivien Malerba + * Copyright (C) 2018 Daniel Espinosa + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GDA_DATA_MODEL_DIR_H__ +#define __GDA_DATA_MODEL_DIR_H__ + +#include + +G_BEGIN_DECLS + +#define GDA_TYPE_DATA_MODEL_DIR (gda_data_model_dir_get_type()) +G_DECLARE_DERIVABLE_TYPE(GdaDataModelDir, gda_data_model_dir, GDA, DATA_MODEL_DIR, GObject) +struct _GdaDataModelDirClass { + GObjectClass parent_class; + + /*< private >*/ + /* Padding for future expansion */ + void (*_gda_reserved1) (void); + void (*_gda_reserved2) (void); + void (*_gda_reserved3) (void); + void (*_gda_reserved4) (void); +}; + +/** + * SECTION:gda-data-model-dir + * @short_description: GdaDataModel to list files in filesystem + * @title: GdaDataModelDir + * @stability: Stable + * @see_also: #GdaDataModel + * + * The #GdaDataModelDir object lists files on a filesystem which are located + * below a "basedir" directory, one file per row. The data model has the following columns: + * + * the "dir_name" column (G_TYPE_STRING): contains the dirname part of the file + * the "file_name" column (G_TYPE_STRING): contains the file name part of the file + * the "size" column (G_TYPE_UINT): contains the size in bytes of the file + * the "mime_type" column (G_TYPE_STRING): contains the mime type of the file (if GnomeVFS has been found, and NULL otherwise) + * the "md5sum" column (G_TYPE_STRING): contains the MD5 hash of each file (if LibGCrypt has been found, and NULL otherwise) + * the "data" column (GDA_TYPE_BLOB): contains the contents of each file + * + * + * Note that the actual values of the "mime_type", "md5sum" and "data" columns are computed only when they + * are requested to help with performances. + */ + +GdaDataModel *gda_data_model_dir_new (const gchar *basedir); + +const GSList *gda_data_model_dir_get_errors (GdaDataModelDir *model); +void gda_data_model_dir_clean_errors (GdaDataModelDir *model); +G_END_DECLS + +#endif diff --git a/.flatpak-builder/cache/objects/56/26de7463e706b1f5dce5bfbb7eec671ff56cda3bd62cfbdba1b3568a9038f6.file b/.flatpak-builder/cache/objects/56/26de7463e706b1f5dce5bfbb7eec671ff56cda3bd62cfbdba1b3568a9038f6.file new file mode 100755 index 0000000..0f82051 --- /dev/null +++ b/.flatpak-builder/cache/objects/56/26de7463e706b1f5dce5bfbb7eec671ff56cda3bd62cfbdba1b3568a9038f6.file @@ -0,0 +1,342 @@ +#!/usr/bin/perl -w +# -*- Mode: perl; indent-tabs-mode: nil; c-basic-offset: 4 -*- + +# Intltool .desktop, .directory Prepare Tool +# +# Copyright (C) 2001 Free Software Foundation. +# +# Intltool is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of the +# License, or (at your option) any later version. +# +# Intltool is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +# +# Author(s): Gediminas Paulauskas +# Kenneth Christiansen + +## Release information +my $PROGRAM = "intltool-prepare"; +my $PACKAGE = "intltool"; +my $VERSION = "0.51.0"; + +## Loaded modules +use strict; +use Getopt::Long; +use File::Find; + +## Scalars used by the option stuff +my $HELP_ARG = "0"; +my $VERSION_ARG = "0"; +my $VERBOSE = "0"; + +my @languages; +my @desktop_files; +my $new; +my $file; + +my $desktop_extension = "(desktop|soundlist|keys|directory)"; + +my $keywords = "Name|Comment|GenericName|SwallowTitle|description"; + +## Always print as the first thing +$| = 1; + +## Handle options +GetOptions ( + "help|h" => \$HELP_ARG, + "version|v" => \$VERSION_ARG, + "verbose|x" => \$VERBOSE + ) or &invalid_option; + + +## Use the supplied arguments +## Check for options. +## This section will check for the different options. + +sub split_on_argument { + + if ($VERSION_ARG) { + &version; + + } elsif ($HELP_ARG) { + &help; + + } else { + &main; + } +} + +&split_on_argument; + +sub main +{ + print "Working, please wait...\n" if (! $VERBOSE); + &find_desktop_files; + &append_keywords; + &add_to_potfiles; + &perform_rescue; + &add_to_cvsignore; + &fix_makefiles; + &generate_empty; +} + +sub version { + print <<_EOF_; +${PROGRAM} ${PACKAGE} $VERSION +Written by Gediminas Paulauskas , 2000. + +Copyright (C) 2000 Free Software Foundation, Inc. +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +_EOF_ + exit; +} + +sub help +{ + print <<_EOF_; +Usage: ${PROGRAM} [OPTION] KEYWORD... +Automates preparation steps before software make use of intltool. +KEYWORD is a list of additional key other than "Name", "Comment" +and "description". + + -h, --help shows this help page + -v, --version shows the version + -x, --verbose show lots of feedback + +Report bugs to http://bugs.launchpad.net/intltool +_EOF_ + exit; +} + +sub invalid_option +{ + ## Handle invalid arguments + ## my $opt = $ARGV[0]; + ## print "$PROGRAM: invalid option -- $opt\n"; + print STDERR "Try `$PROGRAM --help' for more information.\n"; + exit 1; +} + +sub append_keywords +{ + my $arg; + foreach $arg (@ARGV) { + $keywords .= "|$arg"; + } +} + +sub add_to_potfiles +{ + open FILE, ">>po/POTFILES.in"; + my $intro = 0; + foreach my $desktop (@desktop_files) { + next if contains("po/POTFILES.in", "$desktop.in"); + # Print explanation comment only once + unless ($intro) { + print FILE "# files added by intltool-prepare\n"; + $intro = 1; + } + print FILE "$desktop.in\n"; + } + close FILE; +} + +sub perform_rescue +{ + foreach $file (@desktop_files) { + &rescue_file($file); + } +} + +sub rescue_file +{ + my ($filename) = @_; + my ($msgid, $line, $lang); + + print "Rescuing translations from $filename ...\n" if $VERBOSE; + + open ORIG, "<$filename"; + $line = 1; +ENTRY: while () { + chomp; + $line++; + my $entry = $_; + if (($entry =~ /^($keywords)=(.*)$/) || + ($entry =~ /^(\s*description)=(.*)$/)) { + $msgid = $2; + $msgid =~ s/\\/\\\\/g; + $msgid =~ s/\"/\\"/g; + } elsif (($entry =~ /^($keywords)\[(.*?)\]=(.*)$/) || + ($entry =~ /^(\s*\[)(.*?)\]description=(.*)$/)) { + $lang = $2; + + my $msgstr = $3; + $msgstr =~ s/\\/\\\\/g; + $msgstr =~ s/"/\\"/g; + + $line--; + if ((-s "po/$lang.po") && + (contains("po/$lang.po", "msgid \"$msgid\""))) { + next ENTRY; + } + + open POFILE, ">>po/$lang.po"; + + print POFILE "\n#: $filename.in:$line\n"; + print POFILE "msgid \"$msgid\"\n"; + print POFILE "msgstr \"$msgstr\"\n"; + + close POFILE; + } + } +} + +sub generate_empty +{ + my $all = ' '; + foreach my $full (@desktop_files) { + $new = "$full.in"; + $all .= "$new "; + print "Generating empty $new ...\n" if $VERBOSE; + open FULL, "<$full"; + open NEW, ">$new"; + + while () { + unless ( + (/^($keywords)\[.*?\]=.*$/) || + (/^\s*\[(.*?)\]description=.*$/) + ) { + if (/^($keywords)=.*$/) { + print NEW "_$_"; + } elsif (/^(\s*)(description=.*)$/) { + print NEW "$1_$2\n"; + } else { + print NEW; + } + } + } + + close NEW; + } + unless ($all eq ' ') { + print "*** Please add these files to CVS by following command: ***\n" + . "cvs add$all\n"; + } +} + +sub add_to_cvsignore +{ + my $all = ' '; + my $ign; + foreach $file (@desktop_files) { + $file =~ /^(.*\/)?(.+?\.$desktop_extension$)$/; + if ($1) { + $ign = "$1.cvsignore"; + } else { + $ign = ".cvsignore"; + } + my $basename = $2; + + next if contains($ign, $basename); + + print "Appending $basename to $ign\n" if $VERBOSE; + open FILE, ">>$ign"; + print FILE "$basename\n"; + $all .= "$file "; + } + close FILE; + unless ($all eq ' ') { + print "*** Please remove files from CVS by following command: ***\n" + . "cvs remove -f$all\n"; + } +} + +sub fix_makefiles +{ + my $file; + foreach $file (@desktop_files) { + my ($makefile, $line); + + $file =~ /^(.*\/)?(.+?\.$desktop_extension$)$/; + if ($1) { + $makefile = "$1Makefile.am"; + } else { + $makefile = "Makefile.am"; + } + my $basename = $2; + print "Fixing $basename entry in $makefile\n" if $VERBOSE; + + open MAKE, $makefile; + open NEWMAKE, ">$makefile.new"; + my $extra = 0; + while ($line = ) { + $extra = 1 if $line =~ /^EXTRA_DIST/; + if ($extra) { + if (($line =~ /$basename/) && + !($line =~ /$basename\.in/)) { + $line =~ s/$basename/$basename\.in/; + } + $extra = 0 unless $line =~ /\\\s*$/ + } else { + if ($line =~ /^(\w+)_DATA\s*=\s*$basename\s*$/) { + my $name = $1; + $line =~ s/^$name\_DATA/$name\_in_files/; + $line =~ s/$basename/$basename\.in/; + $basename =~ /\.($desktop_extension)$/; + my $ext = $1; + $line .= "$name\_DATA = \$($name\_in_files:.$ext.in=.$ext)\n"; + $ext =~ tr/a-z/A-Z/; + if (!contains($makefile, "\@INTLTOOL_$ext\_RULE\@")) { + $line .= "\@INTLTOOL_$ext\_RULE\@\n"; + } + } + } + print NEWMAKE $line; + } + close NEWMAKE; + rename "$makefile.new", $makefile; + } +} + +sub contains +{ + my ($name, $str) = @_; + open CONT, "<$name"; + while () { + chomp; + return 1 if $_ eq $str; + } + return 0; +} + +sub find_desktop_files +{ + if ($VERBOSE) { + print "Found these interesting files:\n"; + } else { + print "Finding interesting files..."; + } + find (\&wanted, '.'); + print "done\n" unless $VERBOSE; +} + +sub wanted +{ + if (/\.$desktop_extension$/) { + my $file = $File::Find::name; + $file =~ s/\.\///; + push @desktop_files, $file; + print "$file\n" if $VERBOSE; + } +} + +# vim: ts=4 sw=4 expandtab diff --git a/.flatpak-builder/cache/objects/56/27211390c465592d92a949c9d249627ff904ccf30d722350797e35c2a792a4.file b/.flatpak-builder/cache/objects/56/27211390c465592d92a949c9d249627ff904ccf30d722350797e35c2a792a4.file new file mode 100644 index 0000000..a9c6f24 --- /dev/null +++ b/.flatpak-builder/cache/objects/56/27211390c465592d92a949c9d249627ff904ccf30d722350797e35c2a792a4.file @@ -0,0 +1,308 @@ +/* + * Copyright (C) 2006 Murray Cumming + * Copyright (C) 2006 - 2014 Vivien Malerba + * Copyright (C) 2010 David King + * Copyright (C) 2010 Jonh Wendell + * Copyright (C) 2018 Daniel Espinosa + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GDA_SERVER_OPERATION_H__ +#define __GDA_SERVER_OPERATION_H__ + +#include +#include +#include +#include + +G_BEGIN_DECLS + +#define GDA_TYPE_SERVER_OPERATION (gda_server_operation_get_type()) +G_DECLARE_DERIVABLE_TYPE (GdaServerOperation, gda_server_operation, GDA, SERVER_OPERATION, GObject) + +/* + * Types of identified operations + * all the providers don't implement them completely, though + */ +typedef enum { + GDA_SERVER_OPERATION_CREATE_DB, + GDA_SERVER_OPERATION_DROP_DB, + + GDA_SERVER_OPERATION_CREATE_TABLE, + GDA_SERVER_OPERATION_DROP_TABLE, + GDA_SERVER_OPERATION_RENAME_TABLE, + + GDA_SERVER_OPERATION_ADD_COLUMN, + GDA_SERVER_OPERATION_DROP_COLUMN, + GDA_SERVER_OPERATION_RENAME_COLUMN, + + GDA_SERVER_OPERATION_CREATE_INDEX, + GDA_SERVER_OPERATION_DROP_INDEX, + GDA_SERVER_OPERATION_RENAME_INDEX, + + GDA_SERVER_OPERATION_CREATE_VIEW, + GDA_SERVER_OPERATION_DROP_VIEW, + + GDA_SERVER_OPERATION_COMMENT_TABLE, + GDA_SERVER_OPERATION_COMMENT_COLUMN, + + GDA_SERVER_OPERATION_CREATE_USER, + GDA_SERVER_OPERATION_ALTER_USER, + GDA_SERVER_OPERATION_DROP_USER, + + GDA_SERVER_OPERATION_LAST +} GdaServerOperationType; + +/* error reporting */ +extern GQuark gda_server_operation_error_quark (void); +#define GDA_SERVER_OPERATION_ERROR gda_server_operation_error_quark () + +typedef enum { + GDA_SERVER_OPERATION_OBJECT_NAME_ERROR, + GDA_SERVER_OPERATION_INCORRECT_VALUE_ERROR, + GDA_SERVER_OPERATION_XML_ERROR +} GdaServerOperationError; + +typedef enum +{ + GDA_SERVER_OPERATION_CREATE_TABLE_NOTHING_FLAG = 1 << 0, + GDA_SERVER_OPERATION_CREATE_TABLE_PKEY_FLAG = 1 << 1, + GDA_SERVER_OPERATION_CREATE_TABLE_NOT_NULL_FLAG = 1 << 2, + GDA_SERVER_OPERATION_CREATE_TABLE_UNIQUE_FLAG = 1 << 3, + GDA_SERVER_OPERATION_CREATE_TABLE_AUTOINC_FLAG = 1 << 4, + GDA_SERVER_OPERATION_CREATE_TABLE_FKEY_FLAG = 1 << 5, + /* Flags combinations */ + GDA_SERVER_OPERATION_CREATE_TABLE_PKEY_AUTOINC_FLAG = GDA_SERVER_OPERATION_CREATE_TABLE_PKEY_FLAG | GDA_SERVER_OPERATION_CREATE_TABLE_AUTOINC_FLAG +} GdaServerOperationCreateTableFlag; + +typedef enum { + GDA_SERVER_OPERATION_NODE_PARAMLIST, + GDA_SERVER_OPERATION_NODE_DATA_MODEL, + GDA_SERVER_OPERATION_NODE_PARAM, + GDA_SERVER_OPERATION_NODE_SEQUENCE, + GDA_SERVER_OPERATION_NODE_SEQUENCE_ITEM, + + GDA_SERVER_OPERATION_NODE_DATA_MODEL_COLUMN, + GDA_SERVER_OPERATION_NODE_UNKNOWN +} GdaServerOperationNodeType; + +typedef enum { + GDA_SERVER_OPERATION_STATUS_OPTIONAL, + GDA_SERVER_OPERATION_STATUS_REQUIRED, + GDA_SERVER_OPERATION_STATUS_UNKNOWN +} GdaServerOperationNodeStatus; + +/** + * SECTION:gda-server-operation-sequences + * @short_description: Manipulating sequences + * @title: GdaServerOperation: sequences + * @stability: Stable + * @see_also: #GdaServerOperation + * + * The #GdaServerOperation object can contain sequences of templates. For example when creating a table, + * one can specify several foreign keys where for each foreign key, one must define the column(s) on which the + * foreign key applies, the referenced table and the corresponding columns of the referenced table (plus some + * additional information). In this case the foreign keys are defined as a sequence of templates (the foreign key + * definition): there can be zero or more foreign keys. + */ + +/** + * SECTION:gda-server-operation-nodes + * @short_description: Getting information about parts (nodes) composing a path + * @title: GdaServerOperation: individual nodes + * @stability: Stable + * @see_also: #GdaServerOperation + * + * To each part of a path is associated a node (as a #GdaServerOperationNode structure). For example the + * "/TABLE_DEF_P/TABLE_NAME" path has two nodes, one associated to "/TABLE_DEF_P" and one to + * "/TABLE_DEF_P/TABLE_NAME". For more information about the path's format, see the + * gda_server_operation_set_value_at()'s documentation. + * + * This API is designed to get information about all the nodes present in a #GdaServerOperation object (refer to the + * gda_server_operation_get_root_nodes() function) and about each node of a path, and allows inspection + * of its contents. It is mainly reserved for database provider's implementations but can have its purpose + * outside of this scope. + */ + +typedef struct _GdaServerOperationNode { + GdaServerOperationNodeType type; + GdaServerOperationNodeStatus status; + + GdaSet *plist; + GdaDataModel *model; + GdaColumn *column; + GdaHolder *param; + gpointer priv; +} GdaServerOperationNode; + +#define GDA_TYPE_SERVER_OPERATION_NODE gda_server_operation_node_get_type () + +GType gda_server_operation_node_get_type (void) G_GNUC_CONST; +GdaServerOperationNode* + gda_server_operation_node_copy (GdaServerOperationNode *src); +void gda_server_operation_node_free (GdaServerOperationNode *src); + +struct _GdaServerOperationClass { + GObjectClass parent_class; + + /* signals */ + void (*seq_item_added) (GdaServerOperation *op, const gchar *seq_path, gint item_index); + void (*seq_item_remove) (GdaServerOperation *op, const gchar *seq_path, gint item_index); + + /*< private >*/ + /* Padding for future expansion */ + void (*_gda_reserved1) (void); + void (*_gda_reserved2) (void); + void (*_gda_reserved3) (void); + void (*_gda_reserved4) (void); +}; + +/** + * SECTION:gda-server-operation + * @short_description: Handles any DDL query in an abstract way + * @title: GdaServerOperation + * @stability: Stable + * @see_also: + * + * This object is basically just a data store: it can store named values, the values being + * organized hierarchically by their name which are similar to a Unix file path. For example a value can be read from its path + * using the gda_server_operation_get_value_at() method, or set using the gda_server_operation_set_value_at() method. + * + * Each #GdaServerOperation contains some structure which is usually defined by a database provider to implement + * a specific operation. The structure is composed of the following building blocks: + * + * Named values (internally represented as a #GdaHolder object) + * Named values in a vector (internally represented as a #GdaSet object) + * Values in an array (internally represented as a #GdaDataModel object) + * Sequences of one or more of the previous blocks. A sequence can contain any number of + * instances of the template block (there may be lower and upper boundaries to the number of instances) + * + * + * Important note: #GdaServerOperation objects are usually not created + * manually using gda_server_operation_new(), but + * using a #GdaServerProvider object with gda_server_provider_create_operation(). + * See the global introduction about DDL for more information. + * Alternatively one can use the Convenience functions + * which internally manipulate #GdaServerOperation objects. + */ + +GdaServerOperation *gda_server_operation_new (GdaServerOperationType op_type, const gchar *xml_file); +GdaServerOperationType gda_server_operation_get_op_type (GdaServerOperation *op); +const gchar *gda_server_operation_op_type_to_string (GdaServerOperationType type); +GdaServerOperationType gda_server_operation_string_to_op_type (const gchar *str); +GdaServerOperationNode *gda_server_operation_get_node_info (GdaServerOperation *op, const gchar *path_format, ...); + +const GValue *gda_server_operation_get_value_at (GdaServerOperation *op, const gchar *path_format, ...); +const GValue *gda_server_operation_get_value_at_path (GdaServerOperation *op, const gchar *path); +gchar *gda_server_operation_get_sql_identifier_at (GdaServerOperation *op, + const gchar *path_format, GError **error, + ...); +gchar *gda_server_operation_get_sql_identifier_at_path (GdaServerOperation *op, + const gchar *path, GError **error); +gboolean gda_server_operation_set_value_at (GdaServerOperation *op, const gchar *value, + GError **error, const gchar *path_format, ...); +gboolean gda_server_operation_set_value_at_path (GdaServerOperation *op, const gchar *value, + const gchar *path, GError **error); + +xmlNodePtr gda_server_operation_save_data_to_xml (GdaServerOperation *op, GError **error); +gchar* gda_server_operation_save_data_to_xml_string (GdaServerOperation *op, + G_GNUC_UNUSED GError **error); +gboolean gda_server_operation_load_data_from_xml (GdaServerOperation *op, + xmlNodePtr node, GError **error); + +gchar** gda_server_operation_get_root_nodes (GdaServerOperation *op); +GdaServerOperationNodeType gda_server_operation_get_node_type (GdaServerOperation *op, const gchar *path, + GdaServerOperationNodeStatus *status); +gchar *gda_server_operation_get_node_parent (GdaServerOperation *op, const gchar *path); +gchar *gda_server_operation_get_node_path_portion (GdaServerOperation *op, const gchar *path); + +const gchar *gda_server_operation_get_sequence_name (GdaServerOperation *op, const gchar *path); +guint gda_server_operation_get_sequence_size (GdaServerOperation *op, const gchar *path); +guint gda_server_operation_get_sequence_max_size (GdaServerOperation *op, const gchar *path); +guint gda_server_operation_get_sequence_min_size (GdaServerOperation *op, const gchar *path); +gchar **gda_server_operation_get_sequence_item_names (GdaServerOperation *op, const gchar *path); + +guint gda_server_operation_add_item_to_sequence (GdaServerOperation *op, const gchar *seq_path); +gboolean gda_server_operation_del_item_from_sequence (GdaServerOperation *op, const gchar *item_path); + +gboolean gda_server_operation_is_valid (GdaServerOperation *op, const gchar *xml_file, GError **error); +gboolean gda_server_operation_is_valid_from_resource (GdaServerOperation *op, const gchar *resource, GError **error); + +/* + * Database creation and destruction + */ +gchar *gda_server_operation_render (GdaServerOperation *op, GError **error); + +/* + * Tables creation and destruction + */ + +typedef struct _GdaServerOperationCreateTableArg GdaServerOperationCreateTableArg; + +#define GDA_TYPE_SERVER_OPERATION_CREATE_TABLE_ARG (gda_server_operation_create_table_arg_get_type ()) + +GType gda_server_operation_create_table_arg_get_type (void) G_GNUC_CONST; +GdaServerOperationCreateTableArg* + gda_server_operation_create_table_arg_new (void); +GdaServerOperationCreateTableArg* + gda_server_operation_create_table_arg_copy (GdaServerOperationCreateTableArg* src); +void gda_server_operation_create_table_arg_free (GdaServerOperationCreateTableArg *arg); +void gda_server_operation_create_table_arg_set_column_name (GdaServerOperationCreateTableArg *arg, + const gchar *name); +gchar* gda_server_operation_create_table_arg_get_column_name (GdaServerOperationCreateTableArg *arg); +void gda_server_operation_create_table_arg_set_column_type (GdaServerOperationCreateTableArg *arg, + GType ctype); +GType gda_server_operation_create_table_arg_get_column_type (GdaServerOperationCreateTableArg *arg); +void gda_server_operation_create_table_arg_set_flags (GdaServerOperationCreateTableArg *arg, + GdaServerOperationCreateTableFlag flags); +GdaServerOperationCreateTableFlag + gda_server_operation_create_table_arg_get_flags (GdaServerOperationCreateTableArg *arg); +void gda_server_operation_create_table_arg_set_fkey_table (GdaServerOperationCreateTableArg *arg, const gchar *name); +gchar* gda_server_operation_create_table_arg_get_fkey_table (GdaServerOperationCreateTableArg *arg); +void gda_server_operation_create_table_arg_set_fkey_ondelete (GdaServerOperationCreateTableArg *arg, const gchar *action); +gchar* gda_server_operation_create_table_arg_get_fkey_ondelete (GdaServerOperationCreateTableArg *arg); +void gda_server_operation_create_table_arg_set_fkey_ondupdate (GdaServerOperationCreateTableArg *arg, const gchar *action); +gchar* gda_server_operation_create_table_arg_get_fkey_onupdate (GdaServerOperationCreateTableArg *arg); +void gda_server_operation_create_table_arg_set_fkey_refs (GdaServerOperationCreateTableArg *arg, GList *refs); +GList* gda_server_operation_create_table_arg_get_fkey_refs (GdaServerOperationCreateTableArg *arg); + +typedef struct _GdaServerOperationCreateTableArgFKeyRefField GdaServerOperationCreateTableArgFKeyRefField; + +#define GDA_TYPE_SERVER_OPERATION_CREATE_TABLE_ARG_FKEY_REF_FIELD (gda_server_operation_create_table_arg_fkey_ref_field_get_type ()) + +GType gda_server_operation_create_table_arg_fkey_ref_field_get_type (void) G_GNUC_CONST; +GdaServerOperationCreateTableArgFKeyRefField* + gda_server_operation_create_table_arg_fkey_ref_field_new (void); +GdaServerOperationCreateTableArgFKeyRefField* + gda_server_operation_create_table_arg_fkey_ref_field_copy (GdaServerOperationCreateTableArgFKeyRefField *src); +void gda_server_operation_create_table_arg_fkey_ref_field_free (GdaServerOperationCreateTableArgFKeyRefField *ref); +void gda_server_operation_create_table_arg_fkey_ref_field_set_local_field (GdaServerOperationCreateTableArgFKeyRefField *ref, const gchar *name); +gchar* gda_server_operation_create_table_arg_fkey_ref_field_get_local_field (GdaServerOperationCreateTableArgFKeyRefField *ref); +void gda_server_operation_create_table_arg_fkey_ref_field_set_referenced_field (GdaServerOperationCreateTableArgFKeyRefField *ref, const gchar *name); +gchar* gda_server_operation_create_table_arg_fkey_ref_field_get_referenced_field (GdaServerOperationCreateTableArgFKeyRefField *ref); + +G_DEPRECATED_FOR(gda_server_operation_create_table_arg_fkey_ref_field_get_type) +GType gda_server_operation_create_table_arg_get_fkey_ref_field_get_type (void) G_GNUC_CONST; + +GdaServerOperation *gda_server_operation_prepare_create_database (const gchar *provider, const gchar *db_name, GError **error); +gboolean gda_server_operation_perform_create_database (GdaServerOperation *op, const gchar *provider, GError **error); +GdaServerOperation *gda_server_operation_prepare_drop_database (const gchar *provider, const gchar *db_name, GError **error); +gboolean gda_server_operation_perform_drop_database (GdaServerOperation *op, const gchar *provider, GError **error); + +G_END_DECLS + +#endif diff --git a/.flatpak-builder/cache/objects/56/27372e43c0aa15f1c2a3f57226e74989dcf984b0188ddbfdb89f4046fbfb52.dirtree b/.flatpak-builder/cache/objects/56/27372e43c0aa15f1c2a3f57226e74989dcf984b0188ddbfdb89f4046fbfb52.dirtree new file mode 100644 index 0000000..91898c6 Binary files /dev/null and b/.flatpak-builder/cache/objects/56/27372e43c0aa15f1c2a3f57226e74989dcf984b0188ddbfdb89f4046fbfb52.dirtree differ diff --git a/.flatpak-builder/cache/objects/56/49bd1eff989b6f4d192b38a5b4829473d06e0a9c425d8ad4517de5e5c9cc89.file b/.flatpak-builder/cache/objects/56/49bd1eff989b6f4d192b38a5b4829473d06e0a9c425d8ad4517de5e5c9cc89.file new file mode 120000 index 0000000..ca59ee3 --- /dev/null +++ b/.flatpak-builder/cache/objects/56/49bd1eff989b6f4d192b38a5b4829473d06e0a9c425d8ad4517de5e5c9cc89.file @@ -0,0 +1 @@ +../../share/runtime/locale/pa/share/pa \ No newline at end of file diff --git a/.flatpak-builder/cache/objects/56/c4178ded934b608fa6da9957d718c9d8a97af1f1cd0d4669753bb4e2db6201.dirtree b/.flatpak-builder/cache/objects/56/c4178ded934b608fa6da9957d718c9d8a97af1f1cd0d4669753bb4e2db6201.dirtree new file mode 100644 index 0000000..ad9e26e Binary files /dev/null and b/.flatpak-builder/cache/objects/56/c4178ded934b608fa6da9957d718c9d8a97af1f1cd0d4669753bb4e2db6201.dirtree differ diff --git a/.flatpak-builder/cache/objects/57/6929d2ecea46145b24a09967566e18f8ff341f4f7e996d9f7a7b9a6a29ea7b.file b/.flatpak-builder/cache/objects/57/6929d2ecea46145b24a09967566e18f8ff341f4f7e996d9f7a7b9a6a29ea7b.file new file mode 100644 index 0000000..8c2aa87 Binary files /dev/null and b/.flatpak-builder/cache/objects/57/6929d2ecea46145b24a09967566e18f8ff341f4f7e996d9f7a7b9a6a29ea7b.file differ diff --git a/.flatpak-builder/cache/objects/57/7a603f422bc4818343530ae172816ab7c973308e70d92a72ec88dcff5b5d7c.dirtree b/.flatpak-builder/cache/objects/57/7a603f422bc4818343530ae172816ab7c973308e70d92a72ec88dcff5b5d7c.dirtree new file mode 100644 index 0000000..1cceefa Binary files /dev/null and b/.flatpak-builder/cache/objects/57/7a603f422bc4818343530ae172816ab7c973308e70d92a72ec88dcff5b5d7c.dirtree differ diff --git a/.flatpak-builder/cache/objects/57/8f5b4b0a42e118fc09c8642d32e96499525b56b5844d9c635f6b45e5886149.file b/.flatpak-builder/cache/objects/57/8f5b4b0a42e118fc09c8642d32e96499525b56b5844d9c635f6b45e5886149.file new file mode 100644 index 0000000..2864ce0 --- /dev/null +++ b/.flatpak-builder/cache/objects/57/8f5b4b0a42e118fc09c8642d32e96499525b56b5844d9c635f6b45e5886149.file @@ -0,0 +1,579 @@ +/*-*- Mode: C; c-basic-offset: 8 -*-*/ + +#ifndef foocanberrahfoo +#define foocanberrahfoo + +/*** + This file is part of libcanberra. + + Copyright 2008 Lennart Poettering + + libcanberra is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation, either version 2.1 of the + License, or (at your option) any later version. + + libcanberra is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with libcanberra. If not, see + . +***/ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __GNUC__ +/* Make sure __attribute__ works on non-gcc systems. Yes, might be a bit ugly */ +#define __attribute__(x) +#endif + +/** + * CA_MAJOR: + * + * Evaluates to the major version number of libcanberra. + */ +#define CA_MAJOR (0) + +/** + * CA_MINOR: + * + * Evaluates to the minor version number of libcanberra. + */ +#define CA_MINOR (30) + +/** + * CA_CHECK_VERSION: + * + * Evaluates to TRUE when the library version is newer than the + * specified parameters. + */ +#define CA_CHECK_VERSION(major,minor) \ + ((CA_MAJOR > (major)) || \ + (CA_MAJOR == (major) && CA_MINOR >= (minor))) + +/** + * CA_PROP_MEDIA_NAME: + * + * A name describing the media being played. Localized if possible and applicable. + */ +#define CA_PROP_MEDIA_NAME "media.name" + +/** + * CA_PROP_MEDIA_TITLE: + * + * A (song) title describing the media being played. Localized if possible and applicable. + */ +#define CA_PROP_MEDIA_TITLE "media.title" + +/** + * CA_PROP_MEDIA_ARTIST: + * + * The artist of this media. Localized if possible and applicable. + */ +#define CA_PROP_MEDIA_ARTIST "media.artist" + +/** + * CA_PROP_MEDIA_LANGUAGE: + * + * The language this media is in, in some standard POSIX locale string, such as "de_DE". + */ +#define CA_PROP_MEDIA_LANGUAGE "media.language" + +/** + * CA_PROP_MEDIA_FILENAME: + * + * The file name this media was or can be loaded from. + */ +#define CA_PROP_MEDIA_FILENAME "media.filename" + +/** + * CA_PROP_MEDIA_ICON: + * + * An icon for this media in binary PNG format. + */ +#define CA_PROP_MEDIA_ICON "media.icon" + +/** + * CA_PROP_MEDIA_ICON_NAME: + * + * An icon name as defined in the XDG icon naming specifcation. + */ +#define CA_PROP_MEDIA_ICON_NAME "media.icon_name" + +/** + * CA_PROP_MEDIA_ROLE: + * + * The "role" this media is played in. For event sounds the string + * "event". For other cases strings like "music", "video", "game", ... + */ +#define CA_PROP_MEDIA_ROLE "media.role" + +/** + * CA_PROP_EVENT_ID: + * + * A textual id for an event sound, as mandated by the XDG sound naming specification. + */ +#define CA_PROP_EVENT_ID "event.id" + +/** + * CA_PROP_EVENT_DESCRIPTION: + * + * A descriptive string for the sound event. Localized if possible and applicable. + */ +#define CA_PROP_EVENT_DESCRIPTION "event.description" + +/** + * CA_PROP_EVENT_MOUSE_X: + * + * If this sound event was triggered by a mouse input event, the X + * position of the mouse cursor on the screen, formatted as string. + */ +#define CA_PROP_EVENT_MOUSE_X "event.mouse.x" + +/** + * CA_PROP_EVENT_MOUSE_Y: + * + * If this sound event was triggered by a mouse input event, the Y + * position of the mouse cursor on the screen, formatted as string. + */ +#define CA_PROP_EVENT_MOUSE_Y "event.mouse.y" + +/** + * CA_PROP_EVENT_MOUSE_HPOS: + * + * If this sound event was triggered by a mouse input event, the X + * position of the mouse cursor as fractional value between 0 and 1, + * formatted as string, 0 reflecting the left side of the screen, 1 + * the right side. + */ +#define CA_PROP_EVENT_MOUSE_HPOS "event.mouse.hpos" + +/** + * CA_PROP_EVENT_MOUSE_VPOS: + * + * If this sound event was triggered by a mouse input event, the Y + * position of the mouse cursor as fractional value between 0 and 1, + * formatted as string, 0 reflecting the top end of the screen, 1 + * the bottom end. + */ +#define CA_PROP_EVENT_MOUSE_VPOS "event.mouse.vpos" + +/** + * CA_PROP_EVENT_MOUSE_BUTTON: + * + * If this sound event was triggered by a mouse input event, the + * number of the mouse button that triggered it, formatted as string. 1 + * for left mouse button, 3 for right, 2 for middle. + */ +#define CA_PROP_EVENT_MOUSE_BUTTON "event.mouse.button" + +/** + * CA_PROP_WINDOW_NAME: + * + * If this sound event was triggered by a window on the screen, the + * name of this window as human readable string. + */ +#define CA_PROP_WINDOW_NAME "window.name" + +/** + * CA_PROP_WINDOW_ID: + * + * If this sound event was triggered by a window on the screen, some + * identification string for this window, so that the sound system can + * recognize specific windows. + */ +#define CA_PROP_WINDOW_ID "window.id" + +/** + * CA_PROP_WINDOW_ICON: + * + * If this sound event was triggered by a window on the screen, binary + * icon data in PNG format for this window. + */ +#define CA_PROP_WINDOW_ICON "window.icon" + +/** + * CA_PROP_WINDOW_ICON_NAME: + * + * If this sound event was triggered by a window on the screen, an + * icon name for this window, as defined in the XDG icon naming + * specification. + */ +#define CA_PROP_WINDOW_ICON_NAME "window.icon_name" + +/** + * CA_PROP_WINDOW_X: + * + * If this sound event was triggered by a window on the screen, the X + * position of the window measured from the top left corner of the + * screen to the top left corner of the window. + * + * Since: 0.17 + */ +#define CA_PROP_WINDOW_X "window.x" + +/** + * CA_PROP_WINDOW_Y: + * + * If this sound event was triggered by a window on the screen, the y + * position of the window measured from the top left corner of the + * screen to the top left corner of the window. + * + * Since: 0.17 + */ +#define CA_PROP_WINDOW_Y "window.y" + +/** + * CA_PROP_WINDOW_WIDTH: + * + * If this sound event was triggered by a window on the screen, the + * pixel width of the window. + * + * Since: 0.17 + */ +#define CA_PROP_WINDOW_WIDTH "window.width" + +/** + * CA_PROP_WINDOW_HEIGHT: + * + * If this sound event was triggered by a window on the screen, the + * pixel height of the window. + * + * Since: 0.17 + */ +#define CA_PROP_WINDOW_HEIGHT "window.height" + +/** + * CA_PROP_WINDOW_HPOS: + * + * If this sound event was triggered by a window on the screen, the X + * position of the center of the window as fractional value between 0 + * and 1, formatted as string, 0 reflecting the left side of the + * screen, 1 the right side. + * + * Since: 0.17 + */ +#define CA_PROP_WINDOW_HPOS "window.hpos" + +/** + * CA_PROP_WINDOW_VPOS: + * + * If this sound event was triggered by a window on the screen, the Y + * position of the center of the window as fractional value between 0 + * and 1, formatted as string, 0 reflecting the top side of the + * screen, 1 the bottom side. + * + * Since: 0.17 + */ +#define CA_PROP_WINDOW_VPOS "window.vpos" + +/** + * CA_PROP_WINDOW_DESKTOP: + * + * If this sound event was triggered by a window on the screen and the + * windowing system supports multiple desktops, a comma seperated list + * of indexes of the desktops this window is visible on. If this + * property is an empty string, it is visible on all desktops + * (i.e. 'sticky'). The first desktop is 0. (e.g. "0,2,3") + * + * Since: 0.18 + */ +#define CA_PROP_WINDOW_DESKTOP "window.desktop" + +/** + * CA_PROP_WINDOW_X11_DISPLAY: + * + * If this sound event was triggered by a window on the screen and the + * windowing system is X11, the X display name of the window (e.g. ":0"). + */ +#define CA_PROP_WINDOW_X11_DISPLAY "window.x11.display" + +/** + * CA_PROP_WINDOW_X11_SCREEN: + * + * If this sound event was triggered by a window on the screen and the + * windowing system is X11, the X screen id of the window formatted as + * string (e.g. "0"). + */ +#define CA_PROP_WINDOW_X11_SCREEN "window.x11.screen" + +/** + * CA_PROP_WINDOW_X11_MONITOR: + * + * If this sound event was triggered by a window on the screen and the + * windowing system is X11, the X monitor id of the window formatted as + * string (e.g. "0"). + */ +#define CA_PROP_WINDOW_X11_MONITOR "window.x11.monitor" + +/** + * CA_PROP_WINDOW_X11_XID: + * + * If this sound event was triggered by a window on the screen and the + * windowing system is X11, the XID of the window formatted as string. + */ +#define CA_PROP_WINDOW_X11_XID "window.x11.xid" + +/** + * CA_PROP_APPLICATION_NAME: + * + * The name of the application this sound event was triggered by as + * human readable string. (e.g. "GNU Emacs") Localized if possible and + * applicable. + */ +#define CA_PROP_APPLICATION_NAME "application.name" + +/** + * CA_PROP_APPLICATION_ID: + * + * An identifier for the program this sound event was triggered + * by. (e.g. "org.gnu.emacs"). + */ +#define CA_PROP_APPLICATION_ID "application.id" + +/** + * CA_PROP_APPLICATION_VERSION: + * + * A version number for the program this sound event was triggered + * by. (e.g. "22.2") + */ +#define CA_PROP_APPLICATION_VERSION "application.version" + +/** + * CA_PROP_APPLICATION_ICON: + * + * Binary icon data in PNG format for the application this sound event + * is triggered by. + */ +#define CA_PROP_APPLICATION_ICON "application.icon" + +/** + * CA_PROP_APPLICATION_ICON_NAME: + * + * An icon name for the application this sound event is triggered by, + * as defined in the XDG icon naming specification. + */ +#define CA_PROP_APPLICATION_ICON_NAME "application.icon_name" + +/** + * CA_PROP_APPLICATION_LANGUAGE: + * + * The locale string the application that is triggering this sound + * event is running in. A POSIX locale string such as de_DE@euro. + */ +#define CA_PROP_APPLICATION_LANGUAGE "application.language" + +/** + * CA_PROP_APPLICATION_PROCESS_ID: + * + * The unix PID of the process that is triggering this sound event, formatted as string. + */ +#define CA_PROP_APPLICATION_PROCESS_ID "application.process.id" + +/** + * CA_PROP_APPLICATION_PROCESS_BINARY: + * + * The path to the process binary of the process that is triggering this sound event. + */ +#define CA_PROP_APPLICATION_PROCESS_BINARY "application.process.binary" + +/** + * CA_PROP_APPLICATION_PROCESS_USER: + * + * The user that owns the process that is triggering this sound event. + */ +#define CA_PROP_APPLICATION_PROCESS_USER "application.process.user" + +/** + * CA_PROP_APPLICATION_PROCESS_HOST: + * + * The host name of the host the process that is triggering this sound event runs on. + */ +#define CA_PROP_APPLICATION_PROCESS_HOST "application.process.host" + +/** + * CA_PROP_CANBERRA_CACHE_CONTROL: + * + * A special property that can be used to control the automatic sound + * caching of sounds in the sound server. One of "permanent", + * "volatile", "never". "permanent" will cause this sample to be + * cached in the server permanently. This is useful for very + * frequently used sound events such as those used for input + * feedback. "volatile" may be used for cacheing sounds in the sound + * server temporarily. They will expire after some time or on cache + * pressure. Finally, "never" may be used for sounds that should never + * be cached, because they are only generated very seldomly or even + * only once at most (such as desktop login sounds). + * + * If this property is not explicitly passed to ca_context_play() it + * will default to "never". If it is not explicitly passed to + * ca_context_cache() it will default to "permanent". + * + * If the list of properties is handed on to the sound server this + * property is stripped from it. + */ +#define CA_PROP_CANBERRA_CACHE_CONTROL "canberra.cache-control" + +/** + * CA_PROP_CANBERRA_VOLUME: + * + * A special property that can be used to control the volume this + * sound event is played in if the backend supports it. A floating + * point value for the decibel multiplier for the sound. 0 dB relates + * to zero gain, and is the default volume these sounds are played in. + * + * If the list of properties is handed on to the sound server this + * property is stripped from it. + */ +#define CA_PROP_CANBERRA_VOLUME "canberra.volume" + +/** + * CA_PROP_CANBERRA_XDG_THEME_NAME: + * + * A special property that can be used to control the XDG sound theme that + * is used for this sample. + * + * If the list of properties is handed on to the sound server this + * property is stripped from it. + */ +#define CA_PROP_CANBERRA_XDG_THEME_NAME "canberra.xdg-theme.name" + +/** + * CA_PROP_CANBERRA_XDG_THEME_OUTPUT_PROFILE: + * + * A special property that can be used to control the XDG sound theme + * output profile that is used for this sample. + * + * If the list of properties is handed on to the sound server this + * property is stripped from it. + */ +#define CA_PROP_CANBERRA_XDG_THEME_OUTPUT_PROFILE "canberra.xdg-theme.output-profile" + +/** + * CA_PROP_CANBERRA_ENABLE: + * + * A special property that can be used to control whether any sounds + * are played at all. If this property is "1" or unset sounds are + * played as normal. However, if it is "0" all calls to + * ca_context_play() will fail with CA_ERROR_DISABLED. + * + * If the list of properties is handed on to the sound server this + * property is stripped from it. + */ +#define CA_PROP_CANBERRA_ENABLE "canberra.enable" + +/** + * CA_PROP_CANBERRA_FORCE_CHANNEL: + * + * A special property that can be used to control on which channel a + * sound is played. The value should be one of mono, front-left, + * front-right, front-center, rear-left, rear-right, rear-center, lfe, + * front-left-of-center, front-right-of-center, side-left, side-right, + * top-center, top-front-left, top-front-right, top-front-center, + * top-rear-left, top-rear-right, top-rear-center. This property is + * only honoured by some backends, other backends may choose to ignore + * it completely. + * + * If the list of properties is handed on to the sound server this + * property is stripped from it. + * + * Since: 0.13 + */ +#define CA_PROP_CANBERRA_FORCE_CHANNEL "canberra.force_channel" + +/** + * ca_context: + * + * A libcanberra context object. + */ +typedef struct ca_context ca_context; + +/** + * ca_finish_callback_t: + * @c: The libcanberra context this callback is called for + * @id: The numerical id passed to the ca_context_play_full() when starting the event sound playback. + * @error_code: A numerical error code describing the reason this callback is called. If CA_SUCCESS is passed in the playback of the event sound was successfully completed. + * @userdata: Some arbitrary user data the caller of ca_context_play_full() passed in. + * + * Playback completion event callback. The context this callback is + * called in is undefined, it might or might not be called from a + * background thread, and from any stack frame. The code implementing + * this function may not call any libcanberra API call from this + * callback -- this might result in a deadlock. Instead it may only be + * used to asynchronously signal some kind of notification object + * (semaphore, message queue, ...). + */ +typedef void (*ca_finish_callback_t)(ca_context *c, uint32_t id, int error_code, void *userdata); + +/** + * Error codes: + * @CA_SUCCESS: Success + * + * Error codes + */ +enum { + CA_SUCCESS = 0, + CA_ERROR_NOTSUPPORTED = -1, + CA_ERROR_INVALID = -2, + CA_ERROR_STATE = -3, + CA_ERROR_OOM = -4, + CA_ERROR_NODRIVER = -5, + CA_ERROR_SYSTEM = -6, + CA_ERROR_CORRUPT = -7, + CA_ERROR_TOOBIG = -8, + CA_ERROR_NOTFOUND = -9, + CA_ERROR_DESTROYED = -10, + CA_ERROR_CANCELED = -11, + CA_ERROR_NOTAVAILABLE = -12, + CA_ERROR_ACCESS = -13, + CA_ERROR_IO = -14, + CA_ERROR_INTERNAL = -15, + CA_ERROR_DISABLED = -16, + CA_ERROR_FORKED = -17, + CA_ERROR_DISCONNECTED = -18, + _CA_ERROR_MAX = -19 +}; + +/** + * ca_proplist: + * + * A canberra property list object. Basically a hashtable. + */ +typedef struct ca_proplist ca_proplist; + +int ca_proplist_create(ca_proplist **p); +int ca_proplist_destroy(ca_proplist *p); +int ca_proplist_sets(ca_proplist *p, const char *key, const char *value); +int ca_proplist_setf(ca_proplist *p, const char *key, const char *format, ...) __attribute__((format(printf, 3, 4))); +int ca_proplist_set(ca_proplist *p, const char *key, const void *data, size_t nbytes); + +int ca_context_create(ca_context **c); +int ca_context_set_driver(ca_context *c, const char *driver); +int ca_context_change_device(ca_context *c, const char *device); +int ca_context_open(ca_context *c); +int ca_context_destroy(ca_context *c); +int ca_context_change_props(ca_context *c, ...) __attribute__((sentinel)); +int ca_context_change_props_full(ca_context *c, ca_proplist *p); +int ca_context_play_full(ca_context *c, uint32_t id, ca_proplist *p, ca_finish_callback_t cb, void *userdata); +int ca_context_play(ca_context *c, uint32_t id, ...) __attribute__((sentinel)); +int ca_context_cache_full(ca_context *c, ca_proplist *p); +int ca_context_cache(ca_context *c, ...) __attribute__((sentinel)); +int ca_context_cancel(ca_context *c, uint32_t id); +int ca_context_playing(ca_context *c, uint32_t id, int *playing); + +const char *ca_strerror(int code); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/.flatpak-builder/cache/objects/57/c41e14951f4829620b870a3efa1d5cfeafab9aae5acfe844ccdcdef3929341.file b/.flatpak-builder/cache/objects/57/c41e14951f4829620b870a3efa1d5cfeafab9aae5acfe844ccdcdef3929341.file new file mode 100644 index 0000000..effc20c --- /dev/null +++ b/.flatpak-builder/cache/objects/57/c41e14951f4829620b870a3efa1d5cfeafab9aae5acfe844ccdcdef3929341.file @@ -0,0 +1,166 @@ +/* + * Copyright (C) 2008 - 2012 Vivien Malerba + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GDA_DATA_SELECT_H__ +#define __GDA_DATA_SELECT_H__ + +#include +#include +#include +#include + +G_BEGIN_DECLS + +#define GDA_TYPE_DATA_SELECT (gda_data_select_get_type()) + +G_DECLARE_DERIVABLE_TYPE (GdaDataSelect, gda_data_select, GDA, DATA_SELECT, GObject) + +/* + * Depending on model access flags, the implementations are: + * + * if GDA_DATA_MODEL_ACCESS_RANDOM: + * REQUIRED: fetch_nb_rows, fetch_random + * if GDA_STATEMENT_MODEL_CURSOR_FORWARD: + * REQUIRED: fetch_next + * OPTIONAL: fetch_at + * if GDA_STATEMENT_MODEL_CURSOR_BACKWARD: + * REQUIRED: fetch_prev + * OPTIONAL: fetch_at + */ +struct _GdaDataSelectClass { + GObjectClass parent_class; + + /* GDA_DATA_MODEL_ACCESS_RANDOM */ + gint (*fetch_nb_rows) (GdaDataSelect *model); + gboolean (*fetch_random) (GdaDataSelect *model, GdaRow **prow, gint rownum, GError **error); + gboolean (*store_all) (GdaDataSelect *model, GError **error); + + /* GDA_STATEMENT_MODEL_CURSOR_* */ + gboolean (*fetch_next) (GdaDataSelect *model, GdaRow **prow, gint rownum, GError **error); + gboolean (*fetch_prev) (GdaDataSelect *model, GdaRow **prow, gint rownum, GError **error); + gboolean (*fetch_at) (GdaDataSelect *model, GdaRow **prow, gint rownum, GError **error); + + /*< private >*/ + /* Padding for future expansion */ + void (*_gda_reserved1) (void); + void (*_gda_reserved2) (void); + void (*_gda_reserved3) (void); + void (*_gda_reserved4) (void); +}; + + +/* error reporting */ +extern GQuark gda_data_select_error_quark (void); +#define GDA_DATA_SELECT_ERROR gda_data_select_error_quark () + +typedef enum { + GDA_DATA_SELECT_MODIFICATION_STATEMENT_ERROR, + GDA_DATA_SELECT_MISSING_MODIFICATION_STATEMENT_ERROR, + GDA_DATA_SELECT_CONNECTION_ERROR, + GDA_DATA_SELECT_ACCESS_ERROR, + GDA_DATA_SELECT_SQL_ERROR, + GDA_DATA_SELECT_SAFETY_LOCKED_ERROR +} GdaDataSelectError; + +/** + * GdaDataSelectConditionType: + * @GDA_DATA_SELECT_COND_PK: only primary key fields are used + * @GDA_DATA_SELECT_COND_ALL_COLUMNS: all the columns of the tables are used + * + * Defines what criteria gda_data_select_compute_modification_statements_ext() uses + * to uniquely identify a single row in a table when creating modification statements. + */ +typedef enum { + GDA_DATA_SELECT_COND_PK, + GDA_DATA_SELECT_COND_ALL_COLUMNS +} GdaDataSelectConditionType; + +/** + * SECTION:gda-data-select + * @short_description: Base class for data models returned by the execution of a SELECT statement + * @title: GdaDataSelect + * @stability: Stable + * @see_also: #GdaDataModel and the Advanced GdaDataSelect usage section. + * + * This data model implements the GdaDataModel interface and is the required + * base object when database providers implement a data model returned when a SELECT statement has been executed. + * As the GdaDataModel interface is implemented, consult the API + * to access and modify the data held in a GdaDataSelect object. + * + * Depending on the requested data model usage (as specified by the "model_usage" parameter of the + * gda_connection_statement_execute() and similar + * methods, the #GdaDataSelect will allow random access, cursor based access or both. + * + * Also, when later you'll be reading the data contained in a #GdaDataSelect object, depending on the actual + * implementation (which adapts to the API providede by the database server), some calls to the database server + * may be necessary to actually obtain the data. If this behaviour is not the one intended and if you need to + * access the data without having to contact the database server (for example for performances reasons), then + * you can use the gda_data_select_prepare_for_offline() + * method or specify the GDA_STATEMENT_MODEL_OFFLINE + * flag when executing the SELECT statement. + * + * The default behaviour however is to disallow modifications, and this section documents how to parametrize + * a GdaDataSelect to allow modifications. Once this is done, any modification + * done to the data model will be propagated to the modified table in the database using INSERT, UPDATE or DELETE + * statements. + * + * After any modification, it is still possible to read values from the data model (even values for rows which have + * been modified or inserted). The data model might then execute some SELECT statement to fetch some actualized values. + * + * Note: there is a corner case where a modification made to a row would make the row not selected at first in the data model + * (for example is the original SELECT statement included a clause and the modification sets the + * value to 110), then the row will still be in the data model even though it would not be if the SELECT statement + * which execution created the data model in the first place was re-run. This is illustrated in the schema below: + * + * + * + * + * + * GdaDataSelect data model's contents after some modifications + * + * + */ + +gboolean gda_data_select_set_row_selection_condition (GdaDataSelect *model, GdaSqlExpr *expr, GError **error); +gboolean gda_data_select_set_row_selection_condition_sql (GdaDataSelect *model, const gchar *sql_where, GError **error); +gboolean gda_data_select_compute_row_selection_condition (GdaDataSelect *model, GError **error); + +gboolean gda_data_select_set_modification_statement (GdaDataSelect *model, GdaStatement *mod_stmt, GError **error); +gboolean gda_data_select_set_modification_statement_sql (GdaDataSelect *model, const gchar *sql, GError **error); +gboolean gda_data_select_compute_modification_statements (GdaDataSelect *model, GError **error); +gboolean gda_data_select_compute_modification_statements_ext (GdaDataSelect *model, + GdaDataSelectConditionType cond_type, + GError **error); + +gboolean gda_data_select_compute_columns_attributes (GdaDataSelect *model, GError **error); +GdaConnection *gda_data_select_get_connection (GdaDataSelect *model); + +gboolean gda_data_select_prepare_for_offline (GdaDataSelect *model, GError **error); + +#define GDA_TYPE_DATA_SELECT_ITER gda_data_select_iter_get_type() + +G_DECLARE_DERIVABLE_TYPE(GdaDataSelectIter, gda_data_select_iter, GDA, DATA_SELECT_ITER, GdaDataModelIter) + +struct _GdaDataSelectIterClass { + GdaDataModelIterClass parent_class; +}; + +G_END_DECLS + +#endif diff --git a/.flatpak-builder/cache/objects/57/fb82233a1a31031aeca7311318f23777e26f12507cb36794418e23e2339e15.dirtree b/.flatpak-builder/cache/objects/57/fb82233a1a31031aeca7311318f23777e26f12507cb36794418e23e2339e15.dirtree new file mode 100644 index 0000000..b1c0f4b Binary files /dev/null and b/.flatpak-builder/cache/objects/57/fb82233a1a31031aeca7311318f23777e26f12507cb36794418e23e2339e15.dirtree differ diff --git a/.flatpak-builder/cache/objects/58/4244dea64f0e45df802f909b25c5e7aa26e370df4f4fb3a7299e1a879b8888.file b/.flatpak-builder/cache/objects/58/4244dea64f0e45df802f909b25c5e7aa26e370df4f4fb3a7299e1a879b8888.file new file mode 100644 index 0000000..d38b792 --- /dev/null +++ b/.flatpak-builder/cache/objects/58/4244dea64f0e45df802f909b25c5e7aa26e370df4f4fb3a7299e1a879b8888.file @@ -0,0 +1,243 @@ +/* + * Copyright (C) 2019 Daniel Espinosa + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "gda-handler-text.h" +#include +#include +#include +#include + +typedef struct +{ + GWeakRef cnc; +} GdaHandlerTextPrivate; + +static void data_handler_iface_init (GdaDataHandlerInterface *iface); + +G_DEFINE_TYPE_WITH_CODE(GdaHandlerText, gda_handler_text, G_TYPE_OBJECT, + G_ADD_PRIVATE(GdaHandlerText) + G_IMPLEMENT_INTERFACE (GDA_TYPE_DATA_HANDLER, data_handler_iface_init)) + +/** + * gda_handler_text_new: + * + * Creates a data handler for large strings + * + * Returns: (transfer full): the new object + */ +GdaDataHandler* +gda_handler_text_new (void) +{ + GObject *obj; + + obj = g_object_new (GDA_TYPE_HANDLER_TEXT, NULL); + + return (GdaDataHandler *) obj; +} + +/** + * gda_handler_text_new_with_connection: + * @cnc: (nullable): a #GdaConnection object + * + * Creates a data handler for strings, which will use some specific methods implemented + * by the provider object associated with @cnc. + * + * Returns: (type GdaHandlerText) (transfer full): the new object + */ +GdaDataHandler * +gda_handler_text_new_with_connection (GdaConnection *cnc) +{ + GObject *obj; + GdaHandlerText *dh; + + g_return_val_if_fail (cnc != NULL, NULL); + + obj = g_object_new (GDA_TYPE_HANDLER_TEXT, NULL); + dh = (GdaHandlerText*) obj; + + GdaHandlerTextPrivate *priv = gda_handler_text_get_instance_private (dh); + + g_weak_ref_set (&priv->cnc, cnc); + + return (GdaDataHandler *) obj; +} + +static gchar * +gda_handler_text_get_sql_from_value (GdaDataHandler *iface, const GValue *value) +{ + g_return_val_if_fail (GDA_IS_HANDLER_TEXT (iface), NULL); + g_return_val_if_fail (value != NULL, NULL); + + gchar *str, *retval; + GdaHandlerText *hdl; + GdaConnection *cnc; + + hdl = (GdaHandlerText*) (iface); + + GdaHandlerTextPrivate *priv = gda_handler_text_get_instance_private (hdl); + + str = gda_value_stringify ((GValue *) value); + if (str) { + gchar *str2; + cnc = g_weak_ref_get (&priv->cnc); + if (cnc != NULL) { + str2 = gda_server_provider_escape_string (gda_connection_get_provider (cnc), cnc, str); + } else { + str2 = gda_default_escape_string (str); + } + retval = g_strdup_printf ("'%s'", str2); + g_free (str2); + g_free (str); + } else { + retval = g_strdup ("NULL"); + } + + return retval; +} + +static gchar * +gda_handler_text_get_str_from_value (G_GNUC_UNUSED GdaDataHandler *iface, const GValue *value) +{ + g_assert (value); + return gda_value_stringify ((GValue *) value); +} + +static GValue * +gda_handler_text_get_value_from_sql (GdaDataHandler *iface, const gchar *sql, G_GNUC_UNUSED GType type) +{ + GValue *value = NULL; + + g_return_val_if_fail (iface != NULL, NULL); + g_return_val_if_fail (GDA_IS_HANDLER_TEXT (iface), NULL); + g_return_val_if_fail (g_utf8_validate (sql, -1, NULL), NULL); + + if (sql != NULL) { + gchar *unstr = NULL; + if (g_str_has_prefix (sql, "'") && g_str_has_suffix (sql, "'")) { + glong len = g_utf8_strlen (sql, -1); + unstr = g_utf8_substring (sql, 1, len - 1); + } else { + unstr = g_strdup (sql); + } + GdaText *text = gda_text_new (); + gda_text_set_string (text, unstr); + value = gda_value_new (GDA_TYPE_TEXT); + g_value_take_boxed (value, text); + g_free (unstr); + } + else + value = gda_value_new_null (); + + return value; +} + +static GValue * +gda_handler_text_get_value_from_str (G_GNUC_UNUSED GdaDataHandler *iface, const gchar *str, G_GNUC_UNUSED GType type) +{ + GValue *value; + + GdaText *text = gda_text_new (); + gda_text_set_string (text, str); + value = gda_value_new (GDA_TYPE_TEXT); + g_value_take_boxed (value, text); + + return value; +} + +static GValue * +gda_handler_text_get_sane_init_value (G_GNUC_UNUSED GdaDataHandler *iface, G_GNUC_UNUSED GType type) +{ + GValue *value; + + GdaText *text = gda_text_new (); + gda_text_set_string (text, ""); + value = gda_value_new (GDA_TYPE_TEXT); + g_value_take_boxed (value, text); + + return value; +} + +static gboolean +gda_handler_text_accepts_g_type (GdaDataHandler *iface, GType type) +{ + g_return_val_if_fail (iface != NULL, FALSE); + + gboolean ret = FALSE; + + if (g_type_is_a (type, GDA_TYPE_TEXT)) { + ret = TRUE; + } else if (g_type_is_a (type, G_TYPE_STRING)) { + ret = TRUE; + } else if (g_value_type_compatible (type, GDA_TYPE_TEXT)) { + ret = TRUE; + } + return ret; +} + +static const gchar * +gda_handler_text_get_descr (GdaDataHandler *iface) +{ + g_return_val_if_fail (GDA_IS_HANDLER_TEXT (iface), NULL); + return g_object_get_data (G_OBJECT (iface), "descr"); +} + +static void +gda_handler_text_init (GdaHandlerText * hdl) +{ + GdaHandlerTextPrivate *priv = gda_handler_text_get_instance_private (hdl); + g_weak_ref_init (&priv->cnc, NULL); + /* Handler support */ + g_object_set_data (G_OBJECT (hdl), "name", "InternalLargeString"); + g_object_set_data (G_OBJECT (hdl), "descr", _("Large String representation")); +} + +static void +gda_handler_text_dispose (GObject *object) +{ + GdaHandlerText *hdl = (GdaHandlerText *) object; + + g_return_if_fail (object != NULL); + g_return_if_fail (GDA_IS_HANDLER_TEXT (object)); + + GdaHandlerTextPrivate *priv = gda_handler_text_get_instance_private (hdl); + g_weak_ref_clear (&priv->cnc); + + /* for the parent class */ + G_OBJECT_CLASS (gda_handler_text_parent_class)->dispose (object); +} + +static void +data_handler_iface_init (GdaDataHandlerInterface *iface) +{ + iface->get_sql_from_value = gda_handler_text_get_sql_from_value; + iface->get_str_from_value = gda_handler_text_get_str_from_value; + iface->get_value_from_sql = gda_handler_text_get_value_from_sql; + iface->get_value_from_str = gda_handler_text_get_value_from_str; + iface->get_sane_init_value = gda_handler_text_get_sane_init_value; + iface->accepts_g_type = gda_handler_text_accepts_g_type; + iface->get_descr = gda_handler_text_get_descr; +} + +static void +gda_handler_text_class_init (GdaHandlerTextClass * class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (class); + + object_class->dispose = gda_handler_text_dispose; +} diff --git a/.flatpak-builder/cache/objects/58/8623854f205575b04c53416378b10804a085ab710d8a24185d1f87ef0d7758.dirtree b/.flatpak-builder/cache/objects/58/8623854f205575b04c53416378b10804a085ab710d8a24185d1f87ef0d7758.dirtree new file mode 100644 index 0000000..1b15124 Binary files /dev/null and b/.flatpak-builder/cache/objects/58/8623854f205575b04c53416378b10804a085ab710d8a24185d1f87ef0d7758.dirtree differ diff --git a/.flatpak-builder/cache/objects/58/b05e0b78c1387068008be2530905bf46fec51debf9dd7c353d5da817507688.file b/.flatpak-builder/cache/objects/58/b05e0b78c1387068008be2530905bf46fec51debf9dd7c353d5da817507688.file new file mode 100644 index 0000000..b779caa --- /dev/null +++ b/.flatpak-builder/cache/objects/58/b05e0b78c1387068008be2530905bf46fec51debf9dd7c353d5da817507688.file @@ -0,0 +1,11 @@ +prefix=/app +exec_prefix=${prefix} +libdir=${exec_prefix}/lib +includedir=${prefix}/include + +Name: libcanberra +Description: Event Sound API +Version: 0.30 +Libs: -L${libdir} -lcanberra +Cflags: -D_REENTRANT -I${includedir} +Requires: diff --git a/.flatpak-builder/cache/objects/58/cc44fc992100779c0f5b7cbd6d6e73452aecac5248582ab03d317dc5d48c3b.file b/.flatpak-builder/cache/objects/58/cc44fc992100779c0f5b7cbd6d6e73452aecac5248582ab03d317dc5d48c3b.file new file mode 100644 index 0000000..492f19e --- /dev/null +++ b/.flatpak-builder/cache/objects/58/cc44fc992100779c0f5b7cbd6d6e73452aecac5248582ab03d317dc5d48c3b.file @@ -0,0 +1,124 @@ +# gtk_file_filter.py +# +# Copyright 2021 James Westman +# +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation; either version 3 of the +# License, or (at your option) any later version. +# +# This file is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program. If not, see . +# +# SPDX-License-Identifier: LGPL-3.0-or-later + + +from .gobject_object import ObjectContent, validate_parent_type +from .common import * + + +class Filters(AstNode): + @validate() + def container_is_file_filter(self): + validate_parent_type(self, "Gtk", "FileFilter", "file filter properties") + + @validate() + def unique_in_parent(self): + # The token argument to validate() needs to be calculated based on + # the instance, hence wrapping it like this. + @validate(self.tokens["tag_name"]) + def wrapped_validator(self): + self.validate_unique_in_parent( + f"Duplicate {self.tokens['tag_name']} block", + check=lambda child: child.tokens["tag_name"] == self.tokens["tag_name"], + ) + + wrapped_validator(self) + + +class FilterString(AstNode): + @property + def item(self) -> str: + return self.tokens["name"] + + @validate() + def unique_in_parent(self): + self.validate_unique_in_parent( + f"Duplicate {self.tokens['tag_name']} '{self.item}'", + check=lambda child: child.item == self.item, + ) + + +def create_node(tag_name: str, singular: str): + return Group( + Filters, + [ + Keyword(tag_name), + UseLiteral("tag_name", tag_name), + "[", + Delimited( + Group( + FilterString, + [ + UseQuoted("name"), + UseLiteral("tag_name", singular), + ], + ), + ",", + ), + "]", + ], + ) + + +ext_file_filter_mime_types = create_node("mime-types", "mime-type") +ext_file_filter_patterns = create_node("patterns", "pattern") +ext_file_filter_suffixes = create_node("suffixes", "suffix") + + +@completer( + applies_in=[ObjectContent], + applies_in_subclass=("Gtk", "FileFilter"), + matches=new_statement_patterns, +) +def file_filter_completer(ast_node, match_variables): + yield Completion( + "mime-types", CompletionItemKind.Snippet, snippet='mime-types ["$0"]' + ) + yield Completion("patterns", CompletionItemKind.Snippet, snippet='patterns ["$0"]') + yield Completion("suffixes", CompletionItemKind.Snippet, snippet='suffixes ["$0"]') + + +@decompiler("mime-types") +def decompile_mime_types(ctx, gir): + ctx.print("mime-types [") + + +@decompiler("mime-type", cdata=True) +def decompile_mime_type(ctx, gir, cdata): + ctx.print(f'"{cdata}",') + + +@decompiler("patterns") +def decompile_patterns(ctx, gir): + ctx.print("patterns [") + + +@decompiler("pattern", cdata=True) +def decompile_pattern(ctx, gir, cdata): + ctx.print(f'"{cdata}",') + + +@decompiler("suffixes") +def decompile_suffixes(ctx, gir): + ctx.print("suffixes [") + + +@decompiler("suffix", cdata=True) +def decompile_suffix(ctx, gir, cdata): + ctx.print(f'"{cdata}",') diff --git a/.flatpak-builder/cache/objects/58/e4f98f44cb7d6c95b221f357b34eeb7c18e7d2df433d578a6577d39f88347f.file b/.flatpak-builder/cache/objects/58/e4f98f44cb7d6c95b221f357b34eeb7c18e7d2df433d578a6577d39f88347f.file new file mode 100644 index 0000000..718b4c7 --- /dev/null +++ b/.flatpak-builder/cache/objects/58/e4f98f44cb7d6c95b221f357b34eeb7c18e7d2df433d578a6577d39f88347f.file @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2000 Reinhard Müller + * Copyright (C) 2000 - 2002 Rodrigo Moya + * Copyright (C) 2001 Carlos Perelló Marín + * Copyright (C) 2001 - 2012 Vivien Malerba + * Copyright (C) 2002 Gonzalo Paniagua Javier + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GDA_META_STORE_EXTRA_H_ +#define __GDA_META_STORE_EXTRA_H_ + +G_BEGIN_DECLS + +gboolean _gda_meta_store_begin_data_reset (GdaMetaStore *store, GError **error); +gboolean _gda_meta_store_cancel_data_reset (GdaMetaStore *store, GError **error); +gboolean _gda_meta_store_finish_data_reset (GdaMetaStore *store, GError **error); + +GdaMetaContext *_gda_meta_store_validate_context (GdaMetaStore *store, GdaMetaContext *context, GError **error); +GSList *_gda_meta_store_schema_get_upstream_contexts (GdaMetaStore *store, GdaMetaContext *context, GError **error); +GSList *_gda_meta_store_schema_get_downstream_contexts (GdaMetaStore *store, GdaMetaContext *context, GError **error); + +G_END_DECLS + +#endif diff --git a/.flatpak-builder/cache/objects/59/0fcef45719fda14e5aaab578cd89901890aa44a6e11d5f9fd7ab9ed03a2d9e.commit b/.flatpak-builder/cache/objects/59/0fcef45719fda14e5aaab578cd89901890aa44a6e11d5f9fd7ab9ed03a2d9e.commit new file mode 100644 index 0000000..f2a77b0 Binary files /dev/null and b/.flatpak-builder/cache/objects/59/0fcef45719fda14e5aaab578cd89901890aa44a6e11d5f9fd7ab9ed03a2d9e.commit differ diff --git a/.flatpak-builder/cache/objects/59/24bb7aa43181e236e98660625395c7e18fb7232c42bd422d6edc94fd9b8b7e.dirtree b/.flatpak-builder/cache/objects/59/24bb7aa43181e236e98660625395c7e18fb7232c42bd422d6edc94fd9b8b7e.dirtree new file mode 100644 index 0000000..e38b46e Binary files /dev/null and b/.flatpak-builder/cache/objects/59/24bb7aa43181e236e98660625395c7e18fb7232c42bd422d6edc94fd9b8b7e.dirtree differ diff --git a/.flatpak-builder/cache/objects/59/2e0f2e103acca44b913d070dac202f610986c853f0ac2a6ee6ed9624c27eaa.file b/.flatpak-builder/cache/objects/59/2e0f2e103acca44b913d070dac202f610986c853f0ac2a6ee6ed9624c27eaa.file new file mode 100644 index 0000000..c0effd6 Binary files /dev/null and b/.flatpak-builder/cache/objects/59/2e0f2e103acca44b913d070dac202f610986c853f0ac2a6ee6ed9624c27eaa.file differ diff --git a/.flatpak-builder/cache/objects/59/bbcc2dbd6248ee570e2316004dc5a1c0c11abe11e87d4eeb2518f7b9c9d73f.file b/.flatpak-builder/cache/objects/59/bbcc2dbd6248ee570e2316004dc5a1c0c11abe11e87d4eeb2518f7b9c9d73f.file new file mode 100644 index 0000000..5c45b99 --- /dev/null +++ b/.flatpak-builder/cache/objects/59/bbcc2dbd6248ee570e2316004dc5a1c0c11abe11e87d4eeb2518f7b9c9d73f.file @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2005 - 2011 Vivien Malerba + * Copyright (C) 2005 Álvaro Peńa + * Copyright (C) 2008 Przemysław Grzegorczyk + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GDA_COLUMN_H__ +#define __GDA_COLUMN_H__ + +#include +#include +#include +#include + +G_BEGIN_DECLS + +#define GDA_TYPE_COLUMN (gda_column_get_type()) +G_DECLARE_DERIVABLE_TYPE (GdaColumn, gda_column, GDA, COLUMN, GObject) + +struct _GdaColumnClass { + GObjectClass parent_class; + + /* signals */ + void (* name_changed) (GdaColumn *column, const gchar *old_name); + void (* g_type_changed) (GdaColumn *column, GType old_type, GType new_type); + + /*< private >*/ + /* Padding for future expansion */ + void (*_gda_reserved1) (void); + void (*_gda_reserved2) (void); + void (*_gda_reserved3) (void); + void (*_gda_reserved4) (void); +}; + +/** + * SECTION:gda-column + * @short_description: Management of #GdaDataModel column attributes + * @title: GdaDataModel columns + * @stability: Stable + * @see_also: #GdaDataModel + * + * The #GdaColumn object represents a #GdaDataModel's column and handle all its properties. + */ + +GdaColumn *gda_column_new (void); +GdaColumn *gda_column_copy (GdaColumn *column); + +const gchar *gda_column_get_description (GdaColumn *column); +void gda_column_set_description (GdaColumn *column, const gchar *descr); + +const gchar *gda_column_get_name (GdaColumn *column); +void gda_column_set_name (GdaColumn *column, const gchar *name); + +const gchar* gda_column_get_dbms_type (GdaColumn *column); +void gda_column_set_dbms_type (GdaColumn *column, const gchar *dbms_type); + +GType gda_column_get_g_type (GdaColumn *column); +void gda_column_set_g_type (GdaColumn *column, GType type); + +gboolean gda_column_get_allow_null (GdaColumn *column); +void gda_column_set_allow_null (GdaColumn *column, gboolean allow); + +gboolean gda_column_get_auto_increment (GdaColumn *column); +void gda_column_set_auto_increment (GdaColumn *column, gboolean is_auto); + +gint gda_column_get_position (GdaColumn *column); +void gda_column_set_position (GdaColumn *column, gint position); + +const GValue *gda_column_get_default_value (GdaColumn *column); +void gda_column_set_default_value (GdaColumn *column, const GValue *default_value); + + +/** + * gda_column_set_attribute_static: + * @holder: a #GdaHolder + * @attribute: attribute's name + * @value: (nullable): the value to set the attribute to, or %NULL + * + * This function is similar to gda_column_set_attribute() but for static strings + */ +#define gda_column_set_attribute_static(holder,attribute,value) gda_column_set_attribute((holder),(attribute),(value),NULL) + +G_END_DECLS + +#endif diff --git a/.flatpak-builder/cache/objects/59/e975571731af0d6c6b2412a33908ad38dae19bc8f2d31650a0369ca9b1e321.file b/.flatpak-builder/cache/objects/59/e975571731af0d6c6b2412a33908ad38dae19bc8f2d31650a0369ca9b1e321.file new file mode 100644 index 0000000..094e449 --- /dev/null +++ b/.flatpak-builder/cache/objects/59/e975571731af0d6c6b2412a33908ad38dae19bc8f2d31650a0369ca9b1e321.file @@ -0,0 +1,87 @@ +# completions_utils.py +# +# Copyright 2021 James Westman +# +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation; either version 3 of the +# License, or (at your option) any later version. +# +# This file is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program. If not, see . +# +# SPDX-License-Identifier: LGPL-3.0-or-later + + +import typing as T + +from .tokenizer import Token, TokenType +from .lsp_utils import Completion + + +new_statement_patterns = [ + [(TokenType.PUNCTUATION, "{")], + [(TokenType.PUNCTUATION, "}")], + [(TokenType.PUNCTUATION, "]")], + [(TokenType.PUNCTUATION, ";")], +] + + +def applies_to(*ast_types): + """Decorator describing which AST nodes the completer should apply in.""" + + def decorator(func): + for c in ast_types: + c.completers.append(func) + return func + + return decorator + + +def completer(applies_in: T.List, matches: T.List = [], applies_in_subclass=None): + def decorator(func): + def inner(prev_tokens: T.List[Token], ast_node): + # For completers that apply in ObjectContent nodes, we can further + # check that the object is the right class + if applies_in_subclass is not None: + type = ast_node.root.gir.get_type( + applies_in_subclass[1], applies_in_subclass[0] + ) + if ast_node.gir_class and not ast_node.gir_class.assignable_to(type): + return + + any_match = len(matches) == 0 + match_variables: T.List[str] = [] + + for pattern in matches: + match_variables = [] + + if len(pattern) <= len(prev_tokens): + for i in range(0, len(pattern)): + type, value = pattern[i] + token = prev_tokens[i - len(pattern)] + if token.type != type or ( + value is not None and str(token) != value + ): + break + if value is None: + match_variables.append(str(token)) + else: + any_match = True + break + + if not any_match: + return + + yield from func(ast_node, match_variables) + + for c in applies_in: + c.completers.append(inner) + return inner + + return decorator diff --git a/.flatpak-builder/cache/objects/59/fac65baf5744d11ff831fc60ac3b358ca10b1d41c7273145a29fee348453c4.dirtree b/.flatpak-builder/cache/objects/59/fac65baf5744d11ff831fc60ac3b358ca10b1d41c7273145a29fee348453c4.dirtree new file mode 100644 index 0000000..0c0980a Binary files /dev/null and b/.flatpak-builder/cache/objects/59/fac65baf5744d11ff831fc60ac3b358ca10b1d41c7273145a29fee348453c4.dirtree differ diff --git a/.flatpak-builder/cache/objects/5a/33e6dcba3567eae49d6dcf878952c9707ebb7c4e3df3ca73c006e4c5b73085.dirtree b/.flatpak-builder/cache/objects/5a/33e6dcba3567eae49d6dcf878952c9707ebb7c4e3df3ca73c006e4c5b73085.dirtree new file mode 100644 index 0000000..1d8f866 Binary files /dev/null and b/.flatpak-builder/cache/objects/5a/33e6dcba3567eae49d6dcf878952c9707ebb7c4e3df3ca73c006e4c5b73085.dirtree differ diff --git a/.flatpak-builder/cache/objects/5a/63730da8f0de8c965e27d46ca7b056a6a381432050058169517f13709bd0e9.file b/.flatpak-builder/cache/objects/5a/63730da8f0de8c965e27d46ca7b056a6a381432050058169517f13709bd0e9.file new file mode 100644 index 0000000..476fdbe --- /dev/null +++ b/.flatpak-builder/cache/objects/5a/63730da8f0de8c965e27d46ca7b056a6a381432050058169517f13709bd0e9.file @@ -0,0 +1,350 @@ +/* + * Copyright (C) 2006 Rodrigo Moya + * Copyright (C) 2006 - 2013 Vivien Malerba + * Copyright (C) 2007 - 2011 Murray Cumming + * Copyright (C) 2009 Bas Driessen + * Copyright (C) 2010 David King + * Copyright (C) 2010 Jonh Wendell + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "gda-handler-numerical.h" +#include +#include + +struct _GdaHandlerNumerical +{ + GObject parent_instance; + + guint nb_g_types; + GType *valid_g_types; +}; + +static void data_handler_iface_init (GdaDataHandlerInterface *iface); + +G_DEFINE_TYPE_EXTENDED (GdaHandlerNumerical, gda_handler_numerical, G_TYPE_OBJECT, 0, + G_IMPLEMENT_INTERFACE (GDA_TYPE_DATA_HANDLER, data_handler_iface_init)) + +/** + * gda_handler_numerical_new: + * + * Creates a data handler for numerical values + * + * Returns: (type GdaHandlerNumerical) (transfer full): the new object + */ +GdaDataHandler * +gda_handler_numerical_new (void) +{ + GObject *obj; + + obj = g_object_new (GDA_TYPE_HANDLER_NUMERICAL, NULL); + + return (GdaDataHandler *) obj; +} + + +/* Interface implementation */ +static gchar * +gda_handler_numerical_get_sql_from_value (G_GNUC_UNUSED GdaDataHandler *iface, const GValue *value) +{ + g_assert (value); + + gchar *retval; + retval = gda_value_stringify ((GValue *) value); + + if (!retval) + retval = g_strdup ("0"); + + return retval; +} + +static gchar * +gda_handler_numerical_get_str_from_value (G_GNUC_UNUSED GdaDataHandler *iface, const GValue *value) +{ + g_assert (value); + return gda_value_stringify ((GValue *) value); +} + +/* + * if @c_locale is %TRUE, then @str is expected to be in the "C" locale, and if it is %FALSE, + * then @str is expected to be in the current (user defined) locale + */ +static GValue * +_gda_handler_numerical_get_value_from_str_locale (const gchar *str, GType type, gboolean c_locale) +{ + g_assert (str); + GValue *value = NULL; + long long int llint; + char *endptr = NULL; + + if (c_locale) + llint = g_ascii_strtoull (str, &endptr, 10); + else + llint = strtoll (str, &endptr, 10); + + if (type == G_TYPE_INT64) { + if (!*endptr && (llint >= G_MININT64) && (llint <= G_MAXINT64)) { + value = g_value_init (g_new0 (GValue, 1), G_TYPE_INT64); + g_value_set_int64 (value, (gint64) llint); + } + } + else if (type == G_TYPE_DOUBLE) { + gdouble dble; + if (c_locale) + dble = g_ascii_strtod (str, &endptr); + else + dble = g_strtod (str, &endptr); + if (!*endptr) { + value = g_value_init (g_new0 (GValue, 1), G_TYPE_DOUBLE); + g_value_set_double (value, dble); + } + } + else if (type == G_TYPE_FLOAT) { + gfloat flt; + if (c_locale) + flt = g_ascii_strtod (str, &endptr); + else + flt = strtof (str, &endptr); + if (!*endptr) { + value = g_value_init (g_new0 (GValue, 1), G_TYPE_FLOAT); + g_value_set_float (value, flt); + } + } + else if (type == G_TYPE_INT) { + if (!*endptr && (llint >= G_MININT) && (llint <= G_MAXINT)) { + value = g_value_init (g_new0 (GValue, 1), G_TYPE_INT); + g_value_set_int (value, (gint) llint); + } + } + else if (type == GDA_TYPE_NUMERIC) { + GdaNumeric *numeric; + const gchar *p = str; + gboolean ok = TRUE; + gboolean hasdot = FALSE; + + numeric = gda_numeric_new (); + gda_numeric_set_precision (numeric, 0); + gda_numeric_set_width (numeric, 0); + while (p && *p && ok) { + if ((*p == '.') || (*p == ',')) { + if (hasdot) + ok = FALSE; + else + hasdot = TRUE; + } + else { + if (!g_ascii_isdigit (*p)) + ok = FALSE; + else { + if (hasdot) + gda_numeric_set_precision (numeric, + gda_numeric_get_precision (numeric) + 1); + gda_numeric_set_width (numeric, + gda_numeric_get_width (numeric) + 1); + } + } + p++; + } + if (ok) { + gdouble d; + char *end = NULL; + if (c_locale) + d = g_ascii_strtod (str, &end); + else + d = strtod (str, &end); + if (! *end) { + value = g_value_init (g_new0 (GValue, 1), GDA_TYPE_NUMERIC); + gda_numeric_set_double (numeric, d); + gda_value_set_numeric (value, numeric); + } + } + gda_numeric_free (numeric); + } + else if (type == GDA_TYPE_SHORT) { + if (!*endptr && (llint >= G_MINSHORT) && (llint <= G_MAXSHORT)) { + value = g_value_init (g_new0 (GValue, 1), GDA_TYPE_SHORT); + gda_value_set_short (value, (gshort) llint); + } + } + else if (type == G_TYPE_CHAR) { + if (!*endptr && (llint >= G_MININT8) && (llint <= G_MAXINT8)) { + value = g_value_init (g_new0 (GValue, 1), G_TYPE_CHAR); + g_value_set_schar (value, (gchar) llint); + } + } + else if (type == G_TYPE_UINT64) { + if (!*endptr && (llint >= 0) && (llint <= G_MAXINT64)) { + value = g_value_init (g_new0 (GValue, 1), G_TYPE_UINT64); + g_value_set_uint64 (value, (guint64) llint); + } + else { + unsigned long long int lluint; + lluint = strtoull (str, &endptr, 10); + if (!*endptr && (lluint <= G_MAXUINT64)) { + value = g_value_init (g_new0 (GValue, 1), G_TYPE_UINT64); + g_value_set_uint64 (value, (guint64) lluint); + } + } + } + else if (type == GDA_TYPE_USHORT) { + if (!*endptr && (llint >= 0) && (llint <= G_MAXUSHORT)) { + value = g_value_init (g_new0 (GValue, 1), GDA_TYPE_USHORT); + gda_value_set_ushort (value, (gushort) llint); + } + } + else if (type == G_TYPE_UCHAR) { + if (!*endptr && (llint >= 0) && (llint <= G_MAXUINT8)) { + value = g_value_init (g_new0 (GValue, 1), G_TYPE_UCHAR); + g_value_set_uchar (value, (guchar) llint); + } + } + else if (type == G_TYPE_UINT) { + if (!*endptr && (llint >= 0) && (llint <= G_MAXUINT)) { + value = g_value_init (g_new0 (GValue, 1), G_TYPE_UINT); + g_value_set_uint (value, (guint) llint); + } + } + else if (type == G_TYPE_ULONG) { + if (!*endptr && (llint >= 0) && ((gulong) llint <= G_MAXULONG)) { + value = g_value_init (g_new0 (GValue, 1), G_TYPE_ULONG); + g_value_set_ulong (value, (gulong) llint); + } + else { + unsigned long long int lluint; + lluint = strtoull (str, &endptr, 10); + if (!*endptr && (lluint <= G_MAXULONG)) { + value = g_value_init (g_new0 (GValue, 1), G_TYPE_ULONG); + g_value_set_ulong (value, (gulong) lluint); + } + } + } + else if (type == G_TYPE_LONG) { + if (!*endptr && (llint >= G_MINLONG) && (llint <= G_MAXLONG)) { + value = g_value_init (g_new0 (GValue, 1), G_TYPE_LONG); + g_value_set_long (value, (glong) llint); + } + } + else + g_assert_not_reached (); + + return value; +} + +static GValue * +gda_handler_numerical_get_value_from_sql (G_GNUC_UNUSED GdaDataHandler *iface, const gchar *sql, GType type) +{ + return _gda_handler_numerical_get_value_from_str_locale (sql, type, TRUE); +} + +static GValue * +gda_handler_numerical_get_value_from_str (G_GNUC_UNUSED GdaDataHandler *iface, const gchar *str, GType type) +{ + return _gda_handler_numerical_get_value_from_str_locale (str, type, FALSE); +} + +static GValue * +gda_handler_numerical_get_sane_init_value (G_GNUC_UNUSED GdaDataHandler *iface, GType type) +{ + GValue *value; + value = gda_handler_numerical_get_value_from_sql (iface, "", type); + + return value; +} + +static gboolean +gda_handler_numerical_accepts_g_type (GdaDataHandler *iface, GType type) +{ + GdaHandlerNumerical *hdl; + guint i = 0; + + g_assert (iface); + hdl = (GdaHandlerNumerical*) (iface); + for (i = 0; i < hdl->nb_g_types; i++) { + if (hdl->valid_g_types [i] == type) + return TRUE; + } + + return FALSE; +} + +static const gchar * +gda_handler_numerical_get_descr (GdaDataHandler *iface) +{ + g_return_val_if_fail (GDA_IS_HANDLER_NUMERICAL (iface), NULL); + return g_object_get_data (G_OBJECT (iface), "descr"); +} + +static void +gda_handler_numerical_init (GdaHandlerNumerical * hdl) +{ + /* Private structure */ + hdl->nb_g_types = 13; + hdl->valid_g_types = g_new0 (GType, hdl->nb_g_types); + hdl->valid_g_types[0] = G_TYPE_INT64; + hdl->valid_g_types[1] = G_TYPE_DOUBLE; + hdl->valid_g_types[2] = G_TYPE_INT; + hdl->valid_g_types[3] = GDA_TYPE_NUMERIC; + hdl->valid_g_types[4] = G_TYPE_FLOAT; + hdl->valid_g_types[5] = GDA_TYPE_SHORT; + hdl->valid_g_types[6] = G_TYPE_CHAR; + hdl->valid_g_types[7] = G_TYPE_UINT64; + hdl->valid_g_types[8] = GDA_TYPE_USHORT; + hdl->valid_g_types[9] = G_TYPE_UCHAR; + hdl->valid_g_types[10] = G_TYPE_UINT; + hdl->valid_g_types[11] = G_TYPE_ULONG; + hdl->valid_g_types[12] = G_TYPE_LONG; + + g_object_set_data (G_OBJECT (hdl), "name", "InternalNumerical"); + g_object_set_data (G_OBJECT (hdl), "descr", _("Numerical representation")); +} + +static void +gda_handler_numerical_dispose (GObject *object) +{ + GdaHandlerNumerical *hdl; + + g_return_if_fail (object != NULL); + g_return_if_fail (GDA_IS_HANDLER_NUMERICAL (object)); + + hdl = GDA_HANDLER_NUMERICAL (object); + + g_clear_pointer (&hdl->valid_g_types, g_free); + + /* for the parent class */ + G_OBJECT_CLASS (gda_handler_numerical_parent_class)->dispose (object); +} + +static void +data_handler_iface_init (GdaDataHandlerInterface *iface) +{ + iface->get_sql_from_value = gda_handler_numerical_get_sql_from_value; + iface->get_str_from_value = gda_handler_numerical_get_str_from_value; + iface->get_value_from_sql = gda_handler_numerical_get_value_from_sql; + iface->get_value_from_str = gda_handler_numerical_get_value_from_str; + iface->get_sane_init_value = gda_handler_numerical_get_sane_init_value; + iface->accepts_g_type = gda_handler_numerical_accepts_g_type; + iface->get_descr = gda_handler_numerical_get_descr; +} + + +static void +gda_handler_numerical_class_init (GdaHandlerNumericalClass * class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (class); + + object_class->dispose = gda_handler_numerical_dispose; +} diff --git a/.flatpak-builder/cache/objects/5a/8a66529cb2c3d8e7d486f29b9ce5d7095fb8b93aa582a0984779bc1fdce358.file b/.flatpak-builder/cache/objects/5a/8a66529cb2c3d8e7d486f29b9ce5d7095fb8b93aa582a0984779bc1fdce358.file new file mode 120000 index 0000000..7b2a969 --- /dev/null +++ b/.flatpak-builder/cache/objects/5a/8a66529cb2c3d8e7d486f29b9ce5d7095fb8b93aa582a0984779bc1fdce358.file @@ -0,0 +1 @@ +../../share/runtime/locale/el/share/el \ No newline at end of file diff --git a/.flatpak-builder/cache/objects/5a/969185121510f655337e284d7b7eaef0a31bbe6be0747d00594755a93f816c.dirtree b/.flatpak-builder/cache/objects/5a/969185121510f655337e284d7b7eaef0a31bbe6be0747d00594755a93f816c.dirtree new file mode 100644 index 0000000..4ec46f4 Binary files /dev/null and b/.flatpak-builder/cache/objects/5a/969185121510f655337e284d7b7eaef0a31bbe6be0747d00594755a93f816c.dirtree differ diff --git a/.flatpak-builder/cache/objects/5a/f33270d8e0cce9f97daa735c61079b703bee865f7ee71a0fbae359475bad15.dirtree b/.flatpak-builder/cache/objects/5a/f33270d8e0cce9f97daa735c61079b703bee865f7ee71a0fbae359475bad15.dirtree new file mode 100644 index 0000000..b6c8daa Binary files /dev/null and b/.flatpak-builder/cache/objects/5a/f33270d8e0cce9f97daa735c61079b703bee865f7ee71a0fbae359475bad15.dirtree differ diff --git a/.flatpak-builder/cache/objects/5b/685532b813d5ed6073b1ee074280c3856b55aa77066eeae0095058144815f3.file b/.flatpak-builder/cache/objects/5b/685532b813d5ed6073b1ee074280c3856b55aa77066eeae0095058144815f3.file new file mode 100644 index 0000000..d1780d2 --- /dev/null +++ b/.flatpak-builder/cache/objects/5b/685532b813d5ed6073b1ee074280c3856b55aa77066eeae0095058144815f3.file @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2009 - 2011 Vivien Malerba + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GDA_TREE_NODE_H__ +#define __GDA_TREE_NODE_H__ + +#include +#include +#include "gda-decl.h" + +G_BEGIN_DECLS + +#define GDA_TYPE_TREE_NODE (gda_tree_node_get_type()) +G_DECLARE_DERIVABLE_TYPE (GdaTreeNode, gda_tree_node, GDA, TREE_NODE, GObject) + + +struct _GdaTreeNodeClass { + GObjectClass object_class; + + /* signals */ + void (* node_changed) (GdaTreeNode *reporting, GdaTreeNode *node); + void (* node_inserted) (GdaTreeNode *reporting, GdaTreeNode *node); + void (* node_has_child_toggled) (GdaTreeNode *reporting, GdaTreeNode *node); + void (* node_deleted) (GdaTreeNode *reporting, const gchar *relative_path); + + /* virtual methods */ + gchar *(*dump_header) (GdaTreeNode *node); + void (*dump_children) (GdaTreeNode *node, const gchar *prefix, GString *in_string); + + /*< private >*/ + /* Padding for future expansion */ + void (*_gda_reserved1) (void); + void (*_gda_reserved2) (void); + void (*_gda_reserved3) (void); + void (*_gda_reserved4) (void); +}; + +/* error reporting */ +extern GQuark gda_tree_node_error_quark (void); +#define GDA_TREE_NODE_ERROR gda_tree_node_error_quark () + +typedef enum { + GDA_TREE_NODE_UNKNOWN_ERROR +} GdaTreeNodeError; + +/** + * SECTION:gda-tree-node + * @short_description: A node in a #GdaTree + * @title: GdaTreeNode + * @stability: Stable + * @see_also: + * + * Every node in a #GdaTree tree is represented by a single #GdaTreeNode object. There is no distinction + * between nodes which have children and those which don't (leaf nodes). + * + * The #GdaTreeNode is very basic as it only has a "name" attribute: users are encouraged to subclass it to + * add more features if needed (and make use of them by defining a #GdaTreeManagerNodeFunc function and + * calling gda_tree_manager_set_node_create_func()). + */ + +GdaTreeNode* gda_tree_node_new (const gchar *name); + +GdaTreeNode *gda_tree_node_get_parent (GdaTreeNode *node); +GSList *gda_tree_node_get_children (GdaTreeNode *node); +GdaTreeNode *gda_tree_node_get_child_index (GdaTreeNode *node, gint index); +GdaTreeNode *gda_tree_node_get_child_name (GdaTreeNode *node, const gchar *name); + +void gda_tree_node_set_node_attribute(GdaTreeNode *node, const gchar *attribute, const GValue *value, + GDestroyNotify destroy); +const GValue *gda_tree_node_get_node_attribute(GdaTreeNode *node, const gchar *attribute); +const GValue *gda_tree_node_fetch_attribute (GdaTreeNode *node, const gchar *attribute); + +/* private */ +void _gda_tree_node_add_children (GdaTreeNode *node, GdaTreeManager *mgr, const GSList *children); +const GSList *_gda_tree_node_get_children_for_manager (GdaTreeNode *node, GdaTreeManager *mgr); +GSList *_gda_tree_node_get_managers_for_children (GdaTreeNode *node); +GdaTreeManager *_gda_tree_node_get_manager_for_child (GdaTreeNode *node, GdaTreeNode *child); + +G_END_DECLS + +#endif diff --git a/.flatpak-builder/cache/objects/5b/a5b4ca4c385bc36927f399f8039a2f5a5dd932c9998372a2ed49ef0f747eb7.file b/.flatpak-builder/cache/objects/5b/a5b4ca4c385bc36927f399f8039a2f5a5dd932c9998372a2ed49ef0f747eb7.file new file mode 100644 index 0000000..bd4552e --- /dev/null +++ b/.flatpak-builder/cache/objects/5b/a5b4ca4c385bc36927f399f8039a2f5a5dd932c9998372a2ed49ef0f747eb7.file @@ -0,0 +1,197 @@ +/* + * Copyright (C) 2000 Reinhard Müller + * Copyright (C) 2000 - 2005 Rodrigo Moya + * Copyright (C) 2001 - 2015 Vivien Malerba + * Copyright (C) 2002 Gonzalo Paniagua Javier + * Copyright (C) 2003 Laurent Sansonetti + * Copyright (C) 2003 - 2007 Murray Cumming + * Copyright (C) 2005 Andrew Hill + * Copyright (C) 2013, 2018 Daniel Espinosa + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GDA_CONFIG_H__ +#define __GDA_CONFIG_H__ + +#include "gda-decl.h" +#include + +G_BEGIN_DECLS + +typedef struct _GdaDsnInfo GdaDsnInfo; + +/* error reporting */ +extern GQuark gda_config_error_quark (void); +#define GDA_CONFIG_ERROR gda_config_error_quark () + +typedef enum { + GDA_CONFIG_DSN_NOT_FOUND_ERROR, + GDA_CONFIG_PERMISSION_ERROR, + GDA_CONFIG_PROVIDER_NOT_FOUND_ERROR, + GDA_CONFIG_PROVIDER_CREATION_ERROR +} GdaConfigError; + +/** + * GdaDsnInfo: + * @name: the (unique) name of the DSN (plain text, not RFC 1738 encoded) + * @provider: the ID of the database provider to be used (plain text, not RFC 1738 encoded) + * @description: a descriptive string (plain text, not RFC 1738 encoded), can be %NULL. + * @cnc_string: the connection string, a semi-colon separated <key>=<value> list where <key> and <value> are RFC 1738 encoded + * @auth_string: the authentication string, a semi-colon separated <key>=<value> list where <key> and <value> are RFC 1738 encoded. Can be %NULL. + * @is_system: %TRUE if the DSN is a system wide defined data source + * + * This structure defines the properties of a named data source (DSN). + */ +struct _GdaDsnInfo { + gchar *name; + gchar *provider; + gchar *description; + gchar *cnc_string; + gchar *auth_string; + gboolean is_system; + + /*< private >*/ + /* Padding for future expansion */ + gpointer _gda_reserved1; + gpointer _gda_reserved2; + gpointer _gda_reserved3; + gpointer _gda_reserved4; +}; + +#define GDA_TYPE_DSN_INFO (gda_dsn_info_get_type ()) + +GType gda_dsn_info_get_type (void) G_GNUC_CONST; +GdaDsnInfo* gda_dsn_info_new (void); +GdaDsnInfo* gda_dsn_info_copy (const GdaDsnInfo *source); +void gda_dsn_info_free (GdaDsnInfo *dsn); +gboolean gda_dsn_info_equal (const GdaDsnInfo *dsn1, const GdaDsnInfo *dsn2); + +/** + * GdaProviderInfo: + * @id: the unique identifier of the database provider + * @location: the complete path to the shared library implementing the database provider + * @description: provider's description + * @dsn_params: a #GdaSet containing all the parameters which can/must be specified when opening a connection or defining a named data source (DSN) + * @auth_params: a #GdaSet containing all the authentication parameters + * + * This structure holds the information associated to a database provider as discovered by Libgda. + */ +typedef struct { + gchar *id; + gchar *location; + gchar *description; + GdaSet *dsn_params; /* Specs to create a DSN */ + GdaSet *auth_params; /* Specs to authenticate a client */ + gchar *icon_id; /* use gdaui_get_icon_for_db_engine(icon_id) to get the actual GdkPixbuf */ + + /*< private >*/ + /* Padding for future expansion */ + gpointer _gda_reserved1; + gpointer _gda_reserved2; + gpointer _gda_reserved3; + gpointer _gda_reserved4; +} GdaProviderInfo; + +#define GDA_TYPE_PROVIDER_INFO (gda_provider_info_get_type ()) + +GType gda_provider_info_get_type (void) G_GNUC_CONST; + + +/** + * SECTION:gda-config + * @short_description: Access/Management of libgda configuration + * @title: Configuration + * @stability: Stable + * @see_also: + * + * The functions in this section allow applications an easy access to libgda's + * configuration (the list of data sources and database providers). + * + * As soon as a GdaConfig is needed (for example when requesting information + * about a data source or about a server provider), a single instance object is created, + * and no other will need to be created. A pointer to this object can be obtained with + * gda_config_get(). Of course one can (right after having called + * gda_init()) force the creation of a GdaConfig object with some + * specific properties set, using a simple call like: + * + *g_object_new (GDA_TYPE_CONFIG, "user-filename", "my_file", NULL); + * + * Please note that after that call, the caller has a reference to the newly created object, and should technically + * call g_object_unref() when finished using it. It is safe to do this + * but also pointless since that object should not be destroyed (as no other will be created) as &LIBGDA; also + * keeps a reference for itself. + * + *Data sources are defined in a per-user configuration file which is by default ${HOME}/.libgda/config and + * in a system wide configuration file which is by default ${prefix}/etc/libgda-4.0/config. Those + * filenames can be modified by setting the user-file and + * system-file properties for the single GdaConfig + * instance. Note that setting either of these properties to NULL will disable using the corresponding + * configuration file (DSN will exist only in memory and their definition will be lost when the application finishes). + * + * The #GdaConfig object implements its own locking mechanism so it is thread-safe. + * + * Note about localization: when the #GdaConfig loads configuration files, it filters the + * contents based on the current locale, so for example if your current locale is "de" then + * all the loaded strings (for the ones which are translated) will be in the German language. + * Changing the locale afterwards will have no effect on the #GdaConfig and the already loaded + * configuration. + * The consequence is that you should first call setlocale() youself in your code before using + * a #GdaConfig object. As a side note you should also call gtk_init() before gdaui_init() because + * gtk_init() calls setlocale(). + */ + +G_DECLARE_DERIVABLE_TYPE (GdaConfig, gda_config, GDA, CONFIG, GObject) + +#define GDA_TYPE_CONFIG (gda_config_get_type ()) + +struct _GdaConfigClass { + GObjectClass parent_class; + + /* signals */ + void (*dsn_added) (GdaConfig *conf, GdaDsnInfo *new_dsn); + void (*dsn_to_be_removed) (GdaConfig *conf, GdaDsnInfo *old_dsn); + void (*dsn_removed) (GdaConfig *conf, GdaDsnInfo *old_dsn); + void (*dsn_changed) (GdaConfig *conf, GdaDsnInfo *dsn); + + /*< private >*/ + /* Padding for future expansion */ + void (*_gda_reserved1) (void); + void (*_gda_reserved2) (void); + void (*_gda_reserved3) (void); + void (*_gda_reserved4) (void); +}; + +GdaConfig* gda_config_get (void); + +GdaDsnInfo *gda_config_get_dsn_info (const gchar *dsn_name); +gboolean gda_config_define_dsn (const GdaDsnInfo *info, GError **error); +gboolean gda_config_remove_dsn (const gchar *dsn_name, GError **error); +gboolean gda_config_dsn_needs_authentication (const gchar *dsn_name); +GdaDataModel *gda_config_list_dsn (void); +gboolean gda_config_can_modify_system_config (void); + +gint gda_config_get_nb_dsn (void); +gint gda_config_get_dsn_info_index (const gchar *dsn_name); +GdaDsnInfo *gda_config_get_dsn_info_at_index (gint index); + +GdaProviderInfo *gda_config_get_provider_info (const gchar *provider_name); +GdaServerProvider *gda_config_get_provider (const gchar *provider_name, GError **error); +GdaDataModel *gda_config_list_providers (void); + +G_END_DECLS + +#endif diff --git a/.flatpak-builder/cache/objects/5b/fc76fd64b7a4898018fe47aa498b5605c9982860daaa91f2945b787540b795.file b/.flatpak-builder/cache/objects/5b/fc76fd64b7a4898018fe47aa498b5605c9982860daaa91f2945b787540b795.file new file mode 100644 index 0000000..ddbf700 Binary files /dev/null and b/.flatpak-builder/cache/objects/5b/fc76fd64b7a4898018fe47aa498b5605c9982860daaa91f2945b787540b795.file differ diff --git a/.flatpak-builder/cache/objects/5c/4b0e191df3aed50e2d8da279e6aa26da6f480f96d391b4cccfd68014174cfe.file b/.flatpak-builder/cache/objects/5c/4b0e191df3aed50e2d8da279e6aa26da6f480f96d391b4cccfd68014174cfe.file new file mode 100644 index 0000000..fa0a3fe --- /dev/null +++ b/.flatpak-builder/cache/objects/5c/4b0e191df3aed50e2d8da279e6aa26da6f480f96d391b4cccfd68014174cfe.file @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2019 Daniel Espinosa + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GDA_DATA_SELECT_PRIVATE_H__ +#define __GDA_DATA_SELECT_PRIVATE_H__ + +/** + * gda_data_select_get_prep_stmt: + * + * Returns: (transfer none): + */ +GdaPStmt *gda_data_select_get_prep_stmt (GdaDataSelect *model); +gint gda_data_select_get_nb_stored_rows (GdaDataSelect *model); +gint gda_data_select_get_advertized_nrows (GdaDataSelect *model); +void gda_data_select_set_advertized_nrows (GdaDataSelect *model, gint n); + + +G_END_DECLS + +#endif diff --git a/.flatpak-builder/cache/objects/5c/818925722efc3da0b883acc452a20b118fdbe61b2ad10d89265ba1ca8df754.file b/.flatpak-builder/cache/objects/5c/818925722efc3da0b883acc452a20b118fdbe61b2ad10d89265ba1ca8df754.file new file mode 120000 index 0000000..53d7884 --- /dev/null +++ b/.flatpak-builder/cache/objects/5c/818925722efc3da0b883acc452a20b118fdbe61b2ad10d89265ba1ca8df754.file @@ -0,0 +1 @@ +../../share/runtime/locale/zh/share/zh_HK \ No newline at end of file diff --git a/.flatpak-builder/cache/objects/5c/8757775ba10a52dc0c72e58ff1cac0a438bae8ebfe5b15cd584e8df8ac40b8.file b/.flatpak-builder/cache/objects/5c/8757775ba10a52dc0c72e58ff1cac0a438bae8ebfe5b15cd584e8df8ac40b8.file new file mode 120000 index 0000000..d89c7a2 --- /dev/null +++ b/.flatpak-builder/cache/objects/5c/8757775ba10a52dc0c72e58ff1cac0a438bae8ebfe5b15cd584e8df8ac40b8.file @@ -0,0 +1 @@ +../../share/runtime/locale/ar/share/ar \ No newline at end of file diff --git a/.flatpak-builder/cache/objects/5e/34827991bcf7fe97f4885fe8d53abc61dc99d5419cfe38352d2ec6249cbed0.file b/.flatpak-builder/cache/objects/5e/34827991bcf7fe97f4885fe8d53abc61dc99d5419cfe38352d2ec6249cbed0.file new file mode 100644 index 0000000..c25b7b1 --- /dev/null +++ b/.flatpak-builder/cache/objects/5e/34827991bcf7fe97f4885fe8d53abc61dc99d5419cfe38352d2ec6249cbed0.file @@ -0,0 +1,212 @@ +## intltool.m4 - Configure intltool for the target system. -*-Shell-script-*- +## Copyright (C) 2001 Eazel, Inc. +## Author: Maciej Stachowiak +## Kenneth Christiansen +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, but +## WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +## General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, write to the Free Software +## Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +## +## As a special exception to the GNU General Public License, if you +## distribute this file as part of a program that contains a +## configuration script generated by Autoconf, you may include it under +## the same distribution terms that you use for the rest of that program. + +dnl IT_PROG_INTLTOOL([MINIMUM-VERSION], [no-xml]) +# serial 42 IT_PROG_INTLTOOL +AC_DEFUN([IT_PROG_INTLTOOL], [ +AC_PREREQ([2.50])dnl +AC_REQUIRE([AM_NLS])dnl + +case "$am__api_version" in + 1.[01234]) + AC_MSG_ERROR([Automake 1.5 or newer is required to use intltool]) + ;; + *) + ;; +esac + +INTLTOOL_REQUIRED_VERSION_AS_INT=`echo $1 | awk -F. '{ print $ 1 * 1000 + $ 2 * 100 + $ 3; }'` +INTLTOOL_APPLIED_VERSION=`intltool-update --version | head -1 | cut -d" " -f3` +INTLTOOL_APPLIED_VERSION_AS_INT=`echo $INTLTOOL_APPLIED_VERSION | awk -F. '{ print $ 1 * 1000 + $ 2 * 100 + $ 3; }'` +if test -n "$1"; then + AC_MSG_CHECKING([for intltool >= $1]) + AC_MSG_RESULT([$INTLTOOL_APPLIED_VERSION found]) + test "$INTLTOOL_APPLIED_VERSION_AS_INT" -ge "$INTLTOOL_REQUIRED_VERSION_AS_INT" || + AC_MSG_ERROR([Your intltool is too old. You need intltool $1 or later.]) +fi + +AC_PATH_PROG(INTLTOOL_UPDATE, [intltool-update]) +AC_PATH_PROG(INTLTOOL_MERGE, [intltool-merge]) +AC_PATH_PROG(INTLTOOL_EXTRACT, [intltool-extract]) +if test -z "$INTLTOOL_UPDATE" -o -z "$INTLTOOL_MERGE" -o -z "$INTLTOOL_EXTRACT"; then + AC_MSG_ERROR([The intltool scripts were not found. Please install intltool.]) +fi + +if test -z "$AM_DEFAULT_VERBOSITY"; then + AM_DEFAULT_VERBOSITY=1 +fi +AC_SUBST([AM_DEFAULT_VERBOSITY]) + +INTLTOOL_V_MERGE='$(INTLTOOL__v_MERGE_$(V))' +INTLTOOL__v_MERGE_='$(INTLTOOL__v_MERGE_$(AM_DEFAULT_VERBOSITY))' +INTLTOOL__v_MERGE_0='@echo " ITMRG " [$]@;' +AC_SUBST(INTLTOOL_V_MERGE) +AC_SUBST(INTLTOOL__v_MERGE_) +AC_SUBST(INTLTOOL__v_MERGE_0) + +INTLTOOL_V_MERGE_OPTIONS='$(intltool__v_merge_options_$(V))' +intltool__v_merge_options_='$(intltool__v_merge_options_$(AM_DEFAULT_VERBOSITY))' +intltool__v_merge_options_0='-q' +AC_SUBST(INTLTOOL_V_MERGE_OPTIONS) +AC_SUBST(intltool__v_merge_options_) +AC_SUBST(intltool__v_merge_options_0) + + INTLTOOL_DESKTOP_RULE='%.desktop: %.desktop.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*.po) ; $(INTLTOOL_V_MERGE)LC_ALL=C $(INTLTOOL_MERGE) $(INTLTOOL_V_MERGE_OPTIONS) -d -u -c $(top_builddir)/po/.intltool-merge-cache $(top_srcdir)/po $< [$]@' +INTLTOOL_DIRECTORY_RULE='%.directory: %.directory.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*.po) ; $(INTLTOOL_V_MERGE)LC_ALL=C $(INTLTOOL_MERGE) $(INTLTOOL_V_MERGE_OPTIONS) -d -u -c $(top_builddir)/po/.intltool-merge-cache $(top_srcdir)/po $< [$]@' + INTLTOOL_KEYS_RULE='%.keys: %.keys.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*.po) ; $(INTLTOOL_V_MERGE)LC_ALL=C $(INTLTOOL_MERGE) $(INTLTOOL_V_MERGE_OPTIONS) -k -u -c $(top_builddir)/po/.intltool-merge-cache $(top_srcdir)/po $< [$]@' + INTLTOOL_PROP_RULE='%.prop: %.prop.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*.po) ; $(INTLTOOL_V_MERGE)LC_ALL=C $(INTLTOOL_MERGE) $(INTLTOOL_V_MERGE_OPTIONS) -d -u -c $(top_builddir)/po/.intltool-merge-cache $(top_srcdir)/po $< [$]@' + INTLTOOL_OAF_RULE='%.oaf: %.oaf.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*.po) ; $(INTLTOOL_V_MERGE)LC_ALL=C $(INTLTOOL_MERGE) $(INTLTOOL_V_MERGE_OPTIONS) -o -p $(top_srcdir)/po $< [$]@' + INTLTOOL_PONG_RULE='%.pong: %.pong.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*.po) ; $(INTLTOOL_V_MERGE)LC_ALL=C $(INTLTOOL_MERGE) $(INTLTOOL_V_MERGE_OPTIONS) -x -u -c $(top_builddir)/po/.intltool-merge-cache $(top_srcdir)/po $< [$]@' + INTLTOOL_SERVER_RULE='%.server: %.server.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*.po) ; $(INTLTOOL_V_MERGE)LC_ALL=C $(INTLTOOL_MERGE) $(INTLTOOL_V_MERGE_OPTIONS) -o -u -c $(top_builddir)/po/.intltool-merge-cache $(top_srcdir)/po $< [$]@' + INTLTOOL_SHEET_RULE='%.sheet: %.sheet.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*.po) ; $(INTLTOOL_V_MERGE)LC_ALL=C $(INTLTOOL_MERGE) $(INTLTOOL_V_MERGE_OPTIONS) -x -u -c $(top_builddir)/po/.intltool-merge-cache $(top_srcdir)/po $< [$]@' +INTLTOOL_SOUNDLIST_RULE='%.soundlist: %.soundlist.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*.po) ; $(INTLTOOL_V_MERGE)LC_ALL=C $(INTLTOOL_MERGE) $(INTLTOOL_V_MERGE_OPTIONS) -d -u -c $(top_builddir)/po/.intltool-merge-cache $(top_srcdir)/po $< [$]@' + INTLTOOL_UI_RULE='%.ui: %.ui.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*.po) ; $(INTLTOOL_V_MERGE)LC_ALL=C $(INTLTOOL_MERGE) $(INTLTOOL_V_MERGE_OPTIONS) -x -u -c $(top_builddir)/po/.intltool-merge-cache $(top_srcdir)/po $< [$]@' + INTLTOOL_XML_RULE='%.xml: %.xml.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*.po) ; $(INTLTOOL_V_MERGE)LC_ALL=C $(INTLTOOL_MERGE) $(INTLTOOL_V_MERGE_OPTIONS) -x -u -c $(top_builddir)/po/.intltool-merge-cache $(top_srcdir)/po $< [$]@' +if test "$INTLTOOL_APPLIED_VERSION_AS_INT" -ge 5000; then + INTLTOOL_XML_NOMERGE_RULE='%.xml: %.xml.in $(INTLTOOL_MERGE) ; $(INTLTOOL_V_MERGE)LC_ALL=C $(INTLTOOL_MERGE) $(INTLTOOL_V_MERGE_OPTIONS) -x -u --no-translations $< [$]@' +else + INTLTOOL_XML_NOMERGE_RULE='%.xml: %.xml.in $(INTLTOOL_MERGE) ; $(INTLTOOL_V_MERGE)_it_tmp_dir=tmp.intltool.[$][$]RANDOM && mkdir [$][$]_it_tmp_dir && LC_ALL=C $(INTLTOOL_MERGE) $(INTLTOOL_V_MERGE_OPTIONS) -x -u [$][$]_it_tmp_dir $< [$]@ && rmdir [$][$]_it_tmp_dir' +fi + INTLTOOL_XAM_RULE='%.xam: %.xml.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*.po) ; $(INTLTOOL_V_MERGE)LC_ALL=C $(INTLTOOL_MERGE) $(INTLTOOL_V_MERGE_OPTIONS) -x -u -c $(top_builddir)/po/.intltool-merge-cache $(top_srcdir)/po $< [$]@' + INTLTOOL_KBD_RULE='%.kbd: %.kbd.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*.po) ; $(INTLTOOL_V_MERGE)LC_ALL=C $(INTLTOOL_MERGE) $(INTLTOOL_V_MERGE_OPTIONS) -x -u -m -c $(top_builddir)/po/.intltool-merge-cache $(top_srcdir)/po $< [$]@' + INTLTOOL_CAVES_RULE='%.caves: %.caves.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*.po) ; $(INTLTOOL_V_MERGE)LC_ALL=C $(INTLTOOL_MERGE) $(INTLTOOL_V_MERGE_OPTIONS) -d -u -c $(top_builddir)/po/.intltool-merge-cache $(top_srcdir)/po $< [$]@' + INTLTOOL_SCHEMAS_RULE='%.schemas: %.schemas.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*.po) ; $(INTLTOOL_V_MERGE)LC_ALL=C $(INTLTOOL_MERGE) $(INTLTOOL_V_MERGE_OPTIONS) -s -u -c $(top_builddir)/po/.intltool-merge-cache $(top_srcdir)/po $< [$]@' + INTLTOOL_THEME_RULE='%.theme: %.theme.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*.po) ; $(INTLTOOL_V_MERGE)LC_ALL=C $(INTLTOOL_MERGE) $(INTLTOOL_V_MERGE_OPTIONS) -d -u -c $(top_builddir)/po/.intltool-merge-cache $(top_srcdir)/po $< [$]@' + INTLTOOL_SERVICE_RULE='%.service: %.service.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*.po) ; $(INTLTOOL_V_MERGE)LC_ALL=C $(INTLTOOL_MERGE) $(INTLTOOL_V_MERGE_OPTIONS) -d -u -c $(top_builddir)/po/.intltool-merge-cache $(top_srcdir)/po $< [$]@' + INTLTOOL_POLICY_RULE='%.policy: %.policy.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*.po) ; $(INTLTOOL_V_MERGE)LC_ALL=C $(INTLTOOL_MERGE) $(INTLTOOL_V_MERGE_OPTIONS) -x -u -c $(top_builddir)/po/.intltool-merge-cache $(top_srcdir)/po $< [$]@' + +_IT_SUBST(INTLTOOL_DESKTOP_RULE) +_IT_SUBST(INTLTOOL_DIRECTORY_RULE) +_IT_SUBST(INTLTOOL_KEYS_RULE) +_IT_SUBST(INTLTOOL_PROP_RULE) +_IT_SUBST(INTLTOOL_OAF_RULE) +_IT_SUBST(INTLTOOL_PONG_RULE) +_IT_SUBST(INTLTOOL_SERVER_RULE) +_IT_SUBST(INTLTOOL_SHEET_RULE) +_IT_SUBST(INTLTOOL_SOUNDLIST_RULE) +_IT_SUBST(INTLTOOL_UI_RULE) +_IT_SUBST(INTLTOOL_XAM_RULE) +_IT_SUBST(INTLTOOL_KBD_RULE) +_IT_SUBST(INTLTOOL_XML_RULE) +_IT_SUBST(INTLTOOL_XML_NOMERGE_RULE) +_IT_SUBST(INTLTOOL_CAVES_RULE) +_IT_SUBST(INTLTOOL_SCHEMAS_RULE) +_IT_SUBST(INTLTOOL_THEME_RULE) +_IT_SUBST(INTLTOOL_SERVICE_RULE) +_IT_SUBST(INTLTOOL_POLICY_RULE) + +# Check the gettext tools to make sure they are GNU +AC_PATH_PROG(XGETTEXT, xgettext) +AC_PATH_PROG(MSGMERGE, msgmerge) +AC_PATH_PROG(MSGFMT, msgfmt) +AC_PATH_PROG(GMSGFMT, gmsgfmt, $MSGFMT) +if test -z "$XGETTEXT" -o -z "$MSGMERGE" -o -z "$MSGFMT"; then + AC_MSG_ERROR([GNU gettext tools not found; required for intltool]) +fi +xgversion="`$XGETTEXT --version|grep '(GNU ' 2> /dev/null`" +mmversion="`$MSGMERGE --version|grep '(GNU ' 2> /dev/null`" +mfversion="`$MSGFMT --version|grep '(GNU ' 2> /dev/null`" +if test -z "$xgversion" -o -z "$mmversion" -o -z "$mfversion"; then + AC_MSG_ERROR([GNU gettext tools not found; required for intltool]) +fi + +AC_PATH_PROG(INTLTOOL_PERL, perl) +if test -z "$INTLTOOL_PERL"; then + AC_MSG_ERROR([perl not found]) +fi +AC_MSG_CHECKING([for perl >= 5.8.1]) +$INTLTOOL_PERL -e "use 5.8.1;" > /dev/null 2>&1 +if test $? -ne 0; then + AC_MSG_ERROR([perl 5.8.1 is required for intltool]) +else + IT_PERL_VERSION=`$INTLTOOL_PERL -e "printf '%vd', $^V"` + AC_MSG_RESULT([$IT_PERL_VERSION]) +fi +if test "x$2" != "xno-xml"; then + AC_MSG_CHECKING([for XML::Parser]) + if `$INTLTOOL_PERL -e "require XML::Parser" 2>/dev/null`; then + AC_MSG_RESULT([ok]) + else + AC_MSG_ERROR([XML::Parser perl module is required for intltool]) + fi +fi + +# Substitute ALL_LINGUAS so we can use it in po/Makefile +AC_SUBST(ALL_LINGUAS) + +IT_PO_SUBDIR([po]) + +]) + + +# IT_PO_SUBDIR(DIRNAME) +# --------------------- +# All po subdirs have to be declared with this macro; the subdir "po" is +# declared by IT_PROG_INTLTOOL. +# +AC_DEFUN([IT_PO_SUBDIR], +[AC_PREREQ([2.53])dnl We use ac_top_srcdir inside AC_CONFIG_COMMANDS. +dnl +dnl The following CONFIG_COMMANDS should be executed at the very end +dnl of config.status. +AC_CONFIG_COMMANDS_PRE([ + AC_CONFIG_COMMANDS([$1/stamp-it], [ + if [ ! grep "^# INTLTOOL_MAKEFILE$" "$1/Makefile.in" > /dev/null ]; then + AC_MSG_ERROR([$1/Makefile.in.in was not created by intltoolize.]) + fi + rm -f "$1/stamp-it" "$1/stamp-it.tmp" "$1/POTFILES" "$1/Makefile.tmp" + >"$1/stamp-it.tmp" + [sed '/^#/d + s/^[[].*] *// + /^[ ]*$/d + '"s|^| $ac_top_srcdir/|" \ + "$srcdir/$1/POTFILES.in" | sed '$!s/$/ \\/' >"$1/POTFILES" + ] + [sed '/^POTFILES =/,/[^\\]$/ { + /^POTFILES =/!d + r $1/POTFILES + } + ' "$1/Makefile.in" >"$1/Makefile"] + rm -f "$1/Makefile.tmp" + mv "$1/stamp-it.tmp" "$1/stamp-it" + ]) +])dnl +]) + +# _IT_SUBST(VARIABLE) +# ------------------- +# Abstract macro to do either _AM_SUBST_NOTMAKE or AC_SUBST +# +AC_DEFUN([_IT_SUBST], +[ +AC_SUBST([$1]) +m4_ifdef([_AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE([$1])]) +] +) + +# deprecated macros +AU_ALIAS([AC_PROG_INTLTOOL], [IT_PROG_INTLTOOL]) +# A hint is needed for aclocal from Automake <= 1.9.4: +# AC_DEFUN([AC_PROG_INTLTOOL], ...) + diff --git a/.flatpak-builder/cache/objects/5e/7eb4bb77c9211aa1270f9aab9285a50f5f217306212ec02249afa867facaab.file b/.flatpak-builder/cache/objects/5e/7eb4bb77c9211aa1270f9aab9285a50f5f217306212ec02249afa867facaab.file new file mode 100644 index 0000000..f06482c --- /dev/null +++ b/.flatpak-builder/cache/objects/5e/7eb4bb77c9211aa1270f9aab9285a50f5f217306212ec02249afa867facaab.file @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2006 - 2011 Vivien Malerba + * Copyright (C) 2007 Armin Burgmeier + * Copyright (C) 2007 Murray Cumming + * Copyright (C) 2018 Daniel Espinosa + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GDA_TRANSACTION_STATUS_H__ +#define __GDA_TRANSACTION_STATUS_H__ + +#include +#include +#include +#include + +G_BEGIN_DECLS + + + +/** + * GdaTransactionStatusEventType: + * @GDA_TRANSACTION_STATUS_EVENT_SAVEPOINT: + * @GDA_TRANSACTION_STATUS_EVENT_SQL: + * @GDA_TRANSACTION_STATUS_EVENT_SUB_TRANSACTION: + */ +typedef enum { + GDA_TRANSACTION_STATUS_EVENT_SAVEPOINT, + GDA_TRANSACTION_STATUS_EVENT_SQL, + GDA_TRANSACTION_STATUS_EVENT_SUB_TRANSACTION +} GdaTransactionStatusEventType; + +/** + * GdaTransactionStatusState: + * @GDA_TRANSACTION_STATUS_STATE_OK: + * @GDA_TRANSACTION_STATUS_STATE_FAILED: + */ +typedef enum { + GDA_TRANSACTION_STATUS_STATE_OK, + GDA_TRANSACTION_STATUS_STATE_FAILED +} GdaTransactionStatusState; + +#define GDA_TYPE_TRANSACTION_STATUS (gda_transaction_status_get_type()) +G_DECLARE_DERIVABLE_TYPE (GdaTransactionStatus, gda_transaction_status, GDA, TRANSACTION_STATUS, GObject) + +struct _GdaTransactionStatusClass { + GObjectClass parent_class; + + /*< private >*/ + /* Padding for future expansion */ + void (*_gda_reserved1) (void); + void (*_gda_reserved2) (void); + void (*_gda_reserved3) (void); + void (*_gda_reserved4) (void); +}; + + +/** + * GdaTransactionStatusEvent: + * @trans: + * @type: + * @conn_event: + */ +typedef struct { + GdaTransactionStatus *trans; + GdaTransactionStatusEventType type; + union { + gchar *svp_name; /* save point name if this event corresponds to a new save point */ + gchar *sql; /* SQL to store SQL queries in transactions */ + GdaTransactionStatus *sub_trans;/* sub transaction event */ + } pl; + GdaConnectionEvent *conn_event; + + /*< private >*/ + gpointer _gda_reserved1; + gpointer _gda_reserved2; +} GdaTransactionStatusEvent; + +#define GDA_TYPE_TRANSACTION_STATUS_EVENT (gda_transaction_status_event_get_type ()) +/** + * SECTION:gda-transaction-status + * @short_description: Keeps track of the transaction status of a connection + * @title: GdaTransactionStatus + * @stability: Stable + * @see_also: #GdaConnection + * + * On any connection (as a #GdaConnection object), if the database provider used by the connection + * supports it, transactions may be started, committed or rolledback, or savepoints added, removed or rolledback. + * These operations can be performed using Libgda's API (such as gda_connection_begin_transaction()), or directly + * using some SQL on the connection (usually a "BEGIN;" command). The #GdaTransactionStatus's aim is to + * make it easy to keep track of all the commands which have been issued on a connection regarding transactions. + * + * One #GdaTransactionStatus object is automatically attached to a #GdaConnection when a transaction is started, and + * is destroyed when the transaction is finished. A pointer to this object can be fetched using + * gda_connection_get_transaction_status() (beware that it should then not be modified). The end user is not + * supposed to instantiate #GdaTransactionStatus objects + * + * #GdaTransactionStatus's attributes are directly accessible using the public members of the object. + */ + +GdaTransactionStatus *gda_transaction_status_new (const gchar *name); +void gda_transaction_status_set_isolation_level (GdaTransactionStatus *st, GdaTransactionIsolation il); +GdaTransactionIsolation gda_transaction_status_get_isolation_level (GdaTransactionStatus *st); +void gda_transaction_status_set_state (GdaTransactionStatus *st, GdaTransactionStatusState state); +GdaTransactionStatusState gda_transaction_status_get_state (GdaTransactionStatus *st); + + +GType gda_transaction_status_event_get_type (void) G_GNUC_CONST; + +G_END_DECLS + +#endif diff --git a/.flatpak-builder/cache/objects/5f/2038d1c2d8733eedd503255ae79974d52d85acd17a92f1448e1d3a73fc2120.file b/.flatpak-builder/cache/objects/5f/2038d1c2d8733eedd503255ae79974d52d85acd17a92f1448e1d3a73fc2120.file new file mode 100644 index 0000000..cb56868 --- /dev/null +++ b/.flatpak-builder/cache/objects/5f/2038d1c2d8733eedd503255ae79974d52d85acd17a92f1448e1d3a73fc2120.file @@ -0,0 +1,123 @@ +/* gsound-context.h + * + * Copyright (C) 2013 Tristan Brindle + * + * This file is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of the + * License, or (at your option) any later version. + * + * This file is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef GSOUND_CONTEXT_H +#define GSOUND_CONTEXT_H + +#include + +#include "gsound-attr.h" + +G_BEGIN_DECLS +#define GSOUND_TYPE_CONTEXT (gsound_context_get_type ()) +#define GSOUND_CONTEXT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GSOUND_TYPE_CONTEXT, GSoundContext)) +#define GSOUND_CONTEXT_CLASS(obj) (G_TYPE_CHECK_CLASS_CAST ((obj), GSOUND_TYPE_CONTEXT, GSoundContextClass)) +#define GSOUND_IS_CONTEXT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GSOUND_TYPE_CONTEXT)) +#define GSOUND_IS_CONTEXT_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE ((obj), GSOUND_TYPE_CONTEXT)) +#define GSOUND_CONTEXT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GSOUND_TYPE_CONTEXT, GSoundContextClass)) +typedef struct _GSoundContext GSoundContext; +typedef struct _GSoundContextClass GSoundContextClass; + +/** + * GSoundContext: + * ca: the wrapped context + * + * Wrapper for ca_context. + */ + +#define GSOUND_ERROR (gsound_error_quark()) +GQuark gsound_error_quark(void); + +typedef enum +{ + GSOUND_ERROR_NOTSUPPORTED = -1, + GSOUND_ERROR_INVALID = -2, + GSOUND_ERROR_STATE = -3, + GSOUND_ERROR_OOM = -4, + GSOUND_ERROR_NODRIVER = -5, + GSOUND_ERROR_SYSTEM = -6, + GSOUND_ERROR_CORRUPT = -7, + GSOUND_ERROR_TOOBIG = -8, + GSOUND_ERROR_NOTFOUND = -9, + GSOUND_ERROR_DESTROYED = -10, + GSOUND_ERROR_CANCELED = -11, + GSOUND_ERROR_NOTAVAILABLE = -12, + GSOUND_ERROR_ACCESS = -13, + GSOUND_ERROR_IO = -14, + GSOUND_ERROR_INTERNAL = -15, + GSOUND_ERROR_DISABLED = -16, + GSOUND_ERROR_FORKED = -17, + GSOUND_ERROR_DISCONNECTED = -18 +} GSoundError; +GType gsound_context_get_type (void); + +GSoundContext *gsound_context_new (GCancellable *cancellable, + GError **error); + +gboolean gsound_context_open (GSoundContext *context, + GError **error); + +gboolean gsound_context_set_attributes (GSoundContext *context, + GError **error, + ...) G_GNUC_NULL_TERMINATED; + +gboolean gsound_context_set_attributesv (GSoundContext *context, + GHashTable *attrs, + GError **error); + +gboolean gsound_context_set_driver (GSoundContext *context, + const char *driver, + GError **error); + +gboolean gsound_context_play_simple (GSoundContext *context, + GCancellable *cancellable, + GError **error, + ...) G_GNUC_NULL_TERMINATED; + +gboolean gsound_context_play_simplev (GSoundContext *context, + GHashTable *attrs, + GCancellable *cancellable, + GError **error); + +void gsound_context_play_full (GSoundContext *context, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data, + ...) G_GNUC_NULL_TERMINATED; + +void gsound_context_play_fullv (GSoundContext *context, + GHashTable *attrs, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + +gboolean gsound_context_play_full_finish (GSoundContext *context, + GAsyncResult *result, + GError **error); + +gboolean gsound_context_cache (GSoundContext *context, + GError **error, + ...) G_GNUC_NULL_TERMINATED; + +gboolean gsound_context_cachev (GSoundContext *context, + GHashTable *attrs, + GError **error); + +G_END_DECLS +#endif /* GSOUND_CONTEXT_H */ + diff --git a/.flatpak-builder/cache/objects/5f/6b675118c37acdd5cb5b9ae3cfde2eea1d38945e2db7526bba65dd9d0b2c9e.file b/.flatpak-builder/cache/objects/5f/6b675118c37acdd5cb5b9ae3cfde2eea1d38945e2db7526bba65dd9d0b2c9e.file new file mode 100644 index 0000000..88884a4 --- /dev/null +++ b/.flatpak-builder/cache/objects/5f/6b675118c37acdd5cb5b9ae3cfde2eea1d38945e2db7526bba65dd9d0b2c9e.file @@ -0,0 +1,4256 @@ +/* + * Copyright (C) 2006 - 2011 Murray Cumming + * Copyright (C) 2006 - 2015 Vivien Malerba + * Copyright (C) 2007 Armin Burgmeier + * Copyright (C) 2007 Leonardo Boshell + * Copyright (C) 2009 Bas Driessen + * Copyright (C) 2010 David King + * Copyright (C) 2010 Jonh Wendell + * Copyright (C) 2011 - 2012, 2018 Daniel Espinosa + * Copyright (C) 2013 Miguel Angel Cabrera Moya + * Copyright (C) 2018-2019 Daniel Espinosa + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +#define G_LOG_DOMAIN "GDA-data-proxy" + +#include +#include +#include "gda-data-proxy.h" +#include "gda-data-model.h" +#include "gda-data-model-array.h" +#include "gda-data-model-extra.h" +#include "gda-data-model-iter.h" +#include "gda-data-select.h" +#include "gda-holder.h" +#include "gda-set.h" +#include "gda-marshal.h" +#include "gda-enums.h" +#include "gda-util.h" +#include "gda-marshal.h" +#include "gda-data-access-wrapper.h" +#include "gda-enum-types.h" +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Main static functions + */ +static void gda_data_proxy_class_init (GdaDataProxyClass * class); +static void gda_data_proxy_init (GdaDataProxy *srv); +static void gda_data_proxy_dispose (GObject *object); +static void gda_data_proxy_finalize (GObject *object); + +static void gda_data_proxy_set_property (GObject *object, + guint param_id, + const GValue *value, + GParamSpec *pspec); +static void gda_data_proxy_get_property (GObject *object, + guint param_id, + GValue *value, + GParamSpec *pspec); +/* GdaDataModel interface */ +static void gda_data_proxy_data_model_init (GdaDataModelInterface *iface); + +static gint gda_data_proxy_get_n_rows (GdaDataModel *model); +static gint gda_data_proxy_get_n_columns (GdaDataModel *model); +static GdaColumn *gda_data_proxy_describe_column (GdaDataModel *model, gint col); +static const GValue *gda_data_proxy_get_value_at (GdaDataModel *model, gint col, gint row, GError **error); +static GdaValueAttribute gda_data_proxy_get_attributes_at (GdaDataModel *model, gint col, gint row); + + +static GdaDataModelAccessFlags gda_data_proxy_get_access_flags(GdaDataModel *model); + +static gboolean gda_data_proxy_set_value_at (GdaDataModel *model, gint col, gint row, + const GValue *value, GError **error); +static gboolean gda_data_proxy_set_values (GdaDataModel *model, gint row, + GList *values, GError **error); +static gint gda_data_proxy_find_row_from_values (GdaDataModel *model, GSList *values, + gint *cols_index); + +static gint gda_data_proxy_append_values (GdaDataModel *model, const GList *values, GError **error); +static gint gda_data_proxy_append_row (GdaDataModel *model, GError **error); +static gboolean gda_data_proxy_remove_row (GdaDataModel *model, gint row, GError **error); + +static void gda_data_proxy_freeze (GdaDataModel *model); +static void gda_data_proxy_thaw (GdaDataModel *model); +static gboolean gda_data_proxy_get_notify (GdaDataModel *model); +static void gda_data_proxy_send_hint (GdaDataModel *model, GdaDataModelHint hint, + const GValue *hint_value); + +/* cache management */ +static void clean_cached_changes (GdaDataProxy *proxy); +static void migrate_current_changes_to_cache (GdaDataProxy *proxy); +static void fetch_current_cached_changes (GdaDataProxy *proxy); + +#define DEBUG_SYNC +#undef DEBUG_SYNC + +static GMutex parser_mutex; +static GdaSqlParser *internal_parser; +static GMutex provider_mutex; +static GdaVirtualProvider *virtual_provider = NULL; + +/* signals */ +enum +{ + ROW_DELETE_CHANGED, + SAMPLE_SIZE_CHANGED, + SAMPLE_CHANGED, + VALIDATE_ROW_CHANGES, + ROW_CHANGES_APPLIED, + FILTER_CHANGED, + LAST_SIGNAL +}; + +static gint gda_data_proxy_signals[LAST_SIGNAL] = { 0, 0, 0, 0, 0, 0 }; + + +/* properties */ +enum +{ + PROP_0, + PROP_MODEL, + PROP_ADD_NULL_ENTRY, + PROP_DEFER_SYNC, + PROP_SAMPLE_SIZE, + PROP_CACHE_CHANGES +}; + +/* + * Structure to hold the status and all the modifications made to a single + * row. It is not possible to have ((model_row < 0) && !modify_values) + */ +typedef struct +{ + gint model_row; /* row index in the proxied GdaDataModel, -1 if new row */ + gboolean to_be_deleted;/* TRUE if row is to be deleted */ + GSList *modify_values; /* list of RowValue structures */ + GValue **orig_values; /* array of the original GValues, indexed on the column numbers */ + gint orig_values_size; /* size of @orig_values, OR (for new rows) the number of columns of the proxied data model the new row is for */ +} RowModif; +#define ROW_MODIF(x) ((RowModif *)(x)) + +/* + * Structure to hold the modifications made to a single value + */ +typedef struct +{ + RowModif *row_modif; /* RowModif in which this structure instance appears */ + gint model_column; /* column index in the GdaDataModel */ + GValue *value; /* values are owned here */ + GdaValueAttribute attributes; /* holds flags */ +} RowValue; +#define ROW_VALUE(x) ((RowValue *)(x)) + +/* + * Structure to hold which part of the whole data is displayed + */ +typedef struct { + GArray *mapping; /* for proxy's row nb i (or i+1 if + * there is a NULL rows first), mapping[i] points to + * the absolute row. + * + * If mapping is empty, then either there are no + * rows to display, or the number of rows is unknown + * (then it's not filled until row existance can be testes + */ +} DisplayChunk; +static DisplayChunk *display_chunk_new (gint reserved_size); +static void display_chunk_free (DisplayChunk *chunk); + +/* + * NOTE about the row numbers: + * + * There may be more rows in the GdaDataProxy than in the GdaDataModel if: + * - some rows have been added in the proxy + * and are not yet in the GdaDataModel (RowModif->model_row = -1 in this case); or + * - there is a NULL row at the beginning + * + * There are 3 kinds of row numbers: + * - the absolute row numbers which unify under a single numbering scheme all the possible proxy's rows + * which can either be new rows, or data model rows (which may or may not have been modified), + * absolute row numbers are strictly private to the proxy object + * - the row numbers as identified in the proxy (named "proxy_row"), which are the row numbers used + * by the GdaDataModel interface + * - the row numbers in the GdaDataModel being proxied (named "model_row") + * + * Absolute row numbers are assigned as: + * - rows 0 to N-1 included corresponding to the N rows of the proxied data model + * - rows N to N+M-1 included corresponding to the M added rows + * + * The rule to go from one row numbering to the other is to use the row conversion functions. + * + */ +typedef struct { + GRecMutex mutex; + + GdaDataModel *model; /* Gda model which is proxied */ + + GdaConnection *filter_vcnc; /* virtual connection used for filtering */ + gchar *filter_expr; /* NULL if no filter applied */ + GdaStatement *filter_stmt; /* NULL if no filter applied */ + GdaDataModel *filtered_rows; /* NULL if no filter applied. Lists rows (by their number) which must be displayed */ + + GdaValueAttribute *columns_attrs; /* Each GValue holds a flag of GdaValueAttribute to proxy. cols. attributes */ + + gint model_nb_cols; /* = gda_data_model_get_n_columns (model) */ + gint model_nb_rows; /* = gda_data_model_get_n_rows (model) */ + gboolean notify_changes; + + GSList *all_modifs; /* list of RowModif structures, for memory management */ + GSList *new_rows; /* list of RowModif, no data allocated in this list */ + GHashTable *modify_rows; /* key = model_row number, value = RowModif, NOT for new rows */ + + gboolean defer_proxied_model_insert; + gint catched_inserted_row; + + gboolean add_null_entry; /* artificially add a NULL entry at the beginning of the tree model */ + + gboolean defer_sync; + + /* chunking */ + gboolean force_direct_mapping; + gint sample_first_row; + gint sample_last_row; + gint sample_size; + guint chunk_sync_idle_id; + DisplayChunk *chunk; /* number of proxy_rows depends directly on chunk->mapping->len */ + DisplayChunk *chunk_to; /* NULL if nothing to do */ + gint chunk_sep; + gint chunk_proxy_nb_rows; + + /* for ALL the columns of proxy */ + GdaColumn **columns; + + /* modifications cache */ + gboolean cache_changes; + GSList *cached_modifs; + GSList *cached_inserts; +} GdaDataProxyPrivate; +G_DEFINE_TYPE_WITH_CODE(GdaDataProxy, gda_data_proxy, G_TYPE_OBJECT, + G_ADD_PRIVATE (GdaDataProxy) + G_IMPLEMENT_INTERFACE(GDA_TYPE_DATA_MODEL, gda_data_proxy_data_model_init)) + +/* + * Row conversion functions + */ + +/* + * May return -1 if: + * - @model_row < 0 + * - @model_row is out of bounds (only checked if @proxy's number of rows is known) + */ +static gint +model_row_to_absolute_row (GdaDataProxy *proxy, gint model_row) +{ + GdaDataProxyPrivate *priv = gda_data_proxy_get_instance_private (proxy); + if (model_row < 0) + return -1; + if ((model_row >= priv->model_nb_rows) && (priv->model_nb_rows >= 0)) + return -1; + else + return model_row; +} + +/* + * May return -1 if: + * - @rm is NULL + * - @rm is a new row and @proxy's number of rows is NOT know + * - @rm is not a new row and @rm->model_row == -1 + */ +static gint +row_modif_to_absolute_row (GdaDataProxy *proxy, RowModif *rm) +{ + GdaDataProxyPrivate *priv = gda_data_proxy_get_instance_private (proxy); + if (rm == NULL) + return -1; + if (rm->model_row == -1) { + gint index; + if (priv->model_nb_rows == -1) + return -1; + index = g_slist_index (priv->new_rows, rm); + if (index < 0) + return -1; + return priv->model_nb_rows + index; + } + else + return rm->model_row; +} + +/* + * if @rm is not %NULL, then it will contain a pointer to the RowModif structure associated to @row + * + * May return -1 if: + * - absolute row is not a model row + */ +static gint +absolute_row_to_model_row (GdaDataProxy *proxy, gint abs_row, RowModif **rm) +{ + GdaDataProxyPrivate *priv = gda_data_proxy_get_instance_private (proxy); + if (abs_row < 0) + return -1; + if ((abs_row < priv->model_nb_rows) || (priv->model_nb_rows < 0)) { + if (rm) { + gint tmp; + tmp = abs_row; + *rm = g_hash_table_lookup (priv->modify_rows, &tmp); + } + return abs_row; + } + else { + if (rm) + *rm = g_slist_nth_data (priv->new_rows, abs_row - priv->model_nb_rows); + return -1; + } +} + +/* + * May return -1 if: + * - @row is not an absolute row + */ +static gint +proxy_row_to_absolute_row (GdaDataProxy *proxy, gint proxy_row) +{ + GdaDataProxyPrivate *priv = gda_data_proxy_get_instance_private (proxy); + if (proxy_row < 0) + return -1; + if (priv->force_direct_mapping) + return proxy_row; + + if (priv->add_null_entry) { + if (proxy_row == 0) + return -1; + else + proxy_row--; + } + if (priv->chunk) { + if ((guint)proxy_row < priv->chunk->mapping->len) + return g_array_index (priv->chunk->mapping, gint, proxy_row); + else + return -1; + } + else { + if (priv->chunk_to && + priv->chunk_to->mapping && + (proxy_row < priv->chunk_sep) && + ((guint)proxy_row < priv->chunk_to->mapping->len)) + return g_array_index (priv->chunk_to->mapping, gint, proxy_row); + else + return proxy_row; + } +} + +#define proxy_row_to_model_row(proxy, proxy_row) \ + absolute_row_to_model_row ((proxy), proxy_row_to_absolute_row ((proxy), (proxy_row)), NULL); +#define row_modif_to_proxy_row(proxy, rm) \ + absolute_row_to_proxy_row ((proxy), row_modif_to_absolute_row ((proxy), (rm))) + + +static RowModif * +proxy_row_to_row_modif (GdaDataProxy *proxy, gint proxy_row) +{ + RowModif *rm = NULL; + absolute_row_to_model_row (proxy, proxy_row_to_absolute_row (proxy, proxy_row), &rm); + + return rm; +} + +/* + * May return -1 if: + * - @abs_row is not a proxy row + * - @abs_row is out of bounds (only checked if @proxy's number of rows is known) + */ +static gint +absolute_row_to_proxy_row (GdaDataProxy *proxy, gint abs_row) +{ + GdaDataProxyPrivate *priv = gda_data_proxy_get_instance_private (proxy); + gint proxy_row = -1; + if (abs_row < 0) + return -1; + + if (priv->force_direct_mapping) { + gint proxy_n_rows; + proxy_row = abs_row; + proxy_n_rows = gda_data_proxy_get_n_rows ((GdaDataModel*) proxy); + if ((proxy_row >= proxy_n_rows) && (proxy_n_rows >= 0)) + proxy_row = -1; + return proxy_row; + } + + if (priv->chunk) { + gsize i; + for (i = 0; i < priv->chunk->mapping->len; i++) { + if (g_array_index (priv->chunk->mapping, gint, i) == abs_row) { + proxy_row = i; + break; + } + } + if ((proxy_row >= 0) && priv->add_null_entry) + proxy_row ++; + } + else { + if (priv->chunk_to && priv->chunk_to->mapping) { + /* search in the priv->chunk_sep first rows of priv->chunk_to */ + gint i; + for (i = 0; i < MIN ((gint)priv->chunk->mapping->len, priv->chunk_sep); i++) { + if (g_array_index (priv->chunk_to->mapping, gint, i) == abs_row) { + proxy_row = i; + break; + } + } + if ((proxy_row >= 0) && priv->add_null_entry) + proxy_row ++; + } + if (proxy_row < 0) { + gint proxy_n_rows; + proxy_row = abs_row; + if (priv->add_null_entry) + proxy_row ++; + proxy_n_rows = gda_data_proxy_get_n_rows ((GdaDataModel*) proxy); + if ((proxy_row >= proxy_n_rows) && (proxy_n_rows >= 0)) + proxy_row = -1; + } + } + + return proxy_row; +} + + +/* + * Free a RowModif structure + * + * Warning: only the allocated RowModif is freed, it's not removed from any list or hash table. + */ +static void +row_modifs_free (RowModif *rm) +{ + GSList *list; + gint i; + + list = rm->modify_values; + while (list) { + if (ROW_VALUE (list->data)->value) + gda_value_free (ROW_VALUE (list->data)->value); + g_free (list->data); + list = g_slist_next (list); + } + g_slist_free (rm->modify_values); + + if (rm->orig_values) { + for (i = 0; i < rm->orig_values_size; i++) { + if (rm->orig_values [i]) + gda_value_free (rm->orig_values [i]); + } + g_free (rm->orig_values); + } + + g_free (rm); +} + +/* + * Allocates a new RowModif + * + * WARNING: the new RowModif is not inserted in any list or hash table. + */ +static RowModif * +row_modifs_new (GdaDataProxy *proxy, gint proxy_row) +{ + RowModif *rm; + GdaDataProxyPrivate *priv = gda_data_proxy_get_instance_private (proxy); + +#ifdef GDA_DEBUG + rm = proxy_row_to_row_modif (proxy, proxy_row); + if (rm) + g_warning ("%s(): RowModif already exists for that proxy_row", __FUNCTION__); +#endif + + rm = g_new0 (RowModif, 1); + if (proxy_row >= 0) { + gint i, model_row; + + rm->orig_values = g_new0 (GValue *, priv->model_nb_cols); + rm->orig_values_size = priv->model_nb_cols; + model_row = proxy_row_to_model_row (proxy, proxy_row); + + if (model_row >= 0) { + for (i=0; imodel_nb_cols; i++) { + const GValue *oval; + + oval = gda_data_model_get_value_at (priv->model, i, model_row, NULL); + if (oval) + rm->orig_values [i] = gda_value_copy ((GValue *) oval); + } + } + } + + return rm; +} + +/* module error */ +GQuark gda_data_proxy_error_quark (void) +{ + static GQuark quark; + if (!quark) + quark = g_quark_from_static_string ("gda_data_proxy_error"); + return quark; +} + +static gboolean +validate_row_changes_accumulator (G_GNUC_UNUSED GSignalInvocationHint *ihint, + GValue *return_accu, + const GValue *handler_return, + G_GNUC_UNUSED gpointer data) +{ + GError *error; + + error = g_value_get_boxed (handler_return); + g_value_set_boxed (return_accu, error); + + return error ? FALSE : TRUE; /* stop signal if 'thisvalue' is FALSE */ +} + +static GError * +m_validate_row_changes (G_GNUC_UNUSED GdaDataProxy *proxy, G_GNUC_UNUSED gint row, + G_GNUC_UNUSED gint proxied_row) +{ + return NULL; /* defaults allows changes */ +} + +static void +gda_data_proxy_class_init (GdaDataProxyClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + /* signals */ + /** + * GdaDataProxy::row-delete-changed: + * @proxy: the #GdaDataProxy + * @row: the concerned @proxy's row + * @to_be_deleted: tells if the @row is marked to be deleted + * + * Gets emitted whenever a row has been marked to be deleted, or has been unmarked to be deleted + */ + gda_data_proxy_signals [ROW_DELETE_CHANGED] = + g_signal_new ("row-delete-changed", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (GdaDataProxyClass, row_delete_changed), + NULL, NULL, + _gda_marshal_VOID__INT_BOOLEAN, G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_BOOLEAN); + /** + * GdaDataProxy::sample-size-changed: + * @proxy: the #GdaDataProxy + * @sample_size: the new sample size + * + * Gets emitted whenever @proxy's sample size has been changed + */ + gda_data_proxy_signals [SAMPLE_SIZE_CHANGED] = + g_signal_new ("sample-size-changed", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (GdaDataProxyClass, sample_size_changed), + NULL, NULL, + g_cclosure_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT); + /** + * GdaDataProxy::sample-changed: + * @proxy: the #GdaDataProxy + * @sample_start: the first row of the sample + * @sample_end: the last row of the sample + * + * Gets emitted whenever @proxy's sample size has been changed. @sample_start and @sample_end are + * in reference to the proxied data model. + */ + gda_data_proxy_signals [SAMPLE_CHANGED] = + g_signal_new ("sample-changed", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (GdaDataProxyClass, sample_changed), + NULL, NULL, + _gda_marshal_VOID__INT_INT, G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_INT); + /** + * GdaDataProxy::validate-row-changes: + * @proxy: the #GdaDataProxy + * @row: the proxy's row + * @proxied_row: the proxied data model's row + * + * Gets emitted when @proxy is about to commit a row change to the proxied data model. If any + * callback returns a non %NULL value, then the change commit fails with the returned #GError + * + * Returns: a new #GError if validation failed, or %NULL + */ + gda_data_proxy_signals [VALIDATE_ROW_CHANGES] = + g_signal_new ("validate-row-changes", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GdaDataProxyClass, validate_row_changes), + validate_row_changes_accumulator, NULL, + _gda_marshal_ERROR__INT_INT, G_TYPE_ERROR, 2, G_TYPE_INT, G_TYPE_INT); + /** + * GdaDataProxy::row-changes-applied: + * @proxy: the #GdaDataProxy + * @row: the proxy's row + * @proxied_row: the proxied data model's row + * + * Gets emitted when @proxy has committed a row change to the proxied data model. + */ + gda_data_proxy_signals [ROW_CHANGES_APPLIED] = + g_signal_new ("row-changes-applied", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (GdaDataProxyClass, row_changes_applied), + NULL, NULL, + _gda_marshal_VOID__INT_INT, G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_INT); + /** + * GdaDataProxy::filter-changed: + * @proxy: the #GdaDataProxy + * + * Gets emitted when @proxy's filter has been changed + */ + gda_data_proxy_signals [FILTER_CHANGED] = + g_signal_new ("filter-changed", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (GdaDataProxyClass, filter_changed), + NULL, NULL, + _gda_marshal_VOID__VOID, G_TYPE_NONE, 0); + + klass->row_delete_changed = NULL; + klass->sample_size_changed = NULL; + klass->sample_changed = NULL; + klass->validate_row_changes = m_validate_row_changes; + klass->row_changes_applied = NULL; + klass->filter_changed = NULL; + + /* virtual functions */ + object_class->dispose = gda_data_proxy_dispose; + object_class->finalize = gda_data_proxy_finalize; + + /* Properties */ + object_class->set_property = gda_data_proxy_set_property; + object_class->get_property = gda_data_proxy_get_property; + + g_object_class_install_property (object_class, PROP_MODEL, + g_param_spec_object ("model", NULL, "Proxied data model", + GDA_TYPE_DATA_MODEL, + (G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT))); + g_object_class_install_property (object_class, PROP_ADD_NULL_ENTRY, + g_param_spec_boolean ("prepend-null-entry", NULL, + "Tells if a row composed of NULL values is inserted " + "as the proxy's first row", FALSE, + (G_PARAM_READABLE | G_PARAM_WRITABLE))); + g_object_class_install_property (object_class, PROP_DEFER_SYNC, + g_param_spec_boolean ("defer-sync", NULL, + "Tells if changes to the sample of rows displayed " + "is done in background in several steps or if it's " + "done in one step.", TRUE, + (G_PARAM_READABLE | G_PARAM_WRITABLE))); + g_object_class_install_property (object_class, PROP_SAMPLE_SIZE, + g_param_spec_int ("sample-size", NULL, + "Number of rows which the proxy will contain at any time, " + "like a sliding window on the proxied data model", + 0, G_MAXINT - 1, 300, + (G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT))); + + /** + * GdaDataProxy:cache-changes: + * + * Defines how changes kept in the data proxy are handled when the proxied data model + * is changed (using the "model" property). The default is to silently discard all the + * changes, but if this property is set to %TRUE, then the changes are cached. + * + * If set to %TRUE, each cached change will be re-applied to a newly set proxied data model if + * the change's number of columns match the proxied data model's number of columns and based on: + * + * the contents of the proxied data model's modified row for updates and deletes + * the inserts are always kept + * + * + * Since: 5.2 + **/ + g_object_class_install_property (object_class, PROP_CACHE_CHANGES, + g_param_spec_boolean ("cache-changes", NULL, + "set to TRUE to keep track of changes even when the proxied data model is changed", FALSE, + (G_PARAM_READABLE | G_PARAM_WRITABLE))); + + g_mutex_lock (&parser_mutex); + internal_parser = gda_sql_parser_new (); + g_mutex_unlock (&parser_mutex); +} + +static void +gda_data_proxy_data_model_init (GdaDataModelInterface *iface) +{ + iface->get_n_rows = gda_data_proxy_get_n_rows; + iface->get_n_columns = gda_data_proxy_get_n_columns; + iface->describe_column = gda_data_proxy_describe_column; + iface->get_access_flags = gda_data_proxy_get_access_flags; + iface->get_value_at = gda_data_proxy_get_value_at; + iface->get_attributes_at = gda_data_proxy_get_attributes_at; + + iface->create_iter = NULL; + + iface->set_value_at = gda_data_proxy_set_value_at; + iface->set_values = gda_data_proxy_set_values; + iface->append_values = gda_data_proxy_append_values; + iface->append_row = gda_data_proxy_append_row; + iface->remove_row = gda_data_proxy_remove_row; + iface->find_row = gda_data_proxy_find_row_from_values; + + iface->freeze = gda_data_proxy_freeze; + iface->freeze = gda_data_proxy_thaw; + iface->get_notify = gda_data_proxy_get_notify; + iface->send_hint = gda_data_proxy_send_hint; + + iface->row_inserted = NULL; + iface->row_updated = NULL; + iface->row_removed = NULL; +} + +/* + * REM: @add_null_entry, @defer_sync and @cache_changes are not defined + */ +static void +do_init (GdaDataProxy *proxy) +{ + GdaDataProxyPrivate *priv = gda_data_proxy_get_instance_private (proxy); + g_rec_mutex_init (& (priv->mutex)); /* REM: make sure clean_proxy() is called first because + * we must not call g_rec_mutex_init() on an already initialized + * GRecMutex, see doc. */ + + priv->modify_rows = g_hash_table_new_full (g_int_hash, g_int_equal, g_free, NULL); + priv->notify_changes = TRUE; + + priv->force_direct_mapping = FALSE; + priv->sample_size = 0; + priv->chunk = NULL; + priv->chunk_to = NULL; + priv->chunk_sync_idle_id = 0; + priv->columns = NULL; + + priv->defer_proxied_model_insert = FALSE; + priv->catched_inserted_row = -1; +} + +static void +gda_data_proxy_init (GdaDataProxy *proxy) +{ + + do_init (proxy); + GdaDataProxyPrivate *priv = gda_data_proxy_get_instance_private (proxy); + + priv->add_null_entry = FALSE; + priv->defer_sync = FALSE; + priv->cache_changes = FALSE; +} + +static DisplayChunk *compute_display_chunk (GdaDataProxy *proxy); +static void adjust_displayed_chunk (GdaDataProxy *proxy); +static gboolean chunk_sync_idle (GdaDataProxy *proxy); +static void ensure_chunk_sync (GdaDataProxy *proxy); + + +static void proxied_model_row_inserted_cb (GdaDataModel *model, gint row, GdaDataProxy *proxy); +static void proxied_model_row_updated_cb (GdaDataModel *model, gint row, GdaDataProxy *proxy); +static void proxied_model_row_removed_cb (GdaDataModel *model, gint row, GdaDataProxy *proxy); +static void proxied_model_reset_cb (GdaDataModel *model, GdaDataProxy *proxy); +static void proxied_model_access_changed_cb (GdaDataModel *model, GdaDataProxy *proxy); + + +/** + * gda_data_proxy_new: + * @model: (transfer none): Data model to be proxied + * + * Creates a new proxy for @model. For bindings use @gda_data_proxy_new_with_data_model. + * + * Returns: (transfer full): a new #GdaDataProxy object + */ +GObject * +gda_data_proxy_new (GdaDataModel *model) +{ + GObject *obj; + + g_return_val_if_fail (model && GDA_IS_DATA_MODEL (model), NULL); + + obj = g_object_new (GDA_TYPE_DATA_PROXY, "model", model, NULL); + + return obj; +} + +/** + * gda_data_proxy_new_with_data_model: + * @model: (transfer none): Data model to be proxied + * + * Creates a new proxy for @model. This is the preferred method to create + * #GdaDataProxy objects by bindings. + * + * Returns: (transfer full): a new #GdaDataProxy object + * + * Since: 5.2.0 + */ +GdaDataProxy* +gda_data_proxy_new_with_data_model (GdaDataModel *model) +{ + GObject *obj; + + g_return_val_if_fail (model && GDA_IS_DATA_MODEL (model), NULL); + + obj = g_object_new (GDA_TYPE_DATA_PROXY, "model", model, NULL); + + return (GdaDataProxy*) obj; +} + +static void +clean_proxy (GdaDataProxy *proxy) +{ + GdaDataProxyPrivate *priv = gda_data_proxy_get_instance_private (proxy); + if (priv->all_modifs) { + gda_data_proxy_cancel_all_changes (proxy); + g_assert (! priv->all_modifs); + } + + if (priv->modify_rows) { + g_hash_table_destroy (priv->modify_rows); + priv->modify_rows = NULL; + } + + if (priv->filter_vcnc) { + g_object_unref (priv->filter_vcnc); + priv->filter_vcnc = NULL; + } + + if (priv->filter_expr) { + g_free (priv->filter_expr); + priv->filter_expr = NULL; + } + + if (priv->filter_stmt) { + g_object_unref (priv->filter_stmt); + priv->filter_stmt = NULL; + } + + if (priv->filtered_rows) { + g_object_unref (priv->filtered_rows); + priv->filtered_rows = NULL; + } + + priv->force_direct_mapping = FALSE; + if (priv->chunk_sync_idle_id) { + g_idle_remove_by_data (proxy); + priv->chunk_sync_idle_id = 0; + } + + if (priv->chunk) { + display_chunk_free (priv->chunk); + priv->chunk = NULL; + } + if (priv->chunk_to) { + display_chunk_free (priv->chunk_to); + priv->chunk_to = NULL; + } + + if (priv->columns) { + gint i; + for (i = 0; i < 2 * priv->model_nb_cols; i++) + g_object_unref (G_OBJECT (priv->columns[i])); + g_free (priv->columns); + priv->columns = NULL; + } + + if (priv->model) { + g_signal_handlers_disconnect_by_func (G_OBJECT (priv->model), + G_CALLBACK (proxied_model_row_inserted_cb), proxy); + g_signal_handlers_disconnect_by_func (G_OBJECT (priv->model), + G_CALLBACK (proxied_model_row_updated_cb), proxy); + g_signal_handlers_disconnect_by_func (G_OBJECT (priv->model), + G_CALLBACK (proxied_model_row_removed_cb), proxy); + g_signal_handlers_disconnect_by_func (G_OBJECT (priv->model), + G_CALLBACK (proxied_model_reset_cb), proxy); + g_signal_handlers_disconnect_by_func (G_OBJECT (priv->model), + G_CALLBACK (proxied_model_access_changed_cb), proxy); + g_object_unref (priv->model); + priv->model = NULL; + } + + if (priv->columns_attrs) { + g_free (priv->columns_attrs); + priv->columns_attrs = NULL; + } + + g_rec_mutex_clear (& (priv->mutex)); +} + +static void +gda_data_proxy_dispose (GObject *object) +{ + GdaDataProxy *proxy; + + g_return_if_fail (GDA_IS_DATA_PROXY (object)); + + proxy = GDA_DATA_PROXY (object); + clean_proxy (proxy); + + clean_cached_changes (proxy); + + /* parent class */ + G_OBJECT_CLASS (gda_data_proxy_parent_class)->dispose (object); +} + +static void +gda_data_proxy_finalize (GObject *object) +{ + g_return_if_fail (object != NULL); + g_return_if_fail (GDA_IS_DATA_PROXY (object)); + + /* parent class */ + G_OBJECT_CLASS (gda_data_proxy_parent_class)->finalize (object); +} + +static void +gda_data_proxy_set_property (GObject *object, + guint param_id, + const GValue *value, + GParamSpec *pspec) +{ + GdaDataProxy *proxy; + + proxy = GDA_DATA_PROXY (object); + GdaDataProxyPrivate *priv = gda_data_proxy_get_instance_private (proxy); + if (priv) { + g_rec_mutex_lock (& (priv->mutex)); + switch (param_id) { + case PROP_MODEL: { + GdaDataModel *model; + gint col; + gboolean already_set = FALSE; + + if (priv->model) { + if (priv->cache_changes) + migrate_current_changes_to_cache (proxy); + + gboolean notify_changes; + notify_changes = priv->notify_changes; + + priv->notify_changes = FALSE; + clean_proxy (proxy); + priv->notify_changes = notify_changes; + + do_init (proxy); + already_set = TRUE; + g_object_unref (priv->model); + priv->model = NULL; + } + + model = (GdaDataModel*) g_value_get_object (value); + g_return_if_fail (GDA_IS_DATA_MODEL (model)); + + if (! (gda_data_model_get_access_flags (model) & GDA_DATA_MODEL_ACCESS_RANDOM)) { + g_warning (_("GdaDataProxy can't handle non random access data models")); + g_rec_mutex_unlock (& (priv->mutex)); + return; + } + priv->model = g_object_ref (model); + + priv->model_nb_cols = gda_data_model_get_n_columns (model); + priv->model_nb_rows = gda_data_model_get_n_rows (model); + + /* column attributes */ + priv->columns_attrs = g_new0 (GdaValueAttribute, priv->model_nb_cols); + for (col = 0; col < priv->model_nb_cols; col++) { + GdaColumn *column; + GdaValueAttribute flags = GDA_VALUE_ATTR_IS_UNCHANGED; + + column = gda_data_model_describe_column (model, col); + if (gda_column_get_allow_null (column)) + flags |= GDA_VALUE_ATTR_CAN_BE_NULL; + if (gda_column_get_default_value (column)) + flags |= GDA_VALUE_ATTR_CAN_BE_DEFAULT; + priv->columns_attrs[col] = flags; + } + + g_signal_connect (G_OBJECT (model), "row-inserted", + G_CALLBACK (proxied_model_row_inserted_cb), proxy); + g_signal_connect (G_OBJECT (model), "row-updated", + G_CALLBACK (proxied_model_row_updated_cb), proxy); + g_signal_connect (G_OBJECT (model), "row-removed", + G_CALLBACK (proxied_model_row_removed_cb), proxy); + g_signal_connect (G_OBJECT (model), "reset", + G_CALLBACK (proxied_model_reset_cb), proxy); + g_signal_connect (G_OBJECT (model), "access-changed", + G_CALLBACK (proxied_model_access_changed_cb), proxy); + + /* initial chunk settings, no need to emit any signal as it's an initial state */ + priv->chunk = compute_display_chunk (proxy); + if (!priv->chunk->mapping) { + display_chunk_free (priv->chunk); + priv->chunk = NULL; + } + + if (priv->cache_changes) + fetch_current_cached_changes (proxy); + + if (already_set) + gda_data_model_reset (GDA_DATA_MODEL (proxy)); + break; + } + case PROP_ADD_NULL_ENTRY: + if (priv->add_null_entry != g_value_get_boolean (value)) { + priv->add_null_entry = g_value_get_boolean (value); + + if (priv->add_null_entry) + gda_data_model_row_inserted ((GdaDataModel *) proxy, 0); + else + gda_data_model_row_removed ((GdaDataModel *) proxy, 0); + } + break; + case PROP_DEFER_SYNC: + priv->defer_sync = g_value_get_boolean (value); + if (!priv->defer_sync && priv->chunk_sync_idle_id) { + g_idle_remove_by_data (proxy); + priv->chunk_sync_idle_id = 0; + chunk_sync_idle (proxy); + } + break; + case PROP_SAMPLE_SIZE: + priv->sample_size = g_value_get_int (value); + if (priv->sample_size < 0) + priv->sample_size = 0; + + /* initial chunk settings, no need to emit any signal as it's an initial state */ + priv->chunk = compute_display_chunk (proxy); + if (!priv->chunk->mapping) { + display_chunk_free (priv->chunk); + priv->chunk = NULL; + } + break; + case PROP_CACHE_CHANGES: + priv->cache_changes = g_value_get_boolean (value); + if (! priv->cache_changes) + clean_cached_changes (proxy); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + break; + } + g_rec_mutex_unlock (& (priv->mutex)); + } +} + +static void +gda_data_proxy_get_property (GObject *object, + guint param_id, + GValue *value, + GParamSpec *pspec) +{ + GdaDataProxy *proxy; + + proxy = GDA_DATA_PROXY (object); + GdaDataProxyPrivate *priv = gda_data_proxy_get_instance_private (proxy); + if (priv) { + g_rec_mutex_lock (& (priv->mutex)); + switch (param_id) { + case PROP_ADD_NULL_ENTRY: + g_value_set_boolean (value, priv->add_null_entry); + break; + case PROP_DEFER_SYNC: + g_value_set_boolean (value, priv->defer_sync); + break; + case PROP_SAMPLE_SIZE: + g_value_set_int (value, priv->sample_size); + break; + case PROP_CACHE_CHANGES: + g_value_set_boolean (value, priv->cache_changes); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + break; + } + g_rec_mutex_unlock (& (priv->mutex)); + } +} + +static void +proxied_model_row_inserted_cb (G_GNUC_UNUSED GdaDataModel *model, gint row, GdaDataProxy *proxy) +{ + GdaDataProxyPrivate *priv = gda_data_proxy_get_instance_private (proxy); + gint abs_row; + gint signal_row_offset = priv->add_null_entry ? 1 : 0; + abs_row = row; /* can't call model_row_to_absolute_row because @row is not *officially* part of the computations */ + + /* internal cleanups: update chunk and chunk_to arrays */ + if (priv->chunk) { + gsize i; + gint *v; + + for (i = 0; i < priv->chunk->mapping->len; i++) { + v = &g_array_index (priv->chunk->mapping, gint, i); + if (*v >= abs_row) + *v += 1; + } + } + if (priv->chunk_to && priv->chunk->mapping) { + gsize i; + gint *v; + + for (i = 0; i < priv->chunk_to->mapping->len; i++) { + v = &g_array_index (priv->chunk_to->mapping, gint, i); + if (*v >= abs_row) + *v -= 1; + } + } + + /* update all the RowModif where model_row > row */ + if (priv->all_modifs) { + GSList *list; + for (list = priv->all_modifs; list; list = list->next) { + RowModif *tmprm; + tmprm = ROW_MODIF (list->data); + if (tmprm->model_row > row) { + gint tmp; + tmp = tmprm->model_row; + g_hash_table_remove (priv->modify_rows, &tmp); + tmprm->model_row ++; + + gint *ptr; + ptr = g_new (gint, 1); + *ptr = tmprm->model_row; + g_hash_table_insert (priv->modify_rows, ptr, tmprm); + } + } + } + + /* Note: if there is a chunk, then the new row will *not* be part of that chunk and so + * no signal will be emitted for its insertion */ + priv->model_nb_rows ++; + if (priv->defer_proxied_model_insert) + priv->catched_inserted_row = row; + else if (!priv->chunk && !priv->chunk_to) + gda_data_model_row_inserted ((GdaDataModel *) proxy, row + signal_row_offset); +} + +static void +proxied_model_row_updated_cb (G_GNUC_UNUSED GdaDataModel *model, gint row, GdaDataProxy *proxy) +{ + gint proxy_row, tmp; + RowModif *rm; + GdaDataProxyPrivate *priv = gda_data_proxy_get_instance_private (proxy); + + /* destroy any RowModif associated ro @row */ + tmp = row; + rm = g_hash_table_lookup (priv->modify_rows, &tmp); + if (rm) { + /* FIXME: compare with the new value of the updated row and remove RowModif only if there + * are no more differences. For now we only get rid of that RowModif. + */ + g_hash_table_remove (priv->modify_rows, &tmp); + priv->all_modifs = g_slist_remove (priv->all_modifs, rm); + row_modifs_free (rm); + } + + /* if @row is a "visible" row, then emit the updated signal on it */ + proxy_row = absolute_row_to_proxy_row (proxy, model_row_to_absolute_row (proxy, row)); + if (proxy_row >= 0) + gda_data_model_row_updated ((GdaDataModel *) proxy, proxy_row); +} + +static void +proxied_model_row_removed_cb (G_GNUC_UNUSED GdaDataModel *model, gint row, GdaDataProxy *proxy) +{ + gint proxy_row, abs_row; + RowModif *rm; + GdaDataProxyPrivate *priv = gda_data_proxy_get_instance_private (proxy); + + gint signal_row_offset = priv->add_null_entry ? 1 : 0; + abs_row = model_row_to_absolute_row (proxy, row); + proxy_row = absolute_row_to_proxy_row (proxy, abs_row); + + /* internal cleanups: update chunk and chunk_to arrays */ + if (priv->chunk) { + gsize i; + gint *v, remove_index = -1; + + for (i = 0; i < priv->chunk->mapping->len; i++) { + v = &g_array_index (priv->chunk->mapping, gint, i); + if (*v > abs_row) + *v -= 1; + else if (*v == abs_row) { + g_assert (remove_index == -1); + remove_index = i; + } + } + if (remove_index >= 0) + g_array_remove_index (priv->chunk->mapping, remove_index); + if ((proxy_row >= 0) && (priv->chunk_sep >= (proxy_row - signal_row_offset))) + priv->chunk_sep--; + } + if (priv->chunk_to && priv->chunk->mapping) { + guint i; + gint *v, remove_index = -1; + + for (i = 0; i < priv->chunk_to->mapping->len; i++) { + v = &g_array_index (priv->chunk_to->mapping, gint, i); + if (*v > abs_row) + *v -= 1; + else if (*v == abs_row) { + g_assert (remove_index == -1); + remove_index = i; + } + } + if (remove_index >= 0) + g_array_remove_index (priv->chunk_to->mapping, remove_index); + } + priv->chunk_proxy_nb_rows--; + priv->model_nb_rows --; + + /* destroy any RowModif associated ro @row */ + gint tmp; + tmp = row; + rm = g_hash_table_lookup (priv->modify_rows, &tmp); + if (rm) { + g_hash_table_remove (priv->modify_rows, &tmp); + priv->all_modifs = g_slist_remove (priv->all_modifs, rm); + row_modifs_free (rm); + } + + /* update all the RowModif where model_row > row */ + if (priv->all_modifs) { + GSList *list; + for (list = priv->all_modifs; list; list = list->next) { + RowModif *tmprm; + tmprm = ROW_MODIF (list->data); + if (tmprm->model_row > row) { + tmp = tmprm->model_row; + g_hash_table_remove (priv->modify_rows, &tmp); + tmprm->model_row --; + + gint *ptr; + ptr = g_new (gint, 1); + *ptr = tmprm->model_row; + g_hash_table_insert (priv->modify_rows, ptr, tmprm); + } + } + } + + /* actual signal emission if row is 'visible' */ + if (proxy_row >= 0) + gda_data_model_row_removed ((GdaDataModel *) proxy, proxy_row); +} + +/* + * called when the proxied model emits a "reset" signal + */ +static void +proxied_model_reset_cb (GdaDataModel *model, GdaDataProxy *proxy) +{ + g_object_ref (G_OBJECT (model)); + clean_proxy (proxy); + do_init (proxy); + g_object_set (G_OBJECT (proxy), "model", model, NULL); + g_object_unref (G_OBJECT (model)); + GdaDataProxyPrivate *priv = gda_data_proxy_get_instance_private (proxy); + + if (priv->columns) { + /* adjust column's types */ + gint i; + GdaColumn *orig; + for (i = 0; i < priv->model_nb_cols; i++) { + orig = gda_data_model_describe_column (priv->model, i); + gda_column_set_g_type (priv->columns[i], gda_column_get_g_type (orig)); + } + for (; i < 2 * priv->model_nb_cols; i++) { + orig = gda_data_model_describe_column (priv->model, + i - priv->model_nb_cols); + gda_column_set_g_type (priv->columns[i], gda_column_get_g_type (orig)); + } + } + + gda_data_model_reset (GDA_DATA_MODEL (proxy)); +} + +static void +proxied_model_access_changed_cb (G_GNUC_UNUSED GdaDataModel *model, GdaDataProxy *proxy) +{ + g_signal_emit_by_name (proxy, "access-changed"); +} + +/** + * gda_data_proxy_get_proxied_model: + * @proxy: a #GdaDataProxy object + * + * Fetch the #GdaDataModel which @proxy does proxy + * + * Returns: (transfer none): the proxied data model + */ +GdaDataModel * +gda_data_proxy_get_proxied_model (GdaDataProxy *proxy) +{ + g_return_val_if_fail (GDA_IS_DATA_PROXY (proxy), NULL); + GdaDataProxyPrivate *priv = gda_data_proxy_get_instance_private (proxy); + + return priv->model; +} + +/** + * gda_data_proxy_get_proxied_model_n_cols: + * @proxy: a #GdaDataProxy object + * + * Get the number of columns in the proxied data model + * + * Returns: the number of columns, or -1 if an error occurred + */ +gint +gda_data_proxy_get_proxied_model_n_cols (GdaDataProxy *proxy) +{ + g_return_val_if_fail (GDA_IS_DATA_PROXY (proxy), -1); + GdaDataProxyPrivate *priv = gda_data_proxy_get_instance_private (proxy); + + return priv->model_nb_cols; +} + +/** + * gda_data_proxy_get_proxied_model_n_rows: + * @proxy: a #GdaDataProxy object + * + * Get the number of rows in the proxied data model + * + * Returns: the number of rows, or -1 if the number of rows is not known + */ +gint +gda_data_proxy_get_proxied_model_n_rows (GdaDataProxy *proxy) +{ + g_return_val_if_fail (GDA_IS_DATA_PROXY (proxy), -1); + GdaDataProxyPrivate *priv = gda_data_proxy_get_instance_private (proxy); + + return gda_data_model_get_n_rows (priv->model); +} + +/** + * gda_data_proxy_is_read_only: + * @proxy: a #GdaDataProxy object + * + * Returns: TRUE if the proxied data model is itself read-only + */ +gboolean +gda_data_proxy_is_read_only (GdaDataProxy *proxy) +{ + GdaDataModelAccessFlags flags; + + g_return_val_if_fail (GDA_IS_DATA_PROXY (proxy), TRUE); + GdaDataProxyPrivate *priv = gda_data_proxy_get_instance_private (proxy); + + flags = gda_data_model_get_access_flags (priv->model); + return ! (flags & GDA_DATA_MODEL_ACCESS_WRITE); +} + + +static RowModif *find_or_create_row_modif (GdaDataProxy *proxy, gint proxy_row, gint col, RowValue **ret_rv); + + +/* + * Stores the new RowValue in @rv + */ +static RowModif * +find_or_create_row_modif (GdaDataProxy *proxy, gint proxy_row, gint col, RowValue **ret_rv) +{ + RowModif *rm = NULL; + RowValue *rv = NULL; + gint model_row; + GdaDataProxyPrivate *priv = gda_data_proxy_get_instance_private (proxy); + g_assert (proxy_row >= 0); + + model_row = absolute_row_to_model_row (proxy, + proxy_row_to_absolute_row (proxy, proxy_row), &rm); + if (!rm) { + /* create a new RowModif */ + g_assert (model_row >= 0); + rm = row_modifs_new (proxy, proxy_row); + rm->model_row = model_row; + + gint *ptr; + ptr = g_new (gint, 1); + *ptr = model_row; + g_hash_table_insert (priv->modify_rows, ptr, rm); + priv->all_modifs = g_slist_prepend (priv->all_modifs, rm); + } + else { + /* there are already some modifications to the row, try to catch the RowValue if available */ + GSList *list; + + list = rm->modify_values; + while (list && !rv) { + if (ROW_VALUE (list->data)->model_column == col) + rv = ROW_VALUE (list->data); + list = g_slist_next (list); + } + } + + if (ret_rv) + *ret_rv = rv; + return rm; +} + + +/** + * gda_data_proxy_get_values: + * @proxy: a #GdaDataProxy object + * @proxy_row: a proxy row + * @cols_index: (array length=n_cols): array containing the columns for which the values are requested + * @n_cols: size of @cols_index + * + * Retrieve a whole list of values from the @proxy data model. This function + * calls gda_data_proxy_get_value() + * for each column index specified in @cols_index, and generates a #GSList on the way. + * + * Returns: (element-type GValue) (transfer container): a new list of values (the list must be freed, not the values), + * or %NULL if an error occurred + */ +GSList * +gda_data_proxy_get_values (GdaDataProxy *proxy, gint proxy_row, gint *cols_index, gint n_cols) +{ + GSList *retval = NULL; + gint i; + const GValue *value; + + g_return_val_if_fail (GDA_IS_DATA_PROXY (proxy), NULL); + g_return_val_if_fail (proxy_row >= 0, NULL); + GdaDataProxyPrivate *priv = gda_data_proxy_get_instance_private (proxy); + + g_rec_mutex_lock (& (priv->mutex)); + for (i = 0; i < n_cols; i++) { + value = gda_data_proxy_get_value_at ((GdaDataModel *) proxy, cols_index[i], proxy_row, NULL); + if (value) + retval = g_slist_prepend (retval, (GValue *) value); + else { + g_slist_free (retval); + g_rec_mutex_unlock (& (priv->mutex)); + return NULL; + } + } + g_rec_mutex_unlock (& (priv->mutex)); + + return g_slist_reverse (retval); +} + +/** + * gda_data_proxy_get_value_attributes: + * @proxy: a #GdaDataProxy object + * @proxy_row: a proxy row + * @col: a valid proxy column + * + * Get the attributes of the value stored at (proxy_row, col) in @proxy, which + * is an ORed value of #GdaValueAttribute flags + * + * Returns: a #GdaValueAttribute with the value's attributes at given position + */ +GdaValueAttribute +gda_data_proxy_get_value_attributes (GdaDataProxy *proxy, gint proxy_row, gint col) +{ + gint model_row; + RowModif *rm; + gboolean value_has_modifs = FALSE; + GdaValueAttribute flags = 0; + gint model_column; + + g_return_val_if_fail (GDA_IS_DATA_PROXY (proxy), 0); + g_return_val_if_fail (proxy_row >= 0, 0); + GdaDataProxyPrivate *priv = gda_data_proxy_get_instance_private (proxy); + + g_rec_mutex_lock (& (priv->mutex)); + model_column = col % priv->model_nb_cols; + model_row = proxy_row_to_model_row (proxy, proxy_row); + flags = gda_data_model_get_attributes_at (priv->model, model_column, model_row); + if (model_row < 0) + flags |= GDA_VALUE_ATTR_IS_NULL; + + rm = proxy_row_to_row_modif (proxy, proxy_row); + if (rm) { + if (rm->modify_values) { + /* there are some modifications to the row */ + GSList *list; + RowValue *rv = NULL; + + list = rm->modify_values; + while (list && !rv) { + if (ROW_VALUE (list->data)->model_column == model_column) + rv = ROW_VALUE (list->data); + list = g_slist_next (list); + } + if (rv) { + value_has_modifs = TRUE; + flags |= rv->attributes; + if (rv->value && !gda_value_is_null (rv->value)) + flags &= ~GDA_VALUE_ATTR_IS_NULL; + else + flags |= GDA_VALUE_ATTR_IS_NULL; + } + } + } + + if (! value_has_modifs) + flags |= GDA_VALUE_ATTR_IS_UNCHANGED; + + /* compute the GDA_VALUE_ATTR_DATA_NON_VALID attribute */ + if (! (flags & GDA_VALUE_ATTR_CAN_BE_NULL)) { + if ((flags & GDA_VALUE_ATTR_IS_NULL) && !(flags & GDA_VALUE_ATTR_IS_DEFAULT)) + flags |= GDA_VALUE_ATTR_DATA_NON_VALID; + } + + g_rec_mutex_unlock (& (priv->mutex)); + + /*g_print ("%s (%p, %d, %d) => %d\n", __FUNCTION__, proxy, col, proxy_row, flags);*/ + return flags; +} + +/** + * gda_data_proxy_alter_value_attributes: + * @proxy: a #GdaDataProxy object + * @proxy_row: A proxy row number + * @col: a valid column number + * @alter_flags: (transfer none): flags to alter the attributes + * + * Alters the attributes of the value stored at (proxy_row, col) in @proxy. the @alter_flags + * can only contain the GDA_VALUE_ATTR_IS_NULL, GDA_VALUE_ATTR_IS_DEFAULT and GDA_VALUE_ATTR_IS_UNCHANGED + * flags (other flags are ignored). + */ +void +gda_data_proxy_alter_value_attributes (GdaDataProxy *proxy, gint proxy_row, gint col, GdaValueAttribute alter_flags) +{ + gint model_col; + + g_return_if_fail (GDA_IS_DATA_PROXY (proxy)); + g_return_if_fail (proxy_row >= 0); + GdaDataProxyPrivate *priv = gda_data_proxy_get_instance_private (proxy); + + g_rec_mutex_lock (& (priv->mutex)); + + model_col = col % priv->model_nb_cols; + if (alter_flags & GDA_VALUE_ATTR_IS_NULL) + gda_data_proxy_set_value_at ((GdaDataModel*) proxy, + model_col, proxy_row, NULL, NULL); + else { + RowModif *rm; + RowValue *rv = NULL; + + rm = find_or_create_row_modif (proxy, proxy_row, model_col, &rv); + g_assert (rm); + + if (alter_flags & GDA_VALUE_ATTR_IS_DEFAULT) { + GdaValueAttribute flags = 0; + if (!rv) { + /* create a new RowValue */ + rv = g_new0 (RowValue, 1); + rv->row_modif = rm; + rv->model_column = model_col; + rv->attributes = priv->columns_attrs [col]; + flags = rv->attributes; + + rv->value = NULL; + flags &= ~GDA_VALUE_ATTR_IS_UNCHANGED; + if (rm->model_row >= 0) + flags |= GDA_VALUE_ATTR_HAS_VALUE_ORIG; + else + flags &= ~GDA_VALUE_ATTR_HAS_VALUE_ORIG; + + rm->modify_values = g_slist_prepend (rm->modify_values, rv); + } + else { + flags = rv->attributes; + if (rv->value) { + gda_value_free (rv->value); + rv->value = NULL; + } + } + flags |= GDA_VALUE_ATTR_IS_DEFAULT; + rv->attributes = flags; + + if (priv->notify_changes) + gda_data_model_row_updated ((GdaDataModel *) proxy, proxy_row); + } + if (alter_flags & GDA_VALUE_ATTR_IS_UNCHANGED) { + if (!rm->orig_values) + g_warning ("Alter_Flags = GDA_VALUE_ATTR_IS_UNCHANGED, no RowValue!"); + else + gda_data_proxy_set_value_at ((GdaDataModel*) proxy, + model_col, proxy_row, + rm->orig_values [model_col], + NULL); + } + } + + g_rec_mutex_unlock (& (priv->mutex)); +} + +/** + * gda_data_proxy_get_proxied_model_row: + * @proxy: a #GdaDataProxy object + * @proxy_row: A proxy row number + * + * Get the @proxy's proxied model row corresponding to @proxy_row + + * Returns: the proxied model's row, or -1 if @proxy row which only exists @proxy + */ +gint +gda_data_proxy_get_proxied_model_row (GdaDataProxy *proxy, gint proxy_row) +{ + g_return_val_if_fail (GDA_IS_DATA_PROXY (proxy), 0); + g_return_val_if_fail (proxy_row >= 0, 0); + + return proxy_row_to_model_row (proxy, proxy_row); +} + +/** + * gda_data_proxy_delete: + * @proxy: a #GdaDataProxy object + * @proxy_row: A proxy row number + * + * Marks the row @proxy_row to be deleted + */ +void +gda_data_proxy_delete (GdaDataProxy *proxy, gint proxy_row) +{ + RowModif *rm = NULL; + gboolean do_signal = FALSE; + gint model_row, abs_row; + + g_return_if_fail (GDA_IS_DATA_PROXY (proxy)); + g_return_if_fail (proxy_row >= 0); + GdaDataProxyPrivate *priv = gda_data_proxy_get_instance_private (proxy); + + g_rec_mutex_lock (& (priv->mutex)); + + /* ensure that there is no sync to be done */ + ensure_chunk_sync (proxy); + + if (priv->add_null_entry && proxy_row == 0) { + g_warning (_("The first row is an empty row artificially prepended and cannot be removed")); + g_rec_mutex_unlock (& (priv->mutex)); + return; + } + + if (! (gda_data_model_get_access_flags ((GdaDataModel*) proxy) & GDA_DATA_MODEL_ACCESS_DELETE)) { + g_rec_mutex_unlock (& (priv->mutex)); + return; + } + + abs_row = proxy_row_to_absolute_row (proxy, proxy_row); + model_row = absolute_row_to_model_row (proxy, abs_row, &rm); + if (rm) { + if (! rm->to_be_deleted) { + if (rm->model_row == -1) { + /* remove the row completely because it does not exist in the data model */ + priv->all_modifs = g_slist_remove (priv->all_modifs, rm); + priv->new_rows = g_slist_remove (priv->new_rows, rm); + row_modifs_free (rm); + + if (priv->chunk) { + /* Update chunk */ + gsize i; + gint *v; + gint row_cmp = proxy_row - (priv->add_null_entry ? 1 : 0); + for (i = 0; i < priv->chunk->mapping->len; i++) { + v = &g_array_index (priv->chunk->mapping, gint, i); + if (*v > abs_row) + *v -= 1; + } + g_array_remove_index (priv->chunk->mapping, row_cmp); + } + + if (priv->notify_changes) + gda_data_model_row_removed ((GdaDataModel *) proxy, proxy_row); + } + else { + rm->to_be_deleted = TRUE; + do_signal = TRUE; + } + } + } + else { + /* the row is an existing row in the data model, create a new RowModif */ + rm = row_modifs_new (proxy, proxy_row); + rm->model_row = model_row; + + gint *ptr; + ptr = g_new (gint, 1); + *ptr = model_row; + g_hash_table_insert (priv->modify_rows, ptr, rm); + priv->all_modifs = g_slist_prepend (priv->all_modifs, rm); + rm->to_be_deleted = TRUE; + do_signal = TRUE; + } + + if (do_signal && priv->notify_changes) { + gda_data_model_row_updated ((GdaDataModel *) proxy, proxy_row); + g_signal_emit (G_OBJECT (proxy), + gda_data_proxy_signals[ROW_DELETE_CHANGED], + 0, proxy_row, TRUE); + } + + g_rec_mutex_unlock (& (priv->mutex)); +} + +/** + * gda_data_proxy_undelete: + * @proxy: a #GdaDataProxy object + * @proxy_row: A proxy row number + * + * Remove the "to be deleted" mark at the row @proxy_row, if it existed. + */ +void +gda_data_proxy_undelete (GdaDataProxy *proxy, gint proxy_row) +{ + RowModif *rm = NULL; + gboolean do_signal = FALSE; + gint model_row; + + g_return_if_fail (GDA_IS_DATA_PROXY (proxy)); + g_return_if_fail (proxy_row >= 0); + GdaDataProxyPrivate *priv = gda_data_proxy_get_instance_private (proxy); + + g_rec_mutex_lock (& (priv->mutex)); + + /* ensure that there is no sync to be done */ + ensure_chunk_sync (proxy); + + model_row = absolute_row_to_model_row (proxy, + proxy_row_to_absolute_row (proxy, proxy_row), &rm); + if (rm) { + rm->to_be_deleted = FALSE; + if (!rm->modify_values) { + /* get rid of that RowModif */ + do_signal= TRUE; + + gint tmp; + tmp = model_row; + g_hash_table_remove (priv->modify_rows, &tmp); + priv->all_modifs = g_slist_remove (priv->all_modifs, rm); + row_modifs_free (rm); + } + else + do_signal= TRUE; + } + + if (do_signal && priv->notify_changes) { + gda_data_model_row_updated ((GdaDataModel *) proxy, proxy_row); + g_signal_emit (G_OBJECT (proxy), + gda_data_proxy_signals[ROW_DELETE_CHANGED], + 0, proxy_row, FALSE); + } + + g_rec_mutex_unlock (& (priv->mutex)); +} + +/** + * gda_data_proxy_row_is_deleted: + * @proxy: a #GdaDataProxy object + * @proxy_row: A proxy row number + * + * Tells if the row number @proxy_row is marked to be deleted. + * + * Returns: TRUE if the row is marked to be deleted + */ +gboolean +gda_data_proxy_row_is_deleted (GdaDataProxy *proxy, gint proxy_row) +{ + RowModif *rm; + + g_return_val_if_fail (GDA_IS_DATA_PROXY (proxy), FALSE); + g_return_val_if_fail (proxy_row >= 0, FALSE); + + rm = proxy_row_to_row_modif (proxy, proxy_row); + return rm && rm->to_be_deleted ? TRUE : FALSE; +} + +/** + * gda_data_proxy_row_is_inserted: + * @proxy: a #GdaDataProxy object + * @proxy_row: A proxy row number + * + * Tells if the row number @proxy_row is a row which has been inserted in @proxy + * (and is thus not in the proxied data model). + * + * Returns: TRUE if the row is an inserted row + */ +gboolean +gda_data_proxy_row_is_inserted (GdaDataProxy *proxy, gint proxy_row) +{ + RowModif *rm; + + g_return_val_if_fail (GDA_IS_DATA_PROXY (proxy), FALSE); + g_return_val_if_fail (proxy_row >= 0, FALSE); + + rm = proxy_row_to_row_modif (proxy, proxy_row); + if (rm && (rm->model_row < 0)) + return TRUE; + return FALSE; +} + +/* + * gda_data_proxy_append + * @proxy: a #GdaDataProxy object + * + * Appends a new row to the proxy. The operation can fail if either: + * + * The INSERT operation is not accepted by the proxied data model + * There is an unknown number of rows in the proxy + * + * + * Returns: the proxy row number of the new row, or -1 if the row could not be appended + */ +static gint +gda_data_proxy_append (GdaDataProxy *proxy) +{ + RowModif *rm; + gint col; + gint proxy_row; + gint abs_row; + + g_return_val_if_fail (GDA_IS_DATA_PROXY (proxy), -1); + GdaDataProxyPrivate *priv = gda_data_proxy_get_instance_private (proxy); + + /* ensure that there is no sync to be done */ + ensure_chunk_sync (proxy); + + if (! (gda_data_model_get_access_flags ((GdaDataModel *) proxy) & GDA_DATA_MODEL_ACCESS_INSERT)) + return -1; + if (priv->model_nb_rows == -1) + return -1; + + /* RowModif structure */ + rm = row_modifs_new (proxy, -1); + rm->model_row = -1; + rm->orig_values = NULL; /* there is no original value */ + rm->orig_values_size = priv->model_nb_cols; + + priv->all_modifs = g_slist_prepend (priv->all_modifs, rm); + priv->new_rows = g_slist_append (priv->new_rows, rm); + + /* new proxy row value */ + abs_row = row_modif_to_absolute_row (proxy, rm); + if (priv->chunk) { + proxy_row = priv->chunk->mapping->len; + g_array_append_val (priv->chunk->mapping, abs_row); + if (priv->add_null_entry) + proxy_row++; + } + else + proxy_row = gda_data_proxy_get_n_rows ((GdaDataModel*) proxy) - 1; + + /* for the columns which allow a default value, set them to the default value */ + for (col = 0; col < priv->model_nb_cols; col ++) { + GdaColumn *column; + const GValue *def; + RowValue *rv; + GdaValueAttribute flags = 0; + + /* create a new RowValue */ + rv = g_new0 (RowValue, 1); + rv->row_modif = rm; + rv->model_column = col; + rv->attributes = GDA_VALUE_ATTR_NONE; + rv->value = NULL; + rm->modify_values = g_slist_prepend (rm->modify_values, rv); + + column = gda_data_model_describe_column (priv->model, col); + def = gda_column_get_default_value (column); + if (def) { + flags |= (GDA_VALUE_ATTR_IS_DEFAULT | GDA_VALUE_ATTR_CAN_BE_DEFAULT); + if (G_VALUE_TYPE (def) == gda_column_get_g_type (column)) + rv->value = gda_value_copy (def); + } + if (gda_column_get_allow_null (column)) { + GdaValueAttribute attributes; + + attributes = gda_data_model_get_attributes_at (priv->model, col, -1);; + if (attributes & GDA_VALUE_ATTR_CAN_BE_NULL) + flags |= GDA_VALUE_ATTR_CAN_BE_NULL; + } + + if (gda_column_get_auto_increment (column)) + flags |= (GDA_VALUE_ATTR_IS_DEFAULT | GDA_VALUE_ATTR_CAN_BE_DEFAULT); + + rv->attributes = flags; + } + + /* signal row insertion */ + if (priv->notify_changes) + gda_data_model_row_inserted ((GdaDataModel *) proxy, proxy_row); + + return proxy_row; +} + +/** + * gda_data_proxy_cancel_row_changes: + * @proxy: a #GdaDataProxy object + * @proxy_row: the row to cancel changes + * @col: the column to cancel changes, or less than 0 to cancel any change on the @row row + * + * Resets data at the corresponding row and column. If @proxy_row corresponds to a new row, then + * that new row is deleted from @proxy. + */ +void +gda_data_proxy_cancel_row_changes (GdaDataProxy *proxy, gint proxy_row, gint col) +{ + g_return_if_fail (GDA_IS_DATA_PROXY (proxy)); + g_return_if_fail (proxy_row >= 0); + GdaDataProxyPrivate *priv = gda_data_proxy_get_instance_private (proxy); + + g_rec_mutex_lock (& (priv->mutex)); + + /* ensure that there is no sync to be done */ + ensure_chunk_sync (proxy); + + if (((col >= 0) && (col < priv->model_nb_cols)) || + (col < 0)) { + RowModif *rm; + gboolean signal_update = FALSE; + gboolean signal_delete = FALSE; + + rm = proxy_row_to_row_modif (proxy, proxy_row); + if (rm && rm->modify_values) { + /* there are some modifications to the row */ + GSList *list; + RowValue *rv = NULL; + + list = rm->modify_values; + while (list && (!rv || (col < 0))) { + if ((col < 0) || (ROW_VALUE (list->data)->model_column == col)) { + rv = ROW_VALUE (list->data); + + /* remove this RowValue from the RowList */ + rm->modify_values = g_slist_remove (rm->modify_values, rv); + if (!rm->modify_values && !rm->to_be_deleted) { + /* remove this RowList as well */ + priv->all_modifs = g_slist_remove (priv->all_modifs, rm); + if (rm->model_row < 0) { + if (priv->chunk) { + /* Update chunk */ + gsize i; + gint *v, abs_row; + gint row_cmp = proxy_row - (priv->add_null_entry ? 1 : 0); + abs_row = proxy_row_to_absolute_row (proxy, proxy_row); + for (i = 0; i < priv->chunk->mapping->len; i++) { + v = &g_array_index (priv->chunk->mapping, gint, i); + if (*v > abs_row) + *v -= 1; + } + g_array_remove_index (priv->chunk->mapping, row_cmp); + } + signal_delete = TRUE; + priv->new_rows = g_slist_remove (priv->new_rows, rm); + } + else { + gint tmp; + tmp = rm->model_row; + g_hash_table_remove (priv->modify_rows, &tmp); + } + row_modifs_free (rm); + rm = NULL; + } + else { + signal_update = TRUE; + } + if (rm) + list = rm->modify_values; + else + list = NULL; + } + else + list = list->next; + } + } + + if (priv->notify_changes) { + if (signal_delete) + gda_data_model_row_removed ((GdaDataModel *) proxy, proxy_row); + else if (signal_update) + gda_data_model_row_updated ((GdaDataModel *) proxy, proxy_row); + } + } + else + g_warning ("GdaDataProxy column %d is not a modifiable data column", col); + + g_rec_mutex_unlock (& (priv->mutex)); +} + +static gboolean commit_row_modif (GdaDataProxy *proxy, RowModif *rm, gboolean adjust_display, GError **error); + +/** + * gda_data_proxy_apply_row_changes: + * @proxy: a #GdaDataProxy object + * @proxy_row: the row number to commit + * @error: place to store the error, or %NULL + * + * Commits the modified data in the proxy back into the #GdaDataModel. + * + * Returns: TRUE if no error occurred. + */ +gboolean +gda_data_proxy_apply_row_changes (GdaDataProxy *proxy, gint proxy_row, GError **error) +{ + g_return_val_if_fail (GDA_IS_DATA_PROXY (proxy), FALSE); + g_return_val_if_fail (proxy_row >= 0, FALSE); + + return commit_row_modif (proxy, proxy_row_to_row_modif (proxy, proxy_row), TRUE, error); +} + +/* + * Commits the modifications held in one single RowModif structure. + * + * Returns: TRUE if no error occurred + */ +static gboolean +commit_row_modif (GdaDataProxy *proxy, RowModif *rm, gboolean adjust_display, GError **error) +{ + gboolean err = FALSE; + gint proxy_row, model_row; + GError *lerror = NULL; + GdaDataProxyPrivate *priv = gda_data_proxy_get_instance_private (proxy); + + if (!rm) + return TRUE; + + g_rec_mutex_lock (& (priv->mutex)); + + model_row = rm->model_row; + + /* ensure that there is no sync to be done */ + ensure_chunk_sync (proxy); + + /* + * Steps in this procedure: + * -1- send the "validate-row-changes" signal, and abort if return value is FALSE + * -2- apply desired modification (which _should_ trigger "row_{inserted,removed,updated}" signals from + * the proxied model) + * -3- if no error then destroy the RowModif which has just been applied + * and refresh displayed chunks if @adjust_display is set to TRUE + * -4- send the "row-changes-applied" signal + */ + proxy_row = row_modif_to_proxy_row (proxy, rm); + + /* validate the changes to this row */ + g_signal_emit (G_OBJECT (proxy), + gda_data_proxy_signals[VALIDATE_ROW_CHANGES], + 0, proxy_row, rm->model_row, &lerror); + if (lerror) { + g_propagate_error (error, lerror); + g_rec_mutex_unlock (& (priv->mutex)); + return FALSE; + } + + /* apply the changes */ + if (rm->to_be_deleted) { + /* delete the row */ + g_assert (rm->model_row >= 0); + if (!gda_data_model_remove_row (priv->model, rm->model_row, error)) + err = TRUE; + } + else { + if (rm->model_row >= 0) { + /* update the row */ + GList *values = NULL; + gint i; + + g_assert (rm->modify_values); + g_assert (rm->orig_values); + for (i=0; i < rm->orig_values_size; i++) { + gboolean newvalue_found = FALSE; + GValue *newvalue = NULL; + GSList *list; + + for (list = rm->modify_values; list; list = list->next) { + if (ROW_VALUE (list->data)->model_column == i) { + newvalue_found = TRUE; + if (ROW_VALUE (list->data)->attributes & + GDA_VALUE_ATTR_IS_DEFAULT) + newvalue = NULL; + else { + if (! ROW_VALUE (list->data)->value) + newvalue = gda_value_new_null (); + else + newvalue = gda_value_copy (ROW_VALUE (list->data)->value); + } + break; + } + } + if (!newvalue_found && rm->orig_values[i]) + newvalue = gda_value_copy (rm->orig_values[i]); + values = g_list_append (values, newvalue); + } + + err = ! gda_data_model_set_values (priv->model, rm->model_row, + values, error); + g_list_free_full (values, (GDestroyNotify) gda_value_free); + } + else { + /* insert a new row */ + GSList *list; + GList *values = NULL; + gint i; + GValue *newvalue; + GValue **free_val; + gint new_row; + + g_assert (rm->modify_values); + free_val = g_new0 (GValue *, priv->model_nb_cols); + for (i = 0; i < priv->model_nb_cols; i++) { + newvalue = NULL; + + list = rm->modify_values; + while (list && !newvalue) { + if (ROW_VALUE (list->data)->model_column == i) { + if (ROW_VALUE (list->data)->attributes & + GDA_VALUE_ATTR_IS_DEFAULT) + newvalue = NULL; + else { + if (! ROW_VALUE (list->data)->value) { + newvalue = gda_value_new_null (); + free_val [i] = newvalue; + } + else + newvalue = ROW_VALUE (list->data)->value; + + } + } + list = g_slist_next (list); + } + values = g_list_append (values, newvalue); + } + + priv->defer_proxied_model_insert = TRUE; + priv->catched_inserted_row = -1; + new_row = gda_data_model_append_values (priv->model, values, error); + err = new_row >= 0 ? FALSE : TRUE; + + g_list_free (values); + for (i = 0; i < priv->model_nb_cols; i++) + if (free_val [i]) + gda_value_free (free_val [i]); + g_free (free_val); + if (!err) { + if (priv->catched_inserted_row < 0) { + g_warning (_("Proxied data model reports the modifications as accepted, yet did not emit the " + "corresponding \"row-inserted\", \"row-updated\" or \"row-removed\" signal. This " + "is a bug of the %s's implementation (please report a bug)."), + G_OBJECT_TYPE_NAME (priv->model)); + } + + priv->new_rows = g_slist_remove (priv->new_rows, rm); + priv->all_modifs = g_slist_remove (priv->all_modifs, rm); + + gint tmp; + tmp = rm->model_row; + g_hash_table_remove (priv->modify_rows, &tmp); + row_modifs_free (rm); + rm = NULL; + + if (proxy_row >= 0) + gda_data_model_row_updated ((GdaDataModel*) proxy, proxy_row); + + /* signal row actually changed */ + g_signal_emit (G_OBJECT (proxy), + gda_data_proxy_signals[ROW_CHANGES_APPLIED], + 0, proxy_row, -1); + } + + priv->catched_inserted_row = -1; + priv->defer_proxied_model_insert = FALSE; + } + } + + if (!err && rm) { + /* signal row actually changed */ + g_signal_emit (G_OBJECT (proxy), + gda_data_proxy_signals[ROW_CHANGES_APPLIED], + 0, proxy_row, model_row); + + /* get rid of the committed change; if the changes have been applied correctly, @rm should + * have been removed from the priv->all_modifs list because the proxied model + * should habe emitted the "row_{inserted,removed,updated}" signals */ + if (rm && g_slist_find (priv->all_modifs, rm)) { + g_warning (_("Proxied data model reports the modifications as accepted, yet did not emit the " + "corresponding \"row-inserted\", \"row-updated\" or \"row-removed\" signal. This " + "may be a bug of the %s's implementation (please report a bug)."), + G_OBJECT_TYPE_NAME (priv->model)); + priv->new_rows = g_slist_remove (priv->new_rows, rm); + priv->all_modifs = g_slist_remove (priv->all_modifs, rm); + + gint tmp; + tmp = rm->model_row; + g_hash_table_remove (priv->modify_rows, &tmp); + row_modifs_free (rm); + } + } + + if (adjust_display) + adjust_displayed_chunk (proxy); + + g_rec_mutex_unlock (& (priv->mutex)); + + return !err; +} + +/** + * gda_data_proxy_has_changed: + * @proxy: a #GdaDataProxy object + * + * Tells if @proxy contains any modifications not applied to the proxied data model. + * + * Returns: TRUE if there are some modifications in @proxy + */ +gboolean +gda_data_proxy_has_changed (GdaDataProxy *proxy) +{ + g_return_val_if_fail (GDA_IS_DATA_PROXY (proxy), FALSE); + GdaDataProxyPrivate *priv = gda_data_proxy_get_instance_private (proxy); + + return priv->all_modifs ? TRUE : FALSE; +} + +/** + * gda_data_proxy_row_has_changed: + * @proxy: a #GdaDataProxy object + * @proxy_row: A proxy row number + * + * Tells if the row number @proxy_row has changed + * + * Returns: TRUE if the row has changed + */ +gboolean +gda_data_proxy_row_has_changed (GdaDataProxy *proxy, gint proxy_row) +{ + RowModif *rm; + + g_return_val_if_fail (GDA_IS_DATA_PROXY (proxy), FALSE); + g_return_val_if_fail (proxy_row >= 0, FALSE); + + rm = proxy_row_to_row_modif (proxy, proxy_row); + return rm && (rm->modify_values || rm->to_be_deleted) ? TRUE : FALSE; +} + +/** + * gda_data_proxy_get_n_new_rows: + * @proxy: a #GdaDataProxy object + * + * Get the number of rows which have been added to @proxy and which are not part of + * the proxied data model. + * + * Returns: the number of new rows + */ +gint +gda_data_proxy_get_n_new_rows (GdaDataProxy *proxy) +{ + g_return_val_if_fail (GDA_IS_DATA_PROXY (proxy), 0); + GdaDataProxyPrivate *priv = gda_data_proxy_get_instance_private (proxy); + + return g_slist_length (priv->new_rows); +} + +/** + * gda_data_proxy_get_n_modified_rows: + * @proxy: a #GdaDataProxy object + * + * Get the number of rows which have been modified in the proxy (the sum of rows existing in + * the proxied data model which have been modified, and new rows). + * + * Returns: the number of modified rows + */ +gint +gda_data_proxy_get_n_modified_rows (GdaDataProxy *proxy) +{ + g_return_val_if_fail (GDA_IS_DATA_PROXY (proxy), 0); + GdaDataProxyPrivate *priv = gda_data_proxy_get_instance_private (proxy); + + return g_slist_length (priv->all_modifs); +} + +/** + * gda_data_proxy_set_sample_size: + * @proxy: a #GdaDataProxy object + * @sample_size: the requested size of a chunk, or 0 + * + * Sets the size of each chunk of data to display: the maximum number of rows which + * can be "displayed" at a time (the maximum number of rows which @proxy pretends to have). + * The default value is arbitrary 300 as it is big enough to + * be able to display quite a lot of data, but small enough to avoid too much data + * displayed at the same time. + * + * Note: the rows which have been added but not yet committed will always be displayed + * regardless of the current chunk of data, and the modified rows which are not visible + * when the displayed chunk of data changes are still held as modified rows. + * + * To remove the chunking of the data to display, simply pass @sample_size the %0 value. + */ +void +gda_data_proxy_set_sample_size (GdaDataProxy *proxy, gint sample_size) +{ + gint new_sample_size; + g_return_if_fail (GDA_IS_DATA_PROXY (proxy)); + GdaDataProxyPrivate *priv = gda_data_proxy_get_instance_private (proxy); + + g_rec_mutex_lock (& (priv->mutex)); + + /* ensure that there is no sync to be done */ + ensure_chunk_sync (proxy); + + new_sample_size = sample_size <= 0 ? 0 : sample_size; + if (priv->sample_size != new_sample_size) { + priv->sample_size = new_sample_size; + adjust_displayed_chunk (proxy); + g_signal_emit (G_OBJECT (proxy), + gda_data_proxy_signals[SAMPLE_SIZE_CHANGED], + 0, sample_size); + } + + g_rec_mutex_unlock (& (priv->mutex)); +} + +/** + * gda_data_proxy_get_sample_size: + * @proxy: a #GdaDataProxy object + * + * Get the size of each chunk of data displayed at a time. + * + * Returns: the chunk (or sample) size, or 0 if chunking is disabled. + */ +gint +gda_data_proxy_get_sample_size (GdaDataProxy *proxy) +{ + g_return_val_if_fail (GDA_IS_DATA_PROXY (proxy), 0); + GdaDataProxyPrivate *priv = gda_data_proxy_get_instance_private (proxy); + + return priv->sample_size; +} + +/** + * gda_data_proxy_set_sample_start: + * @proxy: a #GdaDataProxy object + * @sample_start: the number of the first row to be displayed + * + * Sets the number of the first row to be available in @proxy (in reference to the proxied data model) + */ +void +gda_data_proxy_set_sample_start (GdaDataProxy *proxy, gint sample_start) +{ + g_return_if_fail (GDA_IS_DATA_PROXY (proxy)); + g_return_if_fail (sample_start >= 0); + GdaDataProxyPrivate *priv = gda_data_proxy_get_instance_private (proxy); + + g_rec_mutex_lock (& (priv->mutex)); + + /* ensure that there is no sync to be done */ + ensure_chunk_sync (proxy); + + if (priv->sample_first_row != sample_start) { + priv->sample_first_row = sample_start; + adjust_displayed_chunk (proxy); + } + + g_rec_mutex_unlock (& (priv->mutex)); +} + +/** + * gda_data_proxy_get_sample_start: + * @proxy: a #GdaDataProxy object + * + * Get the number of the first row to be available in @proxy (in reference to the proxied data model) + * + * Returns: the number of the first proxied model's row. + */ +gint +gda_data_proxy_get_sample_start (GdaDataProxy *proxy) +{ + g_return_val_if_fail (GDA_IS_DATA_PROXY (proxy), 0); + GdaDataProxyPrivate *priv = gda_data_proxy_get_instance_private (proxy); + + return priv->sample_first_row; +} + +/** + * gda_data_proxy_get_sample_end: + * @proxy: a #GdaDataProxy object + * + * Get the number of the last row to be available in @proxy (in reference to the proxied data model) + * + * Returns: the number of the last proxied model's row. + */ +gint +gda_data_proxy_get_sample_end (GdaDataProxy *proxy) +{ + g_return_val_if_fail (GDA_IS_DATA_PROXY (proxy), 0); + GdaDataProxyPrivate *priv = gda_data_proxy_get_instance_private (proxy); + + return priv->sample_last_row; +} + +static DisplayChunk * +display_chunk_new (gint reserved_size) +{ + DisplayChunk *chunk; + + chunk = g_new0 (DisplayChunk, 1); + chunk->mapping = g_array_sized_new (FALSE, TRUE, sizeof (gint), reserved_size); + + return chunk; +} + +static void +display_chunk_free (DisplayChunk *chunk) +{ + if (chunk->mapping) + g_array_free (chunk->mapping, TRUE); + g_free (chunk); +} + +#ifdef GDA_DEBUG +static void +display_chunks_dump (GdaDataProxy *proxy) +{ +#define DUMP +#undef DUMP +#ifdef DUMP + gint i, total1 = 0, total2 = 0; + GdaDataProxyPrivate *priv = gda_data_proxy_get_instance_private (proxy); + + g_print ("================== CHUNK=%p, TO=%p (mapping=%p), SEP=%d\n", priv->chunk, priv->chunk_to, + priv->chunk_to ? priv->chunk_to->mapping : NULL, + priv->chunk_sep); + if (!priv->chunk && !priv->chunk_to) + g_print ("No chunks at all\n"); + + if (priv->chunk) + total1 = priv->chunk->mapping->len; + if (priv->chunk_to && priv->chunk_to->mapping) + total2 = priv->chunk_to->mapping->len; + + g_print ("CHUNK CHUNK_TO\n"); + for (i = 0; i < MAX (total1, total2); i++) { + if (i < total1) + g_print ("%03d", g_array_index (priv->chunk->mapping, gint, i)); + else + g_print (" "); + g_print (" ==== "); + if (i < total2) + g_print ("%03d", g_array_index (priv->chunk_to->mapping, gint, i)); + else + g_print (" "); + g_print ("\n"); + } +#endif +} +#else +static void +display_chunks_dump (G_GNUC_UNUSED GdaDataProxy *proxy) +{} +#endif + +/* + * Makes sure the sync, if necessary, is finished + */ +static void +ensure_chunk_sync (GdaDataProxy *proxy) +{ + GdaDataProxyPrivate *priv = gda_data_proxy_get_instance_private (proxy); + g_rec_mutex_lock (& (priv->mutex)); + if (priv->chunk_sync_idle_id) { + gboolean defer_sync = priv->defer_sync; + priv->defer_sync = FALSE; + + chunk_sync_idle (proxy); + priv->defer_sync = defer_sync; + } + g_rec_mutex_unlock (& (priv->mutex)); +} + +/* + * Emit all the correct signals when switching from priv->chunk to + * priv->chunk_to + */ +static gboolean +chunk_sync_idle (GdaDataProxy *proxy) +{ + GdaDataProxyPrivate *priv = gda_data_proxy_get_instance_private (proxy); +#define IDLE_STEP 50 + if (! g_rec_mutex_trylock (& (priv->mutex))) + return TRUE; /* we have not finished yet */ + + gboolean finished = FALSE; + guint index, max_steps, step; + GdaDataModelIter *iter = NULL; + gint signal_row_offset = priv->add_null_entry ? 1 : 0; + + if (!priv->defer_sync) { + if (priv->chunk_sync_idle_id) { + g_idle_remove_by_data (proxy); + priv->chunk_sync_idle_id = 0; + } + max_steps = G_MAXINT; + } + + if (!priv->chunk_to) { + g_rec_mutex_unlock (& (priv->mutex)); + return FALSE; /* nothing to do */ + } + + max_steps = 0; + if (priv->chunk_proxy_nb_rows < 0) + priv->chunk_proxy_nb_rows = priv->model_nb_rows + g_slist_length (priv->new_rows); + if (priv->chunk_to->mapping) + max_steps = MAX (max_steps, priv->chunk_to->mapping->len - priv->chunk_sep + 1); + else + max_steps = MAX (max_steps, (guint)(priv->chunk_proxy_nb_rows - priv->chunk_sep + 1)); + if (priv->chunk) + max_steps = MAX (max_steps, priv->chunk->mapping->len - priv->chunk_sep + 1); + else + max_steps = MAX (max_steps, (guint)(priv->chunk_proxy_nb_rows - priv->chunk_sep + 1)); + + if (priv->defer_sync) + max_steps = MIN (max_steps, IDLE_STEP); + +#ifdef DEBUG_SYNC + g_print ("////////// %s(defer_sync = %d)\n", __FUNCTION__, priv->defer_sync); + display_chunks_dump (proxy); +#endif + + for (index = priv->chunk_sep, step = 0; + step < max_steps && !finished; + step++) { + gint cur_row, repl_row; + + if (priv->chunk) { + if (index < priv->chunk->mapping->len) + cur_row = g_array_index (priv->chunk->mapping, gint, index); + else + cur_row = -1; + } + else { + cur_row = index; + if (cur_row >= priv->chunk_proxy_nb_rows) + cur_row = -1; + } + + if (priv->chunk_to->mapping) { + if (index < priv->chunk_to->mapping->len) + repl_row = g_array_index (priv->chunk_to->mapping, gint, index); + else + repl_row = -1; + } + else { + repl_row = index; + if (!iter) + iter = gda_data_model_create_iter (priv->model); + if (!gda_data_model_iter_move_to_row (iter, repl_row)) { + if (gda_data_model_iter_get_row (iter) != repl_row) + repl_row = -1; + } + } + +#ifdef DEBUG_SYNC + g_print ("INDEX=%d step=%d max_steps=%d cur_row=%d repl_row=%d\n", index, step, max_steps, cur_row, repl_row); +#endif + if ((cur_row >= 0) && (repl_row >= 0)) { + /* emit the GdaDataModel::"row-updated" signal */ + if (priv->chunk) { + g_array_insert_val (priv->chunk->mapping, index, repl_row); + g_array_remove_index (priv->chunk->mapping, index + 1); + } + priv->chunk_sep++; + + if (cur_row != repl_row) + if (priv->notify_changes) { +#ifdef DEBUG_SYNC + g_print ("Signal: Update row %d\n", index + signal_row_offset); +#endif + gda_data_model_row_updated ((GdaDataModel *) proxy, index + signal_row_offset); + } + index++; + } + else if ((cur_row >= 0) && (repl_row < 0)) { + /* emit the GdaDataModel::"row-removed" signal */ + if (priv->chunk) + g_array_remove_index (priv->chunk->mapping, index); + priv->chunk_proxy_nb_rows--; + if (priv->notify_changes) { +#ifdef DEBUG_SYNC + g_print ("Signal: Remove row %d\n", index + signal_row_offset); +#endif + gda_data_model_row_removed ((GdaDataModel *) proxy, index + signal_row_offset); + } + } + else if ((cur_row < 0) && (repl_row >= 0)) { + /* emit GdaDataModel::"row-inserted" insert signal */ + if (priv->chunk) + g_array_insert_val (priv->chunk->mapping, index, repl_row); + priv->chunk_sep++; + if (priv->notify_changes) { +#ifdef DEBUG_SYNC + g_print ("Signal: Insert row %d\n", index + signal_row_offset); +#endif + gda_data_model_row_inserted ((GdaDataModel *) proxy, index + signal_row_offset); + } + index++; + } + else + finished = TRUE; + } + + if (iter) + g_object_unref (iter); + + if (finished) { + if (priv->chunk_sync_idle_id) { + g_idle_remove_by_data (proxy); + priv->chunk_sync_idle_id = 0; + } + + if (! priv->chunk_to->mapping) { + if (priv->chunk) { + display_chunk_free (priv->chunk); + priv->chunk = NULL; + } + display_chunk_free (priv->chunk_to); + priv->chunk_to = NULL; + } + else { + if (priv->chunk) + display_chunk_free (priv->chunk); + priv->chunk = priv->chunk_to; + priv->chunk_to = NULL; + } +#ifdef DEBUG_SYNC + g_print ("Sync. is now finished\n"); +#endif + } +#ifdef DEBUG_SYNC + else + g_print ("Sync. is NOT finished yet\n"); +#endif + g_rec_mutex_unlock (& (priv->mutex)); + return !finished; +} + +static DisplayChunk * +compute_display_chunk (GdaDataProxy *proxy) +{ + DisplayChunk *ret_chunk = NULL; + GdaDataProxyPrivate *priv = gda_data_proxy_get_instance_private (proxy); + + g_rec_mutex_lock (& (priv->mutex)); + if (priv->filtered_rows) { + /* REM: when there is a filter applied, the new rows are mixed with the + * existing ones => no need to treat them appart + */ + gint nb_rows = gda_data_model_get_n_rows (priv->filtered_rows); + gint i, new_nb_rows = 0; + + g_assert (nb_rows >= 0); /* the number of rows IS known here */ + if (priv->sample_size > 0) { + if (priv->sample_first_row >= nb_rows) + priv->sample_first_row = priv->sample_size * + ((nb_rows - 1) / priv->sample_size); + + priv->sample_last_row = priv->sample_first_row + + priv->sample_size - 1; + if (priv->sample_last_row >= nb_rows) + priv->sample_last_row = nb_rows - 1; + new_nb_rows = priv->sample_last_row - priv->sample_first_row + 1; + } + else { + priv->sample_first_row = 0; + priv->sample_last_row = nb_rows - 1; + new_nb_rows = nb_rows; + } + + ret_chunk = display_chunk_new (priv->sample_size > 0 ? + priv->sample_size : nb_rows); + for (i = 0; i < new_nb_rows; i++) { + const GValue *value; + gint val; + + g_assert (i + priv->sample_first_row < nb_rows); + value = gda_data_model_get_value_at (priv->filtered_rows, + 0, i + priv->sample_first_row, NULL); + g_assert (value); + g_assert (G_VALUE_TYPE (value) == G_TYPE_INT); + val = g_value_get_int (value); + g_array_append_val (ret_chunk->mapping, val); + } + } + else { + gint i, new_nb_rows = 0; + + if (priv->model_nb_rows >= 0) { + /* known number of rows */ + if (priv->sample_size > 0) { + if (priv->sample_first_row >= priv->model_nb_rows) + priv->sample_first_row = priv->sample_size * + ((priv->model_nb_rows - 1) / priv->sample_size); + + priv->sample_last_row = priv->sample_first_row + + priv->sample_size - 1; + if (priv->sample_last_row >= priv->model_nb_rows) + priv->sample_last_row = priv->model_nb_rows - 1; + new_nb_rows = priv->sample_last_row - priv->sample_first_row + 1; + ret_chunk = display_chunk_new (priv->sample_size); + } + else { + /* no chunk_to->mapping needed */ + ret_chunk = g_new0 (DisplayChunk, 1); + + priv->sample_first_row = 0; + priv->sample_last_row = priv->model_nb_rows - 1; + new_nb_rows = priv->model_nb_rows; + } + } + else { + /* no chunk_to->mapping needed */ + ret_chunk = g_new0 (DisplayChunk, 1); + + if (priv->model_nb_rows == 0 ) { + /* known number of rows */ + priv->sample_first_row = 0; + priv->sample_last_row = 0; + new_nb_rows = 0; + } + else { + /* unknown number of rows */ + if (priv->sample_size > 0) { + priv->sample_last_row = priv->sample_first_row + + priv->sample_size - 1; + new_nb_rows = priv->sample_last_row - priv->sample_first_row + 1; + } + else { + priv->sample_first_row = 0; + priv->sample_last_row = G_MAXINT - 1; + new_nb_rows = G_MAXINT; + } + } + } + /* fill @chunk_to is it exists */ + if (ret_chunk && ret_chunk->mapping) { + for (i = 0; i < new_nb_rows; i++) { + g_assert (i + priv->sample_first_row < priv->model_nb_rows); + gint val = model_row_to_absolute_row (proxy, i + priv->sample_first_row); + g_array_append_val (ret_chunk->mapping, val); + } + GSList *list; + for (i++, list = priv->new_rows; list; list = list->next, i++) { + gint val = row_modif_to_absolute_row (proxy, ROW_MODIF (list->data)); + g_array_append_val (ret_chunk->mapping, val); + } + } + } + + g_rec_mutex_unlock (& (priv->mutex)); + return ret_chunk; +} + +/* + * Adjusts the values of the first and last rows to be displayed depending + * on the sample size. + * + * Some rows may be added or removed during the adjustment. + */ +static void +adjust_displayed_chunk (GdaDataProxy *proxy) +{ + GdaDataProxyPrivate *priv = gda_data_proxy_get_instance_private (proxy); + g_return_if_fail (priv->model); + + g_rec_mutex_lock (& (priv->mutex)); + + /* + * Stop idle adding of rows if necessary + */ + if (priv->chunk_sync_idle_id) { + g_idle_remove_by_data (proxy); + priv->chunk_sync_idle_id = 0; + } + + /* compute new DisplayChunk */ + if (priv->chunk_to) { + display_chunk_free (priv->chunk_to); + priv->chunk_to = NULL; + } + priv->chunk_to = compute_display_chunk (proxy); + if (!priv->chunk_to) { + g_rec_mutex_unlock (& (priv->mutex)); + return; /* nothing to do */ + } + + /* determine if chunking has changed */ + gboolean equal = FALSE; + if (priv->chunk && priv->chunk_to->mapping) { + /* compare the 2 chunks */ + if (priv->chunk->mapping->len == priv->chunk_to->mapping->len) { + gsize i; + equal = TRUE; + for (i = 0; i < priv->chunk->mapping->len; i++) { + if (g_array_index (priv->chunk->mapping, gint, i) != + g_array_index (priv->chunk_to->mapping, gint, i)) { + equal = FALSE; + break; + } + } + } + } + else if (!priv->chunk && !priv->chunk_to->mapping) + equal = TRUE; + + /* handle new display chunk (which may be NULL) */ + if (! equal) { +#ifdef DEBUG_SYNC + g_print ("////////// %s(%d)\n", __FUNCTION__, __LINE__); +#endif + display_chunks_dump (proxy); + /* signal sample changed if necessary */ + g_signal_emit (G_OBJECT (proxy), + gda_data_proxy_signals[SAMPLE_CHANGED], + 0, priv->sample_first_row, priv->sample_last_row); + + /* sync priv->chunk to priv->chunk_to */ + priv->chunk_sep = 0; + priv->chunk_proxy_nb_rows = -1; + if (!priv->defer_sync) + chunk_sync_idle (proxy); + else + priv->chunk_sync_idle_id = g_idle_add ((GSourceFunc) chunk_sync_idle, proxy); + } + else { + /* nothing to adjust => destroy priv->chunk_to if necessary */ + if (priv->chunk_to) { + display_chunk_free (priv->chunk_to); + priv->chunk_to = NULL; + } + } + + g_rec_mutex_unlock (& (priv->mutex)); +} + +/** + * gda_data_proxy_apply_all_changes: + * @proxy: a #GdaDataProxy object + * @error: a place to store errors, or %NULL + * + * Apply all the changes stored in the proxy to the proxied data model. The changes are done row + * after row, and if an error + * occurs, then it is possible that not all the changes to all the rows have been applied. + * + * Returns: TRUE if no error occurred + */ +gboolean +gda_data_proxy_apply_all_changes (GdaDataProxy *proxy, GError **error) +{ + gboolean allok = TRUE; + + g_return_val_if_fail (GDA_IS_DATA_PROXY (proxy), FALSE); + GdaDataProxyPrivate *priv = gda_data_proxy_get_instance_private (proxy); + + g_rec_mutex_lock (& (priv->mutex)); + + /* ensure that there is no sync to be done */ + ensure_chunk_sync (proxy); + + gda_data_model_send_hint (priv->model, GDA_DATA_MODEL_HINT_START_BATCH_UPDATE, NULL); + + while (priv->all_modifs && allok) + allok = commit_row_modif (proxy, ROW_MODIF (priv->all_modifs->data), FALSE, error); + + gda_data_model_send_hint (priv->model, GDA_DATA_MODEL_HINT_END_BATCH_UPDATE, NULL); + adjust_displayed_chunk (proxy); + + g_rec_mutex_unlock (& (priv->mutex)); + + return allok; +} + +/** + * gda_data_proxy_cancel_all_changes: + * @proxy: a #GdaDataProxy object + * + * Cancel all the changes stored in the proxy (the @proxy will be reset to its state + * as it was just after creation). Note that if there are some cached changes (i.e. not applied + * to the current proxied data model), then these cached changes are not cleared (set the "cache-changes" + * property to %FALSE for this). + * + * Returns: TRUE if no error occurred + */ +gboolean +gda_data_proxy_cancel_all_changes (GdaDataProxy *proxy) +{ + g_return_val_if_fail (GDA_IS_DATA_PROXY (proxy), FALSE); + GdaDataProxyPrivate *priv = gda_data_proxy_get_instance_private (proxy); + + g_rec_mutex_lock (& (priv->mutex)); + + /* ensure that there is no sync to be done */ + ensure_chunk_sync (proxy); + g_assert (!priv->chunk_to); + + /* new rows are first treated and removed (no memory de-allocation here, though) */ + if (priv->new_rows) { + if (priv->chunk) { + /* Using a chunk */ + priv->chunk_to = display_chunk_new (priv->chunk->mapping->len); + g_array_append_vals (priv->chunk_to->mapping, + priv->chunk->mapping->data, priv->chunk->mapping->len); + + while (priv->new_rows) { + gint proxy_row; + + proxy_row = row_modif_to_proxy_row (proxy, (ROW_MODIF (priv->new_rows->data))); + priv->new_rows = g_slist_delete_link (priv->new_rows, priv->new_rows); + + if ((proxy_row >= 0) && priv->chunk_to) + g_array_remove_index (priv->chunk_to->mapping, + proxy_row - (priv->add_null_entry ? 1 : 0)); + } + + if (priv->chunk_to) { + /* sync priv->chunk to priv->chunk_to */ + gboolean defer_sync = priv->defer_sync; + priv->defer_sync = FALSE; + priv->chunk_sep = 0; + priv->chunk_proxy_nb_rows = -1; + chunk_sync_idle (proxy); + priv->defer_sync = defer_sync; + } + } + else { + /* no chunk used */ + gint nrows = gda_data_proxy_get_n_rows ((GdaDataModel *) proxy); + while (priv->new_rows) { + priv->new_rows = g_slist_delete_link (priv->new_rows, priv->new_rows); + if (priv->notify_changes) { + gda_data_model_row_removed ((GdaDataModel *) proxy, nrows-1); + nrows--; + } + } + } + } + + /* all modified rows are then treated (including memory de-allocation for new rows) */ + while (priv->all_modifs) { + gint model_row = ROW_MODIF (priv->all_modifs->data)->model_row; + gint proxy_row = -1; + + if (priv->notify_changes && (model_row >= 0)) + proxy_row = row_modif_to_proxy_row (proxy, (ROW_MODIF (priv->all_modifs->data))); + + row_modifs_free (ROW_MODIF (priv->all_modifs->data)); + if (model_row >= 0) { + gint tmp; + tmp = model_row; + g_hash_table_remove (priv->modify_rows, &tmp); + } + priv->all_modifs = g_slist_delete_link (priv->all_modifs, priv->all_modifs); + + if ((proxy_row >= 0) && priv->notify_changes) + gda_data_model_row_updated ((GdaDataModel *) proxy, proxy_row); + } + + g_rec_mutex_unlock (& (priv->mutex)); + + return TRUE; +} + +static gboolean +sql_where_foreach (GdaSqlAnyPart *part, GdaDataProxy *proxy, G_GNUC_UNUSED GError **error) +{ + GdaDataProxyPrivate *priv = gda_data_proxy_get_instance_private (proxy); + if (part->type == GDA_SQL_ANY_EXPR) { + GdaSqlExpr *expr = (GdaSqlExpr*) part; + if (expr->value && (G_VALUE_TYPE (expr->value) == G_TYPE_STRING)) { + const gchar *cstr = g_value_get_string (expr->value); + if (*cstr == '_') { + const gchar *ptr; + for (ptr = cstr+1; *ptr; ptr++) + if ((*ptr < '0') || (*ptr > '9')) + break; + if (!*ptr) { + /* column name is "_", use column: - 1 */ + gint colnum; + colnum = atoi (cstr+1) - 1; /* Flawfinder: ignore */ + if ((colnum >= 0) && + (colnum < gda_data_model_get_n_columns ((GdaDataModel*) proxy))) { + GdaColumn *col = gda_data_model_describe_column ((GdaDataModel*) proxy, + colnum); + const gchar *cname = gda_column_get_name (col); + if (cname && *cname) { + g_value_take_string (expr->value, + gda_sql_identifier_quote (cname, + priv->filter_vcnc, + NULL, + FALSE, FALSE)); + } + } + } + } + } + } + return TRUE; +} + +/* + * Applies priv->filter_stmt + * + * Make sure priv->mutex is locked + */ +static gboolean +apply_filter_statement (GdaDataProxy *proxy, GError **error) +{ + GdaConnection *vcnc; + GdaDataModel *filtered_rows = NULL; + GdaStatement *stmt = NULL; + GdaDataProxyPrivate *priv = gda_data_proxy_get_instance_private (proxy); + + if (priv->filter_stmt) { + stmt = priv->filter_stmt; + priv->filter_stmt = NULL; + } + + /* ensure that there is no sync to be done */ + ensure_chunk_sync (proxy); + + if (!stmt) + goto clean_previous_filter; + + g_mutex_lock (&provider_mutex); + if (!virtual_provider) + virtual_provider = gda_vprovider_data_model_new (); + g_mutex_unlock (&provider_mutex); + + /* Force direct data access where proxy_row <=> absolute_row */ + priv->force_direct_mapping = TRUE; + + vcnc = priv->filter_vcnc; + if (!vcnc) { + GError *lerror = NULL; + vcnc = gda_virtual_connection_open (virtual_provider, GDA_CONNECTION_OPTIONS_NONE, &lerror); + if (! vcnc) { + g_print ("Virtual ERROR: %s\n", lerror && lerror->message ? lerror->message : "No detail"); + if (lerror) + g_error_free (lerror); + g_set_error (error, GDA_DATA_PROXY_ERROR, GDA_DATA_PROXY_FILTER_ERROR, + "%s", _("Could not create virtual connection")); + priv->force_direct_mapping = FALSE; + goto clean_previous_filter; + } + GMainContext *ctx; + ctx = gda_connection_get_main_context (NULL, NULL); + if (ctx) + gda_connection_set_main_context (vcnc, NULL, ctx); + priv->filter_vcnc = vcnc; + } + + /* Add the @proxy to the virtual connection. + * + * REM: use a GdaDataModelWrapper to force the viewing of the un-modified columns of @proxy, + * otherwise the GdaVconnectionDataModel will just take into account the modified columns + */ + GdaDataModel *wrapper; + wrapper = gda_data_access_wrapper_new ((GdaDataModel*) proxy); + if (!gda_vconnection_data_model_add_model (GDA_VCONNECTION_DATA_MODEL (vcnc), wrapper, + "proxy", error)) { + g_object_unref (wrapper); + priv->force_direct_mapping = FALSE; + goto clean_previous_filter; + } + g_object_unref (wrapper); + + /* remork the statement for column names */ + GdaSqlStatement *sqlst; + g_object_get (G_OBJECT (stmt), "structure", &sqlst, NULL); + g_assert (sqlst->stmt_type == GDA_SQL_STATEMENT_SELECT); + gda_sql_any_part_foreach (GDA_SQL_ANY_PART (sqlst->contents), (GdaSqlForeachFunc) sql_where_foreach, proxy, NULL); + g_object_set (G_OBJECT (stmt), "structure", sqlst, NULL); +#ifdef GDA_DEBUG_NO + gchar *ser; + ser = gda_sql_statement_serialize (sqlst); + g_print ("Modified Filter: %s\n", ser); + g_free (ser); +#endif + gda_sql_statement_free (sqlst); + + /* execute statement */ + GError *lerror = NULL; + g_rec_mutex_unlock (& (priv->mutex)); + filtered_rows = gda_connection_statement_execute_select (vcnc, stmt, NULL, &lerror); + if (!filtered_rows) { + g_set_error (error, GDA_DATA_PROXY_ERROR, GDA_DATA_PROXY_FILTER_ERROR, + _("Error in filter expression: %s"), lerror && lerror->message ? lerror->message : _("No detail")); + g_clear_error (&lerror); + priv->force_direct_mapping = FALSE; + gda_vconnection_data_model_remove (GDA_VCONNECTION_DATA_MODEL (vcnc), "proxy", NULL); + g_rec_mutex_lock (& (priv->mutex)); + goto clean_previous_filter; + } + + /* copy filtered_rows and remove virtual table */ + GdaDataModel *copy; + copy = (GdaDataModel*) gda_data_model_array_copy_model (filtered_rows, NULL); + gda_vconnection_data_model_remove (GDA_VCONNECTION_DATA_MODEL (vcnc), "proxy", NULL); + g_object_unref (filtered_rows); + if (!copy) { + g_set_error (error, GDA_DATA_PROXY_ERROR, GDA_DATA_PROXY_FILTER_ERROR, + "%s", _("Error in filter expression")); + priv->force_direct_mapping = FALSE; + filtered_rows = NULL; + g_rec_mutex_lock (& (priv->mutex)); + goto clean_previous_filter; + } + filtered_rows = copy; + priv->force_direct_mapping = FALSE; + g_rec_mutex_lock (& (priv->mutex)); + + clean_previous_filter: /* NEED TO BE LOCKED HERE */ + if (priv->filter_expr) { + g_free (priv->filter_expr); + priv->filter_expr = NULL; + } + if (priv->filtered_rows) { + g_object_unref (priv->filtered_rows); + priv->filtered_rows = NULL; + } +#define FILTER_SELECT_WHERE "SELECT __gda_row_nb FROM proxy WHERE " +#define FILTER_SELECT_NOWHERE "SELECT __gda_row_nb FROM proxy " + if (filtered_rows) { + gchar *sql; + sql = gda_statement_to_sql (stmt, NULL, NULL); + if (sql) { + if (!g_ascii_strncasecmp (sql, FILTER_SELECT_WHERE, strlen (FILTER_SELECT_WHERE))) + priv->filter_expr = g_strdup (sql + strlen (FILTER_SELECT_WHERE)); + else if (!g_ascii_strncasecmp (sql, FILTER_SELECT_NOWHERE, strlen (FILTER_SELECT_NOWHERE))) + priv->filter_expr = g_strdup (sql + strlen (FILTER_SELECT_NOWHERE)); + g_free (sql); + } + priv->filtered_rows = filtered_rows; + priv->filter_stmt = stmt; + } + else if (stmt) + g_object_unref (stmt); + + g_signal_emit (G_OBJECT (proxy), + gda_data_proxy_signals[FILTER_CHANGED], + 0); + gda_data_model_reset (GDA_DATA_MODEL (proxy)); + + adjust_displayed_chunk (proxy); + g_rec_mutex_unlock (& (priv->mutex)); + + if (!stmt) + return TRUE; + else + return filtered_rows ? TRUE : FALSE; +} + +/** + * gda_data_proxy_set_filter_expr: + * @proxy: a #GdaDataProxy object + * @filter_expr: (nullable): an SQL based expression which will filter the contents of @proxy, or %NULL to remove any previous filter + * @error: a place to store errors, or %NULL + * + * Sets a filter among the rows presented by @proxy. The filter is defined by a filter expression + * which can be any SQL valid expression using @proxy's columns. For instance if @proxy has the "id" and + * "name" columns, then a filter can be "length(name) < 5" to filter only the rows where the length of the + * name is strictly inferior to 5, or "id >= 1000 and id < 2000 order by name limit 50" to filter only the rows where the id + * is between 1000 and 2000, ordered by name and limited to 50 rows. + * + * Note about column names: real column names can be used (double quoted if necessary), but columns can also be named + * "_<column number>" with column numbers starting at 1. + * + * Note that any previous filter expression is replaced with the new @filter_expr if no error occurs + * (if an error occurs, then any previous filter is left unchanged). + * + * Returns: TRUE if no error occurred + */ +gboolean +gda_data_proxy_set_filter_expr (GdaDataProxy *proxy, const gchar *filter_expr, GError **error) +{ + gchar *sql; + GdaStatement *stmt = NULL; + + g_return_val_if_fail (GDA_IS_DATA_PROXY (proxy), FALSE); + GdaDataProxyPrivate *priv = gda_data_proxy_get_instance_private (proxy); + + g_rec_mutex_lock (& (priv->mutex)); + + if (!filter_expr) { + if (priv->filter_stmt) + g_object_unref (priv->filter_stmt); + priv->filter_stmt = NULL; + + gboolean retval = apply_filter_statement (proxy, error); + return retval; + } + + /* generate SQL with a special case if expression starts with "ORDER BY" */ + gchar *tmp; + const gchar *ptr; + gint i; + tmp = g_strdup (filter_expr); + for (i = 0, ptr = filter_expr; *ptr && (i < 7); ptr++) { + if ((*ptr == ' ') || (*ptr == '\t') || (*ptr == '\n')) { + } + else { + tmp [i] = *ptr; + i++; + } + } + if (! g_ascii_strncasecmp (tmp, "orderby", 7)) + sql = g_strdup_printf (FILTER_SELECT_NOWHERE "%s", filter_expr); + else + sql = g_strdup_printf (FILTER_SELECT_WHERE "%s", filter_expr); + g_free (tmp); + + g_mutex_lock (&parser_mutex); + stmt = gda_sql_parser_parse_string (internal_parser, sql, &ptr, NULL); + g_mutex_unlock (&parser_mutex); + g_free (sql); + if (ptr || !stmt || (gda_statement_get_statement_type (stmt) != GDA_SQL_STATEMENT_SELECT)) { + /* also catches problems with multiple statements in @filter_expr, such as SQL code injection */ + g_set_error (error, GDA_DATA_PROXY_ERROR, GDA_DATA_PROXY_FILTER_ERROR, + "%s", _("Incorrect filter expression")); + if (stmt) + g_object_unref (stmt); + priv->force_direct_mapping = FALSE; + + g_rec_mutex_unlock (& (priv->mutex)); + return FALSE; + } + + if (priv->filter_stmt) + g_object_unref (priv->filter_stmt); + priv->filter_stmt = stmt; + + gboolean retval = apply_filter_statement (proxy, error); + return retval; +} + +/** + * gda_data_proxy_set_ordering_column: + * @proxy: a #GdaDataProxy object + * @col: the column number to order from + * @error: a place to store errors, or %NULL + * + * Orders by the @col column + * + * Returns: TRUE if no error occurred + */ +gboolean +gda_data_proxy_set_ordering_column (GdaDataProxy *proxy, gint col, GError **error) +{ + gboolean retval; + g_return_val_if_fail (GDA_IS_DATA_PROXY (proxy), FALSE); + g_return_val_if_fail (col >= 0, FALSE); + g_return_val_if_fail (col < gda_data_model_get_n_columns ((GdaDataModel*) proxy), FALSE); + GdaDataProxyPrivate *priv = gda_data_proxy_get_instance_private (proxy); + + g_rec_mutex_lock (& (priv->mutex)); + + if (priv->filter_stmt) { + GdaSqlStatement *sqlst; + GdaSqlStatementSelect *selst; + gboolean replaced = FALSE; + const gchar *cname; + gchar *colname; + + cname = gda_column_get_name (gda_data_model_describe_column ((GdaDataModel*) proxy, col)); + if (cname && *cname) + colname = gda_sql_identifier_quote (cname, priv->filter_vcnc, NULL, FALSE, FALSE); + else + colname = g_strdup_printf ("_%d", col + 1); + + g_object_get (G_OBJECT (priv->filter_stmt), "structure", &sqlst, NULL); + g_assert (sqlst->stmt_type == GDA_SQL_STATEMENT_SELECT); + g_free (sqlst->sql); + sqlst->sql = NULL; + selst = (GdaSqlStatementSelect*) sqlst->contents; + + /* test if we can actually toggle the sort ASC <-> DESC */ + if (selst->order_by && !selst->order_by->next) { + GdaSqlSelectOrder *order_by = (GdaSqlSelectOrder*) selst->order_by->data; + if (order_by->expr && order_by->expr->value && + (G_VALUE_TYPE (order_by->expr->value) == G_TYPE_STRING) && + gda_identifier_equal (g_value_get_string (order_by->expr->value), colname)) { + order_by->asc = !order_by->asc; + replaced = TRUE; + g_free (colname); + } + } + + if (!replaced) { + /* replace the whole ordering part */ + if (selst->order_by) { + g_slist_free_full (selst->order_by, (GDestroyNotify) gda_sql_select_order_free); + selst->order_by = NULL; + } + + GdaSqlSelectOrder *order_by; + GdaSqlExpr *expr; + order_by = gda_sql_select_order_new (GDA_SQL_ANY_PART (selst)); + selst->order_by = g_slist_prepend (NULL, order_by); + expr = gda_sql_expr_new (GDA_SQL_ANY_PART (order_by)); + order_by->expr = expr; + order_by->asc = TRUE; + expr->value = gda_value_new (G_TYPE_STRING); + g_value_take_string (expr->value, colname); + } + + g_object_set (G_OBJECT (priv->filter_stmt), "structure", sqlst, NULL); +#ifdef GDA_DEBUG_NO + gchar *ser; + ser = gda_sql_statement_serialize (sqlst); + g_print ("Modified Filter: %s\n", ser); + g_free (ser); +#endif + gda_sql_statement_free (sqlst); + retval = apply_filter_statement (proxy, error); + } + else { + gchar *str; + str = g_strdup_printf ("ORDER BY _%d", col + 1); + g_rec_mutex_unlock (& (priv->mutex)); + retval = gda_data_proxy_set_filter_expr (proxy, str, error); + g_free (str); + } + + return retval; +} + +/** + * gda_data_proxy_get_filter_expr: + * @proxy: a #GdaDataProxy object + * + * Get the current filter expression used by @proxy. + * + * Returns: the current filter expression or %NULL if no filter has been set + */ +const gchar * +gda_data_proxy_get_filter_expr (GdaDataProxy *proxy) +{ + g_return_val_if_fail (GDA_IS_DATA_PROXY (proxy), NULL); + GdaDataProxyPrivate *priv = gda_data_proxy_get_instance_private (proxy); + + return priv->filter_expr; +} + +/** + * gda_data_proxy_get_filtered_n_rows: + * @proxy: a #GdaDataProxy object + * + * Get the total number of filtered rows in @proxy if a filter has been applied. As new rows + * (rows added to the proxy and not yet added to the proxied data model) and rows to remove + * (rows marked for removal but not yet removed from the proxied data model) are also filtered, + * the returned number also contains references to new rows and rows to be removed. + * + * Returns: the number of filtered rows in @proxy, or -1 if no filter has been applied + */ +gint +gda_data_proxy_get_filtered_n_rows (GdaDataProxy *proxy) +{ + g_return_val_if_fail (GDA_IS_DATA_PROXY (proxy), -1); + GdaDataProxyPrivate *priv = gda_data_proxy_get_instance_private (proxy); + + g_rec_mutex_lock (& (priv->mutex)); + if (! priv->filtered_rows) { + g_rec_mutex_unlock (& (priv->mutex)); + return -1; + } + else { + gint n = gda_data_model_get_n_rows (priv->filtered_rows); + g_rec_mutex_unlock (& (priv->mutex)); + return n; + } +} + +/* + * GdaDataModel interface implementation + */ +static gint +gda_data_proxy_get_n_rows (GdaDataModel *model) +{ + gint nbrows; + GdaDataProxy *proxy; + g_return_val_if_fail (GDA_IS_DATA_PROXY (model), -1); + proxy = GDA_DATA_PROXY (model); + GdaDataProxyPrivate *priv = gda_data_proxy_get_instance_private (proxy); + g_return_val_if_fail (priv, -1); + + g_rec_mutex_lock (& (priv->mutex)); + + if (priv->chunk && !priv->force_direct_mapping) + nbrows = priv->chunk->mapping->len; + else { + if (priv->model_nb_rows >= 0) { + if (priv->chunk_to && priv->chunk_to->mapping) { + nbrows = priv->chunk_proxy_nb_rows; + } + else + nbrows = priv->model_nb_rows + + g_slist_length (priv->new_rows); + } + else + return -1; /* unknown number of rows */ + } + if (!priv->force_direct_mapping && priv->add_null_entry) + nbrows += 1; + + g_rec_mutex_unlock (& (priv->mutex)); + + return nbrows; +} + +static gint +gda_data_proxy_get_n_columns (GdaDataModel *model) +{ + GdaDataProxy *proxy; + g_return_val_if_fail (GDA_IS_DATA_PROXY (model), -1); + proxy = GDA_DATA_PROXY (model); + GdaDataProxyPrivate *priv = gda_data_proxy_get_instance_private (proxy); + + return 2 * priv->model_nb_cols; +} + + +typedef struct { + gchar *name; + GType type; +} ExtraColAttrs; + +static void create_columns (GdaDataProxy *proxy) +{ + gint i; + GdaDataProxyPrivate *priv = gda_data_proxy_get_instance_private (proxy); + if (priv->columns) + return; + + priv->columns = g_new0 (GdaColumn *, 2 * priv->model_nb_cols); + + /* current proxy's values */ + for (i = 0; i < priv->model_nb_cols; i++) { + GdaColumn *orig; + + orig = gda_data_model_describe_column (priv->model, i); + priv->columns[i] = gda_column_copy (orig); + gda_column_set_position (priv->columns[i], i); + } + + /* proxied data model's values (original values), again reference columns from proxied data model */ + for (; i < 2 * priv->model_nb_cols; i++) { + GdaColumn *orig; + const gchar *cname; + gchar *newname, *id; + gint k; + + orig = gda_data_model_describe_column (priv->model, + i - priv->model_nb_cols); + priv->columns[i] = gda_column_copy (orig); + g_object_get ((GObject*) priv->columns[i], "id", &id, NULL); + if (id) { + gchar *newid; + newid = g_strdup_printf ("pre%s", id); + g_object_set ((GObject*) priv->columns[i], "id", newid, NULL); + + /* make sure there is no duplicate ID */ + for (k = 0; ; k++) { + gint j; + for (j = 0; j < i; j++) { + gchar *id2; + g_object_get ((GObject*) priv->columns[j], "id", &id2, NULL); + if (id2 && *id2 && !strcmp (id2, newid)) { + g_free (id2); + break; + } + } + if (j == i) + break; + + g_free (newid); + newid = g_strdup_printf ("pre%s_%d", id, k); + g_object_set ((GObject*) priv->columns[i], "id", newid, NULL); + } + g_free (newid); + g_free (id); + } + + cname = gda_column_get_name (orig); + if (cname && *cname) + newname = g_strdup_printf ("pre%s", cname); + else + newname = g_strdup_printf ("pre%d", i); + + /* make sure there is no duplicate name */ + for (k = 0; ; k++) { + gint j; + for (j = 0; j < i; j++) { + const gchar *cname2; + cname2 = gda_column_get_name (priv->columns[j]); + if (cname2 && *cname2 && !strcmp (cname2, newname)) + break; + } + if (j == i) + break; + g_free (newname); + if (cname && *cname) + newname = g_strdup_printf ("pre%s_%d", cname, k); + else + newname = g_strdup_printf ("pre%d_%d", i, k); + } + gda_column_set_name (priv->columns[i], newname); + gda_column_set_description (priv->columns[i], newname); + g_free (newname); + gda_column_set_position (priv->columns[i], i); + } +} + +static GdaColumn * +gda_data_proxy_describe_column (GdaDataModel *model, gint col) +{ + GdaDataProxy *proxy; + g_return_val_if_fail (GDA_IS_DATA_PROXY (model), NULL); + proxy = GDA_DATA_PROXY (model); + GdaDataProxyPrivate *priv = gda_data_proxy_get_instance_private (proxy); + + g_rec_mutex_lock (& (priv->mutex)); + if (!priv->columns) + create_columns (proxy); + g_rec_mutex_unlock (& (priv->mutex)); + if ((col < 0) || (col >= 2 * priv->model_nb_cols)) { + g_warning (_("Column %d out of range (0-%d)"), col, + gda_data_model_get_n_columns (model) - 1); + return NULL; + } + else + return priv->columns [col]; +} + +static const GValue * +gda_data_proxy_get_value_at (GdaDataModel *model, gint column, gint proxy_row, GError **error) +{ + gint model_row; + GValue *retval = NULL; + GdaDataProxy *proxy; + static GValue *null_value = NULL; + + g_return_val_if_fail (GDA_IS_DATA_PROXY (model), NULL); + proxy = GDA_DATA_PROXY (model); + g_return_val_if_fail (proxy_row >= 0, NULL); + GdaDataProxyPrivate *priv = gda_data_proxy_get_instance_private (proxy); + + g_rec_mutex_lock (& (priv->mutex)); + + if ((proxy_row == 0) && priv->add_null_entry) { + if (!null_value) + null_value = gda_value_new_null (); + g_rec_mutex_unlock (& (priv->mutex)); + return null_value; + } + + model_row = proxy_row_to_model_row (proxy, proxy_row); + + /* current proxy's values (values may be different than the ones in the proxied data model) */ + if (column < priv->model_nb_cols) { + RowModif *rm; + gint model_col = column % priv->model_nb_cols; + gboolean value_has_modifs = FALSE; + + rm = proxy_row_to_row_modif (proxy, proxy_row); + if (rm && rm->modify_values) { + /* there are some modifications to the row, see if there are some for the column */ + GSList *list; + RowValue *rv = NULL; + + list = rm->modify_values; + while (list && !rv) { + if (ROW_VALUE (list->data)->model_column == model_col) + rv = ROW_VALUE (list->data); + list = g_slist_next (list); + } + if (rv) { + value_has_modifs = TRUE; + retval = rv->value; + if (!retval) { + if (!null_value) + null_value = gda_value_new_null (); + retval = null_value; + } + } + } + + if (!value_has_modifs) { + /* value has not been modified */ + if (model_row >= 0) { + /* existing row */ + retval = (GValue *) gda_data_model_get_value_at (priv->model, column, model_row, error); + } + else { + /* non existing row, return NULL */ + gint n; + n = gda_data_model_get_n_rows (model); + if (n > 0) + g_set_error (error, GDA_DATA_MODEL_ERROR, GDA_DATA_MODEL_ROW_OUT_OF_RANGE_ERROR, + _("Row %d out of range (0-%d)"), proxy_row, n - 1); + else + g_set_error (error, GDA_DATA_MODEL_ERROR, GDA_DATA_MODEL_ROW_OUT_OF_RANGE_ERROR, + _("Row %d not found (empty data model)"), proxy_row); + retval = NULL; + } + } + + g_rec_mutex_unlock (& (priv->mutex)); + return retval; + } + + /* proxied data model's values (original values) */ + if (column < 2 *priv->model_nb_cols) { + RowModif *rm; + gint model_col = column % priv->model_nb_cols; + + rm = proxy_row_to_row_modif (proxy, proxy_row); + if (rm) { + if (rm->orig_values) + retval = rm->orig_values [model_col]; + else { + if (!null_value) + null_value = gda_value_new_null (); + retval = null_value; + } + } + else { + if (model_row >= 0) { + /* existing row */ + retval = (GValue *) gda_data_model_get_value_at (priv->model, model_col, model_row, error); + } + else { + /* non existing row, return NULL */ + gint n; + n = gda_data_model_get_n_rows (model); + if (n > 0) + g_set_error (error, GDA_DATA_MODEL_ERROR, GDA_DATA_MODEL_ROW_OUT_OF_RANGE_ERROR, + _("Row %d out of range (0-%d)"), proxy_row, n - 1); + else + g_set_error (error, GDA_DATA_MODEL_ERROR, GDA_DATA_MODEL_ROW_OUT_OF_RANGE_ERROR, + _("Row %d not found (empty data model)"), proxy_row); + retval = NULL; + } + } + + g_rec_mutex_unlock (& (priv->mutex)); + return retval; + } + + g_set_error (error, GDA_DATA_MODEL_ERROR, GDA_DATA_MODEL_COLUMN_OUT_OF_RANGE_ERROR, + _("Column %d out of range (0-%d)"), column, 2 *priv->model_nb_cols - 1); + + g_rec_mutex_unlock (& (priv->mutex)); + return NULL; +} + +static GdaValueAttribute +gda_data_proxy_get_attributes_at (GdaDataModel *model, gint col, gint row) +{ + GdaValueAttribute attrs; + GdaDataProxy *proxy; + + g_return_val_if_fail (GDA_IS_DATA_PROXY (model), FALSE); + proxy = (GdaDataProxy*) model; + GdaDataProxyPrivate *priv = gda_data_proxy_get_instance_private (proxy); + + g_rec_mutex_lock (& (priv->mutex)); + attrs = gda_data_proxy_get_value_attributes ((GdaDataProxy *) model, row, col); + g_rec_mutex_unlock (& (priv->mutex)); + return attrs; +} + +static gint +gda_data_proxy_find_row_from_values (GdaDataModel *model, GSList *values, gint *cols_index) +{ + gboolean found = FALSE; + gint proxy_row; + gint current_nb_rows; + GdaDataProxy *proxy; + + proxy = (GdaDataProxy*) model; + g_return_val_if_fail (GDA_IS_DATA_PROXY (proxy), FALSE); + g_return_val_if_fail (values, FALSE); + GdaDataProxyPrivate *priv = gda_data_proxy_get_instance_private (proxy); + + g_rec_mutex_lock (& (priv->mutex)); + + /* ensure that there is no sync to be done */ + ensure_chunk_sync (proxy); + + /* FIXME: use a virtual connection here with some SQL, it'll be much easier and will avoid + * much code + */ + /*TO_IMPLEMENT;*/ + + /* if there are still some rows waiting to be added in the idle loop, then force them to be added + * first, otherwise we might not find what we are looking for! + */ + if (priv->chunk_sync_idle_id) { + g_idle_remove_by_data (proxy); + priv->chunk_sync_idle_id = 0; + while (chunk_sync_idle (proxy)) ; + } + + current_nb_rows = gda_data_proxy_get_n_rows ((GdaDataModel*) proxy); + for (proxy_row = 0; proxy_row < current_nb_rows; proxy_row++) { + gboolean allequal = TRUE; + GSList *list; + gint index; + const GValue *value; + + for (list = values, index = 0; + list; + list = list->next, index++) { + if (cols_index) + g_return_val_if_fail (cols_index [index] < priv->model_nb_cols, FALSE); + value = gda_data_proxy_get_value_at ((GdaDataModel *) proxy, + cols_index ? cols_index [index] : + index, proxy_row, NULL); + if ((!value) || !list->data || + (G_VALUE_TYPE (value) != G_VALUE_TYPE ((GValue *) list->data)) || + gda_value_compare ((GValue *) (list->data), (GValue *) value)) { + allequal = FALSE; + break; + } + } + if (allequal) { + found = TRUE; + break; + } + } + + g_rec_mutex_unlock (& (priv->mutex)); + return found ? proxy_row : -1; +} + +static GdaDataModelAccessFlags +gda_data_proxy_get_access_flags (GdaDataModel *model) +{ + GdaDataProxy *proxy; + g_return_val_if_fail (GDA_IS_DATA_PROXY (model), 0); + proxy = GDA_DATA_PROXY (model); + GdaDataProxyPrivate *priv = gda_data_proxy_get_instance_private (proxy); + + if (priv->model) { + GdaDataModelAccessFlags flags; + g_rec_mutex_lock (& (priv->mutex)); + flags = gda_data_model_get_access_flags (priv->model) | GDA_DATA_MODEL_ACCESS_RANDOM; + g_rec_mutex_unlock (& (priv->mutex)); + return flags; + } + else + return 0; +} + +static gboolean +gda_data_proxy_set_value_at (GdaDataModel *model, gint col, gint proxy_row, const GValue *value, + GError **error) +{ + GdaDataProxy *proxy; + + g_return_val_if_fail (GDA_IS_DATA_PROXY (model), FALSE); + proxy = GDA_DATA_PROXY (model); + g_return_val_if_fail (proxy_row >= 0, FALSE); + g_return_val_if_fail (value, FALSE); + GdaDataProxyPrivate *priv = gda_data_proxy_get_instance_private (proxy); + + g_rec_mutex_lock (& (priv->mutex)); + + /* ensure that there is no sync to be done */ + ensure_chunk_sync (proxy); + + if ((proxy_row == 0) && priv->add_null_entry) { + g_set_error (error, GDA_DATA_PROXY_ERROR, GDA_DATA_PROXY_READ_ONLY_ROW, + "%s", _("The first row is an empty row artificially prepended and cannot be altered")); + g_rec_mutex_unlock (& (priv->mutex)); + return FALSE; + } + + /* current proxy's values (values may be different than the ones in the proxied data model) */ + if ((col >= 0) && (col < priv->model_nb_cols)) { + /* Storing a GValue value */ + RowModif *rm; + RowValue *rv = NULL; + const GValue *cmp_value; + + /* compare with the current stored value */ + cmp_value = gda_data_proxy_get_value_at ((GdaDataModel *) proxy, col, proxy_row, error); + if (!cmp_value) { + GdaValueAttribute attrs; + attrs = gda_data_proxy_get_value_attributes (proxy, proxy_row, col); + if (attrs & GDA_VALUE_ATTR_NO_MODIF) { + g_rec_mutex_unlock (& (priv->mutex)); + return FALSE; + } + else { + GType exptype; + exptype = gda_column_get_g_type (gda_data_model_describe_column ((GdaDataModel *) proxy, + col)); + if ((G_VALUE_TYPE (value) != GDA_TYPE_NULL) && + (exptype != GDA_TYPE_NULL) && + (exptype != G_VALUE_TYPE (value))) { + g_rec_mutex_unlock (& (priv->mutex)); + g_warning (_("Wrong value type: expected '%s' and got '%s'"), + g_type_name (exptype), + g_type_name (G_VALUE_TYPE (value))); + return FALSE; + } + } + } + else if ((G_VALUE_TYPE (cmp_value) != GDA_TYPE_NULL) && + (G_VALUE_TYPE (value) != GDA_TYPE_NULL) && + (G_VALUE_TYPE (value) != G_VALUE_TYPE (cmp_value))) { + g_rec_mutex_unlock (& (priv->mutex)); + g_warning (_("Wrong value type: expected '%s' and got '%s'"), + g_type_name (G_VALUE_TYPE (cmp_value)), + g_type_name (G_VALUE_TYPE (value))); + return FALSE; + } + else if (! gda_value_compare ((GValue *) value, (GValue *) cmp_value)) { + /* nothing to do: values are equal */ + g_rec_mutex_unlock (& (priv->mutex)); + return TRUE; + } + + /* from now on we have a new value for the row */ + rm = find_or_create_row_modif (proxy, proxy_row, col, &rv); + + if (rv) { + /* compare with the original value (before modifications) and either + * delete the RowValue or alter it */ + if (rv->value) { + gda_value_free (rv->value); + rv->value = NULL; + } + + if (rm->orig_values && (col < rm->orig_values_size) && + rm->orig_values [col] && + ! gda_value_compare ((GValue *) value, rm->orig_values [col])) { + /* remove the RowValue */ + rm->modify_values = g_slist_remove (rm->modify_values, rv); + g_free (rv); + rv = NULL; + } + else { + /* simply alter the RowValue */ + GdaValueAttribute flags = rv->attributes; + + if (value && !gda_value_is_null ((GValue *) value)) { + flags &= ~GDA_VALUE_ATTR_IS_NULL; + rv->value = gda_value_copy ((GValue*) value); + } + else + flags |= GDA_VALUE_ATTR_IS_NULL; + rv->attributes = flags; + } + } + else { + /* create a new RowValue */ + GdaValueAttribute flags = 0; + + rv = g_new0 (RowValue, 1); + rv->row_modif = rm; + rv->model_column = col; + rv->attributes = priv->columns_attrs [col]; + flags = rv->attributes; + + if (value && !gda_value_is_null ((GValue*) value)) { + rv->value = gda_value_copy ((GValue*) value); + flags &= ~GDA_VALUE_ATTR_IS_NULL; + } + else + flags |= GDA_VALUE_ATTR_IS_NULL; + if (rm->model_row >= 0) + flags |= GDA_VALUE_ATTR_HAS_VALUE_ORIG; + else + flags &= ~GDA_VALUE_ATTR_HAS_VALUE_ORIG; + rv->attributes = flags; + rm->modify_values = g_slist_prepend (rm->modify_values, rv); + } + + if (rv) { + GdaValueAttribute flags = rv->attributes; + flags &= ~GDA_VALUE_ATTR_IS_UNCHANGED; + flags &= ~GDA_VALUE_ATTR_IS_DEFAULT; + rv->attributes = flags; + } + + if (!rm->to_be_deleted && !rm->modify_values && (rm->model_row >= 0)) { + /* remove that RowModif, it's useless */ + gint tmp; + tmp = rm->model_row; + g_hash_table_remove (priv->modify_rows, &tmp); + priv->all_modifs = g_slist_remove (priv->all_modifs, rm); + row_modifs_free (rm); + } + + if (priv->notify_changes) + gda_data_model_row_updated ((GdaDataModel *) proxy, proxy_row); + } + else { + g_set_error (error, GDA_DATA_PROXY_ERROR, GDA_DATA_PROXY_READ_ONLY_VALUE, + _("Trying to change read-only column: %d"), col); + g_rec_mutex_unlock (& (priv->mutex)); + return FALSE; + } + + g_rec_mutex_unlock (& (priv->mutex)); + return TRUE; +} + +static gboolean +gda_data_proxy_set_values (GdaDataModel *model, gint row, GList *values, GError **error) +{ + GdaDataProxy *proxy; + gboolean notify_changes; + gint col; + GList *list; + gboolean err = FALSE; + + g_return_val_if_fail (GDA_IS_DATA_PROXY (model), FALSE); + proxy = GDA_DATA_PROXY (model); + GdaDataProxyPrivate *priv = gda_data_proxy_get_instance_private (proxy); + if (!values) + return TRUE; + + g_return_val_if_fail ((gint)g_list_length (values) <= gda_data_proxy_get_n_columns (model), FALSE); + + /* check values */ + col = 0; + list = values; + while (list && !err) { + GValue *value = (GValue *)(list->data); + + if (value && !gda_value_is_null (value)) { + GdaColumn *column; + column = gda_data_model_describe_column (model, col); + if (gda_column_get_g_type (column) != G_VALUE_TYPE (value)) { + g_set_error (error, GDA_DATA_MODEL_ERROR, GDA_DATA_MODEL_VALUE_TYPE_ERROR, + _("Value type mismatch %s instead of %s"), + gda_g_type_to_string (G_VALUE_TYPE (value)), + gda_g_type_to_string (gda_column_get_g_type (column))); + err = TRUE; + } + } + col++; + list = g_list_next (list); + } + + /* stop here if there is a value error */ + if (err) + return FALSE; + + g_rec_mutex_lock (& (priv->mutex)); + + /* temporary disable changes notification */ + notify_changes = priv->notify_changes; + priv->notify_changes = FALSE; + + for (col = 0, list = values; list; col ++, list = list->next) { + if (list->data && + !gda_data_proxy_set_value_at (model, col, row, (GValue *)(list->data), error)) { + err = TRUE; + break; + } + } + + priv->notify_changes = notify_changes; + if (col && priv->notify_changes) + /* at least one successful value change occurred */ + gda_data_model_row_updated (model, row); + + g_rec_mutex_unlock (& (priv->mutex)); + return !err; +} + +static gint +gda_data_proxy_append_values (GdaDataModel *model, const GList *values, GError **error) +{ + GdaDataProxy *proxy; + gint newrow; + gboolean notify_changes; + + g_return_val_if_fail (GDA_IS_DATA_PROXY (model), -1); + proxy = GDA_DATA_PROXY (model); + GdaDataProxyPrivate *priv = gda_data_proxy_get_instance_private (proxy); + + g_rec_mutex_lock (& (priv->mutex)); + + /* ensure that there is no sync to be done */ + ensure_chunk_sync (proxy); + + /* temporary disable changes notification */ + notify_changes = priv->notify_changes; + priv->notify_changes = FALSE; + + newrow = gda_data_proxy_append (proxy); + if (! gda_data_proxy_set_values (model, newrow, (GList *) values, error)) { + gda_data_proxy_remove_row (model, newrow, NULL); + priv->notify_changes = notify_changes; + g_rec_mutex_unlock (& (priv->mutex)); + return -1; + } + else { + priv->notify_changes = notify_changes; + if (priv->notify_changes) + gda_data_model_row_inserted (model, newrow); + g_rec_mutex_unlock (& (priv->mutex)); + return newrow; + } +} + +static gint +gda_data_proxy_append_row (GdaDataModel *model, G_GNUC_UNUSED GError **error) +{ + GdaDataProxy *proxy; + gint i; + g_return_val_if_fail (GDA_IS_DATA_PROXY (model), -1); + proxy = GDA_DATA_PROXY (model); + GdaDataProxyPrivate *priv = gda_data_proxy_get_instance_private (proxy); + + g_rec_mutex_lock (& (priv->mutex)); + i = gda_data_proxy_append (proxy); + g_rec_mutex_unlock (& (priv->mutex)); + return i; +} + +static gboolean +gda_data_proxy_remove_row (GdaDataModel *model, gint row, GError **error) +{ + GdaDataProxy *proxy; + g_return_val_if_fail (GDA_IS_DATA_PROXY (model), FALSE); + proxy = GDA_DATA_PROXY (model); + GdaDataProxyPrivate *priv = gda_data_proxy_get_instance_private (proxy); + + g_rec_mutex_lock (& (priv->mutex)); + + if (priv->add_null_entry && row == 0) { + g_set_error (error, GDA_DATA_PROXY_ERROR, GDA_DATA_PROXY_READ_ONLY_ROW, + "%s", _("The first row is an empty row artificially prepended and cannot be removed")); + g_rec_mutex_unlock (& (priv->mutex)); + return FALSE; + } + + gda_data_proxy_delete (proxy, row); + g_rec_mutex_unlock (& (priv->mutex)); + return TRUE; +} + +static void +gda_data_proxy_freeze (GdaDataModel *model) +{ + GdaDataProxy *proxy; + g_return_if_fail (GDA_IS_DATA_PROXY (model)); + proxy = GDA_DATA_PROXY (model); + GdaDataProxyPrivate *priv = gda_data_proxy_get_instance_private (proxy); + + g_rec_mutex_lock (& (priv->mutex)); + priv->notify_changes = FALSE; + g_rec_mutex_unlock (& (priv->mutex)); +} + +static void +gda_data_proxy_thaw (GdaDataModel *model) +{ + GdaDataProxy *proxy; + g_return_if_fail (GDA_IS_DATA_PROXY (model)); + proxy = GDA_DATA_PROXY (model); + GdaDataProxyPrivate *priv = gda_data_proxy_get_instance_private (proxy); + + g_rec_mutex_lock (& (priv->mutex)); + priv->notify_changes = TRUE; + g_rec_mutex_unlock (& (priv->mutex)); +} + +static gboolean +gda_data_proxy_get_notify (GdaDataModel *model) +{ + GdaDataProxy *proxy; + g_return_val_if_fail (GDA_IS_DATA_PROXY (model), FALSE); + proxy = GDA_DATA_PROXY (model); + GdaDataProxyPrivate *priv = gda_data_proxy_get_instance_private (proxy); + + return priv->notify_changes; +} + +static void +gda_data_proxy_send_hint (GdaDataModel *model, GdaDataModelHint hint, const GValue *hint_value) +{ + GdaDataProxy *proxy; + g_return_if_fail (GDA_IS_DATA_PROXY (model)); + proxy = GDA_DATA_PROXY (model); + GdaDataProxyPrivate *priv = gda_data_proxy_get_instance_private (proxy); + + if (priv->model) + gda_data_model_send_hint (priv->model, hint, hint_value); +} + +/* + * Cache management + */ +static void +clean_cached_changes (GdaDataProxy *proxy) +{ + GdaDataProxyPrivate *priv = gda_data_proxy_get_instance_private (proxy); + while (priv->cached_modifs) { + row_modifs_free (ROW_MODIF (priv->cached_modifs->data)); + priv->cached_modifs = g_slist_delete_link (priv->cached_modifs, + priv->cached_modifs); + } + while (priv->cached_inserts) { + row_modifs_free (ROW_MODIF (priv->cached_inserts->data)); + priv->cached_inserts = g_slist_delete_link (priv->cached_inserts, + priv->cached_inserts); + } +} + +static void +migrate_current_changes_to_cache (GdaDataProxy *proxy) +{ + GdaDataProxyPrivate *priv = gda_data_proxy_get_instance_private (proxy); + while (priv->all_modifs) { + RowModif *rm; + rm = (RowModif*) priv->all_modifs->data; +#ifdef GDA_DEBUG_NO + g_print ("=== cached RM %p for row %d\n", rm, rm->model_row); +#endif + if (rm->model_row == -1) + priv->cached_inserts = g_slist_prepend (priv->cached_inserts, rm); + else + priv->cached_modifs = g_slist_prepend (priv->cached_modifs, rm); + priv->all_modifs = g_slist_delete_link (priv->all_modifs, + priv->all_modifs); + } + g_hash_table_remove_all (priv->modify_rows); + if (priv->new_rows) { + g_slist_free (priv->new_rows); + priv->new_rows = NULL; + } +} + +static void +fetch_current_cached_changes (GdaDataProxy *proxy) +{ + GSList *list; + gint ncols; + GdaDataProxyPrivate *priv = gda_data_proxy_get_instance_private (proxy); + g_return_if_fail (priv->model); + + ncols = priv->model_nb_cols; + + /* handle INSERT Row Modifs */ + for (list = priv->cached_inserts; list;) { + RowModif *rm = (RowModif*) list->data; + if (rm->orig_values_size != ncols) { + list = list->next; + continue; + } + + gint i; + for (i = 0; i < ncols; i++) { + GdaColumn *gcol; + const GValue *cv = NULL; + gcol = gda_data_model_describe_column (priv->model, i); + + GSList *rvl; + for (rvl = rm->modify_values; rvl; rvl = rvl->next) { + RowValue *rv = ROW_VALUE (rvl->data); + if (rv->model_column == i) { + cv = rv->value; + break; + } + } + + if (cv && (G_VALUE_TYPE (cv) != GDA_TYPE_NULL) && + G_VALUE_TYPE (cv) != gda_column_get_g_type (gcol)) + break; + } + + if (i == ncols) { + /* Matched! => move that Row Modif from cache */ + GSList *nlist; + nlist = list->next; + priv->cached_inserts = g_slist_delete_link (priv->cached_inserts, + list); + priv->all_modifs = g_slist_prepend (priv->all_modifs, rm); + priv->new_rows = g_slist_append (priv->new_rows, rm); +#ifdef GDA_DEBUG_NO + g_print ("=== fetched RM %p for row %d\n", rm, rm->model_row); +#endif + list = nlist; + } + else + list = list->next; + } + + /* handle UPDATE and DELETE Row Modifs */ + if (! priv->cached_modifs) + return; + + GdaDataModelIter *iter; + iter = gda_data_model_create_iter (priv->model); + while (gda_data_model_iter_move_next (iter)) { + for (list = priv->cached_modifs; list; list = list->next) { + RowModif *rm = (RowModif*) list->data; + const GValue *v1, *v2; + if (rm->orig_values_size != ncols) + continue; + + gint i; + for (i = 0; i < ncols; i++) { + v1 = gda_data_model_iter_get_value_at (iter, i); + v2 = rm->orig_values [i]; + + if ((v1 && !v2) || (!v1 && v2)) + break; + else if (v1 && v2) { + if ((G_VALUE_TYPE (v1) != G_VALUE_TYPE (v2)) || + gda_value_differ (v1, v2)) + break; + } + } + + if (i == ncols) { + /* Matched! => move that Row Modif from cache */ + priv->cached_modifs = g_slist_delete_link (priv->cached_modifs, + list); + priv->all_modifs = g_slist_prepend (priv->all_modifs, rm); + + gint *ptr; + ptr = g_new (gint, 1); +#ifdef GDA_DEBUG_NO + g_print ("=== fetched RM %p for row %d (old %d)\n", rm, gda_data_model_iter_get_row (iter), rm->model_row); +#endif + rm->model_row = gda_data_model_iter_get_row (iter); + *ptr = rm->model_row; + g_hash_table_insert (priv->modify_rows, ptr, rm); + break; /* the FOR over cached_modifs, as there can only be 1 Row Modif + * for the row iter is on */ + } + } + } + g_object_unref (iter); +} + /* RowModif structurdata */ diff --git a/.flatpak-builder/cache/objects/5f/74eacf68700811254e828fe06e11a36891866973506e72b7b5fb233ee389ae.file b/.flatpak-builder/cache/objects/5f/74eacf68700811254e828fe06e11a36891866973506e72b7b5fb233ee389ae.file new file mode 100644 index 0000000..3437c15 --- /dev/null +++ b/.flatpak-builder/cache/objects/5f/74eacf68700811254e828fe06e11a36891866973506e72b7b5fb233ee389ae.file @@ -0,0 +1,1267 @@ +/* + * Copyright (C) 2018 Daniel Espinosa + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + */ +#define G_LOG_DOMAIN "GDA-provider-meta" + +#include +#include +#include + +/* module error */ +GQuark gda_provider_meta_error_quark (void) +{ + static GQuark quark; + if (!quark) + quark = g_quark_from_static_string ("gda_provider_meta_error"); + return quark; +} + +enum { + PROP_CONNECTION = 1, + N_PROPERTIES +}; + +static GParamSpec *obj_properties[N_PROPERTIES] = { NULL, }; + +G_DEFINE_INTERFACE(GdaProviderMeta, gda_provider_meta, G_TYPE_OBJECT) + +static void +gda_provider_meta_default_init (GdaProviderMetaInterface *iface) { + + obj_properties[PROP_CONNECTION] = + g_param_spec_object ("connection", + "Connection", + "Connection to database to get metadata from", + GDA_TYPE_CONNECTION, + G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE); + + g_object_interface_install_property (iface, + obj_properties[PROP_CONNECTION]); +} + +/** + * gda_provider_meta_execute_query: + * @prov: a #GdaProviderMeta + * @sql: a string with the SQL to execute on provider + * @params: (nullable): a #GdaSet with all paramaters to use in query + * @error: place to store errors or %NULL + * + * SQL is specific for current provider. + * + * Returns: (transfer full) (nullable): a new #GdaDataModel with as a result of the query + * Since: 6.0 + * Stability: Unstable + */ +GdaDataModel *gda_provider_meta_execute_query (GdaProviderMeta *prov, + const gchar *sql, + GdaSet *params, + GError **error) +{ + g_return_val_if_fail (prov, NULL); + g_return_val_if_fail (GDA_IS_PROVIDER_META (prov), NULL); + g_return_val_if_fail (sql, NULL); + + GdaConnection *cnc = NULL; + GdaStatement *stmt; + g_object_get (G_OBJECT (prov), "connection", &cnc, NULL); + if (cnc == NULL) { + g_set_error (error, GDA_PROVIDER_META_ERROR, GDA_PROVIDER_META_NO_CONNECTION_ERROR, + _("No connection is set")); + return NULL; + } + if (!gda_connection_is_opened (cnc)) { + g_set_error (error, GDA_PROVIDER_META_ERROR, GDA_PROVIDER_META_NO_CONNECTION_ERROR, + _("Connection is no opened")); + return NULL; + } + stmt = gda_connection_parse_sql_string (cnc, sql, NULL, error); + if (stmt == NULL) { + return NULL; + } + if (!gda_connection_statement_prepare (cnc, stmt, error)) { + return NULL; + } + return gda_connection_statement_execute_select (cnc, stmt, params, error); +} + +/** + * gda_provider_meta_execute_query_row: + * @prov: a #GdaProviderMeta + * @sql: a string with the SQL to execute on provider + * @error: place to store errors or %NULL + * + * SQL is specific for current provider. + * + * Returns: (transfer full) (nullable): a new #GdaDataModel with as a result of the query + * Since: 6.0 + * Stability: Unstable + */ +GdaRow* +gda_provider_meta_execute_query_row (GdaProviderMeta *prov, + const gchar *sql, + GdaSet *params, + GError **error) +{ + GdaDataModel *model = NULL; + model = gda_provider_meta_execute_query (prov, sql, params, error); + if (model == NULL) { + return NULL; + } + if (gda_data_model_get_n_rows (model) != 1) { + g_set_error (error, GDA_PROVIDER_META_ERROR, GDA_PROVIDER_META_NO_CONNECTION_ERROR, + _("No rows or more than one row was returned from query")); + return NULL; + } + return gda_row_new_from_data_model (model, 0); +} + +/** + * gda_provider_meta_get_connection: + * @prov: + * + * Returns: (transfer full): a #GdaConnection used by this object. + * Since: 6.0 + * Stability: Unstable + */ +GdaConnection* +gda_provider_meta_get_connection (GdaProviderMeta *prov) { + g_return_val_if_fail (prov, NULL); + g_return_val_if_fail (GDA_IS_PROVIDER_META (prov), NULL); + GdaConnection *cnc = NULL; + g_object_get (G_OBJECT(prov), "connection", &cnc, NULL); + return cnc; +} + +/* _builtin_data_types */ +/** + * gda_provider_meta_btypes: + * + * Returns: (transfer full): + * Since: 6.0 + * Stability: Unstable + */ +GdaDataModel* +gda_provider_meta_btypes (GdaProviderMeta *prov, GError **error) +{ + g_return_val_if_fail (prov, NULL); + GdaProviderMetaInterface *iface = GDA_PROVIDER_META_GET_IFACE (prov); + if (iface->btypes) { + return iface->btypes (prov, error); + } + return NULL; +} + +/* _udt */ +/** + * gda_provider_meta_udts: + * + * Returns: (transfer full): + * Since: 6.0 + * Stability: Unstable + */ +GdaDataModel* +gda_provider_meta_udts (GdaProviderMeta *prov, GError **error) +{ + g_return_val_if_fail (prov, NULL); + GdaProviderMetaInterface *iface = GDA_PROVIDER_META_GET_IFACE (prov); + if (iface->udts) { + return iface->udts (prov, error); + } + return NULL; +} +/** + * gda_provider_meta_udt: + * + * Returns: (transfer full): + * Since: 6.0 + * Stability: Unstable + */ +GdaRow* +gda_provider_meta_udt (GdaProviderMeta *prov, + const gchar *udt_catalog, const gchar *udt_schema, + GError **error) +{ + g_return_val_if_fail (prov, NULL); + GdaProviderMetaInterface *iface = GDA_PROVIDER_META_GET_IFACE (prov); + if (iface->udt) { + return iface->udt (prov, udt_catalog, udt_schema, error); + } + return NULL; +} + +/* _udt_columns */ +/** + * gda_provider_meta_udt_cols: + * + * Returns: (transfer full): + * Since: 6.0 + * Stability: Unstable + */ +GdaDataModel* +gda_provider_meta_udt_cols (GdaProviderMeta *prov, GError **error) +{ + g_return_val_if_fail (prov, NULL); + GdaProviderMetaInterface *iface = GDA_PROVIDER_META_GET_IFACE (prov); + if (iface->udt_cols) { + return iface->udt_cols (prov, error); + } + return NULL; +} +/** + * gda_provider_meta_udt_col: + * + * Returns: (transfer full): + * Since: 6.0 + * Stability: Unstable + */ +GdaRow* +gda_provider_meta_udt_col (GdaProviderMeta *prov, + const gchar *udt_catalog, + const gchar *udt_schema, + const gchar *udt_name, GError **error) +{ + g_return_val_if_fail (prov, NULL); + GdaProviderMetaInterface *iface = GDA_PROVIDER_META_GET_IFACE (prov); + if (iface->udt_col) { + return iface->udt_col (prov, udt_catalog, udt_schema, udt_name, error); + } + return NULL; +} + +/* _enums */ +/** + * gda_provider_meta_enums_type: + * + * Returns: (transfer full): + * Since: 6.0 + * Stability: Unstable + */ +GdaDataModel* +gda_provider_meta_enums_type (GdaProviderMeta *prov, GError **error) +{ + g_return_val_if_fail (prov, NULL); + GdaProviderMetaInterface *iface = GDA_PROVIDER_META_GET_IFACE (prov); + if (iface->enums_type) { + return iface->enums_type (prov, error); + } + return NULL; +} +/** + * gda_provider_meta_enum_type: + * + * Returns: (transfer full): + * Since: 6.0 + * Stability: Unstable + */ +GdaRow* +gda_provider_meta_enum_type (GdaProviderMeta *prov, + const gchar *udt_catalog, + const gchar *udt_schema, + const gchar *udt_name, + GError **error) +{ + g_return_val_if_fail (prov, NULL); + GdaProviderMetaInterface *iface = GDA_PROVIDER_META_GET_IFACE (prov); + if (iface->enum_type) { + return iface->enum_type (prov, udt_catalog, udt_schema, udt_name, error); + } + return NULL; +} + +/* _domains */ +/** + * gda_provider_meta_domains: + * + * Returns: (transfer full): + * Since: 6.0 + * Stability: Unstable + */ +GdaDataModel* +gda_provider_meta_domains (GdaProviderMeta *prov, GError **error) +{ + g_return_val_if_fail (prov, NULL); + GdaProviderMetaInterface *iface = GDA_PROVIDER_META_GET_IFACE (prov); + if (iface->domains) { + return iface->domains (prov, error); + } + return NULL; +} +/** + * gda_provider_meta_domain: + * + * Returns: (transfer full): + * Since: 6.0 + * Stability: Unstable + */ +GdaRow* +gda_provider_meta_domain (GdaProviderMeta *prov, + const gchar *domain_catalog, + const gchar *domain_schema, + GError **error) +{ + g_return_val_if_fail (prov, NULL); + GdaProviderMetaInterface *iface = GDA_PROVIDER_META_GET_IFACE (prov); + if (iface->domain) { + return iface->domain (prov, domain_catalog, domain_schema, error); + } + return NULL; +} + +/* _domain_constraints */ +/** + * gda_provider_meta_domains_constraints: + * + * Returns: (transfer full): + * Since: 6.0 + * Stability: Unstable + */ +GdaDataModel* +gda_provider_meta_domains_constraints (GdaProviderMeta *prov, GError **error) +{ + g_return_val_if_fail (prov, NULL); + GdaProviderMetaInterface *iface = GDA_PROVIDER_META_GET_IFACE (prov); + if (iface->domains_constraints) { + return iface->domains_constraints (prov, error); + } + return NULL; +} +/** + * gda_provider_meta_domain_constraints: + * + * Returns: (transfer full): + * Since: 6.0 + * Stability: Unstable + */ +GdaDataModel* +gda_provider_meta_domain_constraints (GdaProviderMeta *prov, + const gchar *domain_catalog, + const gchar *domain_schema, + const gchar *domain_name, + GError **error) +{ + g_return_val_if_fail (prov, NULL); + GdaProviderMetaInterface *iface = GDA_PROVIDER_META_GET_IFACE (prov); + if (iface->domain_constraint) { + return iface->domain_constraints (prov, domain_catalog, domain_schema, domain_name, error); + } + return NULL; +} +/** + * gda_provider_meta_domain_constraint: + * + * Returns: (transfer full): + * Since: 6.0 + * Stability: Unstable + */ +GdaRow* +gda_provider_meta_domain_constraint (GdaProviderMeta *prov, + const gchar *domain_catalog, + const gchar *domain_schema, + const gchar *domain_name, + const gchar *constraint_name, + GError **error) +{ + g_return_val_if_fail (prov, NULL); + GdaProviderMetaInterface *iface = GDA_PROVIDER_META_GET_IFACE (prov); + if (iface->domain_constraint) { + return iface->domain_constraint (prov, domain_catalog, domain_schema, + domain_name, constraint_name, error); + } + return NULL; +} + +/* _element_types */ +/** + * gda_provider_meta_element_types: + * + * Returns: (transfer full): + * Since: 6.0 + * Stability: Unstable + */ +GdaDataModel* +gda_provider_meta_element_types (GdaProviderMeta *prov, GError **error) +{ + g_return_val_if_fail (prov, NULL); + GdaProviderMetaInterface *iface = GDA_PROVIDER_META_GET_IFACE (prov); + if (iface->element_types) { + return iface->element_types (prov, error); + } + return NULL; +} +/** + * gda_provider_meta_element_type: + * + * Returns: (transfer full): + * Since: 6.0 + * Stability: Unstable + */ +GdaRow* +gda_provider_meta_element_type (GdaProviderMeta *prov, + const gchar *specific_name, + GError **error) +{ + g_return_val_if_fail (prov, NULL); + GdaProviderMetaInterface *iface = GDA_PROVIDER_META_GET_IFACE (prov); + if (iface->element_type) { + return iface->element_type (prov, specific_name, error); + } + return NULL; +} + +/* _collations */ +/** + * gda_provider_meta_collations: + * + * Returns: (transfer full): + * Since: 6.0 + * Stability: Unstable + */ +GdaDataModel* +gda_provider_meta_collations (GdaProviderMeta *prov, GError **error) +{ + g_return_val_if_fail (prov, NULL); + GdaProviderMetaInterface *iface = GDA_PROVIDER_META_GET_IFACE (prov); + if (iface->collations) { + return iface->collations (prov, error); + } + return NULL; +} +/** + * gda_provider_meta_collation: + * + * Returns: (transfer full): + * Since: 6.0 + * Stability: Unstable + */ +GdaRow* +gda_provider_meta_collation (GdaProviderMeta *prov, + const gchar *collation_catalog, + const gchar *collation_schema, + const gchar *collation_name_n, GError **error) +{ + g_return_val_if_fail (prov, NULL); + GdaProviderMetaInterface *iface = GDA_PROVIDER_META_GET_IFACE (prov); + if (iface->collation) { + return iface->collation (prov, collation_catalog, + collation_schema, collation_name_n, error); + } + return NULL; +} + +/* _character_sets */ +/** + * gda_provider_meta_character_sets: + * + * Returns: (transfer full): + * Since: 6.0 + * Stability: Unstable + */ +GdaDataModel* +gda_provider_meta_character_sets (GdaProviderMeta *prov, GError **error) +{ + g_return_val_if_fail (prov, NULL); + GdaProviderMetaInterface *iface = GDA_PROVIDER_META_GET_IFACE (prov); + if (iface->character_sets) { + return iface->character_sets (prov, error); + } + return NULL; +} +/** + * gda_provider_meta_character_set: + * + * Returns: (transfer full): + * Since: 6.0 + * Stability: Unstable + */ +GdaRow* +gda_provider_meta_character_set (GdaProviderMeta *prov, + const gchar *chset_catalog, + const gchar *chset_schema, + const gchar *chset_name_n, + GError **error) +{ + g_return_val_if_fail (prov, NULL); + GdaProviderMetaInterface *iface = GDA_PROVIDER_META_GET_IFACE (prov); + if (iface->character_set) { + return iface->character_set (prov, chset_catalog, + chset_schema, chset_name_n, error); + } + return NULL; +} + +/* _schemata */ +/** + * gda_provider_meta_schematas: + * + * Returns: (transfer full): + * Since: 6.0 + * Stability: Unstable + */ +GdaDataModel* +gda_provider_meta_schematas (GdaProviderMeta *prov, GError **error) +{ + g_return_val_if_fail (prov, NULL); + GdaProviderMetaInterface *iface = GDA_PROVIDER_META_GET_IFACE (prov); + if (iface->schematas) { + return iface->schematas (prov, error); + } + return NULL; +} +/** + * gda_provider_meta_schemata: + * + * Returns: (transfer full): + * Since: 6.0 + * Stability: Unstable + */ +GdaRow* +gda_provider_meta_schemata (GdaProviderMeta *prov, + const gchar *catalog_name, + const gchar *schema_name_n, + GError **error) +{ + g_return_val_if_fail (prov, NULL); + GdaProviderMetaInterface *iface = GDA_PROVIDER_META_GET_IFACE (prov); + if (iface->schemata) { + return iface->schemata (prov, catalog_name, schema_name_n, error); + } + return NULL; +} + +/* _tables or _views */ +/** + * gda_provider_meta_tables: + * + * Returns: (transfer full): + * Since: 6.0 + * Stability: Unstable + */ +GdaDataModel* +gda_provider_meta_tables (GdaProviderMeta *prov, GError **error) +{ + g_return_val_if_fail (prov, NULL); + GdaProviderMetaInterface *iface = GDA_PROVIDER_META_GET_IFACE (prov); + if (iface->tables) { + return iface->tables (prov, error); + } + return NULL; +} +/** + * gda_provider_meta_table: + * + * Returns: (transfer full): + * Since: 6.0 + * Stability: Unstable + */ +GdaRow* +gda_provider_meta_table (GdaProviderMeta *prov, + const gchar *table_catalog, + const gchar *table_schema, + const gchar *table_name_n, + GError **error) +{ + g_return_val_if_fail (prov, NULL); + GdaProviderMetaInterface *iface = GDA_PROVIDER_META_GET_IFACE (prov); + if (iface->table) { + return iface->table (prov, table_catalog, + table_schema, table_name_n, error); + } + return NULL; +} +/** + * gda_provider_meta_views: + * + * Returns: (transfer full): + * Since: 6.0 + * Stability: Unstable + */ +GdaDataModel* +gda_provider_meta_views (GdaProviderMeta *prov, GError **error) +{ + g_return_val_if_fail (prov, NULL); + GdaProviderMetaInterface *iface = GDA_PROVIDER_META_GET_IFACE (prov); + if (iface->views) { + return iface->views (prov, error); + } + return NULL; +} +/** + * gda_provider_meta_view: + * + * Returns: (transfer full): + * Since: 6.0 + * Stability: Unstable + */ +GdaRow* +gda_provider_meta_view (GdaProviderMeta *prov, + const gchar *view_catalog, + const gchar *view_schema, + const gchar *view_name_n, + GError **error) +{ + g_return_val_if_fail (prov, NULL); + GdaProviderMetaInterface *iface = GDA_PROVIDER_META_GET_IFACE (prov); + if (iface->view) { + return iface->view (prov, view_catalog, + view_schema, view_name_n, error); + } + return NULL; +} + +/* _columns */ +/** + * gda_provider_meta_columns: + * + * Returns: (transfer full): + * Since: 6.0 + * Stability: Unstable + */ +GdaDataModel* +gda_provider_meta_columns (GdaProviderMeta *prov, GError **error) +{ + g_return_val_if_fail (prov, NULL); + GdaProviderMetaInterface *iface = GDA_PROVIDER_META_GET_IFACE (prov); + if (iface->columns) { + return iface->columns (prov, error); + } + return NULL; +} + +/* _tables_column_usage */ +/** + * gda_provider_meta_tables_columns: + * + * Returns: (transfer full): + * Since: 6.0 + * Stability: Unstable + */ +GdaDataModel* +gda_provider_meta_tables_columns (GdaProviderMeta *prov, GError **error) +{ + g_return_val_if_fail (prov, NULL); + GdaProviderMetaInterface *iface = GDA_PROVIDER_META_GET_IFACE (prov); + if (iface->views_columns) { + return iface->views_columns (prov, error); + } + return NULL; +} +/** + * gda_provider_meta_table_columns: + * + * Returns: (transfer full): + * Since: 6.0 + * Stability: Unstable + */ +GdaDataModel* +gda_provider_meta_table_columns (GdaProviderMeta *prov, + const gchar *table_catalog, + const gchar *table_schema, + const gchar *table_name, + GError **error) +{ + g_return_val_if_fail (prov, NULL); + GdaProviderMetaInterface *iface = GDA_PROVIDER_META_GET_IFACE (prov); + if (iface->table_columns) { + return iface->table_columns (prov, table_catalog, table_schema, + table_name, error); + } + return NULL; +} +/** + * gda_provider_meta_table_column: + * + * Returns: (transfer full): + * Since: 6.0 + * Stability: Unstable + */ +GdaRow* +gda_provider_meta_table_column (GdaProviderMeta *prov, + const gchar *table_catalog, + const gchar *table_schema, + const gchar *table_name, + const gchar *column_name, + GError **error) +{ + g_return_val_if_fail (prov, NULL); + GdaProviderMetaInterface *iface = GDA_PROVIDER_META_GET_IFACE (prov); + if (iface->table_column) { + return iface->table_column (prov, table_catalog, + table_schema, table_name, + column_name, error); + } + return NULL; +} + +/* _view_column_usage */ +/** + * gda_provider_meta_views_columns: + * + * Returns: (transfer full): + * Since: 6.0 + * Stability: Unstable + */ +GdaDataModel* +gda_provider_meta_views_columns (GdaProviderMeta *prov, GError **error) +{ + g_return_val_if_fail (prov, NULL); + GdaProviderMetaInterface *iface = GDA_PROVIDER_META_GET_IFACE (prov); + if (iface->views_columns) { + return iface->views_columns (prov, error); + } + return NULL; +} +/** + * gda_provider_meta_view_columns: + * + * Returns: (transfer full): + * Since: 6.0 + * Stability: Unstable + */ +GdaDataModel* +gda_provider_meta_view_columns (GdaProviderMeta *prov, + const gchar *view_catalog, + const gchar *view_schema, + const gchar *view_name, + GError **error) +{ + g_return_val_if_fail (prov, NULL); + GdaProviderMetaInterface *iface = GDA_PROVIDER_META_GET_IFACE (prov); + if (iface->view_columns) { + return iface->view_columns (prov, view_catalog, + view_schema, view_name, error); + } + return NULL; +} +/** + * gda_provider_meta_view_column: + * + * Returns: (transfer full): + * Since: 6.0 + * Stability: Unstable + */ +GdaRow* +gda_provider_meta_view_column (GdaProviderMeta *prov, + const gchar *view_catalog, + const gchar *view_schema, + const gchar *view_name, + const gchar *column_name, + GError **error) +{ + g_return_val_if_fail (prov, NULL); + GdaProviderMetaInterface *iface = GDA_PROVIDER_META_GET_IFACE (prov); + if (iface->view_column) { + return iface->view_column (prov, view_catalog, + view_schema, view_name, column_name, error); + } + return NULL; +} + + +/* _table_constraints */ +/** + * gda_provider_meta_constraints_tables: + * + * Returns: (transfer full): + * Since: 6.0 + * Stability: Unstable + */ +GdaDataModel* +gda_provider_meta_constraints_tables (GdaProviderMeta *prov, GError **error) +{ + g_return_val_if_fail (prov, NULL); + GdaProviderMetaInterface *iface = GDA_PROVIDER_META_GET_IFACE (prov); + if (iface->constraints_tables) { + return iface->constraints_tables (prov, error); + } + return NULL; +} +/** + * gda_provider_meta_constraints_table: + * + * Returns: (transfer full): + * Since: 6.0 + * Stability: Unstable + */ +GdaDataModel* +gda_provider_meta_constraints_table (GdaProviderMeta *prov, + const gchar *table_catalog, + const gchar *table_schema, + const gchar *table_name, + GError **error) +{ + g_return_val_if_fail (prov, NULL); + GdaProviderMetaInterface *iface = GDA_PROVIDER_META_GET_IFACE (prov); + if (iface->constraints_table) { + return iface->constraints_table (prov, table_catalog, + table_schema, + table_name, error); + } + return NULL; +} +/** + * gda_provider_meta_constraint_table: + * + * Returns: (transfer full): + * Since: 6.0 + * Stability: Unstable + */ +GdaRow* +gda_provider_meta_constraint_table (GdaProviderMeta *prov, + const gchar *table_catalog, + const gchar *table_schema, + const gchar *table_name, + const gchar *constraint_name_n, + GError **error) +{ + g_return_val_if_fail (prov, NULL); + GdaProviderMetaInterface *iface = GDA_PROVIDER_META_GET_IFACE (prov); + if (iface->constraint_table) { + return iface->constraint_table (prov, table_catalog, + table_schema, + table_name, + constraint_name_n, + error); + } + return NULL; +} + +/* _referential_constraints */ +/** + * gda_provider_meta_constraints_ref: + * + * Returns: (transfer full): + * Since: 6.0 + * Stability: Unstable + */ +GdaDataModel* +gda_provider_meta_constraints_ref (GdaProviderMeta *prov, GError **error) +{ + g_return_val_if_fail (prov, NULL); + GdaProviderMetaInterface *iface = GDA_PROVIDER_META_GET_IFACE (prov); + if (iface->constraints_ref) { + return iface->constraints_ref (prov, error); + } + return NULL; +} +/** + * gda_provider_meta_constraints_ref_table: + * + * Returns: (transfer full): + * Since: 6.0 + * Stability: Unstable + */ +GdaDataModel* +gda_provider_meta_constraints_ref_table (GdaProviderMeta *prov, + const gchar *table_catalog, + const gchar *table_schema, + const gchar *table_name, + GError **error) +{ + g_return_val_if_fail (prov, NULL); + GdaProviderMetaInterface *iface = GDA_PROVIDER_META_GET_IFACE (prov); + if (iface->constraints_ref_table) { + return iface->constraints_ref_table (prov, table_catalog, table_schema, + table_name, error); + } + return NULL; +} +/** + * gda_provider_meta_constraint_ref: + * + * Returns: (transfer full): + * Since: 6.0 + * Stability: Unstable + */ +GdaRow* +gda_provider_meta_constraint_ref (GdaProviderMeta *prov, + const gchar *table_catalog, + const gchar *table_schema, + const gchar *table_name, + const gchar *constraint_name, + GError **error) +{ + g_return_val_if_fail (prov, NULL); + GdaProviderMetaInterface *iface = GDA_PROVIDER_META_GET_IFACE (prov); + if (iface->constraint_ref) { + return iface->constraint_ref (prov, table_catalog, table_schema, + table_name, constraint_name, + error); + } + return NULL; +} + +/* _key_column_usage */ +/** + * gda_provider_meta_key_columns: + * + * Returns: (transfer full): + * Since: 6.0 + * Stability: Unstable + */ +GdaDataModel* +gda_provider_meta_key_columns (GdaProviderMeta *prov, GError **error) +{ + g_return_val_if_fail (prov, NULL); + GdaProviderMetaInterface *iface = GDA_PROVIDER_META_GET_IFACE (prov); + if (iface->key_columns) { + return iface->key_columns (prov, error); + } + return NULL; +} +/** + * gda_provider_meta_key_column: + * + * Returns: (transfer full): + * Since: 6.0 + * Stability: Unstable + */ +GdaRow* +gda_provider_meta_key_column (GdaProviderMeta *prov, + const gchar *table_catalog, + const gchar *table_schema, + const gchar *table_name, + const gchar *constraint_name, + GError **error) +{ + g_return_val_if_fail (prov, NULL); + GdaProviderMetaInterface *iface = GDA_PROVIDER_META_GET_IFACE (prov); + if (iface->key_column) { + return iface->key_column (prov, table_catalog, table_schema, + table_name, + constraint_name, + error); + } + return NULL; +} + +/* _check_column_usage */ +/** + * gda_provider_meta_check_columns: + * + * Returns: (transfer full): + * Since: 6.0 + * Stability: Unstable + */ +GdaDataModel* +gda_provider_meta_check_columns (GdaProviderMeta *prov, GError **error) +{ + g_return_val_if_fail (prov, NULL); + GdaProviderMetaInterface *iface = GDA_PROVIDER_META_GET_IFACE (prov); + if (iface->check_columns) { + return iface->check_columns (prov, error); + } + return NULL; +} +/** + * gda_provider_meta_check_column: + * + * Returns: (transfer full): + * Since: 6.0 + * Stability: Unstable + */ +GdaRow* +gda_provider_meta_check_column (GdaProviderMeta *prov, + const gchar *table_catalog, + const gchar *table_schema, + const gchar *table_name, + const gchar *constraint_name, + GError **error) +{ + g_return_val_if_fail (prov, NULL); + GdaProviderMetaInterface *iface = GDA_PROVIDER_META_GET_IFACE (prov); + if (iface->check_column) { + return iface->check_column (prov, table_catalog, + table_schema, + table_name, + constraint_name, + error); + } + return NULL; +} + +/* _triggers */ +/** + * gda_provider_meta_triggers: + * + * Returns: (transfer full): + * Since: 6.0 + * Stability: Unstable + */ +GdaDataModel* +gda_provider_meta_triggers (GdaProviderMeta *prov, GError **error) +{ + g_return_val_if_fail (prov, NULL); + GdaProviderMetaInterface *iface = GDA_PROVIDER_META_GET_IFACE (prov); + if (iface->triggers) { + return iface->triggers (prov, error); + } + return NULL; +} +/** + * gda_provider_meta_trigger: + * + * Returns: (transfer full): + * Since: 6.0 + * Stability: Unstable + */ +GdaRow* +gda_provider_meta_trigger (GdaProviderMeta *prov, + const gchar *table_catalog, + const gchar *table_schema, + const gchar *table_name, + GError **error) +{ + g_return_val_if_fail (prov, NULL); + GdaProviderMetaInterface *iface = GDA_PROVIDER_META_GET_IFACE (prov); + if (iface->trigger) { + return iface->trigger (prov, table_catalog, table_schema, + table_name, error); + } + return NULL; +} + +/* _routines */ +/** + * gda_provider_meta_routines: + * + * Returns: (transfer full): + * Since: 6.0 + * Stability: Unstable + */ +GdaDataModel* +gda_provider_meta_routines (GdaProviderMeta *prov, GError **error) +{ + g_return_val_if_fail (prov, NULL); + GdaProviderMetaInterface *iface = GDA_PROVIDER_META_GET_IFACE (prov); + if (iface->routines) { + return iface->routines (prov, error); + } + return NULL; +} +/** + * gda_provider_meta_routine: + * + * Returns: (transfer full): + * Since: 6.0 + * Stability: Unstable + */ +GdaRow* +gda_provider_meta_routine (GdaProviderMeta *prov, + const gchar *routine_catalog, + const gchar *routine_schema, + const gchar *routine_name_n, + GError **error) +{ + g_return_val_if_fail (prov, NULL); + GdaProviderMetaInterface *iface = GDA_PROVIDER_META_GET_IFACE (prov); + if (iface->routine) { + return iface->routine (prov, routine_catalog, routine_schema, + routine_name_n, error); + } + return NULL; +} + +/* _routine_columns */ +/** + * gda_provider_meta_routines_col: + * + * Returns: (transfer full): + * Since: 6.0 + * Stability: Unstable + */ +GdaDataModel* +gda_provider_meta_routines_col (GdaProviderMeta *prov, GError **error) +{ + g_return_val_if_fail (prov, NULL); + GdaProviderMetaInterface *iface = GDA_PROVIDER_META_GET_IFACE (prov); + if (iface->routines_col) { + return iface->routines_col (prov, error); + } + return NULL; +} +/** + * gda_provider_meta_routine_col: + * + * Returns: (transfer full): + * Since: 6.0 + * Stability: Unstable + */ +GdaRow* +gda_provider_meta_routine_col (GdaProviderMeta *prov, + const gchar *rout_catalog, + const gchar *rout_schema, + const gchar *rout_name, + GError **error) +{ + g_return_val_if_fail (prov, NULL); + GdaProviderMetaInterface *iface = GDA_PROVIDER_META_GET_IFACE (prov); + if (iface->routine_col) { + return iface->routine_col (prov, rout_catalog, rout_schema, + rout_name, error); + } + return NULL; +} + +/* _parameters */ +/** + * gda_provider_meta_routines_pars: + * + * Returns: (transfer full): + * Since: 6.0 + * Stability: Unstable + */ +GdaDataModel* +gda_provider_meta_routines_pars (GdaProviderMeta *prov, GError **error) +{ + g_return_val_if_fail (prov, NULL); + GdaProviderMetaInterface *iface = GDA_PROVIDER_META_GET_IFACE (prov); + if (iface->routines_pars) { + return iface->routines_pars (prov, error); + } + return NULL; +} +/** + * gda_provider_meta_routine_pars: + * + * Returns: (transfer full): + * Since: 6.0 + * Stability: Unstable + */ +GdaRow* +gda_provider_meta_routine_pars (GdaProviderMeta *prov, + const gchar *rout_catalog, + const gchar *rout_schema, + const gchar *rout_name, + GError **error) +{ + g_return_val_if_fail (prov, NULL); + GdaProviderMetaInterface *iface = GDA_PROVIDER_META_GET_IFACE (prov); + if (iface->routine_pars) { + return iface->routine_pars (prov,rout_catalog, rout_schema, + rout_name, error); + } + return NULL; +} +/* _table_indexes */ +/** + * gda_provider_meta_indexes_tables: + * + * Returns: (transfer full): + * Since: 6.0 + * Stability: Unstable + */ +GdaDataModel* +gda_provider_meta_indexes_tables (GdaProviderMeta *prov, GError **error) +{ + g_return_val_if_fail (prov, NULL); + GdaProviderMetaInterface *iface = GDA_PROVIDER_META_GET_IFACE (prov); + if (iface->indexes_tables) { + return iface->indexes_tables (prov, error); + } + return NULL; +} +/** + * gda_provider_meta_indexes_table: + * + * Returns: (transfer full): + * Since: 6.0 + * Stability: Unstable + */ +GdaDataModel* +gda_provider_meta_indexes_table (GdaProviderMeta *prov, + const gchar *table_catalog, + const gchar *table_schema, + const gchar *table_name, + GError **error) +{ + g_return_val_if_fail (prov, NULL); + GdaProviderMetaInterface *iface = GDA_PROVIDER_META_GET_IFACE (prov); + if (iface->indexes_table) { + + return iface->indexes_table (prov, table_catalog, table_schema, + table_name, error); + } + return NULL; +} +/** + * gda_provider_meta_index_table: + * + * Returns: (transfer full): + * Since: 6.0 + * Stability: Unstable + */ +GdaRow* +gda_provider_meta_index_table (GdaProviderMeta *prov, + const gchar *table_catalog, + const gchar *table_schema, + const gchar *table_name, + const gchar *index_name_n, + GError **error) +{ + g_return_val_if_fail (prov, NULL); + GdaProviderMetaInterface *iface = GDA_PROVIDER_META_GET_IFACE (prov); + if (iface->index_table) { + + return iface->index_table (prov, table_catalog, table_schema, + table_name, index_name_n, + error); + } + return NULL; +} + +/* _index_column_usage */ +/** + * gda_provider_meta_index_cols: + * + * Returns: (transfer full): + * Since: 6.0 + * Stability: Unstable + */ +GdaDataModel* +gda_provider_meta_index_cols (GdaProviderMeta *prov, GError **error) +{ + g_return_val_if_fail (prov, NULL); + GdaProviderMetaInterface *iface = GDA_PROVIDER_META_GET_IFACE (prov); + if (iface->index_cols) { + return iface->index_cols (prov, error); + } + return NULL; +} +/** + * gda_provider_meta_index_col: + * + * Returns: (transfer full): + * Since: 6.0 + * Stability: Unstable + */ +GdaRow* +gda_provider_meta_index_col (GdaProviderMeta *prov, + const gchar *table_catalog, + const gchar *table_schema, + const gchar *table_name, + const gchar *index_name, GError **error) +{ + g_return_val_if_fail (prov, NULL); + GdaProviderMetaInterface *iface = GDA_PROVIDER_META_GET_IFACE (prov); + if (iface->index_col) { + return iface->index_col (prov, table_catalog, table_schema, + table_name, index_name, error); + } + return NULL; +} + + diff --git a/.flatpak-builder/cache/objects/5f/881d6e67a579d2eb596858cfd244daac6de46325fe48a33849a2db6a47cb39.file b/.flatpak-builder/cache/objects/5f/881d6e67a579d2eb596858cfd244daac6de46325fe48a33849a2db6a47cb39.file new file mode 120000 index 0000000..35ff6ac --- /dev/null +++ b/.flatpak-builder/cache/objects/5f/881d6e67a579d2eb596858cfd244daac6de46325fe48a33849a2db6a47cb39.file @@ -0,0 +1 @@ +../../share/runtime/locale/ko/share/ko \ No newline at end of file diff --git a/.flatpak-builder/cache/objects/5f/a6682b7f70c10fba2aa17cf7be3349a9020e41161972739e4c0636b254a43f.file b/.flatpak-builder/cache/objects/5f/a6682b7f70c10fba2aa17cf7be3349a9020e41161972739e4c0636b254a43f.file new file mode 100644 index 0000000..bbbf69b Binary files /dev/null and b/.flatpak-builder/cache/objects/5f/a6682b7f70c10fba2aa17cf7be3349a9020e41161972739e4c0636b254a43f.file differ diff --git a/.flatpak-builder/cache/objects/5f/b2e6b1408a2c542f1837b1a3327d82eb0aab4dbc15d6d8b6cf01b1de8cebda.file b/.flatpak-builder/cache/objects/5f/b2e6b1408a2c542f1837b1a3327d82eb0aab4dbc15d6d8b6cf01b1de8cebda.file new file mode 100644 index 0000000..ae12b14 Binary files /dev/null and b/.flatpak-builder/cache/objects/5f/b2e6b1408a2c542f1837b1a3327d82eb0aab4dbc15d6d8b6cf01b1de8cebda.file differ diff --git a/.flatpak-builder/cache/objects/5f/dcf6c4592dcd8f302a0c772687e6125674ef2791d6baab797dd208766bde0e.dirtree b/.flatpak-builder/cache/objects/5f/dcf6c4592dcd8f302a0c772687e6125674ef2791d6baab797dd208766bde0e.dirtree new file mode 100644 index 0000000..484d884 Binary files /dev/null and b/.flatpak-builder/cache/objects/5f/dcf6c4592dcd8f302a0c772687e6125674ef2791d6baab797dd208766bde0e.dirtree differ diff --git a/.flatpak-builder/cache/objects/60/0038231bd3c12ff650255e1ffd2aba2e530977d9ac2b9e3ee847c947e61712.file b/.flatpak-builder/cache/objects/60/0038231bd3c12ff650255e1ffd2aba2e530977d9ac2b9e3ee847c947e61712.file new file mode 100644 index 0000000..252d6ed --- /dev/null +++ b/.flatpak-builder/cache/objects/60/0038231bd3c12ff650255e1ffd2aba2e530977d9ac2b9e3ee847c947e61712.file @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2005 Dan Winship + * Copyright (C) 2005 - 2011 Vivien Malerba + * Copyright (C) 2005 Álvaro Peña + * Copyright (C) 2007 - 2009 Murray Cumming + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef _GDA_STATEMENT_STRUCT_UTIL_H +#define _GDA_STATEMENT_STRUCT_UTIL_H + +#include +#include + +G_BEGIN_DECLS + +/* utility functions */ +gchar *_remove_quotes (gchar *str); +gchar *_json_quote_string (const gchar *str); +gboolean _string_is_identifier (const gchar *str); +gboolean _split_identifier_string (gchar *str, gchar **remain, gchar **last); + +gchar *gda_sql_identifier_force_quotes (const gchar *str); +gchar *gda_sql_identifier_prepare_for_compare (gchar *str); + +/* to be removed, only here for debug */ +gchar *gda_sql_value_stringify (const GValue *value); + +G_END_DECLS + +#endif diff --git a/.flatpak-builder/cache/objects/60/4708373a05f00ac2b4d72722678571e6f028b6657b429947c1f8524a559438.file b/.flatpak-builder/cache/objects/60/4708373a05f00ac2b4d72722678571e6f028b6657b429947c1f8524a559438.file new file mode 100644 index 0000000..2c92c6e --- /dev/null +++ b/.flatpak-builder/cache/objects/60/4708373a05f00ac2b4d72722678571e6f028b6657b429947c1f8524a559438.file @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2006 - 2012 Vivien Malerba + * Copyright (C) 2007 - 2011 Murray Cumming + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GDA_HANDLER_TIME__ +#define __GDA_HANDLER_TIME__ + +#include +#include + +G_BEGIN_DECLS + +#define GDA_TYPE_HANDLER_TIME (gda_handler_time_get_type()) +G_DECLARE_FINAL_TYPE (GdaHandlerTime, gda_handler_time, GDA, HANDLER_TIME, GObject) + +/** + * SECTION:gda-handler-time + * @short_description: Default handler for time values + * @title: GdaHanderTime + * @stability: Stable + * @see_also: #GdaDataHandler interface + * + * You should normally not need to use this API, refer to the #GdaDataHandler + * interface documentation for more information. + */ + +GdaDataHandler *gda_handler_time_new (void); +GdaDataHandler *gda_handler_time_new_no_locale (void); +void gda_handler_time_set_sql_spec (GdaHandlerTime *dh, GDateDMY first, GDateDMY sec, + GDateDMY third, gchar separator, gboolean twodigits_years); +void gda_handler_time_set_str_spec (GdaHandlerTime *dh, GDateDMY first, GDateDMY sec, + GDateDMY third, gchar separator, gboolean twodigits_years); +gchar *gda_handler_time_get_no_locale_str_from_value (GdaHandlerTime *dh, const GValue *value); + +gchar *gda_handler_time_get_format (GdaHandlerTime *dh, GType type); +gchar *gda_handler_time_get_hint (GdaHandlerTime *dh, GType type); + +G_END_DECLS + +#endif diff --git a/.flatpak-builder/cache/objects/60/f6ba7e3a7185dc43def41d06c82407714043fd3cfee5499e619eec80176150.file b/.flatpak-builder/cache/objects/60/f6ba7e3a7185dc43def41d06c82407714043fd3cfee5499e619eec80176150.file new file mode 100644 index 0000000..df355af --- /dev/null +++ b/.flatpak-builder/cache/objects/60/f6ba7e3a7185dc43def41d06c82407714043fd3cfee5499e619eec80176150.file @@ -0,0 +1,74 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.flatpak-builder/cache/objects/61/10c59899e01c7fad15261591a6b95b8fc01ee0c672ddf71455afcff2a9b35d.commit b/.flatpak-builder/cache/objects/61/10c59899e01c7fad15261591a6b95b8fc01ee0c672ddf71455afcff2a9b35d.commit new file mode 100644 index 0000000..cf39bc2 Binary files /dev/null and b/.flatpak-builder/cache/objects/61/10c59899e01c7fad15261591a6b95b8fc01ee0c672ddf71455afcff2a9b35d.commit differ diff --git a/.flatpak-builder/cache/objects/61/39a6471253705cedb01d4523101fc5d61eb4810b61a282761a3cb39585cc9f.dirtree b/.flatpak-builder/cache/objects/61/39a6471253705cedb01d4523101fc5d61eb4810b61a282761a3cb39585cc9f.dirtree new file mode 100644 index 0000000..fb6befa Binary files /dev/null and b/.flatpak-builder/cache/objects/61/39a6471253705cedb01d4523101fc5d61eb4810b61a282761a3cb39585cc9f.dirtree differ diff --git a/.flatpak-builder/cache/objects/61/45b57abc5f1b6850549922ebea25b5b44c9e747867fcecbb6c2ab7f6de5650.dirtree b/.flatpak-builder/cache/objects/61/45b57abc5f1b6850549922ebea25b5b44c9e747867fcecbb6c2ab7f6de5650.dirtree new file mode 100644 index 0000000..0035892 Binary files /dev/null and b/.flatpak-builder/cache/objects/61/45b57abc5f1b6850549922ebea25b5b44c9e747867fcecbb6c2ab7f6de5650.dirtree differ diff --git a/.flatpak-builder/cache/objects/62/07810e93da2eb6a51a10f9754b37762d92c0a100766b36ce6a7108fad5e2fb.dirtree b/.flatpak-builder/cache/objects/62/07810e93da2eb6a51a10f9754b37762d92c0a100766b36ce6a7108fad5e2fb.dirtree new file mode 100644 index 0000000..c3d1b00 Binary files /dev/null and b/.flatpak-builder/cache/objects/62/07810e93da2eb6a51a10f9754b37762d92c0a100766b36ce6a7108fad5e2fb.dirtree differ diff --git a/.flatpak-builder/cache/objects/62/4ec2df51ba6a52cce3fae59ecffa66a4f1b86b9cdeb67453a9c69b9fc63103.commit b/.flatpak-builder/cache/objects/62/4ec2df51ba6a52cce3fae59ecffa66a4f1b86b9cdeb67453a9c69b9fc63103.commit new file mode 100644 index 0000000..05f831c Binary files /dev/null and b/.flatpak-builder/cache/objects/62/4ec2df51ba6a52cce3fae59ecffa66a4f1b86b9cdeb67453a9c69b9fc63103.commit differ diff --git a/.flatpak-builder/cache/objects/62/5bbb1914c305f8664644a0b26daabbd609c3d3a1a9d141087449ad303858bb.file b/.flatpak-builder/cache/objects/62/5bbb1914c305f8664644a0b26daabbd609c3d3a1a9d141087449ad303858bb.file new file mode 120000 index 0000000..73b3bb2 --- /dev/null +++ b/.flatpak-builder/cache/objects/62/5bbb1914c305f8664644a0b26daabbd609c3d3a1a9d141087449ad303858bb.file @@ -0,0 +1 @@ +../../share/runtime/locale/es/share/es \ No newline at end of file diff --git a/.flatpak-builder/cache/objects/62/f85dd6148580de7ed1a270ffcddb96203a2993fc78caefcd90dd6a9fb78b76.dirtree b/.flatpak-builder/cache/objects/62/f85dd6148580de7ed1a270ffcddb96203a2993fc78caefcd90dd6a9fb78b76.dirtree new file mode 100644 index 0000000..b858c77 Binary files /dev/null and b/.flatpak-builder/cache/objects/62/f85dd6148580de7ed1a270ffcddb96203a2993fc78caefcd90dd6a9fb78b76.dirtree differ diff --git a/.flatpak-builder/cache/objects/63/69e61aabed840cf4826a0390370cb4045544e2e7ec1926b75eb9b5ab27e4c2.file b/.flatpak-builder/cache/objects/63/69e61aabed840cf4826a0390370cb4045544e2e7ec1926b75eb9b5ab27e4c2.file new file mode 100644 index 0000000..9697888 Binary files /dev/null and b/.flatpak-builder/cache/objects/63/69e61aabed840cf4826a0390370cb4045544e2e7ec1926b75eb9b5ab27e4c2.file differ diff --git a/.flatpak-builder/cache/objects/63/768d148fd62f699ce911b5aa3337f7d7b4d4edd3d40e5494759d71d3a0e027.file b/.flatpak-builder/cache/objects/63/768d148fd62f699ce911b5aa3337f7d7b4d4edd3d40e5494759d71d3a0e027.file new file mode 100644 index 0000000..6ac7a11 --- /dev/null +++ b/.flatpak-builder/cache/objects/63/768d148fd62f699ce911b5aa3337f7d7b4d4edd3d40e5494759d71d3a0e027.file @@ -0,0 +1,174 @@ +# main.py +# +# Copyright 2021 James Westman +# +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation; either version 3 of the +# License, or (at your option) any later version. +# +# This file is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program. If not, see . +# +# SPDX-License-Identifier: LGPL-3.0-or-later + + +import typing as T +import argparse, json, os, sys + +from .errors import PrintableError, report_bug, MultipleErrors, CompilerBugError +from .gir import add_typelib_search_path +from .lsp import LanguageServer +from . import parser, tokenizer, decompiler, interactive_port +from .utils import Colors +from .outputs import XmlOutput + +VERSION = "uninstalled" +LIBDIR = None + + +class BlueprintApp: + def main(self): + self.parser = argparse.ArgumentParser() + self.subparsers = self.parser.add_subparsers(metavar="command") + self.parser.set_defaults(func=self.cmd_help) + + compile = self.add_subcommand( + "compile", "Compile blueprint files", self.cmd_compile + ) + compile.add_argument("--output", dest="output", default="-") + compile.add_argument("--typelib-path", nargs="?", action="append") + compile.add_argument( + "input", metavar="filename", default=sys.stdin, type=argparse.FileType("r") + ) + + batch_compile = self.add_subcommand( + "batch-compile", + "Compile many blueprint files at once", + self.cmd_batch_compile, + ) + batch_compile.add_argument("output_dir", metavar="output-dir") + batch_compile.add_argument("input_dir", metavar="input-dir") + batch_compile.add_argument("--typelib-path", nargs="?", action="append") + batch_compile.add_argument( + "inputs", + nargs="+", + metavar="filenames", + default=sys.stdin, + type=argparse.FileType("r"), + ) + + port = self.add_subcommand("port", "Interactive porting tool", self.cmd_port) + + lsp = self.add_subcommand( + "lsp", "Run the language server (for internal use by IDEs)", self.cmd_lsp + ) + + self.add_subcommand("help", "Show this message", self.cmd_help) + + self.parser.add_argument("--version", action="version", version=VERSION) + + try: + opts = self.parser.parse_args() + opts.func(opts) + except SystemExit as e: + raise e + except KeyboardInterrupt: + print(f"\n\n{Colors.RED}{Colors.BOLD}Interrupted.{Colors.CLEAR}") + except EOFError: + print(f"\n\n{Colors.RED}{Colors.BOLD}Interrupted.{Colors.CLEAR}") + except: + report_bug() + + def add_subcommand(self, name: str, help: str, func): + parser = self.subparsers.add_parser(name, help=help) + parser.set_defaults(func=func) + return parser + + def cmd_help(self, opts): + self.parser.print_help() + + def cmd_compile(self, opts): + if opts.typelib_path != None: + for typelib_path in opts.typelib_path: + add_typelib_search_path(typelib_path) + + data = opts.input.read() + try: + xml, warnings = self._compile(data) + + for warning in warnings: + warning.pretty_print(opts.input.name, data, stream=sys.stderr) + + if opts.output == "-": + print(xml) + else: + with open(opts.output, "w") as file: + file.write(xml) + except PrintableError as e: + e.pretty_print(opts.input.name, data, stream=sys.stderr) + sys.exit(1) + + def cmd_batch_compile(self, opts): + if opts.typelib_path != None: + for typelib_path in opts.typelib_path: + add_typelib_search_path(typelib_path) + + for file in opts.inputs: + data = file.read() + + try: + if not os.path.commonpath([file.name, opts.input_dir]): + print( + f"{Colors.RED}{Colors.BOLD}error: input file '{file.name}' is not in input directory '{opts.input_dir}'{Colors.CLEAR}" + ) + sys.exit(1) + + xml, warnings = self._compile(data) + + for warning in warnings: + warning.pretty_print(file.name, data, stream=sys.stderr) + + path = os.path.join( + opts.output_dir, + os.path.relpath( + os.path.splitext(file.name)[0] + ".ui", opts.input_dir + ), + ) + os.makedirs(os.path.dirname(path), exist_ok=True) + with open(path, "w") as file: + file.write(xml) + except PrintableError as e: + e.pretty_print(file.name, data) + sys.exit(1) + + def cmd_lsp(self, opts): + langserv = LanguageServer() + langserv.run() + + def cmd_port(self, opts): + interactive_port.run(opts) + + def _compile(self, data: str) -> T.Tuple[str, T.List[PrintableError]]: + tokens = tokenizer.tokenize(data) + ast, errors, warnings = parser.parse(tokens) + + if errors: + raise errors + if ast is None: + raise CompilerBugError() + + formatter = XmlOutput() + + return formatter.emit(ast), warnings + + +def main(version, libdir): + global VERSION, LIBDIR + VERSION, LIBDIR = version, libdir + BlueprintApp().main() diff --git a/.flatpak-builder/cache/objects/63/afe560387692e935ddabf28074547cde414175e81143d5dcd0817c104b838a.dirtree b/.flatpak-builder/cache/objects/63/afe560387692e935ddabf28074547cde414175e81143d5dcd0817c104b838a.dirtree new file mode 100644 index 0000000..9e269cf Binary files /dev/null and b/.flatpak-builder/cache/objects/63/afe560387692e935ddabf28074547cde414175e81143d5dcd0817c104b838a.dirtree differ diff --git a/.flatpak-builder/cache/objects/63/bfcb879547cfdfd7d796baff150169ce882b02fa0d0ce02ca10984be9161e9.dirtree b/.flatpak-builder/cache/objects/63/bfcb879547cfdfd7d796baff150169ce882b02fa0d0ce02ca10984be9161e9.dirtree new file mode 100644 index 0000000..788a07f Binary files /dev/null and b/.flatpak-builder/cache/objects/63/bfcb879547cfdfd7d796baff150169ce882b02fa0d0ce02ca10984be9161e9.dirtree differ diff --git a/.flatpak-builder/cache/objects/63/db060e57dab4317a28d01d561db5fa7eb6bcdf998bcdc57cb2900610816599.file b/.flatpak-builder/cache/objects/63/db060e57dab4317a28d01d561db5fa7eb6bcdf998bcdc57cb2900610816599.file new file mode 100644 index 0000000..4d6755f --- /dev/null +++ b/.flatpak-builder/cache/objects/63/db060e57dab4317a28d01d561db5fa7eb6bcdf998bcdc57cb2900610816599.file @@ -0,0 +1,58 @@ + +/* This file is generated by glib-mkenums, do not modify it. This code is licensed under the same license as the containing project. Note that it links to GLib, so must comply with the LGPL linking clauses. */ + +#pragma once + + #include + + + G_BEGIN_DECLS + +/* enumerations from "gda-sql-parser.h" */ + + +GType gda_sql_parser_error_get_type (void); +#define GDA_TYPE_SQL_PARSER_ERROR (gda_sql_parser_error_get_type()) + + +GType gda_sql_parser_mode_get_type (void); +#define GDA_TYPE_SQL_PARSER_MODE (gda_sql_parser_mode_get_type()) + + +GType gda_sql_parser_flavour_get_type (void); +#define GDA_TYPE_SQL_PARSER_FLAVOUR (gda_sql_parser_flavour_get_type()) + +/* enumerations from "gda-statement-struct-compound.h" */ + + +GType gda_sql_statement_compound_type_get_type (void); +#define GDA_TYPE_SQL_STATEMENT_COMPOUND_TYPE (gda_sql_statement_compound_type_get_type()) + +/* enumerations from "gda-statement-struct-decl.h" */ + + +GType gda_sql_error_get_type (void); +#define GDA_TYPE_SQL_ERROR (gda_sql_error_get_type()) + + +GType gda_sql_statement_type_get_type (void); +#define GDA_TYPE_SQL_STATEMENT_TYPE (gda_sql_statement_type_get_type()) + + +GType gda_sql_any_part_type_get_type (void); +#define GDA_TYPE_SQL_ANY_PART_TYPE (gda_sql_any_part_type_get_type()) + +/* enumerations from "gda-statement-struct-parts.h" */ + + +GType gda_sql_operator_type_get_type (void); +#define GDA_TYPE_SQL_OPERATOR_TYPE (gda_sql_operator_type_get_type()) + + +GType gda_sql_select_join_type_get_type (void); +#define GDA_TYPE_SQL_SELECT_JOIN_TYPE (gda_sql_select_join_type_get_type()) + +G_END_DECLS + +/* Generated data ends here */ + diff --git a/.flatpak-builder/cache/objects/64/39d175d6ca461ae068cd8d13804d7768f44cc084ff03a8c65aabae7abf5564.dirtree b/.flatpak-builder/cache/objects/64/39d175d6ca461ae068cd8d13804d7768f44cc084ff03a8c65aabae7abf5564.dirtree new file mode 100644 index 0000000..845c205 Binary files /dev/null and b/.flatpak-builder/cache/objects/64/39d175d6ca461ae068cd8d13804d7768f44cc084ff03a8c65aabae7abf5564.dirtree differ diff --git a/.flatpak-builder/cache/objects/64/5071ef12fa7fec995c298732798730293f09d83fc2ae72f41f096443f59765.dirtree b/.flatpak-builder/cache/objects/64/5071ef12fa7fec995c298732798730293f09d83fc2ae72f41f096443f59765.dirtree new file mode 100644 index 0000000..c4622fc Binary files /dev/null and b/.flatpak-builder/cache/objects/64/5071ef12fa7fec995c298732798730293f09d83fc2ae72f41f096443f59765.dirtree differ diff --git a/.flatpak-builder/cache/objects/64/9ca01f5485a6fcf87e82155fe3c54f8b8345af57ace1f971fa919a3f109920.file b/.flatpak-builder/cache/objects/64/9ca01f5485a6fcf87e82155fe3c54f8b8345af57ace1f971fa919a3f109920.file new file mode 100644 index 0000000..d1f0218 --- /dev/null +++ b/.flatpak-builder/cache/objects/64/9ca01f5485a6fcf87e82155fe3c54f8b8345af57ace1f971fa919a3f109920.file @@ -0,0 +1,207 @@ +/* + * Copyright (C) 2009 - 2012 Vivien Malerba + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +#define G_LOG_DOMAIN "GDA-repetitive-statement" + +#include +#include +#include +#include + +typedef struct +{ + GdaStatement* statement; + GSList* values_sets; /* list of GdaSet pointers, objects referenced here */ +} GdaRepetitiveStatementPrivate; + +G_DEFINE_TYPE_WITH_PRIVATE(GdaRepetitiveStatement, gda_repetitive_statement, G_TYPE_OBJECT) + +enum { + PROP_0, + PROP_STATEMENT +}; + +static void +gda_repetitive_statement_init (GdaRepetitiveStatement *object) +{ + GdaRepetitiveStatementPrivate *priv = gda_repetitive_statement_get_instance_private (object); + + priv->statement = NULL; + priv->values_sets = NULL; +} + +static void +gda_repetitive_statement_finalize (GObject *object) +{ + GdaRepetitiveStatementPrivate *priv = gda_repetitive_statement_get_instance_private (GDA_REPETITIVE_STATEMENT (object)); + + g_object_unref (priv->statement); + g_slist_free_full (priv->values_sets, (GDestroyNotify) g_object_unref); + + G_OBJECT_CLASS (gda_repetitive_statement_parent_class)->finalize (object); +} + +static void +gda_repetitive_statement_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) +{ + g_return_if_fail (GDA_IS_REPETITIVE_STATEMENT (object)); + + GdaRepetitiveStatementPrivate *priv = gda_repetitive_statement_get_instance_private (GDA_REPETITIVE_STATEMENT (object)); + + switch (prop_id) { + case PROP_STATEMENT: + priv->statement = g_value_dup_object (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gda_repetitive_statement_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) +{ + g_return_if_fail (GDA_IS_REPETITIVE_STATEMENT (object)); + + GdaRepetitiveStatementPrivate *priv = gda_repetitive_statement_get_instance_private (GDA_REPETITIVE_STATEMENT (object)); + + switch (prop_id) { + case PROP_STATEMENT: + g_value_set_object (value, priv->statement); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gda_repetitive_statement_class_init (GdaRepetitiveStatementClass *klass) +{ + GObjectClass* object_class = G_OBJECT_CLASS (klass); + + object_class->finalize = gda_repetitive_statement_finalize; + object_class->set_property = gda_repetitive_statement_set_property; + object_class->get_property = gda_repetitive_statement_get_property; + + g_object_class_install_property (object_class, + PROP_STATEMENT, + g_param_spec_object ("statement", + "stmt", + "Statement to Execute", + GDA_TYPE_STATEMENT, + G_PARAM_WRITABLE | G_PARAM_READABLE | G_PARAM_CONSTRUCT_ONLY)); +} + +/** + * gda_repetitive_statement_new: + * @stmt: a #GdaStatement object + * + * Creates a new #GdaRepetitiveStatement object which, when executed, will execute @stmt once for all + * the values set which will have been defined using gda_repetitive_statement_append_set(). + * Use gda_connection_repetitive_statement_execute() to actually execute it. + * + * Returns: a new #GdaRepetitiveStatement object + * + * Since: 4.2 + */ +GdaRepetitiveStatement* +gda_repetitive_statement_new (GdaStatement *stmt) +{ + GdaRepetitiveStatement *rstmt; + + rstmt = GDA_REPETITIVE_STATEMENT (g_object_new (GDA_TYPE_REPETITIVE_STATEMENT, + "statement", stmt, NULL)); + + return rstmt; +} + +/** + * gda_repetitive_statement_get_template_set: + * @rstmt: a #GdaRepetitiveStatement object + * @set: a place to store the returned template set + * @error: (nullable): a place to store error, or %NULL + * + * Gets a new #GdaSet object with the parameters used by the template statement in the + * @rstmt object. + * + * Use this object with gda_repetitive_statement_append_set(). + * + * Returns: %TRUE on success, %FALSE on error + * + * Since: 4.2 + */ +gboolean +gda_repetitive_statement_get_template_set (GdaRepetitiveStatement *rstmt, GdaSet **set, GError **error) +{ + GdaRepetitiveStatementPrivate *priv = gda_repetitive_statement_get_instance_private (rstmt); + + return gda_statement_get_parameters (priv->statement, set, error); +} + +/** + * gda_repetitive_statement_append_set: + * @rstmt: a #GdaRepetitiveStatement object + * @values: a #GdaSet object with the values to be used + * @make_copy: %TRUE if @values is copied, and %FALSE if @values is only ref'ed + * + * Specifies that @rstmt be executed one time with the values contained in @values. + * + * A new #GdaSet to be used as the @values argument can be obtained using + * gda_repetitive_statement_get_template_set(). + * + * Returns: a new #GdaRepetitiveStatement object + * + * Since: 4.2 + */ +gboolean +gda_repetitive_statement_append_set (GdaRepetitiveStatement *rstmt, GdaSet *values, gboolean make_copy) +{ + GdaSet *set; + + g_return_val_if_fail (GDA_IS_REPETITIVE_STATEMENT(rstmt), FALSE); + g_return_val_if_fail (GDA_IS_SET (values), FALSE); + + GdaRepetitiveStatementPrivate *priv = gda_repetitive_statement_get_instance_private (rstmt); + + if (make_copy) + set = gda_set_copy (values); + else + set = g_object_ref (values); + priv->values_sets = g_slist_prepend (priv->values_sets, set); + + return TRUE; +} + +/** + * gda_repetitive_statement_get_all_sets: + * @rstmt: a #GdaRepetitiveStatement object + * + * Get all the values sets which will have been added using gda_repetitive_statement_append_set(). + * + * Returns: (transfer container) (element-type GdaSet): a new #GSList of #GdaSet objects (free with g_slist_free()). + * + * Since: 4.2 + */ +GSList* +gda_repetitive_statement_get_all_sets (GdaRepetitiveStatement *rstmt) +{ + GdaRepetitiveStatementPrivate *priv = gda_repetitive_statement_get_instance_private (rstmt); + + return g_slist_copy (g_slist_reverse (priv->values_sets)); +} diff --git a/.flatpak-builder/cache/objects/64/e2ad6d6ba9d880769dc5d11efbacd8f1e40373f6b212dc42aaa2fc410467cc.file b/.flatpak-builder/cache/objects/64/e2ad6d6ba9d880769dc5d11efbacd8f1e40373f6b212dc42aaa2fc410467cc.file new file mode 100644 index 0000000..cc72e7f --- /dev/null +++ b/.flatpak-builder/cache/objects/64/e2ad6d6ba9d880769dc5d11efbacd8f1e40373f6b212dc42aaa2fc410467cc.file @@ -0,0 +1,10 @@ +prefix=/app +includedir=${prefix}/include +libdir=${prefix}/lib + +Name: gsound +Description: GObject wrapper for libcanberra +Version: 1.0.3 +Requires.private: gobject-2.0, gio-2.0, libcanberra +Libs: -L${libdir} -lgsound +Cflags: -I${includedir} diff --git a/.flatpak-builder/cache/objects/64/e9f7cddb94342f3b5b69c047028f8ea042c19a098ef0e6a6a3b6cdb0b51ddf.dirtree b/.flatpak-builder/cache/objects/64/e9f7cddb94342f3b5b69c047028f8ea042c19a098ef0e6a6a3b6cdb0b51ddf.dirtree new file mode 100644 index 0000000..c551238 Binary files /dev/null and b/.flatpak-builder/cache/objects/64/e9f7cddb94342f3b5b69c047028f8ea042c19a098ef0e6a6a3b6cdb0b51ddf.dirtree differ diff --git a/.flatpak-builder/cache/objects/65/15793fb5acc6412f2caee290f6f3bd57e886097af981b07d29d643488fb315.file b/.flatpak-builder/cache/objects/65/15793fb5acc6412f2caee290f6f3bd57e886097af981b07d29d643488fb315.file new file mode 100644 index 0000000..ca1e8e8 --- /dev/null +++ b/.flatpak-builder/cache/objects/65/15793fb5acc6412f2caee290f6f3bd57e886097af981b07d29d643488fb315.file @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2001 - 2002 Gonzalo Paniagua Javier + * Copyright (C) 2001 - 2002 Rodrigo Moya + * Copyright (C) 2003 Danilo Schoeneberg + * Copyright (C) 2003 Laurent Sansonetti + * Copyright (C) 2005 - 2012 Vivien Malerba + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GDA_SQLITE_UTIL_H__ +#define __GDA_SQLITE_UTIL_H__ + +#include "gda-sqlite.h" + +G_BEGIN_DECLS + +void _gda_sqlite_compute_types_hash (SqliteConnectionData *scnc); +GType _gda_sqlite_compute_g_type (int sqlite_type); + +#ifdef GDA_DEBUG +void _gda_sqlite_test_keywords (void); +#endif +GdaSqlReservedKeywordsFunc _gda_sqlite_get_reserved_keyword_func (void); + +gchar *_gda_sqlite_identifier_quote (GdaServerProvider *provider, GdaConnection *cnc, + const gchar *id, + gboolean meta_store_convention, gboolean force_quotes); + +gboolean _gda_sqlite_check_transaction_started (GdaConnection *cnc, gboolean *out_started, GError **error); + +G_END_DECLS + +#endif + diff --git a/.flatpak-builder/cache/objects/65/83318db9510e405f087dded98e6c4024e44e72e4c5f80489de6c7a264d3448.file b/.flatpak-builder/cache/objects/65/83318db9510e405f087dded98e6c4024e44e72e4c5f80489de6c7a264d3448.file new file mode 100644 index 0000000..f6aae58 Binary files /dev/null and b/.flatpak-builder/cache/objects/65/83318db9510e405f087dded98e6c4024e44e72e4c5f80489de6c7a264d3448.file differ diff --git a/.flatpak-builder/cache/objects/65/8ec059854f3e8a9d8c96536955445d3eccd6806815e1dec5fa1b6f02aac34e.dirtree b/.flatpak-builder/cache/objects/65/8ec059854f3e8a9d8c96536955445d3eccd6806815e1dec5fa1b6f02aac34e.dirtree new file mode 100644 index 0000000..6cf47d7 Binary files /dev/null and b/.flatpak-builder/cache/objects/65/8ec059854f3e8a9d8c96536955445d3eccd6806815e1dec5fa1b6f02aac34e.dirtree differ diff --git a/.flatpak-builder/cache/objects/65/8f40ed81f09e7fc7253309fac99d8a60a6ed2aed41494496e3e427e0698912.file b/.flatpak-builder/cache/objects/65/8f40ed81f09e7fc7253309fac99d8a60a6ed2aed41494496e3e427e0698912.file new file mode 100644 index 0000000..fd28829 Binary files /dev/null and b/.flatpak-builder/cache/objects/65/8f40ed81f09e7fc7253309fac99d8a60a6ed2aed41494496e3e427e0698912.file differ diff --git a/.flatpak-builder/cache/objects/65/c39aba45ce515dc8749835938fcb84c9c0f4e9c43a51b1e0f54670be1e143c.file b/.flatpak-builder/cache/objects/65/c39aba45ce515dc8749835938fcb84c9c0f4e9c43a51b1e0f54670be1e143c.file new file mode 120000 index 0000000..a1ce115 --- /dev/null +++ b/.flatpak-builder/cache/objects/65/c39aba45ce515dc8749835938fcb84c9c0f4e9c43a51b1e0f54670be1e143c.file @@ -0,0 +1 @@ +libcanberra-gtk3-module.so \ No newline at end of file diff --git a/.flatpak-builder/cache/objects/65/dcca074aabb7ff3e90e3e7e98589873c7c189e26bec7579b3d73f23db28d47.dirtree b/.flatpak-builder/cache/objects/65/dcca074aabb7ff3e90e3e7e98589873c7c189e26bec7579b3d73f23db28d47.dirtree new file mode 100644 index 0000000..3799ed3 Binary files /dev/null and b/.flatpak-builder/cache/objects/65/dcca074aabb7ff3e90e3e7e98589873c7c189e26bec7579b3d73f23db28d47.dirtree differ diff --git a/.flatpak-builder/cache/objects/66/5271714217e5b47df3658525aa728772d88bd39f0656b6ce51f9d45e10b64d.file b/.flatpak-builder/cache/objects/66/5271714217e5b47df3658525aa728772d88bd39f0656b6ce51f9d45e10b64d.file new file mode 120000 index 0000000..1738a0c --- /dev/null +++ b/.flatpak-builder/cache/objects/66/5271714217e5b47df3658525aa728772d88bd39f0656b6ce51f9d45e10b64d.file @@ -0,0 +1 @@ +libgsound.so.0.0.2 \ No newline at end of file diff --git a/.flatpak-builder/cache/objects/66/89ac7aa5307c18734b7cb338ffdab6de9f1f30b2e05289e3b8bbe66945d36d.file b/.flatpak-builder/cache/objects/66/89ac7aa5307c18734b7cb338ffdab6de9f1f30b2e05289e3b8bbe66945d36d.file new file mode 120000 index 0000000..68ee8fd --- /dev/null +++ b/.flatpak-builder/cache/objects/66/89ac7aa5307c18734b7cb338ffdab6de9f1f30b2e05289e3b8bbe66945d36d.file @@ -0,0 +1 @@ +../../share/runtime/locale/ca/share/ca@valencia \ No newline at end of file diff --git a/.flatpak-builder/cache/objects/66/9c637ce699d8b561ea1590e270e23cfe292240b8313300822307e7c5f8c824.file b/.flatpak-builder/cache/objects/66/9c637ce699d8b561ea1590e270e23cfe292240b8313300822307e7c5f8c824.file new file mode 100644 index 0000000..545dc33 Binary files /dev/null and b/.flatpak-builder/cache/objects/66/9c637ce699d8b561ea1590e270e23cfe292240b8313300822307e7c5f8c824.file differ diff --git a/.flatpak-builder/cache/objects/67/19f5f1b1f31842b69e4e083142e608d49109ea6eb8615521672d3dd3d52630.dirtree b/.flatpak-builder/cache/objects/67/19f5f1b1f31842b69e4e083142e608d49109ea6eb8615521672d3dd3d52630.dirtree new file mode 100644 index 0000000..f9a7b17 Binary files /dev/null and b/.flatpak-builder/cache/objects/67/19f5f1b1f31842b69e4e083142e608d49109ea6eb8615521672d3dd3d52630.dirtree differ diff --git a/.flatpak-builder/cache/objects/67/4dd835206fb66c14c6dc06748af89580ceee7341c3d0166bfc2e75549eea55.dirtree b/.flatpak-builder/cache/objects/67/4dd835206fb66c14c6dc06748af89580ceee7341c3d0166bfc2e75549eea55.dirtree new file mode 100644 index 0000000..c8c147e Binary files /dev/null and b/.flatpak-builder/cache/objects/67/4dd835206fb66c14c6dc06748af89580ceee7341c3d0166bfc2e75549eea55.dirtree differ diff --git a/.flatpak-builder/cache/objects/67/70e33db227fcd284da3a2c1385abfee5473cdd9654801db84517d5002631db.dirtree b/.flatpak-builder/cache/objects/67/70e33db227fcd284da3a2c1385abfee5473cdd9654801db84517d5002631db.dirtree new file mode 100644 index 0000000..1db3893 Binary files /dev/null and b/.flatpak-builder/cache/objects/67/70e33db227fcd284da3a2c1385abfee5473cdd9654801db84517d5002631db.dirtree differ diff --git a/.flatpak-builder/cache/objects/67/fdc03108658e49304e9e81bc82bde40f2b1257fa657beec9c52c6a79ddbb5d.dirtree b/.flatpak-builder/cache/objects/67/fdc03108658e49304e9e81bc82bde40f2b1257fa657beec9c52c6a79ddbb5d.dirtree new file mode 100644 index 0000000..9e2dab0 Binary files /dev/null and b/.flatpak-builder/cache/objects/67/fdc03108658e49304e9e81bc82bde40f2b1257fa657beec9c52c6a79ddbb5d.dirtree differ diff --git a/.flatpak-builder/cache/objects/68/1efe80d8aa9135c5056d2cc38b754badeec710b547ab0d875e6abe242a88df.file b/.flatpak-builder/cache/objects/68/1efe80d8aa9135c5056d2cc38b754badeec710b547ab0d875e6abe242a88df.file new file mode 100644 index 0000000..f13e661 --- /dev/null +++ b/.flatpak-builder/cache/objects/68/1efe80d8aa9135c5056d2cc38b754badeec710b547ab0d875e6abe242a88df.file @@ -0,0 +1,1167 @@ +/* + * Copyright (C) 2006 - 2008 Murray Cumming + * Copyright (C) 2006 - 2014 Vivien Malerba + * Copyright (C) 2007 Leonardo Boshell + * Copyright (C) 2010 David King + * Copyright (C) 2015 Corentin Noël + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +#define G_LOG_DOMAIN "GDA-data-model-iter" + +#include +#include +#include "gda-data-model-iter.h" +#include "gda-data-model-iter-extra.h" +#include "gda-data-model.h" +#include "gda-data-model-private.h" +#include "gda-holder.h" +#include "gda-marshal.h" +#include "gda-data-proxy.h" +#include "gda-enums.h" +#include "gda-data-select.h" + +/* private structure */ +typedef struct +{ + GWeakRef data_model; /* may be %NULL because there is only a weak ref on it */ + gulong model_changes_signals[3]; + gboolean keep_param_changes; + gint row; /* -1 if row is unknown */ +} GdaDataModelIterPrivate; + +G_DEFINE_TYPE_WITH_PRIVATE(GdaDataModelIter, gda_data_model_iter, GDA_TYPE_SET) + +/* + * Main static functions + */ +static void gda_data_model_iter_finalize (GObject *object); + +static void gda_data_model_iter_set_property (GObject *object, + guint param_id, + const GValue *value, + GParamSpec *pspec); +static void gda_data_model_iter_get_property (GObject *object, + guint param_id, + GValue *value, + GParamSpec *pspec); + +/* Virtual default methods*/ +static gboolean +real_gda_data_model_iter_move_to_row (GdaDataModelIter *iter, gint row); +static gboolean +real_gda_data_model_iter_move_prev (GdaDataModelIter *iter); + +gboolean +real_gda_data_model_iter_move_next (GdaDataModelIter *iter); + +/* follow model changes */ +static void model_row_updated_cb (GdaDataModel *model, gint row, GdaDataModelIter *iter); +static void model_row_removed_cb (GdaDataModel *model, gint row, GdaDataModelIter *iter); +static void model_reset_cb (GdaDataModel *model, GdaDataModelIter *iter); + +static GError *validate_holder_change_cb (GdaSet *paramlist, GdaHolder *param, const GValue *new_value); +static void holder_attr_changed_cb (GdaSet *paramlist, GdaHolder *param, const gchar *att_name, const GValue *att_value); + +/* signals */ +enum +{ + ROW_CHANGED, + END_OF_DATA, + LAST_SIGNAL +}; + +static gint gda_data_model_iter_signals[LAST_SIGNAL] = { 0, 0 }; + +/* properties */ +enum +{ + PROP_0, + PROP_DATA_MODEL, + PROP_CURRENT_ROW, + PROP_UPDATE_MODEL +}; + +/* module error */ +GQuark gda_data_model_iter_error_quark (void) +{ + static GQuark quark; + if (!quark) + quark = g_quark_from_static_string ("gda_data_model_iter_error"); + return quark; +} + +static void +gda_data_model_iter_class_init (GdaDataModelIterClass *class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (class); + GdaSetClass *paramlist_class = GDA_SET_CLASS (class); + /** + * GdaDataModelIter::row-changed: + * @iter: the #GdaDataModelIter + * @row: the new iter's row + * + * Gets emitted when the row @iter is currently pointing has changed + */ + gda_data_model_iter_signals [ROW_CHANGED] = + g_signal_new ("row-changed", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (GdaDataModelIterClass, row_changed), + NULL, NULL, + g_cclosure_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT); + /** + * GdaDataModelIter::end-of-data: + * @iter: the #GdaDataModelIter + * + * Gets emitted when @iter has reached the end of available data (which means the previous + * row it was on was the last one). + */ + gda_data_model_iter_signals [END_OF_DATA] = + g_signal_new ("end-of-data", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (GdaDataModelIterClass, end_of_data), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); + + class->move_to_row = real_gda_data_model_iter_move_to_row; + class->move_next = real_gda_data_model_iter_move_next; + class->move_prev = real_gda_data_model_iter_move_prev; + class->set_value_at = gda_data_model_iter_set_value_at; + class->row_changed = NULL; + class->end_of_data = NULL; + + object_class->finalize = gda_data_model_iter_finalize; + paramlist_class->validate_holder_change = validate_holder_change_cb; + paramlist_class->holder_attr_changed = holder_attr_changed_cb; + + /* Properties */ + object_class->set_property = gda_data_model_iter_set_property; + object_class->get_property = gda_data_model_iter_get_property; + g_object_class_install_property (object_class, PROP_DATA_MODEL, + g_param_spec_object ("data-model", NULL, "Data model for which the iter is for", + GDA_TYPE_DATA_MODEL, + (G_PARAM_READABLE | G_PARAM_WRITABLE | + G_PARAM_CONSTRUCT))); + g_object_class_install_property (object_class, PROP_CURRENT_ROW, + g_param_spec_int ("current-row", NULL, "Current represented row in the data model", + -1, G_MAXINT, -1, + (G_PARAM_READABLE | G_PARAM_WRITABLE))); + g_object_class_install_property (object_class, PROP_UPDATE_MODEL, + g_param_spec_boolean ("update-model", "Tells if parameters changes are forwarded " + "to the GdaDataModel", NULL, TRUE, + (G_PARAM_READABLE | G_PARAM_WRITABLE))); +} + +static void +gda_data_model_iter_init (GdaDataModelIter *iter) +{ + GdaDataModelIterPrivate *priv = gda_data_model_iter_get_instance_private (iter); + g_weak_ref_set (&priv->data_model, NULL); + priv->row = -1; + priv->model_changes_signals[0] = 0; + priv->model_changes_signals[1] = 0; + priv->model_changes_signals[2] = 0; + priv->keep_param_changes = FALSE; +} + +static void +model_row_updated_cb (GdaDataModel *model, gint row, GdaDataModelIter *iter) +{ + g_return_if_fail (model != NULL); + g_return_if_fail (GDA_IS_DATA_MODEL (model)); + g_return_if_fail (iter != NULL); + g_return_if_fail (GDA_IS_DATA_MODEL_ITER (iter)); + + GdaDataModelIterPrivate *priv = gda_data_model_iter_get_instance_private (iter); + + GdaDataModel *obj = g_weak_ref_get (&priv->data_model); + if (obj == NULL) { + g_warning (_("Iter has an invalid/non-existent reference to a data model")); + return; + } + if (model != obj) { + g_warning (_("Referenced data model in iterator doesn't belong to given data model")); + g_object_unref (obj); + return; + } + g_object_unref (obj); + /* sync parameters with the new values in row */ + if (priv->row == row) { + priv->keep_param_changes = TRUE; + gda_data_model_iter_move_to_row (iter, row); + priv->keep_param_changes = FALSE; + } +} + +static void +model_row_removed_cb (G_GNUC_UNUSED GdaDataModel *model, gint row, GdaDataModelIter *iter) +{ + g_return_if_fail (model != NULL); + g_return_if_fail (GDA_IS_DATA_MODEL (model)); + g_return_if_fail (iter != NULL); + g_return_if_fail (GDA_IS_DATA_MODEL_ITER (iter)); + + GdaDataModelIterPrivate *priv = gda_data_model_iter_get_instance_private (iter); + + if (priv->row < 0) + /* we are not concerned by handling this signal */ + return; + + /* if removed row is the one corresponding to iter, + * then make all the parameters invalid */ + if (priv->row == row) { + gda_data_model_iter_invalidate_contents (iter); + gda_data_model_iter_move_to_row (iter, -1); + } + else { + /* shift iter's row by one to keep good numbers */ + if (priv->row > row) + priv->row--; + } +} + +static void +define_holder_for_data_model_column (GdaDataModel *model, gint col, GdaDataModelIter *iter) +{ + g_return_if_fail (model != NULL); + g_return_if_fail (GDA_IS_DATA_MODEL (model)); + g_return_if_fail (iter != NULL); + g_return_if_fail (GDA_IS_DATA_MODEL_ITER (iter)); + + gchar *str; + GdaHolder *param; + GdaColumn *column; + + column = gda_data_model_describe_column (model, col); + param = (GdaHolder *) g_object_new (GDA_TYPE_HOLDER, + "g-type", + gda_column_get_g_type (column), NULL); + + /*g_print ("COL %d allow null=%d\n", col, gda_column_get_allow_null (column));*/ + gda_holder_set_not_null (param, !gda_column_get_allow_null (column)); + g_object_get (G_OBJECT (column), "id", &str, NULL); + if (str) { + g_object_set (G_OBJECT (param), "id", str, NULL); + g_free (str); + } + else { + const gchar *cstr; + gchar *tmp; + + /* ID attribute */ + cstr = gda_column_get_description (column); + if (!cstr) + cstr = gda_column_get_name (column); + if (cstr) + tmp = (gchar *) cstr; + else + tmp = g_strdup_printf ("col%d", col); + + if (gda_set_get_holder ((GdaSet *) iter, tmp)) { + gint e; + for (e = 1; ; e++) { + gchar *tmp2 = g_strdup_printf ("%s_%d", tmp, e); + if (! gda_set_get_holder ((GdaSet *) iter, tmp2)) { + g_object_set (G_OBJECT (param), "id", tmp2, NULL); + g_free (tmp2); + break; + } + g_free (tmp2); + } + } + else + g_object_set (G_OBJECT (param), "id", tmp, NULL); + + if (!cstr) + g_free (tmp); + + /* other attributes */ + cstr = gda_column_get_description (column); + if (cstr) + g_object_set (G_OBJECT (param), "description", cstr, NULL); + cstr = gda_column_get_name (column); + if (cstr) + g_object_set (G_OBJECT (param), "name", cstr, NULL); + } + if (gda_column_get_default_value (column)) + gda_holder_set_default_value (param, gda_column_get_default_value (column)); + else if (gda_column_get_auto_increment (column)) { + GValue *v = gda_value_new_null (); + gda_holder_set_default_value (param, v); + gda_value_free (v); + } + gda_set_add_holder ((GdaSet *) iter, param); + g_object_set_data (G_OBJECT (param), "model_col", GINT_TO_POINTER (col + 1)); + g_object_unref (param); +} + +static void +model_reset_cb (GdaDataModel *model, GdaDataModelIter *iter) +{ + g_return_if_fail (model != NULL); + g_return_if_fail (GDA_IS_DATA_MODEL (model)); + g_return_if_fail (iter != NULL); + g_return_if_fail (GDA_IS_DATA_MODEL_ITER (iter)); + + gint row; + + row = gda_data_model_iter_get_row (iter); + + /* adjust GdaHolder's type if a column's type has changed from GDA_TYPE_NULL + * to something else */ + gint i, nbcols; + GSList *list; + nbcols = gda_data_model_get_n_columns (model); + if (GDA_IS_DATA_PROXY (model)) + nbcols = nbcols / 2; + + for (i = 0, list = gda_set_get_holders (((GdaSet*) iter)); + (i < nbcols) && list; + i++, list = list->next) { + GdaColumn *col; + col = gda_data_model_describe_column (model, i); + + if (gda_holder_get_g_type ((GdaHolder *) list->data) == GDA_TYPE_NULL) { + if (gda_column_get_g_type (col) != GDA_TYPE_NULL) + g_object_set (G_OBJECT (list->data), "g-type", + gda_column_get_g_type (col), NULL); + } + else if (gda_holder_get_g_type ((GdaHolder *) list->data) != + gda_column_get_g_type (col)) + break; + } + + if (list) { + /* remove remaining GdaHolder objects */ + GSList *l2; + l2 = g_slist_copy (list); + for (list = l2; list; list = list->next) + gda_set_remove_holder ((GdaSet*) iter, (GdaHolder *) list->data); + g_slist_free (l2); + row = -1; /* force actual reset of iterator's position */ + } + + if (i < nbcols) { + for (; i < nbcols; i++) + define_holder_for_data_model_column (model, i, iter); + row = -1; /* force actual reset of iterator's position */ + } + + gda_data_model_iter_invalidate_contents (iter); + if (row >= 0) + gda_data_model_iter_move_to_row (iter, row); + else + /* reset the iter to before the 1st row */ + gda_data_model_iter_move_to_row (iter, -1); +} + +/* + * This function is called when a parameter in @paramlist is changed + * to make sure the change is propagated to the GdaDataModel + * paramlist is an iter for, return an error if the data model could not be modified + */ +static GError * +validate_holder_change_cb (GdaSet *paramlist, GdaHolder *param, const GValue *new_value) +{ + g_return_val_if_fail (paramlist != NULL, NULL); + g_return_val_if_fail (GDA_IS_DATA_MODEL_ITER (paramlist), NULL); + + GdaDataModelIter *iter; + gint col; + GError *error = NULL; + GValue *nvalue; + + iter = GDA_DATA_MODEL_ITER (paramlist); + + GdaDataModelIterPrivate *priv = gda_data_model_iter_get_instance_private (iter); + GdaDataModel *model = g_weak_ref_get (&priv->data_model); + + if (model == NULL) { + g_set_error (&error, GDA_DATA_MODEL_ERROR, GDA_DATA_MODEL_INVALID, + _("Invalid data model. Can't validate holder")); + return error; + } + + if (new_value) + nvalue = (GValue*) new_value; + else + nvalue = gda_value_new_null(); + + iter = (GdaDataModelIter *) paramlist; + if (!priv->keep_param_changes && (priv->row >= 0) && (GDA_IS_DATA_MODEL (model))) { + g_signal_handler_block (model, priv->model_changes_signals [0]); + g_signal_handler_block (model, priv->model_changes_signals [1]); + + /* propagate the value update to the data model */ + col = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (param), "model_col")) - 1; + if (col < 0) { + g_set_error (&error, GDA_DATA_MODEL_ERROR, GDA_DATA_MODEL_COLUMN_OUT_OF_RANGE_ERROR, + _("Column %d out of range (0-%d)"), col, g_slist_length (gda_set_get_holders (paramlist)) - 1); + } + else if (GDA_DATA_MODEL_ITER_GET_CLASS (iter)->set_value_at) { + (GDA_DATA_MODEL_ITER_GET_CLASS (iter)->set_value_at) + (iter, col, nvalue, &error); + } + else { + g_print ("using Data Model default set_value_at\n"); + gda_data_model_set_value_at (model, col, priv->row, nvalue, &error); + } + + g_signal_handler_unblock (model, priv->model_changes_signals [0]); + g_signal_handler_unblock (model, priv->model_changes_signals [1]); + } + if (!new_value) + gda_value_free (nvalue); + + if (!error && GDA_SET_CLASS(gda_data_model_iter_parent_class)->validate_holder_change) { + g_object_unref (model); + /* for the parent class */ + return (GDA_SET_CLASS(gda_data_model_iter_parent_class))->validate_holder_change (paramlist, param, new_value); + } + + g_object_unref (model); + + return error; +} + +/* + * This function is called when a parameter in @paramlist has its attributes changed + * to make sure the change is propagated to the GdaDataModel + * paramlist is an iter for + */ +static void +holder_attr_changed_cb (GdaSet *paramlist, GdaHolder *param, const gchar *att_name, const GValue *att_value) +{ + g_return_if_fail (paramlist != NULL); + g_return_if_fail (GDA_IS_DATA_MODEL_ITER (paramlist)); + + GdaDataModelIter *iter; + gint col; + gboolean toset = FALSE; + + iter = GDA_DATA_MODEL_ITER (paramlist); + + GdaDataModelIterPrivate *priv = gda_data_model_iter_get_instance_private (iter); + + GdaDataModel *model = g_weak_ref_get (&priv->data_model); + + if (model == NULL) { + return; + } + + if (!GDA_IS_DATA_PROXY (model)) { + g_object_unref (model); + return; + } + + if (!strcmp (att_name, GDA_ATTRIBUTE_IS_DEFAULT) && + !priv->keep_param_changes && (priv->row >= 0)) { + g_signal_handler_block (model, priv->model_changes_signals [0]); + g_signal_handler_block (model, priv->model_changes_signals [1]); + + /* propagate the value update to the data model */ + col = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (param), "model_col")) - 1; + g_return_if_fail (col >= 0); + + if (att_value && g_value_get_boolean (att_value)) + toset = TRUE; + if (toset && gda_holder_get_default_value (param)) + gda_data_proxy_alter_value_attributes (GDA_DATA_PROXY (model), + priv->row, col, + GDA_VALUE_ATTR_CAN_BE_DEFAULT | GDA_VALUE_ATTR_IS_DEFAULT); + + g_signal_handler_unblock (model, priv->model_changes_signals [0]); + g_signal_handler_unblock (model, priv->model_changes_signals [1]); + } + + /* for the parent class */ + if ((GDA_SET_CLASS(gda_data_model_iter_parent_class))->holder_attr_changed) + (GDA_SET_CLASS(gda_data_model_iter_parent_class))->holder_attr_changed (paramlist, param, att_name, att_value); + + g_object_unref (model); +} + +static void +gda_data_model_iter_finalize (GObject *object) +{ + GdaDataModelIter *iter; + + g_return_if_fail (object != NULL); + g_return_if_fail (GDA_IS_DATA_MODEL_ITER (object)); + + iter = GDA_DATA_MODEL_ITER (object); + GdaDataModelIterPrivate *priv = gda_data_model_iter_get_instance_private (iter); + GdaDataModel *model = g_weak_ref_get (&priv->data_model); + if (model != NULL) { + g_signal_handler_disconnect (model, priv->model_changes_signals [0]); + g_signal_handler_disconnect (model, priv->model_changes_signals [1]); + g_signal_handler_disconnect (model, priv->model_changes_signals [2]); + g_object_unref (model); + } + + /* parent class */ + G_OBJECT_CLASS(gda_data_model_iter_parent_class)->finalize (object); +} + +static void +gda_data_model_iter_set_property (GObject *object, + guint param_id, + const GValue *value, + GParamSpec *pspec) +{ + GdaDataModelIter *iter; + iter = GDA_DATA_MODEL_ITER (object); + GdaDataModelIterPrivate *priv = gda_data_model_iter_get_instance_private (iter); + + if (priv) { + switch (param_id) { + case PROP_DATA_MODEL: { + GdaDataModel *model; + + GObject* ptr = g_value_dup_object (value); + if (!GDA_IS_DATA_MODEL (ptr)) { + g_object_unref (ptr); + g_warning (_("Invalid data model object. Can't set property")); + return; + } + model = GDA_DATA_MODEL (ptr); + GdaDataModel *current = g_weak_ref_get (&priv->data_model); + if (current != NULL) { + if (current == model) + return; + g_signal_handler_disconnect (current, + priv->model_changes_signals [0]); + g_signal_handler_disconnect (current, + priv->model_changes_signals [1]); + g_signal_handler_disconnect (current, + priv->model_changes_signals [2]); + } + + g_weak_ref_set (&priv->data_model, model); + + priv->model_changes_signals [0] = g_signal_connect (G_OBJECT (model), "row-updated", + G_CALLBACK (model_row_updated_cb), + iter); + priv->model_changes_signals [1] = g_signal_connect (G_OBJECT (model), "row-removed", + G_CALLBACK (model_row_removed_cb), + iter); + priv->model_changes_signals [2] = g_signal_connect (G_OBJECT (model), "reset", + G_CALLBACK (model_reset_cb), iter); + model_reset_cb (GDA_DATA_MODEL (ptr), iter); + g_object_unref (ptr); + break; + } + case PROP_CURRENT_ROW: + if (priv->row != g_value_get_int (value)) { + priv->row = g_value_get_int (value); + g_signal_emit (G_OBJECT (iter), + gda_data_model_iter_signals[ROW_CHANGED], + 0, priv->row); + } + break; + case PROP_UPDATE_MODEL: + priv->keep_param_changes = ! g_value_get_boolean (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + break; + } + } +} + +static void +gda_data_model_iter_get_property (GObject *object, + guint param_id, + GValue *value, + GParamSpec *pspec) +{ + GdaDataModelIter *iter = GDA_DATA_MODEL_ITER (object); + GdaDataModelIterPrivate *priv = gda_data_model_iter_get_instance_private (iter); + + if (priv) { + switch (param_id) { + case PROP_DATA_MODEL: + { + GObject *obj = g_weak_ref_get (&priv->data_model); + if (obj != NULL) { + g_value_take_object (value, obj); + } + } + break; + case PROP_CURRENT_ROW: + g_value_set_int (value, priv->row); + break; + case PROP_UPDATE_MODEL: + g_value_set_boolean (value, ! priv->keep_param_changes); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + break; + } + } +} + +/** + * gda_data_model_iter_move_to_row: (virtual move_to_row) + * @iter: a #GdaDataModelIter object + * @row: the row to set @iter to + * + * Synchronizes the values of the parameters in @iter with the values at the @row row. + * + * If @row is not a valid row, then the returned value is %FALSE, and the "current-row" + * property is set to -1 (which means that gda_data_model_iter_is_valid() would return %FALSE), + * with the exception that if @row is -1, then the returned value is %TRUE. + * + * This function can return %FALSE if it was not allowed to be moved (as it emits the + * "validate-set" signal before being moved). + * + * When this function returns %TRUE, then @iter has actually been moved to the next row, + * but some values may not have been read correctly in the row, in which case the + * correcsponding #GdaHolder will be left invalid. + * + * Returns: %TRUE if no error occurred + */ +gboolean +gda_data_model_iter_move_to_row (GdaDataModelIter *iter, gint row) +{ + g_return_val_if_fail (GDA_IS_DATA_MODEL_ITER (iter), FALSE); + + GdaDataModelIterPrivate *priv = gda_data_model_iter_get_instance_private (iter); + + GdaDataModelIterClass *klass = GDA_DATA_MODEL_ITER_GET_CLASS(iter); + if (klass->move_to_row) { + if (klass->move_to_row (iter, row)) { + g_signal_emit (G_OBJECT (iter), + gda_data_model_iter_signals[ROW_CHANGED], + 0, priv->row); + return TRUE; + } + } + return FALSE; +} +static gboolean +real_gda_data_model_iter_move_to_row (GdaDataModelIter *iter, gint row) +{ + g_return_val_if_fail (GDA_IS_DATA_MODEL_ITER (iter), FALSE); + + GdaDataModelIterPrivate *priv = gda_data_model_iter_get_instance_private (iter); + GdaDataModel *model = g_weak_ref_get (&priv->data_model); + gboolean ret = FALSE; + + ret = gda_data_model_iter_move_to_row_default (model, iter, row); + if (model != NULL) { + g_object_unref (model); + } + return ret; +} + +static void +set_param_attributes (GdaHolder *holder, GdaValueAttribute flags) +{ + if (flags & GDA_VALUE_ATTR_IS_DEFAULT) + gda_holder_set_value_to_default (holder); + + if (flags & GDA_VALUE_ATTR_IS_NULL) + gda_holder_set_value (holder, NULL, NULL); + if (flags & GDA_VALUE_ATTR_DATA_NON_VALID) + gda_holder_force_invalid (holder); +} + +/** + * gda_data_model_iter_move_to_row_default: + * @model: a #GdaDataModel + * @iter: a #GdaDataModelIter iterating in @model + * @row: the requested row + * + * Method reserved to #GdaDataModelIter implementations, should not be called directly. + * + * Returns: %TRUE if @iter was moved correctly. + */ +gboolean +gda_data_model_iter_move_to_row_default (GdaDataModel *model, GdaDataModelIter *iter, gint row) +{ + /* default method */ + GSList *list; + gint col; + GdaDataModel *test; + gboolean update_model; + + if ((gda_data_model_iter_get_row (iter) >= 0) && + ! _gda_set_validate ((GdaSet*) iter, NULL)) + return FALSE; + + if (! (gda_data_model_get_access_flags (model) & GDA_DATA_MODEL_ACCESS_RANDOM)) + return FALSE; + + /* validity tests */ + if ((row < 0) || (row >= gda_data_model_get_n_rows (model))) { + gda_data_model_iter_invalidate_contents (iter); + g_object_set (G_OBJECT (iter), "current-row", -1, NULL); + return FALSE; + } + + g_return_val_if_fail (GDA_IS_DATA_MODEL_ITER (iter), FALSE); + + g_object_get (G_OBJECT (iter), "data-model", &test, NULL); + g_return_val_if_fail (test == model, FALSE); + g_object_unref (test); + + /* actual sync. */ + g_object_get (G_OBJECT (iter), "update-model", &update_model, NULL); + g_object_set (G_OBJECT (iter), "update-model", FALSE, NULL); + for (col = 0, list = gda_set_get_holders ((GdaSet *) iter); list; col++, list = list->next) { + const GValue *cvalue; + GError *lerror = NULL; + cvalue = gda_data_model_get_value_at (model, col, row, &lerror); + if (!cvalue || + !gda_holder_set_value ((GdaHolder*) list->data, cvalue, &lerror)) + gda_holder_force_invalid_e ((GdaHolder*) list->data, lerror); + else + set_param_attributes ((GdaHolder*) list->data, + gda_data_model_get_attributes_at (model, col, row)); + } + g_object_set (G_OBJECT (iter), "current-row", row, "update-model", update_model, NULL); + return TRUE; +} + + +/** + * gda_data_model_iter_move_next: (virtual move_next) + * @iter: a #GdaDataModelIter object + * + * Moves @iter one row further than where it already is + * (synchronizes the values of the parameters in @iter with the values at the new row). + * + * If the iterator was on the data model's last row, then it can't be moved forward + * anymore, and the returned value is %FALSE; note also that the "current-row" property + * is set to -1 (which means that gda_data_model_iter_is_valid() would return %FALSE) + * + * This function can return %FALSE if it was not allowed to be moved (as it emits the + * "validate-set" signal before being moved). + * + * When this function returns %TRUE, then @iter has actually been moved to the next row, + * but some values may not have been read correctly in the row, in which case the + * correcsponding #GdaHolder will be left invalid. + * + * Returns: %TRUE if the iterator is now at the next row + */ +gboolean +gda_data_model_iter_move_next (GdaDataModelIter *iter) +{ + g_return_val_if_fail (GDA_IS_DATA_MODEL_ITER (iter), FALSE); + + if ((gda_data_model_iter_get_row (iter) >= 0) && + ! _gda_set_validate ((GdaSet*) iter, NULL)) + return FALSE; + + GdaDataModelIterClass *klass = GDA_DATA_MODEL_ITER_GET_CLASS (iter); + if (klass->move_next) { + return klass->move_next (iter); + } + return FALSE; +} +gboolean +real_gda_data_model_iter_move_next (GdaDataModelIter *iter) +{ + GdaDataModel *model; + g_return_val_if_fail (GDA_IS_DATA_MODEL_ITER (iter), FALSE); + + GdaDataModelIterPrivate *priv = gda_data_model_iter_get_instance_private (iter); + gboolean ret = FALSE; + + model = g_weak_ref_get (&priv->data_model); + + ret = gda_data_model_iter_move_next_default (model, iter); + if (model != NULL) { + g_object_unref (model); + } + return ret; +} + +/** + * gda_data_model_iter_move_next_default: + * @model: a #GdaDataModel + * @iter: a #GdaDataModelIter iterating in @model + * + * Method reserved to #GdaDataModelIter implementations, should not be called directly. + * + * Returns: %TRUE if @iter was moved correctly. + */ +gboolean +gda_data_model_iter_move_next_default (GdaDataModel *model, GdaDataModelIter *iter) +{ + GSList *list; + gint col; + gint row; + GdaDataModel *test; + gboolean update_model; + + if ((gda_data_model_iter_get_row (iter) >= 0) && + ! _gda_set_validate ((GdaSet*) iter, NULL)) + return FALSE; + + if (! (gda_data_model_get_access_flags (model) & GDA_DATA_MODEL_ACCESS_RANDOM)) + return FALSE; + + g_return_val_if_fail (GDA_IS_DATA_MODEL_ITER (iter), FALSE); + + g_object_get (G_OBJECT (iter), "data-model", &test, NULL); + g_return_val_if_fail (test == model, FALSE); + g_object_unref (test); + + g_object_get (G_OBJECT (iter), "current-row", &row, NULL); + row++; + if (row >= gda_data_model_get_n_rows (model)) { + gda_data_model_iter_invalidate_contents (iter); + g_object_set (G_OBJECT (iter), "current-row", -1, NULL); + return FALSE; + } + + /* actual sync. */ + g_object_get (G_OBJECT (iter), "update-model", &update_model, NULL); + g_object_set (G_OBJECT (iter), "update-model", FALSE, NULL); + for (col = 0, list = gda_set_get_holders ((GdaSet *) iter); list; col++, list = list->next) { + const GValue *cvalue; + GError *lerror = NULL; + cvalue = gda_data_model_get_value_at (model, col, row, &lerror); + if (!cvalue || + !gda_holder_set_value ((GdaHolder *) list->data, cvalue, &lerror)) + gda_holder_force_invalid_e ((GdaHolder *) list->data, lerror); + else + set_param_attributes ((GdaHolder *) list->data, + gda_data_model_get_attributes_at (model, col, row)); + } + g_object_set (G_OBJECT (iter), "current-row", row, + "update-model", update_model, NULL); + return TRUE; +} + +/** + * gda_data_model_iter_move_prev: (virtual move_prev) + * @iter: a #GdaDataModelIter object + * + * Moves @iter one row before where it already is (synchronizes the values of the parameters in @iter + * with the values at the new row). + * + * If the iterator was on the data model's first row, then it can't be moved backwards + * anymore, and the returned value is %FALSE; note also that the "current-row" property + * is set to -1 (which means that gda_data_model_iter_is_valid() would return %FALSE). + * + * This function can return %FALSE if it was not allowed to be moved (as it emits the + * "validate-set" signal before being moved). + * + * When this function returns %TRUE, then @iter has actually been moved to the next row, + * but some values may not have been read correctly in the row, in which case the + * correcsponding #GdaHolder will be left invalid. + * + * Returns: %TRUE if the iterator is now at the previous row + */ +gboolean +gda_data_model_iter_move_prev (GdaDataModelIter *iter) +{ + g_return_val_if_fail (GDA_IS_DATA_MODEL_ITER (iter), FALSE); + + GdaDataModelIterClass *klass = GDA_DATA_MODEL_ITER_GET_CLASS (iter); + if (klass->move_prev) { + return klass->move_prev (iter); + } + return FALSE; +} +static gboolean +real_gda_data_model_iter_move_prev (GdaDataModelIter *iter) +{ + GdaDataModel *model; + + g_return_val_if_fail (GDA_IS_DATA_MODEL_ITER (iter), FALSE); + + GdaDataModelIterPrivate *priv = gda_data_model_iter_get_instance_private (iter); + gboolean ret = FALSE; + + model = g_weak_ref_get (&priv->data_model); + /* default method */ + ret = gda_data_model_iter_move_prev_default (model, iter); + if (model != NULL) { + g_object_unref (model); + } + return ret; +} + +/** + * gda_data_model_iter_move_prev_default: + * @model: a #GdaDataModel + * @iter: a #GdaDataModelIter iterating in @model + * + * Method reserved to #GdaDataModelIter implementations, should not be called directly. + * + * Returns: %TRUE if @iter was moved correctly. + */ +gboolean +gda_data_model_iter_move_prev_default (GdaDataModel *model, GdaDataModelIter *iter) +{ + GSList *list; + gint col; + gint row; + GdaDataModel *test; + gboolean update_model; + + if ((gda_data_model_iter_get_row (iter) >= 0) && + ! _gda_set_validate ((GdaSet*) iter, NULL)) + return FALSE; + + if (! (gda_data_model_get_access_flags (model) & GDA_DATA_MODEL_ACCESS_RANDOM)) + return FALSE; + + g_return_val_if_fail (GDA_IS_DATA_MODEL_ITER (iter), FALSE); + + g_object_get (G_OBJECT (iter), "data-model", &test, NULL); + g_return_val_if_fail (test == model, FALSE); + g_object_unref (test); + + g_object_get (G_OBJECT (iter), "current-row", &row, NULL); + row--; + if (row < 0) { + gda_data_model_iter_invalidate_contents (iter); + g_object_set (G_OBJECT (iter), "current-row", -1, NULL); + return FALSE; + } + + /* actual sync. */ + g_object_get (G_OBJECT (iter), "update-model", &update_model, NULL); + g_object_set (G_OBJECT (iter), "update-model", FALSE, NULL); + for (col = 0, list = gda_set_get_holders ((GdaSet *) iter); list; col++, list = list->next) { + const GValue *cvalue; + GError *lerror = NULL; + cvalue = gda_data_model_get_value_at (model, col, row, &lerror); + if (!cvalue || + !gda_holder_set_value ((GdaHolder*) list->data, cvalue, &lerror)) + gda_holder_force_invalid_e ((GdaHolder*) list->data, lerror); + else + set_param_attributes ((GdaHolder*) list->data, + gda_data_model_get_attributes_at (model, col, row)); + } + g_object_set (G_OBJECT (iter), "current-row", row, + "update-model", update_model, NULL); + return TRUE; +} + + +/** + * gda_data_model_iter_get_row: + * @iter: a #GdaDataModelIter object + * + * Get the row which @iter represents in the data model + * + * Returns: the row number, or -1 if @iter is invalid + */ +gint +gda_data_model_iter_get_row (GdaDataModelIter *iter) +{ + g_return_val_if_fail (GDA_IS_DATA_MODEL_ITER (iter), -1); + + GdaDataModelIterPrivate *priv = gda_data_model_iter_get_instance_private (iter); + + g_return_val_if_fail (priv, -1); + + return priv->row; +} + +/** + * gda_data_model_iter_invalidate_contents: + * @iter: a #GdaDataModelIter object + * + * Declare all the parameters in @iter invalid, without modifying the + * #GdaDataModel @iter is for or changing the row it represents. This method + * is for internal usage. Note that for gda_data_model_iter_is_valid() to return %FALSE, + * it is also necessary to set the "current-row" property to -1. + */ +void +gda_data_model_iter_invalidate_contents (GdaDataModelIter *iter) +{ + GSList *list; + g_return_if_fail (GDA_IS_DATA_MODEL_ITER (iter)); + + GdaDataModelIterPrivate *priv = gda_data_model_iter_get_instance_private (iter); + + g_return_if_fail (priv); + + priv->keep_param_changes = TRUE; + for (list = gda_set_get_holders (GDA_SET (iter)); list; list = list->next) + gda_holder_force_invalid (GDA_HOLDER (list->data)); + priv->keep_param_changes = FALSE; +} + +/** + * gda_data_model_iter_is_valid: + * @iter: a #GdaDataModelIter object + * + * Tells if @iter is a valid iterator (if it actually corresponds to a valid row in the model) + * + * Returns: TRUE if @iter is valid + */ +gboolean +gda_data_model_iter_is_valid (GdaDataModelIter *iter) +{ + g_return_val_if_fail (GDA_IS_DATA_MODEL_ITER (iter), FALSE); + + GdaDataModelIterPrivate *priv = gda_data_model_iter_get_instance_private (iter); + + g_return_val_if_fail (priv, FALSE); + + return priv->row >= 0 ? TRUE : FALSE; +} + +/** + * gda_data_model_iter_get_holder_for_field: + * @iter: a #GdaDataModelIter object + * @col: the requested column + * + * Fetch a pointer to the #GdaHolder object which is synchronized with data at + * column @col + * + * Returns: (transfer none): the #GdaHolder, or %NULL if an error occurred + */ +GdaHolder * +gda_data_model_iter_get_holder_for_field (GdaDataModelIter *iter, gint col) +{ + g_return_val_if_fail (GDA_IS_DATA_MODEL_ITER (iter), NULL); + + GdaDataModelIterPrivate *priv = gda_data_model_iter_get_instance_private (iter); + + g_return_val_if_fail (priv, NULL); + + return gda_set_get_nth_holder ((GdaSet *) iter, col); +} + +/** + * gda_data_model_iter_get_value_at: + * @iter: a #GdaDataModelIter object + * @col: the requested column + * + * Get the value stored at the column @col in @iter. The returned value must not be modified. + * + * Returns: (nullable) (transfer none): the #GValue, or %NULL if the value could not be fetched + */ +const GValue * +gda_data_model_iter_get_value_at (GdaDataModelIter *iter, gint col) +{ + GdaHolder *param; + GdaDataModelIterPrivate *priv = gda_data_model_iter_get_instance_private (iter); + + g_return_val_if_fail (GDA_IS_DATA_MODEL_ITER (iter), NULL); + g_return_val_if_fail (priv, NULL); + + param = (GdaHolder *) g_slist_nth_data (gda_set_get_holders ((GdaSet *) iter), col); + if (param) { + if (gda_holder_is_valid (param)) + return gda_holder_get_value (param); + else + return NULL; + } + else + return NULL; +} + +/** + * gda_data_model_iter_get_value_at_e: + * @iter: a #GdaDataModelIter object + * @col: the requested column + * @error: (nullable): a place to store errors, or %NULL + * + * Get the value stored at the column @col in @iter. The returned value must not be modified. + * + * Returns: (nullable) (transfer none): the #GValue, or %NULL if the value could not be fetched + * + * Since: 4.2.10 + */ +const GValue * +gda_data_model_iter_get_value_at_e (GdaDataModelIter *iter, gint col, GError **error) +{ + GdaHolder *param; + GdaDataModelIterPrivate *priv = gda_data_model_iter_get_instance_private (iter); + + g_return_val_if_fail (GDA_IS_DATA_MODEL_ITER (iter), NULL); + g_return_val_if_fail (priv, NULL); + + param = (GdaHolder *) g_slist_nth_data (gda_set_get_holders ((GdaSet *) iter), col); + if (param) { + if (gda_holder_is_valid_e (param, error)) + return gda_holder_get_value (param); + else + return NULL; + } + else + return NULL; +} + +/** + * gda_data_model_iter_set_value_at: (virtual set_value_at) + * @iter: a #GdaDataModelIter object + * @col: the column number + * @value: a #GValue (not %NULL) + * @error: a place to store errors, or %NULL + * + * Sets a value in @iter, at the column specified by @col + * + * Returns: TRUE if no error occurred + */ +gboolean +gda_data_model_iter_set_value_at (GdaDataModelIter *iter, gint col, const GValue *value, GError **error) +{ + GdaHolder *holder; + + g_return_val_if_fail (GDA_IS_DATA_MODEL_ITER (iter), FALSE); + g_return_val_if_fail (value, FALSE); + + holder = gda_data_model_iter_get_holder_for_field (iter, col); + if (!holder) { + g_set_error (error, GDA_DATA_MODEL_ITER_ERROR, GDA_DATA_MODEL_ITER_COLUMN_OUT_OF_RANGE_ERROR, + _("Column %d out of range (0-%d)"), col, + g_slist_length (gda_set_get_holders ((GdaSet *) iter)) - 1); + return FALSE; + } + return gda_holder_set_value (holder, value, error); +} + +/** + * gda_data_model_iter_get_value_for_field: + * @iter: a #GdaDataModelIter object + * @field_name: the requested column name + * + * Get the value stored at the column @field_name in @iter + * + * Returns: (nullable) (transfer none): the #GValue, or %NULL + */ +const GValue * +gda_data_model_iter_get_value_for_field (GdaDataModelIter *iter, const gchar *field_name) +{ + GdaHolder *param; + GdaDataModelIterPrivate *priv = gda_data_model_iter_get_instance_private (iter); + + g_return_val_if_fail (GDA_IS_DATA_MODEL_ITER (iter), NULL); + g_return_val_if_fail (priv, NULL); + + param = gda_set_get_holder ((GdaSet *) iter, field_name); + if (param) { + if (gda_holder_is_valid (param)) + return gda_holder_get_value (param); + else + return NULL; + } + else + return NULL; +} diff --git a/.flatpak-builder/cache/objects/68/33e4b2cd9010d76192b0fec327af00ce76d374982aae7e2656fa062da0d92a.file b/.flatpak-builder/cache/objects/68/33e4b2cd9010d76192b0fec327af00ce76d374982aae7e2656fa062da0d92a.file new file mode 100644 index 0000000..ccda484 --- /dev/null +++ b/.flatpak-builder/cache/objects/68/33e4b2cd9010d76192b0fec327af00ce76d374982aae7e2656fa062da0d92a.file @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2008 Murray Cumming + * Copyright (C) 2008 - 2011 Vivien Malerba + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + + +#ifndef __GDA_DATA_COMPARATOR_H_ +#define __GDA_DATA_COMPARATOR_H_ + +#include "gda-decl.h" +#include + +G_BEGIN_DECLS + +#define GDA_TYPE_DATA_COMPARATOR (gda_data_comparator_get_type()) + +G_DECLARE_DERIVABLE_TYPE(GdaDataComparator, gda_data_comparator, GDA, DATA_COMPARATOR, GObject) + +/* error reporting */ +extern GQuark gda_data_comparator_error_quark (void); +#define GDA_DATA_COMPARATOR_ERROR gda_data_comparator_error_quark () + +typedef enum { + GDA_DATA_COMPARATOR_MISSING_DATA_MODEL_ERROR, + GDA_DATA_COMPARATOR_COLUMN_TYPES_MISMATCH_ERROR, + GDA_DATA_COMPARATOR_MODEL_ACCESS_ERROR, + GDA_DATA_COMPARATOR_USER_CANCELLED_ERROR +} GdaDataComparatorError; + +/* differences reporting */ +typedef enum { + GDA_DIFF_ADD_ROW, + GDA_DIFF_REMOVE_ROW, + GDA_DIFF_MODIFY_ROW +} GdaDiffType; + +typedef struct { + GdaDiffType type; + gint old_row; + gint new_row; + GHashTable *values; /* key = ('+' or '-') and a column position starting at 0 (string) + * value = a GValue pointer */ +} GdaDiff; + +#define GDA_TYPE_DIFF (gda_diff_get_type ()) + +/* struct for the object's class */ +struct _GdaDataComparatorClass +{ + GObjectClass parent_class; + gboolean (* diff_computed) (GdaDataComparator *comp, GdaDiff *diff); + + /*< private >*/ + /* Padding for future expansion */ + void (*_gda_reserved1) (void); + void (*_gda_reserved2) (void); + void (*_gda_reserved3) (void); + void (*_gda_reserved4) (void); +}; + +/** + * SECTION:gda-data-comparator + * @short_description: Simple data model's contents comparison + * @title: GdaDataComparator + * @stability: Stable + * @see_also: #GdaDataModel + * + * The #GdaDataComparator is a simple object which takes two #GdaDataModel objects and compare them. + * Actual comparison is performed when the gda_data_comparator_compute_diff() is called; for each + * difference found, the diff-computed signal + * is emitted (any user installed signal handler which returns FALSE stops the computing process). + * + * There are some limitations to this object: + * + * The data models compared must have the same number and type of columns + * The comparison is done column-for-column: one cannot omit columns in the comparison, nor compare + * columns with different positions + * + */ + + +GObject *gda_data_comparator_new (GdaDataModel *old_model, GdaDataModel *new_model); +void gda_data_comparator_set_key_columns (GdaDataComparator *comp, const gint *col_numbers, gint nb_cols); +gboolean gda_data_comparator_compute_diff (GdaDataComparator *comp, GError **error); +gint gda_data_comparator_get_n_diffs (GdaDataComparator *comp); +const GdaDiff *gda_data_comparator_get_diff (GdaDataComparator *comp, gint pos); + +GType gda_diff_get_type (void) G_GNUC_CONST; + +G_END_DECLS + +#endif diff --git a/.flatpak-builder/cache/objects/68/4bf70cc3ba533d3f9b12577cae4f75d6bb2af456673006ec69527900e4e79e.file b/.flatpak-builder/cache/objects/68/4bf70cc3ba533d3f9b12577cae4f75d6bb2af456673006ec69527900e4e79e.file new file mode 100755 index 0000000..8a9af0b --- /dev/null +++ b/.flatpak-builder/cache/objects/68/4bf70cc3ba533d3f9b12577cae4f75d6bb2af456673006ec69527900e4e79e.file @@ -0,0 +1,41 @@ +# libcanberra-gtk3.la - a libtool library file +# Generated by libtool (GNU libtool) 2.4.2 +# +# Please DO NOT delete this file! +# It is necessary for linking the library. + +# The name that we can dlopen(3). +dlname='libcanberra-gtk3.so.0' + +# Names of this library. +library_names='libcanberra-gtk3.so.0.1.9 libcanberra-gtk3.so.0 libcanberra-gtk3.so' + +# The name of the static archive. +old_library='' + +# Linker flags that can not go in dependency_libs. +inherited_linker_flags=' -pthread' + +# Libraries that this one depends upon. +dependency_libs=' -L/app/lib -lX11 -lgthread-2.0 -lgtk-3 -latk-1.0 -lgio-2.0 -lharfbuzz -lgdk-3 -lz -lpangocairo-1.0 -lpango-1.0 -lgdk_pixbuf-2.0 -lcairo-gobject -lcairo -lgobject-2.0 -lglib-2.0 /app/lib/libcanberra.la -lvorbisfile -lltdl -lm' + +# Names of additional weak libraries provided by this library +weak_library_names='' + +# Version information for libcanberra-gtk3. +current=1 +age=1 +revision=9 + +# Is this an already installed library? +installed=yes + +# Should we warn about portability when linking against -modules? +shouldnotlink=no + +# Files to dlopen/dlpreopen +dlopen='' +dlpreopen='' + +# Directory that this library needs to be installed in: +libdir='/app/lib' diff --git a/.flatpak-builder/cache/objects/68/4e36e2d4195a6b02da2d20cb367ef70964127ade8a734afd9888fadec8b682.dirtree b/.flatpak-builder/cache/objects/68/4e36e2d4195a6b02da2d20cb367ef70964127ade8a734afd9888fadec8b682.dirtree new file mode 100644 index 0000000..d91fb17 Binary files /dev/null and b/.flatpak-builder/cache/objects/68/4e36e2d4195a6b02da2d20cb367ef70964127ade8a734afd9888fadec8b682.dirtree differ diff --git a/.flatpak-builder/cache/objects/68/88cc04eaa8b5c2407041cb7da863baad31601188c395912f49eaa74364f9c8.dirtree b/.flatpak-builder/cache/objects/68/88cc04eaa8b5c2407041cb7da863baad31601188c395912f49eaa74364f9c8.dirtree new file mode 100644 index 0000000..fdc95c0 Binary files /dev/null and b/.flatpak-builder/cache/objects/68/88cc04eaa8b5c2407041cb7da863baad31601188c395912f49eaa74364f9c8.dirtree differ diff --git a/.flatpak-builder/cache/objects/68/a70d32d9c1cd9516daf7a089fe3fe80b67cd688b262b21eb02dbe7315cddc2.file b/.flatpak-builder/cache/objects/68/a70d32d9c1cd9516daf7a089fe3fe80b67cd688b262b21eb02dbe7315cddc2.file new file mode 100644 index 0000000..b44821a --- /dev/null +++ b/.flatpak-builder/cache/objects/68/a70d32d9c1cd9516daf7a089fe3fe80b67cd688b262b21eb02dbe7315cddc2.file @@ -0,0 +1,40 @@ +/*-*- Mode: C; c-basic-offset: 8 -*-*/ + +#ifndef foocanberrasoundthemespechfoo +#define foocanberrasoundthemespechfoo + +/*** + This file is part of libcanberra. + + Copyright 2008 Lennart Poettering + + libcanberra is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation, either version 2.1 of the + License, or (at your option) any later version. + + libcanberra is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with libcanberra. If not, see + . +***/ + +#include "read-sound-file.h" +#include "proplist.h" + +typedef struct ca_theme_data ca_theme_data; + +typedef int (*ca_sound_file_open_callback_t)(ca_sound_file **f, const char *fn); + +int ca_lookup_sound(ca_sound_file **f, char **sound_path, ca_theme_data **t, ca_proplist *cp, ca_proplist *sp); +int ca_lookup_sound_with_callback(ca_sound_file **f, ca_sound_file_open_callback_t sfopen, char **sound_path, ca_theme_data **t, ca_proplist *cp, ca_proplist *sp); +void ca_theme_data_free(ca_theme_data *t); + +int ca_get_data_home(char **e); +const char *ca_get_data_dirs(void); + +#endif diff --git a/.flatpak-builder/cache/objects/69/290b92d01fb48c7b76dc111a4b6ca7e4783368021b034ea29b9d5a3888f161.dirtree b/.flatpak-builder/cache/objects/69/290b92d01fb48c7b76dc111a4b6ca7e4783368021b034ea29b9d5a3888f161.dirtree new file mode 100644 index 0000000..2cf4ad7 Binary files /dev/null and b/.flatpak-builder/cache/objects/69/290b92d01fb48c7b76dc111a4b6ca7e4783368021b034ea29b9d5a3888f161.dirtree differ diff --git a/.flatpak-builder/cache/objects/69/317a8a102567bdc801f49246aa87b7b58ad43e3fe9d6befa1a3bb2f1e00e4b.dirtree b/.flatpak-builder/cache/objects/69/317a8a102567bdc801f49246aa87b7b58ad43e3fe9d6befa1a3bb2f1e00e4b.dirtree new file mode 100644 index 0000000..b7817e3 Binary files /dev/null and b/.flatpak-builder/cache/objects/69/317a8a102567bdc801f49246aa87b7b58ad43e3fe9d6befa1a3bb2f1e00e4b.dirtree differ diff --git a/.flatpak-builder/cache/objects/69/4ed53875c0cb5d85e773564cf520f68c11ff18eb9550755c06056ebd413b34.file b/.flatpak-builder/cache/objects/69/4ed53875c0cb5d85e773564cf520f68c11ff18eb9550755c06056ebd413b34.file new file mode 100755 index 0000000..45af4d5 --- /dev/null +++ b/.flatpak-builder/cache/objects/69/4ed53875c0cb5d85e773564cf520f68c11ff18eb9550755c06056ebd413b34.file @@ -0,0 +1,1510 @@ +#!/usr/bin/perl -w +# -*- Mode: perl; indent-tabs-mode: nil; c-basic-offset: 4 -*- + +# +# The Intltool Message Merger +# +# Copyright (C) 2000, 2003 Free Software Foundation. +# Copyright (C) 2000, 2001 Eazel, Inc +# +# Intltool is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# version 2 published by the Free Software Foundation. +# +# Intltool is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. +# +# Authors: Maciej Stachowiak +# Kenneth Christiansen +# Darin Adler +# +# Proper XML UTF-8'ification written by Cyrille Chepelov +# + +## Release information +my $PROGRAM = "intltool-merge"; +my $PACKAGE = "intltool"; +my $VERSION = "0.51.0"; + +## Loaded modules +use strict; +use Getopt::Long; +use Text::Wrap; +use File::Basename; +use Encode; + +my $must_end_tag = -1; +my $last_depth = -1; +my $translation_depth = -1; +my @tag_stack = (); +my @entered_tag = (); +my @translation_strings = (); +my $leading_space = ""; + +## Scalars used by the option stuff +my $HELP_ARG = 0; +my $VERSION_ARG = 0; +my $BA_STYLE_ARG = 0; +my $XML_STYLE_ARG = 0; +my $KEYS_STYLE_ARG = 0; +my $DESKTOP_STYLE_ARG = 0; +my $SCHEMAS_STYLE_ARG = 0; +my $RFC822DEB_STYLE_ARG = 0; +my $QUOTED_STYLE_ARG = 0; +my $QUOTEDXML_STYLE_ARG = 0; +my $QUIET_ARG = 0; +my $PASS_THROUGH_ARG = 0; +my $UTF8_ARG = 0; +my $MULTIPLE_OUTPUT = 0; +my $NO_TRANSLATIONS_ARG = 0; +my $cache_file; + +## Handle options +GetOptions +( + "help" => \$HELP_ARG, + "version" => \$VERSION_ARG, + "quiet|q" => \$QUIET_ARG, + "oaf-style|o" => \$BA_STYLE_ARG, ## for compatibility + "ba-style|b" => \$BA_STYLE_ARG, + "xml-style|x" => \$XML_STYLE_ARG, + "keys-style|k" => \$KEYS_STYLE_ARG, + "desktop-style|d" => \$DESKTOP_STYLE_ARG, + "schemas-style|s" => \$SCHEMAS_STYLE_ARG, + "rfc822deb-style|r" => \$RFC822DEB_STYLE_ARG, + "quoted-style" => \$QUOTED_STYLE_ARG, + "quotedxml-style" => \$QUOTEDXML_STYLE_ARG, + "pass-through|p" => \$PASS_THROUGH_ARG, + "utf8|u" => \$UTF8_ARG, + "multiple-output|m" => \$MULTIPLE_OUTPUT, + "no-translations" => \$NO_TRANSLATIONS_ARG, + "cache|c=s" => \$cache_file + ) or &error; + +my $PO_DIR; +my $FILE; +my $OUTFILE; + +my %po_files_by_lang = (); +my %translations = (); + +# Use this instead of \w for XML files to handle more possible characters. +my $w = "[-A-Za-z0-9._:]"; + +# XML quoted string contents +my $q = "[^\\\"]*"; + +## Check for options. + +if ($VERSION_ARG) +{ + &print_version; +} +elsif ($HELP_ARG) +{ + &print_help; +} +elsif ($BA_STYLE_ARG && @ARGV > 2) +{ + &utf8_sanity_check; + &preparation; + &print_message; + &ba_merge_translations; + &finalize; +} +elsif ($XML_STYLE_ARG && (@ARGV > 2 || ($NO_TRANSLATIONS_ARG && @ARGV > 1))) +{ + &utf8_sanity_check; + &preparation; + &print_message; + &xml_merge_output; + &finalize; +} +elsif ($KEYS_STYLE_ARG && @ARGV > 2) +{ + &utf8_sanity_check; + &preparation; + &print_message; + &keys_merge_translations; + &finalize; +} +elsif ($DESKTOP_STYLE_ARG && @ARGV > 2) +{ + &utf8_sanity_check; + &preparation; + &print_message; + &desktop_merge_translations; + &finalize; +} +elsif ($SCHEMAS_STYLE_ARG && @ARGV > 2) +{ + &utf8_sanity_check; + &preparation; + &print_message; + &schemas_merge_translations; + &finalize; +} +elsif ($RFC822DEB_STYLE_ARG && @ARGV > 2) +{ + &preparation; + &print_message; + &rfc822deb_merge_translations; + &finalize; +} +elsif (($QUOTED_STYLE_ARG || $QUOTEDXML_STYLE_ARG) && @ARGV > 2) +{ + &utf8_sanity_check; + &preparation; + &print_message; + "ed_merge_translations($QUOTEDXML_STYLE_ARG); + &finalize; +} +else +{ + &print_help; +} + +exit; + +## Sub for printing release information +sub print_version +{ + print <<_EOF_; +${PROGRAM} (${PACKAGE}) ${VERSION} +Written by Maciej Stachowiak, Darin Adler and Kenneth Christiansen. + +Copyright (C) 2000-2003 Free Software Foundation, Inc. +Copyright (C) 2000-2001 Eazel, Inc. +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +_EOF_ + exit; +} + +## Sub for printing usage information +sub print_help +{ + print <<_EOF_; +Usage: ${PROGRAM} [OPTION]... PO_DIRECTORY FILENAME OUTPUT_FILE +Generates an output file that includes some localized attributes from an +untranslated source file. + +Mandatory options: (exactly one must be specified) + -b, --ba-style includes translations in the bonobo-activation style + -d, --desktop-style includes translations in the desktop style + -k, --keys-style includes translations in the keys style + -s, --schemas-style includes translations in the schemas style + -r, --rfc822deb-style includes translations in the RFC822 style + --quoted-style includes translations in the quoted string style + --quotedxml-style includes translations in the quoted xml string style + -x, --xml-style includes translations in the standard xml style + +Other options: + -u, --utf8 convert all strings to UTF-8 before merging + (default for everything except RFC822 style) + -p, --pass-through deprecated, does nothing and issues a warning + -m, --multiple-output output one localized file per locale, instead of + a single file containing all localized elements + --no-translations do not merge any translations: only generates the + unlocalised (English) version -- applies only + to XML merging + -c, --cache=FILE specify cache file name + (usually \$top_builddir/po/.intltool-merge-cache) + -q, --quiet suppress most messages + --help display this help and exit + --version output version information and exit + +Report bugs to http://bugs.launchpad.net/intltool +_EOF_ + exit; +} + + +## Sub for printing error messages +sub print_error +{ + print STDERR "Try `${PROGRAM} --help' for more information.\n"; + exit; +} + + +sub print_message +{ + print "Merging translations into $OUTFILE.\n" unless $QUIET_ARG; +} + + +sub preparation +{ + if (!$XML_STYLE_ARG || !$NO_TRANSLATIONS_ARG) { + $PO_DIR = $ARGV[0]; + $FILE = $ARGV[1]; + $OUTFILE = $ARGV[2]; + + &gather_po_files; + &get_translation_database; + } else { + $FILE = $ARGV[0]; + $OUTFILE = $ARGV[1]; + } +} + +# General-purpose code for looking up translations in .po files + +sub po_file2lang +{ + my ($tmp) = @_; + $tmp =~ s/^.*\/(.*)\.po$/$1/; + return $tmp; +} + +sub gather_po_files +{ + if (my $linguas = $ENV{"LINGUAS"}) + { + for my $lang (split / /, $linguas) { + my $po_file = $PO_DIR . "/" . $lang . ".po"; + if (-e $po_file) { + $po_files_by_lang{$lang} = $po_file; + } + } + } + else + { + if (open LINGUAS_FILE, "$PO_DIR/LINGUAS") + { + while () + { + next if /^#/; + + for my $lang (split) + { + chomp ($lang); + my $po_file = $PO_DIR . "/" . $lang . ".po"; + if (-e $po_file) { + $po_files_by_lang{$lang} = $po_file; + } + } + } + + close LINGUAS_FILE; + } + else + { + for my $po_file (glob "$PO_DIR/*.po") { + $po_files_by_lang{po_file2lang($po_file)} = $po_file; + } + } + } +} + +sub get_po_encoding +{ + my ($in_po_file) = @_; + my $encoding = ""; + + open IN_PO_FILE, $in_po_file or die; + while () + { + ## example: "Content-Type: text/plain; charset=ISO-8859-1\n" + if (/Content-Type\:.*charset=([-a-zA-Z0-9]+)\\n/) + { + $encoding = $1; + last; + } + } + close IN_PO_FILE; + + if (!$encoding) + { + print STDERR "Warning: no encoding found in $in_po_file. Assuming ISO-8859-1\n" unless $QUIET_ARG; + $encoding = "ISO-8859-1"; + } + + return $encoding +} + +sub utf8_sanity_check +{ + print STDERR "Warning: option --pass-through has been removed.\n" if $PASS_THROUGH_ARG; + $UTF8_ARG = 1; +} + +sub get_translation_database +{ + if ($cache_file) { + &get_cached_translation_database; + } else { + &create_translation_database; + } +} + +sub get_newest_po_age +{ + my $newest_age; + + foreach my $file (values %po_files_by_lang) + { + my $file_age = -M $file; + $newest_age = $file_age if !$newest_age || $file_age < $newest_age; + } + + $newest_age = 0 if !$newest_age; + + return $newest_age; +} + +sub create_cache +{ + print "Generating and caching the translation database\n" unless $QUIET_ARG; + + &create_translation_database; + + open CACHE, ">$cache_file" || die; + print CACHE join "\x01", %translations; + close CACHE; +} + +sub load_cache +{ + print "Found cached translation database\n" unless $QUIET_ARG; + + my $contents; + open CACHE, "<$cache_file" || die; + { + local $/; + $contents = ; + } + close CACHE; + %translations = split "\x01", $contents; +} + +sub get_cached_translation_database +{ + my $cache_file_age = -M $cache_file; + if (defined $cache_file_age) + { + if ($cache_file_age <= &get_newest_po_age) + { + &load_cache; + return; + } + print "Found too-old cached translation database\n" unless $QUIET_ARG; + } + + &create_cache; +} + +sub add_translation +{ + my ($lang, $encoding, $msgctxt, $msgid, $msgstr) = @_; + + return if !($msgid && $msgstr); + + if ($msgctxt) { + $msgid = "$msgctxt\004$msgid"; + } + if (uc $encoding ne "UTF-8") { + Encode::from_to ($msgid, $encoding, "UTF-8"); + Encode::from_to ($msgstr, $encoding, "UTF-8"); + } + $translations{$lang, $msgid} = $msgstr; +} + +sub create_translation_database +{ + for my $lang (keys %po_files_by_lang) + { + my $po_file = $po_files_by_lang{$lang}; + my $encoding = "UTF-8"; + + if ($UTF8_ARG) + { + $encoding = get_po_encoding ($po_file); + if (uc $encoding ne "UTF-8") { + print "NOTICE: $po_file is not in UTF-8 but $encoding, converting...\n" unless $QUIET_ARG;; + } + } + open PO_FILE, "<$po_file"; + + my $nextfuzzy = 0; + my $inmsgctxt = 0; + my $inmsgid = 0; + my $inmsgstr = 0; + my $msgctxt = ""; + my $msgid = ""; + my $msgstr = ""; + + while () + { + $nextfuzzy = 1 if /^#, fuzzy/; + + if (/^msgctxt "((\\.|[^\\]+)*)"/ ) + { + if ($inmsgstr) { + add_translation ($lang, $encoding, + $msgctxt, $msgid, $msgstr); + $msgctxt = ""; + $msgid = ""; + $msgstr = ""; + } + + $msgctxt = unescape_po_string($1); + $inmsgctxt = 1; + $inmsgid = 0; + $inmsgstr = 0; + } + + if (/^msgid "((\\.|[^\\]+)*)"/ ) + { + if ($inmsgstr) { + add_translation ($lang, $encoding, + $msgctxt, $msgid, $msgstr); + $msgctxt = ""; + $msgid = ""; + $msgstr = ""; + } + + if ($nextfuzzy) { + $inmsgid = 0; + $nextfuzzy = 0; + } else { + $msgid = unescape_po_string($1); + $inmsgid = 1; + } + $inmsgctxt = 0; + $inmsgstr = 0; + } + + if (/^msgstr "((\\.|[^\\]+)*)"/) + { + $msgstr = unescape_po_string($1); + $inmsgstr = 1; + $inmsgctxt = 0; + $inmsgid = 0; + } + + if (/^"((\\.|[^\\]+)*)"/) + { + $msgctxt .= unescape_po_string($1) if $inmsgctxt; + $msgid .= unescape_po_string($1) if $inmsgid; + $msgstr .= unescape_po_string($1) if $inmsgstr; + } + } + add_translation ($lang, $encoding, $msgctxt, $msgid, $msgstr) + if ($inmsgstr); + } +} + +sub finalize +{ +} + +sub unescape_one_sequence +{ + my ($sequence) = @_; + + return "\\" if $sequence eq "\\\\"; + return "\"" if $sequence eq "\\\""; + return "\n" if $sequence eq "\\n"; + return "\r" if $sequence eq "\\r"; + return "\t" if $sequence eq "\\t"; + return "\b" if $sequence eq "\\b"; + return "\f" if $sequence eq "\\f"; + return "\a" if $sequence eq "\\a"; + return chr(11) if $sequence eq "\\v"; # vertical tab, see ascii(7) + + return chr(hex($1)) if ($sequence =~ /\\x([0-9a-fA-F]{2})/); + return chr(oct($1)) if ($sequence =~ /\\([0-7]{3})/); + + # FIXME: Is \0 supported as well? Kenneth and Rodney don't want it, see bug #48489 + + return $sequence; +} + +sub unescape_po_string +{ + my ($string) = @_; + + $string =~ s/(\\x[0-9a-fA-F]{2}|\\[0-7]{3}|\\.)/unescape_one_sequence($1)/eg; + + return $string; +} + +sub entity_decode +{ + local ($_) = @_; + + s/'/'/g; # ' + s/"/"/g; # " + s/<//g; + s/&/&/g; + + return $_; +} + +# entity_encode: (string) +# +# Encode the given string to XML format (encode '<' etc). + +sub entity_encode +{ + my ($pre_encoded) = @_; + + my @list_of_chars = unpack ('C*', $pre_encoded); + + # with UTF-8 we only encode minimalistic + return join ('', map (&entity_encode_int_minimalist, @list_of_chars)); +} + +sub entity_encode_int_minimalist +{ + return """ if $_ == 34; + return "&" if $_ == 38; + return "'" if $_ == 39; + return "<" if $_ == 60; + return ">" if $_ == 62; + return chr $_; +} + +sub entity_encoded_translation +{ + my ($lang, $string) = @_; + + my $translation = $translations{$lang, $string}; + return $string if !$translation; + return entity_encode ($translation); +} + +## XML (bonobo-activation specific) merge code + +sub ba_merge_translations +{ + my $source; + + { + local $/; # slurp mode + open INPUT, "<$FILE" or die "can't open $FILE: $!"; + $source = ; + close INPUT; + } + + open OUTPUT, ">$OUTFILE" or die "can't open $OUTFILE: $!"; + # Binmode so that selftest works ok if using a native Win32 Perl... + binmode (OUTPUT) if $^O eq 'MSWin32'; + + while ($source =~ s|^(.*?)([ \t]*<\s*$w+\s+($w+\s*=\s*"$q"\s*)+/?>)([ \t]*\n)?||s) + { + print OUTPUT $1; + + my $node = $2 . "\n"; + + my @strings = (); + $_ = $node; + while (s/(\s)_($w+\s*=\s*"($q)")/$1$2/s) { + push @strings, entity_decode($3); + } + print OUTPUT; + + my %langs; + for my $string (@strings) + { + for my $lang (keys %po_files_by_lang) + { + $langs{$lang} = 1 if $translations{$lang, $string}; + } + } + + for my $lang (sort keys %langs) + { + $_ = $node; + s/(\sname\s*=\s*)"($q)"/$1"$2-$lang"/s; + s/(\s)_($w+\s*=\s*")($q)"/$1 . $2 . entity_encoded_translation($lang, $3) . '"'/seg; + print OUTPUT; + } + } + + print OUTPUT $source; + + close OUTPUT; +} + + +## XML (non-bonobo-activation) merge code + + +# Process tag attributes +# Only parameter is a HASH containing attributes -> values mapping +sub getAttributeString +{ + my $sub = shift; + my $do_translate = shift || 0; + my $language = shift || ""; + my $result = ""; + my $translate = shift; + foreach my $e (reverse(sort(keys %{ $sub }))) { + my $key = $e; + my $string = $sub->{$e}; + my $quote = '"'; + + $string =~ s/^[\s]+//; + $string =~ s/[\s]+$//; + + if ($string =~ /^'.*'$/) + { + $quote = "'"; + } + $string =~ s/^['"]//g; + $string =~ s/['"]$//g; + + if ($do_translate && $key =~ /^_/) { + $key =~ s|^_||g; + if ($language) { + # Handle translation + my $decode_string = entity_decode($string); + my $translation = $translations{$language, $decode_string}; + if ($translation) { + $translation = entity_encode($translation); + $string = $translation; + } + $$translate = 2; + } else { + $$translate = 2 if ($translate && (!$$translate)); # watch not to "overwrite" $translate + } + } + + $result .= " $key=$quote$string$quote"; + } + return $result; +} + +# Returns a translatable string from XML node, it works on contents of every node in XML::Parser tree +sub getXMLstring +{ + my $ref = shift; + my $spacepreserve = shift || 0; + my @list = @{ $ref }; + my $result = ""; + + my $count = scalar(@list); + my $attrs = $list[0]; + my $index = 1; + + $spacepreserve = 1 if ((exists $attrs->{"xml:space"}) && ($attrs->{"xml:space"} =~ /^["']?preserve["']?$/)); + $spacepreserve = 0 if ((exists $attrs->{"xml:space"}) && ($attrs->{"xml:space"} =~ /^["']?default["']?$/)); + + while ($index < $count) { + my $type = $list[$index]; + my $content = $list[$index+1]; + if (! $type ) { + # We've got CDATA + if ($content) { + # lets strip the whitespace here, and *ONLY* here + $content =~ s/\s+/ /gs if (!$spacepreserve); + $result .= $content; + } + } elsif ( "$type" ne "1" ) { + # We've got another element + $result .= "<$type"; + $result .= getAttributeString(@{$content}[0], 0); # no nested translatable elements + if ($content) { + my $subresult = getXMLstring($content, $spacepreserve); + if ($subresult) { + $result .= ">".$subresult . ""; + } else { + $result .= "/>"; + } + } else { + $result .= "/>"; + } + } + $index += 2; + } + return $result; +} + +# Translate list of nodes if necessary +sub translate_subnodes +{ + my $fh = shift; + my $content = shift; + my $language = shift || ""; + my $singlelang = shift || 0; + my $spacepreserve = shift || 0; + + my @nodes = @{ $content }; + + my $count = scalar(@nodes); + my $index = 0; + while ($index < $count) { + my $type = $nodes[$index]; + my $rest = $nodes[$index+1]; + if ($singlelang) { + my $oldMO = $MULTIPLE_OUTPUT; + $MULTIPLE_OUTPUT = 1; + traverse($fh, $type, $rest, $language, $spacepreserve); + $MULTIPLE_OUTPUT = $oldMO; + } else { + traverse($fh, $type, $rest, $language, $spacepreserve); + } + $index += 2; + } +} + +sub isWellFormedXmlFragment +{ + my $ret = eval 'require XML::Parser'; + if(!$ret) { + die "You must have XML::Parser installed to run $0\n\n"; + } + + my $fragment = shift; + return 0 if (!$fragment); + + $fragment = "$fragment"; + my $xp = new XML::Parser(Style => 'Tree'); + my $tree = 0; + eval { $tree = $xp->parse($fragment); }; + return $tree; +} + +sub traverse +{ + my $fh = shift; + my $nodename = shift; + my $content = shift; + my $language = shift || ""; + my $spacepreserve = shift || 0; + + if (!$nodename) { + if ($content =~ /^[\s]*$/) { + $leading_space .= $content; + } + print $fh $content; + } else { + # element + my @all = @{ $content }; + my $attrs = shift @all; + my $translate = 0; + my $outattr = getAttributeString($attrs, 1, $language, \$translate); + + if ($nodename =~ /^_/) { + $translate = 1; + $nodename =~ s/^_//; + } + my $lookup = ''; + + $spacepreserve = 0 if ((exists $attrs->{"xml:space"}) && ($attrs->{"xml:space"} =~ /^["']?default["']?$/)); + $spacepreserve = 1 if ((exists $attrs->{"xml:space"}) && ($attrs->{"xml:space"} =~ /^["']?preserve["']?$/)); + + print $fh "<$nodename", $outattr; + if ($translate) { + $content = getXMLstring($content, $spacepreserve); + if (!$spacepreserve) { + $content =~ s/^\s+//s; + $content =~ s/\s+$//s; + } + if (exists $attrs->{"msgctxt"}) { + my $context = entity_decode ($attrs->{"msgctxt"}); + $context =~ s/^["'](.*)["']/$1/; + $lookup = "$context\004$content"; + } else { + $lookup = $content; + } + + if ($lookup || $translate == 2) { + my $translation = $translations{$language, $lookup} if isWellFormedXmlFragment($translations{$language, $lookup}); + if ($MULTIPLE_OUTPUT && ($translation || $translate == 2)) { + $translation = $content if (!$translation); + print $fh " xml:lang=\"", $language, "\"" if $language; + print $fh ">"; + if ($translate == 2) { + translate_subnodes($fh, \@all, $language, 1, $spacepreserve); + } else { + print $fh $translation; + } + print $fh ""; + + return; # this means there will be no same translation with xml:lang="$language"... + # if we want them both, just remove this "return" + } else { + print $fh ">"; + if ($translate == 2) { + translate_subnodes($fh, \@all, $language, 1, $spacepreserve); + } else { + print $fh $content; + } + print $fh ""; + } + } else { + print $fh "/>"; + } + + for my $lang (sort keys %po_files_by_lang) { + if ($MULTIPLE_OUTPUT && $lang ne "$language") { + next; + } + if ($lang) { + # Handle translation + # + my $translate = 0; + my $localattrs = getAttributeString($attrs, 1, $lang, \$translate); + my $translation = $translations{$lang, $lookup} if isWellFormedXmlFragment($translations{$lang, $lookup}); + if ($translate && !$translation) { + $translation = $content; + } + + if ($translation || $translate) { + print $fh "\n"; + $leading_space =~ s/.*\n//g; + print $fh $leading_space; + print $fh "<", $nodename, " xml:lang=\"", $lang, "\"", $localattrs, ">"; + if ($translate == 2) { + translate_subnodes($fh, \@all, $lang, 1, $spacepreserve); + } else { + print $fh $translation; + } + print $fh ""; + } + } + } + + } else { + my $count = scalar(@all); + if ($count > 0) { + print $fh ">"; + my $index = 0; + while ($index < $count) { + my $type = $all[$index]; + my $rest = $all[$index+1]; + traverse($fh, $type, $rest, $language, $spacepreserve); + $index += 2; + } + print $fh ""; + } else { + print $fh "/>"; + } + } + } +} + +sub intltool_tree_comment +{ + my $expat = shift; + my $data = shift; + my $clist = $expat->{Curlist}; + my $pos = $#$clist; + + push @$clist, 1 => $data; +} + +sub intltool_tree_cdatastart +{ + my $expat = shift; + my $clist = $expat->{Curlist}; + my $pos = $#$clist; + + push @$clist, 0 => $expat->original_string(); +} + +sub intltool_tree_cdataend +{ + my $expat = shift; + my $clist = $expat->{Curlist}; + my $pos = $#$clist; + + $clist->[$pos] .= $expat->original_string(); +} + +sub intltool_tree_char +{ + my $expat = shift; + my $text = shift; + my $clist = $expat->{Curlist}; + my $pos = $#$clist; + + # Use original_string so that we retain escaped entities + # in CDATA sections. + # + if ($pos > 0 and $clist->[$pos - 1] eq '0') { + $clist->[$pos] .= $expat->original_string(); + } else { + push @$clist, 0 => $expat->original_string(); + } +} + +sub intltool_tree_start +{ + my $expat = shift; + my $tag = shift; + my @origlist = (); + + # Use original_string so that we retain escaped entities + # in attribute values. We must convert the string to an + # @origlist array to conform to the structure of the Tree + # Style. + # + my @original_array = split /\x/, $expat->original_string(); + my $source = $expat->original_string(); + + # Remove leading tag. + # + $source =~ s|^\s*<\s*(\S+)||s; + + # Grab attribute key/value pairs and push onto @origlist array. + # + while ($source) + { + if ($source =~ /^\s*([\w:-]+)\s*[=]\s*["]/) + { + $source =~ s|^\s*([\w:-]+)\s*[=]\s*["]([^"]*)["]||s; + push @origlist, $1; + push @origlist, '"' . $2 . '"'; + } + elsif ($source =~ /^\s*([\w:-]+)\s*[=]\s*[']/) + { + $source =~ s|^\s*([\w:-]+)\s*[=]\s*[']([^']*)[']||s; + push @origlist, $1; + push @origlist, "'" . $2 . "'"; + } + else + { + last; + } + } + + my $ol = [ { @origlist } ]; + + push @{ $expat->{Lists} }, $expat->{Curlist}; + push @{ $expat->{Curlist} }, $tag => $ol; + $expat->{Curlist} = $ol; +} + +sub readXml +{ + my $filename = shift || return; + if(!-f $filename) { + die "ERROR Cannot find filename: $filename\n"; + } + + my $ret = eval 'require XML::Parser'; + if(!$ret) { + die "You must have XML::Parser installed to run $0\n\n"; + } + my $xp = new XML::Parser(Style => 'Tree'); + $xp->setHandlers(Char => \&intltool_tree_char); + $xp->setHandlers(Start => \&intltool_tree_start); + $xp->setHandlers(CdataStart => \&intltool_tree_cdatastart); + $xp->setHandlers(CdataEnd => \&intltool_tree_cdataend); + my $tree = $xp->parsefile($filename); + +# Hello thereHowdydo +# would be: +# [foo, [{}, head, [{id => "a"}, 0, "Hello ", em, [{}, 0, "there"]], bar, [{}, +# 0, "Howdy", ref, [{}]], 0, "do" ] ] + + return $tree; +} + +sub print_header +{ + my $infile = shift; + my $fh = shift; + my $source; + + if(!-f $infile) { + die "ERROR Cannot find filename: $infile\n"; + } + + print $fh qq{\n}; + { + local $/; + open DOCINPUT, "<${FILE}" or die; + $source = ; + close DOCINPUT; + } + if ($source =~ /()/s) + { + print $fh "$1\n"; + } + elsif ($source =~ /(]*>)/s) + { + print $fh "$1\n"; + } +} + +sub parseTree +{ + my $fh = shift; + my $ref = shift; + my $language = shift || ""; + + my $name = shift @{ $ref }; + my $cont = shift @{ $ref }; + + while (!$name || "$name" eq "1") { + $name = shift @{ $ref }; + $cont = shift @{ $ref }; + } + + my $spacepreserve = 0; + my $attrs = @{$cont}[0]; + $spacepreserve = 1 if ((exists $attrs->{"xml:space"}) && ($attrs->{"xml:space"} =~ /^["']?preserve["']?$/)); + + traverse($fh, $name, $cont, $language, $spacepreserve); +} + +sub xml_merge_output +{ + my $source; + + if ($MULTIPLE_OUTPUT) { + for my $lang (sort keys %po_files_by_lang) { + if ( ! -d $lang ) { + mkdir $lang or -d $lang or die "Cannot create subdirectory $lang: $!\n"; + } + open OUTPUT, ">$lang/$OUTFILE" or die "Cannot open $lang/$OUTFILE: $!\n"; + binmode (OUTPUT) if $^O eq 'MSWin32'; + my $tree = readXml($FILE); + print_header($FILE, \*OUTPUT); + parseTree(\*OUTPUT, $tree, $lang); + close OUTPUT; + print "CREATED $lang/$OUTFILE\n" unless $QUIET_ARG; + } + if ( ! -d "C" ) { + mkdir "C" or -d "C" or die "Cannot create subdirectory C: $!\n"; + } + open OUTPUT, ">C/$OUTFILE" or die "Cannot open C/$OUTFILE: $!\n"; + binmode (OUTPUT) if $^O eq 'MSWin32'; + my $tree = readXml($FILE); + print_header($FILE, \*OUTPUT); + parseTree(\*OUTPUT, $tree); + close OUTPUT; + print "CREATED C/$OUTFILE\n" unless $QUIET_ARG; + } else { + open OUTPUT, ">$OUTFILE" or die "Cannot open $OUTFILE: $!\n"; + binmode (OUTPUT) if $^O eq 'MSWin32'; + my $tree = readXml($FILE); + print_header($FILE, \*OUTPUT); + parseTree(\*OUTPUT, $tree); + close OUTPUT; + print "CREATED $OUTFILE\n" unless $QUIET_ARG; + } +} + +sub keys_merge_translation +{ + my ($lang) = @_; + + if ( ! -d $lang && $MULTIPLE_OUTPUT) + { + mkdir $lang or -d $lang or die "Cannot create subdirectory $lang: $!\n"; + } + + open INPUT, "<${FILE}" or die "Cannot open ${FILE}: $!\n"; + open OUTPUT, ">$lang/$OUTFILE" or die "Cannot open $lang/$OUTFILE: $!\n"; + binmode (OUTPUT) if $^O eq 'MSWin32'; + + while () + { + if (s/^(\s*)_(\w+=(.*))/$1$2/) + { + my $string = $3; + + if (!$MULTIPLE_OUTPUT) + { + print OUTPUT; + + my $non_translated_line = $_; + + for my $lang (sort keys %po_files_by_lang) + { + my $translation = $translations{$lang, $string}; + next if !$translation; + + $_ = $non_translated_line; + s/(\w+)=.*/[$lang]$1=$translation/; + print OUTPUT; + } + } + else + { + my $non_translated_line = $_; + my $translation = $translations{$lang, $string}; + $translation = $string if !$translation; + + $_ = $non_translated_line; + s/(\w+)=.*/$1=$translation/; + print OUTPUT; + } + } + else + { + print OUTPUT; + } + } + + close OUTPUT; + close INPUT; + + print "CREATED $lang/$OUTFILE\n" unless $QUIET_ARG; +} + +sub keys_merge_translations +{ + if ($MULTIPLE_OUTPUT) + { + for my $lang (sort keys %po_files_by_lang) + { + keys_merge_translation ($lang); + } + keys_merge_translation ("C"); + } + else + { + keys_merge_translation ("."); + } +} + +sub desktop_merge_translations +{ + open INPUT, "<${FILE}" or die; + open OUTPUT, ">${OUTFILE}" or die; + binmode (OUTPUT) if $^O eq 'MSWin32'; + + while () + { + if (s/^(\s*)_([A-Za-z0-9\-]+\s*=\s*(.*))/$1$2/) + { + my $string = $3; + + print OUTPUT; + + my $non_translated_line = $_; + + for my $lang (sort keys %po_files_by_lang) + { + my $translation = $translations{$lang, $string}; + next if !$translation; + + $_ = $non_translated_line; + s/(\w+)\s*=\s*.*/${1}[$lang]=$translation/; + print OUTPUT; + } + } + else + { + print OUTPUT; + } + } + + close OUTPUT; + close INPUT; +} + +sub schemas_merge_translations +{ + my $source; + + { + local $/; # slurp mode + open INPUT, "<$FILE" or die "can't open $FILE: $!"; + $source = ; + close INPUT; + } + + open OUTPUT, ">$OUTFILE" or die; + binmode (OUTPUT) if $^O eq 'MSWin32'; + + # FIXME: support attribute translations + + # Empty nodes never need translation, so unmark all of them. + # For example, <_foo/> is just replaced by . + $source =~ s|<\s*_($w+)\s*/>|<$1/>|g; + + while ($source =~ s/ + (.*?) + (\s+)((\s*) + (\s*(?:\s*)?(.*?)\s*<\/default>)?(\s*) + (\s*(?:\s*)?(.*?)\s*<\/short>)?(\s*) + (\s*(?:\s*)?(.*?)\s*<\/long>)?(\s*) + <\/locale>) + //sx) + { + print OUTPUT $1; + + my $locale_start_spaces = $2 ? $2 : ''; + my $default_spaces = $4 ? $4 : ''; + my $short_spaces = $7 ? $7 : ''; + my $long_spaces = $10 ? $10 : ''; + my $locale_end_spaces = $13 ? $13 : ''; + my $c_default_block = $3 ? $3 : ''; + my $default_string = $6 ? $6 : ''; + my $short_string = $9 ? $9 : ''; + my $long_string = $12 ? $12 : ''; + + print OUTPUT "$locale_start_spaces$c_default_block"; + + $default_string =~ s/\s+/ /g; + $default_string = entity_decode($default_string); + $short_string =~ s/\s+/ /g; + $short_string = entity_decode($short_string); + $long_string =~ s/\s+/ /g; + $long_string = entity_decode($long_string); + + for my $lang (sort keys %po_files_by_lang) + { + my $default_translation = $translations{$lang, $default_string}; + my $short_translation = $translations{$lang, $short_string}; + my $long_translation = $translations{$lang, $long_string}; + + next if (!$default_translation && !$short_translation && + !$long_translation); + + print OUTPUT "\n$locale_start_spaces"; + + print OUTPUT "$default_spaces"; + + if ($default_translation) + { + $default_translation = entity_encode($default_translation); + print OUTPUT "$default_translation"; + } + + print OUTPUT "$short_spaces"; + + if ($short_translation) + { + $short_translation = entity_encode($short_translation); + print OUTPUT "$short_translation"; + } + + print OUTPUT "$long_spaces"; + + if ($long_translation) + { + $long_translation = entity_encode($long_translation); + print OUTPUT "$long_translation"; + } + + print OUTPUT "$locale_end_spaces"; + } + } + + print OUTPUT $source; + + close OUTPUT; +} + +sub rfc822deb_merge_translations +{ + my %encodings = (); + for my $lang (keys %po_files_by_lang) { + $encodings{$lang} = ($UTF8_ARG ? 'UTF-8' : get_po_encoding($po_files_by_lang{$lang})); + } + + my $source; + + $Text::Wrap::huge = 'overflow'; + $Text::Wrap::break = qr/\n|\s(?=\S)/; + + { + local $/; # slurp mode + open INPUT, "<$FILE" or die "can't open $FILE: $!"; + $source = ; + close INPUT; + } + + open OUTPUT, ">${OUTFILE}" or die; + binmode (OUTPUT) if $^O eq 'MSWin32'; + + while ($source =~ /(^|\n+)(_*)([^:\s]+)(:[ \t]*)(.*?)(?=\n[\S\n]|$)/sg) + { + my $sep = $1; + my $non_translated_line = $3.$4; + my $string = $5; + my $underscore = length($2); + next if $underscore eq 0 && $non_translated_line =~ /^#/; + # Remove [] dummy strings + my $stripped = $string; + $stripped =~ s/\[\s[^\[\]]*\],/,/g if $underscore eq 2; + $stripped =~ s/\[\s[^\[\]]*\]$//; + $non_translated_line .= $stripped; + + print OUTPUT $sep.$non_translated_line; + + if ($underscore) + { + my @str_list = rfc822deb_split($underscore, $string); + + for my $lang (sort keys %po_files_by_lang) + { + my $is_translated = 1; + my $str_translated = ''; + my $first = 1; + + for my $str (@str_list) + { + my $translation = $translations{$lang, $str}; + + if (!$translation) + { + $is_translated = 0; + last; + } + + # $translation may also contain [] dummy + # strings, mostly to indicate an empty string + $translation =~ s/\[\s[^\[\]]*\]$//; + + if ($first) + { + if ($underscore eq 2) + { + $str_translated .= $translation; + } + else + { + $str_translated .= + Text::Tabs::expand($translation) . + "\n"; + } + } + else + { + if ($underscore eq 2) + { + $str_translated .= ', ' . $translation; + } + else + { + $str_translated .= Text::Tabs::expand( + Text::Wrap::wrap(' ', ' ', $translation)) . + "\n .\n"; + } + } + $first = 0; + + # To fix some problems with Text::Wrap::wrap + $str_translated =~ s/(\n )+\n/\n .\n/g; + } + next unless $is_translated; + + $str_translated =~ s/\n \.\n$//; + $str_translated =~ s/\s+$//; + + $_ = $non_translated_line; + s/^(\w+):\s*.*/$sep${1}-$lang.$encodings{$lang}: $str_translated/s; + print OUTPUT; + } + } + } + print OUTPUT "\n"; + + close OUTPUT; + close INPUT; +} + +sub rfc822deb_split +{ + # Debian defines a special way to deal with rfc822-style files: + # when a value contain newlines, it consists of + # 1. a short form (first line) + # 2. a long description, all lines begin with a space, + # and paragraphs are separated by a single dot on a line + # This routine returns an array of all paragraphs, and reformat + # them. + # When first argument is 2, the string is a comma separated list of + # values. + my $type = shift; + my $text = shift; + $text =~ s/^[ \t]//mg; + return (split(/, */, $text, 0)) if $type ne 1; + return ($text) if $text !~ /\n/; + + $text =~ s/([^\n]*)\n//; + my @list = ($1); + my $str = ''; + + for my $line (split (/\n/, $text)) + { + chomp $line; + if ($line =~ /^\.\s*$/) + { + # New paragraph + $str =~ s/\s*$//; + push(@list, $str); + $str = ''; + } + elsif ($line =~ /^\s/) + { + # Line which must not be reformatted + $str .= "\n" if length ($str) && $str !~ /\n$/; + $line =~ s/\s+$//; + $str .= $line."\n"; + } + else + { + # Continuation line, remove newline + $str .= " " if length ($str) && $str !~ /\n$/; + $str .= $line; + } + } + + $str =~ s/\s*$//; + push(@list, $str) if length ($str); + + return @list; +} + +sub quoted_translation +{ + my ($xml_mode, $lang, $string) = @_; + + $string = entity_decode($string) if $xml_mode; + $string =~ s/\\\"/\"/g; + + my $translation = $translations{$lang, $string}; + $translation = $string if !$translation; + $translation = entity_encode($translation) if $xml_mode; + $translation =~ s/\"/\\\"/g; + return $translation +} + +sub quoted_merge_translations +{ + my ($xml_mode) = @_; + + if (!$MULTIPLE_OUTPUT) { + print "Quoted only supports Multiple Output.\n"; + exit(1); + } + + for my $lang (sort keys %po_files_by_lang) { + if ( ! -d $lang ) { + mkdir $lang or -d $lang or die "Cannot create subdirectory $lang: $!\n"; + } + open INPUT, "<${FILE}" or die; + open OUTPUT, ">$lang/$OUTFILE" or die "Cannot open $lang/$OUTFILE: $!\n"; + binmode (OUTPUT) if $^O eq 'MSWin32'; + while () + { + s/\"(([^\"]|\\\")*[^\\\"])\"/"\"" . "ed_translation($xml_mode, $lang, $1) . "\""/ge; + print OUTPUT; + } + close OUTPUT; + close INPUT; + } +} diff --git a/.flatpak-builder/cache/objects/69/690b18182fdf9e34db3f8ca924c9c43ee563ae11a9efa7d0d0fb33b71b5378.dirtree b/.flatpak-builder/cache/objects/69/690b18182fdf9e34db3f8ca924c9c43ee563ae11a9efa7d0d0fb33b71b5378.dirtree new file mode 100644 index 0000000..47ecbfc Binary files /dev/null and b/.flatpak-builder/cache/objects/69/690b18182fdf9e34db3f8ca924c9c43ee563ae11a9efa7d0d0fb33b71b5378.dirtree differ diff --git a/.flatpak-builder/cache/objects/69/bff954b0c419d76afa231e50ea5ee6e13ca9ee2740960ef521fd7d3a4711bd.file b/.flatpak-builder/cache/objects/69/bff954b0c419d76afa231e50ea5ee6e13ca9ee2740960ef521fd7d3a4711bd.file new file mode 100755 index 0000000..32d3592 Binary files /dev/null and b/.flatpak-builder/cache/objects/69/bff954b0c419d76afa231e50ea5ee6e13ca9ee2740960ef521fd7d3a4711bd.file differ diff --git a/.flatpak-builder/cache/objects/6a/0bb8b2f28fd7c7d8b13eb632186915416f768036dce488115c4494a857bf21.dirtree b/.flatpak-builder/cache/objects/6a/0bb8b2f28fd7c7d8b13eb632186915416f768036dce488115c4494a857bf21.dirtree new file mode 100644 index 0000000..263b65f Binary files /dev/null and b/.flatpak-builder/cache/objects/6a/0bb8b2f28fd7c7d8b13eb632186915416f768036dce488115c4494a857bf21.dirtree differ diff --git a/.flatpak-builder/cache/objects/6a/17ec5890e251ba40180de78a7fa38265bf0c656803038e5f54174b65a3356f.dirtree b/.flatpak-builder/cache/objects/6a/17ec5890e251ba40180de78a7fa38265bf0c656803038e5f54174b65a3356f.dirtree new file mode 100644 index 0000000..64b10e9 Binary files /dev/null and b/.flatpak-builder/cache/objects/6a/17ec5890e251ba40180de78a7fa38265bf0c656803038e5f54174b65a3356f.dirtree differ diff --git a/.flatpak-builder/cache/objects/6a/32af478541584bff7f8f0d75fb17694f45fce32a4567f8f2de0f3378393fc8.file b/.flatpak-builder/cache/objects/6a/32af478541584bff7f8f0d75fb17694f45fce32a4567f8f2de0f3378393fc8.file new file mode 100644 index 0000000..7f504bc --- /dev/null +++ b/.flatpak-builder/cache/objects/6a/32af478541584bff7f8f0d75fb17694f45fce32a4567f8f2de0f3378393fc8.file @@ -0,0 +1,272 @@ + + + + +canberra-gtk + + + + + + + + +
+ + + + + + + + + +
+
+
+ + +
+

canberra-gtk

+

canberra-gtk — Gtk+ libcanberra Bindings

+
+
+

Synopsis

+
ca_context *        ca_gtk_context_get                  (void);
+int                 ca_gtk_proplist_set_for_widget      (ca_proplist *p,
+                                                         GtkWidget *w);
+int                 ca_gtk_play_for_widget              (GtkWidget *w,
+                                                         uint32_t id,
+                                                         ...);
+int                 ca_gtk_proplist_set_for_event       (ca_proplist *p,
+                                                         GdkEvent *e);
+int                 ca_gtk_play_for_event               (GdkEvent *e,
+                                                         uint32_t id,
+                                                         ...);
+void                ca_gtk_widget_disable_sounds        (GtkWidget *w,
+                                                         gboolean enable);
+
+
+
+

Description

+

+libcanberra-gtk provides a few functions that simplify libcanberra +usage from Gtk+ programs. It maintains a single ca_context object +per GdkScreen that is made accessible via +ca_gtk_context_get_for_screen(), with a shortcut ca_gtk_context_get() +to get the context for the default screen. More importantly, it provides +a few functions +to compile event sound property lists based on GtkWidget objects or +GdkEvent events. +

+
+
+

Details

+
+

ca_gtk_context_get ()

+
ca_context *        ca_gtk_context_get                  (void);
+

+Gets the single ca_context object for the default screen. See +ca_gtk_context_get_for_screen(). +

+
++++ + + + + +

Returns :

a ca_context object. The object is owned by libcanberra-gtk +and must not be destroyed
+
+
+
+

ca_gtk_proplist_set_for_widget ()

+
int                 ca_gtk_proplist_set_for_widget      (ca_proplist *p,
+                                                         GtkWidget *w);
+

+Fill in a ca_proplist object for a sound event that shall originate +from the specified Gtk Widget. This will fill in properties like +CA_PROP_WINDOW_NAME or CA_PROP_WINDOW_X11_DISPLAY for you. +

+
++++ + + + + + + + + + + + + + + +

p :

The proplist to store these sound event properties in

w :

The Gtk widget to base these sound event properties on

Returns :

0 on success, negative error code on error.
+
+
+
+

ca_gtk_play_for_widget ()

+
int                 ca_gtk_play_for_widget              (GtkWidget *w,
+                                                         uint32_t id,
+                                                         ...);
+

+Play a sound event for the specified widget. This will internally +call ca_gtk_proplist_set_for_widget() and then merge them with the +properties passed in via the NULL terminated argument +list. Finally, it will call ca_context_play_full() to actually play +the event sound. +

+
++++ + + + + + + + + + + + + + + + + + + +

w :

The Gtk widget to base these sound event properties on

id :

The event id that can later be used to cancel this event sound +using ca_context_cancel(). This can be any integer and shall be +chosen be the client program. It is a good idea to pass 0 here if +cancelling the sound later is not needed. If the same id is passed +to multiple sounds they can be canceled with a single +ca_context_cancel() call.

... :

additional event properties as pairs of strings, terminated by NULL.

Returns :

0 on success, negative error code on error.
+
+
+
+

ca_gtk_proplist_set_for_event ()

+
int                 ca_gtk_proplist_set_for_event       (ca_proplist *p,
+                                                         GdkEvent *e);
+

+Fill in a ca_proplist object for a sound event that is being +triggered by the specified Gdk Event. This will fill in properties +like CA_PROP_EVENT_MOUSE_X or CA_PROP_EVENT_MOUSE_BUTTON for +you. This will internally also cal ca_gtk_proplist_set_for_widget() +on the widget this event belongs to. +

+
++++ + + + + + + + + + + + + + + +

p :

The proplist to store these sound event properties in

e :

The Gdk event to base these sound event properties on

Returns :

0 on success, negative error code on error.
+
+
+
+

ca_gtk_play_for_event ()

+
int                 ca_gtk_play_for_event               (GdkEvent *e,
+                                                         uint32_t id,
+                                                         ...);
+

+Play a sound event for the specified event. This will internally +call ca_gtk_proplist_set_for_event() and then merge them with the +properties passed in via the NULL terminated argument +list. Finally, it will call ca_context_play_full() to actually play +the event sound. +

+
++++ + + + + + + + + + + + + + + + + + + +

e :

The Gdk event to base these sound event properties on

id :

The event id that can later be used to cancel this event sound +using ca_context_cancel(). This can be any integer and shall be +chosen be the client program. It is a good idea to pass 0 here if +cancelling the sound later is not needed. If the same id is passed +to multiple sounds they can be canceled with a single +ca_context_cancel() call.

... :

additional event properties as pairs of strings, terminated by NULL.

Returns :

0 on success, negative error code on error.
+
+
+
+

ca_gtk_widget_disable_sounds ()

+
void                ca_gtk_widget_disable_sounds        (GtkWidget *w,
+                                                         gboolean enable);
+

+By default sound events are automatically generated for all kinds +of input events. Use this function to disable this. This is +intended to be used for widgets which directly generate sound +events. +

+
++++ + + + + + + + + + + +

w :

The Gtk widget to disable automatic event sounds for.

enable :

Boolean specifying whether sound events shall be enabled or disabled for this widget.
+
+
+
+ + + \ No newline at end of file diff --git a/.flatpak-builder/cache/objects/6a/4948e4dd0304114368c7e48c15005fdbfbf39945d4e5a798dc0f1c8fddaad8.file b/.flatpak-builder/cache/objects/6a/4948e4dd0304114368c7e48c15005fdbfbf39945d4e5a798dc0f1c8fddaad8.file new file mode 100644 index 0000000..2231de4 Binary files /dev/null and b/.flatpak-builder/cache/objects/6a/4948e4dd0304114368c7e48c15005fdbfbf39945d4e5a798dc0f1c8fddaad8.file differ diff --git a/.flatpak-builder/cache/objects/6a/6810459f5c6e26331ec5cfc0446d680f8ac6d558b5511d43dbc0a0d15d0e3a.file b/.flatpak-builder/cache/objects/6a/6810459f5c6e26331ec5cfc0446d680f8ac6d558b5511d43dbc0a0d15d0e3a.file new file mode 100644 index 0000000..8233960 --- /dev/null +++ b/.flatpak-builder/cache/objects/6a/6810459f5c6e26331ec5cfc0446d680f8ac6d558b5511d43dbc0a0d15d0e3a.file @@ -0,0 +1,665 @@ +/* + * Copyright (C) 2007 - 2013 Vivien Malerba + * Copyright (C) 2008 - 2011 Murray Cumming + * Copyright (C) 2009 Bas Driessen + * Copyright (C) 2010 David King + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include +#include +#include "gda-vconnection-data-model.h" +#include "gda-vconnection-data-model-private.h" +#include "gda-virtual-provider.h" +#include +#include +#include "../gda-sqlite.h" + +static void gda_vconnection_data_model_class_init (GdaVconnectionDataModelClass *klass); +static void gda_vconnection_data_model_init (GdaVconnectionDataModel *cnc); +static void gda_vconnection_data_model_dispose (GObject *object); + + +typedef struct { + GSList *table_data_list; /* list of GdaVConnectionTableData structures */ + + GMutex lock_context; + GdaStatement *executed_stmt; +} GdaVconnectionDataModelPrivate; + +G_DEFINE_TYPE_WITH_PRIVATE (GdaVconnectionDataModel, gda_vconnection_data_model, GDA_TYPE_VIRTUAL_CONNECTION) + + +static gboolean get_rid_of_vtable (GdaVconnectionDataModel *cnc, GdaVConnectionTableData *td, gboolean force, GError **error); + +enum { + VTABLE_CREATED, + VTABLE_DROPPED, + LAST_SIGNAL +}; + +static gint gda_vconnection_data_model_signals[LAST_SIGNAL] = { 0, 0 }; + +static GObjectClass *parent_class = NULL; + +#ifdef GDA_DEBUG_NO +static void +dump_all_tables (GdaVconnectionDataModel *cnc) +{ + GSList *list; + g_print ("GdaVconnectionDataModel's tables:\n"); + for (list = cnc->priv->table_data_list; list; list = list->next) { + GdaVConnectionTableData *td = (GdaVConnectionTableData *) list->data; + g_print (" table %s, td=%p, spec=%p\n", td->table_name, td, td->spec); + } +} +#endif + +static void +vtable_created (GdaVconnectionDataModel *cnc, const gchar *table_name) +{ + _gda_connection_signal_meta_table_update ((GdaConnection *)cnc, table_name); +#ifdef GDA_DEBUG_NO + dump_all_tables (cnc); +#endif +} + +static void +vtable_dropped (GdaVconnectionDataModel *cnc, const gchar *table_name) +{ + GdaVconnectionDataModelPrivate *priv = gda_vconnection_data_model_get_instance_private (cnc); + GdaVConnectionTableData *td; + td = _gda_vconnection_get_table_data_by_name (cnc, table_name); + if (td) + priv->table_data_list = g_slist_remove (priv->table_data_list, td); + _gda_connection_signal_meta_table_update ((GdaConnection *)cnc, table_name); +#ifdef GDA_DEBUG_NO + dump_all_tables (cnc); +#endif +} + +/* + * GdaVconnectionDataModel class implementation + */ +static void +gda_vconnection_data_model_class_init (GdaVconnectionDataModelClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + parent_class = g_type_class_peek_parent (klass); + + /** + * GdaVconnectionDataModel::vtable-created + * @cnc: the #GdaVconnectionDataModel connection + * @spec: the #GdaVconnectionDataModelSpec for the new virtual table + * + * Signal emitted when a new virtual table has been declared + */ + gda_vconnection_data_model_signals[VTABLE_CREATED] = + g_signal_new ("vtable-created", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GdaVconnectionDataModelClass, vtable_created), + NULL, NULL, + g_cclosure_marshal_VOID__STRING, + G_TYPE_NONE, 1, G_TYPE_STRING); + /** + * GdaVconnectionDataModel::vtable-dropped + * @cnc: the #GdaVconnectionDataModel connection + * @spec: the #GdaVconnectionDataModelSpec for the new virtual table + * + * Signal emitted when a new virtual table has been undeclared + */ + gda_vconnection_data_model_signals[VTABLE_DROPPED] = + g_signal_new ("vtable-dropped", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GdaVconnectionDataModelClass, vtable_dropped), + NULL, NULL, + g_cclosure_marshal_VOID__STRING, + G_TYPE_NONE, 1, G_TYPE_STRING); + + klass->vtable_created = vtable_created; + klass->vtable_dropped = vtable_dropped; + + object_class->dispose = gda_vconnection_data_model_dispose; +} + +static void +gda_vconnection_data_model_init (GdaVconnectionDataModel *cnc) +{ + GdaVconnectionDataModelPrivate *priv = gda_vconnection_data_model_get_instance_private (cnc); + priv = g_new (GdaVconnectionDataModelPrivate, 1); + priv->table_data_list = NULL; + g_mutex_init (& (priv->lock_context)); + + g_object_set (G_OBJECT (cnc), "cnc-string", "_IS_VIRTUAL=TRUE", NULL); +} + +static void +gda_vconnection_data_model_dispose (GObject *object) +{ + GdaVconnectionDataModel *cnc = (GdaVconnectionDataModel *) object; + g_return_if_fail (GDA_IS_VCONNECTION_DATA_MODEL (cnc)); + GdaVconnectionDataModelPrivate *priv = gda_vconnection_data_model_get_instance_private (cnc); + + + /* free memory */ + if (priv->table_data_list != NULL) { + while (priv->table_data_list) { + GdaVConnectionTableData *td; + td = (GdaVConnectionTableData *) priv->table_data_list->data; + get_rid_of_vtable (cnc, td, TRUE, NULL); + } + } + g_mutex_clear (&(priv->lock_context)); + + /* chain to parent class */ + parent_class->dispose (object); +} + +static void +spec_destroy_func (GdaVconnectionDataModelSpec *spec) +{ + g_object_unref (spec->data_model); + g_free (spec); +} + +static GList * +create_columns (GdaVconnectionDataModelSpec *spec, G_GNUC_UNUSED GError **error) +{ + g_return_val_if_fail (spec->data_model, NULL); + + GList *columns = NULL; + guint i, ncols; + ncols = gda_data_model_get_n_columns (spec->data_model); + for (i = 0; i < ncols; i++) { + GdaColumn *mcol = gda_data_model_describe_column (spec->data_model, i); + GdaColumn *ccol = gda_column_copy (mcol); + columns = g_list_prepend (columns, ccol); + } + return g_list_reverse (columns); +} + +/** + * gda_vconnection_data_model_add_model: + * @cnc: a #GdaVconnectionDataModel connection + * @model: a #GdaDataModel + * @table_name: the name of the table + * @error: a place to store errors, or %NULL + * + * Make @model appear as a table named @table_name in the @cnc connection (as if a + * "CREATE TABLE..." statement was executed, except that the data contained within @model + * is actually used when @table_name's contents is read or written). + * + * For a more general approach, see the gda_vconnection_data_model_add() method. + * + * Returns: %TRUE if no error occurred + */ +gboolean +gda_vconnection_data_model_add_model (GdaVconnectionDataModel *cnc, + GdaDataModel *model, const gchar *table_name, GError **error) +{ + g_return_val_if_fail (GDA_IS_DATA_MODEL (model), FALSE); + GdaVconnectionDataModelSpec *spec; + gboolean retval; + + spec = g_new0 (GdaVconnectionDataModelSpec, 1); + spec->data_model = g_object_ref (model); + spec->create_columns_func = create_columns; + retval = gda_vconnection_data_model_add (cnc, spec, (GDestroyNotify) spec_destroy_func, table_name, error); + + return retval; +} + +/** + * gda_vconnection_data_model_add: + * @cnc: a #GdaVconnectionDataModel connection + * @spec: a #GdaVconnectionDataModelSpec structure, used AS IS (not copied) and can be modified + * @spec_free_func: (allow-none): function to call when freeing @spec, or %NULL + * @table_name: the name of the table + * @error: a place to store errors, or %NULL + * + * Create a new virtual table named @table_name in @cnc. The contents of that new table + * is dictated by what's in @spec. + * + * If there is just one #GdaDataModel to make appear as a table + * then the gda_vconnection_data_model_add_model() method is easier to use. + * + * The @spec_free_func can (depending on your code) be used to clean memory allocated for @spec or + * @spec->data_model. + * + * If an error occurs, then the @spec_free_func function is called using @spec as argument. + * + * Returns: %TRUE if no error occurred + */ +gboolean +gda_vconnection_data_model_add (GdaVconnectionDataModel *cnc, GdaVconnectionDataModelSpec *spec, + GDestroyNotify spec_free_func, const gchar *table_name, GError **error) +{ + GdaSqliteProvider *prov; + gchar *str; + int rc; + char *zErrMsg = NULL; + gboolean retval = TRUE; + SqliteConnectionData *scnc; + + static gint counter = 0; + + g_return_val_if_fail (GDA_IS_VCONNECTION_DATA_MODEL (cnc), FALSE); + g_return_val_if_fail (table_name && *table_name, FALSE); + g_return_val_if_fail (spec, FALSE); + g_return_val_if_fail (spec->data_model || (spec->create_columns_func && (spec->create_model_func || spec->create_filtered_model_func)), FALSE); + + GdaVconnectionDataModelPrivate *priv = gda_vconnection_data_model_get_instance_private (cnc); + + /* cleaning functions */ + if (spec->data_model) { + g_return_val_if_fail (GDA_IS_DATA_MODEL (spec->data_model), FALSE); + spec->create_columns_func = create_columns; + spec->create_model_func = NULL; + spec->create_filter_func = NULL; + spec->create_filtered_model_func = NULL; + } + else if (spec->create_filter_func) + spec->create_model_func = NULL; + else { + spec->create_filter_func = NULL; + spec->create_filtered_model_func = NULL; + } + + scnc = (SqliteConnectionData*) gda_connection_internal_get_provider_data_error ((GdaConnection *) cnc, error); + if (!scnc) + return FALSE; + + /* create a new GdaVConnectionTableData structure for this virtual table */ + GdaVConnectionTableData *td; + td = g_new0 (GdaVConnectionTableData, 1); + td->spec = spec; + td->spec_free_func = spec_free_func; + td->table_name = _gda_connection_compute_table_virtual_name (GDA_CONNECTION (cnc), table_name); + td->unique_name = g_strdup_printf ("Spec%d", counter++); + priv->table_data_list = g_slist_append (priv->table_data_list, td); + + /* actually create the virtual table in @cnc */ + prov = (GdaSqliteProvider *) gda_connection_get_provider (GDA_CONNECTION (cnc)); + str = g_strdup_printf ("CREATE VIRTUAL TABLE %s USING %s ('%s')", td->table_name, G_OBJECT_TYPE_NAME (prov), td->unique_name); + rc = SQLITE3_CALL (prov, sqlite3_exec) (scnc->connection, str, NULL, 0, &zErrMsg); + g_free (str); + if (rc != SQLITE_OK) { + g_set_error (error, GDA_SERVER_PROVIDER_ERROR, + GDA_SERVER_PROVIDER_INTERNAL_ERROR, + "%s", zErrMsg); + SQLITE3_CALL (prov, sqlite3_free) (zErrMsg); + _gda_vconnection_data_model_table_data_free (td); + priv->table_data_list = g_slist_remove (priv->table_data_list, td); + retval = FALSE; + } + else { + g_signal_emit (G_OBJECT (cnc), gda_vconnection_data_model_signals[VTABLE_CREATED], 0, + td->table_name); + /*g_print ("Virtual connection: added table %s (spec = %p)\n", td->table_name, td->spec);*/ + } + + return retval; +} + +static gboolean +get_rid_of_vtable (GdaVconnectionDataModel *cnc, GdaVConnectionTableData *td, gboolean force, GError **error) +{ + gchar *str; + int rc; + char *zErrMsg = NULL; + gboolean allok = TRUE; + GdaSqliteProvider *prov; + GdaVconnectionDataModelPrivate *priv = gda_vconnection_data_model_get_instance_private (cnc); + + SqliteConnectionData *scnc; + scnc = (SqliteConnectionData*) gda_connection_internal_get_provider_data_error ((GdaConnection *) cnc, error); + if (!scnc && !force) + return FALSE; + prov = (GdaSqliteProvider *) gda_connection_get_provider (GDA_CONNECTION (cnc)); + + if (scnc) { + str = g_strdup_printf ("DROP TABLE %s", td->table_name); + rc = SQLITE3_CALL (prov, sqlite3_exec) (scnc->connection, str, NULL, 0, &zErrMsg); + g_free (str); + + if (rc != SQLITE_OK) { + g_set_error (error, GDA_SERVER_PROVIDER_ERROR, + GDA_SERVER_PROVIDER_INTERNAL_ERROR, + "%s", zErrMsg); + SQLITE3_CALL (prov, sqlite3_free) (zErrMsg); + allok = FALSE; + if (!force) + return FALSE; + } + } + + /* clean the priv->table_data_list list */ + priv->table_data_list = g_slist_remove (priv->table_data_list, td); + g_signal_emit (G_OBJECT (cnc), gda_vconnection_data_model_signals[VTABLE_DROPPED], 0, + td->table_name); + /*g_print ("Virtual connection: removed table %s (%p)\n", td->table_name, td->spec->data_model);*/ + _gda_vconnection_data_model_table_data_free (td); + + return allok; +} + +/** + * gda_vconnection_data_model_remove: + * @cnc: a #GdaVconnectionDataModel connection + * @table_name: the name of the table to remove from @cnc + * @error: a place to store errors, or %NULL + * + * Remove the table named @table_name in the @cnc connection (as if a "DROP TABLE..." + * statement was executed, except that no data gets destroyed as the associated data model remains the same). + * + * Returns: %TRUE if no error occurred + */ +gboolean +gda_vconnection_data_model_remove (GdaVconnectionDataModel *cnc, const gchar *table_name, GError **error) +{ + GdaVConnectionTableData *td; + + g_return_val_if_fail (GDA_IS_VCONNECTION_DATA_MODEL (cnc), FALSE); + g_return_val_if_fail (table_name && *table_name, FALSE); + + td = _gda_vconnection_get_table_data_by_name (cnc, table_name); + if (!td) { + g_set_error (error, GDA_SERVER_PROVIDER_ERROR, + GDA_SERVER_PROVIDER_MISUSE_ERROR, + "%s", _("Table to remove not found")); + return FALSE; + } + + return get_rid_of_vtable (cnc, td, FALSE, error); +} + +/** + * gda_vconnection_data_model_get: + * @cnc: a #GdaVconnectionDataModel connection + * @table_name: a table name within @cnc + * + * Find the #GdaVconnectionDataModelSpec specifying how the table named @table_name is represented + * in @cnc. + * + * Returns: (transfer none) (allow-none): a #GdaVconnectionDataModelSpec pointer, of %NULL if there is no table named @table_name + * + * Since: 4.2.6 + */ +GdaVconnectionDataModelSpec * +gda_vconnection_data_model_get (GdaVconnectionDataModel *cnc, const gchar *table_name) +{ + GdaVConnectionTableData *td; + g_return_val_if_fail (GDA_IS_VCONNECTION_DATA_MODEL (cnc), NULL); + if (!table_name || !(*table_name)) + return NULL; + td = _gda_vconnection_get_table_data_by_name (cnc, table_name); + if (td) + return td->spec; + else + return NULL; +} + +/** + * gda_vconnection_data_model_get_model: + * @cnc: a #GdaVconnectionDataModel connection + * @table_name: a table name within @cnc + * + * Find the #GdaDataModel object representing the @table_name table in @cnc. it can return %NULL + * either if no table named @table_name exists, or if that table actually exists but no #GdaDataModel + * has yet been created. For a more general approach, use the gda_vconnection_data_model_get(). + * + * Returns: (transfer none) (allow-none): the #GdaDataModel, or %NULL + */ +GdaDataModel * +gda_vconnection_data_model_get_model (GdaVconnectionDataModel *cnc, const gchar *table_name) +{ + GdaVConnectionTableData *td; + g_return_val_if_fail (GDA_IS_VCONNECTION_DATA_MODEL (cnc), NULL); + + if (!table_name || !(*table_name)) + return NULL; + + td = _gda_vconnection_get_table_data_by_name (cnc, table_name); + if (td) + return td->spec->data_model; + else + return NULL; +} + +/** + * gda_vconnection_data_model_get_table_name: + * @cnc: a #GdaVconnectionDataModel connection + * @model: a #GdaDataModel representing a table within @cnc + * + * Find the name of the table associated to @model in @cnc + * + * Returns: (transfer none) (allow-none): the table name, or %NULL if not found + */ +const gchar * +gda_vconnection_data_model_get_table_name (GdaVconnectionDataModel *cnc, GdaDataModel *model) +{ + GdaVConnectionTableData *td; + g_return_val_if_fail (GDA_IS_VCONNECTION_DATA_MODEL (cnc), NULL); + + if (!model) + return NULL; + + g_return_val_if_fail (GDA_IS_DATA_MODEL (model), NULL); + + td = _gda_vconnection_get_table_data_by_model (cnc, model); + if (td) + return td->table_name; + else + return NULL; +} + +/** + * gda_vconnection_data_model_foreach: + * @cnc: a #GdaVconnectionDataModel connection + * @func: a #GdaVconnectionDataModelFunc function pointer + * @data: data to pass to @func calls + * + * Call @func for each table in @cnc. + * + * Warning: @func will be called for any table present in @cnc even if no data + * model represents the contents of the table (which means the 1st argument of @func + * may be %NULL) + */ +void +gda_vconnection_data_model_foreach (GdaVconnectionDataModel *cnc, + GdaVconnectionDataModelFunc func, gpointer data) +{ + GSList *copy, *list; + g_return_if_fail (GDA_IS_VCONNECTION_DATA_MODEL (cnc)); + GdaVconnectionDataModelPrivate *priv = gda_vconnection_data_model_get_instance_private (cnc); + if (!func || !priv->table_data_list) + return; + + copy = g_slist_copy (priv->table_data_list); + for (list = copy; list; list = list->next) { + GdaVConnectionTableData *td = (GdaVConnectionTableData*) list->data; + func (td->spec->data_model, td->table_name, data); + } + g_slist_free (copy); +} + +/* + * private + */ +GdaVConnectionTableData * +_gda_vconnection_get_table_data_by_name (GdaVconnectionDataModel *cnc, const gchar *table_name) +{ + GSList *list; + gchar *quoted; + GdaVconnectionDataModelPrivate *priv = gda_vconnection_data_model_get_instance_private (cnc); + if (!table_name || !*table_name) + return NULL; + quoted = _gda_connection_compute_table_virtual_name (GDA_CONNECTION (cnc), table_name); + for (list = priv->table_data_list; list; list = list->next) { + if (!strcmp (((GdaVConnectionTableData*) list->data)->table_name, quoted)) { + g_free (quoted); + return (GdaVConnectionTableData*) list->data; + } + } + g_free (quoted); + return NULL; +} + +GdaVConnectionTableData * +_gda_vconnection_get_table_data_by_unique_name (GdaVconnectionDataModel *cnc, const gchar *unique_name) +{ + GSList *list; + GdaVconnectionDataModelPrivate *priv = gda_vconnection_data_model_get_instance_private (cnc); + + for (list = priv->table_data_list; list; list = list->next) { + if (!strcmp (((GdaVConnectionTableData*) list->data)->unique_name, unique_name)) + return (GdaVConnectionTableData*) list->data; + } + return NULL; +} + +GdaVConnectionTableData * +_gda_vconnection_get_table_data_by_model (GdaVconnectionDataModel *cnc, GdaDataModel *model) +{ + GSList *list; + GdaVconnectionDataModelPrivate *priv = gda_vconnection_data_model_get_instance_private (cnc); + + for (list = priv->table_data_list; list; list = list->next) { + if (((GdaVConnectionTableData*) list->data)->real_model == model) + return (GdaVConnectionTableData*) list->data; + } + return NULL; +} + +void +_gda_vconnection_data_model_table_data_free (GdaVConnectionTableData *td) +{ + ParamType i; + + if (td->real_model) + g_object_unref (td->real_model); + if (td->columns) { + g_list_free_full (td->columns, g_object_unref); + td->columns = NULL; + } + g_free (td->table_name); + g_free (td->unique_name); + if (td->spec_free_func) + td->spec_free_func (td->spec); + for (i = 0; i < PARAMS_NB; i++) { + if (td->modif_params[i]) + g_object_unref (td->modif_params[i]); + if (td->modif_stmt[i]) + g_object_unref (td->modif_stmt[i]); + } + + if (td->context.hash) + g_hash_table_destroy (td->context.hash); + g_free (td); +} + +static void +vcontext_free (VContext *context) +{ + g_weak_ref_set (&context->context_object, NULL); + if (context->context_data) { + g_ptr_array_free (context->context_data, TRUE); + context->context_data = NULL; + } + g_free (context); +#ifdef DEBUG_VCONTEXT + g_print ("VCFree %p\n", context); +#endif +} + +void +_gda_vconnection_set_working_obj (GdaVconnectionDataModel *cnc, GObject *obj) +{ + GSList *list; + GdaVconnectionDataModelPrivate *priv = gda_vconnection_data_model_get_instance_private (cnc); + if (obj) { + g_mutex_lock (& (priv->lock_context)); + for (list = priv->table_data_list; list; list = list->next) { + GdaVConnectionTableData *td = (GdaVConnectionTableData*) list->data; + VContext *vc = NULL; + + g_assert (!td->context.current_vcontext); + td->context.mutex = &(priv->lock_context); + if (! td->context.hash) + td->context.hash = g_hash_table_new_full (g_direct_hash, g_direct_equal, + NULL, (GDestroyNotify) vcontext_free); + else + vc = g_hash_table_lookup (td->context.hash, obj); + + if (! vc) { + vc = g_new0 (VContext, 1); + g_weak_ref_set (&vc->context_object, obj); + vc->context_data = g_ptr_array_new_with_free_func ((GDestroyNotify) _gda_vconnection_virtual_filtered_data_unref); + vc->vtable = td; + g_hash_table_insert (td->context.hash, obj, vc); +#ifdef DEBUG_VCONTEXT + g_print ("VCNew %p\n", vc); +#endif + } + td->context.current_vcontext = vc; + } + } + else { + for (list = priv->table_data_list; list; list = list->next) { + GdaVConnectionTableData *td = (GdaVConnectionTableData*) list->data; + /* REM: td->context.current_vcontext may already be NULL in case + * an exception already occurred */ + td->context.current_vcontext = NULL; + } + g_mutex_unlock (& (priv->lock_context)); + } +} + +void +_gda_vconnection_change_working_obj (GdaVconnectionDataModel *cnc, GObject *obj) +{ + GSList *list; + GObject *old_obj; + GdaVconnectionDataModelPrivate *priv = gda_vconnection_data_model_get_instance_private (cnc); + + for (list = priv->table_data_list; list; list = list->next) { + GdaVConnectionTableData *td = (GdaVConnectionTableData*) list->data; + if (!td->context.hash) + continue; + + g_assert (td->context.current_vcontext); + + VContext *ovc, *nvc; + ovc = td->context.current_vcontext; + nvc = g_new0 (VContext, 1); + g_weak_ref_init (&nvc->context_object, obj); + nvc->vtable = ovc->vtable; + nvc->context_data = ovc->context_data; + ovc->context_data = NULL; + g_hash_table_insert (td->context.hash, obj, nvc); +#ifdef DEBUG_VCONTEXT + g_print ("VCNew %p\n", nvc); +#endif + old_obj = g_weak_ref_get (&ovc->context_object); + if (old_obj != NULL) { + g_hash_table_remove (td->context.hash, old_obj); + } + } +} diff --git a/.flatpak-builder/cache/objects/6a/7f941e45d0385abbb4a4ae5e398fa2afa59dc0e1f0a5bfae992ee2f3fce677.dirtree b/.flatpak-builder/cache/objects/6a/7f941e45d0385abbb4a4ae5e398fa2afa59dc0e1f0a5bfae992ee2f3fce677.dirtree new file mode 100644 index 0000000..9a00882 Binary files /dev/null and b/.flatpak-builder/cache/objects/6a/7f941e45d0385abbb4a4ae5e398fa2afa59dc0e1f0a5bfae992ee2f3fce677.dirtree differ diff --git a/.flatpak-builder/cache/objects/6a/99c11efdee92254b945408728b4cd860dbcf7182d140cd630d4d02eae5428d.file b/.flatpak-builder/cache/objects/6a/99c11efdee92254b945408728b4cd860dbcf7182d140cd630d4d02eae5428d.file new file mode 100644 index 0000000..f788f8e --- /dev/null +++ b/.flatpak-builder/cache/objects/6a/99c11efdee92254b945408728b4cd860dbcf7182d140cd630d4d02eae5428d.file @@ -0,0 +1,37 @@ +/*** + This file is part of libcanberra. + + Copyright 2009 Lennart Poettering + + libcanberra is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation, either version 2.1 of the + License, or (at your option) any later version. + + libcanberra is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with libcanberra. If not, see + . +***/ + +using Canberra; +using Gdk; +using Gtk; + +[CCode (cprefix = "CA_GTK_", lower_case_cprefix = "ca_gtk_", cheader_filename = "canberra-gtk.h")] +namespace CanberraGtk { + + public unowned Context? context_get(); + public unowned Context? context_get_for_screen(Gdk.Screen? screen); + + public int proplist_set_for_widget(Proplist p, Gtk.Widget w); + public int play_for_widget(Gtk.Widget w, uint32 id, ...); + public int proplist_set_for_event(Proplist p, Gdk.Event e); + public int play_for_event(Gdk.Event e, uint32 id, ...); + + public void widget_disable_sounds(Gtk.Widget w, bool enable = false); +} diff --git a/.flatpak-builder/cache/objects/6a/a3d9ae9d4e10346e9a57f25e1f2488c80c65a1e33ca6e8cb0931ce1176a7b5.file b/.flatpak-builder/cache/objects/6a/a3d9ae9d4e10346e9a57f25e1f2488c80c65a1e33ca6e8cb0931ce1176a7b5.file new file mode 100644 index 0000000..325889c --- /dev/null +++ b/.flatpak-builder/cache/objects/6a/a3d9ae9d4e10346e9a57f25e1f2488c80c65a1e33ca6e8cb0931ce1176a7b5.file @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2005 Dan Winship + * Copyright (C) 2005 - 2011 Vivien Malerba + * Copyright (C) 2005 Álvaro Peña + * Copyright (C) 2007 Armin Burgmeier + * Copyright (C) 2007 - 2009 Murray Cumming + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef _GDA_STATEMENT_STRUCT_DELETE_H_ +#define _GDA_STATEMENT_STRUCT_DELETE_H_ + +#include +#include +#include +#include +#include + +G_BEGIN_DECLS + +/* + * Structure definition + */ +/** + * GdaSqlStatementDelete: + * @any: + * @table: + * @cond: + */ +struct _GdaSqlStatementDelete { + GdaSqlAnyPart any; + GdaSqlTable *table; + GdaSqlExpr *cond; + + /*< private >*/ + /* Padding for future expansion */ + gpointer _gda_reserved1; + gpointer _gda_reserved2; +}; + +/* + * Common operations + */ +GdaSqlStatementContentsInfo *_gda_sql_statement_delete_get_infos (void); + +/* + * Functions used by the parser + */ +void gda_sql_statement_delete_take_table_name (GdaSqlStatement *stmt, GValue *value); +void gda_sql_statement_delete_take_condition (GdaSqlStatement *stmt, GdaSqlExpr *cond); + +G_END_DECLS + +#endif diff --git a/.flatpak-builder/cache/objects/6a/aeee17872339d4a22ce7b823e7123ae5c9c8b2843d472239062625cf07cea2.dirtree b/.flatpak-builder/cache/objects/6a/aeee17872339d4a22ce7b823e7123ae5c9c8b2843d472239062625cf07cea2.dirtree new file mode 100644 index 0000000..d14540f Binary files /dev/null and b/.flatpak-builder/cache/objects/6a/aeee17872339d4a22ce7b823e7123ae5c9c8b2843d472239062625cf07cea2.dirtree differ diff --git a/.flatpak-builder/cache/objects/6b/3d174a92a3329620a8c7552861821129489c4b8d8784ad02148e153b647f30.dirtree b/.flatpak-builder/cache/objects/6b/3d174a92a3329620a8c7552861821129489c4b8d8784ad02148e153b647f30.dirtree new file mode 100644 index 0000000..e6b6187 Binary files /dev/null and b/.flatpak-builder/cache/objects/6b/3d174a92a3329620a8c7552861821129489c4b8d8784ad02148e153b647f30.dirtree differ diff --git a/.flatpak-builder/cache/objects/6b/b2e47ccc8b1f51d67aee08ee0bebd4b3f9f9bcf79505073c444abf5f244e90.file b/.flatpak-builder/cache/objects/6b/b2e47ccc8b1f51d67aee08ee0bebd4b3f9f9bcf79505073c444abf5f244e90.file new file mode 120000 index 0000000..13f4583 --- /dev/null +++ b/.flatpak-builder/cache/objects/6b/b2e47ccc8b1f51d67aee08ee0bebd4b3f9f9bcf79505073c444abf5f244e90.file @@ -0,0 +1 @@ +../../share/runtime/locale/lt/share/lt \ No newline at end of file diff --git a/.flatpak-builder/cache/objects/6b/c2eca095ad671075dfa6f835a956c87ee5f5556baf740bdc9591df9c1af693.file b/.flatpak-builder/cache/objects/6b/c2eca095ad671075dfa6f835a956c87ee5f5556baf740bdc9591df9c1af693.file new file mode 100644 index 0000000..cc42548 Binary files /dev/null and b/.flatpak-builder/cache/objects/6b/c2eca095ad671075dfa6f835a956c87ee5f5556baf740bdc9591df9c1af693.file differ diff --git a/.flatpak-builder/cache/objects/6c/796bbe5439d5ebe2df04ca5d63d1b7bb1a1aef7661f8e661b8834cab5d7d3e.file b/.flatpak-builder/cache/objects/6c/796bbe5439d5ebe2df04ca5d63d1b7bb1a1aef7661f8e661b8834cab5d7d3e.file new file mode 100644 index 0000000..91ab68b --- /dev/null +++ b/.flatpak-builder/cache/objects/6c/796bbe5439d5ebe2df04ca5d63d1b7bb1a1aef7661f8e661b8834cab5d7d3e.file @@ -0,0 +1,54 @@ +/*-*- Mode: C; c-basic-offset: 8 -*-*/ + +#ifndef foocanberramallochfoo +#define foocanberramallochfoo + +/*** + This file is part of libcanberra. + + Copyright 2008 Lennart Poettering + + libcanberra is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation, either version 2.1 of the + License, or (at your option) any later version. + + libcanberra is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with libcanberra. If not, see + . +***/ + +#include +#include + +#include "canberra.h" +#include "macro.h" + +#ifndef PACKAGE +#error "Please include config.h before including this file!" +#endif + +#define ca_malloc malloc +#define ca_free free +#define ca_malloc0(size) calloc(1, (size)) +#define ca_strdup strdup +#ifdef HAVE_STRNDUP +#define ca_strndup strndup +#else +char *ca_strndup(const char *s, size_t n); +#endif + +void* ca_memdup(const void* p, size_t size); + +#define ca_new(t, n) ((t*) ca_malloc(sizeof(t)*(n))) +#define ca_new0(t, n) ((t*) ca_malloc0(sizeof(t)*(n))) +#define ca_newdup(t, p, n) ((t*) ca_memdup(p, sizeof(t)*(n))) + +char *ca_sprintf_malloc(const char *format, ...) __attribute__((format(printf, 1, 2))); + +#endif diff --git a/.flatpak-builder/cache/objects/6c/9006286f7e2a40c9c05d2291b41480170792000854edf057a59a727371e502.dirtree b/.flatpak-builder/cache/objects/6c/9006286f7e2a40c9c05d2291b41480170792000854edf057a59a727371e502.dirtree new file mode 100644 index 0000000..4274d97 Binary files /dev/null and b/.flatpak-builder/cache/objects/6c/9006286f7e2a40c9c05d2291b41480170792000854edf057a59a727371e502.dirtree differ diff --git a/.flatpak-builder/cache/objects/6c/d544b296da3b52fde9c38b162fb6e7960ac129d1c9533808cca61303e29041.dirtree b/.flatpak-builder/cache/objects/6c/d544b296da3b52fde9c38b162fb6e7960ac129d1c9533808cca61303e29041.dirtree new file mode 100644 index 0000000..a150dea Binary files /dev/null and b/.flatpak-builder/cache/objects/6c/d544b296da3b52fde9c38b162fb6e7960ac129d1c9533808cca61303e29041.dirtree differ diff --git a/.flatpak-builder/cache/objects/6c/d79f46e680c1a1f62509a6475fe3b35c7cc60e2ee68d00f8484808616dc0b2.dirtree b/.flatpak-builder/cache/objects/6c/d79f46e680c1a1f62509a6475fe3b35c7cc60e2ee68d00f8484808616dc0b2.dirtree new file mode 100644 index 0000000..4f3331c Binary files /dev/null and b/.flatpak-builder/cache/objects/6c/d79f46e680c1a1f62509a6475fe3b35c7cc60e2ee68d00f8484808616dc0b2.dirtree differ diff --git a/.flatpak-builder/cache/objects/6d/400d71dfaa1d5dc5eb923c87ac88690fccd738c0af3af4df507bd137ae8cab.file b/.flatpak-builder/cache/objects/6d/400d71dfaa1d5dc5eb923c87ac88690fccd738c0af3af4df507bd137ae8cab.file new file mode 100644 index 0000000..2bb8a12 --- /dev/null +++ b/.flatpak-builder/cache/objects/6d/400d71dfaa1d5dc5eb923c87ac88690fccd738c0af3af4df507bd137ae8cab.file @@ -0,0 +1,624 @@ +/* gsound-play.c generated by valac 0.56.8, the Vala compiler + * generated from gsound-play.vala, do not modify */ + +/* gsound-play.vala + * + * Copyright (C) 2014 Tristan Brindle + * + * This file is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of the + * License, or (at your option) any later version. + * + * This file is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include "gsound.h" +#include +#include +#include + +#if !defined(VALA_EXTERN) +#if defined(_MSC_VER) +#define VALA_EXTERN __declspec(dllexport) extern +#elif __GNUC__ >= 4 +#define VALA_EXTERN __attribute__((visibility("default"))) extern +#else +#define VALA_EXTERN extern +#endif +#endif + +typedef struct _PlayData PlayData; +#define _g_option_context_free0(var) ((var == NULL) ? NULL : (var = (g_option_context_free (var), NULL))) +#define _g_object_unref0(var) ((var == NULL) ? NULL : (var = (g_object_unref (var), NULL))) +#define _g_hash_table_unref0(var) ((var == NULL) ? NULL : (var = (g_hash_table_unref (var), NULL))) +#define _g_error_free0(var) ((var == NULL) ? NULL : (var = (g_error_free (var), NULL))) +#define _g_main_loop_unref0(var) ((var == NULL) ? NULL : (var = (g_main_loop_unref (var), NULL))) + +struct _PlayData { + int _state_; + GObject* _source_object_; + GAsyncResult* _res_; + GTask* _async_result; + gint _tmp0_; + GSoundContext* _tmp1_; + GHashTable* _tmp2_; + GError* _inner_error0_; +}; + +VALA_EXTERN gchar* event_id; +gchar* event_id = NULL; +VALA_EXTERN gchar* filename; +gchar* filename = NULL; +VALA_EXTERN gchar* desc; +gchar* desc = NULL; +VALA_EXTERN gchar* cache; +gchar* cache = NULL; +VALA_EXTERN gint loops; +gint loops = 0; +VALA_EXTERN gdouble volume; +gdouble volume = 0.0; +VALA_EXTERN gchar* driver; +gchar* driver = NULL; +VALA_EXTERN GMainLoop* main_loop; +GMainLoop* main_loop = NULL; +VALA_EXTERN GSoundContext* gs_ctx; +GSoundContext* gs_ctx = NULL; +VALA_EXTERN GHashTable* attrs; +GHashTable* attrs = NULL; + +static void play_data_free (gpointer _data); +VALA_EXTERN void play (GAsyncReadyCallback _callback_, + gpointer _user_data_); +VALA_EXTERN void play_finish (GAsyncResult* _res_, + GError** error); +static gboolean play_co (PlayData* _data_); +static void play_ready (GObject* source_object, + GAsyncResult* _res_, + gpointer _user_data_); +static gint _vala_main (gchar** args, + gint args_length1); +static void _g_free0_ (gpointer var); +static void ___lambda4_ (GObject* obj, + GAsyncResult* res); +static void ____lambda4__gasync_ready_callback (GObject* source_object, + GAsyncResult* res, + gpointer self); + +const GOptionEntry opts[8] = {{"id", 'i', (gint) 0, G_OPTION_ARG_STRING, &event_id, "Event sound identifier", "STRING"}, {"file", 'f', (gint) 0, G_OPTION_ARG_FILENAME, &filename, "Play file", "PATH"}, {"description", 'd', (gint) 0, G_OPTION_ARG_STRING, &desc, "Event sound description", "STRING"}, {"cache-control", 'c', (gint) 0, G_OPTION_ARG_STRING, &cache, "Cache control (permanent, volatile, never", "STRING"}, {"loop", 'l', (gint) 0, G_OPTION_ARG_INT, &loops, "Loop many times (default: 1)", "INTEGER"}, {"volume", 'V', (gint) 0, G_OPTION_ARG_DOUBLE, &volume, "A floating point dB value for the sample volume (ex: 0.0)", "STRING"}, {"backend", 'b', (gint) 0, G_OPTION_ARG_STRING, &driver, "libcanberra backend to use", "STRING"}, {NULL}}; + +static void +play_data_free (gpointer _data) +{ + PlayData* _data_; + _data_ = _data; + g_slice_free (PlayData, _data_); +} + +void +play (GAsyncReadyCallback _callback_, + gpointer _user_data_) +{ + PlayData* _data_; + _data_ = g_slice_new0 (PlayData); + _data_->_async_result = g_task_new (NULL, NULL, _callback_, _user_data_); + g_task_set_task_data (_data_->_async_result, _data_, play_data_free); + play_co (_data_); +} + +void +play_finish (GAsyncResult* _res_, + GError** error) +{ + PlayData* _data_; + _data_ = g_task_propagate_pointer (G_TASK (_res_), error); + if (NULL == _data_) { + return; + } +} + +static void +play_ready (GObject* source_object, + GAsyncResult* _res_, + gpointer _user_data_) +{ + PlayData* _data_; +#line 52 "../tools/gsound-play.vala" + _data_ = _user_data_; +#line 52 "../tools/gsound-play.vala" + _data_->_source_object_ = source_object; +#line 52 "../tools/gsound-play.vala" + _data_->_res_ = _res_; +#line 52 "../tools/gsound-play.vala" + play_co (_data_); +#line 146 "gsound-play.c" +} + +static gboolean +play_co (PlayData* _data_) +{ +#line 49 "../tools/gsound-play.vala" + switch (_data_->_state_) { +#line 49 "../tools/gsound-play.vala" + case 0: +#line 156 "gsound-play.c" + goto _state_0; +#line 49 "../tools/gsound-play.vala" + case 1: +#line 160 "gsound-play.c" + goto _state_1; + default: +#line 49 "../tools/gsound-play.vala" + g_assert_not_reached (); +#line 165 "gsound-play.c" + } + _state_0: +#line 51 "../tools/gsound-play.vala" + while (TRUE) { +#line 51 "../tools/gsound-play.vala" + _data_->_tmp0_ = loops; +#line 51 "../tools/gsound-play.vala" + loops = _data_->_tmp0_ - 1; +#line 51 "../tools/gsound-play.vala" + if (!(_data_->_tmp0_ > 0)) { +#line 51 "../tools/gsound-play.vala" + break; +#line 178 "gsound-play.c" + } +#line 52 "../tools/gsound-play.vala" + _data_->_tmp1_ = gs_ctx; +#line 52 "../tools/gsound-play.vala" + _data_->_tmp2_ = attrs; +#line 52 "../tools/gsound-play.vala" + _data_->_state_ = 1; +#line 52 "../tools/gsound-play.vala" + gsound_context_play_fullv (_data_->_tmp1_, _data_->_tmp2_, NULL, play_ready, _data_); +#line 52 "../tools/gsound-play.vala" + return FALSE; +#line 190 "gsound-play.c" + _state_1: +#line 52 "../tools/gsound-play.vala" + gsound_context_play_full_finish (_data_->_tmp1_, _data_->_res_, &_data_->_inner_error0_); +#line 52 "../tools/gsound-play.vala" + if (G_UNLIKELY (_data_->_inner_error0_ != NULL)) { +#line 52 "../tools/gsound-play.vala" + g_task_return_error (_data_->_async_result, _data_->_inner_error0_); +#line 52 "../tools/gsound-play.vala" + g_object_unref (_data_->_async_result); +#line 52 "../tools/gsound-play.vala" + return FALSE; +#line 202 "gsound-play.c" + } + } +#line 49 "../tools/gsound-play.vala" + g_task_return_pointer (_data_->_async_result, _data_, NULL); +#line 49 "../tools/gsound-play.vala" + if (_data_->_state_ != 0) { +#line 49 "../tools/gsound-play.vala" + while (!g_task_get_completed (_data_->_async_result)) { +#line 49 "../tools/gsound-play.vala" + g_main_context_iteration (g_task_get_context (_data_->_async_result), TRUE); +#line 213 "gsound-play.c" + } + } +#line 49 "../tools/gsound-play.vala" + g_object_unref (_data_->_async_result); +#line 49 "../tools/gsound-play.vala" + return FALSE; +#line 220 "gsound-play.c" +} + +static void +_g_free0_ (gpointer var) +{ +#line 80 "../tools/gsound-play.vala" + var = (g_free (var), NULL); +#line 228 "gsound-play.c" +} + +static gchar* +double_to_string (gdouble self) +{ + gchar* _tmp0_; + gchar* _tmp1_; + gint _tmp1__length1; + const gchar* _tmp2_; + gchar* _tmp3_; + gchar* _tmp4_; + gchar* result; +#line 997 "glib-2.0.vapi" + _tmp0_ = g_new0 (gchar, G_ASCII_DTOSTR_BUF_SIZE); +#line 997 "glib-2.0.vapi" + _tmp1_ = _tmp0_; +#line 997 "glib-2.0.vapi" + _tmp1__length1 = G_ASCII_DTOSTR_BUF_SIZE; +#line 997 "glib-2.0.vapi" + _tmp2_ = g_ascii_dtostr (_tmp1_, (gint) G_ASCII_DTOSTR_BUF_SIZE, self); +#line 997 "glib-2.0.vapi" + _tmp3_ = g_strdup (_tmp2_); +#line 997 "glib-2.0.vapi" + _tmp4_ = _tmp3_; +#line 997 "glib-2.0.vapi" + _tmp1_ = (g_free (_tmp1_), NULL); +#line 997 "glib-2.0.vapi" + result = _tmp4_; +#line 997 "glib-2.0.vapi" + return result; +#line 259 "gsound-play.c" +} + +static void +___lambda4_ (GObject* obj, + GAsyncResult* res) +{ + GError* _inner_error0_ = NULL; +#line 99 "../tools/gsound-play.vala" + g_return_if_fail (res != NULL); +#line 269 "gsound-play.c" + { +#line 101 "../tools/gsound-play.vala" + play_finish (res, &_inner_error0_); +#line 101 "../tools/gsound-play.vala" + if (G_UNLIKELY (_inner_error0_ != NULL)) { +#line 275 "gsound-play.c" + goto __catch0_g_error; + } + } + goto __finally0; + __catch0_g_error: + { + GError* e = NULL; + GError* _tmp0_; + const gchar* _tmp1_; +#line 100 "../tools/gsound-play.vala" + e = _inner_error0_; +#line 100 "../tools/gsound-play.vala" + _inner_error0_ = NULL; +#line 103 "../tools/gsound-play.vala" + _tmp0_ = e; +#line 103 "../tools/gsound-play.vala" + _tmp1_ = _tmp0_->message; +#line 103 "../tools/gsound-play.vala" + g_print ("Error: %s\n", _tmp1_); +#line 100 "../tools/gsound-play.vala" + _g_error_free0 (e); +#line 297 "gsound-play.c" + } + __finally0: + { + GError* _inner_error1_ = NULL; + GMainLoop* _tmp2_; +#line 105 "../tools/gsound-play.vala" + _tmp2_ = main_loop; +#line 105 "../tools/gsound-play.vala" + g_main_loop_quit (_tmp2_); +#line 307 "gsound-play.c" + } +#line 100 "../tools/gsound-play.vala" + if (G_UNLIKELY (_inner_error0_ != NULL)) { +#line 100 "../tools/gsound-play.vala" + g_critical ("file %s: line %d: uncaught error: %s (%s, %d)", __FILE__, __LINE__, _inner_error0_->message, g_quark_to_string (_inner_error0_->domain), _inner_error0_->code); +#line 100 "../tools/gsound-play.vala" + g_clear_error (&_inner_error0_); +#line 100 "../tools/gsound-play.vala" + return; +#line 317 "gsound-play.c" + } +} + +static void +____lambda4__gasync_ready_callback (GObject* source_object, + GAsyncResult* res, + gpointer self) +{ +#line 99 "../tools/gsound-play.vala" + ___lambda4_ (source_object, res); +#line 328 "gsound-play.c" +} + +static gint +_vala_main (gchar** args, + gint args_length1) +{ + GOptionContext* opt_ctx = NULL; + GOptionContext* _tmp0_; + GOptionContext* _tmp1_; + GError* _inner_error0_ = NULL; + gint result; +#line 58 "../tools/gsound-play.vala" + setlocale (LC_ALL, ""); +#line 60 "../tools/gsound-play.vala" + g_set_application_name ("gsound-play"); +#line 62 "../tools/gsound-play.vala" + _tmp0_ = g_option_context_new (NULL); +#line 62 "../tools/gsound-play.vala" + opt_ctx = _tmp0_; +#line 63 "../tools/gsound-play.vala" + _tmp1_ = opt_ctx; +#line 63 "../tools/gsound-play.vala" + g_option_context_add_main_entries (_tmp1_, opts, NULL); +#line 352 "gsound-play.c" + { + GOptionContext* _tmp2_; + gboolean _tmp3_ = FALSE; + const gchar* _tmp4_; + GSoundContext* _tmp6_ = NULL; + GSoundContext* _tmp7_; + GSoundContext* _tmp8_; + GSoundContext* _tmp9_; + const gchar* _tmp10_; + GHashFunc _tmp13_; + GEqualFunc _tmp14_; + GHashTable* _tmp15_; + const gchar* _tmp16_; + const gchar* _tmp21_; + const gchar* _tmp26_; + GMainLoop* _tmp34_; + GMainLoop* _tmp35_; +#line 66 "../tools/gsound-play.vala" + _tmp2_ = opt_ctx; +#line 66 "../tools/gsound-play.vala" + g_option_context_parse (_tmp2_, (gint*) (&args_length1), &args, &_inner_error0_); +#line 66 "../tools/gsound-play.vala" + if (G_UNLIKELY (_inner_error0_ != NULL)) { +#line 376 "gsound-play.c" + goto __catch0_g_error; + } +#line 68 "../tools/gsound-play.vala" + _tmp4_ = event_id; +#line 68 "../tools/gsound-play.vala" + if (_tmp4_ == NULL) { +#line 383 "gsound-play.c" + const gchar* _tmp5_; +#line 68 "../tools/gsound-play.vala" + _tmp5_ = filename; +#line 68 "../tools/gsound-play.vala" + _tmp3_ = _tmp5_ == NULL; +#line 389 "gsound-play.c" + } else { +#line 68 "../tools/gsound-play.vala" + _tmp3_ = FALSE; +#line 393 "gsound-play.c" + } +#line 68 "../tools/gsound-play.vala" + if (_tmp3_) { +#line 69 "../tools/gsound-play.vala" + g_print ("No event id or file specified.\n"); +#line 70 "../tools/gsound-play.vala" + result = 1; +#line 70 "../tools/gsound-play.vala" + _g_option_context_free0 (opt_ctx); +#line 70 "../tools/gsound-play.vala" + return result; +#line 405 "gsound-play.c" + } +#line 73 "../tools/gsound-play.vala" + _tmp7_ = gsound_context_new (NULL, &_inner_error0_); +#line 73 "../tools/gsound-play.vala" + _tmp6_ = _tmp7_; +#line 73 "../tools/gsound-play.vala" + if (G_UNLIKELY (_inner_error0_ != NULL)) { +#line 413 "gsound-play.c" + goto __catch0_g_error; + } +#line 73 "../tools/gsound-play.vala" + _tmp8_ = _tmp6_; +#line 73 "../tools/gsound-play.vala" + _tmp6_ = NULL; +#line 73 "../tools/gsound-play.vala" + _g_object_unref0 (gs_ctx); +#line 73 "../tools/gsound-play.vala" + gs_ctx = _tmp8_; +#line 74 "../tools/gsound-play.vala" + _tmp9_ = gs_ctx; +#line 74 "../tools/gsound-play.vala" + gsound_context_set_attributes (_tmp9_, &_inner_error0_, GSOUND_ATTR_APPLICATION_ID, "org.gnome.gsound-test", NULL); +#line 74 "../tools/gsound-play.vala" + if (G_UNLIKELY (_inner_error0_ != NULL)) { +#line 74 "../tools/gsound-play.vala" + _g_object_unref0 (_tmp6_); +#line 432 "gsound-play.c" + goto __catch0_g_error; + } +#line 76 "../tools/gsound-play.vala" + _tmp10_ = driver; +#line 76 "../tools/gsound-play.vala" + if (_tmp10_ != NULL) { +#line 439 "gsound-play.c" + GSoundContext* _tmp11_; + const gchar* _tmp12_; +#line 77 "../tools/gsound-play.vala" + _tmp11_ = gs_ctx; +#line 77 "../tools/gsound-play.vala" + _tmp12_ = driver; +#line 77 "../tools/gsound-play.vala" + gsound_context_set_driver (_tmp11_, _tmp12_, &_inner_error0_); +#line 77 "../tools/gsound-play.vala" + if (G_UNLIKELY (_inner_error0_ != NULL)) { +#line 77 "../tools/gsound-play.vala" + _g_object_unref0 (_tmp6_); +#line 452 "gsound-play.c" + goto __catch0_g_error; + } + } +#line 80 "../tools/gsound-play.vala" + _tmp13_ = g_str_hash; +#line 80 "../tools/gsound-play.vala" + _tmp14_ = g_str_equal; +#line 80 "../tools/gsound-play.vala" + _tmp15_ = g_hash_table_new_full (_tmp13_, _tmp14_, _g_free0_, _g_free0_); +#line 80 "../tools/gsound-play.vala" + _g_hash_table_unref0 (attrs); +#line 80 "../tools/gsound-play.vala" + attrs = _tmp15_; +#line 82 "../tools/gsound-play.vala" + _tmp16_ = event_id; +#line 82 "../tools/gsound-play.vala" + if (_tmp16_ != NULL) { +#line 470 "gsound-play.c" + GHashTable* _tmp17_; + gchar* _tmp18_; + const gchar* _tmp19_; + gchar* _tmp20_; +#line 83 "../tools/gsound-play.vala" + _tmp17_ = attrs; +#line 83 "../tools/gsound-play.vala" + _tmp18_ = g_strdup (GSOUND_ATTR_EVENT_ID); +#line 83 "../tools/gsound-play.vala" + _tmp19_ = event_id; +#line 83 "../tools/gsound-play.vala" + _tmp20_ = g_strdup (_tmp19_); +#line 83 "../tools/gsound-play.vala" + g_hash_table_insert (_tmp17_, _tmp18_, _tmp20_); +#line 485 "gsound-play.c" + } +#line 85 "../tools/gsound-play.vala" + _tmp21_ = filename; +#line 85 "../tools/gsound-play.vala" + if (_tmp21_ != NULL) { +#line 491 "gsound-play.c" + GHashTable* _tmp22_; + gchar* _tmp23_; + const gchar* _tmp24_; + gchar* _tmp25_; +#line 86 "../tools/gsound-play.vala" + _tmp22_ = attrs; +#line 86 "../tools/gsound-play.vala" + _tmp23_ = g_strdup (GSOUND_ATTR_MEDIA_FILENAME); +#line 86 "../tools/gsound-play.vala" + _tmp24_ = filename; +#line 86 "../tools/gsound-play.vala" + _tmp25_ = g_strdup (_tmp24_); +#line 86 "../tools/gsound-play.vala" + g_hash_table_insert (_tmp22_, _tmp23_, _tmp25_); +#line 506 "gsound-play.c" + } +#line 88 "../tools/gsound-play.vala" + _tmp26_ = cache; +#line 88 "../tools/gsound-play.vala" + if (_tmp26_ != NULL) { +#line 512 "gsound-play.c" + GHashTable* _tmp27_; + gchar* _tmp28_; + const gchar* _tmp29_; + gchar* _tmp30_; +#line 89 "../tools/gsound-play.vala" + _tmp27_ = attrs; +#line 89 "../tools/gsound-play.vala" + _tmp28_ = g_strdup (GSOUND_ATTR_CANBERRA_CACHE_CONTROL); +#line 89 "../tools/gsound-play.vala" + _tmp29_ = cache; +#line 89 "../tools/gsound-play.vala" + _tmp30_ = g_strdup (_tmp29_); +#line 89 "../tools/gsound-play.vala" + g_hash_table_insert (_tmp27_, _tmp28_, _tmp30_); +#line 527 "gsound-play.c" + } +#line 91 "../tools/gsound-play.vala" + if (volume != 0.0) { +#line 531 "gsound-play.c" + GHashTable* _tmp31_; + gchar* _tmp32_; + gchar* _tmp33_; +#line 92 "../tools/gsound-play.vala" + _tmp31_ = attrs; +#line 92 "../tools/gsound-play.vala" + _tmp32_ = g_strdup (GSOUND_ATTR_CANBERRA_VOLUME); +#line 92 "../tools/gsound-play.vala" + _tmp33_ = double_to_string (volume); +#line 92 "../tools/gsound-play.vala" + g_hash_table_insert (_tmp31_, _tmp32_, _tmp33_); +#line 543 "gsound-play.c" + } +#line 95 "../tools/gsound-play.vala" + if (loops == 0) { +#line 96 "../tools/gsound-play.vala" + loops = 1; +#line 549 "gsound-play.c" + } +#line 99 "../tools/gsound-play.vala" + play (____lambda4__gasync_ready_callback, NULL); +#line 109 "../tools/gsound-play.vala" + _tmp34_ = g_main_loop_new (NULL, FALSE); +#line 109 "../tools/gsound-play.vala" + _g_main_loop_unref0 (main_loop); +#line 109 "../tools/gsound-play.vala" + main_loop = _tmp34_; +#line 110 "../tools/gsound-play.vala" + _tmp35_ = main_loop; +#line 110 "../tools/gsound-play.vala" + g_main_loop_run (_tmp35_); +#line 65 "../tools/gsound-play.vala" + _g_object_unref0 (_tmp6_); +#line 565 "gsound-play.c" + } + goto __finally0; + __catch0_g_error: + { + GError* e = NULL; + GError* _tmp36_; + const gchar* _tmp37_; +#line 65 "../tools/gsound-play.vala" + e = _inner_error0_; +#line 65 "../tools/gsound-play.vala" + _inner_error0_ = NULL; +#line 113 "../tools/gsound-play.vala" + _tmp36_ = e; +#line 113 "../tools/gsound-play.vala" + _tmp37_ = _tmp36_->message; +#line 113 "../tools/gsound-play.vala" + g_print ("Error: %s\n", _tmp37_); +#line 114 "../tools/gsound-play.vala" + result = 1; +#line 114 "../tools/gsound-play.vala" + _g_error_free0 (e); +#line 114 "../tools/gsound-play.vala" + _g_option_context_free0 (opt_ctx); +#line 114 "../tools/gsound-play.vala" + return result; +#line 591 "gsound-play.c" + } + __finally0: +#line 65 "../tools/gsound-play.vala" + if (G_UNLIKELY (_inner_error0_ != NULL)) { +#line 596 "gsound-play.c" + gint _tmp38_ = -1; +#line 65 "../tools/gsound-play.vala" + _g_option_context_free0 (opt_ctx); +#line 65 "../tools/gsound-play.vala" + g_critical ("file %s: line %d: uncaught error: %s (%s, %d)", __FILE__, __LINE__, _inner_error0_->message, g_quark_to_string (_inner_error0_->domain), _inner_error0_->code); +#line 65 "../tools/gsound-play.vala" + g_clear_error (&_inner_error0_); +#line 65 "../tools/gsound-play.vala" + return _tmp38_; +#line 606 "gsound-play.c" + } +#line 117 "../tools/gsound-play.vala" + result = 0; +#line 117 "../tools/gsound-play.vala" + _g_option_context_free0 (opt_ctx); +#line 117 "../tools/gsound-play.vala" + return result; +#line 614 "gsound-play.c" +} + +int +main (int argc, + char ** argv) +{ +#line 56 "../tools/gsound-play.vala" + return _vala_main (argv, argc); +#line 623 "gsound-play.c" +} + diff --git a/.flatpak-builder/cache/objects/6d/87d517b168dfe4f4d7e0ffdbeb60bb66691def64f13f5ff69b43c2d6eb396e.file b/.flatpak-builder/cache/objects/6d/87d517b168dfe4f4d7e0ffdbeb60bb66691def64f13f5ff69b43c2d6eb396e.file new file mode 100644 index 0000000..2823f77 --- /dev/null +++ b/.flatpak-builder/cache/objects/6d/87d517b168dfe4f4d7e0ffdbeb60bb66691def64f13f5ff69b43c2d6eb396e.file @@ -0,0 +1,160 @@ +# adw_message_dialog.py +# +# Copyright 2023 James Westman +# +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation; either version 3 of the +# License, or (at your option) any later version. +# +# This file is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program. If not, see . +# +# SPDX-License-Identifier: LGPL-3.0-or-later + + +from ..decompiler import truthy, decompile_translatable +from .common import * +from .contexts import ValueTypeCtx +from .gobject_object import ObjectContent, validate_parent_type +from .values import StringValue + + +class ExtAdwMessageDialogFlag(AstNode): + grammar = AnyOf( + UseExact("flag", "destructive"), + UseExact("flag", "suggested"), + UseExact("flag", "disabled"), + ) + + @property + def flag(self) -> str: + return self.tokens["flag"] + + @validate() + def unique(self): + self.validate_unique_in_parent( + f"Duplicate '{self.flag}' flag", check=lambda child: child.flag == self.flag + ) + + @validate() + def exclusive(self): + if self.flag in ["destructive", "suggested"]: + self.validate_unique_in_parent( + "'suggested' and 'destructive' are exclusive", + check=lambda child: child.flag in ["destructive", "suggested"], + ) + + +class ExtAdwMessageDialogResponse(AstNode): + grammar = [ + UseIdent("id"), + Match(":").expected(), + to_parse_node(StringValue).expected("a string or translatable string"), + ZeroOrMore(ExtAdwMessageDialogFlag), + ] + + @property + def id(self) -> str: + return self.tokens["id"] + + @property + def flags(self) -> T.List[ExtAdwMessageDialogFlag]: + return self.children[ExtAdwMessageDialogFlag] + + @property + def appearance(self) -> T.Optional[str]: + if any(flag.flag == "destructive" for flag in self.flags): + return "destructive" + elif any(flag.flag == "suggested" for flag in self.flags): + return "suggested" + else: + return None + + @property + def enabled(self) -> bool: + return not any(flag.flag == "disabled" for flag in self.flags) + + @property + def value(self) -> StringValue: + return self.children[0] + + @context(ValueTypeCtx) + def value_type(self) -> ValueTypeCtx: + return ValueTypeCtx(StringType()) + + @validate("id") + def unique_in_parent(self): + self.validate_unique_in_parent( + f"Duplicate response ID '{self.id}'", + check=lambda child: child.id == self.id, + ) + + +class ExtAdwMessageDialog(AstNode): + grammar = [ + Keyword("responses"), + Match("[").expected(), + Delimited(ExtAdwMessageDialogResponse, ","), + "]", + ] + + @property + def responses(self) -> T.List[ExtAdwMessageDialogResponse]: + return self.children + + @validate("responses") + def container_is_message_dialog(self): + validate_parent_type(self, "Adw", "MessageDialog", "responses") + + @validate("responses") + def unique_in_parent(self): + self.validate_unique_in_parent("Duplicate responses block") + + +@completer( + applies_in=[ObjectContent], + applies_in_subclass=("Adw", "MessageDialog"), + matches=new_statement_patterns, +) +def style_completer(ast_node, match_variables): + yield Completion( + "responses", CompletionItemKind.Keyword, snippet="responses [\n\t$0\n]" + ) + + +@decompiler("responses") +def decompile_responses(ctx, gir): + ctx.print(f"responses [") + + +@decompiler("response", cdata=True) +def decompile_response( + ctx, + gir, + cdata, + id, + appearance=None, + enabled=None, + translatable=None, + context=None, + comments=None, +): + comments, translated = decompile_translatable( + cdata, translatable, context, comments + ) + if comments is not None: + ctx.print(comments) + + flags = "" + if appearance is not None: + flags += f" {appearance}" + if enabled is not None and not truthy(enabled): + flags += " disabled" + + ctx.print(f"{id}: {translated}{flags},") diff --git a/.flatpak-builder/cache/objects/6d/96c2c8c3f5b56c341eb202d302c375f531251ecd8e5851a3d903adcbe5f686.file b/.flatpak-builder/cache/objects/6d/96c2c8c3f5b56c341eb202d302c375f531251ecd8e5851a3d903adcbe5f686.file new file mode 100644 index 0000000..dfe4413 --- /dev/null +++ b/.flatpak-builder/cache/objects/6d/96c2c8c3f5b56c341eb202d302c375f531251ecd8e5851a3d903adcbe5f686.file @@ -0,0 +1,2904 @@ +/* + * Copyright (C) 2001 - 2004 Rodrigo Moya + * Copyright (C) 2002 - 2003 Gonzalo Paniagua Javier + * Copyright (C) 2002 Holger Thon + * Copyright (C) 2003 Laurent Sansonetti + * Copyright (C) 2003 Paisa Seeluangsawat + * Copyright (C) 2003 Philippe CHARLIER + * Copyright (C) 2004 Dani Baeyens + * Copyright (C) 2004 Szalai Ferenc + * Copyright (C) 2004 - 2005 Álvaro Peña + * Copyright (C) 2005 - 2009 Bas Driessen + * Copyright (C) 2005 Dan Winship + * Copyright (C) 2005 Stanislav Brabec + * Copyright (C) 2005 - 2015 Vivien Malerba + * Copyright (C) 2006 - 2011 Murray Cumming + * Copyright (C) 2007 Leonardo Boshell + * Copyright (C) 2008 Phil Longstaff + * Copyright (C) 2008 Przemysław Grzegorczyk + * Copyright (C) 2010 David King + * Copyright (C) 2011 - 2013,2019 Daniel Espinosa + * Copyright (C) 2013 Miguel Angel Cabrera Moya + * Copyright (C) 2015 Corentin Noël + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +#define G_LOG_DOMAIN "GDA-data-model" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef HAVE_LOCALE_H +#ifndef G_OS_WIN32 +#include +#include +#endif +#include +#endif +#include "csv.h" + +static void gda_data_model_default_init (GdaDataModelInterface *iface); + +static xmlNodePtr gda_data_model_to_xml_node (GdaDataModel *model, const gint *cols, gint nb_cols, + const gint *rows, gint nb_rows, const gchar *name); + +static gchar *real_gda_data_model_dump_as_string (GdaDataModel *model, gboolean dump_attributes, + gboolean dump_rows, gboolean dump_title, gboolean null_as_empty, + gint max_width, gboolean dump_separators, gboolean dump_sep_line, + gboolean use_data_handlers, gboolean dump_column_titles, + const gint *rows, gint nb_rows, GError **error); + +G_DEFINE_INTERFACE (GdaDataModel, gda_data_model, G_TYPE_OBJECT) + + +/* signals */ +enum { + CHANGED, + ROW_INSERTED, + ROW_UPDATED, + ROW_REMOVED, + RESET, + ACCESS_CHANGED, + LAST_SIGNAL +}; + +static guint gda_data_model_signals[LAST_SIGNAL] = {0, 0, 0, 0, 0}; + +static void gda_data_model_default_init (GdaDataModelInterface *iface) +{ + /** + * GdaDataModel::changed: + * @model: the #GdaDataModel + * + * Gets emitted when any value in @model has been changed + */ + gda_data_model_signals[CHANGED] = + g_signal_new ("changed", + GDA_TYPE_DATA_MODEL, + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GdaDataModelInterface, changed), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + /** + * GdaDataModel::row-inserted: + * @model: the #GdaDataModel + * @row: the row number + * + * Gets emitted when a row has been inserted in @model + */ + gda_data_model_signals[ROW_INSERTED] = + g_signal_new ("row-inserted", + GDA_TYPE_DATA_MODEL, + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GdaDataModelInterface, row_inserted), + NULL, NULL, + g_cclosure_marshal_VOID__INT, + G_TYPE_NONE, 1, G_TYPE_INT); + /** + * GdaDataModel::row-updated: + * @model: the #GdaDataModel + * @row: the row number + * + * Gets emitted when a row has been modified in @model + */ + gda_data_model_signals[ROW_UPDATED] = + g_signal_new ("row-updated", + GDA_TYPE_DATA_MODEL, + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GdaDataModelInterface, row_updated), + NULL, NULL, + g_cclosure_marshal_VOID__INT, + G_TYPE_NONE, 1, G_TYPE_INT); + /** + * GdaDataModel::row-removed: + * @model: the #GdaDataModel + * @row: the row number + * + * Gets emitted when a row has been removed from @model + */ + gda_data_model_signals[ROW_REMOVED] = + g_signal_new ("row-removed", + GDA_TYPE_DATA_MODEL, + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GdaDataModelInterface, row_removed), + NULL, NULL, + g_cclosure_marshal_VOID__INT, + G_TYPE_NONE, 1, G_TYPE_INT); + /** + * GdaDataModel::reset: + * @model: the #GdaDataModel + * + * Gets emitted when @model's contents has been completely reset (the number and + * type of columns may also have changed) + */ + gda_data_model_signals[RESET] = + g_signal_new ("reset", + GDA_TYPE_DATA_MODEL, + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GdaDataModelInterface, reset), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + /** + * GdaDataModel::access-changed: + * @model: the #GdaDataModel + * + * Gets emitted when @model's access flags have changed. Use + * gda_data_model_get_access_flags() to get the access flags. + */ + gda_data_model_signals[ACCESS_CHANGED] = + g_signal_new ("access-changed", + GDA_TYPE_DATA_MODEL, + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GdaDataModelInterface, access_changed), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); +} + +/* module error */ +GQuark gda_data_model_error_quark (void) +{ + static GQuark quark; + if (!quark) + quark = g_quark_from_static_string ("gda_data_model_error"); + return quark; +} + +static gboolean +do_notify_changes (GdaDataModel *model) +{ + gboolean notify_changes = TRUE; + if (GDA_DATA_MODEL_GET_IFACE (model)->get_notify) + notify_changes = (GDA_DATA_MODEL_GET_IFACE (model)->get_notify) (model); + return notify_changes; +} + +/* + * _gda_data_model_signal_emit_changed + * @model: a #GdaDataModel object. + * + * Notifies listeners of the given data model object of changes + * in the underlying data. Listeners usually will connect + * themselves to the "changed" signal in the #GdaDataModel + * class, thus being notified of any new data being appended + * or removed from the data model. + */ +static void +_gda_data_model_signal_emit_changed (GdaDataModel *model) +{ + g_return_if_fail (GDA_IS_DATA_MODEL (model)); + + if (do_notify_changes (model)) + g_signal_emit (model, gda_data_model_signals[CHANGED], 0); +} + +/** + * gda_data_model_row_inserted: + * @model: a #GdaDataModel object. + * @row: row number. + * + * Emits the 'row_inserted' and 'changed' signals on @model. + * + * This method should only be used by #GdaDataModel implementations to + * signal that a row has been inserted. + */ +void +gda_data_model_row_inserted (GdaDataModel *model, gint row) +{ + g_return_if_fail (GDA_IS_DATA_MODEL (model)); + + /* update column's data types if they are not yet defined */ + if (gda_data_model_get_n_rows (model) == 1) { + GdaColumn *column; + gint i, nbcols; + const GValue *value; + + nbcols = gda_data_model_get_n_columns (model); + for (i = 0; i < nbcols; i++) { + column = gda_data_model_describe_column (model, i); + value = gda_data_model_get_value_at (model, i, 0, NULL); + if (value && (gda_column_get_g_type (column) == GDA_TYPE_NULL)) + gda_column_set_g_type (column, G_VALUE_TYPE ((GValue *)value)); + } + } + + /* notify changes */ + if (do_notify_changes (model)) { + g_signal_emit (G_OBJECT (model), + gda_data_model_signals[ROW_INSERTED], + 0, row); + _gda_data_model_signal_emit_changed (model); + } +} + +/** + * gda_data_model_row_updated: + * @model: a #GdaDataModel object. + * @row: row number. + * + * Emits the 'row_updated' and 'changed' signals on @model. + * + * This method should only be used by #GdaDataModel implementations to + * signal that a row has been updated. + */ +void +gda_data_model_row_updated (GdaDataModel *model, gint row) +{ + g_return_if_fail (GDA_IS_DATA_MODEL (model)); + + if (do_notify_changes (model)) { + g_signal_emit (G_OBJECT (model), + gda_data_model_signals[ROW_UPDATED], + 0, row); + + _gda_data_model_signal_emit_changed (model); + } +} + +/** + * gda_data_model_row_removed: + * @model: a #GdaDataModel object. + * @row: row number. + * + * Emits the 'row_removed' and 'changed' signal on @model. + * + * This method should only be used by #GdaDataModel implementations to + * signal that a row has been removed + */ +void +gda_data_model_row_removed (GdaDataModel *model, gint row) +{ + g_return_if_fail (GDA_IS_DATA_MODEL (model)); + + if (do_notify_changes (model)) { + g_signal_emit (G_OBJECT (model), + gda_data_model_signals[ROW_REMOVED], + 0, row); + + _gda_data_model_signal_emit_changed (model); + } +} + +/** + * gda_data_model_reset: + * @model: a #GdaDataModel object. + * + * Emits the 'reset' and 'changed' signal on @model. + */ +void +gda_data_model_reset (GdaDataModel *model) +{ + g_return_if_fail (GDA_IS_DATA_MODEL (model)); + + if (do_notify_changes (model)) { + g_signal_emit (G_OBJECT (model), + gda_data_model_signals[RESET], 0); + + _gda_data_model_signal_emit_changed (model); + } +} + +/** + * gda_data_model_freeze: + * @model: a #GdaDataModel object. + * + * Disables notifications of changes on the given data model. To + * re-enable notifications again, you should call the + * #gda_data_model_thaw function. + * + */ +void +gda_data_model_freeze (GdaDataModel *model) +{ + g_return_if_fail (GDA_IS_DATA_MODEL (model)); + + if (GDA_DATA_MODEL_GET_IFACE (model)->freeze) + (GDA_DATA_MODEL_GET_IFACE (model)->freeze) (model); +} + +/** + * gda_data_model_thaw: + * @model: a #GdaDataModel object. + * + * Re-enables notifications of changes on the given data model. + */ +void +gda_data_model_thaw (GdaDataModel *model) +{ + g_return_if_fail (GDA_IS_DATA_MODEL (model)); + + if (GDA_DATA_MODEL_GET_IFACE (model)->thaw) + (GDA_DATA_MODEL_GET_IFACE (model)->thaw) (model); +} + +/** + * gda_data_model_get_notify: + * @model: a #GdaDataModel object. + * + * Returns the status of notifications changes on the given data model. + */ +gboolean +gda_data_model_get_notify (GdaDataModel *model) +{ + g_return_val_if_fail (GDA_IS_DATA_MODEL (model), FALSE); + if (GDA_DATA_MODEL_GET_IFACE (model)->get_notify) + return (GDA_DATA_MODEL_GET_IFACE (model)->get_notify) (model); + else + return TRUE; +} + + +/** + * gda_data_model_get_access_flags: + * @model: a #GdaDataModel object. + * + * Get the attributes of @model such as how to access the data it contains if it's modifiable, etc. + * + * Returns: (transfer none): an ORed value of #GdaDataModelAccessFlags flags + */ +GdaDataModelAccessFlags +gda_data_model_get_access_flags (GdaDataModel *model) +{ + g_return_val_if_fail (GDA_IS_DATA_MODEL (model), 0); + if (GDA_DATA_MODEL_GET_IFACE (model)->get_access_flags) { + GdaDataModelAccessFlags flags = (GDA_DATA_MODEL_GET_IFACE (model)->get_access_flags) (model); + if (flags & GDA_DATA_MODEL_ACCESS_RANDOM) + flags |= GDA_DATA_MODEL_ACCESS_CURSOR_FORWARD | GDA_DATA_MODEL_ACCESS_CURSOR_BACKWARD; + return flags; + } + else + return 0; +} + +/** + * gda_data_model_get_n_rows: + * @model: a #GdaDataModel object. + * + * Returns: the number of rows in the given data model, or -1 if the number of rows is not known + */ +gint +gda_data_model_get_n_rows (GdaDataModel *model) +{ + g_return_val_if_fail (GDA_IS_DATA_MODEL (model), -1); + + if (GDA_DATA_MODEL_GET_IFACE (model)->get_n_rows) + return (GDA_DATA_MODEL_GET_IFACE (model)->get_n_rows) (model); + else + return -1; +} + +/** + * gda_data_model_get_n_columns: + * @model: a #GdaDataModel object. + * + * Returns: the number of columns in the given data model, or -1 if unknown. + */ +gint +gda_data_model_get_n_columns (GdaDataModel *model) +{ + g_return_val_if_fail (GDA_IS_DATA_MODEL (model), -1); + + if (GDA_DATA_MODEL_GET_IFACE (model)->get_n_columns) + return (GDA_DATA_MODEL_GET_IFACE (model)->get_n_columns) (model); + else { + /* method not supported */ + return -1; + } +} + +/** + * gda_data_model_describe_column: + * @model: a #GdaDataModel object. + * @col: column number. + * + * Queries the underlying data model implementation for a description + * of a given column. That description is returned in the form of + * a #GdaColumn structure, which contains all the information + * about the given column in the data model. + * + * WARNING: the returned #GdaColumn object belongs to the @model model and + * and should not be destroyed; any modification will affect the whole data model. + * + * Returns: (transfer none) (nullable): the description of the column. + */ +GdaColumn * +gda_data_model_describe_column (GdaDataModel *model, gint col) +{ + g_return_val_if_fail (GDA_IS_DATA_MODEL (model), NULL); + + if (GDA_DATA_MODEL_GET_IFACE (model)->describe_column) + return (GDA_DATA_MODEL_GET_IFACE (model)->describe_column) (model, col); + else { + /* method not supported */ + return NULL; + } +} + +/** + * gda_data_model_get_column_index: + * @model: a #GdaDataModel object. + * @name: a column name + * + * Get the index of the first column named @name in @model. + * + * Returns: the column index, or -1 if no column named @name was found + */ +gint +gda_data_model_get_column_index (GdaDataModel *model, const gchar *name) +{ + gint nbcols, ncol, ret; + + g_return_val_if_fail (GDA_IS_DATA_MODEL (model), -1); + g_return_val_if_fail (name, -1); + + ret = -1; + nbcols = gda_data_model_get_n_columns (model); + for (ncol = 0; ncol < nbcols; ncol++) { + if (g_str_equal (name, gda_data_model_get_column_title (model, ncol))) { + + ret = ncol; + break; + } + } + + return ret; +} + +/** + * gda_data_model_get_column_name: + * @model: a #GdaDataModel object. + * @col: column number. + * + * Since: 3.2 + * + * Returns: the name for the given column in a data model object. + */ +const gchar * +gda_data_model_get_column_name (GdaDataModel *model, gint col) +{ + GdaColumn *column; + g_return_val_if_fail (GDA_IS_DATA_MODEL (model), NULL); + + column = gda_data_model_describe_column (model, col); + if (column) + return gda_column_get_name (column); + else { + g_warning ("%s(): can't get GdaColumn object for column %d\n", __FUNCTION__, col); + return NULL; + } +} + +/** + * gda_data_model_set_column_name: + * @model: a #GdaDataModel object. + * @col: column number + * @name: name for the given column. + * + * Sets the @name of the given @col in @model, and if its title is not set, also sets the + * title to @name. + * + * Since: 3.2 + */ +void +gda_data_model_set_column_name (GdaDataModel *model, gint col, const gchar *name) +{ + GdaColumn *column; + g_return_if_fail (GDA_IS_DATA_MODEL (model)); + + column = gda_data_model_describe_column (model, col); + if (column) { + gda_column_set_name (column, name); + if (!gda_column_get_description (column)) + gda_column_set_description (column, name); + } + else + g_warning ("%s(): can't get GdaColumn object for column %d\n", __FUNCTION__, col); +} + + +/** + * gda_data_model_get_column_title: + * @model: a #GdaDataModel object. + * @col: column number. + * + * Returns: the title for the given column in a data model object. + */ +const gchar * +gda_data_model_get_column_title (GdaDataModel *model, gint col) +{ + GdaColumn *column; + g_return_val_if_fail (GDA_IS_DATA_MODEL (model), NULL); + + column = gda_data_model_describe_column (model, col); + if (column) + return gda_column_get_description (column); + else { + g_warning ("%s(): can't get GdaColumn object for column %d\n", __FUNCTION__, col); + return NULL; + } +} + +/** + * gda_data_model_set_column_title: + * @model: a #GdaDataModel object. + * @col: column number + * @title: title for the given column. + * + * Sets the @title of the given @col in @model. + */ +void +gda_data_model_set_column_title (GdaDataModel *model, gint col, const gchar *title) +{ + GdaColumn *column; + g_return_if_fail (GDA_IS_DATA_MODEL (model)); + + column = gda_data_model_describe_column (model, col); + if (column) + gda_column_set_description (column, title); + else + g_warning ("%s(): can't get GdaColumn object for column %d\n", __FUNCTION__, col); +} + +/** + * gda_data_model_get_value_at: + * @model: a #GdaDataModel object. + * @col: a valid column number. + * @row: a valid row number. + * @error: a place to store errors, or %NULL. + * + * Retrieves the data stored in the given position (identified by + * the @col and @row parameters) on a data model. + * + * Upon errors %NULL will be returned and @error will be assigned a + * #GError from the #GDA_DATA_MODEL_ERROR domain. + * + * This is the main function for accessing data in a model which allows random access to its data. + * To access data in a data model using a cursor, use a #GdaDataModelIter object, obtained using + * gda_data_model_create_iter(). + * + * Note1: the returned #GValue must not be modified directly (unexpected behaviours may + * occur if you do so). + * + * Note2: the returned value may become invalid as soon as any Libgda part is executed again, + * which means if you want to keep the value, a copy must be made, however it will remain valid + * as long as the only Libgda usage is calling gda_data_model_get_value_at() for different values + * of the same row. + * + * If you want to modify a value stored in a #GdaDataModel, use the gda_data_model_set_value_at() or + * gda_data_model_set_values() methods. + * + * Upon errors %NULL will be returned and @error will be assigned a + * #GError from the #GDA_DATA_MODEL_ERROR domain. + * + * Returns: (nullable) (transfer none): a #GValue containing the value stored in the given + * position, or %NULL on error (out-of-bound position, etc). + */ +const GValue * +gda_data_model_get_value_at (GdaDataModel *model, gint col, gint row, GError **error) +{ + g_return_val_if_fail (GDA_IS_DATA_MODEL (model), NULL); + + if (GDA_DATA_MODEL_GET_IFACE (model)->get_value_at) + return (GDA_DATA_MODEL_GET_IFACE (model)->get_value_at) (model, col, row, error); + else { + /* method not supported */ + g_set_error (error, GDA_DATA_MODEL_ERROR, GDA_DATA_MODEL_FEATURE_NON_SUPPORTED_ERROR, + "%s", _("Data model does not support getting individual value")); + return NULL; + } +} + +/** + * gda_data_model_get_typed_value_at: + * @model: a #GdaDataModel object. + * @col: a valid column number. + * @row: a valid row number. + * @expected_type: the expected data type of the returned value + * @nullok: if TRUE, then NULL values (value of type %GDA_TYPE_NULL) will not generate any error + * @error: a place to store errors, or %NULL + * + * Upon errors %NULL will be returned and @error will be assigned a + * #GError from the #GDA_DATA_MODEL_ERROR domain. + * + * This method is similar to gda_data_model_get_value_at(), except that it also allows one to specify the expected + * #GType of the value to get: if the data model returned a #GValue of a type different than the expected one, then + * this method returns %NULL and an error code. + * + * Note: the same limitations and usage instructions apply as for gda_data_model_get_value_at(). + * + * Upon errors %NULL will be returned and @error will be assigned a + * #GError from the #GDA_DATA_MODEL_ERROR domain. + * + * Returns: (nullable) (transfer none): a #GValue containing the value stored in the given + * position, or %NULL on error (out-of-bound position, wrong data type, etc). + */ +const GValue * +gda_data_model_get_typed_value_at (GdaDataModel *model, gint col, gint row, GType expected_type, gboolean nullok, GError **error) +{ + const GValue *cvalue = NULL; + g_return_val_if_fail (GDA_IS_DATA_MODEL (model), NULL); + + if (GDA_DATA_MODEL_GET_IFACE (model)->get_value_at) + cvalue = (GDA_DATA_MODEL_GET_IFACE (model)->get_value_at) (model, col, row, error); + + if (cvalue) { + if (nullok && + (G_VALUE_TYPE (cvalue) != GDA_TYPE_NULL) && + (G_VALUE_TYPE (cvalue) != expected_type)) { + g_set_error (error, GDA_DATA_MODEL_ERROR, GDA_DATA_MODEL_VALUE_TYPE_ERROR, + _("Data model returned value of invalid '%s' type"), + gda_g_type_to_string (G_VALUE_TYPE (cvalue))); + cvalue = NULL; + } + else if (!nullok && (G_VALUE_TYPE (cvalue) != expected_type)) { + if (G_VALUE_TYPE (cvalue) == GDA_TYPE_NULL) + g_set_error (error, GDA_DATA_MODEL_ERROR, GDA_DATA_MODEL_VALUE_TYPE_ERROR, + "%s", _("Data model returned invalid NULL value")); + else + g_set_error (error, GDA_DATA_MODEL_ERROR, GDA_DATA_MODEL_VALUE_TYPE_ERROR, + _("Data model returned value of invalid '%s' type"), + gda_g_type_to_string (G_VALUE_TYPE (cvalue))); + cvalue = NULL; + } + } + return cvalue; +} + +/** + * gda_data_model_get_attributes_at: + * @model: a #GdaDataModel object + * @col: a valid column number + * @row: a valid row number, or -1 + * + * Get the attributes of the value stored at (row, col) in @model, which + * is an ORed value of #GdaValueAttribute flags. As a special case, if + * @row is -1, then the attributes returned correspond to a "would be" value + * if a row was added to @model. + * + * Returns: (transfer none): the attributes as an ORed value of #GdaValueAttribute + */ +GdaValueAttribute +gda_data_model_get_attributes_at (GdaDataModel *model, gint col, gint row) +{ + g_return_val_if_fail (GDA_IS_DATA_MODEL (model), 0); + + if (GDA_DATA_MODEL_GET_IFACE (model)->get_attributes_at) + return (GDA_DATA_MODEL_GET_IFACE (model)->get_attributes_at) (model, col, row); + else { + GdaDataModelAccessFlags flags; + GdaValueAttribute attrs = GDA_VALUE_ATTR_NO_MODIF; + flags = gda_data_model_get_access_flags (model); + if (flags & GDA_DATA_MODEL_ACCESS_WRITE) + attrs = 0; + return attrs; + } +} + +/** + * gda_data_model_set_value_at: + * @model: a #GdaDataModel object. + * @col: column number. + * @row: row number. + * @value: a #GValue (not %NULL) + * @error: a place to store errors, or %NULL + * + * Modifies a value in @model, at (@col, @row). + * + * Upon errors FALSE will be returned and @error will be assigned a + * #GError from the #GDA_DATA_MODEL_ERROR domain. + * + * Returns: TRUE if the value in the data model has been updated and no error occurred + */ +gboolean +gda_data_model_set_value_at (GdaDataModel *model, gint col, gint row, const GValue *value, GError **error) +{ + g_return_val_if_fail (GDA_IS_DATA_MODEL (model), FALSE); + + if (GDA_DATA_MODEL_GET_IFACE (model)->set_value_at) + return (GDA_DATA_MODEL_GET_IFACE (model)->set_value_at) (model, col, row, value, error); + else { + /* method not supported */ + g_set_error (error, GDA_DATA_MODEL_ERROR, GDA_DATA_MODEL_FEATURE_NON_SUPPORTED_ERROR, + "%s", _("Data model does not support setting individual value")); + return FALSE; + } +} + +/** + * gda_data_model_set_values: + * @model: a #GdaDataModel object. + * @row: row number. + * @values: (element-type GObject.Value) (transfer none) (nullable): a list of #GValue (or %NULL), one for at most the number of columns of @model + * @error: a place to store errors, or %NULL + * + * In a similar way to gda_data_model_set_value_at(), this method modifies a data model's contents + * by setting several values at once. + * + * If any value in @values is actually %NULL, then the value in the corresponding column is left + * unchanged. + + * Upon errors FALSE will be returned and @error will be assigned a + * #GError from the #GDA_DATA_MODEL_ERROR domain. + * + * Returns: %TRUE if the value in the data model has been updated and no error occurred + */ +gboolean +gda_data_model_set_values (GdaDataModel *model, gint row, GList *values, GError **error) +{ + g_return_val_if_fail (GDA_IS_DATA_MODEL (model), FALSE); + + + if (GDA_DATA_MODEL_GET_IFACE (model)->set_values) + return (GDA_DATA_MODEL_GET_IFACE (model)->set_values) (model, row, values, error); + else if (GDA_DATA_MODEL_GET_IFACE (model)->set_value_at) { + /* save the values */ + gint col, ncols; + ncols = gda_data_model_get_n_columns (model); + if ((gint)g_list_length (values) > ncols) { + g_set_error (error, GDA_DATA_MODEL_ERROR, GDA_DATA_MODEL_VALUES_LIST_ERROR, + "%s", _("Too many values in list")); + return FALSE; + } + + for (col = 0; + (col < ncols) && values; + col++, values = values->next) { + const GValue *cvalue; + cvalue = (const GValue*) values->data; + if (!cvalue) + continue; + if (! gda_data_model_set_value_at (model, col, row, cvalue, error)) + return FALSE; + } + return TRUE; + } + else { + /* method not supported */ + g_set_error (error, GDA_DATA_MODEL_ERROR, GDA_DATA_MODEL_FEATURE_NON_SUPPORTED_ERROR, + "%s", _("Data model does not support setting values")); + return FALSE; + } +} + +/** + * gda_data_model_create_iter: + * @model: a #GdaDataModel object. + * + * Creates a new iterator object #GdaDataModelIter object which can be used to iterate through + * rows in @model. The new #GdaDataModelIter does not hold any reference to @model (ie. if @model + * is destroyed at some point, the new iterator will become useless but in any case it will not prevent + * the data model from being destroyed). + * + * Depending on the data model's implementation, a new #GdaDataModelIter object may be created, + * or a reference to an already existing #GdaDataModelIter may be returned. For example if @model only + * supports being accessed using a forward moving cursor (say a the result of a SELECT executed by SQLite + * with a cursor access mode specified), then this method will always return the same iterator. + * + * If a new #GdaDataModelIter is created, then the row it represents is undefined. + * + * For models which can be accessed + * randomly, any row can be set using gda_data_model_iter_move_to_row(), + * and for models which are accessible sequentially only then use + * gda_data_model_iter_move_next() (and gda_data_model_iter_move_prev() if + * supported). + * + * Note: for the #GdaDataProxy data model (which proxies any #GdaDataModel for modifications and + * has twice the number of columns of the proxied data model), this method will create an iterator + * in which only the columns of the proxied data model appear. If you need to have a #GdaDataModelIter + * in which all the proxy's columns appear, create it using: + * + * + * Returns: (transfer full): a #GdaDataModelIter object, or %NULL if an error occurred + */ +GdaDataModelIter * +gda_data_model_create_iter (GdaDataModel *model) +{ + g_return_val_if_fail (GDA_IS_DATA_MODEL (model), NULL); + + GdaDataModelIter *iter = NULL; + + if (GDA_DATA_MODEL_GET_IFACE (model)->create_iter) + iter = (GDA_DATA_MODEL_GET_IFACE (model)->create_iter) (model); + else + /* default method */ + iter = GDA_DATA_MODEL_ITER (g_object_new (GDA_TYPE_DATA_MODEL_ITER, + "data-model", model, NULL)); + return iter; +} + +/** + * gda_data_model_append_values: + * @model: a #GdaDataModel object. + * @values: (element-type GObject.Value) (nullable): #GList of #GValue* representing the row to add. The + * length must match model's column count. These #GValue + * are value-copied (the user is still responsible for freeing them). + * @error: a place to store errors, or %NULL + * + * Appends a row to the given data model. If any value in @values is actually %NULL, then + * it is considered as a default value. If @values is %NULL then all values are set to their default value. + * + * Upon errors -1 will be returned and @error will be assigned a + * #GError from the #GDA_DATA_MODEL_ERROR domain. + * + * Returns: the number of the added row, or -1 if an error occurred + */ +gint +gda_data_model_append_values (GdaDataModel *model, const GList *values, GError **error) +{ + g_return_val_if_fail (GDA_IS_DATA_MODEL (model), -1); + + if (GDA_DATA_MODEL_GET_IFACE (model)->append_values) + return (GDA_DATA_MODEL_GET_IFACE (model)->append_values) (model, values, error); + else { + /* method not supported */ + g_set_error (error, GDA_DATA_MODEL_ERROR, GDA_DATA_MODEL_FEATURE_NON_SUPPORTED_ERROR, + "%s", _("Data model does not support row append")); + return -1; + } +} + +/** + * gda_data_model_append_row: + * @model: a #GdaDataModel object. + * @error: a place to store errors, or %NULL + * + * Appends a row to the data model (the new row will possibly have NULL values for all columns, + * or some other values depending on the data model implementation) + * + * Upon errors -1 will be returned and @error will be assigned a + * #GError from the #GDA_DATA_MODEL_ERROR domain. + * + * Returns: the number of the added row, or -1 if an error occurred + */ +gint +gda_data_model_append_row (GdaDataModel *model, GError **error) +{ + g_return_val_if_fail (GDA_IS_DATA_MODEL (model), FALSE); + + if (! (gda_data_model_get_access_flags (model) & GDA_DATA_MODEL_ACCESS_INSERT)) { + g_set_error (error, GDA_DATA_MODEL_ERROR, GDA_DATA_MODEL_ACCESS_ERROR, + "%s", _("Model does not allow row insertion")); + return -1; + } + + if (GDA_DATA_MODEL_GET_IFACE (model)->append_row) + return (GDA_DATA_MODEL_GET_IFACE (model)->append_row) (model, error); + else { + /* method not supported */ + g_set_error (error, GDA_DATA_MODEL_ERROR, GDA_DATA_MODEL_FEATURE_NON_SUPPORTED_ERROR, + "%s", _("Data model does not support row append")); + return -1; + } +} + + +/** + * gda_data_model_remove_row: + * @model: a #GdaDataModel object. + * @row: the row number to be removed. + * @error: a place to store errors, or %NULL + * + * Removes a row from the data model. + * + * Upon errors FALSE will be returned and @error will be assigned a + * #GError from the #GDA_DATA_MODEL_ERROR domain. + * + * Returns: %TRUE if successful, %FALSE otherwise. + */ +gboolean +gda_data_model_remove_row (GdaDataModel *model, gint row, GError **error) +{ + g_return_val_if_fail (GDA_IS_DATA_MODEL (model), FALSE); + + if (! (gda_data_model_get_access_flags (model) & GDA_DATA_MODEL_ACCESS_DELETE)) { + g_set_error (error, GDA_DATA_MODEL_ERROR, GDA_DATA_MODEL_ACCESS_ERROR, + "%s", _("Model does not allow row deletion")); + return FALSE; + } + + if (GDA_DATA_MODEL_GET_IFACE (model)->remove_row) + return (GDA_DATA_MODEL_GET_IFACE (model)->remove_row) (model, row, error); + else { + /* method not supported */ + g_set_error (error, GDA_DATA_MODEL_ERROR, GDA_DATA_MODEL_FEATURE_NON_SUPPORTED_ERROR, + "%s", _("Data model does not support row removal")); + return FALSE; + } +} + +/** + * gda_data_model_get_row_from_values: + * @model: a #GdaDataModel object. + * @values: (element-type GObject.Value): a list of #GValue values (no %NULL is allowed) + * @cols_index: (array): an array of #gint containing the column number to match each value of @values + * + * Returns the first row where all the values in @values at the columns identified at + * @cols_index match. If the row can't be identified, then returns -1; + * + * NOTE: the @cols_index array MUST contain a column index for each value in @values + * + * Returns: the requested row number, of -1 if not found + */ +gint +gda_data_model_get_row_from_values (GdaDataModel *model, GSList *values, gint *cols_index) +{ + gint row = -1; + gint current_row, n_rows, n_cols; + + g_return_val_if_fail (GDA_IS_DATA_MODEL (model), -1); + g_return_val_if_fail (values, -1); + + if (GDA_DATA_MODEL_GET_IFACE (model)->find_row) + return (GDA_DATA_MODEL_GET_IFACE (model)->find_row) (model, values, cols_index); + + n_rows = gda_data_model_get_n_rows (model); + n_cols = gda_data_model_get_n_columns (model); + current_row = 0; + +#ifdef GDA_DEBUG_NO + { + GSList *list = values; + + g_print ("%s() find row for values: ", __FUNCTION__); + while (list) { + g_print ("#%s# ", gda_value_stringify ((GValue *)(list->data))); + list = g_slist_next (list); + } + g_print ("In %d rows\n", n_rows); + } +#endif + + while ((current_row < n_rows) && (row == -1)) { + GSList *list; + gboolean allequal = TRUE; + const GValue *value; + gint index; + + for (list = values, index = 0; + list; + list = list->next, index++) { + if (cols_index) + g_return_val_if_fail (cols_index [index] < n_cols, FALSE); + value = gda_data_model_get_value_at (model, cols_index [index], current_row, NULL); + + if (!value || !(list->data) || + (G_VALUE_TYPE (value) != G_VALUE_TYPE ((GValue *) list->data)) || + gda_value_compare ((GValue *) (list->data), (GValue *) value)) { + allequal = FALSE; + break; + } + } + + if (allequal) + row = current_row; + + current_row++; + } + + return row; +} + +/** + * gda_data_model_send_hint: + * @model: a #GdaDataModel + * @hint: (transfer none): a hint to send to the model + * @hint_value: (nullable): an optional value to specify the hint, or %NULL + * + * Sends a hint to the data model. The hint may or may not be handled by the data + * model, depending on its implementation + */ +void +gda_data_model_send_hint (GdaDataModel *model, GdaDataModelHint hint, const GValue *hint_value) +{ + g_return_if_fail (GDA_IS_DATA_MODEL (model)); + + if (GDA_DATA_MODEL_GET_IFACE (model)->send_hint) + (GDA_DATA_MODEL_GET_IFACE (model)->send_hint) (model, hint, hint_value); +} + +/** + * gda_data_model_get_exceptions: + * @model: a #GdaDataModel + * + * Get the global data model exception(s) that occurred when using @model. + * This is useful for example for the LDAP related + * data models where some rows may be missing because the LDAP search has reached a limit + * imposed by the LDAP server. + * + * Returns: (transfer none) (element-type GLib.Error) (array zero-terminated=1): a pointer to a %NULL terminated array of #GError, or %NULL. + * + * Since: 4.2.6 + */ +GError ** +gda_data_model_get_exceptions (GdaDataModel *model) +{ + g_return_val_if_fail (GDA_IS_DATA_MODEL (model), NULL); + + if (GDA_DATA_MODEL_GET_IFACE (model)->get_exceptions) + return (GDA_DATA_MODEL_GET_IFACE (model)->get_exceptions) (model); + else + return NULL; +} + + +static gchar *export_to_text_separated (GdaDataModel *model, const gint *cols, gint nb_cols, + const gint *rows, gint nb_rows, gchar sep, gchar quote, gboolean field_quotes, + gboolean null_as_empty, gboolean invalid_as_null); + + +/** + * gda_data_model_export_to_string: + * @model: a #GdaDataModel + * @format: the format in which to export data + * @cols: (array length=nb_cols) (nullable): an array containing which columns of @model will be exported, or %NULL for all columns + * @nb_cols: the number of columns in @cols + * @rows: (array length=nb_rows) (nullable): an array containing which rows of @model will be exported, or %NULL for all rows + * @nb_rows: the number of rows in @rows + * @options: list of options for the export + * + * Exports data contained in @model to a string; the format is specified using the @format argument, see the + * gda_data_model_export_to_file() documentation for more information about the @options argument (except for the + * "OVERWRITE" option). + * + * Warning: this function uses a #GdaDataModelIter iterator, and if @model does not offer a random access + * (check using gda_data_model_get_access_flags()), the iterator will be the same as normally used + * to access data in @model previously to calling this method, and this iterator will be moved (point to + * another row). + * + * See also gda_data_model_dump_as_string(); + * + * Returns: (transfer full): a new string, use g_free() when no longer needed + */ +gchar * +gda_data_model_export_to_string (GdaDataModel *model, GdaDataModelIOFormat format, + const gint *cols, gint nb_cols, + const gint *rows, gint nb_rows, GdaSet *options) +{ + g_return_val_if_fail (GDA_IS_DATA_MODEL (model), NULL); + g_return_val_if_fail (!options || GDA_IS_SET (options), NULL); + + switch (format) { + case GDA_DATA_MODEL_IO_DATA_ARRAY_XML: { + const gchar *name = NULL; + xmlChar *xml_contents; + xmlNodePtr xml_node; + gchar *xml; + gint size; + xmlDocPtr xml_doc; + + GdaHolder *holder; + holder = options ? gda_set_get_holder (options, "NAME") : NULL; + if (holder) { + const GValue *value; + value = gda_holder_get_value (holder); + if (value && (G_VALUE_TYPE (value) == G_TYPE_STRING)) + name = g_value_get_string ((GValue *) value); + else + g_warning (_("The '%s' parameter must hold a string value, ignored."), "NAME"); + } + + xml_node = gda_data_model_to_xml_node (model, cols, nb_cols, rows, nb_rows, name); + xml_doc = xmlNewDoc ((xmlChar*)"1.0"); + xmlDocSetRootElement (xml_doc, xml_node); + + xmlDocDumpFormatMemory (xml_doc, &xml_contents, &size, 1); + xmlFreeDoc (xml_doc); + + xml = g_strdup ((gchar*)xml_contents); + xmlFree (xml_contents); + + return xml; + } + + case GDA_DATA_MODEL_IO_TEXT_SEPARATED: { + GString *retstring; + gchar sep = ','; + gchar quote = '"'; + gboolean field_quote = TRUE; + gboolean null_as_empty = FALSE; + gboolean invalid_as_null = FALSE; + + retstring = g_string_new (""); + GdaHolder *holder; + + holder = options ? gda_set_get_holder (options, "SEPARATOR") : NULL; + if (holder) { + const GValue *value; + value = gda_holder_get_value (holder); + if (value && (G_VALUE_TYPE (value) == G_TYPE_STRING)) { + const gchar *str; + + str = g_value_get_string ((GValue *) value); + if (str && *str) + sep = *str; + } + else + g_warning (_("The '%s' parameter must hold a string value, ignored."), "SEPARATOR"); + } + holder = options ? gda_set_get_holder (options, "QUOTE") : NULL; + if (holder) { + const GValue *value; + value = gda_holder_get_value (holder); + if (value && (G_VALUE_TYPE (value) == G_TYPE_STRING)) { + const gchar *str; + + str = g_value_get_string ((GValue *) value); + if (str && *str) + quote = *str; + } + else + g_warning (_("The '%s' parameter must hold a string value, ignored."), "QUOTE"); + } + holder = options ? gda_set_get_holder (options, "FIELD_QUOTE") : NULL; + if (holder) { + const GValue *value; + value = gda_holder_get_value (holder); + if (value && (G_VALUE_TYPE (value) == G_TYPE_BOOLEAN)) + field_quote = g_value_get_boolean ((GValue *) value); + else + g_warning (_("The '%s' parameter must hold a boolean value, ignored."), "FIELD_QUOTE"); + } + + holder = options ? gda_set_get_holder (options, "NULL_AS_EMPTY") : NULL; + if (holder) { + const GValue *value; + value = gda_holder_get_value (holder); + if (value && (G_VALUE_TYPE (value) == G_TYPE_BOOLEAN)) + null_as_empty = g_value_get_boolean ((GValue *) value); + else + g_warning (_("The '%s' parameter must hold a boolean value, ignored."), "NULL_AS_EMPTY"); + } + + holder = options ? gda_set_get_holder (options, "INVALID_AS_NULL") : NULL; + if (holder) { + const GValue *value; + value = gda_holder_get_value (holder); + if (value && (G_VALUE_TYPE (value) == G_TYPE_BOOLEAN)) + invalid_as_null = g_value_get_boolean ((GValue *) value); + else + g_warning (_("The '%s' parameter must hold a boolean value, ignored."), "INVALID_AS_NULL"); + } + + holder = options ? gda_set_get_holder (options, "NAMES_ON_FIRST_LINE") : NULL; + if (!holder && options) + holder = gda_set_get_holder (options, "FIELDS_NAME"); + if (holder) { + const GValue *value; + value = gda_holder_get_value (holder); + if (value && (G_VALUE_TYPE (value) == G_TYPE_BOOLEAN)) { + if (g_value_get_boolean (value)) { + gint col; + gint *rcols; + gint rnb_cols; + + if (cols) { + rcols = (gint *)cols; + rnb_cols = nb_cols; + } + else { + gint i; + + rnb_cols = gda_data_model_get_n_columns (model); + rcols = g_new (gint, rnb_cols); + for (i = 0; i < rnb_cols; i++) + rcols[i] = i; + } + + for (col = 0; col < rnb_cols; col++) { + if (col) + g_string_append_c (retstring, sep); + g_string_append_c (retstring, quote); + g_string_append (retstring, + gda_data_model_get_column_name (model, rcols[col])); + g_string_append_c (retstring, quote); + } + g_string_append_c (retstring, '\n'); + if (!cols) + g_free (rcols); + } + } + else + g_warning (_("The '%s' parameter must hold a boolean value, ignored."), + "FIELDS_NAME"); + } + + if (cols) { + gchar *tmp; + tmp = export_to_text_separated (model, cols, nb_cols, rows, + nb_rows, sep, quote, field_quote, null_as_empty, invalid_as_null); + g_string_append (retstring, tmp); + g_free (tmp); + } + else { + gint *rcols, rnb_cols, i; + gchar *tmp; + rnb_cols = gda_data_model_get_n_columns (model); + rcols = g_new (gint, rnb_cols); + for (i = 0; i < rnb_cols; i++) + rcols[i] = i; + tmp = export_to_text_separated (model, rcols, rnb_cols, rows, nb_rows, + sep, quote, field_quote, null_as_empty, invalid_as_null); + g_string_append (retstring, tmp); + g_free (tmp); + g_free (rcols); + } + return g_string_free (retstring, FALSE); + } + + case GDA_DATA_MODEL_IO_TEXT_TABLE: { + gboolean dump_rows = FALSE; + gboolean dump_title = FALSE; + gboolean dump_column_titles = TRUE; + gboolean null_as_empty = TRUE; + gboolean dump_separators = TRUE; + gboolean dump_title_line = TRUE; + gint max_width = -1; + + /* analyse options */ + GdaHolder *holder; + holder = options ? gda_set_get_holder (options, "ROW_NUMBERS") : NULL; + if (holder) { + const GValue *value; + value = gda_holder_get_value (holder); + if (value && (G_VALUE_TYPE (value) == G_TYPE_BOOLEAN)) + dump_rows = g_value_get_boolean ((GValue *) value); + else + g_warning (_("The '%s' parameter must hold a boolean value, ignored."), "ROW_NUMBERS"); + } + + holder = options ? gda_set_get_holder (options, "NAME") : NULL; + if (holder) { + const GValue *value; + value = gda_holder_get_value (holder); + if (value && (G_VALUE_TYPE (value) == G_TYPE_BOOLEAN)) + dump_title = g_value_get_boolean ((GValue *) value); + else + g_warning (_("The '%s' parameter must hold a boolean value, ignored."), "NAME"); + } + + holder = options ? gda_set_get_holder (options, "NAMES_ON_FIRST_LINE") : NULL; + if (holder) { + const GValue *value; + value = gda_holder_get_value (holder); + if (value && (G_VALUE_TYPE (value) == G_TYPE_BOOLEAN)) + dump_column_titles = g_value_get_boolean ((GValue *) value); + else + g_warning (_("The '%s' parameter must hold a boolean value, ignored."), "NAMES_ON_FIRST_LINE"); + } + + holder = options ? gda_set_get_holder (options, "NULL_AS_EMPTY") : NULL; + if (holder) { + const GValue *value; + value = gda_holder_get_value (holder); + if (value && (G_VALUE_TYPE (value) == G_TYPE_BOOLEAN)) + null_as_empty = g_value_get_boolean ((GValue *) value); + else + g_warning (_("The '%s' parameter must hold a boolean value, ignored."), "NULL_AS_EMPTY"); + } + + holder = options ? gda_set_get_holder (options, "MAX_WIDTH") : NULL; + if (holder) { + const GValue *value; + value = gda_holder_get_value (holder); + if (value && (G_VALUE_TYPE (value) == G_TYPE_INT)) { + max_width = g_value_get_int ((GValue *) value); +#ifdef TIOCGWINSZ + if (max_width < 0) { + struct winsize window_size; + if (ioctl (0,TIOCGWINSZ, &window_size) == 0) + max_width = (int) window_size.ws_col; + } +#endif + } + else + g_warning (_("The '%s' parameter must hold an integer value, ignored."), "MAX_WIDHT"); + } + + holder = options ? gda_set_get_holder (options, "COLUMN_SEPARATORS") : NULL; + if (holder) { + const GValue *value; + value = gda_holder_get_value (holder); + if (value && (G_VALUE_TYPE (value) == G_TYPE_BOOLEAN)) + dump_separators = g_value_get_boolean ((GValue *) value); + else + g_warning (_("The '%s' parameter must hold a boolean value, ignored."), "SEPARATORS"); + } + + holder = options ? gda_set_get_holder (options, "SEPARATOR_LINE") : NULL; + if (holder) { + const GValue *value; + value = gda_holder_get_value (holder); + if (value && (G_VALUE_TYPE (value) == G_TYPE_BOOLEAN)) + dump_title_line = g_value_get_boolean ((GValue *) value); + else + g_warning (_("The '%s' parameter must hold a boolean value, ignored."), "SEPARATOR_LINE"); + } + + /* FIXME: handle @rows argument */ + if (cols) { + GdaDataModel *wrapper; + wrapper = gda_data_access_wrapper_new (model); + gda_data_access_wrapper_set_mapping (GDA_DATA_ACCESS_WRAPPER (wrapper), cols, nb_cols); + gchar *tmp; + tmp = real_gda_data_model_dump_as_string (wrapper, FALSE, dump_rows, + dump_title, null_as_empty, max_width, dump_separators, + dump_title_line, TRUE, dump_column_titles, rows, nb_rows, NULL); + g_object_unref (wrapper); + return tmp; + } + else + return real_gda_data_model_dump_as_string (model, FALSE, dump_rows, + dump_title, null_as_empty, max_width, dump_separators, + dump_title_line, TRUE, dump_column_titles, rows, nb_rows, NULL); + } + + default: + g_warning (_("Unknown GdaDataModelIOFormat %d value"), format); + } + return NULL; +} + +/** + * gda_data_model_export_to_file: + * @model: a #GdaDataModel + * @format: the format in which to export data + * @file: the filename to export to + * @cols: (array length=nb_cols) (nullable): an array containing which columns of @model will be exported, or %NULL for all columns + * @nb_cols: the number of columns in @cols + * @rows: (array length=nb_rows) (nullable): an array containing which rows of @model will be exported, or %NULL for all rows + * @nb_rows: the number of rows in @rows + * @options: list of options for the export + * @error: a place to store errors, or %NULL + * + * Exports data contained in @model to the @file file; the format is specified using the @format argument. Note that + * the date format used is the one used by the connection from which the data model has been made (as the result of a + * SELECT statement), or, for other kinds of data models, the default format (refer to gda_data_handler_get_default()) unless + * the "cnc" property has been set and points to a #GdaConnection to use that connection's date format. + * + * Specifically, the parameters in the @options list can be: + * + * "SEPARATOR": a string value of which the first character is used as a separator in case of CSV export + * + * "QUOTE": a string value of which the first character is used as a quote character in case of CSV export. The + * default if not specified is the double quote character + * "FIELD_QUOTE": a boolean value which can be set to FALSE if no quote around the individual fields + * is requeted, in case of CSV export + * "NAMES_ON_FIRST_LINE": a boolean value which, if set to %TRUE and in case of a CSV or %GDA_DATA_MODEL_IO_TEXT_TABLE export, will add a first line with the name each exported field (note that "FIELDS_NAME" is also accepted as a synonym) + * "NAME": a string value used to name the exported data if the export format is XML or %GDA_DATA_MODEL_IO_TEXT_TABLE + * "OVERWRITE": a boolean value which tells if the file must be over-written if it already exists. + * "NULL_AS_EMPTY": a boolean value which, if set to %TRUE and in case of a CSV or %GDA_DATA_MODEL_IO_TEXT_TABLE export, will render and NULL value as the empty string (instead of the 'NULL' string) + * "INVALID_AS_NULL": a boolean value which, if set to %TRUE, considers any invalid data (for example for the date related values) as NULL + * "COLUMN_SEPARATORS": a boolean value which, if set to %TRUE, adds a separators lines between each column, if the export format is %GDA_DATA_MODEL_IO_TEXT_TABLE + * +* "SEPARATOR_LINE": a boolean value which, if set to %TRUE, adds an horizontal line between column titles and values, if the export format is %GDA_DATA_MODEL_IO_TEXT_TABLE + * + * "ROW_NUMBERS": a boolean value which, if set to %TRUE, prepends a column with row numbers, if the export format is %GDA_DATA_MODEL_IO_TEXT_TABLE + * + * "MAX_WIDTH": an integer value which, if greater than 0, makes all the lines truncated to have at most that number of characters, if the export format is %GDA_DATA_MODEL_IO_TEXT_TABLE + * + * + * + * Warning: this function uses a #GdaDataModelIter iterator, and if @model does not offer a random access + * (check using gda_data_model_get_access_flags()), the iterator will be the same as normally used + * to access data in @model previously to calling this method, and this iterator will be moved (point to + * another row). + * + * Upon errors %FALSE will be returned and @error will be assigned a + * #GError from the #GDA_DATA_MODEL_ERROR domain. + * + * Returns: TRUE if no error occurred + */ +gboolean +gda_data_model_export_to_file (GdaDataModel *model, GdaDataModelIOFormat format, + const gchar *file, + const gint *cols, gint nb_cols, + const gint *rows, gint nb_rows, + GdaSet *options, GError **error) +{ + gchar *body; + gboolean overwrite = FALSE; + + g_return_val_if_fail (GDA_IS_DATA_MODEL (model), FALSE); + g_return_val_if_fail (!options || GDA_IS_SET (options), FALSE); + g_return_val_if_fail (file, FALSE); + + body = gda_data_model_export_to_string (model, format, cols, nb_cols, rows, nb_rows, options); + GdaHolder *holder; + + holder = options ? gda_set_get_holder (options, "OVERWRITE") : NULL; + if (holder) { + const GValue *value; + value = gda_holder_get_value (holder); + if (value && (G_VALUE_TYPE (value) == G_TYPE_BOOLEAN)) + overwrite = g_value_get_boolean ((GValue *) value); + else + g_warning (_("The '%s' parameter must hold a boolean value, ignored."), "OVERWRITE"); + } + + if (g_file_test (file, G_FILE_TEST_EXISTS)) { + if (! overwrite) { + g_free (body); + g_set_error (error, GDA_DATA_MODEL_ERROR, GDA_DATA_MODEL_FILE_EXIST_ERROR, + _("File '%s' already exists"), file); + return FALSE; + } + } + + if (! g_file_set_contents (file, body, -1, error)) { + g_free (body); + return FALSE; + } + g_free (body); + return TRUE; +} + +static gchar * +export_to_text_separated (GdaDataModel *model, const gint *cols, gint nb_cols, + const gint *rows, gint nb_rows, + gchar sep, gchar quote, gboolean field_quotes, + gboolean null_as_empty, gboolean invalid_as_null) +{ + GString *str; + gint c; + GdaDataModelIter *iter; + gboolean addnl = FALSE; + + g_return_val_if_fail (GDA_IS_DATA_MODEL (model), NULL); + + str = g_string_new (""); + iter = gda_data_model_create_iter (model); + if (!iter) + return g_string_free (str, FALSE); + + if ((gda_data_model_iter_get_row (iter) == -1) && ! gda_data_model_iter_move_next (iter)) { + g_object_unref (iter); + return g_string_free (str, FALSE); + } + + for (; gda_data_model_iter_is_valid (iter); gda_data_model_iter_move_next (iter)) { + if (rows) { + gint r; + for (r = 0; r < nb_rows; r++) { + if (gda_data_model_iter_get_row (iter) == rows[r]) + break; + } + if (r == nb_rows) + continue; + } + + if (addnl) + str = g_string_append_c (str, '\n'); + else + addnl = TRUE; + + for (c = 0; c < nb_cols; c++) { + GValue *value; + gchar *txt; + + value = (GValue*) gda_data_model_iter_get_value_at (iter, cols[c]); + if (value && invalid_as_null) { + if (g_type_is_a (G_VALUE_TYPE (value), G_TYPE_DATE)) { + GDate *date = (GDate*) g_value_get_boxed (value); + if (!g_date_valid (date)) + value = NULL; + } + else if (g_type_is_a (G_VALUE_TYPE (value), GDA_TYPE_TIME)) { + const GdaTime *tim = gda_value_get_time (value); + if (!tim) + value = NULL; + } + else if (g_type_is_a (G_VALUE_TYPE (value), G_TYPE_DATE_TIME)) { + GDateTime *ts = g_value_get_boxed (value); + if (ts == NULL) + value = NULL; + } + } + + if (!value) { + if (null_as_empty) + txt = g_strdup (""); + else + txt = g_strdup ("NULL"); + } + else if (G_VALUE_TYPE (value) == G_TYPE_BOOLEAN) + txt = g_strdup (g_value_get_boolean (value) ? "TRUE" : "FALSE"); + else if (null_as_empty && gda_value_is_null (value)) + txt = g_strdup (""); + else { + gboolean alloc = FALSE; + gchar *tmp; + + if (value && (G_VALUE_TYPE (value) == G_TYPE_STRING)) + tmp = (gchar*) g_value_get_string (value); + else { + tmp = gda_value_stringify (value); + alloc = TRUE; + } + if (tmp) { + gsize len, size; + len = strlen (tmp); + size = 2 * len + 3; + txt = g_new (gchar, size); + + len = csv_write2 (txt, size, tmp, len, quote); + txt [len] = 0; + if (!field_quotes) { + txt [len - 1] = 0; + memmove (txt, txt+1, len); + } + if (alloc) + g_free (tmp); + } + else { + if (field_quotes) { + txt = g_new (gchar, 3); + txt [0] = quote; + txt [1] = quote; + txt [2] = 0; + } + else + txt = g_strdup (""); + } + } + if (c > 0) + str = g_string_append_c (str, sep); + + str = g_string_append (str, txt); + g_free (txt); + } + } + + g_object_unref (iter); + return g_string_free (str, FALSE); +} + +static void +xml_set_boolean (xmlNodePtr node, const gchar *name, gboolean value) +{ + xmlSetProp (node, (xmlChar*)name, value ? (xmlChar*)"TRUE" : (xmlChar*)"FALSE"); +} + +/* + * gda_data_model_to_xml_node + * @model: a #GdaDataModel object. + * @cols: (nullable) (array length=nb_cols): an array containing which columns of @model will be exported, or %NULL for all columns + * @nb_cols: the number of columns in @cols + * @rows: (nullable) (array length=nb_rows): an array containing which rows of @model will be exported, or %NULL for all rows + * @nb_rows: the number of rows in @rows + * @name: (nullable): name to use for the XML resulting table or %NULL. + * + * Converts a #GdaDataModel into a xmlNodePtr (as used in libxml). + * + * Returns: a xmlNodePtr representing the whole data model, or %NULL if an error occurred + */ +static xmlNodePtr +gda_data_model_to_xml_node (GdaDataModel *model, const gint *cols, gint nb_cols, + const gint *rows, gint nb_rows, const gchar *name) +{ + xmlNodePtr node; + gint i; + gint *rcols, rnb_cols; + const gchar *cstr; + + g_return_val_if_fail (GDA_IS_DATA_MODEL (model), NULL); + + node = xmlNewNode (NULL, BAD_CAST "gda_array"); + cstr = g_object_get_data (G_OBJECT (model), "id"); + if (cstr) + xmlSetProp (node, BAD_CAST "id", BAD_CAST cstr); + else + xmlSetProp (node, BAD_CAST "id", BAD_CAST "EXPORT"); + + if (name) + xmlSetProp (node, BAD_CAST "name", BAD_CAST name); + else { + cstr = g_object_get_data (G_OBJECT (model), "name"); + if (cstr) + xmlSetProp (node, BAD_CAST "name", BAD_CAST cstr); + else + xmlSetProp (node, BAD_CAST "name", BAD_CAST _("Exported Data")); + } + + /* compute columns if not provided */ + if (!cols) { + rnb_cols = gda_data_model_get_n_columns (model); + rcols = g_new (gint, rnb_cols); + for (i = 0; i < rnb_cols; i++) + rcols [i] = i; + } + else { + rcols = (gint *) cols; + rnb_cols = nb_cols; + } + + /* set the table structure */ + for (i = 0; i < rnb_cols; i++) { + GdaColumn *column; + xmlNodePtr field; + const gchar *cstr; + gchar *str; + + column = gda_data_model_describe_column (model, rcols [i]); + if (!column) { + xmlFreeNode (node); + return NULL; + } + + field = xmlNewChild (node, NULL, BAD_CAST "gda_array_field", NULL); + g_object_get (G_OBJECT (column), "id", &str, NULL); + if (!str) + str = g_strdup_printf ("FI%d", i); + xmlSetProp (field, BAD_CAST "id", BAD_CAST str); + g_free (str); + xmlSetProp (field, BAD_CAST "name", BAD_CAST gda_column_get_name (column)); + cstr = gda_column_get_description (column); + if (cstr && *cstr) + xmlSetProp (field, BAD_CAST "title", BAD_CAST cstr); + cstr = gda_column_get_dbms_type (column); + if (cstr && *cstr) + xmlSetProp (field, BAD_CAST "dbms_type", BAD_CAST cstr); + xmlSetProp (field, BAD_CAST "gdatype", BAD_CAST gda_g_type_to_string (gda_column_get_g_type (column))); + if (gda_column_get_allow_null (column)) + xml_set_boolean (field, "nullok", gda_column_get_allow_null (column)); + if (gda_column_get_auto_increment (column)) + xml_set_boolean (field, "auto_increment", gda_column_get_auto_increment (column)); + } + + /* add the model data to the XML output */ + if (!gda_utility_data_model_dump_data_to_xml (model, node, cols, nb_cols, rows, nb_rows, FALSE)) { + xmlFreeNode (node); + node = NULL; + } + + if (!cols) + g_free (rcols); + + return node; +} + +static GdaColumn * +find_column_from_id (GdaDataModel *model, const gchar *colid, gint *pos) +{ + GdaColumn *column = NULL; + gint c, nbcols; + + /* assume @colid is the ID of a column */ + nbcols = gda_data_model_get_n_columns (model); + for (c = 0; !column && (c < nbcols); c++) { + gchar *id; + column = gda_data_model_describe_column (model, c); + g_object_get (column, "id", &id, NULL); + if (!id || strcmp (id, colid)) + column = NULL; + else + *pos = c; + g_free (id); + } + + /* if no column has been found, assumr @colid is like "_%d" where %d is a column number */ + if (!column && (*colid == '_')) { + gint i; + i = atoi (colid + 1); /* Flawfinder: ignore */ + if (i >= 0) { + column = gda_data_model_describe_column (model, i); + if (column) + *pos = i; + } + } + + return column; +} + +static gboolean +add_xml_row (GdaDataModel *model, xmlNodePtr xml_row, GError **error) +{ + xmlNodePtr xml_field; + GList *value_list = NULL; + GPtrArray *values; + gsize i; + gboolean retval = TRUE; + gint pos = 0; + + const gchar *lang = setlocale(LC_ALL, NULL); + + values = g_ptr_array_new (); + g_ptr_array_set_size (values, gda_data_model_get_n_columns (model)); + for (xml_field = xml_row->xmlChildrenNode; xml_field != NULL; xml_field = xml_field->next) { + GValue *value = NULL; + GdaColumn *column = NULL; + GType gdatype; + gchar *isnull = NULL; + xmlChar *this_lang = NULL; + xmlChar *colid = NULL; + + if (xmlNodeIsText (xml_field)) + continue; + + if (strcmp ((gchar*)xml_field->name, "gda_value") && + strcmp ((gchar*)xml_field->name, "gda_array_value")) { + continue; + } + + this_lang = xmlGetProp (xml_field, BAD_CAST "lang"); + if (this_lang && strncmp ((gchar*)this_lang, lang, strlen ((gchar*)this_lang))) { + xmlFree (this_lang); + continue; + } + + colid = xmlGetProp (xml_field, BAD_CAST "colid"); + + /* create the value for this field */ + if (!colid) { + if (this_lang) + column = gda_data_model_describe_column (model, pos - 1); + else + column = gda_data_model_describe_column (model, pos); + } + else { + column = find_column_from_id (model, (gchar*)colid, &pos); + xmlFree (colid); + if (!column) + continue; + } + + gdatype = gda_column_get_g_type (column); + if ((gdatype == G_TYPE_INVALID) || (gdatype == GDA_TYPE_NULL)) { + g_set_error (error, GDA_DATA_MODEL_ERROR, GDA_DATA_MODEL_XML_FORMAT_ERROR, + "%s", _("Cannot retrieve column data type (type is UNKNOWN or not specified)")); + retval = FALSE; + break; + } + + gboolean nullforced = FALSE; + isnull = (gchar*)xmlGetProp (xml_field, BAD_CAST "isnull"); + if (isnull) { + if ((*isnull == 't') || (*isnull == 'T')) + nullforced = TRUE; + g_free (isnull); + } + + if (!nullforced) { + value = g_new0 (GValue, 1); + gchar* nodeval = (gchar*)xmlNodeGetContent (xml_field); + if (nodeval) { + if (!gda_value_set_from_string (value, nodeval, gdatype)) + gda_value_set_null (value); + xmlFree(nodeval); + } + else + gda_value_set_null (value); + } + + g_ptr_array_index (values, pos) = value; + if (this_lang) + xmlFree (this_lang); + else + pos ++; + } + + if (retval) { + for (i = 0; i < values->len; i++) { + GValue *value = (GValue *) g_ptr_array_index (values, i); + + if (!value) { + value = gda_value_new_null (); + g_ptr_array_index (values, i) = value; + } + + value_list = g_list_append (value_list, value); + } + + if (retval) + gda_data_model_append_values (model, value_list, NULL); + + g_list_free (value_list); + } + + for (i = 0; i < values->len; i++) + if (g_ptr_array_index (values, i)) + gda_value_free ((GValue *) g_ptr_array_index (values, i)); + + g_ptr_array_free (values, TRUE); + + return retval; +} + +/** + * gda_data_model_add_data_from_xml_node: + * @model: a #GdaDataModel. + * @node: an XML node representing a <gda_array_data> XML node. + * @error: a place to store errors, or %NULL + * + * Adds the data from an XML node to the given data model (see the DTD for that node + * in the $prefix/share/libgda/dtd/libgda-array.dtd file). + * + * Upon errors FALSE will be returned and @error will be assigned a + * #GError from the #GDA_DATA_MODEL_ERROR domain. + * + * Returns: %TRUE if successful, %FALSE otherwise. + */ +gboolean +gda_data_model_add_data_from_xml_node (GdaDataModel *model, xmlNodePtr node, GError **error) +{ + xmlNodePtr children; + + g_return_val_if_fail (GDA_IS_DATA_MODEL (model), FALSE); + g_return_val_if_fail (node != NULL, FALSE); + + while (xmlNodeIsText (node)) + node = node->next; + + if (strcmp ((gchar*)node->name, "gda_array_data")) { + g_set_error (error, GDA_DATA_MODEL_ERROR, GDA_DATA_MODEL_XML_FORMAT_ERROR, + _("Expected tag , got <%s>"), node->name); + return FALSE; + } + + for (children = node->xmlChildrenNode; children != NULL; children = children->next) { + if (!strcmp ((gchar*)children->name, "gda_array_row")) { + if (!add_xml_row (model, children, error)) + return FALSE; + } + } + + return TRUE; +} + +/** + * gda_data_model_import_from_model: + * @to: the destination #GdaDataModel + * @from: the source #GdaDataModel + * @overwrite: TRUE if @to is completely overwritten by @from's data, and FALSE if @from's data is appended to @to + * @cols_trans: (element-type gint gint) (nullable): a #GHashTable for columns translating, or %NULL + * @error: a place to store errors, or %NULL + * + * Copy the contents of the @from data model to the @to data model. The copy stops as soon as an error + * orrurs. + * + * The @cols_trans is a hash table for which keys are @to columns numbers and the values are + * the corresponding column numbers in the @from data model. To set the values of a column in @to to NULL, + * create an entry in the hash table with a negative value. For example: + * + * + * Upon errors FALSE will be returned and @error will be assigned a + * #GError from the #GDA_DATA_MODEL_ERROR domain. + * + * Returns: TRUE if no error occurred. + */ +gboolean +gda_data_model_import_from_model (GdaDataModel *to, GdaDataModel *from, + gboolean overwrite, GHashTable *cols_trans, GError **error) +{ + GdaDataModelIter *from_iter; + gboolean retval = TRUE; + gint to_nb_cols, to_nb_rows=-1, to_row = -1; + gint from_nb_cols; + GSList *copy_params = NULL; + gint i; + GList *append_values = NULL; /* list of #GValue values to add to the @to model */ + GType *append_types = NULL; /* array of the Glib type of the values to append */ + GSList *plist; + + g_return_val_if_fail (GDA_IS_DATA_MODEL (to), FALSE); + g_return_val_if_fail (GDA_IS_DATA_MODEL (from), FALSE); + + /* return if @to does not have any column */ + to_nb_cols = gda_data_model_get_n_columns (to); + if (to_nb_cols == 0) + return TRUE; + from_nb_cols = gda_data_model_get_n_columns (from); + if (from_nb_cols == 0) + return TRUE; + + /* obtain an iterator */ + from_iter = gda_data_model_create_iter (from); + if (!from_iter) { + g_set_error (error, GDA_DATA_MODEL_ERROR, GDA_DATA_MODEL_ACCESS_ERROR, + "%s", _("Could not get an iterator for source data model")); + return FALSE; + } + + /* make a list of the parameters which will be used during copy (stored in reverse order: last column of data model + * represented by the 1st GdaHolder) , + * an some tests */ + for (i = 0; i < to_nb_cols; i++) { + GdaHolder *param = NULL; + gint col; /* source column number */ + GdaColumn *column; + + if (cols_trans) { + col = GPOINTER_TO_INT (g_hash_table_lookup (cols_trans, &i)); + if ((col < 0) || (col >= from_nb_cols)) { + g_slist_free (copy_params); + g_set_error (error, GDA_DATA_MODEL_ERROR, GDA_DATA_MODEL_COLUMN_OUT_OF_RANGE_ERROR, + _("Inexistent column in source data model: %d"), col); + return FALSE; + } + } + else + col = i; + if (col >= 0) + param = gda_data_model_iter_get_holder_for_field (from_iter, col); + + /* tests */ + column = gda_data_model_describe_column (to, i); + if (! gda_column_get_allow_null (column) && !param) { + g_slist_free (copy_params); + g_set_error (error, GDA_DATA_MODEL_ERROR, GDA_DATA_MODEL_VALUE_TYPE_ERROR, + _("Destination column %d can't be NULL but has no correspondence in the " + "source data model"), i); + return FALSE; + } + if (param) { + if ((gda_column_get_g_type (column) != G_TYPE_INVALID) && + (gda_holder_get_g_type (param) != G_TYPE_INVALID) && + !g_value_type_transformable (gda_holder_get_g_type (param), + gda_column_get_g_type (column))) { + g_slist_free (copy_params); + g_set_error (error, GDA_DATA_MODEL_ERROR, GDA_DATA_MODEL_VALUE_TYPE_ERROR, + _("Destination column %d has a gda type (%s) incompatible with " + "source column %d type (%s)"), i, + gda_g_type_to_string (gda_column_get_g_type (column)), + col, + gda_g_type_to_string (gda_holder_get_g_type (param))); + return FALSE; + } + } + + copy_params = g_slist_prepend (copy_params, param); + } + +#ifdef GDA_DEBUG_NO + { + GSList *list; + for (list = copy_params; list; list = list->next) { + GdaHolder *param = GDA_HOLDER (list->data); + g_print ("Copy Param: %s (%s)\n", gda_holder_get_id (param), + gda_g_type_to_string (gda_holder_get_g_type (param))); + } + } +#endif + + /* build the append_values list (stored in reverse order!) + * node->data is: + * - NULL if the value must be replaced by the value of the copied model + * - a GValue of type GDA_VALYE_TYPE_NULL if a null value must be inserted in the dest data model + * - a GValue of a different type if the value must be converted from the src data model + */ + append_types = g_new0 (GType, (guint)to_nb_cols); + for (plist = copy_params, i = to_nb_cols - 1; plist; plist = plist->next, i--) { + GdaColumn *column; + + column = gda_data_model_describe_column (to, i); + if (plist->data) { + if ((gda_holder_get_g_type (GDA_HOLDER (plist->data)) != gda_column_get_g_type (column)) && + (gda_column_get_g_type (column) != GDA_TYPE_NULL)) { + GValue *newval; + + newval = g_new0 (GValue, 1); + append_types [i] = gda_column_get_g_type (column); + g_value_init (newval, append_types [i]); + append_values = g_list_prepend (append_values, newval); + } + else + append_values = g_list_prepend (append_values, NULL); + } + else + append_values = g_list_prepend (append_values, gda_value_new_null ()); + } + append_values = g_list_reverse (append_values); +#ifdef GDA_DEBUG_NO + { + GList *list; + for (list = append_values; list; list = list->next) + g_print ("Append Value: %s\n", list->data ? gda_g_type_to_string (G_VALUE_TYPE ((GValue *) (list->data))) : "NULL"); + } +#endif + + /* actual data copy (no memory allocation is needed here) */ + gda_data_model_send_hint (to, GDA_DATA_MODEL_HINT_START_BATCH_UPDATE, NULL); + + if (overwrite) { + to_row = 0; + to_nb_rows = gda_data_model_get_n_rows (to); + } + + gboolean mstatus; + mstatus = gda_data_model_iter_move_next (from_iter); /* move to first row */ + if (!mstatus) { + gint crow; + g_object_get (from_iter, "current-row", &crow, NULL); + if (crow >= 0) + retval = FALSE; + } + while (retval && gda_data_model_iter_is_valid (from_iter)) { + GList *values = NULL; + GList *avlist = append_values; + plist = copy_params; + i = to_nb_cols - 1; + + while (plist && avlist && retval) { + GValue *value; + + value = (GValue *) (avlist->data); + if (plist->data) { + value = (GValue *) gda_holder_get_value (GDA_HOLDER (plist->data)); + if (avlist->data) { + if (append_types [i] && gda_value_is_null ((GValue *) (avlist->data))) + gda_value_reset_with_type ((GValue *) (avlist->data), append_types [i]); + if (!gda_value_is_null (value) && + !g_value_transform (value, (GValue *) (avlist->data))) { + gchar *str; + + str = gda_value_stringify (value); + g_set_error (error, GDA_DATA_MODEL_ERROR, GDA_DATA_MODEL_VALUE_TYPE_ERROR, + _("Can't transform '%s' from GDA type %s to GDA type %s"), + str, + gda_g_type_to_string (G_VALUE_TYPE (value)), + gda_g_type_to_string (G_VALUE_TYPE ((GValue *) (avlist->data)))); + g_free (str); + retval = FALSE; + } + value = (GValue *) (avlist->data); + } + } + + values = g_list_prepend (values, value); + + plist = plist->next; + avlist = avlist->next; + i--; + } + + if (retval) { + if (to_row >= to_nb_rows) + /* we have finished modifying the existing rows */ + to_row = -1; + + if (to_row >= 0) { + if (!gda_data_model_set_values (to, to_row, values, error)) + retval = FALSE; + else + to_row ++; + } + else { + if (gda_data_model_append_values (to, values, error) < 0) + retval = FALSE; + } + } + + g_list_free (values); + mstatus = gda_data_model_iter_move_next (from_iter); + if (!mstatus) { + gint crow; + g_object_get (from_iter, "current-row", &crow, NULL); + if (crow >= 0) + retval = FALSE; + } + } + + /* free memory */ + if (copy_params) { + g_slist_free (copy_params); + } + g_list_free_full (append_values, (GDestroyNotify) gda_value_free); + g_free (append_types); + + if (retval && (to_row >= 0)) { + /* remove extra rows */ + for (; retval && (to_row < to_nb_rows); to_row++) { + if (!gda_data_model_remove_row (to, to_row, error)) + retval = FALSE; + } + } + + gda_data_model_send_hint (to, GDA_DATA_MODEL_HINT_END_BATCH_UPDATE, NULL); + return retval; +} + +/** + * gda_data_model_import_from_string: + * @model: a #GdaDataModel + * @string: the string to import data from + * @cols_trans: (element-type gint gint) (nullable): a hash table containing which columns of @model will be imported, or %NULL for all columns, see gda_data_model_import_from_model() + * @options: list of options for the export + * @error: a place to store errors, or %NULL + * + * Loads the data from @string into @model. + * + * Upon errors FALSE will be returned and @error will be assigned a + * #GError from the #GDA_DATA_MODEL_ERROR domain. + * + * Returns: TRUE if no error occurred. + */ +gboolean +gda_data_model_import_from_string (GdaDataModel *model, + const gchar *string, GHashTable *cols_trans, + GdaSet *options, GError **error) +{ + GdaDataModel *import; + gboolean retval; + + g_return_val_if_fail (GDA_IS_DATA_MODEL (model), FALSE); + g_return_val_if_fail (!options || GDA_IS_SET (options), FALSE); + if (!string) + return TRUE; + + import = gda_data_model_import_new_mem (string, FALSE, options); + retval = gda_data_model_import_from_model (model, import, FALSE, cols_trans, error); + g_object_unref (import); + + return retval; +} + +/** + * gda_data_model_import_from_file: + * @model: a #GdaDataModel + * @file: the filename to import from + * @cols_trans: (element-type gint gint) (nullable): a #GHashTable for columns translating, or %NULL, see gda_data_model_import_from_model() + * @options: list of options for the export + * @error: a place to store errors, or %NULL + * + * Imports data contained in the @file file into @model; the format is detected. + * + * Upon errors FALSE will be returned and @error will be assigned a + * #GError from the #GDA_DATA_MODEL_ERROR domain. + * + * Returns: TRUE if no error occurred + */ +gboolean +gda_data_model_import_from_file (GdaDataModel *model, + const gchar *file, GHashTable *cols_trans, + GdaSet *options, GError **error) +{ + GdaDataModel *import; + gboolean retval; + + g_return_val_if_fail (GDA_IS_DATA_MODEL (model), FALSE); + g_return_val_if_fail (!options || GDA_IS_SET (options), FALSE); + if (!file) + return TRUE; + + import = gda_data_model_import_new_file (file, FALSE, options); + retval = gda_data_model_import_from_model (model, import, FALSE, cols_trans, error); + g_object_unref (import); + + return retval; +} + +/** + * gda_data_model_dump: + * @model: a #GdaDataModel. + * @to_stream: where to dump the data model + * + * Dumps a textual representation of the @model to the @to_stream stream + * + * The following environment variables can affect the resulting output: + * + * GDA_DATA_MODEL_DUMP_ROW_NUMBERS: if set, the first column of the output will contain row numbers + * GDA_DATA_MODEL_DUMP_ATTRIBUTES: if set, also dump the data model's columns' types and value's attributes + * GDA_DATA_MODEL_DUMP_TITLE: if set, also dump the data model's title + * GDA_DATA_MODEL_NULL_AS_EMPTY: if set, replace the 'NULL' string with an empty string for NULL values + * GDA_DATA_MODEL_DUMP_TRUNCATE: if set to a numeric value, truncates the output to the width specified by the value. If the value is -1 then the actual terminal size (if it can be determined) is used + * + */ +void +gda_data_model_dump (GdaDataModel *model, FILE *to_stream) +{ + gchar *str; + gboolean dump_attrs = FALSE; + gboolean dump_rows = FALSE; + gboolean dump_title = FALSE; + gboolean null_as_empty = FALSE; + gint max_width = 0; /* no truncate */ + GError *error = NULL; + const gchar *cstr; + + g_return_if_fail (GDA_IS_DATA_MODEL (model)); + if (!to_stream) + to_stream = stdout; + + if (getenv ("GDA_DATA_MODEL_DUMP_ATTRIBUTES")) /* Flawfinder: ignore */ + dump_attrs = TRUE; + if (getenv ("GDA_DATA_MODEL_DUMP_ROW_NUMBERS")) /* Flawfinder: ignore */ + dump_rows = TRUE; + if (getenv ("GDA_DATA_MODEL_DUMP_TITLE")) /* Flawfinder: ignore */ + dump_title = TRUE; + if (getenv ("GDA_DATA_MODEL_NULL_AS_EMPTY")) /* Flawfinder: ignore */ + null_as_empty = TRUE; + cstr = getenv ("GDA_DATA_MODEL_DUMP_TRUNCATE"); + if (cstr) { + max_width = atoi (cstr); +#ifdef TIOCGWINSZ + if (max_width < 0) { + struct winsize window_size; + if (ioctl (0,TIOCGWINSZ, &window_size) == 0) + max_width = (int) window_size.ws_col; + } +#endif + if (max_width < 0) + max_width = 0; + } + + str = real_gda_data_model_dump_as_string (model, FALSE, dump_rows, dump_title, null_as_empty, max_width, + TRUE, TRUE, FALSE, TRUE, NULL, 0, &error); + if (str) { + g_fprintf (to_stream, "%s", str); + g_free (str); + if (dump_attrs) { + str = real_gda_data_model_dump_as_string (model, TRUE, dump_rows, dump_title, null_as_empty, max_width, + TRUE, TRUE, FALSE, TRUE, NULL, 0, &error); + if (str) { + g_fprintf (to_stream, "%s", str); + g_free (str); + } + else { + g_warning (_("Could not dump data model's attributes: %s"), + error && error->message ? error->message : _("No detail")); + if (error) + g_error_free (error); + } + } + } + else { + g_warning (_("Could not dump data model's contents: %s"), + error && error->message ? error->message : _("No detail")); + if (error) + g_error_free (error); + } +} + +/** + * gda_data_model_dump_as_string: + * @model: a #GdaDataModel. + * + * Dumps a textual representation of the @model into a new string. The main differences with gda_data_model_export_to_string() are that + * the formatting options are passed using environment variables, and that the data is dumped regardless of the user locale (e.g. dates + * are not formatted according to the locale). + * + * The following environment variables can affect the resulting output: + * + * GDA_DATA_MODEL_DUMP_ROW_NUMBERS: if set, the first column of the output will contain row numbers + * GDA_DATA_MODEL_DUMP_TITLE: if set, also dump the data model's title + * GDA_DATA_MODEL_NULL_AS_EMPTY: if set, replace the 'NULL' string with an empty string for NULL values + * GDA_DATA_MODEL_DUMP_TRUNCATE: if set to a numeric value, truncates the output to the width specified by the value. If the value is -1 then the actual terminal size (if it can be determined) is used + * + * + * Returns: (transfer full): a new string. + */ +gchar * +gda_data_model_dump_as_string (GdaDataModel *model) +{ + gboolean dump_attrs = FALSE; + gboolean dump_rows = FALSE; + gboolean dump_title = FALSE; + gboolean null_as_empty = FALSE; + gint max_width = 0; /* no truncate */ + const gchar *cstr; + + g_return_val_if_fail (GDA_IS_DATA_MODEL (model), NULL); + + if (getenv ("GDA_DATA_MODEL_DUMP_ATTRIBUTES")) /* Flawfinder: ignore */ + dump_attrs = TRUE; + if (getenv ("GDA_DATA_MODEL_DUMP_ROW_NUMBERS")) /* Flawfinder: ignore */ + dump_rows = TRUE; + if (getenv ("GDA_DATA_MODEL_DUMP_TITLE")) /* Flawfinder: ignore */ + dump_title = TRUE; + if (getenv ("GDA_DATA_MODEL_NULL_AS_EMPTY")) /* Flawfinder: ignore */ + null_as_empty = TRUE; + cstr = getenv ("GDA_DATA_MODEL_DUMP_TRUNCATE"); + if (cstr) { + max_width = atoi (cstr); +#ifdef TIOCGWINSZ + if (max_width < 0) { + struct winsize window_size; + if (ioctl (0,TIOCGWINSZ, &window_size) == 0) + max_width = (int) window_size.ws_col; + } +#endif + if (max_width < 0) + max_width = 0; + } + if (dump_attrs) { + GString *string; + gchar *tmp; + tmp = real_gda_data_model_dump_as_string (model, FALSE, dump_rows, dump_title, null_as_empty, max_width, + TRUE, TRUE, FALSE, TRUE, NULL, 0, NULL); + string = g_string_new (tmp); + g_free (tmp); + tmp = real_gda_data_model_dump_as_string (model, TRUE, dump_rows, dump_title, null_as_empty, max_width, + TRUE, TRUE, FALSE, TRUE, NULL, 0, NULL); + g_string_append_c (string, '\n'); + g_string_append (string, tmp); + g_free (tmp); + return g_string_free (string, FALSE); + } + else + return real_gda_data_model_dump_as_string (model, FALSE, dump_rows, dump_title, null_as_empty, max_width, + TRUE, TRUE, FALSE, TRUE, NULL, 0, NULL); +} + +static void +string_get_dimensions (const gchar *string, gint *width, gint *rows) +{ + const gchar *ptr; + gint w = 0, h = 0, maxw = 0; + for (ptr = string; *ptr; ptr = g_utf8_next_char (ptr)) { + if (*ptr == '\n') { + h++; + maxw = MAX (maxw, w); + w = 0; + } + else + w++; + } + maxw = MAX (maxw, w); + + if (width) + *width = maxw; + if (rows) + *rows = h; +} + +/* + * Returns: a new string, or %NULL if @model does not support random access + */ +static gchar * +real_gda_data_model_dump_as_string (GdaDataModel *model, gboolean dump_attributes, + gboolean dump_rows, gboolean dump_title, gboolean null_as_empty, + gint max_width, gboolean dump_separators, gboolean dump_sep_line, + gboolean use_data_handlers, gboolean dump_column_titles, + const gint *rows, gint nb_rows, + GError **error) +{ +#define ERROR_STRING "####" +#define MULTI_LINE_NO_SEPARATOR + + gboolean allok = TRUE; + GString *string = NULL; + gchar *str; + gint n_cols, n_rows, real_n_rows; + gint *cols_size; + gboolean *cols_is_num; + gchar *sep_col = " | "; +#ifdef MULTI_LINE_NO_SEPARATOR + gchar *sep_col_e = " "; +#endif + gchar *sep_row = "-+-"; + gchar *sep_fill = "-"; + gint i, j; + const GValue *value; + + gint col_offset = dump_rows ? 1 : 0; + GdaDataModel *ramodel = NULL; + + if (!dump_separators) { + sep_col = " "; + sep_row = "-"; +#ifdef MULTI_LINE_NO_SEPARATOR + sep_col_e = " "; +#endif + } + +#ifdef HAVE_LOCALE_H +#ifndef G_OS_WIN32 + if (dump_separators || dump_sep_line) { + int utf8_mode; + utf8_mode = (strcmp (nl_langinfo (CODESET), "UTF-8") == 0); + if (utf8_mode) { + if (dump_separators) { + sep_col = " │ "; + sep_row = "─┼─"; + } + else + sep_row = "─"; + sep_fill = "─"; + } + } +#endif +#endif + + /* compute the columns widths: using column titles... */ + n_cols = gda_data_model_get_n_columns (model); + n_rows = gda_data_model_get_n_rows (model); + real_n_rows = n_rows; + if (rows) { + /* no error checking is done here, row'existence is checked when used */ + n_rows = nb_rows; + } + cols_size = g_new0 (gint, n_cols + col_offset); + cols_is_num = g_new0 (gboolean, n_cols + col_offset); + + if (dump_rows) { + str = g_strdup_printf ("%d", n_rows); + cols_size [0] = MAX (strlen (str), strlen ("#row")); + cols_is_num [0] = TRUE; + g_free (str); + } + + for (i = 0; i < n_cols; i++) { + GdaColumn *gdacol; + GType coltype; + + if (dump_attributes) { + GdaColumn *col = gda_data_model_describe_column (model, i); + g_print ("Model col %d has type %s\n", i, + gda_g_type_to_string (gda_column_get_g_type (col))); + } + + if (dump_column_titles) { + str = (gchar *) gda_data_model_get_column_title (model, i); + if (str) + cols_size [i + col_offset] = g_utf8_strlen (str, -1); + else + cols_size [i + col_offset] = 6; /* for "" */ + } + + if (! dump_attributes) { + gdacol = gda_data_model_describe_column (model, i); + coltype = gda_column_get_g_type (gdacol); + if ((coltype == G_TYPE_INT64) || + (coltype == G_TYPE_UINT64) || + (coltype == G_TYPE_INT) || + (coltype == GDA_TYPE_NUMERIC) || + (coltype == G_TYPE_FLOAT) || + (coltype == G_TYPE_DOUBLE) || + (coltype == GDA_TYPE_SHORT) || + (coltype == GDA_TYPE_USHORT) || + (coltype == G_TYPE_CHAR) || + (coltype == G_TYPE_UCHAR) || + (coltype == G_TYPE_UINT)) + cols_is_num [i + col_offset] = TRUE; + else + cols_is_num [i + col_offset] = FALSE; + } + else + cols_is_num [i + col_offset] = TRUE; + } + + /* ... and using column data */ + if (gda_data_model_get_access_flags (model) & GDA_DATA_MODEL_ACCESS_RANDOM) + ramodel = g_object_ref (model); + else { + if (! (gda_data_model_get_access_flags (model) & GDA_DATA_MODEL_ACCESS_CURSOR_BACKWARD)) { + g_set_error (error, GDA_DATA_MODEL_ERROR, GDA_DATA_MODEL_ACCESS_ERROR, + "%s", _("Data model does not support backward cursor move")); + allok = FALSE; + goto out; + } + ramodel = gda_data_access_wrapper_new (model); + } + + for (j = 0; j < n_rows; j++) { + if (rows && (rows [j] >= real_n_rows)) + continue; /* ignore that row */ + for (i = 0; i < n_cols; i++) { + if (! dump_attributes) { + if (rows) + value = gda_data_model_get_value_at (ramodel, i, rows[j], NULL); + else + value = gda_data_model_get_value_at (ramodel, i, j, NULL); + if (!value) { + cols_size [i + col_offset] = MAX ((guint)cols_size [i + col_offset], strlen (ERROR_STRING)); + } + else { + gboolean alloc = FALSE; + str = NULL; + if (null_as_empty) { + if (!value || gda_value_is_null (value)) + str = ""; + } + if (!str) { + if (value) { + if (G_VALUE_TYPE (value) == G_TYPE_STRING) + str = (gchar*) g_value_get_string (value); + else { + if (use_data_handlers) { + GdaDataHandler *dh = NULL; + GdaConnection *cnc; + GdaServerProvider *prov; + cnc = g_object_get_data (G_OBJECT (model), "cnc"); + if (!cnc && GDA_IS_DATA_SELECT (model)) + cnc = gda_data_select_get_connection (GDA_DATA_SELECT (model)); + if (cnc) { + prov = gda_connection_get_provider (cnc); + dh = gda_server_provider_get_data_handler_g_type (prov, cnc, + G_VALUE_TYPE (value)); + } + if (!dh) + dh = gda_data_handler_get_default (G_VALUE_TYPE (value)); + else + g_object_ref (dh); + + if (dh) { + str = gda_data_handler_get_str_from_value (dh, value); + g_object_unref (dh); + } + else + str = gda_value_stringify ((GValue*)value); + } + else + str = gda_value_stringify ((GValue*)value); + alloc = TRUE; + } + } + else + str = "NULL"; + } + if (str) { + gint w; + string_get_dimensions (str, &w, NULL); + cols_size [i + col_offset] = MAX (cols_size [i + col_offset], w); + if (alloc) + g_free (str); + } + } + } + else { + GdaValueAttribute attrs; + gint w; + if (rows) + attrs = gda_data_model_get_attributes_at (ramodel, i, rows[j]); + else + attrs = gda_data_model_get_attributes_at (ramodel, i, j); + str = g_strdup_printf ("%u", attrs); + string_get_dimensions (str, &w, NULL); + cols_size [i + col_offset] = MAX (cols_size [i + col_offset], w); + g_free (str); + } + } + } + + string = g_string_new (""); + + /* actual dumping of the contents: data model's title */ + if (dump_title) { + const gchar *title; + title = g_object_get_data (G_OBJECT (model), "name"); + if (title) { + gsize total_width = n_cols -1; + + for (i = 0; i < n_cols; i++) + total_width += cols_size [i]; + if (total_width > strlen (title)) + i = (total_width - strlen (title))/2.; + else + i = 0; + for (; i > 0; i--) + g_string_append_c (string, ' '); + g_string_append (string, title); + g_string_append_c (string, '\n'); + } + } + + /* ...column titles...*/ + if (dump_rows) + g_string_append_printf (string, "%*s", cols_size [0], "#row"); + + if (dump_column_titles) { + for (i = 0; i < n_cols; i++) { + gint j, max; + str = (gchar *) gda_data_model_get_column_title (model, i); + if (dump_rows || (i != 0)) + g_string_append_printf (string, "%s", sep_col); + + if (str) { + g_string_append_printf (string, "%s", str); + max = cols_size [i + col_offset] - g_utf8_strlen (str, -1); + } + else { + g_string_append (string, ""); + max = cols_size [i + col_offset] - 6; + } + for (j = 0; j < max; j++) + g_string_append_c (string, ' '); + } + g_string_append_c (string, '\n'); + + /* ... separation line ... */ + if (dump_sep_line) { + for (i = 0; i < n_cols + col_offset; i++) { + if (i != 0) + g_string_append_printf (string, "%s", sep_row); + for (j = 0; j < cols_size [i]; j++) + g_string_append (string, sep_fill); + } + g_string_append_c (string, '\n'); + } + } + + /* ... and data */ + for (j = 0; j < n_rows; j++) { + if (rows && (rows [j] >= real_n_rows)) + continue; /* ignore that row */ + + /* determine height for each column in that row */ + gint *cols_height = g_new (gint, n_cols + col_offset); + gchar ***cols_str = g_new (gchar **, n_cols + col_offset); + gint k, kmax = 1; + + if (dump_rows) { + str = g_strdup_printf ("%d", j); + cols_str [0] = g_strsplit (str, "\n", -1); + cols_height [0] = 1; + kmax = 1; + } + + for (i = 0; i < n_cols; i++) { + gboolean alloc = FALSE; + str = NULL; + if (!dump_attributes) { + if (rows) + value = gda_data_model_get_value_at (ramodel, i, rows[j], NULL); + else + value = gda_data_model_get_value_at (ramodel, i, j, NULL); + if (!value) + str = ERROR_STRING; + else { + if (null_as_empty) { + if (!value || gda_value_is_null (value)) + str = ""; + } + if (!str) { + if (value) { + if (G_VALUE_TYPE (value) == G_TYPE_STRING) + str = (gchar*) g_value_get_string (value); + else { + if (use_data_handlers) { + GdaDataHandler *dh = NULL; + GdaConnection *cnc; + GdaServerProvider *prov; + cnc = g_object_get_data (G_OBJECT (model), "cnc"); + if (!cnc && GDA_IS_DATA_SELECT (model)) + cnc = gda_data_select_get_connection (GDA_DATA_SELECT (model)); + if (cnc) { + prov = gda_connection_get_provider (cnc); + dh = gda_server_provider_get_data_handler_g_type (prov, cnc, + G_VALUE_TYPE (value)); + } + if (!dh) + dh = gda_data_handler_get_default (G_VALUE_TYPE (value)); + else + g_object_ref (dh); + + if (dh) { + str = gda_data_handler_get_str_from_value (dh, value); + g_object_unref (dh); + } + else + str = gda_value_stringify ((GValue*)value); + } + else + str = gda_value_stringify ((GValue*)value); + alloc = TRUE; + } + } + else + str = "NULL"; + } + } + } + else { + GdaValueAttribute attrs; + if (rows) + attrs = gda_data_model_get_attributes_at (ramodel, i, rows[j]); + else + attrs = gda_data_model_get_attributes_at (ramodel, i, j); + str = g_strdup_printf ("%u", attrs); + alloc = TRUE; + } + if (str) { + cols_str [i + col_offset] = g_strsplit (str, "\n", -1); + if (alloc) + g_free (str); + cols_height [i + col_offset] = g_strv_length (cols_str [i + col_offset]); + kmax = MAX (kmax, cols_height [i + col_offset]); + } + else { + cols_str [i + col_offset] = NULL; + cols_height [i + col_offset] = 0; + } + } + + for (k = 0; k < kmax; k++) { + for (i = 0; i < n_cols + col_offset; i++) { + gboolean align_center = FALSE; + if (i != 0) { +#ifdef MULTI_LINE_NO_SEPARATOR + if (k != 0) + g_string_append_printf (string, "%s", sep_col_e); + else +#endif + g_string_append_printf (string, "%s", sep_col); + } + if (k < cols_height [i]) + str = (cols_str[i])[k]; + else { +#ifdef MULTI_LINE_NO_SEPARATOR + str = ""; +#else + if (cols_height [i] == 0) + str = ""; + else + str = "."; + align_center = TRUE; +#endif + } + + if (cols_is_num [i]) + g_string_append_printf (string, "%*s", cols_size [i], str); + else { + gint j, max; + if (str) + max = cols_size [i] - g_utf8_strlen (str, -1); + else + max = cols_size [i]; + + if (!align_center) { + g_string_append_printf (string, "%s", str); + for (j = 0; j < max; j++) + g_string_append_c (string, ' '); + } + else { + for (j = 0; j < max / 2; j++) + g_string_append_c (string, ' '); + g_string_append_printf (string, "%s", str); + for ( j+= g_utf8_strlen (str, -1); j < cols_size [i]; j++) + g_string_append_c (string, ' '); + } + /* + gint j, max; + if (str) { + g_string_append_printf (string, "%s", str); + max = cols_size [i] - g_utf8_strlen (str, -1); + } + else + max = cols_size [i]; + for (j = 0; j < max; j++) + g_string_append_c (string, ' '); + */ + } + } + g_string_append_c (string, '\n'); + } + + g_free (cols_height); + for (i = 0; i < n_cols; i++) + g_strfreev (cols_str [i]); + g_free (cols_str); + } + + /* status message */ + g_string_append_c (string, '('); + if (n_rows > 0) + g_string_append_printf (string, ngettext("%d row", "%d rows", n_rows), n_rows); + else + g_string_append_printf (string, _("0 row")); + + GError **exceptions; + exceptions = gda_data_model_get_exceptions (model); + if (exceptions) { + gint i; + for (i = 0; exceptions[i]; i++) { + GError *ex; + ex = exceptions[i]; + if (ex && ex->message) { + g_string_append (string, ", "); + g_string_append (string, ex->message); + } + } + } + g_string_append (string, ")\n"); + + + out: + if (ramodel) + g_object_unref (ramodel); + g_free (cols_size); + g_free (cols_is_num); + + if (allok) { + str = string->str; + g_string_free (string, FALSE); + if (max_width > 0) { + /* truncate all lines */ + GString *ns; + ns = g_string_sized_new (strlen (str)); + + gchar *ptr, *sptr; + gint len; /* number of characters since start of line */ + for (ptr = str, sptr = ptr, len=0; + *ptr; + ptr = g_utf8_next_char (ptr), len++) { + if (*ptr == '\n') { + *ptr = 0; + len = 0; + g_string_append (ns, sptr); + g_string_append_c (ns, '\n'); + *ptr = '\n'; + sptr = ptr+1; + } + else if (len >= max_width) { + gchar c; + c = *ptr; + *ptr = 0; + len = 0; + g_string_append (ns, sptr); + g_string_append_c (ns, '\n'); + *ptr = c; + for (; *ptr && (*ptr != '\n'); + ptr = g_utf8_next_char (ptr)); + if (!*ptr) + break; + sptr = ptr+1; + } + } + g_free (str); + str = ns->str; + g_string_free (ns, FALSE); + } + } + else { + str = NULL; + g_string_free (string, TRUE); + } + return str; +} diff --git a/.flatpak-builder/cache/objects/6d/9f7576942ccca9361d3de6202d0c5774876af389ec0f3091da4439cd077c27.dirtree b/.flatpak-builder/cache/objects/6d/9f7576942ccca9361d3de6202d0c5774876af389ec0f3091da4439cd077c27.dirtree new file mode 100644 index 0000000..ec666e7 Binary files /dev/null and b/.flatpak-builder/cache/objects/6d/9f7576942ccca9361d3de6202d0c5774876af389ec0f3091da4439cd077c27.dirtree differ diff --git a/.flatpak-builder/cache/objects/6d/f837f51ca36451f58dc306d86f9a145a4d6bb43ef9f79908f61faea658d7fd.dirtree b/.flatpak-builder/cache/objects/6d/f837f51ca36451f58dc306d86f9a145a4d6bb43ef9f79908f61faea658d7fd.dirtree new file mode 100644 index 0000000..5ff2160 Binary files /dev/null and b/.flatpak-builder/cache/objects/6d/f837f51ca36451f58dc306d86f9a145a4d6bb43ef9f79908f61faea658d7fd.dirtree differ diff --git a/.flatpak-builder/cache/objects/6e/340b9cffb37a989ca544e6bb780a2c78901d3fb33738768511a30617afa01d.dirtree b/.flatpak-builder/cache/objects/6e/340b9cffb37a989ca544e6bb780a2c78901d3fb33738768511a30617afa01d.dirtree new file mode 100644 index 0000000..f76dd23 Binary files /dev/null and b/.flatpak-builder/cache/objects/6e/340b9cffb37a989ca544e6bb780a2c78901d3fb33738768511a30617afa01d.dirtree differ diff --git a/.flatpak-builder/cache/objects/6e/50afac970b1f3600cf564e4c71c3bfc9404979c04c87fd53685ed261068b2c.dirtree b/.flatpak-builder/cache/objects/6e/50afac970b1f3600cf564e4c71c3bfc9404979c04c87fd53685ed261068b2c.dirtree new file mode 100644 index 0000000..c450f12 Binary files /dev/null and b/.flatpak-builder/cache/objects/6e/50afac970b1f3600cf564e4c71c3bfc9404979c04c87fd53685ed261068b2c.dirtree differ diff --git a/.flatpak-builder/cache/objects/6e/612ab26df117fb466e45b6638b3b55f1e5b35bbeeca6960fb8ffbb88ae15d4.dirtree b/.flatpak-builder/cache/objects/6e/612ab26df117fb466e45b6638b3b55f1e5b35bbeeca6960fb8ffbb88ae15d4.dirtree new file mode 100644 index 0000000..ed478ae Binary files /dev/null and b/.flatpak-builder/cache/objects/6e/612ab26df117fb466e45b6638b3b55f1e5b35bbeeca6960fb8ffbb88ae15d4.dirtree differ diff --git a/.flatpak-builder/cache/objects/6e/a160beab989d124b3d618eac5b3a6227a96d1357a192d36cc23c66df0844ff.file b/.flatpak-builder/cache/objects/6e/a160beab989d124b3d618eac5b3a6227a96d1357a192d36cc23c66df0844ff.file new file mode 100644 index 0000000..4e7ae76 --- /dev/null +++ b/.flatpak-builder/cache/objects/6e/a160beab989d124b3d618eac5b3a6227a96d1357a192d36cc23c66df0844ff.file @@ -0,0 +1,161 @@ +/* + * gda-ddl-operation.c + * + * Copyright (C) 2020 Pavlo Solntsev + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#define G_LOG_DOMAIN "GDA-ddl-modifiable" +#include "gda-ddl-modifiable.h" +#include + +G_DEFINE_QUARK (gda_ddl_modifiable_error, gda_ddl_modifiable_error) + +/** + * SECTION:gda-ddl-modifiable + * @title: GdaDdlModifiable + * @short_description: Interface to peform DDL operation + * @see_also: #GdaDbTable, #GdaDbView, #GdaDbIndex, #GdaDbColumn + * @stability: Stable + * @include: libgda/libgda.h + * + * This interface should be used to perform some DDL opration using objects that implement it. + * Calling gda_ddl_modifiable_create() on #GdaDbColumn operation will execute ADD COLUMN + * operation. The user should pass a pointer to instance of #GdaDbTable as user_data where + * column will be added (cretaed). + * + * If the underlying object does not implement the operation, then %FALSE is returned and the error + * is set. + */ + +G_DEFINE_INTERFACE (GdaDdlModifiable, gda_ddl_modifiable, G_TYPE_OBJECT) + + +static void +gda_ddl_modifiable_default_init (GdaDdlModifiableInterface *iface) +{ + /* add properties and signals to the interface here */ +} + +/** + * gda_ddl_modifiable_create: + * @self: Instance of #GdaDdlModifiable + * @cnc: Opened connection + * @user_data: Additional information provided by the user + * @error: Error holder + * + * This method executes CREATE operation. That is, #GdaDbTable, #GdaDbIndex, and #GdaDbView + * implement corresponding CREATE TABLE | CREATE INDEX | CREATE VIEW operations. #GdaDbColumn + * implements ADD COLUMN operation as part of ALTER TABLE operation. + * + * Stability: Stable + * Since: 6.0 + */ +gboolean +gda_ddl_modifiable_create (GdaDdlModifiable *self, + GdaConnection *cnc, + gpointer user_data, + GError **error) +{ + GdaDdlModifiableInterface *iface = NULL; + + g_return_val_if_fail (GDA_IS_DDL_MODIFIABLE (self), FALSE); + g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE); + + if (!gda_connection_is_opened (cnc)) + { + g_set_error (error, GDA_DDL_MODIFIABLE_ERROR, + GDA_DDL_MODIFIABLE_CONNECTION_NOT_OPENED, + _("Connection is not opened")); + return FALSE; + } + + iface = GDA_DDL_MODIFIABLE_GET_IFACE (self); + return iface->create (self, cnc, user_data, error); +} + +/** + * gda_ddl_modifiable_drop: + * @self: Instance of #GdaDdlModifiable + * @cnc: Opened connection + * @user_data: Additional information provided by the user + * @error: Error holder + * + * Execute corresponding DROP operation + * + * Stability: Stable + * Since: 6.0 + */ +gboolean +gda_ddl_modifiable_drop (GdaDdlModifiable *self, + GdaConnection *cnc, + gpointer user_data, + GError **error) +{ + GdaDdlModifiableInterface *iface = NULL; + + g_return_val_if_fail (GDA_IS_DDL_MODIFIABLE (self), FALSE); + g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE); + + if (!gda_connection_is_opened (cnc)) + { + g_set_error (error, GDA_DDL_MODIFIABLE_ERROR, + GDA_DDL_MODIFIABLE_CONNECTION_NOT_OPENED, + _("Connection is not opened")); + return FALSE; + } + + iface = GDA_DDL_MODIFIABLE_GET_IFACE (self); + return iface->drop (self, cnc, user_data, error); +} + +/** + * gda_ddl_modifiable_rename: + * @self: Instance of #GdaDdlModifiable + * @cnc: Opened connection + * @user_data: Additional information provided by the user + * @error: Error holder + * + * Execute corresponding RENAME operation. A lot of RENAME operations are not implemented by + * SQLite3 provider. In this case, the SQL object must be deleted and a new one should be created. + * + * Stability: Stable + * Since: 6.0 + */ +gboolean +gda_ddl_modifiable_rename (GdaDdlModifiable *self, + GdaConnection *cnc, + gpointer user_data, + GError **error) +{ + GdaDdlModifiableInterface *iface = NULL; + + g_return_val_if_fail (GDA_IS_DDL_MODIFIABLE (self), FALSE); + g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE); + + if (!gda_connection_is_opened (cnc)) + { + g_set_error (error, GDA_DDL_MODIFIABLE_ERROR, + GDA_DDL_MODIFIABLE_CONNECTION_NOT_OPENED, + _("Connection is not opened")); + return FALSE; + } + + iface = GDA_DDL_MODIFIABLE_GET_IFACE (self); + return iface->rename (self, cnc, user_data, error); +} + diff --git a/.flatpak-builder/cache/objects/6e/a9150d2485798d5c5aa7fdecbcbfcf448e964ce1a9804ea862a000cd3073ed.dirtree b/.flatpak-builder/cache/objects/6e/a9150d2485798d5c5aa7fdecbcbfcf448e964ce1a9804ea862a000cd3073ed.dirtree new file mode 100644 index 0000000..728c54f Binary files /dev/null and b/.flatpak-builder/cache/objects/6e/a9150d2485798d5c5aa7fdecbcbfcf448e964ce1a9804ea862a000cd3073ed.dirtree differ diff --git a/.flatpak-builder/cache/objects/6e/c640778be058ecd2f3f0309161de32d9892612a7c8f804e5365f36ecb3d348.dirtree b/.flatpak-builder/cache/objects/6e/c640778be058ecd2f3f0309161de32d9892612a7c8f804e5365f36ecb3d348.dirtree new file mode 100644 index 0000000..0e53ed4 Binary files /dev/null and b/.flatpak-builder/cache/objects/6e/c640778be058ecd2f3f0309161de32d9892612a7c8f804e5365f36ecb3d348.dirtree differ diff --git a/.flatpak-builder/cache/objects/6e/ea14a9e54087b447b4274095c854d87b027b31c46c74f54a46a2d3caba6db3.dirtree b/.flatpak-builder/cache/objects/6e/ea14a9e54087b447b4274095c854d87b027b31c46c74f54a46a2d3caba6db3.dirtree new file mode 100644 index 0000000..357a73e Binary files /dev/null and b/.flatpak-builder/cache/objects/6e/ea14a9e54087b447b4274095c854d87b027b31c46c74f54a46a2d3caba6db3.dirtree differ diff --git a/.flatpak-builder/cache/objects/6f/3886bd83dcf8b332d8e688409f72c3e442db51c9739ed46a24fb2deb2d05d4.dirtree b/.flatpak-builder/cache/objects/6f/3886bd83dcf8b332d8e688409f72c3e442db51c9739ed46a24fb2deb2d05d4.dirtree new file mode 100644 index 0000000..7d1303d Binary files /dev/null and b/.flatpak-builder/cache/objects/6f/3886bd83dcf8b332d8e688409f72c3e442db51c9739ed46a24fb2deb2d05d4.dirtree differ diff --git a/.flatpak-builder/cache/objects/6f/75eedfaaf0089a9c65fe717477cc8f931e9a632e7cb24ef6b85b29309f7141.file b/.flatpak-builder/cache/objects/6f/75eedfaaf0089a9c65fe717477cc8f931e9a632e7cb24ef6b85b29309f7141.file new file mode 100644 index 0000000..3205e2e --- /dev/null +++ b/.flatpak-builder/cache/objects/6f/75eedfaaf0089a9c65fe717477cc8f931e9a632e7cb24ef6b85b29309f7141.file @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2009 - 2011 Vivien Malerba + * Copyright (C) 2018 Daniel Espinosa + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GDA_TREE_MGR_SELECT_H__ +#define __GDA_TREE_MGR_SELECT_H__ + +#include +#include "gda-tree-manager.h" + +G_BEGIN_DECLS + +#define GDA_TYPE_TREE_MGR_SELECT (gda_tree_mgr_select_get_type()) +G_DECLARE_DERIVABLE_TYPE(GdaTreeMgrSelect, gda_tree_mgr_select, GDA, TREE_MGR_SELECT, GdaTreeManager) +struct _GdaTreeMgrSelectClass { + GdaTreeManagerClass object_class; +}; + +/** + * SECTION:gda-tree-mgr-select + * @short_description: A tree manager which creates a node for each row resulting from the execution of a SELECT statement + * @title: GdaTreeMgrSelect + * @stability: Stable + * @see_also: + * + * The #GdaTreeMgrSelect is a #GdaTreeManager object which executes a SELECT statement and + * creates a node for each row in the result. + * + * The #GdaConnection and SELECT #GdaStatement to be used need to be specified when the object is created. + * If the SELECT statement to be used needs some parameters, then it is possible to give values to some of them + * when constructing the object, but not necessary. + * + * If the SELECT statement needs some parameters which have not been provided during the construction, then + * these parameters will be fetched from the #GdaTreeNode below which the nodes will be placed (using + * gda_tree_node_fetch_attribute()). + * + * For each node created, an attribute is set for each column in the SELECT statement: the attribute name is + * the column name and the attribute value is the value if that column. + */ + +GdaTreeManager* gda_tree_mgr_select_new (GdaConnection *cnc, GdaStatement *stmt, GdaSet *params); + +G_END_DECLS + +#endif diff --git a/.flatpak-builder/cache/objects/6f/7bee31f1c1d7e0918be69838372ef2a6251e3c7e637eb34c98f2380f35cd7f.dirtree b/.flatpak-builder/cache/objects/6f/7bee31f1c1d7e0918be69838372ef2a6251e3c7e637eb34c98f2380f35cd7f.dirtree new file mode 100644 index 0000000..63ffd2a Binary files /dev/null and b/.flatpak-builder/cache/objects/6f/7bee31f1c1d7e0918be69838372ef2a6251e3c7e637eb34c98f2380f35cd7f.dirtree differ diff --git a/.flatpak-builder/cache/objects/6f/899b710e9dd018daea9012f1453f3ffb35d47753ba050bdaa8358086459b9f.file b/.flatpak-builder/cache/objects/6f/899b710e9dd018daea9012f1453f3ffb35d47753ba050bdaa8358086459b9f.file new file mode 100644 index 0000000..669dfe4 --- /dev/null +++ b/.flatpak-builder/cache/objects/6f/899b710e9dd018daea9012f1453f3ffb35d47753ba050bdaa8358086459b9f.file @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2008 - 2012 Vivien Malerba + * Copyright (C) 2011 Murray Cumming + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GDA_XA_TRANSACTION_H__ +#define __GDA_XA_TRANSACTION_H__ + +#include +#include +#include + +G_BEGIN_DECLS + +#define GDA_TYPE_XA_TRANSACTION (gda_xa_transaction_get_type()) + +G_DECLARE_DERIVABLE_TYPE(GdaXaTransaction, gda_xa_transaction, GDA, XA_TRANSACTION, GObject) +/* error reporting */ +extern GQuark gda_xa_transaction_error_quark (void); +#define GDA_XA_TRANSACTION_ERROR gda_xa_transaction_error_quark () + +typedef enum +{ + GDA_XA_TRANSACTION_ALREADY_REGISTERED_ERROR, + GDA_XA_TRANSACTION_DTP_NOT_SUPPORTED_ERROR, + GDA_XA_TRANSACTION_CONNECTION_BRANCH_LENGTH_ERROR +} GdaXaTransactionError; + +struct _GdaXaTransactionClass { + GObjectClass parent_class; + + /*< private >*/ + /* Padding for future expansion */ + void (*_gda_reserved1) (void); + void (*_gda_reserved2) (void); + void (*_gda_reserved3) (void); + void (*_gda_reserved4) (void); +}; + + +/** + * GdaXaTransactionId: + * @format: any number + * @gtrid_length: number between 1 and 64 + * @bqual_length: number between 1 and 64 + * @data: + */ +struct _GdaXaTransactionId { + guint32 format; + gushort gtrid_length; + gushort bqual_length; + char data [128]; +}; + +typedef struct _GdaXaTransactionId GdaXaTransactionId; + +/** + * SECTION:gda-xa-transaction + * @short_description: Distributed transaction manager + * @title: GdaXaTransaction + * @stability: Stable + * @see_also: + * + * The #GdaXaTransaction object acts as a distributed transaction manager: to make sure local transactions on several + * connections (to possibly different databases and database types) either all succeed or all fail. For more information, + * see the X/Open CAE document Distributed Transaction Processing: The XA Specification. + * This document is published by The Open Group and available at + * http://www.opengroup.org/public/pubs/catalog/c193.htm. + * + * The two phases commit protocol is implemented during the execution of a distributed transaction: modifications + * made on any connection are first prepared (which means that they are store in the database), and + * if that phase succeeded for all the involved connections, then the commit phase is executed + * (where all the data previously stored during the prepare phase are actually committed). + * That second phase may actually fail, but the distributed transaction will still be considered as successfull + * as the data stored during the prepare phase can be committed afterwards. + * + * A distributed transaction involves the following steps: + * + * Create a #GdaXaTransaction object + * Register the connections which will be part of the distributed transaction with that object + * using gda_xa_transaction_register_connection() + * Beging the distributed transaction using gda_xa_transaction_begin() + * Work individually on each connection as normally (make modifications) + * Commit the distributed transaction using gda_xa_transaction_commit() + * Discard the #GdaXaTransaction object using g_object_unref() + * + */ + +GdaXaTransaction *gda_xa_transaction_new (guint32 format, const gchar *global_transaction_id); + +gboolean gda_xa_transaction_register_connection (GdaXaTransaction *xa_trans, GdaConnection *cnc, + const gchar *branch, GError **error); +void gda_xa_transaction_unregister_connection (GdaXaTransaction *xa_trans, GdaConnection *cnc); + +gboolean gda_xa_transaction_begin (GdaXaTransaction *xa_trans, GError **error); +gboolean gda_xa_transaction_commit (GdaXaTransaction *xa_trans, GSList **cnc_to_recover, GError **error); +gboolean gda_xa_transaction_rollback (GdaXaTransaction *xa_trans, GError **error); + +gboolean gda_xa_transaction_commit_recovered (GdaXaTransaction *xa_trans, GSList **cnc_to_recover, + GError **error); + +/* utility functions */ +GType gda_xa_transaction_id_get_type (void) G_GNUC_CONST; +gchar *gda_xa_transaction_id_to_string (const GdaXaTransactionId *xid); +GdaXaTransactionId *gda_xa_transaction_string_to_id (const gchar *str); + +G_END_DECLS + +#endif diff --git a/.flatpak-builder/cache/objects/6f/8c81d836bf4c5911a16383efc75b3c5a9c291c98a11061e51fa2a91de24f09.commit b/.flatpak-builder/cache/objects/6f/8c81d836bf4c5911a16383efc75b3c5a9c291c98a11061e51fa2a91de24f09.commit new file mode 100644 index 0000000..210856d Binary files /dev/null and b/.flatpak-builder/cache/objects/6f/8c81d836bf4c5911a16383efc75b3c5a9c291c98a11061e51fa2a91de24f09.commit differ diff --git a/.flatpak-builder/cache/objects/6f/9ac307b2fda55f666059f5e53029ab99283bc7aeb9a1b37022a669dd6cb623.dirtree b/.flatpak-builder/cache/objects/6f/9ac307b2fda55f666059f5e53029ab99283bc7aeb9a1b37022a669dd6cb623.dirtree new file mode 100644 index 0000000..b14bc5e Binary files /dev/null and b/.flatpak-builder/cache/objects/6f/9ac307b2fda55f666059f5e53029ab99283bc7aeb9a1b37022a669dd6cb623.dirtree differ diff --git a/.flatpak-builder/cache/objects/6f/9e5ec6a9a10b0af0472eeedff8646c7a2342b43d9caa1e3c682bad3a7b520b.file b/.flatpak-builder/cache/objects/6f/9e5ec6a9a10b0af0472eeedff8646c7a2342b43d9caa1e3c682bad3a7b520b.file new file mode 100644 index 0000000..0875c52 --- /dev/null +++ b/.flatpak-builder/cache/objects/6f/9e5ec6a9a10b0af0472eeedff8646c7a2342b43d9caa1e3c682bad3a7b520b.file @@ -0,0 +1,80 @@ +/*-*- Mode: C; c-basic-offset: 8 -*-*/ + +/*** + This file is part of libcanberra. + + Copyright 2008 Lennart Poettering + + libcanberra is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation, either version 2.1 of the + License, or (at your option) any later version. + + libcanberra is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with libcanberra. If not, see + . +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include "mutex.h" +#include "malloc.h" + +struct ca_mutex { + pthread_mutex_t mutex; +}; + +ca_mutex* ca_mutex_new(void) { + ca_mutex *m; + + if (!(m = ca_new(ca_mutex, 1))) + return NULL; + + if (pthread_mutex_init(&m->mutex, NULL) < 0) { + ca_free(m); + return NULL; + } + + return m; +} + +void ca_mutex_free(ca_mutex *m) { + ca_assert(m); + + ca_assert_se(pthread_mutex_destroy(&m->mutex) == 0); + ca_free(m); +} + +void ca_mutex_lock(ca_mutex *m) { + ca_assert(m); + + ca_assert_se(pthread_mutex_lock(&m->mutex) == 0); +} + +ca_bool_t ca_mutex_try_lock(ca_mutex *m) { + int r; + ca_assert(m); + + if ((r = pthread_mutex_trylock(&m->mutex)) != 0) { + ca_assert(r == EBUSY); + return FALSE; + } + + return TRUE; +} + +void ca_mutex_unlock(ca_mutex *m) { + ca_assert(m); + + ca_assert_se(pthread_mutex_unlock(&m->mutex) == 0); +} diff --git a/.flatpak-builder/cache/objects/6f/bea016dbf54539520f4686077360cc52d9ca754ba985f401f4d82837889bec.file b/.flatpak-builder/cache/objects/6f/bea016dbf54539520f4686077360cc52d9ca754ba985f401f4d82837889bec.file new file mode 100644 index 0000000..3ac04f4 --- /dev/null +++ b/.flatpak-builder/cache/objects/6f/bea016dbf54539520f4686077360cc52d9ca754ba985f401f4d82837889bec.file @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2007 - 2014 Vivien Malerba + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GDA_VIRTUAL_PROVIDER_H__ +#define __GDA_VIRTUAL_PROVIDER_H__ + +/* NOTICE: SQLite must be compiled without the SQLITE_OMIT_VIRTUALTABLE flag */ + +#include + +G_BEGIN_DECLS + +#define GDA_TYPE_VIRTUAL_PROVIDER (gda_virtual_provider_get_type()) + +G_DECLARE_DERIVABLE_TYPE (GdaVirtualProvider, gda_virtual_provider, GDA, VIRTUAL_PROVIDER, GdaSqliteProvider) + +struct _GdaVirtualProviderClass { + GdaSqliteProviderClass parent_class; + + /*< private >*/ + void (*_gda_reserved1) (void); + void (*_gda_reserved2) (void); +}; + +/** + * SECTION:gda-virtual-provider + * @short_description: Base class for all virtual provider objects + * @title: GdaVirtualProvider + * @stability: Stable + * @see_also: #GdaVirtualConnection + * + * This is a base virtual class for all virtual providers implementations. + */ + +G_END_DECLS + +#endif diff --git a/.flatpak-builder/cache/objects/6f/e666cb1764ece15dd7d9e782deeff720f94efb4560a647fd7cd46e7761e24c.dirtree b/.flatpak-builder/cache/objects/6f/e666cb1764ece15dd7d9e782deeff720f94efb4560a647fd7cd46e7761e24c.dirtree new file mode 100644 index 0000000..47f800e Binary files /dev/null and b/.flatpak-builder/cache/objects/6f/e666cb1764ece15dd7d9e782deeff720f94efb4560a647fd7cd46e7761e24c.dirtree differ diff --git a/.flatpak-builder/cache/objects/70/9c87ef03b4ca056a3876cddd1d59a33f86f351389999dba74309a15d39adb5.dirtree b/.flatpak-builder/cache/objects/70/9c87ef03b4ca056a3876cddd1d59a33f86f351389999dba74309a15d39adb5.dirtree new file mode 100644 index 0000000..a2a8a56 Binary files /dev/null and b/.flatpak-builder/cache/objects/70/9c87ef03b4ca056a3876cddd1d59a33f86f351389999dba74309a15d39adb5.dirtree differ diff --git a/.flatpak-builder/cache/objects/70/9cb1e45d18c92c086f9c08c70fee0e6668b71ea9311e857ac3bc94df8898a5.file b/.flatpak-builder/cache/objects/70/9cb1e45d18c92c086f9c08c70fee0e6668b71ea9311e857ac3bc94df8898a5.file new file mode 100644 index 0000000..a19fa34 --- /dev/null +++ b/.flatpak-builder/cache/objects/70/9cb1e45d18c92c086f9c08c70fee0e6668b71ea9311e857ac3bc94df8898a5.file @@ -0,0 +1,45 @@ +/*-*- Mode: C; c-basic-offset: 8 -*-*/ + +#ifndef foocanberrareadwavhfoo +#define foocanberrareadwavhfoo + +/*** + This file is part of libcanberra. + + Copyright 2008 Lennart Poettering + + libcanberra is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation, either version 2.1 of the + License, or (at your option) any later version. + + libcanberra is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with libcanberra. If not, see + . +***/ + +#include + +#include "read-sound-file.h" + +typedef struct ca_wav ca_wav; + +int ca_wav_open(ca_wav **v, FILE *f); +void ca_wav_close(ca_wav *f); + +unsigned ca_wav_get_nchannels(ca_wav *f); +unsigned ca_wav_get_rate(ca_wav *f); +ca_sample_type_t ca_wav_get_sample_type(ca_wav *f); +const ca_channel_position_t* ca_wav_get_channel_map(ca_wav *f); + +int ca_wav_read_u8(ca_wav *f, uint8_t *d, size_t *n); +int ca_wav_read_s16le(ca_wav *f, int16_t *d, size_t *n); + +off_t ca_wav_get_size(ca_wav *f); + +#endif diff --git a/.flatpak-builder/cache/objects/70/f2933d97526153db867f8d6855391373f74fcf5c8a5b71326974a4b553a296.file b/.flatpak-builder/cache/objects/70/f2933d97526153db867f8d6855391373f74fcf5c8a5b71326974a4b553a296.file new file mode 100644 index 0000000..2d8aab2 Binary files /dev/null and b/.flatpak-builder/cache/objects/70/f2933d97526153db867f8d6855391373f74fcf5c8a5b71326974a4b553a296.file differ diff --git a/.flatpak-builder/cache/objects/71/028d90a718987a99add584dec5f16ec47fabba264990c31faccd5eab17d5e8.file b/.flatpak-builder/cache/objects/71/028d90a718987a99add584dec5f16ec47fabba264990c31faccd5eab17d5e8.file new file mode 100644 index 0000000..4b99026 --- /dev/null +++ b/.flatpak-builder/cache/objects/71/028d90a718987a99add584dec5f16ec47fabba264990c31faccd5eab17d5e8.file @@ -0,0 +1,122 @@ +/* + * Copyright (C) 2014 Murray Cumming + * Copyright (C) 2014 - 2015 Vivien Malerba + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GDA_WORKER_H__ +#define __GDA_WORKER_H__ + +#include +#include + +G_BEGIN_DECLS + +typedef struct _GdaWorker GdaWorker; + +/** + * SECTION:gda-worker + * @short_description: Execute functions in a sub thread + * @title: GdaWorker + * @stability: Stable + * @see_also: + * + * The purpose of the #GdaWorker object is to execute "jobs" (functions with arguments) within a worker thread, using + * gda_worker_submit_job(). + * + * Any code executing in any thread context can submit jobs to @worker and is guaranted not to be blocked (except if using + * gda_worker_wait_job() or if the + * jobs are submitted within the worker thread itself). Once jobs have been submitted, it's up to the caller to regularly + * check if a job has completed using gda_worker_fetch_job_result(). If you don't want to have to check regularly (which is + * like some polling operation), then you can use gda_worker_set_callback() which adds a callback when any job has completed. + * + * gda_worker_wait_job() allows you to execute a job in the worker thread while blocking the calling thread. + * + * Before fetching a jobs's result, it is also possible to request the cancellation of the job using gda_worker_cancel_job(), or + * completely discard the job using gda_worker_forget_job(). + * + * Jobs can also be submitted using gda_worker_do_job(), which internally runs a #GMainLoop and allows you to execute a job + * while at the same time processing events for the specified #GMainContext. + * + * The #GdaWorker implements its own locking mechanism and can safely be used from multiple + * threads at once without needing further locking. + */ + +/* error reporting */ +extern GQuark gda_worker_error_quark (void); +#define GDA_WORKER_ERROR gda_worker_error_quark () + +typedef enum { + GDA_WORKER_INTER_THREAD_ERROR, + + GDA_WORKER_JOB_NOT_FOUND_ERROR, + GDA_WORKER_JOB_QUEUED_ERROR, + GDA_WORKER_JOB_BEING_PROCESSED_ERROR, + GDA_WORKER_JOB_PROCESSED_ERROR, + GDA_WORKER_JOB_CANCELLED_ERROR, + GDA_WORKER_THREAD_KILLED +} GdaWorkerError; + +#define GDA_TYPE_WORKER gda_worker_get_type() +GType gda_worker_get_type(void) G_GNUC_CONST; +GdaWorker *gda_worker_new (void); +GdaWorker *gda_worker_new_unique (GdaWorker **location, gboolean allow_destroy); +GdaWorker *gda_worker_ref (GdaWorker *worker); +void gda_worker_unref (GdaWorker *worker); + +/** + * GdaWorkerFunc: + * @user_data: pointer to the data (which is the argument passed to gda_worker_submit_job()) + * @error: a place to store errors + * @Returns: a pointer to some data which will be returned by gda_worker_fetch_job_result() + * + * Specifies the type of function to be passed to gda_worker_submit_job(), gda_worker_do_job() and gda_worker_wait_job(). + */ +typedef gpointer (*GdaWorkerFunc) (gpointer user_data, GError **error); +guint gda_worker_submit_job (GdaWorker *worker, GMainContext *callback_context, + GdaWorkerFunc func, gpointer data, GDestroyNotify data_destroy_func, + GDestroyNotify result_destroy_func, GError **error); + +gboolean gda_worker_fetch_job_result (GdaWorker *worker, guint job_id, gpointer *out_result, GError **error); +gboolean gda_worker_cancel_job (GdaWorker *worker, guint job_id, GError **error); +void gda_worker_forget_job (GdaWorker *worker, guint job_id); + +gboolean gda_worker_do_job (GdaWorker *worker, GMainContext *context, gint timeout_ms, + gpointer *out_result, guint *out_job_id, + GdaWorkerFunc func, gpointer data, GDestroyNotify data_destroy_func, + GDestroyNotify result_destroy_func, + GError **error); +gpointer gda_worker_wait_job (GdaWorker *worker, + GdaWorkerFunc func, gpointer data, GDestroyNotify data_destroy_func, + GError **error); + + +typedef void (*GdaWorkerCallback) (GdaWorker *worker, guint job_id, gpointer result_data, GError *error, gpointer user_data); +gboolean gda_worker_set_callback (GdaWorker *worker, GMainContext *context, GdaWorkerCallback callback, + gpointer user_data, GError **error); + +gboolean gda_worker_thread_is_worker (GdaWorker *worker); +GThread *gda_worker_get_worker_thread (GdaWorker *worker); + +/* + * Private + */ +void _gda_worker_bg_unref (GdaWorker *worker); + +G_END_DECLS + +#endif diff --git a/.flatpak-builder/cache/objects/71/86c38efd2fae62947e806607eaf1e7306dae3ed07a38f98ca0c36d8aaf4c54.file b/.flatpak-builder/cache/objects/71/86c38efd2fae62947e806607eaf1e7306dae3ed07a38f98ca0c36d8aaf4c54.file new file mode 100644 index 0000000..fc6eeee --- /dev/null +++ b/.flatpak-builder/cache/objects/71/86c38efd2fae62947e806607eaf1e7306dae3ed07a38f98ca0c36d8aaf4c54.file @@ -0,0 +1,171 @@ +# completions.py +# +# Copyright 2021 James Westman +# +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation; either version 3 of the +# License, or (at your option) any later version. +# +# This file is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program. If not, see . +# +# SPDX-License-Identifier: LGPL-3.0-or-later + +import typing as T + +from . import gir, language +from .language.types import ClassName +from .ast_utils import AstNode +from .completions_utils import * +from .lsp_utils import Completion, CompletionItemKind +from .parser import SKIP_TOKENS +from .tokenizer import TokenType, Token + +Pattern = T.List[T.Tuple[TokenType, T.Optional[str]]] + + +def _complete( + ast_node: AstNode, tokens: T.List[Token], idx: int, token_idx: int +) -> T.Iterator[Completion]: + for child in ast_node.children: + if child.group.start <= idx and ( + idx < child.group.end or (idx == child.group.end and child.incomplete) + ): + yield from _complete(child, tokens, idx, token_idx) + return + + prev_tokens: T.List[Token] = [] + + # collect the 5 previous non-skipped tokens + while len(prev_tokens) < 5 and token_idx >= 0: + token = tokens[token_idx] + if token.type not in SKIP_TOKENS: + prev_tokens.insert(0, token) + token_idx -= 1 + + for completer in ast_node.completers: + yield from completer(prev_tokens, ast_node) + + +def complete( + ast_node: AstNode, tokens: T.List[Token], idx: int +) -> T.Iterator[Completion]: + token_idx = 0 + # find the current token + for i, token in enumerate(tokens): + if token.start < idx <= token.end: + token_idx = i + + # if the current token is an identifier or whitespace, move to the token before it + while tokens[token_idx].type in [TokenType.IDENT, TokenType.WHITESPACE]: + idx = tokens[token_idx].start + token_idx -= 1 + + yield from _complete(ast_node, tokens, idx, token_idx) + + +@completer([language.GtkDirective]) +def using_gtk(ast_node, match_variables): + yield Completion("using Gtk 4.0;", CompletionItemKind.Keyword) + + +@completer( + applies_in=[language.UI, language.ObjectContent, language.Template], + matches=new_statement_patterns, +) +def namespace(ast_node, match_variables): + yield Completion("Gtk", CompletionItemKind.Module, text="Gtk.") + for ns in ast_node.root.children[language.Import]: + if ns.gir_namespace is not None: + yield Completion( + ns.gir_namespace.name, + CompletionItemKind.Module, + text=ns.gir_namespace.name + ".", + ) + + +@completer( + applies_in=[language.UI, language.ObjectContent, language.Template], + matches=[ + [(TokenType.IDENT, None), (TokenType.OP, "."), (TokenType.IDENT, None)], + [(TokenType.IDENT, None), (TokenType.OP, ".")], + ], +) +def object_completer(ast_node, match_variables): + ns = ast_node.root.gir.namespaces.get(match_variables[0]) + if ns is not None: + for c in ns.classes.values(): + yield Completion(c.name, CompletionItemKind.Class, docs=c.doc) + + +@completer( + applies_in=[language.UI, language.ObjectContent, language.Template], + matches=new_statement_patterns, +) +def gtk_object_completer(ast_node, match_variables): + ns = ast_node.root.gir.namespaces.get("Gtk") + if ns is not None: + for c in ns.classes.values(): + yield Completion(c.name, CompletionItemKind.Class, docs=c.doc) + + +@completer( + applies_in=[language.ObjectContent], + matches=new_statement_patterns, +) +def property_completer(ast_node, match_variables): + if ast_node.gir_class and not isinstance(ast_node.gir_class, gir.ExternType): + for prop in ast_node.gir_class.properties: + yield Completion(prop, CompletionItemKind.Property, snippet=f"{prop}: $0;") + + +@completer( + applies_in=[language.Property, language.BaseAttribute], + matches=[[(TokenType.IDENT, None), (TokenType.OP, ":")]], +) +def prop_value_completer(ast_node, match_variables): + if isinstance(ast_node.value_type, gir.Enumeration): + for name, member in ast_node.value_type.members.items(): + yield Completion(name, CompletionItemKind.EnumMember, docs=member.doc) + + elif isinstance(ast_node.value_type, gir.BoolType): + yield Completion("true", CompletionItemKind.Constant) + yield Completion("false", CompletionItemKind.Constant) + + +@completer( + applies_in=[language.ObjectContent], + matches=new_statement_patterns, +) +def signal_completer(ast_node, match_variables): + if ast_node.gir_class and not isinstance(ast_node.gir_class, gir.ExternType): + for signal in ast_node.gir_class.signals: + if not isinstance(ast_node.parent, language.Object): + name = "on" + else: + name = "on_" + ( + ast_node.parent.children[ClassName][0].tokens["id"] + or ast_node.parent.children[ClassName][0] + .tokens["class_name"] + .lower() + ) + yield Completion( + signal, + CompletionItemKind.Property, + snippet=f"{signal} => ${{1:{name}_{signal.replace('-', '_')}}}()$0;", + ) + + +@completer(applies_in=[language.UI], matches=new_statement_patterns) +def template_completer(ast_node, match_variables): + yield Completion( + "template", + CompletionItemKind.Snippet, + snippet="template ${1:ClassName} : ${2:ParentClass} {\n $0\n}", + ) diff --git a/.flatpak-builder/cache/objects/71/f2be5f454078d3849007a631c2006d12351814ce42045c090ec70c633b27b9.file b/.flatpak-builder/cache/objects/71/f2be5f454078d3849007a631c2006d12351814ce42045c090ec70c633b27b9.file new file mode 100644 index 0000000..fad0b5f --- /dev/null +++ b/.flatpak-builder/cache/objects/71/f2be5f454078d3849007a631c2006d12351814ce42045c090ec70c633b27b9.file @@ -0,0 +1,1406 @@ +/* + * Copyright (C) 2007 - 2014 Vivien Malerba + * Copyright (C) 2008 - 2011 Murray Cumming + * Copyright (C) 2009 Bas Driessen + * Copyright (C) 2010 David King + * Copyright (C) 2010 Jonh Wendell + * Copyright (C) 2013, 2018-2019 Daniel Espinosa + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +#define G_LOG_DOMAIN "GDA-data-model-dir" + +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_GIO +#include +#endif + +#include +#include +#include +#include + +#ifndef G_OS_WIN32 +#include +#else +#include +#endif + +#define __GDA_INTERNAL__ +#include "dir-blob-op.h" + + +/* GdaDataModel interface */ +static void gda_data_model_dir_data_model_init (GdaDataModelInterface *iface); +static gint gda_data_model_dir_get_n_rows (GdaDataModel *model); +static gint gda_data_model_dir_get_n_columns (GdaDataModel *model); +static GdaColumn *gda_data_model_dir_describe_column (GdaDataModel *model, gint col); +static GdaDataModelAccessFlags gda_data_model_dir_get_access_flags(GdaDataModel *model); +static const GValue *gda_data_model_dir_get_value_at (GdaDataModel *model, gint col, gint row, GError **error); +static GdaValueAttribute gda_data_model_dir_get_attributes_at (GdaDataModel *model, gint col, gint row); + +static gboolean gda_data_model_dir_set_value_at (GdaDataModel *model, gint col, gint row, const GValue *value, GError **error); +static gboolean gda_data_model_dir_set_values (GdaDataModel *model, gint row, GList *values, GError **error); +static gint gda_data_model_dir_append_values (GdaDataModel *model, const GList *values, GError **error); +static gboolean gda_data_model_dir_remove_row (GdaDataModel *model, gint row, GError **error); + + +typedef struct { + gchar *basedir; + GSList *errors; /* list of errors as GError structures */ + GSList *columns; /* list of GdaColumn objects */ + + GPtrArray *rows; /* array of FileRow pointers */ + gint upd_row; /* internal usage when updating contents */ + + GValue *tmp_value; /* GValue returned by gda_data_model_get_value_at() */ +} GdaDataModelDirPrivate; + +G_DEFINE_TYPE_WITH_CODE (GdaDataModelDir, gda_data_model_dir, G_TYPE_OBJECT, + G_ADD_PRIVATE (GdaDataModelDir) + G_IMPLEMENT_INTERFACE (GDA_TYPE_DATA_MODEL, gda_data_model_dir_data_model_init)) + +/* Row implementation details */ +typedef struct { + gchar *reldir; + gchar *raw_filename_value; /* UTF-8 on Windows, FS encoding otherwise */ + GValue *filename_value; /* in UTF-8 */ + GValue *size_value; + GValue *mime_value; + GValue *md5sum_value; + GValue *data_value; +} FileRow; + +#define FILE_ROW(x) ((FileRow*)(x)) +static FileRow *file_row_new (void); +static void file_row_clean (FileRow *row); +static void file_row_free (FileRow *row); + +static gboolean update_file_size (FileRow *row, const gchar *complete_filename); +static gboolean update_file_md5sum (FileRow *row, const gchar *complete_filename); +static gboolean update_file_mime (FileRow *row, const gchar *complete_filename); + +static gboolean dir_equal (const gchar *path1, const gchar *path2); +static gchar * compute_dirname (GdaDataModelDir *model, FileRow *row); +static gchar * compute_filename (GdaDataModelDir *model, FileRow *row); + +/* properties */ +enum + { + PROP_0, + PROP_BASEDIR + }; + +/* columns */ +enum + { + COL_DIRNAME, + COL_FILENAME, + COL_SIZE, + COL_MIME, + COL_MD5SUM, + COL_DATA, + + COL_LAST + }; + +static void gda_data_model_dir_dispose (GObject *object); + +static void gda_data_model_dir_set_property (GObject *object, + guint param_id, + const GValue *value, + GParamSpec *pspec); +static void gda_data_model_dir_get_property (GObject *object, + guint param_id, + GValue *value, + GParamSpec *pspec); + +static void add_error (GdaDataModelDir *model, const gchar *err); +static void update_data_model (GdaDataModelDir *model); + +#define CLASS(model) (GDA_DATA_MODEL_DIR_CLASS (G_OBJECT_GET_CLASS (model))) + +/* + * Object init and dispose + */ +static void +gda_data_model_dir_data_model_init (GdaDataModelInterface *iface) +{ + iface->get_n_rows = gda_data_model_dir_get_n_rows; + iface->get_n_columns = gda_data_model_dir_get_n_columns; + iface->describe_column = gda_data_model_dir_describe_column; + iface->get_access_flags = gda_data_model_dir_get_access_flags; + iface->get_value_at = gda_data_model_dir_get_value_at; + iface->get_attributes_at = gda_data_model_dir_get_attributes_at; + + iface->create_iter = NULL; + + iface->set_value_at = gda_data_model_dir_set_value_at; + iface->set_values = gda_data_model_dir_set_values; + iface->append_values = gda_data_model_dir_append_values; + iface->append_row = NULL; + iface->remove_row = gda_data_model_dir_remove_row; + iface->find_row = NULL; + + iface->freeze = NULL; + iface->thaw = NULL; + iface->get_notify = NULL; + iface->send_hint = NULL; +} + +static void +gda_data_model_dir_init (GdaDataModelDir *model) +{ + g_return_if_fail (GDA_IS_DATA_MODEL_DIR (model)); + + GdaDataModelDirPrivate *priv = gda_data_model_dir_get_instance_private (model); + priv->basedir = NULL; + priv->columns = NULL; + priv->rows = g_ptr_array_new (); /* array of FileRow pointers */ + priv->tmp_value = NULL; +} + +static void +gda_data_model_dir_class_init (GdaDataModelDirClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + /* properties */ + object_class->set_property = gda_data_model_dir_set_property; + object_class->get_property = gda_data_model_dir_get_property; + g_object_class_install_property (object_class, PROP_BASEDIR, + g_param_spec_string ("basedir", NULL, "Base directory", NULL, + G_PARAM_READABLE | G_PARAM_WRITABLE | + G_PARAM_CONSTRUCT_ONLY)); + + /* virtual functions */ + object_class->dispose = gda_data_model_dir_dispose; +} + +static void +file_row_foreach_func (FileRow *row, G_GNUC_UNUSED gpointer data) +{ + file_row_free (row); +} + +static void +gda_data_model_dir_dispose (GObject * object) +{ + GdaDataModelDir *model = (GdaDataModelDir *) object; + + g_return_if_fail (GDA_IS_DATA_MODEL_DIR (model)); + GdaDataModelDirPrivate *priv = gda_data_model_dir_get_instance_private (model); + + if (priv->tmp_value) { + gda_value_free (priv->tmp_value); + priv->tmp_value = NULL; + } + + if (priv->basedir) { + g_free (priv->basedir); + priv->basedir = NULL; + } + + if (priv->errors) { + g_slist_free_full (priv->errors, (GDestroyNotify) g_error_free); + } + + if (priv->columns) { + g_slist_free_full (priv->columns, (GDestroyNotify) g_object_unref); + priv->columns = NULL; + } + + g_ptr_array_foreach (priv->rows, (GFunc) file_row_foreach_func, NULL); + g_ptr_array_free (priv->rows, TRUE); + + G_OBJECT_CLASS (gda_data_model_dir_parent_class)->dispose (object); +} + +static void +add_error (GdaDataModelDir *model, const gchar *err) +{ + GdaDataModelDirPrivate *priv = gda_data_model_dir_get_instance_private (model); + GError *error = NULL; + + g_set_error (&error, GDA_DATA_MODEL_ERROR, GDA_DATA_MODEL_ACCESS_ERROR, + "%s", err); + priv->errors = g_slist_append (priv->errors, error); +} + +static void +gda_data_model_dir_set_property (GObject *object, + guint param_id, + const GValue *value, + GParamSpec *pspec) +{ + GdaDataModelDir *model; + const gchar *string; + + model = GDA_DATA_MODEL_DIR (object); + GdaDataModelDirPrivate *priv = gda_data_model_dir_get_instance_private (model); + switch (param_id) { + case PROP_BASEDIR: + if (priv->basedir) { + g_free (priv->basedir); + priv->basedir = NULL; + } + string = g_value_get_string (value); + if (string) + priv->basedir = g_strdup (string); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + break; + } + + if (priv->basedir) { + /* create columns */ + priv->columns = NULL; + GdaColumn *column; + + /* COL_DIRNAME */ + column = gda_column_new (); + priv->columns = g_slist_append (priv->columns , column); + gda_column_set_name (column, "dir_name"); + gda_column_set_description (column, "dir_name"); + gda_column_set_g_type (column, G_TYPE_STRING); + + /* COL_FILENAME */ + column = gda_column_new (); + priv->columns = g_slist_append (priv->columns , column); + gda_column_set_name (column, "file_name"); + gda_column_set_description (column, "file_name"); + gda_column_set_g_type (column, G_TYPE_STRING); + + /* COL_SIZE */ + column = gda_column_new (); + priv->columns = g_slist_append (priv->columns , column); + gda_column_set_name (column, "size"); + gda_column_set_description (column, "size"); + gda_column_set_g_type (column, G_TYPE_UINT); + + /* COL_MIME */ + column = gda_column_new (); + priv->columns = g_slist_append (priv->columns , column); + gda_column_set_name (column, "mime_type"); + gda_column_set_description (column, "mime_type"); + gda_column_set_g_type (column, G_TYPE_STRING); + + /* COL_MD5SUM */ + column = gda_column_new (); + priv->columns = g_slist_append (priv->columns , column); + gda_column_set_name (column, "md5sum"); + gda_column_set_description (column, "md5sum"); + gda_column_set_g_type (column, G_TYPE_STRING); + + /* COL_DATA */ + column = gda_column_new (); + priv->columns = g_slist_append (priv->columns , column); + gda_column_set_name (column, "data"); + gda_column_set_description (column, "data"); + gda_column_set_g_type (column, GDA_TYPE_BLOB); + + /* number of rows */ + update_data_model (model); + } +} + +static void +update_data_model_real (GdaDataModelDir *model, const gchar *rel_path) +{ + GDir *dir; + GError *error = NULL; + const gchar *raw_filename; + gchar *complete_dir; + GdaDataModelDirPrivate *priv = gda_data_model_dir_get_instance_private (model); + + complete_dir = g_build_path (G_DIR_SEPARATOR_S, priv->basedir, rel_path, NULL); + dir = g_dir_open (complete_dir, 0, &error); + if (!dir) { + add_error (model, error && error->message ? error->message : _("No detail")); + g_error_free (error); + g_free (complete_dir); + return; + } + + raw_filename = g_dir_read_name (dir); + while (raw_filename) { + gchar *complete_filename; + complete_filename = g_build_filename (complete_dir, raw_filename, NULL); + + if (g_file_test (complete_filename, G_FILE_TEST_IS_DIR)) { + /* the . and .. directories are omitted by g_dir_read_name() */ + /* ignore hidden directories */ + if (*raw_filename != '.') { + gchar *path; + + path = g_build_path (G_DIR_SEPARATOR_S, rel_path, raw_filename, NULL); + update_data_model_real (model, path); + g_free (path); + } + } + else { + /* ignore hidden files */ + if (*raw_filename != '.') { + gchar *utf8_filename; +#ifndef G_OS_WIN32 + /* FIXME: correctly do the conversion */ + utf8_filename = g_strdup (raw_filename); +#else + utf8_filename = g_strdup (raw_filename); +#endif + FileRow *row; + priv->upd_row ++; + + if (priv->upd_row < (int)priv->rows->len) { + row = g_ptr_array_index (priv->rows, priv->upd_row); + file_row_clean (row); + } + else + row = file_row_new (); + row->reldir = g_strdup (rel_path); +#ifndef G_OS_WIN32 + row->raw_filename_value = g_strdup (raw_filename); +#else + row->raw_filename_value = NULL; /* no need top copy on Windows */ +#endif + g_value_take_string (row->filename_value = gda_value_new (G_TYPE_STRING), + utf8_filename); + + /* file size */ + update_file_size (row, complete_filename); + + /* other attributes, computed only when needed */ + row->mime_value = NULL; + row->md5sum_value = NULL; + row->data_value = NULL; + + /* add row */ + if (priv->upd_row < (int)priv->rows->len) + gda_data_model_row_updated ((GdaDataModel *) model, priv->upd_row); + else { + g_ptr_array_add (priv->rows, row); + gda_data_model_row_inserted ((GdaDataModel *) model, + priv->rows->len - 1); + } + } + } + g_free (complete_filename); + + raw_filename = g_dir_read_name (dir); + } + + g_free (complete_dir); + g_dir_close (dir); +} + +/* Returns: TRUE if FileRow value has been changed */ +static gboolean +update_file_size (FileRow *row, const gchar *complete_filename) +{ + struct stat filestat; + gboolean changed = TRUE; + + if (! g_stat (complete_filename, &filestat)) { + if (row->size_value && (G_VALUE_TYPE (row->size_value) == G_TYPE_UINT) + && (g_value_get_uint (row->size_value) == (guint)filestat.st_size)) + changed = FALSE; + else { + if (row->size_value) + gda_value_free (row->size_value); + g_value_set_uint (row->size_value = gda_value_new (G_TYPE_UINT), filestat.st_size); + } + } + else { + if (row->size_value && gda_value_is_null (row->size_value)) + changed = FALSE; + else { + if (row->size_value) + gda_value_free (row->size_value); + row->size_value = gda_value_new_null (); + } + } + + return changed; +} + +/* Returns: TRUE if FileRow value has been changed */ +static gboolean +update_file_md5sum (FileRow *row, const gchar *complete_filename) +{ + gboolean changed = TRUE; + GValue *value = NULL; + int fd; + gpointer map; + guint length; + + /* file mapping in mem */ + length = g_value_get_uint (row->size_value); + if (length == 0) + goto md5end; + fd = open (complete_filename, O_RDONLY); /* Flawfinder: ignore */ + if (fd < 0) + goto md5end; +#ifndef G_OS_WIN32 + map = mmap (NULL, length, PROT_READ, MAP_PRIVATE, fd, 0); + if (map == MAP_FAILED) { + close (fd); + goto md5end; + } +#else + HANDLE view = CreateFileMapping ((HANDLE) fd, + NULL, PAGE_READONLY|SEC_COMMIT, 0,0 , NULL); + if (!view) { + close (fd); + goto md5end; + } + map = MapViewOfFile (view, FILE_MAP_READ, 0, 0, length); + if (!map) { + close (fd); + goto md5end; + } +#endif /* !G_OS_WIN32 */ + + gchar *md5str; + md5str = g_compute_checksum_for_data (G_CHECKSUM_MD5, map, length); + value = gda_value_new (G_TYPE_STRING); + g_value_take_string (value, md5str); + +#ifndef G_OS_WIN32 + munmap (map, length); +#else + UnmapViewOfFile (map); +#endif /* !G_OS_WIN32 */ + close (fd); + + md5end: + if (value) { + if (row->md5sum_value && (G_VALUE_TYPE (row->md5sum_value) == G_TYPE_STRING) + && !gda_value_compare (row->md5sum_value, value)) + changed = FALSE; + else { + if (row->md5sum_value) + gda_value_free (row->md5sum_value); + row->md5sum_value = value; + } + } + else { + if (row->md5sum_value && gda_value_is_null (row->md5sum_value)) + changed = FALSE; + else { + if (row->md5sum_value) + gda_value_free (row->md5sum_value); + row->md5sum_value = gda_value_new_null (); + } + } + + return changed; +} + +/* Returns: TRUE if FileRow value has been changed */ +static gboolean +update_file_mime (FileRow *row, const gchar *complete_filename) +{ + gboolean changed = TRUE; + GValue *value = NULL; +#ifdef HAVE_GIO + GFile *file; + GFileInfo *info; + file = g_file_new_for_path (complete_filename); + info = g_file_query_info (file, + G_FILE_ATTRIBUTE_STANDARD_FAST_CONTENT_TYPE, + G_FILE_QUERY_INFO_NONE, NULL, NULL); + if (info) { + value = gda_value_new (G_TYPE_STRING); + g_value_set_string (value, g_file_info_get_content_type (info)); + g_object_unref (info); + } + else + value = gda_value_new_null (); + g_object_unref (file); +#else + value = gda_value_new_null (); +#endif + + if (value) { + if (row->mime_value && (G_VALUE_TYPE (row->mime_value) == G_TYPE_STRING) + && !gda_value_compare (row->mime_value, value)) + changed = FALSE; + else { + if (row->mime_value) + gda_value_free (row->mime_value); + row->mime_value = value; + } + } + else { + if (row->mime_value && gda_value_is_null (row->mime_value)) + changed = FALSE; + else { + if (row->mime_value) + gda_value_free (row->mime_value); + row->mime_value = gda_value_new_null (); + } + } + + return changed; +} + +static void +update_data_model (GdaDataModelDir *model) +{ + GdaDataModelDirPrivate *priv = gda_data_model_dir_get_instance_private (model); + priv->upd_row = -1; + update_data_model_real (model, ""); + + /* clean extra rows */ + gsize i; + for (i = priv->upd_row + 1; i < priv->rows->len; i++) { + FileRow *row = g_ptr_array_index (priv->rows, priv->rows->len - 1); + file_row_free (row); + g_ptr_array_remove_index (priv->rows, priv->rows->len - 1); + gda_data_model_row_removed ((GdaDataModel *) model, priv->rows->len - 1); + } +} + +static void +gda_data_model_dir_get_property (GObject *object, + guint param_id, + GValue *value, + GParamSpec *pspec) +{ + GdaDataModelDir *model; + + model = GDA_DATA_MODEL_DIR (object); + GdaDataModelDirPrivate *priv = gda_data_model_dir_get_instance_private (model); + if (priv) { + switch (param_id) { + case PROP_BASEDIR: + g_value_set_string (value, priv->basedir); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + break; + } + } +} + +/** + * gda_data_model_dir_new: + * @basedir: a directory + * + * Creates a new #GdaDataModel object to list all the files starting from @basedir + * + * Returns: (transfer full): a new #GdaDataModel + */ +GdaDataModel * +gda_data_model_dir_new (const gchar *basedir) +{ + GdaDataModel *model; + + g_return_val_if_fail (basedir && *basedir, NULL); + + model = (GdaDataModel *) g_object_new (GDA_TYPE_DATA_MODEL_DIR, "basedir", basedir, NULL); + + return model; +} + +/** + * gda_data_model_dir_get_errors: + * @model: a #GdaDataModelDir object + * + * Get the list of errors which have occurred while using @model + * + * Returns: (transfer none) (element-type GLib.Error) : a read-only list of #GError pointers, or %NULL if no error has occurred + */ +const GSList * +gda_data_model_dir_get_errors (GdaDataModelDir *model) +{ + g_return_val_if_fail (GDA_IS_DATA_MODEL_DIR (model), NULL); + GdaDataModelDirPrivate *priv = gda_data_model_dir_get_instance_private (model); + + return priv->errors; +} + +/** + * gda_data_model_dir_clean_errors: + * @model: a #GdaDataModelDir object + * + * Reset the list of errors which have occurred while using @model + */ +void +gda_data_model_dir_clean_errors (GdaDataModelDir *model) +{ + g_return_if_fail (GDA_IS_DATA_MODEL_DIR (model)); + GdaDataModelDirPrivate *priv = gda_data_model_dir_get_instance_private (model); + + if (priv->errors) { + g_slist_free_full (priv->errors, (GDestroyNotify) g_error_free); + priv->errors = NULL; + } +} + +static gint +gda_data_model_dir_get_n_rows (GdaDataModel *model) +{ + GdaDataModelDir *imodel = (GdaDataModelDir *) model; + + g_return_val_if_fail (GDA_IS_DATA_MODEL_DIR (imodel), 0); + GdaDataModelDirPrivate *priv = gda_data_model_dir_get_instance_private (imodel); + + return priv->rows->len; +} + +static gint +gda_data_model_dir_get_n_columns (GdaDataModel *model) +{ + GdaDataModelDir *imodel; + g_return_val_if_fail (GDA_IS_DATA_MODEL_DIR (model), 0); + imodel = GDA_DATA_MODEL_DIR (model); + GdaDataModelDirPrivate *priv = gda_data_model_dir_get_instance_private (imodel); + g_return_val_if_fail (priv, 0); + + return COL_LAST; +} + +static GdaColumn * +gda_data_model_dir_describe_column (GdaDataModel *model, gint col) +{ + GdaDataModelDir *imodel; + g_return_val_if_fail (GDA_IS_DATA_MODEL_DIR (model), NULL); + imodel = GDA_DATA_MODEL_DIR (model); + GdaDataModelDirPrivate *priv = gda_data_model_dir_get_instance_private (imodel); + + return g_slist_nth_data (priv->columns, col); +} + +static GdaDataModelAccessFlags +gda_data_model_dir_get_access_flags (GdaDataModel *model) +{ + return GDA_DATA_MODEL_ACCESS_CURSOR_FORWARD | + GDA_DATA_MODEL_ACCESS_CURSOR_BACKWARD | + GDA_DATA_MODEL_ACCESS_RANDOM | + GDA_DATA_MODEL_ACCESS_WRITE; + +} + +static const GValue * +gda_data_model_dir_get_value_at (GdaDataModel *model, gint col, gint row, GError **error) +{ + GdaDataModelDir *imodel; + GValue *value = NULL; + FileRow *frow; + + g_return_val_if_fail (GDA_IS_DATA_MODEL_DIR (model), NULL); + g_return_val_if_fail (row >= 0, NULL); + imodel = GDA_DATA_MODEL_DIR (model); + GdaDataModelDirPrivate *priv = gda_data_model_dir_get_instance_private (imodel); + + if ((col < 0) || (col > COL_LAST)) { + gchar *tmp; + tmp = g_strdup_printf (_("Column %d out of range (0-%d)"), col, COL_LAST-1); + add_error (imodel, tmp); + g_set_error (error, GDA_DATA_MODEL_ERROR, GDA_DATA_MODEL_COLUMN_OUT_OF_RANGE_ERROR, + "%s", tmp); + g_free (tmp); + return NULL; + } + + if ((guint)row >= priv->rows->len) { + gchar *str; + if (priv->rows->len > 0) + str = g_strdup_printf (_("Row %d out of range (0-%d)"), row, + priv->rows->len - 1); + else + str = g_strdup_printf (_("Row %d not found (empty data model)"), row); + add_error (imodel, str); + g_set_error (error, GDA_DATA_MODEL_ERROR, GDA_DATA_MODEL_ROW_OUT_OF_RANGE_ERROR, + "%s", str); + g_free (str); + return NULL; + } + + frow = g_ptr_array_index (priv->rows, row); + if (frow) { + switch (col) { + case COL_DIRNAME: { + gchar *tmp; + tmp = compute_dirname (imodel, frow); + if (!priv->tmp_value) + priv->tmp_value = gda_value_new (G_TYPE_STRING); + g_value_take_string (priv->tmp_value, tmp); + value = priv->tmp_value; + break; + } + case COL_FILENAME: + value = frow->filename_value; + break; + case COL_SIZE: + value = frow->size_value; + break; + case COL_MIME: + if (! frow->mime_value) { + gchar *filename = compute_filename (imodel, frow); + update_file_mime (frow, filename); + g_free (filename); + } + value = frow->mime_value; + break; + case COL_MD5SUM: + if (! frow->md5sum_value) { + gchar *filename = compute_filename (imodel, frow); + update_file_md5sum (frow, filename); + g_free (filename); + } + value = frow->md5sum_value; + break; + case COL_DATA: + value = frow->data_value; + if (! value) { + value = gda_value_new (GDA_TYPE_BLOB); + GdaBlob *blob; + GdaBlobOp *op; + gchar *filename; + + blob = gda_blob_new (); + + /* file mapping in mem */ + filename = compute_filename (imodel, frow); + op = _gda_dir_blob_op_new (filename); + g_free (filename); + gda_blob_set_op (blob, op); + g_object_unref (op); + + gda_value_take_blob (value, blob); + frow->data_value = value; + } + break; + default: + break; + } + } + else + g_set_error (error, GDA_DATA_MODEL_ERROR, GDA_DATA_MODEL_ROW_NOT_FOUND_ERROR, + "%s", _("Row not found")); + + return value; +} + +static GdaValueAttribute +gda_data_model_dir_get_attributes_at (GdaDataModel *model, gint col, G_GNUC_UNUSED gint row) +{ + GdaDataModelDir *imodel; + GdaValueAttribute flags = 0; + g_return_val_if_fail (GDA_IS_DATA_MODEL_DIR (model), 0); + imodel = GDA_DATA_MODEL_DIR (model); + if ((col < 0) || (col > COL_LAST)) { + gchar *tmp; + tmp = g_strdup_printf (_("Column %d out of range (0-%d)"), col, COL_LAST-1); + add_error (imodel, tmp); + g_free (tmp); + return 0; + } + + switch (col) { + case COL_DIRNAME: + flags = GDA_VALUE_ATTR_CAN_BE_NULL; + break; + case COL_FILENAME: + break; + case COL_SIZE: + case COL_MIME: + case COL_MD5SUM: + flags = GDA_VALUE_ATTR_CAN_BE_NULL | GDA_VALUE_ATTR_NO_MODIF; + break; + case COL_DATA: + flags = GDA_VALUE_ATTR_CAN_BE_NULL; + break; + default: + flags = GDA_VALUE_ATTR_NO_MODIF; + break; + } + + return flags; +} + +static gboolean +gda_data_model_dir_set_value_at (GdaDataModel *model, gint col, gint row, const GValue *value, GError **error) +{ + GList *values = NULL; + gint i; + gboolean retval; + GdaDataModelDir *imodel; + + g_return_val_if_fail (GDA_IS_DATA_MODEL_DIR (model), FALSE); + imodel = GDA_DATA_MODEL_DIR (model); + + if ((col < 0) || (col > COL_LAST)) { + gchar *tmp; + tmp = g_strdup_printf (_("Column %d out of range (0-%d)"), col, COL_LAST-1); + add_error (imodel, tmp); + g_set_error (error, GDA_DATA_MODEL_ERROR, GDA_DATA_MODEL_COLUMN_OUT_OF_RANGE_ERROR, + "%s", tmp); + g_free (tmp); + return FALSE; + } + + /* start padding with default values */ + for (i = 0; i < col; i++) + values = g_list_append (values, NULL); + + values = g_list_append (values, (gpointer) value); + + /* add extra padding */ + for (i++; i < COL_LAST; i++) + values = g_list_append (values, NULL); + + retval = gda_data_model_dir_set_values (model, row, values, error); + g_list_free (values); + + return retval; +} + + +static gboolean +gda_data_model_dir_set_values (GdaDataModel *model, gint row, GList *values, GError **error) +{ + GdaDataModelDir *imodel; + GList *list; + gint col; + FileRow *frow; + gboolean has_changed = FALSE; + + g_return_val_if_fail (GDA_IS_DATA_MODEL_DIR (model), FALSE); + g_return_val_if_fail (row >= 0, FALSE); + imodel = (GdaDataModelDir *) model; + GdaDataModelDirPrivate *priv = gda_data_model_dir_get_instance_private (imodel); + if (!values) + return TRUE; + + if ((guint)row >= priv->rows->len) { + gchar *str; + if (priv->rows->len > 0) + str = g_strdup_printf (_("Row %d out of range (0-%d)"), row, + priv->rows->len - 1); + else + str = g_strdup_printf (_("Row %d not found (empty data model)"), row); + add_error (imodel, str); + g_set_error (error, GDA_DATA_MODEL_ERROR, GDA_DATA_MODEL_ROW_OUT_OF_RANGE_ERROR, + "%s", str); + g_free (str); + return FALSE; + } + + frow = g_ptr_array_index (priv->rows, row); + + for (col = 0, list = values; list; list = list->next, col++) { + GValue *value = (GValue *) list->data; + const GValue *cvalue = gda_data_model_get_value_at (model, col, row, error); + if (!cvalue) + return FALSE; + if (!value || !gda_value_compare (value, cvalue)) + continue; + + switch (col) { + case COL_SIZE: + case COL_MIME: + case COL_MD5SUM: + default: + add_error (imodel, _("Column cannot be modified")); + g_set_error (error, GDA_DATA_MODEL_ERROR, GDA_DATA_MODEL_ACCESS_ERROR, + "%s", _("Column cannot be modified")); + return FALSE; + case COL_DIRNAME: { + /* check that the new dir still starts with the basedir */ + const gchar *new_path; + gchar *old_path; + gint len, base_len; + + new_path = value ? g_value_get_string (value) : ""; + len = strlen (new_path); + base_len = strlen (priv->basedir); + if ((len < base_len) || + (strncmp (new_path, priv->basedir, base_len))) { + add_error (imodel, + _("New path must be a subpath of the base directory")); + g_set_error (error, GDA_DATA_MODEL_ERROR, GDA_DATA_MODEL_ACCESS_ERROR, + "%s", + _("New path must be a subpath of the base directory")); + return FALSE; + } + + old_path = compute_dirname (imodel, frow); + if (dir_equal (new_path, old_path)) { + g_free (old_path); + g_print ("Paths are equal...\n"); + break; + } + + if (!g_mkdir_with_parents (new_path, 0755)) { + gchar *new_filename; + GMappedFile *old_file; + gboolean allok = FALSE; + gchar *filename; + + new_filename = g_build_filename (new_path, + frow->raw_filename_value ? frow->raw_filename_value : + g_value_get_string (frow->filename_value), NULL); + filename = compute_filename (imodel, frow); + old_file = g_mapped_file_new (filename, FALSE, NULL); + if (old_file) { + if (g_file_set_contents (new_filename, g_mapped_file_get_contents (old_file), + g_mapped_file_get_length (old_file), NULL)) { + g_unlink (filename); + allok = TRUE; + + if (frow->data_value) { + GdaBlob *blob; + blob = (GdaBlob *) gda_value_get_blob (frow->data_value); + if (blob && gda_blob_get_op (blob)) + _gda_dir_blob_set_filename (GDA_DIR_BLOB_OP (gda_blob_get_op (blob)), + new_filename); + } + } + g_mapped_file_unref (old_file); + } + if (!allok) { + gchar *str; + str = g_strdup_printf (_("Could not rename file '%s' to '%s'"), + filename, new_filename); + add_error (imodel, str); + g_set_error (error, + GDA_DATA_MODEL_ERROR, GDA_DATA_MODEL_ACCESS_ERROR, + "%s", str); + g_free (str); + g_free (new_filename); + g_free (filename); + g_free (old_path); + return FALSE; + } + else { + /* renaming succeeded => update FileRow */ +#ifndef G_OS_WIN32 + g_rmdir (old_path); +#endif + g_free (frow->reldir); + frow->reldir = g_strdup (new_path + base_len); + } + g_free (filename); + g_free (new_filename); + has_changed = TRUE; + } + else { + gchar *str; + str = g_strdup_printf (_("Could not create directory '%s'"), new_path); + add_error (imodel, str); + g_set_error (error, GDA_DATA_MODEL_ERROR, GDA_DATA_MODEL_ACCESS_ERROR, + "%s", str); + g_free (str); + g_free (old_path); + return FALSE; + } + g_free (old_path); + break; + } + case COL_FILENAME: { + gchar *new_filename; + gchar *filename; + + new_filename = g_build_filename (priv->basedir, + frow->reldir, + g_value_get_string (value), NULL); + filename = compute_filename (imodel, frow); + if (g_rename (filename, new_filename)) { + gchar *str; + str = g_strdup_printf (_("Could not rename file '%s' to '%s'"), filename, new_filename); + add_error (imodel, str); + g_set_error (error, GDA_DATA_MODEL_ERROR, GDA_DATA_MODEL_ACCESS_ERROR, + "%s", str); + g_free (str); + g_free (new_filename); + g_free (filename); + return FALSE; + } + else { + /* renaming succeeded => update FileRow */ + gda_value_free (frow->filename_value); + frow->filename_value = gda_value_copy (value); + if (frow->raw_filename_value) { + g_free (frow->raw_filename_value); + frow->raw_filename_value = g_strdup (g_value_get_string (value)); + } + if (frow->data_value) { + GdaBlob *blob; + blob = (GdaBlob *) gda_value_get_blob (frow->data_value); + if (blob && gda_blob_get_op (blob)) + _gda_dir_blob_set_filename (GDA_DIR_BLOB_OP (gda_blob_get_op (blob)), + new_filename); + } + } + g_free (new_filename); + g_free (filename); + has_changed = TRUE; + break; + } + case COL_DATA: { + GdaBlob *blob = NULL; + if (gda_value_isa (value, GDA_TYPE_BLOB)) { + blob = (GdaBlob *) gda_value_get_blob (value); + } + else if (gda_value_isa (value, GDA_TYPE_BINARY)) { + blob = (GdaBlob *) gda_value_get_binary (value); + } + else if (gda_value_is_null (value)) { + /* create a new empty blob */ + blob = gda_blob_new (); + } + + if (blob) { + GdaBlobOp *op; + gchar *filename; + filename = compute_filename (imodel, frow); + op = _gda_dir_blob_op_new (filename); + if (gda_blob_op_write_all (op, blob) < 0) { + gchar *str; + str = g_strdup_printf (_("Could not overwrite contents of file '%s'"), filename); + add_error (imodel, str); + g_set_error (error, GDA_DATA_MODEL_ERROR, + GDA_DATA_MODEL_ACCESS_ERROR, + "%s", str); + g_free (str); + g_object_unref (op); + g_free (filename); + return FALSE; + } + g_object_unref (op); + if (gda_value_is_null (value)) + g_free (blob); + has_changed = FALSE; + has_changed = update_file_size (frow, filename); + has_changed = update_file_md5sum (frow, filename) || has_changed; + has_changed = update_file_mime (frow, filename) || has_changed; + g_free (filename); + } + else { + add_error (imodel, _("Wrong type of data")); + g_set_error (error, GDA_DATA_MODEL_ERROR, GDA_DATA_MODEL_ACCESS_ERROR, + "%s", _("Wrong type of data")); + return FALSE; + } + break; + } + } + } + + if (has_changed) + /* signal changes to data model */ + gda_data_model_row_updated ((GdaDataModel *) model, row); + + return TRUE; +} + +static gint +gda_data_model_dir_append_values (GdaDataModel *model, const GList *values, GError **error) +{ + GdaDataModelDir *imodel; + const gchar *dirname = NULL, *filename = NULL; + GdaBinary *bin_data = NULL; + + g_return_val_if_fail (GDA_IS_DATA_MODEL_DIR (model), -1); + imodel = (GdaDataModelDir *) model; + GdaDataModelDirPrivate *priv = gda_data_model_dir_get_instance_private (imodel); + + GList *list; + gint col; + + if (!values) + return -1; + for (col = 0, list = (GList *) values; list; list = list->next, col++) { + GValue *value = (GValue *) list->data; + if (!value || gda_value_is_null (value)) + continue; + + switch (col) { + case COL_SIZE: + case COL_MIME: + case COL_MD5SUM: + default: + add_error (imodel, _("Column cannot be set")); + g_set_error (error, GDA_DATA_MODEL_ERROR, GDA_DATA_MODEL_ACCESS_ERROR, + "%s", + _("Column cannot be set")); + return -1; + case COL_DIRNAME: + if (G_VALUE_TYPE (value) == G_TYPE_STRING) { + gint len, base_len; + base_len = strlen (priv->basedir); + dirname = g_value_get_string (value); + len = strlen (dirname); + if ((len < base_len) || + (strncmp (dirname, priv->basedir, base_len))) { + add_error (imodel, _("New path must be a subpath of the base directory")); + g_set_error (error, GDA_DATA_MODEL_ERROR, + GDA_DATA_MODEL_ACCESS_ERROR, + "%s", + _("New path must be a subpath of the base directory")); + return -1; + } + } + break; + case COL_FILENAME: + if (G_VALUE_TYPE (value) == G_TYPE_STRING) + filename = g_value_get_string (value); + break; + case COL_DATA: + if (G_VALUE_TYPE (value) == GDA_TYPE_BLOB) + bin_data = (GdaBinary *) gda_value_get_blob (value); + else if (G_VALUE_TYPE (value) == GDA_TYPE_BINARY) + bin_data = (GdaBinary *) gda_value_get_binary (value); + break; + } + } + + if (dirname && filename && *filename) { + if (!g_mkdir_with_parents (dirname, 0755)) { + gchar *complete_filename; + gboolean bin_to_free = FALSE; + complete_filename = g_build_filename (dirname, filename, NULL); + if (!bin_data) { + bin_data = gda_binary_new (); + bin_to_free = TRUE; + } + if (g_file_set_contents (complete_filename, (gchar *) gda_binary_get_data (bin_data), + gda_binary_get_size (bin_data), NULL)) { + FileRow *row; + + row = file_row_new (); + row->reldir = g_strdup (dirname + strlen (priv->basedir)); +#ifndef G_OS_WIN32 + row->raw_filename_value = g_strdup (filename); +#else + row->raw_filename_value = NULL; /* no need top copy on Windows */ +#endif + g_value_set_string (row->filename_value = gda_value_new (G_TYPE_STRING), + filename); + + /* file size */ + update_file_size (row, complete_filename); + + /* other attributes, computed only when needed */ + row->mime_value = NULL; + row->md5sum_value = NULL; + row->data_value = NULL; + if (bin_to_free) + g_free (bin_data); + g_ptr_array_add (priv->rows, row); + gda_data_model_row_inserted (model, priv->rows->len - 1); + return priv->rows->len - 1; + } + else { +#ifndef G_OS_WIN32 + g_rmdir (dirname); +#endif + gchar *str; + str = g_strdup_printf (_("Cannot set contents of filename '%s'"), complete_filename); + add_error (imodel, str); + g_set_error (error, GDA_DATA_MODEL_ERROR, GDA_DATA_MODEL_ACCESS_ERROR, + "%s", str); + g_free (str); + if (bin_to_free) + g_free (bin_data); + return -1; + } + } + else { + gchar *str; + str = g_strdup_printf (_("Cannot create directory '%s'"), dirname); + add_error (imodel, str); + g_set_error (error, GDA_DATA_MODEL_ERROR, GDA_DATA_MODEL_ACCESS_ERROR, + "%s", str); + g_free (str); + return -1; + } + } + else { + add_error (imodel, _("Cannot add row: filename missing")); + g_set_error (error, GDA_DATA_MODEL_ERROR, GDA_DATA_MODEL_ACCESS_ERROR, + "%s", _("Cannot add row: filename missing")); + return -1; + } + + return -1; +} + +static gboolean +gda_data_model_dir_remove_row (GdaDataModel *model, gint row, GError **error) +{ + GdaDataModelDir *imodel; + gchar *filename; + FileRow *frow; + + g_return_val_if_fail (GDA_IS_DATA_MODEL_DIR (model), FALSE); + g_return_val_if_fail (row >=0, FALSE); + imodel = (GdaDataModelDir *) model; + GdaDataModelDirPrivate *priv = gda_data_model_dir_get_instance_private (imodel); + + if ((guint)row >= priv->rows->len) { + gchar *str; + if (priv->rows->len > 0) + str = g_strdup_printf (_("Row %d out of range (0-%d)"), row, + priv->rows->len - 1); + else + str = g_strdup_printf (_("Row %d not found (empty data model)"), row); + add_error (imodel, str); + g_set_error (error, GDA_DATA_MODEL_ERROR, GDA_DATA_MODEL_ACCESS_ERROR, + "%s", str); + g_free (str); + return FALSE; + } + + frow = g_ptr_array_index (priv->rows, row); + + /* remove filename */ + filename = g_build_filename (priv->basedir, + frow->reldir, + frow->raw_filename_value ? frow->raw_filename_value : + g_value_get_string (frow->filename_value), NULL); + if (g_unlink (filename)) { + gchar *str; + str = g_strdup_printf (_("Cannot remove file '%s'"), filename); + add_error (imodel, str); + g_set_error (error, GDA_DATA_MODEL_ERROR, GDA_DATA_MODEL_ACCESS_ERROR, + "%s", str); + g_free (str); + g_free (filename); + return FALSE; + } + g_free (filename); + + /* remove dir */ +#ifndef G_OS_WIN32 + gchar *path; + + path = g_build_path (G_DIR_SEPARATOR_S, priv->basedir, + frow->reldir, NULL); + g_rmdir (path); + g_free (path); +#endif + + /* remove row from data model */ + file_row_free (frow); + g_ptr_array_remove_index (priv->rows, row); + gda_data_model_row_removed (model, row); + + return TRUE; +} + +/* + * Returns: TRUE if @path1 and @path2 relate in fact to the same dir + */ +static gboolean +dir_equal (const gchar *path1, const gchar *path2) +{ + g_assert (path1); + g_assert (path2); + const gchar *p1, *p2; + for (p1 = path1, p2 = path2; *p1 && *p2; ) { + if (*p1 != *p2) + return FALSE; + if (*p1 == G_DIR_SEPARATOR) { + /* skip all the separators from p1 and p2 */ + while (*p1 == G_DIR_SEPARATOR) + p1++; + while (*p2 == G_DIR_SEPARATOR) + p2++; + } + else { + p1++; + p2++; + } + } + if (*p1) { + while (*p1 == G_DIR_SEPARATOR) + p1++; + } + if (*p2) { + while (*p2 == G_DIR_SEPARATOR) + p2++; + } + if (*p1 || *p2) + return FALSE; + else + return TRUE; +} + +static gchar * +compute_dirname (GdaDataModelDir *model, FileRow *row) +{ + GdaDataModelDirPrivate *priv = gda_data_model_dir_get_instance_private (model); + return g_build_path (G_DIR_SEPARATOR_S, priv->basedir, row->reldir, NULL); +} + +static gchar * +compute_filename (GdaDataModelDir *model, FileRow *row) +{ + GdaDataModelDirPrivate *priv = gda_data_model_dir_get_instance_private (model); + return g_build_filename (priv->basedir, row->reldir, + row->raw_filename_value ? row->raw_filename_value : + g_value_get_string (row->filename_value), NULL); +} + +/* + * FileRow implementation details + */ +static FileRow * +file_row_new (void) +{ + FileRow *fr; + + fr = g_new0 (FileRow, 1); + return fr; +} + +static void +file_row_clean (FileRow *row) +{ + if (!row) + return; + + g_free (row->reldir); + g_free (row->raw_filename_value); + gda_value_free (row->filename_value); + gda_value_free (row->size_value); + if (row->mime_value) + gda_value_free (row->mime_value); + if (row->md5sum_value) + gda_value_free (row->md5sum_value); + if (row->data_value) + gda_value_free (row->data_value); +} + +static void +file_row_free (FileRow *row) +{ + if (!row) + return; + file_row_clean (row); + g_free (row); +} diff --git a/.flatpak-builder/cache/objects/72/b2cdafe9f53f70f8011b2af6a11910f5da50c639ad9660202c9d436e9b0287.file b/.flatpak-builder/cache/objects/72/b2cdafe9f53f70f8011b2af6a11910f5da50c639ad9660202c9d436e9b0287.file new file mode 100644 index 0000000..b0146ff --- /dev/null +++ b/.flatpak-builder/cache/objects/72/b2cdafe9f53f70f8011b2af6a11910f5da50c639ad9660202c9d436e9b0287.file @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2007 - 2014 Vivien Malerba + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GDA_VPROVIDER_DATA_MODEL_H__ +#define __GDA_VPROVIDER_DATA_MODEL_H__ + +#include "gda-virtual-provider.h" + + +/* error reporting */ +extern GQuark gda_vprovider_data_model_error_quark (void); +#define GDA_VPROVIDER_DATA_MODEL_ERROR gda_vprovider_data_model_error_quark () + +typedef enum { + GDA_VPROVIDER_DATA_MODEL_GENERAL_ERROR +} GdaVproviderDataModelError; + + +#define GDA_TYPE_VPROVIDER_DATA_MODEL (gda_vprovider_data_model_get_type()) + +G_BEGIN_DECLS + +G_DECLARE_DERIVABLE_TYPE (GdaVproviderDataModel, gda_vprovider_data_model, GDA, VPROVIDER_DATA_MODEL, GdaVirtualProvider) + +struct _GdaVproviderDataModelClass { + GdaVirtualProviderClass parent_class; + + /*< private >*/ + void (*_gda_reserved1) (void); + void (*_gda_reserved2) (void); + void (*_gda_reserved3) (void); + void (*_gda_reserved4) (void); +}; + +/** + * SECTION:gda-vprovider-data-model + * @short_description: Virtual provider for connections based on a list of GdaDataModel + * @title: GdaVproviderDataModel + * @stability: Stable + * @see_also: See also the introduction to virtual connections + * + * This provider is used to create virtual connections in which each #GdaDataModel data model can be + * added as a table in the connection. Using gda_virtual_connection_open() with this provider as argument + * will generate a #GdaVconnectionDataModel connection object, from which data models can be added. + */ + +GdaVirtualProvider *gda_vprovider_data_model_new (void); + +G_END_DECLS + +#endif diff --git a/.flatpak-builder/cache/objects/72/da859ecebbd8c4c75bf9e549d8aac3d665476bf7ee616d26a6e2ad8a9e63ff.dirtree b/.flatpak-builder/cache/objects/72/da859ecebbd8c4c75bf9e549d8aac3d665476bf7ee616d26a6e2ad8a9e63ff.dirtree new file mode 100644 index 0000000..0301d99 Binary files /dev/null and b/.flatpak-builder/cache/objects/72/da859ecebbd8c4c75bf9e549d8aac3d665476bf7ee616d26a6e2ad8a9e63ff.dirtree differ diff --git a/.flatpak-builder/cache/objects/73/74ccaadacdb8644b117ccba1b58f12aa9ec5722fdcd533e83fe99afa38520f.dirtree b/.flatpak-builder/cache/objects/73/74ccaadacdb8644b117ccba1b58f12aa9ec5722fdcd533e83fe99afa38520f.dirtree new file mode 100644 index 0000000..84ff4d7 Binary files /dev/null and b/.flatpak-builder/cache/objects/73/74ccaadacdb8644b117ccba1b58f12aa9ec5722fdcd533e83fe99afa38520f.dirtree differ diff --git a/.flatpak-builder/cache/objects/73/87b7646b6364a342dac75afc2b65f3562578d64e655391f0cd6a32e93d0077.file b/.flatpak-builder/cache/objects/73/87b7646b6364a342dac75afc2b65f3562578d64e655391f0cd6a32e93d0077.file new file mode 100644 index 0000000..f5904a4 --- /dev/null +++ b/.flatpak-builder/cache/objects/73/87b7646b6364a342dac75afc2b65f3562578d64e655391f0cd6a32e93d0077.file @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2007 - 2011 Vivien Malerba + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GDA_VCONNECTION_HUB_H__ +#define __GDA_VCONNECTION_HUB_H__ + +#include "gda-vconnection-data-model.h" + +#define GDA_TYPE_VCONNECTION_HUB (gda_vconnection_hub_get_type()) + +G_BEGIN_DECLS + +G_DECLARE_DERIVABLE_TYPE (GdaVconnectionHub, gda_vconnection_hub, GDA, VCONNECTION_HUB, GdaVconnectionDataModel) + +struct _GdaVconnectionHubClass { + GdaVconnectionDataModelClass parent_class; + + /*< private >*/ + /* Padding for future expansion */ + void (*_gda_reserved1) (void); + void (*_gda_reserved2) (void); + void (*_gda_reserved3) (void); + void (*_gda_reserved4) (void); +}; + +typedef void (*GdaVConnectionHubFunc) (GdaConnection *cnc, const gchar *ns, gpointer data); + +/** + * SECTION:gda-vconnection-hub + * @short_description: Virtual connection which bind together connections + * @title: GdaVconnectionHub + * @stability: Stable + * @see_also: + * + * The #GdaVconnectionHub object "binds" together the tables from other (opened) connections to make it possible to run + * SQL queries on data from several connections at once. + * + * A #GdaVconnectionHub connection can bind several other connections, each separated in its own namespace (which is specified + * when adding a connection using gda_vconnection_hub_add()). + * + * For example if a connection A has two tables 'table_1' and 'table_2', then after gda_vconnection_hub_add() has been called + * with A as connection argument and with a "c1" namespace, then in the corresponding #GdaVconnectionHub connection, table + * 'table_1' must be referred to as 'c1.table_1' and 'table_2' must be referred to as 'c1.table_2'. + */ + +gboolean gda_vconnection_hub_add (GdaVconnectionHub *hub, + GdaConnection *cnc, const gchar *ns, GError **error); +gboolean gda_vconnection_hub_remove (GdaVconnectionHub *hub, GdaConnection *cnc, GError **error); +GdaConnection *gda_vconnection_hub_get_connection (GdaVconnectionHub *hub, const gchar *ns); +void gda_vconnection_hub_foreach (GdaVconnectionHub *hub, + GdaVConnectionHubFunc func, gpointer data); + +G_END_DECLS + +#endif diff --git a/.flatpak-builder/cache/objects/73/b36a7d748e2d159cea27573ce4948ecc8a21694fe0b3bf80baef2520aeeebe.file b/.flatpak-builder/cache/objects/73/b36a7d748e2d159cea27573ce4948ecc8a21694fe0b3bf80baef2520aeeebe.file new file mode 100644 index 0000000..d1e252f --- /dev/null +++ b/.flatpak-builder/cache/objects/73/b36a7d748e2d159cea27573ce4948ecc8a21694fe0b3bf80baef2520aeeebe.file @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2006 - 2012 Vivien Malerba + * Copyright (C) 2007 Murray Cumming + * Copyright (C) 2019 Daniel Espinosa + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GDA_SQLITE_HANDLER_BIN__ +#define __GDA_SQLITE_HANDLER_BIN__ + +#include +#include + +G_BEGIN_DECLS + +#define GDA_TYPE_SQLITE_HANDLER_BIN (gda_sqlite_handler_bin_get_type()) + +G_DECLARE_DERIVABLE_TYPE (GdaSqliteHandlerBin, gda_sqlite_handler_bin, GDA, SQLITE_HANDLER_BIN, GObject) + +/* struct for the object's class */ +struct _GdaSqliteHandlerBinClass +{ + GObjectClass parent_class; +}; + + +GdaDataHandler *_gda_sqlite_handler_bin_new (void); + +G_END_DECLS + +#endif diff --git a/.flatpak-builder/cache/objects/74/064ef9c31878d02408b8e6a927fab992765ee3c0ddc532e5a0dab372b7942b.file b/.flatpak-builder/cache/objects/74/064ef9c31878d02408b8e6a927fab992765ee3c0ddc532e5a0dab372b7942b.file new file mode 100644 index 0000000..0cb24c5 --- /dev/null +++ b/.flatpak-builder/cache/objects/74/064ef9c31878d02408b8e6a927fab992765ee3c0ddc532e5a0dab372b7942b.file @@ -0,0 +1,100 @@ +/*-*- Mode: C; c-basic-offset: 8 -*-*/ + +/*** + This file is part of libcanberra. + + Copyright 2008 Lennart Poettering + + libcanberra is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation, either version 2.1 of the + License, or (at your option) any later version. + + libcanberra is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with libcanberra. If not, see + . +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#include "malloc.h" +#include "macro.h" + +void* ca_memdup(const void* p, size_t size) { + void *r; + + ca_assert(p); + + if (!(r = ca_malloc(size))) + return NULL; + + memcpy(r, p, size); + return r; +} + +char *ca_sprintf_malloc(const char *format, ...) { + size_t size = 100; + char *c = NULL; + + ca_assert(format); + + for(;;) { + int r; + va_list ap; + + ca_free(c); + + if (!(c = ca_new(char, size))) + return NULL; + + va_start(ap, format); + r = vsnprintf(c, size, format, ap); + va_end(ap); + + c[size-1] = 0; + + if (r > -1 && (size_t) r < size) + return c; + + if (r > -1) /* glibc 2.1 */ + size = (size_t) r+1; + else /* glibc 2.0 */ + size *= 2; + } +} + +#ifndef HAVE_STRNDUP +char *ca_strndup(const char *s, size_t n) { + size_t n_avail; + char *p; + + if (!s) + return NULL; + + if (memchr(s, '\0', n)) { + n_avail = strlen(s); + if (n_avail > n) + n_avail = n; + } else + n_avail = n; + + if (!(p = ca_new(char, n_avail + 1))) + return NULL; + + memcpy(p, s, n_avail); + p[n_avail] = '\0'; + + return p; +} +#endif diff --git a/.flatpak-builder/cache/objects/74/0ca062fc641395e7581ebe14bfbc0cedd2f6aa66dee9377ca73304a4d559ca.file b/.flatpak-builder/cache/objects/74/0ca062fc641395e7581ebe14bfbc0cedd2f6aa66dee9377ca73304a4d559ca.file new file mode 120000 index 0000000..55ef877 --- /dev/null +++ b/.flatpak-builder/cache/objects/74/0ca062fc641395e7581ebe14bfbc0cedd2f6aa66dee9377ca73304a4d559ca.file @@ -0,0 +1 @@ +../../share/runtime/locale/fr/share/fr \ No newline at end of file diff --git a/.flatpak-builder/cache/objects/74/6bbeae14a7b4fa6a3d12488607bd500ba07748d1d8e54ee780e191e2b23136.dirtree b/.flatpak-builder/cache/objects/74/6bbeae14a7b4fa6a3d12488607bd500ba07748d1d8e54ee780e191e2b23136.dirtree new file mode 100644 index 0000000..08408cf Binary files /dev/null and b/.flatpak-builder/cache/objects/74/6bbeae14a7b4fa6a3d12488607bd500ba07748d1d8e54ee780e191e2b23136.dirtree differ diff --git a/.flatpak-builder/cache/objects/75/76003c60432ea5b801876c0fe5103848a6f559414dd16a0ade9d00490daad9.file b/.flatpak-builder/cache/objects/75/76003c60432ea5b801876c0fe5103848a6f559414dd16a0ade9d00490daad9.file new file mode 100644 index 0000000..a14059f Binary files /dev/null and b/.flatpak-builder/cache/objects/75/76003c60432ea5b801876c0fe5103848a6f559414dd16a0ade9d00490daad9.file differ diff --git a/.flatpak-builder/cache/objects/75/d0358b7df2f2eb9aa68259579f4763ec51859b0a7eec4b7c0b7417bfe594b2.dirtree b/.flatpak-builder/cache/objects/75/d0358b7df2f2eb9aa68259579f4763ec51859b0a7eec4b7c0b7417bfe594b2.dirtree new file mode 100644 index 0000000..5913170 Binary files /dev/null and b/.flatpak-builder/cache/objects/75/d0358b7df2f2eb9aa68259579f4763ec51859b0a7eec4b7c0b7417bfe594b2.dirtree differ diff --git a/.flatpak-builder/cache/objects/75/dda9860928eaa2be88f3473f5b1258a245f643cd16a42dae9b1c304250da8a.file b/.flatpak-builder/cache/objects/75/dda9860928eaa2be88f3473f5b1258a245f643cd16a42dae9b1c304250da8a.file new file mode 100644 index 0000000..1a1d987 --- /dev/null +++ b/.flatpak-builder/cache/objects/75/dda9860928eaa2be88f3473f5b1258a245f643cd16a42dae9b1c304250da8a.file @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2008 - 2012 Vivien Malerba + * Copyright (C) 2012 Jasper Lievisse Adriaanse + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GDA_SQLITE_PSTMT_H__ +#define __GDA_SQLITE_PSTMT_H__ + +#include +#include +#ifdef STATIC_SQLITE +#include "sqlite-src/sqlite3.h" +#else +# ifdef HAVE_SQLITE +# include +# else +# include "sqlite-src/sqlite3.h" +#endif +#endif + +G_BEGIN_DECLS + +#define GDA_TYPE_SQLITE_PSTMT (_gda_sqlite_pstmt_get_type()) + +G_DECLARE_DERIVABLE_TYPE (GdaSqlitePStmt, _gda_sqlite_pstmt, GDA, SQLITE_PSTMT, GdaPStmt) + +struct _GdaSqlitePStmtClass { + GdaPStmtClass parent_class; +}; + +GdaSqlitePStmt *_gda_sqlite_pstmt_new (GdaSqliteProvider *provider, + sqlite3_stmt *sqlite_stmt); + +GdaSqliteProvider *_gda_sqlite_pstmt_get_provider (GdaSqlitePStmt *pstmt); +sqlite3_stmt *_gda_sqlite_pstmt_get_stmt (GdaSqlitePStmt *pstmt); +gboolean _gda_sqlite_pstmt_get_is_used (GdaSqlitePStmt *pstmt); +void _gda_sqlite_pstmt_set_is_used (GdaSqlitePStmt *pstmt, + gboolean used); + +GHashTable *_gda_sqlite_pstmt_get_rowid_hash (GdaSqlitePStmt *pstmt); +void _gda_sqlite_pstmt_set_rowid_hash (GdaSqlitePStmt *pstmt, + GHashTable *hash); +gint _gda_sqlite_pstmt_get_nb_rowid_columns (GdaSqlitePStmt *pstmt); +void _gda_sqlite_pstmt_set_nb_rowid_columns (GdaSqlitePStmt *pstmt, + gint nb); + +G_END_DECLS + +#endif diff --git a/.flatpak-builder/cache/objects/75/e95fe45f5d34573044c9d941e4482949107593eb6519f218f4bc6e4970fb9f.file b/.flatpak-builder/cache/objects/75/e95fe45f5d34573044c9d941e4482949107593eb6519f218f4bc6e4970fb9f.file new file mode 100644 index 0000000..4bd3503 Binary files /dev/null and b/.flatpak-builder/cache/objects/75/e95fe45f5d34573044c9d941e4482949107593eb6519f218f4bc6e4970fb9f.file differ diff --git a/.flatpak-builder/cache/objects/76/109aebd12cfe30b2ab08a2f1ac86248d74dcdc73ac1e746c244ee796b68e54.commit b/.flatpak-builder/cache/objects/76/109aebd12cfe30b2ab08a2f1ac86248d74dcdc73ac1e746c244ee796b68e54.commit new file mode 100644 index 0000000..de02154 Binary files /dev/null and b/.flatpak-builder/cache/objects/76/109aebd12cfe30b2ab08a2f1ac86248d74dcdc73ac1e746c244ee796b68e54.commit differ diff --git a/.flatpak-builder/cache/objects/76/170d6c433500ad82d20fb7ee879d19fd241f00c74a368142766d0b15dcbc06.dirtree b/.flatpak-builder/cache/objects/76/170d6c433500ad82d20fb7ee879d19fd241f00c74a368142766d0b15dcbc06.dirtree new file mode 100644 index 0000000..3eee8c8 Binary files /dev/null and b/.flatpak-builder/cache/objects/76/170d6c433500ad82d20fb7ee879d19fd241f00c74a368142766d0b15dcbc06.dirtree differ diff --git a/.flatpak-builder/cache/objects/76/2b18bb764c78fba80881a962891ce670ea148a8fcbce1be2225c625b36c680.file b/.flatpak-builder/cache/objects/76/2b18bb764c78fba80881a962891ce670ea148a8fcbce1be2225c625b36c680.file new file mode 100644 index 0000000..3aa217d --- /dev/null +++ b/.flatpak-builder/cache/objects/76/2b18bb764c78fba80881a962891ce670ea148a8fcbce1be2225c625b36c680.file @@ -0,0 +1,60 @@ +.TH INTLTOOLIZE 8 "2003-08-02" "intltool" + +.SH NAME +intltoolize \- copy intltool related files to software package + +.SH SYNOPSIS +.B intltoolize +[\fIoption\fR]... + + +.SH DESCRIPTION +This prepares a package to use intltool by linking or copying +various files needed by intltool into place for use when building. +Note that you must change your working directory to the top +level directory of the package before running +.B intltoolize. + + +.SH OPTIONS +.IP "\fB\-\-automake\fR" 4 +Work silently and assume that \fIautomake\fR is being used in software. +.IP "\fB\-c\fR" 4 +.PD 0 +.IP "\fB\-\-copy\fR" 4 +.PD +Copy files rather than creating symbolic links to them. +.IP "\fB\-\-debug\fR" 4 +Enable verbose shell tracing. +.IP "\fB\-n\fR" 4 +.PD 0 +.IP "\fB\-\-dry-run\fR" 4 +.PD +Print commands only, instead of executing them. +.IP "\fB\-f\fR" 4 +.PD 0 +.IP "\fB\-\-force\fR" 4 +.PD +Replace existing files if they exist. +.IP "\fB\-\-help\fR" 4 +Show usage and basic help information. +.IP "\fB\-\-version\fR" 4 +Show version information. + + +.SH REPORTING BUGS +Report bugs to http://bugs.launchpad.net/intltool + +.SH AUTHOR +Darin Adler +.br +Kenneth Christiansen +.br +Maciej Stachowiak + + +.SH SEE ALSO +.BR intltool-prepare (8), +.BR intltool-extract (8), +.BR intltool-merge (8), +.BR intltool-update (8) diff --git a/.flatpak-builder/cache/objects/76/5359d4da48ccf73c19559e42cfa1e50e0458bfd0c02ef07ff855811ffeb7ed.commit b/.flatpak-builder/cache/objects/76/5359d4da48ccf73c19559e42cfa1e50e0458bfd0c02ef07ff855811ffeb7ed.commit new file mode 100644 index 0000000..ef26a67 Binary files /dev/null and b/.flatpak-builder/cache/objects/76/5359d4da48ccf73c19559e42cfa1e50e0458bfd0c02ef07ff855811ffeb7ed.commit differ diff --git a/.flatpak-builder/cache/objects/76/8579e407d9510ba005fc2844775d59f419a113e7d532993c51473d161aa306.dirtree b/.flatpak-builder/cache/objects/76/8579e407d9510ba005fc2844775d59f419a113e7d532993c51473d161aa306.dirtree new file mode 100644 index 0000000..f82049a Binary files /dev/null and b/.flatpak-builder/cache/objects/76/8579e407d9510ba005fc2844775d59f419a113e7d532993c51473d161aa306.dirtree differ diff --git a/.flatpak-builder/cache/objects/76/a4a6e159d870b496e2e09c650c05d539a35ed38e3c722160d846bd5d20aed7.file b/.flatpak-builder/cache/objects/76/a4a6e159d870b496e2e09c650c05d539a35ed38e3c722160d846bd5d20aed7.file new file mode 100644 index 0000000..3539163 --- /dev/null +++ b/.flatpak-builder/cache/objects/76/a4a6e159d870b496e2e09c650c05d539a35ed38e3c722160d846bd5d20aed7.file @@ -0,0 +1,354 @@ +/* gda-db-base.c + * + * Copyright (C) 2018 Pavlo Solntsev + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +#define G_LOG_DOMAIN "GDA-db-base" + +#include "gda-db-base.h" +#include + +typedef struct +{ + gchar *m_catalog; + gchar *m_schema; + gchar *m_name; + gchar *m_fullname; +} GdaDbBasePrivate; + +/** + * SECTION:gda-db-base + * @short_description: The basic class for all database objects + * @see_also: #GdaDbTable, #GdaDbView + * @stability: Stable + * @include: libgda/libgda.h + * + * This is a basic class for database objects, e.g. #GdaDbTable and #GdaDbView. It is not common to + * use it directly. + */ + +G_DEFINE_TYPE_WITH_PRIVATE (GdaDbBase, gda_db_base, G_TYPE_OBJECT) + +/** + * gda_db_base_new: + * + * Create a new #GdaDbBase instance + * + * Returns: a new #GdaDbBase instance + */ +GdaDbBase* +gda_db_base_new (void) +{ + return g_object_new (GDA_TYPE_DB_BASE, NULL); +} + +static void +gda_db_base_finalize (GObject *object) +{ + GdaDbBase *self = (GdaDbBase *)object; + GdaDbBasePrivate *priv = gda_db_base_get_instance_private (self); + + g_free (priv->m_catalog); + g_free (priv->m_schema); + g_free (priv->m_name); + g_free (priv->m_fullname); + + G_OBJECT_CLASS (gda_db_base_parent_class)->finalize (object); +} + +static void +gda_db_base_class_init (GdaDbBaseClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->finalize = gda_db_base_finalize; +} + +static void +gda_db_base_init (GdaDbBase *self) +{ + GdaDbBasePrivate *priv = gda_db_base_get_instance_private (self); + + priv->m_catalog = NULL; + priv->m_schema = NULL; + priv->m_name = NULL; + priv->m_fullname = NULL; +} + +/** + * gda_db_base_set_names: + * @self: a #GdaDbBase object + * @catalog: (nullable): a catalog name associated with the table + * @schema: (nullable): a schema name associated with the table + * @name: a table name associated with the table + * + * Sets database object names. @catalog and @schema can be %NULL but + * @name always should be a valid, not %NULL string. The @name must be + * set. If @catalog is %NULL @schema may not be %NULL but if @schema is + * %NULL @catalog also should be %NULL. + * + * Since: 6.0 + */ +void +gda_db_base_set_names (GdaDbBase *self, + const gchar* catalog, + const gchar* schema, + const gchar* name) +{ + g_return_if_fail (self); + g_return_if_fail (name); + + GdaDbBasePrivate *priv = gda_db_base_get_instance_private (self); + + g_free (priv->m_name); + g_free (priv->m_schema); + g_free (priv->m_catalog); + g_free (priv->m_fullname); + + priv->m_name = g_strdup (name); + priv->m_schema = NULL; + priv->m_catalog = NULL; + + if (schema) + priv->m_schema = g_strdup (schema); + + if (catalog) + priv->m_catalog = g_strdup (catalog); + + GString *fullnamestr = NULL; + + fullnamestr = g_string_new (NULL); + + if (priv->m_catalog && priv->m_schema) + g_string_printf (fullnamestr, "%s.%s.%s", priv->m_catalog, + priv->m_schema, priv->m_name); + else if (priv->m_schema) + g_string_printf (fullnamestr, "%s.%s", priv->m_schema, priv->m_name); + else + g_string_printf (fullnamestr, "%s", priv->m_name); + + priv->m_fullname = g_string_free (fullnamestr, FALSE); +} + +/** + * gda_db_base_get_full_name: + * @self: an instance of #GdaDbBase + * + * This method returns a full name in the format catalog.schema.name. + * If schema is %NULL but catalog and name are not, then only name is + * returned. If catalog is %NULL then full name will be in the format: + * schema.name. If all three components are not set, then %NULL is returned. + * + * Returns: Full name of the database object or %NULL. + * + * Since: 6.0 + */ +const gchar* +gda_db_base_get_full_name (GdaDbBase *self) +{ + g_return_val_if_fail (self, NULL); + + GdaDbBasePrivate *priv = gda_db_base_get_instance_private (self); + + GString *fullnamestr = NULL; + g_free (priv->m_fullname); + + fullnamestr = g_string_new (NULL); + + if (priv->m_catalog && priv->m_schema && priv->m_name) + g_string_printf (fullnamestr, "%s.%s.%s", priv->m_catalog, + priv->m_schema, priv->m_name); + else if (priv->m_schema && priv->m_name) + g_string_printf (fullnamestr, "%s.%s", priv->m_schema, priv->m_name); + else if (priv->m_name) + g_string_printf (fullnamestr, "%s", priv->m_name); + else + { + g_string_free (fullnamestr, TRUE); + return NULL; + } + + priv->m_fullname = g_string_free (fullnamestr, FALSE); + + return priv->m_fullname; +} + +/** + * gda_db_base_get_catalog: + * @self: a #GdaDbBase object + * + * Returns current catalog name. The returned string should not be freed. + * + * Returns: Current catalog or %NULL + * + * Since: 6.0 + */ +const gchar* +gda_db_base_get_catalog (GdaDbBase *self) +{ + g_return_val_if_fail (self, NULL); + + GdaDbBasePrivate *priv = gda_db_base_get_instance_private (self); + + return priv->m_catalog; +} + +/** + * gda_db_base_get_schema: + * @self: GdaDbBase object + * + * Returns current schema name. The returned string should not be freed. + * + * Returns: Current scheme or %NULL + * + * Since: 6.0 + */ +const gchar* +gda_db_base_get_schema (GdaDbBase *self) +{ + g_return_val_if_fail (self, NULL); + + GdaDbBasePrivate *priv = gda_db_base_get_instance_private (self); + + return priv->m_schema; +} + +/** + * gda_db_base_get_name: + * @self: GdaDbBase object + * + * Returns current object name. The returned string should not be freed. + * + * Returns: Current object name or %NULL + * + * Since: 6.0 + */ +const gchar* +gda_db_base_get_name (GdaDbBase *self) +{ + g_return_val_if_fail (self, NULL); + + GdaDbBasePrivate *priv = gda_db_base_get_instance_private (self); + + return priv->m_name; +} + +/** + * gda_db_base_set_catalog: + * @self: a #GdaDbBase instance + * @catalog: Catalog name as a string + * + * Set catalog name + * + * Since: 6.0 + */ +void +gda_db_base_set_catalog (GdaDbBase *self, + const gchar *catalog) +{ + g_return_if_fail (self); + + GdaDbBasePrivate *priv = gda_db_base_get_instance_private (self); + + g_free (priv->m_catalog); + priv->m_catalog = g_strdup (catalog); +} + +/** + * gda_db_base_set_schema: + * @self: a #GdaDbBase instance + * @schema: Schema name as a string + * + * Set object schema. If @schema is %NULL the function just returns. + * + * Since: 6.0 + */ +void +gda_db_base_set_schema (GdaDbBase *self, + const gchar *schema) +{ + g_return_if_fail (self); + + if (!schema) + return; + + GdaDbBasePrivate *priv = gda_db_base_get_instance_private (self); + + g_free (priv->m_schema); + priv->m_schema = g_strdup (schema); +} + +/** + * gda_db_base_set_name: + * @self: a #GdaDbBase instance + * @name: Object name as a string + * + * Set object name. If @name is %NULL the function just returns. + * + * Since: 6.0 + */ +void +gda_db_base_set_name (GdaDbBase *self, + const gchar *name) +{ + g_return_if_fail (self); + + if (!name) + return; + + GdaDbBasePrivate *priv = gda_db_base_get_instance_private (self); + + g_free (priv->m_name); + priv->m_name = g_strdup (name); +} + +/** + * gda_db_base_compare: + * @a: first #GdaDbBase object + * @b: second #GdaDbBase object + * + * Compares two objects similar to g_strcmp(). + * + * Returns: 0 if catalog, schema and name are the same + * + * Since: 6.0 + */ +gint +gda_db_base_compare (GdaDbBase *a, + GdaDbBase *b) +{ + if (!a && !b) + return 0; + else if (!a && b) + return -1; + else if (a && !b) + return 1; + + gint res = g_strcmp0 (gda_db_base_get_name(a), gda_db_base_get_name(b)); + + if (!res) + { + res = g_strcmp0 (gda_db_base_get_catalog(a), gda_db_base_get_catalog(b)); + + if (!res) + return g_strcmp0(gda_db_base_get_schema(a), gda_db_base_get_schema(b)); + else + return res; + } + else + return res; +} diff --git a/.flatpak-builder/cache/objects/76/a8564f01b81fbd1aaba6a852523b8a60eeba6a35763e61cb512705f7b07acb.file b/.flatpak-builder/cache/objects/76/a8564f01b81fbd1aaba6a852523b8a60eeba6a35763e61cb512705f7b07acb.file new file mode 100644 index 0000000..113287f --- /dev/null +++ b/.flatpak-builder/cache/objects/76/a8564f01b81fbd1aaba6a852523b8a60eeba6a35763e61cb512705f7b07acb.file @@ -0,0 +1,36 @@ +/*-*- Mode: C; c-basic-offset: 8 -*-*/ + +/*** + This file is part of libcanberra. + + Copyright 2008 Lennart Poettering + + libcanberra is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation, either version 2.1 of the + License, or (at your option) any later version. + + libcanberra is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with libcanberra. If not, see + . +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "macro.h" + +ca_bool_t ca_debug(void) { + const char *d; + + if ((d = getenv("CANBERRA_DEBUG"))) + return !!*d; + + return FALSE; +} diff --git a/.flatpak-builder/cache/objects/76/afca12ea06b8b707297100d569d26d15cf6595a1efb6e2f7f258839e64b27e.file b/.flatpak-builder/cache/objects/76/afca12ea06b8b707297100d569d26d15cf6595a1efb6e2f7f258839e64b27e.file new file mode 120000 index 0000000..c1ea73a --- /dev/null +++ b/.flatpak-builder/cache/objects/76/afca12ea06b8b707297100d569d26d15cf6595a1efb6e2f7f258839e64b27e.file @@ -0,0 +1 @@ +../../share/runtime/locale/id/share/id \ No newline at end of file diff --git a/.flatpak-builder/cache/objects/76/c593b12cfcb380390e4873819d8b04de4d0d2a1de12a95e35c6c3a848e07f6.file b/.flatpak-builder/cache/objects/76/c593b12cfcb380390e4873819d8b04de4d0d2a1de12a95e35c6c3a848e07f6.file new file mode 100755 index 0000000..b86b284 Binary files /dev/null and b/.flatpak-builder/cache/objects/76/c593b12cfcb380390e4873819d8b04de4d0d2a1de12a95e35c6c3a848e07f6.file differ diff --git a/.flatpak-builder/cache/objects/76/d0f6c67d1606343ed58ea65e6dcdad6be648bed021a5df1dbb26027663b00f.file b/.flatpak-builder/cache/objects/76/d0f6c67d1606343ed58ea65e6dcdad6be648bed021a5df1dbb26027663b00f.file new file mode 100644 index 0000000..314c753 --- /dev/null +++ b/.flatpak-builder/cache/objects/76/d0f6c67d1606343ed58ea65e6dcdad6be648bed021a5df1dbb26027663b00f.file @@ -0,0 +1,262 @@ +# expressions.py +# +# Copyright 2022 James Westman +# +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation; either version 3 of the +# License, or (at your option) any later version. +# +# This file is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program. If not, see . +# +# SPDX-License-Identifier: LGPL-3.0-or-later + + +from .common import * +from .contexts import ScopeCtx, ValueTypeCtx +from .types import TypeName +from .gtkbuilder_template import Template + + +expr = Sequence() + + +class ExprBase(AstNode): + @context(ValueTypeCtx) + def value_type(self) -> ValueTypeCtx: + if rhs := self.rhs: + return rhs.context[ValueTypeCtx] + else: + return self.parent.context[ValueTypeCtx] + + @property + def type(self) -> T.Optional[GirType]: + raise NotImplementedError() + + @property + def type_complete(self) -> bool: + return True + + @property + def rhs(self) -> T.Optional["ExprBase"]: + if isinstance(self.parent, Expression): + children = list(self.parent.children) + if children.index(self) + 1 < len(children): + return children[children.index(self) + 1] + else: + return self.parent.rhs + else: + return None + + +class Expression(ExprBase): + grammar = expr + + @property + def last(self) -> ExprBase: + return self.children[-1] + + @property + def type(self) -> T.Optional[GirType]: + return self.last.type + + @property + def type_complete(self) -> bool: + return self.last.type_complete + + +class InfixExpr(ExprBase): + @property + def lhs(self): + children = list(self.parent_by_type(Expression).children) + return children[children.index(self) - 1] + + +class LiteralExpr(ExprBase): + grammar = LITERAL + + @property + def is_object(self) -> bool: + from .values import IdentLiteral + + return isinstance(self.literal.value, IdentLiteral) and ( + self.literal.value.ident in self.context[ScopeCtx].objects + or self.root.is_legacy_template(self.literal.value.ident) + ) + + @property + def literal(self): + from .values import Literal + + return self.children[Literal][0] + + @property + def type(self) -> T.Optional[GirType]: + return self.literal.value.type + + @property + def type_complete(self) -> bool: + from .values import IdentLiteral + + if isinstance(self.literal.value, IdentLiteral): + if object := self.context[ScopeCtx].objects.get(self.literal.value.ident): + return not object.gir_class.incomplete + return True + + +class LookupOp(InfixExpr): + grammar = [".", UseIdent("property")] + + @context(ValueTypeCtx) + def value_type(self) -> ValueTypeCtx: + return ValueTypeCtx(None) + + @property + def property_name(self) -> str: + return self.tokens["property"] + + @property + def type(self) -> T.Optional[GirType]: + if isinstance(self.lhs.type, gir.Class) or isinstance( + self.lhs.type, gir.Interface + ): + if property := self.lhs.type.properties.get(self.property_name): + return property.type + + return None + + @validate("property") + def property_exists(self): + if self.lhs.type is None: + raise CompileError( + f"Could not determine the type of the preceding expression", + hints=[ + f"add a type cast so blueprint knows which type the property {self.property_name} belongs to" + ], + ) + + if self.lhs.type.incomplete: + return + + elif not isinstance(self.lhs.type, gir.Class) and not isinstance( + self.lhs.type, gir.Interface + ): + raise CompileError( + f"Type {self.lhs.type.full_name} does not have properties" + ) + + elif self.lhs.type.properties.get(self.property_name) is None: + raise CompileError( + f"{self.lhs.type.full_name} does not have a property called {self.property_name}", + did_you_mean=(self.property_name, self.lhs.type.properties.keys()), + ) + + +class CastExpr(InfixExpr): + grammar = [ + "as", + AnyOf( + ["<", TypeName, Match(">").expected()], + [ + UseExact("lparen", "("), + TypeName, + UseExact("rparen", ")").expected("')'"), + ], + ), + ] + + @context(ValueTypeCtx) + def value_type(self): + return ValueTypeCtx(self.type) + + @property + def type(self) -> T.Optional[GirType]: + return self.children[TypeName][0].gir_type + + @property + def type_complete(self) -> bool: + return True + + @validate() + def cast_makes_sense(self): + if self.type is None or self.lhs.type is None: + return + + if not self.type.assignable_to(self.lhs.type): + raise CompileError( + f"Invalid cast. No instance of {self.lhs.type.full_name} can be an instance of {self.type.full_name}." + ) + + @validate("lparen", "rparen") + def upgrade_to_angle_brackets(self): + if self.tokens["lparen"]: + raise UpgradeWarning( + "Use angle bracket syntax introduced in blueprint 0.8.0", + actions=[ + CodeAction( + "Use <> instead of ()", + f"<{self.children[TypeName][0].as_string}>", + ) + ], + ) + + +class ClosureArg(AstNode): + grammar = Expression + + @property + def expr(self) -> Expression: + return self.children[Expression][0] + + @context(ValueTypeCtx) + def value_type(self) -> ValueTypeCtx: + return ValueTypeCtx(None) + + +class ClosureExpr(ExprBase): + grammar = [ + Optional(["$", UseLiteral("extern", True)]), + UseIdent("name"), + "(", + Delimited(ClosureArg, ","), + ")", + ] + + @property + def type(self) -> T.Optional[GirType]: + if isinstance(self.rhs, CastExpr): + return self.rhs.type + else: + return None + + @property + def closure_name(self) -> str: + return self.tokens["name"] + + @property + def args(self) -> T.List[ClosureArg]: + return self.children[ClosureArg] + + @validate() + def cast_to_return_type(self): + if not isinstance(self.rhs, CastExpr): + raise CompileError( + "Closure expression must be cast to the closure's return type" + ) + + @validate() + def builtin_exists(self): + if not self.tokens["extern"]: + raise CompileError(f"{self.closure_name} is not a builtin function") + + +expr.children = [ + AnyOf(ClosureExpr, LiteralExpr, ["(", Expression, ")"]), + ZeroOrMore(AnyOf(LookupOp, CastExpr)), +] diff --git a/.flatpak-builder/cache/objects/76/d7e523e0fe59ff21ff52deac682e847f1cc2fac50ae794686ee06a33a4c4fb.file b/.flatpak-builder/cache/objects/76/d7e523e0fe59ff21ff52deac682e847f1cc2fac50ae794686ee06a33a4c4fb.file new file mode 100644 index 0000000..34446f5 --- /dev/null +++ b/.flatpak-builder/cache/objects/76/d7e523e0fe59ff21ff52deac682e847f1cc2fac50ae794686ee06a33a4c4fb.file @@ -0,0 +1,544 @@ +/*-*- Mode: C; c-basic-offset: 8 -*-*/ + +/*** + This file is part of libcanberra. + + Copyright 2008 Lennart Poettering + + libcanberra is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation, either version 2.1 of the + License, or (at your option) any later version. + + libcanberra is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with libcanberra. If not, see + . +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#include "canberra.h" +#include "canberra-gtk.h" +#include "common.h" +#include "malloc.h" +#include "proplist.h" +#include "fork-detect.h" + +/** + * SECTION:canberra-gtk + * @short_description: Gtk+ libcanberra Bindings + * + * libcanberra-gtk provides a few functions that simplify libcanberra + * usage from Gtk+ programs. It maintains a single ca_context object + * per #GdkScreen that is made accessible via + * ca_gtk_context_get_for_screen(), with a shortcut ca_gtk_context_get() + * to get the context for the default screen. More importantly, it provides + * a few functions + * to compile event sound property lists based on GtkWidget objects or + * GdkEvent events. + */ + +static void read_sound_theme_name(ca_context *c, GtkSettings *s) { + gchar *theme_name = NULL; + + g_object_get(G_OBJECT(s), "gtk-sound-theme-name", &theme_name, NULL); + + if (theme_name) { + ca_context_change_props(c, CA_PROP_CANBERRA_XDG_THEME_NAME, theme_name, NULL); + g_free(theme_name); + } +} + +static void read_enable_event_sounds(ca_context *c, GtkSettings *s) { + gboolean enable_event_sounds = TRUE; + + if (!g_getenv("CANBERRA_FORCE_EVENT_SOUNDS")) + g_object_get(G_OBJECT(s), "gtk-enable-event-sounds", &enable_event_sounds, NULL); + + ca_context_change_props(c, CA_PROP_CANBERRA_ENABLE, enable_event_sounds ? "1" : "0", NULL); +} + +static void sound_theme_name_changed(GtkSettings *s, GParamSpec *arg1, ca_context *c) { + read_sound_theme_name(c, s); +} + +static void enable_event_sounds_changed(GtkSettings *s, GParamSpec *arg1, ca_context *c) { + read_enable_event_sounds(c, s); +} + +/** + * ca_gtk_context_get: + * + * Gets the single ca_context object for the default screen. See + * ca_gtk_context_get_for_screen(). + * + * Returns: a ca_context object. The object is owned by libcanberra-gtk + * and must not be destroyed + */ +ca_context *ca_gtk_context_get(void) { + return ca_gtk_context_get_for_screen(NULL); +} + +/** + * ca_gtk_context_get_for_screen: + * @screen: the #GdkScreen to get the context for, or %NULL to use + * the default screen + * + * libcanberra-gtk maintains a single ca_context object for each + * #GdkScreen. Use this function to access it. The + * %CA_PROP_CANBERRA_XDG_THEME_NAME of this context property is + * dynamically bound to the XSETTINGS setting for the XDG theme + * name. CA_PROP_APPLICATION_NAME is bound to + * g_get_application_name(). + * + * Returns: a ca_context object. The object is owned by libcanberra-gtk + * and must not be destroyed + * + * Since: 0.13 + */ +ca_context *ca_gtk_context_get_for_screen(GdkScreen *screen) { + ca_context *c = NULL; + ca_proplist *p = NULL; + const char *name; + GtkSettings *s; + + if (!screen) + screen = gdk_screen_get_default(); + + if ((c = g_object_get_data(G_OBJECT(screen), "canberra::gtk::context"))) + return c; + + if (ca_context_create(&c) != CA_SUCCESS) + return NULL; + + if (ca_proplist_create(&p) != CA_SUCCESS) { + ca_context_destroy(c); + return NULL; + } + + if ((name = g_get_application_name())) + ca_proplist_sets(p, CA_PROP_APPLICATION_NAME, name); + else { + ca_proplist_sets(p, CA_PROP_APPLICATION_NAME, "libcanberra-gtk"); + ca_proplist_sets(p, CA_PROP_APPLICATION_VERSION, PACKAGE_VERSION); + ca_proplist_sets(p, CA_PROP_APPLICATION_ID, "org.freedesktop.libcanberra.gtk"); + } + + if ((name = gtk_window_get_default_icon_name())) + ca_proplist_sets(p, CA_PROP_APPLICATION_ICON_NAME, name); + + if ((name = gdk_display_get_name(gdk_screen_get_display(screen)))) + ca_proplist_sets(p, CA_PROP_WINDOW_X11_DISPLAY, name); + + ca_proplist_setf(p, CA_PROP_WINDOW_X11_SCREEN, "%i", gdk_screen_get_number(screen)); + + ca_context_change_props_full(c, p); + ca_proplist_destroy(p); + + if ((s = gtk_settings_get_for_screen(screen))) { + + if (g_object_class_find_property(G_OBJECT_GET_CLASS(s), "gtk-sound-theme-name")) { + g_signal_connect(G_OBJECT(s), "notify::gtk-sound-theme-name", G_CALLBACK(sound_theme_name_changed), c); + read_sound_theme_name(c, s); + } else + g_debug("This Gtk+ version doesn't have the GtkSettings::gtk-sound-theme-name property."); + + if (g_object_class_find_property(G_OBJECT_GET_CLASS(s), "gtk-enable-event-sounds")) { + g_signal_connect(G_OBJECT(s), "notify::gtk-enable-event-sounds", G_CALLBACK(enable_event_sounds_changed), c); + read_enable_event_sounds(c, s); + } else + g_debug("This Gtk+ version doesn't have the GtkSettings::gtk-enable-event-sounds property."); + } + + g_object_set_data_full(G_OBJECT(screen), "canberra::gtk::context", c, (GDestroyNotify) ca_context_destroy); + + return c; +} + +static GtkWindow* get_toplevel(GtkWidget *w) { + if (!(w = gtk_widget_get_toplevel(w))) + return NULL; + + if (!GTK_IS_WINDOW(w)) + return NULL; + + return GTK_WINDOW(w); +} + +static gint window_get_desktop(GdkDisplay *d, GdkWindow *w) { + Atom type_return; + gint format_return; + gulong nitems_return; + gulong bytes_after_return; + guchar *data = NULL; + gint ret = -1; + + if (XGetWindowProperty(GDK_DISPLAY_XDISPLAY(d), GDK_WINDOW_XID(w), + gdk_x11_get_xatom_by_name_for_display(d, "_NET_WM_DESKTOP"), + 0, G_MAXLONG, False, XA_CARDINAL, &type_return, + &format_return, &nitems_return, &bytes_after_return, + &data) != Success) + return -1; + + if (type_return == XA_CARDINAL && format_return == 32 && data) { + guint32 desktop = *(guint32*) data; + + if (desktop != 0xFFFFFFFF) + ret = (gint) desktop; + } + + if (type_return != None && data != NULL) + XFree(data); + + return ret; +} + +/** + * ca_gtk_proplist_set_for_widget: + * @p: The proplist to store these sound event properties in + * @w: The Gtk widget to base these sound event properties on + * + * Fill in a ca_proplist object for a sound event that shall originate + * from the specified Gtk Widget. This will fill in properties like + * %CA_PROP_WINDOW_NAME or %CA_PROP_WINDOW_X11_DISPLAY for you. + * + * Returns: 0 on success, negative error code on error. + */ + +int ca_gtk_proplist_set_for_widget(ca_proplist *p, GtkWidget *widget) { + GtkWindow *w; + int ret; + const char *t, *role; + + ca_return_val_if_fail(p, CA_ERROR_INVALID); + ca_return_val_if_fail(widget, CA_ERROR_INVALID); + ca_return_val_if_fail(!ca_detect_fork(), CA_ERROR_FORKED); + + if (!(w = get_toplevel(widget))) + return CA_ERROR_INVALID; + + if ((t = gtk_window_get_title(w))) + if ((ret = ca_proplist_sets(p, CA_PROP_WINDOW_NAME, t)) < 0) + return ret; + + if ((role = gtk_window_get_role(w))) { + if (role && t) { + char *id = ca_sprintf_malloc("%s#%s", t, role); + + if ((ret = ca_proplist_sets(p, CA_PROP_WINDOW_ID, id)) < 0) { + ca_free(id); + return ret; + } + + ca_free(id); + } + } else if (t) + if ((ret = ca_proplist_sets(p, CA_PROP_WINDOW_ID, t)) < 0) + return ret; + + if ((t = gtk_window_get_icon_name(w))) + if ((ret = ca_proplist_sets(p, CA_PROP_WINDOW_ICON_NAME, t)) < 0) + return ret; + + if (gtk_widget_get_realized(GTK_WIDGET(w))) { + GdkWindow *dw = NULL; + GdkScreen *screen = NULL; + GdkDisplay *display = NULL; + gint x = -1, y = -1, width = -1, height = -1, screen_width = -1, screen_height = -1; + + if ((dw = gtk_widget_get_window(GTK_WIDGET(w)))) + if ((ret = ca_proplist_setf(p, CA_PROP_WINDOW_X11_XID, "%lu", (unsigned long) GDK_WINDOW_XID(dw))) < 0) + return ret; + + if ((display = gtk_widget_get_display(GTK_WIDGET(w)))) { + if ((t = gdk_display_get_name(display))) + if ((ret = ca_proplist_sets(p, CA_PROP_WINDOW_X11_DISPLAY, t)) < 0) + return ret; + + if (dw) { + gint desktop = window_get_desktop(display, dw); + + if (desktop >= 0) + if ((ret = ca_proplist_setf(p, CA_PROP_WINDOW_DESKTOP, "%i", desktop)) < 0) + return ret; + } + } + + if ((screen = gtk_widget_get_screen(GTK_WIDGET(w)))) { + + if ((ret = ca_proplist_setf(p, CA_PROP_WINDOW_X11_SCREEN, "%i", gdk_screen_get_number(screen))) < 0) + return ret; + + if (dw) + if ((ret = ca_proplist_setf(p, CA_PROP_WINDOW_X11_MONITOR, "%i", gdk_screen_get_monitor_at_window(screen, dw))) < 0) + return ret; + } + + /* FIXME, this might cause a round trip */ + + if (dw) { + gdk_window_get_origin(dw, &x, &y); + + if (x >= 0) + if ((ret = ca_proplist_setf(p, CA_PROP_WINDOW_X, "%i", x)) < 0) + return ret; + if (y >= 0) + if ((ret = ca_proplist_setf(p, CA_PROP_WINDOW_Y, "%i", y)) < 0) + return ret; + } + + gtk_window_get_size(w, &width, &height); + + if (width > 0) + if ((ret = ca_proplist_setf(p, CA_PROP_WINDOW_WIDTH, "%i", width)) < 0) + return ret; + if (height > 0) + if ((ret = ca_proplist_setf(p, CA_PROP_WINDOW_HEIGHT, "%i", height)) < 0) + return ret; + + if (x >= 0 && width > 0) { + screen_width = gdk_screen_get_width(gtk_widget_get_screen(GTK_WIDGET(w))); + + x += width/2; + x = CA_CLAMP(x, 0, screen_width-1); + + /* We use these strange format strings here to avoid that libc + * applies locale information on the formatting of floating + * numbers. */ + + if ((ret = ca_proplist_setf(p, CA_PROP_WINDOW_HPOS, "%i.%03i", + (int) (x/(screen_width-1)), (int) (1000.0*x/(screen_width-1)) % 1000)) < 0) + return ret; + } + + if (y >= 0 && height > 0) { + screen_height = gdk_screen_get_height(gtk_widget_get_screen(GTK_WIDGET(w))); + + y += height/2; + y = CA_CLAMP(y, 0, screen_height-1); + + if ((ret = ca_proplist_setf(p, CA_PROP_WINDOW_VPOS, "%i.%03i", + (int) (y/(screen_height-1)), (int) (1000.0*y/(screen_height-1)) % 1000)) < 0) + return ret; + } + } + + return CA_SUCCESS; +} + +/** + * ca_gtk_proplist_set_for_event: + * @p: The proplist to store these sound event properties in + * @e: The Gdk event to base these sound event properties on + * + * Fill in a ca_proplist object for a sound event that is being + * triggered by the specified Gdk Event. This will fill in properties + * like %CA_PROP_EVENT_MOUSE_X or %CA_PROP_EVENT_MOUSE_BUTTON for + * you. This will internally also cal ca_gtk_proplist_set_for_widget() + * on the widget this event belongs to. + * + * Returns: 0 on success, negative error code on error. + */ + +int ca_gtk_proplist_set_for_event(ca_proplist *p, GdkEvent *e) { + gdouble x, y; + GdkWindow *gw; + GtkWidget *w = NULL; + int ret; + + ca_return_val_if_fail(p, CA_ERROR_INVALID); + ca_return_val_if_fail(e, CA_ERROR_INVALID); + ca_return_val_if_fail(!ca_detect_fork(), CA_ERROR_FORKED); + + if ((gw = e->any.window)) { + gdk_window_get_user_data(gw, (gpointer*) &w); + + if (w) + if ((ret = ca_gtk_proplist_set_for_widget(p, w)) < 0) + return ret; + } + + if (gdk_event_get_root_coords(e, &x, &y)) { + + if ((ret = ca_proplist_setf(p, CA_PROP_EVENT_MOUSE_X, "%0.0f", x)) < 0) + return ret; + + if ((ret = ca_proplist_setf(p, CA_PROP_EVENT_MOUSE_Y, "%0.0f", y)) < 0) + return ret; + + if (w) { + int width, height; + + width = gdk_screen_get_width(gtk_widget_get_screen(w)); + height = gdk_screen_get_height(gtk_widget_get_screen(w)); + + /* We use these strange format strings here to avoid that + * libc applies locale information on the formatting of + * floating numbers. */ + + if ((ret = ca_proplist_setf(p, CA_PROP_EVENT_MOUSE_HPOS, "%i.%03i", + (int) (x/(width-1)), (int) (1000.0*x/(width-1)) % 1000)) < 0) + return ret; + + if ((ret = ca_proplist_setf(p, CA_PROP_EVENT_MOUSE_VPOS, "%i.%03i", + (int) (y/(height-1)), (int) (1000.0*y/(height-1)) % 1000)) < 0) + return ret; + } + } + + if (e->type == GDK_BUTTON_PRESS || + e->type == GDK_2BUTTON_PRESS || + e->type == GDK_3BUTTON_PRESS || + e->type == GDK_BUTTON_RELEASE) { + + if ((ret = ca_proplist_setf(p, CA_PROP_EVENT_MOUSE_BUTTON, "%u", e->button.button)) < 0) + return ret; + } + + return CA_SUCCESS; +} + +/** + * ca_gtk_play_for_widget: + * @w: The Gtk widget to base these sound event properties on + * @id: The event id that can later be used to cancel this event sound + * using ca_context_cancel(). This can be any integer and shall be + * chosen be the client program. It is a good idea to pass 0 here if + * cancelling the sound later is not needed. If the same id is passed + * to multiple sounds they can be canceled with a single + * ca_context_cancel() call. + * @...: additional event properties as pairs of strings, terminated by NULL. + * + * Play a sound event for the specified widget. This will internally + * call ca_gtk_proplist_set_for_widget() and then merge them with the + * properties passed in via the NULL terminated argument + * list. Finally, it will call ca_context_play_full() to actually play + * the event sound. + * + * Returns: 0 on success, negative error code on error. + */ + +int ca_gtk_play_for_widget(GtkWidget *w, uint32_t id, ...) { + va_list ap; + int ret; + ca_proplist *p; + GdkScreen *s; + + ca_return_val_if_fail(w, CA_ERROR_INVALID); + ca_return_val_if_fail(!ca_detect_fork(), CA_ERROR_FORKED); + + if ((ret = ca_proplist_create(&p)) < 0) + return ret; + + if ((ret = ca_gtk_proplist_set_for_widget(p, w)) < 0) + goto fail; + + va_start(ap, id); + ret = ca_proplist_merge_ap(p, ap); + va_end(ap); + + if (ret < 0) + goto fail; + + s = gtk_widget_get_screen(w); + ret = ca_context_play_full(ca_gtk_context_get_for_screen(s), id, p, NULL, NULL); + +fail: + + ca_assert_se(ca_proplist_destroy(p) == 0); + + return ret; +} + +/** + * ca_gtk_play_for_event: + * @e: The Gdk event to base these sound event properties on + * @id: The event id that can later be used to cancel this event sound + * using ca_context_cancel(). This can be any integer and shall be + * chosen be the client program. It is a good idea to pass 0 here if + * cancelling the sound later is not needed. If the same id is passed + * to multiple sounds they can be canceled with a single + * ca_context_cancel() call. + * @...: additional event properties as pairs of strings, terminated by NULL. + * + * Play a sound event for the specified event. This will internally + * call ca_gtk_proplist_set_for_event() and then merge them with the + * properties passed in via the NULL terminated argument + * list. Finally, it will call ca_context_play_full() to actually play + * the event sound. + * + * Returns: 0 on success, negative error code on error. + */ + +int ca_gtk_play_for_event(GdkEvent *e, uint32_t id, ...) { + va_list ap; + int ret; + ca_proplist *p; + GdkScreen *s; + + ca_return_val_if_fail(e, CA_ERROR_INVALID); + ca_return_val_if_fail(!ca_detect_fork(), CA_ERROR_FORKED); + + if ((ret = ca_proplist_create(&p)) < 0) + return ret; + + if ((ret = ca_gtk_proplist_set_for_event(p, e)) < 0) + goto fail; + + va_start(ap, id); + ret = ca_proplist_merge_ap(p, ap); + va_end(ap); + + if (ret < 0) + goto fail; + + if (e->any.window) +#if GTK_CHECK_VERSION (2, 90, 7) + s = gdk_window_get_screen(e->any.window); +#else + s = gdk_drawable_get_screen(GDK_DRAWABLE(e->any.window)); +#endif + else + s = gdk_screen_get_default(); + + ret = ca_context_play_full(ca_gtk_context_get_for_screen(s), id, p, NULL, NULL); + +fail: + + ca_assert_se(ca_proplist_destroy(p) == 0); + + return ret; +} + +/** + * ca_gtk_widget_disable_sounds: + * @w: The Gtk widget to disable automatic event sounds for. + * @enable: Boolean specifying whether sound events shall be enabled or disabled for this widget. + * + * By default sound events are automatically generated for all kinds + * of input events. Use this function to disable this. This is + * intended to be used for widgets which directly generate sound + * events. + */ + +void ca_gtk_widget_disable_sounds(GtkWidget *w, gboolean enable) { + static GQuark disable_sound_quark = 0; + + /* This is the same quark used by libgnomeui! */ + if (!disable_sound_quark) + disable_sound_quark = g_quark_from_static_string("gnome_disable_sound_events"); + + g_object_set_qdata(G_OBJECT(w), disable_sound_quark, GINT_TO_POINTER(!!enable)); +} diff --git a/.flatpak-builder/cache/objects/77/16da7ee0090fbe1245c80cb1ad21469388acf7c7816762d42b3ae9b31f3a62.dirtree b/.flatpak-builder/cache/objects/77/16da7ee0090fbe1245c80cb1ad21469388acf7c7816762d42b3ae9b31f3a62.dirtree new file mode 100644 index 0000000..dc8cb69 Binary files /dev/null and b/.flatpak-builder/cache/objects/77/16da7ee0090fbe1245c80cb1ad21469388acf7c7816762d42b3ae9b31f3a62.dirtree differ diff --git a/.flatpak-builder/cache/objects/77/3331d9bfa230f1bec7cdc0b6f85070b1a9b3b1d1a4a1babeab4de836641fc3.dirtree b/.flatpak-builder/cache/objects/77/3331d9bfa230f1bec7cdc0b6f85070b1a9b3b1d1a4a1babeab4de836641fc3.dirtree new file mode 100644 index 0000000..b5d5c71 Binary files /dev/null and b/.flatpak-builder/cache/objects/77/3331d9bfa230f1bec7cdc0b6f85070b1a9b3b1d1a4a1babeab4de836641fc3.dirtree differ diff --git a/.flatpak-builder/cache/objects/77/825d3055735fe29c5598b5dc7a462bc77c525eecc7747c4c6b6966dc21783d.file b/.flatpak-builder/cache/objects/77/825d3055735fe29c5598b5dc7a462bc77c525eecc7747c4c6b6966dc21783d.file new file mode 100755 index 0000000..4c15b63 --- /dev/null +++ b/.flatpak-builder/cache/objects/77/825d3055735fe29c5598b5dc7a462bc77c525eecc7747c4c6b6966dc21783d.file @@ -0,0 +1,1304 @@ +#!/usr/bin/perl -w +# -*- Mode: perl; indent-tabs-mode: nil; c-basic-offset: 4 -*- + +# +# The Intltool Message Updater +# +# Copyright (C) 2000-2003 Free Software Foundation. +# +# Intltool is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# version 2 published by the Free Software Foundation. +# +# Intltool is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. +# +# Authors: Kenneth Christiansen +# Maciej Stachowiak +# Darin Adler + +## Release information +my $PROGRAM = "intltool-update"; +my $VERSION = "0.51.0"; +my $PACKAGE = "intltool"; + +## Loaded modules +use strict; +use Getopt::Long; +use Cwd; +use File::Copy; +use File::Find; + +## Scalars used by the option stuff +my $HELP_ARG = 0; +my $VERSION_ARG = 0; +my $DIST_ARG = 0; +my $POT_ARG = 0; +my $HEADERS_ARG = 0; +my $MAINTAIN_ARG = 0; +my $REPORT_ARG = 0; +my $VERBOSE = 0; +my $GETTEXT_PACKAGE = ""; +my $OUTPUT_FILE = ""; + +my @languages; +my %varhash = (); +my %po_files_by_lang = (); + +# Regular expressions to categorize file types. +# FIXME: Please check if the following is correct + +my $xml_support = +"xml(?:\\.in)*|". # http://www.w3.org/XML/ (Note: .in is not required) +"ui|". # Bonobo specific - User Interface desc. files +"lang|". # ? +"glade2?(?:\\.in)*|". # Glade specific - User Interface desc. files (Note: .in is not required) +"oaf(?:\\.in)+|". # DEPRECATED: Replaces by Bonobo .server files +"etspec|". # ? +"server(?:\\.in)+|". # Bonobo specific +"sheet(?:\\.in)+|". # ? +"schemas(?:\\.in)+|". # GConf specific +"gschema.xml|". # GLib schema (ie: GSettings) specific +"pong(?:\\.in)+|". # DEPRECATED: PONG is not used [by GNOME] any longer. +"kbd(?:\\.in)+|". # GOK specific. +"policy(?:\\.in)+"; # PolicyKit files + +my $ini_support = +"icon(?:\\.in)+|". # http://www.freedesktop.org/Standards/icon-theme-spec +"desktop(?:\\.in)+|". # http://www.freedesktop.org/Standards/menu-spec +"caves(?:\\.in)+|". # GNOME Games specific +"directory(?:\\.in)+|". # http://www.freedesktop.org/Standards/menu-spec +"soundlist(?:\\.in)+|". # GNOME specific +"keys(?:\\.in)+|". # GNOME Mime database specific +"theme(?:\\.in)+|". # http://www.freedesktop.org/Standards/icon-theme-spec +"service(?:\\.in)+"; # DBus specific + +my $tlk_support = +"tlk(?:\\.in)+"; # Bioware Aurora Talk Table Format + +my $buildin_gettext_support = +"c|y|cs|cc|cpp|c\\+\\+|h|hh|gob|py|scm(?:\\.in)*"; + +## Always flush buffer when printing +$| = 1; + +## Sometimes the source tree will be rooted somewhere else. +my $SRCDIR = $ENV{"srcdir"} || "."; +my $POTFILES_in; + +$POTFILES_in = "<$SRCDIR/POTFILES.in"; + +my $devnull = ($^O eq 'MSWin32' ? 'NUL:' : '/dev/null'); + +## Handle options +GetOptions +( + "help" => \$HELP_ARG, + "version" => \$VERSION_ARG, + "dist|d" => \$DIST_ARG, + "pot|p" => \$POT_ARG, + "headers|s" => \$HEADERS_ARG, + "maintain|m" => \$MAINTAIN_ARG, + "report|r" => \$REPORT_ARG, + "verbose|x" => \$VERBOSE, + "gettext-package|g=s" => \$GETTEXT_PACKAGE, + "output-file|o=s" => \$OUTPUT_FILE, + ) or &Console_WriteError_InvalidOption; + +&Console_Write_IntltoolHelp if $HELP_ARG; +&Console_Write_IntltoolVersion if $VERSION_ARG; + +my $arg_count = ($DIST_ARG > 0) + + ($POT_ARG > 0) + + ($HEADERS_ARG > 0) + + ($MAINTAIN_ARG > 0) + + ($REPORT_ARG > 0); + +&Console_Write_IntltoolHelp if $arg_count > 1; + +my $MODULE = $GETTEXT_PACKAGE || FindPackageName() || "unknown"; + +if ($POT_ARG) +{ + &GenerateHeaders; + &GeneratePOTemplate; +} +elsif ($HEADERS_ARG) +{ + &GenerateHeaders; +} +elsif ($MAINTAIN_ARG) +{ + &FindLeftoutFiles; +} +elsif ($REPORT_ARG) +{ + &GenerateHeaders; + &GeneratePOTemplate; + &Console_Write_CoverageReport; +} +elsif ((defined $ARGV[0]) && $ARGV[0] =~ /^[a-z]/) +{ + my $lang = $ARGV[0]; + + ## Report error if the language file supplied + ## to the command line is non-existent + &Console_WriteError_NotExisting("$SRCDIR/$lang.po") + if ! -s "$SRCDIR/$lang.po"; + + if (!$DIST_ARG) + { + print "Working, please wait..." if $VERBOSE; + &GenerateHeaders; + &GeneratePOTemplate; + } + &POFile_Update ($lang, $OUTPUT_FILE); + &Console_Write_TranslationStatus ($lang, $OUTPUT_FILE); +} +else +{ + &Console_Write_IntltoolHelp; +} + +exit; + +######### + +sub Console_Write_IntltoolVersion +{ + print <<_EOF_; +${PROGRAM} (${PACKAGE}) $VERSION +Written by Kenneth Christiansen, Maciej Stachowiak, and Darin Adler. + +Copyright (C) 2000-2003 Free Software Foundation, Inc. +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +_EOF_ + exit; +} + +sub Console_Write_IntltoolHelp +{ + print <<_EOF_; +Usage: ${PROGRAM} [OPTION]... LANGCODE +Updates PO template files and merge them with the translations. + +Mode of operation (only one is allowed): + -p, --pot generate the PO template only + -s, --headers generate the header files in POTFILES.in + -m, --maintain search for left out files from POTFILES.in + -r, --report display a status report for the module + -d, --dist merge LANGCODE.po with existing PO template + +Extra options: + -g, --gettext-package=NAME override PO template name, useful with --pot + -o, --output-file=FILE write merged translation to FILE + -x, --verbose display lots of feedback + --help display this help and exit + --version output version information and exit + +Examples of use: +${PROGRAM} --pot just create a new PO template +${PROGRAM} xy create new PO template and merge xy.po with it + +Report bugs to http://bugs.launchpad.net/intltool +_EOF_ + exit; +} + +sub echo_n +{ + my $str = shift; + my $ret = `echo "$str"`; + + $ret =~ s/\n$//; # do we need the "s" flag? + + return $ret; +} + +sub POFile_DetermineType ($) +{ + my $type = $_; + my $gettext_type; + + my $xml_regex = "(?:" . $xml_support . ")"; + my $ini_regex = "(?:" . $ini_support . ")"; + my $tlk_regex = "(?:" . $tlk_support . ")"; + my $buildin_regex = "(?:" . $buildin_gettext_support . ")"; + + if ($type =~ /\[type: gettext\/([^\]].*)]/) + { + $gettext_type=$1; + } + elsif ($type =~ /gschema.xml$/) + { + $gettext_type="gsettings"; + } + elsif ($type =~ /schemas(\.in)+$/) + { + $gettext_type="schemas"; + } + elsif ($type =~ /glade2?(\.in)*$/) + { + $gettext_type="glade"; + } + elsif ($type =~ /scm(\.in)*$/) + { + $gettext_type="scheme"; + } + elsif ($type =~ /keys(\.in)+$/) + { + $gettext_type="keys"; + } + + # bucket types + + elsif ($type =~ /$xml_regex$/) + { + $gettext_type="xml"; + } + elsif ($type =~ /$ini_regex$/) + { + $gettext_type="ini"; + } + elsif ($type =~ /$tlk_regex$/) + { + $gettext_type="tlk"; + } + elsif ($type =~ /$buildin_regex$/) + { + $gettext_type="buildin"; + } + else + { + $gettext_type="unknown"; + } + + return "gettext\/$gettext_type"; +} + +sub TextFile_DetermineEncoding ($) +{ + my $gettext_code="UTF-8"; # All files are UTF-8 by default + my $filetype=`file $_ | cut -d ' ' -f 2`; + + if ($? eq "0") + { + if ($filetype =~ /^(ISO|UTF)/) + { + chomp ($gettext_code = $filetype); + } + elsif ($filetype =~ /^XML/) + { + $gettext_code="UTF-8"; # We asume that .glade and other .xml files are UTF-8 + } + } + + return $gettext_code; +} + +sub isNotValidMissing +{ + my ($file) = @_; + my $package_name = ""; + my $version = ""; + $package_name = $varhash{"PACKAGE"} if (defined $varhash{"PACKAGE"}); + $version = $varhash{"VERSION"} if (defined $varhash{"VERSION"}); + + return if $file =~ /^\{arch\}\/.*$/; + return if $file =~ /^$package_name-$version\/.*$/; +} + +sub removeFromArray +{ + my ($file, @array) = @_; + + my $i = 0; + foreach my $potfile (@array) { + delete $array[$i] if $potfile =~ m/$file/; + $i++; + } +} + +sub AddFileToListIfMissing +{ + my ($file, $list) = @_; + + my $name_pattern; + if ($file =~ /^\.\.\//) { + $name_pattern = "x3 A*"; + } else { + $name_pattern = "A*"; + } + + my $file_name = unpack($name_pattern, $file); + if (defined isNotValidMissing ($file_name)) { + ## Remove the first 3 chars if needed and add newline + push @$list, $file_name . "\n"; + } +} + +sub FindLeftoutFiles +{ + my (@buf_i18n_plain, + @buf_i18n_xml, + @buf_i18n_xml_unmarked, + @buf_i18n_ini, + @buf_potfiles, + @buf_potfiles_ignore, + @buf_allfiles, + @buf_allfiles_sorted, + @buf_potfiles_sorted, + @buf_potfiles_ignore_sorted + ); + + ## Search and find all translatable files + find sub { + # Ignore hidden files + return if "$File::Find::name" =~ /\/\./; + push @buf_i18n_plain, "$File::Find::name" if /\.($buildin_gettext_support)$/; + push @buf_i18n_xml, "$File::Find::name" if /\.($xml_support)$/; + push @buf_i18n_ini, "$File::Find::name" if /\.($ini_support)$/; + push @buf_i18n_xml_unmarked, "$File::Find::name" if /\.(schemas(\.in)+)$/; + }, ".."; + find sub { + # Ignore hidden files + return if "$File::Find::name" =~ /\/\.[^.]/; + push @buf_i18n_plain, "$File::Find::name" if /\.($buildin_gettext_support)$/; + push @buf_i18n_xml, "$File::Find::name" if /\.($xml_support)$/; + push @buf_i18n_ini, "$File::Find::name" if /\.($ini_support)$/; + push @buf_i18n_xml_unmarked, "$File::Find::name" if /\.(schemas(\.in)+)$/; + }, "$SRCDIR/.." if "$SRCDIR" ne "."; + + open POTFILES, $POTFILES_in or die "$PROGRAM: there's no POTFILES.in!\n"; + @buf_potfiles = grep !/^(#|\s*$)/, ; + close POTFILES; + + foreach (@buf_potfiles) { + s/^\[.*]\s*//; + } + + print "Searching for missing translatable files...\n" if $VERBOSE; + + ## Check if we should ignore some found files, when + ## comparing with POTFILES.in + foreach my $ignore ("POTFILES.skip", "POTFILES.ignore") + { + (-s "$SRCDIR/$ignore") or next; + + if ("$ignore" eq "POTFILES.ignore") + { + print "The usage of POTFILES.ignore is deprecated. Please consider moving the\n". + "content of this file to POTFILES.skip.\n"; + } + + print "Found $ignore: Ignoring files...\n" if $VERBOSE; + open FILE, "<$SRCDIR/$ignore" or die "ERROR: Failed to open $SRCDIR/$ignore!\n"; + + while () + { + next if (/^$/); + next if (/^(#|\s*$)/); + + my $skipdir = "../$_"; + $skipdir = "$SRCDIR/../$_" if "$SRCDIR" ne "."; + $skipdir =~ s/\n//g; + + my @dirignored; + + if (-d "$skipdir") + { + find sub { + push @dirignored, "$File::Find::name" if /\.($buildin_gettext_support)$/; + push @dirignored, "$File::Find::name" if /\.($xml_support)$/; + push @dirignored, "$File::Find::name" if /\.($ini_support)$/; + push @dirignored, "$File::Find::name" if /\.(schemas(\.in)+)$/; + }, "$skipdir"; + foreach my $ignored (@dirignored) + { + $ignored =~ s/^$SRCDIR\///g; + $ignored =~ s/^..\///g; + $ignored =~ s/$/\n/g; + + removeFromArray ($ignored, @buf_i18n_plain); + removeFromArray ($ignored, @buf_i18n_xml); + removeFromArray ($ignored, @buf_i18n_ini); + removeFromArray ($ignored, @buf_i18n_xml_unmarked); + push @buf_potfiles_ignore, $ignored; + } + next; + } + removeFromArray ($_, @buf_i18n_plain); + removeFromArray ($_, @buf_i18n_xml); + removeFromArray ($_, @buf_i18n_ini); + removeFromArray ($_, @buf_i18n_xml_unmarked); + push @buf_potfiles_ignore, $_; + } + close FILE; + + @buf_potfiles_ignore_sorted = sort (@buf_potfiles_ignore); + } + + foreach my $file (@buf_i18n_plain) + { + my $in_comment = 0; + my $in_macro = 0; + my $in_string = 0; + my @multiline_quotes; + if ($file =~ /\.scm/) { + @multiline_quotes = ('"'); + } else { + @multiline_quotes = ("'''", '"""'); + } + + open FILE, "<$file"; + while () + { + if ($file =~ /\.scm/) { + # Strip single quotes from .scm files. + s-\'--g; + } + + # Handle continued multi-line comment. + if ($in_comment) + { + next unless s-.*\*/--; + $in_comment = 0; + } + + # Handle continued multi-line string. + if ($in_string) + { + my $pattern = join '|', @multiline_quotes; + if (!s/.*$pattern//) { + s///s; + next; + }; + $in_string = 0; + } + + # Handle continued macro. + if ($in_macro) + { + $in_macro = 0 unless /\\$/; + next; + } + + # Handle start of macro (or any preprocessor directive). + if (/^\s*\#/) + { + $in_macro = 1 if /^([^\\]|\\.)*\\$/; + next; + } + + # Handle comments and quoted text. + while (m-(/\*|//|\'\'\'|\"\"\"|\'|\")-) # \' and \" keep emacs perl mode happy + { + my $match = $1; + if ($match eq "/*") + { + if (!s-/\*.*?\*/--) + { + s-/\*.*--; + $in_comment = 1; + } + } + elsif ($match eq "//") + { + s-//.*--; + } + elsif (grep($match, @multiline_quotes)) + { + if (!s-$match(\\$match|[^$match])*$match-QUOTEDTEXT-g) + { + s-$match.*-QUOTEDTEXT-s; + $in_string = 1; + } + } + else # ' or " + { + s-$match(\\$match|[^$match])*$match-QUOTEDTEXT-g; + + # Handle inline # comments. + s/^([^$match]+)\#.*/$1/; + + if (m-$match-) + { + warn "mismatched quotes at line $. in $file\n"; + s-$match.*--; + } + } + } + + if (/\w\.GetString *\(QUOTEDTEXT/) + { + AddFileToListIfMissing($file, \@buf_allfiles); + last; + } + + ## C_ N_ NC_ Q_ and _ are the macros defined in gi8n.h + if (/(NC_|[NCQ]_|[^_]_|(^|$)[_]) *\(?QUOTEDTEXT/m) + { + AddFileToListIfMissing($file, \@buf_allfiles); + last; + } + + # Check for direct calls to the glib gettext wrappers + if (/g_d[np]?gettext[2]? *\(QUOTEDTEXT/) + { + AddFileToListIfMissing($file, \@buf_allfiles); + last; + } + } + close FILE; + } + + foreach my $file (@buf_i18n_xml) + { + open FILE, "<$file"; + + while () + { + # FIXME: share the pattern matching code with intltool-extract + if (/\s_[-A-Za-z0-9._:]+\s*=\s*\"([^"]+)\"/ || /<_[^>]+>/ || /translatable=\"yes\"/) + { + AddFileToListIfMissing($file, \@buf_allfiles); + last; + } + } + close FILE; + } + + foreach my $file (@buf_i18n_ini) + { + open FILE, "<$file"; + while () + { + if (/_(.*)=/) + { + AddFileToListIfMissing($file, \@buf_allfiles); + last; + } + } + close FILE; + } + + foreach my $file (@buf_i18n_xml_unmarked) + { + AddFileToListIfMissing($file, \@buf_allfiles); + } + + + @buf_allfiles_sorted = sort (@buf_allfiles); + @buf_potfiles_sorted = sort (@buf_potfiles); + + my %in2; + foreach (@buf_potfiles_sorted) + { + s#^$SRCDIR/../##; + s#^$SRCDIR/##; + $in2{$_} = 1; + } + + foreach (@buf_potfiles_ignore_sorted) + { + s#^$SRCDIR/../##; + s#^$SRCDIR/##; + $in2{$_} = 1; + } + + my @result; + + foreach (@buf_allfiles_sorted) + { + my $dummy = $_; + my $srcdir = $SRCDIR; + + $srcdir =~ s#^../##; + $dummy =~ s#^$srcdir/../##; + $dummy =~ s#^$srcdir/##; + $dummy =~ s#_build/##; + if (!exists($in2{$dummy})) + { + push @result, $dummy + } + } + + my @buf_potfiles_notexist; + + foreach (@buf_potfiles_sorted) + { + chomp (my $dummy = $_); + if ("$dummy" ne "" and !(-f "$SRCDIR/../$dummy" or -f "../$dummy")) + { + push @buf_potfiles_notexist, $_; + } + } + + ## Save file with information about the files missing + ## if any, and give information about this procedure. + if (@result + @buf_potfiles_notexist > 0) + { + if (@result) + { + print "\n" if $VERBOSE; + unlink "missing"; + open OUT, ">missing"; + print OUT @result; + close OUT; + warn "The following files contain translations and are currently not in use. Please\n". + "consider adding these to the POTFILES.in file, located in the po/ directory.\n\n"; + print STDERR @result, "\n"; + warn "If some of these files are left out on purpose then please add them to\n". + "POTFILES.skip instead of POTFILES.in. A file 'missing' containing this list\n". + "of left out files has been written in the current directory.\n"; + warn "Please report to ". $varhash{"PACKAGE_BUGREPORT"} ."\n" if (defined $varhash{"PACKAGE_BUGREPORT"}); + } + if (@buf_potfiles_notexist) + { + unlink "notexist"; + open OUT, ">notexist"; + print OUT @buf_potfiles_notexist; + close OUT; + warn "\n" if ($VERBOSE or @result); + warn "The following files do not exist anymore:\n\n"; + warn @buf_potfiles_notexist, "\n"; + warn "Please remove them from POTFILES.in. A file 'notexist'\n". + "containing this list of absent files has been written in the current directory.\n"; + warn "Please report to ". $varhash{"PACKAGE_BUGREPORT"} ."\n" if (defined $varhash{"PACKAGE_BUGREPORT"}); + } + } + + ## If there is nothing to complain about, notify the user + else { + print "\nAll files containing translations are present in POTFILES.in.\n" if $VERBOSE; + } +} + +sub Console_WriteError_InvalidOption +{ + ## Handle invalid arguments + print STDERR "Try `${PROGRAM} --help' for more information.\n"; + exit 1; +} + +sub isProgramInPath +{ + my ($file) = @_; + # If a file is executable (or exists on Windows), + # or when it returns 0 exit status. + return 1 if ( + ((-x $file) or ($^O eq 'MSWin32' and (-e $file))) or + (system("$file --version >$devnull") == 0)); + return 0; +} + +sub isGNUGettextTool +{ + my ($file) = @_; + # Check that we are using GNU gettext tools + if (isProgramInPath ($file)) + { + my $version = `$file --version`; + return 1 if ($version =~ m/.*\(GNU .*\).*/); + } + return 0; +} + +sub GenerateHeaders +{ + my $EXTRACT = $ENV{"INTLTOOL_EXTRACT"} || "intltool-extract"; + + ## Generate the .h header files, so we can allow glade and + ## xml translation support + if (! isProgramInPath ("$EXTRACT")) + { + print STDERR "\n *** The intltool-extract script wasn't found!" + ."\n *** Without it, intltool-update can not generate files.\n"; + exit; + } + else + { + open (FILE, $POTFILES_in) or die "$PROGRAM: POTFILES.in not found.\n"; + + while () + { + chomp; + next if /^\[\s*encoding/; + + ## Find xml files in POTFILES.in and generate the + ## files with help from the extract script + + my $gettext_type= &POFile_DetermineType ($1); + + if (/\.($xml_support|$ini_support|$tlk_support)$/ || /^\[/) + { + s/^\[[^\[].*]\s*//; + + my @cmd = ($EXTRACT, "--update", "--type=$gettext_type", + "--srcdir=$SRCDIR"); + + unshift (@cmd, $^X) if ($^O eq 'MSWin32' && !($EXTRACT =~ /perl/)); + + push (@cmd, "--quiet") if (! $VERBOSE); + push (@cmd, "../$_"); + + system (@cmd); + } + } + close FILE; + } +} + +# +# Generate .pot file from POTFILES.in +# +sub GeneratePOTemplate +{ + my $XGETTEXT = $ENV{"XGETTEXT"} || "xgettext"; + my $XGETTEXT_ARGS = $ENV{"XGETTEXT_ARGS"} || ''; + chomp $XGETTEXT; + + if (! isGNUGettextTool ("$XGETTEXT")) + { + print STDERR " *** GNU xgettext is not found on this system!\n". + " *** Without it, intltool-update can not extract strings.\n"; + exit; + } + + print "Building $MODULE.pot...\n" if $VERBOSE; + + open INFILE, $POTFILES_in; + unlink "POTFILES.in.temp"; + open OUTFILE, ">POTFILES.in.temp" or die("Cannot open POTFILES.in.temp for writing"); + + my $gettext_support_nonascii = 0; + + # checks for GNU gettext >= 0.12 + my $dummy = `$XGETTEXT --version --from-code=UTF-8 >$devnull 2>$devnull`; + if ($? == 0) + { + $gettext_support_nonascii = 1; + } + else + { + # require gnu gettext >= 0.12 + die "$PROGRAM: GNU gettext >= 0.12 is required for intltool\n"; + } + + my $encoding = "UTF-8"; + my $forced_gettext_code; + my @temp_headers; + my $encoding_problem_is_reported = 0; + + while () + { + next if (/^#/ or /^\s*$/); + + chomp; + + my $gettext_code; + + if (/^\[\s*encoding:\s*(.*)\s*\]/) + { + $forced_gettext_code=$1; + } + elsif (/\.($xml_support|$ini_support|$tlk_support)$/ || /^\[/) + { + s/^\[.*]\s*//; + print OUTFILE "../$_.h\n"; + push @temp_headers, "../$_.h"; + $gettext_code = &TextFile_DetermineEncoding ("../$_.h") if ($gettext_support_nonascii and not defined $forced_gettext_code); + } + else + { + print OUTFILE "../$_\n"; + $gettext_code = &TextFile_DetermineEncoding ("$SRCDIR/../$_") if ($gettext_support_nonascii and not defined $forced_gettext_code); + } + + next if (! $gettext_support_nonascii); + + if (defined $forced_gettext_code) + { + $encoding=$forced_gettext_code; + } + elsif (defined $gettext_code and "$encoding" ne "$gettext_code") + { + if ($encoding eq "ASCII") + { + $encoding=$gettext_code; + } + elsif ($gettext_code ne "ASCII") + { + # Only report once because the message is quite long + if (! $encoding_problem_is_reported) + { + print STDERR "WARNING: You should use the same file encoding for all your project files,\n". + " but $PROGRAM thinks that most of the source files are in\n". + " $encoding encoding, while \"$_\" is (likely) in\n". + " $gettext_code encoding. If you are sure that all translatable strings\n". + " are in same encoding (say UTF-8), please *prepend* the following\n". + " line to POTFILES.in:\n\n". + " [encoding: UTF-8]\n\n". + " and make sure that configure.in/ac checks for $PACKAGE >= 0.27 .\n". + "(such warning message will only be reported once.)\n"; + $encoding_problem_is_reported = 1; + } + } + } + } + + close OUTFILE; + close INFILE; + + unlink "$MODULE.pot"; + my @xgettext_argument=("$XGETTEXT", + "--add-comments", + "--directory\=.", + "--directory\=$SRCDIR", + "--default-domain\=$MODULE", + "--flag\=g_strdup_printf:1:c-format", + "--flag\=g_string_printf:2:c-format", + "--flag\=g_string_append_printf:2:c-format", + "--flag\=g_error_new:3:c-format", + "--flag\=g_set_error:4:c-format", + "--flag\=g_markup_printf_escaped:1:c-format", + "--flag\=g_log:3:c-format", + "--flag\=g_print:1:c-format", + "--flag\=g_printerr:1:c-format", + "--flag\=g_printf:1:c-format", + "--flag\=g_fprintf:2:c-format", + "--flag\=g_sprintf:2:c-format", + "--flag\=g_snprintf:3:c-format", + "--flag\=g_scanner_error:2:c-format", + "--flag\=g_scanner_warn:2:c-format", + "--output\=$MODULE\.pot", + "--files-from\=\.\/POTFILES\.in\.temp"); + my $XGETTEXT_KEYWORDS = &FindPOTKeywords; + push @xgettext_argument, $XGETTEXT_KEYWORDS; + my $MSGID_BUGS_ADDRESS = &FindMakevarsBugAddress; + push @xgettext_argument, "--msgid-bugs-address\=\"$MSGID_BUGS_ADDRESS\"" if $MSGID_BUGS_ADDRESS; + push @xgettext_argument, "--from-code\=$encoding" if ($gettext_support_nonascii); + push @xgettext_argument, $XGETTEXT_ARGS if $XGETTEXT_ARGS; + my $xgettext_command = join ' ', @xgettext_argument; + + # intercept xgettext error message + print "Running $xgettext_command\n" if $VERBOSE; + my $xgettext_error_msg = `$xgettext_command 2>\&1`; + my $command_failed = $?; + + unlink "POTFILES.in.temp"; + + print "Removing generated header (.h) files..." if $VERBOSE; + unlink foreach (@temp_headers); + print "done.\n" if $VERBOSE; + + if (! $command_failed) + { + if (! -e "$MODULE.pot") + { + print "None of the files in POTFILES.in contain strings marked for translation.\n" if $VERBOSE; + } + else + { + print "Wrote $MODULE.pot\n" if $VERBOSE; + } + } + else + { + if ($xgettext_error_msg =~ /--from-code/) + { + my $errlocation = "unknown"; + + if ($xgettext_error_msg =~ /Non-ASCII string at (.*)\..*/) + { + $errlocation = $1; + } + print STDERR "ERROR: xgettext failed to generate PO tempalte file because the following \n". + " file contains strings marked for translation, not encoded in UTF-8. \n". + " Please ensure all strings marked for translation are UTF-8 encoded. \n\n". + " $errlocation\n\n"; + } + else + { + print STDERR "$xgettext_error_msg"; + if (-e "$MODULE.pot") + { + # is this possible? + print STDERR "ERROR: xgettext failed but still managed to generate PO template file.\n". + " Please consult error message above if there is any.\n"; + } + else + { + print STDERR "ERROR: xgettext failed to generate PO template file. Please consult\n". + " error message above if there is any.\n"; + } + } + exit (1); + } +} + +sub POFile_Update +{ + -f "$MODULE.pot" or die "$PROGRAM: $MODULE.pot does not exist.\n"; + + my $MSGMERGE = $ENV{"MSGMERGE"} || "msgmerge"; + my ($lang, $outfile) = @_; + + if (! isGNUGettextTool ("$MSGMERGE")) + { + print STDERR " *** GNU msgmerge is not found on this system!\n". + " *** Without it, intltool-update can not extract strings.\n"; + exit; + } + + print "Merging $SRCDIR/$lang.po with $MODULE.pot..." if $VERBOSE; + + my $infile = "$SRCDIR/$lang.po"; + $outfile = "$SRCDIR/$lang.po" if ($outfile eq ""); + + # I think msgmerge won't overwrite old file if merge is not successful + system ("$MSGMERGE", "-o", $outfile, $infile, "$MODULE.pot"); +} + +sub Console_WriteError_NotExisting +{ + my ($file) = @_; + + ## Report error if supplied language file is non-existing + print STDERR "$PROGRAM: $file does not exist!\n"; + print STDERR "Try '$PROGRAM --help' for more information.\n"; + exit; +} + +sub GatherPOFiles +{ + my @po_files = glob ("./*.po"); + + @languages = map (&POFile_GetLanguage, @po_files); + + foreach my $lang (@languages) + { + $po_files_by_lang{$lang} = shift (@po_files); + } +} + +sub POFile_GetLanguage ($) +{ + s/^(.*\/)?(.+)\.po$/$2/; + return $_; +} + +sub Console_Write_TranslationStatus +{ + my ($lang, $output_file) = @_; + my $MSGFMT = $ENV{"MSGFMT"} || "msgfmt"; + + if (! isGNUGettextTool ("$MSGFMT")) + { + print STDERR " *** GNU msgfmt is not found on this system!\n". + " *** Without it, intltool-update can not extract strings.\n"; + exit; + } + + $output_file = "$SRCDIR/$lang.po" if ($output_file eq ""); + + system ("$MSGFMT", "-o", "$devnull", "--verbose", $output_file); +} + +sub Console_Write_CoverageReport +{ + my $MSGFMT = $ENV{"MSGFMT"} || "msgfmt"; + + if (! isGNUGettextTool ("$MSGFMT")) + { + print STDERR " *** GNU msgfmt is not found on this system!\n". + " *** Without it, intltool-update can not extract strings.\n"; + exit; + } + + &GatherPOFiles; + + foreach my $lang (@languages) + { + print STDERR "$lang: "; + &POFile_Update ($lang, ""); + } + + print STDERR "\n\n * Current translation support in $MODULE \n\n"; + + foreach my $lang (@languages) + { + print STDERR "$lang: "; + system ("$MSGFMT", "-o", "$devnull", "--verbose", "$SRCDIR/$lang.po"); + } +} + +sub SubstituteVariable +{ + my ($str) = @_; + + # always need to rewind file whenever it has been accessed + seek (CONF, 0, 0); + + # cache each variable. varhash is global to we can add + # variables elsewhere. + while () + { + if (/^(\w+)=(.*)$/) + { + ($varhash{$1} = $2) =~ s/^["'](.*)["']$/$1/; + } + } + + if ($str =~ /^(.*)\${?([A-Z_]+)}?(.*)$/) + { + my $rest = $3; + my $untouched = $1; + my $sub = ""; + # Ignore recursive definitions of variables + $sub = $varhash{$2} if defined $varhash{$2} and $varhash{$2} !~ /\${?$2}?/; + + return SubstituteVariable ("$untouched$sub$rest"); + } + + # We're using Perl backticks ` and "echo -n" here in order to + # expand any shell escapes (such as backticks themselves) in every variable + return echo_n ($str); +} + +sub CONF_Handle_Open +{ + my $base_dirname = getcwd(); + $base_dirname =~ s@.*/@@; + + my ($conf_in, $src_dir); + + if ($base_dirname =~ /^po(-.+)?$/) + { + if (-f "Makevars") + { + my $makefile_source; + + local (*IN); + open (IN, ") + { + if (/^top_builddir[ \t]*=/) + { + $src_dir = $_; + $src_dir =~ s/^top_builddir[ \t]*=[ \t]*([^ \t\n\r]*)/$1/; + + chomp $src_dir; + if (-f "$src_dir" . "/configure.ac") { + $conf_in = "$src_dir" . "/configure.ac" . "\n"; + } else { + $conf_in = "$src_dir" . "/configure.in" . "\n"; + } + last; + } + } + close IN; + + $conf_in || die "Cannot find top_builddir in Makevars."; + } + elsif (-f "$SRCDIR/../configure.ac") + { + $conf_in = "$SRCDIR/../configure.ac"; + } + elsif (-f "$SRCDIR/../configure.in") + { + $conf_in = "$SRCDIR/../configure.in"; + } + else + { + my $makefile_source; + + local (*IN); + open (IN, ") + { + if (/^top_srcdir[ \t]*=/) + { + $src_dir = $_; + $src_dir =~ s/^top_srcdir[ \t]*=[ \t]*([^ \t\n\r]*)/$1/; + + chomp $src_dir; + $conf_in = "$src_dir" . "/configure.in" . "\n"; + + last; + } + } + close IN; + + $conf_in || die "Cannot find top_srcdir in Makefile."; + } + + open (CONF, "<$conf_in"); + } + else + { + print STDERR "$PROGRAM: Unable to proceed.\n" . + "Make sure to run this script inside the po directory.\n"; + exit; + } +} + +sub FindPackageName +{ + my $version; + my $domain = &FindMakevarsDomain; + my $name = $domain || "untitled"; + my $bugurl; + + &CONF_Handle_Open; + + my $conf_source; { + local (*IN); + open (IN, "<&CONF") || return $name; + seek (IN, 0, 0); + local $/; # slurp mode + $conf_source = ; + close IN; + } + + # priority for getting package name: + # 1. GETTEXT_PACKAGE + # 2. first argument of AC_INIT (with >= 2 arguments) + # 3. first argument of AM_INIT_AUTOMAKE (with >= 2 argument) + + # /^AM_INIT_AUTOMAKE\([\s\[]*([^,\)\s\]]+)/m + # the \s makes this not work, why? + if ($conf_source =~ /^AM_INIT_AUTOMAKE\(([^,\)]+),([^,\)]+)/m) + { + ($name, $version) = ($1, $2); + $name =~ s/[\[\]\s]//g; + $version =~ s/[\[\]\s]//g; + $name =~ s/\(+$//g; + $version =~ s/\(+$//g; + + $varhash{"PACKAGE_NAME"} = $name if (not $name =~ /\${?AC_PACKAGE_NAME}?/); + $varhash{"PACKAGE"} = $name if (not $name =~ /\${?PACKAGE}?/); + $varhash{"PACKAGE_VERSION"} = $version if (not $name =~ /\${?AC_PACKAGE_VERSION}?/); + $varhash{"VERSION"} = $version if (not $name =~ /\${?VERSION}?/); + } + + if ($conf_source =~ /^AC_INIT\(([^,\)]+),([^,\)]+)[,]?([^,\)]+)?/m) + { + ($name, $version) = ($1, $2); + $bugurl = $3 if (defined $3); + + # Handle m4_esyscmd + # FIXME: We should do this in a more generic way that works for all vars + if ($version =~ /m4_esyscmd\([\[]?([^\)\]]+)/) + { + my $cwd = getcwd (); + chdir ("$SRCDIR/.."); + $version = qx($1); + chdir ($cwd); + } + + + $name =~ s/[\[\]\s]//g; + $version =~ s/[\[\]\s]//g; + $bugurl =~ s/[\[\]\s]//g if (defined $bugurl); + $name =~ s/\(+$//g; + $version =~ s/\(+$//g; + $bugurl =~ s/\(+$//g if (defined $bugurl); + + $varhash{"PACKAGE_NAME"} = $name if (not $name =~ /\${?AC_PACKAGE_NAME}?/); + $varhash{"PACKAGE"} = $name if (not $name =~ /\${?PACKAGE}?/); + $varhash{"PACKAGE_VERSION"} = $version if (not $name =~ /\${?AC_PACKAGE_VERSION}?/); + $varhash{"VERSION"} = $version if (not $name =~ /\${?VERSION}?/); + $varhash{"PACKAGE_BUGREPORT"} = $bugurl if (defined $bugurl and not $bugurl =~ /\${?\w+}?/); + } + + # \s makes this not work, why? + $name = $1 if $conf_source =~ /^GETTEXT_PACKAGE=\[?([^\n\]]+)/m; + + # m4 macros AC_PACKAGE_NAME, AC_PACKAGE_VERSION etc. have same value + # as corresponding $PACKAGE_NAME, $PACKAGE_VERSION etc. shell variables. + $name =~ s/\bAC_PACKAGE_/\$PACKAGE_/g; + + $name = $domain if $domain; + + $name = SubstituteVariable ($name); + $name =~ s/^["'](.*)["']$/$1/; + + return $name if $name; +} + + +sub FindPOTKeywords +{ + + my $keywords = "--keyword=_ --keyword=N_ --keyword=C_:1c,2 --keyword=NC_:1c,2 --keyword=Q_ --keyword=g_dgettext:2 --keyword=g_dngettext:2,3 --keyword=g_dpgettext:2 --keyword=g_dpgettext2=2c,3"; + my $varname = "XGETTEXT_OPTIONS"; + my $make_source; { + local (*IN); + open (IN, "; + close IN; + } + + # unwrap lines split with a trailing \ + $make_source =~ s/\\ $ \n/ /mxg; + $keywords = $1 if $make_source =~ /^$varname[ ]*=\[?([^\n\]]+)/m; + + return $keywords; +} + +sub FindMakevarsDomain +{ + + my $domain = ""; + my $makevars_source; { + local (*IN); + open (IN, "; + close IN; + } + + $domain = $1 if $makevars_source =~ /^DOMAIN[ ]*=\[?([^\n\]\$]+)/m; + $domain =~ s/^\s+//; + $domain =~ s/\s+$//; + + return $domain; +} + +sub FindMakevarsBugAddress +{ + + my $address = ""; + my $makevars_source; { + local (*IN); + open (IN, "; + close IN; + } + + $address = $1 if $makevars_source =~ /^MSGID_BUGS_ADDRESS[ ]*=\[?([^\n\]\$]+)/m; + $address =~ s/^\s+//; + $address =~ s/\s+$//; + + return $address; +} diff --git a/.flatpak-builder/cache/objects/77/943df6409185c35572ea3bbaf89ad52817f45d6fb4a8dab7f0077cc4bd64f5.dirtree b/.flatpak-builder/cache/objects/77/943df6409185c35572ea3bbaf89ad52817f45d6fb4a8dab7f0077cc4bd64f5.dirtree new file mode 100644 index 0000000..4222733 Binary files /dev/null and b/.flatpak-builder/cache/objects/77/943df6409185c35572ea3bbaf89ad52817f45d6fb4a8dab7f0077cc4bd64f5.dirtree differ diff --git a/.flatpak-builder/cache/objects/78/0a35fb7f13ff1772a0c9c2fde120acad9afa60b0dffbf9ae7995a935a2a80c.dirtree b/.flatpak-builder/cache/objects/78/0a35fb7f13ff1772a0c9c2fde120acad9afa60b0dffbf9ae7995a935a2a80c.dirtree new file mode 100644 index 0000000..b76b024 Binary files /dev/null and b/.flatpak-builder/cache/objects/78/0a35fb7f13ff1772a0c9c2fde120acad9afa60b0dffbf9ae7995a935a2a80c.dirtree differ diff --git a/.flatpak-builder/cache/objects/78/466efd1f4aaf232bb22633fcdaf2d24bb39f8e28fc85c3e84ac208d918b51f.dirtree b/.flatpak-builder/cache/objects/78/466efd1f4aaf232bb22633fcdaf2d24bb39f8e28fc85c3e84ac208d918b51f.dirtree new file mode 100644 index 0000000..83c7926 Binary files /dev/null and b/.flatpak-builder/cache/objects/78/466efd1f4aaf232bb22633fcdaf2d24bb39f8e28fc85c3e84ac208d918b51f.dirtree differ diff --git a/.flatpak-builder/cache/objects/78/720a6d2dcf19cd64fb32ada7de6ffb862566f3665823ab8fb1af51e19f6ea2.dirtree b/.flatpak-builder/cache/objects/78/720a6d2dcf19cd64fb32ada7de6ffb862566f3665823ab8fb1af51e19f6ea2.dirtree new file mode 100644 index 0000000..7e06dfe Binary files /dev/null and b/.flatpak-builder/cache/objects/78/720a6d2dcf19cd64fb32ada7de6ffb862566f3665823ab8fb1af51e19f6ea2.dirtree differ diff --git a/.flatpak-builder/cache/objects/78/e4cbdc9004900eb6d2cc7cbd6c422fe58688dca44afb05d9256b88aad2b0a1.file b/.flatpak-builder/cache/objects/78/e4cbdc9004900eb6d2cc7cbd6c422fe58688dca44afb05d9256b88aad2b0a1.file new file mode 100644 index 0000000..00ca8cf --- /dev/null +++ b/.flatpak-builder/cache/objects/78/e4cbdc9004900eb6d2cc7cbd6c422fe58688dca44afb05d9256b88aad2b0a1.file @@ -0,0 +1,371 @@ +/* + * Copyright (C) 2009 - 2013 Vivien Malerba + * Copyright (C) 2010 David King + * Copyright (C) 2018 Daniel Espinosa + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +#define G_LOG_DOMAIN "GDA-tree-mgr-tables" + +#include +#include +#include +#include "gda-tree-mgr-tables.h" +#include "gda-tree-node.h" + +typedef struct { + GdaConnection *cnc; + GdaMetaStore *mstore; + gchar *schema; /* imposed upon construction */ + + GdaStatement *stmt_with_schema; + GdaStatement *stmt_all_visible; + GdaSet *params; +} GdaTreeMgrTablesPrivate; + +G_DEFINE_TYPE_WITH_PRIVATE (GdaTreeMgrTables, gda_tree_mgr_tables, GDA_TYPE_TREE_MANAGER) + +static void gda_tree_mgr_tables_dispose (GObject *object); +static void gda_tree_mgr_tables_set_property (GObject *object, + guint param_id, + const GValue *value, + GParamSpec *pspec); +static void gda_tree_mgr_tables_get_property (GObject *object, + guint param_id, + GValue *value, + GParamSpec *pspec); + +/* virtual methods */ +static GSList *gda_tree_mgr_tables_update_children (GdaTreeManager *manager, GdaTreeNode *node, const GSList *children_nodes, + gboolean *out_error, GError **error); + +/* properties */ +enum { + PROP_0, + PROP_CNC, + PROP_SCHEMA, + PROP_META_STORE +}; + +/* + * GdaTreeMgrTables class implementation + * @klass: + */ +static void +gda_tree_mgr_tables_class_init (GdaTreeMgrTablesClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + /* virtual methods */ + ((GdaTreeManagerClass*) klass)->update_children = gda_tree_mgr_tables_update_children; + + /* Properties */ + object_class->set_property = gda_tree_mgr_tables_set_property; + object_class->get_property = gda_tree_mgr_tables_get_property; + + /** + * GdaTreeMgrTables:connection: + * + * Defines the #GdaConnection to display information for. Necessary upon construction unless + * the #GdaTreeMgrTables:meta-store property is specified instead. + */ + g_object_class_install_property (object_class, PROP_CNC, + g_param_spec_object ("connection", NULL, "Connection to use", + GDA_TYPE_CONNECTION, + G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)); + + /** + * GdaTreeMgrTables:meta-store: + * + * Defines the #GdaMetaStore to extract information from. Necessary upon construction unless + * the #GdaTreeMgrTables:connection property is specified instead. This property has + * priority over the GdaTreeMgrTables:connection property. + * + * Since: 4.2.4 + */ + g_object_class_install_property (object_class, PROP_META_STORE, + g_param_spec_object ("meta-store", NULL, "GdaMetaStore to use", + GDA_TYPE_META_STORE, + G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)); + + /** + * GdaTreeMgrTables:schema: + * + * If no set, then the table name will be fetched from the parent node using the "schema" attribute. If not + * found that way, then the list of visible tables (tables which can be identified without having to specify + * a schema) will be used + */ + g_object_class_install_property (object_class, PROP_SCHEMA, + g_param_spec_string ("schema", NULL, + "Database schema to get the tables list from", + NULL, G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)); + + object_class->dispose = gda_tree_mgr_tables_dispose; +} + +static void +gda_tree_mgr_tables_init (GdaTreeMgrTables *mgr) {} + +static void +gda_tree_mgr_tables_dispose (GObject *object) +{ + GdaTreeMgrTables *mgr = (GdaTreeMgrTables *) object; + + g_return_if_fail (GDA_IS_TREE_MGR_TABLES (mgr)); + GdaTreeMgrTablesPrivate *priv = gda_tree_mgr_tables_get_instance_private (mgr); + + if (priv->cnc) { + g_object_unref (priv->cnc); + priv->cnc = NULL; + } + if (priv->mstore) { + g_object_unref (priv->mstore); + priv->mstore = NULL; + } + g_free (priv->schema); + + if (priv->stmt_with_schema) { + g_object_unref (priv->stmt_with_schema); + priv->stmt_with_schema = NULL; + } + if (priv->stmt_all_visible) { + g_object_unref (priv->stmt_all_visible); + priv->stmt_all_visible = NULL; + } + if (priv->params) { + g_object_unref (priv->params); + priv->params = NULL; + } + + + /* chain to parent class */ + G_OBJECT_CLASS (gda_tree_mgr_tables_parent_class)->dispose (object); +} + + +static void +gda_tree_mgr_tables_set_property (GObject *object, + guint param_id, + const GValue *value, + GParamSpec *pspec) +{ + GdaTreeMgrTables *mgr; + + mgr = GDA_TREE_MGR_TABLES (object); + GdaTreeMgrTablesPrivate *priv = gda_tree_mgr_tables_get_instance_private (mgr); + switch (param_id) { + case PROP_CNC: + priv->cnc = (GdaConnection*) g_value_get_object (value); + if (priv->cnc) + g_object_ref (priv->cnc); + break; + case PROP_META_STORE: + priv->mstore = (GdaMetaStore*) g_value_get_object (value); + if (priv->mstore) + g_object_ref (priv->mstore); + break; + case PROP_SCHEMA: + priv->schema = g_value_dup_string (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + break; + } +} + +static void +gda_tree_mgr_tables_get_property (GObject *object, + guint param_id, + GValue *value, + GParamSpec *pspec) +{ + GdaTreeMgrTables *mgr; + + mgr = GDA_TREE_MGR_TABLES (object); + GdaTreeMgrTablesPrivate *priv = gda_tree_mgr_tables_get_instance_private (mgr); + switch (param_id) { + case PROP_CNC: + g_value_set_object (value, priv->cnc); + break; + case PROP_META_STORE: + g_value_set_object (value, priv->mstore); + break; + case PROP_SCHEMA: + g_value_set_string (value, priv->schema); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + break; + } +} + +/** + * gda_tree_mgr_tables_new: + * @cnc: a #GdaConnection object + * @schema: (nullable): a schema name or %NULL + * + * Creates a new #GdaTreeManager object which will add one tree node for each table found in the + * @schema if it is not %NULL, or for each table visible by default in @cnc. + * + * Returns: (transfer full): a new #GdaTreeManager object + * + * Since: 4.2 + */ +GdaTreeManager* +gda_tree_mgr_tables_new (GdaConnection *cnc, const gchar *schema) +{ + GdaTreeMgrTables *mgr; + g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL); + + mgr = (GdaTreeMgrTables*) g_object_new (GDA_TYPE_TREE_MGR_TABLES, + "connection", cnc, + "schema", schema, NULL); + return (GdaTreeManager*) mgr; +} + +static GSList * +gda_tree_mgr_tables_update_children (GdaTreeManager *manager, GdaTreeNode *node, + G_GNUC_UNUSED const GSList *children_nodes, gboolean *out_error, + GError **error) +{ + GdaTreeMgrTables *mgr = GDA_TREE_MGR_TABLES (manager); + GdaMetaStore *store; + GdaDataModel *model; + GSList *list = NULL; + GdaConnection *scnc; + GdaTreeMgrTablesPrivate *priv = gda_tree_mgr_tables_get_instance_private (mgr); + + if (!priv->cnc && !priv->mstore) { + g_set_error (error, GDA_TREE_MANAGER_ERROR, GDA_TREE_MANAGER_UNKNOWN_ERROR, + "%s", _("No connection and no GdaMetaStore specified")); + if (out_error) + *out_error = TRUE; + return NULL; + } + else if (priv->mstore) + store = priv->mstore; + else + store = gda_connection_get_meta_store (priv->cnc); + + scnc = gda_meta_store_get_internal_connection (store); + + /* create statements if necessary */ + if (!priv->stmt_with_schema) { + GdaSqlParser *parser; + GdaStatement *stmt1, *stmt2; + + parser = gda_connection_create_parser (scnc); + if (! parser) + parser = gda_sql_parser_new (); + + stmt1 = gda_sql_parser_parse_string (parser, + "SELECT table_name, table_schema FROM " + "_tables WHERE " + "table_type LIKE '%TABLE%' AND " + "table_schema = ##schema::string " + "ORDER BY table_name DESC", NULL, error); + + stmt2 = gda_sql_parser_parse_string (parser, + "SELECT table_short_name, table_schema " + "FROM _tables WHERE " + "table_type LIKE '%TABLE%' AND " + "table_short_name != table_full_name " + "ORDER BY table_short_name DESC", NULL, error); + g_object_unref (parser); + if (!stmt1 || !stmt2) { + if (out_error) + *out_error = TRUE; + if (stmt1) g_object_unref (stmt1); + if (stmt2) g_object_unref (stmt2); + return NULL; + } + + if (!gda_statement_get_parameters (stmt1, &(priv->params), error)) { + if (out_error) + *out_error = TRUE; + g_object_unref (stmt1); + g_object_unref (stmt2); + return NULL; + } + priv->stmt_with_schema = stmt1; + priv->stmt_all_visible = stmt2; + } + + gboolean schema_specified = FALSE; + gboolean schema_from_parent = FALSE; + if (priv->schema) { + schema_specified = TRUE; + g_assert (gda_set_set_holder_value (priv->params, NULL, "schema", priv->schema)); + } + else if (node) { + /* looking for a schema in @node's attributes */ + const GValue *cvalue; + cvalue = gda_tree_node_fetch_attribute (node, "schema"); + if (cvalue) { + GdaHolder *h = gda_set_get_holder (priv->params, "schema"); + if (!gda_holder_set_value (h, cvalue, error)) { + if (out_error) + *out_error = TRUE; + return NULL; + } + schema_specified = TRUE; + schema_from_parent = TRUE; + } + } + if (schema_specified) + model = gda_connection_statement_execute_select (scnc, priv->stmt_with_schema, + priv->params, error); + else + model = gda_connection_statement_execute_select (scnc, priv->stmt_all_visible, + NULL, error); + + if (!model) { + if (out_error) + *out_error = TRUE; + return NULL; + } + + GdaDataModelIter *iter; + iter = gda_data_model_create_iter (model); + for (; iter && gda_data_model_iter_move_next (iter);) { + GdaTreeNode* snode; + const GValue *cvalue, *cvalue2; + + cvalue = gda_data_model_iter_get_value_at (iter, 0); + cvalue2 = gda_data_model_iter_get_value_at (iter, 1); + if (!cvalue || !cvalue2) { + if (list) { + g_slist_free_full (list, (GDestroyNotify) g_object_unref); + } + if (out_error) + *out_error = TRUE; + g_set_error (error, GDA_TREE_MANAGER_ERROR, GDA_TREE_MANAGER_UNKNOWN_ERROR, + "%s", _("Unable to get table name")); + return NULL; + } + + snode = gda_tree_manager_create_node (manager, node, g_value_get_string (cvalue)); + gda_tree_node_set_node_attribute (snode, "table_name", cvalue, NULL); + if (!schema_from_parent) + gda_tree_node_set_node_attribute (snode, "schema", cvalue2, NULL); + list = g_slist_prepend (list, snode); + } + if (iter) + g_object_unref (iter); + g_object_unref (model); + + return list; +} diff --git a/.flatpak-builder/cache/objects/79/00bb2a7cb2f65645d0f86f41d6d7dcfafdd752b7b1bf8ff5fe05537cff3459.file b/.flatpak-builder/cache/objects/79/00bb2a7cb2f65645d0f86f41d6d7dcfafdd752b7b1bf8ff5fe05537cff3459.file new file mode 120000 index 0000000..a4d4dd5 --- /dev/null +++ b/.flatpak-builder/cache/objects/79/00bb2a7cb2f65645d0f86f41d6d7dcfafdd752b7b1bf8ff5fe05537cff3459.file @@ -0,0 +1 @@ +../../share/runtime/locale/ga/share/ga \ No newline at end of file diff --git a/.flatpak-builder/cache/objects/79/0ac063325e7b4a530293a2ce57fe53234591e684cd59f272f5d980d6e25a07.dirtree b/.flatpak-builder/cache/objects/79/0ac063325e7b4a530293a2ce57fe53234591e684cd59f272f5d980d6e25a07.dirtree new file mode 100644 index 0000000..8568763 Binary files /dev/null and b/.flatpak-builder/cache/objects/79/0ac063325e7b4a530293a2ce57fe53234591e684cd59f272f5d980d6e25a07.dirtree differ diff --git a/.flatpak-builder/cache/objects/79/14efe36ca083b630d081e6705fb0594a4da1624179a3c45cf757ff68a2fba6.dirtree b/.flatpak-builder/cache/objects/79/14efe36ca083b630d081e6705fb0594a4da1624179a3c45cf757ff68a2fba6.dirtree new file mode 100644 index 0000000..1abc84e Binary files /dev/null and b/.flatpak-builder/cache/objects/79/14efe36ca083b630d081e6705fb0594a4da1624179a3c45cf757ff68a2fba6.dirtree differ diff --git a/.flatpak-builder/cache/objects/79/5e3631f68c53d299deee8a2f29d165c78d42450aff80a2f6584eaa9d9a15c7.file b/.flatpak-builder/cache/objects/79/5e3631f68c53d299deee8a2f29d165c78d42450aff80a2f6584eaa9d9a15c7.file new file mode 100644 index 0000000..3c6617b --- /dev/null +++ b/.flatpak-builder/cache/objects/79/5e3631f68c53d299deee8a2f29d165c78d42450aff80a2f6584eaa9d9a15c7.file @@ -0,0 +1,40 @@ + + + +%array-dtd; + + + + + + + + + + + + + + + diff --git a/.flatpak-builder/cache/objects/79/85492060b0fdd4e5f7dc7dd1819d37300a19083fd2dc1ac1e1ea6b8af7fda7.file b/.flatpak-builder/cache/objects/79/85492060b0fdd4e5f7dc7dd1819d37300a19083fd2dc1ac1e1ea6b8af7fda7.file new file mode 100644 index 0000000..79d1e20 --- /dev/null +++ b/.flatpak-builder/cache/objects/79/85492060b0fdd4e5f7dc7dd1819d37300a19083fd2dc1ac1e1ea6b8af7fda7.file @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2006 - 2011 Vivien Malerba + * Copyright (C) 2007 Murray Cumming + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GDA_HANDLER_TYPE__ +#define __GDA_HANDLER_TYPE__ + +#include +#include + +G_BEGIN_DECLS + +#define GDA_TYPE_HANDLER_TYPE (gda_handler_type_get_type()) +G_DECLARE_FINAL_TYPE (GdaHandlerType, gda_handler_type, GDA, HANDLER_TYPE, GObject) + +/** + * SECTION:gda-handler-type + * @short_description: Default handler for GType values + * @title: GdaHanderType + * @stability: Stable + * @see_also: #GdaDataHandler interface + * + * You should normally not need to use this API, refer to the #GdaDataHandler + * interface documentation for more information. + */ + +GdaDataHandler *gda_handler_type_new (void); + +G_END_DECLS + +#endif diff --git a/.flatpak-builder/cache/objects/79/dc4fcc870141ac2cc8ecf72baf66cebfdd17e522be74b2231e14563f7bb7aa.dirtree b/.flatpak-builder/cache/objects/79/dc4fcc870141ac2cc8ecf72baf66cebfdd17e522be74b2231e14563f7bb7aa.dirtree new file mode 100644 index 0000000..dfde508 Binary files /dev/null and b/.flatpak-builder/cache/objects/79/dc4fcc870141ac2cc8ecf72baf66cebfdd17e522be74b2231e14563f7bb7aa.dirtree differ diff --git a/.flatpak-builder/cache/objects/79/f8fa040a45e9ef8b085076fb41fb7c7258beed6d76c4e82b04ace1c840980f.file b/.flatpak-builder/cache/objects/79/f8fa040a45e9ef8b085076fb41fb7c7258beed6d76c4e82b04ace1c840980f.file new file mode 100644 index 0000000..9e25b86 --- /dev/null +++ b/.flatpak-builder/cache/objects/79/f8fa040a45e9ef8b085076fb41fb7c7258beed6d76c4e82b04ace1c840980f.file @@ -0,0 +1,144 @@ +/* + * Copyright (C) 2006 - 2007 Murray Cumming + * Copyright (C) 2006 - 2012 Vivien Malerba + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + + +#ifndef __GDA_DATA_MODEL_ITER_H_ +#define __GDA_DATA_MODEL_ITER_H_ + +#include "gda-decl.h" +#include "gda-set.h" + +G_BEGIN_DECLS + +#define GDA_TYPE_DATA_MODEL_ITER (gda_data_model_iter_get_type()) + +G_DECLARE_DERIVABLE_TYPE(GdaDataModelIter, gda_data_model_iter, GDA, DATA_MODEL_ITER, GdaSet) + +/* struct for the object's class */ +struct _GdaDataModelIterClass +{ + GdaSetClass parent_class; + + /* Virtual methods */ + gboolean (* move_to_row) (GdaDataModelIter *iter, gint row); + gboolean (* move_next) (GdaDataModelIter *iter); + gboolean (* move_prev) (GdaDataModelIter *iter); + gboolean (* set_value_at) (GdaDataModelIter *iter, gint col, + const GValue *value, GError **error); + + /* Signals */ + void (* row_changed) (GdaDataModelIter *iter, gint row); + void (* end_of_data) (GdaDataModelIter *iter); + + /*< private >*/ + /* Padding for future expansion */ + gpointer padding[12]; +}; + +/* error reporting */ +extern GQuark gda_data_model_iter_error_quark (void); +#define GDA_DATA_MODEL_ITER_ERROR gda_data_model_iter_error_quark () + +typedef enum +{ + GDA_DATA_MODEL_ITER_COLUMN_OUT_OF_RANGE_ERROR +} GdaDataModelIterError; + + +/** + * SECTION:gda-data-model-iter + * @short_description: Data model iterator + * @title: GdaDataModelIter + * @stability: Stable + * @see_also: #GdaDataModel + * + * A #GdaDataModelIter object is used to iterate through the rows of a #GdaDataModel. If the data model is accessible + * in a random access way then any number of #GdaDataModelIter objects can be created on the same data model, and + * if the data model only supports a cursor based access then only one #GdaDataModelIter can be created. In any case + * creating a #GdaDataModelIter should be done using the gda_data_model_create_iter() method. Note that if + * the data model only supports a cursor based access, then calling this method several times will always return + * the same #GdaDataModelIter, but with its reference count increased by 1 (so you should call g_object_unref() when + * finished with it). + * + * When a #GdaDataModelIter is valid (that is when it points to an existing row in the data model it iterates through), + * the individual values (corresponding to each column of the data model, at the pointer row) can be accessed + * using the gda_data_model_iter_get_value_at() or gda_data_model_iter_get_value_for_field() methods + * (or in the same way #GdaSet's values are accessed as #GdaDataModelIter inherits the #GdaSet). + * + * Right after being created, a #GdaDataModelIter is invalid (does not point to any row of its data model). To read the + * first row of the data model, use the gda_data_model_iter_move_next() method. Calling this method several times will + * move the iterator forward, up to when the data model has no more rows and the #GdaDataModelIter will be declared invalid + * (and gda_data_model_iter_move_next() has returned FALSE). Note that at this point, the number of rows in the data + * model will be known. + * + * If the data model supports it, a #GdaDataModelIter can be moved backwards using the gda_data_model_iter_move_prev() + * method. However if the iterator is invalid, moving backwards will not be possible (on the contrary to + * gda_data_model_iter_move_next() which moves to the first row). + * + * The gda_data_model_iter_move_to_row() method, if the iterator can be moved both forward and backwards, can move the + * iterator to a specific row (sometimes faster than moving it forward or backwards a number of times). + * + * The following figure illustrates the #GdaDataModelIter usage: + * + * + * + * + * + * GdaDataModelIter's usage + * + * + * + * Note: the new #GdaDataModelIter does not hold any reference to the data model it iterates through (ie. + * if this data model is destroyed at some point, the new iterator will become useless but in + * any case it will not prevent the data model from being destroyed). + * + * Note: when the data model emits the "reset" signal, then: + * + * the number of columns of the iterator can change to reflect the new data model + * being itered on. In this case the iterator's position is reset as if it was + * just created + * some column types which were unknown (i.e. GDA_TYPE_NULL type), can change + * to their correct type. In this case there is no other iterator change + * some column types which were not GDA_TYPE_NULL can change, and in this case + * the iterator's position is reset as if it was just created + * + */ + +const GValue *gda_data_model_iter_get_value_at (GdaDataModelIter *iter, gint col); +const GValue *gda_data_model_iter_get_value_at_e (GdaDataModelIter *iter, gint col, GError **error); +const GValue *gda_data_model_iter_get_value_for_field (GdaDataModelIter *iter, const gchar *field_name); +gboolean gda_data_model_iter_set_value_at (GdaDataModelIter *iter, gint col, + const GValue *value, GError **error); + +gboolean gda_data_model_iter_move_to_row (GdaDataModelIter *iter, gint row); +gboolean gda_data_model_iter_move_next (GdaDataModelIter *iter); +gboolean gda_data_model_iter_move_prev (GdaDataModelIter *iter); +gint gda_data_model_iter_get_row (GdaDataModelIter *iter); + +void gda_data_model_iter_invalidate_contents (GdaDataModelIter *iter); +gboolean gda_data_model_iter_is_valid (GdaDataModelIter *iter); + +GdaHolder *gda_data_model_iter_get_holder_for_field (GdaDataModelIter *iter, gint col); + +#define gda_data_model_iter_move_at_row gda_data_model_iter_move_to_row + +G_END_DECLS + +#endif diff --git a/.flatpak-builder/cache/objects/79/fdfabf5c7332402923c96406fabfb8fc92c1b537fe2dbfdcbbc6b5162764de.file b/.flatpak-builder/cache/objects/79/fdfabf5c7332402923c96406fabfb8fc92c1b537fe2dbfdcbbc6b5162764de.file new file mode 100644 index 0000000..3c7143d --- /dev/null +++ b/.flatpak-builder/cache/objects/79/fdfabf5c7332402923c96406fabfb8fc92c1b537fe2dbfdcbbc6b5162764de.file @@ -0,0 +1,522 @@ +#include + +#if defined (__ELF__) && ( __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 6)) +# define SECTION __attribute__ ((section (".gresource.sqlite"), aligned (8))) +#else +# define SECTION +#endif + +static const SECTION union { const guint8 data[5075]; const double alignment; void * const ptr;} sqlite_resource_data = { + "\107\126\141\162\151\141\156\164\000\000\000\000\000\000\000\000" + "\030\000\000\000\304\001\000\000\000\000\000\050\017\000\000\000" + "\000\000\000\000\000\000\000\000\000\000\000\000\001\000\000\000" + "\002\000\000\000\004\000\000\000\006\000\000\000\007\000\000\000" + "\011\000\000\000\011\000\000\000\011\000\000\000\012\000\000\000" + "\013\000\000\000\015\000\000\000\015\000\000\000\156\214\371\111" + "\014\000\000\000\304\001\000\000\034\000\166\000\340\001\000\000" + "\256\002\000\000\103\145\251\316\014\000\000\000\256\002\000\000" + "\036\000\166\000\320\002\000\000\244\003\000\000\116\241\341\175" + "\005\000\000\000\244\003\000\000\005\000\114\000\254\003\000\000" + "\260\003\000\000\255\202\005\335\014\000\000\000\260\003\000\000" + "\036\000\166\000\320\003\000\000\274\004\000\000\231\241\156\020" + "\014\000\000\000\274\004\000\000\042\000\166\000\340\004\000\000" + "\245\005\000\000\324\265\002\000\377\377\377\377\245\005\000\000" + "\001\000\114\000\250\005\000\000\254\005\000\000\360\221\177\364" + "\014\000\000\000\254\005\000\000\037\000\166\000\320\005\000\000" + "\244\006\000\000\063\004\072\073\014\000\000\000\244\006\000\000" + "\041\000\166\000\310\006\000\000\203\007\000\000\000\275\161\233" + "\014\000\000\000\203\007\000\000\037\000\166\000\250\007\000\000" + "\174\010\000\000\102\347\213\124\014\000\000\000\174\010\000\000" + "\040\000\166\000\240\010\000\000\277\011\000\000\271\372\213\141" + "\014\000\000\000\277\011\000\000\030\000\166\000\330\011\000\000" + "\363\013\000\000\317\123\262\066\014\000\000\000\363\013\000\000" + "\041\000\166\000\030\014\000\000\263\017\000\000\057\174\217\375" + "\002\000\000\000\263\017\000\000\007\000\114\000\274\017\000\000" + "\354\017\000\000\052\235\062\101\014\000\000\000\354\017\000\000" + "\037\000\166\000\020\020\000\000\160\021\000\000\337\176\244\335" + "\014\000\000\000\160\021\000\000\041\000\166\000\230\021\000\000" + "\322\023\000\000\163\161\154\151\164\145\137\163\160\145\143\163" + "\137\144\162\157\160\137\144\142\056\162\141\167\056\170\155\154" + "\151\001\000\000\001\000\000\000\170\332\225\120\315\012\202\100" + "\020\276\373\024\303\136\072\372\002\052\124\032\004\025\121\335" + "\145\324\061\227\266\126\146\267\302\267\157\112\264\010\072\004" + "\163\231\217\357\217\057\162\304\267\334\266\111\000\040\027\265" + "\310\170\046\117\354\100\127\261\112\147\171\232\355\347\371\126" + "\301\105\160\001\320\143\201\216\046\016\052\162\045\353\326\153" + "\173\121\117\371\247\172\020\157\246\353\114\301\261\102\337\265" + "\242\076\226\215\060\230\261\023\277\253\061\366\024\253\305\164" + "\265\317\276\355\137\257\352\043\142\165\150\172\000\154\015\010" + "\325\300\361\026\112\046\364\102\014\177\025\110\227\273\277\362" + "\065\123\351\055\167\143\366\210\300\275\041\226\120\351\062\066" + "\250\265\041\270\153\143\240\030\112\104\341\173\302\044\210\302" + "\141\337\007\001\352\166\273\000\050\165\165\141\171\051\163\161" + "\154\151\164\145\137\163\160\145\143\163\137\144\162\157\160\137" + "\166\151\145\167\056\162\141\167\056\170\155\154\000\000\000\000" + "\075\001\000\000\001\000\000\000\170\332\165\220\313\016\202\060" + "\020\105\367\176\305\244\077\300\017\200\011\201\232\064\121\143" + "\054\076\166\115\205\212\215\225\222\266\076\370\173\007\215\300" + "\306\345\144\316\334\063\271\261\127\356\041\154\073\237\001\304" + "\255\164\362\246\202\162\036\164\225\220\075\243\007\221\123\236" + "\211\015\351\367\123\142\004\326\351\212\022\250\053\031\272\126" + "\045\244\056\057\310\070\047\073\002\315\335\030\173\115\310\042" + "\135\162\144\274\275\273\022\021\221\263\254\020\375\061\027\010" + "\141\040\106\151\365\044\120\051\137\272\357\000\301\342\150\320" + "\105\040\372\157\147\013\172\144\274\340\323\017\116\326\032\045" + "\233\321\137\154\167\364\047\142\147\120\057\355\203\037\154\271" + "\263\055\074\172\245\155\114\007\372\014\072\014\314\107\035\107" + "\143\063\363\131\034\375\072\173\003\056\317\146\251\000\050\165" + "\165\141\171\051\163\160\145\143\057\000\000\000\014\000\000\000" + "\163\161\154\151\164\145\137\163\160\145\143\163\137\143\162\145" + "\141\164\145\137\144\142\056\162\141\167\056\170\155\154\000\000" + "\211\001\000\000\001\000\000\000\170\332\215\220\101\153\303\060" + "\014\205\357\375\025\302\227\035\163\037\161\241\233\035\050\153" + "\327\322\355\036\324\104\115\314\274\330\310\356\112\376\375\324" + "\225\144\143\060\030\350\242\307\173\117\037\052\023\361\107\035" + "\342\162\001\040\123\106\144\174\247\114\234\300\265\132\231\207" + "\332\330\252\336\053\030\104\226\035\063\036\061\321\135\202\226" + "\122\303\056\146\027\006\165\115\377\014\117\331\347\325\326\052" + "\350\132\314\143\224\164\327\364\342\140\306\121\372\316\336\207" + "\067\255\252\325\346\305\376\256\377\132\325\355\204\126\257\375" + "\115\200\160\002\204\166\362\344\000\015\023\146\061\026\177\001" + "\230\365\341\177\367\243\077\167\156\320\352\344\074\045\362\367" + "\333\235\261\172\277\176\174\252\166\033\143\017\063\240\143\152" + "\162\340\161\206\233\025\270\364\304\102\045\260\063\342\265\015" + "\056\316\173\070\116\224\145\361\375\342\345\242\054\246\377\177" + "\002\120\000\200\376\000\050\165\165\141\171\051\163\161\154\151" + "\164\145\137\163\160\145\143\163\137\162\145\156\141\155\145\137" + "\143\157\154\165\155\156\056\162\141\167\056\170\155\154\000\000" + "\220\001\000\000\001\000\000\000\170\332\225\221\101\016\202\060" + "\020\105\367\234\142\322\013\160\201\142\122\261\254\112\065\212" + "\161\331\124\150\320\130\050\051\240\341\366\266\202\312\302\205" + "\054\147\362\376\274\311\014\156\225\275\013\323\254\002\000\334" + "\110\053\053\325\051\333\302\265\210\120\274\145\307\224\213\015" + "\115\304\016\171\140\216\274\210\214\254\031\025\234\244\024\101" + "\131\310\156\150\124\204\312\374\342\040\153\345\200\240\356\265" + "\066\267\010\045\204\035\034\123\273\254\113\311\263\126\010\012" + "\325\346\166\252\240\063\100\130\106\367\010\302\237\246\151\227" + "\245\252\330\350\276\252\077\256\261\364\062\253\074\360\207\115" + "\160\172\132\142\344\352\001\343\350\311\351\033\371\350\235\051" + "\161\370\075\366\052\300\341\373\015\117\175\022\177\363\000\050" + "\165\165\141\171\051\057\000\000\002\000\000\000\163\161\154\151" + "\164\145\137\163\160\145\143\163\137\144\162\157\160\137\164\141" + "\142\154\145\056\162\141\167\056\170\155\154\000\000\000\000\000" + "\104\001\000\000\001\000\000\000\170\332\175\220\113\012\203\060" + "\024\105\347\256\342\221\015\270\001\025\254\106\020\154\051\215" + "\205\316\102\324\150\103\123\043\111\054\165\367\115\245\176\106" + "\035\136\070\357\236\313\013\014\327\057\252\206\310\003\010\006" + "\246\331\223\133\256\015\210\046\104\145\174\050\060\115\061\111" + "\350\031\175\201\075\262\043\116\361\021\043\350\032\146\247\201" + "\207\250\253\357\016\322\232\115\010\372\121\112\365\010\121\026" + "\027\304\061\106\215\272\166\010\115\363\244\244\363\065\241\216" + "\162\225\256\214\125\222\043\150\270\251\365\057\201\125\056\113" + "\347\103\340\377\131\220\147\370\226\223\222\354\127\124\112\111" + "\316\372\155\103\171\271\342\305\225\267\300\337\302\130\263\372" + "\122\255\006\260\263\124\365\162\002\321\202\260\053\064\313\003" + "\177\173\120\344\005\376\362\272\017\170\013\150\104\000\050\165" + "\165\141\171\051\163\161\154\151\164\145\137\163\160\145\143\163" + "\137\162\145\156\141\155\145\137\164\141\142\154\145\056\162\141" + "\167\056\170\155\154\000\000\000\070\001\000\000\001\000\000\000" + "\170\332\225\220\335\012\202\100\020\205\357\175\212\141\136\300" + "\027\130\005\323\015\202\222\100\241\313\145\323\301\042\153\145" + "\166\055\174\373\326\237\310\253\240\313\231\371\346\234\303\021" + "\226\370\251\114\027\007\000\242\323\254\357\344\210\055\134\353" + "\010\313\144\263\227\052\223\105\252\216\070\002\153\144\105\344" + "\311\101\042\064\265\166\103\107\021\066\325\305\103\314\172\100" + "\170\364\155\153\156\021\156\223\175\341\031\153\172\256\074\242" + "\262\135\132\252\351\273\120\236\362\222\136\114\237\133\102\250" + "\311\126\274\114\340\014\060\215\147\204\360\127\002\171\372\043" + "\305\154\227\323\013\146\345\305\161\134\270\311\165\145\050\302" + "\157\051\161\040\302\117\135\157\220\130\143\220\000\050\165\165" + "\141\171\051\163\161\154\151\164\145\137\163\160\145\143\163\137" + "\144\162\157\160\137\151\156\144\145\170\056\162\141\167\056\170" + "\155\154\000\000\000\000\000\000\105\001\000\000\001\000\000\000" + "\170\332\175\220\101\012\203\060\020\105\367\236\142\310\005\274" + "\200\026\304\104\020\132\051\215\005\167\041\325\150\103\123\043" + "\111\054\172\373\246\322\252\253\056\077\274\371\357\063\221\025" + "\346\305\364\160\010\000\242\201\033\376\024\116\030\013\262\211" + "\121\136\140\122\061\114\150\312\316\350\003\354\221\035\121\044" + "\047\202\240\153\270\233\007\021\243\256\276\173\310\030\076\043" + "\350\107\245\364\043\106\131\162\244\236\261\172\064\265\107\030" + "\316\323\222\055\327\204\062\217\371\116\337\326\067\142\102\320" + "\010\133\233\157\002\247\175\126\136\210\040\374\063\041\317\110" + "\225\323\222\356\147\334\264\126\202\367\333\210\362\162\045\253" + "\253\005\061\111\353\354\352\303\106\017\040\027\251\356\325\014" + "\262\005\351\126\150\221\107\341\366\241\103\020\205\277\337\275" + "\001\045\145\150\371\000\050\165\165\141\171\051\163\161\154\151" + "\164\145\137\163\160\145\143\163\137\143\162\145\141\164\145\137" + "\166\151\145\167\056\162\141\167\056\170\155\154\000\000\000\000" + "\305\002\000\000\001\000\000\000\170\332\255\222\317\116\303\060" + "\014\306\357\173\012\053\027\216\175\201\256\322\304\122\251\022" + "\353\046\032\376\334\252\154\365\106\104\326\104\111\126\350\333" + "\343\166\254\255\020\040\100\134\162\260\363\331\077\333\137\354" + "\321\065\245\261\311\014\040\266\322\311\043\006\164\036\124\065" + "\147\367\031\177\050\227\074\055\067\014\152\112\120\104\341\313" + "\225\207\012\375\316\051\033\224\251\131\047\234\112\107\145\276" + "\130\161\006\207\112\206\326\222\366\260\173\242\077\316\311\226" + "\252\235\264\066\317\163\226\056\156\012\176\051\236\323\313\316" + "\265\207\116\135\346\275\005\065\241\132\145\043\365\011\223\040" + "\267\032\313\056\033\107\143\364\214\022\015\054\137\263\011\276" + "\332\114\331\266\306\150\224\365\110\046\156\357\006\060\201\107" + "\153\010\275\205\206\250\076\303\351\347\370\033\111\226\346\153" + "\301\037\263\102\024\077\006\132\327\272\005\265\007\025\240\062" + "\110\133\062\001\132\014\200\257\312\207\141\205\327\016\145\300" + "\236\031\314\267\212\377\235\210\034\363\233\263\057\161\257\152" + "\325\173\351\303\361\253\111\046\352\015\072\266\367\311\054\216" + "\056\336\175\003\324\234\345\377\000\050\165\165\141\171\051\163" + "\161\154\151\164\145\137\163\160\145\143\163\137\144\163\156\056" + "\162\141\167\056\170\155\154\000\041\006\000\000\001\000\000\000" + "\170\332\255\125\115\157\332\100\020\275\367\127\214\174\011\110" + "\015\334\043\034\311\305\113\204\342\000\005\242\346\206\026\173" + "\154\126\131\166\255\335\165\011\375\365\035\333\301\006\051\121" + "\035\225\023\232\257\235\067\357\015\343\121\302\035\277\265\350" + "\156\155\216\361\375\067\200\121\316\015\337\243\103\143\113\363" + "\334\001\042\361\275\360\307\146\026\074\061\017\062\052\075\346" + "\350\173\131\274\243\014\143\370\321\003\125\110\251\137\175\157" + "\022\104\053\312\121\124\110\045\324\143\313\055\126\246\007\011" + "\332\330\370\336\172\127\073\100\247\300\041\071\345\070\015\005" + "\375\364\016\302\355\164\341\300\121\332\040\331\366\075\030\176" + "\210\047\130\054\330\054\334\020\054\366\262\146\263\325\164\076" + "\073\307\266\325\132\042\127\055\262\365\362\271\001\026\344\071" + "\252\004\156\350\375\233\006\127\210\251\120\150\101\244\125\357" + "\052\010\370\346\120\131\241\025\050\304\244\004\271\105\340\125" + "\171\155\226\251\357\324\000\067\131\261\107\345\274\032\060\101" + "\046\074\233\337\134\026\170\137\021\063\032\266\216\172\246\141" + "\063\324\147\244\207\323\145\067\316\163\131\144\102\371\136\052" + "\044\132\224\167\117\363\220\371\213\351\370\161\062\217\102\266" + "\154\104\021\006\143\247\315\261\035\374\344\201\303\016\015\126" + "\043\065\262\224\257\201\260\140\051\001\223\317\304\040\011\226" + "\301\146\362\074\033\257\111\207\125\147\041\330\233\063\034\322" + "\102\305\216\070\266\015\044\246\370\226\372\026\226\147\325\236" + "\340\145\036\364\112\036\013\222\301\174\207\301\140\320\377\210" + "\361\262\317\227\011\137\262\007\366\262\350\214\277\336\031\070" + "\125\135\154\122\305\143\035\151\220\137\015\147\115\370\170\036" + "\105\301\327\030\217\164\314\245\370\103\313\033\353\075\275\051" + "\354\277\171\217\265\224\274\204\017\004\140\247\023\342\077\232" + "\217\203\210\066\236\376\105\341\070\130\261\353\051\060\171\354" + "\074\313\057\072\025\220\322\136\212\114\301\053\036\317\347\040" + "\167\214\227\301\053\162\137\337\233\356\254\007\344\072\264\307" + "\244\005\132\007\126\077\043\341\252\023\050\065\117\316\362\110" + "\011\241\262\152\223\312\310\246\211\364\372\377\275\123\147\046" + "\135\374\321\360\362\213\360\027\004\251\376\314\000\050\165\165" + "\141\171\051\163\161\154\151\164\145\137\163\160\145\143\163\137" + "\143\162\145\141\164\145\137\164\141\142\154\145\056\162\141\167" + "\056\170\155\154\000\000\000\000\275\015\000\000\001\000\000\000" + "\170\332\255\127\113\123\333\060\020\276\363\053\064\071\264\160" + "\012\347\066\060\043\034\007\074\070\262\353\307\114\351\305\143" + "\154\045\321\240\130\251\037\264\351\344\307\167\045\307\217\200" + "\003\012\303\005\360\256\166\367\333\207\276\025\223\202\346\317" + "\221\330\134\237\041\064\331\304\171\274\246\045\315\013\304\322" + "\253\121\200\157\154\063\232\232\263\310\035\241\014\064\040\212" + "\037\071\375\132\240\224\026\111\316\066\045\023\331\110\232\366" + "\215\173\266\004\317\315\021\132\246\161\271\335\200\365\062\131" + "\301\241\074\217\267\340\257\342\134\074\135\215\146\330\366\315" + "\306\075\201\237\243\332\171\027\113\252\366\101\040\014\070\213" + "\236\143\136\321\353\122\352\043\251\235\214\073\151\015\146\334" + "\242\171\003\135\140\316\335\076\272\107\041\070\215\263\016\133" + "\340\205\055\264\200\256\067\002\300\157\221\212\073\004\110\245" + "\362\101\054\326\214\070\201\371\323\362\003\137\033\222\223\361" + "\055\142\013\304\112\224\012\012\205\022\045\332\322\022\321\277" + "\254\050\333\062\032\071\215\113\132\243\106\342\115\223\217\346" + "\324\373\054\256\317\100\160\266\367\241\172\255\262\234\131\246" + "\075\365\043\374\162\220\022\301\253\165\126\064\103\324\032\105" + "\013\106\171\252\114\015\307\016\347\344\344\131\232\051\007\152" + "\170\320\370\175\367\301\203\173\314\375\212\145\345\325\010\064" + "\112\167\044\334\024\324\250\326\153\104\363\255\137\007\321\052" + "\010\061\334\144\237\375\323\164\151\140\133\327\147\022\163\075" + "\247\204\204\266\366\074\022\030\046\070\157\153\171\306\141\340" + "\130\304\320\166\216\253\122\040\226\045\071\135\123\231\227\106" + "\210\220\130\077\102\123\073\102\230\261\337\225\136\131\334\173" + "\363\101\333\257\233\263\265\344\215\047\272\325\162\016\204\213" + "\103\073\170\147\326\373\021\246\164\021\127\274\273\362\373\157" + "\244\156\254\126\114\343\316\064\356\117\210\150\254\150\362\324" + "\121\214\374\202\253\234\025\145\036\263\136\167\336\217\353\330" + "\066\016\314\123\042\213\065\220\015\105\300\066\053\221\166\020" + "\004\347\261\134\107\352\030\072\277\261\010\366\036\166\304\061" + "\260\157\136\350\325\300\041\063\333\062\202\223\300\144\013\316" + "\222\036\331\356\005\050\247\005\060\233\002\124\043\105\347\036" + "\344\172\203\215\373\035\276\161\274\140\067\303\226\275\263\156" + "\211\343\231\073\317\164\155\154\264\070\153\276\125\161\025\235" + "\116\012\012\223\231\045\264\246\122\030\276\310\157\151\116\344" + "\224\055\063\065\135\203\373\105\035\367\140\211\253\105\243\307" + "\240\205\250\362\004\216\104\123\250\107\155\350\107\115\104\217" + "\056\150\056\321\244\307\127\141\116\027\221\122\152\254\303\027" + "\213\102\302\175\271\055\024\227\027\155\225\353\117\140\003\124" + "\256\050\132\274\252\300\221\076\317\356\153\307\047\157\221\166" + "\174\216\073\226\005\166\117\362\337\326\370\260\101\143\125\362" + "\175\001\006\112\276\070\016\110\156\250\106\174\240\310\305\237" + "\116\176\320\047\226\106\320\252\127\115\032\070\067\170\246\067" + "\250\375\040\175\161\007\352\140\252\217\015\352\034\007\306\335" + "\133\313\370\360\032\066\105\134\307\145\262\212\344\351\342\333" + "\145\123\265\271\024\356\167\362\176\162\224\210\145\313\346\122" + "\302\123\150\015\343\003\163\024\147\360\070\242\150\337\324\354" + "\131\360\147\232\016\215\266\102\210\174\153\356\332\247\077\366" + "\124\216\016\011\335\251\056\353\065\031\306\211\044\223\050\171" + "\354\362\163\062\124\155\122\371\270\253\225\103\150\211\203\260" + "\021\130\016\371\050\324\251\151\233\237\002\065\245\234\176\016" + "\324\311\270\341\303\366\261\171\100\220\365\213\032\350\334\017" + "\074\154\221\300\357\330\362\226\213\307\230\367\126\125\061\114" + "\232\235\161\004\277\055\162\333\143\374\166\311\151\334\362\201" + "\064\325\252\105\347\365\303\027\175\131\226\337\321\345\305\051" + "\051\313\277\353\377\331\376\003\056\126\140\223\000\050\165\165" + "\141\171\051\163\161\154\151\164\145\057\000\000\015\000\000\000" + "\003\000\000\000\016\000\000\000\013\000\000\000\011\000\000\000" + "\000\000\000\000\010\000\000\000\006\000\000\000\001\000\000\000" + "\012\000\000\000\004\000\000\000\007\000\000\000\163\161\154\151" + "\164\145\137\163\160\145\143\163\137\141\144\144\137\143\157\154" + "\165\155\156\056\162\141\167\056\170\155\154\000\000\000\000\000" + "\342\003\000\000\001\000\000\000\170\332\235\223\321\156\202\060" + "\024\206\357\175\212\223\336\354\146\011\057\000\046\014\061\133" + "\206\150\006\134\154\067\244\102\325\306\112\111\133\114\334\323" + "\357\130\024\131\242\103\167\331\376\075\337\371\150\017\256\146" + "\152\237\313\172\074\002\160\153\252\350\216\031\246\064\360\322" + "\043\301\074\312\146\161\076\011\247\371\202\100\205\021\356\111" + "\321\354\252\047\015\045\323\205\342\265\341\262\042\307\342\176" + "\271\255\116\375\227\050\314\143\177\026\022\130\227\324\034\152" + "\054\137\027\033\074\244\024\075\040\260\021\102\156\075\062\365" + "\243\044\074\363\123\272\024\214\264\364\323\012\233\035\063\002" + "\316\325\076\047\313\107\033\115\071\023\145\013\156\261\010\306" + "\352\174\117\105\303\306\205\375\314\374\030\273\316\145\273\355" + "\357\164\002\177\011\245\237\213\133\102\033\136\031\217\140\142" + "\263\033\202\023\214\301\346\127\374\020\300\326\114\375\327\055" + "\171\373\372\345\326\040\357\242\221\176\144\235\105\302\277\207" + "\156\076\011\374\350\136\132\101\305\340\103\306\131\324\247\055" + "\245\024\214\126\327\201\261\064\200\347\243\001\046\216\260\237" + "\105\351\300\174\364\301\023\266\242\215\060\335\044\236\326\140" + "\357\372\031\166\264\102\222\124\007\340\053\150\207\005\270\206" + "\170\236\336\243\023\274\206\301\373\003\062\301\206\025\333\116" + "\305\256\260\151\245\215\242\366\252\155\263\336\323\353\361\310" + "\165\316\077\366\017\345\052\076\243\000\050\165\165\141\171\051" + "\163\161\154\151\164\145\137\163\160\145\143\163\137\143\162\145" + "\141\164\145\137\151\156\144\145\170\056\162\141\167\056\170\155" + "\154\000\000\000\000\000\000\000\063\010\000\000\001\000\000\000" + "\170\332\325\126\115\157\233\100\020\075\047\277\142\305\051\071" + "\321\252\267\312\266\104\000\113\110\024\122\203\245\344\204\066" + "\060\161\126\305\273\164\167\235\332\122\177\174\227\005\002\304" + "\004\210\157\275\130\232\331\067\157\336\174\011\057\004\360\327" + "\204\025\253\153\204\026\005\346\170\017\022\270\100\044\133\032" + "\136\340\270\017\211\343\256\223\173\003\121\365\242\134\064\203" + "\043\312\100\244\234\024\222\060\152\224\201\335\320\116\144\374" + "\170\357\032\150\227\141\171\052\124\354\056\175\121\040\316\361" + "\111\261\035\362\234\375\132\032\361\146\253\040\202\035\170\252" + "\020\045\116\174\377\322\044\213\225\131\363\253\014\212\047\171" + "\305\371\001\126\333\300\373\271\165\027\146\353\251\064\230\157" + "\042\106\104\005\326\217\051\121\153\313\217\334\106\104\240\176" + "\215\252\342\246\174\252\135\346\110\222\060\110\142\353\316\237" + "\231\250\051\077\161\074\073\256\002\243\244\311\037\122\044\361" + "\123\076\221\320\133\007\141\354\076\170\121\034\165\163\076\061" + "\226\003\246\357\373\335\060\347\047\104\236\021\221\050\143\040" + "\020\145\022\235\100\042\070\022\041\337\112\266\071\140\011\210" + "\350\312\331\150\310\300\250\164\205\123\223\352\230\142\165\255" + "\034\245\117\300\357\003\320\024\072\105\256\075\327\167\242\104" + "\125\270\047\224\110\330\213\245\361\125\031\370\130\033\337\172" + "\153\012\031\172\046\220\147\067\342\166\154\113\065\353\047\007" + "\325\237\262\251\347\126\253\033\224\200\030\127\075\052\070\010" + "\321\336\114\257\121\244\202\047\032\076\275\332\037\227\143\207" + "\276\157\305\363\356\256\122\152\263\275\042\002\244\230\136\130" + "\326\016\236\345\071\056\117\134\303\320\315\235\027\130\233\307" + "\277\101\150\133\221\173\073\276\216\121\270\211\223\160\343\270" + "\233\117\335\277\140\134\266\347\037\051\013\225\241\165\256\205" + "\331\354\104\273\044\072\120\324\112\312\246\151\376\232\240\244" + "\353\367\132\277\126\075\256\061\044\233\067\172\163\202\107\302" + "\121\136\316\244\302\160\343\356\075\160\366\247\365\367\026\306" + "\212\354\263\065\071\007\211\024\150\106\350\156\020\132\071\007" + "\022\315\022\340\270\163\024\070\160\211\204\256\273\355\115\307" + "\253\067\140\140\344\372\013\362\077\315\374\152\126\257\077\370" + "\342\235\343\050\121\027\322\303\135\135\336\142\175\162\315\205" + "\225\327\127\375\123\370\007\246\052\222\370\000\050\165\165\141" + "\171\051" }; + +static GStaticResource static_resource = { sqlite_resource_data.data, sizeof (sqlite_resource_data.data) - 1 /* nul terminator */, NULL, NULL, NULL }; + +G_GNUC_INTERNAL +GResource *sqlite_get_resource (void); +GResource *sqlite_get_resource (void) +{ + return g_static_resource_get_resource (&static_resource); +} +/* GLIB - Library of useful routines for C programming + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * SPDX-License-Identifier: LGPL-2.1-or-later + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + */ + +/* + * Modified by the GLib Team and others 1997-2000. See the AUTHORS + * file for a list of people on the GLib Team. See the ChangeLog + * files for a list of changes. These files are distributed with + * GLib at ftp://ftp.gtk.org/pub/gtk/. + */ + +#ifndef __G_CONSTRUCTOR_H__ +#define __G_CONSTRUCTOR_H__ + +/* + If G_HAS_CONSTRUCTORS is true then the compiler support *both* constructors and + destructors, in a usable way, including e.g. on library unload. If not you're on + your own. + + Some compilers need #pragma to handle this, which does not work with macros, + so the way you need to use this is (for constructors): + + #ifdef G_DEFINE_CONSTRUCTOR_NEEDS_PRAGMA + #pragma G_DEFINE_CONSTRUCTOR_PRAGMA_ARGS(my_constructor) + #endif + G_DEFINE_CONSTRUCTOR(my_constructor) + static void my_constructor(void) { + ... + } + +*/ + +#ifndef __GTK_DOC_IGNORE__ + +#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 7) + +#define G_HAS_CONSTRUCTORS 1 + +#define G_DEFINE_CONSTRUCTOR(_func) static void __attribute__((constructor)) _func (void); +#define G_DEFINE_DESTRUCTOR(_func) static void __attribute__((destructor)) _func (void); + +#elif defined (_MSC_VER) && (_MSC_VER >= 1500) +/* Visual studio 2008 and later has _Pragma */ + +/* + * Only try to include gslist.h if not already included via glib.h, + * so that items using gconstructor.h outside of GLib (such as + * GResources) continue to build properly. + */ +#ifndef __G_LIB_H__ +#include "gslist.h" +#endif + +#include + +#define G_HAS_CONSTRUCTORS 1 + +/* We do some weird things to avoid the constructors being optimized + * away on VS2015 if WholeProgramOptimization is enabled. First we + * make a reference to the array from the wrapper to make sure its + * references. Then we use a pragma to make sure the wrapper function + * symbol is always included at the link stage. Also, the symbols + * need to be extern (but not dllexport), even though they are not + * really used from another object file. + */ + +/* We need to account for differences between the mangling of symbols + * for x86 and x64/ARM/ARM64 programs, as symbols on x86 are prefixed + * with an underscore but symbols on x64/ARM/ARM64 are not. + */ +#ifdef _M_IX86 +#define G_MSVC_SYMBOL_PREFIX "_" +#else +#define G_MSVC_SYMBOL_PREFIX "" +#endif + +#define G_DEFINE_CONSTRUCTOR(_func) G_MSVC_CTOR (_func, G_MSVC_SYMBOL_PREFIX) +#define G_DEFINE_DESTRUCTOR(_func) G_MSVC_DTOR (_func, G_MSVC_SYMBOL_PREFIX) + +#define G_MSVC_CTOR(_func,_sym_prefix) \ + static void _func(void); \ + extern int (* _array ## _func)(void); \ + int _func ## _wrapper(void) { _func(); g_slist_find (NULL, _array ## _func); return 0; } \ + __pragma(comment(linker,"/include:" _sym_prefix # _func "_wrapper")) \ + __pragma(section(".CRT$XCU",read)) \ + __declspec(allocate(".CRT$XCU")) int (* _array ## _func)(void) = _func ## _wrapper; + +#define G_MSVC_DTOR(_func,_sym_prefix) \ + static void _func(void); \ + extern int (* _array ## _func)(void); \ + int _func ## _constructor(void) { atexit (_func); g_slist_find (NULL, _array ## _func); return 0; } \ + __pragma(comment(linker,"/include:" _sym_prefix # _func "_constructor")) \ + __pragma(section(".CRT$XCU",read)) \ + __declspec(allocate(".CRT$XCU")) int (* _array ## _func)(void) = _func ## _constructor; + +#elif defined (_MSC_VER) + +#define G_HAS_CONSTRUCTORS 1 + +/* Pre Visual studio 2008 must use #pragma section */ +#define G_DEFINE_CONSTRUCTOR_NEEDS_PRAGMA 1 +#define G_DEFINE_DESTRUCTOR_NEEDS_PRAGMA 1 + +#define G_DEFINE_CONSTRUCTOR_PRAGMA_ARGS(_func) \ + section(".CRT$XCU",read) +#define G_DEFINE_CONSTRUCTOR(_func) \ + static void _func(void); \ + static int _func ## _wrapper(void) { _func(); return 0; } \ + __declspec(allocate(".CRT$XCU")) static int (*p)(void) = _func ## _wrapper; + +#define G_DEFINE_DESTRUCTOR_PRAGMA_ARGS(_func) \ + section(".CRT$XCU",read) +#define G_DEFINE_DESTRUCTOR(_func) \ + static void _func(void); \ + static int _func ## _constructor(void) { atexit (_func); return 0; } \ + __declspec(allocate(".CRT$XCU")) static int (* _array ## _func)(void) = _func ## _constructor; + +#elif defined(__SUNPRO_C) + +/* This is not tested, but i believe it should work, based on: + * http://opensource.apple.com/source/OpenSSL098/OpenSSL098-35/src/fips/fips_premain.c + */ + +#define G_HAS_CONSTRUCTORS 1 + +#define G_DEFINE_CONSTRUCTOR_NEEDS_PRAGMA 1 +#define G_DEFINE_DESTRUCTOR_NEEDS_PRAGMA 1 + +#define G_DEFINE_CONSTRUCTOR_PRAGMA_ARGS(_func) \ + init(_func) +#define G_DEFINE_CONSTRUCTOR(_func) \ + static void _func(void); + +#define G_DEFINE_DESTRUCTOR_PRAGMA_ARGS(_func) \ + fini(_func) +#define G_DEFINE_DESTRUCTOR(_func) \ + static void _func(void); + +#else + +/* constructors not supported for this compiler */ + +#endif + +#endif /* __GTK_DOC_IGNORE__ */ +#endif /* __G_CONSTRUCTOR_H__ */ + +#ifdef G_HAS_CONSTRUCTORS + +#ifdef G_DEFINE_CONSTRUCTOR_NEEDS_PRAGMA +#pragma G_DEFINE_CONSTRUCTOR_PRAGMA_ARGS(sqliteresource_constructor) +#endif +G_DEFINE_CONSTRUCTOR(sqliteresource_constructor) +#ifdef G_DEFINE_DESTRUCTOR_NEEDS_PRAGMA +#pragma G_DEFINE_DESTRUCTOR_PRAGMA_ARGS(sqliteresource_destructor) +#endif +G_DEFINE_DESTRUCTOR(sqliteresource_destructor) + +#else +#warning "Constructor not supported on this compiler, linking in resources will not work" +#endif + +static void sqliteresource_constructor (void) +{ + g_static_resource_init (&static_resource); +} + +static void sqliteresource_destructor (void) +{ + g_static_resource_fini (&static_resource); +} diff --git a/.flatpak-builder/cache/objects/7a/cdd01e486d0d256b8710b5d4bc0eb962320f46c149468f8db01154096dd157.dirtree b/.flatpak-builder/cache/objects/7a/cdd01e486d0d256b8710b5d4bc0eb962320f46c149468f8db01154096dd157.dirtree new file mode 100644 index 0000000..90b6146 Binary files /dev/null and b/.flatpak-builder/cache/objects/7a/cdd01e486d0d256b8710b5d4bc0eb962320f46c149468f8db01154096dd157.dirtree differ diff --git a/.flatpak-builder/cache/objects/7a/ce61f7976ad38a3e83f75ca68607597d3f91a9f881abe2196cf879d83db025.dirtree b/.flatpak-builder/cache/objects/7a/ce61f7976ad38a3e83f75ca68607597d3f91a9f881abe2196cf879d83db025.dirtree new file mode 100644 index 0000000..12bf30e Binary files /dev/null and b/.flatpak-builder/cache/objects/7a/ce61f7976ad38a3e83f75ca68607597d3f91a9f881abe2196cf879d83db025.dirtree differ diff --git a/.flatpak-builder/cache/objects/7b/584599daa75ce4d91914f3849ba7b59a801103ed0e16bfcf9a04695230e134.file b/.flatpak-builder/cache/objects/7b/584599daa75ce4d91914f3849ba7b59a801103ed0e16bfcf9a04695230e134.file new file mode 100644 index 0000000..830d11f --- /dev/null +++ b/.flatpak-builder/cache/objects/7b/584599daa75ce4d91914f3849ba7b59a801103ed0e16bfcf9a04695230e134.file @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2000 Reinhard Müller + * Copyright (C) 2000 - 2002 Rodrigo Moya + * Copyright (C) 2001 Carlos Perelló Marín + * Copyright (C) 2001 - 2012 Vivien Malerba + * Copyright (C) 2002 Gonzalo Paniagua Javier + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GDA_META_STRUCT_PRIVATE_H__ +#define __GDA_META_STRUCT_PRIVATE_H__ + +#include + +G_BEGIN_DECLS + +GdaMetaDbObject *_gda_meta_struct_add_db_object (GdaMetaStruct *mstruct, GdaMetaDbObject *dbo, GError **error); + +G_END_DECLS + +#endif diff --git a/.flatpak-builder/cache/objects/7b/d0e3214dc6a865c4d10c1cda30f5da24ba1d867dea3c1a8cf3c0ca4da97322.dirtree b/.flatpak-builder/cache/objects/7b/d0e3214dc6a865c4d10c1cda30f5da24ba1d867dea3c1a8cf3c0ca4da97322.dirtree new file mode 100644 index 0000000..f43b86d Binary files /dev/null and b/.flatpak-builder/cache/objects/7b/d0e3214dc6a865c4d10c1cda30f5da24ba1d867dea3c1a8cf3c0ca4da97322.dirtree differ diff --git a/.flatpak-builder/cache/objects/7b/f076607ca00833056013127f892584a5cba7e81f8de8a31e5db29f169a8679.dirtree b/.flatpak-builder/cache/objects/7b/f076607ca00833056013127f892584a5cba7e81f8de8a31e5db29f169a8679.dirtree new file mode 100644 index 0000000..b625eee Binary files /dev/null and b/.flatpak-builder/cache/objects/7b/f076607ca00833056013127f892584a5cba7e81f8de8a31e5db29f169a8679.dirtree differ diff --git a/.flatpak-builder/cache/objects/7c/1efc2ea52438cabffa1b708d1b7f723c43789a0f48885bf6b4f76715780d52.file b/.flatpak-builder/cache/objects/7c/1efc2ea52438cabffa1b708d1b7f723c43789a0f48885bf6b4f76715780d52.file new file mode 100644 index 0000000..4232ff7 --- /dev/null +++ b/.flatpak-builder/cache/objects/7c/1efc2ea52438cabffa1b708d1b7f723c43789a0f48885bf6b4f76715780d52.file @@ -0,0 +1,763 @@ +/* file contains automatically generated code, DO NOT MODIFY * + * + * The code in this file implements a function that determines whether + * or not a given identifier is really an SQL keyword. The same thing + * might be implemented more directly using a hand-written hash table. + * But by using this automatically generated code, the size of the code + * is substantially reduced. This is important for embedded applications + * on platforms with limited memory. + * + * This code has been copied from SQLite's mkkeywordhash.c file and modified. + * to read the SQL keywords from a file instead of static ones + */ + +/* Parsed keywords + * + * From line: ABSOLUTE,ACTION,ADD,ALL,ALLOCATE,ALTER,AND + * KEYWORD: 'ABSOLUTE' + * KEYWORD: 'ACTION' + * KEYWORD: 'ADD' + * KEYWORD: 'ALL' + * KEYWORD: 'ALLOCATE' + * KEYWORD: 'ALTER' + * KEYWORD: 'AND' + * + * From line: ANY,ARE,AS,ASC + * KEYWORD: 'ANY' + * KEYWORD: 'ARE' + * KEYWORD: 'AS' + * KEYWORD: 'ASC' + * + * From line: ASSERTION,AT,AUTHORIZATION,AVG + * KEYWORD: 'ASSERTION' + * KEYWORD: 'AT' + * KEYWORD: 'AUTHORIZATION' + * KEYWORD: 'AVG' + * + * From line: BEGIN,BETWEEN,BIT,BIT_LENGTH,BOTH,BY + * KEYWORD: 'BEGIN' + * KEYWORD: 'BETWEEN' + * KEYWORD: 'BIT' + * KEYWORD: 'BIT_LENGTH' + * KEYWORD: 'BOTH' + * KEYWORD: 'BY' + * + * From line: CASCADE,CASCADED,CASE,CAST,CATALOG,CHAR,CHARACTER,CHAR_ + * KEYWORD: 'CASCADE' + * KEYWORD: 'CASCADED' + * KEYWORD: 'CASE' + * KEYWORD: 'CAST' + * KEYWORD: 'CATALOG' + * KEYWORD: 'CHAR' + * KEYWORD: 'CHARACTER' + * KEYWORD: 'CHAR_' + * + * From line: LENGTH + * KEYWORD: 'LENGTH' + * + * From line: CHARACTER_LENGTH,CHECK,CLOSE,COALESCE,COLLATE,COLLATION + * KEYWORD: 'CHARACTER_LENGTH' + * KEYWORD: 'CHECK' + * KEYWORD: 'CLOSE' + * KEYWORD: 'COALESCE' + * KEYWORD: 'COLLATE' + * KEYWORD: 'COLLATION' + * + * From line: COLUMN,COMMIT,CONNECT,CONNECTION,CONSTRAINT + * KEYWORD: 'COLUMN' + * KEYWORD: 'COMMIT' + * KEYWORD: 'CONNECT' + * KEYWORD: 'CONNECTION' + * KEYWORD: 'CONSTRAINT' + * + * From line: CONSTRAINTS,CONTINUE + * KEYWORD: 'CONSTRAINTS' + * KEYWORD: 'CONTINUE' + * + * From line: CONVERT,CORRESPONDING,COUNT,CREATE,CROSS,CURRENT + * KEYWORD: 'CONVERT' + * KEYWORD: 'CORRESPONDING' + * KEYWORD: 'COUNT' + * KEYWORD: 'CREATE' + * KEYWORD: 'CROSS' + * KEYWORD: 'CURRENT' + * + * From line: CURRENT_DATE,CURRENT_TIME,CURRENT_TIMESTAMP,CURRENT_ + * KEYWORD: 'CURRENT_DATE' + * KEYWORD: 'CURRENT_TIME' + * KEYWORD: 'CURRENT_TIMESTAMP' + * KEYWORD: 'CURRENT_' + * + * From line: USER,CURSOR + * KEYWORD: 'USER' + * KEYWORD: 'CURSOR' + * + * From line: DATE,DAY,DEALLOCATE,DEC,DECIMAL,DECLARE,DEFAULT,DEFERRABLE + * KEYWORD: 'DATE' + * KEYWORD: 'DAY' + * KEYWORD: 'DEALLOCATE' + * KEYWORD: 'DEC' + * KEYWORD: 'DECIMAL' + * KEYWORD: 'DECLARE' + * KEYWORD: 'DEFAULT' + * KEYWORD: 'DEFERRABLE' + * + * From line: DEFERRED,DELETE,DESC,DESCRIBE,DESCRIPTOR,DIAGNOSTICS + * KEYWORD: 'DEFERRED' + * KEYWORD: 'DELETE' + * KEYWORD: 'DESC' + * KEYWORD: 'DESCRIBE' + * KEYWORD: 'DESCRIPTOR' + * KEYWORD: 'DIAGNOSTICS' + * + * From line: DISCONNECT,DISTINCT,DOMAIN,DOUBLE,DROP + * KEYWORD: 'DISCONNECT' + * KEYWORD: 'DISTINCT' + * KEYWORD: 'DOMAIN' + * KEYWORD: 'DOUBLE' + * KEYWORD: 'DROP' + * + * From line: ELSE,END,END-EXEC,ESCAPE,EXCEPT,EXCEPTION + * KEYWORD: 'ELSE' + * KEYWORD: 'END' + * KEYWORD: 'END' + * KEYWORD: 'EXEC' + * KEYWORD: 'ESCAPE' + * KEYWORD: 'EXCEPT' + * KEYWORD: 'EXCEPTION' + * + * From line: EXEC,EXECUTE,EXISTS + * KEYWORD: 'EXEC' + * KEYWORD: 'EXECUTE' + * KEYWORD: 'EXISTS' + * + * From line: EXTERNAL,EXTRACT + * KEYWORD: 'EXTERNAL' + * KEYWORD: 'EXTRACT' + * + * From line: FALSE,FETCH,FIRST,FLOAT,FOR,FOREIGN,FOUND,FROM,FULL + * KEYWORD: 'FALSE' + * KEYWORD: 'FETCH' + * KEYWORD: 'FIRST' + * KEYWORD: 'FLOAT' + * KEYWORD: 'FOR' + * KEYWORD: 'FOREIGN' + * KEYWORD: 'FOUND' + * KEYWORD: 'FROM' + * KEYWORD: 'FULL' + * + * From line: GET,GLOBAL,GO,GOTO,GRANT,GROUP + * KEYWORD: 'GET' + * KEYWORD: 'GLOBAL' + * KEYWORD: 'GO' + * KEYWORD: 'GOTO' + * KEYWORD: 'GRANT' + * KEYWORD: 'GROUP' + * + * From line: HAVING,HOUR + * KEYWORD: 'HAVING' + * KEYWORD: 'HOUR' + * + * From line: IDENTITY,IMMEDIATE,IN,INDICATOR,INITIALLY,INNER,INPUT + * KEYWORD: 'IDENTITY' + * KEYWORD: 'IMMEDIATE' + * KEYWORD: 'IN' + * KEYWORD: 'INDICATOR' + * KEYWORD: 'INITIALLY' + * KEYWORD: 'INNER' + * KEYWORD: 'INPUT' + * + * From line: INSENSITIVE,INSERT,INT,INTEGER,INTERSECT,INTERVAL,INTO,IS + * KEYWORD: 'INSENSITIVE' + * KEYWORD: 'INSERT' + * KEYWORD: 'INT' + * KEYWORD: 'INTEGER' + * KEYWORD: 'INTERSECT' + * KEYWORD: 'INTERVAL' + * KEYWORD: 'INTO' + * KEYWORD: 'IS' + * + * From line: ISOLATION + * KEYWORD: 'ISOLATION' + * + * From line: JOIN + * KEYWORD: 'JOIN' + * + * From line: KEY + * KEYWORD: 'KEY' + * + * From line: LANGUAGE,LAST,LEADING,LEFT,LEVEL,LIKE,LOCAL,LOWER + * KEYWORD: 'LANGUAGE' + * KEYWORD: 'LAST' + * KEYWORD: 'LEADING' + * KEYWORD: 'LEFT' + * KEYWORD: 'LEVEL' + * KEYWORD: 'LIKE' + * KEYWORD: 'LOCAL' + * KEYWORD: 'LOWER' + * + * From line: MATCH,MAX,MIN,MINUTE,MODULE,MONTH + * KEYWORD: 'MATCH' + * KEYWORD: 'MAX' + * KEYWORD: 'MIN' + * KEYWORD: 'MINUTE' + * KEYWORD: 'MODULE' + * KEYWORD: 'MONTH' + * + * From line: NAMES,NATIONAL,NATURAL,NCHAR,NEXT,NO,NOT,NULL + * KEYWORD: 'NAMES' + * KEYWORD: 'NATIONAL' + * KEYWORD: 'NATURAL' + * KEYWORD: 'NCHAR' + * KEYWORD: 'NEXT' + * KEYWORD: 'NO' + * KEYWORD: 'NOT' + * KEYWORD: 'NULL' + * + * From line: NULLIF,NUMERIC + * KEYWORD: 'NULLIF' + * KEYWORD: 'NUMERIC' + * + * From line: OCTET_LENGTH,OF,ON,ONLY,OPEN,OPTION,OR + * KEYWORD: 'OCTET_LENGTH' + * KEYWORD: 'OF' + * KEYWORD: 'ON' + * KEYWORD: 'ONLY' + * KEYWORD: 'OPEN' + * KEYWORD: 'OPTION' + * KEYWORD: 'OR' + * + * From line: ORDER,OUTER + * KEYWORD: 'ORDER' + * KEYWORD: 'OUTER' + * + * From line: OUTPUT,OVERLAPS + * KEYWORD: 'OUTPUT' + * KEYWORD: 'OVERLAPS' + * + * From line: PAD,PARTIAL,POSITION,PRECISION,PREPARE,PRESERVE,PRIMARY + * KEYWORD: 'PAD' + * KEYWORD: 'PARTIAL' + * KEYWORD: 'POSITION' + * KEYWORD: 'PRECISION' + * KEYWORD: 'PREPARE' + * KEYWORD: 'PRESERVE' + * KEYWORD: 'PRIMARY' + * + * From line: PRIOR,PRIVILEGES,PROCEDURE,PUBLIC + * KEYWORD: 'PRIOR' + * KEYWORD: 'PRIVILEGES' + * KEYWORD: 'PROCEDURE' + * KEYWORD: 'PUBLIC' + * + * From line: READ,REAL,REFERENCES,RELATIVE,RESTRICT,REVOKE,RIGHT + * KEYWORD: 'READ' + * KEYWORD: 'REAL' + * KEYWORD: 'REFERENCES' + * KEYWORD: 'RELATIVE' + * KEYWORD: 'RESTRICT' + * KEYWORD: 'REVOKE' + * KEYWORD: 'RIGHT' + * + * From line: ROLLBACK,ROWS + * KEYWORD: 'ROLLBACK' + * KEYWORD: 'ROWS' + * + * From line: SCHEMA,SCROLL,SECOND,SECTION,SELECT,SESSION,SESSION_ + * KEYWORD: 'SCHEMA' + * KEYWORD: 'SCROLL' + * KEYWORD: 'SECOND' + * KEYWORD: 'SECTION' + * KEYWORD: 'SELECT' + * KEYWORD: 'SESSION' + * KEYWORD: 'SESSION_' + * + * From line: USER,SET + * KEYWORD: 'USER' + * KEYWORD: 'SET' + * + * From line: SIZE,SMALLINT,SOME,SPACE,SQL,SQLCODE,SQLERROR,SQLSTATE + * KEYWORD: 'SIZE' + * KEYWORD: 'SMALLINT' + * KEYWORD: 'SOME' + * KEYWORD: 'SPACE' + * KEYWORD: 'SQL' + * KEYWORD: 'SQLCODE' + * KEYWORD: 'SQLERROR' + * KEYWORD: 'SQLSTATE' + * + * From line: SUBSTRING,SUM,SYSTEM_USER + * KEYWORD: 'SUBSTRING' + * KEYWORD: 'SUM' + * KEYWORD: 'SYSTEM_USER' + * + * From line: TABLE,TEMPORARY,THEN,TIME,TIMESTAMP,TIMEZONE_ + * KEYWORD: 'TABLE' + * KEYWORD: 'TEMPORARY' + * KEYWORD: 'THEN' + * KEYWORD: 'TIME' + * KEYWORD: 'TIMESTAMP' + * KEYWORD: 'TIMEZONE_' + * + * From line: HOUR,TIMEZONE_MINUTE + * KEYWORD: 'HOUR' + * KEYWORD: 'TIMEZONE_MINUTE' + * + * From line: TO,TRAILING,TRANSACTION,TRANSLATE,TRANSLATION,TRIM,TRUE + * KEYWORD: 'TO' + * KEYWORD: 'TRAILING' + * KEYWORD: 'TRANSACTION' + * KEYWORD: 'TRANSLATE' + * KEYWORD: 'TRANSLATION' + * KEYWORD: 'TRIM' + * KEYWORD: 'TRUE' + * + * From line: UNION,UNIQUE,UNKNOWN,UPDATE,UPPER,USAGE,USER,USING + * KEYWORD: 'UNION' + * KEYWORD: 'UNIQUE' + * KEYWORD: 'UNKNOWN' + * KEYWORD: 'UPDATE' + * KEYWORD: 'UPPER' + * KEYWORD: 'USAGE' + * KEYWORD: 'USER' + * KEYWORD: 'USING' + * + * From line: VALUE,VALUES,VARCHAR,VARYING,VIEW + * KEYWORD: 'VALUE' + * KEYWORD: 'VALUES' + * KEYWORD: 'VARCHAR' + * KEYWORD: 'VARYING' + * KEYWORD: 'VIEW' + * + * From line: WHEN,WHENEVER,WHERE,WITH,WORK,WRITE + * KEYWORD: 'WHEN' + * KEYWORD: 'WHENEVER' + * KEYWORD: 'WHERE' + * KEYWORD: 'WITH' + * KEYWORD: 'WORK' + * KEYWORD: 'WRITE' + * + * From line: YEAR + * KEYWORD: 'YEAR' + * + * From line: ZONE + * KEYWORD: 'ZONE' + */ +static char *keywords[] = { + "ABSOLUTE", + "ACTION", + "ADD", + "ALL", + "ALLOCATE", + "ALTER", + "AND", + "ANY", + "ARE", + "AS", + "ASC", + "ASSERTION", + "AT", + "AUTHORIZATION", + "AVG", + "BEGIN", + "BETWEEN", + "BIT", + "BIT_LENGTH", + "BOTH", + "BY", + "CASCADE", + "CASCADED", + "CASE", + "CAST", + "CATALOG", + "CHAR", + "CHARACTER", + "CHAR_", + "LENGTH", + "CHARACTER_LENGTH", + "CHECK", + "CLOSE", + "COALESCE", + "COLLATE", + "COLLATION", + "COLUMN", + "COMMIT", + "CONNECT", + "CONNECTION", + "CONSTRAINT", + "CONSTRAINTS", + "CONTINUE", + "CONVERT", + "CORRESPONDING", + "COUNT", + "CREATE", + "CROSS", + "CURRENT", + "CURRENT_DATE", + "CURRENT_TIME", + "CURRENT_TIMESTAMP", + "CURRENT_", + "USER", + "CURSOR", + "DATE", + "DAY", + "DEALLOCATE", + "DEC", + "DECIMAL", + "DECLARE", + "DEFAULT", + "DEFERRABLE", + "DEFERRED", + "DELETE", + "DESC", + "DESCRIBE", + "DESCRIPTOR", + "DIAGNOSTICS", + "DISCONNECT", + "DISTINCT", + "DOMAIN", + "DOUBLE", + "DROP", + "ELSE", + "END", + "END", + "EXEC", + "ESCAPE", + "EXCEPT", + "EXCEPTION", + "EXEC", + "EXECUTE", + "EXISTS", + "EXTERNAL", + "EXTRACT", + "FALSE", + "FETCH", + "FIRST", + "FLOAT", + "FOR", + "FOREIGN", + "FOUND", + "FROM", + "FULL", + "GET", + "GLOBAL", + "GO", + "GOTO", + "GRANT", + "GROUP", + "HAVING", + "HOUR", + "IDENTITY", + "IMMEDIATE", + "IN", + "INDICATOR", + "INITIALLY", + "INNER", + "INPUT", + "INSENSITIVE", + "INSERT", + "INT", + "INTEGER", + "INTERSECT", + "INTERVAL", + "INTO", + "IS", + "ISOLATION", + "JOIN", + "KEY", + "LANGUAGE", + "LAST", + "LEADING", + "LEFT", + "LEVEL", + "LIKE", + "LOCAL", + "LOWER", + "MATCH", + "MAX", + "MIN", + "MINUTE", + "MODULE", + "MONTH", + "NAMES", + "NATIONAL", + "NATURAL", + "NCHAR", + "NEXT", + "NO", + "NOT", + "NULL", + "NULLIF", + "NUMERIC", + "OCTET_LENGTH", + "OF", + "ON", + "ONLY", + "OPEN", + "OPTION", + "OR", + "ORDER", + "OUTER", + "OUTPUT", + "OVERLAPS", + "PAD", + "PARTIAL", + "POSITION", + "PRECISION", + "PREPARE", + "PRESERVE", + "PRIMARY", + "PRIOR", + "PRIVILEGES", + "PROCEDURE", + "PUBLIC", + "READ", + "REAL", + "REFERENCES", + "RELATIVE", + "RESTRICT", + "REVOKE", + "RIGHT", + "ROLLBACK", + "ROWS", + "SCHEMA", + "SCROLL", + "SECOND", + "SECTION", + "SELECT", + "SESSION", + "SESSION_", + "USER", + "SET", + "SIZE", + "SMALLINT", + "SOME", + "SPACE", + "SQL", + "SQLCODE", + "SQLERROR", + "SQLSTATE", + "SUBSTRING", + "SUM", + "SYSTEM_USER", + "TABLE", + "TEMPORARY", + "THEN", + "TIME", + "TIMESTAMP", + "TIMEZONE_", + "HOUR", + "TIMEZONE_MINUTE", + "TO", + "TRAILING", + "TRANSACTION", + "TRANSLATE", + "TRANSLATION", + "TRIM", + "TRUE", + "UNION", + "UNIQUE", + "UNKNOWN", + "UPDATE", + "UPPER", + "USAGE", + "USER", + "USING", + "VALUE", + "VALUES", + "VARCHAR", + "VARYING", + "VIEW", + "WHEN", + "WHENEVER", + "WHERE", + "WITH", + "WORK", + "WRITE", + "YEAR", + "ZONE", +}; +/* Hash score: 675 */ +static int keywordCode(const char *z, int n){ + /* zText[] encodes 1645 bytes of keywords in 1047 bytes */ + /* DISCONNECTIONLYEAREADDEALLOCATEMPORARYINTERSECTIONCHAR */ + /* ACTER_LENGTHENDECIMALTEREALANGUAGETABLEVELSECONDECLAREFERENCES */ + /* CAPEXCEPTIONEXTERNALIKEYSCROLLBACKVARCHAR_INTERVALUESMALLINT */ + /* EGEREVOKEXECUTENDEFERRABLEADINGLOBALOCALASTIMEZONE_MINUTEXISTS */ + /* CHEMATCHECKABSOLUTEXTRACTRANSACTIONAMESQLCODELETEASSERTION */ + /* ATIONALEFTRANSLATEAUTHORIZATIONATURALOWERELATIVEBEGINDICATOR */ + /* DERESTRICTRANSLATIONOTRIMMEDIATEBETWEENULLIFALSELECTRAILING */ + /* ROUPDATEBIT_LENGTHAVINGOTOCTET_LENGTHOURIGHTRUEBOTHOUROWS */ + /* QLERRORCASETCLOSESSION_COLLATECOLLATIONUMERICREATECURRENT_DATE */ + /* CURSORDESCRIBEDESCRIPTORDOMAINITIALLYDOUBLEDROPENFETCH */ + /* ISOLATIONJOINNERMODULEMONTHOPTIONPADAYPARTIALPOSITIONPRECISION */ + /* PREPAREPRIORPRIVILEGESQLSTATEPROCEDUREUNIONUSAGEWHEREWITHWRITE */ + /* ANDEFAULTANYAVGRANTBYCASCADEDEFERREDIAGNOSTICSIZECASTCATALOG */ + /* COALESCECOLUMNCOMMITCONSTRAINTSOMECONTINUECONVERTCORRESPONDING */ + /* COUNTCROSSPACECURRENT_TIMESTAMPRESERVEDISTINCTFIRSTFLOAT */ + /* FOREIGNFOUNDFROMAXFULLIDENTITYINPUTINSENSITIVEINSERTINTOFOUTER */ + /* OUTPUTOVERLAPSUBSTRINGPRIMARYPUBLICSUMSYSTEM_USERUNIQUEUNKNOWN */ + /* UPPERUSINGVARYINGVIEWHENEVERWORK */ + static const char zText[1046] = { + 'D','I','S','C','O','N','N','E','C','T','I','O','N','L','Y','E','A','R', + 'E','A','D','D','E','A','L','L','O','C','A','T','E','M','P','O','R','A', + 'R','Y','I','N','T','E','R','S','E','C','T','I','O','N','C','H','A','R', + 'A','C','T','E','R','_','L','E','N','G','T','H','E','N','D','E','C','I', + 'M','A','L','T','E','R','E','A','L','A','N','G','U','A','G','E','T','A', + 'B','L','E','V','E','L','S','E','C','O','N','D','E','C','L','A','R','E', + 'F','E','R','E','N','C','E','S','C','A','P','E','X','C','E','P','T','I', + 'O','N','E','X','T','E','R','N','A','L','I','K','E','Y','S','C','R','O', + 'L','L','B','A','C','K','V','A','R','C','H','A','R','_','I','N','T','E', + 'R','V','A','L','U','E','S','M','A','L','L','I','N','T','E','G','E','R', + 'E','V','O','K','E','X','E','C','U','T','E','N','D','E','F','E','R','R', + 'A','B','L','E','A','D','I','N','G','L','O','B','A','L','O','C','A','L', + 'A','S','T','I','M','E','Z','O','N','E','_','M','I','N','U','T','E','X', + 'I','S','T','S','C','H','E','M','A','T','C','H','E','C','K','A','B','S', + 'O','L','U','T','E','X','T','R','A','C','T','R','A','N','S','A','C','T', + 'I','O','N','A','M','E','S','Q','L','C','O','D','E','L','E','T','E','A', + 'S','S','E','R','T','I','O','N','A','T','I','O','N','A','L','E','F','T', + 'R','A','N','S','L','A','T','E','A','U','T','H','O','R','I','Z','A','T', + 'I','O','N','A','T','U','R','A','L','O','W','E','R','E','L','A','T','I', + 'V','E','B','E','G','I','N','D','I','C','A','T','O','R','D','E','R','E', + 'S','T','R','I','C','T','R','A','N','S','L','A','T','I','O','N','O','T', + 'R','I','M','M','E','D','I','A','T','E','B','E','T','W','E','E','N','U', + 'L','L','I','F','A','L','S','E','L','E','C','T','R','A','I','L','I','N', + 'G','R','O','U','P','D','A','T','E','B','I','T','_','L','E','N','G','T', + 'H','A','V','I','N','G','O','T','O','C','T','E','T','_','L','E','N','G', + 'T','H','O','U','R','I','G','H','T','R','U','E','B','O','T','H','O','U', + 'R','O','W','S','Q','L','E','R','R','O','R','C','A','S','E','T','C','L', + 'O','S','E','S','S','I','O','N','_','C','O','L','L','A','T','E','C','O', + 'L','L','A','T','I','O','N','U','M','E','R','I','C','R','E','A','T','E', + 'C','U','R','R','E','N','T','_','D','A','T','E','C','U','R','S','O','R', + 'D','E','S','C','R','I','B','E','D','E','S','C','R','I','P','T','O','R', + 'D','O','M','A','I','N','I','T','I','A','L','L','Y','D','O','U','B','L', + 'E','D','R','O','P','E','N','F','E','T','C','H','I','S','O','L','A','T', + 'I','O','N','J','O','I','N','N','E','R','M','O','D','U','L','E','M','O', + 'N','T','H','O','P','T','I','O','N','P','A','D','A','Y','P','A','R','T', + 'I','A','L','P','O','S','I','T','I','O','N','P','R','E','C','I','S','I', + 'O','N','P','R','E','P','A','R','E','P','R','I','O','R','P','R','I','V', + 'I','L','E','G','E','S','Q','L','S','T','A','T','E','P','R','O','C','E', + 'D','U','R','E','U','N','I','O','N','U','S','A','G','E','W','H','E','R', + 'E','W','I','T','H','W','R','I','T','E','A','N','D','E','F','A','U','L', + 'T','A','N','Y','A','V','G','R','A','N','T','B','Y','C','A','S','C','A', + 'D','E','D','E','F','E','R','R','E','D','I','A','G','N','O','S','T','I', + 'C','S','I','Z','E','C','A','S','T','C','A','T','A','L','O','G','C','O', + 'A','L','E','S','C','E','C','O','L','U','M','N','C','O','M','M','I','T', + 'C','O','N','S','T','R','A','I','N','T','S','O','M','E','C','O','N','T', + 'I','N','U','E','C','O','N','V','E','R','T','C','O','R','R','E','S','P', + 'O','N','D','I','N','G','C','O','U','N','T','C','R','O','S','S','P','A', + 'C','E','C','U','R','R','E','N','T','_','T','I','M','E','S','T','A','M', + 'P','R','E','S','E','R','V','E','D','I','S','T','I','N','C','T','F','I', + 'R','S','T','F','L','O','A','T','F','O','R','E','I','G','N','F','O','U', + 'N','D','F','R','O','M','A','X','F','U','L','L','I','D','E','N','T','I', + 'T','Y','I','N','P','U','T','I','N','S','E','N','S','I','T','I','V','E', + 'I','N','S','E','R','T','I','N','T','O','F','O','U','T','E','R','O','U', + 'T','P','U','T','O','V','E','R','L','A','P','S','U','B','S','T','R','I', + 'N','G','P','R','I','M','A','R','Y','P','U','B','L','I','C','S','U','M', + 'S','Y','S','T','E','M','_','U','S','E','R','U','N','I','Q','U','E','U', + 'N','K','N','O','W','N','U','P','P','E','R','U','S','I','N','G','V','A', + 'R','Y','I','N','G','V','I','E','W','H','E','N','E','V','E','R','W','O', + 'R','K', + }; + static const unsigned int aHash[128] = { + 209, 120, 230, 149, 0, 0, 223, 226, 219, 196, 0, 155, 212, + 0, 41, 0, 0, 220, 231, 153, 44, 115, 124, 25, 48, 232, + 0, 157, 91, 142, 20, 132, 0, 0, 0, 71, 169, 138, 119, + 117, 168, 0, 0, 184, 217, 0, 170, 194, 0, 203, 165, 0, + 186, 55, 6, 129, 31, 229, 104, 127, 51, 131, 176, 29, 178, + 200, 172, 83, 198, 166, 134, 207, 74, 102, 0, 163, 130, 202, + 36, 123, 189, 0, 0, 108, 175, 201, 179, 192, 206, 121, 181, + 204, 133, 0, 180, 205, 160, 167, 0, 86, 227, 0, 214, 197, + 187, 68, 228, 154, 164, 215, 0, 218, 216, 58, 137, 0, 80, + 49, 161, 173, 146, 0, 27, 195, 0, 224, 210, 2, + }; + static const unsigned int aNext[232] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 5, 0, 0, 0, 18, 4, 0, 0, 10, + 0, 13, 0, 0, 0, 0, 0, 0, 23, 0, 7, 0, 33, + 0, 19, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 52, 21, 9, 0, 17, 28, 45, 0, 40, 26, 0, 0, 0, + 0, 0, 0, 43, 0, 11, 0, 0, 70, 0, 75, 53, 0, + 0, 63, 59, 0, 62, 0, 0, 0, 0, 78, 85, 87, 0, + 73, 0, 0, 56, 0, 0, 0, 12, 0, 0, 0, 64, 32, + 35, 94, 0, 22, 24, 47, 92, 89, 0, 110, 0, 0, 0, + 106, 0, 42, 0, 16, 72, 100, 0, 0, 54, 0, 0, 3, + 34, 0, 128, 1, 77, 61, 114, 125, 93, 30, 0, 65, 69, + 60, 90, 98, 0, 95, 147, 81, 0, 118, 152, 15, 0, 140, + 39, 0, 82, 37, 159, 8, 67, 66, 99, 96, 50, 151, 122, + 0, 113, 0, 141, 139, 0, 0, 162, 0, 0, 57, 84, 112, + 174, 177, 105, 171, 150, 107, 0, 156, 0, 185, 0, 126, 182, + 143, 183, 136, 0, 199, 188, 191, 0, 0, 79, 38, 88, 103, + 0, 158, 101, 97, 145, 190, 211, 144, 0, 213, 109, 111, 0, + 221, 222, 208, 193, 46, 76, 0, 135, 148, 116, 225, + }; + static const unsigned char aLen[232] = { + 10, 2, 10, 7, 4, 4, 4, 3, 10, 3, 8, 9, 9, + 7, 5, 16, 4, 9, 6, 4, 3, 7, 5, 4, 8, 3, + 5, 5, 4, 6, 7, 3, 10, 6, 9, 6, 4, 8, 4, + 3, 6, 8, 7, 5, 8, 6, 5, 8, 7, 6, 7, 4, + 4, 3, 10, 7, 6, 5, 4, 15, 9, 4, 2, 3, 6, + 2, 6, 6, 5, 5, 8, 7, 11, 6, 5, 7, 6, 9, + 2, 8, 4, 9, 13, 2, 7, 5, 8, 5, 9, 5, 8, + 11, 3, 4, 9, 7, 6, 4, 5, 6, 8, 5, 6, 10, + 3, 6, 4, 2, 12, 4, 5, 4, 4, 4, 4, 8, 4, + 3, 5, 7, 8, 7, 9, 7, 6, 12, 4, 6, 8, 10, + 4, 2, 6, 9, 6, 4, 4, 5, 9, 4, 5, 6, 5, + 6, 3, 3, 7, 8, 9, 7, 3, 5, 10, 8, 3, 9, + 5, 5, 5, 4, 5, 3, 7, 3, 3, 5, 2, 8, 7, + 3, 8, 11, 2, 4, 4, 7, 8, 6, 6, 11, 10, 3, + 4, 8, 7, 13, 2, 5, 5, 5, 17, 7, 8, 12, 4, + 9, 8, 8, 5, 5, 7, 3, 5, 4, 3, 4, 8, 5, + 11, 6, 4, 2, 5, 6, 8, 9, 7, 6, 3, 11, 4, + 4, 4, 6, 7, 5, 5, 7, 4, 8, 4, 4, + }; + static const unsigned short int aOffset[232] = { + 0, 1, 3, 3, 11, 14, 17, 19, 21, 23, 23, 29, 38, + 43, 49, 50, 50, 50, 60, 64, 66, 68, 73, 77, 80, 86, + 88, 91, 94, 96, 101, 101, 106, 114, 119, 119, 127, 128, 135, + 137, 140, 142, 150, 153, 158, 163, 163, 168, 173, 179, 184, 184, + 184, 190, 192, 200, 206, 211, 215, 218, 218, 222, 223, 227, 227, + 228, 232, 237, 241, 244, 249, 256, 262, 267, 272, 276, 281, 287, + 287, 295, 302, 305, 314, 322, 326, 332, 336, 344, 347, 354, 358, + 365, 375, 377, 379, 388, 394, 394, 399, 402, 407, 414, 417, 423, + 423, 432, 437, 437, 440, 451, 454, 458, 462, 465, 468, 471, 479, + 481, 484, 487, 487, 495, 502, 510, 516, 522, 530, 534, 540, 548, + 548, 555, 558, 562, 571, 577, 579, 583, 588, 597, 599, 604, 610, + 615, 621, 623, 626, 633, 641, 650, 654, 657, 662, 671, 671, 679, + 688, 693, 698, 703, 707, 712, 714, 721, 724, 726, 731, 733, 733, + 734, 740, 747, 751, 757, 761, 765, 772, 780, 786, 792, 792, 799, + 802, 806, 814, 821, 822, 834, 839, 843, 848, 848, 848, 848, 856, + 856, 864, 872, 880, 885, 890, 890, 897, 902, 905, 908, 912, 920, + 925, 936, 942, 945, 947, 952, 958, 965, 974, 981, 987, 990, 997, + 997, 997, 1001, 1007, 1014, 1019, 1024, 1031, 1034, 1034, 1042, + }; + int h, i; + if( n<2 ) return 0; + h = ((charMap(z[0])*4) ^ + (charMap(z[n-1])*3) ^ + n) % 128; + for(i=((int)aHash[h])-1; i>=0; i=((int)aNext[i])-1){ + if( aLen[i]==n && casecmp(&zText[aOffset[i]],z,n)==0 ){ + return 1; + } + } + return 0; +} + +static gboolean +is_keyword (const char *z) +{ + return keywordCode(z, strlen (z)); +} + + +static void +test_keywords (void) +{ + int i; + for (i = 0; i < 232; i++) { + if (! is_keyword (keywords[i])) + g_print ("KEYWORK %s ignored!\n", keywords[i]); + } +} + diff --git a/.flatpak-builder/cache/objects/7d/66342d6a4ed7314ebfabfeae199044f8aa9b46944259ccb0b5449c1bc20e5a.file b/.flatpak-builder/cache/objects/7d/66342d6a4ed7314ebfabfeae199044f8aa9b46944259ccb0b5449c1bc20e5a.file new file mode 100644 index 0000000..2dc66ea --- /dev/null +++ b/.flatpak-builder/cache/objects/7d/66342d6a4ed7314ebfabfeae199044f8aa9b46944259ccb0b5449c1bc20e5a.file @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2006 - 2014 Vivien Malerba + * Copyright (C) 2007 Armin Burgmeier + * Copyright (C) 2007 Murray Cumming + * Copyright (C) 2009 Bas Driessen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GDA_SERVER_PROVIDER_EXTRA__ +#define __GDA_SERVER_PROVIDER_EXTRA__ + +#include +#include +#include +#include +#include + +G_BEGIN_DECLS + +/** + * SECTION:provider-support + * @short_description: Methods dedicated to implementing providers + * @title: Misc API for database providers + * @stability: Stable + * @see_also: + * + * The methods mentioned in this section are reserved for database providers implementations and should + * not bu used by developers outside that scope. + */ + +/* + * GdaSqlParser associated to each provider + */ +GdaSqlParser *gda_server_provider_internal_get_parser (GdaServerProvider *prov); + +/* + * Default perform operation + */ +gboolean gda_server_provider_perform_operation_default (GdaServerProvider *provider, GdaConnection *cnc, + GdaServerOperation *op, GError **error); + +/* default data handler method */ +GdaDataHandler *gda_server_provider_handler_use_default (GdaServerProvider *provider, GType type); + +/* Convert a SELECT statement with potentially some parameters to another SELECT statement + * where all the parameters are removed and where the WHERE condition is set to "0 = 1" + * to make sure no row will ever be returned + */ +GdaStatement *gda_select_alter_select_for_empty (GdaStatement *stmt, GError **error); + +/* + * Help to implement the GdaDataHandler retrieving for the providers + */ +typedef struct { + GdaConnection *cnc; + GType g_type; + gchar *dbms_type; +} GdaServerProviderHandlerInfo; +GdaDataHandler *gda_server_provider_handler_find (GdaServerProvider *prov, GdaConnection *cnc, + GType g_type, const gchar *dbms_type); +void gda_server_provider_handler_declare (GdaServerProvider *prov, GdaDataHandler *dh, + GdaConnection *cnc, + GType g_type, const gchar *dbms_type); +void _gda_server_provider_handlers_clear_for_cnc (GdaServerProvider *prov, GdaConnection *cnc); + +/* + * misc + */ +gchar *gda_server_provider_load_resource_contents (const gchar *prov_name, const gchar *resource); + +G_END_DECLS + +#endif + + + diff --git a/.flatpak-builder/cache/objects/7d/98b6a9116c6c4e053f0800448969691f2e4c8aaf8ea3f1549dc476dda91367.dirtree b/.flatpak-builder/cache/objects/7d/98b6a9116c6c4e053f0800448969691f2e4c8aaf8ea3f1549dc476dda91367.dirtree new file mode 100644 index 0000000..79c0ccb Binary files /dev/null and b/.flatpak-builder/cache/objects/7d/98b6a9116c6c4e053f0800448969691f2e4c8aaf8ea3f1549dc476dda91367.dirtree differ diff --git a/.flatpak-builder/cache/objects/7d/99de4d16fae1c4f87448a988e122a594409a8ddd4a279aa369baec8477af07.dirtree b/.flatpak-builder/cache/objects/7d/99de4d16fae1c4f87448a988e122a594409a8ddd4a279aa369baec8477af07.dirtree new file mode 100644 index 0000000..8eaabc6 Binary files /dev/null and b/.flatpak-builder/cache/objects/7d/99de4d16fae1c4f87448a988e122a594409a8ddd4a279aa369baec8477af07.dirtree differ diff --git a/.flatpak-builder/cache/objects/7d/d5104fff9637508aad3dd2bcdda2310cf907a9faa05c0df9b7bba7209b6d5a.dirtree b/.flatpak-builder/cache/objects/7d/d5104fff9637508aad3dd2bcdda2310cf907a9faa05c0df9b7bba7209b6d5a.dirtree new file mode 100644 index 0000000..7d4fcc3 Binary files /dev/null and b/.flatpak-builder/cache/objects/7d/d5104fff9637508aad3dd2bcdda2310cf907a9faa05c0df9b7bba7209b6d5a.dirtree differ diff --git a/.flatpak-builder/cache/objects/7e/fe4208c83594d6118023f9557604750274bae4b815c710f830b6b77613b7b5.file b/.flatpak-builder/cache/objects/7e/fe4208c83594d6118023f9557604750274bae4b815c710f830b6b77613b7b5.file new file mode 100755 index 0000000..3361cc6 --- /dev/null +++ b/.flatpak-builder/cache/objects/7e/fe4208c83594d6118023f9557604750274bae4b815c710f830b6b77613b7b5.file @@ -0,0 +1,40 @@ +#!/usr/bin/env python3 + +# blueprint-compiler.py +# +# Copyright 2021 James Westman +# +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation; either version 3 of the +# License, or (at your option) any later version. +# +# This file is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program. If not, see . +# +# SPDX-License-Identifier: LGPL-3.0-or-later + +import os, sys + +# These variables should be set by meson. If they aren't, we're running +# uninstalled, and we might have to guess some values. +version = "0.8.1" +module_path = r"/app/lib/python3.10/site-packages/" +libdir = r"/app/lib" + +if version == "\u0040VERSION@": + version = "uninstalled" + libdir = None +else: + # If Meson set the configuration values, insert the module path it set + sys.path.insert(0, module_path) + +from blueprintcompiler import main + +if __name__ == "__main__": + main.main(version, libdir) diff --git a/.flatpak-builder/cache/objects/7f/12196efb25c58e74bb86ea23066099dfe86e1516fce7368ed0e844780a48bb.file b/.flatpak-builder/cache/objects/7f/12196efb25c58e74bb86ea23066099dfe86e1516fce7368ed0e844780a48bb.file new file mode 100644 index 0000000..dd82b55 --- /dev/null +++ b/.flatpak-builder/cache/objects/7f/12196efb25c58e74bb86ea23066099dfe86e1516fce7368ed0e844780a48bb.file @@ -0,0 +1,60 @@ +/* + * gda-db-buildable.h + * + * Copyright (C) 2018 Pavlo Solntsev + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +#ifndef GDA_DB_BUILDABLE_H +#define GDA_DB_BUILDABLE_H + +#include +#include +#include +#include + +G_BEGIN_DECLS + +#define GDA_TYPE_DB_BUILDABLE gda_db_buildable_get_type () + +G_DECLARE_INTERFACE(GdaDbBuildable, gda_db_buildable, GDA, DB_BUILDABLE, GObject) + +struct _GdaDbBuildableInterface +{ + GTypeInterface parent_iface; + + gboolean (*parse_node)(GdaDbBuildable *self, + xmlNodePtr node, + GError **error); + + gboolean (*write_node)(GdaDbBuildable *self, + xmlNodePtr node, + GError **error); +}; + +gboolean gda_db_buildable_parse_node (GdaDbBuildable *self, + xmlNodePtr node, + GError **error); + +gboolean gda_db_buildable_write_node (GdaDbBuildable *self, + xmlNodePtr node, + GError **error); + +G_END_DECLS + +#endif /* end of include guard: GDA-DB-BUILDABLE_H */ + + diff --git a/.flatpak-builder/cache/objects/7f/8213ce9728e040214e6022319c9efab77cfb80f3ea4d2d4200998c2bde428c.file b/.flatpak-builder/cache/objects/7f/8213ce9728e040214e6022319c9efab77cfb80f3ea4d2d4200998c2bde428c.file new file mode 100644 index 0000000..fdffad9 --- /dev/null +++ b/.flatpak-builder/cache/objects/7f/8213ce9728e040214e6022319c9efab77cfb80f3ea4d2d4200998c2bde428c.file @@ -0,0 +1,131 @@ +/* + * Copyright (C) 2000 Reinhard Müller + * Copyright (C) 2000 - 2002 Rodrigo Moya + * Copyright (C) 2001 Carlos Perelló Marín + * Copyright (C) 2001 - 2013 Vivien Malerba + * Copyright (C) 2002 Gonzalo Paniagua Javier + * Copyright (C) 2006 - 2007 Murray Cumming + * Copyright (C) 2007 Armin Burgmeier + * Copyright (C) 2008 Przemysław Grzegorczyk + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GDA_UTIL_H__ +#define __GDA_UTIL_H__ + +#include +#include "gda-holder.h" +#include "gda-row.h" +#include "gda-connection.h" +#include +#include + +G_BEGIN_DECLS + +/** + * SECTION:gda-util + * @short_description: Utility functions + * @title: Utility functions + * @stability: Stable + * @see_also: + * + * Some useful functions. + */ + +/* + * Type utilities + */ +const gchar *gda_g_type_to_string (GType type); +GType gda_g_type_from_string (const gchar *str); + +/* + * SQL escaping + */ +gchar *gda_default_escape_string (const gchar *string); +gchar *gda_default_unescape_string (const gchar *string); +guint gda_identifier_hash (const gchar *id); +gboolean gda_identifier_equal (const gchar *id1, const gchar *id2); +gchar **gda_completion_list_get (GdaConnection *cnc, const gchar *sql, gint start, gint end); +gchar **gda_sql_identifier_split (const gchar *id); +gchar *gda_sql_identifier_quote (const gchar *id, GdaConnection *cnc, GdaServerProvider *prov, + gboolean meta_store_convention, gboolean force_quotes); + +/* + * Param & model utilities + */ +gboolean gda_utility_check_data_model (GdaDataModel *model, gint nbcols, ...); +gboolean gda_utility_check_data_model_v (GdaDataModel *model, gint nbcols, GType* types); +gboolean gda_utility_data_model_dump_data_to_xml (GdaDataModel *model, xmlNodePtr parent, + const gint *cols, gint nb_cols, const gint *rows, gint nb_rows, + gboolean use_col_ids); +const gchar *gda_utility_data_model_find_column_description (GdaDataSelect *model, const gchar *field_name); +gboolean gda_utility_holder_load_attributes (GdaHolder *holder, xmlNodePtr node, GSList *sources, GError **error); + +GdaSqlStatement *gda_statement_rewrite_for_default_values (GdaStatement *stmt, GdaSet *params, + gboolean remove, GError **error); + +/* + * translate any text to an alphanumerical text + */ +gchar *gda_text_to_alphanum (const gchar *text); +gchar *gda_alphanum_to_text (gchar *text); + +/* + * Statement computation (using data from meta store) + */ +GdaSqlExpr *gda_compute_unique_table_row_condition (GdaSqlStatementSelect *stsel, GdaMetaTable *mtable, + gboolean require_pk, GError **error); +GdaSqlExpr *gda_compute_unique_table_row_condition_with_cnc (GdaConnection *cnc, + GdaSqlStatementSelect *stsel, + GdaMetaTable *mtable, gboolean require_pk, + GError **error); + +gboolean gda_compute_dml_statements (GdaConnection *cnc, GdaStatement *select_stmt, gboolean require_pk, + GdaStatement **insert_stmt, GdaStatement **update_stmt, GdaStatement **delete_stmt, + GError **error); +GdaSqlStatement *gda_compute_select_statement_from_update (GdaStatement *update_stmt, GError **error); +GdaSqlStatement *gda_rewrite_sql_statement_for_null_parameters (GdaSqlStatement *sqlst, GdaSet *params, + gboolean *out_modified, GError **error); +gboolean gda_rewrite_statement_for_null_parameters (GdaStatement *stmt, GdaSet *params, + GdaStatement **out_stmt, GError **error); +void _gda_modify_statement_param_types (GdaStatement *stmt, GdaDataModel *model); + +/* + * DSN and connection string manipulations + */ +gchar *gda_rfc1738_encode (const gchar *string); +gboolean gda_rfc1738_decode (gchar *string); +void gda_dsn_split (const gchar *string, gchar **out_dsn, + gchar **out_username, gchar **out_password); +void gda_connection_string_split (const gchar *string, gchar **out_cnc_params, gchar **out_provider, + gchar **out_username, gchar **out_password); + +/* + * Date and time parsing from ISO 8601 (well, part of it) + */ +gboolean gda_parse_iso8601_date (GDate *gdate, const gchar *value); +GdaTime *gda_parse_iso8601_time (const gchar *value); + +gboolean gda_parse_formatted_date (GDate *gdate, const gchar *value, + GDateDMY first, GDateDMY second, GDateDMY third, gchar sep); +GdaTime *gda_parse_formatted_time (const gchar *value, gchar sep); +GDateTime *gda_parse_formatted_timestamp (const gchar *value, + GDateDMY first, GDateDMY second, GDateDMY third, gchar sep); + +G_END_DECLS + +#endif diff --git a/.flatpak-builder/cache/objects/7f/af90ba3059528122da747d939f490a0639a52e9b8ded8087eaf1f3303cd15c.file b/.flatpak-builder/cache/objects/7f/af90ba3059528122da747d939f490a0639a52e9b8ded8087eaf1f3303cd15c.file new file mode 100644 index 0000000..2ba6df2 --- /dev/null +++ b/.flatpak-builder/cache/objects/7f/af90ba3059528122da747d939f490a0639a52e9b8ded8087eaf1f3303cd15c.file @@ -0,0 +1,166 @@ +/* + * Copyright (C) 2008 - 2011 Vivien Malerba + * Copyright (C) 2013 Daniel Espinosa + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + + +#ifndef __GDA_SET_H_ +#define __GDA_SET_H_ + +#include "gda-value.h" +#include + +G_BEGIN_DECLS + +/* error reporting */ +extern GQuark gda_set_error_quark (void); +#define GDA_SET_ERROR gda_set_error_quark () + +typedef enum +{ + GDA_SET_XML_SPEC_ERROR, + GDA_SET_HOLDER_NOT_FOUND_ERROR, + GDA_SET_INVALID_ERROR, + GDA_SET_READ_ONLY_ERROR, + GDA_SET_IMPLEMENTATION_ERROR +} GdaSetError; + +typedef struct _GdaSetNode GdaSetNode; +typedef struct _GdaSetGroup GdaSetGroup; +typedef struct _GdaSetSource GdaSetSource; + +#define GDA_TYPE_SET_NODE (gda_set_node_get_type ()) +#define GDA_SET_NODE(x) ((GdaSetNode *)(x)) +GType gda_set_node_get_type (void) G_GNUC_CONST; +GdaSetNode *gda_set_node_new (GdaHolder *holder); +void gda_set_node_free (GdaSetNode *node); +GdaSetNode *gda_set_node_copy (GdaSetNode *node); +GdaHolder *gda_set_node_get_holder (GdaSetNode *node); +void gda_set_node_set_holder (GdaSetNode *node, GdaHolder *holder); +GdaDataModel *gda_set_node_get_data_model (GdaSetNode *node); +void gda_set_node_set_data_model (GdaSetNode *node, GdaDataModel *model); +gint gda_set_node_get_source_column (GdaSetNode *node); +void gda_set_node_set_source_column (GdaSetNode *node, gint column); + +#define GDA_TYPE_SET_GROUP (gda_set_group_get_type ()) +#define GDA_SET_GROUP(x) ((GdaSetGroup *)(x)) +GType gda_set_group_get_type (void) G_GNUC_CONST; +GdaSetGroup *gda_set_group_new (GdaSetNode *node); +void gda_set_group_free (GdaSetGroup *sg); +GdaSetGroup *gda_set_group_copy (GdaSetGroup *sg); +void gda_set_group_add_node (GdaSetGroup *sg, GdaSetNode *node); +GdaSetNode *gda_set_group_get_node (GdaSetGroup *sg); +GSList *gda_set_group_get_nodes (GdaSetGroup *sg); +gint gda_set_group_get_n_nodes (GdaSetGroup *sg); +void gda_set_group_set_source (GdaSetGroup *sg, GdaSetSource *source); +GdaSetSource *gda_set_group_get_source (GdaSetGroup *sg); + +#define GDA_TYPE_SET_SOURCE (gda_set_source_get_type ()) +#define GDA_SET_SOURCE(x) ((GdaSetSource *)(x)) +GType gda_set_source_get_type (void) G_GNUC_CONST; +GdaSetSource *gda_set_source_new (GdaDataModel *model); +void gda_set_source_free (GdaSetSource *s); +GdaSetSource *gda_set_source_copy (GdaSetSource *s); +void gda_set_source_add_node (GdaSetSource *s, GdaSetNode *node); +GSList *gda_set_source_get_nodes (GdaSetSource *s); +gint gda_set_source_get_n_nodes (GdaSetSource *s); +GdaDataModel *gda_set_source_get_data_model (GdaSetSource *s); +void gda_set_source_set_data_model (GdaSetSource *s, GdaDataModel *model); + +/* struct for the object's data */ + +#define GDA_TYPE_SET (gda_set_get_type()) + +G_DECLARE_DERIVABLE_TYPE(GdaSet, gda_set, GDA, SET, GObject) + +/* struct for the object's class */ +struct _GdaSetClass +{ + GObjectClass parent_class; + + GError *(*validate_holder_change)(GdaSet *set, GdaHolder *holder, const GValue *new_value); + GError *(*validate_set) (GdaSet *set); + void (*holder_changed) (GdaSet *set, GdaHolder *holder); + void (*holder_attr_changed) (GdaSet *set, GdaHolder *holder, + const gchar *attr_name, const GValue *attr_value); + void (*public_data_changed) (GdaSet *set); + void (*holder_type_set) (GdaSet *set, GdaHolder *holder); + void (*source_model_changed) (GdaSet *set, GdaSetSource *source); + + /*< private >*/ + /* Padding for future expansion */ + void (*_gda_reserved1) (void); + void (*_gda_reserved2) (void); + void (*_gda_reserved3) (void); + void (*_gda_reserved4) (void); +}; + +/** + * SECTION:gda-set + * @short_description: Container for several values + * @title: GdaSet + * @stability: Stable + * @see_also: #GdaHolder + * + * The #GdaSet object is a container for several values (as #GdaHolder objects). Each #GdaSet object also + * maintains some publicly accessible information about the #GdaHolder objects, through the #GdaSetNode, #GdaSetSource and + * #GdaSetGroup structures (see gda_set_get_node(), gda_set_get_source() and gda_set_get_group()). + * + * It is possible to control the values a #GdaHolder can have in the #GdaSet by connecting to the + * "before-holder-change" signal. + */ + +GdaSet *gda_set_new (GSList *holders); +GdaSet *gda_set_copy (GdaSet *set); +GdaSet *gda_set_new_inline (gint nb, ...); + +GdaSet *gda_set_new_from_spec_string (const gchar *xml_spec, GError **error); +GdaSet *gda_set_new_from_spec_node (xmlNodePtr xml_spec, GError **error); + +gboolean gda_set_set_holder_value (GdaSet *set, GError **error, const gchar *holder_id, ...); +const GValue *gda_set_get_holder_value (GdaSet *set, const gchar *holder_id); +GSList *gda_set_get_holders (GdaSet *set); +GdaHolder *gda_set_get_holder (GdaSet *set, const gchar *holder_id); +GdaHolder *gda_set_get_nth_holder (GdaSet *set, gint pos); +gboolean gda_set_add_holder (GdaSet *set, GdaHolder *holder); +void gda_set_remove_holder (GdaSet *set, GdaHolder *holder); +void gda_set_merge_with_set (GdaSet *set, GdaSet *set_to_merge); +gboolean gda_set_is_valid (GdaSet *set, GError **error); + +void gda_set_replace_source_model (GdaSet *set, GdaSetSource *source, + GdaDataModel *model); + +/* public data lookup functions */ +GSList *gda_set_get_nodes (GdaSet *set); +GdaSetNode *gda_set_get_node (GdaSet *set, GdaHolder *holder); +GSList *gda_set_get_sources (GdaSet *set); +GdaSetSource *gda_set_get_source_for_model (GdaSet *set, GdaDataModel *model); +GdaSetSource *gda_set_get_source (GdaSet *set, GdaHolder *holder); +GSList *gda_set_get_groups (GdaSet *set); +GdaSetGroup *gda_set_get_group (GdaSet *set, GdaHolder *holder); + +/* private */ +gboolean _gda_set_validate (GdaSet *set, GError **error); +GdaSet * gda_set_new_read_only (GSList *holders); + + + + +G_END_DECLS + +#endif diff --git a/.flatpak-builder/cache/objects/7f/ce1d80046e30594109aaee7c9f9943d6432880bc674f40fc0b21649c7ae78a.dirtree b/.flatpak-builder/cache/objects/7f/ce1d80046e30594109aaee7c9f9943d6432880bc674f40fc0b21649c7ae78a.dirtree new file mode 100644 index 0000000..4da2975 Binary files /dev/null and b/.flatpak-builder/cache/objects/7f/ce1d80046e30594109aaee7c9f9943d6432880bc674f40fc0b21649c7ae78a.dirtree differ diff --git a/.flatpak-builder/cache/objects/7f/ea2b38aa9ab4f82e0d56425739932213b61ad7cb5a91d530bc0ce0bbed1bd5.file b/.flatpak-builder/cache/objects/7f/ea2b38aa9ab4f82e0d56425739932213b61ad7cb5a91d530bc0ce0bbed1bd5.file new file mode 100644 index 0000000..94f34ca --- /dev/null +++ b/.flatpak-builder/cache/objects/7f/ea2b38aa9ab4f82e0d56425739932213b61ad7cb5a91d530bc0ce0bbed1bd5.file @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2009 - 2011 Vivien Malerba + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef _GDA_REPETITIVE_STATEMENT_H_ +#define _GDA_REPETITIVE_STATEMENT_H_ + +#include +#include +#include + +G_BEGIN_DECLS + +#define GDA_TYPE_REPETITIVE_STATEMENT (gda_repetitive_statement_get_type ()) +G_DECLARE_DERIVABLE_TYPE(GdaRepetitiveStatement, gda_repetitive_statement, GDA, REPETITIVE_STATEMENT, GObject) + +struct _GdaRepetitiveStatementClass +{ + GObjectClass parent_class; +}; + +/** + * SECTION:gda-repetitive-statement + * @short_description: Execute the same statement several times with different values + * @title: GdaRepetitiveStatement + * @stability: Stable + * @see_also: #GdaStatement, #GdaBatch and #GdaConnection + * + * The #GdaRepetitiveStatement object allows one to specify a statement to be executed + * several times using different variables' values sets for each execution. Using the object + * has almost no interrest at all if the statement to be executed several times has no parameter. + * + * Use the gda_connection_repetitive_statement_execute() method to execute the repetitive statement. + */ + +GdaRepetitiveStatement* gda_repetitive_statement_new (GdaStatement *stmt); +gboolean gda_repetitive_statement_get_template_set (GdaRepetitiveStatement *rstmt, GdaSet **set, GError **error); +GSList *gda_repetitive_statement_get_all_sets (GdaRepetitiveStatement *rstmt); +gboolean gda_repetitive_statement_append_set (GdaRepetitiveStatement *rstmt, GdaSet *values, gboolean make_copy); + +G_END_DECLS + +#endif diff --git a/.flatpak-builder/cache/objects/80/2c312f5eecfe339e7c1e009ffa437f50cc4cc36de291f3b78fbc5abc0b326f.dirtree b/.flatpak-builder/cache/objects/80/2c312f5eecfe339e7c1e009ffa437f50cc4cc36de291f3b78fbc5abc0b326f.dirtree new file mode 100644 index 0000000..06a22a8 Binary files /dev/null and b/.flatpak-builder/cache/objects/80/2c312f5eecfe339e7c1e009ffa437f50cc4cc36de291f3b78fbc5abc0b326f.dirtree differ diff --git a/.flatpak-builder/cache/objects/80/34b22563bec8b122a7bf7d6dd964eb040fc61bda93eb554c11e886385b3cd2.dirtree b/.flatpak-builder/cache/objects/80/34b22563bec8b122a7bf7d6dd964eb040fc61bda93eb554c11e886385b3cd2.dirtree new file mode 100644 index 0000000..2a300d9 Binary files /dev/null and b/.flatpak-builder/cache/objects/80/34b22563bec8b122a7bf7d6dd964eb040fc61bda93eb554c11e886385b3cd2.dirtree differ diff --git a/.flatpak-builder/cache/objects/80/56275e35b5584466c68924a294256a9f39987819156620014d5b411c51be1c.dirtree b/.flatpak-builder/cache/objects/80/56275e35b5584466c68924a294256a9f39987819156620014d5b411c51be1c.dirtree new file mode 100644 index 0000000..5f93116 Binary files /dev/null and b/.flatpak-builder/cache/objects/80/56275e35b5584466c68924a294256a9f39987819156620014d5b411c51be1c.dirtree differ diff --git a/.flatpak-builder/cache/objects/80/df963fb1afef1f35b3658312cba6d69deaf3db23b9d59776843ee5f48f0acb.file b/.flatpak-builder/cache/objects/80/df963fb1afef1f35b3658312cba6d69deaf3db23b9d59776843ee5f48f0acb.file new file mode 120000 index 0000000..ebfe9c5 --- /dev/null +++ b/.flatpak-builder/cache/objects/80/df963fb1afef1f35b3658312cba6d69deaf3db23b9d59776843ee5f48f0acb.file @@ -0,0 +1 @@ +../../share/runtime/locale/mk/share/mk \ No newline at end of file diff --git a/.flatpak-builder/cache/objects/80/e549e362bd4aa95250b82a481a7f681d3ae094f83c68d8d292f1f38dc2f921.dirtree b/.flatpak-builder/cache/objects/80/e549e362bd4aa95250b82a481a7f681d3ae094f83c68d8d292f1f38dc2f921.dirtree new file mode 100644 index 0000000..1340277 Binary files /dev/null and b/.flatpak-builder/cache/objects/80/e549e362bd4aa95250b82a481a7f681d3ae094f83c68d8d292f1f38dc2f921.dirtree differ diff --git a/.flatpak-builder/cache/objects/81/08c46596cc65c3628a3b8c024582b2ada93e05855c23ba0f0f2d2255cb89df.dirtree b/.flatpak-builder/cache/objects/81/08c46596cc65c3628a3b8c024582b2ada93e05855c23ba0f0f2d2255cb89df.dirtree new file mode 100644 index 0000000..3ffc2a0 Binary files /dev/null and b/.flatpak-builder/cache/objects/81/08c46596cc65c3628a3b8c024582b2ada93e05855c23ba0f0f2d2255cb89df.dirtree differ diff --git a/.flatpak-builder/cache/objects/81/2320bbfa095337542c65eb49a5034f0701721f85e1d527ff27e644e0b2977f.file b/.flatpak-builder/cache/objects/81/2320bbfa095337542c65eb49a5034f0701721f85e1d527ff27e644e0b2977f.file new file mode 100644 index 0000000..6babc10 --- /dev/null +++ b/.flatpak-builder/cache/objects/81/2320bbfa095337542c65eb49a5034f0701721f85e1d527ff27e644e0b2977f.file @@ -0,0 +1,298 @@ +# typelib.py +# +# Copyright 2022 James Westman +# +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation; either version 3 of the +# License, or (at your option) any later version. +# +# This file is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program. If not, see . +# +# SPDX-License-Identifier: LGPL-3.0-or-later + +import sys +import typing as T +import math +from ctypes import * +import mmap, os + +from .errors import CompilerBugError + + +BLOB_TYPE_STRUCT = 3 +BLOB_TYPE_BOXED = 4 +BLOB_TYPE_ENUM = 5 +BLOB_TYPE_FLAGS = 6 +BLOB_TYPE_OBJECT = 7 +BLOB_TYPE_INTERFACE = 8 + +TYPE_VOID = 0 +TYPE_BOOLEAN = 1 +TYPE_INT8 = 2 +TYPE_UINT8 = 3 +TYPE_INT16 = 4 +TYPE_UINT16 = 5 +TYPE_INT32 = 6 +TYPE_UINT32 = 7 +TYPE_INT64 = 8 +TYPE_UINT64 = 9 +TYPE_FLOAT = 10 +TYPE_DOUBLE = 11 +TYPE_GTYPE = 12 +TYPE_UTF8 = 13 +TYPE_FILENAME = 14 +TYPE_ARRAY = 15 +TYPE_INTERFACE = 16 +TYPE_GLIST = 17 +TYPE_GSLIST = 18 +TYPE_GHASH = 19 +TYPE_ERROR = 20 +TYPE_UNICHAR = 21 + + +class Field: + def __init__(self, offset: int, type: str, shift=0, mask=None): + self._offset = offset + self._type = type + self._shift = shift + self._mask = (1 << mask) - 1 if mask else None + self._name = f"{offset}__{type}__{shift}__{mask}" + + def __get__(self, typelib: "Typelib", _objtype=None): + if typelib is None: + return self + + def shift_mask(n): + n = n >> self._shift + if self._mask: + n = n & self._mask + return n + + tl = typelib[self._offset] + if self._type == "u8": + return shift_mask(tl.u8) + elif self._type == "u16": + return shift_mask(tl.u16) + elif self._type == "u32": + return shift_mask(tl.u32) + elif self._type == "i8": + return shift_mask(tl.i8) + elif self._type == "i16": + return shift_mask(tl.i16) + elif self._type == "i32": + return shift_mask(tl.i32) + elif self._type == "pointer": + return tl.header[tl.u32] + elif self._type == "offset": + return tl + elif self._type == "string": + return tl.string + elif self._type == "dir_entry": + return tl.header.dir_entry(tl.u16) + else: + raise CompilerBugError(self._type) + + +class Typelib: + AS_DIR_ENTRY = Field(0, "dir_entry") + + HEADER_N_ENTRIES = Field(0x14, "u16") + HEADER_N_LOCAL_ENTRIES = Field(0x16, "u16") + HEADER_DIRECTORY = Field(0x18, "pointer") + HEADER_N_ATTRIBUTES = Field(0x1C, "u32") + HEADER_ATTRIBUTES = Field(0x20, "pointer") + + HEADER_DEPENDENCIES = Field(0x24, "pointer") + + HEADER_NAMESPACE = Field(0x2C, "string") + HEADER_NSVERSION = Field(0x30, "string") + + HEADER_ENTRY_BLOB_SIZE = Field(0x3C, "u16") + HEADER_FUNCTION_BLOB_SIZE = Field(0x3E, "u16") + HEADER_CALLBACK_BLOB_SIZE = Field(0x40, "u16") + HEADER_SIGNAL_BLOB_SIZE = Field(0x42, "u16") + HEADER_PROPERTY_BLOB_SIZE = Field(0x48, "u16") + HEADER_FIELD_BLOB_SIZE = Field(0x4A, "u16") + HEADER_VALUE_BLOB_SIZE = Field(0x4C, "u16") + HEADER_ATTRIBUTE_BLOB_SIZE = Field(0x4E, "u16") + HEADER_ENUM_BLOB_SIZE = Field(0x56, "u16") + HEADER_OBJECT_BLOB_SIZE = Field(0x5A, "u16") + HEADER_INTERFACE_BLOB_SIZE = Field(0x5C, "u16") + + DIR_ENTRY_BLOB_TYPE = Field(0x0, "u16") + DIR_ENTRY_LOCAL = Field(0x2, "u16", 0, 1) + DIR_ENTRY_NAME = Field(0x4, "string") + DIR_ENTRY_OFFSET = Field(0x8, "pointer") + DIR_ENTRY_NAMESPACE = Field(0x8, "string") + + ATTR_OFFSET = Field(0x0, "u32") + ATTR_NAME = Field(0x0, "string") + ATTR_VALUE = Field(0x0, "string") + + TYPE_BLOB_TAG = Field(0x0, "u8", 3, 5) + TYPE_BLOB_INTERFACE = Field(0x2, "dir_entry") + TYPE_BLOB_ARRAY_INNER = Field(0x4, "u32") + + BLOB_NAME = Field(0x4, "string") + + ENUM_GTYPE_NAME = Field(0x8, "string") + ENUM_N_VALUES = Field(0x10, "u16") + ENUM_N_METHODS = Field(0x12, "u16") + ENUM_VALUES = Field(0x18, "offset") + + INTERFACE_GTYPE_NAME = Field(0x8, "string") + INTERFACE_N_PREREQUISITES = Field(0x12, "u16") + INTERFACE_N_PROPERTIES = Field(0x14, "u16") + INTERFACE_N_METHODS = Field(0x16, "u16") + INTERFACE_N_SIGNALS = Field(0x18, "u16") + INTERFACE_N_VFUNCS = Field(0x1A, "u16") + INTERFACE_N_CONSTANTS = Field(0x1C, "u16") + INTERFACE_PREREQUISITES = Field(0x28, "offset") + + OBJ_DEPRECATED = Field(0x02, "u16", 0, 1) + OBJ_ABSTRACT = Field(0x02, "u16", 1, 1) + OBJ_FUNDAMENTAL = Field(0x02, "u16", 2, 1) + OBJ_FINAL = Field(0x02, "u16", 3, 1) + OBJ_GTYPE_NAME = Field(0x08, "string") + OBJ_PARENT = Field(0x10, "dir_entry") + OBJ_GTYPE_STRUCT = Field(0x14, "string") + OBJ_N_INTERFACES = Field(0x14, "u16") + OBJ_N_FIELDS = Field(0x16, "u16") + OBJ_N_PROPERTIES = Field(0x18, "u16") + OBJ_N_METHODS = Field(0x1A, "u16") + OBJ_N_SIGNALS = Field(0x1C, "u16") + OBJ_N_VFUNCS = Field(0x1E, "u16") + OBJ_N_CONSTANTS = Field(0x20, "u16") + OBJ_N_FIELD_CALLBACKS = Field(0x22, "u16") + + PROP_NAME = Field(0x0, "string") + PROP_DEPRECATED = Field(0x4, "u32", 0, 1) + PROP_READABLE = Field(0x4, "u32", 1, 1) + PROP_WRITABLE = Field(0x4, "u32", 2, 1) + PROP_CONSTRUCT = Field(0x4, "u32", 3, 1) + PROP_CONSTRUCT_ONLY = Field(0x4, "u32", 4, 1) + PROP_TYPE = Field(0xC, "u32") + + VALUE_NAME = Field(0x4, "string") + VALUE_VALUE = Field(0x8, "i32") + + def __init__(self, typelib_file, offset: int): + self._typelib_file = typelib_file + self._offset = offset + + def __getitem__(self, index: int): + return Typelib(self._typelib_file, self._offset + index) + + def attr(self, name): + return self.header.attr(self._offset, name) + + @property + def header(self) -> "TypelibHeader": + return TypelibHeader(self._typelib_file) + + @property + def u8(self) -> int: + """Gets the 8-bit unsigned int at this location.""" + return self._int(1, False) + + @property + def u16(self) -> int: + """Gets the 16-bit unsigned int at this location.""" + return self._int(2, False) + + @property + def u32(self) -> int: + """Gets the 32-bit unsigned int at this location.""" + return self._int(4, False) + + @property + def i8(self) -> int: + """Gets the 8-bit unsigned int at this location.""" + return self._int(1, True) + + @property + def i16(self) -> int: + """Gets the 16-bit unsigned int at this location.""" + return self._int(2, True) + + @property + def i32(self) -> int: + """Gets the 32-bit unsigned int at this location.""" + return self._int(4, True) + + @property + def string(self) -> T.Optional[str]: + """Interprets the 32-bit unsigned int at this location as a pointer + within the typelib file, and returns the null-terminated string at that + pointer.""" + + loc = self.u32 + if loc == 0: + return None + + end = loc + while self._typelib_file[end] != 0: + end += 1 + return self._typelib_file[loc:end].decode("utf-8") + + def _int(self, size, signed) -> int: + return int.from_bytes( + self._typelib_file[self._offset : self._offset + size], sys.byteorder + ) + + +class TypelibHeader(Typelib): + def __init__(self, typelib_file): + super().__init__(typelib_file, 0) + + def dir_entry(self, index) -> T.Optional[Typelib]: + if index == 0: + return None + else: + return self.HEADER_DIRECTORY[(index - 1) * self.HEADER_ENTRY_BLOB_SIZE] + + def attr(self, offset, name): + lower = 0 + upper = self.HEADER_N_ATTRIBUTES + attr_size = self.HEADER_ATTRIBUTE_BLOB_SIZE + attrs = self.HEADER_ATTRIBUTES + mid = 0 + + while lower <= upper: + mid = math.floor((upper + lower) / 2) + attr = attrs[mid * attr_size] + if attr.ATTR_OFFSET < offset: + lower = mid + 1 + elif attr.ATTR_OFFSET > offset: + upper = mid - 1 + else: + while mid >= 0 and attrs[(mid - 1) * attr_size].ATTR_OFFSET == offset: + mid -= 1 + break + if attrs[mid * attr_size].ATTR_OFFSET != offset: + # no match found + return None + while attrs[mid * attr_size].ATTR_OFFSET == offset: + if attrs[mid * attr_size].ATTR_NAME == name: + return attrs[mid * attr_size].ATTR_VALUE + mid += 1 + return None + + def attr_by_index(self, index): + pass + + @property + def dir_entries(self): + return [self.dir_entry(i) for i in range(self[0x16].u16)] + + +def load_typelib(path: str) -> Typelib: + with open(path, "rb") as f: + return Typelib(f.read(), 0) diff --git a/.flatpak-builder/cache/objects/81/3d16474f7c53f0075e4218aab09ced9cf34ec0d31680dd7934d4cdf170a5aa.dirtree b/.flatpak-builder/cache/objects/81/3d16474f7c53f0075e4218aab09ced9cf34ec0d31680dd7934d4cdf170a5aa.dirtree new file mode 100644 index 0000000..cdaf0f8 Binary files /dev/null and b/.flatpak-builder/cache/objects/81/3d16474f7c53f0075e4218aab09ced9cf34ec0d31680dd7934d4cdf170a5aa.dirtree differ diff --git a/.flatpak-builder/cache/objects/81/4a2032618a6e6a45435a819d7bb4b06625b1cb5ac36cb903ecc61758c16e37.dirtree b/.flatpak-builder/cache/objects/81/4a2032618a6e6a45435a819d7bb4b06625b1cb5ac36cb903ecc61758c16e37.dirtree new file mode 100644 index 0000000..e5796c7 Binary files /dev/null and b/.flatpak-builder/cache/objects/81/4a2032618a6e6a45435a819d7bb4b06625b1cb5ac36cb903ecc61758c16e37.dirtree differ diff --git a/.flatpak-builder/cache/objects/81/771c81c92f9c3c93b59325b54bc889c1e7dc84a7aa63805673c82e533128dd.file b/.flatpak-builder/cache/objects/81/771c81c92f9c3c93b59325b54bc889c1e7dc84a7aa63805673c82e533128dd.file new file mode 100644 index 0000000..239777b --- /dev/null +++ b/.flatpak-builder/cache/objects/81/771c81c92f9c3c93b59325b54bc889c1e7dc84a7aa63805673c82e533128dd.file @@ -0,0 +1,112 @@ +/* gda-db-catalog.h + * + * Copyright (C) 2018 Pavlo Solntsev + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef GDA_DB_CATALOG_H +#define GDA_DB_CATALOG_H + +#include +#include +#include "gda-db-table.h" +#include "gda-db-view.h" +#include "gda-server-operation.h" +#include + +G_BEGIN_DECLS + +#define GDA_TYPE_DB_CATALOG (gda_db_catalog_get_type()) + +G_DECLARE_DERIVABLE_TYPE (GdaDbCatalog, gda_db_catalog, GDA, DB_CATALOG, GObject) + +struct _GdaDbCatalogClass +{ + GObjectClass parent; +}; + +/** + * GdaDbCatalogError: + * @GDA_DB_CATALOG_CONTEXT_NULL: Context is %NULL. Should not be %NULL for normal operation. + * @GDA_DB_CATALOG_DOC_NULL: #xmlDocPtr is %NULL. + * @GDA_DB_CATALOG_INVALID_XML: Sets if xml check fails. Xml file structure doesn't match with DTD + * file + * @GDA_DB_CATALOG_INVALID_SCHEMA: Sets if the used schema is invalid. + * @GDA_DB_CATALOG_SERVER_OPERATION: Sets if server operation is %NULL. + * @GDA_DB_CATALOG_FILE_READ: Sets if xml file is not readable + * @GDA_DB_CATALOG_PARSE_CONTEXT: Sets if an error with context during parsing an xml file + * @GDA_DB_CATALOG_PARSE: Sets if parsing reports an error + * @GDA_DB_CATALOG_PARSE_CHUNK: If set, error with parse chunk algorithm. + * @GDA_DB_CATALOG_CONNECTION_CLOSED: Connection is not open. + * + * These error are primary for developers to troubleshoot the problem rather than for user. + */ +typedef enum { + GDA_DB_CATALOG_CONTEXT_NULL, + GDA_DB_CATALOG_DOC_NULL, + GDA_DB_CATALOG_INVALID_XML, + GDA_DB_CATALOG_INVALID_SCHEMA, + GDA_DB_CATALOG_SERVER_OPERATION, + GDA_DB_CATALOG_FILE_READ, + GDA_DB_CATALOG_PARSE_CONTEXT, + GDA_DB_CATALOG_PARSE, + GDA_DB_CATALOG_PARSE_CHUNK, + GDA_DB_CATALOG_CONNECTION_CLOSED +} GdaDbCatalogError; + +#define GDA_DB_CATALOG_ERROR gda_db_catalog_error_quark() +GQuark gda_db_catalog_error_quark (void); + +GdaDbCatalog *gda_db_catalog_new (void); + +gboolean gda_db_catalog_parse_file_from_path (GdaDbCatalog *self, + const gchar *xmlfile, + GError **error); + +gboolean gda_db_catalog_parse_file (GdaDbCatalog *self, + GFile *xmlfile, + GError **error); + +GList *gda_db_catalog_get_tables (GdaDbCatalog *self); +GList *gda_db_catalog_get_views (GdaDbCatalog *self); + +gboolean gda_db_catalog_parse_cnc (GdaDbCatalog *self, + GError **error); + +void gda_db_catalog_append_table (GdaDbCatalog *self, + GdaDbTable *table); + +void gda_db_catalog_append_view (GdaDbCatalog *self, + GdaDbView *view); + +gboolean gda_db_catalog_perform_operation (GdaDbCatalog *self, + GError **error); + +gboolean gda_db_catalog_write_to_file (GdaDbCatalog *self, + GFile *file, + GError **error); + +gboolean gda_db_catalog_write_to_path (GdaDbCatalog *self, + const gchar *path, + GError **error); + +gboolean gda_db_catalog_validate_file_from_path (const gchar *xmlfile, + GError **error); +G_END_DECLS + +#endif /* GDA_DB_CATALOG_H */ + diff --git a/.flatpak-builder/cache/objects/81/ccb2c165ccc90d93f74baa2804986ddde0f7d2bf0789f4c8cdc5c4e0610a72.file b/.flatpak-builder/cache/objects/81/ccb2c165ccc90d93f74baa2804986ddde0f7d2bf0789f4c8cdc5c4e0610a72.file new file mode 100644 index 0000000..f48ab22 --- /dev/null +++ b/.flatpak-builder/cache/objects/81/ccb2c165ccc90d93f74baa2804986ddde0f7d2bf0789f4c8cdc5c4e0610a72.file @@ -0,0 +1,58 @@ +/*-*- Mode: C; c-basic-offset: 8 -*-*/ + +#ifndef foocanberraproplisthfoo +#define foocanberraproplisthfoo + +/*** + This file is part of libcanberra. + + Copyright 2008 Lennart Poettering + + libcanberra is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation, either version 2.1 of the + License, or (at your option) any later version. + + libcanberra is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with libcanberra. If not, see + . +***/ + +#include + +#include "canberra.h" +#include "mutex.h" + +#define N_HASHTABLE 31 + +typedef struct ca_prop { + char *key; + size_t nbytes; + struct ca_prop *next_in_slot, *next_item, *prev_item; +} ca_prop; + +#define CA_PROP_DATA(p) ((void*) ((char*) (p) + CA_ALIGN(sizeof(ca_prop)))) + +struct ca_proplist { + ca_mutex *mutex; + + ca_prop *prop_hashtable[N_HASHTABLE]; + ca_prop *first_item; +}; + +int ca_proplist_merge(ca_proplist **_a, ca_proplist *b, ca_proplist *c); +ca_bool_t ca_proplist_contains(ca_proplist *p, const char *key); + +/* Both of the following two functions are not locked! Need manual locking! */ +ca_prop* ca_proplist_get_unlocked(ca_proplist *p, const char *key); +const char* ca_proplist_gets_unlocked(ca_proplist *p, const char *key); + +int ca_proplist_merge_ap(ca_proplist *p, va_list ap); +int ca_proplist_from_ap(ca_proplist **_p, va_list ap); + +#endif diff --git a/.flatpak-builder/cache/objects/81/e96803a70e9db651deaf0b1145e73f8a37d8ea8df7c1f7e0a4faa714876ec7.file b/.flatpak-builder/cache/objects/81/e96803a70e9db651deaf0b1145e73f8a37d8ea8df7c1f7e0a4faa714876ec7.file new file mode 100644 index 0000000..18d1ffa Binary files /dev/null and b/.flatpak-builder/cache/objects/81/e96803a70e9db651deaf0b1145e73f8a37d8ea8df7c1f7e0a4faa714876ec7.file differ diff --git a/.flatpak-builder/cache/objects/82/0785d8b5556b5a32b2e12fde5e3ffd4a5d06274501949a1adea60c12dea33b.file b/.flatpak-builder/cache/objects/82/0785d8b5556b5a32b2e12fde5e3ffd4a5d06274501949a1adea60c12dea33b.file new file mode 100755 index 0000000..02fe7d1 Binary files /dev/null and b/.flatpak-builder/cache/objects/82/0785d8b5556b5a32b2e12fde5e3ffd4a5d06274501949a1adea60c12dea33b.file differ diff --git a/.flatpak-builder/cache/objects/82/0cb6ffdac2bfa6f05d9ae3bb5a24892982550d065f06bf83de8978a3daef9b.dirtree b/.flatpak-builder/cache/objects/82/0cb6ffdac2bfa6f05d9ae3bb5a24892982550d065f06bf83de8978a3daef9b.dirtree new file mode 100644 index 0000000..f19a88c Binary files /dev/null and b/.flatpak-builder/cache/objects/82/0cb6ffdac2bfa6f05d9ae3bb5a24892982550d065f06bf83de8978a3daef9b.dirtree differ diff --git a/.flatpak-builder/cache/objects/82/84ccc062cb36861659245814e85b32da007cef751f1805f21a5dfc136e2f9d.dirtree b/.flatpak-builder/cache/objects/82/84ccc062cb36861659245814e85b32da007cef751f1805f21a5dfc136e2f9d.dirtree new file mode 100644 index 0000000..4c8109f Binary files /dev/null and b/.flatpak-builder/cache/objects/82/84ccc062cb36861659245814e85b32da007cef751f1805f21a5dfc136e2f9d.dirtree differ diff --git a/.flatpak-builder/cache/objects/82/cbc3bcb56384bdc39eb6bcfd681202e9f62e0794acc4f07c04b428d4e3dda5.file b/.flatpak-builder/cache/objects/82/cbc3bcb56384bdc39eb6bcfd681202e9f62e0794acc4f07c04b428d4e3dda5.file new file mode 100644 index 0000000..07d931d --- /dev/null +++ b/.flatpak-builder/cache/objects/82/cbc3bcb56384bdc39eb6bcfd681202e9f62e0794acc4f07c04b428d4e3dda5.file @@ -0,0 +1,256 @@ +/* + * Copyright (C) 2006 - 2013 Vivien Malerba + * Copyright (C) 2007 Armin Burgmeier + * Copyright (C) 2007 Murray Cumming + * Copyright (C) 2009 Bas Driessen + * Copyright (C) 2010 David King + * Copyright (C) 2019 Daniel Espinosa + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "gda-sqlite-handler-bin.h" +#include +#include +#include +#include + +static void gda_sqlite_handler_bin_class_init (GdaSqliteHandlerBinClass * class); +static void gda_sqlite_handler_bin_init (GdaSqliteHandlerBin * wid); +static void gda_sqlite_handler_bin_dispose (GObject * object); + + +/* GdaDataHandler interface */ +static void gda_sqlite_handler_bin_data_handler_init (GdaDataHandlerInterface *iface); +static gchar *gda_sqlite_handler_bin_get_sql_from_value (GdaDataHandler *dh, const GValue *value); +static gchar *gda_sqlite_handler_bin_get_str_from_value (GdaDataHandler *dh, const GValue *value); +static GValue *gda_sqlite_handler_bin_get_value_from_sql (GdaDataHandler *dh, const gchar *sql, + GType type); +static GValue *gda_sqlite_handler_bin_get_value_from_str (GdaDataHandler *dh, const gchar *sql, + GType type); +static gboolean gda_sqlite_handler_bin_accepts_g_type (GdaDataHandler * dh, GType type); + +static const gchar *gda_sqlite_handler_bin_get_descr (GdaDataHandler *dh); + +G_DEFINE_TYPE_WITH_CODE (GdaSqliteHandlerBin, gda_sqlite_handler_bin, G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (GDA_TYPE_DATA_HANDLER, gda_sqlite_handler_bin_data_handler_init)) + +static void +gda_sqlite_handler_bin_data_handler_init (GdaDataHandlerInterface *iface) +{ + iface->get_sql_from_value = gda_sqlite_handler_bin_get_sql_from_value; + iface->get_str_from_value = gda_sqlite_handler_bin_get_str_from_value; + iface->get_value_from_sql = gda_sqlite_handler_bin_get_value_from_sql; + iface->get_value_from_str = gda_sqlite_handler_bin_get_value_from_str; + iface->get_sane_init_value = NULL; + iface->accepts_g_type = gda_sqlite_handler_bin_accepts_g_type; + iface->get_descr = gda_sqlite_handler_bin_get_descr; +} + + +static void +gda_sqlite_handler_bin_class_init (GdaSqliteHandlerBinClass * class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (class); + + object_class->dispose = gda_sqlite_handler_bin_dispose; +} + +static void +gda_sqlite_handler_bin_init (GdaSqliteHandlerBin * hdl) +{ + /* Private structure */ + g_object_set_data (G_OBJECT (hdl), "name", "SqliteBin"); + g_object_set_data (G_OBJECT (hdl), "descr", _("SQLite binary representation")); +} + +static void +gda_sqlite_handler_bin_dispose (GObject * object) +{ + /* for the parent class */ + G_OBJECT_CLASS (gda_sqlite_handler_bin_parent_class)->dispose (object); +} + +/** + * _gda_sqlite_handler_bin_new + * + * Creates a data handler for binary values + * + * Returns: the new object + */ +GdaDataHandler * +_gda_sqlite_handler_bin_new (void) +{ + GObject *obj; + + obj = g_object_new (GDA_TYPE_SQLITE_HANDLER_BIN, NULL); + + return (GdaDataHandler *) obj; +} + +static gchar * +gda_sqlite_handler_bin_get_sql_from_value (G_GNUC_UNUSED GdaDataHandler *iface, const GValue *value) +{ + g_assert (value); + + gchar *retval; + GdaBinary *bin; + gint i; + + bin = (GdaBinary *) gda_value_get_binary ((GValue *) value); + retval = g_new0 (gchar, gda_binary_get_size (bin) * 2 + 4); + retval [0] = 'x'; + retval [1] = '\''; + for (i = 0; i < gda_binary_get_size (bin); i++) { + guchar *ptr; + + ptr = gda_binary_get_data (bin) + i; + if ((*ptr >> 4) <= 9) + retval [2*i + 2] = (*ptr >> 4) + '0'; + else + retval [2*i + 2] = (*ptr >> 4) + 'A' - 10; + if ((*ptr & 0xF) <= 9) + retval [2*i + 3] = (*ptr & 0xF) + '0'; + else + retval [2*i + 3] = (*ptr & 0xF) + 'A' - 10; + } + retval [gda_binary_get_size (bin) * 2 + 2] = '\''; + + return retval; +} + +static gchar * +gda_sqlite_handler_bin_get_str_from_value (G_GNUC_UNUSED GdaDataHandler *iface, const GValue *value) +{ + g_assert (value); + + gchar *retval; + GdaBinary *bin; + gint i; + + bin = (GdaBinary *) gda_value_get_binary ((GValue *) value); + retval = g_new0 (gchar, gda_binary_get_size (bin) * 2 + 1); + for (i = 0; i < gda_binary_get_size (bin); i++) { + guchar *ptr; + + ptr = gda_binary_get_data (bin) + i; + if ((*ptr >> 4) <= 9) + retval [2*i] = (*ptr >> 4) + '0'; + else + retval [2*i] = (*ptr >> 4) + 'A' - 10; + if ((*ptr & 0xF) <= 9) + retval [2*i + 1] = (*ptr & 0xF) + '0'; + else + retval [2*i + 1] = (*ptr & 0xF) + 'A' - 10; + } + + return retval; +} + +static int hex_to_int (int h) { + if (h >= '0' && h <= '9') + return h - '0'; + else if (h >= 'a' && h <= 'f') + return h - 'a' + 10; + else { + if (h >= 'A' && h <= 'F') + return h - 'A' + 10; + else + return 0; + } +} + +static GValue * +gda_sqlite_handler_bin_get_value_from_sql (G_GNUC_UNUSED GdaDataHandler *iface, const gchar *sql, G_GNUC_UNUSED GType type) +{ + g_assert (sql); + GValue *value = NULL; + + if (*sql) { + gint n = strlen (sql); + if ((n >= 3) && + ! ((n-3) % 2) && + ((sql[0] == 'x') || (sql[0] == 'X')) && + (sql[1] == '\'') && + (sql[n] == '\'')) { + GdaBinary *bin; + + bin = gda_binary_new (); + if (n > 3) { + gint i; + guchar* buffer = g_new0 (guchar, (n-3)/2); + for (i = 2; i < n-1; i += 2) + buffer [i/2 - 1] = (hex_to_int (sql[i]) << 4) | hex_to_int (sql [i+1]); + gda_binary_set_data (bin, buffer, n-3); + g_free (buffer); + } + + value = gda_value_new (GDA_TYPE_BINARY); + gda_value_take_binary (value, bin); + } + } + + return value; +} + +static GValue * +gda_sqlite_handler_bin_get_value_from_str (G_GNUC_UNUSED GdaDataHandler *iface, const gchar *str, G_GNUC_UNUSED GType type) +{ + g_assert (str); + + GValue *value = NULL; + + if (*str) { + gint n = strlen (str); + if (! (n % 2)) { + GdaBinary *bin; + + bin = gda_binary_new (); + guchar* buffer = NULL; + if (n > 0) { + gint i; + buffer = g_new0 (guchar, n/2); + for (i = 0; i < n; i += 2) + buffer [i/2] = (hex_to_int (str[i]) << 4) | hex_to_int (str [i+1]); + } + gda_binary_set_data (bin, buffer, n); + value = gda_value_new (GDA_TYPE_BINARY); + gda_value_take_binary (value, bin); + } + } + else { + GdaBinary *bin; + bin = gda_string_to_binary (str); + value = gda_value_new (GDA_TYPE_BINARY); + gda_value_take_binary (value, bin); + } + + return value; +} + +static gboolean +gda_sqlite_handler_bin_accepts_g_type (G_GNUC_UNUSED GdaDataHandler *iface, GType type) +{ + g_assert (iface); + return type == GDA_TYPE_BINARY ? TRUE : FALSE; +} + +static const gchar * +gda_sqlite_handler_bin_get_descr (GdaDataHandler *iface) +{ + g_return_val_if_fail (GDA_IS_SQLITE_HANDLER_BIN (iface), NULL); + return g_object_get_data (G_OBJECT (iface), "descr"); +} diff --git a/.flatpak-builder/cache/objects/82/f0a65e4d5d7d8ced8675f26a0ff1e21f21ee7bef4566e16f245205c5eaf5e6.file b/.flatpak-builder/cache/objects/82/f0a65e4d5d7d8ced8675f26a0ff1e21f21ee7bef4566e16f245205c5eaf5e6.file new file mode 100644 index 0000000..058341c --- /dev/null +++ b/.flatpak-builder/cache/objects/82/f0a65e4d5d7d8ced8675f26a0ff1e21f21ee7bef4566e16f245205c5eaf5e6.file @@ -0,0 +1,876 @@ +/* + * Copyright (C) 2009 - 2013 Vivien Malerba + * Copyright (C) 2010 David King + * Copyright (C) 2011 Murray Cumming + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +#define G_LOG_DOMAIN "GDA-tree-node" + +#include +#include "gda-tree-node.h" +#include "gda-tree-manager.h" +#include +#include + +typedef struct { + GSList *children; /* list of GdaTreeNodesList */ + GdaTreeNode *parent; + gchar *name; +} GdaTreeNodePrivate; +G_DEFINE_TYPE_WITH_PRIVATE (GdaTreeNode, gda_tree_node, G_TYPE_OBJECT) +/* + * The GdaTreeNodesList stores the list of children nodes created by a GdaTreeManager object + */ +typedef struct { + GdaTreeManager *mgr; /* which created @nodes */ + GSList *nodes; /* list of GdaTreeNode */ + gint length; /* length of @nodes */ +} GdaTreeNodesList; +#define GDA_TREE_NODES_LIST(x) ((GdaTreeNodesList*)(x)) + +void _gda_nodes_list_free (GdaTreeNodesList *nl); + +/* + * GObject functions + */ +static void gda_tree_node_dispose (GObject *object); +static void gda_tree_node_set_property (GObject *object, + guint param_id, + const GValue *value, + GParamSpec *pspec); +static void gda_tree_node_get_property (GObject *object, + guint param_id, + GValue *value, + GParamSpec *pspec); + +/* default virtual methods */ +static gchar *gda_tree_node_dump_header (GdaTreeNode *node); +static void gda_tree_node_dump_children (GdaTreeNode *node, const gchar *prefix, GString *in_string); + +enum { + NODE_CHANGED, + NODE_INSERTED, + NODE_HAS_CHILD_TOGGLED, + NODE_DELETED, + LAST_SIGNAL +}; + +static gint gda_tree_node_signals[LAST_SIGNAL] = { 0, 0, 0, 0 }; + +/* properties */ +enum { + PROP_0, + PROP_NAME +}; + +static void m_node_changed (GdaTreeNode *reporting, GdaTreeNode *node); +static void m_node_inserted (GdaTreeNode *reporting, GdaTreeNode *node); +static void m_node_has_child_toggled (GdaTreeNode *reporting, GdaTreeNode *node); +static void m_node_deleted (GdaTreeNode *reporting, const gchar *relative_path); + +/* + * GdaTreeNode class implementation + * @klass: + */ +static void +gda_tree_node_class_init (GdaTreeNodeClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + /* signals */ + /** + * GdaTreeNode::node-changed: + * @reporting: the #GdaTreeNode which emits the signal (may be a parent of @node, or @node itself) + * @node: the #GdaTreeNode which has changed + * + * Gets emitted when a @node has changed + * + * Since: 4.2 + */ + gda_tree_node_signals[NODE_CHANGED] = + g_signal_new ("node_changed", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GdaTreeNodeClass, node_changed), + NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, GDA_TYPE_TREE_NODE); + /** + * GdaTreeNode::node-inserted: + * @reporting: the #GdaTreeNode which emits the signal (may be a parent of @node, or @node itself) + * @node: the #GdaTreeNode which has been inserted + * + * Gets emitted when a @node has been inserted + * + * Since: 4.2 + */ + gda_tree_node_signals[NODE_INSERTED] = + g_signal_new ("node_inserted", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GdaTreeNodeClass, node_inserted), + NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, GDA_TYPE_TREE_NODE); + /** + * GdaTreeNode::node-has-child-toggled: + * @reporting: the #GdaTreeNode which emits the signal (may be a parent of @node, or @node itself) + * @node: the #GdaTreeNode which changed from having children to being a + * leaf or the other way around + * + * Gets emitted when a @node has has a child when it did not have any or when it + * does not have a ny children anymore when it had some + * + * Since: 4.2 + */ + gda_tree_node_signals[NODE_HAS_CHILD_TOGGLED] = + g_signal_new ("node-has-child-toggled", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GdaTreeNodeClass, node_has_child_toggled), + NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, GDA_TYPE_TREE_NODE); + /** + * GdaTreeNode::node-deleted: + * @reporting: the #GdaTreeNode which emits the signal (a parent of the removed node) + * @relative_path: the path the node held, relative to @reporting + * + * Gets emitted when a @node has been removed + * + * Since: 4.2 + */ + gda_tree_node_signals[NODE_DELETED] = + g_signal_new ("node_deleted", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GdaTreeNodeClass, node_deleted), + NULL, NULL, + g_cclosure_marshal_VOID__STRING, + G_TYPE_NONE, 1, G_TYPE_STRING); + + klass->node_changed = m_node_changed; + klass->node_inserted = m_node_inserted; + klass->node_has_child_toggled = m_node_has_child_toggled; + klass->node_deleted = m_node_deleted; + + /* virtual methods */ + klass->dump_header = gda_tree_node_dump_header; + klass->dump_children = gda_tree_node_dump_children; + + /* Properties */ + object_class->set_property = gda_tree_node_set_property; + object_class->get_property = gda_tree_node_get_property; + + g_object_class_install_property (object_class, PROP_NAME, + g_param_spec_string ("name", NULL, + "Node's name attribute", + NULL, G_PARAM_WRITABLE | G_PARAM_READABLE)); + + object_class->dispose = gda_tree_node_dispose; + +} + +static void +m_node_changed (GdaTreeNode *reporting, GdaTreeNode *node) +{ + g_return_if_fail (GDA_IS_TREE_NODE (reporting)); + GdaTreeNodePrivate *priv = gda_tree_node_get_instance_private (reporting); + if (priv->parent) + g_signal_emit (priv->parent, gda_tree_node_signals[NODE_CHANGED], + 0, node); +} + +static void +m_node_inserted (GdaTreeNode *reporting, GdaTreeNode *node) +{ + g_return_if_fail (GDA_IS_TREE_NODE (reporting)); + GdaTreeNodePrivate *priv = gda_tree_node_get_instance_private (reporting); + if (priv->parent) + g_signal_emit (priv->parent, gda_tree_node_signals[NODE_INSERTED], + 0, node); +} + +static void +m_node_has_child_toggled (GdaTreeNode *reporting, GdaTreeNode *node) +{ + g_return_if_fail (GDA_IS_TREE_NODE (reporting)); + GdaTreeNodePrivate *priv = gda_tree_node_get_instance_private (reporting); + if (priv->parent) + g_signal_emit (priv->parent, gda_tree_node_signals[NODE_HAS_CHILD_TOGGLED], + 0, node); +} + +/* + * Get child's position + * + * Returns: the requested position, or -1 if child not found + */ +static gint +_get_child_pos (GdaTreeNode *node, GdaTreeNode *child) +{ + gint pos = 0; + g_return_val_if_fail (GDA_IS_TREE_NODE (node), -1); + GdaTreeNodePrivate *priv = gda_tree_node_get_instance_private (node); + + if (priv->children) { + GSList *parts; + for (parts = priv->children; parts; parts = parts->next) { + GdaTreeNodesList *tn = GDA_TREE_NODES_LIST (parts->data); + GSList *sl; + for (sl = tn->nodes; sl; sl = sl->next) { + if (sl->data == child) + return pos; + else + pos++; + } + } + } + + return -1; +} + +static void +m_node_deleted (GdaTreeNode *reporting, const gchar *relative_path) +{ + g_return_if_fail (GDA_IS_TREE_NODE (reporting)); + GdaTreeNodePrivate *priv = gda_tree_node_get_instance_private (reporting); + if (priv->parent) { + gint pos; + gchar *path; + pos = _get_child_pos (priv->parent, reporting); + g_assert (pos >= 0); + path = g_strdup_printf ("%d:%s", pos, relative_path); + g_signal_emit (priv->parent, gda_tree_node_signals[NODE_DELETED], + 0, path); + g_free (path); + } +} + +static void +gda_tree_node_init (GdaTreeNode *tnode) +{ + g_return_if_fail (GDA_IS_TREE_NODE (tnode)); + GdaTreeNodePrivate *priv = gda_tree_node_get_instance_private (tnode); + priv->children = NULL; + priv->name = NULL; +} + +static void +gda_tree_node_dispose (GObject *object) +{ + GdaTreeNode *tnode = (GdaTreeNode *) object; + + g_return_if_fail (GDA_IS_TREE_NODE (tnode)); + GdaTreeNodePrivate *priv = gda_tree_node_get_instance_private (tnode); + + if (priv->children != NULL) { + g_slist_free_full (priv->children, (GDestroyNotify) _gda_nodes_list_free); + priv->children = NULL; + } + if (priv->name != NULL) { + g_free (priv->name); + priv->name = NULL; + } + + /* chain to parent class */ + G_OBJECT_CLASS (gda_tree_node_parent_class)->dispose (object); +} + + +/* module error */ +GQuark gda_tree_node_error_quark (void) +{ + static GQuark quark; + if (!quark) + quark = g_quark_from_static_string ("gda_tree_node_error"); + return quark; +} + +static void +gda_tree_node_set_property (GObject *object, + guint param_id, + const GValue *value, + GParamSpec *pspec) +{ + GdaTreeNode *tnode; + + tnode = GDA_TREE_NODE (object); + GdaTreeNodePrivate *priv = gda_tree_node_get_instance_private (tnode); + + switch (param_id) { + case PROP_NAME: + priv->name = g_value_dup_string (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + break; + } +} + +static void +gda_tree_node_get_property (GObject *object, + guint param_id, + GValue *value, + GParamSpec *pspec) +{ + GdaTreeNode *tnode; + + tnode = GDA_TREE_NODE (object); + GdaTreeNodePrivate *priv = gda_tree_node_get_instance_private (tnode); + + switch (param_id) { + case PROP_NAME: { + g_value_set_string (value, priv->name); + break; + } + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + break; + } +} + +static gchar * +gda_tree_node_dump_header (GdaTreeNode *node) +{ + GdaTreeNodePrivate *priv = gda_tree_node_get_instance_private (node); + + if (g_getenv ("GDA_TREE_DUMP_ALL_ATTRIBUTES")) { + GString *string; + string = g_string_new (""); + if (priv->name != NULL) + g_string_append (string, priv->name); + else + g_string_append (string, "Unnamed node"); + g_string_append_c (string, ':'); + + // Attributes now are data associations in the GObject and not iterable + // FIXME: how to iterate over. This method is not used anyother place + return g_string_free (string, FALSE); + } + else { + if (priv->name != NULL) + return g_strdup (priv->name); + else + return g_strdup_printf ("Unnamed node"); + } +} + + +static void +gda_tree_node_dump_children (GdaTreeNode *node, const gchar *prefix, GString *in_string) +{ + g_return_if_fail (GDA_IS_TREE_NODE (node)); + gchar *prefix2 = "|-- "; + GdaTreeNodeClass *klass; + GSList *parts; + GdaTreeNodePrivate *priv = gda_tree_node_get_instance_private (node); + + for (parts = priv->children; parts; parts = parts->next) { + GSList *list; + GdaTreeNodesList *tn = GDA_TREE_NODES_LIST (parts->data); + for (list = tn->nodes; list; list = list->next) { + GdaTreeNode *child_node = GDA_TREE_NODE (list->data); + klass = (GdaTreeNodeClass*) G_OBJECT_GET_CLASS (child_node); + + /* header */ + if ((!list->next) && (!parts->next)) + prefix2 = "`-- "; + if (klass->dump_header) { + gchar *tmp = klass->dump_header (child_node); + g_string_append_printf (in_string, "%s%s%s\n", prefix, prefix2, tmp); + g_free (tmp); + } + else + g_string_append_printf (in_string, "%s%sGdaTreeNode (%s) %p\n", prefix, prefix2, + G_OBJECT_TYPE_NAME(child_node), child_node); + + /* contents */ + gchar *ch_prefix; + if (list->next || parts->next) + ch_prefix = g_strdup_printf ("%s| ", prefix); + else + ch_prefix = g_strdup_printf ("%s ", prefix); + if (klass->dump_children) + klass->dump_children (child_node, ch_prefix, in_string); + else + gda_tree_node_dump_children (child_node, ch_prefix, in_string); + g_free (ch_prefix); + } + } +} + +/** + * gda_tree_node_new: + * @name: (nullable): a name, or %NULL + * + * Creates a new #GdaTreeNode object + * + * Returns: (transfer full): a new #GdaTreeNode + * + * Since: 4.2 + */ +GdaTreeNode * +gda_tree_node_new (const gchar *name) +{ + return (GdaTreeNode*) g_object_new (GDA_TYPE_TREE_NODE, "name", name, NULL); +} + +/* + * _gda_tree_node_add_children: + * @node: a #GdaTreeNode + * @mgr: a #GdaTreeManager object + * @childen: (nullable): a list of #GdaTreeNode objects, or %NULL + * + * Requests that @node take the list of nodes in @children as its children. The children list + * may be a new list of children, or may be an update of a list of children which previously existed. + * + * @node steals the ownership of each #GdaTreeNode object listed in @children. + */ +void +_gda_tree_node_add_children (GdaTreeNode *node, GdaTreeManager *mgr, const GSList *children) +{ + GSList *list; + const GSList *clist; + GdaTreeNodesList *etn; + gint pos, nb_before_etn = 0; + gint n_children = 0; + + g_return_if_fail (GDA_IS_TREE_NODE (node)); + g_return_if_fail (GDA_IS_TREE_MANAGER (mgr)); + GdaTreeNodePrivate *priv = gda_tree_node_get_instance_private (node); + + /* find existing GdaTreeNodesList */ + for (etn = NULL, pos = 0, list = priv->children; list; list = list->next, pos++) { + if (GDA_TREE_NODES_LIST (list->data)->mgr == mgr) { + etn = GDA_TREE_NODES_LIST (list->data); + nb_before_etn = n_children; + n_children += GDA_TREE_NODES_LIST (list->data)->length; + } + else + n_children += GDA_TREE_NODES_LIST (list->data)->length; + } + + /* prepare new GdaTreeNodesList */ + for (clist = children; clist; clist = clist->next) { + GdaTreeNode *child = GDA_TREE_NODE (clist->data); + if (!GDA_IS_TREE_NODE (child)) + continue; + GdaTreeNodePrivate *priv = gda_tree_node_get_instance_private (child); + priv->parent = node; + } + if (!etn) { + /* create new GdaTreeNodesList */ + etn = g_new0 (GdaTreeNodesList, 1); + etn->mgr = g_object_ref (mgr); + priv->children = g_slist_append (priv->children, etn); + + /* fill it */ + for (clist = children; clist; clist = clist->next) { + etn->nodes = g_slist_append (etn->nodes, clist->data); + etn->length ++; + n_children ++; + g_signal_emit (node, gda_tree_node_signals [NODE_INSERTED], 0, clist->data); + if (n_children == 1) + g_signal_emit (node, gda_tree_node_signals [NODE_HAS_CHILD_TOGGLED], 0, node); + } + } + else { + GSList *enodes; + + for (clist = children, enodes = etn->nodes, pos = nb_before_etn; + clist; + clist = clist->next, pos ++) { + if (enodes) { + if (clist->data == enodes->data) { + /* signal a change */ + g_signal_emit (node, gda_tree_node_signals [NODE_CHANGED], 0, (gpointer) clist->data); + g_object_unref (G_OBJECT (clist->data)); /* loose 1 reference */ + enodes = enodes->next; + } + else { + gchar *rpath = g_strdup_printf ("%d", pos); + for (; enodes; ) { + if (clist->data != enodes->data) { + /* signal deletion */ + GSList *next = enodes->next; + g_object_unref (G_OBJECT (enodes->data)); + etn->nodes = g_slist_delete_link (etn->nodes, enodes); + etn->length --; + n_children --; + enodes = next; + g_signal_emit (node, gda_tree_node_signals [NODE_DELETED], 0, rpath); + + if (n_children == 0) + g_signal_emit (node, gda_tree_node_signals [NODE_HAS_CHILD_TOGGLED], 0, node); + } + else + break; + } + g_free (rpath); + + if (enodes) { + /* signal a change */ + g_signal_emit (node, gda_tree_node_signals [NODE_CHANGED], 0, + (gpointer) clist->data); + g_object_unref (G_OBJECT (clist->data)); /* loose 1 reference */ + enodes = enodes->next; + } + else { + /* signal an insertion */ + etn->nodes = g_slist_append (etn->nodes, clist->data); + etn->length ++; + n_children ++; + g_signal_emit (node, gda_tree_node_signals [NODE_INSERTED], 0, + (gpointer) clist->data); + if (n_children == 1) + g_signal_emit (node, gda_tree_node_signals [NODE_HAS_CHILD_TOGGLED], 0, node); + } + } + } + else { + /* signal an insertion */ + etn->nodes = g_slist_append (etn->nodes, clist->data); + etn->length ++; + n_children ++; + g_signal_emit (node, gda_tree_node_signals [NODE_INSERTED], 0, (gpointer) clist->data); + if (n_children == 1) + g_signal_emit (node, gda_tree_node_signals [NODE_HAS_CHILD_TOGGLED], 0, node); + } + } + if (enodes) { + gchar *rpath; + rpath = g_strdup_printf ("%d", pos); + for (; enodes; ) { + /* signal deletion */ + GSList *next = enodes->next; + g_object_unref (G_OBJECT (enodes->data)); + etn->nodes = g_slist_delete_link (etn->nodes, enodes); + etn->length --; + n_children --; + enodes = next; + g_signal_emit (node, gda_tree_node_signals [NODE_DELETED], 0, rpath); + if (n_children == 0) + g_signal_emit (node, gda_tree_node_signals [NODE_HAS_CHILD_TOGGLED], 0, node); + } + g_free (rpath); + } + } +} + +/* + * _gda_tree_node_get_children_for_manager: + * @node: a #GdaTreeNode + * @manager: a #GdaTreeManager + * + * Get the list of #GdaTreeNode objects which have already bee created by @mgr. + * + * Returns: a list (which must not be modified), or %NULL + */ +const GSList * +_gda_tree_node_get_children_for_manager (GdaTreeNode *node, GdaTreeManager *mgr) +{ + GSList *list; + g_return_val_if_fail (GDA_IS_TREE_NODE (node), NULL); + g_return_val_if_fail (GDA_IS_TREE_MANAGER (mgr), NULL); + GdaTreeNodePrivate *priv = gda_tree_node_get_instance_private (node); + + for (list = priv->children; list; list = list->next) { + if (GDA_TREE_NODES_LIST (list->data)->mgr == mgr) + return GDA_TREE_NODES_LIST (list->data)->nodes; + } + return NULL; +} + +/* + * _gda_tree_node_get_managers_for_children: + */ +GSList * +_gda_tree_node_get_managers_for_children (GdaTreeNode *node) +{ + GSList *list, *mgrlist = NULL; + g_return_val_if_fail (GDA_IS_TREE_NODE (node), NULL); + GdaTreeNodePrivate *priv = gda_tree_node_get_instance_private (node); + + for (list = priv->children; list; list = list->next) + mgrlist = g_slist_prepend (mgrlist, GDA_TREE_NODES_LIST (list->data)->mgr); + + return g_slist_reverse (mgrlist); +} + +/* + * _gda_tree_node_get_manager_for_child: + */ +GdaTreeManager * +_gda_tree_node_get_manager_for_child (GdaTreeNode *node, GdaTreeNode *child) +{ + GSList *list; + g_return_val_if_fail (GDA_IS_TREE_NODE (node), NULL); + GdaTreeNodePrivate *priv = gda_tree_node_get_instance_private (node); + g_return_val_if_fail (GDA_IS_TREE_NODE (child), NULL); + GdaTreeNodePrivate *cpriv = gda_tree_node_get_instance_private (child); + g_return_val_if_fail (cpriv->parent == node, NULL); + + for (list = priv->children; list; list = list->next) + if (g_slist_find (GDA_TREE_NODES_LIST (list->data)->nodes, child)) + return GDA_TREE_NODES_LIST (list->data)->mgr; + + return NULL; +} + +/** + * gda_tree_node_fetch_attribute: + * @node: a #GdaTreeNode + * @attribute: attribute name as a string + * + * Get the value associated to the attribute named @attribute for @node. If the attribute is not set, + * then @node's parents is queries (recursively up to the top level node). + * + * Attributes can have any name, but Libgda proposes some default names, + * see this section. + * + * Returns: (transfer none): a read-only #GValue, or %NULL if not attribute named @attribute has been set for @node + * + * Since: 4.2 + */ +const GValue * +gda_tree_node_fetch_attribute (GdaTreeNode *node, const gchar *attribute) +{ + const GValue *cvalue; + g_return_val_if_fail (GDA_IS_TREE_NODE (node), NULL); + GdaTreeNodePrivate *priv = gda_tree_node_get_instance_private (node); + cvalue = g_object_get_data (G_OBJECT (node), attribute); + if (cvalue == NULL && priv->parent != NULL) { + cvalue = gda_tree_node_fetch_attribute (priv->parent, attribute); + } + return (const GValue*) cvalue; +} + +/** + * gda_tree_node_get_node_attribute: + * @node: a #GdaTreeNode + * @attribute: attribute name as a string + * + * Get the value associated to the attribute named @attribute for @node. The difference with gda_tree_node_fetch_attribute() + * is that gda_tree_node_fetch_attribute() will also query @node's parents (recursively up to the top level node) if + * the attribute is not set for @node. + * + * Attributes can have any name, but Libgda proposes some default names, + * see this section. + * + * Returns: (transfer none): a read-only #GValue, or %NULL if not attribute named @attribute has been set for @node + * + * Since: 4.2 + */ +const GValue * +gda_tree_node_get_node_attribute (GdaTreeNode *node, const gchar *attribute) +{ + g_return_val_if_fail (GDA_IS_TREE_NODE (node), NULL); + + return g_object_get_data (G_OBJECT (node), attribute); +} + +/** + * gda_tree_node_set_node_attribute: + * @node: a #GdaTreeNode + * @attribute: attribute name + * @value: (transfer none) (nullable): a #GValue, or %NULL + * @destroy: a function to be called when @attribute is not needed anymore, or %NULL + * + * Set the value associated to a named attribute. The @attribute string is used AS IT IS by this method (eg. + * no copy of it is made), and + * the memory it uses will be freed using the @destroy function when no longer needed (if @destroy is %NULL, + * then the string will not be freed at all). + * + * Attributes can have any name, but Libgda proposes some default names, + * see this section. + * + * For example one would use it as: + * + * + * gda_tree_node_set_node_attribute (node, g_strdup (my_attribute), my_value, g_free); + * gda_tree_node_set_node_attribute (node, GDA_ATTRIBUTE_NAME, my_value, NULL); + * + * + * If there is already an attribute named @attribute set, then its value is replaced with the new value (@value is + * copied), except if @value is %NULL, in which case the attribute is removed. + * + * Since: 4.2 + */ +void +gda_tree_node_set_node_attribute (GdaTreeNode *node, const gchar *attribute, const GValue *value, GDestroyNotify destroy) +{ + const GValue *cvalue; + g_return_if_fail (GDA_IS_TREE_NODE (node)); + g_return_if_fail (attribute); + + cvalue = g_object_get_data (G_OBJECT (node), attribute); + if ((value && cvalue && !gda_value_differ (cvalue, value)) || + (!value && !cvalue)) + return; + + if (!g_strcmp0 (attribute, GDA_ATTRIBUTE_TREE_NODE_UNKNOWN_CHILDREN) && + (!value || (G_VALUE_TYPE (value) == G_TYPE_BOOLEAN))) { + gboolean ouc = FALSE; + gboolean nuc = FALSE; + if (cvalue && (G_VALUE_TYPE (cvalue) == G_TYPE_BOOLEAN) && + g_value_get_boolean (cvalue)) + ouc = TRUE; + + if (value && g_value_get_boolean (value)) + nuc = TRUE; + + if (ouc != nuc) { + g_object_set_data_full (G_OBJECT (node), attribute, (gpointer) value, (GDestroyNotify) gda_value_free); + g_signal_emit (node, gda_tree_node_signals[NODE_HAS_CHILD_TOGGLED], 0, node); + g_signal_emit (node, gda_tree_node_signals[NODE_CHANGED], 0, node); + return; + } + } + + g_object_set_data_full (G_OBJECT (node), attribute, (gpointer) value, (GDestroyNotify) gda_value_free); + g_signal_emit (node, gda_tree_node_signals[NODE_CHANGED], 0, node); +} + +/** + * gda_tree_node_get_parent: + * @node: a #GdaTreeNode object + * + * Get the #GdaTreeNode parent of @node in the #GdaTree node belongs to. If @node is at the top level, + * then this method return %NULL. + * + * Returns: (transfer none): the parent #GdaTreeNode + * + * Since: 4.2 + */ +GdaTreeNode * +gda_tree_node_get_parent (GdaTreeNode *node) +{ + GdaTreeNode *parent; + g_return_val_if_fail (GDA_IS_TREE_NODE (node), NULL); + GdaTreeNodePrivate *priv = gda_tree_node_get_instance_private (node); + parent = priv->parent; + GdaTreeNodePrivate *ppriv = gda_tree_node_get_instance_private (parent); + + if (parent && !ppriv->parent) + return NULL; /* avoid returning the private GdaTree's ROOT node */ + + return parent; +} + +/** + * gda_tree_node_get_children: + * @node: a #GdaTreeNode object + * + * Get a list of all @node's children, free it with g_slist_free() after usage + * + * Returns: (transfer container) (element-type GdaTreeNode): a new #GSList of #GdaTreeNode objects, or %NULL if @node does not have any child + * + * Since: 4.2 + */ +GSList * +gda_tree_node_get_children (GdaTreeNode *node) +{ + g_return_val_if_fail (GDA_IS_TREE_NODE (node), NULL); + GdaTreeNodePrivate *priv = gda_tree_node_get_instance_private (node); + if (priv->children) { + GSList *parts, *list = NULL; + + for (parts = priv->children; parts; parts = parts->next) { + if (GDA_TREE_NODES_LIST (parts->data)->nodes) + list = g_slist_concat (list, g_slist_copy (GDA_TREE_NODES_LIST (parts->data)->nodes)); + } + return list; + } + else + return NULL; +} + +/** + * gda_tree_node_get_child_index: + * @node: a #GdaTreeNode object + * @index: a index + * + * Get the #GdaTreeNode child of @node at position @index (starting at 0). + * + * Returns: (transfer none): the #GdaTreeNode, or %NULL if not found + * + * Since: 4.2 + */ +GdaTreeNode * +gda_tree_node_get_child_index (GdaTreeNode *node, gint index) +{ + g_return_val_if_fail (GDA_IS_TREE_NODE (node), NULL); + g_return_val_if_fail (index >= 0, NULL); + GdaTreeNodePrivate *priv = gda_tree_node_get_instance_private (node); + + if (priv->children) { + gint i = index; + GSList *parts; + for (parts = priv->children; parts; parts = parts->next) { + GdaTreeNodesList *tn = GDA_TREE_NODES_LIST (parts->data); + if (i < tn->length) + return g_slist_nth_data (tn->nodes, i); + i -= tn->length; + } + return NULL; + } + else + return NULL; +} + +/** + * gda_tree_node_get_child_name: + * @node: a #GdaTreeNode object + * @name: requested node's name + * + * Get the #GdaTreeNode child of @node which has the #GDA_ATTRIBUTE_NAME set to @name + * + * Returns: (transfer none): the #GdaTreeNode, or %NULL if not found + * + * Since: 4.2 + */ +GdaTreeNode * +gda_tree_node_get_child_name (GdaTreeNode *node, const gchar *name) +{ + g_return_val_if_fail (GDA_IS_TREE_NODE (node), NULL); + g_return_val_if_fail (name, NULL); + GdaTreeNodePrivate *priv = gda_tree_node_get_instance_private (node); + + if (priv->children) { + GSList *parts; + for (parts = priv->children; parts; parts = parts->next) { + GdaTreeNodesList *tn = GDA_TREE_NODES_LIST (parts->data); + GSList *list; + for (list = tn->nodes; list; list = list->next) { + if (priv->name && !g_strcmp0 (name, priv->name)) + return (GdaTreeNode*) list->data; + } + } + } + return NULL; +} + +void +_gda_nodes_list_free (GdaTreeNodesList *nl) +{ + if (nl->nodes) { + g_slist_free_full (nl->nodes, (GDestroyNotify) g_object_unref); + } + g_object_unref (nl->mgr); + g_free (nl); +} diff --git a/.flatpak-builder/cache/objects/83/0389acf130b07c763140085c516e9281159431e80fcef281bae0da3002b6f6.dirtree b/.flatpak-builder/cache/objects/83/0389acf130b07c763140085c516e9281159431e80fcef281bae0da3002b6f6.dirtree new file mode 100644 index 0000000..abeb5d7 Binary files /dev/null and b/.flatpak-builder/cache/objects/83/0389acf130b07c763140085c516e9281159431e80fcef281bae0da3002b6f6.dirtree differ diff --git a/.flatpak-builder/cache/objects/83/0593576500dad86075a28edb8bab41411c8339f5942550b858d3340194bb5b.file b/.flatpak-builder/cache/objects/83/0593576500dad86075a28edb8bab41411c8339f5942550b858d3340194bb5b.file new file mode 100644 index 0000000..baef5f6 --- /dev/null +++ b/.flatpak-builder/cache/objects/83/0593576500dad86075a28edb8bab41411c8339f5942550b858d3340194bb5b.file @@ -0,0 +1,133 @@ +/* + * Copyright (C) 2008 - 2012 Vivien Malerba + * Copyright (C) 2009 Bas Driessen + * Copyright (C) 2010 David King + * Copyright (C) 2010 Murray Cumming + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include +#include +#include +#include + +static gpointer gda_sql_statement_unknown_new (void); +static void gda_sql_statement_unknown_free (gpointer stmt); +static gpointer gda_sql_statement_unknown_copy (gpointer src); +static gchar *gda_sql_statement_unknown_serialize (gpointer stmt); + +GdaSqlStatementContentsInfo unknown_infos = { + GDA_SQL_STATEMENT_UNKNOWN, + "UNKNOWN", + gda_sql_statement_unknown_new, + gda_sql_statement_unknown_free, + gda_sql_statement_unknown_copy, + gda_sql_statement_unknown_serialize, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL +}; + +GdaSqlStatementContentsInfo * +_gda_sql_statement_unknown_get_infos (void) +{ + return &unknown_infos; +} + +static gpointer +gda_sql_statement_unknown_new (void) +{ + GdaSqlStatementUnknown *stmt; + stmt = g_new0 (GdaSqlStatementUnknown, 1); + GDA_SQL_ANY_PART (stmt)->type = GDA_SQL_ANY_STMT_UNKNOWN; + return (gpointer) stmt; +} + +static void +gda_sql_statement_unknown_free (gpointer stmt) +{ + GdaSqlStatementUnknown *unknown = (GdaSqlStatementUnknown *) stmt; + g_slist_free_full (unknown->expressions, (GDestroyNotify) gda_sql_expr_free); + g_free (unknown); +} + +static gpointer +gda_sql_statement_unknown_copy (gpointer src) +{ + GdaSqlStatementUnknown *dest; + GSList *list; + GdaSqlStatementUnknown *unknown = (GdaSqlStatementUnknown *) src; + + dest = gda_sql_statement_unknown_new (); + for (list = unknown->expressions; list; list = list->next) { + dest->expressions = g_slist_prepend (dest->expressions, + gda_sql_expr_copy ((GdaSqlExpr*) list->data)); + gda_sql_any_part_set_parent (dest->expressions->data, dest); + } + dest->expressions = g_slist_reverse (dest->expressions); + return dest; +} + +static gchar * +gda_sql_statement_unknown_serialize (gpointer stmt) +{ + GString *string; + gchar *str; + GSList *list; + GdaSqlStatementUnknown *unknown = (GdaSqlStatementUnknown *) stmt; + + g_return_val_if_fail (stmt, NULL); + + string = g_string_new ("\"contents\":["); + for (list = unknown->expressions; list; list = list->next) { + gchar *str; + str = gda_sql_expr_serialize ((GdaSqlExpr*) list->data); + if (list != unknown->expressions) + g_string_append_c (string, ','); + g_string_append (string, str); + g_free (str); + } + g_string_append_c (string, ']'); + str = string->str; + g_string_free (string, FALSE); + return str; +} + +/** + * gda_sql_statement_unknown_take_expressions: + * @stmt: a #GdaSqlStatement pointer + * @expressions: (element-type Gda.SqlExpr): a list of #GdaSqlExpr pointers + * + * Sets @stmt's list of expressions + * + * @expressions's + * ownership is transferred to + * @stmt (which means @stmt is then responsible for freeing it when no longer needed). + */ +void +gda_sql_statement_unknown_take_expressions (GdaSqlStatement *stmt, GSList *expressions) +{ + GSList *l; + GdaSqlStatementUnknown *unknown = (GdaSqlStatementUnknown *) stmt->contents; + unknown->expressions = expressions; + + for (l = expressions; l; l = l->next) + gda_sql_any_part_set_parent (l->data, unknown); +} diff --git a/.flatpak-builder/cache/objects/83/06a8a3108c267731232a1aed8afffb8cae4988d14950c4fbe81cb5dddcb5ba.commit b/.flatpak-builder/cache/objects/83/06a8a3108c267731232a1aed8afffb8cae4988d14950c4fbe81cb5dddcb5ba.commit new file mode 100644 index 0000000..7e0aacb Binary files /dev/null and b/.flatpak-builder/cache/objects/83/06a8a3108c267731232a1aed8afffb8cae4988d14950c4fbe81cb5dddcb5ba.commit differ diff --git a/.flatpak-builder/cache/objects/83/2793fbedce2985767a2f7752acff952bab8d425357564ae47d65a899008adc.file b/.flatpak-builder/cache/objects/83/2793fbedce2985767a2f7752acff952bab8d425357564ae47d65a899008adc.file new file mode 100755 index 0000000..077a230 Binary files /dev/null and b/.flatpak-builder/cache/objects/83/2793fbedce2985767a2f7752acff952bab8d425357564ae47d65a899008adc.file differ diff --git a/.flatpak-builder/cache/objects/83/2b13bbdc25d2646e5d3bbc6bf732838a54dfc70d47035356b8c36f15137d06.file b/.flatpak-builder/cache/objects/83/2b13bbdc25d2646e5d3bbc6bf732838a54dfc70d47035356b8c36f15137d06.file new file mode 100644 index 0000000..4df22d2 --- /dev/null +++ b/.flatpak-builder/cache/objects/83/2b13bbdc25d2646e5d3bbc6bf732838a54dfc70d47035356b8c36f15137d06.file @@ -0,0 +1,4 @@ +[Application] +name=io.gitlab.idevecore.PomodoroDevel +runtime=org.gnome.Platform/x86_64/44 +sdk=org.gnome.Sdk/x86_64/44 diff --git a/.flatpak-builder/cache/objects/83/7d9b8f4381876ba307fa93eed678819bd96f4f845329211d60d71a0c66b7e7.file b/.flatpak-builder/cache/objects/83/7d9b8f4381876ba307fa93eed678819bd96f4f845329211d60d71a0c66b7e7.file new file mode 100644 index 0000000..3ec0f44 Binary files /dev/null and b/.flatpak-builder/cache/objects/83/7d9b8f4381876ba307fa93eed678819bd96f4f845329211d60d71a0c66b7e7.file differ diff --git a/.flatpak-builder/cache/objects/85/66f33e8db9215d8ab30580d27875143208a7273510014b4360fb70fd6c5a56.file b/.flatpak-builder/cache/objects/85/66f33e8db9215d8ab30580d27875143208a7273510014b4360fb70fd6c5a56.file new file mode 100644 index 0000000..7dce168 --- /dev/null +++ b/.flatpak-builder/cache/objects/85/66f33e8db9215d8ab30580d27875143208a7273510014b4360fb70fd6c5a56.file @@ -0,0 +1,428 @@ +/* + * Copyright (C) 2008 Murray Cumming + * Copyright (C) 2008 - 2013 Vivien Malerba + * Copyright (C) 2013 Miguel Angel Cabrera Moya + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +#define G_LOG_DOMAIN "GDA-meta-struct-io" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +static GdaMetaDbObject *create_table_object (GdaMetaStruct *mstruct, const GValue *catalog, const gchar *quoted_catalog, + const GValue *schema, const gchar *quoted_schema, xmlNodePtr node, GError **error); +/* +static GdaMetaDbObject *create_view_object (GdaMetaStruct *mstruct, const GValue *catalog, const gchar *quoted_catalog, + const GValue *schema, const gchar *quoted_schema, xmlNodePtr node, GError **error); +*/ + + + +/** + * gda_meta_struct_load_from_xml_file: + * @mstruct: a #GdaMetaStruct object + * @catalog: (nullable): the catalog name, or %NULL + * @schema: (nullable): the schema name, or %NULL + * @xml_spec_file: the specifications as the name of an XML file + * @error: (nullable): a place to store errors, or %NULL + * + * Loads an XML description into @mstruct. This method is still experimental and no description + * the XML file structure is given, and no guarantee that it will remain as it is given. + * + * returns: TRUE if no error has occurred + */ +gboolean +gda_meta_struct_load_from_xml_file (GdaMetaStruct *mstruct, const gchar *catalog, const gchar *schema, + const gchar *xml_spec_file, GError **error) +{ + xmlNodePtr node; + xmlDocPtr doc; + + GValue *catalog_value = NULL; + gchar *quoted_catalog = NULL; + GValue *schema_value = NULL; + gchar *quoted_schema = NULL; + + g_return_val_if_fail (GDA_IS_META_STRUCT (mstruct), FALSE); + g_return_val_if_fail (xml_spec_file && *xml_spec_file, FALSE); + + if (catalog) { + g_value_set_string ((catalog_value = gda_value_new (G_TYPE_STRING)), catalog); + quoted_catalog = gda_sql_identifier_quote (catalog, NULL, NULL, FALSE, FALSE); + } + if (schema) { + g_value_set_string ((schema_value = gda_value_new (G_TYPE_STRING)), schema); + quoted_schema = gda_sql_identifier_quote (schema, NULL, NULL, FALSE, FALSE); + } + + /* load information schema's structure XML file */ + doc = xmlParseFile (xml_spec_file); + if (!doc) { + g_set_error (error, GDA_META_STRUCT_ERROR, GDA_META_STRUCT_XML_ERROR, + _("Could not load file '%s'"), xml_spec_file); + return FALSE; + } + + node = xmlDocGetRootElement (doc); + if (!node || strcmp ((gchar *) node->name, "schema")) { + g_set_error (error, GDA_META_STRUCT_ERROR, GDA_META_STRUCT_XML_ERROR, + _("Root node of file '%s' should be ."), xml_spec_file); + xmlFreeDoc (doc); + return FALSE; + } + + /* walk through the xmlDoc */ + for (node = node->children; node; node = node->next) { + /* tag for table creation */ + if (!strcmp ((gchar *) node->name, "table")) { + GdaMetaDbObject *dbo; + dbo = create_table_object (mstruct, catalog_value, quoted_catalog, + schema_value, quoted_schema, node, error); + if (!dbo) { + xmlFreeDoc (doc); + return FALSE; + } + } + /* tag for view creation */ + else if (!strcmp ((gchar *) node->name, "view")) { + TO_IMPLEMENT; + /* + GdaMetaDbObject *dbo; + dbo = create_view_object (mstruct, catalog_value, quoted_catalog, + schema_value, quoted_schema, node, error); + if (!dbo) { + xmlFreeDoc (doc); + return FALSE; + } + */ + } + } + xmlFreeDoc (doc); + + /* sort database objects */ + if (! gda_meta_struct_sort_db_objects (mstruct, GDA_META_SORT_DEPENDENCIES, error)) + return FALSE; + +#ifdef GDA_DEBUG + GSList *objlist, *list; + objlist = gda_meta_struct_get_all_db_objects (mstruct); + + for (list = objlist; list; list = list->next) { + GSList *dl; + g_print ("Database object: %s\n", GDA_META_DB_OBJECT (list->data)->obj_name); + for (dl = GDA_META_DB_OBJECT (list->data)->depend_list; dl; dl = dl->next) { + g_print (" depend on %s\n", GDA_META_DB_OBJECT (dl->data)->obj_name); + } + } + g_slist_free (objlist); +#endif + + /* dump as a graph */ +#ifdef GDA_DEBUG + gchar *graph; + GError *lerror = NULL; + graph = gda_meta_struct_dump_as_graph (mstruct, GDA_META_GRAPH_COLUMNS, &lerror); + if (graph) { + if (g_file_set_contents ("graph.dot", graph, -1, &lerror)) + g_print ("Graph written to 'graph.dot'\n"); + else { + g_print ("Could not save graph to file: %s\n", lerror && lerror->message ? lerror->message : "No detail"); + g_error_free (lerror); + } + g_free (graph); + } + else { + g_print ("Could not create a graph: %s\n", lerror && lerror->message ? lerror->message : "No detail"); + g_error_free (lerror); + } +#endif + + return TRUE; +} + +static GdaMetaDbObject * +create_table_object (GdaMetaStruct *mstruct, const GValue *catalog, const gchar *quoted_catalog, + const GValue *schema, const gchar *quoted_schema, xmlNodePtr node, GError **error) +{ + GdaMetaDbObject *dbobj; + xmlChar *table_name, *table_schema; + GString *full_table_name; + GValue *v1 = NULL, *v2 = NULL, *v3 = NULL; + GArray *pk_cols_array = NULL; + gchar *tmp; + + table_name = xmlGetProp (node, BAD_CAST "name"); + if (!table_name) { + g_set_error (error, GDA_META_STRUCT_ERROR, GDA_META_STRUCT_XML_ERROR, + "%s", _("Missing table name from
node")); + return NULL; + } + table_schema = xmlGetProp (node, BAD_CAST "schema"); + + /* determine object's complete name */ + full_table_name = g_string_new (""); + if (quoted_catalog) { + v1 = gda_value_copy (catalog); + g_string_append (full_table_name, quoted_catalog); + g_string_append_c (full_table_name, '.'); + } + if (table_schema) { + g_value_set_string ((v2 = gda_value_new (G_TYPE_STRING)), (gchar *) table_schema); + tmp = gda_sql_identifier_quote ((gchar *) table_schema, NULL, NULL, FALSE, FALSE); + g_string_append (full_table_name, tmp); + g_free (tmp); + g_string_append_c (full_table_name, '.'); + } + else if (quoted_schema) { + v2 = gda_value_copy (schema); + g_string_append (full_table_name, quoted_schema); + g_string_append_c (full_table_name, '.'); + } + g_value_set_string ((v3 = gda_value_new (G_TYPE_STRING)), (gchar *) table_name); + + tmp = gda_sql_identifier_quote ((gchar *) table_name, NULL, NULL, FALSE, FALSE); + g_string_append (full_table_name, tmp); + g_free (tmp); + + /* a new GdaMetaDbObject structure */ + dbobj = g_new0 (GdaMetaDbObject, 1); + dbobj->obj_type = GDA_META_DB_TABLE; + dbobj->obj_catalog = catalog ? g_value_dup_string (catalog) : NULL; + dbobj->obj_schema = table_schema ? g_strdup ((gchar *) table_schema) : + (schema ? g_value_dup_string (schema) : NULL); + dbobj->obj_name = g_strdup ((gchar *) table_name); + dbobj->obj_full_name = full_table_name->str; + g_string_free (full_table_name, FALSE); + dbobj = _gda_meta_struct_add_db_object (mstruct, dbobj, error); + if (!dbobj) + goto onerror; + + /* walk through the columns and Fkey nodes */ + GdaMetaTable *mtable = GDA_META_TABLE (dbobj); + xmlNodePtr cnode; + pk_cols_array = g_array_new (FALSE, FALSE, sizeof (gint)); + gint colsindex = 0; + for (cnode = node->children; cnode; cnode = cnode->next) { + if (!strcmp ((gchar *) cnode->name, "column")) { + xmlChar *cname, *ctype, *xstr, *extra; + gboolean pkey = FALSE; + gboolean nullok = FALSE; + + if (strcmp ((gchar *) cnode->name, "column")) + continue; + cname = xmlGetProp (cnode, BAD_CAST "name"); + if (!cname) { + g_set_error (error, GDA_META_STRUCT_ERROR, + GDA_META_STRUCT_XML_ERROR, + _("Missing column name for table '%s'"), + dbobj->obj_full_name); + goto onerror; + } + xstr = xmlGetProp (cnode, BAD_CAST "pkey"); + if (xstr) { + if ((*xstr == 't') || (*xstr == 'T')) + pkey = TRUE; + xmlFree (xstr); + } + xstr = xmlGetProp (cnode, BAD_CAST "nullok"); + if (xstr) { + if ((*xstr == 't') || (*xstr == 'T')) + nullok = TRUE; + xmlFree (xstr); + } + ctype = xmlGetProp (cnode, BAD_CAST "type"); + + /* a field */ + GdaMetaTableColumn *tcol; + + tcol = g_new0 (GdaMetaTableColumn, 1); + tcol->column_name = g_strdup ((gchar *) cname); + xmlFree (cname); + tcol->column_type = g_strdup (ctype ? (gchar *) ctype : "string"); + tcol->gtype = ctype ? gda_g_type_from_string ((gchar *) ctype) : G_TYPE_STRING; + if (ctype) + xmlFree (ctype); + if (tcol->gtype == G_TYPE_INVALID) + tcol->gtype = GDA_TYPE_NULL; + tcol->pkey = pkey; + tcol->nullok = nullok; + if (pkey) + g_array_append_val (pk_cols_array, colsindex); + colsindex++; + + /* FIXME: handle default value */ + extra = xmlGetProp (cnode, BAD_CAST "autoinc"); + if (extra) { + tcol->auto_incement = TRUE; + xmlFree (extra); + } + + mtable->columns = g_slist_append (mtable->columns, tcol); + } + else if (!strcmp ((gchar *) cnode->name, "fkey")) { + xmlNodePtr fnode; + xmlChar *ref_table; + + ref_table = xmlGetProp (cnode, BAD_CAST "ref_table"); + if (!ref_table) { + g_set_error (error, GDA_META_STRUCT_ERROR, + GDA_META_STRUCT_XML_ERROR, + _("Missing foreign key's referenced table name for table '%s'"), + dbobj->obj_full_name); + goto onerror; + } + + /* referenced GdaMetaDbObject */ + GdaMetaDbObject *ref_obj; + gchar *name_part, *schema_part, *catalog_part = NULL; + gchar *tmp = g_strdup ((gchar *) ref_table); + if (!_split_identifier_string (tmp, &schema_part, &name_part)) { + g_set_error (error, GDA_META_STRUCT_ERROR, + GDA_META_STRUCT_XML_ERROR, + _("Invalid referenced table name '%s'"), ref_table); + xmlFree (ref_table); + goto onerror; + } + if (schema_part && !_split_identifier_string (schema_part, &catalog_part, &schema_part)) { + g_set_error (error, GDA_META_STRUCT_ERROR, + GDA_META_STRUCT_XML_ERROR, + _("Invalid referenced table name '%s'"), ref_table); + xmlFree (ref_table); + goto onerror; + } + if (catalog_part) { + g_set_error (error, GDA_META_STRUCT_ERROR, + GDA_META_STRUCT_XML_ERROR, + _("Invalid referenced table name '%s'"), ref_table); + xmlFree (ref_table); + goto onerror; + } + GValue *rv2 = NULL, *rv3; + if (schema_part) + g_value_set_string ((rv2 = gda_value_new (G_TYPE_STRING)), schema_part); + g_value_set_string ((rv3 = gda_value_new (G_TYPE_STRING)), name_part); + ref_obj = gda_meta_struct_get_db_object (mstruct, NULL, rv2, rv3); + if (rv2) gda_value_free (rv2); + gda_value_free (rv3); + + if (!ref_obj) { + ref_obj = g_new0 (GdaMetaDbObject, 1); + ref_obj->obj_type = GDA_META_DB_UNKNOWN; + ref_obj->obj_full_name = g_strdup ((gchar *) ref_table); + ref_obj->obj_name = name_part; + ref_obj->obj_schema = schema_part; + xmlFree (ref_table); + ref_obj = _gda_meta_struct_add_db_object (mstruct, ref_obj, error); + if (! ref_obj) + goto onerror; + } + else + xmlFree (ref_table); + + /* GdaMetaTableForeignKey structure */ + GdaMetaTableForeignKey *mfkey; + GArray *fk_names_array = g_array_new (FALSE, FALSE, sizeof (gchar *)); + GArray *ref_pk_names_array = g_array_new (FALSE, FALSE, sizeof (gchar *)); + + for (fnode = cnode->children; fnode; fnode = fnode->next) { + xmlChar *col, *ref_col; + gchar *tmp; + if (strcmp ((gchar *) fnode->name, "part")) + continue; + col = xmlGetProp (fnode, BAD_CAST "column"); + if (!col) { + g_set_error (error, GDA_META_STRUCT_ERROR, + GDA_META_STRUCT_XML_ERROR, + _("Missing foreign key's column name for table '%s'"), + dbobj->obj_full_name); + g_array_free (fk_names_array, TRUE); + g_array_free (ref_pk_names_array, TRUE); + goto onerror; + } + tmp = g_strdup ((gchar *) col); + g_array_append_val (fk_names_array, tmp); + ref_col = xmlGetProp (fnode, BAD_CAST "ref_column"); + if (ref_col) { + tmp = g_strdup ((gchar *) ref_col); + g_array_append_val (ref_pk_names_array, tmp); + xmlFree (ref_col); + } + else { + tmp = g_strdup ((gchar *) col); + g_array_append_val (ref_pk_names_array, tmp); + } + xmlFree (col); + } + + mfkey = g_new0 (GdaMetaTableForeignKey, 1); + mfkey->meta_table = dbobj; + mfkey->depend_on = ref_obj; + mfkey->cols_nb = fk_names_array->len; + mfkey->fk_cols_array = NULL; + mfkey->fk_names_array = (gchar **) fk_names_array->data; + mfkey->ref_pk_cols_array = NULL; + mfkey->ref_pk_names_array = (gchar **) ref_pk_names_array->data; + g_array_free (fk_names_array, FALSE); + g_array_free (ref_pk_names_array, FALSE); + mtable->fk_list = g_slist_append (mtable->fk_list, mfkey); + + if (mfkey->depend_on->obj_type == GDA_META_DB_TABLE) { + GdaMetaTable *dot = GDA_META_TABLE (mfkey->depend_on); + dot->reverse_fk_list = g_slist_prepend (dot->reverse_fk_list, mfkey); + } + dbobj->depend_list = g_slist_append (dbobj->depend_list, mfkey->depend_on); + } + /* FIXME: Add support for unique node */ + if (!strcmp ((gchar *) cnode->name, "unique")) { + TO_IMPLEMENT; + } + } + mtable->pk_cols_array = (gint*) pk_cols_array->data; + mtable->pk_cols_nb = pk_cols_array->len; + g_array_free (pk_cols_array, FALSE); + + return dbobj; + + onerror: + if (v1) gda_value_free (v1); + if (v2) gda_value_free (v2); + gda_value_free (v3); + + if (pk_cols_array) + g_array_free (pk_cols_array, TRUE); + + return NULL; +} + +/* +static GdaMetaDbObject * +create_view_object (GdaMetaStruct *mstruct, const GValue *catalog, const gchar *quoted_catalog, + const GValue *schema, const gchar *quoted_schema, xmlNodePtr node, GError **error) +{ + TO_IMPLEMENT; + return NULL; +} +*/ + diff --git a/.flatpak-builder/cache/objects/85/a4d69a20b55fe58703a5e6a79316e8c09fdcf29757b4a26b4243d26a26202b.file b/.flatpak-builder/cache/objects/85/a4d69a20b55fe58703a5e6a79316e8c09fdcf29757b4a26b4243d26a26202b.file new file mode 100644 index 0000000..cbcbe90 Binary files /dev/null and b/.flatpak-builder/cache/objects/85/a4d69a20b55fe58703a5e6a79316e8c09fdcf29757b4a26b4243d26a26202b.file differ diff --git a/.flatpak-builder/cache/objects/85/c97c2d396506a9e9afa0119cdafba8aeeaa5377afdb4a381fe078b879b4de7.dirtree b/.flatpak-builder/cache/objects/85/c97c2d396506a9e9afa0119cdafba8aeeaa5377afdb4a381fe078b879b4de7.dirtree new file mode 100644 index 0000000..213c01f Binary files /dev/null and b/.flatpak-builder/cache/objects/85/c97c2d396506a9e9afa0119cdafba8aeeaa5377afdb4a381fe078b879b4de7.dirtree differ diff --git a/.flatpak-builder/cache/objects/85/ca9fff968291319bed7cf12784aab6d83a59d12786a9241b04de49039ba504.file b/.flatpak-builder/cache/objects/85/ca9fff968291319bed7cf12784aab6d83a59d12786a9241b04de49039ba504.file new file mode 100644 index 0000000..2257091 --- /dev/null +++ b/.flatpak-builder/cache/objects/85/ca9fff968291319bed7cf12784aab6d83a59d12786a9241b04de49039ba504.file @@ -0,0 +1,310 @@ +/* + * Copyright (C) 2006 - 2013 Vivien Malerba + * Copyright (C) 2007 Murray Cumming + * Copyright (C) 2009 Bas Driessen + * Copyright (C) 2010 David King + * Copyright (C) 2015 Corentin Noël + * Copyright (C) 2018 Daniel Espinosa + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +#define G_LOG_DOMAIN "GDA-data-handler" + +#include "gda-data-handler.h" +#include "handlers/gda-handler-bin.h" +#include "handlers/gda-handler-boolean.h" +#include "handlers/gda-handler-numerical.h" +#include "handlers/gda-handler-string.h" +#include "handlers/gda-handler-text.h" +#include "handlers/gda-handler-time.h" +#include "handlers/gda-handler-type.h" + +G_DEFINE_INTERFACE (GdaDataHandler, gda_data_handler, G_TYPE_OBJECT) + +char *gda_data_handler_get_sql_from_value_default (GdaDataHandler *dh, const GValue *value); + +static void +gda_data_handler_default_init (GdaDataHandlerInterface *iface) { + iface->get_sql_from_value = gda_data_handler_get_sql_from_value_default; +} + +char * +gda_data_handler_get_sql_from_value_default (GdaDataHandler *dh, const GValue *value) +{ + g_return_val_if_fail (dh && GDA_IS_DATA_HANDLER (dh), NULL); + + if (! value || gda_value_is_null (value)) + return g_strdup ("NULL"); + + g_return_val_if_fail (gda_data_handler_accepts_g_type (dh, G_VALUE_TYPE (value)), NULL); + return NULL; +} +/** + * gda_data_handler_get_sql_from_value: + * @dh: an object which implements the #GdaDataHandler interface + * @value: (nullable): the value to be converted to a string, or %NULL + * + * Creates a new string which is an SQL representation of the given value, the returned string + * can be used directly in an SQL statement. For example if @value is a G_TYPE_STRING, then + * the returned string will be correctly quoted. Note however that it is a better practice + * to use variables in statements instead of value literals, see + * the GdaSqlParser for more information. + * + * If the value is NULL or is of type GDA_TYPE_NULL, + * or is a G_TYPE_STRING and g_value_get_string() returns %NULL, the returned string is "NULL". + * + * Returns: (transfer full): the new string, or %NULL if an error occurred + */ +gchar * +gda_data_handler_get_sql_from_value (GdaDataHandler *dh, const GValue *value) +{ + g_return_val_if_fail (dh && GDA_IS_DATA_HANDLER (dh), NULL); + + if (GDA_DATA_HANDLER_GET_IFACE (dh)->get_sql_from_value) + return (GDA_DATA_HANDLER_GET_IFACE (dh)->get_sql_from_value) (dh, value); + + return NULL; +} + + +/** + * gda_data_handler_get_str_from_value: + * @dh: an object which implements the #GdaDataHandler interface + * @value: (nullable): the value to be converted to a string, or %NULL + * + * Creates a new string which is a "user friendly" representation of the given value + * (in the user's locale, specially for the dates). If the value is + * NULL or is of type GDA_TYPE_NULL, the returned string is a copy of "" (empty string). + * + * Note: the returned value will be in the current locale representation. + * + * Returns: (transfer full): the new string, or %NULL if an error occurred + */ +gchar * +gda_data_handler_get_str_from_value (GdaDataHandler *dh, const GValue *value) +{ + g_return_val_if_fail (dh && GDA_IS_DATA_HANDLER (dh), NULL); + + if (! value || gda_value_is_null (value)) + return g_strdup (""); + + g_return_val_if_fail (gda_data_handler_accepts_g_type (dh, G_VALUE_TYPE (value)), NULL); + + /* Calling the real function with value != NULL and not of type GDA_TYPE_NULL */ + if (GDA_DATA_HANDLER_GET_IFACE (dh)->get_str_from_value) + return (GDA_DATA_HANDLER_GET_IFACE (dh)->get_str_from_value) (dh, value); + + return NULL; +} + +/** + * gda_data_handler_get_value_from_sql: + * @dh: an object which implements the #GdaDataHandler interface + * @sql: (nullable) (transfer none): an SQL string, or %NULL + * @type: a GType + * + * Creates a new GValue which represents the SQL value given as argument. This is + * the opposite of the function gda_data_handler_get_sql_from_value(). The type argument + * is used to determine the real data type requested for the returned value. + * + * If the @sql string is %NULL, then the returned GValue is of type GDA_TYPE_NULL; + * if the @sql string does not correspond to a valid SQL string for the requested type, then + * the %NULL is returned. + * + * Returns: (transfer full): the new #GValue or %NULL on error + */ +GValue * +gda_data_handler_get_value_from_sql (GdaDataHandler *dh, const gchar *sql, GType type) +{ + g_return_val_if_fail (dh && GDA_IS_DATA_HANDLER (dh), NULL); + g_return_val_if_fail (gda_data_handler_accepts_g_type (dh, type), NULL); + + if (!sql) + return gda_value_new_null (); + + if (GDA_DATA_HANDLER_GET_IFACE (dh)->get_value_from_sql) + return (GDA_DATA_HANDLER_GET_IFACE (dh)->get_value_from_sql) (dh, sql, type); + + return NULL; +} + + +/** + * gda_data_handler_get_value_from_str: + * @dh: an object which implements the #GdaDataHandler interface + * @str: (nullable) (transfer none): a string or %NULL + * @type: a GType + * + * Creates a new GValue which represents the @str value given as argument. This is + * the opposite of the function gda_data_handler_get_str_from_value(). The type argument + * is used to determine the real data type requested for the returned value. + * + * If the @str string is %NULL, then the returned GValue is of type GDA_TYPE_NULL; + * if the @str string does not correspond to a valid string for the requested type, then + * %NULL is returned. + * + * Note: the @str string must be in the current locale representation + * + * Returns: (transfer full): the new #GValue or %NULL on error + */ +GValue * +gda_data_handler_get_value_from_str (GdaDataHandler *dh, const gchar *str, GType type) +{ + g_return_val_if_fail (dh && GDA_IS_DATA_HANDLER (dh), NULL); + g_return_val_if_fail (gda_data_handler_accepts_g_type (dh, type), NULL); + + if (!str) + return gda_value_new_null (); + + if (GDA_DATA_HANDLER_GET_IFACE (dh)->get_value_from_str) + return (GDA_DATA_HANDLER_GET_IFACE (dh)->get_value_from_str) (dh, str, type); + else { + /* if the get_value_from_str() method is not implemented, then we try the + get_value_from_sql() method */ + if (GDA_DATA_HANDLER_GET_IFACE (dh)->get_value_from_sql) + return (GDA_DATA_HANDLER_GET_IFACE (dh)->get_value_from_sql) (dh, str, type); + } + + return NULL; +} + + +/** + * gda_data_handler_get_sane_init_value: + * @dh: an object which implements the #GdaDataHandler interface + * @type: a #GType + * + * Creates a new GValue which holds a sane initial value to be used if no value is specifically + * provided. For example for a simple string, this would return a new value containing the "" string. + * + * Returns: (nullable) (transfer full): the new #GValue, or %NULL if no such value can be created. + */ +GValue * +gda_data_handler_get_sane_init_value (GdaDataHandler *dh, GType type) +{ + g_return_val_if_fail (dh && GDA_IS_DATA_HANDLER (dh), NULL); + g_return_val_if_fail (gda_data_handler_accepts_g_type (dh, type), NULL); + + if (GDA_DATA_HANDLER_GET_IFACE (dh)->get_sane_init_value) + return (GDA_DATA_HANDLER_GET_IFACE (dh)->get_sane_init_value) (dh, type); + + return NULL; +} + +/** + * gda_data_handler_accepts_g_type: + * @dh: an object which implements the #GdaDataHandler interface + * @type: a #GType + * + * Checks wether the GdaDataHandler is able to handle the gda type given as argument. + * + * Returns: %TRUE if the gda type can be handled + */ +gboolean +gda_data_handler_accepts_g_type (GdaDataHandler *dh, GType type) +{ + g_return_val_if_fail (GDA_IS_DATA_HANDLER (dh), FALSE); + if (GDA_DATA_HANDLER_GET_IFACE (dh)->accepts_g_type) + return (GDA_DATA_HANDLER_GET_IFACE (dh)->accepts_g_type) (dh, type); + + return FALSE; +} + +/** + * gda_data_handler_get_descr: + * @dh: an object which implements the #GdaDataHandler interface + * + * Get a short description of the GdaDataHandler + * + * Returns: (transfer none): the description + */ +const gchar * +gda_data_handler_get_descr (GdaDataHandler *dh) +{ + g_return_val_if_fail (dh && GDA_IS_DATA_HANDLER (dh), NULL); + + if (GDA_DATA_HANDLER_GET_IFACE (dh)->get_descr) + return (GDA_DATA_HANDLER_GET_IFACE (dh)->get_descr) (dh); + + return NULL; +} + +/** + * gda_data_handler_get_default: + * @for_type: a #GType type + * + * Obtain a pointer to a #GdaDataHandler which can manage #GValue values of type @for_type. The returned + * data handler will be adapted to use the current locale information (for example dates will be formatted + * taking into account the locale). + * + * The returned pointer is %NULL if there is no default data handler available for the @for_type data type + * + * Returns: (transfer full): a #GdaDataHandler which must be destroyed using g_object_unref() + * + * Since: 4.2.3 + */ +GdaDataHandler * +gda_data_handler_get_default (GType for_type) +{ + GdaDataHandler *dh = NULL; + + if (for_type == G_TYPE_INT64) { + dh = gda_handler_numerical_new (); + } else if (for_type == G_TYPE_UINT64) { + dh = gda_handler_numerical_new (); + } else if (for_type == GDA_TYPE_BINARY) { + dh = gda_handler_bin_new (); + } else if (for_type == GDA_TYPE_BLOB) { + dh = gda_handler_bin_new (); + } else if (for_type == G_TYPE_BOOLEAN) { + dh = gda_handler_boolean_new (); + } else if (for_type == G_TYPE_DATE) { + dh = gda_handler_time_new (); + } else if (for_type == G_TYPE_DOUBLE) { + dh = gda_handler_numerical_new (); + } else if (for_type == G_TYPE_INT) { + dh = gda_handler_numerical_new (); + } else if (for_type == GDA_TYPE_NUMERIC) { + dh = gda_handler_numerical_new (); + } else if (for_type == G_TYPE_FLOAT) { + dh = gda_handler_numerical_new (); + } else if (for_type == GDA_TYPE_SHORT) { + dh = gda_handler_numerical_new (); + } else if (for_type == GDA_TYPE_USHORT) { + dh = gda_handler_numerical_new (); + } else if (for_type == G_TYPE_STRING) { + dh = gda_handler_string_new (); + } else if (for_type == GDA_TYPE_TEXT) { + dh = gda_handler_text_new (); + } else if (for_type == GDA_TYPE_TIME) { + dh = gda_handler_time_new (); + } else if (for_type == G_TYPE_DATE_TIME) { + dh = gda_handler_time_new (); + } else if (for_type == G_TYPE_CHAR) { + dh = gda_handler_numerical_new (); + } else if (for_type == G_TYPE_UCHAR) { + dh = gda_handler_numerical_new (); + } else if (for_type == G_TYPE_ULONG) { + dh = gda_handler_numerical_new (); + } else if (for_type == G_TYPE_LONG) { + dh = gda_handler_numerical_new (); + } else if (for_type == G_TYPE_GTYPE) { + dh = gda_handler_type_new (); + } else if (for_type == G_TYPE_UINT) { + dh = gda_handler_numerical_new (); + } + return dh; +} diff --git a/.flatpak-builder/cache/objects/85/d15d1b3ebf05f181c60a3b09e5ea78f1bbe81718c3fce72e87fd578b30a18f.file b/.flatpak-builder/cache/objects/85/d15d1b3ebf05f181c60a3b09e5ea78f1bbe81718c3fce72e87fd578b30a18f.file new file mode 100755 index 0000000..b3ac3e7 --- /dev/null +++ b/.flatpak-builder/cache/objects/85/d15d1b3ebf05f181c60a3b09e5ea78f1bbe81718c3fce72e87fd578b30a18f.file @@ -0,0 +1,259 @@ +#! /bin/sh +# intltoolize - Prepare a package to use intltool. +# intltoolize. Generated from intltoolize.in by configure. +# Copyright (C) 1996-1999 Free Software Foundation, Inc. +# Copyright (C) 2001 Eazel, Inc. +# +# Originally based on libtoolize by Gordon Matzigkeit , 1996 +# +# Modified for xml-i18n-tools by Maciej Stachowiak +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# The name of this program. +progname=`echo "$0" | sed 's%^.*/%%'` + +# Constants. +PROGRAM=intltoolize +PACKAGE=intltool +VERSION=0.51.0 + +# Directory names. +prefix=/app + +case "`uname`" in +MINGW32*) + # Assume intltoolize is in $prefix/bin. Strip off the script name and the "bin" + prefix=`dirname $0` + prefix=`dirname $prefix` + ;; +esac + +datarootdir=${prefix}/share +datadir=${datarootdir} +pkgdatadir=${datadir}/intltool + +aclocaldir=${datadir}/aclocal +intltool_m4="${aclocaldir}/intltool.m4" + +dry_run=no +help="Try '$progname --help' for more information." +rm="rm -f" +rm_rec="rm -rf" +ln_s="ln -s" +cp="cp -f" +mkdir="mkdir" +mkinstalldirs="mkinstalldirs" + +# Global variables. +automake= +copy= +force= +status=0 + +for arg +do + case "$arg" in + --help) + cat <&2 + echo "$help" 1>&2 + exit 1 + ;; + + *) + echo "$progname: too many arguments" 1>&2 + echo "$help" 1>&2 + exit 1 + ;; + esac +done + +if test -f configure.ac; then + configure="configure.ac" +else + if test -f configure.in; then + configure="configure.in" + else + echo "$progname: neither 'configure.ac' nor 'configure.in' exists" 1>&2 + echo "$help" 1>&2 + exit 1 + fi +fi + + +files='po/Makefile.in.in' + +if test -z "$automake"; then + if egrep '^(AC|IT)_PROG_INTLTOOL' $configure >/dev/null 2>&1; then : + else + echo "ERROR: 'IT_PROG_INTLTOOL' must appear in $configure for intltool to work." + exit 1 + fi + + if grep 'generated automatically by aclocal' aclocal.m4 >/dev/null 2>&1; then + updatemsg="update your 'aclocal.m4' by running aclocal" + else + updatemsg="add the contents of '$intltool_m4' to 'aclocal.m4'" + fi + + if egrep '^AC_DEFUN\(\[IT_PROG_INTLTOOL\]' aclocal.m4 >/dev/null 2>&1; then + # Check the version number on intltool.m4 and the one used in aclocal.m4. + instserial=`grep '^# serial ' $intltool_m4 | grep 'IT_PROG_INTLTOOL' | sed -e 's/^# serial \([0-9][0-9]*\).*$/\1/; q'` + + if test -z "$instserial"; then + echo "$progname: warning: no serial number on '$intltool_m4'" 1>&2 + else + # If the local macro has no serial number, we assume it's ancient. + localserial=`grep '^# serial ' aclocal.m4 | grep 'IT_PROG_INTLTOOL' | sed -e 's/^# serial \([0-9][0-9]*\).*$/\1/; q'` + + test -z "$localserial" && localserial=0 + + if test "$localserial" -lt "$instserial"; then + echo "You should $updatemsg." + elif test "$localserial" -gt "$instserial"; then + echo "$progname: '$intltool_m4' is serial $instserial, less than $localserial in 'aclocal.m4'" 1>&2 + if test -z "$force"; then + echo "Use '--force' to replace newer intltool files with this version." 1>&2 + exit 1 + fi + echo "To remain compatible, you should $updatemsg." + fi + fi + else + echo "You should $updatemsg." + fi +fi + + +# Copy or symlink the Makefile.in.in +( +for file in $files; do + if test -f "$file" && test -z "$force"; then + test -z "$automake" && echo "$progname: '$file' exists: use '--force' to overwrite" 1>&2 + continue + fi + + $rm $file + if test -n "$ln_s" && $ln_s $pkgdatadir/`basename $file` $file; then : + elif $cp $pkgdatadir/`basename $file` $file; then : + else + echo "$progname: cannot copy '$pkgdatadir/`basename $file`' to '$file'" 1>&2 + status=1 + fi +# Touch script names for backward compatibility + for script in intltool-extract.in intltool-merge.in intltool-update.in; do + # Always remove the script files now + rm -f $script + if egrep $script Makefile.am >/dev/null 2>&1; then + touch $script + fi + done +done + +exit $status +# make sure this subshell exits with the exit value if it failed +) || exit $? + + +# If the AC_CONFIG_MACRO_DIR() macro is used, copy intltool.m4 from our +# prefix to that directory. This makes sure that the M4 macro used +# matches the intltool scripts we install. +# If AC_CONFIG_MACRO_DIR is not used, things will behave as before (aclocal +# will be used to pull in the macro. +m4dir=`cat "$configure" | grep '^AC_CONFIG_MACRO_DIR' | sed -n -e 's/AC_CONFIG_MACRO_DIR(\([^()]*\))/\1/p' | sed -e 's/^\[\(.*\)\]$/\1/' | sed -e 1q` +if test -n "$m4dir"; then + rm -f $m4dir/intltool.m4 + if test -n "$ln_s" && $ln_s $intltool_m4 $m4dir/intltool.m4; then : + elif $cp $intltool_m4 $m4dir/intltool.m4; then : + else + echo "$progname: cannot copy '$intltool_m4' to '$m4dir/intltool.m4'" 1>&2 + exit 1 + fi +fi + + +# FIXME: This probably does not work w/ builddir != srcdir because it +# gets at source files relative to the current directory. + +grep INTLTOOL_MAKEFILE po/Makefile.in.in >/dev/null || { + echo "$progname: 'po/Makefile.in.in' is out of date: use '--force' to overwrite" + exit 1 +} + +exit $status + +# Local Variables: +# mode:shell-script +# sh-indentation:2 +# End: diff --git a/.flatpak-builder/cache/objects/86/322709178b5e41f5b2b37274da732fb28efae42775360a769db563f49bea41.file b/.flatpak-builder/cache/objects/86/322709178b5e41f5b2b37274da732fb28efae42775360a769db563f49bea41.file new file mode 100644 index 0000000..6fd78e4 --- /dev/null +++ b/.flatpak-builder/cache/objects/86/322709178b5e41f5b2b37274da732fb28efae42775360a769db563f49bea41.file @@ -0,0 +1,1794 @@ +/* + * Copyright (C) 2007 - 2016 Vivien Malerba + * Copyright (C) 2009 Bas Driessen + * Copyright (C) 2010 David King + * Copyright (C) 2017,2018 Daniel Espinosa + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include +#include +#include "gda-vprovider-data-model.h" +#include "gda-vconnection-data-model.h" +#include "gda-vconnection-data-model-private.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +/* module error */ +GQuark gda_vprovider_data_model_error_quark (void) +{ + static GQuark quark; + if (!quark) + quark = g_quark_from_static_string ("gda_vprovider_data_model_error"); + return quark; +} + + +#define GDA_DEBUG_VIRTUAL +#undef GDA_DEBUG_VIRTUAL + +typedef struct { + int foo; +} GdaVproviderDataModelPrivate; + +G_DEFINE_TYPE_WITH_PRIVATE (GdaVproviderDataModel, gda_vprovider_data_model, GDA_TYPE_VIRTUAL_PROVIDER) + + +static GdaConnection *gda_vprovider_data_model_create_connection (GdaServerProvider *provider); +static gboolean gda_vprovider_data_model_open_connection (GdaServerProvider *provider, GdaConnection *cnc, + GdaQuarkList *params, GdaQuarkList *auth); +static gboolean gda_vprovider_data_model_prepare_connection (GdaServerProvider *provider, GdaConnection *cnc, + GdaQuarkList *params, GdaQuarkList *auth); +static gboolean gda_vprovider_data_model_close_connection (GdaServerProvider *provider, + GdaConnection *cnc); +static GObject *gda_vprovider_data_model_statement_execute (GdaServerProvider *provider, GdaConnection *cnc, + GdaStatement *stmt, GdaSet *params, + GdaStatementModelUsage model_usage, + GType *col_types, GdaSet **last_inserted_row, + GError **error); +static const gchar *gda_vprovider_data_model_get_name (GdaServerProvider *provider); + +static GValue **create_gvalues_array_from_sqlite3_array (GdaSqliteProvider *prov, int argc, sqlite3_value **argv); + + +/* + * GdaVproviderDataModel class implementation + */ +GdaServerProviderBase data_model_base_functions = { + gda_vprovider_data_model_get_name, + NULL, + NULL, + NULL, + NULL, + gda_vprovider_data_model_create_connection, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + gda_vprovider_data_model_open_connection, + gda_vprovider_data_model_prepare_connection, + gda_vprovider_data_model_close_connection, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + gda_vprovider_data_model_statement_execute, + + NULL, NULL, NULL, NULL, /* padding */ +}; + +static void +gda_vprovider_data_model_class_init (GdaVproviderDataModelClass *klass) +{ + /* set virtual functions */ + gda_server_provider_set_impl_functions (GDA_SERVER_PROVIDER_CLASS (klass), + GDA_SERVER_PROVIDER_FUNCTIONS_BASE, + (gpointer) &data_model_base_functions); +} + + +static void +gda_vprovider_data_model_init (GdaVproviderDataModel *prov) +{ +} + +/** + * gda_vprovider_data_model_new + * + * Creates a new GdaVirtualProvider object which allows one to + * add and remove GdaDataModel objects as tables within a connection + * + * Returns: a new #GdaVirtualProvider object. + */ +GdaVirtualProvider * +gda_vprovider_data_model_new (void) +{ + GdaVirtualProvider *provider; + + provider = g_object_new (gda_vprovider_data_model_get_type (), NULL); + return provider; +} + +/* + * Note about RowIDs and how SQLite uses them: + * + * SQLite considers that each virtual table has unique row IDs, absolute value available all the time. + * When an UPDATE or DELETE statement is executed, SQLite does the following: + * - xBegin (table): request a transaction start + * - xOpen (table): create a new cursor + * - xFilter (cursor): initialize the cursor + * - moves the cursor one step at a time up to the end (xEof, xColumn and xNext). If it finds a + * row needing to be updated or deleted, it calls xRowid (cursor) to get the RowID + * - xClose (cursor): free the now useless cursor + * - calls xUpdate (table) as many times as needed (one time for each row where xRowid was called) + * - xSync (table) + * - xCommit (table) + * + * This does not work well with Libgda because RowID are not pre-defined. To circumvent this problem, + * for each data model, the RowID as returned for each cursor is the row number in the data model, plus + * an offset defined uniquely for each table: + * RowID (guint 64) = ID (guint32) << 32 + row (guint 31) + */ + +#ifdef GDA_DEBUG_VIRTUAL +#define TRACE(table,cursor) g_print ("== %s (table=>%p cursor=>%p)\n", __FUNCTION__, (table), (cursor)) +#else +#define TRACE(table,cursor) +#endif + +typedef struct VirtualTable VirtualTable; +typedef struct VirtualCursor VirtualCursor; + +struct VirtualTable { + sqlite3_vtab base; + GdaVconnectionDataModel *cnc; + GdaVConnectionTableData *td; + gboolean locked; + + guint32 rows_offset; +}; + +#define MAX_VDATA_NUMBER 30 + +struct VirtualCursor { + sqlite3_vtab_cursor base; /* base.pVtab is a pointer to the sqlite3_vtab virtual table */ + VirtualFilteredData *data; /* a ref is held here */ + gint row; /* starts at 0 */ + GWeakRef provider; +}; + + + +static VirtualFilteredData * +virtual_filtered_data_new (VirtualTable *vtable, GdaDataModel *model, + int idxNum, const char *idxStr, int argc, sqlite3_value **argv) +{ + VirtualFilteredData *data; + GdaSqliteProvider *prov = GDA_SQLITE_PROVIDER (gda_connection_get_provider (GDA_CONNECTION (vtable->cnc))); + + g_assert (model); + data = g_new0 (VirtualFilteredData, 1); + data->refcount = 1; + data->reuseable = TRUE; + data->idxNum = idxNum; + data->idxStr = idxStr ? g_strdup (idxStr) : NULL; + data->argc = argc; + data->argv = create_gvalues_array_from_sqlite3_array (prov, argc, argv); + data->model = g_object_ref (model); + if (GDA_IS_DATA_PROXY (model)) + data->iter = g_object_new (GDA_TYPE_DATA_MODEL_ITER, + "data-model", model, NULL); + else + data->iter = gda_data_model_create_iter (model); + g_object_set (data->iter, "validate-changes", FALSE, NULL); + + gint n; + n = gda_data_model_get_n_columns (model); + n = (n >= 0) ? n : 1; + data->values_array = g_ptr_array_new_full (1, (GDestroyNotify) gda_value_free); + data->ncols = gda_data_model_get_n_columns (model); + data->nrows = -1; + data->rowid_offset = vtable->rows_offset; + vtable->rows_offset ++; + +#ifdef DEBUG_VCONTEXT + g_print ("New VData %p for table [%s] idxNum=%d, idxStr=[%s], argc=%d\n", data, vtable->td->table_name, + idxNum, idxStr, argc); + for (n= 0; n < data->argc; n++) + g_print (" [%s]\n", gda_value_stringify (data->argv [n])); +#endif + return data; +} + +static void +virtual_filtered_data_free (VirtualFilteredData *data) +{ + g_return_if_fail (data != NULL); + if (data->argv) { + int i; + for (i = 0; i < data->argc; i++) + gda_value_free (data->argv [i]); + g_free (data->argv); + } + g_free (data->idxStr); + g_object_unref (data->model); + if (data->iter) + g_object_unref (data->iter); + + if (data->values_array) { + g_ptr_array_free (data->values_array, TRUE); + } + g_free (data); + +#ifdef DEBUG_VCONTEXT + g_print ("Freed VData %p\n", data); +#endif +} + +static VirtualFilteredData * +virtual_filtered_data_ref (VirtualFilteredData *data) +{ + g_return_val_if_fail (data != NULL, NULL); + data->refcount ++; + return data; +} + +void +_gda_vconnection_virtual_filtered_data_unref (VirtualFilteredData *data) +{ + g_return_if_fail (data != NULL); + data->refcount --; + if (data->refcount == 0) + virtual_filtered_data_free (data); +} + +static void +virtual_cursor_free (VirtualCursor *cursor) +{ + if (!cursor) + return; + + _gda_vconnection_virtual_filtered_data_unref (cursor->data); + cursor->data = NULL; + g_free (cursor); +} + +/* module creation */ +static int virtualCreate (sqlite3 *db, void *pAux, int argc, const char *const *argv, sqlite3_vtab **ppVtab, char **pzErr); +static int virtualConnect (sqlite3 *db, void *pAux, int argc, const char *const *argv, sqlite3_vtab **ppVtab, char **pzErr); +static int virtualDisconnect (sqlite3_vtab *pVtab); +static int virtualDestroy (sqlite3_vtab *pVtab); +static int virtualOpen (sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor); +static int virtualClose (sqlite3_vtab_cursor *cur); +static int virtualEof (sqlite3_vtab_cursor *cur); +static int virtualNext (sqlite3_vtab_cursor *cur); +static int virtualColumn (sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i); +static int virtualRowid (sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid); +static int virtualFilter (sqlite3_vtab_cursor *pVtabCursor, int idxNum, const char *idxStr, int argc, sqlite3_value **argv); +static int virtualBestIndex (sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo); +static int virtualUpdate (sqlite3_vtab *tab, int nData, sqlite3_value **apData, sqlite_int64 *pRowid); +static int virtualBegin (sqlite3_vtab *tab); +static int virtualSync (sqlite3_vtab *tab); +static int virtualCommit (sqlite3_vtab *tab); +static int virtualRollback (sqlite3_vtab *tab); +static int virtualRename (sqlite3_vtab *pVtab, const char *zNew); + +static sqlite3_module Module = { + 1, /* iVersion */ + virtualCreate, + virtualConnect, + virtualBestIndex, + virtualDisconnect, + virtualDestroy, + virtualOpen, /* xOpen - open a cursor */ + virtualClose, /* xClose - close a cursor */ + virtualFilter, /* xFilter - configure scan constraints */ + virtualNext, /* xNext - advance a cursor */ + virtualEof, /* xEof */ + virtualColumn, /* xColumn - read data */ + virtualRowid, /* xRowid - read data */ + virtualUpdate, /* xUpdate - write data */ + virtualBegin, /* xBegin - begin transaction */ + virtualSync, /* xSync - sync transaction */ + virtualCommit, /* xCommit - commit transaction */ + virtualRollback, /* xRollback - rollback transaction */ + NULL, /* xFindFunction - function overloading */ + virtualRename, /* Rename - Notification that the table will be given a new name */ +#if SQLITE_VERSION_NUMBER >= 3007007 + NULL, /* xSavepoint */ + NULL, /* xRelease */ + NULL /* xRollbackTo */ +#endif +}; + +static GdaConnection * +gda_vprovider_data_model_create_connection (GdaServerProvider *provider) +{ + GdaConnection *cnc; + g_return_val_if_fail (GDA_IS_VPROVIDER_DATA_MODEL (provider), NULL); + + cnc = g_object_new (GDA_TYPE_VCONNECTION_DATA_MODEL, "provider", provider, NULL); + + return cnc; +} + +static gboolean +gda_vprovider_data_model_open_connection (GdaServerProvider *provider, GdaConnection *cnc, + GdaQuarkList *params, GdaQuarkList *auth) +{ + GdaQuarkList *m_params; + + g_return_val_if_fail (GDA_IS_VPROVIDER_DATA_MODEL (provider), FALSE); + g_return_val_if_fail (GDA_IS_VCONNECTION_DATA_MODEL (cnc), FALSE); + + if (params) { + m_params = gda_quark_list_copy (params); + gda_quark_list_add_from_string (m_params, "_IS_VIRTUAL=TRUE;EXTRA_FUNCTIONS=TRUE", TRUE); + } + else + m_params = gda_quark_list_new_from_string ("_IS_VIRTUAL=TRUE;EXTRA_FUNCTIONS=TRUE"); + + GdaServerProviderBase *parent_functions; + parent_functions = gda_server_provider_get_impl_functions_for_class (gda_vprovider_data_model_parent_class, GDA_SERVER_PROVIDER_FUNCTIONS_BASE); + //g_print ("Open connection for Provider Name %\n", parent_functions->get_name(provider)); + if (parent_functions->open_connection) { + if (! parent_functions->open_connection (GDA_SERVER_PROVIDER (provider), cnc, m_params, auth)) { + gda_quark_list_free (m_params); + return FALSE; + } + + } + + gda_quark_list_free (m_params); + + SqliteConnectionData *scnc; + scnc = (SqliteConnectionData*) gda_connection_internal_get_provider_data_error ((GdaConnection *) cnc, NULL); + if (!scnc) { + gda_connection_close (cnc, NULL); + gda_connection_add_event_string (cnc, _("Connection is closed")); + return FALSE; + } + GdaSqliteProvider *prov = GDA_SQLITE_PROVIDER (provider); + /* Module to declare wirtual tables */ + if (SQLITE3_CALL (prov, sqlite3_create_module) (scnc->connection, G_OBJECT_TYPE_NAME (provider), &Module, cnc) != SQLITE_OK) + return FALSE; + /*g_print ("==== Declared module for DB %p\n", scnc->connection);*/ + + return TRUE; +} + +static gboolean +gda_vprovider_data_model_prepare_connection (GdaServerProvider *provider, GdaConnection *cnc, + GdaQuarkList *params, GdaQuarkList *auth) +{ + g_return_val_if_fail (GDA_IS_VPROVIDER_DATA_MODEL (provider), FALSE); + g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE); + + /* calling the parent's function first */ + GdaServerProviderBase *parent_functions; + parent_functions = gda_server_provider_get_impl_functions_for_class (gda_vprovider_data_model_parent_class, GDA_SERVER_PROVIDER_FUNCTIONS_BASE); + //g_print ("Provider Class: %s\n", parent_functions->get_name (GDA_SERVER_PROVIDER (provider))); + if (parent_functions->prepare_connection) { + if (! parent_functions->prepare_connection (GDA_SERVER_PROVIDER (provider), cnc, params, auth)) + return FALSE; + } + + return TRUE; +} + + +static void +cnc_close_foreach_func (G_GNUC_UNUSED GdaDataModel *model, const gchar *table_name, GdaVconnectionDataModel *cnc) +{ + /*g_print ("---- FOREACH: Removing virtual table '%s'\n", table_name);*/ + GError *lerror = NULL; + if (! gda_vconnection_data_model_remove (cnc, table_name, &lerror)) { + g_warning ("Internal GdaVproviderDataModel error: %s", + lerror && lerror->message ? lerror->message : _("No detail")); + g_clear_error (&lerror); + } +} + +static gboolean +gda_vprovider_data_model_close_connection (GdaServerProvider *provider, GdaConnection *cnc) +{ + g_return_val_if_fail (GDA_IS_VPROVIDER_DATA_MODEL (provider), FALSE); + g_return_val_if_fail (GDA_IS_VCONNECTION_DATA_MODEL (cnc), FALSE); + + gda_vconnection_data_model_foreach (GDA_VCONNECTION_DATA_MODEL (cnc), + (GdaVconnectionDataModelFunc) cnc_close_foreach_func, cnc); + + GdaServerProviderBase *parent_functions; + parent_functions = gda_server_provider_get_impl_functions_for_class (gda_vprovider_data_model_parent_class, GDA_SERVER_PROVIDER_FUNCTIONS_BASE); + if (parent_functions->close_connection) + return parent_functions->close_connection (provider, cnc); + else { + g_warning (_("Internal Implementation error: No close connection method is defined")); + return FALSE; + } +} + +static GObject * +gda_vprovider_data_model_statement_execute (GdaServerProvider *provider, GdaConnection *cnc, + GdaStatement *stmt, GdaSet *params, + GdaStatementModelUsage model_usage, + GType *col_types, GdaSet **last_inserted_row,GError **error) +{ + GObject *retval = NULL; + _gda_vconnection_set_working_obj ((GdaVconnectionDataModel*) cnc, (GObject*) stmt); + + GdaServerProviderBase *parent_functions; + parent_functions = gda_server_provider_get_impl_functions_for_class (gda_vprovider_data_model_parent_class, GDA_SERVER_PROVIDER_FUNCTIONS_BASE); + retval = parent_functions->statement_execute (provider, cnc, stmt, params, + model_usage, col_types, + last_inserted_row, error); + + if (retval) { + if (! GDA_IS_DATA_MODEL (retval)) + _gda_vconnection_set_working_obj ((GdaVconnectionDataModel*) cnc, NULL); + + gchar *sql; + sql = gda_statement_to_sql (stmt, params, NULL); + if (sql) { + gchar *ptr = NULL; + /* look for DROP TABLE to signal table removal */ + if (! g_ascii_strncasecmp (sql, "DROP", 4)) + ptr = sql + 4; + else if (! g_ascii_strncasecmp (sql, "CREATE", 6)) + ptr = sql + 6; + if (ptr) { + /* skip spaces */ + for (; *ptr && (g_ascii_isspace (*ptr) || (*ptr == '\n')); ptr++); + + if (! g_ascii_strncasecmp (ptr, "TABLE", 5)) { + /* skip spaces */ + gchar delim = 0; + gchar *table_name, *quoted; + for (ptr = ptr+5; + *ptr && (g_ascii_isspace (*ptr) || (*ptr == '\n')); + ptr++); + if (*ptr == '\'') { + delim = '\''; + ptr++; + } + else if (*ptr == '"') { + delim = '"'; + ptr++; + } + table_name = ptr; + if (delim) + for (; *ptr && (*ptr != delim) ; ptr++); + else + for (; *ptr && g_ascii_isalnum (*ptr); ptr++); + *ptr = 0; + quoted = _gda_connection_compute_table_virtual_name (GDA_CONNECTION (cnc), table_name); + /*g_print ("%s() emits the 'vtable-dropped' signal for table [%s]\n", + __FUNCTION__, quoted);*/ + g_signal_emit_by_name (cnc, "vtable-dropped", quoted); + g_free (quoted); + } + } + g_free (sql); + } + } + else + _gda_vconnection_set_working_obj ((GdaVconnectionDataModel*) cnc, NULL); + return retval; +} + +static const gchar * +gda_vprovider_data_model_get_name (G_GNUC_UNUSED GdaServerProvider *provider) +{ + GdaServerProviderBase *parent_functions; + parent_functions = gda_server_provider_get_impl_functions_for_class (gda_vprovider_data_model_parent_class, GDA_SERVER_PROVIDER_FUNCTIONS_BASE); + if (parent_functions->get_name) + return parent_functions->get_name (provider); + else + return "Virtual data model"; +} + +static int +virtualCreate (sqlite3 *db, void *pAux, int argc, const char *const *argv, sqlite3_vtab **ppVtab, char **pzErr) +{ + GdaVconnectionDataModel *cnc = GDA_VCONNECTION_DATA_MODEL (pAux); + GString *sql; + gint i, ncols; + gchar *spec_name, *tmp; + GdaVConnectionTableData *td; + GHashTable *hash; + GdaSqliteProvider *prov = GDA_SQLITE_PROVIDER (gda_connection_get_provider (GDA_CONNECTION (cnc))); + + TRACE (NULL, NULL); + + /* find Spec */ + g_assert (argc == 4); + spec_name = g_strdup (argv[3]); + i = strlen (spec_name); + if (spec_name [i-1] == '\'') + spec_name [i-1] = 0; + if (*spec_name == '\'') + memmove (spec_name, spec_name+1, i); + + td = _gda_vconnection_get_table_data_by_unique_name (cnc, spec_name); + g_free (spec_name); + if (!td) { + /* wrong usage! */ + *pzErr = SQLITE3_CALL (prov, sqlite3_mprintf) (_("Wrong usage of Libgda's virtual tables")); + return SQLITE_ERROR; + } + + /* preparations */ + if (td->spec->data_model) { + ncols = gda_data_model_get_n_columns (td->spec->data_model); + if (ncols <= 0) { + *pzErr = SQLITE3_CALL (prov, sqlite3_mprintf) (_("Data model must have at least one column")); + return SQLITE_ERROR; + } + td->real_model = td->spec->data_model; + g_object_ref (td->real_model); + } + + GError *error = NULL; + if (!td->columns && td->spec->create_columns_func) + td->columns = td->spec->create_columns_func (td->spec, &error); + if (!td->columns) { + if (error && error->message) { + int len = strlen (error->message) + 1; + *pzErr = SQLITE3_CALL (prov, sqlite3_malloc) (sizeof (gchar) * len); + memcpy (*pzErr, error->message, len); /* Flawfinder: ignore */ + } + else + *pzErr = SQLITE3_CALL (prov, sqlite3_mprintf) (_("Could not compute virtual table's columns")); + return SQLITE_ERROR; + } + ncols = g_list_length (td->columns); + td->n_columns = ncols; + + /* create the CREATE TABLE statement */ + sql = g_string_new ("CREATE TABLE "); + tmp = gda_connection_quote_sql_identifier (GDA_CONNECTION (cnc), argv[2]); + g_string_append (sql, tmp); + g_free (tmp); + g_string_append (sql, " ("); + hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); + for (i = 0; i < ncols; i++) { + GdaColumn *column; + const gchar *name, *type; + GType gtype; + gchar *newcolname, *tmp; + + if (i != 0) + g_string_append (sql, ", "); + column = g_list_nth_data (td->columns, i); + if (!column) { + *pzErr = SQLITE3_CALL (prov, sqlite3_mprintf) (_("Can't get data model description for column %d"), i); + g_string_free (sql, TRUE); + return SQLITE_ERROR; + } + + name = gda_column_get_name (column); + if (!name || !(*name)) + newcolname = g_strdup_printf ("_%d", i + 1); + else { + GString *string; + gchar *ptr; + string = g_string_new (""); + newcolname = gda_sql_identifier_quote (name, GDA_CONNECTION (cnc), NULL, FALSE, FALSE); + for (ptr = newcolname; *ptr; ptr++) { + if ((*ptr == '_') || + ((*ptr >= 'a') && (*ptr <= 'z')) || + ((*ptr >= 'A') && (*ptr <= 'Z'))) + g_string_append_c (string, *ptr); + else if ((*ptr >= '0') && (*ptr <= '9')) { + if (ptr == name) + g_string_append_c (string, '_'); + else + g_string_append_c (string, *ptr); + } + else + g_string_append_c (string, '_'); + } + g_free (newcolname); + newcolname = g_string_free (string, FALSE); + } + + tmp = g_ascii_strdown (newcolname, -1); + if (g_hash_table_lookup (hash, tmp)) { + gint i; + g_free (tmp); + for (i = 0; ; i++) { + gchar *nc2; + nc2 = g_strdup_printf ("%s%d", newcolname, i); + tmp = g_ascii_strdown (nc2, -1); + if (! g_hash_table_lookup (hash, tmp)) { + g_free (newcolname); + newcolname = nc2; + break; + } + g_free (tmp); + g_free (nc2); + } + } + + gtype = gda_column_get_g_type (column); + type = g_type_name (gtype); + if (!type) { + *pzErr = SQLITE3_CALL (prov, sqlite3_mprintf) (_("Can't get data model's column type for column %d"), i); + g_string_free (sql, TRUE); + return SQLITE_ERROR; + } + else if (gtype == GDA_TYPE_BLOB) + type = "blob"; + else if (gtype == GDA_TYPE_BINARY) + type = "binary"; + else if (gtype == G_TYPE_STRING) + type = "string"; + else if (gtype == G_TYPE_INT) + type = "integer"; + else if (gtype == G_TYPE_UINT) + type = "unsigned integer"; + else if ((gtype == G_TYPE_INT64) || (gtype == G_TYPE_LONG)) + type = "int64"; + else if ((gtype == G_TYPE_UINT64) || (gtype == G_TYPE_ULONG)) + type = "uint64"; + else if ((gtype == G_TYPE_DOUBLE) || (gtype == G_TYPE_FLOAT)) + type = "real"; + else if (gtype == G_TYPE_DATE) + type = "date"; + else if (gtype == GDA_TYPE_TIME) + type = "time"; + else if (gtype == G_TYPE_DATE_TIME) + type = "timestamp"; + else if (gtype == GDA_TYPE_SHORT) + type = "short"; + else if (gtype == GDA_TYPE_USHORT) + type = "unsigned short"; + else + type = "text"; + + g_string_append (sql, newcolname); + g_hash_table_insert (hash, tmp, (gpointer) 0x01); + g_free (newcolname); + g_string_append_c (sql, ' '); + g_string_append (sql, type); + if (! gda_column_get_allow_null (column)) + g_string_append (sql, " NOT NULL"); + if (gtype == G_TYPE_STRING) + g_string_append (sql, " COLLATE LOCALE"); + } + g_hash_table_destroy (hash); + + /* add a hidden column which contains the row number of the data model */ + if (ncols != 0) + g_string_append (sql, ", "); + g_string_append (sql, "__gda_row_nb hidden integer"); + + g_string_append_c (sql, ')'); + + /* VirtualTable structure */ + VirtualTable *vtable; + vtable = g_new0 (VirtualTable, 1); + vtable->cnc = cnc; + vtable->td = td; + vtable->rows_offset = 0; + *ppVtab = &(vtable->base); + + if (SQLITE3_CALL (prov, sqlite3_declare_vtab) (db, sql->str) != SQLITE_OK) { + sqlite3_mutex_enter (sqlite3_db_mutex (db)); + *pzErr = SQLITE3_CALL (prov, sqlite3_mprintf) (_("Can't declare virtual table (\"%s\"): %s"), sql->str, + sqlite3_errmsg (db)); + sqlite3_mutex_leave (sqlite3_db_mutex (db)); + + g_string_free (sql, TRUE); + g_free (vtable); + *ppVtab = NULL; + return SQLITE_ERROR; + } + + /*g_print ("VIRTUAL TABLE [%p]: %s\n", vtable, sql->str);*/ + g_string_free (sql, TRUE); + + return SQLITE_OK; +} + +static int +virtualConnect (sqlite3 *db, void *pAux, int argc, const char *const *argv, sqlite3_vtab **ppVtab, char **pzErr) +{ + TRACE (NULL, NULL); + + return virtualCreate (db, pAux, argc, argv, ppVtab, pzErr); +} + +static int +virtualDisconnect (sqlite3_vtab *pVtab) +{ + /*VirtualTable *vtable = (VirtualTable *) pVtab;*/ + + TRACE (pVtab, NULL); + g_free (pVtab); + + return SQLITE_OK; +} + +static int +virtualDestroy (sqlite3_vtab *pVtab) +{ + TRACE (pVtab, NULL); + + return virtualDisconnect (pVtab); +} + +static int +virtualOpen (G_GNUC_UNUSED sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor) +{ + VirtualCursor *cursor; + + /* create empty cursor */ + cursor = g_new0 (VirtualCursor, 1); + *ppCursor = (sqlite3_vtab_cursor*) cursor; + TRACE (pVTab, cursor); + + return SQLITE_OK; +} + +static int +virtualClose (sqlite3_vtab_cursor *cur) +{ + VirtualCursor *cursor = (VirtualCursor*) cur; + /*VirtualTable *vtable = (VirtualTable*) cur->pVtab;*/ + + TRACE (cur->pVtab, cur); + + virtual_cursor_free (cursor); + + return SQLITE_OK; +} + +static int +virtualEof (sqlite3_vtab_cursor *cur) +{ + VirtualCursor *cursor = (VirtualCursor*) cur; + + TRACE (cur->pVtab, cur); + + if (cursor->data->iter) + return FALSE; + else { + if (cursor->row >= cursor->data->nrows) + return TRUE; + else + return FALSE; + } +} + +/* + * handle data model exceptions and return appropriate code + */ +static int +handle_data_model_exception (sqlite3_vtab *pVtab, GdaDataModel *model) +{ + GError **exceptions; + gint i; + VirtualTable *vtab = (VirtualTable*) pVtab; + GdaSqliteProvider *prov = GDA_SQLITE_PROVIDER (gda_connection_get_provider (GDA_CONNECTION (vtab->cnc))); + exceptions = gda_data_model_get_exceptions (model); + if (!exceptions) + return SQLITE_OK; + + GError *trunc_error = NULL; + GError *fatal_error = NULL; + for (i = 0; exceptions [i]; i++) { + GError *e; + e = exceptions [i]; + if ((e->domain == GDA_DATA_MODEL_ERROR) && + (e->code == GDA_DATA_MODEL_TRUNCATED_ERROR)) + trunc_error = e; + else { + fatal_error = e; + break; + } + } + if (fatal_error || trunc_error) { + GError *e; + e = fatal_error; + if (!e) + e = trunc_error; + if (pVtab->zErrMsg) + SQLITE3_CALL (prov, sqlite3_free) (pVtab->zErrMsg); + pVtab->zErrMsg = SQLITE3_CALL (prov, sqlite3_mprintf) + ("%s", e->message ? e->message : _("No detail")); + if (fatal_error) + return SQLITE_ERROR; + else + return SQLITE_IOERR_TRUNCATE; + } + return SQLITE_OK; +} + +static int +virtualNext (sqlite3_vtab_cursor *cur) +{ + VirtualCursor *cursor = (VirtualCursor*) cur; + VirtualFilteredData *data; + VirtualTable *vtab = (VirtualTable*) cur->pVtab; + GdaSqliteProvider *prov = GDA_SQLITE_PROVIDER (gda_connection_get_provider (GDA_CONNECTION (vtab->cnc))); + + TRACE (cur->pVtab, cur); + + data = cursor->data; + if (!data) { + cur->pVtab->zErrMsg = SQLITE3_CALL (prov, sqlite3_mprintf) + (_("Internal SQLite error: no data to iterate on")); + return SQLITE_MISUSE; + } + + cursor->row ++; + if (data->iter && (gda_data_model_iter_get_row (data->iter) < cursor->row)) { + /* move to next row */ + if (gda_data_model_iter_move_next (data->iter)) { + int exc_res; + exc_res = handle_data_model_exception (cur->pVtab, data->model); + if (exc_res != SQLITE_OK) + goto onerror; + + /* load data for row */ + GSList *list; + gint count; + for (count = 0, list = gda_set_get_holders ((GdaSet*) data->iter); list; + count++, list = list->next) { + GdaHolder *h = (GdaHolder*) list->data; + GError *lerror = NULL; + if (! gda_holder_is_valid_e (h, &lerror)) { + GValue *value = gda_value_new (G_TYPE_ERROR); + g_value_take_boxed (value, lerror); + g_ptr_array_insert (data->values_array, -1, value); + } + else { + const GValue *cvalue; + cvalue = gda_holder_get_value (h); + if (cvalue && (G_VALUE_TYPE (cvalue) != 0)) { + GValue *copy = gda_value_new (G_VALUE_TYPE (cvalue)); + g_value_copy (cvalue, copy); + g_ptr_array_insert (data->values_array, -1, copy); + } + else { + GValue *value = gda_value_new (G_TYPE_ERROR); + g_value_take_boxed (value, lerror); + g_ptr_array_insert (data->values_array, -1, value); + } + } + } + g_assert (count == data->ncols); + } + else { + int exc_res; + exc_res = handle_data_model_exception (cur->pVtab, data->model); + if (exc_res != SQLITE_OK) + goto onerror; + else { + /* end of data */ + g_object_unref (data->iter); + data->iter = NULL; + data->nrows = cursor->row; + } + } + } + return SQLITE_OK; + + onerror: + cursor->row--; + g_object_unref (data->iter); + data->iter = NULL; + data->nrows = cursor->row; + return SQLITE_ERROR; +} + +/* + * @cursor may be %NULL + */ +static const GValue * +get_data_value (VirtualTable *vtable, VirtualCursor *cursor, gint row, gint64 rowid, gint col, GError **error) +{ + VirtualFilteredData *data = NULL; + const GValue *value = NULL; + + if ((col < 0) || (col >= vtable->td->n_columns)) { + g_set_error (error, GDA_VPROVIDER_DATA_MODEL_ERROR, GDA_VPROVIDER_DATA_MODEL_GENERAL_ERROR, _("Column %d out of range (0-%d)"), col, vtable->td->n_columns - 1); + return NULL; + } + if (cursor) { + data = cursor->data; + g_assert (data); + } + else { + g_assert (row < 0); + row = (gint) (rowid & 0xFFFFFFFF); + + g_assert (vtable->td->context.current_vcontext); + guint i; + GPtrArray *values_array = vtable->td->context.current_vcontext->context_data; + if (values_array != NULL) { + for (i = 0; i < values_array->len; i++) { + VirtualFilteredData *vd; + vd = g_ptr_array_index (values_array, i); + if (vd->rowid_offset == (guint32) (rowid >> 32)) { + data = vd; + break; + } + } + } + } + + if (data) + value = g_ptr_array_index (data->values_array, row * data->ncols + col); + + if (!value) + g_set_error (error, GDA_VPROVIDER_DATA_MODEL_ERROR, GDA_VPROVIDER_DATA_MODEL_GENERAL_ERROR, + _("Could not find requested value at row %d and col %d"), + row, col); +#ifdef DEBUG_VCONTEXT + g_print ("Read from [%s] [%s] %d x %d x %lld\n", vtable->td->table_name, gda_value_stringify (value), col, row, rowid); +#endif + return value; +} + +static int +virtualColumn (sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i) +{ + VirtualCursor *cursor = (VirtualCursor*) cur; + VirtualTable *vtab = (VirtualTable*) cur->pVtab; + GdaSqliteProvider *prov = GDA_SQLITE_PROVIDER (gda_connection_get_provider (GDA_CONNECTION (vtab->cnc))); + + TRACE (cur->pVtab, cur); + + if (i == ((VirtualTable*) cur->pVtab)->td->n_columns) { + /* private hidden column, which returns the row number */ + SQLITE3_CALL (prov, sqlite3_result_int) (ctx, cursor->row); + return SQLITE_OK; + } + + if (i >= cursor->data->ncols) { + SQLITE3_CALL (prov, sqlite3_result_text) (ctx, _("Column not found"), -1, SQLITE_TRANSIENT); + return SQLITE_MISUSE; + } + + const GValue *value; + GError *lerror = NULL; + value = get_data_value ((VirtualTable*) cur->pVtab, cursor, cursor->row, 0, i, &lerror); + if (! value) { + g_hash_table_insert (error_blobs_hash, lerror, GINT_TO_POINTER (1)); + SQLITE3_CALL (prov, sqlite3_result_blob) (ctx, lerror, sizeof (GError), NULL); + } + else if (G_VALUE_TYPE (value) == G_TYPE_ERROR) { + GError *lerror; + lerror = g_value_get_boxed (value); + /* Can't call: + * SQLITE3_CALL (sqlite3_result_error) (ctx, lerror && lerror->message ? lerror->message : _("No detail"), -1); + * because then the whole processing stops and no further rows are read */ + if (lerror) + lerror = g_error_copy (lerror); + else + g_set_error (&lerror, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_DATA_ERROR, + _("No detail")); + g_hash_table_insert (error_blobs_hash, lerror, GINT_TO_POINTER (1)); + SQLITE3_CALL (prov, sqlite3_result_blob) (ctx, lerror, sizeof (GError), NULL); + } + else if (!value || gda_value_is_null (value)) + SQLITE3_CALL (prov, sqlite3_result_null) (ctx); + else if (G_VALUE_TYPE (value) == G_TYPE_INT) + SQLITE3_CALL (prov, sqlite3_result_int) (ctx, g_value_get_int (value)); + else if (G_VALUE_TYPE (value) == G_TYPE_INT64) + SQLITE3_CALL (prov, sqlite3_result_int64) (ctx, g_value_get_int64 (value)); + else if (G_VALUE_TYPE (value) == G_TYPE_DOUBLE) + SQLITE3_CALL (prov, sqlite3_result_double) (ctx, g_value_get_double (value)); + else if (G_VALUE_TYPE (value) == GDA_TYPE_BLOB) { + GdaBlob *blob; + GdaBinary *bin; + blob = (GdaBlob *) gda_value_get_blob (value); + bin = (GdaBinary *) blob; + if (gda_blob_get_op (blob) && + (gda_binary_get_size (bin) != gda_blob_op_get_length (gda_blob_get_op(blob)))) + gda_blob_op_read_all (gda_blob_get_op (blob), blob); + SQLITE3_CALL (prov, sqlite3_result_blob) (ctx, gda_binary_get_data (gda_blob_get_binary (blob)), + gda_binary_get_size (gda_blob_get_binary (blob)), + SQLITE_TRANSIENT); + } + else if (G_VALUE_TYPE (value) == GDA_TYPE_BINARY) { + GdaBinary *bin; + bin = gda_value_get_binary (value); + SQLITE3_CALL (prov, sqlite3_result_blob) (ctx, gda_binary_get_data (bin), gda_binary_get_size (bin), SQLITE_TRANSIENT); + } + else { + gchar *str = gda_value_stringify (value); + SQLITE3_CALL (prov, sqlite3_result_text) (ctx, str, -1, SQLITE_TRANSIENT); + g_free (str); + } + + return SQLITE_OK; +} + +static int +virtualRowid (sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid) +{ + VirtualCursor *cursor = (VirtualCursor*) cur; + + TRACE ((VirtualTable*) cur->pVtab, cur); + + *pRowid = ((sqlite_int64) cursor->row) + (((sqlite_int64) cursor->data->rowid_offset) << 32); + return SQLITE_OK; +} + +/* NEVER returns %NULL */ +static GValue * +create_value_from_sqlite3_value_notype (GdaSqliteProvider *prov, sqlite3_value *svalue) +{ + GValue *value; + value = g_new0 (GValue, 1); + + switch (SQLITE3_CALL (prov, sqlite3_value_type) (svalue)) { + case SQLITE_INTEGER: + g_value_init (value, G_TYPE_INT64); + g_value_set_int64 (value, SQLITE3_CALL (prov, sqlite3_value_int64) (svalue)); + break; + case SQLITE_FLOAT: + g_value_init (value, G_TYPE_DOUBLE); + g_value_set_double (value, SQLITE3_CALL (prov, sqlite3_value_double) (svalue)); + break; + case SQLITE_BLOB: { + GdaBinary *bin; + g_value_init (value, GDA_TYPE_BINARY); + bin = gda_binary_new (); + glong length = SQLITE3_CALL (prov, sqlite3_value_bytes) (svalue); + if (length > 0) { + //gpointer data = g_new (guchar, length); + gda_binary_set_data (bin, SQLITE3_CALL (prov, sqlite3_value_blob) (svalue), length); + } + gda_value_take_binary (value, bin); + break; + } + case SQLITE_NULL: + gda_value_set_null (value); + break; + case SQLITE3_TEXT: + default: + g_value_init (value, G_TYPE_STRING); + g_value_set_string (value, (gchar *) SQLITE3_CALL (prov, sqlite3_value_text) (svalue)); + break; + } + return value; +} + +/* + * Returns: a new array of @argc values, and %NULL if @argc = 0 + */ +static GValue ** +create_gvalues_array_from_sqlite3_array (GdaSqliteProvider *prov, int argc, sqlite3_value **argv) +{ + GValue **array; + gint i; + if (argc == 0) + return NULL; + array = g_new (GValue *, argc); + for (i = 0; i < argc; i++) + array[i] = create_value_from_sqlite3_value_notype (prov, argv[i]); + return array; +} + +static void +virtual_table_manage_real_data_model (VirtualTable *vtable, int idxNum, const char *idxStr, + int argc, sqlite3_value **argv) +{ + GdaSqliteProvider *prov = GDA_SQLITE_PROVIDER (gda_connection_get_provider (GDA_CONNECTION (vtable->cnc))); + /*g_print ("================== %s (VTable=> %p, %s)\n", __FUNCTION__, + vtable, vtable->td->table_name);*/ + if (!vtable->td->spec->create_filtered_model_func && !vtable->td->spec->create_model_func) + return; + + if (vtable->td->real_model) { + g_object_unref (vtable->td->real_model); + vtable->td->real_model = NULL; + } + + /* actual data model creation */ + if (vtable->td->spec->create_filtered_model_func) { + GValue **gargv; + gargv = create_gvalues_array_from_sqlite3_array (prov, argc, argv); + vtable->td->real_model = vtable->td->spec->create_filtered_model_func (vtable->td->spec, + idxNum, idxStr, + argc, gargv); + if (gargv) { + gint i; + for (i = 0; i < argc; i++) + gda_value_free (gargv[i]); + g_free (gargv); + } + } + else if (vtable->td->spec->create_model_func) + vtable->td->real_model = vtable->td->spec->create_model_func (vtable->td->spec); + if (! vtable->td->real_model) + return; + + /* columns if not yet created */ + if (! vtable->td->columns && vtable->td->spec->create_columns_func) + vtable->td->columns = vtable->td->spec->create_columns_func (vtable->td->spec, NULL); + + if (vtable->td->columns) { + /* columns */ + GList *list; + guint i, ncols; + ncols = gda_data_model_get_n_columns (vtable->td->real_model); + g_assert (ncols == g_list_length (vtable->td->columns)); + for (i = 0, list = vtable->td->columns; + i < ncols; + i++, list = list->next) { + GdaColumn *mcol = gda_data_model_describe_column (vtable->td->real_model, i); + GdaColumn *ccol = (GdaColumn*) list->data; + if (gda_column_get_g_type (mcol) == GDA_TYPE_NULL) + gda_column_set_g_type (mcol, gda_column_get_g_type (ccol)); + } + } + +#ifdef GDA_DEBUG_VIRTUAL + g_print ("Created real model %p for table %s\n", vtable->td->real_model, vtable->td->table_name); +#endif +} + +static int +virtualFilter (sqlite3_vtab_cursor *pVtabCursor, int idxNum, const char *idxStr, int argc, sqlite3_value **argv) +{ + VirtualCursor *cursor = (VirtualCursor*) pVtabCursor; + VirtualTable *vtable = (VirtualTable*) pVtabCursor->pVtab; + GdaSqliteProvider *prov = GDA_SQLITE_PROVIDER (gda_connection_get_provider (GDA_CONNECTION (vtable->cnc))); + + TRACE (pVtabCursor->pVtab, pVtabCursor); +#ifdef GDA_DEBUG_VIRTUAL + g_print ("\tidxStr=[%s], idxNum=[%d]\n", idxStr, idxNum); +#endif + + /* find a VirtualFilteredData corresponding to this filter */ + VirtualFilteredData *data = NULL; + g_assert (vtable->td->context.current_vcontext); + GPtrArray *values_array = vtable->td->context.current_vcontext->context_data; + if (values_array != NULL) { + if (values_array->len > 0) { + guint i; + for (i = 0; i < values_array->len; i++) { + VirtualFilteredData *vd; + vd = g_ptr_array_index (values_array, i); + if (vd->reuseable && + (vd->idxNum == idxNum) && + (vd->argc == argc) && + ((!idxStr && !vd->idxStr) || (idxStr && vd->idxStr && !strcmp (idxStr, vd->idxStr)))) { + GValue **avalues; + gint i; + gboolean equal = TRUE; + avalues = create_gvalues_array_from_sqlite3_array (prov, argc, argv); + for (i = 0; i < argc; i++) { + GValue *v1, *v2; + v1 = vd->argv [i]; + v2 = avalues [i]; + + if (! ((!v1 && !v2) || + (v1 && v2 && (G_VALUE_TYPE (v1) == G_VALUE_TYPE (v2)) && + !gda_value_differ (v1, v2)))) { + equal = FALSE; + break; + } + } + for (i = 0; i < argc; i++) { + GValue *v2; + v2 = avalues [i]; + if (v2) + gda_value_free (v2); + } + g_free (avalues); + + if (equal) { + data = vd; + break; + } + } + } + } + } + +#ifdef DEBUG_VCONTEXT + if (data) + g_print ("REUSE VData %p\n", data); +#endif + + if (!data && values_array != NULL) { + virtual_table_manage_real_data_model (vtable, idxNum, idxStr, argc, argv); + if (! vtable->td->real_model) + return SQLITE_ERROR; + data = virtual_filtered_data_new (vtable, vtable->td->real_model, idxNum, idxStr, argc, argv); + g_ptr_array_insert (values_array, -1, data); +#ifdef DEBUG_VCONTEXT + g_print ("VData %p prepended to array %p wt %d\n", data, values_array, + values_array->len); +#endif + if (values_array->len > MAX_VDATA_NUMBER) { + VirtualFilteredData *ldata; + gint index; + index = values_array->len - 1; + ldata = g_ptr_array_index (values_array, index); + _gda_vconnection_virtual_filtered_data_unref (ldata); + g_ptr_array_remove_index (values_array, index); + } + } + + if (cursor->data != data) { + if (cursor->data) + _gda_vconnection_virtual_filtered_data_unref (cursor->data); + cursor->data = virtual_filtered_data_ref (data); + } + + /* initialize cursor */ + cursor->row = -1; + + return virtualNext (pVtabCursor); +} + +#ifdef GDA_DEBUG_VIRTUAL + +static void +index_info_dump (sqlite3_index_info *pIdxInfo, gboolean dump_out) +{ + int nc; + if (dump_out) { + g_print ("Dump of OUT sqlite3_index_info [%p]\n", pIdxInfo); + for (nc = 0; nc < pIdxInfo->nConstraint; nc++) { + struct sqlite3_index_constraint_usage *cons; + cons = &(pIdxInfo->aConstraintUsage[nc]); + g_print ("sqlite3_index_constraint_usage[%d]\n", nc); + g_print (" argvIndex=%d\n", cons->argvIndex); + g_print (" omit=%d\n", cons->omit); + } + g_print ("idxNum=%d\n", pIdxInfo->idxNum); + g_print ("orderByConsumed=%d\n", pIdxInfo->orderByConsumed); + } + else { + g_print ("Dump of IN sqlite3_index_info [%p]\n", pIdxInfo); + for (nc = 0; nc < pIdxInfo->nConstraint; nc++) { + struct sqlite3_index_constraint *cons; + cons = &(pIdxInfo->aConstraint[nc]); + g_print ("sqlite3_index_constraint[%d]\n", nc); + g_print (" iColumn=%d\n", cons->iColumn); + g_print (" op=%d\n", cons->op); + g_print (" usable=%d\n", cons->usable); + g_print (" iTermOffset=%d\n", cons->iTermOffset); + } + + for (nc = 0; nc < pIdxInfo->nOrderBy; nc++) { + struct sqlite3_index_orderby *cons; + cons = &(pIdxInfo->aOrderBy[nc]); + g_print ("sqlite3_index_orderby[%d]\n", nc); + g_print (" iColumn=%d\n", cons->iColumn); + g_print (" desc=%d\n", cons->desc); + } + } +} +#endif + +static void +map_sqlite3_info_to_gda_filter (sqlite3_index_info *info, GdaVconnectionDataModelFilter *filter) +{ + memset (filter, 0, sizeof (GdaVconnectionDataModelFilter)); + if (info->nConstraint > 0) { + gint i, j; + filter->aConstraint = g_new (struct GdaVirtualConstraint, info->nConstraint); + filter->aConstraintUsage = g_new (struct GdaVirtualConstraintUsage, info->nConstraint); + for (i = 0, j = 0; i < info->nConstraint; i++) { + if (! info->aConstraint[i].usable) + continue; + + filter->aConstraint[j].iColumn = info->aConstraint[i].iColumn; + switch (info->aConstraint[i].op) { + case SQLITE_INDEX_CONSTRAINT_EQ: + filter->aConstraint[j].op = GDA_SQL_OPERATOR_TYPE_EQ; + break; + case SQLITE_INDEX_CONSTRAINT_GT: + filter->aConstraint[j].op = GDA_SQL_OPERATOR_TYPE_GT; + break; + case SQLITE_INDEX_CONSTRAINT_LE: + filter->aConstraint[j].op = GDA_SQL_OPERATOR_TYPE_LEQ; + break; + case SQLITE_INDEX_CONSTRAINT_LT: + filter->aConstraint[j].op = GDA_SQL_OPERATOR_TYPE_LT; + break; + case SQLITE_INDEX_CONSTRAINT_GE: + filter->aConstraint[j].op = GDA_SQL_OPERATOR_TYPE_GEQ; + break; + case SQLITE_INDEX_CONSTRAINT_MATCH: + filter->aConstraint[j].op = GDA_SQL_OPERATOR_TYPE_REGEXP; + break; + case SQLITE_INDEX_CONSTRAINT_LIKE: + filter->aConstraint[j].op = GDA_SQL_OPERATOR_TYPE_LIKE; + break; + default: + g_assert_not_reached (); + } + + filter->aConstraintUsage[j].argvIndex = 0; + filter->aConstraintUsage[j].omit = FALSE; + j++; + } + filter->nConstraint = j; + } + filter->nOrderBy = info->nOrderBy; + if (filter->nOrderBy > 0) { + gint i; + filter->aOrderBy = g_new (struct GdaVirtualOrderby, filter->nOrderBy); + for (i = 0; i < info->nOrderBy; i++) { + filter->aOrderBy[i].iColumn = info->aOrderBy[i].iColumn; + filter->aOrderBy[i].desc = info->aOrderBy[i].desc ? TRUE : FALSE; + } + } + filter->idxNum = 0; + filter->idxPointer = NULL; + filter->orderByConsumed = FALSE; + filter->estimatedCost = info->estimatedCost; +} + +/* + * Also frees @filter's dynamically allocated parts + */ +static void +map_consume_gda_filter_to_sqlite3_info (GdaVconnectionDataModelFilter *filter, sqlite3_index_info *info) +{ + g_assert (filter->nConstraint == info->nConstraint); + if (info->nConstraint > 0) { + gint i, j; + for (i = 0, j = 0; i < info->nConstraint; i++) { + if (! info->aConstraint[i].usable) + continue; + info->aConstraintUsage[i].argvIndex = filter->aConstraintUsage[j].argvIndex; + info->aConstraintUsage[i].omit = filter->aConstraintUsage[j].omit ? 1 : 0; + j++; + } + g_free (filter->aConstraint); + g_free (filter->aConstraintUsage); + + } + if (filter->nOrderBy > 0) + g_free (filter->aOrderBy); + info->idxNum = filter->idxNum; + info->idxStr = (char*) filter->idxPointer; + info->needToFreeIdxStr = 0; + info->orderByConsumed = filter->orderByConsumed ? 1 : 0; + info->estimatedCost = filter->estimatedCost; +} + +static int +virtualBestIndex (sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo) +{ + VirtualTable *vtable = (VirtualTable *) tab; + + TRACE (tab, NULL); +#ifdef GDA_DEBUG_VIRTUAL + index_info_dump (pIdxInfo, FALSE); +#endif + + if (vtable->td->spec->create_filter_func) { + GdaVconnectionDataModelFilter filter; + map_sqlite3_info_to_gda_filter (pIdxInfo, &filter); + vtable->td->spec->create_filter_func (vtable->td->spec, &filter); + map_consume_gda_filter_to_sqlite3_info (&filter, pIdxInfo); +#ifdef GDA_DEBUG_VIRTUAL + index_info_dump (pIdxInfo, TRUE); +#endif + } + + return SQLITE_OK; +} + +/* + * + * Returns: >= 0 if Ok, -1 on error + */ +static gint +param_name_to_number (gint maxrows, const gchar *str) +{ + gchar *endptr [1]; + long int i; + i = strtol (str, endptr, 10); + if ((**endptr == '\0') && (i < maxrows) && (i >= 0)) + return i; + else + return -1; +} + +/* + * optype value: see virtualUpdate() + */ +static int +update_data_select_model (sqlite3_vtab *tab, gint optype, G_GNUC_UNUSED int nData, sqlite3_value **apData) +{ + VirtualTable *vtable = (VirtualTable *) tab; + GdaSqliteProvider *prov = GDA_SQLITE_PROVIDER (gda_connection_get_provider (GDA_CONNECTION (vtable->cnc))); + + /* determine parameters required to execute MOD statement */ + GdaStatement *stmt = NULL; + ParamType ptype; + switch (optype) { + case 1: + ptype = PARAMS_DELETE; + if (! vtable->td->modif_stmt [ptype]) + g_object_get (vtable->td->real_model, "delete-stmt", &stmt, NULL); + break; + case 2: + ptype = PARAMS_INSERT; + if (! vtable->td->modif_stmt [ptype]) + g_object_get (vtable->td->real_model, "insert-stmt", &stmt, NULL); + break; + case 3: + ptype = PARAMS_UPDATE; + if (! vtable->td->modif_stmt [ptype]) + g_object_get (vtable->td->real_model, "update-stmt", &stmt, NULL); + break; + default: + g_assert_not_reached (); + } + + if (! vtable->td->modif_stmt [ptype]) { + if (! stmt) { + tab->zErrMsg = SQLITE3_CALL (prov, sqlite3_mprintf) + (_("No statement specified to modify the data")); + return SQLITE_READONLY; + } + + GdaSet *params; + if (! gda_statement_get_parameters (stmt, ¶ms, NULL) || !params) { + tab->zErrMsg = SQLITE3_CALL (prov, sqlite3_mprintf) + (_("Invalid statement specified to modify the data")); + g_object_unref (stmt); + return SQLITE_READONLY; + } + vtable->td->modif_stmt [ptype] = stmt; + vtable->td->modif_params [ptype] = params; + } + stmt = vtable->td->modif_stmt [ptype]; + + /* bind parameters */ + GSList *list; + + for (list = gda_set_get_holders (vtable->td->modif_params [ptype]); list; list = list->next) { + const gchar *id; + GdaHolder *holder = GDA_HOLDER (list->data); + gboolean holder_value_set = FALSE; + + id = gda_holder_get_id (holder); + if (!id) { + tab->zErrMsg = SQLITE3_CALL (prov, sqlite3_mprintf) + (_("Invalid parameter in statement to modify the data")); + return SQLITE_READONLY; + } + if (*id == '+' && id[1]) { + long int i; + i = param_name_to_number (vtable->td->n_columns, id+1); + if (i >= 0) { + GType type; + GValue *value; + type = gda_column_get_g_type (gda_data_model_describe_column (vtable->td->real_model, i)); + if ((type != GDA_TYPE_NULL) && SQLITE3_CALL (prov, sqlite3_value_text) (apData [i+2])) + value = gda_value_new_from_string ((const gchar*) SQLITE3_CALL (prov, sqlite3_value_text) (apData [i+2]), type); + else + value = gda_value_new_null (); + if (gda_holder_take_value (holder, value, NULL)) + holder_value_set = TRUE; + } + } + else if (*id == '-') { + gint64 rowid = SQLITE3_CALL (prov, sqlite3_value_int64) (apData [0]); + long int i; + const GValue *value; + + i = param_name_to_number (vtable->td->n_columns, id+1); + value = get_data_value (vtable, NULL, -1, rowid, i, NULL); + if (value && gda_holder_set_value (holder, value, NULL)) + holder_value_set = TRUE; + } + + if (! holder_value_set) { + GdaSet *exec_set; + GdaHolder *eh; + g_object_get (vtable->td->real_model, "exec-params", + &exec_set, NULL); + if (! exec_set) { + /* can't give value to param named @id */ + tab->zErrMsg = SQLITE3_CALL (prov, sqlite3_mprintf) + (_("Invalid parameter in statement to modify the data")); + return SQLITE_READONLY; + } + eh = gda_set_get_holder (exec_set, id); + if (! eh || + ! gda_holder_set_bind (holder, eh, NULL)) { + /* can't give value to param named @id */ + tab->zErrMsg = SQLITE3_CALL (prov, sqlite3_mprintf) + (_("Invalid parameter in statement to modify the data")); + return SQLITE_READONLY; + } + } + } + + GdaConnection *cnc; + cnc = gda_data_select_get_connection (GDA_DATA_SELECT (vtable->td->real_model)); + + GError *lerror = NULL; +#ifdef GDA_DEBUG_NO + gchar *sql; + sql = gda_statement_to_sql (stmt, NULL, NULL); + g_print ("SQL: [%s] ", sql); + g_free (sql); + sql = gda_statement_to_sql_extended (stmt, cnc, vtable->td->modif_params [ptype], GDA_STATEMENT_SQL_PRETTY, NULL, &lerror); + if (sql) { + g_print ("With params: [%s]\n", sql); + g_free (sql); + } + else { + g_print ("params ERROR [%s]\n", lerror && lerror->message ? lerror->message : "No detail"); + } + g_clear_error (&lerror); +#endif + + if (!cnc || + (gda_connection_statement_execute_non_select (cnc, stmt, + vtable->td->modif_params [ptype], + NULL, &lerror) == -1)) { + /* failed to execute */ + tab->zErrMsg = SQLITE3_CALL (prov, sqlite3_mprintf) + (_("Failed to modify data: %s"), + lerror && lerror->message ? lerror->message : _("No detail")); + g_clear_error (&lerror); + return SQLITE_READONLY; + } + return SQLITE_OK; +} + +/* + * apData[0] apData[1] apData[2..] + * + * INTEGER DELETE + * + * INTEGER NULL (nCol args) UPDATE (do not set rowid) + * INTEGER INTEGER (nCol args) UPDATE (with SET rowid = ) + * + * NULL NULL (nCol args) INSERT INTO (automatic rowid value) + * NULL INTEGER (nCol args) INSERT (incl. rowid value) + */ +static int +virtualUpdate (sqlite3_vtab *tab, int nData, sqlite3_value **apData, sqlite_int64 *pRowid) +{ + VirtualTable *vtable = (VirtualTable *) tab; + GdaSqliteProvider *prov = GDA_SQLITE_PROVIDER (gda_connection_get_provider (GDA_CONNECTION (vtable->cnc))); + const gchar *api_misuse_error = NULL; + gint optype; /* 1 => DELETE + * 2 => INSERT + * 3 => UPDATE + */ + + TRACE (tab, NULL); + + g_assert (vtable->td->context.current_vcontext); + GPtrArray *values_array = vtable->td->context.current_vcontext->context_data; + if (values_array != NULL) { + guint i; + for (i = 0; i < values_array->len; i++) { + VirtualFilteredData *data; + data = g_ptr_array_index (values_array, i); + data->reuseable = FALSE; + } + } + + /* determine operation type */ + if (nData == 1) + optype = 1; + else if ((nData > 1) && (SQLITE3_CALL (prov, sqlite3_value_type) (apData[0]) == SQLITE_NULL)) { + optype = 2; + if (SQLITE3_CALL (prov, sqlite3_value_type) (apData[1]) != SQLITE_NULL) { + /* argc>1 and argv[0] is not NULL: rowid is imposed by SQLite + * which is not supported */ + return SQLITE_READONLY; + } } + else if ((nData > 1) && (SQLITE3_CALL (prov, sqlite3_value_type) (apData[0]) == SQLITE_INTEGER)) { + optype = 3; + if (SQLITE3_CALL (prov, sqlite3_value_int) (apData[0]) != + SQLITE3_CALL (prov, sqlite3_value_int) (apData[1])) { + /* argc>1 and argv[0]==argv[1]: rowid is imposed by SQLite + * which is not supported */ + return SQLITE_READONLY; + } + } + else + return SQLITE_MISUSE; + + /* handle data model */ + if (! vtable->td->real_model) { + virtual_table_manage_real_data_model (vtable, -1, NULL, 0, NULL); + if (! vtable->td->real_model) + return SQLITE_ERROR; + } + + GdaDataModelAccessFlags access_flags; + access_flags = gda_data_model_get_access_flags (vtable->td->real_model); + if (((optype == 1) && ! (access_flags & GDA_DATA_MODEL_ACCESS_DELETE)) || + ((optype == 2) && ! (access_flags & GDA_DATA_MODEL_ACCESS_INSERT)) || + ((optype == 3) && ! (access_flags & GDA_DATA_MODEL_ACCESS_UPDATE))) { + /* we can't use vtable->td->real_model because it can't be accessed correctly */ + if (GDA_IS_DATA_SELECT (vtable->td->real_model)) + return update_data_select_model (tab, optype, nData, apData); + else { + TO_IMPLEMENT; + tab->zErrMsg = SQLITE3_CALL (prov, sqlite3_mprintf) + (_("Data model representing the table is read only")); + return SQLITE_READONLY; + } + } + + /* REM: when using the values of apData[], the limit is + * (nData -1 ) and not nData because the last column of the corresponding CREATE TABLE ... + * is an internal hidden field which does not correspond to any column of the real data model + */ + + if (optype == 1) { + /* DELETE */ + if (SQLITE3_CALL (prov, sqlite3_value_type) (apData[0]) == SQLITE_INTEGER) { + gint rowid = SQLITE3_CALL (prov, sqlite3_value_int) (apData [0]); + return gda_data_model_remove_row (vtable->td->real_model, rowid, NULL) ? + SQLITE_OK : SQLITE_READONLY; + } + else { + api_misuse_error = "argc==1 and argv[0] is not an integer"; + goto api_misuse; + } + } + else if (optype == 2) { + /* INSERT */ + gint newrow, i; + GList *values = NULL; + + for (i = 2; i < (nData - 1); i++) { + GType type; + GValue *value; + type = gda_column_get_g_type (gda_data_model_describe_column (vtable->td->real_model, i - 2)); + if ((type != GDA_TYPE_NULL) && SQLITE3_CALL (prov, sqlite3_value_text) (apData [i])) + value = gda_value_new_from_string ((const gchar*) SQLITE3_CALL (prov, sqlite3_value_text) (apData [i]), type); + else + value = gda_value_new_null (); + /*g_print ("TXT #%s# => value %p (type=%s) apData[]=%p\n", + SQLITE3_CALL (prov, sqlite3_value_text) (apData [i]), value, + g_type_name (type), apData[i]);*/ + values = g_list_prepend (values, value); + } + values = g_list_reverse (values); + + newrow = gda_data_model_append_values (vtable->td->real_model, values, NULL); + g_list_free_full (values, (GDestroyNotify) gda_value_free); + if (newrow < 0) + return SQLITE_READONLY; + + *pRowid = newrow; + } + else if (optype == 3) { + /* UPDATE */ + gint i; + + + for (i = 2; i < (nData - 1); i++) { + GValue *value; + GType type; + gint rowid = SQLITE3_CALL (prov, sqlite3_value_int) (apData [0]); + gboolean res; + GError *error = NULL; + + /*g_print ("%d => %s\n", i, SQLITE3_CALL (prov, sqlite3_value_text) (apData [i]));*/ + type = gda_column_get_g_type (gda_data_model_describe_column (vtable->td->real_model, i - 2)); + value = gda_value_new_from_string ((const gchar*) SQLITE3_CALL (prov, sqlite3_value_text) (apData [i]), type); + res = gda_data_model_set_value_at (vtable->td->real_model, i - 2, rowid, + value, &error); + gda_value_free (value); + if (!res) { + /*g_print ("Error: %s\n", error && error->message ? error->message : "???");*/ + g_clear_error (&error); + return SQLITE_READONLY; + } + } + return SQLITE_OK; + } + else { + api_misuse_error = "argc>1 and argv[0] is not NULL and not an integer"; + goto api_misuse; + } + + return SQLITE_OK; + + api_misuse: + g_warning ("Error in the xUpdate SQLite's virtual method: %s\n" + "this is an SQLite error, please report it", api_misuse_error); + return SQLITE_ERROR; +} + +static int +virtualBegin (G_GNUC_UNUSED sqlite3_vtab *tab) +{ + VirtualTable *vtable = (VirtualTable *) tab; + TRACE (tab, NULL); + + if (vtable->locked) + return SQLITE_ERROR; + else { + vtable->locked = TRUE; + return SQLITE_OK; + } +} + +static int +virtualSync (G_GNUC_UNUSED sqlite3_vtab *tab) +{ + TRACE (tab, NULL); + /* no documentation currently available, don't do anything */ + return SQLITE_OK; +} + +static int +virtualCommit (G_GNUC_UNUSED sqlite3_vtab *tab) +{ + VirtualTable *vtable = (VirtualTable *) tab; + TRACE (tab, NULL); + + vtable->locked = FALSE; + return SQLITE_OK; +} + +static int +virtualRollback (G_GNUC_UNUSED sqlite3_vtab *tab) +{ + VirtualTable *vtable = (VirtualTable *) tab; + TRACE (tab, NULL); + + vtable->locked = FALSE; + return SQLITE_OK; +} + +static int +virtualRename (G_GNUC_UNUSED sqlite3_vtab *pVtab, G_GNUC_UNUSED const char *zNew) +{ + TRACE (pVtab, NULL); + /* not yet analysed and implemented */ + return SQLITE_OK; +} diff --git a/.flatpak-builder/cache/objects/86/32d98ec7aebe22a6752c016bf9337ad507209a1a52eb33547036cf023fca05.file b/.flatpak-builder/cache/objects/86/32d98ec7aebe22a6752c016bf9337ad507209a1a52eb33547036cf023fca05.file new file mode 100644 index 0000000..dcd4aca --- /dev/null +++ b/.flatpak-builder/cache/objects/86/32d98ec7aebe22a6752c016bf9337ad507209a1a52eb33547036cf023fca05.file @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2000 Reinhard Müller + * Copyright (C) 2000 - 2002 Rodrigo Moya + * Copyright (C) 2001 Carlos Perelló Marín + * Copyright (C) 2001 - 2011 Vivien Malerba + * Copyright (C) 2002 Gonzalo Paniagua Javier + * Copyright (C) 2009 Murray Cumming + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef _GDA_STATEMENT_STRUCT_UNKNOWN_H_ +#define _GDA_STATEMENT_STRUCT_UNKNOWN_H_ + +#include +#include +#include +#include + +G_BEGIN_DECLS + +/* + * Structure definition + */ +/** + * GdaSqlStatementUnknown: + * @any: + * @expressions: a list of #GdaSqlExpr pointers + * + * Represents any statement which type is not identified (any DDL statement or database specific dialect) + */ +struct _GdaSqlStatementUnknown { + GdaSqlAnyPart any; + GSList *expressions; + + /*< private >*/ + /* Padding for future expansion */ + gpointer _gda_reserved1; + gpointer _gda_reserved2; +}; + +/* + * Common operations + */ +GdaSqlStatementContentsInfo *_gda_sql_statement_unknown_get_infos (void); + +/* + * Functions used by the parser + */ +void gda_sql_statement_unknown_take_expressions (GdaSqlStatement *stmt, GSList *expressions); + +G_END_DECLS + +#endif diff --git a/.flatpak-builder/cache/objects/86/f6dfa279c125a269c71b93c589c1f3a1c817f3b507cd3c768611fcc23dfb60.dirtree b/.flatpak-builder/cache/objects/86/f6dfa279c125a269c71b93c589c1f3a1c817f3b507cd3c768611fcc23dfb60.dirtree new file mode 100644 index 0000000..b440d5c Binary files /dev/null and b/.flatpak-builder/cache/objects/86/f6dfa279c125a269c71b93c589c1f3a1c817f3b507cd3c768611fcc23dfb60.dirtree differ diff --git a/.flatpak-builder/cache/objects/87/07d077ceff69cd7970c87e5286af54ed28a8a355a22000419de9d7cadb3559.dirtree b/.flatpak-builder/cache/objects/87/07d077ceff69cd7970c87e5286af54ed28a8a355a22000419de9d7cadb3559.dirtree new file mode 100644 index 0000000..08b7e5f Binary files /dev/null and b/.flatpak-builder/cache/objects/87/07d077ceff69cd7970c87e5286af54ed28a8a355a22000419de9d7cadb3559.dirtree differ diff --git a/.flatpak-builder/cache/objects/87/46bc689a6c0637b5064a49ddbb8e443111cdccb66daadc5fea2ccfa71562d9.file b/.flatpak-builder/cache/objects/87/46bc689a6c0637b5064a49ddbb8e443111cdccb66daadc5fea2ccfa71562d9.file new file mode 100644 index 0000000..c9f69db --- /dev/null +++ b/.flatpak-builder/cache/objects/87/46bc689a6c0637b5064a49ddbb8e443111cdccb66daadc5fea2ccfa71562d9.file @@ -0,0 +1,290 @@ +/* + * Copyright (C) 2007 Armin Burgmeier + * Copyright (C) 2007 - 2012 Vivien Malerba + * Copyright (C) 2009 Bas Driessen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "gda-binreloc.h" +/* include source file as mentioned in gbr_init_lib()'s doc */ +#include "binreloc.c" + +#ifdef G_OS_WIN32 +#include +/* Remember HMODULE to retrieve path to it lateron */ +static HMODULE hdllmodule = NULL; +BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved) +{ + switch(fdwReason) + { + case DLL_PROCESS_ATTACH: + hdllmodule = (HMODULE)hinstDLL; + break; + } + + return TRUE; +} +#elif HAVE_CARBON + #ifdef ENABLE_BINRELOC + #include + #endif +#endif + + +/** + * gda_gbr_init + */ +void +gda_gbr_init (void) +{ +#ifdef G_OS_WIN32 + /* nothing */ +#elif HAVE_CARBON + /* nothing */ +#else + _gda_gbr_init_lib (NULL); +#endif +} + +/* + * gda_gbr_get_file_path + */ +gchar * +gda_gbr_get_file_path (GdaPrefixDir where, ...) +{ + gchar *prefix = NULL; + gchar *tmp, *file_part; + va_list ap; + gchar **parts; + gint size, i; + const gchar *prefix_dir_name = NULL; + gint prefix_len = strlen (LIBGDAPREFIX); + + /* + g_print ("LIBGDAPREFIX = %s\n", LIBGDAPREFIX); + g_print ("LIBGDABIN = %s\n", LIBGDABIN); + g_print ("LIBGDASBIN = %s\n", LIBGDASBIN); + g_print ("LIBGDADATA = %s\n",LIBGDADATA ); + g_print ("LIBGDALIB = %s\n", LIBGDALIB); + g_print ("LIBGDALIBEXEC = %s\n",LIBGDALIBEXEC ); + g_print ("LIBGDASYSCONF = %s\n", LIBGDASYSCONF); + */ + +#ifdef G_OS_WIN32 + wchar_t path[MAX_PATH]; /* Flawfinder: ignore */ + gchar* p; +#endif + + switch (where) { + default: + case GDA_NO_DIR: + break; + case GDA_BIN_DIR: + tmp = LIBGDABIN; +#ifndef G_OS_WIN32 + if (! g_str_has_prefix (tmp, LIBGDAPREFIX) || (tmp [prefix_len] != G_DIR_SEPARATOR)) + prefix = g_strdup (tmp); + else + prefix_dir_name = tmp + prefix_len + 1; +#else + prefix_dir_name = "bin"; +#endif + break; + case GDA_SBIN_DIR: + tmp = LIBGDASBIN; +#ifndef G_OS_WIN32 + if (! g_str_has_prefix (tmp, LIBGDAPREFIX) || (tmp [prefix_len] != G_DIR_SEPARATOR)) + prefix = g_strdup (tmp); + else + prefix_dir_name = tmp + prefix_len + 1; +#else + prefix_dir_name = "sbin"; +#endif + break; + case GDA_DATA_DIR: + tmp = LIBGDADATA; +#ifndef G_OS_WIN32 + if (! g_str_has_prefix (tmp, LIBGDAPREFIX) || (tmp [prefix_len] != G_DIR_SEPARATOR)) + prefix = g_strdup (tmp); + else + prefix_dir_name = tmp + prefix_len + 1; +#else + prefix_dir_name = "share"; +#endif + break; + case GDA_LOCALE_DIR: + tmp = LIBGDADATA; +#ifndef G_OS_WIN32 + if (! g_str_has_prefix (tmp, LIBGDAPREFIX) || (tmp [prefix_len] != G_DIR_SEPARATOR)) { + prefix = g_strdup (tmp); + prefix_dir_name = "locale"; + } + else + prefix_dir_name = "share" G_DIR_SEPARATOR_S "locale"; +#else + prefix_dir_name = "share" G_DIR_SEPARATOR_S "locale"; +#endif + break; + case GDA_LIB_DIR: + tmp = LIBGDALIB; +#ifndef G_OS_WIN32 + if (! g_str_has_prefix (tmp, LIBGDAPREFIX) || (tmp [prefix_len] != G_DIR_SEPARATOR)) + prefix = g_strdup (tmp); + else + prefix_dir_name = tmp + prefix_len + 1; +#else + prefix_dir_name = "lib"; +#endif + break; + case GDA_LIBEXEC_DIR: + tmp = LIBGDALIBEXEC; +#ifndef G_OS_WIN32 + if (! g_str_has_prefix (tmp, LIBGDAPREFIX) || (tmp [prefix_len] != G_DIR_SEPARATOR)) + prefix = g_strdup (tmp); + else + prefix_dir_name = tmp + prefix_len + 1; +#else + prefix_dir_name = "libexec"; +#endif + break; + case GDA_ETC_DIR: + tmp = LIBGDASYSCONF; +#ifndef G_OS_WIN32 + if (! g_str_has_prefix (tmp, LIBGDAPREFIX) || (tmp [prefix_len] != G_DIR_SEPARATOR)) + prefix = g_strdup (tmp); + else + prefix_dir_name = tmp + prefix_len + 1; +#else + prefix_dir_name = "etc"; +#endif + break; + } + +#ifdef GDA_DEBUG_NO + g_print ("%s ()\n", __FUNCTION__); +#endif + + if (!prefix) { + /* prefix part for each OS */ +#ifdef G_OS_WIN32 + /* Get from location of libgda DLL */ + GetModuleFileNameW (hdllmodule, path, MAX_PATH); + prefix = g_utf16_to_utf8 (path, -1, NULL, NULL, NULL); + if ((p = strrchr (prefix, G_DIR_SEPARATOR)) != NULL) + *p = '\0'; + + p = strrchr (prefix, G_DIR_SEPARATOR); + if (p && (g_ascii_strcasecmp (p + 1, "bin") == 0 || + g_ascii_strcasecmp (p + 1, "lib") == 0)) + *p = '\0'; +#elif HAVE_CARBON + #ifdef ENABLE_BINRELOC + #define MAXLEN 500 + ProcessSerialNumber myProcess; + FSRef bundleLocation; + unsigned char bundlePath[MAXLEN]; /* Flawfinder: ignore */ + + if ((GetCurrentProcess (&myProcess) == noErr) && + (GetProcessBundleLocation (&myProcess, &bundleLocation) == noErr) && + (FSRefMakePath (&bundleLocation, bundlePath, MAXLEN) == noErr)) { + if (g_str_has_suffix ((const gchar*) bundlePath, ".app")) + prefix = g_strdup_printf ("%s/Contents/Resources", (const gchar*) bundlePath); + else { + prefix = g_path_get_dirname ((const char*) bundlePath); + if (g_str_has_suffix (prefix, "bin")) + prefix [strlen (prefix) - 3] = 0; + } +#ifdef GDA_DEBUG_NO + g_print ("BUNDLE=%s, prefix=%s\n", bundlePath, prefix); +#endif + } + else + g_warning ("Could not get PREFIX (using Mac OS X Carbon)"); + #else +#ifdef GDA_DEBUG_NO + g_print ("Binreloc disabled, using %s\n", LIBGDAPREFIX); +#endif + #endif + + if (!prefix) + prefix = g_strdup (LIBGDAPREFIX); +#else + if (!prefix) + prefix = _gda_gbr_find_prefix (LIBGDAPREFIX); +#endif + } + + if (!prefix || !*prefix) { + g_free (prefix); + return NULL; + } + + /* filename part */ + size = 10; + parts = g_new0 (gchar *, size); + va_start (ap, where); + for (i = 0, tmp = va_arg (ap, gchar *); tmp; tmp = va_arg (ap, gchar *)) { + if (i == size - 1) { + size += 10; + parts = g_renew (gchar *, parts, size); + } + parts[i] = g_strdup (tmp); +#ifdef GDA_DEBUG_NO + g_print ("\t+ %s\n", tmp); +#endif + i++; + } + parts[i] = NULL; + va_end (ap); + + file_part = g_build_filenamev (parts); + g_strfreev (parts); + + /* result */ + if (prefix_dir_name) + tmp = g_build_filename (prefix, prefix_dir_name, file_part, NULL); + else + tmp = g_build_filename (prefix, file_part, NULL); + + if (!g_file_test (tmp, G_FILE_TEST_EXISTS)) { + if (g_str_has_suffix (prefix, "libgda")) { + /* test if we are in the sources */ + g_free (tmp); + if (prefix_dir_name) + tmp = g_build_filename (LIBGDAPREFIX, prefix_dir_name, file_part, NULL); + else + tmp = g_build_filename (LIBGDAPREFIX, file_part, NULL); + } + else { + g_free (prefix); + prefix = g_strdup (LIBGDAPREFIX); + g_free (tmp); + if (prefix_dir_name) + tmp = g_build_filename (prefix, prefix_dir_name, file_part, NULL); + else + tmp = g_build_filename (prefix, file_part, NULL); + } + } + + g_free (prefix); + g_free (file_part); +#ifdef GDA_DEBUG_NO + g_print ("\t=> %s\n", tmp); +#endif + + return tmp; +} diff --git a/.flatpak-builder/cache/objects/87/6bfca005edf75697f89f0bcd5f5681b9ca02ac550a15456593e3d68b0df485.dirtree b/.flatpak-builder/cache/objects/87/6bfca005edf75697f89f0bcd5f5681b9ca02ac550a15456593e3d68b0df485.dirtree new file mode 100644 index 0000000..a217184 Binary files /dev/null and b/.flatpak-builder/cache/objects/87/6bfca005edf75697f89f0bcd5f5681b9ca02ac550a15456593e3d68b0df485.dirtree differ diff --git a/.flatpak-builder/cache/objects/87/b054aedb09fbc03ee9dfeebb4a1f4df8091448ea7faa282eff8636017c4e2f.file b/.flatpak-builder/cache/objects/87/b054aedb09fbc03ee9dfeebb4a1f4df8091448ea7faa282eff8636017c4e2f.file new file mode 100644 index 0000000..c1364ed --- /dev/null +++ b/.flatpak-builder/cache/objects/87/b054aedb09fbc03ee9dfeebb4a1f4df8091448ea7faa282eff8636017c4e2f.file @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2009 - 2011 Vivien Malerba + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GDA_TREE_MGR_LABEL_H__ +#define __GDA_TREE_MGR_LABEL_H__ + +#include +#include "gda-tree-manager.h" + +G_BEGIN_DECLS + +#define GDA_TYPE_TREE_MGR_LABEL (gda_tree_mgr_label_get_type()) +G_DECLARE_DERIVABLE_TYPE (GdaTreeMgrLabel, gda_tree_mgr_label, GDA, TREE_MGR_LABEL, GdaTreeManager) + +struct _GdaTreeMgrLabelClass { + GdaTreeManagerClass parent_class; +}; + +/** + * SECTION:gda-tree-mgr-label + * @short_description: A tree manager which creates a single node + * @title: GdaTreeMgrLabel + * @stability: Stable + * @see_also: + * + * The #GdaTreeMgrLabel is a #GdaTreeManager object which creates a single node. This tree manager + * is useful to create "sections" in a #GdaTree hierarchy. + */ + +GdaTreeManager* gda_tree_mgr_label_new (const gchar *label); + +G_END_DECLS + +#endif diff --git a/.flatpak-builder/cache/objects/87/b447815e51b015912ad0c1e4b345429ab7b55ab7fb28f3e65ded2732d7e6c4.dirtree b/.flatpak-builder/cache/objects/87/b447815e51b015912ad0c1e4b345429ab7b55ab7fb28f3e65ded2732d7e6c4.dirtree new file mode 100644 index 0000000..ce800b6 Binary files /dev/null and b/.flatpak-builder/cache/objects/87/b447815e51b015912ad0c1e4b345429ab7b55ab7fb28f3e65ded2732d7e6c4.dirtree differ diff --git a/.flatpak-builder/cache/objects/87/c671e8e30e69e3d64d63a9deaa879bb57ca3321ffe07a3c5c23e07a1e8c10d.file b/.flatpak-builder/cache/objects/87/c671e8e30e69e3d64d63a9deaa879bb57ca3321ffe07a3c5c23e07a1e8c10d.file new file mode 100644 index 0000000..da2b22a --- /dev/null +++ b/.flatpak-builder/cache/objects/87/c671e8e30e69e3d64d63a9deaa879bb57ca3321ffe07a3c5c23e07a1e8c10d.file @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2008 - 2014 Vivien Malerba + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GDA_LOCKABLE_H__ +#define __GDA_LOCKABLE_H__ + +#include + +G_BEGIN_DECLS + +#define GDA_TYPE_LOCKABLE (gda_lockable_get_type()) +G_DECLARE_INTERFACE (GdaLockable, gda_lockable, GDA, LOCKABLE, GObject) +/* struct for the interface */ +struct _GdaLockableInterface { + GTypeInterface g_iface; + + /* virtual table */ + void (* lock) (GdaLockable *lockable); + gboolean (* trylock) (GdaLockable *lockable); + void (* unlock) (GdaLockable *lockable); +}; + +/** + * SECTION:gda-lockable + * @short_description: Interface for locking objects in a multi threaded environment + * @title: GdaLockable + * @stability: Stable + * @see_also: #GRecMutex and #GMutex + * + * This interface is implemented by objects which are thread safe (ie. can be used by several threads at + * the same time). Before using an object from a thread, one has to call gda_lockable_lock() or + * gda_lockable_trylock() and call gda_lockable_unlock() when the object is not used anymore. + */ + +void gda_lockable_lock (GdaLockable *lockable); +gboolean gda_lockable_trylock (GdaLockable *lockable); +void gda_lockable_unlock (GdaLockable *lockable); + +G_END_DECLS + +#endif diff --git a/.flatpak-builder/cache/objects/88/1c994d8dfbc7a0e3256732e44ab9dc151acf5c7a3ccbac29f14e0dfd20ef26.file b/.flatpak-builder/cache/objects/88/1c994d8dfbc7a0e3256732e44ab9dc151acf5c7a3ccbac29f14e0dfd20ef26.file new file mode 120000 index 0000000..e92ae76 --- /dev/null +++ b/.flatpak-builder/cache/objects/88/1c994d8dfbc7a0e3256732e44ab9dc151acf5c7a3ccbac29f14e0dfd20ef26.file @@ -0,0 +1 @@ +../../share/runtime/locale/it/share/it \ No newline at end of file diff --git a/.flatpak-builder/cache/objects/88/5dba4803651d3b893fa40372f019a3ccb6c6fc1962a5f35a6e16510f5ac614.file b/.flatpak-builder/cache/objects/88/5dba4803651d3b893fa40372f019a3ccb6c6fc1962a5f35a6e16510f5ac614.file new file mode 100644 index 0000000..7d34954 Binary files /dev/null and b/.flatpak-builder/cache/objects/88/5dba4803651d3b893fa40372f019a3ccb6c6fc1962a5f35a6e16510f5ac614.file differ diff --git a/.flatpak-builder/cache/objects/88/85f4ece17df9d811da984e55175d889b5517b9158b0e1efc0596cff76fdcbd.file b/.flatpak-builder/cache/objects/88/85f4ece17df9d811da984e55175d889b5517b9158b0e1efc0596cff76fdcbd.file new file mode 100644 index 0000000..92832e3 Binary files /dev/null and b/.flatpak-builder/cache/objects/88/85f4ece17df9d811da984e55175d889b5517b9158b0e1efc0596cff76fdcbd.file differ diff --git a/.flatpak-builder/cache/objects/88/bc41256cc5b416242925f68c66c6e35cc54525cc03256a4127ecd4738b2050.file b/.flatpak-builder/cache/objects/88/bc41256cc5b416242925f68c66c6e35cc54525cc03256a4127ecd4738b2050.file new file mode 100644 index 0000000..d67a281 --- /dev/null +++ b/.flatpak-builder/cache/objects/88/bc41256cc5b416242925f68c66c6e35cc54525cc03256a4127ecd4738b2050.file @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2006 - 2013 Vivien Malerba + * Copyright (C) 2007 Murray Cumming + * Copyright (C) 2011 Daniel Espinosa + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GLOBAL_DECL_H_ +#define __GLOBAL_DECL_H_ + +#include + +typedef struct _GdaConfig GdaConfig; +typedef struct _GdaConfigClass GdaConfigClass; + +typedef struct _GdaConnection GdaConnection; +typedef struct _GdaConnectionClass GdaConnectionClass; + +typedef struct _GdaServerProvider GdaServerProvider; +typedef struct _GdaServerProviderClass GdaServerProviderClass; + +typedef struct _GdaDataModelIface GdaDataModelIface; +typedef struct _GdaDataModel GdaDataModel; + +typedef struct _GdaColumn GdaColumn; +typedef struct _GdaColumnClass GdaColumnClass; + +typedef struct _GdaHolder GdaHolder; +typedef struct _GdaHolderClass GdaHolderClass; + +typedef struct _GdaBlobOp GdaBlobOp; +typedef struct _GdaBlobOpClass GdaBlobOpClass; + +/* + * Statements & parser + */ + +typedef struct _GdaStatement GdaStatement; +typedef struct _GdaStatementClass GdaStatementClass; + +typedef struct _GdaRepetitiveStatement GdaRepetitiveStatement; +typedef struct _GdaRepetitiveStatementClass GdaRepetitiveStatementClass; + +typedef struct _GdaSqlParser GdaSqlParser; +typedef struct _GdaSqlParserClass GdaSqlParserClass; + +/* + * Meta data + */ +typedef struct _GdaMetaStruct GdaMetaStruct; +typedef struct _GdaMetaStructClass GdaMetaStructClass; + +/* + * Determines if @word is a reserved SQL keyword + */ +typedef gboolean (*GdaSqlReservedKeywordsFunc) (const gchar *word); + +typedef struct _GdaTreeNode GdaTreeNode; +typedef struct _GdaTreeNodeClass GdaTreeNodeClass; + +#endif + diff --git a/.flatpak-builder/cache/objects/89/21370961875ef641942ed162c5e90d8f522f3f31e46760e666fe7f27d35a33.file b/.flatpak-builder/cache/objects/89/21370961875ef641942ed162c5e90d8f522f3f31e46760e666fe7f27d35a33.file new file mode 100644 index 0000000..63f8a74 --- /dev/null +++ b/.flatpak-builder/cache/objects/89/21370961875ef641942ed162c5e90d8f522f3f31e46760e666fe7f27d35a33.file @@ -0,0 +1,701 @@ +/* gda-db-fkey.c + * + * Copyright (C) 2018-2019 Pavlo Solntsev + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +#define G_LOG_DOMAIN "GDA-db-fkey" + +#include "gda-db-fkey.h" +#include +#include "gda-db-buildable.h" +#include "gda-db-fkey-private.h" + +typedef struct +{ + /* /FKEY_S/%d/FKEY_REF_TABLE */ + gchar *mp_ref_table; + /* /FKEY_S/%d/FKEY_FIELDS_A/@FK_FIELD */ + + GList *mp_field; + /* /FKEY_S/FKEY_FIELDS_A/@FK_REF_PK_FIELD */ + GList *mp_ref_field; + /* /FKEY_S/FKEY_ONUPDATE This action is reserved for ONUPDATE */ + GdaDbFkeyReferenceAction m_onupdate; + /* /FKEY_S/FKEY_ONDELETE This action is reserved for ONDELETE */ + GdaDbFkeyReferenceAction m_ondelete; +}GdaDbFkeyPrivate; + +/** + * SECTION:gda-db-fkey + * @short_description: Object to hold information for foregn key. + * @stability: Stable + * @include: libgda/libgda.h + * + * For generating database from xml file or for mapping + * database to an xml file #GdaDbFkey holds information about + * foregn keys with a convenient set of methods to manipulate them. + * #GdaDbFkey implements #GdaDbBuildable interface for parsing xml file. This is an example how + * #GdaDbFkey can be used: + * + * |[ + * GdaDbFkey *fkey = gda_db_fkey_new (); + * gda_db_fkey_set_ref_table (fkey, "Project"); + * gda_db_fkey_set_ondelete (fkey, GDA_DB_FKEY_RESTRICT); + * gda_db_fkey_set_onupdate (fkey, GDA_DB_FKEY_RESTRICT); + * gda_db_fkey_set_field (fkey, "project_id", "id"); + * + * gda_db_table_append_fkey (temployee, fkey); + * ]| + */ + +static void gda_db_fkey_buildable_interface_init (GdaDbBuildableInterface *iface); + +G_DEFINE_TYPE_WITH_CODE (GdaDbFkey, gda_db_fkey, G_TYPE_OBJECT, + G_ADD_PRIVATE (GdaDbFkey) + G_IMPLEMENT_INTERFACE (GDA_TYPE_DB_BUILDABLE, + gda_db_fkey_buildable_interface_init)) + +static const gchar *OnAction[] = { + "NO ACTION", + "SET NULL", + "RESTRICT", + "SET DEFAULT", + "CASCADE" +}; + +/* This is convenient way to name all nodes from xml file */ +enum { + GDA_DB_FKEY_NODE, + GDA_DB_FKEY_REFTABLE, + GDA_DB_FKEY_ONUPDATE, + GDA_DB_FKEY_ONDELETE, + GDA_DB_FKEY_FKFIELD, + GDA_DB_FKEY_FKFIELD_NAME, + GDA_DB_FKEY_FKFIELD_REFIELD, + GDA_DB_FKEY_N_NODES +}; + +static const gchar *gdadbfkeynodes[GDA_DB_FKEY_N_NODES] = { + "fkey", + "reftable", + "onupdate", + "ondelete", + "fk_field", + "name", + "reffield" +}; + +/** + * gda_db_fkey_new: + * + * Create a new #GdaDbFkey object. + * + * Stability: Stable + * Since: 6.0 + */ +GdaDbFkey * +gda_db_fkey_new (void) +{ + return g_object_new (GDA_TYPE_DB_FKEY, NULL); +} + +/** + * gda_db_fkey_new_from_meta: + * @metafkey: a #GdaMetaTableForeignKey instance + * + * Create a new instance from the corresponding meta object. If @metafkey is %NULL, + * this function is identical to gda_db_fkey_new(). + * + * Stability: Stable + * Since: 6.0 + */ +GdaDbFkey* +gda_db_fkey_new_from_meta (GdaMetaTableForeignKey *metafkey) +{ + if (!metafkey) + return gda_db_fkey_new (); + + GdaMetaDbObject *refobject = GDA_META_DB_OBJECT (metafkey->meta_table); + + GdaDbFkey *fkey = gda_db_fkey_new (); + + gda_db_fkey_set_ref_table (fkey, refobject->obj_full_name); + + for (gint i = 0; i < metafkey->cols_nb; i++) + gda_db_fkey_set_field (fkey, + metafkey->fk_names_array[i], + metafkey->ref_pk_names_array[i]); + + GdaMetaForeignKeyPolicy policy = GDA_META_TABLE_FOREIGN_KEY_ON_UPDATE_POLICY(metafkey); + + switch (policy) + { + case GDA_META_FOREIGN_KEY_NONE: + gda_db_fkey_set_onupdate (fkey, GDA_DB_FKEY_NO_ACTION); + break; + case GDA_META_FOREIGN_KEY_CASCADE: + gda_db_fkey_set_onupdate (fkey, GDA_DB_FKEY_CASCADE); + break; + case GDA_META_FOREIGN_KEY_RESTRICT: + gda_db_fkey_set_onupdate (fkey, GDA_DB_FKEY_RESTRICT); + break; + case GDA_META_FOREIGN_KEY_SET_DEFAULT: + gda_db_fkey_set_onupdate (fkey, GDA_DB_FKEY_SET_DEFAULT); + break; + default: + break; + } + + policy = GDA_META_TABLE_FOREIGN_KEY_ON_DELETE_POLICY(metafkey); + switch (policy) + { + case GDA_META_FOREIGN_KEY_NONE: + gda_db_fkey_set_ondelete (fkey, GDA_DB_FKEY_NO_ACTION); + break; + case GDA_META_FOREIGN_KEY_CASCADE: + gda_db_fkey_set_ondelete (fkey, GDA_DB_FKEY_CASCADE); + break; + case GDA_META_FOREIGN_KEY_RESTRICT: + gda_db_fkey_set_ondelete (fkey, GDA_DB_FKEY_RESTRICT); + break; + case GDA_META_FOREIGN_KEY_SET_DEFAULT: + gda_db_fkey_set_ondelete (fkey, GDA_DB_FKEY_SET_DEFAULT); + break; + default: + break; + } + + return fkey; +} + +static void +gda_db_fkey_finalize (GObject *object) +{ + GdaDbFkey *self = GDA_DB_FKEY(object); + GdaDbFkeyPrivate *priv = gda_db_fkey_get_instance_private (self); + + if (priv->mp_field) g_list_free_full (priv->mp_field, g_free); + if (priv->mp_ref_field) g_list_free_full (priv->mp_ref_field, g_free); + + g_free (priv->mp_ref_table); + + G_OBJECT_CLASS (gda_db_fkey_parent_class)->finalize (object); +} + +static void +gda_db_fkey_class_init (GdaDbFkeyClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->finalize = gda_db_fkey_finalize; +} + +static void +gda_db_fkey_init (GdaDbFkey *self) +{ + GdaDbFkeyPrivate *priv = gda_db_fkey_get_instance_private (self); + + priv->mp_field = NULL; + priv->mp_ref_field = NULL; + priv->mp_ref_table = NULL; + + priv->m_onupdate = GDA_DB_FKEY_NO_ACTION; + priv->m_ondelete = GDA_DB_FKEY_NO_ACTION; +} + +/** + * gda_db_fkey_parse_node: + * @self: #GdaDbFkey object + * @node: xml node to parse as #xmlNodePtr + * @error: #GError object to store error + * + * Use this method to populate corresponding #GdaDbFkey object from xml node. Usually, + * this method is called from #GdaDbCatalog during parsing the input xml file. + * + * The corresponding DTD section suitable for parsing by this method should correspond + * th the following code: + * + * |[ + * + * + * + * + * + * + * + * + * ]| + * + * Returns: %FALSE if an error occurs, %TRUE otherwise + * + * Since: 6.0 + */ +static gboolean +gda_db_fkey_parse_node (GdaDbBuildable *buildable, + xmlNodePtr node, + GError **error) +{ + g_return_val_if_fail (buildable, FALSE); + g_return_val_if_fail (node, FALSE); + + /* + * + * + * + * + */ + xmlChar *name = NULL; + if (g_strcmp0 ((gchar*)node->name, gdadbfkeynodes[GDA_DB_FKEY_NODE])) + return FALSE; + + GdaDbFkey *self = GDA_DB_FKEY (buildable); + GdaDbFkeyPrivate *priv = gda_db_fkey_get_instance_private (self); + + xmlChar *prop = NULL; + + prop = xmlGetProp (node, (xmlChar *)gdadbfkeynodes[GDA_DB_FKEY_REFTABLE]); + + g_assert (prop); /* Bug with xml valdation */ + + priv->mp_ref_table = g_strdup ((gchar *)prop); + xmlFree (prop); + prop = NULL; + + prop = xmlGetProp (node, (xmlChar *)gdadbfkeynodes[GDA_DB_FKEY_ONUPDATE]); + + if (prop) + { + priv->m_onupdate = GDA_DB_FKEY_NO_ACTION; + + for (guint i = 0; i < G_N_ELEMENTS(OnAction); i++) + { + if (!g_strcmp0 ((gchar *)prop, OnAction[i])) + priv->m_onupdate = (GdaDbFkeyReferenceAction)i; + } + + xmlFree (prop); + prop = NULL; + } + + prop = xmlGetProp (node, (xmlChar *)gdadbfkeynodes[GDA_DB_FKEY_ONDELETE]); + + if (prop) + { + for (guint i = 0; i < G_N_ELEMENTS(OnAction); i++) + { + if (!g_strcmp0 ((gchar *)prop, OnAction[i])) + priv->m_ondelete = (GdaDbFkeyReferenceAction)i; + } + + xmlFree (prop); + prop = NULL; + + } + + name = NULL; + xmlChar *reffield = NULL; + + for (xmlNodePtr it = node->children; it; it = it->next) + { + if (!g_strcmp0 ((gchar *)it->name, gdadbfkeynodes[GDA_DB_FKEY_FKFIELD])) + { + name = xmlGetProp (it, (xmlChar *)gdadbfkeynodes[GDA_DB_FKEY_FKFIELD_NAME]); + + g_assert(name); + priv->mp_field = g_list_append (priv->mp_field, g_strdup ((const gchar *)name)); + xmlFree (name); + + reffield = xmlGetProp (it, (xmlChar *)gdadbfkeynodes[GDA_DB_FKEY_FKFIELD_REFIELD]); + g_assert(reffield); + priv->mp_ref_field = g_list_append (priv->mp_ref_field, + g_strdup ((const gchar *)reffield)); + xmlFree (reffield); + } /* end of if */ + } /* end of for loop */ + return TRUE; +} + +/** + * gda_db_fkey_write_node: + * @self: An object #GdaDbFkey + * @writer: An object to #xmlTextWriterPtr instance + * @error: A place to store error + * + * An appropriate encoding and version should be placed to the writer before + * it is used. This method will not add any header, just populate appropriate + * fields in the xml tree. The new xml block should be something like: + * + * |[ + * + * + * + * + * + *]| + * Returns: TRUE if no error, FALSE otherwise + */ +static gboolean +gda_db_fkey_write_node (GdaDbBuildable *buildable, + xmlNodePtr rootnode, + GError **error) +{ + g_return_val_if_fail (buildable, FALSE); + g_return_val_if_fail (rootnode,FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + GdaDbFkey *self = GDA_DB_FKEY (buildable); + GdaDbFkeyPrivate *priv = gda_db_fkey_get_instance_private (self); + + xmlNodePtr node = NULL; + node = xmlNewChild (rootnode, NULL, (xmlChar*)gdadbfkeynodes[GDA_DB_FKEY_NODE], NULL); + + xmlNewProp (node, BAD_CAST gdadbfkeynodes[GDA_DB_FKEY_REFTABLE], + BAD_CAST priv->mp_ref_table); + + xmlNewProp (node, BAD_CAST gdadbfkeynodes[GDA_DB_FKEY_ONUPDATE], + BAD_CAST priv->m_onupdate); + + xmlNewProp (node, BAD_CAST gdadbfkeynodes[GDA_DB_FKEY_ONDELETE], + BAD_CAST priv->m_ondelete); + + GList *it = priv->mp_field; + GList *jt = priv->mp_ref_field; + + for (; it && jt; it = it->next, jt=jt->next ) + { + xmlNodePtr tnode = NULL; + tnode = xmlNewChild (node, NULL,(xmlChar*)gdadbfkeynodes[GDA_DB_FKEY_FKFIELD], NULL); + + xmlNewProp (tnode, (xmlChar*)gdadbfkeynodes[GDA_DB_FKEY_FKFIELD_NAME], + BAD_CAST it->data); + + xmlNewProp (tnode, (xmlChar*)gdadbfkeynodes[GDA_DB_FKEY_FKFIELD_REFIELD], + BAD_CAST jt->data); + } + + return TRUE; +} + +static void +gda_db_fkey_buildable_interface_init (GdaDbBuildableInterface *iface) +{ + iface->parse_node = gda_db_fkey_parse_node; + iface->write_node = gda_db_fkey_write_node; +} + +/** + * gda_db_fkey_get_ondelete: + * @self: An object #GdaDbFkey + * + * Return: ON DELETE action as a string. If the action is not set then the string corresponding to + * NO_ACTION is returned. + * + * Stability: Stable + * Since: 6.0 + */ +const gchar * +gda_db_fkey_get_ondelete (GdaDbFkey *self) +{ + g_return_val_if_fail (self, NULL); + + GdaDbFkeyPrivate *priv = gda_db_fkey_get_instance_private (self); + + return OnAction[priv->m_ondelete]; +} + +/** + * gda_db_fkey_get_ondelete_id: + * @self: a #GdaDbFkey object + * + * The default value is %NO_ACTION + * + * Return: ON DELETE action as a #GdaDbFkeyReferenceAction. + * + * Stability: Stable + * Since: 6.0 + */ +GdaDbFkeyReferenceAction +gda_db_fkey_get_ondelete_id (GdaDbFkey *self) +{ + g_return_val_if_fail (self, GDA_DB_FKEY_NO_ACTION); + + GdaDbFkeyPrivate *priv = gda_db_fkey_get_instance_private (self); + + return priv->m_ondelete; +} + +/** + * gda_db_fkey_set_onupdate: + * @self: An object #GdaDbFkey + * @id: #GdaDbFkeyReferenceAction action to set + * + * Set action for ON_UPDATE + * + * Stability: Stable + * Since: 6.0 + */ +void +gda_db_fkey_set_onupdate (GdaDbFkey *self, + GdaDbFkeyReferenceAction id) +{ + g_return_if_fail (self); + + GdaDbFkeyPrivate *priv = gda_db_fkey_get_instance_private (self); + + priv->m_onupdate = id; +} + +/** + * gda_db_fkey_set_ondelete: + * @self: An object #GdaDbFkey + * @id: #GdaDbFkeyReferenceAction action to set + * + * Set action for ON_DELETE + * + * Stability: Stable + * Since: 6.0 + */ +void +gda_db_fkey_set_ondelete (GdaDbFkey *self, + GdaDbFkeyReferenceAction id) +{ + g_return_if_fail (self); + + GdaDbFkeyPrivate *priv = gda_db_fkey_get_instance_private (self); + + priv->m_ondelete = id; +} + +/** + * gda_db_fkey_get_onupdate: + * @self: a #GdaDbFkey instance + * + * Returns: ON_UPDATE action as a string. Never %NULL + * + * Stability: Stable + * Since: 6.0 + */ +const gchar * +gda_db_fkey_get_onupdate (GdaDbFkey *self) +{ + g_return_val_if_fail (self, NULL); + + GdaDbFkeyPrivate *priv = gda_db_fkey_get_instance_private (self); + + return OnAction[priv->m_onupdate]; +} + +/** + * gda_db_fkey_get_onupdate_id: + * @self: a #GdaDbFkey instance + * + * Return: ON_UPDATE action as a #GdaDbFkeyReferenceAction + * + * Stability: Stable + * Since: 6.0 + */ +GdaDbFkeyReferenceAction +gda_db_fkey_get_onupdate_id (GdaDbFkey *self) +{ + GdaDbFkeyPrivate *priv = gda_db_fkey_get_instance_private (self); + + return priv->m_onupdate; +} + +/** + * gda_db_fkey_get_ref_table: + * @self: a #GdaDbFkey object + * + * Return: Returns reference table name as a string or %NULL if table name + * hasn't been set. + * + * Stability: Stable + * Since: 6.0 + */ +const gchar * +gda_db_fkey_get_ref_table (GdaDbFkey *self) +{ + g_return_val_if_fail (self, NULL); + + GdaDbFkeyPrivate *priv = gda_db_fkey_get_instance_private (self); + + return priv->mp_ref_table; +} + +/** + * gda_db_fkey_set_ref_table: + * @self: #GdaDbFkey object + * @rtable: reference table name + * + * Set reference table + * + * Stability: Stable + * Since: 6.0 + */ +void +gda_db_fkey_set_ref_table (GdaDbFkey *self, + const gchar *rtable) +{ + g_return_if_fail (self); + + GdaDbFkeyPrivate *priv = gda_db_fkey_get_instance_private (self); + g_free (priv->mp_ref_table); + + priv->mp_ref_table = g_strdup (rtable); +} + +/** + * gda_db_fkey_get_field_name: + * @self: a #GdaDbFkey object + * + * Returns: (element-type utf8) (transfer none): A const #GList of strings where each string + * corresponds to a foreign key field or %NULL. + * + * Stability: Stable + * Since: 6.0 + */ +const GList* +gda_db_fkey_get_field_name (GdaDbFkey *self) +{ + g_return_val_if_fail (self, NULL); + + GdaDbFkeyPrivate *priv = gda_db_fkey_get_instance_private (self); + + return priv->mp_field; +} + +/** + * gda_db_fkey_get_ref_field: + * @self: a #GdaDbFkey object + * + * Returns: (element-type utf8) (transfer none): A #GList of strings where each string corresponds + * to a foreign key reference field or %NULL. + * + * Stability: Stable + * Since: 6.0 + */ +const GList * +gda_db_fkey_get_ref_field (GdaDbFkey *self) +{ + g_return_val_if_fail (self, NULL); + + GdaDbFkeyPrivate *priv = gda_db_fkey_get_instance_private (self); + + return priv->mp_ref_field; +} + +/** + * gda_db_fkey_set_field: + * @self: An object #GdaDbFkey + * @field: Field name as a string + * @reffield: A reference field name as a string + * + * All arguments should be valid strings. + * + * Stability: Stable + * Since: 6.0 + */ +void +gda_db_fkey_set_field (GdaDbFkey *self, + const gchar *field, + const gchar *reffield) +{ + g_return_if_fail (self); + g_return_if_fail (field); + g_return_if_fail (reffield); + + GdaDbFkeyPrivate *priv = gda_db_fkey_get_instance_private (self); + + priv->mp_field = g_list_append (priv->mp_field, (gpointer)field); + priv->mp_ref_field = g_list_append(priv->mp_ref_field, (gpointer)reffield); +} + +/** + * gda_db_fkey_prepare_create: + * @self: a #GdaDbFkey instance + * @op: a #GdaServerOperation to populate + * @i: Order number + * @error: error container + * + * Prepare @op object for execution by populating with information stored in @self. + * + * Returns: %TRUE if no error or %FALSE otherwise. + * + * Stability: Stable + * Since: 6.0 + */ +gboolean +gda_db_fkey_prepare_create (GdaDbFkey *self, + GdaServerOperation *op, + gint i, + GError **error) +{ + GdaDbFkeyPrivate *priv = gda_db_fkey_get_instance_private (self); + + if (!gda_server_operation_set_value_at (op, + priv->mp_ref_table, + error, + "/FKEY_S/%d/FKEY_REF_TABLE", i)) + return FALSE; + + if (!gda_server_operation_set_value_at (op, + OnAction[priv->m_ondelete], + error, + "/FKEY_S/%d/FKEY_ONDELETE", i)) + return FALSE; + + if (!gda_server_operation_set_value_at (op, + OnAction[priv->m_onupdate], + error, + "/FKEY_S/%d/FKEY_ONUPDATE", i)) + return FALSE; + + GList *itfield = NULL; + GList *itreffield = NULL; + gint fkeycount = 0; + + itreffield = priv->mp_ref_field; + itfield = priv->mp_field; + + for (;itfield && itreffield;) + { + if (!gda_server_operation_set_value_at (op, + itfield->data, + error, + "/FKEY_S/%d/FKEY_FIELDS_A/@FK_FIELD/%d", + i, fkeycount)) + return FALSE; + + if (!gda_server_operation_set_value_at (op, + itreffield->data, + error, + "/FKEY_S/%d/FKEY_FIELDS_A/@FK_REF_PK_FIELD/%d", + i, fkeycount)) + return FALSE; + + fkeycount++; + + /* It will make for loop overloaded and hard to read. Therefore, + * advancement to the next element will be performed here. It is + * only one reason. + */ + itfield = itfield->next; + itreffield = itreffield->next; + } + + return TRUE; +} diff --git a/.flatpak-builder/cache/objects/89/6bdf885ed6689365e231c69437bce58355f262b42d6c161afdc2c527b30848.file b/.flatpak-builder/cache/objects/89/6bdf885ed6689365e231c69437bce58355f262b42d6c161afdc2c527b30848.file new file mode 100755 index 0000000..a50974e Binary files /dev/null and b/.flatpak-builder/cache/objects/89/6bdf885ed6689365e231c69437bce58355f262b42d6c161afdc2c527b30848.file differ diff --git a/.flatpak-builder/cache/objects/8a/09798704283756c64d6531dc7a772087191d2eac6971f1f2f4dce53d029bc7.file b/.flatpak-builder/cache/objects/8a/09798704283756c64d6531dc7a772087191d2eac6971f1f2f4dce53d029bc7.file new file mode 100755 index 0000000..0b715b0 --- /dev/null +++ b/.flatpak-builder/cache/objects/8a/09798704283756c64d6531dc7a772087191d2eac6971f1f2f4dce53d029bc7.file @@ -0,0 +1,41 @@ +# libcanberra-gtk3-module.la - a libtool library file +# Generated by libtool (GNU libtool) 2.4.2 +# +# Please DO NOT delete this file! +# It is necessary for linking the library. + +# The name that we can dlopen(3). +dlname='libcanberra-gtk3-module.so' + +# Names of this library. +library_names='libcanberra-gtk3-module.so libcanberra-gtk3-module.so libcanberra-gtk3-module.so' + +# The name of the static archive. +old_library='' + +# Linker flags that can not go in dependency_libs. +inherited_linker_flags=' -pthread' + +# Libraries that this one depends upon. +dependency_libs=' -L/app/lib /app/lib/libcanberra-gtk3.la -lX11 -lgthread-2.0 -lgtk-3 -latk-1.0 -lgio-2.0 -lharfbuzz -lgdk-3 -lz -lpangocairo-1.0 -lpango-1.0 -lgdk_pixbuf-2.0 -lcairo-gobject -lcairo -lgobject-2.0 -lglib-2.0 /app/lib/libcanberra.la -lvorbisfile -lltdl -lm' + +# Names of additional weak libraries provided by this library +weak_library_names='' + +# Version information for libcanberra-gtk3-module. +current=0 +age=0 +revision=0 + +# Is this an already installed library? +installed=yes + +# Should we warn about portability when linking against -modules? +shouldnotlink=yes + +# Files to dlopen/dlpreopen +dlopen='' +dlpreopen='' + +# Directory that this library needs to be installed in: +libdir='/app/lib/gtk-3.0/modules' diff --git a/.flatpak-builder/cache/objects/8a/19042b4232a202bcd58f5e82363e0f8de103b0c090aeb3287832a6f487ae79.dirtree b/.flatpak-builder/cache/objects/8a/19042b4232a202bcd58f5e82363e0f8de103b0c090aeb3287832a6f487ae79.dirtree new file mode 100644 index 0000000..6af8bd5 Binary files /dev/null and b/.flatpak-builder/cache/objects/8a/19042b4232a202bcd58f5e82363e0f8de103b0c090aeb3287832a6f487ae79.dirtree differ diff --git a/.flatpak-builder/cache/objects/8a/24d10ddd978030981a58d3a7a35165fab7b4794bd46e75f562cb4359b95780.file b/.flatpak-builder/cache/objects/8a/24d10ddd978030981a58d3a7a35165fab7b4794bd46e75f562cb4359b95780.file new file mode 120000 index 0000000..85b9a0a --- /dev/null +++ b/.flatpak-builder/cache/objects/8a/24d10ddd978030981a58d3a7a35165fab7b4794bd46e75f562cb4359b95780.file @@ -0,0 +1 @@ +../../share/runtime/locale/ne/share/ne \ No newline at end of file diff --git a/.flatpak-builder/cache/objects/8a/7207239516bc5e463aedb8de6a686c209585feaa72dea32a64c12813d914c8.dirtree b/.flatpak-builder/cache/objects/8a/7207239516bc5e463aedb8de6a686c209585feaa72dea32a64c12813d914c8.dirtree new file mode 100644 index 0000000..737aa34 Binary files /dev/null and b/.flatpak-builder/cache/objects/8a/7207239516bc5e463aedb8de6a686c209585feaa72dea32a64c12813d914c8.dirtree differ diff --git a/.flatpak-builder/cache/objects/8a/837f9e627b64f1696b91e6e79969c1bb4fbd7f2eb58545fb2458b6df010262.file b/.flatpak-builder/cache/objects/8a/837f9e627b64f1696b91e6e79969c1bb4fbd7f2eb58545fb2458b6df010262.file new file mode 100644 index 0000000..b8297c6 --- /dev/null +++ b/.flatpak-builder/cache/objects/8a/837f9e627b64f1696b91e6e79969c1bb4fbd7f2eb58545fb2458b6df010262.file @@ -0,0 +1,11 @@ +prefix=/app +exec_prefix=${prefix} +libdir=${exec_prefix}/lib +includedir=${prefix}/include + +Name: libcanberra-gtk3 +Description: Gtk3 Event Sound API +Version: 0.30 +Libs: -L${libdir} -lcanberra-gtk3 -lX11 +Cflags: -D_REENTRANT -I${includedir} +Requires: libcanberra gdk-3.0 gtk+-3.0 diff --git a/.flatpak-builder/cache/objects/8a/a7de17ca3f7ff1074acde72816b498560212ad5dede0de0eff85c29b78ea18.file b/.flatpak-builder/cache/objects/8a/a7de17ca3f7ff1074acde72816b498560212ad5dede0de0eff85c29b78ea18.file new file mode 100644 index 0000000..926bf56 --- /dev/null +++ b/.flatpak-builder/cache/objects/8a/a7de17ca3f7ff1074acde72816b498560212ad5dede0de0eff85c29b78ea18.file @@ -0,0 +1,137 @@ +/* gsound.vapi generated by vapigen, do not modify. */ + +[CCode (cprefix = "GSound", gir_namespace = "GSound", gir_version = "1.0", lower_case_cprefix = "gsound_")] +namespace GSound { + namespace Attribute { + [CCode (cheader_filename = "gsound.h", cname = "GSOUND_ATTR_APPLICATION_ICON")] + public const string APPLICATION_ICON; + [CCode (cheader_filename = "gsound.h", cname = "GSOUND_ATTR_APPLICATION_ICON_NAME")] + public const string APPLICATION_ICON_NAME; + [CCode (cheader_filename = "gsound.h", cname = "GSOUND_ATTR_APPLICATION_ID")] + public const string APPLICATION_ID; + [CCode (cheader_filename = "gsound.h", cname = "GSOUND_ATTR_APPLICATION_LANGUAGE")] + public const string APPLICATION_LANGUAGE; + [CCode (cheader_filename = "gsound.h", cname = "GSOUND_ATTR_APPLICATION_NAME")] + public const string APPLICATION_NAME; + [CCode (cheader_filename = "gsound.h", cname = "GSOUND_ATTR_APPLICATION_PROCESS_BINARY")] + public const string APPLICATION_PROCESS_BINARY; + [CCode (cheader_filename = "gsound.h", cname = "GSOUND_ATTR_APPLICATION_PROCESS_HOST")] + public const string APPLICATION_PROCESS_HOST; + [CCode (cheader_filename = "gsound.h", cname = "GSOUND_ATTR_APPLICATION_PROCESS_ID")] + public const string APPLICATION_PROCESS_ID; + [CCode (cheader_filename = "gsound.h", cname = "GSOUND_ATTR_APPLICATION_PROCESS_USER")] + public const string APPLICATION_PROCESS_USER; + [CCode (cheader_filename = "gsound.h", cname = "GSOUND_ATTR_APPLICATION_VERSION")] + public const string APPLICATION_VERSION; + [CCode (cheader_filename = "gsound.h", cname = "GSOUND_ATTR_CANBERRA_CACHE_CONTROL")] + public const string CANBERRA_CACHE_CONTROL; + [CCode (cheader_filename = "gsound.h", cname = "GSOUND_ATTR_CANBERRA_ENABLE")] + public const string CANBERRA_ENABLE; + [CCode (cheader_filename = "gsound.h", cname = "GSOUND_ATTR_CANBERRA_FORCE_CHANNEL")] + public const string CANBERRA_FORCE_CHANNEL; + [CCode (cheader_filename = "gsound.h", cname = "GSOUND_ATTR_CANBERRA_VOLUME")] + public const string CANBERRA_VOLUME; + [CCode (cheader_filename = "gsound.h", cname = "GSOUND_ATTR_CANBERRA_XDG_THEME_NAME")] + public const string CANBERRA_XDG_THEME_NAME; + [CCode (cheader_filename = "gsound.h", cname = "GSOUND_ATTR_CANBERRA_XDG_THEME_OUTPUT_PROFILE")] + public const string CANBERRA_XDG_THEME_OUTPUT_PROFILE; + [CCode (cheader_filename = "gsound.h", cname = "GSOUND_ATTR_EVENT_DESCRIPTION")] + public const string EVENT_DESCRIPTION; + [CCode (cheader_filename = "gsound.h", cname = "GSOUND_ATTR_EVENT_ID")] + public const string EVENT_ID; + [CCode (cheader_filename = "gsound.h", cname = "GSOUND_ATTR_EVENT_MOUSE_BUTTON")] + public const string EVENT_MOUSE_BUTTON; + [CCode (cheader_filename = "gsound.h", cname = "GSOUND_ATTR_EVENT_MOUSE_HPOS")] + public const string EVENT_MOUSE_HPOS; + [CCode (cheader_filename = "gsound.h", cname = "GSOUND_ATTR_EVENT_MOUSE_VPOS")] + public const string EVENT_MOUSE_VPOS; + [CCode (cheader_filename = "gsound.h", cname = "GSOUND_ATTR_EVENT_MOUSE_X")] + public const string EVENT_MOUSE_X; + [CCode (cheader_filename = "gsound.h", cname = "GSOUND_ATTR_EVENT_MOUSE_Y")] + public const string EVENT_MOUSE_Y; + [CCode (cheader_filename = "gsound.h", cname = "GSOUND_ATTR_MEDIA_ARTIST")] + public const string MEDIA_ARTIST; + [CCode (cheader_filename = "gsound.h", cname = "GSOUND_ATTR_MEDIA_FILENAME")] + public const string MEDIA_FILENAME; + [CCode (cheader_filename = "gsound.h", cname = "GSOUND_ATTR_MEDIA_ICON")] + public const string MEDIA_ICON; + [CCode (cheader_filename = "gsound.h", cname = "GSOUND_ATTR_MEDIA_ICON_NAME")] + public const string MEDIA_ICON_NAME; + [CCode (cheader_filename = "gsound.h", cname = "GSOUND_ATTR_MEDIA_LANGUAGE")] + public const string MEDIA_LANGUAGE; + [CCode (cheader_filename = "gsound.h", cname = "GSOUND_ATTR_MEDIA_NAME")] + public const string MEDIA_NAME; + [CCode (cheader_filename = "gsound.h", cname = "GSOUND_ATTR_MEDIA_ROLE")] + public const string MEDIA_ROLE; + [CCode (cheader_filename = "gsound.h", cname = "GSOUND_ATTR_MEDIA_TITLE")] + public const string MEDIA_TITLE; + [CCode (cheader_filename = "gsound.h", cname = "GSOUND_ATTR_WINDOW_DESKTOP")] + public const string WINDOW_DESKTOP; + [CCode (cheader_filename = "gsound.h", cname = "GSOUND_ATTR_WINDOW_HEIGHT")] + public const string WINDOW_HEIGHT; + [CCode (cheader_filename = "gsound.h", cname = "GSOUND_ATTR_WINDOW_HPOS")] + public const string WINDOW_HPOS; + [CCode (cheader_filename = "gsound.h", cname = "GSOUND_ATTR_WINDOW_ICON")] + public const string WINDOW_ICON; + [CCode (cheader_filename = "gsound.h", cname = "GSOUND_ATTR_WINDOW_ICON_NAME")] + public const string WINDOW_ICON_NAME; + [CCode (cheader_filename = "gsound.h", cname = "GSOUND_ATTR_WINDOW_ID")] + public const string WINDOW_ID; + [CCode (cheader_filename = "gsound.h", cname = "GSOUND_ATTR_WINDOW_NAME")] + public const string WINDOW_NAME; + [CCode (cheader_filename = "gsound.h", cname = "GSOUND_ATTR_WINDOW_VPOS")] + public const string WINDOW_VPOS; + [CCode (cheader_filename = "gsound.h", cname = "GSOUND_ATTR_WINDOW_WIDTH")] + public const string WINDOW_WIDTH; + [CCode (cheader_filename = "gsound.h", cname = "GSOUND_ATTR_WINDOW_X")] + public const string WINDOW_X; + [CCode (cheader_filename = "gsound.h", cname = "GSOUND_ATTR_WINDOW_X11_DISPLAY")] + public const string WINDOW_X11_DISPLAY; + [CCode (cheader_filename = "gsound.h", cname = "GSOUND_ATTR_WINDOW_X11_MONITOR")] + public const string WINDOW_X11_MONITOR; + [CCode (cheader_filename = "gsound.h", cname = "GSOUND_ATTR_WINDOW_X11_SCREEN")] + public const string WINDOW_X11_SCREEN; + [CCode (cheader_filename = "gsound.h", cname = "GSOUND_ATTR_WINDOW_X11_XID")] + public const string WINDOW_X11_XID; + [CCode (cheader_filename = "gsound.h", cname = "GSOUND_ATTR_WINDOW_Y")] + public const string WINDOW_Y; + } + [CCode (cheader_filename = "gsound.h", type_id = "gsound_context_get_type ()")] + public class Context : GLib.Object, GLib.Initable { + [CCode (has_construct_function = false)] + public Context (GLib.Cancellable? cancellable = null) throws GLib.Error; + public bool cache (...) throws GLib.Error; + public bool cachev (GLib.HashTable attrs) throws GLib.Error; + public bool open () throws GLib.Error; + public async bool play_full (GLib.Cancellable? cancellable, ...) throws GLib.Error; + [CCode (finish_name = "gsound_context_play_full_finish")] + public async bool play_fullv (GLib.HashTable attrs, GLib.Cancellable? cancellable) throws GLib.Error; + public bool play_simple (GLib.Cancellable? cancellable = null, ...) throws GLib.Error; + public bool play_simplev (GLib.HashTable attrs, GLib.Cancellable? cancellable = null) throws GLib.Error; + public bool set_attributes (...) throws GLib.Error; + public bool set_attributesv (GLib.HashTable attrs) throws GLib.Error; + public bool set_driver (string driver) throws GLib.Error; + } + [CCode (cheader_filename = "gsound.h", cprefix = "GSOUND_ERROR_", has_type_id = false)] + public errordomain Error { + NOTSUPPORTED, + INVALID, + STATE, + OOM, + NODRIVER, + SYSTEM, + CORRUPT, + TOOBIG, + NOTFOUND, + DESTROYED, + CANCELED, + NOTAVAILABLE, + ACCESS, + IO, + INTERNAL, + DISABLED, + FORKED, + DISCONNECTED; + public static GLib.Quark quark (); + } +} diff --git a/.flatpak-builder/cache/objects/8a/b12952c06e156f4909674fdc5866f37ac8bf98248259c5385705a193d9436c.file b/.flatpak-builder/cache/objects/8a/b12952c06e156f4909674fdc5866f37ac8bf98248259c5385705a193d9436c.file new file mode 100644 index 0000000..dd1569e --- /dev/null +++ b/.flatpak-builder/cache/objects/8a/b12952c06e156f4909674fdc5866f37ac8bf98248259c5385705a193d9436c.file @@ -0,0 +1,91 @@ +.TH INTLTOOL-EXTRACT 8 "2003-08-02" "intltool" + +.SH NAME +intltool-extract \- generate header files which can be read by gettext + +.SH SYNOPSIS +.B intltool-extract +.I "[options]..." SOURCE_FILE + + +.SH DESCRIPTION +.B intltool-extract +extracts strings in the specified XML/INI type \fISOURCE_FILE\fR and writes +them into a C header file. Then \fBxgettext\fR(1) can merge these strings +inside header file into po template. + +.B intltool-extract +is usually not executed manually, but called from \fBintltool-update\fR(8) +instead. + +.SH OPTIONS +.IP "\fB\-l\fR" 4 +.PD 0 +.IP "\fB\-\-local\fR" 4 +.PD +Creates a subdirectory under current working directory (named "\fBtmp/\fR") +and writes files there. This option can't be used with \fB\-\-update\fR option. +.IP "\fB\-\-update\fR" 4 +.PD +Writes header file into the same directory the source file is in. New file +name is the source file name appending ".h" extension. This option can't be +used with +.BR \-l / \-\-local +option. Besides, this option is the default option if neither \fB\-\-local\fR +nor \fB\-\-update\fR is specified. +.IP "\fB\-\-type\fR=\fITYPE\fR" 4 +.PD +Specify the type of source file. Currently supported types are: +.br +"gettext/glade" (.glade, .glade2) +.br +"gettext/gsettings" (.gschema.xml) +.br +"gettext/ini" (Generic INI file) +.br +"gettext/keys" (.keys) +.br +"gettext/rfc822deb" (RFC 822 format file) +.br +"gettext/quoted" (all strings within "") +.br +"gettext/schemas" (.schemas) +.br +"gettext/scheme" (.scm) +.br +"gettext/xml" (Generic XML file) +.br +"gettext/qtdesigner" (Qt Designer .ui files) +.IP "\fB\-v\fR" 4 +.PD 0 +.IP "\fB\-\-version\fR" 4 +.PD +Show version information. +.IP "\fB\-h\fR" 4 +.PD 0 +.IP "\fB\--help\fR" 4 +.PD +Show usage and basic help information. +.IP "\fB\-q\fR" 4 +.PD 0 +.IP "\fB\-\-quiet\fR" 4 +.PD +Be quiet while running. + +.SH REPORTING BUGS +Report bugs to http://bugs.launchpad.net/intltool + +.SH AUTHOR +Darin Adler +.br +Kenneth Christiansen +.br +Maciej Stachowiak + + +.SH SEE ALSO +.BR intltoolize (8), +.BR intltool-prepare (8), +.BR intltool-merge (8), +.BR intltool-update (8), +.BR xgettext (1) diff --git a/.flatpak-builder/cache/objects/8b/01622589f8896a09c0abf0e581c8c4fb1fdb8b3568fe1c21b9bdaaadc6c6d6.file b/.flatpak-builder/cache/objects/8b/01622589f8896a09c0abf0e581c8c4fb1fdb8b3568fe1c21b9bdaaadc6c6d6.file new file mode 100644 index 0000000..1d50290 --- /dev/null +++ b/.flatpak-builder/cache/objects/8b/01622589f8896a09c0abf0e581c8c4fb1fdb8b3568fe1c21b9bdaaadc6c6d6.file @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2000 Reinhard Müller + * Copyright (C) 2000 - 2002 Rodrigo Moya + * Copyright (C) 2001 Carlos Perelló Marín + * Copyright (C) 2001 - 2012 Vivien Malerba + * Copyright (C) 2002 Gonzalo Paniagua Javier + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GDA_VCONNECTION_DATA_MODEL_PRIVATE_H__ +#define __GDA_VCONNECTION_DATA_MODEL_PRIVATE_H__ + +G_BEGIN_DECLS + +typedef enum { + PARAMS_INSERT, + PARAMS_UPDATE, + PARAMS_DELETE, + PARAMS_NB +} ParamType; + +typedef struct GdaVConnectionTableData GdaVConnectionTableData; +typedef struct VContext VContext; +typedef struct ExecContext ExecContext; +typedef struct VirtualFilteredData VirtualFilteredData; + +struct VContext{ + GWeakRef context_object; + GPtrArray *context_data; + GdaVConnectionTableData *vtable; +}; + +struct ExecContext { + VContext *current_vcontext; + GMutex *mutex; + GHashTable *hash; /* key = a GObject, value = a VContext where @context_object == key */ +}; + +/* + * This structure holds data to be used by a virtual cursor, for a specific filter, + * it keeps track of data which has been assigned a rowID + */ +struct VirtualFilteredData { + /* status */ + guint8 refcount; + gboolean reuseable; + + /* filter */ + int idxNum; + char *idxStr; + int argc; + GValue **argv; + + /* row numbers offset */ + guint32 rowid_offset; + + /* data */ + GdaDataModel *model; + GdaDataModelIter *iter; /* not NULL while nrows == -1 */ + GPtrArray *values_array; + gint ncols; + gint nrows; /* -1 until known */ +}; + +struct GdaVConnectionTableData { + GdaVconnectionDataModelSpec *spec; + GDestroyNotify spec_free_func; + + GdaDataModel *real_model; /* data model really being used, a reference is kept */ + GList *columns; + gchar *table_name; + gchar *unique_name; + gint n_columns; + + GdaStatement *modif_stmt[PARAMS_NB]; + GdaSet *modif_params[PARAMS_NB]; + + ExecContext context; /* not a pointer! */ +}; + + +void _gda_vconnection_virtual_filtered_data_unref (VirtualFilteredData *data); + +void _gda_vconnection_data_model_table_data_free (GdaVConnectionTableData *td); + +GdaVConnectionTableData *_gda_vconnection_get_table_data_by_name (GdaVconnectionDataModel *cnc, const gchar *table_name); +GdaVConnectionTableData *_gda_vconnection_get_table_data_by_model (GdaVconnectionDataModel *cnc, GdaDataModel *model); +GdaVConnectionTableData *_gda_vconnection_get_table_data_by_unique_name (GdaVconnectionDataModel *cnc, const gchar *unique_name); + +void _gda_vconnection_set_working_obj (GdaVconnectionDataModel *cnc, GObject *obj); +void _gda_vconnection_change_working_obj (GdaVconnectionDataModel *cnc, GObject *obj); + +G_END_DECLS + +#endif diff --git a/.flatpak-builder/cache/objects/8b/b189c13439fa78b67d9c5acbf14cf2c1a7d3e80c1167638a2d88a992be168a.dirtree b/.flatpak-builder/cache/objects/8b/b189c13439fa78b67d9c5acbf14cf2c1a7d3e80c1167638a2d88a992be168a.dirtree new file mode 100644 index 0000000..a184092 Binary files /dev/null and b/.flatpak-builder/cache/objects/8b/b189c13439fa78b67d9c5acbf14cf2c1a7d3e80c1167638a2d88a992be168a.dirtree differ diff --git a/.flatpak-builder/cache/objects/8b/fda8d0b69fca20cbedd681575fb679fb66e3857485d4ccfcfe015b264e29ec.file b/.flatpak-builder/cache/objects/8b/fda8d0b69fca20cbedd681575fb679fb66e3857485d4ccfcfe015b264e29ec.file new file mode 100644 index 0000000..b187433 --- /dev/null +++ b/.flatpak-builder/cache/objects/8b/fda8d0b69fca20cbedd681575fb679fb66e3857485d4ccfcfe015b264e29ec.file @@ -0,0 +1,470 @@ +/* + * Copyright (C) 2008 - 2010 Murray Cumming + * Copyright (C) 2008 - 2012 Vivien Malerba + * Copyright (C) 2009 Bas Driessen + * Copyright (C) 2010 David King + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include +#include +#include +#include +#include +#include + +static gpointer gda_sql_statement_select_new (void); +static gboolean gda_sql_statement_select_check_structure (GdaSqlAnyPart *stmt, gpointer data, GError **error); +static gboolean gda_sql_statement_select_check_validity (GdaSqlAnyPart *stmt, gpointer data, GError **error); + +GdaSqlStatementContentsInfo select_infos = { + GDA_SQL_STATEMENT_SELECT, + "SELECT", + gda_sql_statement_select_new, + _gda_sql_statement_select_free, + _gda_sql_statement_select_copy, + _gda_sql_statement_select_serialize, + + gda_sql_statement_select_check_structure, + gda_sql_statement_select_check_validity, + NULL, + NULL, + NULL, + NULL +}; + +GdaSqlStatementContentsInfo * +_gda_sql_statement_select_get_infos (void) +{ + return &select_infos; +} + +static gpointer +gda_sql_statement_select_new (void) +{ + GdaSqlStatementSelect *stmt; + stmt = g_new0 (GdaSqlStatementSelect, 1); + GDA_SQL_ANY_PART (stmt)->type = GDA_SQL_ANY_STMT_SELECT; + return (gpointer) stmt; +} + +void +_gda_sql_statement_select_free (gpointer stmt) +{ + GdaSqlStatementSelect *select = (GdaSqlStatementSelect *) stmt; + + if (select->distinct_expr) + gda_sql_expr_free (select->distinct_expr); + if (select->expr_list) { + g_slist_free_full (select->expr_list, (GDestroyNotify) gda_sql_select_field_free); + } + gda_sql_select_from_free (select->from); + gda_sql_expr_free (select->where_cond); + if (select->group_by) { + g_slist_free_full (select->group_by, (GDestroyNotify) gda_sql_expr_free); + } + gda_sql_expr_free (select->having_cond); + if (select->order_by) { + g_slist_free_full (select->order_by, (GDestroyNotify) gda_sql_select_order_free); + } + gda_sql_expr_free (select->limit_count); + gda_sql_expr_free (select->limit_offset); + g_free (select); +} + +gpointer +_gda_sql_statement_select_copy (gpointer src) +{ + GdaSqlStatementSelect *dest; + GdaSqlStatementSelect *select = (GdaSqlStatementSelect *) src; + GSList *list; + + dest = gda_sql_statement_select_new (); + dest->distinct = select->distinct; + + dest->distinct_expr = gda_sql_expr_copy (select->distinct_expr); + gda_sql_any_part_set_parent (dest->distinct_expr, dest); + + for (list = select->expr_list; list; list = list->next) { + dest->expr_list = g_slist_prepend (dest->expr_list, + gda_sql_select_field_copy ((GdaSqlSelectField*) list->data)); + gda_sql_any_part_set_parent (dest->expr_list->data, dest); + } + dest->expr_list = g_slist_reverse (dest->expr_list); + + dest->from = gda_sql_select_from_copy (select->from); + gda_sql_any_part_set_parent (dest->from, dest); + + dest->where_cond = gda_sql_expr_copy (select->where_cond); + gda_sql_any_part_set_parent (dest->where_cond, dest); + + for (list = select->group_by; list; list = list->next) { + dest->group_by = g_slist_prepend (dest->group_by, + gda_sql_expr_copy ((GdaSqlExpr*) list->data)); + gda_sql_any_part_set_parent (dest->group_by->data, dest); + } + dest->group_by = g_slist_reverse (dest->group_by); + + dest->having_cond = gda_sql_expr_copy (select->having_cond); + gda_sql_any_part_set_parent (dest->having_cond, dest); + + for (list = select->order_by; list; list = list->next) { + dest->order_by = g_slist_prepend (dest->order_by, + gda_sql_select_order_copy ((GdaSqlSelectOrder*) list->data)); + gda_sql_any_part_set_parent (dest->order_by->data, dest); + } + dest->order_by = g_slist_reverse (dest->order_by); + + dest->limit_count = gda_sql_expr_copy (select->limit_count); + gda_sql_any_part_set_parent (dest->limit_count, dest); + + dest->limit_offset = gda_sql_expr_copy (select->limit_offset); + gda_sql_any_part_set_parent (dest->limit_offset, dest); + + return dest; +} + +gchar * +_gda_sql_statement_select_serialize (gpointer stmt) +{ + GString *string; + gchar *str; + GSList *list; + GdaSqlStatementSelect *select = (GdaSqlStatementSelect *) stmt; + + g_return_val_if_fail (stmt, NULL); + + string = g_string_new ("\"contents\":{"); + /* distinct */ + g_string_append (string, "\"distinct\":"); + g_string_append (string, select->distinct ? "\"true\"" : "\"false\""); + if (select->distinct_expr) { + g_string_append (string, ",\"distinct_on\":"); + str = gda_sql_expr_serialize (select->distinct_expr); + g_string_append (string, str); + g_free (str); + } + g_string_append (string, ",\"fields\":"); + if (select->expr_list) { + g_string_append_c (string, '['); + for (list = select->expr_list; list; list = list->next) { + if (list != select->expr_list) + g_string_append_c (string, ','); + str = gda_sql_select_field_serialize ((GdaSqlSelectField*) list->data); + g_string_append (string, str); + g_free (str); + } + g_string_append_c (string, ']'); + } + else + g_string_append (string, "null"); + + if (select->from) { + g_string_append (string, ",\"from\":"); + str = gda_sql_select_from_serialize (select->from); + g_string_append (string, str); + g_free (str); + } + + if (select->where_cond) { + g_string_append (string, ",\"where\":"); + str = gda_sql_expr_serialize (select->where_cond); + g_string_append (string, str); + g_free (str); + } + + if (select->group_by) { + g_string_append (string, ",\"group_by\":"); + g_string_append_c (string, '['); + for (list = select->group_by; list; list = list->next) { + if (list != select->group_by) + g_string_append_c (string, ','); + str = gda_sql_expr_serialize ((GdaSqlExpr*) list->data); + g_string_append (string, str); + g_free (str); + } + g_string_append_c (string, ']'); + } + + if (select->having_cond) { + g_string_append (string, ",\"having\":"); + str = gda_sql_expr_serialize (select->having_cond); + g_string_append (string, str); + g_free (str); + } + + if (select->order_by) { + g_string_append (string, ",\"order_by\":"); + g_string_append_c (string, '['); + for (list = select->order_by; list; list = list->next) { + if (list != select->order_by) + g_string_append_c (string, ','); + str = gda_sql_select_order_serialize ((GdaSqlSelectOrder*) list->data); + g_string_append (string, str); + g_free (str); + } + g_string_append_c (string, ']'); + } + + if (select->limit_count) { + g_string_append (string, ",\"limit\":"); + str = gda_sql_expr_serialize (select->limit_count); + g_string_append (string, str); + g_free (str); + + if (select->limit_offset) { + g_string_append (string, ",\"offset\":"); + str = gda_sql_expr_serialize (select->limit_offset); + g_string_append (string, str); + g_free (str); + } + } + + g_string_append_c (string, '}'); + str = string->str; + g_string_free (string, FALSE); + return str; +} + +/** + * gda_sql_statement_select_take_distinct: + * @stmt: a #GdaSqlStatement pointer + * @distinct: a TRUE/FALSE value + * @distinct_expr: (nullable): a #GdaSqlExpr pointer representing what the DISTINCT is on, or %NULL + * + * Sets the DISTINCT clause of @stmt. + * + * @distinct_expr's ownership is transferred to + * @stmt (which means @stmt is then responsible for freeing it when no longer needed). + */ +void +gda_sql_statement_select_take_distinct (GdaSqlStatement *stmt, gboolean distinct, GdaSqlExpr *distinct_expr) +{ + GdaSqlStatementSelect *select = (GdaSqlStatementSelect *) stmt->contents; + select->distinct = distinct; + select->distinct_expr = distinct_expr; + gda_sql_any_part_set_parent (select->distinct_expr, select); +} + +/** + * gda_sql_statement_select_take_expr_list: + * @stmt: a #GdaSqlStatement pointer + * @expr_list: (element-type Gda.SqlSelectField): a list of #GdaSqlSelectField pointers + * + * Sets list of expressions selected by @stmt + * + * @expr_list's ownership is transferred to + * @stmt (which means @stmt is then responsible for freeing it when no longer needed). + */ +void +gda_sql_statement_select_take_expr_list (GdaSqlStatement *stmt, GSList *expr_list) +{ + GSList *l; + GdaSqlStatementSelect *select = (GdaSqlStatementSelect *) stmt->contents; + select->expr_list = expr_list; + for (l = expr_list; l; l = l->next) + gda_sql_any_part_set_parent (l->data, select); +} + +/** + * gda_sql_statement_select_take_from: + * @stmt: a #GdaSqlStatement pointer + * @from: a #GdaSqlSelectFrom pointer + * + * Sets the FROM clause of @stmt + * + * @from's ownership is transferred to + * @stmt (which means @stmt is then responsible for freeing it when no longer needed). + */ +void +gda_sql_statement_select_take_from (GdaSqlStatement *stmt, GdaSqlSelectFrom *from) +{ + GdaSqlStatementSelect *select = (GdaSqlStatementSelect *) stmt->contents; + select->from = from; + gda_sql_any_part_set_parent (from, select); +} + +/** + * gda_sql_statement_select_take_where_cond: + * @stmt: a #GdaSqlStatement pointer + * @expr: a #GdaSqlExpr pointer + * + * Sets the WHERE clause of @stmt + * + * @expr's ownership is transferred to + * @stmt (which means @stmt is then responsible for freeing it when no longer needed). + */ +void +gda_sql_statement_select_take_where_cond (GdaSqlStatement *stmt, GdaSqlExpr *expr) +{ + GdaSqlStatementSelect *select = (GdaSqlStatementSelect *) stmt->contents; + select->where_cond = expr; + gda_sql_any_part_set_parent (expr, select); +} + +/** + * gda_sql_statement_select_take_group_by: + * @stmt: a #GdaSqlStatement pointer + * @group_by: (element-type GdaSqlExpr): a list of #GdaSqlExpr pointer + * + * Sets the GROUP BY clause of @stmt + * + * @group_by's ownership is transferred to + * @stmt (which means @stmt is then responsible for freeing it when no longer needed). + */ +void +gda_sql_statement_select_take_group_by (GdaSqlStatement *stmt, GSList *group_by) +{ + GSList *l; + GdaSqlStatementSelect *select = (GdaSqlStatementSelect *) stmt->contents; + select->group_by = group_by; + for (l = group_by; l; l = l->next) + gda_sql_any_part_set_parent (l->data, select); +} + +/** + * gda_sql_statement_select_take_having_cond: + * @stmt: a #GdaSqlStatement pointer + * @expr: a #GdaSqlExpr pointer + * + * Sets the HAVING clause of @stmt + * + * @expr's ownership is transferred to + * @stmt (which means @stmt is then responsible for freeing it when no longer needed). + */ +void +gda_sql_statement_select_take_having_cond (GdaSqlStatement *stmt, GdaSqlExpr *expr) +{ + GdaSqlStatementSelect *select = (GdaSqlStatementSelect *) stmt->contents; + select->having_cond = expr; + gda_sql_any_part_set_parent (expr, select); +} + +/** + * gda_sql_statement_select_take_order_by: + * @stmt: a #GdaSqlStatement pointer + * @order_by: (element-type GdaSqlSelectOrder): a list of #GdaSqlSelectOrder pointer + * + * Sets the ORDER BY clause of @stmt + * + * @order_by's ownership is transferred to + * @stmt (which means @stmt is then responsible for freeing it when no longer needed). + */ +void +gda_sql_statement_select_take_order_by (GdaSqlStatement *stmt, GSList *order_by) +{ + GSList *l; + GdaSqlStatementSelect *select = (GdaSqlStatementSelect *) stmt->contents; + select->order_by = order_by; + for (l = order_by; l; l = l->next) + gda_sql_any_part_set_parent (l->data, select); +} + +/** + * gda_sql_statement_select_take_limits: + * @stmt: a #GdaSqlStatement pointer + * @count: a #GdaSqlExpr pointer + * @offset: a #GdaSqlExpr pointer + * + * Sets the LIMIT clause of @stmt + * + * @count and @offset's responsibility are transferred to + * @stmt (which means @stmt is then responsible for freeing them when no longer needed). + */ +void +gda_sql_statement_select_take_limits (GdaSqlStatement *stmt, GdaSqlExpr *count, GdaSqlExpr *offset) +{ + GdaSqlStatementSelect *select = (GdaSqlStatementSelect *) stmt->contents; + select->limit_count = count; + gda_sql_any_part_set_parent (count, select); + select->limit_offset = offset; + gda_sql_any_part_set_parent (offset, select); +} + +static gboolean +gda_sql_statement_select_check_structure (GdaSqlAnyPart *stmt, G_GNUC_UNUSED gpointer data, GError **error) +{ + GdaSqlStatementSelect *select = (GdaSqlStatementSelect *) stmt; + if (!select->expr_list) { + g_set_error (error, GDA_SQL_ERROR, GDA_SQL_STRUCTURE_CONTENTS_ERROR, + "%s", _("SELECT does not contain any expression")); + return FALSE; + } + + if (select->distinct_expr && !select->distinct) { + g_set_error (error, GDA_SQL_ERROR, GDA_SQL_STRUCTURE_CONTENTS_ERROR, + "%s", _("SELECT can't have a DISTINCT expression if DISTINCT is not set")); + return FALSE; + } + + if (select->having_cond && !select->group_by) { + g_set_error (error, GDA_SQL_ERROR, GDA_SQL_STRUCTURE_CONTENTS_ERROR, + "%s", _("SELECT can't have a HAVING without GROUP BY")); + return FALSE; + } + + if (select->limit_offset && !select->limit_count) { + g_set_error (error, GDA_SQL_ERROR, GDA_SQL_STRUCTURE_CONTENTS_ERROR, + "%s", _("SELECT can't have a limit offset without a limit")); + return FALSE; + } + return TRUE; +} + +static gboolean +gda_sql_statement_select_check_validity (GdaSqlAnyPart *stmt, G_GNUC_UNUSED gpointer data, GError **error) +{ + GdaSqlStatementSelect *select = (GdaSqlStatementSelect *) stmt; + gboolean retval = TRUE; + + /* validate target's names and aliases: + * - there can't be 2 targets with the same alias + * - each target name or alias can only reference at most one target + */ + if (select->from && select->from->targets) { + GHashTable *hash; /* key = target name or alias, value = GdaSqlSelectTarget pointer */ + GSList *list; + hash = g_hash_table_new (g_str_hash, g_str_equal); + for (list = select->from->targets; list; list = list->next) { + GdaSqlSelectTarget *t = (GdaSqlSelectTarget*) list->data; + if (t->as) { + if (g_hash_table_lookup (hash, t->as)) { + g_set_error (error, GDA_SQL_ERROR, GDA_SQL_VALIDATION_ERROR, + _("Multiple targets named or aliased '%s'"), t->as); + retval = FALSE; + break; + } + g_hash_table_insert (hash, t->as, t); + } + else if (t->table_name) { + if (g_hash_table_lookup (hash, t->table_name)) { + g_set_error (error, GDA_SQL_ERROR, GDA_SQL_VALIDATION_ERROR, + _("Multiple targets named or aliased '%s'"), t->table_name); + retval = FALSE; + break; + } + g_hash_table_insert (hash, t->table_name, t); + } + + if (!retval) + break; + } + g_hash_table_destroy (hash); + } + + return retval; +} diff --git a/.flatpak-builder/cache/objects/8c/003bdcafde1362f20e17e779a347388bf865abc9a9bf06fe62afb1894de42e.dirtree b/.flatpak-builder/cache/objects/8c/003bdcafde1362f20e17e779a347388bf865abc9a9bf06fe62afb1894de42e.dirtree new file mode 100644 index 0000000..b99cbdd Binary files /dev/null and b/.flatpak-builder/cache/objects/8c/003bdcafde1362f20e17e779a347388bf865abc9a9bf06fe62afb1894de42e.dirtree differ diff --git a/.flatpak-builder/cache/objects/8c/1ed0bc7a88fb681b7a74fa8c6d3803805f6cef518b33afb8db3d5fe145efdc.file b/.flatpak-builder/cache/objects/8c/1ed0bc7a88fb681b7a74fa8c6d3803805f6cef518b33afb8db3d5fe145efdc.file new file mode 120000 index 0000000..5660269 --- /dev/null +++ b/.flatpak-builder/cache/objects/8c/1ed0bc7a88fb681b7a74fa8c6d3803805f6cef518b33afb8db3d5fe145efdc.file @@ -0,0 +1 @@ +../../share/runtime/locale/eu/share/eu \ No newline at end of file diff --git a/.flatpak-builder/cache/objects/8c/464c62f82966286fe36d854b557e5777b74d93d94a96fecf3ac5c9a648598b.dirtree b/.flatpak-builder/cache/objects/8c/464c62f82966286fe36d854b557e5777b74d93d94a96fecf3ac5c9a648598b.dirtree new file mode 100644 index 0000000..7a1bc32 Binary files /dev/null and b/.flatpak-builder/cache/objects/8c/464c62f82966286fe36d854b557e5777b74d93d94a96fecf3ac5c9a648598b.dirtree differ diff --git a/.flatpak-builder/cache/objects/8c/b73321c6cca18ef0c0ffe507bc56de508f89d5ab839183debcd96d5e6ddc08.file b/.flatpak-builder/cache/objects/8c/b73321c6cca18ef0c0ffe507bc56de508f89d5ab839183debcd96d5e6ddc08.file new file mode 100644 index 0000000..edef840 --- /dev/null +++ b/.flatpak-builder/cache/objects/8c/b73321c6cca18ef0c0ffe507bc56de508f89d5ab839183debcd96d5e6ddc08.file @@ -0,0 +1,44 @@ +# parser.py +# +# Copyright 2021 James Westman +# +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation; either version 3 of the +# License, or (at your option) any later version. +# +# This file is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program. If not, see . +# +# SPDX-License-Identifier: LGPL-3.0-or-later + + +from .errors import MultipleErrors, PrintableError +from .parse_tree import * +from .tokenizer import TokenType +from .language import OBJECT_CONTENT_HOOKS, Template, UI + + +def parse( + tokens: T.List[Token], +) -> T.Tuple[T.Optional[UI], T.Optional[MultipleErrors], T.List[PrintableError]]: + """Parses a list of tokens into an abstract syntax tree.""" + + try: + ctx = ParseContext(tokens) + AnyOf(UI).parse(ctx) + ast_node = ctx.last_group.to_ast() if ctx.last_group else None + + errors = [*ctx.errors, *ast_node.errors] + warnings = [*ctx.warnings, *ast_node.warnings] + + return (ast_node, MultipleErrors(errors) if len(errors) else None, warnings) + except MultipleErrors as e: + return (None, e, []) + except CompileError as e: + return (None, MultipleErrors([e]), []) diff --git a/.flatpak-builder/cache/objects/8c/bb68c31d5beae8a829cfae0ae86d8efae442a544303ebeb6098ec9fd920d7f.dirtree b/.flatpak-builder/cache/objects/8c/bb68c31d5beae8a829cfae0ae86d8efae442a544303ebeb6098ec9fd920d7f.dirtree new file mode 100644 index 0000000..5867465 Binary files /dev/null and b/.flatpak-builder/cache/objects/8c/bb68c31d5beae8a829cfae0ae86d8efae442a544303ebeb6098ec9fd920d7f.dirtree differ diff --git a/.flatpak-builder/cache/objects/8d/077d28e9f259fb177dbc3e8bb5dd275890a487ca0d575a1a88333a749fa12f.file b/.flatpak-builder/cache/objects/8d/077d28e9f259fb177dbc3e8bb5dd275890a487ca0d575a1a88333a749fa12f.file new file mode 100644 index 0000000..f18f13d --- /dev/null +++ b/.flatpak-builder/cache/objects/8d/077d28e9f259fb177dbc3e8bb5dd275890a487ca0d575a1a88333a749fa12f.file @@ -0,0 +1,722 @@ +/*-*- Mode: C; c-basic-offset: 8 -*-*/ + +/*** + This file is part of libcanberra. + + Copyright 2008 Lennart Poettering + + libcanberra is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation, either version 2.1 of the + License, or (at your option) any later version. + + libcanberra is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with libcanberra. If not, see + . +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include "canberra.h" +#include "common.h" +#include "malloc.h" +#include "driver.h" +#include "proplist.h" +#include "macro.h" +#include "fork-detect.h" + +/** + * SECTION:canberra + * @short_description: General libcanberra API + * + * libcanberra defines a simple abstract interface for playing event sounds. + * + * libcanberra relies on the XDG sound naming specification for + * identifying event sounds. On Unix/Linux the right sound to play is + * found via the mechanisms defined in the XDG sound themeing + * specification. On other systems the XDG sound name is translated to + * the native sound id for the operating system. + * + * An event sound is triggered via libcanberra by calling the + * ca_context_play() function on a previously created ca_context + * object. The ca_context_play() takes a list of key-value pairs that + * describe the event sound to generate as closely as possible. The + * most important property is %CA_PROP_EVENT_ID which defines the XDG + * sound name for the sound to play. + * + * libcanberra is not a generic event abstraction system. It's only + * purpose is playing sounds -- however in a very elaborate way. As + * much information about the context the sound is triggered from + * shall be supplied to the sound system as possible, so that it can + * replace the sound with some other kind of feedback for a11y + * cases. Also this additional information can be used to enhance user + * experience (e.g. by positioning sounds in space depending on the + * place on the screen the sound was triggered from, and similar + * uses). + * + * The set of properties defined for event sounds is extensible and + * shared with other audio systems, such as PulseAudio. Some of + * the properties that may be set are specific to an application, to a + * window, to an input event or to the media being played back. + * + * The user can attach a set of properties to the context itself, + * which is than automatically inherited by each sample being played + * back. (ca_context_change_props()). + * + * Some of the properties can be filled in by libcanberra or one of + * its backends automatically and thus need not be be filled in by the + * application (such as %CA_PROP_APPLICATION_PROCESS_ID and + * friends). However the application can always overwrite any of these + * implicit properties. + * + * libcanberra is thread-safe and OOM-safe (as far as the backend + * allows this). It is not async-signal safe. + * + * Most libcanberra functions return an integer that indicates success + * when 0 (%CA_SUCCESS) or an error when negative. In the latter case + * ca_strerror() can be used to convert this code into a human + * readable string. + * + * libcanberra property names need to be in 7bit ASCII, string + * property values UTF8. + * + * Optionally a libcanberra backend can support caching of sounds in a + * sound system. If this functionality is used, the latencies for + * event sound playback can be much smaller and fewer resources are + * needed to start playback. If a backend does not support cacheing, + * the respective functions will return an error code of + * %CA_ERROR_NOTSUPPORTED. + * + * It is highly recommended that the application sets the + * %CA_PROP_APPLICATION_NAME, %CA_PROP_APPLICATION_ID, + * %CA_PROP_APPLICATION_ICON_NAME/%CA_PROP_APPLICATION_ICON properties + * immediately after creating the ca_context, before calling + * ca_context_open() or ca_context_play(). + * + * Its is highly recommended to pass at least %CA_PROP_EVENT_ID, + * %CA_PROP_EVENT_DESCRIPTION to ca_context_play() for each event + * sound generated. For sound events based on mouse inputs events + * %CA_PROP_EVENT_MOUSE_X, %CA_PROP_EVENT_MOUSE_Y, %CA_PROP_EVENT_MOUSE_HPOS, + * %CA_PROP_EVENT_MOUSE_VPOS, %CA_PROP_EVENT_MOUSE_BUTTON should be + * passed. For sound events attached to a widget on the screen, the + * %CA_PROP_WINDOW_xxx properties should be set. + * + * + */ + +/** + * ca_context_create: + * @c: A pointer wheere to fill in the newly created context object. + * + * Create an (unconnected) context object. This call will not connect + * to the sound system, calling this function might even suceed if no + * working driver backend is available. To find out if one is + * available call ca_context_open(). + * + * Returns: 0 on success, negative error code on error. + */ + +int ca_context_create(ca_context **_c) { + ca_context *c; + int ret; + const char *d; + + ca_return_val_if_fail(!ca_detect_fork(), CA_ERROR_FORKED); + ca_return_val_if_fail(_c, CA_ERROR_INVALID); + + if (!(c = ca_new0(ca_context, 1))) + return CA_ERROR_OOM; + + if (!(c->mutex = ca_mutex_new())) { + ca_context_destroy(c); + return CA_ERROR_OOM; + } + + if ((ret = ca_proplist_create(&c->props)) < 0) { + ca_context_destroy(c); + return ret; + } + + if ((d = getenv("CANBERRA_DRIVER"))) { + if ((ret = ca_context_set_driver(c, d)) < 0) { + ca_context_destroy(c); + return ret; + } + } + + if ((d = getenv("CANBERRA_DEVICE"))) { + if ((ret = ca_context_change_device(c, d)) < 0) { + ca_context_destroy(c); + return ret; + } + } + + *_c = c; + return CA_SUCCESS; +} + +/** + * ca_context_destroy: + * @c: the context to destroy. + * + * Destroy a (connected or unconnected) context object. + * + * Returns: 0 on success, negative error code on error. + */ +int ca_context_destroy(ca_context *c) { + int ret = CA_SUCCESS; + + ca_return_val_if_fail(!ca_detect_fork(), CA_ERROR_FORKED); + ca_return_val_if_fail(c, CA_ERROR_INVALID); + + /* There's no locking necessary here, because the application is + * broken anyway if it destructs this object in one thread and + * still is calling a method of it in another. */ + + if (c->opened) + ret = driver_destroy(c); + + if (c->props) + ca_assert_se(ca_proplist_destroy(c->props) == CA_SUCCESS); + + if (c->mutex) + ca_mutex_free(c->mutex); + + ca_free(c->driver); + ca_free(c->device); + ca_free(c); + + return ret; +} + +/** + * ca_context_set_driver: + * @c: the context to change the backend driver for + * @driver: the backend driver to use (e.g. "alsa", "pulse", "null", ...) + * + * Specify the backend driver used. This function may not be called again after + * ca_context_open() suceeded. This function might suceed even when + * the specified driver backend is not available. Use + * ca_context_open() to find out whether the backend is available. + * + * Returns: 0 on success, negative error code on error. + */ +int ca_context_set_driver(ca_context *c, const char *driver) { + char *n; + int ret; + + ca_return_val_if_fail(!ca_detect_fork(), CA_ERROR_FORKED); + ca_return_val_if_fail(c, CA_ERROR_INVALID); + ca_mutex_lock(c->mutex); + ca_return_val_if_fail_unlock(!c->opened, CA_ERROR_STATE, c->mutex); + + if (!driver) + n = NULL; + else if (!(n = ca_strdup(driver))) { + ret = CA_ERROR_OOM; + goto fail; + } + + ca_free(c->driver); + c->driver = n; + + ret = CA_SUCCESS; + +fail: + ca_mutex_unlock(c->mutex); + + return ret; +} + +/** + * ca_context_change_device: + * @c: the context to change the backend device for + * @device: the backend device to use, in a format that is specific to the backend. + * + * Specify the backend device to use. This function may be called not be called after + * ca_context_open() suceeded. This function might suceed even when + * the specified driver backend is not available. Use + * ca_context_open() to find out whether the backend is available + * + * Depending on the backend use this might or might not cause all + * currently playing event sounds to be moved to the new device.. + * + * Returns: 0 on success, negative error code on error. + */ +int ca_context_change_device(ca_context *c, const char *device) { + char *n; + int ret; + + ca_return_val_if_fail(!ca_detect_fork(), CA_ERROR_FORKED); + ca_return_val_if_fail(c, CA_ERROR_INVALID); + ca_mutex_lock(c->mutex); + + if (!device) + n = NULL; + else if (!(n = ca_strdup(device))) { + ret = CA_ERROR_OOM; + goto fail; + } + + ret = c->opened ? driver_change_device(c, n) : CA_SUCCESS; + + if (ret == CA_SUCCESS) { + ca_free(c->device); + c->device = n; + } else + ca_free(n); + +fail: + ca_mutex_unlock(c->mutex); + + return ret; +} + +static int context_open_unlocked(ca_context *c) { + int ret; + + ca_return_val_if_fail(!ca_detect_fork(), CA_ERROR_FORKED); + ca_return_val_if_fail(c, CA_ERROR_INVALID); + + if (c->opened) + return CA_SUCCESS; + + if ((ret = driver_open(c)) == CA_SUCCESS) + c->opened = TRUE; + + return ret; +} + +/** + * ca_context_open: + * @c: the context to connect. + * + * Connect the context to the sound system. This call is implicitly + * called in ca_context_play() or ca_context_cache() if not called + * explicitly. It is recommended to initialize application properties + * with ca_context_change_props() before calling this function. + * + * Returns: 0 on success, negative error code on error. + */ +int ca_context_open(ca_context *c) { + int ret; + + ca_return_val_if_fail(!ca_detect_fork(), CA_ERROR_FORKED); + ca_return_val_if_fail(c, CA_ERROR_INVALID); + ca_mutex_lock(c->mutex); + ca_return_val_if_fail_unlock(!c->opened, CA_ERROR_STATE, c->mutex); + + ret = context_open_unlocked(c); + + ca_mutex_unlock(c->mutex); + + return ret; +} + +/** + * ca_context_change_props: + * @c: the context to set the properties on. + * @...: the list of string pairs for the properties. Needs to be a NULL terminated list. + * + * Write one or more string properties to the context object. Requires + * final NULL sentinel. Properties set like this will be attached to + * both the client object of the sound server and to all event sounds + * played or cached. It is recommended to call this function at least + * once before calling ca_context_open(), so that the initial + * application properties are set properly before the initial + * connection to the sound system. This function can be called both + * before and after the ca_context_open() call. Properties that have + * already been set before will be overwritten. + * + * Returns: 0 on success, negative error code on error. + */ + +int ca_context_change_props(ca_context *c, ...) { + va_list ap; + int ret; + ca_proplist *p = NULL; + + ca_return_val_if_fail(!ca_detect_fork(), CA_ERROR_FORKED); + ca_return_val_if_fail(c, CA_ERROR_INVALID); + + va_start(ap, c); + ret = ca_proplist_from_ap(&p, ap); + va_end(ap); + + if (ret < 0) + return ret; + + ret = ca_context_change_props_full(c, p); + + ca_assert_se(ca_proplist_destroy(p) == 0); + + return ret; +} + +/** + * ca_context_change_props_full: + * @c: the context to set the properties on. + * @p: the property list to set. + * + * Similar to ca_context_change_props(), but takes a ca_proplist + * instead of a variable list of properties. Can be used to set binary + * properties such as %CA_PROP_APPLICATION_ICON. + * + * Returns: 0 on success, negative error code on error. + */ + +int ca_context_change_props_full(ca_context *c, ca_proplist *p) { + int ret; + ca_proplist *merged; + + ca_return_val_if_fail(!ca_detect_fork(), CA_ERROR_FORKED); + ca_return_val_if_fail(c, CA_ERROR_INVALID); + ca_return_val_if_fail(p, CA_ERROR_INVALID); + + ca_mutex_lock(c->mutex); + + if ((ret = ca_proplist_merge(&merged, c->props, p)) < 0) + goto finish; + + ret = c->opened ? driver_change_props(c, p, merged) : CA_SUCCESS; + + if (ret == CA_SUCCESS) { + ca_assert_se(ca_proplist_destroy(c->props) == CA_SUCCESS); + c->props = merged; + } else + ca_assert_se(ca_proplist_destroy(merged) == CA_SUCCESS); + +finish: + + ca_mutex_unlock(c->mutex); + + return ret; +} + +/** + * ca_context_play: + * @c: the context to play the event sound on + * @id: an integer id this sound can later be identified with when calling ca_context_cancel() + * @...: additional properties for this sound event. + * + * Play one event sound. id can be any numeric value which later can + * be used to cancel an event sound that is currently being + * played. You may use the same id twice or more times if you want to + * cancel multiple event sounds with a single ca_context_cancel() call + * at once. It is recommended to pass 0 for the id if the event sound + * shall never be canceled. If the requested sound is not cached in + * the server yet this call might result in the sample being uploaded + * temporarily or permanently (this may be controlled with %CA_PROP_CANBERRA_CACHE_CONTROL). This function will start playback + * in the background. It will not wait until playback + * completed. Depending on the backend used a sound that is started + * shortly before your application terminates might or might not continue to + * play after your application terminated. If you want to make sure + * that all sounds finish to play you need to wait synchronously for + * the callback function of ca_context_play_full() to be called before you + * terminate your application. + * + * The sample to play is identified by the %CA_PROP_EVENT_ID + * property. If it is already cached in the server the cached version + * is played. The properties passed in this call are merged with the + * properties supplied when the sample was cached (if applicable) + * and the context properties as set with ca_context_change_props(). + * + * If %CA_PROP_EVENT_ID is not defined the sound file passed in the + * %CA_PROP_MEDIA_FILENAME is played. + * + * On Linux/Unix the right sound to play is determined according to + * %CA_PROP_EVENT_ID, + * %CA_PROP_APPLICATION_LANGUAGE/%CA_PROP_MEDIA_LANGUAGE, the system + * locale, %CA_PROP_CANBERRA_XDG_THEME_NAME and + * %CA_PROP_CANBERRA_XDG_THEME_OUTPUT_PROFILE, following the XDG Sound + * Theming Specification. On non-Unix systems the native event sound + * that matches the XDG sound name in %CA_PROP_EVENT_ID is played. + * + * Returns: 0 on success, negative error code on error. + */ + +int ca_context_play(ca_context *c, uint32_t id, ...) { + int ret; + va_list ap; + ca_proplist *p = NULL; + + ca_return_val_if_fail(!ca_detect_fork(), CA_ERROR_FORKED); + ca_return_val_if_fail(c, CA_ERROR_INVALID); + + va_start(ap, id); + ret = ca_proplist_from_ap(&p, ap); + va_end(ap); + + if (ret < 0) + return ret; + + ret = ca_context_play_full(c, id, p, NULL, NULL); + + ca_assert_se(ca_proplist_destroy(p) == 0); + + return ret; +} + +/** + * ca_context_play_full: + * @c: the context to play the event sound on + * @id: an integer id this sound can be later be identified with when calling ca_context_cancel() or when the callback is called. + * @p: A property list of properties for this event sound + * @cb: A callback to call when this sound event sucessfully finished playing or when an error occured during playback. + * + * Play one event sound, and call the specified callback function when + * completed. See ca_finish_callback_t for the semantics the callback + * is called in. Also see ca_context_play(). + * + * It is guaranteed that the callback is called exactly once if + * ca_context_play_full() returns CA_SUCCESS. You thus may safely pass + * allocated memory to the callback and assume that it is freed + * properly. + * + * Returns: 0 on success, negative error code on error. + */ + +int ca_context_play_full(ca_context *c, uint32_t id, ca_proplist *p, ca_finish_callback_t cb, void *userdata) { + int ret; + const char *t; + ca_bool_t enabled = TRUE; + + ca_return_val_if_fail(!ca_detect_fork(), CA_ERROR_FORKED); + ca_return_val_if_fail(c, CA_ERROR_INVALID); + ca_return_val_if_fail(p, CA_ERROR_INVALID); + ca_return_val_if_fail(!userdata || cb, CA_ERROR_INVALID); + + ca_mutex_lock(c->mutex); + + ca_return_val_if_fail_unlock(ca_proplist_contains(p, CA_PROP_EVENT_ID) || + ca_proplist_contains(c->props, CA_PROP_EVENT_ID) || + ca_proplist_contains(p, CA_PROP_MEDIA_FILENAME) || + ca_proplist_contains(c->props, CA_PROP_MEDIA_FILENAME), CA_ERROR_INVALID, c->mutex); + + ca_mutex_lock(c->props->mutex); + if ((t = ca_proplist_gets_unlocked(c->props, CA_PROP_CANBERRA_ENABLE))) + enabled = !ca_streq(t, "0"); + ca_mutex_unlock(c->props->mutex); + + ca_mutex_lock(p->mutex); + if ((t = ca_proplist_gets_unlocked(p, CA_PROP_CANBERRA_ENABLE))) + enabled = !ca_streq(t, "0"); + ca_mutex_unlock(p->mutex); + + ca_return_val_if_fail_unlock(enabled, CA_ERROR_DISABLED, c->mutex); + + if ((ret = context_open_unlocked(c)) < 0) + goto finish; + + ca_assert(c->opened); + + ret = driver_play(c, id, p, cb, userdata); + +finish: + + ca_mutex_unlock(c->mutex); + + return ret; +} + +/** + * + * ca_context_cancel: + * @c: the context to cancel the sounds on + * @id: the id that identify the sounds to cancel. + * + * Cancel one or more event sounds that have been started via + * ca_context_play(). If the sound was started with + * ca_context_play_full() and a callback function was passed this + * might cause this function to be called with %CA_ERROR_CANCELED as + * error code. + * + * Returns: 0 on success, negative error code on error. + */ +int ca_context_cancel(ca_context *c, uint32_t id) { + int ret; + + ca_return_val_if_fail(!ca_detect_fork(), CA_ERROR_FORKED); + ca_return_val_if_fail(c, CA_ERROR_INVALID); + ca_mutex_lock(c->mutex); + ca_return_val_if_fail_unlock(c->opened, CA_ERROR_STATE, c->mutex); + + ret = driver_cancel(c, id); + + ca_mutex_unlock(c->mutex); + + return ret; +} + +/** + * ca_context_cache: + * @c: The context to use for uploading. + * @...: The properties for this event sound. Terminated with NULL. + * + * Upload the specified sample into the audio server and attach the + * specified properties to it. This function will only return after + * the sample upload was finished. + * + * The sound to cache is found with the same algorithm that is used to + * find the sounds for ca_context_play(). + * + * If the backend doesn't support caching sound samples this function + * will return %CA_ERROR_NOTSUPPORTED. + * + * Returns: 0 on success, negative error code on error. + */ + +int ca_context_cache(ca_context *c, ...) { + int ret; + va_list ap; + ca_proplist *p = NULL; + + ca_return_val_if_fail(!ca_detect_fork(), CA_ERROR_FORKED); + ca_return_val_if_fail(c, CA_ERROR_INVALID); + + va_start(ap, c); + ret = ca_proplist_from_ap(&p, ap); + va_end(ap); + + if (ret < 0) + return ret; + + ret = ca_context_cache_full(c, p); + + ca_assert_se(ca_proplist_destroy(p) == 0); + + return ret; +} + +/** + * ca_context_cache_full: + * @c: The context to use for uploading. + * @p: The property list for this event sound. + * + * Upload the specified sample into the server and attach the + * specified properties to it. Similar to ca_context_cache() but takes + * a ca_proplist instead of a variable number of arguments. + * + * If the backend doesn't support caching sound samples this function + * will return CA_ERROR_NOTSUPPORTED. + * + * Returns: 0 on success, negative error code on error. + */ +int ca_context_cache_full(ca_context *c, ca_proplist *p) { + int ret; + + ca_return_val_if_fail(!ca_detect_fork(), CA_ERROR_FORKED); + ca_return_val_if_fail(c, CA_ERROR_INVALID); + ca_return_val_if_fail(p, CA_ERROR_INVALID); + + ca_mutex_lock(c->mutex); + + ca_return_val_if_fail_unlock(ca_proplist_contains(p, CA_PROP_EVENT_ID) || + ca_proplist_contains(c->props, CA_PROP_EVENT_ID), CA_ERROR_INVALID, c->mutex); + + if ((ret = context_open_unlocked(c)) < 0) + goto finish; + + ca_assert(c->opened); + + ret = driver_cache(c, p); + +finish: + + ca_mutex_unlock(c->mutex); + + return ret; +} + +/** + * ca_strerror: + * @code: Numerical error code as returned by a libcanberra API function + * + * Converts a numerical error code as returned by most libcanberra API functions into a human readable error string. + * + * Returns: a human readable error string. + */ +const char *ca_strerror(int code) { + + const char * const error_table[-_CA_ERROR_MAX] = { + [-CA_SUCCESS] = "Success", + [-CA_ERROR_NOTSUPPORTED] = "Operation not supported", + [-CA_ERROR_INVALID] = "Invalid argument", + [-CA_ERROR_STATE] = "Invalid state", + [-CA_ERROR_OOM] = "Out of memory", + [-CA_ERROR_NODRIVER] = "No such driver", + [-CA_ERROR_SYSTEM] = "System error", + [-CA_ERROR_CORRUPT] = "File or data corrupt", + [-CA_ERROR_TOOBIG] = "File or data too large", + [-CA_ERROR_NOTFOUND] = "File or data not found", + [-CA_ERROR_DESTROYED] = "Destroyed", + [-CA_ERROR_CANCELED] = "Canceled", + [-CA_ERROR_NOTAVAILABLE] = "Not available", + [-CA_ERROR_ACCESS] = "Access forbidden", + [-CA_ERROR_IO] = "IO error", + [-CA_ERROR_INTERNAL] = "Internal error", + [-CA_ERROR_DISABLED] = "Sound disabled", + [-CA_ERROR_FORKED] = "Process forked", + [-CA_ERROR_DISCONNECTED] = "Disconnected" + }; + + ca_return_val_if_fail(code <= 0, NULL); + ca_return_val_if_fail(code > _CA_ERROR_MAX, NULL); + + return error_table[-code]; +} + +/* Not exported */ +int ca_parse_cache_control(ca_cache_control_t *control, const char *c) { + ca_return_val_if_fail(control, CA_ERROR_INVALID); + ca_return_val_if_fail(c, CA_ERROR_INVALID); + + if (ca_streq(c, "never")) + *control = CA_CACHE_CONTROL_NEVER; + else if (ca_streq(c, "permanent")) + *control = CA_CACHE_CONTROL_PERMANENT; + else if (ca_streq(c, "volatile")) + *control = CA_CACHE_CONTROL_VOLATILE; + else + return CA_ERROR_INVALID; + + return CA_SUCCESS; +} + +/** + * ca_context_playing: + * @c: the context to check if sound is still playing + * @id: the id that identify the sounds to check + * @playing: a pointer to a boolean that will be updated with the play status + * + * Check if at least one sound with the specified id is still + * playing. Returns 0 in *playing if no sound with this id is playing + * anymore or non-zero if there is at least one playing. + * + * Returns: 0 on success, negative error code on error. + * Since: 0.16 + */ +int ca_context_playing(ca_context *c, uint32_t id, int *playing) { + int ret; + + ca_return_val_if_fail(!ca_detect_fork(), CA_ERROR_FORKED); + ca_return_val_if_fail(c, CA_ERROR_INVALID); + ca_return_val_if_fail(playing, CA_ERROR_INVALID); + ca_mutex_lock(c->mutex); + ca_return_val_if_fail_unlock(c->opened, CA_ERROR_STATE, c->mutex); + + ret = driver_playing(c, id, playing); + + ca_mutex_unlock(c->mutex); + + return ret; +} diff --git a/.flatpak-builder/cache/objects/8d/f7ee53d979553253415cf14c6c01519d239585c533d0650a72d4680e9db87b.dirtree b/.flatpak-builder/cache/objects/8d/f7ee53d979553253415cf14c6c01519d239585c533d0650a72d4680e9db87b.dirtree new file mode 100644 index 0000000..ee8c5e0 Binary files /dev/null and b/.flatpak-builder/cache/objects/8d/f7ee53d979553253415cf14c6c01519d239585c533d0650a72d4680e9db87b.dirtree differ diff --git a/.flatpak-builder/cache/objects/8e/aa4f2676245485dc1118d5b6d29096cca573fc08cce9a8ba51b1fc5bde9240.file b/.flatpak-builder/cache/objects/8e/aa4f2676245485dc1118d5b6d29096cca573fc08cce9a8ba51b1fc5bde9240.file new file mode 120000 index 0000000..75db63b --- /dev/null +++ b/.flatpak-builder/cache/objects/8e/aa4f2676245485dc1118d5b6d29096cca573fc08cce9a8ba51b1fc5bde9240.file @@ -0,0 +1 @@ +../../share/runtime/locale/tr/share/tr \ No newline at end of file diff --git a/.flatpak-builder/cache/objects/8e/aaac009c5455862da59eccdae713d026e46a772e656bd95cee338b7f9d5914.file b/.flatpak-builder/cache/objects/8e/aaac009c5455862da59eccdae713d026e46a772e656bd95cee338b7f9d5914.file new file mode 100644 index 0000000..f93638e --- /dev/null +++ b/.flatpak-builder/cache/objects/8e/aaac009c5455862da59eccdae713d026e46a772e656bd95cee338b7f9d5914.file @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2008 - 2012 Vivien Malerba + * Copyright (C) 2012 Daniel Espinosa + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GDA_ATTRIBUTES_MANAGER_H__ +#define __GDA_ATTRIBUTES_MANAGER_H__ + +#include + +G_BEGIN_DECLS + +/* possible predefined attribute names for gda_holder_get_attribute() or gda_column_get_attribute() */ +/** + * GDA_ATTRIBUTE_DESCRIPTION: + * The corresponding attribute is the description of the object it refers to (value has a G_TYPE_STRING type). + */ +#define GDA_ATTRIBUTE_DESCRIPTION "__gda_attr_descr" + +/** + * GDA_ATTRIBUTE_NAME: + * The corresponding attribute is the name of the object it refers to (value has a G_TYPE_STRING type). + */ +#define GDA_ATTRIBUTE_NAME "__gda_attr_name" + +/** + * GDA_ATTRIBUTE_NUMERIC_PRECISION: + * The corresponding attribute is the number of significant digits of the object it refers to (value has a G_TYPE_INT type). + */ +#define GDA_ATTRIBUTE_NUMERIC_PRECISION "__gda_attr_numeric_precision" + +/** + * GDA_ATTRIBUTE_NUMERIC_SCALE: + * The corresponding attribute is the number of significant digits to the right of the decimal point of the object it refers to (value has a G_TYPE_INT type). + */ +#define GDA_ATTRIBUTE_NUMERIC_SCALE "__gda_attr_numeric_scale" + +/** + * GDA_ATTRIBUTE_AUTO_INCREMENT: + * The corresponding attribute specifies if the object it refers to is auto incremented (value has a G_TYPE_BOOLEAN type). + */ +#define GDA_ATTRIBUTE_AUTO_INCREMENT "__gda_attr_autoinc" + +/** + * GDA_ATTRIBUTE_IS_DEFAULT: + * The corresponding attribute specifies if the object it refers to has its value to default (value has a G_TYPE_BOOLEAN type). + */ +#define GDA_ATTRIBUTE_IS_DEFAULT "__gda_attr_is_default" + +/** + * GDA_ATTRIBUTE_TREE_NODE_UNKNOWN_CHILDREN: + * This attribute, if %TRUE specifies that a tree node may or may not have any children nodes (value has a G_TYPE_BOOLEAN type). + */ +#define GDA_ATTRIBUTE_TREE_NODE_UNKNOWN_CHILDREN "__gda_attr_tnuchild" + + +/** + * SECTION:gda-attributes-manager + * @short_description: Manager for lists of attributes + * @title: Attributes manager + * @stability: Stable + * + * he #GdaAttributesManager manages lists of named values (attributes) for the benefit of + * others (objects or resources for which only a pointer is known). It is used internally by &LIBGDA; + * whenever an object or a simple structure may have several attributes. + * + * The features are similar to those of the g_object_set_data() and similar + * but with the following major differences: + * + * it works with GObject objects and also with simple pointers to data + * attributes names are considered static (they are not copied) and so they must either be static strings or allocated strings which exist (unchanged) while an attribute uses it as name + * it is possible to iterate through the attributes + * the associated values are expected to be #GValue values + * + * + * Attibute names can be any string, but &LIBGDA; reserves some for its own usage, see below. + * + * The #GdaAttributesManager implements its own locking mechanism so it is thread-safe. + * + * + */ + +G_END_DECLS + +#endif diff --git a/.flatpak-builder/cache/objects/8e/b73d69a8dc891cb5e03d47ae2062da34b3ac9164d9bb9994aec0bcf49848cf.file b/.flatpak-builder/cache/objects/8e/b73d69a8dc891cb5e03d47ae2062da34b3ac9164d9bb9994aec0bcf49848cf.file new file mode 100644 index 0000000..0058359 --- /dev/null +++ b/.flatpak-builder/cache/objects/8e/b73d69a8dc891cb5e03d47ae2062da34b3ac9164d9bb9994aec0bcf49848cf.file @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2006 - 2013 Vivien Malerba + * Copyright (C) 2007 Murray Cumming + * Copyright (C) 2010 David King + * Copyright (C) 2018 Daniel Espinosa + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + + +#ifndef __GDA_DATA_HANDLER_H_ +#define __GDA_DATA_HANDLER_H_ + +#include +#include "gda-decl.h" +#include "gda-value.h" + +G_BEGIN_DECLS + +#define GDA_TYPE_DATA_HANDLER (gda_data_handler_get_type()) +G_DECLARE_INTERFACE(GdaDataHandler, gda_data_handler, GDA, DATA_HANDLER, GObject) + +/* struct for the interface */ +struct _GdaDataHandlerInterface +{ + GTypeInterface g_iface; + + /* virtual table */ + gchar *(* get_sql_from_value) (GdaDataHandler *dh, const GValue *value); + gchar *(* get_str_from_value) (GdaDataHandler *dh, const GValue *value); + GValue *(* get_value_from_sql) (GdaDataHandler *dh, const gchar *sql, GType type); + GValue *(* get_value_from_str) (GdaDataHandler *dh, const gchar *str, GType type); + GValue *(* get_sane_init_value) (GdaDataHandler *dh, GType type); + + gboolean (* accepts_g_type) (GdaDataHandler *dh, GType type); + const gchar *(* get_descr) (GdaDataHandler *dh); +}; + + +/** + * SECTION:gda-data-handler + * @short_description: Interface which provides data handling (conversions) capabilities + * @title: GdaDataHandler + * @stability: Stable + * @see_also: + * + * Because data types vary a lot from a DBMS to another, the #GdaDataHandler interface helps + * managing data in its various representations, and converting from one to another: + * + * as a #GValue which is a generic value container for the C language + * as a human readable string (in the user defined locale) + * as an SQL string (a string which can be used in SQL statements) + * + * + * For each data type, a corresponding #GdaDataHandler object can be requested using the + * gda_data_handler_get_default() function. However, when working + * with a specific database provider, it's better to use a #GdaDataHandler which may be specific to the + * database provider which will correctly handle each database specifics using + * gda_server_provider_get_data_handler_g_type() or + * gda_server_provider_get_data_handler_dbms(). + */ + + +/* Simple data manipulation */ +gchar *gda_data_handler_get_sql_from_value (GdaDataHandler *dh, const GValue *value); +gchar *gda_data_handler_get_str_from_value (GdaDataHandler *dh, const GValue *value); +GValue *gda_data_handler_get_value_from_sql (GdaDataHandler *dh, const gchar *sql, GType type); +GValue *gda_data_handler_get_value_from_str (GdaDataHandler *dh, const gchar *str, GType type); +GValue *gda_data_handler_get_sane_init_value (GdaDataHandler *dh, GType type); + +/* information about the data handler itself */ +gboolean gda_data_handler_accepts_g_type (GdaDataHandler *dh, GType type); +const gchar *gda_data_handler_get_descr (GdaDataHandler *dh); +GdaDataHandler *gda_data_handler_get_default (GType for_type); + +G_END_DECLS + +#endif diff --git a/.flatpak-builder/cache/objects/8f/58b5d4c3e3549c1a31d07e17f2296f53ffa43537d5b1c7f43cb7d539ba7048.file b/.flatpak-builder/cache/objects/8f/58b5d4c3e3549c1a31d07e17f2296f53ffa43537d5b1c7f43cb7d539ba7048.file new file mode 100644 index 0000000..dbce44f --- /dev/null +++ b/.flatpak-builder/cache/objects/8f/58b5d4c3e3549c1a31d07e17f2296f53ffa43537d5b1c7f43cb7d539ba7048.file @@ -0,0 +1,163 @@ +# types.py +# +# Copyright 2022 James Westman +# +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation; either version 3 of the +# License, or (at your option) any later version. +# +# This file is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program. If not, see . +# +# SPDX-License-Identifier: LGPL-3.0-or-later + + +from .common import * +from ..gir import Class, ExternType, Interface + + +class TypeName(AstNode): + grammar = AnyOf( + [ + UseIdent("namespace"), + ".", + UseIdent("class_name"), + ], + [ + AnyOf("$", [".", UseLiteral("old_extern", True)]), + UseIdent("class_name"), + UseLiteral("extern", True), + ], + UseIdent("class_name"), + ) + + @validate() + def old_extern(self): + if self.tokens["old_extern"]: + raise UpgradeWarning( + "Use the '$' extern syntax introduced in blueprint 0.8.0", + actions=[CodeAction("Use '$' syntax", "$" + self.tokens["class_name"])], + ) + + @validate("class_name") + def type_exists(self): + if not self.tokens["extern"] and self.gir_ns is not None: + self.root.gir.validate_type( + self.tokens["class_name"], self.tokens["namespace"] + ) + + @validate("namespace") + def gir_ns_exists(self): + if not self.tokens["extern"]: + self.root.gir.validate_ns(self.tokens["namespace"]) + + @property + def gir_ns(self): + if not self.tokens["extern"]: + return self.root.gir.namespaces.get(self.tokens["namespace"] or "Gtk") + + @property + def gir_type(self) -> gir.GirType: + if self.tokens["class_name"] and not self.tokens["extern"]: + return self.root.gir.get_type( + self.tokens["class_name"], self.tokens["namespace"] + ) + + return gir.ExternType(self.tokens["class_name"]) + + @property + def glib_type_name(self) -> str: + if gir_type := self.gir_type: + return gir_type.glib_type_name + else: + return self.tokens["class_name"] + + @docs("namespace") + def namespace_docs(self): + if ns := self.root.gir.namespaces.get(self.tokens["namespace"]): + return ns.doc + + @docs("class_name") + def class_docs(self): + if self.gir_type: + return self.gir_type.doc + + @property + def as_string(self) -> str: + if self.tokens["extern"]: + return "$" + self.tokens["class_name"] + elif self.tokens["namespace"]: + return f"{self.tokens['namespace']}.{self.tokens['class_name']}" + else: + return self.tokens["class_name"] + + +class ClassName(TypeName): + @validate("namespace", "class_name") + def gir_class_exists(self): + if ( + self.gir_type is not None + and not isinstance(self.gir_type, ExternType) + and not isinstance(self.gir_type, Class) + ): + if isinstance(self.gir_type, Interface): + raise CompileError( + f"{self.gir_type.full_name} is an interface, not a class" + ) + else: + raise CompileError(f"{self.gir_type.full_name} is not a class") + + +class ConcreteClassName(ClassName): + @validate("namespace", "class_name") + def not_abstract(self): + if isinstance(self.gir_type, Class) and self.gir_type.abstract: + raise CompileError( + f"{self.gir_type.full_name} can't be instantiated because it's abstract", + hints=[f"did you mean to use a subclass of {self.gir_type.full_name}?"], + ) + + +class TemplateClassName(ClassName): + """Handles the special case of a template type. The old syntax uses an identifier, + which is ambiguous with the new syntax. So this class displays an appropriate + upgrade warning instead of a class not found error.""" + + @property + def is_legacy(self): + return ( + self.tokens["extern"] is None + and self.tokens["namespace"] is None + and self.root.gir.get_type(self.tokens["class_name"], "Gtk") is None + ) + + @property + def gir_type(self) -> gir.GirType: + if self.is_legacy: + return gir.ExternType(self.tokens["class_name"]) + else: + return super().gir_type + + @validate("class_name") + def type_exists(self): + if self.is_legacy: + if type := self.root.gir.get_type_by_cname(self.tokens["class_name"]): + replacement = type.full_name + else: + replacement = "$" + self.tokens["class_name"] + + raise UpgradeWarning( + "Use type syntax here (introduced in blueprint 0.8.0)", + actions=[CodeAction("Use type syntax", replace_with=replacement)], + ) + + if not self.tokens["extern"] and self.gir_ns is not None: + self.root.gir.validate_type( + self.tokens["class_name"], self.tokens["namespace"] + ) diff --git a/.flatpak-builder/cache/objects/8f/5b8f85416b78a0b63d571628fd067c560d4ec20fe926ee48e8b957bcf02249.file b/.flatpak-builder/cache/objects/8f/5b8f85416b78a0b63d571628fd067c560d4ec20fe926ee48e8b957bcf02249.file new file mode 120000 index 0000000..6bc4160 --- /dev/null +++ b/.flatpak-builder/cache/objects/8f/5b8f85416b78a0b63d571628fd067c560d4ec20fe926ee48e8b957bcf02249.file @@ -0,0 +1 @@ +libgda-6.0.so.6.0.0 \ No newline at end of file diff --git a/.flatpak-builder/cache/objects/8f/90979e8f8f1c3558daf39d5ff32b74fb2dd0eebed684113badc2e6ffeee4f4.file b/.flatpak-builder/cache/objects/8f/90979e8f8f1c3558daf39d5ff32b74fb2dd0eebed684113badc2e6ffeee4f4.file new file mode 120000 index 0000000..a2fece0 --- /dev/null +++ b/.flatpak-builder/cache/objects/8f/90979e8f8f1c3558daf39d5ff32b74fb2dd0eebed684113badc2e6ffeee4f4.file @@ -0,0 +1 @@ +../../share/runtime/locale/pt/share/pt \ No newline at end of file diff --git a/.flatpak-builder/cache/objects/8f/ca9cb3f6923bd9bc9a96dbb62aa32a2a4f53e195cc6cc8db55d24a9ec6695e.file b/.flatpak-builder/cache/objects/8f/ca9cb3f6923bd9bc9a96dbb62aa32a2a4f53e195cc6cc8db55d24a9ec6695e.file new file mode 100644 index 0000000..149152a --- /dev/null +++ b/.flatpak-builder/cache/objects/8f/ca9cb3f6923bd9bc9a96dbb62aa32a2a4f53e195cc6cc8db55d24a9ec6695e.file @@ -0,0 +1,88 @@ +# gtkbuilder_template.py +# +# Copyright 2022 James Westman +# +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation; either version 3 of the +# License, or (at your option) any later version. +# +# This file is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program. If not, see . +# +# SPDX-License-Identifier: LGPL-3.0-or-later + +import typing as T + +from blueprintcompiler.language.common import GirType + +from .gobject_object import Object, ObjectContent +from .common import * +from ..gir import TemplateType +from .types import ClassName, TemplateClassName + + +class Template(Object): + grammar = [ + UseExact("id", "template"), + to_parse_node(TemplateClassName).expected("template type"), + Optional( + [ + Match(":"), + to_parse_node(ClassName).expected("parent class"), + ] + ), + ObjectContent, + ] + + @property + def id(self) -> str: + return "template" + + @property + def gir_class(self) -> GirType: + if isinstance(self.class_name.gir_type, ExternType): + if gir := self.parent_type: + return TemplateType(self.class_name.gir_type.full_name, gir.gir_type) + return self.class_name.gir_type + + @property + def parent_type(self) -> T.Optional[ClassName]: + if len(self.children[ClassName]) == 2: + return self.children[ClassName][1] + else: + return None + + @validate() + def parent_only_if_extern(self): + if not isinstance(self.class_name.gir_type, ExternType): + if self.parent_type is not None: + raise CompileError( + "Parent type may only be specified if the template type is extern" + ) + + @validate("id") + def unique_in_parent(self): + self.validate_unique_in_parent( + f"Only one template may be defined per file, but this file contains {len(self.parent.children[Template])}", + ) + + +@decompiler("template") +def decompile_template(ctx: DecompileCtx, gir, klass, parent=None): + def class_name(cname: str) -> str: + if gir := ctx.type_by_cname(cname): + return decompile.full_name(gir) + else: + return "$" + cname + + ctx.print(f"template {class_name(klass)} : {class_name(parent)} {{") + + ctx.template_class = klass + + return ctx.type_by_cname(klass) or ctx.type_by_cname(parent) diff --git a/.flatpak-builder/cache/objects/8f/fecc2fcf7107ee8fb4d2f9f9655e55f5bb395b5b9caa22878faf4730fa206a.dirtree b/.flatpak-builder/cache/objects/8f/fecc2fcf7107ee8fb4d2f9f9655e55f5bb395b5b9caa22878faf4730fa206a.dirtree new file mode 100644 index 0000000..763e923 Binary files /dev/null and b/.flatpak-builder/cache/objects/8f/fecc2fcf7107ee8fb4d2f9f9655e55f5bb395b5b9caa22878faf4730fa206a.dirtree differ diff --git a/.flatpak-builder/cache/objects/90/46af50ffe23de49a2d4a3c268fadb033bbe465f59d0f00e35095fae1e16c1e.dirtree b/.flatpak-builder/cache/objects/90/46af50ffe23de49a2d4a3c268fadb033bbe465f59d0f00e35095fae1e16c1e.dirtree new file mode 100644 index 0000000..857a0a2 Binary files /dev/null and b/.flatpak-builder/cache/objects/90/46af50ffe23de49a2d4a3c268fadb033bbe465f59d0f00e35095fae1e16c1e.dirtree differ diff --git a/.flatpak-builder/cache/objects/90/916eb39acfcd7b1f2d4b5ab3d7324484cd15b2afb31704f0ab79522a6ba51b.file b/.flatpak-builder/cache/objects/90/916eb39acfcd7b1f2d4b5ab3d7324484cd15b2afb31704f0ab79522a6ba51b.file new file mode 100644 index 0000000..01a9771 --- /dev/null +++ b/.flatpak-builder/cache/objects/90/916eb39acfcd7b1f2d4b5ab3d7324484cd15b2afb31704f0ab79522a6ba51b.file @@ -0,0 +1,161 @@ +/* + * Copyright (C) 2018 Daniel Espinosa + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include +#include +#include +#include + +#ifndef __GDA_PROVIDER_H__ +#define __GDA_PROVIDER_H__ + +G_BEGIN_DECLS + +#define GDA_TYPE_PROVIDER gda_provider_get_type() + +G_DECLARE_INTERFACE(GdaProvider, gda_provider, GDA, PROVIDER, GObject) + +struct _GdaProviderInterface +{ + GTypeInterface g_iface; + + const gchar *(* get_name) (GdaProvider *provider); + const gchar *(* get_version) (GdaProvider *provider); + const gchar *(* get_server_version) (GdaProvider *provider, GdaConnection *cnc); + gboolean (* supports_feature) (GdaProvider *provider, GdaConnection *cnc, + GdaConnectionFeature feature); + GdaConnection *(* create_connection) (GdaProvider *provider); /* may be NULL */ + GdaSqlParser *(* create_parser) (GdaProvider *provider, GdaConnection *cnc); /* may be NULL */ + GdaDataHandler *(* get_data_handler) (GdaProvider *provider, GdaConnection *cnc, /* may be NULL */ + GType g_type, const gchar *dbms_type); + const gchar *(* get_def_dbms_type) (GdaProvider *provider, GdaConnection *cnc, GType g_type); /* may be NULL */ + gboolean (* supports_operation) (GdaProvider *provider, GdaConnection *cnc, + GdaServerOperationType type, GdaSet *options); + GdaServerOperation *(* create_operation) (GdaProvider *provider, GdaConnection *cnc, + GdaServerOperationType type, GdaSet *options, GError **error); + gchar *(* render_operation) (GdaProvider *provider, GdaConnection *cnc, + GdaServerOperation *op, GError **error); + gchar *(* statement_to_sql) (GdaProvider *provider, GdaConnection *cnc, + GdaStatement *stmt, GdaSet *params, GdaStatementSqlFlag flags, + GSList **params_used, GError **error); + gchar *(* identifier_quote) (GdaProvider *provider, GdaConnection *cnc, /* may be NULL */ + const gchar *id, + gboolean for_meta_store, gboolean force_quotes); + GdaSqlStatement *(* statement_rewrite) (GdaProvider *provider, GdaConnection *cnc, + GdaStatement *stmt, GdaSet *params, GError **error); + gboolean (* open_connection) (GdaProvider *provider, GdaConnection *cnc, + GdaQuarkList *params, GdaQuarkList *auth); + gboolean (* prepare_connection) (GdaProvider *provider, GdaConnection *cnc, + GdaQuarkList *params, GdaQuarkList *auth); + gboolean (* close_connection) (GdaProvider *provider, GdaConnection *cnc); + gchar *(* escape_string) (GdaProvider *provider, GdaConnection *cnc, const gchar *str); /* may be NULL */ + gchar *(* unescape_string) (GdaProvider *provider, GdaConnection *cnc, const gchar *str); /* may be NULL */ + gboolean (* perform_operation) (GdaProvider *provider, GdaConnection *cnc, /* may be NULL */ + GdaServerOperation *op, GError **error); + gboolean (* begin_transaction) (GdaProvider *provider, GdaConnection *cnc, + const gchar *name, GdaTransactionIsolation level, GError **error); + gboolean (* commit_transaction) (GdaProvider *provider, GdaConnection *cnc, + const gchar *name, GError **error); + gboolean (* rollback_transaction)(GdaProvider *provider, GdaConnection *cnc, + const gchar *name, GError **error); + gboolean (* add_savepoint) (GdaProvider *provider, GdaConnection *cnc, + const gchar *name, GError **error); + gboolean (* rollback_savepoint) (GdaProvider *provider, GdaConnection *cnc, + const gchar *name, GError **error); + gboolean (* delete_savepoint) (GdaProvider *provider, GdaConnection *cnc, + const gchar *name, GError **error); + gboolean (* statement_prepare) (GdaProvider *provider, GdaConnection *cnc, + GdaStatement *stmt, GError **error); + GObject *(* statement_execute) (GdaProvider *provider, GdaConnection *cnc, + GdaStatement *stmt, GdaSet *params, + GdaStatementModelUsage model_usage, + GType *col_types, GdaSet **last_inserted_row, + GError **error); + GdaSet *(* get_last_inserted) (GdaProvider *provider, GdaConnection *cnc, + GError **error); + + /* Padding for future expansion */ + gpointer padding[12]; +}; + + +const gchar *gda_provider_get_name (GdaProvider *provider); +const gchar *gda_provider_get_version (GdaProvider *provider); +const gchar *gda_provider_get_server_version (GdaProvider *provider, GdaConnection *cnc); +gboolean gda_provider_supports_feature (GdaProvider *provider, GdaConnection *cnc, + GdaConnectionFeature feature); +GdaSqlParser *gda_provider_create_parser (GdaProvider *provider, GdaConnection *cnc); /* may be NULL */ +GdaConnection *gda_provider_create_connection (GdaProvider *provider); +GdaDataHandler *gda_provider_get_data_handler (GdaProvider *provider, GdaConnection *cnc, /* may be NULL */ + GType g_type, const gchar *dbms_type); +const gchar *gda_provider_get_def_dbms_type (GdaProvider *provider, GdaConnection *cnc, + GType g_type); /* may be NULL */ +gboolean gda_provider_supports_operation (GdaProvider *provider, GdaConnection *cnc, + GdaServerOperationType type, GdaSet *options); +GdaServerOperation *gda_provider_create_operation (GdaProvider *provider, GdaConnection *cnc, + GdaServerOperationType type, GdaSet *options, + GError **error); +gchar *gda_provider_render_operation (GdaProvider *provider, GdaConnection *cnc, + GdaServerOperation *op, GError **error); +gchar *gda_provider_statement_to_sql (GdaProvider *provider, GdaConnection *cnc, + GdaStatement *stmt, GdaSet *params, + GdaStatementSqlFlag flags, + GSList **params_used, GError **error); +gchar *gda_provider_identifier_quote (GdaProvider *provider, GdaConnection *cnc, /* may be NULL */ + const gchar *id, + gboolean for_meta_store, gboolean force_quotes); +GdaSqlStatement *gda_provider_statement_rewrite (GdaProvider *provider, GdaConnection *cnc, + GdaStatement *stmt, GdaSet *params, GError **error); +gboolean gda_provider_open_connection (GdaProvider *provider, GdaConnection *cnc, + GdaQuarkList *params, GdaQuarkList *auth); +gboolean gda_provider_prepare_connection (GdaProvider *provider, GdaConnection *cnc, + GdaQuarkList *params, GdaQuarkList *auth); +gboolean gda_provider_close_connection (GdaProvider *provider, GdaConnection *cnc); +gchar *gda_provider_escape_string (GdaProvider *provider, GdaConnection *cnc, + const gchar *str); /* may be NULL */ +gchar *gda_provider_unescape_string (GdaProvider *provider, GdaConnection *cnc, + const gchar *str); /* may be NULL */ +gboolean gda_provider_perform_operation (GdaProvider *provider, GdaConnection *cnc, /* may be NULL */ + GdaServerOperation *op, GError **error); +gboolean gda_provider_begin_transaction (GdaProvider *provider, GdaConnection *cnc, + const gchar *name, GdaTransactionIsolation level, + GError **error); +gboolean gda_provider_commit_transaction (GdaProvider *provider, GdaConnection *cnc, + const gchar *name, GError **error); +gboolean gda_provider_rollback_transaction (GdaProvider *provider, GdaConnection *cnc, + const gchar *name, GError **error); +gboolean gda_provider_add_savepoint (GdaProvider *provider, GdaConnection *cnc, + const gchar *name, GError **error); +gboolean gda_provider_rollback_savepoint (GdaProvider *provider, GdaConnection *cnc, + const gchar *name, GError **error); +gboolean gda_provider_delete_savepoint (GdaProvider *provider, GdaConnection *cnc, + const gchar *name, GError **error); +gboolean gda_provider_statement_prepare (GdaProvider *provider, GdaConnection *cnc, + GdaStatement *stmt, GError **error); +GObject *gda_provider_statement_execute (GdaProvider *provider, GdaConnection *cnc, + GdaStatement *stmt, GdaSet *params, + GdaStatementModelUsage model_usage, + GType *col_types, GdaSet **last_inserted_row, + GError **error); +GdaSet *gda_provider_get_last_inserted (GdaProvider *provider, GdaConnection *cnc, + GError **error); + +G_END_DECLS + +#endif diff --git a/.flatpak-builder/cache/objects/90/b898d24f54a8e3fb80dfd77a7db4862a58dfdda3c35e5d0083f566f0c9cfc2.dirtree b/.flatpak-builder/cache/objects/90/b898d24f54a8e3fb80dfd77a7db4862a58dfdda3c35e5d0083f566f0c9cfc2.dirtree new file mode 100644 index 0000000..dde8215 Binary files /dev/null and b/.flatpak-builder/cache/objects/90/b898d24f54a8e3fb80dfd77a7db4862a58dfdda3c35e5d0083f566f0c9cfc2.dirtree differ diff --git a/.flatpak-builder/cache/objects/90/c7e6d465f437764c0a146b44f7e53a4eb9d4e35445d15cdb8d9cafa63b45e5.commit b/.flatpak-builder/cache/objects/90/c7e6d465f437764c0a146b44f7e53a4eb9d4e35445d15cdb8d9cafa63b45e5.commit new file mode 100644 index 0000000..72e1bfd Binary files /dev/null and b/.flatpak-builder/cache/objects/90/c7e6d465f437764c0a146b44f7e53a4eb9d4e35445d15cdb8d9cafa63b45e5.commit differ diff --git a/.flatpak-builder/cache/objects/91/01da5a47c5217cb65d395bbe196449d82e9194feee8fc6e63e44e26fa70955.file b/.flatpak-builder/cache/objects/91/01da5a47c5217cb65d395bbe196449d82e9194feee8fc6e63e44e26fa70955.file new file mode 120000 index 0000000..984639f --- /dev/null +++ b/.flatpak-builder/cache/objects/91/01da5a47c5217cb65d395bbe196449d82e9194feee8fc6e63e44e26fa70955.file @@ -0,0 +1 @@ +libgda-6.0.so.6 \ No newline at end of file diff --git a/.flatpak-builder/cache/objects/91/a8cce7aa8c0b2aad86ea180cdfb0947159ed2509f5e94e9044f0e897697ac0.file b/.flatpak-builder/cache/objects/91/a8cce7aa8c0b2aad86ea180cdfb0947159ed2509f5e94e9044f0e897697ac0.file new file mode 100644 index 0000000..09873bc --- /dev/null +++ b/.flatpak-builder/cache/objects/91/a8cce7aa8c0b2aad86ea180cdfb0947159ed2509f5e94e9044f0e897697ac0.file @@ -0,0 +1,100 @@ +# gobject_property.py +# +# Copyright 2022 James Westman +# +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation; either version 3 of the +# License, or (at your option) any later version. +# +# This file is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program. If not, see . +# +# SPDX-License-Identifier: LGPL-3.0-or-later + + +from .gtkbuilder_template import Template +from .values import Value, ObjectValue +from .common import * +from .contexts import ValueTypeCtx +from .property_binding import PropertyBinding +from .binding import Binding + + +class Property(AstNode): + grammar = Statement( + UseIdent("name"), ":", AnyOf(PropertyBinding, Binding, ObjectValue, Value) + ) + + @property + def name(self) -> str: + return self.tokens["name"] + + @property + def value(self) -> T.Union[PropertyBinding, Binding, ObjectValue, Value]: + return self.children[0] + + @property + def gir_class(self): + return self.parent.parent.gir_class + + @property + def gir_property(self): + if self.gir_class is not None and not isinstance(self.gir_class, ExternType): + return self.gir_class.properties.get(self.tokens["name"]) + + @validate() + def binding_valid(self): + if ( + (isinstance(self.value, PropertyBinding) or isinstance(self.value, Binding)) + and self.gir_property is not None + and self.gir_property.construct_only + ): + raise CompileError( + f"{self.gir_property.full_name} can't be bound because it is construct-only", + hints=["construct-only properties may only be set to a static value"], + ) + + @context(ValueTypeCtx) + def value_type(self) -> ValueTypeCtx: + if self.gir_property is not None: + type = self.gir_property.type + else: + type = None + + return ValueTypeCtx(type) + + @validate("name") + def property_exists(self): + if self.gir_class is None or self.gir_class.incomplete: + # Objects that we have no gir data on should not be validated + # This happens for classes defined by the app itself + return + + if self.gir_property is None: + raise CompileError( + f"Class {self.gir_class.full_name} does not have a property called {self.tokens['name']}", + did_you_mean=(self.tokens["name"], self.gir_class.properties.keys()), + ) + + @validate("name") + def property_writable(self): + if self.gir_property is not None and not self.gir_property.writable: + raise CompileError(f"{self.gir_property.full_name} is not writable") + + @validate("name") + def unique_in_parent(self): + self.validate_unique_in_parent( + f"Duplicate property '{self.tokens['name']}'", + check=lambda child: child.tokens["name"] == self.tokens["name"], + ) + + @docs("name") + def property_docs(self): + if self.gir_property is not None: + return self.gir_property.doc diff --git a/.flatpak-builder/cache/objects/91/d1c567c009d029c245331a418fbc3f9e2eec207331587cf60a468ebdc53978.file b/.flatpak-builder/cache/objects/91/d1c567c009d029c245331a418fbc3f9e2eec207331587cf60a468ebdc53978.file new file mode 100644 index 0000000..dc84b39 --- /dev/null +++ b/.flatpak-builder/cache/objects/91/d1c567c009d029c245331a418fbc3f9e2eec207331587cf60a468ebdc53978.file @@ -0,0 +1,552 @@ +/* + * File generated by the tools/information-schema-types program from the + * libgda/information_schema.xml file, + * This file contains declaration of the expected data types when + * extracting meta data, it should be updated when the libgda/information_schema.xml file changes + * DO NOT MODIFY + */ + + +#ifdef __GNUC__ +#define MAY_BE_UNUSED __attribute__ ((unused)) +#else +#define MAY_BE_UNUSED +#endif + + + +/* + * TABLE: _attributes + * + * Table to store (key,value) pairs (keys starting with '_' are reserved) + */ +MAY_BE_UNUSED static GType _col_types_attributes[] = { + G_TYPE_STRING /* column: att_name */ +, G_TYPE_STRING /* column: att_value */ +, G_TYPE_NONE /* end of array marker */ +}; + + + +/* + * TABLE: _information_schema_catalog_name + * + * Name of the current database (current catalog), has only one row + */ +MAY_BE_UNUSED static GType _col_types_information_schema_catalog_name[] = { + G_TYPE_STRING /* column: catalog_name */ +, G_TYPE_NONE /* end of array marker */ +}; + + + +/* + * TABLE: _schemata + * + * List of schemas + */ +MAY_BE_UNUSED static GType _col_types_schemata[] = { + G_TYPE_STRING /* column: catalog_name */ +, G_TYPE_STRING /* column: schema_name */ +, G_TYPE_STRING /* column: schema_owner */ +, G_TYPE_BOOLEAN /* column: schema_internal */ +, G_TYPE_BOOLEAN /* column: schema_default */ +, G_TYPE_NONE /* end of array marker */ +}; + + + +/* + * TABLE: _builtin_data_types + * + * List of built-in data types such as varchar, int, ... + */ +MAY_BE_UNUSED static GType _col_types_builtin_data_types[] = { + G_TYPE_STRING /* column: short_type_name */ +, G_TYPE_STRING /* column: full_type_name */ +, G_TYPE_STRING /* column: gtype */ +, G_TYPE_STRING /* column: comments */ +, G_TYPE_STRING /* column: synonyms */ +, G_TYPE_BOOLEAN /* column: internal */ +, G_TYPE_NONE /* end of array marker */ +}; + + + +/* + * TABLE: _udt + * + * User defined data types + */ +MAY_BE_UNUSED static GType _col_types_udt[] = { + G_TYPE_STRING /* column: udt_catalog */ +, G_TYPE_STRING /* column: udt_schema */ +, G_TYPE_STRING /* column: udt_name */ +, G_TYPE_STRING /* column: udt_gtype */ +, G_TYPE_STRING /* column: udt_comments */ +, G_TYPE_STRING /* column: udt_short_name */ +, G_TYPE_STRING /* column: udt_full_name */ +, G_TYPE_BOOLEAN /* column: udt_internal */ +, G_TYPE_STRING /* column: udt_owner */ +, G_TYPE_NONE /* end of array marker */ +}; + + + +/* + * TABLE: _udt_columns + * + * List of components for a user defined data type for composed data types (such as a complex number data type which has real and imaginary parts) + */ +MAY_BE_UNUSED static GType _col_types_udt_columns[] = { + G_TYPE_STRING /* column: udt_catalog */ +, G_TYPE_STRING /* column: udt_schema */ +, G_TYPE_STRING /* column: udt_name */ +, G_TYPE_STRING /* column: udt_column */ +, G_TYPE_INT /* column: ordinal_position */ +, G_TYPE_STRING /* column: data_type */ +, G_TYPE_STRING /* column: array_spec */ +, G_TYPE_INT /* column: character_maximum_length */ +, G_TYPE_INT /* column: character_octet_length */ +, G_TYPE_INT /* column: numeric_precision */ +, G_TYPE_INT /* column: numeric_scale */ +, G_TYPE_INT /* column: datetime_precision */ +, G_TYPE_STRING /* column: character_set_catalog */ +, G_TYPE_STRING /* column: character_set_schema */ +, G_TYPE_STRING /* column: character_set_name */ +, G_TYPE_STRING /* column: collation_catalog */ +, G_TYPE_STRING /* column: collation_schema */ +, G_TYPE_STRING /* column: collation_name */ +, G_TYPE_NONE /* end of array marker */ +}; + + + +/* + * TABLE: _enums + * + * List of possible enumeration labels for enumerations + */ +MAY_BE_UNUSED static GType _col_types_enums[] = { + G_TYPE_STRING /* column: udt_catalog */ +, G_TYPE_STRING /* column: udt_schema */ +, G_TYPE_STRING /* column: udt_name */ +, G_TYPE_STRING /* column: label */ +, G_TYPE_INT /* column: ordinal_position */ +, G_TYPE_NONE /* end of array marker */ +}; + + + +/* + * TABLE: _element_types + * + * Array specific attributes for array data types + */ +MAY_BE_UNUSED static GType _col_types_element_types[] = { + G_TYPE_STRING /* column: specific_name */ +, G_TYPE_STRING /* column: object_catalog */ +, G_TYPE_STRING /* column: object_schema */ +, G_TYPE_STRING /* column: object_name */ +, G_TYPE_STRING /* column: object_type */ +, G_TYPE_STRING /* column: data_type */ +, G_TYPE_STRING /* column: array_spec */ +, G_TYPE_INT /* column: min_cardinality */ +, G_TYPE_INT /* column: max_cardinality */ +, G_TYPE_NONE /* end of array marker */ +}; + + + +/* + * TABLE: _domains + * + * List of domains + */ +MAY_BE_UNUSED static GType _col_types_domains[] = { + G_TYPE_STRING /* column: domain_catalog */ +, G_TYPE_STRING /* column: domain_schema */ +, G_TYPE_STRING /* column: domain_name */ +, G_TYPE_STRING /* column: data_type */ +, G_TYPE_STRING /* column: array_spec */ +, G_TYPE_STRING /* column: domain_gtype */ +, G_TYPE_INT /* column: character_maximum_length */ +, G_TYPE_INT /* column: character_octet_length */ +, G_TYPE_STRING /* column: collation_catalog */ +, G_TYPE_STRING /* column: collation_schema */ +, G_TYPE_STRING /* column: collation_name */ +, G_TYPE_STRING /* column: character_set_catalog */ +, G_TYPE_STRING /* column: character_set_schema */ +, G_TYPE_STRING /* column: character_set_name */ +, G_TYPE_INT /* column: numeric_precision */ +, G_TYPE_INT /* column: numeric_scale */ +, G_TYPE_STRING /* column: domain_default */ +, G_TYPE_STRING /* column: domain_comments */ +, G_TYPE_STRING /* column: domain_short_name */ +, G_TYPE_STRING /* column: domain_full_name */ +, G_TYPE_BOOLEAN /* column: domain_internal */ +, G_TYPE_STRING /* column: domain_owner */ +, G_TYPE_NONE /* end of array marker */ +}; + + + +/* + * TABLE: _tables + * + * List of tables (tables, views or other objects which can contain data) + */ +MAY_BE_UNUSED static GType _col_types_tables[] = { + G_TYPE_STRING /* column: table_catalog */ +, G_TYPE_STRING /* column: table_schema */ +, G_TYPE_STRING /* column: table_name */ +, G_TYPE_STRING /* column: table_type */ +, G_TYPE_BOOLEAN /* column: is_insertable_into */ +, G_TYPE_STRING /* column: table_comments */ +, G_TYPE_STRING /* column: table_short_name */ +, G_TYPE_STRING /* column: table_full_name */ +, G_TYPE_STRING /* column: table_owner */ +, G_TYPE_NONE /* end of array marker */ +}; + + + +/* + * TABLE: _views + * + * List of views and their specific information + */ +MAY_BE_UNUSED static GType _col_types_views[] = { + G_TYPE_STRING /* column: table_catalog */ +, G_TYPE_STRING /* column: table_schema */ +, G_TYPE_STRING /* column: table_name */ +, G_TYPE_STRING /* column: view_definition */ +, G_TYPE_STRING /* column: check_option */ +, G_TYPE_BOOLEAN /* column: is_updatable */ +, G_TYPE_NONE /* end of array marker */ +}; + + + +/* + * TABLE: _collations + * + * List of collations methods + */ +MAY_BE_UNUSED static GType _col_types_collations[] = { + G_TYPE_STRING /* column: collation_catalog */ +, G_TYPE_STRING /* column: collation_schema */ +, G_TYPE_STRING /* column: collation_name */ +, G_TYPE_STRING /* column: collation_comments */ +, G_TYPE_STRING /* column: collation_short_name */ +, G_TYPE_STRING /* column: collation_full_name */ +, G_TYPE_NONE /* end of array marker */ +}; + + + +/* + * TABLE: _character_sets + * + * List of character sets + */ +MAY_BE_UNUSED static GType _col_types_character_sets[] = { + G_TYPE_STRING /* column: character_set_catalog */ +, G_TYPE_STRING /* column: character_set_schema */ +, G_TYPE_STRING /* column: character_set_name */ +, G_TYPE_STRING /* column: default_collate_catalog */ +, G_TYPE_STRING /* column: default_collate_schema */ +, G_TYPE_STRING /* column: default_collate_name */ +, G_TYPE_STRING /* column: character_set_comments */ +, G_TYPE_STRING /* column: character_set_short_name */ +, G_TYPE_STRING /* column: character_set_full_name */ +, G_TYPE_NONE /* end of array marker */ +}; + + + +/* + * TABLE: _routines + * + * List of functions and stored procedures (note: the primary jey for that table is composed of (specific_catalog, specific_schema, specific_name)) + */ +MAY_BE_UNUSED static GType _col_types_routines[] = { + G_TYPE_STRING /* column: specific_catalog */ +, G_TYPE_STRING /* column: specific_schema */ +, G_TYPE_STRING /* column: specific_name */ +, G_TYPE_STRING /* column: routine_catalog */ +, G_TYPE_STRING /* column: routine_schema */ +, G_TYPE_STRING /* column: routine_name */ +, G_TYPE_STRING /* column: routine_type */ +, G_TYPE_STRING /* column: return_type */ +, G_TYPE_BOOLEAN /* column: returns_set */ +, G_TYPE_INT /* column: nb_args */ +, G_TYPE_STRING /* column: routine_body */ +, G_TYPE_STRING /* column: routine_definition */ +, G_TYPE_STRING /* column: external_name */ +, G_TYPE_STRING /* column: external_language */ +, G_TYPE_STRING /* column: parameter_style */ +, G_TYPE_BOOLEAN /* column: is_deterministic */ +, G_TYPE_STRING /* column: sql_data_access */ +, G_TYPE_BOOLEAN /* column: is_null_call */ +, G_TYPE_STRING /* column: routine_comments */ +, G_TYPE_STRING /* column: routine_short_name */ +, G_TYPE_STRING /* column: routine_full_name */ +, G_TYPE_STRING /* column: routine_owner */ +, G_TYPE_NONE /* end of array marker */ +}; + + + +/* + * TABLE: _triggers + * + * List of triggers + */ +MAY_BE_UNUSED static GType _col_types_triggers[] = { + G_TYPE_STRING /* column: trigger_catalog */ +, G_TYPE_STRING /* column: trigger_schema */ +, G_TYPE_STRING /* column: trigger_name */ +, G_TYPE_STRING /* column: event_manipulation */ +, G_TYPE_STRING /* column: event_object_catalog */ +, G_TYPE_STRING /* column: event_object_schema */ +, G_TYPE_STRING /* column: event_object_table */ +, G_TYPE_STRING /* column: action_statement */ +, G_TYPE_STRING /* column: action_orientation */ +, G_TYPE_STRING /* column: condition_timing */ +, G_TYPE_STRING /* column: trigger_comments */ +, G_TYPE_STRING /* column: trigger_short_name */ +, G_TYPE_STRING /* column: trigger_full_name */ +, G_TYPE_NONE /* end of array marker */ +}; + + + +/* + * TABLE: _columns + * + * List of columns composing tables + */ +MAY_BE_UNUSED static GType _col_types_columns[] = { + G_TYPE_STRING /* column: table_catalog */ +, G_TYPE_STRING /* column: table_schema */ +, G_TYPE_STRING /* column: table_name */ +, G_TYPE_STRING /* column: column_name */ +, G_TYPE_INT /* column: ordinal_position */ +, G_TYPE_STRING /* column: column_default */ +, G_TYPE_BOOLEAN /* column: is_nullable */ +, G_TYPE_STRING /* column: data_type */ +, G_TYPE_STRING /* column: array_spec */ +, G_TYPE_STRING /* column: gtype */ +, G_TYPE_INT /* column: character_maximum_length */ +, G_TYPE_INT /* column: character_octet_length */ +, G_TYPE_INT /* column: numeric_precision */ +, G_TYPE_INT /* column: numeric_scale */ +, G_TYPE_INT /* column: datetime_precision */ +, G_TYPE_STRING /* column: character_set_catalog */ +, G_TYPE_STRING /* column: character_set_schema */ +, G_TYPE_STRING /* column: character_set_name */ +, G_TYPE_STRING /* column: collation_catalog */ +, G_TYPE_STRING /* column: collation_schema */ +, G_TYPE_STRING /* column: collation_name */ +, G_TYPE_STRING /* column: extra */ +, G_TYPE_BOOLEAN /* column: is_updatable */ +, G_TYPE_STRING /* column: column_comments */ +, G_TYPE_NONE /* end of array marker */ +}; + + + +/* + * TABLE: _table_constraints + * + * List of constraints applied to tables (Check, primary or foreign key, or unique constraints) + */ +MAY_BE_UNUSED static GType _col_types_table_constraints[] = { + G_TYPE_STRING /* column: constraint_catalog */ +, G_TYPE_STRING /* column: constraint_schema */ +, G_TYPE_STRING /* column: constraint_name */ +, G_TYPE_STRING /* column: table_catalog */ +, G_TYPE_STRING /* column: table_schema */ +, G_TYPE_STRING /* column: table_name */ +, G_TYPE_STRING /* column: constraint_type */ +, G_TYPE_STRING /* column: check_clause */ +, G_TYPE_BOOLEAN /* column: is_deferrable */ +, G_TYPE_BOOLEAN /* column: initially_deferred */ +, G_TYPE_NONE /* end of array marker */ +}; + + + +/* + * TABLE: _referential_constraints + * + * List of foreign key constraints, along with some specific attributes + */ +MAY_BE_UNUSED static GType _col_types_referential_constraints[] = { + G_TYPE_STRING /* column: table_catalog */ +, G_TYPE_STRING /* column: table_schema */ +, G_TYPE_STRING /* column: table_name */ +, G_TYPE_STRING /* column: constraint_name */ +, G_TYPE_STRING /* column: ref_table_catalog */ +, G_TYPE_STRING /* column: ref_table_schema */ +, G_TYPE_STRING /* column: ref_table_name */ +, G_TYPE_STRING /* column: ref_constraint_name */ +, G_TYPE_STRING /* column: match_option */ +, G_TYPE_STRING /* column: update_rule */ +, G_TYPE_STRING /* column: delete_rule */ +, G_TYPE_NONE /* end of array marker */ +}; + + + +/* + * TABLE: _key_column_usage + * + * List of primary key constraints and the name of the tables' columns involved + */ +MAY_BE_UNUSED static GType _col_types_key_column_usage[] = { + G_TYPE_STRING /* column: table_catalog */ +, G_TYPE_STRING /* column: table_schema */ +, G_TYPE_STRING /* column: table_name */ +, G_TYPE_STRING /* column: constraint_name */ +, G_TYPE_STRING /* column: column_name */ +, G_TYPE_INT /* column: ordinal_position */ +, G_TYPE_NONE /* end of array marker */ +}; + + + +/* + * TABLE: _check_column_usage + * + * List of check constraints and the name of the tables' columns involved + */ +MAY_BE_UNUSED static GType _col_types_check_column_usage[] = { + G_TYPE_STRING /* column: table_catalog */ +, G_TYPE_STRING /* column: table_schema */ +, G_TYPE_STRING /* column: table_name */ +, G_TYPE_STRING /* column: constraint_name */ +, G_TYPE_STRING /* column: column_name */ +, G_TYPE_NONE /* end of array marker */ +}; + + + +/* + * TABLE: _view_column_usage + * + * List of the tables' columns involved in a view + */ +MAY_BE_UNUSED static GType _col_types_view_column_usage[] = { + G_TYPE_STRING /* column: view_catalog */ +, G_TYPE_STRING /* column: view_schema */ +, G_TYPE_STRING /* column: view_name */ +, G_TYPE_STRING /* column: table_catalog */ +, G_TYPE_STRING /* column: table_schema */ +, G_TYPE_STRING /* column: table_name */ +, G_TYPE_STRING /* column: column_name */ +, G_TYPE_NONE /* end of array marker */ +}; + + + +/* + * TABLE: _domain_constraints + * + * List of constraints applicable to domains + */ +MAY_BE_UNUSED static GType _col_types_domain_constraints[] = { + G_TYPE_STRING /* column: constraint_catalog */ +, G_TYPE_STRING /* column: constraint_schema */ +, G_TYPE_STRING /* column: constraint_name */ +, G_TYPE_STRING /* column: domain_catalog */ +, G_TYPE_STRING /* column: domain_schema */ +, G_TYPE_STRING /* column: domain_name */ +, G_TYPE_STRING /* column: check_clause */ +, G_TYPE_BOOLEAN /* column: is_deferrable */ +, G_TYPE_BOOLEAN /* column: initially_deferred */ +, G_TYPE_NONE /* end of array marker */ +}; + + + +/* + * TABLE: _parameters + * + * List of routines' (functions and stored procedures) parameters (may not contain data for some routines which accept any type of parameter) + */ +MAY_BE_UNUSED static GType _col_types_parameters[] = { + G_TYPE_STRING /* column: specific_catalog */ +, G_TYPE_STRING /* column: specific_schema */ +, G_TYPE_STRING /* column: specific_name */ +, G_TYPE_INT /* column: ordinal_position */ +, G_TYPE_STRING /* column: parameter_mode */ +, G_TYPE_STRING /* column: parameter_name */ +, G_TYPE_STRING /* column: data_type */ +, G_TYPE_STRING /* column: array_spec */ +, G_TYPE_NONE /* end of array marker */ +}; + + + +/* + * TABLE: _routine_columns + * + * List of routines' (functions and stored procedures) returned values' parts (columns) for routines returning composed values + */ +MAY_BE_UNUSED static GType _col_types_routine_columns[] = { + G_TYPE_STRING /* column: specific_catalog */ +, G_TYPE_STRING /* column: specific_schema */ +, G_TYPE_STRING /* column: specific_name */ +, G_TYPE_STRING /* column: column_name */ +, G_TYPE_INT /* column: ordinal_position */ +, G_TYPE_STRING /* column: data_type */ +, G_TYPE_STRING /* column: array_spec */ +, G_TYPE_NONE /* end of array marker */ +}; + + + +/* + * TABLE: _table_indexes + * + * List of tables' indexes which do not relate to primary keys + */ +MAY_BE_UNUSED static GType _col_types_table_indexes[] = { + G_TYPE_STRING /* column: index_catalog */ +, G_TYPE_STRING /* column: index_schema */ +, G_TYPE_STRING /* column: index_name */ +, G_TYPE_STRING /* column: table_catalog */ +, G_TYPE_STRING /* column: table_schema */ +, G_TYPE_STRING /* column: table_name */ +, G_TYPE_BOOLEAN /* column: is_unique */ +, G_TYPE_STRING /* column: index_def */ +, G_TYPE_STRING /* column: index_type */ +, G_TYPE_STRING /* column: extra */ +, G_TYPE_STRING /* column: index_owner */ +, G_TYPE_STRING /* column: index_comments */ +, G_TYPE_NONE /* end of array marker */ +}; + + + +/* + * TABLE: _index_column_usage + * + * List of the tables' columns involved in an index listed in the _table_indexes table + */ +MAY_BE_UNUSED static GType _col_types_index_column_usage[] = { + G_TYPE_STRING /* column: index_catalog */ +, G_TYPE_STRING /* column: index_schema */ +, G_TYPE_STRING /* column: index_name */ +, G_TYPE_STRING /* column: table_catalog */ +, G_TYPE_STRING /* column: table_schema */ +, G_TYPE_STRING /* column: table_name */ +, G_TYPE_STRING /* column: column_name */ +, G_TYPE_STRING /* column: column_expr */ +, G_TYPE_INT /* column: ordinal_position */ +, G_TYPE_NONE /* end of array marker */ +}; + +#undef MAY_BE_UNUSED diff --git a/.flatpak-builder/cache/objects/92/1697dee24225efd87d240d76ea27c866da7a76e59cbf06fb603072ad5a23b9.dirtree b/.flatpak-builder/cache/objects/92/1697dee24225efd87d240d76ea27c866da7a76e59cbf06fb603072ad5a23b9.dirtree new file mode 100644 index 0000000..871e531 Binary files /dev/null and b/.flatpak-builder/cache/objects/92/1697dee24225efd87d240d76ea27c866da7a76e59cbf06fb603072ad5a23b9.dirtree differ diff --git a/.flatpak-builder/cache/objects/92/1af5fef0174b147612a41be597c2376663ea8b8178cbdac1785a2c74307191.file b/.flatpak-builder/cache/objects/92/1af5fef0174b147612a41be597c2376663ea8b8178cbdac1785a2c74307191.file new file mode 100644 index 0000000..bf85a7a Binary files /dev/null and b/.flatpak-builder/cache/objects/92/1af5fef0174b147612a41be597c2376663ea8b8178cbdac1785a2c74307191.file differ diff --git a/.flatpak-builder/cache/objects/92/2c0b8c638fb393c6639608adeb982abb2989c176a71ac2e614617bc0419526.dirtree b/.flatpak-builder/cache/objects/92/2c0b8c638fb393c6639608adeb982abb2989c176a71ac2e614617bc0419526.dirtree new file mode 100644 index 0000000..2e2aaa7 Binary files /dev/null and b/.flatpak-builder/cache/objects/92/2c0b8c638fb393c6639608adeb982abb2989c176a71ac2e614617bc0419526.dirtree differ diff --git a/.flatpak-builder/cache/objects/92/2ed3ec8bc963ac947ccba143c5b4ab9d814ba9b9bfa5b2e46114242c2da8f5.file b/.flatpak-builder/cache/objects/92/2ed3ec8bc963ac947ccba143c5b4ab9d814ba9b9bfa5b2e46114242c2da8f5.file new file mode 120000 index 0000000..3605254 --- /dev/null +++ b/.flatpak-builder/cache/objects/92/2ed3ec8bc963ac947ccba143c5b4ab9d814ba9b9bfa5b2e46114242c2da8f5.file @@ -0,0 +1 @@ +../../share/runtime/locale/bs/share/bs \ No newline at end of file diff --git a/.flatpak-builder/cache/objects/92/6d51d2213ebd9331bace15f7d198069d5a67fff621e2dd910926d204445f70.file b/.flatpak-builder/cache/objects/92/6d51d2213ebd9331bace15f7d198069d5a67fff621e2dd910926d204445f70.file new file mode 100644 index 0000000..33420b1 Binary files /dev/null and b/.flatpak-builder/cache/objects/92/6d51d2213ebd9331bace15f7d198069d5a67fff621e2dd910926d204445f70.file differ diff --git a/.flatpak-builder/cache/objects/92/8b415e5609156c6f266218a5be85e3144ec21135796f8d056e6bb1ea9dfebd.file b/.flatpak-builder/cache/objects/92/8b415e5609156c6f266218a5be85e3144ec21135796f8d056e6bb1ea9dfebd.file new file mode 100644 index 0000000..e28a517 --- /dev/null +++ b/.flatpak-builder/cache/objects/92/8b415e5609156c6f266218a5be85e3144ec21135796f8d056e6bb1ea9dfebd.file @@ -0,0 +1,1344 @@ +/*-*- Mode: C; c-basic-offset: 8 -*-*/ + +/*** + This file is part of libcanberra. + + Copyright 2008 Lennart Poettering + + libcanberra is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation, either version 2.1 of the + License, or (at your option) any later version. + + libcanberra is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with libcanberra. If not, see + . +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +/* The locking order needs to be strictly followed! First take the + * mainloop mutex, only then take outstanding_mutex if you need both! + * Not the other way round, beacause we might then enter a + * deadlock! */ + +#include +#include + +#include +#include +#include +#include +#include + +#include "canberra.h" +#include "common.h" +#include "driver.h" +#include "llist.h" +#include "read-sound-file.h" +#include "sound-theme-spec.h" +#include "malloc.h" + +enum outstanding_type { + OUTSTANDING_SAMPLE, + OUTSTANDING_STREAM, + OUTSTANDING_UPLOAD +}; + +struct outstanding { + CA_LLIST_FIELDS(struct outstanding); + enum outstanding_type type; + ca_context *context; + uint32_t id; + uint32_t sink_input; + pa_stream *stream; + pa_operation *drain_operation; + ca_finish_callback_t callback; + void *userdata; + ca_sound_file *file; + int error; + unsigned clean_up:1; /* Handler needs to clean up the outstanding struct */ + unsigned finished:1; /* finished playing */ +}; + +struct private { + pa_threaded_mainloop *mainloop; + pa_context *context; + ca_theme_data *theme; + ca_bool_t subscribed; + ca_bool_t reconnect; + + ca_mutex *outstanding_mutex; + CA_LLIST_HEAD(struct outstanding, outstanding); +}; + +#define PRIVATE(c) ((struct private *) ((c)->private)) + +static void context_state_cb(pa_context *pc, void *userdata); +static void context_subscribe_cb(pa_context *pc, pa_subscription_event_type_t t, uint32_t idx, void *userdata); + +static void outstanding_disconnect(struct outstanding *o) { + ca_assert(o); + + if (o->stream) { + if (o->drain_operation) { + pa_operation_cancel(o->drain_operation); + pa_operation_unref(o->drain_operation); + o->drain_operation = NULL; + } + + pa_stream_set_write_callback(o->stream, NULL, NULL); + pa_stream_set_state_callback(o->stream, NULL, NULL); + pa_stream_disconnect(o->stream); + pa_stream_unref(o->stream); + o->stream = NULL; + } +} + +static void outstanding_free(struct outstanding *o) { + ca_assert(o); + + outstanding_disconnect(o); + + if (o->file) + ca_sound_file_close(o->file); + + ca_free(o); +} + +static int convert_proplist(pa_proplist **_l, ca_proplist *c) { + pa_proplist *l; + ca_prop *i; + + ca_return_val_if_fail(_l, CA_ERROR_INVALID); + ca_return_val_if_fail(c, CA_ERROR_INVALID); + + if (!(l = pa_proplist_new())) + return CA_ERROR_OOM; + + ca_mutex_lock(c->mutex); + + for (i = c->first_item; i; i = i->next_item) + if (pa_proplist_set(l, i->key, CA_PROP_DATA(i), i->nbytes) < 0) { + ca_mutex_unlock(c->mutex); + pa_proplist_free(l); + return CA_ERROR_INVALID; + } + + ca_mutex_unlock(c->mutex); + + *_l = l; + + return CA_SUCCESS; +} + +static pa_proplist *strip_prefix(pa_proplist *l, const char *prefix) { + const char *key; + void *state = NULL; + ca_assert(l); + + while ((key = pa_proplist_iterate(l, &state))) + if (strncmp(key, prefix, strlen(prefix)) == 0) + pa_proplist_unset(l, key); + + return l; +} + +static void add_common(pa_proplist *l) { + ca_assert(l); + + if (!pa_proplist_contains(l, CA_PROP_MEDIA_ROLE)) + pa_proplist_sets(l, CA_PROP_MEDIA_ROLE, "event"); + + if (!pa_proplist_contains(l, CA_PROP_MEDIA_NAME)) { + const char *t; + + if ((t = pa_proplist_gets(l, CA_PROP_EVENT_ID))) + pa_proplist_sets(l, CA_PROP_MEDIA_NAME, t); + else if ((t = pa_proplist_gets(l, CA_PROP_MEDIA_FILENAME))) + pa_proplist_sets(l, CA_PROP_MEDIA_NAME, t); + else + pa_proplist_sets(l, CA_PROP_MEDIA_NAME, "libcanberra"); + } +} + +static int translate_error(int error) { + static const int table[PA_ERR_MAX] = { + [PA_OK] = CA_SUCCESS, + [PA_ERR_ACCESS] = CA_ERROR_ACCESS, + [PA_ERR_COMMAND] = CA_ERROR_IO, + [PA_ERR_INVALID] = CA_ERROR_INVALID, + [PA_ERR_EXIST] = CA_ERROR_IO, + [PA_ERR_NOENTITY] = CA_ERROR_NOTFOUND, + [PA_ERR_CONNECTIONREFUSED] = CA_ERROR_NOTAVAILABLE, + [PA_ERR_PROTOCOL] = CA_ERROR_IO, + [PA_ERR_TIMEOUT] = CA_ERROR_IO, + [PA_ERR_AUTHKEY] = CA_ERROR_ACCESS, + [PA_ERR_INTERNAL] = CA_ERROR_IO, + [PA_ERR_CONNECTIONTERMINATED] = CA_ERROR_IO, + [PA_ERR_KILLED] = CA_ERROR_DESTROYED, + [PA_ERR_INVALIDSERVER] = CA_ERROR_INVALID, + [PA_ERR_MODINITFAILED] = CA_ERROR_NODRIVER, + [PA_ERR_BADSTATE] = CA_ERROR_STATE, + [PA_ERR_NODATA] = CA_ERROR_IO, + [PA_ERR_VERSION] = CA_ERROR_NOTSUPPORTED, + [PA_ERR_TOOLARGE] = CA_ERROR_TOOBIG, +#ifdef PA_ERR_NOTSUPPORTED + [PA_ERR_NOTSUPPORTED] = CA_ERROR_NOTSUPPORTED, +#endif +#ifdef PA_ERR_UNKNOWN + [PA_ERR_UNKNOWN] = CA_ERROR_IO, +#endif +#ifdef PA_ERR_NOEXTENSION + [PA_ERR_NOEXTENSION] = CA_ERROR_NOTSUPPORTED, +#endif +#ifdef PA_ERR_OBSOLETE + [PA_ERR_OBSOLETE] = CA_ERROR_NOTSUPPORTED, +#endif +#ifdef PA_ERR_NOTIMPLEMENTED + [PA_ERR_NOTIMPLEMENTED] = CA_ERROR_NOTSUPPORTED +#endif + }; + + ca_assert(error >= 0); + + if (error >= PA_ERR_MAX || !table[error]) + return CA_ERROR_IO; + + return table[error]; +} + +static int context_connect(ca_context *c, ca_bool_t nofail) { + pa_proplist *l; + struct private *p; + int ret; + + ca_return_val_if_fail(c, CA_ERROR_INVALID); + ca_return_val_if_fail(p = c->private, CA_ERROR_STATE); + ca_return_val_if_fail(p->mainloop, CA_ERROR_STATE); + ca_return_val_if_fail(!p->context, CA_ERROR_STATE); + + /* If this immediate attempt fails, don't try to reconnect. */ + p->reconnect = FALSE; + + if ((ret = convert_proplist(&l, c->props)) < 0) + return ret; + + strip_prefix(l, "canberra."); + + if (!pa_proplist_contains(l, PA_PROP_APPLICATION_NAME)) { + pa_proplist_sets(l, PA_PROP_APPLICATION_NAME, "libcanberra"); + pa_proplist_sets(l, PA_PROP_APPLICATION_VERSION, PACKAGE_VERSION); + + if (!pa_proplist_contains(l, PA_PROP_APPLICATION_ID)) + pa_proplist_sets(l, PA_PROP_APPLICATION_ID, "org.freedesktop.libcanberra"); + + } + + if (!(p->context = pa_context_new_with_proplist(pa_threaded_mainloop_get_api(p->mainloop), NULL, l))) { + pa_proplist_free(l); + return CA_ERROR_OOM; + } + + pa_proplist_free(l); + + pa_context_set_state_callback(p->context, context_state_cb, c); + pa_context_set_subscribe_callback(p->context, context_subscribe_cb, c); + + if (pa_context_connect(p->context, NULL, nofail ? PA_CONTEXT_NOFAIL : 0, NULL) < 0) { + ret = translate_error(p->context ? pa_context_errno(p->context) : PA_ERR_CONNECTIONREFUSED); + + if (p->context) { + pa_context_disconnect(p->context); + pa_context_unref(p->context); + p->context = NULL; + } + + return ret; + } + + return CA_SUCCESS; +} + +static void context_state_cb(pa_context *pc, void *userdata) { + ca_context *c = userdata; + pa_context_state_t state; + struct private *p; + + ca_assert(pc); + ca_assert(c); + + p = PRIVATE(c); + + state = pa_context_get_state(pc); + if (state == PA_CONTEXT_FAILED || state == PA_CONTEXT_TERMINATED) { + struct outstanding *out; + int ret; + + if (state == PA_CONTEXT_TERMINATED) + ret = CA_ERROR_DESTROYED; + else + ret = translate_error(pa_context_errno(pc)); + + ca_mutex_lock(p->outstanding_mutex); + + while ((out = p->outstanding)) { + + outstanding_disconnect(out); + CA_LLIST_REMOVE(struct outstanding, p->outstanding, out); + + ca_mutex_unlock(p->outstanding_mutex); + + if (out->callback) + out->callback(c, out->id, ret, out->userdata); + + outstanding_free(out); + + ca_mutex_lock(p->outstanding_mutex); + } + + ca_mutex_unlock(p->outstanding_mutex); + + if (state == PA_CONTEXT_FAILED && p->reconnect) { + + if (p->context) { + pa_context_disconnect(p->context); + pa_context_unref(p->context); + p->context = NULL; + } + + p->subscribed = FALSE; + + /* If we managed to connect once, then let's try to + * reconnect, and pass NOFAIL */ + context_connect(c, TRUE); + } + + } else if (state == PA_CONTEXT_READY) + /* OK, the connection suceeded once, if it dies now try to + * reconnect */ + p->reconnect = TRUE; + + pa_threaded_mainloop_signal(p->mainloop, FALSE); +} + +static void context_subscribe_cb(pa_context *pc, pa_subscription_event_type_t t, uint32_t idx, void *userdata) { + struct outstanding *out, *n; + CA_LLIST_HEAD(struct outstanding, l); + ca_context *c = userdata; + struct private *p; + + ca_assert(pc); + ca_assert(c); + + if (t != (PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_REMOVE)) + return; + + p = PRIVATE(c); + + CA_LLIST_HEAD_INIT(struct outstanding, l); + + ca_mutex_lock(p->outstanding_mutex); + + for (out = p->outstanding; out; out = n) { + n = out->next; + + if (!out->clean_up || out->type != OUTSTANDING_SAMPLE || out->sink_input != idx) + continue; + + outstanding_disconnect(out); + CA_LLIST_REMOVE(struct outstanding, p->outstanding, out); + + CA_LLIST_PREPEND(struct outstanding, l, out); + } + + ca_mutex_unlock(p->outstanding_mutex); + + while (l) { + out = l; + + CA_LLIST_REMOVE(struct outstanding, l, out); + + if (out->callback) + out->callback(c, out->id, CA_SUCCESS, out->userdata); + + outstanding_free(out); + } +} + +int driver_open(ca_context *c) { + struct private *p; + int ret; + + ca_return_val_if_fail(c, CA_ERROR_INVALID); + ca_return_val_if_fail(!c->driver || ca_streq(c->driver, "pulse"), CA_ERROR_NODRIVER); + ca_return_val_if_fail(!PRIVATE(c), CA_ERROR_STATE); + + if (!(c->private = p = ca_new0(struct private, 1))) + return CA_ERROR_OOM; + + if (!(p->outstanding_mutex = ca_mutex_new())) { + driver_destroy(c); + return CA_ERROR_OOM; + } + + if (!(p->mainloop = pa_threaded_mainloop_new())) { + driver_destroy(c); + return CA_ERROR_OOM; + } + + /* The initial connection is without NOFAIL, since we want to have + * this call fail cleanly if we cannot connect. */ + if ((ret = context_connect(c, FALSE)) != CA_SUCCESS) { + driver_destroy(c); + return ret; + } + + pa_threaded_mainloop_lock(p->mainloop); + + if (pa_threaded_mainloop_start(p->mainloop) < 0) { + pa_threaded_mainloop_unlock(p->mainloop); + driver_destroy(c); + return CA_ERROR_OOM; + } + + for (;;) { + pa_context_state_t state; + + if (!p->context) { + ret = translate_error(PA_ERR_CONNECTIONREFUSED); + pa_threaded_mainloop_unlock(p->mainloop); + driver_destroy(c); + return ret; + } + + state = pa_context_get_state(p->context); + + if (state == PA_CONTEXT_READY) + break; + + if (state == PA_CONTEXT_FAILED) { + ret = translate_error(pa_context_errno(p->context)); + pa_threaded_mainloop_unlock(p->mainloop); + driver_destroy(c); + return ret; + } + + ca_assert(state != PA_CONTEXT_TERMINATED); + + pa_threaded_mainloop_wait(p->mainloop); + } + + pa_threaded_mainloop_unlock(p->mainloop); + + return CA_SUCCESS; +} + +int driver_destroy(ca_context *c) { + struct private *p; + + ca_return_val_if_fail(c, CA_ERROR_INVALID); + ca_return_val_if_fail(c->private, CA_ERROR_STATE); + + p = PRIVATE(c); + + if (p->mainloop) + pa_threaded_mainloop_stop(p->mainloop); + + if (p->context) { + pa_context_disconnect(p->context); + pa_context_unref(p->context); + } + + while (p->outstanding) { + struct outstanding *out = p->outstanding; + CA_LLIST_REMOVE(struct outstanding, p->outstanding, out); + + if (out->callback) + out->callback(c, out->id, CA_ERROR_DESTROYED, out->userdata); + + outstanding_free(out); + } + + if (p->mainloop) + pa_threaded_mainloop_free(p->mainloop); + + if (p->theme) + ca_theme_data_free(p->theme); + + if (p->outstanding_mutex) + ca_mutex_free(p->outstanding_mutex); + + ca_free(p); + + c->private = NULL; + + return CA_SUCCESS; +} + +int driver_change_device(ca_context *c, const char *device) { + ca_return_val_if_fail(c, CA_ERROR_INVALID); + ca_return_val_if_fail(c->private, CA_ERROR_STATE); + + /* We're happy with any device change. We might however add code + * here eventually to move all currently played back event sounds + * to the new device. */ + + return CA_SUCCESS; +} + +int driver_change_props(ca_context *c, ca_proplist *changed, ca_proplist *merged) { + struct private *p; + pa_operation *o; + pa_proplist *l; + int ret = CA_SUCCESS; + + ca_return_val_if_fail(c, CA_ERROR_INVALID); + ca_return_val_if_fail(changed, CA_ERROR_INVALID); + ca_return_val_if_fail(merged, CA_ERROR_INVALID); + ca_return_val_if_fail(c->private, CA_ERROR_STATE); + + p = PRIVATE(c); + + ca_return_val_if_fail(p->mainloop, CA_ERROR_STATE); + + pa_threaded_mainloop_lock(p->mainloop); + + if (!p->context) { + pa_threaded_mainloop_unlock(p->mainloop); + return CA_ERROR_STATE; /* can be silently ignored */ + } + + if ((ret = convert_proplist(&l, changed)) < 0) + return ret; + + strip_prefix(l, "canberra."); + + /* We start these asynchronously and don't care about the return + * value */ + + if (!(o = pa_context_proplist_update(p->context, PA_UPDATE_REPLACE, l, NULL, NULL))) + ret = translate_error(pa_context_errno(p->context)); + else + pa_operation_unref(o); + + pa_threaded_mainloop_unlock(p->mainloop); + + pa_proplist_free(l); + + return ret; +} + +static int subscribe(ca_context *c) { + struct private *p; + pa_operation *o; + int ret = CA_SUCCESS; + + ca_return_val_if_fail(c, CA_ERROR_INVALID); + ca_return_val_if_fail(c->private, CA_ERROR_STATE); + p = PRIVATE(c); + + ca_return_val_if_fail(p->mainloop, CA_ERROR_STATE); + + if (p->subscribed) + return CA_SUCCESS; + + pa_threaded_mainloop_lock(p->mainloop); + + if (!p->context) { + pa_threaded_mainloop_unlock(p->mainloop); + return CA_ERROR_STATE; + } + + /* We start these asynchronously and don't care about the return + * value */ + + if (!(o = pa_context_subscribe(p->context, PA_SUBSCRIPTION_MASK_SINK_INPUT, NULL, NULL))) + ret = translate_error(pa_context_errno(p->context)); + else + pa_operation_unref(o); + + pa_threaded_mainloop_unlock(p->mainloop); + + p->subscribed = TRUE; + + return ret; +} + +static void play_sample_cb(pa_context *c, uint32_t idx, void *userdata) { + struct private *p; + struct outstanding *out = userdata; + + ca_assert(c); + ca_assert(out); + + p = PRIVATE(out->context); + + if (idx != PA_INVALID_INDEX) { + out->error = CA_SUCCESS; + out->sink_input = idx; + } else + out->error = translate_error(pa_context_errno(c)); + + pa_threaded_mainloop_signal(p->mainloop, FALSE); +} + +static void stream_state_cb(pa_stream *s, void *userdata) { + struct private *p; + struct outstanding *out = userdata; + pa_stream_state_t state; + + ca_assert(s); + ca_assert(out); + + p = PRIVATE(out->context); + + state = pa_stream_get_state(s); + + switch (state) { + case PA_STREAM_CREATING: + case PA_STREAM_UNCONNECTED: + break; + + case PA_STREAM_READY: + out->sink_input = pa_stream_get_index(out->stream); + break; + + case PA_STREAM_FAILED: + case PA_STREAM_TERMINATED: { + int err; + + err = state == PA_STREAM_FAILED ? translate_error(pa_context_errno(pa_stream_get_context(s))) : CA_ERROR_DESTROYED; + + if (out->clean_up) { + ca_mutex_lock(p->outstanding_mutex); + outstanding_disconnect(out); + CA_LLIST_REMOVE(struct outstanding, p->outstanding, out); + ca_mutex_unlock(p->outstanding_mutex); + + if (out->callback) + out->callback(out->context, out->id, out->error, out->userdata); + + outstanding_free(out); + } else { + out->finished = TRUE; + out->error = err; + } + + break; + } + } + + pa_threaded_mainloop_signal(p->mainloop, FALSE); +} + +static void stream_drain_cb(pa_stream *s, int success, void *userdata) { + struct private *p; + struct outstanding *out = userdata; + int err; + + ca_assert(s); + ca_assert(out); + ca_assert(out->type == OUTSTANDING_STREAM); + + p = PRIVATE(out->context); + err = success ? CA_SUCCESS : translate_error(pa_context_errno(p->context)); + + if (out->clean_up) { + ca_mutex_lock(p->outstanding_mutex); + outstanding_disconnect(out); + CA_LLIST_REMOVE(struct outstanding, p->outstanding, out); + ca_mutex_unlock(p->outstanding_mutex); + + if (out->callback) + out->callback(out->context, out->id, err, out->userdata); + + outstanding_free(out); + + } else { + pa_stream_disconnect(s); + out->error = err; + out->finished = TRUE; + + if (out->drain_operation) { + pa_operation_unref(out->drain_operation); + out->drain_operation = NULL; + } + } + + pa_threaded_mainloop_signal(p->mainloop, FALSE); +} + +static void stream_write_cb(pa_stream *s, size_t bytes, void *userdata) { + struct outstanding *out = userdata; + struct private *p; + void *data; + int ret; + ca_bool_t eof = FALSE; + + ca_assert(s); + ca_assert(bytes > 0); + ca_assert(out); + + p = PRIVATE(out->context); + + while (bytes > 0) { + size_t rbytes = bytes; + + if (!(data = ca_malloc(rbytes))) { + ret = CA_ERROR_OOM; + goto finish; + } + + if ((ret = ca_sound_file_read_arbitrary(out->file, data, &rbytes)) < 0) + goto finish; + + if (rbytes <= 0) { + eof = TRUE; + break; + } + + ca_assert(rbytes <= bytes); + + if ((ret = pa_stream_write(s, data, rbytes, ca_free, 0, PA_SEEK_RELATIVE)) < 0) { + ret = translate_error(ret); + goto finish; + } + + data = NULL; + + bytes -= rbytes; + } + + if (eof || ca_sound_file_get_size(out->file) <= 0) { + + /* We reached EOF */ + + if (out->type == OUTSTANDING_UPLOAD) { + + if (pa_stream_finish_upload(s) < 0) { + ret = translate_error(pa_context_errno(p->context)); + goto finish; + } + + /* Let's just signal driver_cache() which has been waiting for us */ + pa_threaded_mainloop_signal(p->mainloop, FALSE); + + } else { + ca_assert(out->type == OUTSTANDING_STREAM); + + if (out->drain_operation) { + pa_operation_cancel(out->drain_operation); + pa_operation_unref(out->drain_operation); + } + + if (!(out->drain_operation = pa_stream_drain(s, stream_drain_cb, out))) { + ret = translate_error(pa_context_errno(p->context)); + goto finish; + } + } + + pa_stream_set_write_callback(s, NULL, NULL); + } + + ca_free(data); + + return; + +finish: + + ca_free(data); + + if (out->clean_up) { + ca_mutex_lock(p->outstanding_mutex); + outstanding_disconnect(out); + CA_LLIST_REMOVE(struct outstanding, p->outstanding, out); + ca_mutex_unlock(p->outstanding_mutex); + + if (out->callback) + out->callback(out->context, out->id, ret, out->userdata); + + outstanding_free(out); + + } else { + pa_stream_disconnect(s); + out->error = ret; + out->finished = TRUE; + } + + pa_threaded_mainloop_signal(p->mainloop, FALSE); +} + +static const pa_sample_format_t sample_type_table[] = { + [CA_SAMPLE_S16NE] = PA_SAMPLE_S16NE, + [CA_SAMPLE_S16RE] = PA_SAMPLE_S16RE, + [CA_SAMPLE_U8] = PA_SAMPLE_U8 +}; + +static const pa_channel_position_t channel_table[_CA_CHANNEL_POSITION_MAX] = { + [CA_CHANNEL_MONO] = PA_CHANNEL_POSITION_MONO, + [CA_CHANNEL_FRONT_LEFT] = PA_CHANNEL_POSITION_FRONT_LEFT, + [CA_CHANNEL_FRONT_RIGHT] = PA_CHANNEL_POSITION_FRONT_RIGHT, + [CA_CHANNEL_FRONT_CENTER] = PA_CHANNEL_POSITION_FRONT_CENTER, + [CA_CHANNEL_REAR_LEFT] = PA_CHANNEL_POSITION_REAR_LEFT, + [CA_CHANNEL_REAR_RIGHT] = PA_CHANNEL_POSITION_REAR_RIGHT, + [CA_CHANNEL_REAR_CENTER] = PA_CHANNEL_POSITION_REAR_CENTER, + [CA_CHANNEL_LFE] = PA_CHANNEL_POSITION_LFE, + [CA_CHANNEL_FRONT_LEFT_OF_CENTER] = PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER, + [CA_CHANNEL_FRONT_RIGHT_OF_CENTER] = PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER, + [CA_CHANNEL_SIDE_LEFT] = PA_CHANNEL_POSITION_SIDE_LEFT, + [CA_CHANNEL_SIDE_RIGHT] = PA_CHANNEL_POSITION_SIDE_RIGHT, + [CA_CHANNEL_TOP_CENTER] = PA_CHANNEL_POSITION_TOP_CENTER, + [CA_CHANNEL_TOP_FRONT_LEFT] = PA_CHANNEL_POSITION_FRONT_LEFT, + [CA_CHANNEL_TOP_FRONT_RIGHT] = PA_CHANNEL_POSITION_FRONT_RIGHT, + [CA_CHANNEL_TOP_FRONT_CENTER] = PA_CHANNEL_POSITION_FRONT_CENTER, + [CA_CHANNEL_TOP_REAR_LEFT] = PA_CHANNEL_POSITION_REAR_LEFT, + [CA_CHANNEL_TOP_REAR_RIGHT] = PA_CHANNEL_POSITION_REAR_RIGHT, + [CA_CHANNEL_TOP_REAR_CENTER] = PA_CHANNEL_POSITION_TOP_REAR_CENTER +}; + +static ca_bool_t convert_channel_map(ca_sound_file *f, pa_channel_map *cm) { + const ca_channel_position_t *positions; + unsigned c; + + ca_assert(f); + ca_assert(cm); + + if (!(positions = ca_sound_file_get_channel_map(f))) + return FALSE; + + cm->channels = ca_sound_file_get_nchannels(f); + for (c = 0; c < cm->channels; c++) + cm->map[c] = channel_table[positions[c]]; + + return TRUE; +} + +int driver_play(ca_context *c, uint32_t id, ca_proplist *proplist, ca_finish_callback_t cb, void *userdata) { + struct private *p; + pa_proplist *l = NULL; + const char *n, *vol, *ct, *channel; + char *name = NULL; +#if defined(PA_MAJOR) && ((PA_MAJOR > 0) || (PA_MAJOR == 0 && PA_MINOR > 9) || (PA_MAJOR == 0 && PA_MINOR == 9 && PA_MICRO >= 15)) + pa_volume_t v = (pa_volume_t) -1; +#else + pa_volume_t v = PA_VOLUME_NORM; +#endif + ca_bool_t volume_set = FALSE; + pa_cvolume cvol; + pa_sample_spec ss; + pa_channel_map cm; + pa_channel_position_t position = PA_CHANNEL_POSITION_INVALID; + ca_bool_t cm_good; + ca_cache_control_t cache_control = CA_CACHE_CONTROL_NEVER; + struct outstanding *out = NULL; + int try = 3; + int ret; + pa_operation *o; + char *sp; + pa_buffer_attr ba; + + ca_return_val_if_fail(c, CA_ERROR_INVALID); + ca_return_val_if_fail(proplist, CA_ERROR_INVALID); + ca_return_val_if_fail(!userdata || cb, CA_ERROR_INVALID); + ca_return_val_if_fail(c->private, CA_ERROR_STATE); + + p = PRIVATE(c); + + ca_return_val_if_fail(p->mainloop, CA_ERROR_STATE); + + if (!(out = ca_new0(struct outstanding, 1))) { + ret = CA_ERROR_OOM; + goto finish_unlocked; + } + + out->type = OUTSTANDING_SAMPLE; + out->context = c; + out->sink_input = PA_INVALID_INDEX; + out->id = id; + out->callback = cb; + out->userdata = userdata; + + if ((ret = convert_proplist(&l, proplist)) < 0) + goto finish_unlocked; + + if ((n = pa_proplist_gets(l, CA_PROP_EVENT_ID))) + if (!(name = ca_strdup(n))) { + ret = CA_ERROR_OOM; + goto finish_unlocked; + } + + if ((vol = pa_proplist_gets(l, CA_PROP_CANBERRA_VOLUME))) { + char *e = NULL; + double dvol; + + errno = 0; + dvol = strtod(vol, &e); + if (errno != 0 || !e || *e) { + ret = CA_ERROR_INVALID; + goto finish_unlocked; + } + + v = pa_sw_volume_from_dB(dvol); + volume_set = TRUE; + } + + if ((ct = pa_proplist_gets(l, CA_PROP_CANBERRA_CACHE_CONTROL))) + if ((ret = ca_parse_cache_control(&cache_control, ct)) < 0) { + ret = CA_ERROR_INVALID; + goto finish_unlocked; + } + + if ((channel = pa_proplist_gets(l, CA_PROP_CANBERRA_FORCE_CHANNEL))) { + pa_channel_map t; + + if (!pa_channel_map_parse(&t, channel) || + t.channels != 1) { + ret = CA_ERROR_INVALID; + goto finish_unlocked; + } + + position = t.map[0]; + + /* We cannot remap cached samples, so let's fail when cacheing + * shall be used */ + if (cache_control != CA_CACHE_CONTROL_NEVER) { + ret = CA_ERROR_NOTSUPPORTED; + goto finish_unlocked; + } + } + + strip_prefix(l, "canberra."); + add_common(l); + + if ((ret = subscribe(c)) < 0) + goto finish_unlocked; + + if (name && cache_control != CA_CACHE_CONTROL_NEVER) { + + /* Ok, this sample has an event id, let's try to play it from the cache */ + + for (;;) { + ca_bool_t canceled; + + pa_threaded_mainloop_lock(p->mainloop); + + if (!p->context) { + ret = CA_ERROR_STATE; + goto finish_locked; + } + + /* Let's try to play the sample */ + if (!(o = pa_context_play_sample_with_proplist(p->context, name, c->device, v, l, play_sample_cb, out))) { + ret = translate_error(pa_context_errno(p->context)); + goto finish_locked; + } + + for (;;) { + pa_operation_state_t state = pa_operation_get_state(o); + + if (state == PA_OPERATION_DONE) { + canceled = FALSE; + break; + } else if (state == PA_OPERATION_CANCELED) { + canceled = TRUE; + break; + } + + pa_threaded_mainloop_wait(p->mainloop); + } + + pa_operation_unref(o); + + if (!canceled && p->context && out->error == CA_SUCCESS) { + ret = CA_SUCCESS; + goto finish_locked; + } + + pa_threaded_mainloop_unlock(p->mainloop); + + /* The operation might have been canceled due to connection termination */ + if (canceled || !p->context) { + ret = CA_ERROR_DISCONNECTED; + goto finish_unlocked; + } + + /* Did some other error occur? */ + if (out->error != CA_ERROR_NOTFOUND) { + ret = out->error; + goto finish_unlocked; + } + + /* Hmm, we need to play it directly */ + if (cache_control != CA_CACHE_CONTROL_PERMANENT) + break; + + /* Don't loop forever */ + if (--try <= 0) + break; + + /* Let's upload the sample and retry playing */ + if ((ret = driver_cache(c, proplist)) < 0) + goto finish_unlocked; + } + } + + out->type = OUTSTANDING_STREAM; + + /* Let's stream the sample directly */ + if ((ret = ca_lookup_sound(&out->file, &sp, &p->theme, c->props, proplist)) < 0) + goto finish_unlocked; + + if (sp) + if (!pa_proplist_contains(l, CA_PROP_MEDIA_FILENAME)) + pa_proplist_sets(l, CA_PROP_MEDIA_FILENAME, sp); + + ca_free(sp); + + ss.format = sample_type_table[ca_sound_file_get_sample_type(out->file)]; + ss.channels = (uint8_t) ca_sound_file_get_nchannels(out->file); + ss.rate = ca_sound_file_get_rate(out->file); + + if (position != PA_CHANNEL_POSITION_INVALID) { + unsigned u; + /* Apply canberra.force_channel */ + + cm.channels = ss.channels; + for (u = 0; u < cm.channels; u++) + cm.map[u] = position; + + cm_good = TRUE; + } else + cm_good = convert_channel_map(out->file, &cm); + + pa_threaded_mainloop_lock(p->mainloop); + + if (!p->context) { + ret = CA_ERROR_STATE; + goto finish_locked; + } + + if (!(out->stream = pa_stream_new_with_proplist(p->context, NULL, &ss, cm_good ? &cm : NULL, l))) { + ret = translate_error(pa_context_errno(p->context)); + goto finish_locked; + } + + pa_stream_set_state_callback(out->stream, stream_state_cb, out); + pa_stream_set_write_callback(out->stream, stream_write_cb, out); + + if (volume_set) + pa_cvolume_set(&cvol, ss.channels, v); + + /* Make sure we get the longest latency possible, to minimize CPU + * consumption */ + ba.maxlength = (uint32_t) -1; + ba.tlength = (uint32_t) -1; + ba.prebuf = (uint32_t) -1; + ba.minreq = (uint32_t) -1; + ba.fragsize = (uint32_t) -1; + + if (pa_stream_connect_playback(out->stream, c->device, &ba, +#ifdef PA_STREAM_FAIL_ON_SUSPEND + PA_STREAM_FAIL_ON_SUSPEND +#else + 0 +#endif + | (position != PA_CHANNEL_POSITION_INVALID ? PA_STREAM_NO_REMIX_CHANNELS : 0) + , volume_set ? &cvol : NULL, NULL) < 0) { + ret = translate_error(pa_context_errno(p->context)); + goto finish_locked; + } + + for (;;) { + pa_stream_state_t state; + + if (!p->context || !out->stream) { + ret = CA_ERROR_STATE; + goto finish_locked; + } + + state = pa_stream_get_state(out->stream); + + /* Stream sucessfully created */ + if (state == PA_STREAM_READY) + break; + + /* Check for failure */ + if (state == PA_STREAM_FAILED) { + ret = translate_error(pa_context_errno(p->context)); + goto finish_locked; + } + + /* Prematurely ended */ + if (state == PA_STREAM_TERMINATED) { + ret = out->error; + goto finish_locked; + } + + pa_threaded_mainloop_wait(p->mainloop); + } + + ret = CA_SUCCESS; + +finish_locked: + + /* We keep the outstanding struct around to clean up later if the sound din't finish yet*/ + if (ret == CA_SUCCESS && !out->finished) { + out->clean_up = TRUE; + + ca_mutex_lock(p->outstanding_mutex); + CA_LLIST_PREPEND(struct outstanding, p->outstanding, out); + ca_mutex_unlock(p->outstanding_mutex); + } else + outstanding_free(out); + + out = NULL; + + pa_threaded_mainloop_unlock(p->mainloop); + +finish_unlocked: + + if (out) + outstanding_free(out); + + if (l) + pa_proplist_free(l); + + ca_free(name); + + return ret; +} + +int driver_cancel(ca_context *c, uint32_t id) { + struct private *p; + pa_operation *o; + int ret = CA_SUCCESS; + struct outstanding *out, *n; + + ca_return_val_if_fail(c, CA_ERROR_INVALID); + ca_return_val_if_fail(c->private, CA_ERROR_STATE); + + p = PRIVATE(c); + + ca_return_val_if_fail(p->mainloop, CA_ERROR_STATE); + + pa_threaded_mainloop_lock(p->mainloop); + + if (!p->context) { + pa_threaded_mainloop_unlock(p->mainloop); + return CA_ERROR_STATE; + } + + ca_mutex_lock(p->outstanding_mutex); + + /* We start these asynchronously and don't care about the return + * value */ + + for (out = p->outstanding; out; out = n) { + int ret2 = CA_SUCCESS; + n = out->next; + + if (out->type == OUTSTANDING_UPLOAD || + out->id != id || + out->sink_input == PA_INVALID_INDEX) + continue; + + if (!(o = pa_context_kill_sink_input(p->context, out->sink_input, NULL, NULL))) + ret2 = translate_error(pa_context_errno(p->context)); + else + pa_operation_unref(o); + + /* We make sure here to kill all streams identified by the id + * here. However, we will return only the first error we + * encounter */ + + if (ret2 && ret == CA_SUCCESS) + ret = ret2; + + if (out->callback) + out->callback(c, out->id, CA_ERROR_CANCELED, out->userdata); + + outstanding_disconnect(out); + CA_LLIST_REMOVE(struct outstanding, p->outstanding, out); + outstanding_free(out); + } + + ca_mutex_unlock(p->outstanding_mutex); + + pa_threaded_mainloop_unlock(p->mainloop); + + return ret; +} + +int driver_cache(ca_context *c, ca_proplist *proplist) { + struct private *p; + pa_proplist *l = NULL; + const char *n, *ct; + pa_sample_spec ss; + pa_channel_map cm; + ca_bool_t cm_good; + ca_cache_control_t cache_control = CA_CACHE_CONTROL_PERMANENT; + struct outstanding *out; + int ret; + char *sp; + + ca_return_val_if_fail(c, CA_ERROR_INVALID); + ca_return_val_if_fail(proplist, CA_ERROR_INVALID); + ca_return_val_if_fail(c->private, CA_ERROR_STATE); + + p = PRIVATE(c); + + ca_return_val_if_fail(p->mainloop, CA_ERROR_STATE); + + if (!(out = ca_new0(struct outstanding, 1))) { + ret = CA_ERROR_OOM; + goto finish_unlocked; + } + + out->type = OUTSTANDING_UPLOAD; + out->context = c; + out->sink_input = PA_INVALID_INDEX; + + if ((ret = convert_proplist(&l, proplist)) < 0) + goto finish_unlocked; + + if (!(n = pa_proplist_gets(l, CA_PROP_EVENT_ID))) { + ret = CA_ERROR_INVALID; + goto finish_unlocked; + } + + if ((ct = pa_proplist_gets(l, CA_PROP_CANBERRA_CACHE_CONTROL))) + if ((ret = ca_parse_cache_control(&cache_control, ct)) < 0) { + ret = CA_ERROR_INVALID; + goto finish_unlocked; + } + + if (cache_control != CA_CACHE_CONTROL_PERMANENT) { + ret = CA_ERROR_INVALID; + goto finish_unlocked; + } + + if ((ct = pa_proplist_gets(l, CA_PROP_CANBERRA_FORCE_CHANNEL))) { + ret = CA_ERROR_NOTSUPPORTED; + goto finish_unlocked; + } + + strip_prefix(l, "canberra."); + strip_prefix(l, "event.mouse."); + strip_prefix(l, "window."); + add_common(l); + + /* Let's stream the sample directly */ + if ((ret = ca_lookup_sound(&out->file, &sp, &p->theme, c->props, proplist)) < 0) + goto finish_unlocked; + + if (sp) + if (!pa_proplist_contains(l, CA_PROP_MEDIA_FILENAME)) + pa_proplist_sets(l, CA_PROP_MEDIA_FILENAME, sp); + + ca_free(sp); + + ss.format = sample_type_table[ca_sound_file_get_sample_type(out->file)]; + ss.channels = (uint8_t) ca_sound_file_get_nchannels(out->file); + ss.rate = ca_sound_file_get_rate(out->file); + + cm_good = convert_channel_map(out->file, &cm); + + pa_threaded_mainloop_lock(p->mainloop); + + if (!p->context) { + ret = CA_ERROR_STATE; + goto finish_locked; + } + + if (!(out->stream = pa_stream_new_with_proplist(p->context, NULL, &ss, cm_good ? &cm : NULL, l))) { + ret = translate_error(pa_context_errno(p->context)); + goto finish_locked; + } + + pa_stream_set_state_callback(out->stream, stream_state_cb, out); + pa_stream_set_write_callback(out->stream, stream_write_cb, out); + + if (pa_stream_connect_upload(out->stream, (size_t) ca_sound_file_get_size(out->file)) < 0) { + ret = translate_error(pa_context_errno(p->context)); + goto finish_locked; + } + + for (;;) { + pa_stream_state_t state; + + if (!p->context || !out->stream) { + ret = CA_ERROR_STATE; + goto finish_locked; + } + + state = pa_stream_get_state(out->stream); + + /* Stream sucessfully created and uploaded */ + if (state == PA_STREAM_TERMINATED) + break; + + /* Check for failure */ + if (state == PA_STREAM_FAILED) { + ret = translate_error(pa_context_errno(p->context)); + goto finish_locked; + } + + pa_threaded_mainloop_wait(p->mainloop); + } + + ret = CA_SUCCESS; + +finish_locked: + outstanding_free(out); + out = NULL; + + pa_threaded_mainloop_unlock(p->mainloop); + +finish_unlocked: + + if (out) + outstanding_free(out); + + if (l) + pa_proplist_free(l); + + return ret; +} + +int driver_playing(ca_context *c, uint32_t id, int *playing) { + struct private *p; + struct outstanding *out; + + ca_return_val_if_fail(c, CA_ERROR_INVALID); + ca_return_val_if_fail(c->private, CA_ERROR_STATE); + ca_return_val_if_fail(playing, CA_ERROR_INVALID); + + p = PRIVATE(c); + + *playing = 0; + + ca_mutex_lock(p->outstanding_mutex); + + for (out = p->outstanding; out; out = out->next) { + + if (out->type == OUTSTANDING_UPLOAD || + out->id != id || + out->sink_input == PA_INVALID_INDEX) + continue; + + *playing = 1; + break; + } + + ca_mutex_unlock(p->outstanding_mutex); + + return CA_SUCCESS; +} diff --git a/.flatpak-builder/cache/objects/92/c0790b0938453faa882aa1097df71d6954fedd048f0fa81dd0f724f63b1bbc.file b/.flatpak-builder/cache/objects/92/c0790b0938453faa882aa1097df71d6954fedd048f0fa81dd0f724f63b1bbc.file new file mode 100755 index 0000000..032ff9c Binary files /dev/null and b/.flatpak-builder/cache/objects/92/c0790b0938453faa882aa1097df71d6954fedd048f0fa81dd0f724f63b1bbc.file differ diff --git a/.flatpak-builder/cache/objects/93/1cffb52a562d1bc8245e7c2ba39c8f32e1c417c3136fc26364f877f99246db.file b/.flatpak-builder/cache/objects/93/1cffb52a562d1bc8245e7c2ba39c8f32e1c417c3136fc26364f877f99246db.file new file mode 100755 index 0000000..c5b740f Binary files /dev/null and b/.flatpak-builder/cache/objects/93/1cffb52a562d1bc8245e7c2ba39c8f32e1c417c3136fc26364f877f99246db.file differ diff --git a/.flatpak-builder/cache/objects/93/352634c917d212de511fc91626351fd4bc735a53150692052c9b8567ce1692.dirtree b/.flatpak-builder/cache/objects/93/352634c917d212de511fc91626351fd4bc735a53150692052c9b8567ce1692.dirtree new file mode 100644 index 0000000..2cfd8b4 Binary files /dev/null and b/.flatpak-builder/cache/objects/93/352634c917d212de511fc91626351fd4bc735a53150692052c9b8567ce1692.dirtree differ diff --git a/.flatpak-builder/cache/objects/93/bfbf782c434ca8cf7631d7a4153859bbe4b9d182a2f8cde1f2981d00dc41bd.dirtree b/.flatpak-builder/cache/objects/93/bfbf782c434ca8cf7631d7a4153859bbe4b9d182a2f8cde1f2981d00dc41bd.dirtree new file mode 100644 index 0000000..dc083b9 Binary files /dev/null and b/.flatpak-builder/cache/objects/93/bfbf782c434ca8cf7631d7a4153859bbe4b9d182a2f8cde1f2981d00dc41bd.dirtree differ diff --git a/.flatpak-builder/cache/objects/93/cad7ddcd692a8d0fdbe22b07fb9dcd70252e72c3bcdebdf80f62517a65ee8f.dirtree b/.flatpak-builder/cache/objects/93/cad7ddcd692a8d0fdbe22b07fb9dcd70252e72c3bcdebdf80f62517a65ee8f.dirtree new file mode 100644 index 0000000..423daeb Binary files /dev/null and b/.flatpak-builder/cache/objects/93/cad7ddcd692a8d0fdbe22b07fb9dcd70252e72c3bcdebdf80f62517a65ee8f.dirtree differ diff --git a/.flatpak-builder/cache/objects/93/cb049af54570d10d536fcb08d16efa262e0006aa5b59ad237c80a7d0cf39c1.dirtree b/.flatpak-builder/cache/objects/93/cb049af54570d10d536fcb08d16efa262e0006aa5b59ad237c80a7d0cf39c1.dirtree new file mode 100644 index 0000000..ceb3b3b Binary files /dev/null and b/.flatpak-builder/cache/objects/93/cb049af54570d10d536fcb08d16efa262e0006aa5b59ad237c80a7d0cf39c1.dirtree differ diff --git a/.flatpak-builder/cache/objects/93/dee4be8c9397ebe4b2b1b6bdc5438b2ff7075c46d397d84f2a1b69bcf16b2c.file b/.flatpak-builder/cache/objects/93/dee4be8c9397ebe4b2b1b6bdc5438b2ff7075c46d397d84f2a1b69bcf16b2c.file new file mode 100644 index 0000000..ec74ad9 --- /dev/null +++ b/.flatpak-builder/cache/objects/93/dee4be8c9397ebe4b2b1b6bdc5438b2ff7075c46d397d84f2a1b69bcf16b2c.file @@ -0,0 +1,495 @@ +/* +libcsv - parse and write csv data +Copyright (C) 2007 Robert Gamble + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ +#define G_LOG_DOMAIN "GDA-libcsv" + +#if ___STDC_VERSION__ >= 199901L +# include +#else +# define SIZE_MAX ((size_t)-1) /* C89 doesn't have stdint.h or SIZE_MAX */ +#endif + +#include "csv.h" + +#define VERSION "2.0.0" + +#define ROW_NOT_BEGUN 0 +#define FIELD_NOT_BEGUN 1 +#define FIELD_BEGUN 2 +#define FIELD_MIGHT_HAVE_ENDED 3 + +/* + Explanation of states + ROW_NOT_BEGUN There have not been any fields encountered for this row + FIELD_NOT_BEGUN There have been fields but we are currently not in one + FIELD_BEGUN We are in a field + FIELD_MIGHT_HAVE_ENDED + We encountered a double quote inside a quoted field, the + field is either ended or the quote is literal +*/ + +#define MEM_BLK_SIZE 128 + +#define SUBMIT_FIELD(p) \ + do { \ + if (!quoted) \ + entry_pos -= spaces; \ + if (cb1) \ + cb1(p->entry_buf, entry_pos, data); \ + pstate = FIELD_NOT_BEGUN; \ + entry_pos = quoted = spaces = 0; \ + } while (0) + +#define SUBMIT_ROW(p, c) \ + do { \ + if (cb2) \ + cb2(c, data); \ + pstate = ROW_NOT_BEGUN; \ + entry_pos = quoted = spaces = 0; \ + } while (0) + +#define SUBMIT_CHAR(p, c) ((p)->entry_buf[entry_pos++] = (c)) + +static char *csv_errors[] = {"success", + "error parsing data while strict checking enabled", + "memory exhausted while increasing buffer size", + "data size too large", + "invalid status code"}; + +int +csv_error(struct csv_parser *p) +{ + return p->status; +} + +char * +csv_strerror(int status) +{ + if (status >= CSV_EINVALID || status < 0) + return csv_errors[CSV_EINVALID]; + else + return csv_errors[status]; +} + +int +csv_opts(struct csv_parser *p, unsigned char options) +{ + if (p == NULL) + return -1; + + p->options = options; + return 0; +} + +int +csv_init(struct csv_parser **p, unsigned char options) +{ + /* Initialize a csv_parser object returns 0 on success, -1 on error */ + if (p == NULL) + return -1; + + if ((*p = malloc(sizeof(struct csv_parser))) == NULL) + return -1; + + if ( ((*p)->entry_buf = malloc(MEM_BLK_SIZE)) == NULL ) { + free(*p); + return -1; + } + (*p)->pstate = ROW_NOT_BEGUN; + (*p)->quoted = 0; + (*p)->spaces = 0; + (*p)->entry_pos = 0; + (*p)->entry_size = MEM_BLK_SIZE; + (*p)->status = 0; + (*p)->options = options; + (*p)->quote_char = CSV_QUOTE; + (*p)->delim_char = CSV_COMMA; + (*p)->is_space = NULL; + (*p)->is_term = NULL; + + return 0; +} + +void +csv_free(struct csv_parser *p) +{ + /* Free the entry_buffer and the csv_parser object */ + if (p == NULL) + return; + + if (p->entry_buf) + free(p->entry_buf); + + free(p); + return; +} + +int +csv_fini(struct csv_parser *p, void (*cb1)(char *, size_t, void *), void (*cb2)(char c, void *), void *data) +{ + /* Finalize parsing. Needed, for example, when file does not end in a newline */ + int quoted = p->quoted; + int pstate = p->pstate; /* This is used by the macros, but the compiler thinks it is not used. */ + (void)pstate; /* Avoid the "set but not used" compiler warning. */ + size_t spaces = p->spaces; + size_t entry_pos = p->entry_pos; + + if (p == NULL) + return -1; + + + if (p->pstate == FIELD_BEGUN && p->quoted && p->options & CSV_STRICT && p->options & CSV_STRICT_FINI) { + p->status = CSV_EPARSE; + return -1; + } + + switch (p->pstate) { + case FIELD_MIGHT_HAVE_ENDED: + p->entry_pos -= p->spaces + 1; /* get rid of spaces and original quote */ + /* fallthrough */ + case FIELD_NOT_BEGUN: + case FIELD_BEGUN: + quoted = p->quoted, pstate = p->pstate; + spaces = p->spaces, entry_pos = p->entry_pos; + SUBMIT_FIELD(p); + SUBMIT_ROW(p, 0); + case ROW_NOT_BEGUN: /* Already ended properly */ + ; + } + + p->spaces = p->quoted = p->entry_pos = p->status = 0; + p->pstate = ROW_NOT_BEGUN; + + return 0; +} + +void +csv_set_delim(struct csv_parser *p, char c) +{ + if (p) p->delim_char = c; +} + +void +csv_set_quote(struct csv_parser *p, char c) +{ + if (p) p->quote_char = c; +} + +char +csv_get_delim(struct csv_parser *p) +{ + return p->delim_char; +} + +char +csv_get_quote(struct csv_parser *p) +{ + return p->quote_char; +} + +void +csv_set_space_func(struct csv_parser *p, int (*f)(char)) +{ + if (p) p->is_space = f; +} + +void +csv_set_term_func(struct csv_parser *p, int (*f)(char)) +{ + if (p) p->is_term = f; +} + +static int +csv_increase_buffer(struct csv_parser *p) +{ + size_t to_add = MEM_BLK_SIZE; + void *vp; + while ( p->entry_size >= SIZE_MAX - to_add ) + to_add /= 2; + if (!to_add) { + p->status = CSV_ETOOBIG; + return -1; + } + while ((vp = realloc(p->entry_buf, p->entry_size + to_add)) == NULL) { + to_add /= 2; + if (!to_add) { + p->status = CSV_ENOMEM; + return -1; + } + } + p->entry_buf = vp; + p->entry_size += to_add; + return 0; +} + +size_t +csv_parse(struct csv_parser *p, const char *s, size_t len, void (*cb1)(char *, size_t, void *), void (*cb2)(char c, void *), void *data) +{ + char c; /* The character we are currently processing */ + size_t pos = 0; /* The number of characters we have processed in this call */ + char delim = p->delim_char; + char quote = p->quote_char; + int (*is_space)(char) = p->is_space; + int (*is_term)(char) = p->is_term; + int quoted = p->quoted; + int pstate = p->pstate; + size_t spaces = p->spaces; + size_t entry_pos = p->entry_pos; + + while (pos < len) { + /* Check memory usage */ + if (entry_pos == p->entry_size) + if (csv_increase_buffer(p) != 0) { + p->quoted = quoted, p->pstate = pstate, p->spaces = spaces, p->entry_pos = entry_pos; + return pos; + } + + c = s[pos++]; + switch (pstate) { + case ROW_NOT_BEGUN: + case FIELD_NOT_BEGUN: + if (is_space ? is_space(c) : c == CSV_SPACE || c == CSV_TAB) { /* Space or Tab */ + continue; + } else if (is_term ? is_term(c) : c == CSV_CR || c == CSV_LF) { /* Carriage Return or Line Feed */ + if (pstate == FIELD_NOT_BEGUN) { + SUBMIT_FIELD(p); + SUBMIT_ROW(p, c); + } else { /* ROW_NOT_BEGUN */ + /* Don't submit empty rows by default */ + if (p->options & CSV_REPALL_NL) { + SUBMIT_ROW(p, c); + } + } + continue; + } else if (c == delim) { /* Comma */ + SUBMIT_FIELD(p); + break; + } else if (c == quote) { /* Quote */ + pstate = FIELD_BEGUN; + quoted = 1; + } else { /* Anything else */ + pstate = FIELD_BEGUN; + quoted = 0; + SUBMIT_CHAR(p, c); + } + break; + case FIELD_BEGUN: + if (c == quote) { /* Quote */ + if (quoted) { + SUBMIT_CHAR(p, c); + pstate = FIELD_MIGHT_HAVE_ENDED; + } else { + /* STRICT ERROR - double quote inside non-quoted field */ + if (p->options & CSV_STRICT) { + p->status = CSV_EPARSE; + p->quoted = quoted, p->pstate = pstate, p->spaces = spaces, p->entry_pos = entry_pos; + return pos-1; + } + SUBMIT_CHAR(p, c); + spaces = 0; + } + } else if (c == delim) { /* Comma */ + if (quoted) { + SUBMIT_CHAR(p, c); + } else { + SUBMIT_FIELD(p); + } + } else if (is_term ? is_term(c) : c == CSV_CR || c == CSV_LF) { /* Carriage Return or Line Feed */ + if (!quoted) { + SUBMIT_FIELD(p); + SUBMIT_ROW(p, c); + } else { + SUBMIT_CHAR(p, c); + } + } else if (!quoted && (is_space? is_space(c) : c == CSV_SPACE || c == CSV_TAB)) { /* Tab or space for non-quoted field */ + SUBMIT_CHAR(p, c); + spaces++; + } else { /* Anything else */ + SUBMIT_CHAR(p, c); + spaces = 0; + } + break; + case FIELD_MIGHT_HAVE_ENDED: + /* This only happens when a quote character is encountered in a quoted field */ + if (c == delim) { /* Comma */ + entry_pos -= spaces + 1; /* get rid of spaces and original quote */ + SUBMIT_FIELD(p); + } else if (is_term ? is_term(c) : c == CSV_CR || c == CSV_LF) { /* Carriage Return or Line Feed */ + entry_pos -= spaces + 1; /* get rid of spaces and original quote */ + SUBMIT_FIELD(p); + SUBMIT_ROW(p, c); + } else if (is_space ? is_space(c) : c == CSV_SPACE || c == CSV_TAB) { /* Space or Tab */ + SUBMIT_CHAR(p, c); + spaces++; + } else if (c == quote) { /* Quote */ + if (spaces) { + /* STRICT ERROR - unescaped double quote */ + if (p->options & CSV_STRICT) { + p->status = CSV_EPARSE; + p->quoted = quoted, p->pstate = pstate, p->spaces = spaces, p->entry_pos = entry_pos; + return pos-1; + } + spaces = 0; + SUBMIT_CHAR(p, c); + } else { + /* Two quotes in a row */ + pstate = FIELD_BEGUN; + } + } else { /* Anything else */ + /* STRICT ERROR - unescaped double quote */ + if (p->options & CSV_STRICT) { + p->status = CSV_EPARSE; + p->quoted = quoted, p->pstate = pstate, p->spaces = spaces, p->entry_pos = entry_pos; + return pos-1; + } + pstate = FIELD_BEGUN; + spaces = 0; + SUBMIT_CHAR(p, c); + } + break; + default: + break; + } + } + p->quoted = quoted, p->pstate = pstate, p->spaces = spaces, p->entry_pos = entry_pos; + return pos; +} + +size_t +csv_write (char *dest, size_t dest_size, const char *src, size_t src_size) +{ + size_t chars = 0; + + if (src == NULL) + return 0; + + if (dest == NULL) + dest_size = 0; + + if (dest_size > 0) + *dest++ = '"'; + chars++; + + while (src_size) { + if (*src == '"') { + if (dest_size > chars) + *dest++ = '"'; + if (chars < SIZE_MAX) chars++; + } + if (dest_size > chars) + *dest++ = *src; + if (chars < SIZE_MAX) chars++; + src_size--; + src++; + } + + if (dest_size > chars) + *dest = '"'; + if (chars < SIZE_MAX) chars++; + + return chars; +} + +int +csv_fwrite (FILE *fp, const char *src, size_t src_size) +{ + if (fp == NULL || src == NULL) + return 0; + + if (fputc('"', fp) == EOF) + return EOF; + + while (src_size) { + if (*src == '"') { + if (fputc('"', fp) == EOF) + return EOF; + } + if (fputc(*src, fp) == EOF) + return EOF; + src_size--; + src++; + } + + if (fputc('"', fp) == EOF) { + return EOF; + } + + return 0; +} + +size_t +csv_write2 (char *dest, size_t dest_size, const char *src, size_t src_size, char quote) +{ + size_t chars = 0; + + if (src == NULL) + return 0; + + if (dest == NULL) + dest_size = 0; + + if (dest_size > 0) + *dest++ = quote; + chars++; + + while (src_size) { + if (*src == quote) { + if (dest_size > chars) + *dest++ = quote; + if (chars < SIZE_MAX) chars++; + } + if (dest_size > chars) + *dest++ = *src; + if (chars < SIZE_MAX) chars++; + src_size--; + src++; + } + + if (dest_size > chars) + *dest = quote; + if (chars < SIZE_MAX) chars++; + + return chars; +} + +int +csv_fwrite2 (FILE *fp, const char *src, size_t src_size, char quote) +{ + if (fp == NULL || src == NULL) + return 0; + + if (fputc(quote, fp) == EOF) + return EOF; + + while (src_size) { + if (*src == quote) { + if (fputc(quote, fp) == EOF) + return EOF; + } + if (fputc(*src, fp) == EOF) + return EOF; + src_size--; + src++; + } + + if (fputc(quote, fp) == EOF) { + return EOF; + } + + return 0; +} diff --git a/.flatpak-builder/cache/objects/94/aa95a217ab0090ab68d50b7df15f5c141fd52044fa72dc6668447cfd850caa.dirtree b/.flatpak-builder/cache/objects/94/aa95a217ab0090ab68d50b7df15f5c141fd52044fa72dc6668447cfd850caa.dirtree new file mode 100644 index 0000000..4874ecc Binary files /dev/null and b/.flatpak-builder/cache/objects/94/aa95a217ab0090ab68d50b7df15f5c141fd52044fa72dc6668447cfd850caa.dirtree differ diff --git a/.flatpak-builder/cache/objects/95/4a2a5d95c14278a1ee5e41bca4a7dd5cc1c0a009336b38480b19c12ca44d4a.dirtree b/.flatpak-builder/cache/objects/95/4a2a5d95c14278a1ee5e41bca4a7dd5cc1c0a009336b38480b19c12ca44d4a.dirtree new file mode 100644 index 0000000..4a16bec Binary files /dev/null and b/.flatpak-builder/cache/objects/95/4a2a5d95c14278a1ee5e41bca4a7dd5cc1c0a009336b38480b19c12ca44d4a.dirtree differ diff --git a/.flatpak-builder/cache/objects/95/58e0e755a4fdc1e5337597c1f0c155b66a151ffa145b19651e80eb89bafa67.file b/.flatpak-builder/cache/objects/95/58e0e755a4fdc1e5337597c1f0c155b66a151ffa145b19651e80eb89bafa67.file new file mode 100644 index 0000000..5e19368 --- /dev/null +++ b/.flatpak-builder/cache/objects/95/58e0e755a4fdc1e5337597c1f0c155b66a151ffa145b19651e80eb89bafa67.file @@ -0,0 +1,1120 @@ +/* + * Copyright (C) 2014 - 2015 Vivien Malerba + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "gda-worker.h" +#include "itsignaler.h" +#include "background.h" +#include +#include + +#define DEBUG_NOTIFICATION +#undef DEBUG_NOTIFICATION + +typedef struct { + ITSignaler *its; /* ref held */ + GdaWorker *worker; /* no ref held */ + GMainContext *context; /* ref held */ + GdaWorkerCallback callback; + gpointer user_data; + guint source_sig_id; +} DeclaredCallback; + +static DeclaredCallback * +declared_callback_new (GdaWorker *worker, GMainContext *context, GdaWorkerCallback callback, gpointer user_data) +{ + g_assert (callback); + g_assert (context); + + ITSignaler *its; + its = itsignaler_new (); + if (!its) + return NULL; + + DeclaredCallback *dc; + dc = g_slice_new0 (DeclaredCallback); + dc->its = its; + dc->worker = worker; + dc->context = g_main_context_ref (context); + dc->callback = callback; + dc->user_data = user_data; + dc->source_sig_id = 0; + + return dc; +} + +static void +declared_callback_free (DeclaredCallback *dc) +{ + if (!dc) + return; + if (dc->source_sig_id) + g_assert (itsignaler_remove (dc->its, dc->context, dc->source_sig_id)); + if (dc->its) + itsignaler_unref (dc->its); + g_main_context_unref (dc->context); + g_slice_free (DeclaredCallback, dc); +} + +/* structure is completely opaque for end user */ +struct _GdaWorker { + GRecMutex rmutex; /* protects all the attributes in GdaWorker and any WorkerJob */ + + guint ref_count; /* +1 for any user + * Object is destroyed when ref_count reaches 0 */ + + GThread *worker_thread; /* used to join thread when cleaning up, created when 1st job is submitted */ + gint8 worker_must_quit; /* set to 1 if worker is requested to exit */ + + ITSignaler *submit_its; /* used to submit jobs to worker thread, jobs IDs are pushed */ + + GHashTable *callbacks_hash; /* used to declare callbacks + * gda_worker_set_callback() was called + * key = a GMainContext (ref held), + * value = corresponding DeclaredCallback (memory managed here) */ + + GHashTable *jobs_hash; /* locked by @mutex when reading or writing, by any thread + * key = a #WorkerJob's job ID, value = the #WorkerJob */ + + GdaWorker **location; +}; + +GdaWorker * +gda_worker_copy (GdaWorker *src) { + return gda_worker_ref (src); +} +void +gda_worker_free (GdaWorker *w) { + gda_worker_unref (w); +} + +G_DEFINE_BOXED_TYPE(GdaWorker, gda_worker, gda_worker_copy, gda_worker_free) + + +/* module error */ +GQuark gda_worker_error_quark (void) +{ + static GQuark quark; + if (!quark) + quark = g_quark_from_static_string ("gda_worker_error"); + return quark; +} + +/* + * Individual jobs + * + * If the status is in JOB_QUEUED or JOB_BEING_PROCESSED, then it may be in the ITSignaler's internal queue + * It the status is JOB_PROCESSED, then it will _not_ be in the ITSignaler's internal queue + */ +typedef enum { + JOB_QUEUED = 1, + JOB_BEING_PROCESSED = 1 << 1, + JOB_PROCESSED = 1 << 2, + JOB_CANCELLED = 1 << 3, +} JobStatus; + +typedef struct { + guint id; + JobStatus status; /* protected by associated worker's mutex */ + + ITSignaler *reply_its; /* where to push the result to, ref held */ + + /* information to call function in worker thread */ + GdaWorkerFunc func; + gpointer data; + GDestroyNotify data_destroy_func; /* to destroy @data */ + + /* result */ + gpointer result; + GDestroyNotify result_destroy_func; /* to destroy @result */ + GError *error; +} WorkerJob; + +static WorkerJob * +worker_job_new (ITSignaler *reply_its, GdaWorkerFunc func, gpointer data, GDestroyNotify data_destroy_func, + GDestroyNotify result_destroy_func) +{ + static guint counter = 0; + + WorkerJob *job; + job = g_slice_new0 (WorkerJob); + counter ++; + job->id = counter; + job->status = JOB_QUEUED; + job->reply_its = reply_its ? itsignaler_ref (reply_its) : NULL; + + job->func = func; + job->data = data; + job->data_destroy_func = data_destroy_func; + + job->result = NULL; + job->result_destroy_func = result_destroy_func; + job->error = NULL; + + return job; +} + +static void +worker_job_free (WorkerJob *job) +{ + if (!job) + return; + if (job->data_destroy_func && job->data) + job->data_destroy_func (job->data); + if (job->result) { + if (job->result_destroy_func) + job->result_destroy_func (job->result); + else + g_warning (_("Possible memory leak as no destroy function provided to free value returned by the worker thread")); + } + if (job->error) + g_error_free (job->error); + if (job->reply_its) + itsignaler_unref (job->reply_its); + g_slice_free (WorkerJob, job); +} + +/* + * main function of the worker thread + */ +static gpointer +worker_thread_main (GdaWorker *worker) +{ +#define TIMER 150 +#ifdef DEBUG_NOTIFICATION + g_print ("[W] GdaWorker %p, worker thread %p started!\n", worker, g_thread_self()); +#endif + itsignaler_ref (worker->submit_its); + while (1) { + WorkerJob *job; + job = itsignaler_pop_notification (worker->submit_its, TIMER); + if (job) { + g_rec_mutex_lock (&worker->rmutex); + if (! (job->status & JOB_CANCELLED)) { + /* handle job */ + job->status |= JOB_BEING_PROCESSED; + g_rec_mutex_unlock (&worker->rmutex); + + job->result = job->func (job->data, & job->error); + + g_rec_mutex_lock (&worker->rmutex); + job->status |= JOB_PROCESSED; + if (job->reply_its) + itsignaler_push_notification (job->reply_its, job, NULL); + } + + if ((job->status & JOB_CANCELLED) && worker->jobs_hash) + g_hash_table_remove (worker->jobs_hash, &job->id); + g_rec_mutex_unlock (&worker->rmutex); + } + + if (worker->worker_must_quit) { +#ifdef DEBUG_NOTIFICATION + g_print ("[W] GdaWorker %p, worker thread %p finished!\n", worker, g_thread_self()); +#endif + itsignaler_unref (worker->submit_its); + g_rec_mutex_clear (& worker->rmutex); + g_slice_free (GdaWorker, worker); + bg_update_stats (BG_DESTROYED_WORKER); + + bg_join_thread (); + return NULL; + } + } + return NULL; +} + +/** + * gda_worker_new: + * + * Creates a new #GdaWorker object. + * + * Returns: (transfer full): a new #GdaWorker, or %NULL if an error occurred + * + * Since: 6.0 + */ +GdaWorker * +gda_worker_new (void) +{ + GdaWorker *worker; + worker = bg_get_spare_gda_worker (); + if (worker) + return worker; + + worker = g_slice_new0 (GdaWorker); + worker->submit_its = itsignaler_new (); + if (!worker->submit_its) { + g_slice_free (GdaWorker, worker); + return NULL; + } + + worker->ref_count = 1; + + worker->callbacks_hash = g_hash_table_new_full (NULL, NULL, NULL, + (GDestroyNotify) declared_callback_free); + worker->jobs_hash = g_hash_table_new_full (g_int_hash, g_int_equal, NULL, (GDestroyNotify) worker_job_free); + + worker->worker_must_quit = 0; + worker->location = NULL; + + g_rec_mutex_init (& worker->rmutex); + + gchar *str; + static guint counter = 0; + str = g_strdup_printf ("gdaWrkrTh%u", counter); + counter++; + worker->worker_thread = g_thread_try_new (str, (GThreadFunc) worker_thread_main, worker, NULL); + g_free (str); + if (!worker->worker_thread) { + itsignaler_unref (worker->submit_its); + g_hash_table_destroy (worker->callbacks_hash); + g_hash_table_destroy (worker->jobs_hash); + g_rec_mutex_clear (& worker->rmutex); + g_slice_free (GdaWorker, worker); + return NULL; + } + else + bg_update_stats (BG_STARTED_THREADS); + +#ifdef DEBUG_NOTIFICATION + g_print ("[W] created GdaWorker %p\n", worker); +#endif + + bg_update_stats (BG_CREATED_WORKER); + return worker; +} + +static GMutex unique_worker_mutex; + +/** + * gda_worker_new_unique: + * @location: a place to store and test for existence, not %NULL + * @allow_destroy: defines if the created @GdaWorker (see case 1 below) will allow its reference to drop to 0 and be destroyed + * + * This function creates a new #GdaWorker, or reuses the one at @location. Specifically: + * + * if *@location is %NULL, then a new #GdaWorker is created. In this case if @allow_destroy is %FALSE, then the returned + * #GdaWorker's reference count is 2, thus preventing it form ever being destroyed (unless gda_worker_unref() is called somewhere else) + * if *@location is not %NULL, the the #GdaWorker it points to is returned, its reference count increased by 1 + * + * + * When the returned #GdaWorker's reference count reaches 0, then it is destroyed, and *@location is set to %NULL. + * + * In any case, the returned value is the same as *@location. + * + * Returns: (transfer full): a #GdaWorker + */ +GdaWorker * +gda_worker_new_unique (GdaWorker **location, gboolean allow_destroy) +{ + g_return_val_if_fail (location, NULL); + + g_mutex_lock (&unique_worker_mutex); + if (*location) + gda_worker_ref (*location); + else { + GdaWorker *worker; + worker = gda_worker_new (); + if (! allow_destroy) + gda_worker_ref (worker); + worker->location = location; + *location = worker; + } + g_mutex_unlock (&unique_worker_mutex); + + return *location; +} + +/** + * gda_worker_ref: + * @worker: a #GdaWorker + * + * Increases @worker's reference count. + * + * Returns: (transfer full): @worker + * + * Since: 6.0 + */ +GdaWorker * +gda_worker_ref (GdaWorker *worker) +{ + g_return_val_if_fail (worker, NULL); + g_rec_mutex_lock (& worker->rmutex); + worker->ref_count ++; +#ifdef DEBUG_NOTIFICATION + g_print ("[W] GdaWorker %p reference increased to %u\n", worker, worker->ref_count); +#endif + g_rec_mutex_unlock (& worker->rmutex); + + return worker; +} + +void +_gda_worker_unref (GdaWorker *worker, gboolean give_to_bg) +{ + g_assert (worker); + + gboolean unique_locked = FALSE; + if (worker->location) { + g_mutex_lock (&unique_worker_mutex); + unique_locked = TRUE; + } + +#ifdef DEBUG_NOTIFICATION + g_print ("[W] GdaWorker %p reference decreased to ", worker); +#endif + + g_rec_mutex_lock (& worker->rmutex); + worker->ref_count --; + +#ifdef DEBUG_NOTIFICATION + g_print ("%u\n", worker->ref_count); +#endif + + if (worker->ref_count == 0) { + /* destroy all the interal resources which will not be reused even if the GdaWorker is reused */ + g_hash_table_destroy (worker->callbacks_hash); + worker->callbacks_hash = NULL; + g_hash_table_destroy (worker->jobs_hash); + worker->jobs_hash = NULL; + if (worker->location) + *(worker->location) = NULL; + + if (give_to_bg) { + /* re-create the resources so the GdaWorker is ready to be used again */ + worker->ref_count = 1; + worker->callbacks_hash = g_hash_table_new_full (NULL, NULL, NULL, + (GDestroyNotify) declared_callback_free); + worker->jobs_hash = g_hash_table_new_full (g_int_hash, g_int_equal, NULL, (GDestroyNotify) worker_job_free); + worker->worker_must_quit = 0; + worker->location = NULL; + + bg_set_spare_gda_worker (worker); + } + else { + /* REM: we don't need to g_thread_join() the worker thread because the "background" will do it */ + + /* free all the resources used by @worker */ + itsignaler_unref (worker->submit_its); + worker->worker_must_quit = 1; /* request the worker thread to exit */ + } + g_rec_mutex_unlock (& worker->rmutex); + } + else + g_rec_mutex_unlock (& worker->rmutex); + + if (unique_locked) + g_mutex_unlock (&unique_worker_mutex); +} + +void +_gda_worker_bg_unref (GdaWorker *worker) +{ + g_assert (worker); + g_assert (worker->ref_count == 1); + + _gda_worker_unref (worker, FALSE); +} + +/** + * gda_worker_unref: + * @worker: (nullable): a #GdaWorker, or %NULL + * + * Decreases @worker's reference count. When reference count reaches %0, then the + * object is destroyed, note that in this case this function only returns when the + * worker thread actually has terminated, which can take some time if it's busy. + * + * If @worker is %NULL, then nothing happens. + * + * Since: 6.0 + */ +void +gda_worker_unref (GdaWorker *worker) +{ + if (worker) + _gda_worker_unref (worker, TRUE); +} + +/* + * WARNING: calling this function, the worker->rmutex _must_ be locked + * + * Returns: a job ID, or %0 if an error occurred + */ +static guint +_gda_worker_submit_job_with_its (GdaWorker *worker, ITSignaler *reply_its, GdaWorkerFunc func, + gpointer data, GDestroyNotify data_destroy_func, + GDestroyNotify result_destroy_func, G_GNUC_UNUSED GError **error) +{ + guint jid = 0; + WorkerJob *job; + job = worker_job_new (reply_its, func, data, data_destroy_func, result_destroy_func); + g_assert (job); + if (worker->worker_thread == g_thread_self ()) { + /* run the job right away */ + g_hash_table_insert (worker->jobs_hash, & job->id, job); + jid = job->id; + job->status |= JOB_BEING_PROCESSED; + job->result = job->func (job->data, & job->error); + job->status |= JOB_PROCESSED; + if (job->reply_its) + itsignaler_push_notification (job->reply_its, job, NULL); + } + else { + if (itsignaler_push_notification (worker->submit_its, job, NULL)) { + g_hash_table_insert (worker->jobs_hash, & job->id, job); + jid = job->id; + } + else + worker_job_free (job); + } + + return jid; +} + +/** + * gda_worker_submit_job: + * @worker: a #GdaWorker object + * @callback_context: (nullable): a #GMainContext, or %NULL (ignored if no setting has been defined with gda_worker_set_callback()) + * @func: the function to call from the worker thread + * @data: (nullable): the data to pass to @func, or %NULL + * @data_destroy_func: (nullable): a function to destroy @data, or %NULL + * @result_destroy_func: (nullable): a function to destroy the result, if any, of the execution of @func, or %NULL + * @error: (nullable): a place to store errors, or %NULL. + * + * Request that the worker thread call @func with the @data argument. + * + * Notes: + * + * if @data_destroy_func is not %NULL, then it will be called to destroy @data when the job is removed, + * which can occur within the context of the worker thread, or within the context of any thread using @worker. + * if @result_destroy_func is not %NULL, then it will be called to destroy the result produced by @func. + * Similarly to @data_destroy_func, if it is not %NULL (and if there is a non %NULL result), then that function can be + * called in the context of any thread. + * the error here can only report failures while executing gda_worker_submit_job(), not any error which may occur + * while executing @func from the worker thread. + * when this function returns, the job may already have been completed, so you should not assume that the job + * is in any specific state. + * passing %NULL for @callback_context is similar to passing the result of g_main_context_ref_thread_default() + * + * + * Returns: a job ID, or %0 if an error occurred + * + * Since: 6.0 + */ +guint +gda_worker_submit_job (GdaWorker *worker, GMainContext *callback_context, GdaWorkerFunc func, + gpointer data, GDestroyNotify data_destroy_func, + GDestroyNotify result_destroy_func, GError **error) +{ + g_return_val_if_fail (worker, 0); + g_return_val_if_fail (func, 0); + if (!worker->callbacks_hash) { + g_warning ("GdaWorker has been destroyed\n"); + return 0; + } + + DeclaredCallback *dc; + guint jid; + GMainContext *co; + gboolean unref_co = FALSE; + + co = callback_context; + if (!co) { + co = g_main_context_ref_thread_default (); + unref_co = TRUE; + } + + g_rec_mutex_lock (& worker->rmutex); + dc = g_hash_table_lookup (worker->callbacks_hash, co); + jid = _gda_worker_submit_job_with_its (worker, dc ? dc->its : NULL, + func, data, data_destroy_func, result_destroy_func, error); + g_rec_mutex_unlock (& worker->rmutex); + + if (unref_co) + g_main_context_unref (co); + + return jid; +} + +/** + * gda_worker_fetch_job_result: + * @worker: a #GdaWorker object + * @job_id: the ID of the job, as returned by gda_worker_submit_job() + * @out_result: (nullable): a place to store the value returned by the execution of the requested function within the worker thread, or %NULL + * @error: (nullable): a place to store errors, or %NULL + * + * Fetch the value returned by execution the @job_id job. + * + * Warning: if an error occurred during the + * execution of the requested function within the worker thread, then it will show as @error, while the return value + * of this function will be %TRUE. + * + * Note: if there is a result, it will be stored in @out_result, and it's up to the caller to free + * the result, the #GdaWorker object will not do it (ownership of the result is transfered to the caller). + * + * Returns: %TRUE if the jobs has completed + * + * Since: 6.0 + */ +gboolean +gda_worker_fetch_job_result (GdaWorker *worker, guint job_id, gpointer *out_result, GError **error) +{ + g_return_val_if_fail (worker, FALSE); + if (!worker->jobs_hash) { + g_warning ("GdaWorker has been destroyed\n"); + return FALSE; + } + + gda_worker_ref (worker); /* increase reference count to having @worker freed while destroying job */ + + if (out_result) + *out_result = NULL; + + g_rec_mutex_lock (&worker->rmutex); + WorkerJob *job; + job = g_hash_table_lookup (worker->jobs_hash, &job_id); + if (!job) { + g_rec_mutex_unlock (& worker->rmutex); + g_set_error (error, GDA_WORKER_ERROR, GDA_WORKER_JOB_NOT_FOUND_ERROR, + _("Unknown requested job %u"), job_id); + gda_worker_unref (worker); + return FALSE; + } + + gboolean retval = FALSE; + if (job->status & JOB_CANCELLED) + g_set_error (error, GDA_WORKER_ERROR, GDA_WORKER_JOB_CANCELLED_ERROR, + _("Job %u has been cancelled"), job_id); + else if (job->status & JOB_PROCESSED) { + retval = TRUE; + if (out_result) { + *out_result = job->result; + job->result = NULL; + } + if (job->error) { + g_propagate_error (error, job->error); + job->error = NULL; + } + g_hash_table_remove (worker->jobs_hash, &job_id); + } + else if (job->status & JOB_BEING_PROCESSED) + g_set_error (error, GDA_WORKER_ERROR, GDA_WORKER_JOB_BEING_PROCESSED_ERROR, + _("Job %u is being processed"), job_id); + else + g_set_error (error, GDA_WORKER_ERROR, GDA_WORKER_JOB_QUEUED_ERROR, + _("Job %u has not yet been processed"), job_id); + g_rec_mutex_unlock (&worker->rmutex); + + gda_worker_unref (worker); + + return retval; +} + +/** + * gda_worker_cancel_job: + * @worker: a #GdaWorker object + * @job_id: the ID of the job, as returned by gda_worker_submit_job() + * @error: (nullable): a place to store errors, or %NULL + * + * Cancels a job which has not yet been processed. If the job cannot be found, is being processed or has already been processed, + * then this function returns %FALSE. + * + * This function can be called on already cancelled jobs, and simply returns %TRUE in that case. + * + * Returns: %TRUE if the job was cancelled + * + * Since: 6.0 + */ +gboolean +gda_worker_cancel_job (GdaWorker *worker, guint job_id, GError **error) +{ + g_return_val_if_fail (worker, FALSE); + + if (!worker->jobs_hash) { + g_warning ("GdaWorker has been destroyed\n"); + return FALSE; + } + + g_rec_mutex_lock (& worker->rmutex); + + WorkerJob *job; + job = g_hash_table_lookup (worker->jobs_hash, &job_id); + if (!job) { + g_rec_mutex_unlock (& worker->rmutex); + g_set_error (error, GDA_WORKER_ERROR, GDA_WORKER_JOB_NOT_FOUND_ERROR, + _("Unknown requested job %u"), job_id); + return FALSE; + } + + gboolean retval = FALSE; + if (job->status & JOB_BEING_PROCESSED) + g_set_error (error, GDA_WORKER_ERROR, GDA_WORKER_JOB_BEING_PROCESSED_ERROR, + _("Job %u is being processed"), job_id); + else if (job->status & JOB_PROCESSED) + g_set_error (error, GDA_WORKER_ERROR, GDA_WORKER_JOB_QUEUED_ERROR, + _("Job %u has already been processed"), job_id); + else { + retval = TRUE; + job->status |= JOB_CANCELLED; + } + + g_rec_mutex_unlock (&worker->rmutex); + + return retval; +} + +/** + * gda_worker_forget_job: + * @worker: a #GdaWorker object + * @job_id: the ID of the job, as returned by gda_worker_submit_job() + * + * Forget all about the job with ID @job_id. As opposed to gda_worker_cancel_job(), this function can be used to tell + * @worker that whatever happens to the specific job, you are not interrested anymore (i.e. that @worker can + * do whatever is possible to simple discard everything related to that job). + * + * Since: 6.0 + */ +void +gda_worker_forget_job (GdaWorker *worker, guint job_id) +{ + g_return_if_fail (worker); + + if (!worker->jobs_hash) { + g_warning ("GdaWorker has been destroyed\n"); + return; + } + + g_rec_mutex_lock (& worker->rmutex); + WorkerJob *job; + job = g_hash_table_lookup (worker->jobs_hash, &job_id); + if (job) { + if (job->status & JOB_PROCESSED) + /* only case where we can remove the job because the worker thread won't use it */ + g_hash_table_remove (worker->jobs_hash, & job->id); + else + /* the job will be 'cleared' by the worker thread */ + job->status |= JOB_CANCELLED; + } + g_rec_mutex_unlock (&worker->rmutex); +} + +static gboolean +dc_callback (DeclaredCallback *dc) +{ + WorkerJob *job; + job = itsignaler_pop_notification (dc->its, 0); + g_assert (job); + + gpointer result; + guint jid; + GError *error = NULL; + jid = job->id; + if (gda_worker_fetch_job_result (dc->worker, jid, &result, &error)) { + dc->callback (dc->worker, jid, result, error, dc->user_data); + g_clear_error (&error); + } + return TRUE; /* don't remove the source from poll, this can be done using gda_worker_set_callback() */ +} + +/** + * gda_worker_set_callback: + * @worker: a #GdaWorker object + * @context: (nullable): a #GMainContext, or %NULL + * @callback: (nullable) (scope call): the function to call when a job submitted from within the calling thread using gda_worker_submit_job() has finished being processed. + * @user_data: argument passed to @callback + * @error: (nullable): a place to store errors, or %NULL + * + * Declare a callback function to be called when a job has been processed. If @callback is %NULL, then any previously + * effect of this function is removed. If the same function is called with a different @callback value, then the previous one + * is simply replaced. + * + * Since this function adds a new source of events to the specified #GMainContext (or the default one if @context is %NULL), + * + * Notes: + * + * before calling this function, @worker internally gets rid of the job, so the @jib_id passed + * to @callback does not actually designate a known job ID, and so calling gda_worker_fetch_job_result() for that + * job ID will fail + * the job's result, if any, has to be freed by @callback (@worker does not do it) + * any call to this function will only be honored for the jobs submitted _after_ calling it, the ones + * submitted before are not affected + * passing %NULL for @context is similar to passing the result of g_main_context_ref_thread_default() + * + * + * Returns: %TRUE if no error occurred. + * + * Since: 6.0 + */ +gboolean +gda_worker_set_callback (GdaWorker *worker, GMainContext *context, GdaWorkerCallback callback, + gpointer user_data, GError **error) +{ + g_return_val_if_fail (worker, FALSE); + g_return_val_if_fail (callback, FALSE); + if (!worker->callbacks_hash) { + g_warning ("GdaWorker has been destroyed\n"); + return FALSE; + } + + GMainContext *co; + gboolean unref_co = FALSE; + + co = context; + if (!co) { + co = g_main_context_ref_thread_default (); + unref_co = TRUE; + } + +#ifdef DEBUG_NOTIFICATION + g_print ("[W] %s() GMainContext=%p, thread=%p\n", __FUNCTION__, co, g_thread_self()); +#endif + g_rec_mutex_lock (& worker->rmutex); + + gboolean retval = TRUE; + DeclaredCallback *dc = NULL; + dc = g_hash_table_lookup (worker->callbacks_hash, co); + + if (dc) { + if (callback) { + /* change callback's attributes */ + dc->callback = callback; + dc->user_data = user_data; + } + else { + /* remove callback */ + g_hash_table_remove (worker->callbacks_hash, co); + } + } + if (!dc) { + if (callback) { + /* add callback */ + dc = declared_callback_new (worker, co, callback, user_data); + if (!dc) { + g_set_error (error, GDA_WORKER_ERROR, GDA_WORKER_INTER_THREAD_ERROR, + _("Cannot build inter thread communication device")); + g_rec_mutex_unlock (& worker->rmutex); + return FALSE; + } + g_hash_table_insert (worker->callbacks_hash, co, dc); + dc->source_sig_id = itsignaler_add (dc->its, co, (ITSignalerFunc) dc_callback, dc, NULL); + if (dc->source_sig_id == 0) { + g_hash_table_remove (worker->callbacks_hash, co); + g_set_error (error, GDA_WORKER_ERROR, GDA_WORKER_INTER_THREAD_ERROR, + _("GdaWorker internal error")); + retval = FALSE; + } + } + else { + /* nothing to do */ + } + } + + g_rec_mutex_unlock (& worker->rmutex); + + if (unref_co) + g_main_context_unref (co); + + return retval; +} + +static gboolean +do_timer_cb (GMainLoop *loop) +{ + if (g_main_loop_is_running (loop)) + g_main_loop_quit (loop); + return FALSE; /* remove timer */ +} + +static gboolean +do_itsignaler_cb (GMainLoop *loop) +{ + if (g_main_loop_is_running (loop)) + g_main_loop_quit (loop); + return TRUE; /* keep */ +} + +/** + * gda_worker_do_job: + * @worker: a #GdaWorker object + * @context: (nullable): a #GMainContext to execute a main loop in (while waiting), or %NULL + * @timeout_ms: the maximum number of milisecons to wait before returning, or %0 for unlimited wait + * @out_result: (nullable): a place to store the result, if any, of @func's execution, or %NULL + * @out_job_id: (nullable): a place to store the ID of the job having been submitted, or %NULL + * @func: the function to call from the worker thread + * @data: (nullable): the data to pass to @func, or %NULL + * @data_destroy_func: (nullable): a function to destroy @data, or %NULL + * @result_destroy_func: (nullable): a function to destroy the result, if any, of @func's execution, or %NULL + * @error: (nullable): a place to store errors, or %NULL. + * + * Request that the worker thread call @func with the @data argument, much like gda_worker_submit_job(), + * but waits (starting a #GMainLoop) for a maximum of @timeout_ms miliseconds for @func to be executed. + * + * If this function is called from within @worker's worker thread, then this function simply calls @func with @data and does not + * use @context. + * + * The following cases are possible if this function is not called from within @worker's worker thread: + * + * the call to @func took less than @timeout_ms miliseconds: the return value is %TRUE and + * @out_result contains the result of the @func's execution, and @out_job_id contains %NULL. Note in this + * case that @error may still contain an error code if @func's execution produced an error. Also note that in this case + * any setting defined by gda_worker_set_callback() is not applied (as the result is immediately returned) + * The call to @func takes more then @timeout_ms miliseconds: the return value is %TRUE and + * @out_result is %NULL and @out_job_id contains the ID of the job as if it had been submitted using gda_worker_submit_job(). + * If @out_job_id is %NULL, and if no setting has been defined using gda_worker_set_callback(), then the job will be discarded + * (as if gda_worker_forget_job() had been called). + * + * The call to @func could not be done (some kind of plumbing error for instance): the returned value is %FALSE + * and @out_result and @out_job_id are set to %NULL (if they are not %NULL) + * + * + * Notes: + * + * @result_destroy_func is needed in case @out_result is %NULL (to avoid memory leaks) + * passing %NULL for @context is similar to passing the result of g_main_context_ref_thread_default() + * + * + * Returns: %TRUE if no error occurred + * + * Since: 6.0 + */ +gboolean +gda_worker_do_job (GdaWorker *worker, GMainContext *context, gint timeout_ms, + gpointer *out_result, guint *out_job_id, + GdaWorkerFunc func, gpointer data, GDestroyNotify data_destroy_func, + GDestroyNotify result_destroy_func, + GError **error) +{ + if (out_result) + *out_result = NULL; + if (out_job_id) + *out_job_id = 0; + + g_return_val_if_fail (worker, FALSE); + g_return_val_if_fail (func, FALSE); + if (!worker->callbacks_hash || !worker->jobs_hash) { + g_warning ("GdaWorker has been destroyed\n"); + return FALSE; + } + + if (gda_worker_thread_is_worker (worker)) { + /* we are called from within the worker thread => call the function directly */ + gpointer result; + result = func (data, error); + if (data_destroy_func) + data_destroy_func (data); + if (out_result) + *out_result = result; + else if (result && result_destroy_func) + result_destroy_func (result); + return TRUE; + } + + guint jid, itsid, timer = 0; + + /* determine which GMainContext to use */ + GMainContext *co; + gboolean unref_co = FALSE; + + co = context; + if (!co) { + co = g_main_context_ref_thread_default (); + unref_co = TRUE; + } + + /* prepare main loop */ + GMainLoop *loop; + loop = g_main_loop_new (co, FALSE); + + /* prepare ITSignaler to be notified */ + ITSignaler *its; + its = itsignaler_new (); + itsid = itsignaler_add (its, co, (ITSignalerFunc) do_itsignaler_cb, + g_main_loop_ref (loop), (GDestroyNotify) g_main_loop_unref); + + /* push job */ + g_rec_mutex_lock (& worker->rmutex); /* required to call _gda_worker_submit_job_with_its() */ + jid = _gda_worker_submit_job_with_its (worker, its, + func, data, data_destroy_func, result_destroy_func, error); + g_rec_mutex_unlock (& worker->rmutex); + if (jid == 0) { + /* an error occurred */ + g_assert (itsignaler_remove (its, co, itsid)); + itsignaler_unref (its); + g_main_loop_unref (loop); + + if (unref_co) + g_main_context_unref (co); + + return FALSE; + } + + /* check if result is already here */ + WorkerJob *job; + job = itsignaler_pop_notification (its, 0); + if (!job) { + if (timeout_ms > 0) { + /* start timer to limit waiting time */ + GSource *timer_src; + timer_src = g_timeout_source_new (timeout_ms); + g_source_set_callback (timer_src, (GSourceFunc) do_timer_cb, loop, NULL); + timer = g_source_attach (timer_src, co); + g_source_unref (timer_src); + } + g_main_loop_run (loop); + + /* either timer has arrived or job has been done */ + job = itsignaler_pop_notification (its, 0); + } + g_main_loop_unref (loop); + + g_assert (itsignaler_remove (its, co, itsid)); + itsignaler_unref (its); + + if (job) { + /* job done before the timer, if any, elapsed */ + + if (timer > 0) + g_assert (g_source_remove (timer)); + + g_assert (gda_worker_fetch_job_result (worker, jid, out_result, error)); + } + else { + /* timer came first, job is not yet finished */ + + /* apply settings from gda_worker_set_callback(), if any */ + g_rec_mutex_lock (&worker->rmutex); + DeclaredCallback *dc; + dc = g_hash_table_lookup (worker->callbacks_hash, co); + if (dc) { + job = g_hash_table_lookup (worker->jobs_hash, &jid); + g_assert (job); + g_assert (!job->reply_its); + job->reply_its = itsignaler_ref (dc->its); + } + g_rec_mutex_unlock (& worker->rmutex); + + /* cleanups */ + if (out_job_id) + *out_job_id = jid; + else if (!dc) + /* forget all about the job */ + gda_worker_forget_job (worker, jid); + } + + if (unref_co) + g_main_context_unref (co); + + return TRUE; +} + +/** + * gda_worker_wait_job: + * @worker: a #GdaWorker object + * @func: the function to call from the worker thread + * @data: (nullable): the data to pass to @func, or %NULL + * @data_destroy_func: (nullable): a function to destroy @data, or %NULL + * @error: (nullable): a place to store errors, or %NULL. + * + * Request that the worker thread call @func with the @data argument, much like gda_worker_submit_job(), + * but waits (blocks) until @func has been executed. + * + * Note: it's up to the caller to free the result, the #GdaWorker object will not do it (ownership of the result is + * transfered to the caller). + * + * Returns: (transfer full): the result of @func's execution + * + * Since: 6.0 + */ +gpointer +gda_worker_wait_job (GdaWorker *worker, GdaWorkerFunc func, gpointer data, GDestroyNotify data_destroy_func, + GError **error) +{ + g_return_val_if_fail (worker, NULL); + g_return_val_if_fail (func, NULL); + + if (gda_worker_thread_is_worker (worker)) { + /* we are called from within the worker thread => call the function directly */ + gpointer retval; + retval = func (data, error); + if (data_destroy_func) + data_destroy_func (data); + return retval; + } + + guint jid; + + /* prepare ITSignaler to be notified */ + ITSignaler *its; + its = itsignaler_new (); + + /* push job */ + g_rec_mutex_lock (& worker->rmutex); /* required to call _gda_worker_submit_job_with_its() */ + jid = _gda_worker_submit_job_with_its (worker, its, + func, data, data_destroy_func, NULL, error); + g_rec_mutex_unlock (& worker->rmutex); + + if (jid == 0) { + /* an error occurred */ + itsignaler_unref (its); + return NULL; + } + + WorkerJob *job; + job = itsignaler_pop_notification (its, -1); + g_assert (job); + itsignaler_unref (its); + + gpointer result; + g_assert (gda_worker_fetch_job_result (worker, jid, &result, error)); + + return result; +} + +/** + * gda_worker_thread_is_worker: + * @worker: a #GdaWorker + * + * Tells if the thread from which this function is called is @worker's worker thread. + * + * Returns: %TRUE if this function is called is @worker's worker thread + * + * Since: 6.0 + */ +gboolean +gda_worker_thread_is_worker (GdaWorker *worker) +{ + g_return_val_if_fail (worker, FALSE); + return worker->worker_thread == g_thread_self () ? TRUE : FALSE; +} + +/** + * gda_worker_get_worker_thread: + * @worker: a #GdaWorker + * + * Get a pointer to @worker's inner worker thread + * + * Returns: (transfer none): the #GThread + * + * Since: 6.0 + */ +GThread * +gda_worker_get_worker_thread (GdaWorker *worker) +{ + g_return_val_if_fail (worker, NULL); + return worker->worker_thread; +} diff --git a/.flatpak-builder/cache/objects/95/88bd378a9b4bccb57da077b977e65a18949788e028bf5b08920e09e41fb3fd.file b/.flatpak-builder/cache/objects/95/88bd378a9b4bccb57da077b977e65a18949788e028bf5b08920e09e41fb3fd.file new file mode 100644 index 0000000..475063b --- /dev/null +++ b/.flatpak-builder/cache/objects/95/88bd378a9b4bccb57da077b977e65a18949788e028bf5b08920e09e41fb3fd.file @@ -0,0 +1,993 @@ +/* + * Copyright (C) 2007 - 2014 Vivien Malerba + * Copyright (C) 2008 - 2011 Murray Cumming + * Copyright (C) 2009 Bas Driessen + * Copyright (C) 2010 David King + * Copyright (C) 2017-2018 Daniel Espinosa + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include +#include +#include "gda-vconnection-hub.h" +#include "gda-virtual-provider.h" +#include +#include +#include +#include +#include "../gda-sqlite.h" +#include +#include + +typedef struct { + GdaVconnectionHub *hub; + GdaConnection *cnc; + gchar *ns; /* can be NULL in one case only among all the HubConnection structs */ +} HubConnection; + +static void hub_connection_free (HubConnection *hc); +static gboolean attach_hub_connection (GdaVconnectionHub *hub, HubConnection *hc, GError **error); +static void detach_hub_connection (GdaVconnectionHub *hub, HubConnection *hc); + +typedef struct { + GSList *hub_connections; /* list of HubConnection structures */ + GdaSqlParser *internal_parser; +} GdaVconnectionHubPrivate; + +static void gda_vconnection_hub_dispose (GObject *object); + +G_DEFINE_TYPE_WITH_PRIVATE (GdaVconnectionHub, gda_vconnection_hub, GDA_TYPE_VCONNECTION_DATA_MODEL) + + +static HubConnection *get_hub_cnc_by_ns (GdaVconnectionHub *hub, const gchar *ns); +static HubConnection *get_hub_cnc_by_cnc (GdaVconnectionHub *hub, GdaConnection *cnc); + +/* + * GdaVconnectionHub class implementation + */ +static void +gda_vconnection_hub_class_init (GdaVconnectionHubClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->dispose = gda_vconnection_hub_dispose; +} + +static void +gda_vconnection_hub_init (GdaVconnectionHub *cnc) +{ + GdaVconnectionHubPrivate *priv = gda_vconnection_hub_get_instance_private (cnc); + priv->hub_connections = NULL; + priv->internal_parser = gda_sql_parser_new ();; +} + +static void +gda_vconnection_hub_dispose (GObject *object) +{ + GdaVconnectionHub *cnc = (GdaVconnectionHub *) object; + GdaVconnectionHubPrivate *priv = gda_vconnection_hub_get_instance_private (cnc); + + g_return_if_fail (GDA_IS_VCONNECTION_HUB (cnc)); + + /* free memory */ + gda_connection_close ((GdaConnection *) cnc, NULL); + if (priv->hub_connections) { + g_slist_free_full (priv->hub_connections, (GDestroyNotify) hub_connection_free); + priv->hub_connections = NULL; + } + if (priv->internal_parser) { + g_object_unref (priv->internal_parser); + priv->internal_parser = NULL; + } + + /* chain to parent class */ + G_OBJECT_CLASS (gda_vconnection_hub_parent_class)->dispose (object); +} + +/** + * gda_vconnection_hub_add: + * @hub: a #GdaVconnectionHub connection + * @cnc: a #GdaConnection + * @ns: a namespace, or %NULL + * @error: a place to store errors, or %NULL + * + * Make all the tables of @cnc appear as tables (of the same name) in the @hub connection. + * If the @ns is not %NULL, then within @hub, the tables will be accessible using the '@ns.@table_name' + * notation. + * + * Within any instance of @hub, there can be only one added connection where @ns is %NULL. + * + * Returns: TRUE if no error occurred + */ +gboolean +gda_vconnection_hub_add (GdaVconnectionHub *hub, + GdaConnection *cnc, const gchar *ns, GError **error) +{ + HubConnection *hc; + + g_return_val_if_fail (GDA_IS_VCONNECTION_HUB (hub), FALSE); + g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE); + + if (ns == NULL) { + g_set_error (error, GDA_SERVER_PROVIDER_ERROR, + GDA_SERVER_PROVIDER_MISUSE_ERROR, + "%s", _("Namespace must be specified")); + return FALSE; + } + + /* check for constraints */ + hc = get_hub_cnc_by_ns (hub, ns); + if (hc && (hc->cnc != cnc)) { + g_set_error (error, GDA_SERVER_PROVIDER_ERROR, + GDA_SERVER_PROVIDER_MISUSE_ERROR, + _("There is already a namespace named '%s' in use with another connection"), ns); + return FALSE; + } + + if (hc) + return TRUE; + + if (!gda_connection_is_opened (cnc)) { + g_set_error (error, GDA_SERVER_PROVIDER_ERROR, + GDA_SERVER_PROVIDER_MISUSE_ERROR, + _("Connection was not added to virtual connection because it is closed")); + return FALSE; + } + + /* actually adding @cnc */ + hc = g_new (HubConnection, 1); + hc->hub = hub; + hc->cnc = GDA_CONNECTION (g_object_ref (cnc)); + hc->ns = g_strdup (ns); + + if (!attach_hub_connection (hub, hc, error)) { + hub_connection_free (hc); + return FALSE; + } + + return TRUE; +} + +/** + * gda_vconnection_hub_remove: + * @hub: a #GdaVconnectionHub connection + * @cnc: a #GdaConnection + * @error: a place to store errors, or %NULL + * + * Remove all the tables in @hub representing @cnc's tables. + * + * Returns: TRUE if no error occurred + */ +gboolean +gda_vconnection_hub_remove (GdaVconnectionHub *hub, GdaConnection *cnc, GError **error) +{ + HubConnection *hc; + + g_return_val_if_fail (GDA_IS_VCONNECTION_HUB (hub), FALSE); + g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE); + + hc = get_hub_cnc_by_cnc (hub, cnc); + + if (!hc) { + g_set_error (error, GDA_SERVER_PROVIDER_ERROR, + GDA_SERVER_PROVIDER_MISUSE_ERROR, + "%s", _("Connection was not represented in hub")); + return FALSE; + } + + /* clean the priv->hub_connections list */ + detach_hub_connection (hub, hc); + return TRUE; +} + +static HubConnection* +get_hub_cnc_by_ns (GdaVconnectionHub *hub, const gchar *ns) +{ + g_return_val_if_fail (ns != NULL, NULL); + GSList *list; + GdaVconnectionHubPrivate *priv = gda_vconnection_hub_get_instance_private (hub); + for (list = priv->hub_connections; list; list = list->next) { + if ((!ns && !((HubConnection*) list->data)->ns)|| + (ns && ((HubConnection*) list->data)->ns && !strcmp (((HubConnection*) list->data)->ns, ns))) + return (HubConnection*) list->data; + } + return NULL; +} + +static HubConnection * +get_hub_cnc_by_cnc (GdaVconnectionHub *hub, GdaConnection *cnc) +{ + GSList *list; + GdaVconnectionHubPrivate *priv = gda_vconnection_hub_get_instance_private (hub); + for (list = priv->hub_connections; list; list = list->next) { + if (((HubConnection*) list->data)->cnc == cnc) + return (HubConnection*) list->data; + } + return NULL; +} + +/** + * gda_vconnection_hub_get_connection: + * @hub: a #GdaVconnectionHub connection + * @ns: (nullable): a name space, or %NULL + * + * Find the #GdaConnection object in @hub associated to the @ns name space + * + * Returns: the #GdaConnection, or %NULL if no connection is associated to @ns + */ +GdaConnection * +gda_vconnection_hub_get_connection (GdaVconnectionHub *hub, const gchar *ns) +{ + HubConnection *hc; + g_return_val_if_fail (GDA_IS_VCONNECTION_HUB (hub), NULL); + + hc = get_hub_cnc_by_ns (hub, ns); + if (hc) + return hc->cnc; + else + return NULL; +} + +/** + * gda_vconnection_hub_foreach: + * @hub: a #GdaVconnectionHub connection + * @func: a #GdaVconnectionDataModelFunc function pointer + * @data: data to pass to @func calls + * + * Call @func for each #GdaConnection represented in @hub. + */ +void +gda_vconnection_hub_foreach (GdaVconnectionHub *hub, + GdaVConnectionHubFunc func, gpointer data) +{ + GSList *list, *next; + g_return_if_fail (GDA_IS_VCONNECTION_HUB (hub)); + GdaVconnectionHubPrivate *priv = gda_vconnection_hub_get_instance_private (hub); + + if (!func) + return; + + list = priv->hub_connections; + while (list) { + HubConnection *hc = (HubConnection*) list->data; + next = list->next; + func (hc->cnc, hc->ns, data); + list = next; + } +} + +static void meta_changed_cb (GdaMetaStore *store, GSList *changes, HubConnection *hc); + +typedef struct { + GdaVconnectionDataModelSpec spec; + GValue *table_name; + HubConnection *hc; + + GError *cols_error; + gint ncols; + gchar **col_names; /* free using g_strfreev */ + GType *col_gtypes;/* free using g_free */ + gchar **col_dtypes;/* free using g_strfreev */ + + GHashTable *filters_hash; /* key = string; value = a ComputedFilter pointer */ +} LocalSpec; + +static void local_spec_free (LocalSpec *spec) +{ + gda_value_free (spec->table_name); + if (spec->col_names) + g_strfreev (spec->col_names); + if (spec->col_gtypes) + g_free (spec->col_gtypes); + if (spec->col_dtypes) + g_strfreev (spec->col_dtypes); + g_clear_error (&(spec->cols_error)); + if (spec->filters_hash) + g_hash_table_destroy (spec->filters_hash); + g_free (spec); +} + +static void +compute_column_specs (GdaVconnectionDataModelSpec *spec) +{ + LocalSpec *lspec = (LocalSpec *) spec; + gint i, nrows; + GdaDataModel *model; + + if (lspec->col_names) + return; + + model = gda_connection_get_meta_store_data (lspec->hc->cnc, + GDA_CONNECTION_META_FIELDS, NULL, 1, "name", lspec->table_name); + if (!model) + return; + + nrows = gda_data_model_get_n_rows (model); + lspec->col_names = g_new0 (gchar *, nrows+1); + lspec->col_gtypes = g_new0 (GType, nrows); + lspec->col_dtypes = g_new0 (gchar *, nrows+1); + + for (i = 0; i < nrows; i++) { + const GValue *v0, *v1, *v2; + + v0 = gda_data_model_get_value_at (model, 0, i, NULL); + v1 = gda_data_model_get_value_at (model, 1, i, NULL); + v2 = gda_data_model_get_value_at (model, 2, i, NULL); + + if (!v0 || !v1 || !v2) { + break; + } + + lspec->col_names[i] = g_value_dup_string (v0); + lspec->col_gtypes[i] = gda_g_type_from_string (g_value_get_string (v2)); + if (lspec->col_gtypes[i] == G_TYPE_INVALID) + lspec->col_gtypes[i] = GDA_TYPE_NULL; + lspec->col_dtypes[i] = g_value_dup_string (v1); + } + g_object_unref (model); + + if (i != nrows) { + /* there has been an error */ + g_strfreev (lspec->col_names); + lspec->col_names = NULL; + g_free (lspec->col_gtypes); + lspec->col_gtypes = NULL; + g_strfreev (lspec->col_dtypes); + lspec->col_dtypes = NULL; + g_set_error (&(lspec->cols_error), GDA_META_STORE_ERROR, GDA_META_STORE_INTERNAL_ERROR, + _("Unable to get information about table '%s'"), + g_value_get_string (lspec->table_name)); + } + else + lspec->ncols = nrows; +} + +static GList * +dict_table_create_columns_func (GdaVconnectionDataModelSpec *spec, GError **error) +{ + LocalSpec *lspec = (LocalSpec *) spec; + GList *columns = NULL; + gint i; + + compute_column_specs (spec); + if (lspec->cols_error) { + if (error) + *error = g_error_copy (lspec->cols_error); + return NULL; + } + + for (i = 0; i < lspec->ncols; i++) { + GdaColumn *col; + + col = gda_column_new (); + gda_column_set_name (col, lspec->col_names[i]); + gda_column_set_g_type (col, lspec->col_gtypes[i]); + gda_column_set_dbms_type (col, lspec->col_dtypes[i]); + columns = g_list_prepend (columns, col); + } + + return g_list_reverse (columns); +} + +static gchar * +make_string_for_filter (GdaVconnectionDataModelFilter *info) +{ + GString *string; + gint i; + + string = g_string_new (""); + for (i = 0; i < info->nConstraint; i++) { + const struct GdaVirtualConstraint *cons; + cons = &(info->aConstraint [i]); + g_string_append_printf (string, "|%d,%d", cons->iColumn, cons->op); + } + g_string_append_c (string, '/'); + for (i = 0; i < info->nOrderBy; i++) { + struct GdaVirtualOrderby *order; + order = &(info->aOrderBy[i]); + g_string_append_printf (string, "|%d,%d", order->iColumn, order->desc ? 1 : 0); + } + return g_string_free (string, FALSE); +} + +typedef struct { + GdaStatement *stmt; + int orderByConsumed; + struct GdaVirtualConstraintUsage *out_const; +} ComputedFilter; + +static void +computed_filter_free (ComputedFilter *filter) +{ + g_object_unref (filter->stmt); + g_free (filter->out_const); + g_free (filter); +} + +static void +dict_table_create_filter (GdaVconnectionDataModelSpec *spec, GdaVconnectionDataModelFilter *info) +{ + LocalSpec *lspec = (LocalSpec *) spec; + GdaSqlBuilder *b; + gint i; + gchar *hash; + + compute_column_specs (spec); + if (lspec->cols_error) + return; + + hash = make_string_for_filter (info); + if (lspec->filters_hash) { + ComputedFilter *filter; + filter = g_hash_table_lookup (lspec->filters_hash, hash); + if (filter) { + info->idxPointer = filter->stmt; + info->orderByConsumed = filter->orderByConsumed; + memcpy (info->aConstraintUsage, + filter->out_const, + sizeof (struct GdaVirtualConstraintUsage) * info->nConstraint); + /*g_print ("Reusing filter %p, hash=[%s]\n", filter, hash);*/ + g_free (hash); + return; + } + } + + /* SELECT core */ + b = gda_sql_builder_new (GDA_SQL_STATEMENT_SELECT); + for (i = 0; i < lspec->ncols; i++) + gda_sql_builder_select_add_field (b, lspec->col_names[i], NULL, NULL); + gda_sql_builder_select_add_target_id (b, + gda_sql_builder_add_id (b, g_value_get_string (lspec->table_name)), + NULL); + + /* WHERE part */ + gint argpos; + GdaSqlBuilderId *op_ids; + op_ids = g_new (GdaSqlBuilderId, info->nConstraint); + for (i = 0, argpos = 0; i < info->nConstraint; i++) { + const struct GdaVirtualConstraint *cons; + cons = &(info->aConstraint [i]); + if (cons->iColumn >= lspec->ncols) { + g_warning ("Internal error: column known by SQLite's virtual table %d is not known for " + "table '%s', which has %d column(s)", cons->iColumn, + g_value_get_string (lspec->table_name), lspec->ncols); + continue; + } + + GdaSqlBuilderId fid, pid, eid; + gchar *pname; + + if (lspec->col_gtypes[cons->iColumn] == GDA_TYPE_BLOB) /* ignore BLOBs */ + continue; + + fid = gda_sql_builder_add_id (b, lspec->col_names[cons->iColumn]); + pname = g_strdup_printf ("param%d", argpos); + pid = gda_sql_builder_add_param (b, pname, lspec->col_gtypes[cons->iColumn], TRUE); + g_free (pname); + eid = gda_sql_builder_add_cond (b, cons->op, fid, pid, 0); + op_ids[argpos] = eid; + + /* update info->aConstraintUsage */ + info->aConstraintUsage [i].argvIndex = argpos+1; + info->aConstraintUsage [i].omit = 1; + argpos++; + } + if (argpos > 0) { + GdaSqlBuilderId whid; + whid = gda_sql_builder_add_cond_v (b, GDA_SQL_OPERATOR_TYPE_AND, op_ids, argpos); + gda_sql_builder_set_where (b, whid); + } + g_free (op_ids); + + /* ORDER BY part */ + info->orderByConsumed = FALSE; + for (i = 0; i < info->nOrderBy; i++) { + struct GdaVirtualOrderby *ao; + GdaSqlBuilderId fid; + info->orderByConsumed = TRUE; + ao = &(info->aOrderBy [i]); + if (ao->iColumn >= lspec->ncols) { + g_warning ("Internal error: column known by SQLite's virtual table %d is not known for " + "table '%s', which has %d column(s)", ao->iColumn, + g_value_get_string (lspec->table_name), lspec->ncols); + info->orderByConsumed = FALSE; + continue; + } + fid = gda_sql_builder_add_id (b, lspec->col_names[ao->iColumn]); + gda_sql_builder_select_order_by (b, fid, ao->desc ? FALSE : TRUE, NULL); + } + + GdaStatement *stmt; + stmt = gda_sql_builder_get_statement (b, NULL); + g_object_unref (b); + if (stmt) { + ComputedFilter *filter; + + filter = g_new0 (ComputedFilter, 1); + filter->stmt = stmt; + filter->orderByConsumed = info->orderByConsumed; + filter->out_const = g_new (struct GdaVirtualConstraintUsage, info->nConstraint); + memcpy (filter->out_const, + info->aConstraintUsage, + sizeof (struct GdaVirtualConstraintUsage) * info->nConstraint); + + gchar *sql; + sql = gda_statement_to_sql (stmt, NULL, NULL); + /*g_print ("Filter %p for [%s] hash=[%s]\n", filter, sql, hash);*/ + g_free (sql); + + if (! lspec->filters_hash) + lspec->filters_hash = g_hash_table_new_full (g_str_hash, g_str_equal, + g_free, + (GDestroyNotify) computed_filter_free); + + g_hash_table_insert (lspec->filters_hash, hash, filter); + info->idxPointer = filter->stmt; + /*g_print ("There are now %d statements in store...\n", g_hash_table_size (lspec->filters_hash));*/ + } + else { + for (i = 0, argpos = 0; i < info->nConstraint; i++) { + info->aConstraintUsage[i].argvIndex = 0; + info->aConstraintUsage[i].omit = FALSE; + } + info->idxPointer = NULL; + info->orderByConsumed = FALSE; + g_free (hash); + } +} + + +/* + * Takes as input #GValue created when calling spec->create_filtered_model_func() + * and creates a GValue with the correct requested type + */ +static GValue * +create_value_from_sqlite3_gvalue (GType type, GValue *svalue, GError **error) +{ + GValue *value; + gboolean allok = TRUE; + value = g_new0 (GValue, 1); + + g_value_init (value, type); + + if (type == GDA_TYPE_NULL) + ; + else if (type == G_TYPE_INT) { + if (G_VALUE_TYPE (svalue) != G_TYPE_INT64) + allok = FALSE; + else { + gint64 i; + i = g_value_get_int64 (svalue); + if ((i > G_MAXINT) || (i < G_MININT)) { + g_set_error (error, GDA_SERVER_PROVIDER_ERROR, + GDA_SERVER_PROVIDER_DATA_ERROR, + "%s", _("Integer value is out of bounds")); + allok = FALSE; + } + else + g_value_set_int (value, (gint) i); + } + } + else if (type == G_TYPE_UINT) { + if (G_VALUE_TYPE (svalue) != G_TYPE_INT64) + allok = FALSE; + else { + gint64 i; + i = g_value_get_int64 (svalue); + if ((i < 0) || (i > G_MAXUINT)) { + g_set_error (error, GDA_SERVER_PROVIDER_ERROR, + GDA_SERVER_PROVIDER_DATA_ERROR, + "%s", _("Integer value is out of bounds")); + allok = FALSE; + } + else + g_value_set_uint (value, (guint) i); + } + } + else if (type == G_TYPE_INT64) { + if (G_VALUE_TYPE (svalue) != G_TYPE_INT64) + allok = FALSE; + else + g_value_set_int64 (value, g_value_get_int64 (svalue)); + } + else if (type == G_TYPE_UINT64) { + if (G_VALUE_TYPE (svalue) != G_TYPE_INT64) + allok = FALSE; + else + g_value_set_uint64 (value, (guint64) g_value_get_int64 (svalue)); + } + else if (type == G_TYPE_DOUBLE) { + if (G_VALUE_TYPE (svalue) != G_TYPE_DOUBLE) + allok = FALSE; + else + g_value_set_double (value, g_value_get_double (svalue)); + } + else if (type == G_TYPE_STRING) { + if (G_VALUE_TYPE (svalue) != G_TYPE_STRING) + allok = FALSE; + else + g_value_set_string (value, g_value_get_string (svalue)); + } + else if (type == GDA_TYPE_BINARY) { + if (G_VALUE_TYPE (svalue) != GDA_TYPE_BINARY) + allok = FALSE; + else + gda_value_set_binary (value, gda_value_get_binary (svalue)); + } + else if (type == GDA_TYPE_BLOB) { + g_set_error (error, GDA_SERVER_PROVIDER_ERROR, + GDA_SERVER_PROVIDER_DATA_ERROR, + "%s", _("Blob constraints are not handled in virtual table condition")); + allok = FALSE; + } + else if (type == G_TYPE_BOOLEAN) { + if (G_VALUE_TYPE (svalue) != G_TYPE_INT64) + allok = FALSE; + else + g_value_set_boolean (value, g_value_get_int64 (svalue) == 0 ? FALSE : TRUE); + } + else if (type == G_TYPE_DATE) { + if (G_VALUE_TYPE (svalue) != G_TYPE_STRING) + allok = FALSE; + else { + GDate date; + if (!gda_parse_iso8601_date (&date, g_value_get_string (svalue))) { + g_set_error (error, GDA_SERVER_PROVIDER_ERROR, + GDA_SERVER_PROVIDER_DATA_ERROR, + _("Invalid date '%s' (date format should be YYYY-MM-DD)"), + g_value_get_string (svalue)); + allok = FALSE; + } + else + g_value_set_boxed (value, &date); + } + } + else if (type == GDA_TYPE_TIME) { + if (G_VALUE_TYPE (svalue) != G_TYPE_STRING) + allok = FALSE; + else { + GdaTime* timegda = gda_parse_iso8601_time (g_value_get_string (svalue)); + if (!timegda) { + g_set_error (error, GDA_SERVER_PROVIDER_ERROR, + GDA_SERVER_PROVIDER_DATA_ERROR, + _("Invalid time '%s' (time format should be HH:MM:SS[.ms])"), + g_value_get_string (svalue)); + allok = FALSE; + } + else + gda_value_set_time (value, timegda); + gda_time_free (timegda); + } + } + else if (g_type_is_a (type, G_TYPE_DATE_TIME)) { + if (!g_type_is_a (G_VALUE_TYPE (svalue), G_TYPE_STRING)) + allok = FALSE; + else { + GTimeZone *tz = g_time_zone_new_utc (); + GDateTime* timestamp = g_date_time_new_from_iso8601 (g_value_get_string (svalue), tz); + g_time_zone_unref (tz); + if (timestamp == NULL) { + g_set_error (error, GDA_SERVER_PROVIDER_ERROR, + GDA_SERVER_PROVIDER_DATA_ERROR, + _("Invalid timestamp '%s' (format should be YYYY-MM-DDTHH:MM:SS[.ms])"), + g_value_get_string (svalue)); + allok = FALSE; + } + else { + g_value_set_boxed (value, timestamp); + g_date_time_unref (timestamp); + } + } + } + else + g_error ("Unhandled GDA type %s in SQLite recordset", + gda_g_type_to_string (type)); + + if (! allok) { + g_free (value); + return NULL; + } + else + return value; +} + +static GdaDataModel * +dict_table_create_model_func (GdaVconnectionDataModelSpec *spec, G_GNUC_UNUSED int idxNum, const char *idxStr, + int argc, GValue **argv) +{ + GdaDataModel *model; + GdaStatement *stmt = NULL; + GdaSet *params = NULL; + LocalSpec *lspec = (LocalSpec *) spec; + + if (idxStr) { + gint i; + GSList *list; + stmt = GDA_STATEMENT ((GdaStatement*) idxStr); + g_assert (GDA_IS_STATEMENT (stmt)); + if (! gda_statement_get_parameters (stmt, ¶ms, NULL)) + return NULL; + if (argc > 0) { + g_assert (params && ((guint)argc == g_slist_length (gda_set_get_holders (params)))); + for (i = 0, list = gda_set_get_holders (params); i < argc; i++, list = list->next) { + GdaHolder *holder = GDA_HOLDER (list->data); + GValue *value; + value = create_value_from_sqlite3_gvalue (gda_holder_get_g_type (holder), + argv [i], NULL); + if (value) + g_assert (gda_holder_take_value (holder, value, NULL)); + else { + g_object_ref (params); + return NULL; + } + } + } + g_object_ref (stmt); + } + else { + GdaSqlBuilder *b; + b = gda_sql_builder_new (GDA_SQL_STATEMENT_SELECT); + if (lspec->ncols > 0) { + gint i; + for (i = 0; i < lspec->ncols; i++) + gda_sql_builder_select_add_field (b, lspec->col_names[i], NULL, NULL); + } + else + gda_sql_builder_add_field_value_id (b, + gda_sql_builder_add_id (b, "*"), 0); + gda_sql_builder_select_add_target_id (b, + gda_sql_builder_add_id (b, g_value_get_string (lspec->table_name)), + NULL); + stmt = gda_sql_builder_get_statement (b, NULL); + g_object_unref (b); + g_assert (stmt); + } + GError *lerror = NULL; +#ifdef GDA_DEBUG_NO + gchar *sql; + sql = gda_statement_to_sql (stmt, params, NULL); + g_print ("Executed: [%s]\n", sql); + g_free (sql); +#endif + model = gda_connection_statement_execute_select_full (lspec->hc->cnc, stmt, params, + GDA_STATEMENT_MODEL_CURSOR_FORWARD, NULL, + &lerror); + g_object_unref (stmt); + if (params) + g_object_unref (params); + if (model) + gda_data_select_compute_modification_statements (GDA_DATA_SELECT (model), NULL); + else { + gda_log_message ("Virtual table: data model error: %s", + lerror && lerror->message ? lerror->message : "no detail"); + g_clear_error (&lerror); + } + + return model; +} +static gboolean table_add (HubConnection *hc, const GValue *table_name, GError **error); +static void table_remove (HubConnection *hc, const GValue *table_name); +static gchar *get_complete_table_name (HubConnection *hc, const GValue *table_name); + +static gboolean +attach_hub_connection (GdaVconnectionHub *hub, HubConnection *hc, GError **error) +{ + gchar *tmp; + GdaMetaStore *store; + GdaMetaContext context; + GdaConnectionOptions options; + GdaVconnectionHubPrivate *priv = gda_vconnection_hub_get_instance_private (hub); + + store = gda_connection_get_meta_store (hc->cnc); + g_assert (store); + g_object_get ((GObject*) hc->cnc, "options", &options, NULL); + if (! (options & GDA_CONNECTION_OPTIONS_AUTO_META_DATA)) { + /* make sure the meta store is up to date */ + context.table_name = "_tables"; + context.size = 0; + if (!gda_connection_update_meta_store (hc->cnc, &context, error)) + return FALSE; + } + + /* add a :memory: database */ + if (hc->ns) { + GdaStatement *stmt; + tmp = g_strdup_printf ("ATTACH ':memory:' AS %s", hc->ns); + stmt = gda_sql_parser_parse_string (priv->internal_parser, tmp, NULL, NULL); + g_free (tmp); + g_assert (stmt); + if (gda_connection_statement_execute_non_select (GDA_CONNECTION (hub), stmt, NULL, NULL, error) == -1) { + g_object_unref (stmt); + return FALSE; + } + g_object_unref (stmt); + } + + /* add virtual tables */ + GdaDataModel *model; + gint i, nrows; + model = gda_connection_get_meta_store_data (hc->cnc, GDA_CONNECTION_META_TABLES, error, 0); + if (!model) + return FALSE; + + nrows = gda_data_model_get_n_rows (model); + for (i = 0; i < nrows; i++) { + const GValue *cv = gda_data_model_get_value_at (model, 0, i, error); + const GValue *cv1 = gda_data_model_get_value_at (model, 2, i, error); + if (!cv || !cv1) { + g_object_unref (model); + return FALSE; + } + + /* ignore tables which require a complete name . */ + if (!gda_value_differ (cv, cv1)) + continue; + + if (!table_add (hc, cv, error)) { + g_object_unref (model); + return FALSE; + } + } + g_object_unref (model); + + /* monitor changes */ + g_signal_connect (store, "meta-changed", G_CALLBACK (meta_changed_cb), hc); + + priv->hub_connections = g_slist_append (priv->hub_connections, hc); + return TRUE; +} + +static gchar * +get_complete_table_name (HubConnection *hc, const GValue *table_name) +{ + if (hc->ns) + return g_strdup_printf ("%s.%s", hc->ns, g_value_get_string (table_name)); + else + return g_strdup (g_value_get_string (table_name)); +} + +static void +meta_changed_cb (G_GNUC_UNUSED GdaMetaStore *store, GSList *changes, HubConnection *hc) +{ + GSList *list; + for (list = changes; list; list = list->next) { + GdaMetaStoreChange *ch = (GdaMetaStoreChange*) list->data; + GValue *tsn, *tn; + + /* we are only interested in changes occurring in the "_tables" table */ + if (!strcmp (gda_meta_store_change_get_table_name (ch), "_tables")) { + switch (gda_meta_store_change_get_change_type (ch)) { + case GDA_META_STORE_ADD: { + /* we only want tables where table_short_name = table_name */ + tsn = g_hash_table_lookup (gda_meta_store_change_get_keys (ch), "+6"); + tn = g_hash_table_lookup (gda_meta_store_change_get_keys (ch), "+2"); + if (tn && tsn && !gda_value_compare (tsn, tn)) + table_add (hc, tn, NULL); + break; + } + case GDA_META_STORE_REMOVE: { + /* we only want tables where table_short_name = table_name */ + tsn = g_hash_table_lookup (gda_meta_store_change_get_keys (ch), "-6"); + tn = g_hash_table_lookup (gda_meta_store_change_get_keys (ch), "-2"); + if (tn && tsn && !gda_value_compare (tsn, tn)) + table_remove (hc, tn); + break; + } + case GDA_META_STORE_MODIFY: { + /* we only want tables where table_short_name = table_name */ + tsn = g_hash_table_lookup (gda_meta_store_change_get_keys (ch), "-6"); + tn = g_hash_table_lookup (gda_meta_store_change_get_keys (ch), "-2"); + if (tn && tsn && !gda_value_compare (tsn, tn)) + table_remove (hc, tn); + tsn = g_hash_table_lookup (gda_meta_store_change_get_keys (ch), "+6"); + tn = g_hash_table_lookup (gda_meta_store_change_get_keys (ch), "+2"); + if (tn && tsn && !gda_value_compare (tsn, tn)) + table_add (hc, tn, NULL); + break; + } + } + } + else if (!strcmp (gda_meta_store_change_get_table_name (ch), "_columns")) { + /* TODO */ + } + } +} + +static gboolean +table_add (HubConnection *hc, const GValue *table_name, GError **error) +{ + LocalSpec *lspec; + gchar *tmp; + + lspec = g_new0 (LocalSpec, 1); + GDA_VCONNECTION_DATA_MODEL_SPEC (lspec)->data_model = NULL; + GDA_VCONNECTION_DATA_MODEL_SPEC (lspec)->create_columns_func = (GdaVconnectionDataModelCreateColumnsFunc) dict_table_create_columns_func; + GDA_VCONNECTION_DATA_MODEL_SPEC (lspec)->create_model_func = NULL; + GDA_VCONNECTION_DATA_MODEL_SPEC (lspec)->create_filter_func = dict_table_create_filter; + GDA_VCONNECTION_DATA_MODEL_SPEC (lspec)->create_filtered_model_func = dict_table_create_model_func; + lspec->table_name = gda_value_copy (table_name); + lspec->hc = hc; + tmp = get_complete_table_name (hc, lspec->table_name); + /*g_print ("%s (HC=%p, table_name=%s) name=%s\n", __FUNCTION__, hc, g_value_get_string (table_name), tmp);*/ + if (!gda_vconnection_data_model_add (GDA_VCONNECTION_DATA_MODEL (hc->hub), (GdaVconnectionDataModelSpec*) lspec, + (GDestroyNotify) local_spec_free, tmp, error)) { + g_free (tmp); + return FALSE; + } + g_free (tmp); + return TRUE; +} + +static void +table_remove (HubConnection *hc, const GValue *table_name) +{ + gchar *name; + + name = get_complete_table_name (hc, table_name); + /*g_print ("%s (HC=%p, table_name=%s) name=%s\n", __FUNCTION__, hc, g_value_get_string (table_name), name);*/ + gda_vconnection_data_model_remove (GDA_VCONNECTION_DATA_MODEL (hc->hub), name, NULL); + g_free (name); +} + +static void +detach_hub_connection (GdaVconnectionHub *hub, HubConnection *hc) +{ + GdaMetaStore *store; + GdaDataModel *model; + gint i, nrows; + GdaVconnectionHubPrivate *priv = gda_vconnection_hub_get_instance_private (hub); + + /* un-monitor changes */ + g_object_get (G_OBJECT (hc->cnc), "meta-store", &store, NULL); + g_assert (store); + g_signal_handlers_disconnect_by_func (store, G_CALLBACK (meta_changed_cb), hc); + + /* remove virtual tables */ + model = gda_connection_get_meta_store_data (hc->cnc, GDA_CONNECTION_META_TABLES, NULL, 0); + if (!model) + return; + nrows = gda_data_model_get_n_rows (model); + for (i = 0; i < nrows; i++) { + const GValue *cv = gda_data_model_get_value_at (model, 0, i, NULL); + if (cv) + table_remove (hc, cv); + } + g_object_unref (model); + + /* remove the :memory: database */ + if (hc->ns) { + GdaStatement *stmt; + gchar *tmp; + tmp = g_strdup_printf ("DETACH %s", hc->ns); + stmt = gda_sql_parser_parse_string (priv->internal_parser, tmp, NULL, NULL); + g_free (tmp); + g_assert (stmt); + gda_connection_statement_execute_non_select (GDA_CONNECTION (hub), stmt, NULL, NULL, NULL); + g_object_unref (stmt); + } + + priv->hub_connections = g_slist_remove (priv->hub_connections, hc); + hub_connection_free (hc); +} + +static void +hub_connection_free (HubConnection *hc) +{ + g_object_unref (hc->cnc); + g_free (hc->ns); + g_free (hc); +} diff --git a/.flatpak-builder/cache/objects/95/ac0b0d7aec6ee5115a448ae65248f7dff7144a6565cb46bb20ee7bcf4ce699.dirtree b/.flatpak-builder/cache/objects/95/ac0b0d7aec6ee5115a448ae65248f7dff7144a6565cb46bb20ee7bcf4ce699.dirtree new file mode 100644 index 0000000..f9ad021 Binary files /dev/null and b/.flatpak-builder/cache/objects/95/ac0b0d7aec6ee5115a448ae65248f7dff7144a6565cb46bb20ee7bcf4ce699.dirtree differ diff --git a/.flatpak-builder/cache/objects/95/db12dd21805a3c316c6bbaaee3a53fc16faf93d694eea309cdb8546f445258.file b/.flatpak-builder/cache/objects/95/db12dd21805a3c316c6bbaaee3a53fc16faf93d694eea309cdb8546f445258.file new file mode 120000 index 0000000..456d71b --- /dev/null +++ b/.flatpak-builder/cache/objects/95/db12dd21805a3c316c6bbaaee3a53fc16faf93d694eea309cdb8546f445258.file @@ -0,0 +1 @@ +../../share/runtime/locale/lv/share/lv \ No newline at end of file diff --git a/.flatpak-builder/cache/objects/95/dfe17758846d4e8e92c7697284d7721fffb4af6064ca6a7793b2670bbdc664.file b/.flatpak-builder/cache/objects/95/dfe17758846d4e8e92c7697284d7721fffb4af6064ca6a7793b2670bbdc664.file new file mode 100644 index 0000000..4e5b6f7 --- /dev/null +++ b/.flatpak-builder/cache/objects/95/dfe17758846d4e8e92c7697284d7721fffb4af6064ca6a7793b2670bbdc664.file @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2007 Armin Burgmeier + * Copyright (C) 2007 - 2014 Vivien Malerba + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GDA_BLOB_OP_H__ +#define __GDA_BLOB_OP_H__ + +#include +#include +#include +#include + +G_BEGIN_DECLS + +#define GDA_TYPE_BLOB_OP (gda_blob_op_get_type()) +G_DECLARE_DERIVABLE_TYPE (GdaBlobOp, gda_blob_op, GDA, BLOB_OP, GObject) +struct _GdaBlobOpClass { + GObjectClass parent_class; + gpointer functions; + + /* Padding for future expansion */ + gpointer padding[12]; +}; + +/** + * SECTION:gda-blob-op + * @short_description: Binary data and BLOBs handling + * @title: GdaBlob + * @stability: Stable + * @see_also: + * + * This object is a base class for individual database providers which support BLOB types. It supports + * operations to read and write data in a BLOB value (of type GDA_BLOB_TYPE). + * + * Libgda offers two methods to manipulate binary values as two containers: GdaBinary + * and GdaBlob: + * + * When reading from a data model returned by &LIBGDA; binary data will often be in a GdaBlob + * object, and the associated GdaBlobOp object can be used to manipulate the + * binary object (in a database for example) + * When the binary value is created by the user, then there is no point in using a GdaBlob as + * there can not be any GdaBlobOp object, so the GdaBinary container is + * enough. + * + * + * Note that a GdaBlob value (the "data" attribute) will often not contain any data + * (or only some part of the actual BLOB) + * and that it's up to the user to use the associated GdaBlobOp object to + * "load" the data into the container (into the actual process heap). + * + * For example to load the 1st 40 bytes of a blob: + * + *GValue *blob_value = ... + *GdaBlob *blob; + * + *blob = (GdaBlob*) gda_value_get_blob (blob_value); + *gda_blob_op_read (blob->op, blob, 0, 40); + * + * + * Another example is to write the contents of a blob to a file on disk, using a special + * GdaBlobOp object (internal to &LIBGDA; which interfaces + * with a file in a filesystem): + * + *GValue *blob_value; // value to copy from + *GValue *tmp_value; + *GdaBlob *file_blob; + * + *GValue *blob_value = ... + *tmp_value = gda_value_new_blob_from_file ("MyFile.bin"); + *file_blob = (GdaBlob*) gda_value_get_blob (tmp_value); + * + *if (! gda_blob_op_write_all (file_blob->op, gda_value_get_blob (blob_value))) { + * // error + *} + *else { + * gsize size; + * size = gda_blob_op_get_length (file_blob->op); + * g_print ("Wrote %s, size = %d\n", filename, size); + *} + *gda_value_free (tmp_value); + * + * + * For further information, see: + * + * the section about Binary large objects (BLOBs)'s + * abstraction + * Virtual methods for Blob operations + * section for more information + * about how to implement the virtual methods when creating a database provider + * + */ + +glong gda_blob_op_get_length (GdaBlobOp *op); +glong gda_blob_op_read (GdaBlobOp *op, GdaBlob *blob, glong offset, glong size); +gboolean gda_blob_op_read_all (GdaBlobOp *op, GdaBlob *blob); +glong gda_blob_op_write (GdaBlobOp *op, GdaBlob *blob, glong offset); +gboolean gda_blob_op_write_all (GdaBlobOp *op, GdaBlob *blob); + +G_END_DECLS + +#endif + diff --git a/.flatpak-builder/cache/objects/95/ef0f39add0046c6fbbce84ab176c947b5743f975ef3338b3e3c5d49aeed55f.file b/.flatpak-builder/cache/objects/95/ef0f39add0046c6fbbce84ab176c947b5743f975ef3338b3e3c5d49aeed55f.file new file mode 100644 index 0000000..f8072ec --- /dev/null +++ b/.flatpak-builder/cache/objects/95/ef0f39add0046c6fbbce84ab176c947b5743f975ef3338b3e3c5d49aeed55f.file @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2006 - 2007 Murray Cumming + * Copyright (C) 2006 - 2014 Vivien Malerba + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GDA_ENUMS__ +#define __GDA_ENUMS__ + +/** + * GdaTransactionIsolation: + * @GDA_TRANSACTION_ISOLATION_SERVER_DEFAULT: isolation level defined by the server + * @GDA_TRANSACTION_ISOLATION_READ_COMMITTED: + * @GDA_TRANSACTION_ISOLATION_READ_UNCOMMITTED: + * @GDA_TRANSACTION_ISOLATION_REPEATABLE_READ: + * @GDA_TRANSACTION_ISOLATION_SERIALIZABLE: + * + * Describes transactions' isolation level + */ +typedef enum { + GDA_TRANSACTION_ISOLATION_SERVER_DEFAULT, + GDA_TRANSACTION_ISOLATION_READ_COMMITTED, + GDA_TRANSACTION_ISOLATION_READ_UNCOMMITTED, + GDA_TRANSACTION_ISOLATION_REPEATABLE_READ, + GDA_TRANSACTION_ISOLATION_SERIALIZABLE +} GdaTransactionIsolation; + +#define GDA_TRANSACTION_ISOLATION_UNKNOWN GDA_TRANSACTION_ISOLATION_SERVER_DEFAULT + +/** + * GdaValueAttribute: + * @GDA_VALUE_ATTR_NONE: no specific attribute + * @GDA_VALUE_ATTR_IS_NULL: value is NULL (in the SQL sense) + * @GDA_VALUE_ATTR_CAN_BE_NULL: value can be set to NULL (in the SQL sense) + * @GDA_VALUE_ATTR_IS_DEFAULT: value is defined as the default value (the value itself is not specified) + * @GDA_VALUE_ATTR_CAN_BE_DEFAULT: a default value (not specified) exists for the value + * @GDA_VALUE_ATTR_IS_UNCHANGED: the value has not been changed (in the context of the attribute usage) + * @GDA_VALUE_ATTR_DATA_NON_VALID: the value is not valid (with regards to the context) + * @GDA_VALUE_ATTR_HAS_VALUE_ORIG: the value can be resetted to its "original" value (i.e. before it was modified) + * @GDA_VALUE_ATTR_READ_ONLY: the value can't be modified + * + * Attributes of a value, used internally by Libgda in different contexts. Values can be OR'ed. + */ +typedef enum { + GDA_VALUE_ATTR_NONE = 0, + GDA_VALUE_ATTR_IS_NULL = 1 << 0, + GDA_VALUE_ATTR_CAN_BE_NULL = 1 << 1, + GDA_VALUE_ATTR_IS_DEFAULT = 1 << 2, + GDA_VALUE_ATTR_CAN_BE_DEFAULT = 1 << 3, + GDA_VALUE_ATTR_IS_UNCHANGED = 1 << 4, + GDA_VALUE_ATTR_DATA_NON_VALID = 1 << 6, + GDA_VALUE_ATTR_HAS_VALUE_ORIG = 1 << 7, + GDA_VALUE_ATTR_NO_MODIF = 1 << 8, + GDA_VALUE_ATTR_READ_ONLY = 1 << 8, /* same as GDA_VALUE_ATTR_NO_MODIF */ +} GdaValueAttribute; + +/* how SQL identifiers are represented */ +/** + * GdaSqlIdentifierStyle: + * @GDA_SQL_IDENTIFIERS_LOWER_CASE: case insensitive SQL identifiers are represented in lower case (meaning that any SQL identifier which has a non lower case character is case sensitive) + * @GDA_SQL_IDENTIFIERS_UPPER_CASE: case insensitive SQL identifiers are represented in upper case (meaning that any SQL identifier which has a non upper case character is case sensitive) + * + * Specifies how SQL identifiers are represented by a specific database + */ +typedef enum { + GDA_SQL_IDENTIFIERS_LOWER_CASE = 1 << 0, + GDA_SQL_IDENTIFIERS_UPPER_CASE = 1 << 1 +} GdaSqlIdentifierStyle; + +/* possible different keywords used when qualifying a table's column's extra attributes */ +#define GDA_EXTRA_AUTO_INCREMENT "AUTO_INCREMENT" + +#endif + + + diff --git a/.flatpak-builder/cache/objects/96/2716897a1982a5a83a584fac878184b744c88f6f1131ca637f5b5e7b0bca3f.file b/.flatpak-builder/cache/objects/96/2716897a1982a5a83a584fac878184b744c88f6f1131ca637f5b5e7b0bca3f.file new file mode 100644 index 0000000..33dfeae Binary files /dev/null and b/.flatpak-builder/cache/objects/96/2716897a1982a5a83a584fac878184b744c88f6f1131ca637f5b5e7b0bca3f.file differ diff --git a/.flatpak-builder/cache/objects/97/369ece91e3cc3141b78906f84386b4b794a49a25fe3bcabe7d1a38780ac0cc.file b/.flatpak-builder/cache/objects/97/369ece91e3cc3141b78906f84386b4b794a49a25fe3bcabe7d1a38780ac0cc.file new file mode 100644 index 0000000..1a99fb8 Binary files /dev/null and b/.flatpak-builder/cache/objects/97/369ece91e3cc3141b78906f84386b4b794a49a25fe3bcabe7d1a38780ac0cc.file differ diff --git a/.flatpak-builder/cache/objects/97/7f084853d6ef10270a6869e3d5c9f60820ed852028f9f7cce21fa44cfd571c.file b/.flatpak-builder/cache/objects/97/7f084853d6ef10270a6869e3d5c9f60820ed852028f9f7cce21fa44cfd571c.file new file mode 100644 index 0000000..caf8955 --- /dev/null +++ b/.flatpak-builder/cache/objects/97/7f084853d6ef10270a6869e3d5c9f60820ed852028f9f7cce21fa44cfd571c.file @@ -0,0 +1,670 @@ +#include + +#if defined (__ELF__) && ( __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 6)) +# define SECTION __attribute__ ((section (".gresource.libgda"), aligned (8))) +#else +# define SECTION +#endif + +static const SECTION union { const guint8 data[7443]; const double alignment; void * const ptr;} libgda_resource_data = { + "\107\126\141\162\151\141\156\164\000\000\000\000\000\000\000\000" + "\030\000\000\000\344\000\000\000\000\000\000\050\007\000\000\000" + "\000\000\000\000\001\000\000\000\001\000\000\000\002\000\000\000" + "\004\000\000\000\005\000\000\000\005\000\000\000\337\054\111\350" + "\003\000\000\000\344\000\000\000\020\000\166\000\370\000\000\000" + "\160\002\000\000\324\265\002\000\377\377\377\377\160\002\000\000" + "\001\000\114\000\164\002\000\000\170\002\000\000\115\243\021\271" + "\003\000\000\000\170\002\000\000\024\000\166\000\220\002\000\000" + "\032\004\000\000\106\075\160\121\001\000\000\000\032\004\000\000" + "\007\000\114\000\044\004\000\000\070\004\000\000\073\122\262\217" + "\003\000\000\000\070\004\000\000\026\000\166\000\120\004\000\000" + "\137\031\000\000\356\327\201\053\003\000\000\000\137\031\000\000" + "\025\000\166\000\170\031\000\000\237\033\000\000\165\015\205\023" + "\003\000\000\000\237\033\000\000\033\000\166\000\300\033\000\000" + "\022\035\000\000\154\151\142\147\144\141\055\141\162\162\141\171" + "\056\144\164\144\000\000\000\000\362\003\000\000\001\000\000\000" + "\170\332\205\122\115\157\302\060\014\075\323\137\141\304\141\055" + "\132\021\333\141\207\011\061\125\064\223\252\265\254\203\200\264" + "\023\012\064\100\264\320\242\064\260\061\361\343\327\217\015\062" + "\221\210\234\042\277\147\373\075\333\275\246\353\102\365\070\233" + "\257\022\342\022\041\310\241\223\310\304\202\323\363\261\017\313" + "\114\374\122\156\162\250\110\271\302\230\122\221\263\054\205\273" + "\116\127\211\016\262\355\101\260\325\132\202\075\160\340\276\333" + "\175\200\051\333\063\232\102\104\070\025\163\142\271\156\337\262" + "\172\115\024\242\010\015\061\024\325\147\125\155\260\117\337\331" + "\222\121\236\264\157\317\340\054\041\222\074\071\375\042\321\303" + "\070\014\306\112\242\325\000\140\011\014\043\374\372\202\206\320" + "\012\242\070\014\220\257\210\112\311\206\302\300\367\260\247\103" + "\277\066\374\221\223\164\145\146\044\064\137\010\063\234\113\042" + "\167\071\330\257\061\076\216\320\233\163\342\350\215\326\356\000" + "\105\061\176\327\032\252\011\046\133\015\275\237\206\331\110\001" + "\111\046\271\056\245\350\051\017\133\172\356\122\350\237\004\243" + "\032\314\331\067\325\366\137\263\124\376\001\343\177\210\166\122" + "\145\251\154\047\026\072\001\351\216\363\354\003\154\074\232\240" + "\343\263\027\216\321\325\361\225\247\240\036\213\310\076\333\216" + "\201\133\140\065\165\117\370\216\266\217\147\244\016\134\346\125" + "\161\260\133\161\245\365\342\342\052\270\132\115\136\112\327\216" + "\307\260\007\203\304\053\015\025\122\131\173\221\161\365\050\324" + "\165\231\333\376\000\375\217\033\114\000\050\165\165\141\171\051" + "\057\000\000\000\003\000\000\000\154\151\142\147\144\141\055\160" + "\141\162\141\155\154\151\163\164\056\144\164\144\000\000\000\000" + "\172\003\000\000\001\000\000\000\170\332\255\122\321\152\302\060" + "\024\175\136\277\342\252\010\125\254\270\075\354\141\023\107\321" + "\156\224\265\352\154\024\174\032\261\215\032\026\333\222\244\062" + "\301\217\137\032\135\147\245\173\031\313\133\356\071\367\336\163" + "\116\322\257\131\026\234\016\243\253\115\204\255\024\163\274\143" + "\124\310\156\044\043\343\106\001\043\064\202\165\302\341\045\302" + "\001\221\040\122\022\322\065\015\261\244\111\054\064\143\101\270" + "\120\027\270\355\366\364\175\230\244\007\116\067\133\011\346\260" + "\005\167\275\336\075\054\350\236\222\030\174\314\010\137\141\303" + "\262\006\206\321\257\071\143\344\242\045\064\001\163\216\017\226" + "\332\010\301\062\100\216\017\365\263\034\015\344\122\352\003\243" + "\131\260\036\165\263\347\370\152\000\104\130\142\113\020\151\345" + "\312\300\324\006\210\124\222\072\040\222\214\207\104\074\265\006" + "\227\015\077\214\013\166\133\161\372\065\033\041\317\015\056\051" + "\271\041\032\301\330\107\223\127\147\014\015\327\237\172\256\063" + "\312\313\261\242\300\160\144\043\273\124\376\334\261\007\206\343" + "\115\005\024\021\021\362\212\272\220\130\146\112\315\144\212\216" + "\063\347\255\125\200\325\272\301\124\321\274\357\061\313\110\273" + "\003\130\112\116\127\231\044\277\130\270\166\240\026\314\335\331" + "\131\320\152\047\344\041\045\225\376\324\222\137\261\377\363\036" + "\147\214\045\037\140\242\331\334\071\076\333\136\340\264\112\170" + "\312\262\015\215\253\102\323\217\133\001\154\151\054\377\034\162" + "\221\046\230\215\251\036\122\112\265\200\257\103\370\116\265\064" + "\354\374\377\116\357\245\177\157\376\106\252\323\060\276\000\050" + "\174\375\230\000\050\165\165\141\171\051\154\151\142\147\144\141" + "\057\000\000\000\004\000\000\000\000\000\000\000\005\000\000\000" + "\002\000\000\000\006\000\000\000\151\156\146\157\162\155\141\164" + "\151\157\156\137\163\143\150\145\155\141\056\170\155\154\000\000" + "\105\220\000\000\001\000\000\000\170\332\355\075\333\162\343\270" + "\261\357\376\012\104\057\226\122\264\275\116\245\122\247\046\366" + "\344\310\062\075\253\254\054\071\222\074\163\374\244\242\051\130" + "\342\016\105\052\044\345\313\337\237\156\134\050\202\004\051\220" + "\262\167\075\227\324\146\327\042\201\356\006\320\067\164\067\300" + "\263\177\075\257\174\362\110\243\330\013\203\363\326\351\361\057" + "\055\102\003\067\234\173\301\342\274\165\073\275\072\372\237\326" + "\277\076\036\234\375\345\350\350\200\300\377\372\301\103\030\255" + "\234\004\132\223\330\135\322\225\103\340\001\031\170\367\213\271" + "\163\030\223\271\347\342\073\047\172\041\227\027\307\254\313\164" + "\351\305\004\376\111\226\224\334\073\061\225\375\234\140\116\134" + "\047\040\367\224\320\347\204\006\163\072\047\367\057\304\131\257" + "\175\317\145\030\142\366\173\216\264\220\200\076\061\150\227\027" + "\327\023\022\336\377\116\335\044\266\310\375\046\371\300\000\037" + "\316\016\311\072\242\017\336\063\242\212\150\114\243\107\200\247" + "\320\346\005\011\215\002\307\217\217\217\217\017\370\150\256\157" + "\106\343\151\167\070\045\303\321\324\376\100\236\226\064\040\053" + "\030\374\203\107\347\026\131\373\024\350\375\300\232\376\225\104" + "\233\200\044\141\350\307\047\336\166\022\216\370\140\216\346\241" + "\313\006\264\012\037\051\043\150\101\003\032\071\011\322\340\371" + "\360\050\044\320\344\244\167\142\002\054\171\131\323\170\027\070" + "\237\015\353\144\035\205\217\336\034\326\357\050\336\254\327\141" + "\224\110\014\136\340\106\164\105\203\204\365\357\335\216\307\366" + "\160\072\233\364\176\265\257\273\263\317\366\170\322\037\015\311" + "\034\146\054\240\320\126\202\203\377\037\255\150\342\034\305\111" + "\030\321\143\076\050\157\005\063\221\202\162\303\010\346\167\035" + "\006\270\056\014\031\221\113\272\362\026\021\347\015\200\230\054" + "\235\204\121\173\160\164\364\361\340\340\340\214\067\372\010\135" + "\220\235\210\244\234\304\153\352\302\214\273\044\063\025\104\000" + "\046\033\140\230\263\210\256\175\307\245\037\161\334\342\157\022" + "\207\100\347\022\131\343\311\113\226\231\237\324\207\056\155\067" + "\204\325\176\116\030\207\205\201\377\202\154\326\072\271\352\333" + "\203\313\311\254\173\362\277\275\321\340\366\172\070\233\336\335" + "\330\055\342\360\221\255\102\034\144\107\101\355\055\002\230\010" + "\206\231\377\311\060\221\265\023\045\161\051\226\337\354\273\331" + "\244\105\200\371\064\050\157\340\255\026\045\116\023\314\215\234" + "\216\370\043\173\172\226\316\123\340\254\350\171\353\046\214\223" + "\105\104\047\377\031\264\076\012\112\345\374\020\101\316\171\351" + "\100\351\363\072\072\157\305\111\004\023\325\222\123\071\303\011" + "\074\157\075\072\221\273\164\242\326\111\123\260\013\020\260\074" + "\120\174\264\027\300\177\374\275\002\344\131\312\376\372\271\272" + "\176\171\263\151\152\237\376\362\113\347\075\315\325\075\150\023" + "\352\004\171\240\362\361\026\260\140\343\014\134\316\256\125\055" + "\264\074\154\270\010\260\004\136\102\133\157\064\123\052\366\263" + "\223\214\364\110\105\043\224\323\234\306\156\344\255\231\166\021" + "\242\226\070\367\240\114\071\231\063\047\201\365\006\203\102\343" + "\026\157\173\336\232\262\367\040\372\114\033\222\366\127\372\142" + "\075\072\376\206\166\100\001\170\121\314\236\304\360\026\264\101" + "\252\211\320\024\071\320\132\032\241\216\030\372\231\033\372\233" + "\125\040\320\001\266\031\376\325\042\153\200\001\250\306\267\166" + "\072\246\102\113\206\224\277\076\073\141\124\363\341\051\003\310" + "\250\317\031\037\363\014\354\250\343\207\013\201\111\214\152\010" + "\077\110\370\300\225\371\006\224\071\050\366\071\064\144\306\271" + "\055\237\210\256\035\213\054\235\230\053\267\020\114\105\024\076" + "\151\307\243\142\312\214\211\300\332\004\111\166\200\345\043\340" + "\124\047\116\112\352\300\213\023\044\225\277\210\367\300\254\035" + "\074\357\311\055\025\262\243\343\005\334\117\341\370\364\353\041" + "\246\326\140\240\045\075\303\047\260\345\055\022\154\174\077\374" + "\132\101\236\001\021\322\245\151\021\364\031\266\322\116\122\016" + "\246\276\017\236\117\026\040\072\110\251\311\005\336\306\067\351" + "\362\247\246\236\133\341\066\232\377\115\274\161\174\130\176\060" + "\162\207\011\132\070\351\041\165\052\151\003\337\302\331\370\111" + "\176\240\365\010\005\033\314\274\102\001\214\173\150\340\330\070" + "\114\336\034\164\013\011\147\041\224\275\160\223\310\276\154\171" + "\044\171\017\260\112\040\217\017\063\326\324\100\124\122\145\205" + "\166\236\360\321\345\071\015\341\151\337\244\232\011\321\126\063" + "\374\375\306\363\141\044\063\234\377\031\163\373\012\254\317\232" + "\034\201\077\205\155\010\167\015\343\215\273\044\040\225\302\026" + "\131\350\332\132\004\334\132\255\200\304\113\160\013\031\164\125" + "\017\114\360\071\153\043\071\056\105\241\137\330\007\130\310\054" + "\234\054\363\013\230\127\320\244\016\310\005\173\245\262\210\266" + "\241\033\256\220\055\143\311\100\150\072\114\372\305\057\101\030" + "\274\254\142\223\266\245\322\244\343\321\164\140\205\015\107\225" + "\100\241\074\301\172\154\374\071\011\102\046\114\214\303\141\171" + "\263\373\236\224\274\115\340\375\167\103\123\156\254\134\326\224" + "\355\266\235\312\031\157\063\117\322\141\335\002\355\142\047\060" + "\317\160\231\226\227\240\237\224\224\327\322\265\073\070\004\061" + "\012\115\250\143\270\242\302\254\104\261\133\111\043\276\122\366" + "\036\152\071\333\014\250\216\325\045\334\117\123\144\044\047\216" + "\103\327\143\273\274\214\136\336\061\067\115\005\203\315\053\143" + "\041\076\132\243\061\060\015\120\243\375\373\223\250\002\211\072" + "\153\134\152\067\122\007\105\157\040\024\351\330\145\037\164\235" + "\045\243\147\373\146\375\215\202\151\331\241\043\324\065\253\253" + "\041\004\011\105\233\004\074\007\373\177\344\072\266\074\016\116" + "\271\106\205\260\227\254\155\254\150\026\322\226\006\314\141\257" + "\175\372\014\363\277\272\107\030\151\337\247\245\007\155\320\367" + "\004\153\357\213\070\204\003\273\001\214\055\261\355\167\247\236" + "\206\252\245\224\052\006\304\011\343\221\020\206\327\213\015\245" + "\141\137\065\366\046\104\031\351\272\067\301\314\037\354\136\044" + "\336\257\215\153\336\061\000\035\106\163\140\022\177\006\134\347" + "\241\354\113\335\303\067\222\002\101\217\367\220\155\054\276\207" + "\213\061\054\163\252\007\233\272\150\045\052\374\062\235\225\034" + "\335\336\203\072\073\300\312\260\077\214\234\027\013\237\007\344" + "\220\375\230\241\113\176\310\174\163\012\276\034\262\173\202\201" + "\323\225\303\202\112\303\333\301\240\304\335\336\166\057\241\254" + "\213\015\224\355\157\051\111\045\276\027\370\230\216\013\232\174" + "\266\162\236\275\325\146\065\363\151\260\110\226\352\314\032\370" + "\160\051\234\020\376\235\064\204\002\232\202\106\236\073\133\107" + "\260\207\211\013\013\154\016\040\166\035\237\326\355\014\154\100" + "\023\157\105\233\243\337\316\002\254\364\126\125\325\355\050\225" + "\211\272\344\073\245\103\005\302\205\277\056\210\320\367\371\326" + "\251\016\361\151\247\246\204\247\000\114\211\056\130\157\164\172" + "\167\033\356\335\346\271\242\105\251\225\056\020\103\271\023\063" + "\313\372\332\171\210\131\321\126\134\002\261\175\057\107\047\363" + "\065\105\274\216\330\303\225\341\314\350\271\054\312\334\336\117" + "\203\123\304\324\112\035\012\012\162\127\164\045\100\003\307\036" + "\266\242\114\054\271\117\347\073\367\324\347\276\105\346\161\374" + "\206\366\336\036\336\136\227\130\271\077\310\270\357\117\201\221" + "\045\337\017\015\133\230\335\041\113\043\023\174\123\151\173\337" + "\217\360\126\160\264\042\302\252\271\115\043\154\333\260\062\367" + "\225\271\061\256\336\145\253\362\255\135\322\160\213\141\005\073" + "\052\057\130\130\174\343\303\274\352\165\004\276\062\370\311\030" + "\260\146\276\004\242\376\075\364\260\135\311\222\261\224\352\126" + "\222\152\111\017\357\314\137\000\021\374\041\037\351\075\305\100" + "\035\167\076\356\351\334\304\177\343\224\110\171\252\043\103\157" + "\101\107\151\350\374\055\220\161\061\224\233\143\200\227\165\050" + "\315\021\222\151\367\142\140\317\172\243\201\105\056\107\327\335" + "\376\320\042\267\227\123\376\140\074\272\235\366\207\266\372\343" + "\246\073\156\346\366\136\340\226\174\236\367\175\071\125\322\365" + "\275\127\333\274\047\027\270\234\064\075\246\225\207\136\017\127" + "\157\136\362\122\327\367\003\377\271\116\367\162\325\063\017\127" + "\310\365\005\163\052\237\153\227\222\275\063\062\226\025\321\072" + "\006\304\200\243\005\066\003\263\130\036\266\253\211\313\054\154" + "\147\014\264\356\206\217\103\116\271\136\374\174\117\334\136\044" + "\251\162\076\027\345\221\307\367\265\045\334\265\043\061\147\357" + "\114\010\066\005\132\153\163\242\337\335\230\162\374\336\350\165" + "\173\043\215\020\064\305\143\260\165\155\066\327\022\060\012\103" + "\155\102\136\157\316\367\042\243\301\334\327\304\367\047\207\076" + "\270\126\320\347\165\253\172\064\115\121\110\023\122\047\113\041" + "\372\324\111\124\210\056\145\271\212\252\076\257\231\074\310\233" + "\347\272\371\203\234\301\255\223\102\370\121\202\023\073\262\045" + "\005\336\251\225\060\141\077\212\036\031\177\114\332\374\277\026" + "\171\364\350\123\214\245\201\041\050\203\110\226\262\212\060\072" + "\326\021\012\345\304\274\122\175\212\203\201\332\323\217\143\060" + "\014\204\203\343\332\307\213\253\207\311\310\207\253\007\122\335" + "\124\111\207\015\137\175\040\027\335\211\315\167\113\026\371\334" + "\267\277\130\144\060\352\165\007\144\152\143\151\160\167\174\147" + "\221\311\335\004\176\311\106\237\006\243\013\365\175\167\320\357" + "\116\160\101\047\167\303\321\360\356\272\244\266\040\006\005\023" + "\323\210\223\004\272\046\054\344\104\265\226\103\311\220\262\316" + "\207\061\057\235\303\354\233\250\237\226\005\071\125\263\320\124" + "\011\013\006\250\243\203\171\227\214\012\316\142\064\354\375\232" + "\232\065\047\057\165\025\253\052\002\257\225\232\335\117\331\060" + "\055\122\320\065\134\267\360\255\004\365\364\225\325\157\246\121" + "\020\371\037\242\120\152\041\062\322\047\206\020\261\331\214\205" + "\115\225\250\246\106\222\044\222\317\320\003\043\162\130\206\134" + "\342\101\122\367\353\054\134\163\170\132\030\275\356\244\327\275" + "\264\323\332\270\004\134\107\126\214\317\302\175\111\310\313\341" + "\150\072\020\254\374\367\067\170\232\002\237\174\351\117\177\045" + "\275\137\355\336\157\144\164\063\355\217\206\377\344\206\347\311" + "\213\251\105\100\141\331\245\372\152\263\146\065\027\133\107\261" + "\206\246\102\102\114\024\125\101\224\205\025\065\021\144\023\161" + "\255\154\123\067\336\233\156\225\164\025\021\362\025\301\163\010" + "\341\274\244\126\265\270\121\255\125\101\132\334\147\066\354\336" + "\240\172\065\103\173\103\123\222\241\276\216\071\331\166\333\341" + "\325\327\265\013\232\325\250\153\033\212\013\362\132\366\101\067" + "\352\132\046\102\331\234\152\070\066\273\367\054\341\126\375\166" + "\277\036\327\150\167\352\173\200\150\300\271\142\307\052\344\227" + "\326\111\133\347\273\066\114\136\347\301\064\313\273\253\313\321" + "\124\010\325\005\251\045\210\112\327\327\026\106\075\263\325\026" + "\110\055\277\355\265\031\316\250\375\222\135\151\031\177\051\304" + "\027\224\315\211\031\064\335\030\012\152\307\020\226\246\162\135" + "\065\011\265\265\124\011\113\324\322\124\121\270\111\274\100\263" + "\167\176\330\004\056\067\252\254\312\023\017\341\314\361\334\240" + "\113\347\233\010\067\325\101\230\120\176\000\124\146\074\177\207" + "\305\343\045\243\170\302\216\141\361\342\155\021\042\000\155\247" + "\001\012\261\020\126\352\047\213\331\314\074\100\012\073\235\352" + "\044\155\225\333\074\221\036\170\260\323\177\026\263\140\162\216" + "\104\045\327\014\161\251\073\335\000\157\251\123\135\300\232\101" + "\100\332\042\265\261\162\202\205\057\052\173\327\241\377\262\012" + "\243\365\022\372\110\066\050\111\173\210\327\173\207\235\363\344" + "\124\144\132\044\312\375\002\314\172\204\273\247\133\142\057\315" + "\100\233\257\234\004\125\221\316\272\272\035\366\160\177\140\221" + "\233\361\250\147\137\336\216\155\213\164\077\175\032\333\237\272" + "\323\062\260\064\331\104\201\131\222\214\267\345\247\171\312\146" + "\005\167\017\362\371\074\004\001\307\212\156\336\021\064\300\013" + "\341\147\357\252\150\211\147\054\222\136\122\155\036\155\150\026" + "\205\350\102\034\164\201\110\333\073\246\307\026\131\201\276\364" + "\326\240\066\030\262\070\255\071\340\234\255\224\277\002\377\002" + "\264\355\157\034\311\043\050\241\022\012\203\373\231\023\055\142" + "\155\061\314\220\227\077\003\062\150\262\141\206\235\264\217\116" + "\231\214\000\110\217\253\313\142\243\035\214\173\037\316\137\014" + "\266\251\175\125\120\171\176\020\366\254\251\002\026\231\113\170" + "\144\361\363\325\366\377\115\355\361\260\073\250\106\137\153\257" + "\214\345\016\161\270\211\134\330\312\342\231\352\034\223\153\021" + "\341\305\001\030\263\257\312\275\150\007\047\073\346\107\210\055" + "\323\167\114\211\265\175\057\370\112\342\227\325\175\350\167\044" + "\121\262\327\016\252\174\320\164\033\147\101\053\106\054\233\344" + "\151\174\212\274\004\266\316\260\231\327\343\000\063\017\377\145" + "\206\067\171\361\313\060\334\310\126\204\265\042\355\117\366\320" + "\036\167\141\025\377\335\375\334\265\370\202\212\147\074\124\200" + "\142\070\351\224\306\004\346\010\154\005\213\032\047\236\333\040" + "\056\220\027\075\046\132\070\315\140\316\101\360\142\262\360\036" + "\305\062\260\307\133\151\000\111\240\217\064\052\261\114\377\365" + "\371\031\072\307\165\151\034\227\120\362\145\111\131\314\075\113" + "\110\252\251\221\335\321\313\170\022\215\074\324\074\316\234\205" + "\352\105\330\042\346\262\336\306\250\211\105\172\243\341\264\333" + "\037\116\054\062\266\273\227\360\237\353\321\145\377\252\157\127" + "\314\036\122\005\366\313\367\367\230\271\047\317\367\121\137\042" + "\030\074\347\362\300\064\043\036\315\005\336\364\260\214\056\235" + "\062\140\043\134\316\035\346\264\341\076\042\265\215\231\035\104" + "\255\070\257\004\320\064\116\054\373\277\146\244\270\350\323\325" + "\335\177\024\174\263\327\212\007\024\247\253\136\166\052\362\026" + "\013\032\151\362\123\362\205\066\206\312\137\066\334\373\313\336" + "\215\166\375\262\163\203\375\076\350\211\040\231\201\233\351\255" + "\067\262\266\101\343\254\332\217\374\112\023\166\115\111\044\352" + "\351\004\132\322\006\311\266\307\123\213\334\336\134\202\377\143" + "\241\032\270\264\007\366\324\356\124\041\315\227\121\032\234\041" + "\144\045\150\045\151\063\261\215\311\320\005\062\055\013\167\215" + "\112\066\024\262\366\255\121\176\013\232\104\204\331\044\343\127" + "\027\263\256\166\312\345\273\146\031\104\067\360\113\046\151\300" + "\235\241\007\224\364\231\272\233\144\353\312\012\152\112\252\265" + "\070\306\060\362\344\221\305\255\147\202\344\162\303\362\224\061" + "\115\162\160\234\051\303\300\345\007\255\250\343\056\371\346\067" + "\306\235\154\024\076\261\054\262\362\172\233\034\150\217\107\137" + "\130\122\162\012\334\173\155\017\247\235\262\340\152\060\147\036" + "\332\054\361\126\354\272\023\151\174\074\064\277\111\346\174\227" + "\112\127\373\302\276\032\215\155\304\321\275\002\147\260\123\055" + "\306\215\323\217\122\207\324\112\100\212\116\257\034\242\052\150" + "\303\332\231\304\234\102\334\053\054\125\231\051\321\153\243\054" + "\076\243\134\212\126\173\024\241\124\007\241\164\342\136\204\321" + "\310\050\026\027\272\136\210\274\364\174\053\173\056\302\106\130" + "\132\255\114\266\161\356\164\217\144\150\343\364\246\111\072\005" + "\176\064\351\371\106\047\053\005\101\065\352\312\204\053\255\313" + "\115\376\074\273\251\273\140\343\073\073\326\231\331\332\247\113" + "\313\331\227\133\123\207\010\150\014\204\305\127\103\140\123\034" + "\232\024\131\352\147\310\143\315\331\056\155\174\263\015\276\304" + "\336\042\100\027\337\301\173\223\274\205\127\032\205\061\255\266" + "\334\071\034\214\127\300\014\233\216\212\341\333\157\104\362\002" + "\012\320\257\313\064\024\063\207\311\132\071\076\310\066\214\241" + "\363\147\236\217\175\235\012\341\367\160\130\166\377\332\362\067" + "\070\071\233\217\146\105\145\261\357\336\344\063\341\327\344\261" + "\373\227\076\220\356\355\164\064\353\017\173\143\346\163\002\100" + "\161\005\033\345\176\073\136\057\311\316\201\036\057\371\105\226" + "\151\135\146\303\342\223\052\203\122\303\345\174\207\145\050\332" + "\114\244\232\322\257\223\110\255\223\056\065\152\373\212\371\123" + "\343\324\250\151\332\323\040\251\371\363\074\266\054\013\015\100" + "\200\301\164\350\112\104\266\357\370\145\072\342\142\042\121\321" + "\334\303\332\065\053\315\274\202\211\301\030\055\230\022\176\354" + "\024\176\163\037\074\013\247\123\122\026\045\033\030\146\367\252" + "\217\243\156\301\031\151\307\024\267\121\232\257\062\100\122\201" + "\271\032\165\003\157\374\333\333\167\244\243\125\052\262\131\161" + "\242\105\060\230\320\377\064\044\277\331\167\230\202\354\137\167" + "\307\167\370\003\371\350\166\330\377\117\271\215\306\012\112\327" + "\167\066\061\065\314\062\261\056\354\172\121\032\307\212\117\055" + "\051\144\176\265\150\267\175\152\361\044\145\132\077\131\221\045" + "\171\240\240\052\232\131\057\226\061\303\013\027\005\030\074\077" + "\154\002\344\233\052\245\214\160\150\350\340\302\166\262\112\005" + "\145\064\112\126\215\300\046\313\017\263\127\077\353\316\333\267" + "\276\063\251\331\331\133\233\025\177\230\345\206\274\073\261\222" + "\366\221\103\255\321\305\060\102\307\115\131\156\150\273\207\263" + "\162\022\167\131\135\056\175\005\042\012\012\244\073\236\366\273" + "\003\124\036\345\065\316\314\307\244\263\150\123\232\077\025\265" + "\327\026\231\330\123\046\374\374\257\113\373\252\173\073\230\142" + "\346\157\062\035\367\173\123\254\244\046\135\126\077\121\215\162" + "\016\156\306\333\243\324\253\002\105\320\376\160\255\120\364\321" + "\324\325\067\217\171\032\214\103\303\366\265\143\237\105\061\250" + "\033\370\314\113\105\165\320\123\327\273\040\042\152\351\336\216" + "\031\054\127\277\320\100\200\231\155\142\126\240\220\277\226\147" + "\173\201\210\352\006\362\263\045\112\175\027\267\063\207\151\324" + "\324\013\036\103\377\021\314\326\217\246\177\377\270\130\253\046" + "\133\066\342\035\322\300\153\056\224\211\226\322\013\362\156\016" + "\056\157\333\015\067\360\147\046\114\333\371\376\025\211\214\374" + "\277\003\352\267\034\122\055\300\030\107\341\040\330\027\125\270" + "\074\373\040\257\161\326\113\302\204\050\070\303\130\050\013\116" + "\020\011\102\214\161\306\230\021\024\253\057\123\316\307\144\252" + "\362\002\023\151\026\265\016\240\115\030\275\034\147\267\221\212" + "\372\230\111\034\263\207\257\346\056\133\112\030\120\302\077\312" + "\302\324\311\046\370\032\204\117\101\376\052\362\126\135\151\324" + "\173\014\337\153\166\306\314\327\253\205\272\150\360\032\166\157" + "\060\354\255\135\153\064\364\114\220\317\133\121\120\145\253\265" + "\331\351\016\340\334\142\303\064\144\103\256\176\003\146\235\213" + "\113\204\055\126\216\112\361\050\245\113\347\257\240\130\352\373" + "\044\373\371\043\315\175\021\145\151\162\307\007\312\325\127\375" + "\371\371\176\374\266\146\363\265\053\146\047\202\035\125\236\133" + "\076\150\361\323\147\173\113\237\355\247\203\364\176\034\244\302" + "\001\371\152\101\251\022\003\166\175\074\077\026\136\172\020\274" + "\231\074\260\256\215\304\201\365\374\041\342\304\373\310\037\277" + "\030\101\317\112\352\262\325\066\054\312\322\325\265\051\231\325" + "\253\121\373\364\335\211\145\172\043\124\215\254\223\053\277\302" + "\125\165\271\341\317\024\122\223\203\321\025\067\102\356\163\301" + "\143\363\013\033\015\106\254\344\173\214\152\305\336\107\072\106" + "\345\336\035\267\177\031\335\361\125\335\310\134\251\354\274\046" + "\241\050\132\365\357\111\050\210\210\171\365\153\271\072\111\117" + "\101\025\325\210\074\115\172\110\332\073\216\021\343\307\374\044" + "\030\176\034\021\367\171\331\153\270\130\375\024\113\063\111\250" + "\242\054\032\217\033\255\023\166\002\107\226\017\246\260\232\234" + "\032\336\357\350\357\036\007\170\367\213\101\356\070\241\266\012" + "\347\164\127\233\106\245\111\265\353\072\123\174\151\151\347\366" + "\311\036\325\235\377\144\367\333\070\176\034\146\117\262\152\271" + "\202\241\141\134\123\372\375\274\346\105\241\332\301\224\153\244" + "\364\334\275\341\141\050\303\043\117\273\232\375\254\311\331\165" + "\023\102\151\141\172\035\245\226\036\270\346\007\231\017\267\337" + "\054\146\260\073\114\251\245\372\214\267\306\102\276\364\256\004" + "\336\357\233\327\142\157\225\203\121\105\163\027\025\077\126\011" + "\372\117\125\363\215\224\377\171\301\234\076\227\336\132\172\110" + "\304\173\341\356\314\103\161\043\203\317\056\234\013\263\151\142" + "\275\242\140\375\137\145\107\306\040\031\010\055\307\270\377\076" + "\254\036\276\037\040\056\203\105\331\254\236\263\354\172\015\263" + "\335\024\316\026\354\244\266\207\036\360\011\311\336\024\141\012" + "\145\207\066\145\347\152\267\037\072\026\252\225\165\115\077\240" + "\173\061\035\333\066\377\162\356\053\324\276\117\172\366\360\262" + "\077\374\124\001\220\123\136\165\144\135\047\076\337\164\041\173" + "\325\007\313\371\350\366\011\322\006\142\105\061\021\316\037\141" + "\027\125\273\211\373\202\153\353\247\275\164\315\117\305\261\323" + "\001\253\177\216\005\341\140\335\156\005\234\127\073\271\050\171" + "\211\255\223\341\107\252\124\243\252\227\225\314\272\237\374\271" + "\347\113\312\275\222\157\043\314\134\160\162\010\026\310\234\261" + "\113\160\205\212\331\272\127\171\315\002\157\324\257\016\247\016" + "\314\326\026\175\234\330\003\273\067\045\271\117\155\203\246\317" + "\077\262\310\202\037\312\123\035\063\154\251\076\261\210\324\346" + "\354\253\355\374\242\041\150\045\377\006\106\023\137\054\267\304" + "\204\360\170\002\064\121\103\204\126\376\271\274\273\056\367\230" + "\041\315\203\312\174\062\315\122\036\346\201\310\317\242\111\000" + "\127\343\321\065\321\174\266\376\340\166\330\037\015\017\304\174" + "\251\337\226\266\110\372\371\153\376\147\172\132\233\377\334\116" + "\110\366\223\321\234\006\205\162\113\371\267\062\206\054\355\222" + "\146\101\054\374\124\251\053\174\126\302\042\331\017\336\244\277" + "\062\144\346\076\144\221\076\050\041\066\277\122\271\025\312\254" + "\014\261\012\043\023\144\213\160\361\331\111\206\035\031\257\043" + "\173\163\143\232\145\364\071\005\327\325\127\053\262\256\344\265" + "\020\372\222\054\113\124\217\111\111\050\265\263\262\200\040\127" + "\054\126\056\057\221\173\254\350\010\164\265\036\276\252\225\035" + "\326\266\225\360\301\263\215\344\124\245\155\330\144\145\133\360" + "\205\371\352\236\036\147\164\204\150\301\237\310\345\000\030\205" + "\272\022\302\276\053\375\240\041\051\137\076\242\266\314\320\245" + "\126\211\250\315\044\161\177\313\023\267\335\303\145\250\313\045" + "\161\322\101\050\117\371\130\363\206\014\333\346\237\035\144\105" + "\265\344\240\005\240\025\305\204\244\077\034\332\143\362\357\121" + "\177\110\012\165\301\070\004\062\032\222\266\156\016\317\161\174" + "\352\254\166\207\227\272\071\314\264\024\223\132\150\310\330\170" + "\333\214\053\317\155\243\334\144\234\363\251\125\236\165\014\007" + "\164\052\007\224\037\314\251\176\060\271\201\234\152\007\242\014" + "\342\124\063\210\342\000\116\113\007\360\345\127\173\154\353\227" + "\373\234\061\125\341\261\350\070\032\137\302\310\057\356\012\002" + "\130\020\266\234\144\351\231\113\230\333\022\005\164\166\302\101" + "\175\074\370\177\217\227\136\265\000\050\165\165\141\171\051\154" + "\151\142\147\144\141\055\144\142\055\143\141\164\141\154\157\147" + "\056\144\164\144\000\000\000\000\006\007\000\000\001\000\000\000" + "\170\332\255\124\115\163\233\060\020\275\373\127\050\361\241\070" + "\061\231\244\247\036\062\311\060\240\314\060\103\034\327\310\275" + "\172\144\130\022\325\102\242\040\334\272\343\037\137\020\376\100" + "\216\355\322\114\165\321\327\173\253\175\253\335\275\277\260\155" + "\244\007\147\363\327\230\332\161\314\355\050\007\252\144\176\023" + "\253\270\207\166\303\043\036\112\144\276\001\176\052\120\005\105" + "\162\376\035\042\125\264\140\337\040\057\230\024\350\356\346\266" + "\165\352\312\154\225\263\327\067\205\054\167\200\076\337\336\175" + "\101\143\272\344\022\205\222\013\125\300\262\147\333\017\275\336" + "\375\005\016\360\063\036\021\124\104\157\220\122\144\051\072\347" + "\160\075\104\113\006\077\257\006\017\025\302\041\044\360\303\035" + "\102\320\024\120\353\041\317\041\116\065\367\375\347\161\340\143" + "\317\060\252\215\041\053\222\151\012\102\075\016\043\311\313\124" + "\124\326\223\005\254\256\206\050\222\242\120\071\145\102\231\117" + "\065\074\005\151\326\254\232\141\221\311\024\257\237\234\040\304" + "\203\172\177\251\227\227\357\211\007\056\356\174\334\216\376\004" + "\177\235\372\223\332\331\103\152\221\321\010\316\121\217\311\154" + "\144\265\164\242\045\345\045\124\163\025\262\150\361\150\150\333" + "\200\117\204\361\254\213\033\252\132\145\037\245\146\125\334\133" + "\320\016\021\335\020\113\301\176\224\360\001\042\055\225\144\042" + "\372\167\242\020\045\357\342\252\361\017\072\376\133\106\177\254" + "\103\243\243\277\205\350\217\331\033\155\103\266\357\067\220\202" + "\375\076\227\103\373\074\170\107\214\050\207\056\304\266\343\165" + "\232\034\363\312\020\267\255\225\323\230\272\254\220\225\054\146" + "\011\003\036\137\033\262\364\135\016\111\223\347\215\127\307\124" + "\150\234\024\145\026\123\125\325\356\004\207\144\342\273\144\355" + "\072\241\353\170\170\035\142\062\033\115\203\140\075\172\231\071" + "\056\361\137\106\372\310\303\117\316\064\040\203\063\361\331\130" + "\216\201\303\177\261\154\010\157\044\037\377\321\335\255\121\164" + "\235\352\146\107\255\042\327\054\376\102\155\347\132\325\102\221" + "\025\103\302\004\123\125\213\066\263\254\276\074\154\124\335\174" + "\322\324\034\062\156\264\252\016\225\245\211\165\127\065\336\354" + "\112\144\211\220\360\213\025\252\070\105\254\367\146\105\356\305" + "\033\031\373\007\123\015\326\015\000\050\165\165\141\171\051\154" + "\151\142\147\144\141\055\163\145\162\166\145\162\055\157\160\145" + "\162\141\164\151\157\156\056\144\164\144\000\000\000\000\000\000" + "\164\002\000\000\001\000\000\000\170\332\215\220\137\153\302\060" + "\024\305\237\327\117\161\165\014\132\131\304\355\141\017\233\164" + "\210\055\243\314\252\133\203\340\223\304\366\352\002\375\267\044" + "\212\102\077\374\222\272\225\125\034\054\117\311\071\207\163\177" + "\067\303\016\041\160\072\051\137\157\023\106\044\212\075\012\122" + "\224\050\230\342\105\336\117\124\142\135\151\337\243\036\154\012" + "\001\057\011\213\352\314\354\047\002\262\304\230\157\170\134\277" + "\144\235\136\240\220\306\272\353\017\352\367\270\050\217\202\157" + "\077\024\330\143\007\356\007\203\007\130\360\075\307\034\102\226" + "\242\130\063\213\020\327\262\206\035\177\112\003\272\204\033\050" + "\231\140\131\312\245\042\232\000\242\145\104\375\020\272\337\224" + "\215\151\360\272\256\165\323\112\077\325\105\023\077\324\145\140" + "\026\132\025\045\330\166\235\101\245\311\052\335\261\142\102\260" + "\143\045\361\163\207\171\214\125\343\072\275\133\220\305\116\304" + "\050\237\035\127\067\215\050\235\004\121\323\144\366\121\307\022" + "\141\354\215\350\010\256\203\160\076\011\174\317\310\011\312\130" + "\234\351\156\033\346\064\255\115\323\134\057\160\071\275\063\206" + "\223\154\246\361\004\246\041\235\275\372\323\026\104\256\273\056" + "\260\035\262\364\061\145\371\366\237\330\106\317\170\316\025\146" + "\362\342\230\214\035\376\066\245\142\152\047\301\236\315\151\365" + "\356\277\071\277\177\343\013\227\253\277\302\000\050\165\165\141" + "\171\051" }; + +static GStaticResource static_resource = { libgda_resource_data.data, sizeof (libgda_resource_data.data) - 1 /* nul terminator */, NULL, NULL, NULL }; + +G_GNUC_INTERNAL +GResource *libgda_get_resource (void); +GResource *libgda_get_resource (void) +{ + return g_static_resource_get_resource (&static_resource); +} +/* GLIB - Library of useful routines for C programming + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * SPDX-License-Identifier: LGPL-2.1-or-later + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + */ + +/* + * Modified by the GLib Team and others 1997-2000. See the AUTHORS + * file for a list of people on the GLib Team. See the ChangeLog + * files for a list of changes. These files are distributed with + * GLib at ftp://ftp.gtk.org/pub/gtk/. + */ + +#ifndef __G_CONSTRUCTOR_H__ +#define __G_CONSTRUCTOR_H__ + +/* + If G_HAS_CONSTRUCTORS is true then the compiler support *both* constructors and + destructors, in a usable way, including e.g. on library unload. If not you're on + your own. + + Some compilers need #pragma to handle this, which does not work with macros, + so the way you need to use this is (for constructors): + + #ifdef G_DEFINE_CONSTRUCTOR_NEEDS_PRAGMA + #pragma G_DEFINE_CONSTRUCTOR_PRAGMA_ARGS(my_constructor) + #endif + G_DEFINE_CONSTRUCTOR(my_constructor) + static void my_constructor(void) { + ... + } + +*/ + +#ifndef __GTK_DOC_IGNORE__ + +#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 7) + +#define G_HAS_CONSTRUCTORS 1 + +#define G_DEFINE_CONSTRUCTOR(_func) static void __attribute__((constructor)) _func (void); +#define G_DEFINE_DESTRUCTOR(_func) static void __attribute__((destructor)) _func (void); + +#elif defined (_MSC_VER) && (_MSC_VER >= 1500) +/* Visual studio 2008 and later has _Pragma */ + +/* + * Only try to include gslist.h if not already included via glib.h, + * so that items using gconstructor.h outside of GLib (such as + * GResources) continue to build properly. + */ +#ifndef __G_LIB_H__ +#include "gslist.h" +#endif + +#include + +#define G_HAS_CONSTRUCTORS 1 + +/* We do some weird things to avoid the constructors being optimized + * away on VS2015 if WholeProgramOptimization is enabled. First we + * make a reference to the array from the wrapper to make sure its + * references. Then we use a pragma to make sure the wrapper function + * symbol is always included at the link stage. Also, the symbols + * need to be extern (but not dllexport), even though they are not + * really used from another object file. + */ + +/* We need to account for differences between the mangling of symbols + * for x86 and x64/ARM/ARM64 programs, as symbols on x86 are prefixed + * with an underscore but symbols on x64/ARM/ARM64 are not. + */ +#ifdef _M_IX86 +#define G_MSVC_SYMBOL_PREFIX "_" +#else +#define G_MSVC_SYMBOL_PREFIX "" +#endif + +#define G_DEFINE_CONSTRUCTOR(_func) G_MSVC_CTOR (_func, G_MSVC_SYMBOL_PREFIX) +#define G_DEFINE_DESTRUCTOR(_func) G_MSVC_DTOR (_func, G_MSVC_SYMBOL_PREFIX) + +#define G_MSVC_CTOR(_func,_sym_prefix) \ + static void _func(void); \ + extern int (* _array ## _func)(void); \ + int _func ## _wrapper(void) { _func(); g_slist_find (NULL, _array ## _func); return 0; } \ + __pragma(comment(linker,"/include:" _sym_prefix # _func "_wrapper")) \ + __pragma(section(".CRT$XCU",read)) \ + __declspec(allocate(".CRT$XCU")) int (* _array ## _func)(void) = _func ## _wrapper; + +#define G_MSVC_DTOR(_func,_sym_prefix) \ + static void _func(void); \ + extern int (* _array ## _func)(void); \ + int _func ## _constructor(void) { atexit (_func); g_slist_find (NULL, _array ## _func); return 0; } \ + __pragma(comment(linker,"/include:" _sym_prefix # _func "_constructor")) \ + __pragma(section(".CRT$XCU",read)) \ + __declspec(allocate(".CRT$XCU")) int (* _array ## _func)(void) = _func ## _constructor; + +#elif defined (_MSC_VER) + +#define G_HAS_CONSTRUCTORS 1 + +/* Pre Visual studio 2008 must use #pragma section */ +#define G_DEFINE_CONSTRUCTOR_NEEDS_PRAGMA 1 +#define G_DEFINE_DESTRUCTOR_NEEDS_PRAGMA 1 + +#define G_DEFINE_CONSTRUCTOR_PRAGMA_ARGS(_func) \ + section(".CRT$XCU",read) +#define G_DEFINE_CONSTRUCTOR(_func) \ + static void _func(void); \ + static int _func ## _wrapper(void) { _func(); return 0; } \ + __declspec(allocate(".CRT$XCU")) static int (*p)(void) = _func ## _wrapper; + +#define G_DEFINE_DESTRUCTOR_PRAGMA_ARGS(_func) \ + section(".CRT$XCU",read) +#define G_DEFINE_DESTRUCTOR(_func) \ + static void _func(void); \ + static int _func ## _constructor(void) { atexit (_func); return 0; } \ + __declspec(allocate(".CRT$XCU")) static int (* _array ## _func)(void) = _func ## _constructor; + +#elif defined(__SUNPRO_C) + +/* This is not tested, but i believe it should work, based on: + * http://opensource.apple.com/source/OpenSSL098/OpenSSL098-35/src/fips/fips_premain.c + */ + +#define G_HAS_CONSTRUCTORS 1 + +#define G_DEFINE_CONSTRUCTOR_NEEDS_PRAGMA 1 +#define G_DEFINE_DESTRUCTOR_NEEDS_PRAGMA 1 + +#define G_DEFINE_CONSTRUCTOR_PRAGMA_ARGS(_func) \ + init(_func) +#define G_DEFINE_CONSTRUCTOR(_func) \ + static void _func(void); + +#define G_DEFINE_DESTRUCTOR_PRAGMA_ARGS(_func) \ + fini(_func) +#define G_DEFINE_DESTRUCTOR(_func) \ + static void _func(void); + +#else + +/* constructors not supported for this compiler */ + +#endif + +#endif /* __GTK_DOC_IGNORE__ */ +#endif /* __G_CONSTRUCTOR_H__ */ + +#ifdef G_HAS_CONSTRUCTORS + +#ifdef G_DEFINE_CONSTRUCTOR_NEEDS_PRAGMA +#pragma G_DEFINE_CONSTRUCTOR_PRAGMA_ARGS(libgdaresource_constructor) +#endif +G_DEFINE_CONSTRUCTOR(libgdaresource_constructor) +#ifdef G_DEFINE_DESTRUCTOR_NEEDS_PRAGMA +#pragma G_DEFINE_DESTRUCTOR_PRAGMA_ARGS(libgdaresource_destructor) +#endif +G_DEFINE_DESTRUCTOR(libgdaresource_destructor) + +#else +#warning "Constructor not supported on this compiler, linking in resources will not work" +#endif + +static void libgdaresource_constructor (void) +{ + g_static_resource_init (&static_resource); +} + +static void libgdaresource_destructor (void) +{ + g_static_resource_fini (&static_resource); +} diff --git a/.flatpak-builder/cache/objects/97/d2dc0361b87aedf6dbac46d0407a037c30af344278ee94332abaa3123924ba.dirtree b/.flatpak-builder/cache/objects/97/d2dc0361b87aedf6dbac46d0407a037c30af344278ee94332abaa3123924ba.dirtree new file mode 100644 index 0000000..5425051 Binary files /dev/null and b/.flatpak-builder/cache/objects/97/d2dc0361b87aedf6dbac46d0407a037c30af344278ee94332abaa3123924ba.dirtree differ diff --git a/.flatpak-builder/cache/objects/98/37f901745158a397af80bc561b298a0800bdf940dbe8d778390dc99f59de15.file b/.flatpak-builder/cache/objects/98/37f901745158a397af80bc561b298a0800bdf940dbe8d778390dc99f59de15.file new file mode 100644 index 0000000..1b042cb --- /dev/null +++ b/.flatpak-builder/cache/objects/98/37f901745158a397af80bc561b298a0800bdf940dbe8d778390dc99f59de15.file @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2001 - 2002 Gonzalo Paniagua Javier + * Copyright (C) 2001 - 2004 Rodrigo Moya + * Copyright (C) 2002 Carlos Perelló Marín + * Copyright (C) 2005 Bas Driessen + * Copyright (C) 2005 Stanislav Brabec + * Copyright (C) 2005 - 2015 Vivien Malerba + * Copyright (C) 2010 David King + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include +#include +#include +#include "gda-sqlite-provider.h" +#include +#include + +const gchar *plugin_get_name (void); +const gchar *plugin_get_description (void); +gchar *plugin_get_dsn_spec (void); +GdaServerProvider *plugin_create_provider (void); + +/* + * Functions executed when calling g_module_open() and g_module_close() + */ +const gchar * +g_module_check_init (G_GNUC_UNUSED GModule *module) +{ + /*g_module_make_resident (module);*/ + return NULL; +} + +void +g_module_unload (G_GNUC_UNUSED GModule *module) +{ +} + +/* + * Normal plugin functions + */ +void +plugin_init (const gchar *real_path) +{ +} + +const gchar * +plugin_get_name (void) +{ + return "SQLite"; +} + +const gchar * +plugin_get_description (void) +{ + return _("Provider for SQLite databases"); +} + +gchar * +plugin_get_dsn_spec (void) +{ + return gda_server_provider_load_resource_contents ("sqlite", "sqlite_specs_dsn.raw.xml"); +} + +gchar * +plugin_get_auth_spec (void) +{ +#define AUTH "" \ + "" \ + " " \ + "" + + return g_strdup (AUTH); +} + +GdaServerProvider * +plugin_create_provider (void) +{ + GdaServerProvider *prov; + + prov = (GdaServerProvider*) g_object_new (GDA_TYPE_SQLITE_PROVIDER, NULL); + return prov; +} diff --git a/.flatpak-builder/cache/objects/99/4d3275104f7c8c7f978549c13439c8aee49a6915856a570f9b85a7c42dff47.dirtree b/.flatpak-builder/cache/objects/99/4d3275104f7c8c7f978549c13439c8aee49a6915856a570f9b85a7c42dff47.dirtree new file mode 100644 index 0000000..9547c3f Binary files /dev/null and b/.flatpak-builder/cache/objects/99/4d3275104f7c8c7f978549c13439c8aee49a6915856a570f9b85a7c42dff47.dirtree differ diff --git a/.flatpak-builder/cache/objects/99/829ab338dfb31318581ba4a44877ffc216852e4363e8357a7a543cfb4b3020.dirtree b/.flatpak-builder/cache/objects/99/829ab338dfb31318581ba4a44877ffc216852e4363e8357a7a543cfb4b3020.dirtree new file mode 100644 index 0000000..065618d Binary files /dev/null and b/.flatpak-builder/cache/objects/99/829ab338dfb31318581ba4a44877ffc216852e4363e8357a7a543cfb4b3020.dirtree differ diff --git a/.flatpak-builder/cache/objects/99/a869d1be514fa4f4364c9cd1be7133a12cdaad431778ca76375b77593c984c.dirtree b/.flatpak-builder/cache/objects/99/a869d1be514fa4f4364c9cd1be7133a12cdaad431778ca76375b77593c984c.dirtree new file mode 100644 index 0000000..41f1917 Binary files /dev/null and b/.flatpak-builder/cache/objects/99/a869d1be514fa4f4364c9cd1be7133a12cdaad431778ca76375b77593c984c.dirtree differ diff --git a/.flatpak-builder/cache/objects/99/f00a6e8dc3463ad1b7a7e3ac78f3b71b870b73ae8e5b5c9125262aeb63619c.file b/.flatpak-builder/cache/objects/99/f00a6e8dc3463ad1b7a7e3ac78f3b71b870b73ae8e5b5c9125262aeb63619c.file new file mode 100644 index 0000000..998d2fc --- /dev/null +++ b/.flatpak-builder/cache/objects/99/f00a6e8dc3463ad1b7a7e3ac78f3b71b870b73ae8e5b5c9125262aeb63619c.file @@ -0,0 +1,64 @@ +/* gda-db-base.h + * + * Copyright (C) 2018 Pavlo Solntsev + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef GDA_DB_BASE_H +#define GDA_DB_BASE_H + +#include +#include + +G_BEGIN_DECLS + +#define GDA_TYPE_DB_BASE (gda_db_base_get_type()) + +G_DECLARE_DERIVABLE_TYPE (GdaDbBase, gda_db_base, GDA, DB_BASE, GObject) + +struct _GdaDbBaseClass +{ + GObjectClass parent; +}; + +GdaDbBase* gda_db_base_new (void); + +void gda_db_base_set_names (GdaDbBase *self, + const gchar *catalog, + const gchar *schema, + const gchar *name); + +const gchar* gda_db_base_get_full_name (GdaDbBase *self); +const gchar* gda_db_base_get_name (GdaDbBase *self); +void gda_db_base_set_name (GdaDbBase *self, + const gchar *name); + +const gchar* gda_db_base_get_catalog (GdaDbBase *self); +void gda_db_base_set_catalog (GdaDbBase *self, + const gchar *catalog); + +const gchar* gda_db_base_get_schema (GdaDbBase *self); +void gda_db_base_set_schema (GdaDbBase *self, + const gchar *schema); + +gint gda_db_base_compare (GdaDbBase *a, GdaDbBase *b); + +#define GDA_BOOL_TO_STR(x) (x ? "TRUE" : "FALSE") +G_END_DECLS + +#endif /* GDA_DB_BASE_H */ + diff --git a/.flatpak-builder/cache/objects/9a/00551848f59c9fca21c1415015f0bd5c9c2a26ee9cb1971980b358c72a1734.dirtree b/.flatpak-builder/cache/objects/9a/00551848f59c9fca21c1415015f0bd5c9c2a26ee9cb1971980b358c72a1734.dirtree new file mode 100644 index 0000000..4e28289 Binary files /dev/null and b/.flatpak-builder/cache/objects/9a/00551848f59c9fca21c1415015f0bd5c9c2a26ee9cb1971980b358c72a1734.dirtree differ diff --git a/.flatpak-builder/cache/objects/9a/33417e12c5830d7aebae9fc95515e5f456e9ca61f8246fc6ec0d09dd108139.file b/.flatpak-builder/cache/objects/9a/33417e12c5830d7aebae9fc95515e5f456e9ca61f8246fc6ec0d09dd108139.file new file mode 100644 index 0000000..d418779 --- /dev/null +++ b/.flatpak-builder/cache/objects/9a/33417e12c5830d7aebae9fc95515e5f456e9ca61f8246fc6ec0d09dd108139.file @@ -0,0 +1,307 @@ +/* + * Copyright (C) 2008 - 2010 Murray Cumming + * Copyright (C) 2008 - 2012 Vivien Malerba + * Copyright (C) 2009 Bas Driessen + * Copyright (C) 2010 David King + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include +#include +#include +#include +#include +#include +#include + +static gpointer gda_sql_statement_update_new (void); +static void gda_sql_statement_update_free (gpointer stmt); +static gpointer gda_sql_statement_update_copy (gpointer src); +static gchar *gda_sql_statement_update_serialize (gpointer stmt); +static gboolean gda_sql_statement_update_check_structure (GdaSqlAnyPart *stmt, gpointer data, GError **error); + +GdaSqlStatementContentsInfo update_infos = { + GDA_SQL_STATEMENT_UPDATE, + "UPDATE", + gda_sql_statement_update_new, + gda_sql_statement_update_free, + gda_sql_statement_update_copy, + gda_sql_statement_update_serialize, + + gda_sql_statement_update_check_structure, + NULL, + NULL, + NULL, + NULL, + NULL +}; + +GdaSqlStatementContentsInfo * +_gda_sql_statement_update_get_infos (void) +{ + return &update_infos; +} + +static gpointer +gda_sql_statement_update_new (void) +{ + GdaSqlStatementUpdate *stmt; + stmt = g_new0 (GdaSqlStatementUpdate, 1); + GDA_SQL_ANY_PART (stmt)->type = GDA_SQL_ANY_STMT_UPDATE; + return (gpointer) stmt; +} + +static void +gda_sql_statement_update_free (gpointer stmt) +{ + GdaSqlStatementUpdate *update = (GdaSqlStatementUpdate *) stmt; + GSList *list; + + if (update->table) + gda_sql_table_free (update->table); + for (list = update->fields_list; list; list = list->next) { + if (list->data) + gda_sql_field_free ((GdaSqlField *) list->data); + } + if (update->fields_list) + g_slist_free (update->fields_list); + + for (list = update->expr_list; list; list = list->next) { + if (list->data) + gda_sql_expr_free ((GdaSqlExpr *) list->data); + } + if (update->expr_list) + g_slist_free (update->expr_list); + + if (update->cond) + gda_sql_expr_free (update->cond); + g_free (update); +} + +static gpointer +gda_sql_statement_update_copy (gpointer src) +{ + GdaSqlStatementUpdate *dest; + GdaSqlStatementUpdate *update = (GdaSqlStatementUpdate *) src; + GSList *list; + + dest = gda_sql_statement_update_new (); + if (update->on_conflict) + dest->on_conflict = g_strdup (update->on_conflict); + + dest->table = gda_sql_table_copy (update->table); + gda_sql_any_part_set_parent (dest->table, dest); + + for (list = update->fields_list; list; list = list->next) { + dest->fields_list = g_slist_prepend (dest->fields_list, + gda_sql_field_copy ((GdaSqlField *) list->data)); + gda_sql_any_part_set_parent (dest->fields_list->data, dest); + } + dest->fields_list = g_slist_reverse (dest->fields_list); + + for (list = update->expr_list; list; list = list->next) { + dest->expr_list = g_slist_prepend (dest->expr_list, + gda_sql_expr_copy ((GdaSqlExpr *) list->data)); + gda_sql_any_part_set_parent (dest->expr_list->data, dest); + } + dest->expr_list = g_slist_reverse (dest->expr_list); + + dest->cond = gda_sql_expr_copy (update->cond); + gda_sql_any_part_set_parent (dest->cond, dest); + + return dest; +} + +static gchar * +gda_sql_statement_update_serialize (gpointer stmt) +{ + GString *string; + gchar *str; + GSList *list; + GdaSqlStatementUpdate *update = (GdaSqlStatementUpdate *) stmt; + + g_return_val_if_fail (stmt, NULL); + + string = g_string_new ("\"contents\":{"); + + /* table name */ + g_string_append (string, "\"table\":"); + str = gda_sql_table_serialize (update->table); + g_string_append (string, str); + g_free (str); + + /* fields */ + g_string_append (string, ",\"fields\":"); + if (update->fields_list) { + g_string_append_c (string, '['); + for (list = update->fields_list; list; list = list->next) { + if (list != update->fields_list) + g_string_append_c (string, ','); + str = gda_sql_field_serialize ((GdaSqlField *) list->data); + g_string_append (string, str); + g_free (str); + } + g_string_append_c (string, ']'); + } + else + g_string_append (string, "null"); + + /* expressions */ + g_string_append (string, ",\"expressions\":"); + if (update->expr_list) { + g_string_append_c (string, '['); + for (list = update->expr_list; list; list = list->next) { + if (list != update->expr_list) + g_string_append_c (string, ','); + str = gda_sql_expr_serialize ((GdaSqlExpr *) list->data); + g_string_append (string, str); + g_free (str); + } + g_string_append_c (string, ']'); + } + else + g_string_append (string, "null"); + + /* condition */ + if (update->cond) { + g_string_append (string, ",\"condition\":"); + str = gda_sql_expr_serialize (update->cond); + g_string_append (string, str); + g_free (str); + } + + /* conflict clause */ + if (update->on_conflict) { + g_string_append (string, ",\"on_conflict\":"); + str = _json_quote_string (update->on_conflict); + g_string_append (string, str); + g_free (str); + } + g_string_append_c (string, '}'); + str = string->str; + g_string_free (string, FALSE); + return str; +} + +/** + * gda_sql_statement_update_take_table_name + * @stmt: a #GdaSqlStatement pointer + * @value: a table name, as a G_TYPE_STRING #GValue + * + * Sets the name of the table to delete from in @stmt. + * + * @value's ownership is transferred to + * @stmt (which means @stmt is then responsible for freeing it when no longer needed). + */ +void +gda_sql_statement_update_take_table_name (GdaSqlStatement *stmt, GValue *value) +{ + GdaSqlStatementUpdate *update = (GdaSqlStatementUpdate *) stmt->contents; + if (value) { + update->table = gda_sql_table_new (GDA_SQL_ANY_PART (update)); + gda_sql_table_take_name (update->table, value); + } +} + +/** + * gda_sql_statement_update_take_on_conflict + * @stmt: a #GdaSqlStatement pointer + * @value: name of the resolution conflict algorithm, as a G_TYPE_STRING #GValue + * + * Sets the name of the resolution conflict algorithm used by @stmt. @value's ownership is transferred to + * @stmt (which means @stmt is then responsible for freeing it when no longer needed). + */ +void +gda_sql_statement_update_take_on_conflict (GdaSqlStatement *stmt, GValue *value) +{ + GdaSqlStatementUpdate *update = (GdaSqlStatementUpdate *) stmt->contents; + if (value) { + update->on_conflict = g_value_dup_string (value); + g_value_reset (value); + g_free (value); + } +} + +/** + * gda_sql_statement_update_take_condition + * @stmt: a #GdaSqlStatement pointer + * @cond: a #GdaSqlExpr pointer + * + * Sets the WHERE clause of @stmt + * + * @expr's ownership is transferred to + * @stmt (which means @stmt is then responsible for freeing it when no longer needed). + */ +void +gda_sql_statement_update_take_condition (GdaSqlStatement *stmt, GdaSqlExpr *cond) +{ + GdaSqlStatementUpdate *update = (GdaSqlStatementUpdate *) stmt->contents; + update->cond = cond; + gda_sql_any_part_set_parent (cond, update); +} + + +/** + * gda_sql_statement_update_take_set_value + * @stmt: a #GdaSqlStatement pointer + * @fname: a field name, as a G_TYPE_STRING #GValue + * @expr: a #GdaSqlExpr pointer + * + * Specifies that the field named @fname will be updated with the expression @expr. + * + * @fname and @expr's responsibility are transferred to + * @stmt (which means @stmt is then responsible for freeing them when no longer needed). + */ +void +gda_sql_statement_update_take_set_value (GdaSqlStatement *stmt, GValue *fname, GdaSqlExpr *expr) +{ + GdaSqlStatementUpdate *update = (GdaSqlStatementUpdate *) stmt->contents; + GdaSqlField *sf; + + sf = gda_sql_field_new (GDA_SQL_ANY_PART (update)); + gda_sql_field_take_name (sf, fname); + update->fields_list = g_slist_append (update->fields_list, sf); + + update->expr_list = g_slist_append (update->expr_list, expr); + gda_sql_any_part_set_parent (expr, update); +} + +static gboolean +gda_sql_statement_update_check_structure (GdaSqlAnyPart *stmt, G_GNUC_UNUSED gpointer data, GError **error) +{ + GdaSqlStatementUpdate *update = (GdaSqlStatementUpdate *) stmt; + + if (!update->table) { + g_set_error (error, GDA_SQL_ERROR, GDA_SQL_STRUCTURE_CONTENTS_ERROR, + "%s", _("UPDATE statement needs a table to update data")); + return FALSE; + } + + if (g_slist_length (update->fields_list) != g_slist_length (update->expr_list)) { + g_set_error (error, GDA_SQL_ERROR, GDA_SQL_STRUCTURE_CONTENTS_ERROR, + "%s", _("UPDATE statement does not have the same number of target columns and expressions")); + return FALSE; + } + + if (!update->fields_list) { + g_set_error (error, GDA_SQL_ERROR, GDA_SQL_STRUCTURE_CONTENTS_ERROR, + "%s", _("UPDATE statement does not have any target columns to update")); + return FALSE; + } + + return TRUE; +} diff --git a/.flatpak-builder/cache/objects/9a/4d619b0e8e20cc67bf7ae3362128c511095dcea86ff5bcc2a37b5b7dc7aad7.file b/.flatpak-builder/cache/objects/9a/4d619b0e8e20cc67bf7ae3362128c511095dcea86ff5bcc2a37b5b7dc7aad7.file new file mode 100644 index 0000000..62e0a4c --- /dev/null +++ b/.flatpak-builder/cache/objects/9a/4d619b0e8e20cc67bf7ae3362128c511095dcea86ff5bcc2a37b5b7dc7aad7.file @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2000 Reinhard Müller + * Copyright (C) 2000 - 2002 Rodrigo Moya + * Copyright (C) 2001 Carlos Perelló Marín + * Copyright (C) 2001 - 2012 Vivien Malerba + * Copyright (C) 2002 Gonzalo Paniagua Javier + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GDA_BINRELOC_H__ +#define __GDA_BINRELOC_H__ + +#include + +G_BEGIN_DECLS + +/* + * Locating files + */ +typedef enum { + GDA_NO_DIR, + GDA_BIN_DIR, + GDA_SBIN_DIR, + GDA_DATA_DIR, + GDA_LOCALE_DIR, + GDA_LIB_DIR, + GDA_LIBEXEC_DIR, + GDA_ETC_DIR +} GdaPrefixDir; + +void gda_gbr_init (void); +gchar *gda_gbr_get_file_path (GdaPrefixDir where, ...); + +G_END_DECLS + +#endif diff --git a/.flatpak-builder/cache/objects/9a/5ba3429b8daf47d655653a436a4bb242556adba4375f201cf49e2dee67a316.file b/.flatpak-builder/cache/objects/9a/5ba3429b8daf47d655653a436a4bb242556adba4375f201cf49e2dee67a316.file new file mode 100644 index 0000000..74cd2c4 --- /dev/null +++ b/.flatpak-builder/cache/objects/9a/5ba3429b8daf47d655653a436a4bb242556adba4375f201cf49e2dee67a316.file @@ -0,0 +1,572 @@ +/* + * Copyright (C) 2009 Bas Driessen + * Copyright (C) 2009 - 2013 Vivien Malerba + * Copyright (C) 2010 David King + * Copyright (C) 2019 Daniel Espinosa + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +#define G_LOG_DOMAIN "GDA-data-meta-wrapper" + +#undef GDA_DISABLE_DEPRECATED +#include "gda-data-meta-wrapper.h" + +#include +#include +#include +#include +#include + +/* we don't want to duplicate the symbols in , so simply + * declare them as external + */ +extern const unsigned char UpperToLower[]; +#define charMap(X) UpperToLower[(unsigned char)(X)] +extern int casecmp(const char *zLeft, const char *zRight, int N); +#include "keywords_hash.code" /* this one is dynamically generated */ + +/* + * Each value in @values may be %NULL, a valid pointer, or 0x1 + */ +typedef struct { + gint row; /* row number it is for */ + gint size; /* size of the @values array */ + GValue **values; +} CompRow; + +#define NON_COMP_VALUE ((GValue*) 0x1) + +static void +comp_row_free (CompRow *row) +{ + if (row->values) { + gint i; + for (i = 0; i < row->size; i++) { + if (row->values [i] && (row->values [i] != NON_COMP_VALUE)) + gda_value_free (row->values [i]); + } + g_free (row->values); + } + g_free (row); +} + + +static void gda_data_meta_wrapper_class_init (GdaDataMetaWrapperClass *klass); +static void gda_data_meta_wrapper_init (GdaDataMetaWrapper *model); +static void gda_data_meta_wrapper_dispose (GObject *object); + +static void gda_data_meta_wrapper_set_property (GObject *object, + guint param_id, + const GValue *value, + GParamSpec *pspec); +static void gda_data_meta_wrapper_get_property (GObject *object, + guint param_id, + GValue *value, + GParamSpec *pspec); + +/* GdaDataModel interface */ +static void gda_data_meta_wrapper_data_model_init (GdaDataModelInterface *iface); +static gint gda_data_meta_wrapper_get_n_rows (GdaDataModel *model); +static gint gda_data_meta_wrapper_get_n_columns (GdaDataModel *model); +static GdaColumn *gda_data_meta_wrapper_describe_column (GdaDataModel *model, gint col); +static GdaDataModelAccessFlags gda_data_meta_wrapper_get_access_flags(GdaDataModel *model); +static const GValue *gda_data_meta_wrapper_get_value_at (GdaDataModel *model, gint col, gint row, GError **error); + + +typedef struct { + GdaDataModel *model; + gint nb_cols; + + gint *cols_to_wrap; + gint cols_to_wrap_size; + GdaSqlIdentifierStyle mode; + GdaSqlReservedKeywordsFunc reserved_keyword_func; + + GHashTable *computed_rows; /* key = row number, value = a CompRow pointer + * may be %NULL if we don't keep computed values */ + CompRow *buffer; /* may be %NULL if we keep computed values */ + + /* note: either @computed_rows or @buffer is NULL, not both and one is not NULL */ +} GdaDataMetaWrapperPrivate; + + +G_DEFINE_TYPE_WITH_CODE (GdaDataMetaWrapper, gda_data_meta_wrapper,G_TYPE_OBJECT, + G_ADD_PRIVATE (GdaDataMetaWrapper) + G_IMPLEMENT_INTERFACE(GDA_TYPE_DATA_MODEL,gda_data_meta_wrapper_data_model_init)) + +/* properties */ +enum +{ + PROP_0, + PROP_MODEL, +}; + +static void +gda_data_meta_wrapper_class_init (GdaDataMetaWrapperClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + /* properties */ + object_class->set_property = gda_data_meta_wrapper_set_property; + object_class->get_property = gda_data_meta_wrapper_get_property; + g_object_class_install_property (object_class, PROP_MODEL, + g_param_spec_object ("model", NULL, "Data model being wrapped", + GDA_TYPE_DATA_MODEL, + G_PARAM_READABLE | G_PARAM_WRITABLE | + G_PARAM_CONSTRUCT_ONLY)); + + /* virtual functions */ + object_class->dispose = gda_data_meta_wrapper_dispose; +#ifdef GDA_DEBUG + test_keywords (); +#endif +} + +static void +gda_data_meta_wrapper_data_model_init (GdaDataModelInterface *iface) +{ + iface->get_n_rows = gda_data_meta_wrapper_get_n_rows; + iface->get_n_columns = gda_data_meta_wrapper_get_n_columns; + iface->describe_column = gda_data_meta_wrapper_describe_column; + iface->get_access_flags = gda_data_meta_wrapper_get_access_flags; + iface->get_value_at = gda_data_meta_wrapper_get_value_at; + iface->get_attributes_at = NULL; + + iface->create_iter = NULL; + + iface->set_value_at = NULL; + iface->set_values = NULL; + iface->append_values = NULL; + iface->append_row = NULL; + iface->remove_row = NULL; + iface->find_row = NULL; + + iface->freeze = NULL; + iface->thaw = NULL; + iface->get_notify = NULL; + iface->send_hint = NULL; +} + +static void +gda_data_meta_wrapper_init (GdaDataMetaWrapper *model) +{ + g_return_if_fail (GDA_IS_DATA_META_WRAPPER (model)); + GdaDataMetaWrapperPrivate *priv = gda_data_meta_wrapper_get_instance_private (model); + priv->model = NULL; + priv->cols_to_wrap = NULL; + priv->cols_to_wrap_size = 0; + priv->mode = GDA_SQL_IDENTIFIERS_LOWER_CASE; + priv->reserved_keyword_func = NULL; + priv->computed_rows = NULL; + priv->buffer = NULL; +} + +static void +gda_data_meta_wrapper_dispose (GObject *object) +{ + GdaDataMetaWrapper *model = (GdaDataMetaWrapper *) object; + + g_return_if_fail (GDA_IS_DATA_META_WRAPPER (model)); + + GdaDataMetaWrapperPrivate *priv = gda_data_meta_wrapper_get_instance_private (model); + + /* free memory */ + /* random meta model free */ + if (priv->model) { + g_object_unref (priv->model); + priv->model = NULL; + } + + if (priv->computed_rows) { + g_hash_table_destroy (priv->computed_rows); + priv->computed_rows = NULL; + } + + if (priv->buffer) { + comp_row_free (priv->buffer); + priv->buffer = NULL; + } + + if (priv->cols_to_wrap) { + g_free (priv->cols_to_wrap); + priv->cols_to_wrap = NULL; + priv->cols_to_wrap_size = 0; + } + + /* chain to parent class */ + G_OBJECT_CLASS(gda_data_meta_wrapper_parent_class)->dispose (object); +} + +static void +gda_data_meta_wrapper_set_property (GObject *object, + guint param_id, + const GValue *value, + GParamSpec *pspec) +{ + GdaDataMetaWrapper *model; + + model = GDA_DATA_META_WRAPPER (object); + GdaDataMetaWrapperPrivate *priv = gda_data_meta_wrapper_get_instance_private (model); + switch (param_id) { + case PROP_MODEL: { + GdaDataModel *mod = g_value_get_object(value); + if (mod) { + g_return_if_fail (GDA_IS_DATA_MODEL (mod)); + if (! (gda_data_model_get_access_flags (mod) & GDA_DATA_MODEL_ACCESS_RANDOM)) { + g_warning ("Internal implementation error: data model does not support random access"); + return; + } + + if (priv->model) + g_object_unref (priv->model); + + priv->model = mod; + g_object_ref (mod); + priv->nb_cols = gda_data_model_get_n_columns (mod); + } + break; + } + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + break; + } +} + +static void +gda_data_meta_wrapper_get_property (GObject *object, + guint param_id, + GValue *value, + GParamSpec *pspec) +{ + GdaDataMetaWrapper *model; + + model = GDA_DATA_META_WRAPPER (object); + GdaDataMetaWrapperPrivate *priv = gda_data_meta_wrapper_get_instance_private (model); + switch (param_id) { + case PROP_MODEL: + g_value_set_object (value, G_OBJECT (priv->model)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + break; + } +} + +/** + * gda_data_meta_wrapper_new: + * @model: a #GdaDataModel + * + * Creates a new #GdaDataModel object which buffers the rows of @model. This object is useful + * only if @model can only be metaed using cursor based method. + * + * Returns: a pointer to the newly created #GdaDataModel. + */ +GdaDataModel * +_gda_data_meta_wrapper_new (GdaDataModel *model, gboolean reusable, gint *cols, + gint size, GdaSqlIdentifierStyle mode, + GdaSqlReservedKeywordsFunc reserved_keyword_func) +{ + GdaDataMetaWrapper *retmodel; + + g_return_val_if_fail (GDA_IS_DATA_MODEL (model), NULL); + + retmodel = g_object_new (GDA_TYPE_DATA_META_WRAPPER, + "model", model, NULL); + GdaDataMetaWrapperPrivate *retpriv = gda_data_meta_wrapper_get_instance_private (retmodel); + + retpriv->cols_to_wrap = g_new (gint, size); + memcpy (retpriv->cols_to_wrap, cols, sizeof (gint) * size); /* Flawfinder: ignore */ + retpriv->cols_to_wrap_size = size; + retpriv->mode = mode; + retpriv->reserved_keyword_func = reserved_keyword_func; + + if (reusable) + retpriv->computed_rows = g_hash_table_new_full (g_int_hash, g_int_equal, + NULL, (GDestroyNotify) comp_row_free); + else { + retpriv->buffer = g_new0 (CompRow, 1); + retpriv->buffer->size = size; + retpriv->buffer->values = g_new0 (GValue *, size); + } + + return GDA_DATA_MODEL (retmodel); +} + +/* + * GdaDataModel interface implementation + */ +static gint +gda_data_meta_wrapper_get_n_rows (GdaDataModel *model) +{ + GdaDataMetaWrapper *imodel; + g_return_val_if_fail (GDA_IS_DATA_META_WRAPPER (model), 0); + imodel = GDA_DATA_META_WRAPPER (model); + GdaDataMetaWrapperPrivate *priv = gda_data_meta_wrapper_get_instance_private (imodel); + + return gda_data_model_get_n_rows (priv->model); +} + +static gint +gda_data_meta_wrapper_get_n_columns (GdaDataModel *model) +{ + GdaDataMetaWrapper *imodel; + g_return_val_if_fail (GDA_IS_DATA_META_WRAPPER (model), 0); + imodel = GDA_DATA_META_WRAPPER (model); + GdaDataMetaWrapperPrivate *priv = gda_data_meta_wrapper_get_instance_private (imodel); + g_return_val_if_fail (priv, 0); + + if (priv->model) + return priv->nb_cols; + else + return 0; +} + +static GdaColumn * +gda_data_meta_wrapper_describe_column (GdaDataModel *model, gint col) +{ + GdaDataMetaWrapper *imodel; + g_return_val_if_fail (GDA_IS_DATA_META_WRAPPER (model), NULL); + imodel = GDA_DATA_META_WRAPPER (model); + GdaDataMetaWrapperPrivate *priv = gda_data_meta_wrapper_get_instance_private (imodel); + + if (priv->model) + return gda_data_model_describe_column (priv->model, col); + else + return NULL; +} + +static GdaDataModelAccessFlags +gda_data_meta_wrapper_get_access_flags (GdaDataModel *model) +{ + return GDA_DATA_MODEL_ACCESS_RANDOM; +} + +static gboolean +identifier_needs_quotes (const gchar *str, GdaSqlIdentifierStyle mode) +{ + const gchar *ptr; + for (ptr = str; *ptr; ptr++) { + /* quote if 1st char is a number */ + if ((*ptr <= '9') && (*ptr >= '0')) { + if (ptr == str) + return TRUE; + continue; + } + if ((*ptr >= 'A') && (*ptr <= 'Z')) { + if (mode == GDA_SQL_IDENTIFIERS_LOWER_CASE) + return TRUE; + continue; + } + if ((*ptr >= 'a') && (*ptr <= 'z')) { + if (mode == GDA_SQL_IDENTIFIERS_UPPER_CASE) + return TRUE; + continue; + } + if ((*ptr != '$') && (*ptr != '_') && (*ptr != '#')) + return TRUE; + } + return FALSE; +} + +static gboolean +identifier_is_all_lower (const gchar *str) +{ + const gchar *ptr; + for (ptr = str; *ptr; ptr++) { + if (*ptr != g_ascii_tolower (*ptr)) + return FALSE; + } + return TRUE; +} + +static gchar * +to_lower (gchar *str) +{ + gchar *ptr; + for (ptr = str; *ptr; ptr++) + *ptr = g_ascii_tolower (*ptr); + return str; +} + +/** + * _gda_data_meta_wrapper_compute_value: + * + * Returns: + * - NULL if no changes are necessary from the current value + * - a new GValue if changes were necessary + */ +GValue * +_gda_data_meta_wrapper_compute_value (const GValue *value, GdaSqlIdentifierStyle mode, GdaSqlReservedKeywordsFunc reserved_keyword_func) +{ + GValue *retval = NULL; + const gchar *str; + + if (G_VALUE_TYPE (value) != G_TYPE_STRING) + return NULL; + str = g_value_get_string (value); + if (!str) + return NULL; + if ((*str == '"') && (str[strlen(str) - 1] == '"')) + return NULL; /* already quoted */ + gchar **sa = g_strsplit (str, ".", 0); + if (sa[1]) { + gint i; + gboolean onechanged = FALSE; + for (i = 0; sa[i]; i++) { + if (identifier_needs_quotes (sa[i], mode)) { + gchar *tmp = gda_sql_identifier_force_quotes (sa[i]); + g_free (sa[i]); + sa[i] = tmp; + onechanged = TRUE; + } + else { + if (! identifier_is_all_lower (sa[i])) { + to_lower (sa[i]); + onechanged = TRUE; + } + + if ((reserved_keyword_func && reserved_keyword_func (sa[i])) || + (! reserved_keyword_func && is_keyword (sa[i]))) { + gchar *tmp = gda_sql_identifier_force_quotes (sa[i]); + g_free (sa[i]); + sa[i] = tmp; + onechanged = TRUE; + } + } + } + if (onechanged) { + retval = gda_value_new (G_TYPE_STRING); + g_value_take_string (retval, g_strjoinv (".", sa)); + } + } + else { + if (identifier_needs_quotes (str, mode)) { + retval = gda_value_new (G_TYPE_STRING); + g_value_take_string (retval, gda_sql_identifier_force_quotes (str)); + } + else { + gchar *tmp = NULL; + if (! identifier_is_all_lower (str)) + tmp = to_lower (g_strdup (str)); + + if ((reserved_keyword_func && reserved_keyword_func (tmp ? tmp : str)) || + (! reserved_keyword_func && is_keyword (tmp ? tmp : str))) { + gchar *tmp2 = gda_sql_identifier_force_quotes (tmp ? tmp : str); + if (tmp) + g_free (tmp); + tmp = tmp2; + } + if (tmp) { + retval = gda_value_new (G_TYPE_STRING); + g_value_take_string (retval, tmp); + } + } + } + g_strfreev (sa); + + return retval; +} + +/* + * Returns: the index in @imodel->priv->cols_to_wrap for column @col, or -1 if not found + */ +static gint +get_index_col (GdaDataMetaWrapper *imodel, gint col) +{ + GdaDataMetaWrapperPrivate *priv = gda_data_meta_wrapper_get_instance_private (imodel); + gint i; + for (i = 0; i < priv->cols_to_wrap_size; i++) { + if (priv->cols_to_wrap [i] == col) + return i; + else if (priv->cols_to_wrap [i] > col) + return -1; + } + return -1; +} + +static const GValue * +gda_data_meta_wrapper_get_value_at (GdaDataModel *model, gint col, gint row, GError **error) +{ + GdaDataMetaWrapper *imodel; + + g_return_val_if_fail (GDA_IS_DATA_META_WRAPPER (model), NULL); + imodel = GDA_DATA_META_WRAPPER (model); + GdaDataMetaWrapperPrivate *priv = gda_data_meta_wrapper_get_instance_private (imodel); + g_return_val_if_fail (priv, NULL); + g_return_val_if_fail (priv->model, NULL); + g_return_val_if_fail (row >= 0, NULL); + + if (col >= priv->nb_cols) { + g_set_error (error, GDA_DATA_MODEL_ERROR, GDA_DATA_MODEL_COLUMN_OUT_OF_RANGE_ERROR, + _("Column %d out of range (0-%d)"), col, priv->nb_cols - 1); + return NULL; + } + + gint indexcol = get_index_col (imodel, col); + if (indexcol == -1) + return gda_data_model_get_value_at (priv->model, col, row, error); + + /* data may need to be changed */ + if (priv->computed_rows) { + CompRow *crow = NULL; + crow = g_hash_table_lookup (priv->computed_rows, &row); + if (!crow || !(crow->values[indexcol]) || (crow->values[indexcol] == NON_COMP_VALUE)) { + const GValue *cvalue; + cvalue = gda_data_model_get_value_at (priv->model, col, row, error); + if (!cvalue) + return NULL; + + GValue *retval; + retval = _gda_data_meta_wrapper_compute_value (cvalue, priv->mode, + priv->reserved_keyword_func); + if (!retval) + return cvalue; + + if (!crow) { + crow = g_new0 (CompRow, 1); + crow->row = row; + crow->size = priv->cols_to_wrap_size; + crow->values = g_new (GValue *, crow->size); + gint i; + for (i = 0; i < crow->size; i++) + crow->values [i] = NON_COMP_VALUE; + g_hash_table_insert (priv->computed_rows, &(crow->row), crow); + } + crow->values[indexcol] = retval; + return retval; + } + else + return crow->values[indexcol]; + } + else { + const GValue *cvalue; + cvalue = gda_data_model_get_value_at (priv->model, col, row, error); + if (!cvalue) + return NULL; + + GValue *retval; + retval = _gda_data_meta_wrapper_compute_value (cvalue, priv->mode, + priv->reserved_keyword_func); + if (!retval) + return cvalue; + if (priv->buffer->values [indexcol]) + gda_value_free (priv->buffer->values [indexcol]); + priv->buffer->values [indexcol] = retval; + return retval; + } + return NULL; +} + diff --git a/.flatpak-builder/cache/objects/9b/24c59a11beaa9eb42059567031108493449b56e0d6f3197f21a0a0db5388ff.dirtree b/.flatpak-builder/cache/objects/9b/24c59a11beaa9eb42059567031108493449b56e0d6f3197f21a0a0db5388ff.dirtree new file mode 100644 index 0000000..3e2090b Binary files /dev/null and b/.flatpak-builder/cache/objects/9b/24c59a11beaa9eb42059567031108493449b56e0d6f3197f21a0a0db5388ff.dirtree differ diff --git a/.flatpak-builder/cache/objects/9b/7db89158ecadf217cee163d2db3e94e715c62db84567c9e3b25fd1940411db.file b/.flatpak-builder/cache/objects/9b/7db89158ecadf217cee163d2db3e94e715c62db84567c9e3b25fd1940411db.file new file mode 100644 index 0000000..96b1802 --- /dev/null +++ b/.flatpak-builder/cache/objects/9b/7db89158ecadf217cee163d2db3e94e715c62db84567c9e3b25fd1940411db.file @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2009 - 2011 Vivien Malerba + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GDA_TREE_H__ +#define __GDA_TREE_H__ + +#include +#include +#include +#include "gda-decl.h" + +G_BEGIN_DECLS + +#define GDA_TYPE_TREE (gda_tree_get_type()) + +G_DECLARE_DERIVABLE_TYPE(GdaTree, gda_tree, GDA, TREE, GObject) +/* error reporting */ +extern GQuark gda_tree_error_quark (void); +#define GDA_TREE_ERROR gda_tree_error_quark () + +typedef enum { + GDA_TREE_UNKNOWN_ERROR +} GdaTreeError; + + +struct _GdaTreeClass { + GObjectClass object_class; + + /* signals */ + void (* node_changed) (GdaTree *tree, GdaTreeNode *node); + void (* node_inserted) (GdaTree *tree, GdaTreeNode *node); + void (* node_has_child_toggled) (GdaTree *tree, GdaTreeNode *node); + void (* node_deleted) (GdaTree *tree, const gchar *node_path); + + /*< private >*/ + /* Padding for future expansion */ + void (*_gda_reserved1) (void); + void (*_gda_reserved2) (void); + void (*_gda_reserved3) (void); + void (*_gda_reserved4) (void); +}; + +/** + * SECTION:gda-tree + * @short_description: A tree-structure + * @title: GdaTree + * @stability: Stable + * @see_also: + * + * The #GdaTree is the top level object representing hierarchically structured data. From this object it + * is also possible (depending on the tree managers it uses), to clean (remove all the nodes) the whole tree, + * or to request a complete or partial update of the nodes. + * + * It is also possible to set attributes to the tree itself (as it is possible to do for tree nodes), + * or to dump the whole or part of a tree in an indented and easy to read fashion. + */ + +GdaTree* gda_tree_new (void); +void gda_tree_add_manager (GdaTree *tree, GdaTreeManager *manager); + +void gda_tree_clean (GdaTree *tree); +gboolean gda_tree_update_all (GdaTree *tree, GError **error); +gboolean gda_tree_update_part (GdaTree *tree, GdaTreeNode *node, GError **error); +gboolean gda_tree_update_children (GdaTree *tree, GdaTreeNode *node, GError **error); + +GSList *gda_tree_get_nodes_in_path (GdaTree *tree, const gchar *tree_path, gboolean use_names); +GdaTreeNode *gda_tree_get_node (GdaTree *tree, const gchar *tree_path, gboolean use_names); +gchar *gda_tree_get_node_path (GdaTree *tree, GdaTreeNode *node); +GdaTreeManager *gda_tree_get_node_manager (GdaTree *tree, GdaTreeNode *node); + +void gda_tree_set_attribute (GdaTree *tree, const gchar *attribute, const GValue *value, + GDestroyNotify destroy); + +void gda_tree_dump (GdaTree *tree, GdaTreeNode *node, FILE *stream); + +G_END_DECLS + +#endif diff --git a/.flatpak-builder/cache/objects/9b/962d951215961f29990d4595fd3f8db86efc5f09024f7de089c7f98303408d.file b/.flatpak-builder/cache/objects/9b/962d951215961f29990d4595fd3f8db86efc5f09024f7de089c7f98303408d.file new file mode 100644 index 0000000..6cdb07b --- /dev/null +++ b/.flatpak-builder/cache/objects/9b/962d951215961f29990d4595fd3f8db86efc5f09024f7de089c7f98303408d.file @@ -0,0 +1,9 @@ +from ..language import UI + + +class OutputFormat: + def emit(self, ui: UI) -> str: + raise NotImplementedError() + + +from .xml import XmlOutput diff --git a/.flatpak-builder/cache/objects/9b/c7d41eed7ce622d5bd87e31edc522000fa3fa0f1880afbc745a22ce33785fd.file b/.flatpak-builder/cache/objects/9b/c7d41eed7ce622d5bd87e31edc522000fa3fa0f1880afbc745a22ce33785fd.file new file mode 100644 index 0000000..9ab5f81 --- /dev/null +++ b/.flatpak-builder/cache/objects/9b/c7d41eed7ce622d5bd87e31edc522000fa3fa0f1880afbc745a22ce33785fd.file @@ -0,0 +1,40 @@ + + + + +libcanberra Reference Manual + + + + + + + +
+
+
+
+

+ The latest version of this documentation can be found on-line at + http://0pointer.de/lennart/projects/libcanberra/gtkdoc/index.html. +

+ +
+ +
+
libcanberra
+
+
+canberra — General libcanberra API +
+
+canberra-gtk — Gtk+ libcanberra Bindings +
+
+
+ + + + \ No newline at end of file diff --git a/.flatpak-builder/cache/objects/9b/effc4a3f277dce58793cfa42c1178e344f0e4b49caa5610c499274ff28d45b.file b/.flatpak-builder/cache/objects/9b/effc4a3f277dce58793cfa42c1178e344f0e4b49caa5610c499274ff28d45b.file new file mode 100644 index 0000000..4689593 Binary files /dev/null and b/.flatpak-builder/cache/objects/9b/effc4a3f277dce58793cfa42c1178e344f0e4b49caa5610c499274ff28d45b.file differ diff --git a/.flatpak-builder/cache/objects/9b/f7cec51f53a3d3c803dc5dd040d8fa8fab10fbd01e783d571945b053bf214d.dirtree b/.flatpak-builder/cache/objects/9b/f7cec51f53a3d3c803dc5dd040d8fa8fab10fbd01e783d571945b053bf214d.dirtree new file mode 100644 index 0000000..43b1e1b Binary files /dev/null and b/.flatpak-builder/cache/objects/9b/f7cec51f53a3d3c803dc5dd040d8fa8fab10fbd01e783d571945b053bf214d.dirtree differ diff --git a/.flatpak-builder/cache/objects/9b/fd0b442bdc6ea957b1c4923e23fe20fdcb84eff2ba9e24f346b537896bd619.file b/.flatpak-builder/cache/objects/9b/fd0b442bdc6ea957b1c4923e23fe20fdcb84eff2ba9e24f346b537896bd619.file new file mode 100644 index 0000000..f0ae225 --- /dev/null +++ b/.flatpak-builder/cache/objects/9b/fd0b442bdc6ea957b1c4923e23fe20fdcb84eff2ba9e24f346b537896bd619.file @@ -0,0 +1,329 @@ +/* + * Copyright (C) 2014 Vivien Malerba + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "gda-connect.h" +#include "itsignaler.h" +#include +#include + +#define DEBUG_NOTIFICATION +#undef DEBUG_NOTIFICATION + +#ifdef DEBUG_NOTIFICATION +static gchar * +_value_stringify (const GValue *value) +{ + if (!value) + return g_strdup ("NULL"); + if (g_value_type_transformable (G_VALUE_TYPE (value), G_TYPE_STRING)) { + GValue *string; + gchar *str; + + string = g_value_init (g_new0 (GValue, 1), G_TYPE_STRING); + g_value_transform (value, string); + str = g_value_dup_string (string); + g_value_reset (string); + g_free (string); + return str; + } + else { + GType type = G_VALUE_TYPE (value); + if (type == G_TYPE_DATE) { + GDate *date; + date = (GDate *) g_value_get_boxed (value); + if (date) { + if (g_date_valid (date)) + return g_strdup_printf ("%04u-%02u-%02u", + g_date_get_year (date), + g_date_get_month (date), + g_date_get_day (date)); + else + return g_strdup_printf ("%04u-%02u-%02u", + date->year, date->month, date->day); + } + else + return g_strdup ("0000-00-00"); + } + else if (G_TYPE_IS_OBJECT (type)) { + GObject *obj; + obj = g_value_get_object (value); + return g_strdup_printf ("%p (%s)", obj, G_OBJECT_TYPE_NAME (obj)); + } + else + return g_strdup (""); + } +} +#endif + +typedef struct _SigClosure SigClosure; +struct _SigClosure +{ + GClosure closure; + GMutex mutex; + GMainContext *context; /* ref held */ + + GClosure *rcl; /* real closure, used in the main loop context */ + + ITSignaler *signal_its; + ITSignaler *return_its; + guint its_add_id; +}; + +static void +sig_closure_finalize (G_GNUC_UNUSED gpointer notify_data, GClosure *closure) +{ + SigClosure *sig_closure = (SigClosure *)closure; + + /*g_print ("%s (%p)\n", __FUNCTION__, closure);*/ + itsignaler_remove (sig_closure->signal_its, sig_closure->context, sig_closure->its_add_id); + itsignaler_unref (sig_closure->signal_its); + itsignaler_unref (sig_closure->return_its); + if (sig_closure->rcl) + g_closure_unref (sig_closure->rcl); + g_mutex_clear (& (sig_closure->mutex)); + + g_main_context_unref (sig_closure->context); +} + +/* data to pass through ITSignaler and back */ +typedef struct { + GValue *return_value; + guint n_param_values; + GValue *param_values; + gpointer invocation_hint; /* value is never copied */ + GClosure *rcl; +} PassedData; + +/* + * This function is called in the thread which emitted the signal + * + * In it we pack the data, push it through the ITSignaler to the thread in which the callback will be called, and + * wait for the result before returning. + */ +static void +sig_closure_marshal (GClosure *closure, + GValue *return_value, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint, + G_GNUC_UNUSED gpointer marshal_data) +{ + SigClosure *sig_closure; + sig_closure = (SigClosure *) closure; + +#ifdef DEBUG_NOTIFICATION + g_print ("Th%p: %s (closure->data = \"%s\") called\n", g_thread_self(), __FUNCTION__, (gchar*) closure->data); + guint n; + for (n = 0; n < n_param_values; n++) { + gchar *tmp; + tmp = _value_stringify (& (param_values [n])); + g_print ("Th%p Param value %d is [%s]\n", g_thread_self(), n, tmp); + g_free (tmp); + } + if (return_value) + g_print ("Th%p Return value expected: of type %s\n", g_thread_self(), g_type_name (G_VALUE_TYPE (return_value))); + else + g_print ("Th%p Return value expected: none\n", g_thread_self()); +#endif + + gboolean is_owner; + is_owner = g_main_context_is_owner (sig_closure->context); + if (g_main_context_acquire (sig_closure->context)) { + /* warning about not owner context */ + if (!is_owner) + g_warning (_("The GMainContext passed when gda_signal_connect() was called is not owned by any thread, you may " + "expect some undesired behaviours, use g_main_context_acquire()")); + + /* the signal has to be propagated in the same thread */ + GClosure *rcl; + rcl = g_closure_ref (sig_closure->rcl); + g_closure_invoke (rcl, return_value, n_param_values, param_values, invocation_hint); + g_closure_unref (rcl); + g_main_context_release (sig_closure->context); + } + else { + PassedData data; + data.n_param_values = n_param_values; + data.invocation_hint = invocation_hint; + data.return_value = return_value; + data.param_values = (GValue*) param_values; + data.rcl = g_closure_ref (sig_closure->rcl); + + g_mutex_lock (& (sig_closure->mutex)); /* This mutex ensures that push_notification() and + * the following pop_notification() are treated as a single atomic operation + * in case there are some return values */ + if (itsignaler_push_notification (sig_closure->signal_its, &data, NULL)) { + gpointer rdata; + rdata = itsignaler_pop_notification (sig_closure->return_its, -1); + g_assert (rdata == &data); + } + else + g_warning ("Internal Gda connect error, the signal will not be propagated, please report the bug"); + g_mutex_unlock (& (sig_closure->mutex)); + + g_closure_unref (data.rcl); + } +} + +/* + * This function is called in the thread where the signal is intended by the + * programmer to be propagated, when a PassedData pointer is available through the ITS + */ +static gboolean +propagate_signal (SigClosure *sig_closure) +{ + PassedData *data; + data = itsignaler_pop_notification (sig_closure->signal_its, 0); + if (data) { + g_closure_invoke (data->rcl, data->return_value, data->n_param_values, + data->param_values, data->invocation_hint); + if (! itsignaler_push_notification (sig_closure->return_its, data, NULL)) + g_warning ("Internal Gda Connect error, the signal result will not be propagated, please report the bug"); + } + else + g_warning ("Internal Gda Connect error: no signal data to process, please report a bug"); + return TRUE; /* don't remove the source! */ +} + +static SigClosure * +sig_closure_new (gpointer instance, GMainContext *context, gboolean swapped, GCallback c_handler, gpointer data) +{ + g_assert (context); + g_assert (instance); + g_assert (c_handler); + + ITSignaler *its1, *its2; + its1 = itsignaler_new (); + its2 = itsignaler_new (); + if (! its1 || ! its2) { + g_warning ("Not enough ressources to allocate internal communication object"); + itsignaler_unref (its1); /* in case it was created */ + return NULL; + } + + GClosure *closure; + SigClosure *sig_closure; + + closure = g_closure_new_simple (sizeof (SigClosure), data); + sig_closure = (SigClosure *) closure; + sig_closure->context = g_main_context_ref (context); + sig_closure->signal_its = its1; + sig_closure->return_its = its2; + g_mutex_init (& (sig_closure->mutex)); + + if (swapped) + sig_closure->rcl = g_cclosure_new_swap (c_handler, closure->data, NULL); + else + sig_closure->rcl = g_cclosure_new (c_handler, closure->data, NULL); + g_closure_set_marshal (sig_closure->rcl, g_cclosure_marshal_generic); + + sig_closure->its_add_id = itsignaler_add (sig_closure->signal_its, context, + (ITSignalerFunc) propagate_signal, sig_closure, NULL); + + /* initialize closure */ + g_closure_set_marshal (closure, sig_closure_marshal); + gpointer notify_data = NULL; /* as unused in sig_closure_finalize() */ + g_closure_add_finalize_notifier (closure, notify_data, sig_closure_finalize); + + /*g_print ("%s (%p)\n", __FUNCTION__, closure);*/ + return sig_closure; +} + +/** + * gda_signal_connect: + * @instance: the instance to connect to + * @detailed_signal: a string of the form "signal-name::detail" + * @c_handler: the GCallback to connect + * @data: (nullable): data to pass to @c_handler, or %NULL + * @destroy_data: (nullable): function to destroy @data when not needed anymore, or %NULL + * @connect_flags: a combination of #GConnectFlags. + * @context: (nullable): the #GMainContext in which signals will actually be treated, or %NULL for the default one + * + * Connects a GCallback function to a signal for a particular object. The difference with g_signal_connect() is that the + * callback will be called from withing the thread which is the owner of @context. If needed you may have to use g_main_context_acquire() + * to ensure a specific thread is the owner of @context. + * + * Returns: the handler id, or %0 if an error occurred + * + * Since: 6.0 + */ +gulong +gda_signal_connect (gpointer instance, + const gchar *detailed_signal, + GCallback c_handler, + gpointer data, + G_GNUC_UNUSED GClosureNotify destroy_data, + GConnectFlags connect_flags, + GMainContext *context) +{ + g_return_val_if_fail (instance, 0); + g_return_val_if_fail (c_handler, 0); + + guint signal_id; + if (! g_signal_parse_name (detailed_signal, G_TYPE_FROM_INSTANCE (instance), &signal_id, NULL, FALSE)) { + g_warning (_("Could not find signal named \"%s\""), detailed_signal); + return 0; + } + + if (context) + g_main_context_ref (context); + else + context = g_main_context_ref_thread_default (); + + SigClosure *sig_closure; + sig_closure = sig_closure_new (instance, context, + connect_flags & G_CONNECT_SWAPPED, c_handler, data); + g_main_context_unref (context); + if (!sig_closure) + return 0; + + GSignalQuery query; + g_signal_query (signal_id, &query); + g_assert (query.signal_id == signal_id); + + gulong handler_id; + handler_id = g_signal_connect_closure (instance, detailed_signal, (GClosure *) sig_closure, + (connect_flags & G_CONNECT_AFTER) ? TRUE : FALSE); + if (handler_id > 0) + return handler_id; + else { + g_closure_unref ((GClosure *) sig_closure); + return 0; + } + +} + +/** + * gda_signal_handler_disconnect: + * @instance: the instance to disconnect from + * @handler_id: the signal handler, as returned by gda_signal_connect() + * + * Disconnect a callback using the signal handler, see gda_signal_connect(). This function is similar to calling + * g_signal_handler_disconnect(). + * + * Since: 6.0 + */ +void +gda_signal_handler_disconnect (gpointer instance, gulong handler_id) +{ + g_return_if_fail (instance); + g_return_if_fail (handler_id > 0); + + g_signal_handler_disconnect (instance, handler_id); +} diff --git a/.flatpak-builder/cache/objects/9c/01e46fb9e6efd3a62a5e6d1197cfd85d54e60a8f6554b0fe87dfb0e7f901d3.file b/.flatpak-builder/cache/objects/9c/01e46fb9e6efd3a62a5e6d1197cfd85d54e60a8f6554b0fe87dfb0e7f901d3.file new file mode 100644 index 0000000..930bf57 --- /dev/null +++ b/.flatpak-builder/cache/objects/9c/01e46fb9e6efd3a62a5e6d1197cfd85d54e60a8f6554b0fe87dfb0e7f901d3.file @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2014 Vivien Malerba + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __ITSIGNALER_H__ +#define __ITSIGNALER_H__ + +#include +#ifdef G_OS_WIN32 + #include +#endif + +G_BEGIN_DECLS + +typedef struct _ITSignaler ITSignaler; + +ITSignaler *itsignaler_new (void); + +#ifdef G_OS_WIN32 +SOCKET itsignaler_windows_get_poll_fd (ITSignaler *its); +#else +int itsignaler_unix_get_poll_fd (ITSignaler *its); +#endif + +ITSignaler *itsignaler_ref (ITSignaler *its); +void itsignaler_unref (ITSignaler *its); + +gboolean itsignaler_push_notification (ITSignaler *its, gpointer data, GDestroyNotify destroy_func); +gpointer itsignaler_pop_notification (ITSignaler *its, gint timeout_ms); + +GSource *itsignaler_create_source (ITSignaler *its); + +/* + * Returns: %FALSE if the source should be removed from the poll + */ +typedef gboolean (*ITSignalerFunc) (gpointer user_data); + +guint itsignaler_add (ITSignaler *its, GMainContext *context, ITSignalerFunc func, gpointer data, GDestroyNotify notify); +gboolean itsignaler_remove (ITSignaler *its, GMainContext *context, guint id); + +/* + * Private + */ +void _itsignaler_bg_unref (ITSignaler *its); + +G_END_DECLS + +#endif diff --git a/.flatpak-builder/cache/objects/9c/2f0d851f4cc2dcc179f802eb69293c4a639719e27078dacfca893b12cacf30.file b/.flatpak-builder/cache/objects/9c/2f0d851f4cc2dcc179f802eb69293c4a639719e27078dacfca893b12cacf30.file new file mode 100644 index 0000000..32affd0 --- /dev/null +++ b/.flatpak-builder/cache/objects/9c/2f0d851f4cc2dcc179f802eb69293c4a639719e27078dacfca893b12cacf30.file @@ -0,0 +1,868 @@ +/*-*- Mode: C; c-basic-offset: 8 -*-*/ + +/*** + This file is part of libcanberra. + + Copyright 2008 Lennart Poettering + + libcanberra is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation, either version 2.1 of the + License, or (at your option) any later version. + + libcanberra is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with libcanberra. If not, see + . +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include + +#include "sound-theme-spec.h" +#include "malloc.h" +#include "llist.h" +#include "cache.h" + +#define DEFAULT_THEME "freedesktop" +#define FALLBACK_THEME "freedesktop" +#define DEFAULT_OUTPUT_PROFILE "stereo" +#define N_THEME_DIR_MAX 8 + +typedef struct ca_data_dir ca_data_dir; + +struct ca_data_dir { + CA_LLIST_FIELDS(ca_data_dir); + + char *theme_name; + char *dir_name; + char *output_profile; +}; + +struct ca_theme_data { + char *name; + + CA_LLIST_HEAD(ca_data_dir, data_dirs); + ca_data_dir *last_dir; + + unsigned n_theme_dir; + ca_bool_t loaded_fallback_theme; +}; + +int ca_get_data_home(char **e) { + const char *env, *subdir; + char *r; + ca_return_val_if_fail(e, CA_ERROR_INVALID); + + if ((env = getenv("XDG_DATA_HOME")) && *env == '/') + subdir = ""; + else if ((env = getenv("HOME")) && *env == '/') + subdir = "/.local/share"; + else { + *e = NULL; + return CA_SUCCESS; + } + + if (!(r = ca_new(char, strlen(env) + strlen(subdir) + 1))) + return CA_ERROR_OOM; + + sprintf(r, "%s%s", env, subdir); + *e = r; + + return CA_SUCCESS; +} + +static ca_bool_t data_dir_matches(ca_data_dir *d, const char*output_profile) { + ca_assert(d); + ca_assert(output_profile); + + /* We might want to add more elaborate matching here eventually */ + + if (!d->output_profile) + return TRUE; + + return ca_streq(d->output_profile, output_profile); +} + +static ca_data_dir* find_data_dir(ca_theme_data *t, const char *theme_name, const char *dir_name) { + ca_data_dir *d; + + ca_assert(t); + ca_assert(theme_name); + ca_assert(dir_name); + + for (d = t->data_dirs; d; d = d->next) + if (ca_streq(d->theme_name, theme_name) && + ca_streq(d->dir_name, dir_name)) + return d; + + return NULL; +} + +static int add_data_dir(ca_theme_data *t, const char *theme_name, const char *dir_name) { + ca_data_dir *d; + + ca_return_val_if_fail(t, CA_ERROR_INVALID); + ca_return_val_if_fail(theme_name, CA_ERROR_INVALID); + ca_return_val_if_fail(dir_name, CA_ERROR_INVALID); + + if (find_data_dir(t, theme_name, dir_name)) + return CA_SUCCESS; + + if (!(d = ca_new0(ca_data_dir, 1))) + return CA_ERROR_OOM; + + if (!(d->theme_name = ca_strdup(theme_name))) { + ca_free(d); + return CA_ERROR_OOM; + } + + if (!(d->dir_name = ca_strdup(dir_name))) { + ca_free(d->theme_name); + ca_free(d); + return CA_ERROR_OOM; + } + + CA_LLIST_INSERT_AFTER(ca_data_dir, t->data_dirs, t->last_dir, d); + t->last_dir = d; + + return CA_SUCCESS; +} + +static int load_theme_dir(ca_theme_data *t, const char *name); + +static int load_theme_path(ca_theme_data *t, const char *prefix, const char *name) { + char *fn, *inherits = NULL; + FILE *f; + ca_bool_t in_sound_theme_section = FALSE; + ca_data_dir *current_data_dir = NULL; + int ret; + + ca_return_val_if_fail(t, CA_ERROR_INVALID); + ca_return_val_if_fail(prefix, CA_ERROR_INVALID); + ca_return_val_if_fail(name, CA_ERROR_INVALID); + + if (!(fn = ca_new(char, strlen(prefix) + sizeof("/sounds/")-1 + strlen(name) + sizeof("/index.theme")))) + return CA_ERROR_OOM; + + sprintf(fn, "%s/sounds/%s/index.theme", prefix, name); + f = fopen(fn, "r"); + ca_free(fn); + + if (!f) { + if (errno == ENOENT) + return CA_ERROR_NOTFOUND; + + return CA_ERROR_SYSTEM; + } + + for (;;) { + char ln[1024]; + + if (!(fgets(ln, sizeof(ln), f))) { + + if (feof(f)) + break; + + ca_assert(ferror(f)); + ret = CA_ERROR_SYSTEM; + goto fail; + } + + ln[strcspn(ln, "\n\r#")] = 0; + + if (!ln[0]) + continue; + + if (ca_streq(ln, "[Sound Theme]")) { + in_sound_theme_section = TRUE; + current_data_dir = NULL; + continue; + } + + if (ln[0] == '[' && ln[strlen(ln)-1] == ']') { + char *d; + + if (!(d = ca_strndup(ln+1, strlen(ln)-2))) { + ret = CA_ERROR_OOM; + goto fail; + } + + current_data_dir = find_data_dir(t, name, d); + ca_free(d); + + in_sound_theme_section = FALSE; + continue; + } + + ca_assert(!in_sound_theme_section || !current_data_dir); + ca_assert(!current_data_dir || !in_sound_theme_section); + + if (in_sound_theme_section) { + + if (!strncmp(ln, "Inherits=", 9)) { + + if (inherits) { + ret = CA_ERROR_CORRUPT; + goto fail; + } + + if (!(inherits = ca_strdup(ln + 9))) { + ret = CA_ERROR_OOM; + goto fail; + } + + continue; + } + + if (!strncmp(ln, "Directories=", 12)) { + char *d; + + d = ln+12; + for (;;) { + size_t k = strcspn(d, ", "); + + if (k > 0) { + char *p; + + if (!(p = ca_strndup(d, k))) { + ret = CA_ERROR_OOM; + goto fail; + } + + ret = add_data_dir(t, name, p); + ca_free(p); + + if (ret != CA_SUCCESS) + goto fail; + } + + if (d[k] == 0) + break; + + d += k+1; + } + + continue; + } + } + + if (current_data_dir) { + + if (!strncmp(ln, "OutputProfile=", 14)) { + + if (!current_data_dir->output_profile) { + + if (!(current_data_dir->output_profile = ca_strdup(ln+14))) { + ret = CA_ERROR_OOM; + goto fail; + } + + } else if (!ca_streq(current_data_dir->output_profile, ln+14)) { + ret = CA_ERROR_CORRUPT; + goto fail; + } + + continue; + } + } + } + + t->n_theme_dir ++; + + if (inherits) { + char *i = inherits; + for (;;) { + size_t k = strcspn(i, ", "); + + if (k > 0) { + char *p; + + if (!(p = ca_strndup(i, k))) { + ret = CA_ERROR_OOM; + goto fail; + } + + ret = load_theme_dir(t, p); + ca_free(p); + + if (ret != CA_SUCCESS) + goto fail; + } + + if (i[k] == 0) + break; + + i += k+1; + } + } + + ret = CA_SUCCESS; + +fail: + + ca_free(inherits); + fclose(f); + + return ret; +} + +const char *ca_get_data_dirs(void) { + const char *g; + + if (!(g = getenv("XDG_DATA_DIRS")) || *g == 0) + return "/usr/local/share:/usr/share"; + + return g; +} + +static int load_theme_dir(ca_theme_data *t, const char *name) { + int ret; + char *e; + const char *g; + + ca_return_val_if_fail(t, CA_ERROR_INVALID); + ca_return_val_if_fail(name, CA_ERROR_INVALID); + ca_return_val_if_fail(t->n_theme_dir < N_THEME_DIR_MAX, CA_ERROR_CORRUPT); + + if (ca_streq(name, FALLBACK_THEME)) + t->loaded_fallback_theme = TRUE; + + if ((ret = ca_get_data_home(&e)) < 0) + return ret; + + if (e) { + ret = load_theme_path(t, e, name); + ca_free(e); + + if (ret != CA_ERROR_NOTFOUND) + return ret; + } + + g = ca_get_data_dirs(); + + for (;;) { + size_t k; + + k = strcspn(g, ":"); + + if (g[0] == '/' && k > 0) { + char *p; + + if (!(p = ca_strndup(g, k))) + return CA_ERROR_OOM; + + ret = load_theme_path(t, p, name); + ca_free(p); + + if (ret != CA_ERROR_NOTFOUND) + return ret; + } + + if (g[k] == 0) + break; + + g += k+1; + } + + return CA_ERROR_NOTFOUND; +} + +static int load_theme_data(ca_theme_data **_t, const char *name) { + ca_theme_data *t; + int ret; + + ca_return_val_if_fail(_t, CA_ERROR_INVALID); + ca_return_val_if_fail(name, CA_ERROR_INVALID); + + if (*_t) + if (ca_streq((*_t)->name, name)) + return CA_SUCCESS; + + if (!(t = ca_new0(ca_theme_data, 1))) + return CA_ERROR_OOM; + + if (!(t->name = ca_strdup(name))) { + ret = CA_ERROR_OOM; + goto fail; + } + + if ((ret = load_theme_dir(t, name)) < 0) + goto fail; + + /* The fallback theme may intentionally not exist so ignore failure */ + if (!t->loaded_fallback_theme) + load_theme_dir(t, FALLBACK_THEME); + + if (*_t) + ca_theme_data_free(*_t); + + *_t = t; + + return CA_SUCCESS; + +fail: + + if (t) + ca_theme_data_free(t); + + return ret; +} + +static int find_sound_for_suffix( + ca_sound_file **f, + ca_sound_file_open_callback_t sfopen, + char **sound_path, + const char *theme_name, + const char *name, + const char *path, + const char *suffix, + const char *locale, + const char *subdir) { + + char *fn; + int ret; + + ca_return_val_if_fail(f, CA_ERROR_INVALID); + ca_return_val_if_fail(sfopen, CA_ERROR_INVALID); + ca_return_val_if_fail(name, CA_ERROR_INVALID); + ca_return_val_if_fail(path, CA_ERROR_INVALID); + ca_return_val_if_fail(path[0] == '/', CA_ERROR_INVALID); + + if (!(fn = ca_sprintf_malloc("%s%s%s%s%s%s%s/%s%s", + path, + theme_name ? "/" : "", + theme_name ? theme_name : "", + subdir ? "/" : "", + subdir ? subdir : "", + locale ? "/" : "", + locale ? locale : "", + name, suffix))) + return CA_ERROR_OOM; + + if (ca_streq(suffix, ".disabled")) { + + if (access(fn, F_OK) == 0) + ret = CA_ERROR_DISABLED; + else + ret = errno == ENOENT ? CA_ERROR_NOTFOUND : CA_ERROR_SYSTEM; + + } else + ret = sfopen(f, fn); + + if (ret == CA_SUCCESS && sound_path) + *sound_path = fn; + else + ca_free(fn); + + return ret; +} + +static int find_sound_in_locale( + ca_sound_file **f, + ca_sound_file_open_callback_t sfopen, + char **sound_path, + const char *theme_name, + const char *name, + const char *path, + const char *locale, + const char *subdir) { + + int ret; + char *p; + + ca_return_val_if_fail(f, CA_ERROR_INVALID); + ca_return_val_if_fail(sfopen, CA_ERROR_INVALID); + ca_return_val_if_fail(name && *name, CA_ERROR_INVALID); + ca_return_val_if_fail(path, CA_ERROR_INVALID); + ca_return_val_if_fail(path[0] == '/', CA_ERROR_INVALID); + + if (!(p = ca_new(char, strlen(path) + sizeof("/sounds")))) + return CA_ERROR_OOM; + + sprintf(p, "%s/sounds", path); + + if ((ret = find_sound_for_suffix(f, sfopen, sound_path, theme_name, name, p, ".disabled", locale, subdir)) == CA_ERROR_NOTFOUND) + if ((ret = find_sound_for_suffix(f, sfopen, sound_path,theme_name, name, p, ".oga", locale, subdir)) == CA_ERROR_NOTFOUND) + if ((ret = find_sound_for_suffix(f, sfopen, sound_path,theme_name, name, p, ".ogg", locale, subdir)) == CA_ERROR_NOTFOUND) + ret = find_sound_for_suffix(f, sfopen, sound_path,theme_name, name, p, ".wav", locale, subdir); + + ca_free(p); + + return ret; +} + +static int find_sound_for_locale( + ca_sound_file **f, + ca_sound_file_open_callback_t sfopen, + char **sound_path, + const char *theme_name, + const char *name, + const char *path, + const char *locale, + const char *subdir) { + + const char *e; + int ret; + + ca_return_val_if_fail(f, CA_ERROR_INVALID); + ca_return_val_if_fail(sfopen, CA_ERROR_INVALID); + ca_return_val_if_fail(name && *name, CA_ERROR_INVALID); + ca_return_val_if_fail(path, CA_ERROR_INVALID); + ca_return_val_if_fail(locale, CA_ERROR_INVALID); + + /* First, try the locale def itself */ + if ((ret = find_sound_in_locale(f, sfopen, sound_path, theme_name, name, path, locale, subdir)) != CA_ERROR_NOTFOUND) + return ret; + + /* Then, try to truncate at the @ */ + if ((e = strchr(locale, '@'))) { + char *t; + + if (!(t = ca_strndup(locale, (size_t) (e - locale)))) + return CA_ERROR_OOM; + + ret = find_sound_in_locale(f, sfopen, sound_path, theme_name, name, path, t, subdir); + ca_free(t); + + if (ret != CA_ERROR_NOTFOUND) + return ret; + } + + /* Followed by truncating at the _ */ + if ((e = strchr(locale, '_'))) { + char *t; + + if (!(t = ca_strndup(locale, (size_t) (e - locale)))) + return CA_ERROR_OOM; + + ret = find_sound_in_locale(f, sfopen, sound_path, theme_name, name, path, t, subdir); + ca_free(t); + + if (ret != CA_ERROR_NOTFOUND) + return ret; + } + + /* Then, try "C" as fallback locale */ + if (strcmp(locale, "C")) + if ((ret = find_sound_in_locale(f, sfopen, sound_path, theme_name, name, path, "C", subdir)) != CA_ERROR_NOTFOUND) + return ret; + + /* Try without locale */ + return find_sound_in_locale(f, sfopen, sound_path, theme_name, name, path, NULL, subdir); +} + +static int find_sound_for_name( + ca_sound_file **f, + ca_sound_file_open_callback_t sfopen, + char **sound_path, + const char *theme_name, + const char *name, + const char *path, + const char *locale, + const char *subdir) { + + int ret; + const char *k; + + ca_return_val_if_fail(f, CA_ERROR_INVALID); + ca_return_val_if_fail(sfopen, CA_ERROR_INVALID); + ca_return_val_if_fail(name && *name, CA_ERROR_INVALID); + + if ((ret = find_sound_for_locale(f, sfopen, sound_path, theme_name, name, path, locale, subdir)) != CA_ERROR_NOTFOUND) + return ret; + + k = strchr(name, 0); + for (;;) { + char *n; + + do { + k--; + + if (k <= name) + return CA_ERROR_NOTFOUND; + + } while (*k != '-'); + + if (!(n = ca_strndup(name, (size_t) (k-name)))) + return CA_ERROR_OOM; + + if ((ret = find_sound_for_locale(f, sfopen, sound_path, theme_name, n, path, locale, subdir)) != CA_ERROR_NOTFOUND) { + ca_free(n); + return ret; + } + + ca_free(n); + } +} + +static int find_sound_in_subdir( + ca_sound_file **f, + ca_sound_file_open_callback_t sfopen, + char **sound_path, + const char *theme_name, + const char *name, + const char *locale, + const char *subdir) { + + int ret; + char *e = NULL; + const char *g; + + ca_return_val_if_fail(f, CA_ERROR_INVALID); + ca_return_val_if_fail(sfopen, CA_ERROR_INVALID); + ca_return_val_if_fail(name, CA_ERROR_INVALID); + + if ((ret = ca_get_data_home(&e)) < 0) + return ret; + + if (e) { + ret = find_sound_for_name(f, sfopen, sound_path, theme_name, name, e, locale, subdir); + ca_free(e); + + if (ret != CA_ERROR_NOTFOUND) + return ret; + } + + g = ca_get_data_dirs(); + + for (;;) { + size_t k; + + k = strcspn(g, ":"); + + if (g[0] == '/' && k > 0) { + char *p; + + if (!(p = ca_strndup(g, k))) + return CA_ERROR_OOM; + + ret = find_sound_for_name(f, sfopen, sound_path, theme_name, name, p, locale, subdir); + ca_free(p); + + if (ret != CA_ERROR_NOTFOUND) + return ret; + } + + if (g[k] == 0) + break; + + g += k+1; + } + + return CA_ERROR_NOTFOUND; +} + +static int find_sound_in_profile( + ca_sound_file **f, + ca_sound_file_open_callback_t sfopen, + char **sound_path, + ca_theme_data *t, + const char *name, + const char *locale, + const char *profile) { + + ca_data_dir *d; + + ca_return_val_if_fail(f, CA_ERROR_INVALID); + ca_return_val_if_fail(t, CA_ERROR_INVALID); + ca_return_val_if_fail(sfopen, CA_ERROR_INVALID); + ca_return_val_if_fail(name, CA_ERROR_INVALID); + + for (d = t->data_dirs; d; d = d->next) + if (data_dir_matches(d, profile)) { + int ret; + + if ((ret = find_sound_in_subdir(f, sfopen, sound_path, d->theme_name, name, locale, d->dir_name)) != CA_ERROR_NOTFOUND) + return ret; + } + + return CA_ERROR_NOTFOUND; +} + +static int find_sound_in_theme( + ca_sound_file **f, + ca_sound_file_open_callback_t sfopen, + char **sound_path, + ca_theme_data *t, + const char *name, + const char *locale, + const char *profile) { + + int ret; + + ca_return_val_if_fail(f, CA_ERROR_INVALID); + ca_return_val_if_fail(name, CA_ERROR_INVALID); + ca_return_val_if_fail(sfopen, CA_ERROR_INVALID); + ca_return_val_if_fail(profile, CA_ERROR_INVALID); + + if (t) { + /* First, try the profile def itself */ + if ((ret = find_sound_in_profile(f, sfopen, sound_path, t, name, locale, profile)) != CA_ERROR_NOTFOUND) + return ret; + + /* Then, fall back to stereo */ + if (!ca_streq(profile, DEFAULT_OUTPUT_PROFILE)) + if ((ret = find_sound_in_profile(f, sfopen, sound_path, t, name, locale, DEFAULT_OUTPUT_PROFILE)) != CA_ERROR_NOTFOUND) + return ret; + } + + /* And fall back to no profile */ + return find_sound_in_subdir(f, sfopen, sound_path, t ? t->name : NULL, name, locale, NULL); +} + +static int find_sound_for_theme( + ca_sound_file **f, + ca_sound_file_open_callback_t sfopen, + char **sound_path, + ca_theme_data **t, + const char *theme, + const char *name, + const char *locale, + const char *profile) { + + int ret; + + ca_return_val_if_fail(f, CA_ERROR_INVALID); + ca_return_val_if_fail(t, CA_ERROR_INVALID); + ca_return_val_if_fail(sfopen, CA_ERROR_INVALID); + ca_return_val_if_fail(theme, CA_ERROR_INVALID); + ca_return_val_if_fail(name && *name, CA_ERROR_INVALID); + ca_return_val_if_fail(locale, CA_ERROR_INVALID); + ca_return_val_if_fail(profile, CA_ERROR_INVALID); + + /* First, try in the theme itself, and if that fails the fallback theme */ + if ((ret = load_theme_data(t, theme)) == CA_ERROR_NOTFOUND) + if (!ca_streq(theme, FALLBACK_THEME)) + ret = load_theme_data(t, FALLBACK_THEME); + + if (ret == CA_SUCCESS) + if ((ret = find_sound_in_theme(f, sfopen, sound_path, *t, name, locale, profile)) != CA_ERROR_NOTFOUND) + return ret; + + /* Then, fall back to "unthemed" files */ + return find_sound_in_theme(f, sfopen, sound_path, NULL, name, locale, profile); +} + +int ca_lookup_sound_with_callback( + ca_sound_file **f, + ca_sound_file_open_callback_t sfopen, + char **sound_path, + ca_theme_data **t, + ca_proplist *cp, + ca_proplist *sp) { + int ret = CA_ERROR_INVALID; + const char *name, *fname; + + ca_return_val_if_fail(f, CA_ERROR_INVALID); + ca_return_val_if_fail(t, CA_ERROR_INVALID); + ca_return_val_if_fail(cp, CA_ERROR_INVALID); + ca_return_val_if_fail(sp, CA_ERROR_INVALID); + ca_return_val_if_fail(sfopen, CA_ERROR_INVALID); + + *f = NULL; + + if (sound_path) + *sound_path = NULL; + + ca_mutex_lock(cp->mutex); + ca_mutex_lock(sp->mutex); + + if ((name = ca_proplist_gets_unlocked(sp, CA_PROP_EVENT_ID))) { + const char *theme, *locale, *profile; + + if (!(theme = ca_proplist_gets_unlocked(sp, CA_PROP_CANBERRA_XDG_THEME_NAME))) + if (!(theme = ca_proplist_gets_unlocked(cp, CA_PROP_CANBERRA_XDG_THEME_NAME))) + theme = DEFAULT_THEME; + + if (!(locale = ca_proplist_gets_unlocked(sp, CA_PROP_MEDIA_LANGUAGE))) + if (!(locale = ca_proplist_gets_unlocked(sp, CA_PROP_APPLICATION_LANGUAGE))) + if (!(locale = ca_proplist_gets_unlocked(cp, CA_PROP_MEDIA_LANGUAGE))) + if (!(locale = ca_proplist_gets_unlocked(cp, CA_PROP_APPLICATION_LANGUAGE))) + if (!(locale = setlocale(LC_MESSAGES, NULL))) + locale = "C"; + + if (!(profile = ca_proplist_gets_unlocked(sp, CA_PROP_CANBERRA_XDG_THEME_OUTPUT_PROFILE))) + if (!(profile = ca_proplist_gets_unlocked(cp, CA_PROP_CANBERRA_XDG_THEME_OUTPUT_PROFILE))) + profile = DEFAULT_OUTPUT_PROFILE; + +#ifdef HAVE_CACHE + if ((ret = ca_cache_lookup_sound(f, sfopen, sound_path, theme, name, locale, profile)) >= 0) { + + /* This entry is available in the cache, let's transform + * negative cache entries to CA_ERROR_NOTFOUND */ + + if (!*f) + ret = CA_ERROR_NOTFOUND; + + } else { + char *spath = NULL; + + /* Either this entry was not available in the database, + * neither positive nor negative, or the database was + * corrupt, or it was out-of-date. In all cases try to + * find the entry manually. */ + + if ((ret = find_sound_for_theme(f, sfopen, sound_path ? sound_path : &spath, t, theme, name, locale, profile)) >= 0) + /* Ok, we found it. Let's update the cache */ + ca_cache_store_sound(theme, name, locale, profile, sound_path ? *sound_path : spath); + else if (ret == CA_ERROR_NOTFOUND) + /* Doesn't seem to be around, let's create a negative cache entry */ + ca_cache_store_sound(theme, name, locale, profile, NULL); + + ca_free(spath); + } + +#else + ret = find_sound_for_theme(f, sfopen, sound_path, t, theme, name, locale, profile); +#endif + } + + if (ret == CA_ERROR_NOTFOUND || !name) { + if ((fname = ca_proplist_gets_unlocked(sp, CA_PROP_MEDIA_FILENAME))) + ret = sfopen(f, fname); + } + + ca_mutex_unlock(cp->mutex); + ca_mutex_unlock(sp->mutex); + + return ret; +} + +int ca_lookup_sound( + ca_sound_file **f, + char **sound_path, + ca_theme_data **t, + ca_proplist *cp, + ca_proplist *sp) { + + return ca_lookup_sound_with_callback(f, ca_sound_file_open, sound_path, t, cp, sp); +} + +void ca_theme_data_free(ca_theme_data *t) { + ca_assert(t); + + while (t->data_dirs) { + ca_data_dir *d = t->data_dirs; + + CA_LLIST_REMOVE(ca_data_dir, t->data_dirs, d); + + ca_free(d->theme_name); + ca_free(d->dir_name); + ca_free(d->output_profile); + ca_free(d); + } + + ca_free(t->name); + ca_free(t); +} diff --git a/.flatpak-builder/cache/objects/9d/51c1f6b733bb74c8c484db9915250f708835c689a8ddd99e85814e40262891.dirtree b/.flatpak-builder/cache/objects/9d/51c1f6b733bb74c8c484db9915250f708835c689a8ddd99e85814e40262891.dirtree new file mode 100644 index 0000000..069550b Binary files /dev/null and b/.flatpak-builder/cache/objects/9d/51c1f6b733bb74c8c484db9915250f708835c689a8ddd99e85814e40262891.dirtree differ diff --git a/.flatpak-builder/cache/objects/9d/5d4032fcb25ef32559df415119c38a85920be15078a9810cd87564d4dc8241.file b/.flatpak-builder/cache/objects/9d/5d4032fcb25ef32559df415119c38a85920be15078a9810cd87564d4dc8241.file new file mode 100644 index 0000000..78d9c67 --- /dev/null +++ b/.flatpak-builder/cache/objects/9d/5d4032fcb25ef32559df415119c38a85920be15078a9810cd87564d4dc8241.file @@ -0,0 +1,57 @@ +# gtk_combo_box_text.py +# +# Copyright 2021 James Westman +# +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation; either version 3 of the +# License, or (at your option) any later version. +# +# This file is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program. If not, see . +# +# SPDX-License-Identifier: LGPL-3.0-or-later + + +from .gobject_object import ObjectContent, validate_parent_type +from .values import StringValue +from .common import * + + +class Item(AstNode): + grammar = StringValue + + @property + def child(self) -> StringValue: + return self.children[StringValue][0] + + +class ExtStringListStrings(AstNode): + grammar = [ + Keyword("strings"), + "[", + Delimited(Item, ","), + "]", + ] + + @validate("items") + def container_is_string_list(self): + validate_parent_type(self, "Gtk", "StringList", "StringList items") + + @validate("strings") + def unique_in_parent(self): + self.validate_unique_in_parent("Duplicate strings block") + + +@completer( + applies_in=[ObjectContent], + applies_in_subclass=("Gtk", "StringList"), + matches=new_statement_patterns, +) +def strings_completer(ast_node, match_variables): + yield Completion("strings", CompletionItemKind.Snippet, snippet="strings [$0]") diff --git a/.flatpak-builder/cache/objects/9d/5db4b9ff9bc68cba89d19935947afa815cf4022d4a656891e4ddbfccef62fa.file b/.flatpak-builder/cache/objects/9d/5db4b9ff9bc68cba89d19935947afa815cf4022d4a656891e4ddbfccef62fa.file new file mode 100644 index 0000000..e243b5e Binary files /dev/null and b/.flatpak-builder/cache/objects/9d/5db4b9ff9bc68cba89d19935947afa815cf4022d4a656891e4ddbfccef62fa.file differ diff --git a/.flatpak-builder/cache/objects/9d/60e67ebbf62429c6e075579c2024abd1720a0d5fe8232d0e28890ed98f172a.file b/.flatpak-builder/cache/objects/9d/60e67ebbf62429c6e075579c2024abd1720a0d5fe8232d0e28890ed98f172a.file new file mode 100644 index 0000000..1928576 --- /dev/null +++ b/.flatpak-builder/cache/objects/9d/60e67ebbf62429c6e075579c2024abd1720a0d5fe8232d0e28890ed98f172a.file @@ -0,0 +1,335 @@ +/* GDA common library + * Copyright (C) 2008 The GNOME Foundation. + * + * AUTHORS: + * Johannes Schmid + * Vivien Malerba + * + * This Library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This Library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this Library; see the file COPYING.LIB. If not, + * write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +#define G_LOG_DOMAIN "GDA-custom-marshal" + +#include + + +/* These marshallers are hardcoded here because glib-genmarshal does not support the marshalled types */ + +void +_gda_marshal_VOID__GTYPE_GTYPE (GClosure *closure, + GValue *return_value G_GNUC_UNUSED, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint G_GNUC_UNUSED, + gpointer marshal_data) +{ + typedef void (*GMarshalFunc_VOID__GTYPE_GTYPE) (gpointer data1, + GType arg_1, + GType arg_2, + gpointer data2); + register GMarshalFunc_VOID__GTYPE_GTYPE callback; + register GCClosure *cc = (GCClosure*) closure; + register gpointer data1, data2; + + g_return_if_fail (n_param_values == 3); + + if (G_CCLOSURE_SWAP_DATA (closure)) { + data1 = closure->data; + data2 = g_value_peek_pointer (param_values + 0); + } + else { + data1 = g_value_peek_pointer (param_values + 0); + data2 = closure->data; + } + callback = (GMarshalFunc_VOID__GTYPE_GTYPE) (marshal_data ? marshal_data : cc->callback); + + callback (data1, + g_value_get_gtype (param_values + 1), + g_value_get_gtype (param_values + 2), + data2); +} + +void +_gda_marshal_ERROR__OBJECT_VALUE (GClosure *closure, + GValue *return_value G_GNUC_UNUSED, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint G_GNUC_UNUSED, + gpointer marshal_data) +{ + typedef GError *(*GMarshalFunc_ERROR__OBJECT_VALUE) (gpointer data1, + gpointer arg_1, + gpointer arg_2, + gpointer data2); + register GMarshalFunc_ERROR__OBJECT_VALUE callback; + register GCClosure *cc = (GCClosure*) closure; + register gpointer data1, data2; + GError *v_return; + + g_return_if_fail (n_param_values == 3); + + if (G_CCLOSURE_SWAP_DATA (closure)) { + data1 = closure->data; + data2 = g_value_peek_pointer (param_values + 0); + } + else { + data1 = g_value_peek_pointer (param_values + 0); + data2 = closure->data; + } + callback = (GMarshalFunc_ERROR__OBJECT_VALUE) (marshal_data ? marshal_data : cc->callback); + + v_return = callback (data1, + g_value_get_object (param_values + 1), + g_value_get_boxed (param_values + 2), + data2); + g_value_take_boxed (return_value, v_return); +} + +void +_gda_marshal_VOID__OBJECT_STRING_VALUE (GClosure *closure, + GValue *return_value G_GNUC_UNUSED, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint G_GNUC_UNUSED, + gpointer marshal_data) +{ + typedef void (*GMarshalFunc_VOID__OBJECT_STRING_VALUE) (gpointer data1, + gpointer arg_1, + gpointer arg_2, + gpointer arg_3, + gpointer data2); + register GMarshalFunc_VOID__OBJECT_STRING_VALUE callback; + register GCClosure *cc = (GCClosure*) closure; + register gpointer data1, data2; + + g_return_if_fail (n_param_values == 4); + + if (G_CCLOSURE_SWAP_DATA (closure)) { + data1 = closure->data; + data2 = g_value_peek_pointer (param_values + 0); + } + else { + data1 = g_value_peek_pointer (param_values + 0); + data2 = closure->data; + } + callback = (GMarshalFunc_VOID__OBJECT_STRING_VALUE) (marshal_data ? marshal_data : cc->callback); + + callback (data1, + g_value_get_object (param_values + 1), + (gpointer) g_value_get_string (param_values + 2), + g_value_get_boxed (param_values + 3), + data2); +} + +void +_gda_marshal_ERROR__VOID (GClosure *closure, + GValue *return_value G_GNUC_UNUSED, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint G_GNUC_UNUSED, + gpointer marshal_data) +{ + typedef GError *(*GMarshalFunc_ERROR__VOID) (gpointer data1, + gpointer data2); + register GMarshalFunc_ERROR__VOID callback; + register GCClosure *cc = (GCClosure*) closure; + register gpointer data1, data2; + GError *v_return; + + g_return_if_fail (n_param_values == 1); + + if (G_CCLOSURE_SWAP_DATA (closure)) { + data1 = closure->data; + data2 = g_value_peek_pointer (param_values + 0); + } + else { + data1 = g_value_peek_pointer (param_values + 0); + data2 = closure->data; + } + callback = (GMarshalFunc_ERROR__VOID) (marshal_data ? marshal_data : cc->callback); + + v_return = callback (data1, data2); + g_value_take_boxed (return_value, v_return); +} + +void +_gda_marshal_VOID__STRING_VALUE (GClosure *closure, + GValue *return_value G_GNUC_UNUSED, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint G_GNUC_UNUSED, + gpointer marshal_data) +{ + typedef void (*GMarshalFunc_VOID__STRING_VALUE) (gpointer data1, + gpointer arg_1, + gpointer arg_2, + gpointer data2); + register GMarshalFunc_VOID__STRING_VALUE callback; + register GCClosure *cc = (GCClosure*) closure; + register gpointer data1, data2; + + g_return_if_fail (n_param_values == 3); + + if (G_CCLOSURE_SWAP_DATA (closure)) { + data1 = closure->data; + data2 = g_value_peek_pointer (param_values + 0); + } + else { + data1 = g_value_peek_pointer (param_values + 0); + data2 = closure->data; + } + callback = (GMarshalFunc_VOID__STRING_VALUE) (marshal_data ? marshal_data : cc->callback); + + callback (data1, + (gpointer) g_value_get_string (param_values + 1), + g_value_get_boxed (param_values + 2), + data2); +} + +void +_gda_marshal_ERROR__VALUE (GClosure *closure, + GValue *return_value G_GNUC_UNUSED, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint G_GNUC_UNUSED, + gpointer marshal_data) +{ + typedef GError *(*GMarshalFunc_ERROR__VALUE) (gpointer data1, + gpointer arg_1, + gpointer data2); + register GMarshalFunc_ERROR__VALUE callback; + register GCClosure *cc = (GCClosure*) closure; + register gpointer data1, data2; + GError *v_return; + + g_return_if_fail (n_param_values == 2); + + if (G_CCLOSURE_SWAP_DATA (closure)) { + data1 = closure->data; + data2 = g_value_peek_pointer (param_values + 0); + } + else { + data1 = g_value_peek_pointer (param_values + 0); + data2 = closure->data; + } + callback = (GMarshalFunc_ERROR__VALUE) (marshal_data ? marshal_data : cc->callback); + + v_return = callback (data1, + g_value_get_boxed (param_values + 1), + data2); + g_value_take_boxed (return_value, v_return); +} + +void +_gda_marshal_ERROR__INT_INT (GClosure *closure, + GValue *return_value G_GNUC_UNUSED, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint G_GNUC_UNUSED, + gpointer marshal_data) +{ + typedef GError *(*GMarshalFunc_ERROR__INT_INT) (gpointer data1, + gint arg_1, + gint arg_2, + gpointer data2); + register GMarshalFunc_ERROR__INT_INT callback; + register GCClosure *cc = (GCClosure*) closure; + register gpointer data1, data2; + GError *v_return; + + g_return_if_fail (n_param_values == 3); + + if (G_CCLOSURE_SWAP_DATA (closure)) { + data1 = closure->data; + data2 = g_value_peek_pointer (param_values + 0); + } + else { + data1 = g_value_peek_pointer (param_values + 0); + data2 = closure->data; + } + callback = (GMarshalFunc_ERROR__INT_INT) (marshal_data ? marshal_data : cc->callback); + + v_return = callback (data1, + g_value_get_int (param_values + 1), + g_value_get_int (param_values + 2), + data2); + g_value_take_boxed (return_value, v_return); +} + +void +_gda_marshal_VOID__SLIST (GClosure *closure, + GValue *return_value G_GNUC_UNUSED, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint G_GNUC_UNUSED, + gpointer marshal_data) +{ + typedef void (*GMarshalFunc_VOID__SLIST) (gpointer data1, + gpointer arg_1, + gpointer data2); + register GMarshalFunc_VOID__SLIST callback; + register GCClosure *cc = (GCClosure*) closure; + register gpointer data1, data2; + + g_return_if_fail (n_param_values == 2); + + if (G_CCLOSURE_SWAP_DATA (closure)) { + data1 = closure->data; + data2 = g_value_peek_pointer (param_values + 0); + } + else { + data1 = g_value_peek_pointer (param_values + 0); + data2 = closure->data; + } + callback = (GMarshalFunc_VOID__SLIST) (marshal_data ? marshal_data : cc->callback); + + callback (data1, + g_value_get_pointer (param_values + 1), + data2); +} + +void +_gda_marshal_ERROR__METACONTEXT (GClosure *closure, + GValue *return_value G_GNUC_UNUSED, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint G_GNUC_UNUSED, + gpointer marshal_data) +{ + typedef GError *(*GMarshalFunc_ERROR__METACONTEXT) (gpointer data1, + gpointer arg_1, + gpointer data2); + register GMarshalFunc_ERROR__METACONTEXT callback; + register GCClosure *cc = (GCClosure*) closure; + register gpointer data1, data2; + GError *v_return; + + g_return_if_fail (n_param_values == 2); + + if (G_CCLOSURE_SWAP_DATA (closure)) { + data1 = closure->data; + data2 = g_value_peek_pointer (param_values + 0); + } + else { + data1 = g_value_peek_pointer (param_values + 0); + data2 = closure->data; + } + callback = (GMarshalFunc_ERROR__METACONTEXT) (marshal_data ? marshal_data : cc->callback); + + v_return = callback (data1, + g_value_get_pointer (param_values + 1), + data2); + g_value_take_boxed (return_value, v_return); +} diff --git a/.flatpak-builder/cache/objects/9e/52c4de5d566a18bd04d37fd4d2c97d964409a800b42a86c8e4468cb8d75d96.file b/.flatpak-builder/cache/objects/9e/52c4de5d566a18bd04d37fd4d2c97d964409a800b42a86c8e4468cb8d75d96.file new file mode 100644 index 0000000..61a6dff --- /dev/null +++ b/.flatpak-builder/cache/objects/9e/52c4de5d566a18bd04d37fd4d2c97d964409a800b42a86c8e4468cb8d75d96.file @@ -0,0 +1,143 @@ +/* + * Copyright (C) 2007 - 2014 Vivien Malerba + * Copyright (C) 2010 David King + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include +#include +#include "gda-vprovider-hub.h" +#include "gda-vconnection-hub.h" +#include +#include + +typedef struct { + int foo; +} GdaVproviderHubPrivate; + +/* properties */ +enum +{ + PROP_0, +}; + +static void gda_vprovider_hub_class_init (GdaVproviderHubClass *klass); +static void gda_vprovider_hub_init (GdaVproviderHub *prov); + +G_DEFINE_TYPE_WITH_PRIVATE (GdaVproviderHub, gda_vprovider_hub, GDA_TYPE_VPROVIDER_DATA_MODEL) + +static GdaConnection *gda_vprovider_hub_create_connection (GdaServerProvider *provider); +static gboolean gda_vprovider_hub_close_connection (GdaServerProvider *provider, GdaConnection *cnc); +static const gchar *gda_vprovider_hub_get_name (GdaServerProvider *provider); + + +/* + * GdaVproviderHub class implementation + */ +static GdaServerProviderBase hub_base_functions = { + gda_vprovider_hub_get_name, + NULL, + NULL, + NULL, + NULL, + gda_vprovider_hub_create_connection, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + gda_vprovider_hub_close_connection, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + + NULL, NULL, NULL, NULL, /* padding */ +}; + +static void +gda_vprovider_hub_class_init (GdaVproviderHubClass *klass) +{ + /* set virtual functions */ + gda_server_provider_set_impl_functions (GDA_SERVER_PROVIDER_CLASS (klass), + GDA_SERVER_PROVIDER_FUNCTIONS_BASE, + (gpointer) &hub_base_functions); +} + + +static void +gda_vprovider_hub_init (GdaVproviderHub *prov) +{ +} + +/** + * gda_vprovider_hub_new + * + * Creates a new GdaVirtualProvider object which allows one to + * add and remove GdaDataModel objects as tables within a connection + * + * Returns: a new #GdaVirtualProvider object. + */ +GdaVirtualProvider * +gda_vprovider_hub_new (void) +{ + GdaVirtualProvider *provider; + + provider = g_object_new (gda_vprovider_hub_get_type (), NULL); + return provider; +} + +static GdaConnection * +gda_vprovider_hub_create_connection (GdaServerProvider *provider) +{ + GdaConnection *cnc; + g_return_val_if_fail (GDA_IS_VPROVIDER_HUB (provider), NULL); + + cnc = g_object_new (GDA_TYPE_VCONNECTION_HUB, "provider", provider, NULL); + + return cnc; +} + +static gboolean +gda_vprovider_hub_close_connection (GdaServerProvider *provider, GdaConnection *cnc) +{ + g_return_val_if_fail (GDA_IS_VPROVIDER_HUB (provider), FALSE); + g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE); + + GdaServerProviderBase *parent_functions; + parent_functions = gda_server_provider_get_impl_functions_for_class (gda_vprovider_hub_parent_class, GDA_SERVER_PROVIDER_FUNCTIONS_BASE); + return parent_functions->close_connection (provider, cnc); +} + +static const gchar * +gda_vprovider_hub_get_name (G_GNUC_UNUSED GdaServerProvider *provider) +{ + return "Virtual hub"; +} diff --git a/.flatpak-builder/cache/objects/9e/6bcf17349a7e39c23eec30ac49e634146705eb165a15b80f2162ed0da7b07a.file b/.flatpak-builder/cache/objects/9e/6bcf17349a7e39c23eec30ac49e634146705eb165a15b80f2162ed0da7b07a.file new file mode 100644 index 0000000..3e02040 --- /dev/null +++ b/.flatpak-builder/cache/objects/9e/6bcf17349a7e39c23eec30ac49e634146705eb165a15b80f2162ed0da7b07a.file @@ -0,0 +1,197 @@ +/*-*- Mode: C; c-basic-offset: 8 -*-*/ + +/*** + This file is part of libcanberra. + + Copyright 2008 Lennart Poettering + + libcanberra is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation, either version 2.1 of the + License, or (at your option) any later version. + + libcanberra is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with libcanberra. If not, see + . +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include +#include + +static int ret = 0; +static ca_proplist *proplist = NULL; +static int n_loops = 1; + +static void callback(ca_context *c, uint32_t id, int error, void *userdata); + +static gboolean idle_quit(gpointer userdata) { + gtk_main_quit(); + return FALSE; +} + +static gboolean idle_play(gpointer userdata) { + int r; + + g_assert(n_loops > 1); + + n_loops--; + + r = ca_context_play_full(ca_gtk_context_get(), 1, proplist, callback, NULL); + + if (r < 0) { + g_printerr("Failed to play sound: %s\n", ca_strerror(r)); + ret = 1; + gtk_main_quit(); + } + + return FALSE; +} + +static void callback(ca_context *c, uint32_t id, int error, void *userdata) { + + if (error < 0) { + g_printerr("Failed to play sound (callback): %s\n", ca_strerror(error)); + ret = 1; + + } else if (n_loops > 1) { + /* So, why don't we call ca_context_play_full() here directly? + -- Because the context this callback is called from is + explicitly documented as undefined and no libcanberra function + may be called from it. */ + + g_idle_add(idle_play, NULL); + return; + } + + /* So, why don't we call gtk_main_quit() here directly? -- Because + * otherwise we might end up with a small race condition: this + * callback might get called before the main loop actually started + * running */ + g_idle_add(idle_quit, NULL); +} + +static GQuark error_domain(void) { + return g_quark_from_static_string("canberra-error-quark"); +} + +static gboolean property_callback( + const gchar *option_name, + const gchar *value, + gpointer data, + GError **error) { + + const char *equal; + char *t; + + if (!(equal = strchr(value, '='))) { + g_set_error(error, error_domain(), 0, "Property lacks '='."); + return FALSE; + } + + t = g_strndup(value, equal - value); + + if (ca_proplist_sets(proplist, t, equal + 1) < 0) { + g_set_error(error, error_domain(), 0, "Invalid property."); + g_free(t); + return FALSE; + } + + g_free(t); + return TRUE; +} + +int main (int argc, char *argv[]) { + GOptionContext *oc; + static gchar *event_id = NULL, *filename = NULL, *event_description = NULL, *cache_control = NULL, *volume = NULL; + int r; + static gboolean version = FALSE; + GError *error = NULL; + + static const GOptionEntry options[] = { + { "version", 'v', 0, G_OPTION_ARG_NONE, &version, "Display version number and quit", NULL }, + { "id", 'i', 0, G_OPTION_ARG_STRING, &event_id, "Event sound identifier", "STRING" }, + { "file", 'f', 0, G_OPTION_ARG_STRING, &filename, "Play file", "PATH" }, + { "description", 'd', 0, G_OPTION_ARG_STRING, &event_description, "Event sound description", "STRING" }, + { "cache-control", 'c', 0, G_OPTION_ARG_STRING, &cache_control, "Cache control (permanent, volatile, never)", "STRING" }, + { "loop", 'l', 0, G_OPTION_ARG_INT, &n_loops, "Loop how many times (detault: 1)", "INTEGER" }, + { "volume", 'V', 0, G_OPTION_ARG_STRING, &volume, "A floating point dB value for the sample volume (ex: 0.0)", "STRING" }, + { "property", 0, 0, G_OPTION_ARG_CALLBACK, (void*) property_callback, "An arbitrary property", "STRING" }, + { NULL, 0, 0, 0, NULL, NULL, NULL } + }; + + setlocale(LC_ALL, ""); + + g_type_init(); + + ca_proplist_create(&proplist); + + oc = g_option_context_new("- canberra-gtk-play"); + g_option_context_add_main_entries(oc, options, NULL); + g_option_context_add_group(oc, gtk_get_option_group(TRUE)); + g_option_context_set_help_enabled(oc, TRUE); + + if (!(g_option_context_parse(oc, &argc, &argv, &error))) { + g_print("Option parsing failed: %s\n", error->message); + return 1; + } + g_option_context_free(oc); + + if (version) { + g_print("canberra-gtk-play from %s\n", PACKAGE_STRING); + return 0; + } + + if (!event_id && !filename) { + g_printerr("No event id or file specified.\n"); + return 1; + } + + ca_context_change_props(ca_gtk_context_get(), + CA_PROP_APPLICATION_NAME, "canberra-gtk-play", + CA_PROP_APPLICATION_VERSION, PACKAGE_VERSION, + CA_PROP_APPLICATION_ID, "org.freedesktop.libcanberra.gtk-play", + NULL); + + if (event_id) + ca_proplist_sets(proplist, CA_PROP_EVENT_ID, event_id); + + if (filename) + ca_proplist_sets(proplist, CA_PROP_MEDIA_FILENAME, filename); + + if (cache_control) + ca_proplist_sets(proplist, CA_PROP_CANBERRA_CACHE_CONTROL, cache_control); + + if (event_description) + ca_proplist_sets(proplist, CA_PROP_EVENT_DESCRIPTION, event_description); + + if (volume) + ca_proplist_sets(proplist, CA_PROP_CANBERRA_VOLUME, volume); + + r = ca_context_play_full(ca_gtk_context_get(), 1, proplist, callback, NULL); + + if (r < 0) { + g_printerr("Failed to play sound: %s\n", ca_strerror(r)); + ret = 1; + goto finish; + } + + gtk_main(); + +finish: + + ca_proplist_destroy(proplist); + + return ret; +} diff --git a/.flatpak-builder/cache/objects/9e/8a20c5d74820db56f522f9bec05a1a520e466f0ec616c8d6b66f633e1ca70e.file b/.flatpak-builder/cache/objects/9e/8a20c5d74820db56f522f9bec05a1a520e466f0ec616c8d6b66f633e1ca70e.file new file mode 100644 index 0000000..a02e6c2 --- /dev/null +++ b/.flatpak-builder/cache/objects/9e/8a20c5d74820db56f522f9bec05a1a520e466f0ec616c8d6b66f633e1ca70e.file @@ -0,0 +1,37 @@ +/*-*- Mode: C; c-basic-offset: 8 -*-*/ + +#ifndef foocanberramutexhfoo +#define foocanberramutexhfoo + +/*** + This file is part of libcanberra. + + Copyright 2008 Lennart Poettering + + libcanberra is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation, either version 2.1 of the + License, or (at your option) any later version. + + libcanberra is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with libcanberra. If not, see + . +***/ + +#include "macro.h" + +typedef struct ca_mutex ca_mutex; + +ca_mutex* ca_mutex_new(void); +void ca_mutex_free(ca_mutex *m); + +void ca_mutex_lock(ca_mutex *m); +ca_bool_t ca_mutex_try_lock(ca_mutex *m); +void ca_mutex_unlock(ca_mutex *m); + +#endif diff --git a/.flatpak-builder/cache/objects/9e/a0408dbf9712bc34b216c273c0ed986b7a1e0dec703ea258850624778d986b.file b/.flatpak-builder/cache/objects/9e/a0408dbf9712bc34b216c273c0ed986b7a1e0dec703ea258850624778d986b.file new file mode 100644 index 0000000..52adcf5 --- /dev/null +++ b/.flatpak-builder/cache/objects/9e/a0408dbf9712bc34b216c273c0ed986b7a1e0dec703ea258850624778d986b.file @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2008 - 2014 Vivien Malerba + * Copyright (C) 2010 David King + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +#define G_LOG_DOMAIN "GDA-lockable" + +#include + +G_DEFINE_INTERFACE(GdaLockable, gda_lockable, G_TYPE_OBJECT) + +void +gda_lockable_default_init (GdaLockableInterface *iface) {} + +/** + * gda_lockable_lock: + * @lockable: a #GdaLockable object. + * + * Locks @lockable. If it is already locked by another thread, the current thread will block until it is unlocked + * by the other thread. + * + * Note: unlike g_mutex_lock(), this method recursive, which means a thread can lock @lockable several times + * (and has to unlock it as many times to actually unlock it). + */ +void +gda_lockable_lock (GdaLockable *lockable) +{ + g_return_if_fail (GDA_IS_LOCKABLE (lockable)); + GdaLockableInterface *iface = GDA_LOCKABLE_GET_IFACE (lockable); + if (iface->lock) + (iface->lock) (lockable); + else + g_warning ("Internal implementation error: %s() method not implemented\n", "lock"); +} + +/** + * gda_lockable_trylock: + * @lockable: a #GdaLockable object. + * + * Tries to lock @lockable. If it is already locked by another thread, then it immediately returns FALSE, otherwise + * it locks @lockable. + * + * Note: unlike g_mutex_lock(), this method recursive, which means a thread can lock @lockable several times + * (and has to unlock it as many times to actually unlock it). + * + * Returns: TRUE if the object has successfully been locked. + */ +gboolean +gda_lockable_trylock (GdaLockable *lockable) +{ + g_return_val_if_fail (GDA_IS_LOCKABLE (lockable), FALSE); + GdaLockableInterface *iface = GDA_LOCKABLE_GET_IFACE (lockable); + + if (iface->trylock) + return (iface->trylock) (lockable); + + g_warning ("Internal implementation error: %s() method not implemented\n", "trylock"); + return FALSE; +} + +/** + * gda_lockable_unlock: + * @lockable: a #GdaLockable object. + * + * Unlocks @lockable. This method should not be called if the current does not already holds a lock on @lockable (having + * used gda_lockable_lock() or gda_lockable_trylock()). + */ +void +gda_lockable_unlock (GdaLockable *lockable) +{ + g_return_if_fail (GDA_IS_LOCKABLE (lockable)); + GdaLockableInterface *iface = GDA_LOCKABLE_GET_IFACE (lockable); + + if (iface->unlock) + (iface->unlock) (lockable); + else + g_warning ("Internal implementation error: %s() method not implemented\n", "unlock"); +} diff --git a/.flatpak-builder/cache/objects/9f/2fc8f079503d0710b205e916fe89a58da6a0d7b825143155b4450d43228fd5.file b/.flatpak-builder/cache/objects/9f/2fc8f079503d0710b205e916fe89a58da6a0d7b825143155b4450d43228fd5.file new file mode 100644 index 0000000..ec56343 --- /dev/null +++ b/.flatpak-builder/cache/objects/9f/2fc8f079503d0710b205e916fe89a58da6a0d7b825143155b4450d43228fd5.file @@ -0,0 +1,167 @@ +/* + * Copyright (C) 2000 Reinhard Müller + * Copyright (C) 2000 - 2003 Rodrigo Moya + * Copyright (C) 2001 - 2013 Vivien Malerba + * Copyright (C) 2002 - 2003 Gonzalo Paniagua Javier + * Copyright (C) 2003 Laurent Sansonetti + * Copyright (C) 2003 Paisa Seeluangsawat + * Copyright (C) 2004 Alan Knowles + * Copyright (C) 2004 Dani Baeyens + * Copyright (C) 2005 Martin Schulze + * Copyright (C) 2008 Przemysław Grzegorczyk + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +#define G_LOG_DOMAIN "GDA-log" + +#include +#include +#include +#ifndef G_OS_WIN32 +#include +#endif +#include +#include +#include + +static GRecMutex gda_rmutex; +#define GDA_LOG_LOCK() g_rec_mutex_lock(&gda_rmutex) +#define GDA_LOG_UNLOCK() g_rec_mutex_unlock(&gda_rmutex) +static gboolean log_enabled = TRUE; +static gboolean log_opened = FALSE; + +/* + * Private functions + */ + +/** + * gda_log_enable: + * + * Enables GDA logs. + */ +void +gda_log_enable (void) +{ + GDA_LOG_LOCK (); + log_enabled = TRUE; + if (!log_opened) { +#ifndef G_OS_WIN32 + openlog (g_get_prgname (), LOG_CONS | LOG_NOWAIT | LOG_PID, LOG_USER); +#endif + log_opened = TRUE; + } + GDA_LOG_UNLOCK (); +} + +/** + * gda_log_disable: + * + * Disables GDA logs. + */ +void +gda_log_disable (void) +{ + GDA_LOG_LOCK (); + log_enabled = FALSE; + if (log_opened) { +#ifndef G_OS_WIN32 + closelog (); +#endif + log_opened = FALSE; + } + GDA_LOG_UNLOCK (); +} + +/** + * gda_log_is_enabled: + * + * Returns: whether GDA logs are enabled (%TRUE or %FALSE). + */ +gboolean +gda_log_is_enabled (void) +{ + return log_enabled; +} + +/** + * gda_log_message: + * @format: format string (see the printf(3) documentation). + * @...: arguments to insert in the message. + * + * Logs the given message in the GDA log file. + */ +void +gda_log_message (const gchar *format, ...) +{ + va_list args; + gchar *msg; + + g_return_if_fail (format != NULL); + + if (!log_enabled) + return; + + GDA_LOG_LOCK (); + if (!log_opened) + gda_log_enable (); + + /* build the message string */ + va_start (args, format); + msg = g_strdup_vprintf (format, args); + va_end (args); +#ifdef G_OS_WIN32 + g_log ("Gda", G_LOG_LEVEL_INFO, "%s", msg); +#else + syslog (LOG_USER | LOG_INFO, "%s", msg); +#endif + g_free (msg); + GDA_LOG_UNLOCK (); +} + +/** + * gda_log_error: + * @format: format string (see the printf(3) documentation). + * @...: arguments to insert in the error. + * + * Logs the given error in the GDA log file. + */ +void +gda_log_error (const gchar * format, ...) +{ + va_list args; + gchar *msg; + + g_return_if_fail (format != NULL); + + if (!log_enabled) + return; + + GDA_LOG_LOCK (); + if (!log_opened) + gda_log_enable (); + + /* build the message string */ + va_start (args, format); + msg = g_strdup_vprintf (format, args); + va_end (args); +#ifdef G_OS_WIN32 + g_log ("Gda", G_LOG_LEVEL_DEBUG, "%s", msg); +#else + syslog (LOG_USER | LOG_ERR, "%s", msg); +#endif + g_free (msg); + GDA_LOG_UNLOCK (); +} diff --git a/.flatpak-builder/cache/objects/9f/9f82608b298063d1477b5ed9bec23091b8a27ee95359f7c5bbaa9172391051.file b/.flatpak-builder/cache/objects/9f/9f82608b298063d1477b5ed9bec23091b8a27ee95359f7c5bbaa9172391051.file new file mode 100644 index 0000000..45e0caf --- /dev/null +++ b/.flatpak-builder/cache/objects/9f/9f82608b298063d1477b5ed9bec23091b8a27ee95359f7c5bbaa9172391051.file @@ -0,0 +1,99 @@ +/* + * gda-db-buildable.c + * + * Copyright (C) 2018 Pavlo Solntsev + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +#define G_LOG_DOMAIN "GDA-db-buildable" + +#include "gda-db-buildable.h" + +G_DEFINE_INTERFACE (GdaDbBuildable, gda_db_buildable, G_TYPE_OBJECT) + +/** + * SECTION:gda-db-buildable + * @title: GdaDbBuildable + * @short: Represents interface for parsing and writing xml nodes + * @see_also: #GdaDbTable, #GdaDbView + * @stability: Stable + * @include: libgda/gda-db-buildable.h + * + * #GdaDbBuildable represents an interface for writing and reading xml nodes. #GdaDbTable and + * #GdaDbView implement this interface. + */ + +static void +gda_db_buildable_default_init (GdaDbBuildableInterface *iface) +{ + /* add properties and signals to the interface here */ +} + +/** + * gda_db_buildable_parse_node: + * @self: an instance of #GdaDbBuildable where parsed data should be storred + * @node: a node to parse + * @error: (nullable): an object to store the error + * + * This method parse XML node and populate @self object. + * + * Returns: %TRUE on success, %FALSE if an error occurred + * Since: 6.0 + * Stability: stable + */ +gboolean +gda_db_buildable_parse_node (GdaDbBuildable *self, + xmlNodePtr node, + GError **error) +{ + GdaDbBuildableInterface *iface = NULL; + + g_return_val_if_fail (GDA_IS_DB_BUILDABLE (self), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + iface = GDA_DB_BUILDABLE_GET_IFACE (self); + g_return_val_if_fail (iface->parse_node != NULL, FALSE); + return iface->parse_node (self, node, error); +} + +/** + * gda_db_buildable_write_node: + * @self: an instance of #GdaDbBuildable where data should be taken + * @node: a node to write data in + * @error: (nullable): an object to store error + * + * Write content from the @self to the @node + * + * Returns: %TRUE on success, %FALSE if an error occurred + * Since: 6.0 + * Stability: stable + */ +gboolean +gda_db_buildable_write_node (GdaDbBuildable *self, + xmlNodePtr node, + GError **error) +{ + GdaDbBuildableInterface *iface; + + g_return_val_if_fail (GDA_IS_DB_BUILDABLE (self), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + iface = GDA_DB_BUILDABLE_GET_IFACE (self); + g_return_val_if_fail (iface->write_node != NULL, FALSE); + return iface->write_node (self, node, error); +} + + diff --git a/.flatpak-builder/cache/objects/9f/b5f9148298c83d0d7693cedf1f4089ede86d23e90aa151f5120aa2952d7217.file b/.flatpak-builder/cache/objects/9f/b5f9148298c83d0d7693cedf1f4089ede86d23e90aa151f5120aa2952d7217.file new file mode 100644 index 0000000..41b9a56 --- /dev/null +++ b/.flatpak-builder/cache/objects/9f/b5f9148298c83d0d7693cedf1f4089ede86d23e90aa151f5120aa2952d7217.file @@ -0,0 +1,365 @@ +/* + * Copyright (C) 2008 - 2015 Vivien Malerba + * Copyright (C) 2010 David King + * Copyright (C) 2010 Jonh Wendell + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include +#include +#include "gda-pstmt.h" +#include + +static void gda_pstmt_dispose (GObject *object); + +typedef struct { + GRecMutex mutex; + GWeakRef gda_stmt_ref; /* holds a weak reference to #GdaStatement, or %NULL */ + gchar *sql; /* actual SQL code used for this prepared statement, mem freed by GdaPStmt */ + GSList *param_ids; /* list of parameters' IDs (as gchar *), mem freed by GdaPStmt */ + + /* meta data */ + gint ncols; + GType *types; /* array of ncols types */ + GSList *tmpl_columns; /* list of #GdaColumn objects which data models created from this prep. statement can copy */ +} GdaPStmtPrivate; + +G_DEFINE_TYPE_WITH_PRIVATE (GdaPStmt, gda_pstmt, G_TYPE_OBJECT) + +static void +gda_pstmt_class_init (GdaPStmtClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + /* virtual functions */ + object_class->dispose = gda_pstmt_dispose; +} + +static void +gda_pstmt_init (GdaPStmt *pstmt) +{ + g_return_if_fail (GDA_IS_PSTMT (pstmt)); + GdaPStmtPrivate *priv = gda_pstmt_get_instance_private (pstmt); + g_rec_mutex_init (& priv->mutex); + g_weak_ref_init (&priv->gda_stmt_ref, NULL); + priv->sql = NULL; + priv->param_ids = NULL; + priv->ncols = -1; + priv->types = NULL; + priv->tmpl_columns = NULL; +} + +/* + * @stmt may be %NULL + */ +static void +gda_stmt_reset_cb (GdaStatement *stmt, GdaPStmt *pstmt) +{ + GdaPStmtPrivate *priv = gda_pstmt_get_instance_private (pstmt); + g_rec_mutex_lock (& priv->mutex); + if (stmt) { + g_object_ref (stmt); + g_signal_handlers_disconnect_by_func (G_OBJECT (stmt), + G_CALLBACK (gda_stmt_reset_cb), pstmt); + g_object_unref (stmt); + } + else { + GdaStatement *stm = g_weak_ref_get (& priv->gda_stmt_ref); + if (stm) { + g_signal_handlers_disconnect_by_func (G_OBJECT (stm), + G_CALLBACK (gda_stmt_reset_cb), pstmt); + g_object_unref (stm); + } + } + + g_weak_ref_set (& priv->gda_stmt_ref, NULL); + g_rec_mutex_unlock (& priv->mutex); +} + +static void +gda_pstmt_dispose (GObject *object) +{ + GdaPStmt *pstmt = (GdaPStmt *) object; + GdaPStmtPrivate *priv = gda_pstmt_get_instance_private (pstmt); + + gda_stmt_reset_cb (NULL, pstmt); + + /* free memory */ + g_rec_mutex_clear (& priv->mutex); + g_weak_ref_clear (&priv->gda_stmt_ref); + + if (priv->sql != NULL) { + g_free (priv->sql); + priv->sql = NULL; + } + if (priv->param_ids != NULL) { + g_slist_free_full (priv->param_ids, (GDestroyNotify) g_free); + priv->param_ids = NULL; + } + if (priv->types != NULL) { + g_free (priv->types); + priv->types = NULL; + } + if (priv->tmpl_columns != NULL) { + g_slist_free_full (priv->tmpl_columns, (GDestroyNotify) g_object_unref); + priv->tmpl_columns = NULL; + } + + /* chain to parent class */ + G_OBJECT_CLASS (gda_pstmt_parent_class)->dispose (object); +} + + +/** + * gda_pstmt_set_gda_statement: + * @pstmt: a #GdaPStmt object + * @stmt: (nullable): a #GdaStatement object, or %NULL + * + * Informs @pstmt that it corresponds to the preparation of the @stmt statement + */ +void +gda_pstmt_set_gda_statement (GdaPStmt *pstmt, GdaStatement *stmt) +{ + g_return_if_fail (GDA_IS_PSTMT (pstmt)); + g_return_if_fail (!stmt || GDA_IS_STATEMENT (stmt)); + GdaPStmtPrivate *priv = gda_pstmt_get_instance_private (pstmt); + + g_rec_mutex_lock (& priv->mutex); + g_object_ref (stmt); + + GdaStatement *estmt; + estmt = g_weak_ref_get (& priv->gda_stmt_ref); + if (estmt == stmt) { + if (estmt) + g_object_unref (estmt); + g_rec_mutex_unlock (& priv->mutex); + return; + } + + gda_stmt_reset_cb (NULL, pstmt); + + g_weak_ref_set (& priv->gda_stmt_ref, stmt); + g_signal_connect (G_OBJECT (stmt), "reset", G_CALLBACK (gda_stmt_reset_cb), pstmt); + g_object_unref (stmt); + g_rec_mutex_unlock (& priv->mutex); +} + +/** + * gda_pstmt_copy_contents: + * @src: a #GdaPStmt object + * @dest: a #GdaPStmt object + * + * Copies @src's data to @dest + */ +void +gda_pstmt_copy_contents (GdaPStmt *src, GdaPStmt *dest) +{ + GSList *list; + g_return_if_fail (GDA_IS_PSTMT (src)); + g_return_if_fail (GDA_IS_PSTMT (dest)); + GdaPStmtPrivate *priv = gda_pstmt_get_instance_private (src); + GdaPStmtPrivate *dpriv = gda_pstmt_get_instance_private (dest); + + g_rec_mutex_lock (& priv->mutex); + g_rec_mutex_lock (& dpriv->mutex); + + g_free (dpriv->sql); + dpriv->sql = NULL; + if (priv->sql) + dpriv->sql = g_strdup (priv->sql); + if (dpriv->param_ids) { + g_slist_free_full (dpriv->param_ids, (GDestroyNotify) g_free); + dpriv->param_ids = NULL; + } + for (list = priv->param_ids; list; list = list->next) + dpriv->param_ids = g_slist_append (dpriv->param_ids, g_strdup ((gchar *) list->data)); + dpriv->ncols = priv->ncols; + if (dpriv->types != NULL) { + g_free (dpriv->types); + } + dpriv->types = NULL; + if (priv->types) { + dpriv->types = g_new (GType, dpriv->ncols); + memcpy (dpriv->types, priv->types, sizeof (GType) * dpriv->ncols); /* Flawfinder: ignore */ + } + if (priv->tmpl_columns) { + GSList *list; + for (list = priv->tmpl_columns; list; list = list->next) + dpriv->tmpl_columns = g_slist_append (dpriv->tmpl_columns, + gda_column_copy (GDA_COLUMN (list->data))); + } + GdaStatement *stmt; + stmt = g_weak_ref_get (& priv->gda_stmt_ref); + if (stmt) { + gda_pstmt_set_gda_statement (dest, stmt); + g_object_unref (stmt); + } + + g_rec_mutex_unlock (& priv->mutex); + g_rec_mutex_unlock (& dpriv->mutex); + +} + +/** + * gda_pstmt_get_gda_statement: + * @pstmt: a #GdaPStmt object + * + * Get a pointer to the #GdaStatement which led to the creation of this prepared statement. + * + * Note: if that statement has been modified since the creation of @pstmt, then this method + * will return %NULL + * + * Returns: (transfer full): the #GdaStatement + */ +GdaStatement * +gda_pstmt_get_gda_statement (GdaPStmt *pstmt) +{ + g_return_val_if_fail (GDA_IS_PSTMT (pstmt), NULL); + GdaPStmtPrivate *priv = gda_pstmt_get_instance_private (pstmt); + g_rec_mutex_lock (& priv->mutex); + GdaStatement *stmt; + stmt = g_weak_ref_get (& priv->gda_stmt_ref); + g_rec_mutex_unlock (& priv->mutex); + return stmt; +} +/** + * gda_pstmt_get_sql: + * Actual SQL code used for this prepared statement, mem freed by GdaPStmt + * + * Returns: (transfer none): SQL command used + */ +gchar* +gda_pstmt_get_sql (GdaPStmt *pstmt) { + GdaPStmtPrivate *priv = gda_pstmt_get_instance_private (pstmt); + return priv->sql; +} +/** + * gda_pstmt_set_sql: + * + * Set SQL code used for this prepared statement, mem freed by GdaPStmt + */ +void +gda_pstmt_set_sql (GdaPStmt *ps, const gchar *sql) { + g_return_if_fail (ps != NULL); + g_return_if_fail (GDA_IS_PSTMT (ps)); + GdaPStmtPrivate *priv = gda_pstmt_get_instance_private (ps); + priv->sql = g_strdup (sql); +} +/** + * gda_pstmt_get_param_ids: + * + * List of parameters' IDs (as gchar *) + * + * Returns: (element-type utf8) (transfer none): a list of string with parameters ID's + */ +GSList* +gda_pstmt_get_param_ids (GdaPStmt *ps) { + g_return_val_if_fail (ps != NULL, NULL); + g_return_val_if_fail (GDA_IS_PSTMT (ps), NULL); + GdaPStmtPrivate *priv = gda_pstmt_get_instance_private (ps); + return priv->param_ids; +} + +/** + * gda_pstmt_set_param_ids: + * @ps: a #GdaPStmt + * @params: (element-type utf8) (transfer full): a list of strings with ID's to set + * + * List of parameters' IDs (as gchar *), list is stolen + */ +void +gda_pstmt_set_param_ids (GdaPStmt *ps, GSList* params) { + g_return_if_fail (ps != NULL); + g_return_if_fail (GDA_IS_PSTMT (ps)); + GdaPStmtPrivate *priv = gda_pstmt_get_instance_private (ps); + priv->param_ids = params; +} +/** + * gda_pstmt_get_ncols: + * + * Returns: number of columns or -1 if something is wrong + */ +gint +gda_pstmt_get_ncols (GdaPStmt *ps) { + g_return_val_if_fail (ps != NULL, -1); + g_return_val_if_fail (GDA_IS_PSTMT (ps), -1); + GdaPStmtPrivate *priv = gda_pstmt_get_instance_private (ps); + return priv->ncols; +} +/** + * gda_pstmt_get_types: + * + * Set column's types for statement. @types will be stolen and should + * no be modified anymore. + * + * Returns: (array) (transfer none): an array of #GType used in the columns + */ +GType* +gda_pstmt_get_types (GdaPStmt *ps) { + g_return_val_if_fail (ps != NULL, NULL); + g_return_val_if_fail (GDA_IS_PSTMT (ps), NULL); + GdaPStmtPrivate *priv = gda_pstmt_get_instance_private (ps); + return priv->types; +} +/** + * gda_pstmt_set_cols: + * @ps: a #GdaPStmt + * @ncols: number of columns and size of given array + * @types: (array length=ncols) (transfer full): an array of types to use for each column + * + * Set column's types for statement. @types is stalen and should + * no be modified + */ +void +gda_pstmt_set_cols (GdaPStmt *ps, gint ncols, GType *types) { + g_return_if_fail (ps != NULL); + g_return_if_fail (GDA_IS_PSTMT (ps)); + GdaPStmtPrivate *priv = gda_pstmt_get_instance_private (ps); + priv->ncols = ncols; + priv->types = types; +} +/** + *gda_pstmt_get_tmpl_columns: + * + * List of #GdaColumn objects which data models created from this + * prepared statement can copy + * + * Returns: (element-type Gda.Column) (transfer none): a list of #GdaColumn objects + */ +GSList* +gda_pstmt_get_tmpl_columns (GdaPStmt *ps) { + g_return_val_if_fail (ps != NULL, NULL); + g_return_val_if_fail (GDA_IS_PSTMT (ps), NULL); + GdaPStmtPrivate *priv = gda_pstmt_get_instance_private (ps); + return priv->tmpl_columns; +} +/** + * gda_pstmt_set_tmpl_columns: + * @ps: a #GdaPStmt + * @columns: (element-type Gda.Column) (transfer full): a list of #GdaColumn + * + * Set the list of #GdaColumn objects which data models created from this + * prepared statement can copy. The list is stolen, so you should not + * free it. + */ +void +gda_pstmt_set_tmpl_columns (GdaPStmt *ps, GSList* columns) { + g_return_if_fail (ps != NULL); + g_return_if_fail (GDA_IS_PSTMT (ps)); + GdaPStmtPrivate *priv = gda_pstmt_get_instance_private (ps); + priv->tmpl_columns = columns; +} diff --git a/.flatpak-builder/cache/objects/9f/f670b2aa9d53561ed235f1d79c84f9485a2be4cde7551458bd164f3520053f.dirtree b/.flatpak-builder/cache/objects/9f/f670b2aa9d53561ed235f1d79c84f9485a2be4cde7551458bd164f3520053f.dirtree new file mode 100644 index 0000000..da17a41 Binary files /dev/null and b/.flatpak-builder/cache/objects/9f/f670b2aa9d53561ed235f1d79c84f9485a2be4cde7551458bd164f3520053f.dirtree differ diff --git a/.flatpak-builder/cache/objects/a0/adb957938594bddb3232ba4d7ca8ce12814c266bced690f6139515b5706317.file b/.flatpak-builder/cache/objects/a0/adb957938594bddb3232ba4d7ca8ce12814c266bced690f6139515b5706317.file new file mode 100644 index 0000000..03749c8 --- /dev/null +++ b/.flatpak-builder/cache/objects/a0/adb957938594bddb3232ba4d7ca8ce12814c266bced690f6139515b5706317.file @@ -0,0 +1,44 @@ +/*-*- Mode: C; c-basic-offset: 8 -*-*/ + +#ifndef foocanberrareadvorbishfoo +#define foocanberrareadvorbishfoo + +/*** + This file is part of libcanberra. + + Copyright 2008 Lennart Poettering + + libcanberra is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation, either version 2.1 of the + License, or (at your option) any later version. + + libcanberra is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with libcanberra. If not, see + . +***/ + +#include +#include + +#include "read-sound-file.h" + +typedef struct ca_vorbis ca_vorbis; + +int ca_vorbis_open(ca_vorbis **v, FILE *f); +void ca_vorbis_close(ca_vorbis *v); + +unsigned ca_vorbis_get_nchannels(ca_vorbis *v); +unsigned ca_vorbis_get_rate(ca_vorbis *v); +const ca_channel_position_t* ca_vorbis_get_channel_map(ca_vorbis *v); + +int ca_vorbis_read_s16ne(ca_vorbis *v, int16_t *d, size_t *n); + +off_t ca_vorbis_get_size(ca_vorbis *f); + +#endif diff --git a/.flatpak-builder/cache/objects/a0/b45af78d2bca3a416234aa2e962c284e2b50849c352301cc9c0b16834d9b7c.commit b/.flatpak-builder/cache/objects/a0/b45af78d2bca3a416234aa2e962c284e2b50849c352301cc9c0b16834d9b7c.commit new file mode 100644 index 0000000..473f98e Binary files /dev/null and b/.flatpak-builder/cache/objects/a0/b45af78d2bca3a416234aa2e962c284e2b50849c352301cc9c0b16834d9b7c.commit differ diff --git a/.flatpak-builder/cache/objects/a0/dd45bb727dc10eb11da8aff1ede3bd41ff19587143ae09414811b0797a8410.dirtree b/.flatpak-builder/cache/objects/a0/dd45bb727dc10eb11da8aff1ede3bd41ff19587143ae09414811b0797a8410.dirtree new file mode 100644 index 0000000..4c17371 Binary files /dev/null and b/.flatpak-builder/cache/objects/a0/dd45bb727dc10eb11da8aff1ede3bd41ff19587143ae09414811b0797a8410.dirtree differ diff --git a/.flatpak-builder/cache/objects/a0/f63d5563a02d82489156caa9b6b08087fe6e137303cc3901e8b29333432f64.file b/.flatpak-builder/cache/objects/a0/f63d5563a02d82489156caa9b6b08087fe6e137303cc3901e8b29333432f64.file new file mode 100644 index 0000000..b13d5da --- /dev/null +++ b/.flatpak-builder/cache/objects/a0/f63d5563a02d82489156caa9b6b08087fe6e137303cc3901e8b29333432f64.file @@ -0,0 +1,53 @@ +# binding.py +# +# Copyright 2023 James Westman +# +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation; either version 3 of the +# License, or (at your option) any later version. +# +# This file is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program. If not, see . +# +# SPDX-License-Identifier: LGPL-3.0-or-later + +from dataclasses import dataclass + +from .common import * +from .expression import Expression, LookupOp, LiteralExpr + + +class Binding(AstNode): + grammar = [ + Keyword("bind"), + Expression, + ] + + @property + def expression(self) -> Expression: + return self.children[Expression][0] + + @property + def simple_binding(self) -> T.Optional["SimpleBinding"]: + if isinstance(self.expression.last, LookupOp): + if isinstance(self.expression.last.lhs, LiteralExpr): + from .values import IdentLiteral + + if isinstance(self.expression.last.lhs.literal.value, IdentLiteral): + return SimpleBinding( + self.expression.last.lhs.literal.value.ident, + self.expression.last.property_name, + ) + return None + + +@dataclass +class SimpleBinding: + source: str + property_name: str diff --git a/.flatpak-builder/cache/objects/a1/a96c615bb4471faa2c1ce7ff5bc963e6fe910716960546f89c1c350f7fe241.file b/.flatpak-builder/cache/objects/a1/a96c615bb4471faa2c1ce7ff5bc963e6fe910716960546f89c1c350f7fe241.file new file mode 100644 index 0000000..667a204 --- /dev/null +++ b/.flatpak-builder/cache/objects/a1/a96c615bb4471faa2c1ce7ff5bc963e6fe910716960546f89c1c350f7fe241.file @@ -0,0 +1,68 @@ +/* + * gda-db-index.h + * Copyright (C) 2019 Pavlo Solntsev + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, see . + * + */ + +#ifndef GDA_DB_INDEX_H +#define GDA_DB_INDEX_H + +#include +#include +#include "gda-db-base.h" +#include "gda-db-index-field.h" + +G_BEGIN_DECLS + +#define GDA_TYPE_DB_INDEX (gda_db_index_get_type()) + +G_DECLARE_DERIVABLE_TYPE (GdaDbIndex, gda_db_index, GDA, DB_INDEX, GdaDbBase) + +struct _GdaDbIndexClass +{ + GdaDbBaseClass parent_class; +}; + +/** + * GdaDbIndexError: + * + */ +typedef enum { + GDA_DB_INDEX_CONNECTION_NOT_OPENED, + GDA_DB_INDEX_SERVER_OPERATION +} GdaDbIndexError; + +#define GDA_DB_INDEX_ERROR gda_db_index_error_quark() + +GQuark gda_db_index_error_quark(void); + +GdaDbIndex *gda_db_index_new (void); + +void gda_db_index_set_unique (GdaDbIndex *self, gboolean val); +gboolean gda_db_index_get_unique (GdaDbIndex *self); + +void gda_db_index_append_field (GdaDbIndex *self, GdaDbIndexField *field); + +void gda_db_index_remove_field (GdaDbIndex *self, const gchar *name); + +GSList *gda_db_index_get_fields (GdaDbIndex *self); + +G_END_DECLS + +#endif /* end of include guard: GDA-DB-INDEX_H */ + + + diff --git a/.flatpak-builder/cache/objects/a1/c3f3dd877f031d8562acbf0a2eba807c0a3a9317cb212bdaad2c95d2aff270.file b/.flatpak-builder/cache/objects/a1/c3f3dd877f031d8562acbf0a2eba807c0a3a9317cb212bdaad2c95d2aff270.file new file mode 100644 index 0000000..c87cb9f --- /dev/null +++ b/.flatpak-builder/cache/objects/a1/c3f3dd877f031d8562acbf0a2eba807c0a3a9317cb212bdaad2c95d2aff270.file @@ -0,0 +1,120 @@ +.TH INTLTOOL-MERGE 8 "2003-08-02" "intltool" + +.SH NAME +intltool-merge \- merge translated strings into various types of file + +.SH SYNOPSIS +.B "intltool-merge" +.I "[option]..." PO_DIRECTORY FILENAME OUTPUT_FILE + + +.SH DESCRIPTION +.PP +Merge translated strings in po files in \fIPO_DIRECTORY\fR with the original +application file \fIFILENAME\fR, and output the file \fIOUTPUT_FILE\fR +containing both original and localized strings. +.PP +If \fIFILENAME\fR is an XML file, \fIOUTPUT_FILE\fR will contain repeated +xml nodes, where each node contains one of the localized strings with +"xml:lang" attribute. + + +.SH OPTIONS +.\" ------------------------------------------------------- +.SS "Mode of operation" +.\" ------------------------------------------------------- +.IP "\fB\-b\fR" 4 +.PD 0 +.IP "\fB\-\-ba-style\fR" 4 +.PD +Merge files in bonobo-activation style, which is used for bonobo servers. +.IP "\fB\-d\fR" 4 +.PD 0 +.IP "\fB\-\-desktop-style\fR" 4 +.PD +Merge files in desktop style, which is similar to the Windows .ini file format. +.IP "\fB\-k\fR" 4 +.PD 0 +.IP "\fB\-\-keys-style\fR" 4 +.PD +Merge files in keys style, which is used for metadata. +.IP "\fB\-o\fR" 4 +.PD 0 +.IP "\fB\-\-oaf-style\fR" 4 +.PD +(OBSOLETE) Same as +.BR \-b / \-\-ba-style "." +.IP "\fB\-r\fR" 4 +.PD 0 +.IP "\fB\-\-rfc822deb-style\fR" 4 +.PD +Merge files in RFC 822 style, which is usually used in Debian configuration files. +.IP "\fB\-\-quoted-style\fR" 4 +.PD +Merge files in quoted string style, which just translates any strings within "". +.IP "\fB\-x\fR" 4 +.PD 0 +.IP "\fB\-\-xml-style\fR" 4 +.PD +Merge files in standard XML style, both as attributes and as raw pcdata. + +.\" ------------------------------------------------------- +.SS "Other options" +.\" ------------------------------------------------------- +.IP "\fB\-u\fR" 4 +.PD 0 +.IP "\fB\-\-utf8\fR" 4 +.PD +Convert all strings to UTF-8 before merging. +.IP "\fB\-p\fR" 4 +.PD 0 +.IP "\fB\-\-pass-through\fR" 4 +.PD +Use strings as is in .po files without conversion (STRONGLY unrecommended +with \-x). +.IP "\fB\-c\fR" 4 +.PD 0 +.IP "\fB\-\-cache\fR" 4 +.PD +(TBD) +.IP "\fB\-q\fR" 4 +.PD 0 +.IP "\fB\-\-quiet\fR" 4 +.PD +Be quiet while running. +.IP "\fB\-v\fR" 4 +.PD 0 +.IP "\fB\-\-version\fR" 4 +.PD +Show version information. +.IP "\fB\-h\fR" 4 +.PD 0 +.IP "\fB\-\-help\fR" 4 +.PD +Show usage and basic help information. + + +.SH FILES +.IP "\fBpo/.intltool-merge-cache\fR" +Cache file generated by \fBintltool-merge\fR, that contains all strings +in all po files separated by \\01. + + +.SH REPORTING BUGS +Report bugs to http://bugs.launchpad.net/intltool + + +.SH AUTHOR +Darin Adler +.br +Kenneth Christiansen +.br +Maciej Stachowiak + + +.SH SEE ALSO +.BR iconv (1), +.BR intltoolize (8), +.BR intltool-prepare (8), +.BR intltool-extract (8), +.BR intltool-update (8) diff --git a/.flatpak-builder/cache/objects/a2/4ec80e816fc6375f183591866e3c00095bc84112df38677da63f2aae52bbdc.file b/.flatpak-builder/cache/objects/a2/4ec80e816fc6375f183591866e3c00095bc84112df38677da63f2aae52bbdc.file new file mode 100644 index 0000000..5698e12 --- /dev/null +++ b/.flatpak-builder/cache/objects/a2/4ec80e816fc6375f183591866e3c00095bc84112df38677da63f2aae52bbdc.file @@ -0,0 +1,251 @@ +# gtk_menus.py +# +# Copyright 2021 James Westman +# +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation; either version 3 of the +# License, or (at your option) any later version. +# +# This file is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program. If not, see . +# +# SPDX-License-Identifier: LGPL-3.0-or-later + +import typing as T + +from blueprintcompiler.language.values import StringValue + +from .common import * +from .contexts import ValueTypeCtx +from .gobject_object import RESERVED_IDS + + +class Menu(AstNode): + @property + def gir_class(self): + return self.root.gir.namespaces["Gtk"].lookup_type("Gio.Menu") + + @property + def id(self) -> str: + return self.tokens["id"] + + @property + def tag(self) -> str: + return self.tokens["tag"] + + @property + def items(self) -> T.List[T.Union["Menu", "MenuAttribute"]]: + return self.children + + @validate("menu") + def has_id(self): + if self.tokens["tag"] == "menu" and self.tokens["id"] is None: + raise CompileError("Menu requires an ID") + + @validate("id") + def object_id_not_reserved(self): + if self.id in RESERVED_IDS: + raise CompileWarning(f"{self.id} may be a confusing object ID") + + +class MenuAttribute(AstNode): + tag_name = "attribute" + + @property + def name(self) -> str: + return self.tokens["name"] + + @property + def value(self) -> StringValue: + return self.children[StringValue][0] + + @context(ValueTypeCtx) + def value_type(self) -> ValueTypeCtx: + return ValueTypeCtx(None) + + @validate("name") + def unique(self): + self.validate_unique_in_parent( + f"Duplicate attribute '{self.name}'", lambda x: x.name == self.name + ) + + +menu_child = AnyOf() + +menu_attribute = Group( + MenuAttribute, + [ + UseIdent("name"), + ":", + Err(StringValue, "Expected string or translated string"), + Match(";").expected(), + ], +) + +menu_section = Group( + Menu, + [ + "section", + UseLiteral("tag", "section"), + Optional(UseIdent("id")), + Match("{").expected(), + Until(AnyOf(menu_child, menu_attribute), "}"), + ], +) + +menu_submenu = Group( + Menu, + [ + "submenu", + UseLiteral("tag", "submenu"), + Optional(UseIdent("id")), + Match("{").expected(), + Until(AnyOf(menu_child, menu_attribute), "}"), + ], +) + +menu_item = Group( + Menu, + [ + "item", + UseLiteral("tag", "item"), + Match("{").expected(), + Until(menu_attribute, "}"), + ], +) + +menu_item_shorthand = Group( + Menu, + [ + "item", + UseLiteral("tag", "item"), + "(", + Group( + MenuAttribute, + [UseLiteral("name", "label"), StringValue], + ), + Optional( + [ + ",", + Optional( + [ + Group( + MenuAttribute, + [UseLiteral("name", "action"), StringValue], + ), + Optional( + [ + ",", + Group( + MenuAttribute, + [UseLiteral("name", "icon"), StringValue], + ), + ] + ), + ] + ), + ] + ), + Match(")").expected(), + ], +) + +menu_child.children = [ + menu_section, + menu_submenu, + menu_item_shorthand, + menu_item, +] + +menu: Group = Group( + Menu, + [ + Keyword("menu"), + UseLiteral("tag", "menu"), + Optional(UseIdent("id")), + [ + Match("{"), + Until( + AnyOf( + menu_child, + Fail( + menu_attribute, + "Attributes are not permitted at the top level of a menu", + ), + ), + "}", + ), + ], + ], +) + +from .ui import UI + + +@completer( + applies_in=[UI], + matches=new_statement_patterns, +) +def menu_completer(ast_node, match_variables): + yield Completion("menu", CompletionItemKind.Snippet, snippet="menu {\n $0\n}") + + +@completer( + applies_in=[Menu], + matches=new_statement_patterns, +) +def menu_content_completer(ast_node, match_variables): + yield Completion( + "submenu", CompletionItemKind.Snippet, snippet="submenu {\n $0\n}" + ) + yield Completion( + "section", CompletionItemKind.Snippet, snippet="section {\n $0\n}" + ) + yield Completion("item", CompletionItemKind.Snippet, snippet="item {\n $0\n}") + yield Completion( + "item (shorthand)", + CompletionItemKind.Snippet, + snippet='item (_("${1:Label}"), "${2:action-name}", "${3:icon-name}")', + ) + + yield Completion("label", CompletionItemKind.Snippet, snippet="label: $0;") + yield Completion("action", CompletionItemKind.Snippet, snippet='action: "$0";') + yield Completion("icon", CompletionItemKind.Snippet, snippet='icon: "$0";') + + +@decompiler("menu") +def decompile_menu(ctx, gir, id=None): + if id: + ctx.print(f"menu {id} {{") + else: + ctx.print("menu {") + + +@decompiler("submenu") +def decompile_submenu(ctx, gir, id=None): + if id: + ctx.print(f"submenu {id} {{") + else: + ctx.print("submenu {") + + +@decompiler("item") +def decompile_item(ctx, gir, id=None): + if id: + ctx.print(f"item {id} {{") + else: + ctx.print("item {") + + +@decompiler("section") +def decompile_section(ctx, gir, id=None): + if id: + ctx.print(f"section {id} {{") + else: + ctx.print("section {") diff --git a/.flatpak-builder/cache/objects/a3/474de5d8a8b75ce97da78e6227710350dc9efba95f95ce112ec7de076f2e66.file b/.flatpak-builder/cache/objects/a3/474de5d8a8b75ce97da78e6227710350dc9efba95f95ce112ec7de076f2e66.file new file mode 100755 index 0000000..0b69a59 Binary files /dev/null and b/.flatpak-builder/cache/objects/a3/474de5d8a8b75ce97da78e6227710350dc9efba95f95ce112ec7de076f2e66.file differ diff --git a/.flatpak-builder/cache/objects/a3/bcdd1d647e2e0431913099210cd355eacbc4cbeaa7108c49a6b177f95dd0cf.commit b/.flatpak-builder/cache/objects/a3/bcdd1d647e2e0431913099210cd355eacbc4cbeaa7108c49a6b177f95dd0cf.commit new file mode 100644 index 0000000..b536303 Binary files /dev/null and b/.flatpak-builder/cache/objects/a3/bcdd1d647e2e0431913099210cd355eacbc4cbeaa7108c49a6b177f95dd0cf.commit differ diff --git a/.flatpak-builder/cache/objects/a3/c3d69929fe1f555e01fd870185df34eaf092e43af8fa54dd67244def7b3798.file b/.flatpak-builder/cache/objects/a3/c3d69929fe1f555e01fd870185df34eaf092e43af8fa54dd67244def7b3798.file new file mode 100644 index 0000000..f08168f --- /dev/null +++ b/.flatpak-builder/cache/objects/a3/c3d69929fe1f555e01fd870185df34eaf092e43af8fa54dd67244def7b3798.file @@ -0,0 +1,151 @@ +# gobject_signal.py +# +# Copyright 2022 James Westman +# +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation; either version 3 of the +# License, or (at your option) any later version. +# +# This file is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program. If not, see . +# +# SPDX-License-Identifier: LGPL-3.0-or-later + +import typing as T + +from .gtkbuilder_template import Template +from .contexts import ScopeCtx +from .common import * + + +class SignalFlag(AstNode): + grammar = AnyOf( + UseExact("flag", "swapped"), + UseExact("flag", "after"), + ) + + @property + def flag(self) -> str: + return self.tokens["flag"] + + @validate() + def unique(self): + self.validate_unique_in_parent( + f"Duplicate flag '{self.flag}'", lambda x: x.flag == self.flag + ) + + +class Signal(AstNode): + grammar = Statement( + UseIdent("name"), + Optional( + [ + "::", + UseIdent("detail_name").expected("a signal detail name"), + ] + ), + "=>", + Optional(["$", UseLiteral("extern", True)]), + UseIdent("handler").expected("the name of a function to handle the signal"), + Match("(").expected("argument list"), + Optional(UseIdent("object")).expected("object identifier"), + Match(")").expected(), + ZeroOrMore(SignalFlag), + ) + + @property + def name(self) -> str: + return self.tokens["name"] + + @property + def detail_name(self) -> T.Optional[str]: + return self.tokens["detail_name"] + + @property + def full_name(self) -> str: + if self.detail_name is None: + return self.name + else: + return self.name + "::" + self.detail_name + + @property + def handler(self) -> str: + return self.tokens["handler"] + + @property + def object_id(self) -> T.Optional[str]: + return self.tokens["object"] + + @property + def flags(self) -> T.List[SignalFlag]: + return self.children[SignalFlag] + + @property + def is_swapped(self) -> bool: + return any(x.flag == "swapped" for x in self.flags) + + @property + def is_after(self) -> bool: + return any(x.flag == "after" for x in self.flags) + + @property + def gir_signal(self): + if self.gir_class is not None and not isinstance(self.gir_class, ExternType): + return self.gir_class.signals.get(self.tokens["name"]) + + @property + def gir_class(self): + return self.parent.parent.gir_class + + @validate("handler") + def old_extern(self): + if not self.tokens["extern"]: + if self.handler is not None: + raise UpgradeWarning( + "Use the '$' extern syntax introduced in blueprint 0.8.0", + actions=[CodeAction("Use '$' syntax", "$" + self.handler)], + ) + + @validate("name") + def signal_exists(self): + if self.gir_class is None or self.gir_class.incomplete: + # Objects that we have no gir data on should not be validated + # This happens for classes defined by the app itself + return + + if self.gir_signal is None: + raise CompileError( + f"Class {self.gir_class.full_name} does not contain a signal called {self.tokens['name']}", + did_you_mean=(self.tokens["name"], self.gir_class.signals.keys()), + ) + + @validate("object") + def object_exists(self): + object_id = self.tokens["object"] + if object_id is None: + return + + if self.context[ScopeCtx].objects.get(object_id) is None: + raise CompileError(f"Could not find object with ID '{object_id}'") + + @docs("name") + def signal_docs(self): + if self.gir_signal is not None: + return self.gir_signal.doc + + +@decompiler("signal") +def decompile_signal(ctx, gir, name, handler, swapped="false", object=None): + object_name = object or "" + name = name.replace("_", "-") + if decompile.truthy(swapped): + ctx.print(f"{name} => ${handler}({object_name}) swapped;") + else: + ctx.print(f"{name} => ${handler}({object_name});") + return gir diff --git a/.flatpak-builder/cache/objects/a4/928c0ffff57e32efb180e122003dbecc6214ae8b4b516d8c1627435487efa8.file b/.flatpak-builder/cache/objects/a4/928c0ffff57e32efb180e122003dbecc6214ae8b4b516d8c1627435487efa8.file new file mode 100644 index 0000000..e8e5aab --- /dev/null +++ b/.flatpak-builder/cache/objects/a4/928c0ffff57e32efb180e122003dbecc6214ae8b4b516d8c1627435487efa8.file @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2009 - 2014 Vivien Malerba + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GDA_SQLITE_BLOB_OP_H__ +#define __GDA_SQLITE_BLOB_OP_H__ + +#include + +G_BEGIN_DECLS + +#define GDA_TYPE_SQLITE_BLOB_OP (gda_sqlite_blob_op_get_type()) +G_DECLARE_DERIVABLE_TYPE(GdaSqliteBlobOp, gda_sqlite_blob_op, GDA, SQLITE_BLOB_OP, GdaBlobOp) + +struct _GdaSqliteBlobOpClass { + GdaBlobOpClass parent_class; +}; + +GdaBlobOp *_gda_sqlite_blob_op_new (GdaConnection *cnc, + const gchar *db_name, const gchar *table_name, + const gchar *column_name, sqlite3_int64 rowid); + +G_END_DECLS + +#endif + diff --git a/.flatpak-builder/cache/objects/a4/fe4b2083b20fccd7c0ebf1150fa7d68fa0ae44638351ae38909275670413ae.file b/.flatpak-builder/cache/objects/a4/fe4b2083b20fccd7c0ebf1150fa7d68fa0ae44638351ae38909275670413ae.file new file mode 100644 index 0000000..32909ae Binary files /dev/null and b/.flatpak-builder/cache/objects/a4/fe4b2083b20fccd7c0ebf1150fa7d68fa0ae44638351ae38909275670413ae.file differ diff --git a/.flatpak-builder/cache/objects/a5/b9fa2cd45c271a8fbe19a4e0105dec9d29a3269bb5a016a38a0a9b622e790d.file b/.flatpak-builder/cache/objects/a5/b9fa2cd45c271a8fbe19a4e0105dec9d29a3269bb5a016a38a0a9b622e790d.file new file mode 100644 index 0000000..e3a5268 --- /dev/null +++ b/.flatpak-builder/cache/objects/a5/b9fa2cd45c271a8fbe19a4e0105dec9d29a3269bb5a016a38a0a9b622e790d.file @@ -0,0 +1,119 @@ +/* gsound-play.vala + * + * Copyright (C) 2014 Tristan Brindle + * + * This file is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of the + * License, or (at your option) any later version. + * + * This file is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +string event_id; +string filename; +string desc; +string cache; +int loops; +double volume; +string driver; + +MainLoop main_loop; +GSound.Context gs_ctx; +HashTable attrs; + +const OptionEntry[] opts = { + { "id", 'i', 0, OptionArg.STRING, ref event_id, + "Event sound identifier", "STRING" }, + { "file", 'f', 0, OptionArg.FILENAME, ref filename, + "Play file", "PATH" }, + { "description", 'd', 0, OptionArg.STRING, ref desc, + "Event sound description", "STRING" }, + { "cache-control", 'c', 0, OptionArg.STRING, ref cache, + "Cache control (permanent, volatile, never", "STRING" }, + { "loop", 'l', 0, OptionArg.INT, ref loops, + "Loop many times (default: 1)", "INTEGER" }, + { "volume", 'V', 0, OptionArg.DOUBLE, ref volume, + "A floating point dB value for the sample volume (ex: 0.0)", "STRING" }, + { "backend", 'b', 0, OptionArg.STRING, ref driver, + "libcanberra backend to use", "STRING" }, + { null } +}; + +async void play() throws Error +{ + while (loops-- > 0) { + yield gs_ctx.play_fullv(attrs, null); + } +} + +int main(string[] args) +{ + Intl.setlocale (LocaleCategory.ALL, ""); + + Environment.set_application_name("gsound-play"); + + var opt_ctx = new OptionContext(); + opt_ctx.add_main_entries(opts, null); + + try { + opt_ctx.parse(ref args); + + if (event_id == null && filename == null) { + print("No event id or file specified.\n"); + return 1; + } + + gs_ctx = new GSound.Context(); + gs_ctx.set_attributes(GSound.Attribute.APPLICATION_ID, "org.gnome.gsound-test"); + + if (driver != null) { + gs_ctx.set_driver(driver); + } + + attrs = new HashTable(str_hash, str_equal); + + if (event_id != null) { + attrs.insert(GSound.Attribute.EVENT_ID, event_id); + } + if (filename != null) { + attrs.insert(GSound.Attribute.MEDIA_FILENAME, filename); + } + if (cache != null) { + attrs.insert(GSound.Attribute.CANBERRA_CACHE_CONTROL, cache); + } + if (volume != 0.0) { + attrs.insert(GSound.Attribute.CANBERRA_VOLUME, volume.to_string()); + } + + if (loops == 0) { + loops = 1; + } + + play.begin((obj, res) => { + try { + play.end(res); + } catch (Error e) { + print("Error: %s\n", e.message); + } finally { + main_loop.quit(); + } + }); + + main_loop = new MainLoop(); + main_loop.run(); + + } catch (Error e) { + print("Error: %s\n", e.message); + return 1; + } + + return 0; +} + diff --git a/.flatpak-builder/cache/objects/a5/dc2654d848c89233b978aca24237d827ee9cd827790ff3c1954e4103330c8a.file b/.flatpak-builder/cache/objects/a5/dc2654d848c89233b978aca24237d827ee9cd827790ff3c1954e4103330c8a.file new file mode 100644 index 0000000..6591aa5 --- /dev/null +++ b/.flatpak-builder/cache/objects/a5/dc2654d848c89233b978aca24237d827ee9cd827790ff3c1954e4103330c8a.file @@ -0,0 +1,72 @@ +# gtk_styles.py +# +# Copyright 2021 James Westman +# +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation; either version 3 of the +# License, or (at your option) any later version. +# +# This file is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program. If not, see . +# +# SPDX-License-Identifier: LGPL-3.0-or-later + + +from .gobject_object import ObjectContent, validate_parent_type +from .common import * + + +class StyleClass(AstNode): + grammar = UseQuoted("name") + + @property + def name(self) -> str: + return self.tokens["name"] + + @validate("name") + def unique_in_parent(self): + self.validate_unique_in_parent( + f"Duplicate style class '{self.name}'", lambda x: x.name == self.name + ) + + +class ExtStyles(AstNode): + grammar = [ + Keyword("styles"), + "[", + Delimited(StyleClass, ","), + "]", + ] + + @validate("styles") + def container_is_widget(self): + validate_parent_type(self, "Gtk", "Widget", "style classes") + + @validate("styles") + def unique_in_parent(self): + self.validate_unique_in_parent("Duplicate styles block") + + +@completer( + applies_in=[ObjectContent], + applies_in_subclass=("Gtk", "Widget"), + matches=new_statement_patterns, +) +def style_completer(ast_node, match_variables): + yield Completion("styles", CompletionItemKind.Keyword, snippet='styles ["$0"]') + + +@decompiler("style") +def decompile_style(ctx, gir): + ctx.print(f"styles [") + + +@decompiler("class") +def decompile_style_class(ctx, gir, name): + ctx.print(f'"{name}",') diff --git a/.flatpak-builder/cache/objects/a5/df964f6c37c190ebdc48e0a1973e08461cc7e9fa965549a22355da3aa3909e.dirtree b/.flatpak-builder/cache/objects/a5/df964f6c37c190ebdc48e0a1973e08461cc7e9fa965549a22355da3aa3909e.dirtree new file mode 100644 index 0000000..d89901b Binary files /dev/null and b/.flatpak-builder/cache/objects/a5/df964f6c37c190ebdc48e0a1973e08461cc7e9fa965549a22355da3aa3909e.dirtree differ diff --git a/.flatpak-builder/cache/objects/a6/11ecaeea78d23e0108a4f775572433630a59fa5b3d5602b3ab98ad3e4bb931.dirtree b/.flatpak-builder/cache/objects/a6/11ecaeea78d23e0108a4f775572433630a59fa5b3d5602b3ab98ad3e4bb931.dirtree new file mode 100644 index 0000000..051af9b Binary files /dev/null and b/.flatpak-builder/cache/objects/a6/11ecaeea78d23e0108a4f775572433630a59fa5b3d5602b3ab98ad3e4bb931.dirtree differ diff --git a/.flatpak-builder/cache/objects/a6/2b4744955e62dda064417724cf00d6a4bbe8346ee7c89678e102bfec19a07c.dirtree b/.flatpak-builder/cache/objects/a6/2b4744955e62dda064417724cf00d6a4bbe8346ee7c89678e102bfec19a07c.dirtree new file mode 100644 index 0000000..6f88dc4 Binary files /dev/null and b/.flatpak-builder/cache/objects/a6/2b4744955e62dda064417724cf00d6a4bbe8346ee7c89678e102bfec19a07c.dirtree differ diff --git a/.flatpak-builder/cache/objects/a6/8f61023f699aedcf31830f0da173fcca8750429d4d86e88dc128d46ada8ff3.dirtree b/.flatpak-builder/cache/objects/a6/8f61023f699aedcf31830f0da173fcca8750429d4d86e88dc128d46ada8ff3.dirtree new file mode 100644 index 0000000..3aa5cf8 Binary files /dev/null and b/.flatpak-builder/cache/objects/a6/8f61023f699aedcf31830f0da173fcca8750429d4d86e88dc128d46ada8ff3.dirtree differ diff --git a/.flatpak-builder/cache/objects/a6/95ce5901f8e7a4f059bc0c3db59af3e675a391d493445bf4309b35858c2088.file b/.flatpak-builder/cache/objects/a6/95ce5901f8e7a4f059bc0c3db59af3e675a391d493445bf4309b35858c2088.file new file mode 100644 index 0000000..33cfa8b --- /dev/null +++ b/.flatpak-builder/cache/objects/a6/95ce5901f8e7a4f059bc0c3db59af3e675a391d493445bf4309b35858c2088.file @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2011 Vivien Malerba + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GDA_DATA_PIVOT_H__ +#define __GDA_DATA_PIVOT_H__ + +#include + +G_BEGIN_DECLS + +#define GDA_TYPE_DATA_PIVOT (gda_data_pivot_get_type()) +G_DECLARE_DERIVABLE_TYPE(GdaDataPivot, gda_data_pivot, GDA, DATA_PIVOT, GObject) + +struct _GdaDataPivotClass { + GObjectClass parent_class; + + /*< private >*/ + /* Padding for future expansion */ + void (*_gda_reserved1) (void); + void (*_gda_reserved2) (void); + void (*_gda_reserved3) (void); + void (*_gda_reserved4) (void); +}; + +/* error reporting */ +extern GQuark gda_data_pivot_error_quark (void); +#define GDA_DATA_PIVOT_ERROR gda_data_pivot_error_quark () + +/** + * GdaDataPivotError: + * + * Possible #GdaDataPivot related errors. + */ +typedef enum { + GDA_DATA_PIVOT_INTERNAL_ERROR, + GDA_DATA_PIVOT_SOURCE_MODEL_ERROR, + GDA_DATA_PIVOT_FIELD_FORMAT_ERROR, + GDA_DATA_PIVOT_USAGE_ERROR, + GDA_DATA_PIVOT_OVERFLOW_ERROR +} GdaDataPivotError; + +/** + * GdaDataPivotAggregate: + * @GDA_DATA_PIVOT_AVG: + * @GDA_DATA_PIVOT_COUNT: + * @GDA_DATA_PIVOT_MAX: + * @GDA_DATA_PIVOT_MIN: + * @GDA_DATA_PIVOT_SUM: + * + * Possible operations for the data fields. + */ +typedef enum { + GDA_DATA_PIVOT_AVG, + GDA_DATA_PIVOT_COUNT, + GDA_DATA_PIVOT_MAX, + GDA_DATA_PIVOT_MIN, + GDA_DATA_PIVOT_SUM +} GdaDataPivotAggregate; + +/** + * SECTION:gda-data-pivot + * @short_description: A data model for data summarisation + * @title: GdaDataPivot + * @stability: Stable + * + * The #GdaDataPivot data model allows one to do some analysis and summarisation on the contents + * of a data model. + * + * + */ + +/** + * GdaDataPivotFieldType: + * @GDA_DATA_PIVOT_FIELD_ROW: + * @GDA_DATA_PIVOT_FIELD_COLUMN: + * + * Define types of field to be used when defining a #GdaDataPivot analysis. + */ +typedef enum { + GDA_DATA_PIVOT_FIELD_ROW, + GDA_DATA_PIVOT_FIELD_COLUMN +} GdaDataPivotFieldType; + +GdaDataModel *gda_data_pivot_new (GdaDataModel *model); + +gboolean gda_data_pivot_add_field (GdaDataPivot *pivot, GdaDataPivotFieldType field_type, + const gchar *field, const gchar *alias, GError **error); +gboolean gda_data_pivot_add_data (GdaDataPivot *pivot, GdaDataPivotAggregate aggregate_type, + const gchar *field, const gchar *alias, GError **error); + +gboolean gda_data_pivot_populate (GdaDataPivot *pivot, GError **error); + + +G_END_DECLS + +#endif diff --git a/.flatpak-builder/cache/objects/a6/ac27b03c65f7ff9de12d09aa681faf4e6646e7a0a94b8749b1335a3f38fbe8.dirtree b/.flatpak-builder/cache/objects/a6/ac27b03c65f7ff9de12d09aa681faf4e6646e7a0a94b8749b1335a3f38fbe8.dirtree new file mode 100644 index 0000000..eb38f7e Binary files /dev/null and b/.flatpak-builder/cache/objects/a6/ac27b03c65f7ff9de12d09aa681faf4e6646e7a0a94b8749b1335a3f38fbe8.dirtree differ diff --git a/.flatpak-builder/cache/objects/a7/5e679e8df7f8b2b6ebd6bc5fe708fcd945fa3b2e2e85c7626fce8fd9d6e546.file b/.flatpak-builder/cache/objects/a7/5e679e8df7f8b2b6ebd6bc5fe708fcd945fa3b2e2e85c7626fce8fd9d6e546.file new file mode 100644 index 0000000..b5fb856 --- /dev/null +++ b/.flatpak-builder/cache/objects/a7/5e679e8df7f8b2b6ebd6bc5fe708fcd945fa3b2e2e85c7626fce8fd9d6e546.file @@ -0,0 +1,5385 @@ +/* + * Copyright (C) 2001 - 2002 Carlos Perelló Marín + * Copyright (C) 2001 - 2003 Rodrigo Moya + * Copyright (C) 2002 - 2003 Gonzalo Paniagua Javier + * Copyright (C) 2004 Benjamin Otte + * Copyright (C) 2004 J.H.M. Dassen (Ray) + * Copyright (C) 2004 Julio M. Merino Vidal + * Copyright (C) 2004 Jürg Billeter + * Copyright (C) 2004 Nikolai Weibull + * Copyright (C) 2005 Denis Fortin + * Copyright (C) 2005 - 2015 Vivien Malerba + * Copyright (C) 2005 Álvaro Peña + * Copyright (C) 2008 - 2009 Bas Driessen + * Copyright (C) 2008 - 2014 Murray Cumming + * Copyright (C) 2009 Armin Burgmeier + * Copyright (C) 2010 David King + * Copyright (C) 2011,2018 Daniel Espinosa + * Copyright (C) 2011 Marek Černocký + * Copyright (C) 2012 Marco Ciampa + * Copyright (C) 2017-2018 Daniel Espinosa + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#undef GDA_DISABLE_DEPRECATED +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "gda-sqlite.h" +#include "gda-sqlite-provider.h" +#include "gda-sqlite-recordset.h" +#include "gda-sqlite-ddl.h" +#include "gda-sqlite-util.h" +#include "gda-sqlite-meta.h" +#include "gda-sqlite-handler-bin.h" +#include "gda-sqlite-handler-boolean.h" +#include "gda-sqlite-blob-op.h" +#include +#include +#include +#include +#include +#include +#define _GDA_PSTMT(x) ((GdaPStmt*)(x)) +#include +#include +#include +#include + +#define FILE_EXTENSION ".db" +static gchar *get_table_nth_column_name (GdaServerProvider *prov, GdaConnection *cnc, const gchar *table_name, gint pos); + +/* TMP */ +typedef struct { + GdaSqlStatement *stmt; + gchar *db; + gchar *table; + gchar *column; + gboolean free_column; /* set to %TRUE if @column has been dynamically allocated */ + GdaBlob *blob; +} PendingBlob; + +static PendingBlob* +make_pending_blob (GdaServerProvider *provider, GdaConnection *cnc, GdaStatement *stmt, GdaHolder *holder, GError **error) +{ + PendingBlob *pb = NULL; + GdaSqlStatement *sqlst; + const gchar *hname; + + g_return_val_if_fail (GDA_IS_STATEMENT (stmt), NULL); + g_return_val_if_fail (GDA_IS_HOLDER (holder), NULL); + hname = gda_holder_get_id (holder); + g_return_val_if_fail (hname && *hname, NULL); + + g_object_get (G_OBJECT (stmt), "structure", &sqlst, NULL); + g_return_val_if_fail (sqlst, NULL); + + switch (sqlst->stmt_type) { + case GDA_SQL_STATEMENT_INSERT: { + GdaSqlStatementInsert *istmt = (GdaSqlStatementInsert*) sqlst->contents; + gint pos = -1; + GSList *vll; + for (vll = istmt->values_list; vll && (pos == -1); vll = vll->next) { + GSList *vlist; + gint p; + for (p = 0, vlist = (GSList *) vll->data; + vlist; + p++, vlist = vlist->next) { + GdaSqlExpr *expr = (GdaSqlExpr *) vlist->data; + if (!expr->param_spec) + continue; + if (expr->param_spec->name && + !strcmp (expr->param_spec->name, hname)) { + pos = p; + break; + } + } + } + if (pos == -1) { + g_set_error (error, GDA_SERVER_PROVIDER_ERROR, + GDA_SERVER_PROVIDER_INTERNAL_ERROR, + _("Parameter '%s' not found in statement"), hname); + goto out; + } + GdaSqlField *field; + field = g_slist_nth_data (istmt->fields_list, pos); + if (field) { + pb = g_new0 (PendingBlob, 1); + pb->table = istmt->table->table_name; + pb->column = field->field_name; + pb->free_column = FALSE; + } + else if (istmt->fields_list) { + g_set_error (error, GDA_SERVER_PROVIDER_ERROR, + GDA_SERVER_PROVIDER_INTERNAL_ERROR, + _("No column name to associate to parameter '%s'"), + hname); + goto out; + } + else { + gchar *fname; + fname = get_table_nth_column_name (provider, cnc, istmt->table->table_name, pos); + if (fname) { + pb = g_new0 (PendingBlob, 1); + pb->table = istmt->table->table_name; + pb->column = fname; + pb->free_column = TRUE; + } + else { + g_set_error (error, GDA_SERVER_PROVIDER_ERROR, + GDA_SERVER_PROVIDER_INTERNAL_ERROR, + _("No column name to associate to parameter '%s'"), + hname); + goto out; + } + } + + break; + } + case GDA_SQL_STATEMENT_UPDATE: { + GdaSqlStatementUpdate *ustmt = (GdaSqlStatementUpdate*) sqlst->contents; + gint pos = -1; + GSList *vlist; + gint p; + for (p = 0, vlist = ustmt->expr_list; + vlist; + p++, vlist = vlist->next) { + GdaSqlExpr *expr = (GdaSqlExpr *) vlist->data; + if (!expr->param_spec) + continue; + if (expr->param_spec->name && + !strcmp (expr->param_spec->name, hname)) { + pos = p; + break; + } + } + if (pos == -1) { + g_set_error (error, GDA_SERVER_PROVIDER_ERROR, + GDA_SERVER_PROVIDER_INTERNAL_ERROR, + _("Parameter '%s' not found is statement"), hname); + goto out; + } + GdaSqlField *field; + field = g_slist_nth_data (ustmt->fields_list, pos); + if (field) { + pb = g_new0 (PendingBlob, 1); + pb->table = ustmt->table->table_name; + pb->column = field->field_name; + pb->free_column = FALSE; + } + if (ustmt->fields_list) { + g_set_error (error, GDA_SERVER_PROVIDER_ERROR, + GDA_SERVER_PROVIDER_INTERNAL_ERROR, + _("No column name to associate to parameter '%s'"), + hname); + goto out; + } + else { + gchar *fname; + fname = get_table_nth_column_name (provider, cnc, ustmt->table->table_name, pos); + if (fname) { + pb = g_new0 (PendingBlob, 1); + pb->table = ustmt->table->table_name; + pb->column = fname; + pb->free_column = TRUE; + } + else { + g_set_error (error, GDA_SERVER_PROVIDER_ERROR, + GDA_SERVER_PROVIDER_INTERNAL_ERROR, + _("No column name to associate to parameter '%s'"), + hname); + goto out; + } + } + break; + } + default: + g_set_error (error, GDA_SERVER_PROVIDER_ERROR, + GDA_SERVER_PROVIDER_NON_SUPPORTED_ERROR, + "%s",_("Binding a BLOB for this type of statement is not supported")); + goto out; + } + + out: + if (pb) + pb->stmt = sqlst; + else + gda_sql_statement_free (sqlst); + return pb; +} + +static void +pending_blobs_free_list (GSList *blist) +{ + if (!blist) + return; + GSList *l; + for (l = blist; l; l = l->next) { + PendingBlob *pb = (PendingBlob*) l->data; + if (pb->stmt) + gda_sql_statement_free (pb->stmt); + if (pb->free_column) + g_free (pb->column); + g_free (pb); + } + + g_slist_free (blist); +} + + +static void +gda_sqlite_provider_meta_iface_init (GdaProviderMetaInterface *iface); + +static void +gda_sqlite_provider_iface_init (GdaProviderInterface *iface); + +// API routines from library +Sqlite3ApiRoutines *s3r; + +/** + * call it if you are implementing a new derived provider using + * a different SQLite library, like SQLCipher + */ +static gpointer +gda_sqlite_provider_get_api_internal (GdaSqliteProvider *prov) { + return s3r; +} +/* properties */ +enum +{ + PROP_0, + PROP_IS_DEFAULT, + PROP_CONNECTION +}; + +/* + * GObject methods + */ +typedef struct { + GPtrArray *internal_stmt; + gboolean is_default; +} GdaSqliteProviderPrivate; + + +G_DEFINE_TYPE_WITH_CODE (GdaSqliteProvider, gda_sqlite_provider, GDA_TYPE_SERVER_PROVIDER, + G_ADD_PRIVATE (GdaSqliteProvider) + G_IMPLEMENT_INTERFACE (GDA_TYPE_PROVIDER_META, gda_sqlite_provider_meta_iface_init) + G_IMPLEMENT_INTERFACE (GDA_TYPE_PROVIDER, gda_sqlite_provider_iface_init)) + + +/* + * GdaServerProvider's virtual methods + */ +/* connection management */ +static gboolean gda_sqlite_provider_open_connection (GdaServerProvider *provider, GdaConnection *cnc, + GdaQuarkList *params, GdaQuarkList *auth); +static gboolean gda_sqlite_provider_prepare_connection (GdaServerProvider *provider, + GdaConnection *cnc, GdaQuarkList *params, GdaQuarkList *auth); +static gboolean gda_sqlite_provider_close_connection (GdaServerProvider *provider, GdaConnection *cnc); +static const gchar *gda_sqlite_provider_get_server_version (GdaServerProvider *provider, GdaConnection *cnc); + +/* DDL operations */ +static gboolean gda_sqlite_provider_supports_operation (GdaServerProvider *provider, GdaConnection *cnc, + GdaServerOperationType type, GdaSet *options); +static GdaServerOperation *gda_sqlite_provider_create_operation (GdaServerProvider *provider, GdaConnection *cnc, + GdaServerOperationType type, + GdaSet *options, GError **error); +static gchar *gda_sqlite_provider_render_operation (GdaServerProvider *provider, GdaConnection *cnc, + GdaServerOperation *op, GError **error); + +static gboolean gda_sqlite_provider_perform_operation (GdaServerProvider *provider, GdaConnection *cnc, + GdaServerOperation *op, GError **error); +/* transactions */ +static gboolean gda_sqlite_provider_begin_transaction (GdaServerProvider *provider, GdaConnection *cnc, + const gchar *name, GdaTransactionIsolation level, + GError **error); +static gboolean gda_sqlite_provider_commit_transaction (GdaServerProvider *provider, GdaConnection *cnc, + const gchar *name, GError **error); +static gboolean gda_sqlite_provider_rollback_transaction (GdaServerProvider *provider, GdaConnection * cnc, + const gchar *name, GError **error); +static gboolean gda_sqlite_provider_add_savepoint (GdaServerProvider *provider, GdaConnection *cnc, + const gchar *name, GError **error); +static gboolean gda_sqlite_provider_rollback_savepoint (GdaServerProvider *provider, GdaConnection *cnc, + const gchar *name, GError **error); +static gboolean gda_sqlite_provider_delete_savepoint (GdaServerProvider *provider, GdaConnection *cnc, + const gchar *name, GError **error); + +/* information retrieval */ +static const gchar *gda_sqlite_provider_get_version (GdaServerProvider *provider); +static gboolean gda_sqlite_provider_supports_feature (GdaServerProvider *provider, GdaConnection *cnc, + GdaConnectionFeature feature); + +static GdaWorker *gda_sqlite_provider_create_worker (GdaServerProvider *provider, gboolean for_cnc); +static const gchar *gda_sqlite_provider_get_name (GdaServerProvider *provider); + +static GdaDataHandler *gda_sqlite_provider_get_data_handler (GdaServerProvider *provider, GdaConnection *cnc, + GType g_type, const gchar *dbms_type); + +static const gchar* gda_sqlite_provider_get_default_dbms_type (GdaServerProvider *provider, GdaConnection *cnc, + GType type); +/* statements */ +static GdaSqlParser *gda_sqlite_provider_create_parser (GdaServerProvider *provider, GdaConnection *cnc); +static gchar *gda_sqlite_provider_statement_to_sql (GdaServerProvider *provider, GdaConnection *cnc, + GdaStatement *stmt, GdaSet *params, + GdaStatementSqlFlag flags, + GSList **params_used, GError **error); +static gboolean gda_sqlite_provider_statement_prepare (GdaServerProvider *provider, GdaConnection *cnc, + GdaStatement *stmt, GError **error); +static GObject *gda_sqlite_provider_statement_execute (GdaServerProvider *provider, GdaConnection *cnc, + GdaStatement *stmt, GdaSet *params, + GdaStatementModelUsage model_usage, + GType *col_types, GdaSet **last_inserted_row, GError **error); +static GdaSqlStatement *gda_sqlite_provider_statement_rewrite (GdaServerProvider *provider, GdaConnection *cnc, + GdaStatement *stmt, GdaSet *params, GError **error); + +/* string escaping */ +static gchar *gda_sqlite_provider_escape_string (GdaServerProvider *provider, GdaConnection *cnc, + const gchar *string); +static gchar *gda_sqlite_provider_unescape_string (GdaServerProvider *provider, GdaConnection *cnc, + const gchar *string); +GdaSet *gda_sqlite_provider_get_last_inserted (GdaServerProvider *provider, + GdaConnection *cnc, GError **error); + +/* + * private connection data destroy + */ +static void gda_sqlite_free_cnc_data (SqliteConnectionData *cdata); + +/* + * extending SQLite with our own functions and collations + */ +static void scalar_gda_file_exists_func (sqlite3_context *context, int argc, sqlite3_value **argv); +static void scalar_gda_hex_print_func (sqlite3_context *context, int argc, sqlite3_value **argv); +static void scalar_gda_hex_print_func2 (sqlite3_context *context, int argc, sqlite3_value **argv); +static void scalar_gda_hex_func (sqlite3_context *context, int argc, sqlite3_value **argv); +static void scalar_gda_hex_func2 (sqlite3_context *context, int argc, sqlite3_value **argv); +static void scalar_rmdiacr (sqlite3_context *context, int argc, sqlite3_value **argv); +static void scalar_lower (sqlite3_context *context, int argc, sqlite3_value **argv); +static void scalar_upper (sqlite3_context *context, int argc, sqlite3_value **argv); +typedef struct { + char *name; + int nargs; + gpointer user_data; /* retrieve it in func. implementations using sqlite3_user_data() */ + void (*xFunc)(sqlite3_context*,int,sqlite3_value**); +} ScalarFunction; +static ScalarFunction scalars[] = { + {"gda_file_exists", 1, NULL, scalar_gda_file_exists_func}, + {"gda_hex_print", 1, NULL, scalar_gda_hex_print_func}, + {"gda_hex_print", 2, NULL, scalar_gda_hex_print_func2}, + {"gda_hex", 1, NULL, scalar_gda_hex_func}, + {"gda_hex", 2, NULL, scalar_gda_hex_func2}, + {"gda_rmdiacr", 1, NULL, scalar_rmdiacr}, + {"gda_rmdiacr", 2, NULL, scalar_rmdiacr}, + {"gda_lower", 1, NULL, scalar_lower}, + {"gda_upper", 1, NULL, scalar_upper}, +}; + +/* Regexp handling */ +static void scalar_regexp_func (sqlite3_context *context, int argc, sqlite3_value **argv); +static void scalar_regexp_match_func (sqlite3_context *context, int argc, sqlite3_value **argv); + +static ScalarFunction regexp_functions[] = { + {"regexp", 2, NULL, scalar_regexp_func}, + {"regexp", 3, NULL, scalar_regexp_func}, + {"regexp_match", 2, NULL, scalar_regexp_match_func}, + {"regexp_match", 3, NULL, scalar_regexp_match_func} +}; + +/* Collations */ +static int locale_collate_func (G_GNUC_UNUSED void *pArg, int nKey1, const void *pKey1, + int nKey2, const void *pKey2); +static int dcase_collate_func (G_GNUC_UNUSED void *pArg, int nKey1, const void *pKey1, + int nKey2, const void *pKey2); +typedef struct { + char *name; + int (*xFunc)(void *, int, const void *, int, const void *); +} CollationFunction; +static CollationFunction collation_functions[] = { + {"LOCALE", locale_collate_func}, + {"DCASE", dcase_collate_func} +}; + + +/* GdaProviderMeta methods declarations */ +static GdaDataModel *gda_sqlite_provider_meta_btypes (GdaProviderMeta *prov, + GError **error); +static GdaDataModel *gda_sqlite_provider_meta_udts (GdaProviderMeta *prov, + GError **error); +static GdaRow *gda_sqlite_provider_meta_udt (GdaProviderMeta *prov, + const gchar *udt_catalog, const gchar *udt_schema, + GError **error); +static GdaDataModel *gda_sqlite_provider_meta_udt_cols (GdaProviderMeta *prov, + GError **error); +static GdaRow *gda_sqlite_provider_meta_udt_col (GdaProviderMeta *prov, + const gchar *udt_catalog, const gchar *udt_schema, + const gchar *udt_name, GError **error); +static GdaDataModel *gda_sqlite_provider_meta_enums_type (GdaProviderMeta *prov, + GError **error); +static GdaRow *gda_sqlite_provider_meta_enum_type (GdaProviderMeta *prov, + const gchar *udt_catalog, const gchar *udt_schema, const gchar *udt_name, GError **error); +static GdaDataModel *gda_sqlite_provider_meta_domains (GdaProviderMeta *prov, + GError **error); +static GdaRow *gda_sqlite_provider_meta_domain (GdaProviderMeta *prov, + const gchar *domain_catalog, const gchar *domain_schema, GError **error); +static GdaDataModel *gda_sqlite_provider_meta_domains_constraints (GdaProviderMeta *prov, + GError **error); +static GdaDataModel *gda_sqlite_provider_meta_domain_constraints (GdaProviderMeta *prov, + const gchar *domain_catalog, const gchar *domain_schema, + const gchar *domain_name, GError **error); +static GdaRow *gda_sqlite_provider_meta_domain_constraint (GdaProviderMeta *prov, + const gchar *domain_catalog, const gchar *domain_schema, + const gchar *domain_name, const gchar *contraint_name, + GError **error); +static GdaDataModel *gda_sqlite_provider_meta_element_types (GdaProviderMeta *prov, + GError **error); +static GdaRow *gda_sqlite_provider_meta_element_type (GdaProviderMeta *prov, + const gchar *specific_name, GError **error); +static GdaDataModel *gda_sqlite_provider_meta_collations (GdaProviderMeta *prov, + GError **error); +static GdaRow *gda_sqlite_provider_meta_collation (GdaProviderMeta *prov, + const gchar *collation_catalog, const gchar *collation_schema, + const gchar *collation_name_n, GError **error); +static GdaDataModel *gda_sqlite_provider_meta_character_sets (GdaProviderMeta *prov, + GError **error); +static GdaRow *gda_sqlite_provider_meta_character_set (GdaProviderMeta *prov, + const gchar *chset_catalog, const gchar *chset_schema, + const gchar *chset_name_n, GError **error); +static GdaDataModel *gda_sqlite_provider_meta_schematas (GdaProviderMeta *prov, + GError **error); +static GdaRow *gda_sqlite_provider_meta_schemata (GdaProviderMeta *prov, + const gchar *catalog_name, const gchar *schema_name_n, GError **error); +static GdaDataModel *gda_sqlite_provider_meta_tables (GdaProviderMeta *prov, + GError **error); +static GdaRow *gda_sqlite_provider_meta_table (GdaProviderMeta *prov, + const gchar *table_catalog, const gchar *table_schema, + const gchar *table_name_n, GError **error); +static GdaDataModel *gda_sqlite_provider_meta_views (GdaProviderMeta *prov, + GError **error); +static GdaRow *gda_sqlite_provider_meta_view (GdaProviderMeta *prov, + const gchar *table_catalog, const gchar *table_schema, + const gchar *table_name_n, GError **error); +static GdaDataModel *gda_sqlite_provider_meta_tables_columns (GdaProviderMeta *prov, + GError **error); +static GdaDataModel *gda_sqlite_provider_meta_table_columns (GdaProviderMeta *prov, + const gchar *table_catalog, const gchar *table_schema, + const gchar *table_name, GError **error); +static GdaRow *gda_sqlite_provider_meta_table_column (GdaProviderMeta *prov, + const gchar *table_catalog, const gchar *table_schema, + const gchar *table_name, + const gchar *column_name, GError **error); +static GdaDataModel *gda_sqlite_provider_meta_views_columns (GdaProviderMeta *prov, + GError **error); +static GdaDataModel *gda_sqlite_provider_meta_view_columns (GdaProviderMeta *prov, + const gchar *view_catalog, const gchar *view_schema, + const gchar *view_name, GError **error); +static GdaRow *gda_sqlite_provider_meta_view_column (GdaProviderMeta *prov, + const gchar *view_catalog, const gchar *view_schema, + const gchar *view_name, + const gchar *column_name, + GError **error); +static GdaDataModel *gda_sqlite_provider_meta_constraints_tables (GdaProviderMeta *prov, GError **error); +static GdaDataModel *gda_sqlite_provider_meta_constraints_table (GdaProviderMeta *prov, + const gchar *table_catalog, const gchar *table_schema, + const gchar *table_name, + GError **error); +static GdaRow *gda_sqlite_provider_meta_constraint_table (GdaProviderMeta *prov, + const gchar *table_catalog, const gchar *table_schema, + const gchar *table_name, + const gchar *constraint_name_n, GError **error); +static GdaDataModel *gda_sqlite_provider_meta_columns (GdaProviderMeta *prov, + GError **error); +static GdaDataModel *gda_sqlite_provider_meta_constraints_ref (GdaProviderMeta *prov, + GError **error); +static GdaDataModel *gda_sqlite_provider_meta_constraints_ref_table (GdaProviderMeta *prov, + const gchar *table_catalog, + const gchar *table_schema, const gchar *table_name, + GError **error); +static GdaRow *gda_sqlite_provider_meta_constraint_ref (GdaProviderMeta *prov, + const gchar *table_catalog, + const gchar *table_schema, const gchar *table_name, + const gchar *constraint_name, GError **error); +static GdaDataModel *gda_sqlite_provider_meta_key_columns (GdaProviderMeta *prov, + GError **error); +static GdaRow *gda_sqlite_provider_meta_key_column (GdaProviderMeta *prov, + const gchar *table_catalog, const gchar *table_schema, + const gchar *table_name, + const gchar *constraint_name, GError **error); +static GdaDataModel *gda_sqlite_provider_meta_check_columns (GdaProviderMeta *prov, + GError **error); +static GdaRow *gda_sqlite_provider_meta_check_column (GdaProviderMeta *prov, + const gchar *table_catalog, + const gchar *table_schema, + const gchar *table_name, + const gchar *constraint_name, GError **error); +static GdaDataModel *gda_sqlite_provider_meta_triggers (GdaProviderMeta *prov, + GError **error); +static GdaRow *gda_sqlite_provider_meta_trigger (GdaProviderMeta *prov, + const gchar *table_catalog, + const gchar *table_schema, + const gchar *table_name, GError **error); +static GdaDataModel *gda_sqlite_provider_meta_routines (GdaProviderMeta *prov, + GError **error); +static GdaRow *gda_sqlite_provider_meta_routine (GdaProviderMeta *prov, + const gchar *routine_catalog, const gchar *routine_schema, + const gchar *routine_name_n, GError **error); +static GdaDataModel *gda_sqlite_provider_meta_routines_col (GdaProviderMeta *prov, GError **error); +static GdaRow *gda_sqlite_provider_meta_routine_col (GdaProviderMeta *prov, + const gchar *rout_catalog, const gchar *rout_schema, + const gchar *rout_name, GError **error); +static GdaDataModel *gda_sqlite_provider_meta_routines_pars (GdaProviderMeta *prov, + GError **error); +static GdaRow *gda_sqlite_provider_meta_routine_pars (GdaProviderMeta *prov, + const gchar *rout_catalog, const gchar *rout_schema, + const gchar *rout_name, GError **error); +static GdaDataModel *gda_sqlite_provider_meta_indexes_tables (GdaProviderMeta *prov, + GError **error); +static GdaDataModel *gda_sqlite_provider_meta_indexes_table (GdaProviderMeta *prov, + const gchar *table_catalog, const gchar *table_schema, + const gchar *table_name, GError **error); +static GdaRow *gda_sqlite_provider_meta_index_table (GdaProviderMeta *prov, + const gchar *table_catalog, + const gchar *table_schema, + const gchar *table_name, + const gchar *index_name_n, GError **error); +static GdaDataModel *gda_sqlite_provider_meta_index_cols (GdaProviderMeta *prov, + GError **error); +static GdaRow *gda_sqlite_provider_meta_index_col (GdaProviderMeta *prov, + const gchar *table_catalog, + const gchar *table_schema, + const gchar *table_name, + const gchar *index_name, GError **error); + +static void +gda_sqlite_provider_meta_iface_init (GdaProviderMetaInterface *iface) { + iface->btypes = gda_sqlite_provider_meta_btypes; + iface->udts = gda_sqlite_provider_meta_udts; + iface->udt = gda_sqlite_provider_meta_udt; + iface->udt_cols = gda_sqlite_provider_meta_udt_cols; + iface->udt_col = gda_sqlite_provider_meta_udt_col; + iface->enums_type = gda_sqlite_provider_meta_enums_type; + iface->enum_type = gda_sqlite_provider_meta_enum_type; + iface->domains = gda_sqlite_provider_meta_domains; + iface->domain = gda_sqlite_provider_meta_domain; + iface->domains_constraints = gda_sqlite_provider_meta_domains_constraints; + iface->domain_constraints = gda_sqlite_provider_meta_domain_constraints; + iface->domain_constraint = gda_sqlite_provider_meta_domain_constraint; + iface->element_types = gda_sqlite_provider_meta_element_types; + iface->element_type = gda_sqlite_provider_meta_element_type; + iface->collations = gda_sqlite_provider_meta_collations; + iface->collation = gda_sqlite_provider_meta_collation; + iface->character_sets = gda_sqlite_provider_meta_character_sets; + iface->character_set = gda_sqlite_provider_meta_character_set; + iface->schematas = gda_sqlite_provider_meta_schematas; + iface->schemata = gda_sqlite_provider_meta_schemata; + iface->tables_columns = gda_sqlite_provider_meta_tables_columns; + iface->tables = gda_sqlite_provider_meta_tables; + iface->table = gda_sqlite_provider_meta_table; + iface->views = gda_sqlite_provider_meta_views; + iface->view = gda_sqlite_provider_meta_view; + iface->columns = gda_sqlite_provider_meta_columns; + iface->table_columns = gda_sqlite_provider_meta_table_columns; + iface->table_column = gda_sqlite_provider_meta_table_column; + iface->views_columns = gda_sqlite_provider_meta_views_columns; + iface->view_columns = gda_sqlite_provider_meta_view_columns; + iface->view_column = gda_sqlite_provider_meta_view_column; + iface->constraints_tables = gda_sqlite_provider_meta_constraints_tables; + iface->constraints_table = gda_sqlite_provider_meta_constraints_table; + iface->constraint_table = gda_sqlite_provider_meta_constraint_table; + iface->constraints_ref = gda_sqlite_provider_meta_constraints_ref; + iface->constraints_ref_table = gda_sqlite_provider_meta_constraints_ref_table; + iface->constraint_ref = gda_sqlite_provider_meta_constraint_ref; + iface->key_columns = gda_sqlite_provider_meta_key_columns; + iface->key_column = gda_sqlite_provider_meta_key_column; + iface->check_columns = gda_sqlite_provider_meta_check_columns; + iface->check_column = gda_sqlite_provider_meta_check_column; + iface->triggers = gda_sqlite_provider_meta_triggers; + iface->trigger = gda_sqlite_provider_meta_trigger; + iface->routines = gda_sqlite_provider_meta_routines; + iface->routine = gda_sqlite_provider_meta_routine; + iface->routines_col = gda_sqlite_provider_meta_routines_col; + iface->routine_col = gda_sqlite_provider_meta_routine_col; + iface->routines_pars = gda_sqlite_provider_meta_routines_pars; + iface->routine_pars = gda_sqlite_provider_meta_routine_pars; + iface->indexes_tables = gda_sqlite_provider_meta_indexes_tables; + iface->indexes_table = gda_sqlite_provider_meta_indexes_table; + iface->index_table = gda_sqlite_provider_meta_index_table; + iface->index_cols = gda_sqlite_provider_meta_index_cols; + iface->index_col = gda_sqlite_provider_meta_index_col; +} + +static const gchar *gda_sqlite_provider_iface_get_name (GdaProvider *provider); +static const gchar *gda_sqlite_provider_iface_get_version (GdaProvider *provider); +static const gchar *gda_sqlite_provider_iface_get_server_version (GdaProvider *provider, GdaConnection *cnc); +static gboolean gda_sqlite_provider_iface_supports_feature (GdaProvider *provider, GdaConnection *cnc, + GdaConnectionFeature feature); +static GdaSqlParser *gda_sqlite_provider_iface_create_parser (GdaProvider *provider, GdaConnection *cnc); /* may be NULL */ +static GdaConnection *gda_sqlite_provider_iface_create_connection (GdaProvider *provider); +static GdaDataHandler *gda_sqlite_provider_iface_get_data_handler (GdaProvider *provider, GdaConnection *cnc, /* may be NULL */ + GType g_type, const gchar *dbms_type); +static const gchar *gda_sqlite_provider_iface_get_def_dbms_type (GdaProvider *provider, GdaConnection *cnc, + GType g_type); /* may be NULL */ +static gboolean gda_sqlite_provider_iface_supports_operation (GdaProvider *provider, GdaConnection *cnc, + GdaServerOperationType type, GdaSet *options); +static GdaServerOperation *gda_sqlite_provider_iface_create_operation (GdaProvider *provider, GdaConnection *cnc, + GdaServerOperationType type, GdaSet *options, + GError **error); +static gchar *gda_sqlite_provider_iface_render_operation (GdaProvider *provider, GdaConnection *cnc, + GdaServerOperation *op, GError **error); +static gchar *gda_sqlite_provider_iface_statement_to_sql (GdaProvider *provider, GdaConnection *cnc, + GdaStatement *stmt, GdaSet *params, + GdaStatementSqlFlag flags, + GSList **params_used, GError **error); +static gchar *gda_sqlite_provider_iface_identifier_quote (GdaProvider *provider, GdaConnection *cnc, /* may be NULL */ + const gchar *id, + gboolean for_meta_store, gboolean force_quotes); +static GdaSqlStatement *gda_sqlite_provider_iface_statement_rewrite (GdaProvider *provider, GdaConnection *cnc, + GdaStatement *stmt, GdaSet *params, GError **error); +static gboolean gda_sqlite_provider_iface_open_connection (GdaProvider *provider, GdaConnection *cnc, + GdaQuarkList *params, GdaQuarkList *auth); +static gboolean gda_sqlite_provider_iface_prepare_connection (GdaProvider *provider, GdaConnection *cnc, + GdaQuarkList *params, GdaQuarkList *auth); +static gboolean gda_sqlite_provider_iface_close_connection (GdaProvider *provider, GdaConnection *cnc); +static gchar *gda_sqlite_provider_iface_escape_string (GdaProvider *provider, GdaConnection *cnc, + const gchar *str); /* may be NULL */ +static gchar *gda_sqlite_provider_iface_unescape_string (GdaProvider *provider, GdaConnection *cnc, + const gchar *str); /* may be NULL */ +static gboolean gda_sqlite_provider_iface_perform_operation (GdaProvider *provider, GdaConnection *cnc, /* may be NULL */ + GdaServerOperation *op, GError **error); +static gboolean gda_sqlite_provider_iface_begin_transaction (GdaProvider *provider, GdaConnection *cnc, + const gchar *name, GdaTransactionIsolation level, + GError **error); +static gboolean gda_sqlite_provider_iface_commit_transaction (GdaProvider *provider, GdaConnection *cnc, + const gchar *name, GError **error); +static gboolean gda_sqlite_provider_iface_rollback_transaction (GdaProvider *provider, GdaConnection *cnc, + const gchar *name, GError **error); +static gboolean gda_sqlite_provider_iface_add_savepoint (GdaProvider *provider, GdaConnection *cnc, + const gchar *name, GError **error); +static gboolean gda_sqlite_provider_iface_rollback_savepoint (GdaProvider *provider, GdaConnection *cnc, + const gchar *name, GError **error); +static gboolean gda_sqlite_provider_iface_delete_savepoint (GdaProvider *provider, GdaConnection *cnc, + const gchar *name, GError **error); +static gboolean gda_sqlite_provider_iface_statement_prepare (GdaProvider *provider, GdaConnection *cnc, + GdaStatement *stmt, GError **error); +static GObject *gda_sqlite_provider_iface_statement_execute (GdaProvider *provider, GdaConnection *cnc, + GdaStatement *stmt, GdaSet *params, + GdaStatementModelUsage model_usage, + GType *col_types, GdaSet **last_inserted_row, + GError **error); +static GdaSet *gda_sqlite_provider_iface_get_last_inserted (GdaProvider *provider, GdaConnection *cnc, + GError **error); + + +static void +gda_sqlite_provider_iface_init (GdaProviderInterface *iface) +{ + iface->get_name = gda_sqlite_provider_iface_get_name; + iface->get_version = gda_sqlite_provider_iface_get_version; + iface->get_server_version = gda_sqlite_provider_iface_get_server_version; + iface->supports_feature = gda_sqlite_provider_iface_supports_feature; + iface->create_parser = gda_sqlite_provider_iface_create_parser; + iface->create_connection = gda_sqlite_provider_iface_create_connection; + iface->get_data_handler = gda_sqlite_provider_iface_get_data_handler; + iface->get_def_dbms_type = gda_sqlite_provider_iface_get_def_dbms_type; + iface->supports_operation = gda_sqlite_provider_iface_supports_operation; + iface->create_operation = gda_sqlite_provider_iface_create_operation; + iface->render_operation = gda_sqlite_provider_iface_render_operation; + iface->statement_to_sql = gda_sqlite_provider_iface_statement_to_sql; + iface->identifier_quote = gda_sqlite_provider_iface_identifier_quote; + iface->statement_rewrite = gda_sqlite_provider_iface_statement_rewrite; + iface->open_connection = gda_sqlite_provider_iface_open_connection; + iface->prepare_connection = gda_sqlite_provider_iface_prepare_connection; + iface->close_connection = gda_sqlite_provider_iface_close_connection; + iface->escape_string = gda_sqlite_provider_iface_escape_string; + iface->unescape_string = gda_sqlite_provider_iface_unescape_string; + iface->perform_operation = gda_sqlite_provider_iface_perform_operation; + iface->begin_transaction = gda_sqlite_provider_iface_begin_transaction; + iface->commit_transaction = gda_sqlite_provider_iface_commit_transaction; + iface->rollback_transaction = gda_sqlite_provider_iface_rollback_transaction; + iface->add_savepoint = gda_sqlite_provider_iface_add_savepoint; + iface->rollback_savepoint = gda_sqlite_provider_iface_rollback_savepoint; + iface->delete_savepoint = gda_sqlite_provider_iface_delete_savepoint; + iface->statement_prepare = gda_sqlite_provider_iface_statement_prepare; + iface->statement_execute = gda_sqlite_provider_iface_statement_execute; + iface->get_last_inserted = gda_sqlite_provider_iface_get_last_inserted; +} + +/* + * Prepared internal statements + */ +typedef enum { + INTERNAL_PRAGMA_INDEX_LIST, + INTERNAL_PRAGMA_INDEX_INFO, + INTERNAL_PRAGMA_FK_LIST, + INTERNAL_PRAGMA_TABLE_INFO, + INTERNAL_SELECT_A_TABLE_ROW, + INTERNAL_SELECT_ALL_TABLES, + INTERNAL_SELECT_A_TABLE, + INTERNAL_PRAGMA_PROC_LIST, + INTERNAL_PRAGMA_EMPTY_RESULT, + + INTERNAL_BEGIN, + INTERNAL_BEGIN_NAMED, + INTERNAL_COMMIT, + INTERNAL_COMMIT_NAMED, + INTERNAL_ROLLBACK, + INTERNAL_ROLLBACK_NAMED, + + INTERNAL_ADD_SAVEPOINT, + INTERNAL_ROLLBACK_SAVEPOINT, + INTERNAL_RELEASE_SAVEPOINT +} InternalStatementItem; + +static gchar *internal_sql[] = { + "PRAGMA index_list(##tblname::string)", + "PRAGMA index_info(##idxname::string)", + "PRAGMA foreign_key_list (##tblname::string)", + "PRAGMA table_info (##tblname::string)", + "SELECT * FROM ##tblname::string LIMIT 1", + "SELECT name as 'Table', 'system' as 'Owner', ' ' as 'Description', sql as 'Definition' FROM (SELECT * FROM sqlite_master UNION ALL SELECT * FROM sqlite_temp_master) WHERE type = ##type::string AND name not like 'sqlite_%%' ORDER BY name", + "SELECT name as 'Table', 'system' as 'Owner', ' ' as 'Description', sql as 'Definition' FROM (SELECT * FROM sqlite_master UNION ALL SELECT * FROM sqlite_temp_master) WHERE type = ##type::string AND name = ##tblname::string AND name not like 'sqlite_%%' ORDER BY name", + "PRAGMA proc_list", + "PRAGMA empty_result_callbacks = ON", + + "BEGIN TRANSACTION", + "BEGIN TRANSACTION ##name::string", + "COMMIT TRANSACTION", + "COMMIT TRANSACTION ##name::string", + "ROLLBACK TRANSACTION", + "ROLLBACK TRANSACTION ##name::string", + + "SAVEPOINT ##name::string", + "ROLLBACK TO ##name::string", + "RELEASE ##name::string" +}; + +static gchar * +get_table_nth_column_name (GdaServerProvider *provider, GdaConnection *cnc, const gchar *table_name, gint pos) +{ + GdaSet *params_set = NULL; + GdaDataModel *model; + gchar *fname = NULL; + GdaStatement *stm; + GdaSqliteProviderPrivate *priv = gda_sqlite_provider_get_instance_private (GDA_SQLITE_PROVIDER (provider)); + + g_assert (table_name); + params_set = gda_set_new_inline (1, "tblname", G_TYPE_STRING, table_name); + stm = (GdaStatement*) g_ptr_array_index (priv->internal_stmt, INTERNAL_PRAGMA_TABLE_INFO); + model = gda_connection_statement_execute_select (cnc, + stm, + params_set, NULL); + g_object_unref (params_set); + if (model) { + const GValue *cvalue; + cvalue = gda_data_model_get_value_at (model, 1, pos, NULL); + if (cvalue) + fname = g_value_dup_string (cvalue); + g_object_unref (model); + } + return fname; +} + +/* + * GdaSqliteProvider class implementation + */ +GdaServerProviderBase sqlite_base_functions = { + gda_sqlite_provider_get_name, + gda_sqlite_provider_get_version, + gda_sqlite_provider_get_server_version, + gda_sqlite_provider_supports_feature, + gda_sqlite_provider_create_worker, + NULL, + gda_sqlite_provider_create_parser, + gda_sqlite_provider_get_data_handler, + gda_sqlite_provider_get_default_dbms_type, + gda_sqlite_provider_supports_operation, + gda_sqlite_provider_create_operation, + gda_sqlite_provider_render_operation, + gda_sqlite_provider_statement_to_sql, + NULL, + gda_sqlite_provider_statement_rewrite, + gda_sqlite_provider_open_connection, + gda_sqlite_provider_prepare_connection, + gda_sqlite_provider_close_connection, + gda_sqlite_provider_escape_string, + gda_sqlite_provider_unescape_string, + gda_sqlite_provider_perform_operation, + gda_sqlite_provider_begin_transaction, + gda_sqlite_provider_commit_transaction, + gda_sqlite_provider_rollback_transaction, + gda_sqlite_provider_add_savepoint, + gda_sqlite_provider_rollback_savepoint, + gda_sqlite_provider_delete_savepoint, + gda_sqlite_provider_statement_prepare, + gda_sqlite_provider_statement_execute, + + NULL, NULL, NULL, NULL, /* padding */ +}; + +GdaServerProviderMeta sqlite_meta_functions = { + _gda_sqlite_meta__info, + _gda_sqlite_meta__btypes, + _gda_sqlite_meta__udt, + _gda_sqlite_meta_udt, + _gda_sqlite_meta__udt_cols, + _gda_sqlite_meta_udt_cols, + _gda_sqlite_meta__enums, + _gda_sqlite_meta_enums, + _gda_sqlite_meta__domains, + _gda_sqlite_meta_domains, + _gda_sqlite_meta__constraints_dom, + _gda_sqlite_meta_constraints_dom, + _gda_sqlite_meta__el_types, + _gda_sqlite_meta_el_types, + _gda_sqlite_meta__collations, + _gda_sqlite_meta_collations, + _gda_sqlite_meta__character_sets, + _gda_sqlite_meta_character_sets, + _gda_sqlite_meta__schemata, + _gda_sqlite_meta_schemata, + _gda_sqlite_meta__tables_views, + _gda_sqlite_meta_tables_views, + _gda_sqlite_meta__columns, + _gda_sqlite_meta_columns, + _gda_sqlite_meta__view_cols, + _gda_sqlite_meta_view_cols, + _gda_sqlite_meta__constraints_tab, + _gda_sqlite_meta_constraints_tab, + _gda_sqlite_meta__constraints_ref, + _gda_sqlite_meta_constraints_ref, + _gda_sqlite_meta__key_columns, + _gda_sqlite_meta_key_columns, + _gda_sqlite_meta__check_columns, + _gda_sqlite_meta_check_columns, + _gda_sqlite_meta__triggers, + _gda_sqlite_meta_triggers, + _gda_sqlite_meta__routines, + _gda_sqlite_meta_routines, + _gda_sqlite_meta__routine_col, + _gda_sqlite_meta_routine_col, + _gda_sqlite_meta__routine_par, + _gda_sqlite_meta_routine_par, + _gda_sqlite_meta__indexes_tab, + _gda_sqlite_meta_indexes_tab, + _gda_sqlite_meta__index_cols, + _gda_sqlite_meta_index_cols, + + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* padding */ +}; + +static void +gda_sqlite_provider_get_property (G_GNUC_UNUSED GObject *object, + guint property_id, + GValue *value, + G_GNUC_UNUSED GParamSpec *pspec) +{ + GdaSqliteProviderPrivate *priv = gda_sqlite_provider_get_instance_private (GDA_SQLITE_PROVIDER (object)); + switch (property_id) { + case PROP_IS_DEFAULT: + g_value_set_boolean (value, priv->is_default); + break; + case PROP_CONNECTION: + g_value_set_object (value, NULL); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +gda_sqlite_provider_set_property (G_GNUC_UNUSED GObject *object, + guint property_id, + G_GNUC_UNUSED const GValue *value, + G_GNUC_UNUSED GParamSpec *pspec) +{ + GdaSqliteProviderPrivate *priv = gda_sqlite_provider_get_instance_private (GDA_SQLITE_PROVIDER (object)); + switch (property_id) { + case PROP_IS_DEFAULT: + priv->is_default = g_value_get_boolean (value); + break; + case PROP_CONNECTION: + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +gda_sqlite_provider_dispose (GObject *object) +{ + GdaSqliteProvider *prov = GDA_SQLITE_PROVIDER (object); + GdaSqliteProviderPrivate *priv = gda_sqlite_provider_get_instance_private (prov); + g_ptr_array_unref (priv->internal_stmt); + priv->internal_stmt = NULL; +} + +static void +gda_sqlite_provider_class_init (GdaSqliteProviderClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->get_property = gda_sqlite_provider_get_property; + object_class->set_property = gda_sqlite_provider_set_property; + object_class->dispose = gda_sqlite_provider_dispose; + + + g_object_class_install_property (object_class, PROP_IS_DEFAULT, + g_param_spec_boolean ("is-default", "Is Default Provider", + _("Set to TRUE if the provider is the internal default"), + TRUE, + (G_PARAM_WRITABLE | G_PARAM_EXPLICIT_NOTIFY))); + /* set virtual functions */ + gda_server_provider_set_impl_functions (GDA_SERVER_PROVIDER_CLASS (klass), + GDA_SERVER_PROVIDER_FUNCTIONS_BASE, + (gpointer) &sqlite_base_functions); + gda_server_provider_set_impl_functions (GDA_SERVER_PROVIDER_CLASS (klass), + GDA_SERVER_PROVIDER_FUNCTIONS_META, + (gpointer) &sqlite_meta_functions); + gda_server_provider_set_impl_functions (GDA_SERVER_PROVIDER_CLASS (klass), + GDA_SERVER_PROVIDER_FUNCTIONS_XA, + NULL); + g_object_class_override_property (G_OBJECT_CLASS (klass), PROP_CONNECTION, "connection"); + +#ifdef HAVE_SQLITE + GModule *module2; + + module2 = gda_sqlite_find_library ("libsqlite3"); + if (module2) + gda_sqlite_load_symbols (module2, &s3r); + if (s3r == NULL) { + g_warning (_("Can't find libsqlite3." G_MODULE_SUFFIX " file.")); + } + klass->get_api = gda_sqlite_provider_get_api_internal; +#endif +} + +static void +gda_sqlite_provider_init (GdaSqliteProvider *sqlite_prv) +{ + GdaSqliteProviderPrivate *priv = gda_sqlite_provider_get_instance_private (sqlite_prv); + priv->internal_stmt = g_ptr_array_new_full (1, (GDestroyNotify) g_object_unref); + + InternalStatementItem i; + GdaSqlParser *parser; + parser = gda_server_provider_internal_get_parser ((GdaServerProvider*) sqlite_prv); + + for (i = INTERNAL_PRAGMA_INDEX_LIST; i < sizeof (internal_sql) / sizeof (gchar*); i++) { + GdaStatement *stm; + stm = gda_sql_parser_parse_string (parser, internal_sql[i], NULL, NULL); + if (stm != NULL) { + g_ptr_array_add (priv->internal_stmt, stm); + } else { + g_error ("Could not parse internal statement: %s\n", internal_sql[i]); + } + } + /* Set as defualt */ + priv->is_default = TRUE; + + /* meta data init */ + _gda_sqlite_provider_meta_init ((GdaServerProvider*) sqlite_prv); +} + +static GdaWorker * +gda_sqlite_provider_create_worker (GdaServerProvider *provider, gboolean for_cnc) +{ + /* see http://www.sqlite.org/threadsafe.html */ + GdaSqliteProvider *prov = GDA_SQLITE_PROVIDER (provider); + + static GdaWorker *unique_worker = NULL; + if (SQLITE3_CALL (prov, sqlite3_threadsafe) ()) { + if (for_cnc) + return gda_worker_new (); + else + return gda_worker_new_unique (&unique_worker, TRUE); + } + else + return gda_worker_new_unique (&unique_worker, TRUE); +} + +/* + * Get provider name request + */ +static const gchar * +gda_sqlite_provider_get_name (G_GNUC_UNUSED GdaServerProvider *provider) +{ + return PNAME; +} + +/* + * Get provider's version + */ +static const gchar * +gda_sqlite_provider_get_version (G_GNUC_UNUSED GdaServerProvider *provider) +{ + return PACKAGE_VERSION; +} + +typedef enum { + CASE_UP, + CASE_DOWN, + CASE_UNCHANGED +} CaseModif; + +gchar * +remove_diacritics_and_change_case (const gchar *str, gssize len, CaseModif cmod) +{ + gchar *retval = NULL; + + if (str) { + GString* string; + gchar *normstr, *ptr; + + normstr = g_utf8_normalize (str, len, G_NORMALIZE_NFD); + string = g_string_new (""); + ptr = normstr; + while (ptr) { + gunichar c; + c = g_utf8_get_char (ptr); + if (c != '\0') { + if (!g_unichar_ismark(c)) { + switch (cmod) { + case CASE_UP: + c = g_unichar_toupper (c); + break; + case CASE_DOWN: + c = g_unichar_tolower (c); + break; + case CASE_UNCHANGED: + break; + } + g_string_append_unichar (string, c); + } + ptr = g_utf8_next_char (ptr); + } + else + break; + } + + retval = g_string_free (string, FALSE); + g_free (normstr); + } + + return retval; +} + + +/* + * Open connection request + */ +static gboolean +gda_sqlite_provider_open_connection (GdaServerProvider *provider, GdaConnection *cnc, + GdaQuarkList *params, G_GNUC_UNUSED GdaQuarkList *auth) +{ + gchar *filename = NULL; + const gchar *dirname = NULL, *dbname = NULL; + const gchar *is_virtual = NULL; + const gchar *append_extension = NULL; + gint errmsg; + SqliteConnectionData *cdata; + gchar *dup = NULL; +#ifdef SQLITE_HAS_CODEC + const gchar *passphrase = NULL; +#endif + + g_return_val_if_fail (GDA_IS_SQLITE_PROVIDER (provider), FALSE); + g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE); + + GdaSqliteProvider *prov = GDA_SQLITE_PROVIDER (provider); + + /* get all parameters received */ + dirname = gda_quark_list_find (params, "DB_DIR"); + if (!dirname) + dirname="."; /* default to current directory */ + dbname = gda_quark_list_find (params, "DB_NAME"); + append_extension = gda_quark_list_find (params, "APPEND_DB_EXTENSION"); + is_virtual = gda_quark_list_find (params, "_IS_VIRTUAL"); + + if (! is_virtual) { + if (!dbname) { + const gchar *str; + + str = gda_quark_list_find (params, "URI"); + if (!str) { + gda_connection_add_event_string (cnc, + _("The connection string must contain DB_DIR and DB_NAME values")); + return FALSE; + } + else { + gint len = strlen (str); + gint elen = strlen (FILE_EXTENSION); + + if (g_str_has_suffix (str, FILE_EXTENSION)) { + gchar *ptr; + + dup = g_strdup (str); + dup [len-elen] = 0; + for (ptr = dup + (len - elen - 1); (ptr >= dup) && (*ptr != G_DIR_SEPARATOR); ptr--); + dbname = ptr; + if (*ptr == G_DIR_SEPARATOR) + dbname ++; + + if ((*ptr == G_DIR_SEPARATOR) && (ptr > dup)) { + dirname = dup; + while ((ptr >= dup) && (*ptr != G_DIR_SEPARATOR)) + ptr--; + *ptr = 0; + } + } + if (!dbname) { + gda_connection_add_event_string (cnc, + _("The connection string format has changed: replace URI with " + "DB_DIR (the path to the database file) and DB_NAME " + "(the database file without the '%s' at the end)."), FILE_EXTENSION); + g_free (dup); + return FALSE; + } + else + g_warning (_("The connection string format has changed: replace URI with " + "DB_DIR (the path to the database file) and DB_NAME " + "(the database file without the '%s' at the end)."), FILE_EXTENSION); + } + } + + if (! g_ascii_strcasecmp (dbname,":memory:")) + /* we have an in memory database */ + filename = g_strdup (":memory:"); + else if (! g_ascii_strcasecmp (dbname,"__gda_tmp")) + /* we have an in memory database */ + filename = NULL/*g_strdup ("")*/; + else { + if (!g_file_test (dirname, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)) { + gda_connection_add_event_string (cnc, + _("The DB_DIR part of the connection string must point " + "to a valid directory")); + g_free (dup); + return FALSE; + } + + /* try first with the file extension */ + gchar *tmp, *f1, *f2; + if (!append_extension || + (append_extension && ((*append_extension == 't') || (*append_extension == 'T')))) + tmp = g_strdup_printf ("%s%s", dbname, FILE_EXTENSION); + else + tmp = g_strdup (dbname); + f1 = g_build_filename (dirname, tmp, NULL); + g_free (tmp); + f2 = g_build_filename (dirname, dbname, NULL); + if (g_file_test (f1, G_FILE_TEST_EXISTS)) { + filename = f1; + f1 = NULL; + } + else if (g_file_test (f2, G_FILE_TEST_EXISTS)) { + filename = f2; + f2 = NULL; + } + else { + filename = f1; + f1 = NULL; + } + g_free (f1); + g_free (f2); + g_free (dup); + } + } + + cdata = g_new0 (SqliteConnectionData, 1); + g_weak_ref_init (&cdata->provider, prov); + + if (filename) + cdata->file = filename; + + errmsg = SQLITE3_CALL (prov, sqlite3_open_v2) (filename, &cdata->connection, SQLITE_OPEN_FULLMUTEX | SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL); + + if (errmsg != SQLITE_OK) { + gda_connection_add_event_string (cnc, SQLITE3_CALL (prov, sqlite3_errmsg) (cdata->connection)); + gda_sqlite_free_cnc_data (cdata); + + return FALSE; + } + +#ifdef SQLITE_HAS_CODEC + /* TODO Fix this compiler warning: the address of 'sqlite3_key' will always evaluate as 'true' */ + /* We disable this warning in the meantime with -Wno-address */ + + if (auth) + passphrase = gda_quark_list_find (auth, "PASSWORD"); + + if (passphrase != NULL) { + errmsg = SQLITE3_CALL (prov,sqlite3_key_v2) (cdata->connection, filename, + (void*) passphrase, strlen (passphrase)); + if (errmsg != SQLITE_OK) { + gda_connection_add_event_string (cnc, _("Wrong encryption passphrase")); + gda_sqlite_free_cnc_data (cdata); + return FALSE; + } + } +#endif + + gda_connection_internal_set_provider_data (cnc, (GdaServerProviderConnectionData*) cdata, + (GDestroyNotify) gda_sqlite_free_cnc_data); + return TRUE; +} + +static gboolean +gda_sqlite_provider_prepare_connection (GdaServerProvider *provider, GdaConnection *cnc, GdaQuarkList *params, G_GNUC_UNUSED GdaQuarkList *auth) +{ + SqliteConnectionData *cdata; + GdaStatement *stm; + GdaSqliteProviderPrivate *priv = gda_sqlite_provider_get_instance_private (GDA_SQLITE_PROVIDER (provider)); + + cdata = (SqliteConnectionData*) gda_connection_internal_get_provider_data_error (cnc, NULL); + if (!cdata) + return FALSE; + + GdaSqliteProvider *prov = GDA_SQLITE_PROVIDER (provider); + + const gchar *use_extra_functions = NULL, *with_fk = NULL, *regexp, *locale_collate, *extensions; + with_fk = gda_quark_list_find (params, "FK"); + use_extra_functions = gda_quark_list_find (params, "EXTRA_FUNCTIONS"); + if (!use_extra_functions) + use_extra_functions = gda_quark_list_find (params, "LOAD_GDA_FUNCTIONS"); + regexp = gda_quark_list_find (params, "REGEXP"); + locale_collate = gda_quark_list_find (params, "EXTRA_COLLATIONS"); + extensions = gda_quark_list_find (params, "EXTENSIONS"); + + /* use extended result codes */ + SQLITE3_CALL (prov, sqlite3_extended_result_codes) (cdata->connection, 1); + + /* allow a busy timeout of 500 ms */ + SQLITE3_CALL (prov, sqlite3_busy_timeout) (cdata->connection, 500); + + /* allow loading extensions using SELECT load_extension ()... */ + if (extensions && ((*extensions == 't') || (*extensions == 'T'))) { + sqlite3_db_config (cdata->connection, SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION, 1, NULL); + g_message (_("SECURITY WARNING: Load Extension is enable for SQL commands, this means an attacker can access extension load capabilities")); + } + + /* try to prepare all the internal statements */ + InternalStatementItem i; + for (i = INTERNAL_PRAGMA_INDEX_LIST; i < sizeof (internal_sql) / sizeof (gchar*); i++) { + stm = (GdaStatement*) g_ptr_array_index (priv->internal_stmt, i); + gda_connection_statement_prepare (cnc, stm, NULL); /* Note: some may fail because + * the SQL cannot be "prepared" */ + } + + /* set SQLite library options */ + GObject *obj; + GError *lerror = NULL; + stm = (GdaStatement*) g_ptr_array_index (priv->internal_stmt, INTERNAL_PRAGMA_EMPTY_RESULT); + obj = gda_connection_statement_execute (cnc, stm, + NULL, GDA_STATEMENT_MODEL_RANDOM_ACCESS, NULL, &lerror); + if (!obj) { + gda_connection_add_event_string (cnc, + _("Could not set empty_result_callbacks SQLite option: %s"), + lerror && lerror->message ? lerror->message : _("no detail")); + g_clear_error (&lerror); + } + else + g_object_unref (obj); + + /* make sure the internals are completely initialized now */ + { + gchar **data = NULL; + gint ncols; + gint nrows; + gint status; + gchar *errmsg; + + status = SQLITE3_CALL (prov, sqlite3_get_table) (cdata->connection, "SELECT name" + " FROM (SELECT * FROM sqlite_master UNION ALL " + " SELECT * FROM sqlite_temp_master)", + &data, + &nrows, + &ncols, + &errmsg); + if (status == SQLITE_OK) + SQLITE3_CALL (prov, sqlite3_free_table) (data); + else { + gda_connection_add_event_string (cnc, errmsg); + SQLITE3_CALL (prov, sqlite3_free) (errmsg); + gda_sqlite_free_cnc_data (cdata); + gda_connection_internal_set_provider_data (cnc, NULL, NULL); + return FALSE; + } + } + + /* set connection parameters */ + gboolean enforce_fk = TRUE; + if (with_fk && ((*with_fk == 'f') || (*with_fk == 'F'))) + enforce_fk = FALSE; + int res; + sqlite3_stmt *pStmt; + if (enforce_fk) + res = SQLITE3_CALL (prov, sqlite3_prepare_v2) (cdata->connection, + "PRAGMA foreign_keys = ON", -1, + &pStmt, NULL); + else + res = SQLITE3_CALL (prov, sqlite3_prepare_v2) (cdata->connection, + "PRAGMA foreign_keys = OFF", -1, + &pStmt, NULL); + + if (res != SQLITE_OK) { + if (with_fk) { + gda_sqlite_free_cnc_data (cdata); + gda_connection_internal_set_provider_data (cnc, NULL, NULL); + return FALSE; + } + } + else { + res = SQLITE3_CALL (prov, sqlite3_step) (pStmt); + SQLITE3_CALL (prov, sqlite3_reset) (pStmt); + SQLITE3_CALL (prov, sqlite3_finalize) (pStmt); + if (res != SQLITE_DONE) { + if (with_fk) { + gda_sqlite_free_cnc_data (cdata); + gda_connection_internal_set_provider_data (cnc, NULL, NULL); + return FALSE; + } + } +#ifdef GDA_DEBUG_NO + else { + if (enforce_fk) + g_print ("SQLite provider enforces foreign keys.\n"); + else + g_print ("SQLite provider does not enforce foreign keys.\n"); + } +#endif + } + + if (priv->is_default) { + if (!use_extra_functions || ((*use_extra_functions == 't') || (*use_extra_functions == 'T'))) { + gsize i; + + for (i = 0; i < sizeof (scalars) / sizeof (ScalarFunction); i++) { + ScalarFunction *func = (ScalarFunction *) &(scalars [i]); + g_object_ref (prov); + gint res = (s3r->sqlite3_create_function_v2) (cdata->connection, + func->name, func->nargs, + SQLITE_UTF8, prov, + func->xFunc, NULL, NULL, g_object_unref); + if (res != SQLITE_OK) { + gda_connection_add_event_string (cnc, _("Could not register function '%s'"), + func->name); + gda_sqlite_free_cnc_data (cdata); + gda_connection_internal_set_provider_data (cnc, NULL, NULL); + return FALSE; + } + } + } + + if (!regexp || ((*regexp == 't') || (*regexp == 'T'))) { + gsize i; + + for (i = 0; i < sizeof (regexp_functions) / sizeof (ScalarFunction); i++) { + ScalarFunction *func = (ScalarFunction *) &(regexp_functions [i]); + g_object_ref (prov); + gint res = (s3r->sqlite3_create_function_v2) (cdata->connection, + func->name, func->nargs, + SQLITE_UTF8, prov, + func->xFunc, NULL, NULL, g_object_unref); + if (res != SQLITE_OK) { + gda_connection_add_event_string (cnc, _("Could not register function '%s'"), + func->name); + gda_sqlite_free_cnc_data (cdata); + gda_connection_internal_set_provider_data (cnc, NULL, NULL); + return FALSE; + } + } + } + + if (! locale_collate || ((*locale_collate == 't') || (*locale_collate == 'T'))) { + gsize i; + for (i = 0; i < sizeof (collation_functions) / sizeof (CollationFunction); i++) { + CollationFunction *func = (CollationFunction*) &(collation_functions [i]); + gint res; + res = (s3r->sqlite3_create_collation) (cdata->connection, func->name, + SQLITE_UTF8, prov, func->xFunc); + if (res != SQLITE_OK) { + gda_connection_add_event_string (cnc, + _("Could not define the %s collation"), + func->name); + gda_sqlite_free_cnc_data (cdata); + gda_connection_internal_set_provider_data (cnc, NULL, NULL); + return FALSE; + } + } + } + } + + return TRUE; +} + +static int +locale_collate_func (G_GNUC_UNUSED void *pArg, + int nKey1, const void *pKey1, + int nKey2, const void *pKey2) +{ + gchar *tmp1, *tmp2; + int res; + tmp1 = g_utf8_collate_key ((gchar*) pKey1, nKey1); + tmp2 = g_utf8_collate_key ((gchar*) pKey2, nKey2); + res = strcmp (tmp1, tmp2); + g_free (tmp1); + g_free (tmp2); + return res; +} + +static int +dcase_collate_func (G_GNUC_UNUSED void *pArg, + int nKey1, const void *pKey1, + int nKey2, const void *pKey2) +{ + gchar *tmp1, *tmp2; + int res; + tmp1 = remove_diacritics_and_change_case ((gchar*) pKey1, nKey1, CASE_DOWN); + tmp2 = remove_diacritics_and_change_case ((gchar*) pKey2, nKey2, CASE_DOWN); + res = strcmp (tmp1, tmp2); + g_free (tmp1); + g_free (tmp2); + return res; +} + +/* + * Close connection request + */ +static gboolean +gda_sqlite_provider_close_connection (GdaServerProvider *provider, GdaConnection *cnc) +{ + g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE); + g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE); + + return TRUE; +} + +/* + * Server version request + */ +static const gchar * +gda_sqlite_provider_get_server_version (GdaServerProvider *provider, GdaConnection *cnc) +{ + static gchar *version_string = NULL; + + g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE); + g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, NULL); + + gda_lockable_lock (GDA_LOCKABLE(provider)); + if (!version_string) + version_string = g_strdup_printf ("SQLite version %s", SQLITE_VERSION); + gda_lockable_unlock (GDA_LOCKABLE(provider)); + + return (const gchar *) version_string; +} + +/* + * Support operation request + */ +static gboolean +gda_sqlite_provider_supports_operation (G_GNUC_UNUSED GdaServerProvider *provider, G_GNUC_UNUSED GdaConnection *cnc, + GdaServerOperationType type, G_GNUC_UNUSED GdaSet *options) +{ + switch (type) { + case GDA_SERVER_OPERATION_CREATE_DB: + case GDA_SERVER_OPERATION_DROP_DB: + + case GDA_SERVER_OPERATION_CREATE_TABLE: + case GDA_SERVER_OPERATION_DROP_TABLE: + case GDA_SERVER_OPERATION_RENAME_TABLE: + + case GDA_SERVER_OPERATION_ADD_COLUMN: + case GDA_SERVER_OPERATION_RENAME_COLUMN: + + case GDA_SERVER_OPERATION_CREATE_INDEX: + case GDA_SERVER_OPERATION_DROP_INDEX: + + case GDA_SERVER_OPERATION_CREATE_VIEW: + case GDA_SERVER_OPERATION_DROP_VIEW: + return TRUE; + default: + return FALSE; + } +} + +/* + * Create operation request + */ +static GdaServerOperation * +gda_sqlite_provider_create_operation (GdaServerProvider *provider, GdaConnection *cnc, + GdaServerOperationType type, + G_GNUC_UNUSED GdaSet *options, G_GNUC_UNUSED GError **error) +{ + gchar *file; + GdaServerOperation *op; + gchar *str; + + file = g_strdup_printf (PNAME "_specs_%s", gda_server_operation_op_type_to_string (type)); + str = g_utf8_strdown (file, -1); + + g_free (file); + file = NULL; + + gchar *lpname; + lpname = g_utf8_strdown (PNAME, -1); + file = g_strdup_printf ("/spec/%s/%s.raw.xml", lpname, str); + g_free (lpname); + + op = GDA_SERVER_OPERATION (g_object_new (GDA_TYPE_SERVER_OPERATION, + "op-type", type, + "spec-resource", file, + "provider", provider, + "connection", cnc, + NULL)); + + g_free (file); + g_free (str); + + return op; +} + +/* + * Render operation request + */ +static gchar * +gda_sqlite_provider_render_operation (GdaServerProvider *provider, GdaConnection *cnc, + GdaServerOperation *op, GError **error) +{ + gchar *sql = NULL; + gchar *str; + str = g_strdup_printf ("/spec/" PNAME "/" PNAME "_specs_%s.raw.xml", + gda_server_operation_op_type_to_string (gda_server_operation_get_op_type (op))); + gchar *res = g_utf8_strdown (str, -1); + g_free (str); + GBytes *contents; + contents = g_resources_lookup_data (res, + G_RESOURCE_LOOKUP_FLAGS_NONE, + error); + if (contents == NULL) { + g_assert (*error != NULL); +#ifdef GDA_DEBUG + g_print ("Error at getting specs '%s': %s\n", res, (*error)->message); +#endif + g_free (str); + g_free (res); + return NULL; + } + g_free (res); + /* else: TO_IMPLEMENT */ + g_bytes_unref (contents); + + /* actual rendering */ + switch (gda_server_operation_get_op_type (op)) { + case GDA_SERVER_OPERATION_CREATE_DB: + case GDA_SERVER_OPERATION_DROP_DB: + sql = NULL; + break; + case GDA_SERVER_OPERATION_CREATE_TABLE: + sql = _gda_sqlite_render_CREATE_TABLE (provider, cnc, op, error); + break; + case GDA_SERVER_OPERATION_DROP_TABLE: + sql = _gda_sqlite_render_DROP_TABLE (provider, cnc, op, error); + break; + case GDA_SERVER_OPERATION_RENAME_TABLE: + sql = _gda_sqlite_render_RENAME_TABLE (provider, cnc, op, error); + break; + case GDA_SERVER_OPERATION_ADD_COLUMN: + sql = _gda_sqlite_render_ADD_COLUMN (provider, cnc, op, error); + break; + case GDA_SERVER_OPERATION_RENAME_COLUMN: + sql = _gda_sqlite_render_RENAME_COLUMN (provider, cnc, op, error); + break; + case GDA_SERVER_OPERATION_CREATE_INDEX: + sql = _gda_sqlite_render_CREATE_INDEX (provider, cnc, op, error); + break; + case GDA_SERVER_OPERATION_DROP_INDEX: + sql = _gda_sqlite_render_DROP_INDEX (provider, cnc, op, error); + break; + case GDA_SERVER_OPERATION_CREATE_VIEW: + sql = _gda_sqlite_render_CREATE_VIEW (provider, cnc, op, error); + break; + case GDA_SERVER_OPERATION_DROP_VIEW: + sql = _gda_sqlite_render_DROP_VIEW (provider, cnc, op, error); + break; + + default: + g_assert_not_reached (); + } + return sql; +} + +/* + * Perform operation request + */ +static gboolean +gda_sqlite_provider_perform_operation (GdaServerProvider *provider, GdaConnection *cnc, + GdaServerOperation *op, GError **error) +{ + GdaServerOperationType optype; + optype = gda_server_operation_get_op_type (op); + switch (optype) { + case GDA_SERVER_OPERATION_CREATE_DB: { + const GValue *value; + const gchar *dbname = NULL, *append_extension = NULL; + const gchar *dir = NULL; + SqliteConnectionData *cdata; + gint errmsg; + gchar *filename, *tmp; + gboolean retval = TRUE; + GdaSqliteProvider *prov = GDA_SQLITE_PROVIDER (provider); + + value = gda_server_operation_get_value_at (op, "/DB_DEF_P/DB_NAME"); + if (value && G_VALUE_HOLDS (value, G_TYPE_STRING) && g_value_get_string (value)) + dbname = g_value_get_string (value); + value = gda_server_operation_get_value_at (op, "/DB_DEF_P/APPEND_DB_EXTENSION"); + if (value && G_VALUE_HOLDS (value, G_TYPE_STRING) && g_value_get_string (value)) + append_extension = g_value_get_string (value); + value = gda_server_operation_get_value_at (op, "/DB_DEF_P/DB_DIR"); + if (value && G_VALUE_HOLDS (value, G_TYPE_STRING) && g_value_get_string (value)) + dir = g_value_get_string (value); + + if (!append_extension || + (append_extension && ((*append_extension == 't') || (*append_extension == 'T')))) + tmp = g_strdup_printf ("%s%s", dbname, FILE_EXTENSION); + else + tmp = g_strdup (dbname); + filename = g_build_filename (dir, tmp, NULL); + g_free (tmp); + + cdata = g_new0 (SqliteConnectionData, 1); + errmsg = SQLITE3_CALL (prov, sqlite3_open) (filename, &cdata->connection); + g_free (filename); + + if (errmsg != SQLITE_OK) { + g_set_error (error, GDA_SERVER_PROVIDER_ERROR, + GDA_SERVER_PROVIDER_PREPARE_STMT_ERROR, + "%s", SQLITE3_CALL (prov, sqlite3_errmsg) (cdata->connection)); + retval = FALSE; + } + +#ifdef SQLITE_HAS_CODEC + value = gda_server_operation_get_value_at (op, "/DB_DEF_P/PASSWORD"); + if (value && G_VALUE_HOLDS (value, G_TYPE_STRING) && + g_value_get_string (value) && + *g_value_get_string (value)) { + const gchar *passphrase = g_value_get_string (value); + errmsg = SQLITE3_CALL (prov, sqlite3_key_v2) (cdata->connection, cdata->file, (void*) passphrase, + strlen (passphrase)); + if (errmsg != SQLITE_OK) { + g_set_error (error, GDA_SERVER_PROVIDER_ERROR, + GDA_SERVER_PROVIDER_INTERNAL_ERROR, + "%s", SQLITE3_CALL (prov, sqlite3_errmsg) (cdata->connection)); + retval = FALSE; + } + else { + /* create some contents */ + int res; + sqlite3_stmt *pStmt; + res = SQLITE3_CALL (prov, sqlite3_prepare_v2) (cdata->connection, + "CREATE TABLE data (id int)", -1, + &pStmt, NULL); + + if (res != SQLITE_OK) { + g_set_error (error, GDA_SERVER_PROVIDER_ERROR, + GDA_SERVER_PROVIDER_INTERNAL_ERROR, + "%s", + _("Error initializing database with passphrase")); + retval = FALSE; + goto outcontents; + } + res = SQLITE3_CALL (prov, sqlite3_step) (pStmt); + SQLITE3_CALL (prov, sqlite3_reset) (pStmt); + SQLITE3_CALL (prov, sqlite3_finalize) (pStmt); + if (res != SQLITE_DONE) { + g_set_error (error, GDA_SERVER_PROVIDER_ERROR, + GDA_SERVER_PROVIDER_INTERNAL_ERROR, + "%s", + _("Error initializing database with passphrase")); + retval = FALSE; + goto outcontents; + /* end */ + } + + res = SQLITE3_CALL (prov, sqlite3_prepare_v2) (cdata->connection, + "DROP TABLE data", -1, + &pStmt, NULL); + + if (res != SQLITE_OK) { + g_set_error (error, GDA_SERVER_PROVIDER_ERROR, + GDA_SERVER_PROVIDER_INTERNAL_ERROR, + "%s", + _("Error initializing database with passphrase")); + retval = FALSE; + goto outcontents; + } + res = SQLITE3_CALL (prov, sqlite3_step) (pStmt); + SQLITE3_CALL (prov, sqlite3_reset) (pStmt); + SQLITE3_CALL (prov, sqlite3_finalize) (pStmt); + if (res != SQLITE_DONE) { + g_set_error (error, GDA_SERVER_PROVIDER_ERROR, + GDA_SERVER_PROVIDER_INTERNAL_ERROR, + "%s", + _("Error initializing database with passphrase")); + retval = FALSE; + goto outcontents; + /* end */ + } + outcontents: + ; + } + } +#endif + gda_sqlite_free_cnc_data (cdata); + + return retval; + } + case GDA_SERVER_OPERATION_DROP_DB: { + const GValue *value; + const gchar *dbname = NULL; + const gchar *dir = NULL; + gboolean retval = TRUE; + + value = gda_server_operation_get_value_at (op, "/DB_DESC_P/DB_NAME"); + if (value && G_VALUE_HOLDS (value, G_TYPE_STRING) && g_value_get_string (value)) + dbname = g_value_get_string (value); + value = gda_server_operation_get_value_at (op, "/DB_DESC_P/DB_DIR"); + if (value && G_VALUE_HOLDS (value, G_TYPE_STRING) && g_value_get_string (value)) + dir = g_value_get_string (value); + + if (dbname && dir) { + gchar *filename, *tmp; + tmp = g_strdup_printf ("%s%s", dbname, FILE_EXTENSION); + filename = (gchar *) g_build_filename (dir, tmp, NULL); + g_free (tmp); + + if (g_unlink (filename)) { + g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_OPERATION_ERROR, + "%s", g_strerror (errno)); + retval = FALSE; + } + g_free (filename); + } + else { + g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_OPERATION_ERROR, + "%s", _("Missing database name or directory")); + retval = FALSE; + } + + return retval; + } + default: + /* use the SQL from the provider to perform the action */ + return gda_server_provider_perform_operation_default (provider, cnc, op, error); + } +} + +/* + * Begin transaction request + */ +static gboolean +gda_sqlite_provider_begin_transaction (GdaServerProvider *provider, GdaConnection *cnc, + const gchar *name, G_GNUC_UNUSED GdaTransactionIsolation level, + GError **error) +{ + gboolean status = TRUE; + GdaStatement *stm; + + g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE); + g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE); + GdaSqliteProviderPrivate *priv = gda_sqlite_provider_get_instance_private (GDA_SQLITE_PROVIDER (provider)); + + if (gda_connection_get_options (cnc) & GDA_CONNECTION_OPTIONS_READ_ONLY) { + gda_connection_add_event_string (cnc, _("Transactions are not supported in read-only mode")); + return FALSE; + } + + if (name) { + GdaSet *params_set = NULL; + gda_lockable_lock (GDA_LOCKABLE(provider)); + if (!params_set) + params_set = gda_set_new_inline (1, "name", G_TYPE_STRING, name); + else if (! gda_set_set_holder_value (params_set, error, "name", name)) + status = FALSE; + stm = (GdaStatement*) g_ptr_array_index (priv->internal_stmt, INTERNAL_BEGIN_NAMED); + if (status && gda_connection_statement_execute_non_select (cnc, stm, + params_set, NULL, error) == -1) + status = FALSE; + g_object_unref (params_set); + gda_lockable_unlock (GDA_LOCKABLE(provider)); + } + else { + stm = (GdaStatement*) g_ptr_array_index (priv->internal_stmt, INTERNAL_BEGIN); + if (gda_connection_statement_execute_non_select (cnc, stm, + NULL, NULL, error) == -1) + status = FALSE; + } + + /*g_print ("%s(%p) => %s\n", __FUNCTION__, cnc, status ? "TRUE" : "FALSE");*/ + return status; +} + +/* + * Commit transaction request + */ +static gboolean +gda_sqlite_provider_commit_transaction (GdaServerProvider *provider, GdaConnection *cnc, + const gchar *name, GError **error) +{ + gboolean status = TRUE; + GdaStatement *stm; + + g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE); + g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE); + GdaSqliteProviderPrivate *priv = gda_sqlite_provider_get_instance_private (GDA_SQLITE_PROVIDER (provider)); + + if (name) { + GdaSet *params_set = NULL; + gda_lockable_lock (GDA_LOCKABLE(provider)); + if (!params_set) + params_set = gda_set_new_inline (1, "name", G_TYPE_STRING, name); + else if (!gda_set_set_holder_value (params_set, error, "name", name)) + status = FALSE; + stm = (GdaStatement*) g_ptr_array_index (priv->internal_stmt, INTERNAL_COMMIT_NAMED); + if (status && gda_connection_statement_execute_non_select (cnc, stm, + params_set, NULL, error) == -1) + status = FALSE; + g_object_unref (params_set); + gda_lockable_unlock (GDA_LOCKABLE(provider)); + } + else { + stm = (GdaStatement*) g_ptr_array_index (priv->internal_stmt, INTERNAL_COMMIT); + if (gda_connection_statement_execute_non_select (cnc, stm, + NULL, NULL, error) == -1) + status = FALSE; + } + + /*g_print ("%s(%p) => %s\n", __FUNCTION__, cnc, status ? "TRUE" : "FALSE");*/ + return status; +} + +/* + * Rollback transaction request + */ +static gboolean +gda_sqlite_provider_rollback_transaction (GdaServerProvider *provider, + GdaConnection *cnc, + const gchar *name, GError **error) +{ + gboolean status = TRUE; + GdaStatement *stm; + + g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE); + g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE); + GdaSqliteProviderPrivate *priv = gda_sqlite_provider_get_instance_private (GDA_SQLITE_PROVIDER (provider)); + + if (name) { + GdaSet *params_set = NULL; + gda_lockable_lock (GDA_LOCKABLE(provider)); + if (!params_set) + params_set = gda_set_new_inline (1, "name", G_TYPE_STRING, name); + else if (! gda_set_set_holder_value (params_set, error, "name", name)) + status = FALSE; + stm = (GdaStatement*) g_ptr_array_index (priv->internal_stmt, INTERNAL_ROLLBACK_NAMED); + if (status && gda_connection_statement_execute_non_select (cnc, stm, + params_set, NULL, error) == -1) + status = FALSE; + g_object_unref (params_set); + gda_lockable_unlock (GDA_LOCKABLE(provider)); + } + else { + stm = (GdaStatement*) g_ptr_array_index (priv->internal_stmt, INTERNAL_ROLLBACK); + if (gda_connection_statement_execute_non_select (cnc, stm, + NULL, NULL, error) == -1) + status = FALSE; + } + + /*g_print ("%s(%p) => %s\n", __FUNCTION__, cnc, status ? "TRUE" : "FALSE");*/ + return status; +} + +static gboolean +gda_sqlite_provider_add_savepoint (GdaServerProvider *provider, GdaConnection *cnc, + const gchar *name, GError **error) +{ + gboolean status = TRUE; + GdaStatement *stm; + + g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE); + g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE); + g_return_val_if_fail (name && *name, FALSE); + GdaSqliteProviderPrivate *priv = gda_sqlite_provider_get_instance_private (GDA_SQLITE_PROVIDER (provider)); + + GdaSet *params_set = NULL; + gda_lockable_lock (GDA_LOCKABLE(provider)); + if (!params_set) + params_set = gda_set_new_inline (1, "name", G_TYPE_STRING, name); + else if (! gda_set_set_holder_value (params_set, error, "name", name)) + status = FALSE; + stm = (GdaStatement*) g_ptr_array_index (priv->internal_stmt, INTERNAL_ADD_SAVEPOINT); + if (status && gda_connection_statement_execute_non_select (cnc, stm, + params_set, NULL, error) == -1) + status = FALSE; + g_object_unref (params_set); + gda_lockable_unlock (GDA_LOCKABLE(provider)); + + /*g_print ("%s(%p) => %s\n", __FUNCTION__, cnc, status ? "TRUE" : "FALSE");*/ + return status; +} + +static gboolean +gda_sqlite_provider_rollback_savepoint (GdaServerProvider *provider, GdaConnection *cnc, + const gchar *name, GError **error) +{ + gboolean status = TRUE; + GdaStatement *stm; + + g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE); + g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE); + g_return_val_if_fail (name && *name, FALSE); + GdaSqliteProviderPrivate *priv = gda_sqlite_provider_get_instance_private (GDA_SQLITE_PROVIDER (provider)); + + GdaSet *params_set = NULL; + gda_lockable_lock (GDA_LOCKABLE(provider)); + if (!params_set) + params_set = gda_set_new_inline (1, "name", G_TYPE_STRING, name); + else if (! gda_set_set_holder_value (params_set, error, "name", name)) + status = FALSE; + stm = (GdaStatement*) g_ptr_array_index (priv->internal_stmt, INTERNAL_ROLLBACK_SAVEPOINT); + if (status && gda_connection_statement_execute_non_select (cnc, stm, + params_set, NULL, error) == -1) + status = FALSE; + g_object_unref (params_set); + gda_lockable_unlock (GDA_LOCKABLE(provider)); + + /*g_print ("%s(%p) => %s\n", __FUNCTION__, cnc, status ? "TRUE" : "FALSE");*/ + return status; +} + +static gboolean +gda_sqlite_provider_delete_savepoint (GdaServerProvider *provider, GdaConnection *cnc, + const gchar *name, GError **error) +{ + gboolean status = TRUE; + + g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE); + g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE); + g_return_val_if_fail (name && *name, FALSE); + GdaSqliteProviderPrivate *priv = gda_sqlite_provider_get_instance_private (GDA_SQLITE_PROVIDER (provider)); + + GdaSet *params_set = NULL; + GdaStatement *stm; + gda_lockable_lock (GDA_LOCKABLE(provider)); + if (!params_set) + params_set = gda_set_new_inline (1, "name", G_TYPE_STRING, name); + else if (! gda_set_set_holder_value (params_set, error, "name", name)) + status = FALSE; + stm = (GdaStatement*) g_ptr_array_index (priv->internal_stmt, INTERNAL_RELEASE_SAVEPOINT); + if (status && gda_connection_statement_execute_non_select (cnc, stm, + params_set, NULL, error) == -1) { + status = FALSE; + } + g_object_unref (params_set); + gda_lockable_unlock (GDA_LOCKABLE(provider)); + + /*g_print ("%s(%p) => %s\n", __FUNCTION__, cnc, status ? "TRUE" : "FALSE");*/ + return status; +} + +/* + * Feature support request + */ +static gboolean +gda_sqlite_provider_supports_feature (GdaServerProvider *provider, + GdaConnection *cnc, + GdaConnectionFeature feature) +{ + if (cnc) { + g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE); + g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE); + } + + switch (feature) { + case GDA_CONNECTION_FEATURE_SQL : + case GDA_CONNECTION_FEATURE_TRANSACTIONS : + case GDA_CONNECTION_FEATURE_AGGREGATES : + case GDA_CONNECTION_FEATURE_INDEXES : + case GDA_CONNECTION_FEATURE_TRIGGERS : + case GDA_CONNECTION_FEATURE_VIEWS : + case GDA_CONNECTION_FEATURE_PROCEDURES : + return TRUE; + default: + return FALSE; + } +} + +/* + * Get data handler request + */ +static GdaDataHandler * +gda_sqlite_provider_get_data_handler (GdaServerProvider *provider, GdaConnection *cnc, + GType type, G_GNUC_UNUSED const gchar *dbms_type) +{ + GdaDataHandler *dh = NULL; + + if (cnc) { + g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE); + g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE); + } + + if (type == G_TYPE_INVALID) { + TO_IMPLEMENT; /* use @dbms_type */ + dh = NULL; + } + else if (type == G_TYPE_STRING) { + dh = gda_server_provider_handler_find (provider, cnc, type, NULL); + if (!dh) { + dh = gda_handler_string_new_with_provider (provider, cnc); + if (dh) { + gda_server_provider_handler_declare (provider, dh, cnc, G_TYPE_STRING, NULL); + g_object_unref (dh); + } + } + } + else if (type == GDA_TYPE_BINARY) { + dh = gda_server_provider_handler_find (provider, cnc, type, NULL); + if (!dh) { + dh = _gda_sqlite_handler_bin_new (); + if (dh) { + gda_server_provider_handler_declare (provider, dh, cnc, GDA_TYPE_BINARY, NULL); + g_object_unref (dh); + } + } + } + else if ((type == GDA_TYPE_TIME) || + (type == G_TYPE_DATE_TIME) || + (type == G_TYPE_DATE)) { + dh = gda_server_provider_handler_find (provider, NULL, type, NULL); + if (!dh) { + dh = gda_handler_time_new (); + /* SQLite format is 'YYYY-MM-DD HH:MM:SS.SSS' */ + gda_handler_time_set_sql_spec (GDA_HANDLER_TIME (dh), G_DATE_YEAR, G_DATE_MONTH, + G_DATE_DAY, '-', FALSE); + gda_handler_time_set_str_spec (GDA_HANDLER_TIME (dh), G_DATE_YEAR, G_DATE_MONTH, + G_DATE_DAY, '-', FALSE); + gda_server_provider_handler_declare (provider, dh, NULL, GDA_TYPE_TIME, NULL); + gda_server_provider_handler_declare (provider, dh, NULL, G_TYPE_DATE_TIME, NULL); + gda_server_provider_handler_declare (provider, dh, NULL, G_TYPE_DATE, NULL); + g_object_unref (dh); + } + } + else if (type == G_TYPE_BOOLEAN) { + dh = gda_server_provider_handler_find (provider, cnc, type, NULL); + if (!dh) { + dh = _gda_sqlite_handler_boolean_new (); + if (dh) { + gda_server_provider_handler_declare (provider, dh, cnc, G_TYPE_BOOLEAN, NULL); + g_object_unref (dh); + } + } + } + else + dh = gda_server_provider_handler_use_default (provider, type); + + return dh; +} + +/* + * Get default DBMS type request + */ +static const gchar* +gda_sqlite_provider_get_default_dbms_type (G_GNUC_UNUSED GdaServerProvider *provider, G_GNUC_UNUSED GdaConnection *cnc, GType type) +{ + if ((type == G_TYPE_INT64) || + (type == G_TYPE_INT) || + (type == GDA_TYPE_SHORT) || + (type == GDA_TYPE_USHORT) || + (type == G_TYPE_CHAR) || + (type == G_TYPE_UCHAR) || + (type == G_TYPE_ULONG) || + (type == G_TYPE_LONG) || + (type == G_TYPE_UINT) || + (type == G_TYPE_UINT64)) + return "integer"; + + if (type == GDA_TYPE_BINARY) + return "blob"; + + if (type == G_TYPE_BOOLEAN) + return "boolean"; + + if ((type == GDA_TYPE_GEOMETRIC_POINT) || + (type == G_TYPE_OBJECT) || + (type == G_TYPE_STRING) || + (type == GDA_TYPE_TEXT) || + (type == G_TYPE_INVALID)) + return "text"; + + if ((type == G_TYPE_DOUBLE) || + (type == GDA_TYPE_NUMERIC) || + (type == G_TYPE_FLOAT)) + return "real"; + + if (type == GDA_TYPE_TIME) + return "time"; + if (type == G_TYPE_DATE_TIME) + return "timestamp"; + if (type == G_TYPE_DATE) + return "date"; + + if ((type == GDA_TYPE_NULL) || + (type == G_TYPE_GTYPE)) + return NULL; + + return "text"; +} + +/* + * Create parser request + */ +static GdaSqlParser * +gda_sqlite_provider_create_parser (G_GNUC_UNUSED GdaServerProvider *provider, G_GNUC_UNUSED GdaConnection *cnc) +{ + return (GdaSqlParser*) g_object_new (GDA_TYPE_SQL_PARSER, "tokenizer-flavour", GDA_SQL_PARSER_FLAVOUR_SQLITE, NULL); +} + + +/* + * GdaStatement to SQL request + */ +static gchar *sqlite_render_compound (GdaSqlStatementCompound *stmt, GdaSqlRenderingContext *context, GError **error); + +static gchar *sqlite_render_operation (GdaSqlOperation *op, GdaSqlRenderingContext *context, GError **error); +static gchar *sqlite_render_expr (GdaSqlExpr *expr, GdaSqlRenderingContext *context, + gboolean *is_default, gboolean *is_null, + GError **error); +static gchar *sqlite_render_distinct (GdaSqlStatementSelect *stmt, + GdaSqlRenderingContext *context, GError **error); + +static gchar * +gda_sqlite_provider_statement_to_sql (GdaServerProvider *provider, GdaConnection *cnc, + GdaStatement *stmt, GdaSet *params, GdaStatementSqlFlag flags, + GSList **params_used, GError **error) +{ + gchar *str; + GdaSqlRenderingContext context; + + g_return_val_if_fail (GDA_IS_STATEMENT (stmt), NULL); + if (cnc) { + g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL); + g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, NULL); + } + + memset (&context, 0, sizeof (context)); + context.provider = provider; + context.cnc = cnc; + context.params = params; + context.flags = flags; + context.render_operation = (GdaSqlRenderingFunc) sqlite_render_operation; /* specific REGEXP rendering */ + context.render_compound = (GdaSqlRenderingFunc) sqlite_render_compound; /* don't surround each SELECT with parenthesis, EXCEPT ALL and INTERSECT ALL are not supported */ + context.render_expr = sqlite_render_expr; /* render "FALSE" as 0 and TRUE as 1 */ + context.render_distinct = (GdaSqlRenderingFunc) sqlite_render_distinct; /* DISTINCT ON (...) is not supported */ + + str = gda_statement_to_sql_real (stmt, &context, error); + + if (str) { + if (params_used) + *params_used = context.params_used; + else + g_slist_free (context.params_used); + } + else { + if (params_used) + *params_used = NULL; + g_slist_free (context.params_used); + } + return str; +} + +/* + * The difference with the default implementation is that DISTINCT ON (...) is not supported + */ +static gchar * +sqlite_render_distinct (GdaSqlStatementSelect *stmt, GdaSqlRenderingContext *context, GError **error) +{ + if (stmt->distinct) { + if (stmt->distinct_expr) { + g_set_error (error, GDA_SERVER_PROVIDER_ERROR, + GDA_SERVER_PROVIDER_NON_SUPPORTED_ERROR, + "%s", _("SQLite does not support specifying fields to apply DISTINCT clause on")); + return NULL; + } + else { + gchar *tmp; + tmp = g_strdup ("DISTINCT\n"); + if (! (context->flags & GDA_STATEMENT_SQL_PRETTY)) + tmp [8] = 0; + return tmp; + } + } + else + return NULL; +} + +/* + * The difference with the default implementation is to avoid surrounding each SELECT with parenthesis + * and that EXCEPT ALL and INTERSECT ALL are not supported + */ +static gchar * +sqlite_render_compound (GdaSqlStatementCompound *stmt, GdaSqlRenderingContext *context, GError **error) +{ + GString *string; + gchar *str; + GSList *list; + + g_return_val_if_fail (stmt, NULL); + g_return_val_if_fail (GDA_SQL_ANY_PART (stmt)->type == GDA_SQL_ANY_STMT_COMPOUND, NULL); + + string = g_string_new (""); + + for (list = stmt->stmt_list; list; list = list->next) { + GdaSqlStatement *sqlstmt = (GdaSqlStatement*) list->data; + if (list != stmt->stmt_list) { + switch (stmt->compound_type) { + case GDA_SQL_STATEMENT_COMPOUND_UNION: + g_string_append (string, " UNION "); + break; + case GDA_SQL_STATEMENT_COMPOUND_UNION_ALL: + g_string_append (string, " UNION ALL "); + break; + case GDA_SQL_STATEMENT_COMPOUND_INTERSECT: + g_string_append (string, " INTERSECT "); + break; + case GDA_SQL_STATEMENT_COMPOUND_INTERSECT_ALL: + g_set_error (error, GDA_SERVER_PROVIDER_ERROR, + GDA_SERVER_PROVIDER_NON_SUPPORTED_ERROR, + _("'%s' compound not supported by SQLite"), + "INTERSECT ALL"); + goto err; + break; + case GDA_SQL_STATEMENT_COMPOUND_EXCEPT: + g_string_append (string, " EXCEPT "); + break; + case GDA_SQL_STATEMENT_COMPOUND_EXCEPT_ALL: + g_set_error (error, GDA_SERVER_PROVIDER_ERROR, + GDA_SERVER_PROVIDER_NON_SUPPORTED_ERROR, + _("'%s' compound not supported by SQLite"), + "EXCEPT ALL"); + goto err; + break; + default: + g_assert_not_reached (); + } + } + switch (sqlstmt->stmt_type) { + case GDA_SQL_ANY_STMT_SELECT: + str = context->render_select (GDA_SQL_ANY_PART (sqlstmt->contents), context, error); + if (!str) goto err; + g_string_append (string, str); + g_free (str); + break; + case GDA_SQL_ANY_STMT_COMPOUND: + str = context->render_compound (GDA_SQL_ANY_PART (sqlstmt->contents), context, error); + if (!str) goto err; + g_string_append (string, str); + g_free (str); + break; + default: + g_assert_not_reached (); + } + } + + str = string->str; + g_string_free (string, FALSE); + return str; + + err: + g_string_free (string, TRUE); + return NULL; +} + +/* The difference with the default implementation is specific REGEXP rendering */ +static gchar * +sqlite_render_operation (GdaSqlOperation *op, GdaSqlRenderingContext *context, GError **error) +{ + gchar *str; + GSList *list; + GSList *sql_list; /* list of SqlOperand */ + GString *string; + gchar *multi_op = NULL; + + typedef struct { + gchar *sql; + gboolean is_null; + gboolean is_default; + gboolean is_composed; + } SqlOperand; +#define SQL_OPERAND(x) ((SqlOperand*)(x)) + + g_return_val_if_fail (op, NULL); + g_return_val_if_fail (GDA_SQL_ANY_PART (op)->type == GDA_SQL_ANY_SQL_OPERATION, NULL); + + /* can't have: + * - op->operands == NULL + * - incorrect number of operands + */ + if (!gda_sql_any_part_check_structure (GDA_SQL_ANY_PART (op), error)) { + g_assert (*error != NULL); + return NULL; + } + + /* render operands */ + for (list = op->operands, sql_list = NULL; list; list = list->next) { + SqlOperand *sqlop = g_new0 (SqlOperand, 1); + GdaSqlExpr *expr = (GdaSqlExpr*) list->data; + str = context->render_expr (expr, context, &(sqlop->is_default), &(sqlop->is_null), error); + if (!str) { + g_free (sqlop); + g_assert (*error != NULL); + goto out; + } + sqlop->sql = str; + if (expr->cond || expr->case_s || expr->select) + sqlop->is_composed = TRUE; + sql_list = g_slist_prepend (sql_list, sqlop); + } + sql_list = g_slist_reverse (sql_list); + + str = NULL; + switch (op->operator_type) { + case GDA_SQL_OPERATOR_TYPE_EQ: + if (SQL_OPERAND (sql_list->next->data)->is_null) + str = g_strdup_printf ("%s IS NULL", SQL_OPERAND (sql_list->data)->sql); + else + str = g_strdup_printf ("%s = %s", SQL_OPERAND (sql_list->data)->sql, SQL_OPERAND (sql_list->next->data)->sql); + break; + case GDA_SQL_OPERATOR_TYPE_IS: + str = g_strdup_printf ("%s IS %s", SQL_OPERAND (sql_list->data)->sql, SQL_OPERAND (sql_list->next->data)->sql); + break; + case GDA_SQL_OPERATOR_TYPE_LIKE: + str = g_strdup_printf ("%s LIKE %s", SQL_OPERAND (sql_list->data)->sql, SQL_OPERAND (sql_list->next->data)->sql); + break; + case GDA_SQL_OPERATOR_TYPE_NOTLIKE: + str = g_strdup_printf ("%s NOT LIKE %s", SQL_OPERAND (sql_list->data)->sql, SQL_OPERAND (sql_list->next->data)->sql); + break; + case GDA_SQL_OPERATOR_TYPE_ILIKE: + case GDA_SQL_OPERATOR_TYPE_NOTILIKE: + g_set_error (error, GDA_STATEMENT_ERROR, GDA_STATEMENT_SYNTAX_ERROR, + "%s", _("ILIKE operation not supported")); + goto out; + break; + case GDA_SQL_OPERATOR_TYPE_GT: + str = g_strdup_printf ("%s > %s", SQL_OPERAND (sql_list->data)->sql, SQL_OPERAND (sql_list->next->data)->sql); + break; + case GDA_SQL_OPERATOR_TYPE_LT: + str = g_strdup_printf ("%s < %s", SQL_OPERAND (sql_list->data)->sql, SQL_OPERAND (sql_list->next->data)->sql); + break; + case GDA_SQL_OPERATOR_TYPE_GEQ: + str = g_strdup_printf ("%s >= %s", SQL_OPERAND (sql_list->data)->sql, SQL_OPERAND (sql_list->next->data)->sql); + break; + case GDA_SQL_OPERATOR_TYPE_LEQ: + str = g_strdup_printf ("%s <= %s", SQL_OPERAND (sql_list->data)->sql, SQL_OPERAND (sql_list->next->data)->sql); + break; + case GDA_SQL_OPERATOR_TYPE_DIFF: + str = g_strdup_printf ("%s != %s", SQL_OPERAND (sql_list->data)->sql, SQL_OPERAND (sql_list->next->data)->sql); + break; + case GDA_SQL_OPERATOR_TYPE_REGEXP: + str = g_strdup_printf ("regexp (%s, %s)", SQL_OPERAND (sql_list->next->data)->sql, SQL_OPERAND (sql_list->data)->sql); + break; + case GDA_SQL_OPERATOR_TYPE_REGEXP_CI: + str = g_strdup_printf ("regexp (%s, %s, 'i')", SQL_OPERAND (sql_list->next->data)->sql, + SQL_OPERAND (sql_list->data)->sql); + break; + case GDA_SQL_OPERATOR_TYPE_NOT_REGEXP_CI: + str = g_strdup_printf ("NOT regexp (%s, %s, 'i')", SQL_OPERAND (sql_list->next->data)->sql, + SQL_OPERAND (sql_list->data)->sql); + break; + case GDA_SQL_OPERATOR_TYPE_SIMILAR: + /* does not exist in SQLite => error */ + g_set_error (error, GDA_STATEMENT_ERROR, GDA_STATEMENT_SYNTAX_ERROR, + "%s", _("SIMILAR operation not supported")); + goto out; + break; + case GDA_SQL_OPERATOR_TYPE_NOT_REGEXP: + str = g_strdup_printf ("NOT regexp (%s, %s)", SQL_OPERAND (sql_list->next->data)->sql, + SQL_OPERAND (sql_list->data)->sql); + break; + case GDA_SQL_OPERATOR_TYPE_REM: + str = g_strdup_printf ("%s %% %s", SQL_OPERAND (sql_list->data)->sql, SQL_OPERAND (sql_list->next->data)->sql); + break; + case GDA_SQL_OPERATOR_TYPE_DIV: + str = g_strdup_printf ("%s / %s", SQL_OPERAND (sql_list->data)->sql, SQL_OPERAND (sql_list->next->data)->sql); + break; + case GDA_SQL_OPERATOR_TYPE_BITAND: + str = g_strdup_printf ("%s & %s", SQL_OPERAND (sql_list->data)->sql, SQL_OPERAND (sql_list->next->data)->sql); + break; + case GDA_SQL_OPERATOR_TYPE_BITOR: + str = g_strdup_printf ("%s | %s", SQL_OPERAND (sql_list->data)->sql, SQL_OPERAND (sql_list->next->data)->sql); + break; + case GDA_SQL_OPERATOR_TYPE_BETWEEN: + str = g_strdup_printf ("%s BETWEEN %s AND %s", SQL_OPERAND (sql_list->data)->sql, + SQL_OPERAND (sql_list->next->data)->sql, + SQL_OPERAND (sql_list->next->next->data)->sql); + break; + case GDA_SQL_OPERATOR_TYPE_ISNULL: + str = g_strdup_printf ("%s IS NULL", SQL_OPERAND (sql_list->data)->sql); + break; + case GDA_SQL_OPERATOR_TYPE_ISNOTNULL: + str = g_strdup_printf ("%s IS NOT NULL", SQL_OPERAND (sql_list->data)->sql); + break; + case GDA_SQL_OPERATOR_TYPE_BITNOT: + str = g_strdup_printf ("~ %s", SQL_OPERAND (sql_list->data)->sql); + break; + case GDA_SQL_OPERATOR_TYPE_NOT: + str = g_strdup_printf ("NOT %s", SQL_OPERAND (sql_list->data)->sql); + break; + case GDA_SQL_OPERATOR_TYPE_IN: + case GDA_SQL_OPERATOR_TYPE_NOTIN: { + gboolean add_p = TRUE; + if (sql_list->next && !(sql_list->next->next) && + *(SQL_OPERAND (sql_list->next->data)->sql)=='(') + add_p = FALSE; + string = g_string_new (""); + string = g_string_append (string, SQL_OPERAND (sql_list->data)->sql); + if (op->operator_type == GDA_SQL_OPERATOR_TYPE_IN) + g_string_append (string, " IN "); + else + g_string_append (string, " NOT IN "); + if (add_p) + g_string_append_c (string, '('); + for (list = sql_list->next; list; list = list->next) { + if (list != sql_list->next) + g_string_append (string, ", "); + g_string_append (string, SQL_OPERAND (list->data)->sql); + } + if (add_p) + g_string_append_c (string, ')'); + str = string->str; + g_string_free (string, FALSE); + string = NULL; + break; + } + case GDA_SQL_OPERATOR_TYPE_CONCAT: + multi_op = "||"; + break; + case GDA_SQL_OPERATOR_TYPE_PLUS: + multi_op = "+"; + break; + case GDA_SQL_OPERATOR_TYPE_MINUS: + multi_op = "-"; + break; + case GDA_SQL_OPERATOR_TYPE_STAR: + multi_op = "*"; + break; + case GDA_SQL_OPERATOR_TYPE_AND: + multi_op = "AND"; + break; + case GDA_SQL_OPERATOR_TYPE_OR: + multi_op = "OR"; + break; + default: + g_assert_not_reached (); + break; + } + + if (multi_op) { + if (!sql_list->next) { + /* 1 operand only */ + string = g_string_new (""); + g_string_append_printf (string, "%s %s", multi_op, SQL_OPERAND (sql_list->data)->sql); + } + else { + /* 2 or more operands */ + if (SQL_OPERAND (sql_list->data)->is_composed) { + string = g_string_new ("("); + g_string_append (string, SQL_OPERAND (sql_list->data)->sql); + g_string_append_c (string, ')'); + } + else + string = g_string_new (SQL_OPERAND (sql_list->data)->sql); + for (list = sql_list->next; list; list = list->next) { + g_string_append_printf (string, " %s ", multi_op); + if (SQL_OPERAND (list->data)->is_composed) { + g_string_append_c (string, '('); + g_string_append (string, SQL_OPERAND (list->data)->sql); + g_string_append_c (string, ')'); + } + else + g_string_append (string, SQL_OPERAND (list->data)->sql); + } + } + str = string->str; + g_string_free (string, FALSE); + } + + out: + for (list = sql_list; list; list = list->next) { + g_free (((SqlOperand*)list->data)->sql); + g_free (list->data); + } + g_slist_free (sql_list); + + if (str == NULL && *error == NULL) + g_set_error (error, GDA_STATEMENT_ERROR, GDA_STATEMENT_SYNTAX_ERROR, + "%s", _("Operator type not supported")); + g_assert (str != NULL); + return str; +} + +/* + * The difference with the default implementation is to render TRUE and FALSE as 0 and 1 + */ +static gchar * +sqlite_render_expr (GdaSqlExpr *expr, GdaSqlRenderingContext *context, gboolean *is_default, + gboolean *is_null, GError **error) +{ + GString *string; + gchar *str = NULL; + + g_return_val_if_fail (expr, NULL); + g_return_val_if_fail (GDA_SQL_ANY_PART (expr)->type == GDA_SQL_ANY_EXPR, NULL); + + if (is_default) + *is_default = FALSE; + if (is_null) + *is_null = FALSE; + + /* can't have: + * - expr->cast_as && expr->param_spec + */ + if (!gda_sql_any_part_check_structure (GDA_SQL_ANY_PART (expr), error)) return NULL; + + string = g_string_new (""); + if (expr->param_spec) { + str = context->render_param_spec (expr->param_spec, expr, context, is_default, is_null, error); + if (!str) goto err; + } + else if (expr->value) { + if (G_VALUE_TYPE (expr->value) == G_TYPE_STRING) { + /* specific treatment for strings, see documentation about GdaSqlExpr's value attribute */ + const gchar *vstr; + vstr = g_value_get_string (expr->value); + if (vstr) { + if (expr->value_is_ident) { + gchar **ids_array; + gint i; + GString *string = NULL; + GdaConnectionOptions cncoptions = 0; + if (context->cnc) + g_object_get (G_OBJECT (context->cnc), "options", &cncoptions, NULL); + ids_array = gda_sql_identifier_split (vstr); + if (!ids_array) + str = g_strdup (vstr); + else if (!(ids_array[0])) goto err; + else { + for (i = 0; ids_array[i]; i++) { + gchar *tmp; + if (!string) + string = g_string_new (""); + else + g_string_append_c (string, '.'); + tmp = gda_sql_identifier_quote (ids_array[i], context->cnc, + context->provider, FALSE, + cncoptions & GDA_CONNECTION_OPTIONS_SQL_IDENTIFIERS_CASE_SENSITIVE); + g_string_append (string, tmp); + g_free (tmp); + } + g_strfreev (ids_array); + str = g_string_free (string, FALSE); + } + } + else { + /* we don't have an identifier */ + if (!g_ascii_strcasecmp (vstr, "default")) { + if (is_default) + *is_default = TRUE; + str = g_strdup ("DEFAULT"); + } + else if (!g_ascii_strcasecmp (vstr, "FALSE")) { + g_free (str); + str = g_strdup ("0"); + } + else if (!g_ascii_strcasecmp (vstr, "TRUE")) { + g_free (str); + str = g_strdup ("1"); + } + else + str = g_strdup (vstr); + } + } + else { + str = g_strdup ("NULL"); + if (is_null) + *is_null = TRUE; + } + } + if (!str) { + /* use a GdaDataHandler to render the value as valid SQL */ + GdaDataHandler *dh; + if (context->cnc) { + GdaServerProvider *prov; + prov = gda_connection_get_provider (context->cnc); + dh = gda_server_provider_get_data_handler_g_type (prov, context->cnc, + G_VALUE_TYPE (expr->value)); + if (!dh) + goto err; + else + g_object_ref (dh); + } + else + dh = gda_data_handler_get_default (G_VALUE_TYPE (expr->value)); + + if (dh) { + str = gda_data_handler_get_sql_from_value (dh, expr->value); + g_object_unref (dh); + } + else + str = gda_value_stringify (expr->value); + if (!str) goto err; + } + } + else if (expr->func) { + str = context->render_function (GDA_SQL_ANY_PART (expr->func), context, error); + if (!str) goto err; + } + else if (expr->cond) { + gchar *tmp; + tmp = context->render_operation (GDA_SQL_ANY_PART (expr->cond), context, error); + if (!tmp) goto err; + str = NULL; + if (GDA_SQL_ANY_PART (expr)->parent) { + if (GDA_SQL_ANY_PART (expr)->parent->type == GDA_SQL_ANY_STMT_SELECT) { + GdaSqlStatementSelect *selst; + selst = (GdaSqlStatementSelect*) (GDA_SQL_ANY_PART (expr)->parent); + if ((expr == selst->where_cond) || + (expr == selst->having_cond)) + str = tmp; + } + else if (GDA_SQL_ANY_PART (expr)->parent->type == GDA_SQL_ANY_STMT_DELETE) { + GdaSqlStatementDelete *delst; + delst = (GdaSqlStatementDelete*) (GDA_SQL_ANY_PART (expr)->parent); + if (expr == delst->cond) + str = tmp; + } + else if (GDA_SQL_ANY_PART (expr)->parent->type == GDA_SQL_ANY_STMT_UPDATE) { + GdaSqlStatementUpdate *updst; + updst = (GdaSqlStatementUpdate*) (GDA_SQL_ANY_PART (expr)->parent); + if (expr == updst->cond) + str = tmp; + } + } + + if (!str) { + str = g_strconcat ("(", tmp, ")", NULL); + g_free (tmp); + } + } + else if (expr->select) { + gchar *str1; + if (GDA_SQL_ANY_PART (expr->select)->type == GDA_SQL_ANY_STMT_SELECT) + str1 = context->render_select (GDA_SQL_ANY_PART (expr->select), context, error); + else if (GDA_SQL_ANY_PART (expr->select)->type == GDA_SQL_ANY_STMT_COMPOUND) + str1 = context->render_compound (GDA_SQL_ANY_PART (expr->select), context, error); + else + g_assert_not_reached (); + if (!str1) goto err; + + if (! GDA_SQL_ANY_PART (expr)->parent || + (GDA_SQL_ANY_PART (expr)->parent->type != GDA_SQL_ANY_SQL_FUNCTION)) { + str = g_strconcat ("(", str1, ")", NULL); + g_free (str1); + } + else + str = str1; + } + else if (expr->case_s) { + str = context->render_case (GDA_SQL_ANY_PART (expr->case_s), context, error); + if (!str) goto err; + } + else { + if (is_null) + *is_null = TRUE; + str = g_strdup ("NULL"); + } + + if (!str) goto err; + + if (expr->cast_as) + g_string_append_printf (string, "CAST (%s AS %s)", str, expr->cast_as); + else + g_string_append (string, str); + g_free (str); + + str = string->str; + g_string_free (string, FALSE); + return str; + + err: + g_string_free (string, TRUE); + return NULL; +} + +/* + * Statement prepare request + */ +static GdaSqlitePStmt *real_prepare (GdaServerProvider *provider, GdaConnection *cnc, GdaStatement *stmt, GError **error); +static gboolean +gda_sqlite_provider_statement_prepare (GdaServerProvider *provider, GdaConnection *cnc, + GdaStatement *stmt, GError **error) +{ + GdaSqlitePStmt *ps; + + g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE); + g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE); + g_return_val_if_fail (GDA_IS_STATEMENT (stmt), FALSE); + + /* fetch prepares stmt if already done */ + ps = (GdaSqlitePStmt *) gda_connection_get_prepared_statement (cnc, stmt); + if (ps) + return TRUE; + + ps = real_prepare (provider, cnc, stmt, error); + if (!ps) + return FALSE; + else { + gda_connection_add_prepared_statement (cnc, stmt, (GdaPStmt *) ps); + g_object_unref (ps); + return TRUE; + } +} + +/* + * Creates a new GdaStatement, as a copy of @stmt, and adds new OID columns, one for each table involved + * in the SELECT + * The GHashTable created (as @out_hash) contains: + * - key = table name + * - value = column number in the SELECT (use GPOINTER_TO_INT) + * + * This step is required for BLOBs which needs to table's ROWID to be opened. The extra columns + * won't appear in the final result set. + */ +static GdaStatement * +add_oid_columns (GdaStatement *stmt, GHashTable **out_hash, gint *out_nb_cols_added) +{ + GHashTable *hash = NULL; + GdaStatement *nstmt; + GdaSqlStatement *sqlst; + GdaSqlStatementSelect *sst; + gint nb_cols_added = 0; + gint add_index; + GSList *list; + + *out_hash = NULL; + *out_nb_cols_added = 0; + + GdaSqlStatementType type; + type = gda_statement_get_statement_type (stmt); + if (type == GDA_SQL_STATEMENT_COMPOUND) { + return g_object_ref (stmt); + } + else if (type != GDA_SQL_STATEMENT_SELECT) { + return g_object_ref (stmt); + } + + g_object_get (G_OBJECT (stmt), "structure", &sqlst, NULL); + g_assert (sqlst); + hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); + sst = (GdaSqlStatementSelect*) sqlst->contents; + + if (!sst->from || sst->distinct) { + gda_sql_statement_free (sqlst); + return g_object_ref (stmt); + } + + /* if there is an ORDER BY test if we can alter it */ + if (sst->order_by) { + for (list = sst->order_by; list; list = list->next) { + GdaSqlSelectOrder *order = (GdaSqlSelectOrder*) list->data; + if (order->expr && order->expr->value && + (G_VALUE_TYPE (order->expr->value) != G_TYPE_STRING)) { + gda_sql_statement_free (sqlst); + return g_object_ref (stmt); + } + } + } + + add_index = 0; + for (list = sst->from->targets; list; list = list->next) { + GdaSqlSelectTarget *target = (GdaSqlSelectTarget*) list->data; + GdaSqlSelectField *field; + + if (!target->table_name) + continue; + + /* add a field */ + field = gda_sql_select_field_new (GDA_SQL_ANY_PART (sst)); + sst->expr_list = g_slist_insert (sst->expr_list, field, add_index); + + field->expr = gda_sql_expr_new (GDA_SQL_ANY_PART (field)); + + gchar *str, *tmp; + const gchar *name; + if (target->as) + name = target->as; + else + name = target->table_name; + + tmp = gda_sql_identifier_quote (name, NULL, NULL, FALSE, FALSE); + str = g_strdup_printf ("%s.rowid", tmp); + g_free (tmp); + g_value_take_string ((field->expr->value = gda_value_new (G_TYPE_STRING)), str); + + /* add to hash table */ + add_index++; + g_hash_table_insert (hash, gda_sql_identifier_prepare_for_compare (g_strdup (name)), + GINT_TO_POINTER (add_index)); /* ADDED 1 to column number, + * don't forget to remove 1 when using */ + if (target->as) + g_hash_table_insert (hash, gda_sql_identifier_prepare_for_compare (g_strdup (target->table_name)), + GINT_TO_POINTER (add_index)); /* ADDED 1 to column number, + * don't forget to remove 1 when using */ + nb_cols_added ++; + } + + /* if there is an ORDER BY which uses numbers, then also alter that */ + if (sst->order_by) { + for (list = sst->order_by; list; list = list->next) { + GdaSqlSelectOrder *order = (GdaSqlSelectOrder*) list->data; + if (order->expr && order->expr->value) { + long i; + const gchar *cstr; + gchar *endptr = NULL; + cstr = g_value_get_string (order->expr->value); + i = strtol (cstr, (char **) &endptr, 10); + if (!endptr || !(*endptr)) { + i += nb_cols_added; + endptr = g_strdup_printf ("%ld", i); + g_value_take_string (order->expr->value, endptr); + } + } + } + } + + /* prepare return */ + nstmt = (GdaStatement*) g_object_new (GDA_TYPE_STATEMENT, "structure", sqlst, NULL); + gda_sql_statement_free (sqlst); + /*g_print ("%s(): Added %d columns: %s\n", __FUNCTION__, nb_cols_added, gda_statement_to_sql (nstmt, NULL, NULL));*/ + + *out_hash = hash; + *out_nb_cols_added = nb_cols_added; + + return nstmt; +} + +static GdaSqlitePStmt * +real_prepare (GdaServerProvider *provider, GdaConnection *cnc, GdaStatement *stmt, GError **error) +{ + int status; + SqliteConnectionData *cdata; + sqlite3_stmt *sqlite_stmt; + gchar *sql; + const char *left; + GdaSqlitePStmt *ps; + GdaSet *params = NULL; + GSList *used_params = NULL; + + GdaStatement *real_stmt; + GHashTable *hash; + gint nb_rows_added; + GdaSqliteProvider *prov = GDA_SQLITE_PROVIDER (provider); + + /* get SQLite's private data */ + cdata = (SqliteConnectionData*) gda_connection_internal_get_provider_data_error (cnc, error); + if (!cdata) + return NULL; + + /* render as SQL understood by SQLite */ + if (! gda_statement_get_parameters (stmt, ¶ms, error)) + return NULL; + + real_stmt = add_oid_columns (stmt, &hash, &nb_rows_added); + sql = gda_sqlite_provider_statement_to_sql (provider, cnc, real_stmt, params, GDA_STATEMENT_SQL_PARAMS_AS_QMARK, + &used_params, error); + if (!sql) + goto out_err; + + /* prepare statement */ + status = SQLITE3_CALL (prov, sqlite3_prepare_v2) (cdata->connection, sql, -1, &sqlite_stmt, &left); + if (status != SQLITE_OK) { + g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_PREPARE_STMT_ERROR, + "%s", SQLITE3_CALL (prov, sqlite3_errmsg) (cdata->connection)); + goto out_err; + } + + if (left && (*left != 0)) + g_warning ("SQlite SQL: %s (REMAIN:%s)\n", sql, left); + + /* make a list of the parameter names used in the statement */ + GSList *param_ids = NULL; + if (used_params) { + GSList *list; + for (list = used_params; list; list = list->next) { + const gchar *cid; + cid = gda_holder_get_id (GDA_HOLDER (list->data)); + if (cid) { + param_ids = g_slist_append (param_ids, g_strdup (cid)); + /*g_print ("PREPARATION: param ID: %s\n", cid);*/ + } + else { + g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_PREPARE_STMT_ERROR, + "%s", _("Unnamed parameter is not allowed in prepared statements")); + g_slist_free_full (param_ids, (GDestroyNotify) g_free); + goto out_err; + } + } + g_slist_free (used_params); + } + if (params) + g_object_unref (params); + + /* create a prepared statement object */ + ps = _gda_sqlite_pstmt_new (GDA_SQLITE_PROVIDER (provider), sqlite_stmt); + gda_pstmt_set_gda_statement (_GDA_PSTMT (ps), stmt); + gda_pstmt_set_param_ids (_GDA_PSTMT (ps), param_ids); + gda_pstmt_set_sql (_GDA_PSTMT (ps), sql); + _gda_sqlite_pstmt_set_rowid_hash (ps, hash); + _gda_sqlite_pstmt_set_nb_rowid_columns (ps, nb_rows_added); + g_object_unref (real_stmt); + /*g_print ("%s(%s) => GdaSqlitePStmt %p\n", __FUNCTION__, sql, ps);*/ + g_free (sql); + if (hash) + g_hash_table_destroy (hash); + return ps; + + out_err: + if (hash) + g_hash_table_destroy (hash); + g_object_unref (real_stmt); + if (used_params) + g_slist_free (used_params); + if (params) + g_object_unref (params); + if (sql != NULL) { + g_free (sql); + } + return NULL; +} + +#define MAKE_LAST_INSERTED_SET_ID "__gda" +static void +lir_stmt_reset_cb (GdaStatement *stmt, G_GNUC_UNUSED gpointer data) +{ + /* get rid of the SELECT statement used in make_last_inserted_set() */ + g_object_set_data ((GObject*) stmt, MAKE_LAST_INSERTED_SET_ID, NULL); +} + +static GdaSet * +make_last_inserted_set (GdaConnection *cnc, GdaStatement *stmt, sqlite3_int64 last_id) +{ + GError *lerror = NULL; + + GdaStatement *statement; + statement = g_object_get_data ((GObject*) stmt, MAKE_LAST_INSERTED_SET_ID); + if (!statement) { + /* analyze @stmt */ + GdaSqlStatement *sql_insert; + GdaSqlStatementInsert *insert; + if (gda_statement_get_statement_type (stmt) != GDA_SQL_STATEMENT_INSERT) + /* unable to compute anything */ + return NULL; + g_object_get (G_OBJECT (stmt), "structure", &sql_insert, NULL); + g_assert (sql_insert); + insert = (GdaSqlStatementInsert *) sql_insert->contents; + + /* build corresponding SELECT statement */ + GdaSqlStatementSelect *select; + GdaSqlSelectTarget *target; + GdaSqlStatement *sql_statement = gda_sql_statement_new (GDA_SQL_STATEMENT_SELECT); + + select = (GdaSqlStatementSelect*) sql_statement->contents; + + /* FROM */ + select->from = gda_sql_select_from_new (GDA_SQL_ANY_PART (select)); + target = gda_sql_select_target_new (GDA_SQL_ANY_PART (select->from)); + gda_sql_select_from_take_new_target (select->from, target); + + /* Filling in the target */ + GValue *value; + g_value_set_string ((value = gda_value_new (G_TYPE_STRING)), insert->table->table_name); + gda_sql_select_target_take_table_name (target, value); + gda_sql_statement_free (sql_insert); + + /* selected fields */ + GdaSqlSelectField *field; + GSList *fields_list = NULL; + + field = gda_sql_select_field_new (GDA_SQL_ANY_PART (select)); + g_value_set_string ((value = gda_value_new (G_TYPE_STRING)), "*"); + gda_sql_select_field_take_star_value (field, value); + fields_list = g_slist_append (fields_list, field); + + gda_sql_statement_select_take_expr_list (sql_statement, fields_list); + + /* WHERE */ + GdaSqlExpr *where, *expr; + GdaSqlOperation *cond; + where = gda_sql_expr_new (GDA_SQL_ANY_PART (select)); + cond = gda_sql_operation_new (GDA_SQL_ANY_PART (where)); + where->cond = cond; + cond->operator_type = GDA_SQL_OPERATOR_TYPE_EQ; + expr = gda_sql_expr_new (GDA_SQL_ANY_PART (cond)); + g_value_set_string ((value = gda_value_new (G_TYPE_STRING)), "rowid"); + expr->value = value; + cond->operands = g_slist_append (NULL, expr); + + GdaSqlParamSpec *pspec = g_new0 (GdaSqlParamSpec, 1); + pspec->name = g_strdup ("lid"); + pspec->g_type = G_TYPE_INT64; + pspec->nullok = TRUE; + pspec->is_param = TRUE; + expr = gda_sql_expr_new (GDA_SQL_ANY_PART (cond)); + expr->param_spec = pspec; + cond->operands = g_slist_append (cond->operands, expr); + + gda_sql_statement_select_take_where_cond (sql_statement, where); + + if (gda_sql_statement_check_structure (sql_statement, &lerror) == FALSE) { + g_warning (_("Can't build SELECT statement to get last inserted row: %s"), + lerror && lerror->message ? lerror->message : _("No detail")); + if (lerror) + g_error_free (lerror); + gda_sql_statement_free (sql_statement); + return NULL; + } + statement = g_object_new (GDA_TYPE_STATEMENT, "structure", sql_statement, NULL); + gda_sql_statement_free (sql_statement); + + GdaSet *params; + if (! gda_statement_get_parameters (statement, ¶ms, &lerror)) { + g_warning (_("Can't build SELECT statement to get last inserted row: %s"), + lerror && lerror->message ? lerror->message : _("No detail")); + if (lerror) + g_error_free (lerror); + g_object_unref (statement); + return NULL; + } + + g_object_set_data_full ((GObject*) stmt, MAKE_LAST_INSERTED_SET_ID, statement, g_object_unref); + g_object_set_data_full ((GObject*) stmt, MAKE_LAST_INSERTED_SET_ID "P", params, g_object_unref); + g_signal_connect (stmt, "reset", + G_CALLBACK (lir_stmt_reset_cb), NULL); + } + + /* execute SELECT statement */ + GdaDataModel *model; + GdaSet *params; + params = g_object_get_data ((GObject*) stmt, MAKE_LAST_INSERTED_SET_ID "P"); + g_assert (params); + g_assert (gda_set_set_holder_value (params, NULL, "lid", last_id)); + model = gda_connection_statement_execute_select (cnc, statement, params, NULL); + if (!model) { + /* may have failed if the table has the WITHOUT ROWID optimization + * see: https://www.sqlite.org/withoutrowid.html + */ + return NULL; + } + else { + GdaSet *set = NULL; + GSList *holders = NULL; + gint nrows, ncols, i; + + nrows = gda_data_model_get_n_rows (model); + if (nrows <= 0) { + g_warning (_("SELECT statement to get last inserted row did not return any row")); + return NULL; + } + else if (nrows > 1) { + g_warning (_("SELECT statement to get last inserted row returned too many (%d) rows"), + nrows); + return NULL; + } + ncols = gda_data_model_get_n_columns (model); + for (i = 0; i < ncols; i++) { + GdaHolder *h; + GdaColumn *col; + gchar *id; + const GValue *cvalue; + col = gda_data_model_describe_column (model, i); + id = g_strdup_printf ("+%d", i); + h = gda_holder_new (gda_column_get_g_type (col), id); + g_object_set (G_OBJECT (h), + "name", gda_column_get_name (col), NULL); + g_free (id); + cvalue = gda_data_model_get_value_at (model, i, 0, NULL); + if (!cvalue || !gda_holder_set_value (h, cvalue, NULL)) { + if (holders) { + g_slist_free_full (holders, (GDestroyNotify) g_object_unref); + holders = NULL; + } + break; + } + holders = g_slist_prepend (holders, h); + } + g_object_unref (model); + + if (holders) { + holders = g_slist_reverse (holders); + set = gda_set_new_read_only (holders); + g_slist_free_full (holders, (GDestroyNotify) g_object_unref); + } + + return set; + } +} + +/* + * This function opens any blob which has been inserted or updated as a ZERO blob (the blob currently + * only contains zeros) and fills its contents with the blob passed as parameter when executing the statement. + * + * @blobs_list is freed here + */ +static GdaConnectionEvent * +fill_blob_data (GdaConnection *cnc, GdaSet *params, + SqliteConnectionData *cdata, GdaSqlitePStmt *pstmt, GSList *blobs_list, GError **error) +{ + if (!blobs_list) + /* nothing to do */ + return NULL; + + const gchar *cstr = NULL; + GdaStatement *stmt; + sqlite3_int64 rowid = -1; + GdaDataModel *model = NULL; + GError *lerror = NULL; + GdaSqliteProvider *prov = GDA_SQLITE_PROVIDER (gda_connection_get_provider (cnc)); + + /* get single ROWID or a list of ROWID */ + stmt = gda_pstmt_get_gda_statement (GDA_PSTMT (pstmt)); + if (!stmt) { + g_set_error (&lerror, GDA_SERVER_PROVIDER_ERROR, + GDA_SERVER_PROVIDER_INTERNAL_ERROR, "%s", + _("Prepared statement has no associated GdaStatement")); + goto blobs_out; + } + if (gda_statement_get_statement_type (stmt) == GDA_SQL_STATEMENT_INSERT) { + rowid = SQLITE3_CALL (prov, sqlite3_last_insert_rowid) (cdata->connection); + } + else if (gda_statement_get_statement_type (stmt) == GDA_SQL_STATEMENT_UPDATE) { + GdaSqlStatement *sel_stmt; + GdaSqlStatementSelect *sst; + sel_stmt = gda_compute_select_statement_from_update (stmt, &lerror); + if (!sel_stmt) + goto blobs_out; + sst = (GdaSqlStatementSelect*) sel_stmt->contents; + GdaSqlSelectField *oidfield; + oidfield = gda_sql_select_field_new (GDA_SQL_ANY_PART (sst)); + sst->expr_list = g_slist_prepend (NULL, oidfield); + oidfield->expr = gda_sql_expr_new (GDA_SQL_ANY_PART (oidfield)); + g_value_set_string ((oidfield->expr->value = gda_value_new (G_TYPE_STRING)), "rowid"); + + GdaStatement *select; + select = (GdaStatement *) g_object_new (GDA_TYPE_STATEMENT, "structure", sel_stmt, NULL); + gda_sql_statement_free (sel_stmt); + model = gda_connection_statement_execute_select (cnc, select, params, &lerror); + if (!model) { + g_object_unref (select); + goto blobs_out; + } + g_object_unref (select); + } + g_object_unref (stmt); + + /* actual blob filling */ + GSList *list; + for (list = blobs_list; list; list = list->next) { + PendingBlob *pb = (PendingBlob*) list->data; + + if (rowid >= 0) { + /*g_print ("Filling BLOB @ %s.%s.%s, rowID %ld\n", pb->db, pb->table, pb->column, rowid);*/ + GdaSqliteBlobOp *bop; + bop = (GdaSqliteBlobOp*) _gda_sqlite_blob_op_new (cnc, pb->db, pb->table, pb->column, rowid); + if (!bop) { + cstr = _("Can't create SQLite BLOB handle"); + goto blobs_out; + } + if (gda_blob_op_write (GDA_BLOB_OP (bop), pb->blob, 0) < 0) { + cstr = _("Can't write to SQLite's BLOB"); + g_object_unref (bop); + goto blobs_out; + } + g_object_unref (bop); + } + else if (model) { + gint nrows, i; + nrows = gda_data_model_get_n_rows (model); + for (i = 0; i < nrows; i++) { + const GValue *cvalue; + cvalue = gda_data_model_get_value_at (model, 0, i, &lerror); + if (!cvalue) { + g_object_unref (model); + goto blobs_out; + } + if (G_VALUE_TYPE (cvalue) == G_TYPE_INT64) + rowid = g_value_get_int64 (cvalue); + else if (G_VALUE_TYPE (cvalue) == G_TYPE_INT) + rowid = g_value_get_int (cvalue); + else { + g_set_error (&lerror, GDA_SERVER_PROVIDER_ERROR, + GDA_SERVER_PROVIDER_INTERNAL_ERROR, + _("Can't obtain SQLite BLOB handle (reported type is '%s'), " + "please report this bug to " + "http://gitlab.gnome.org/GNOME/libgda/issues"), + g_type_name (G_VALUE_TYPE (cvalue))); + g_object_unref (model); + goto blobs_out; + } + GdaSqliteBlobOp *bop; + bop = (GdaSqliteBlobOp*) _gda_sqlite_blob_op_new (cnc, pb->db, pb->table, pb->column, rowid); + if (!bop) { + cstr = _("Can't create SQLite BLOB handle"); + g_object_unref (model); + goto blobs_out; + } + if (gda_blob_op_write (GDA_BLOB_OP (bop), pb->blob, 0) < 0) { + cstr = _("Can't write to SQLite's BLOB"); + g_object_unref (bop); + g_object_unref (model); + goto blobs_out; + } + g_object_unref (bop); + } + g_object_unref (model); + } + else + cstr = _("Can't identify the ROWID of the blob to fill"); + } + + blobs_out: + pending_blobs_free_list (blobs_list); + + if (cstr) { + GdaConnectionEvent *event; + event = gda_connection_point_available_event (cnc, GDA_CONNECTION_EVENT_ERROR); + gda_connection_event_set_description (event, cstr); + g_set_error (error, GDA_SERVER_PROVIDER_ERROR, + GDA_SERVER_PROVIDER_DATA_ERROR, "%s", cstr); + return event; + } + if (lerror) { + GdaConnectionEvent *event; + event = gda_connection_point_available_event (cnc, GDA_CONNECTION_EVENT_ERROR); + gda_connection_event_set_description (event, lerror->message ? lerror->message : _("No detail")); + g_propagate_error (error, lerror); + return event; + } + return NULL; +} + +/* + * Execute statement request + */ +static GObject * +gda_sqlite_provider_statement_execute (GdaServerProvider *provider, GdaConnection *cnc, + GdaStatement *stmt, GdaSet *params, + GdaStatementModelUsage model_usage, + GType *col_types, GdaSet **last_inserted_row, GError **error) +{ + GdaSqlitePStmt *ps; + SqliteConnectionData *cdata; + gboolean new_ps = FALSE; + gboolean allow_noparam; + gboolean empty_rs = FALSE; /* TRUE when @allow_noparam is TRUE and there is a problem with @params + => resulting data model will be empty (0 row) */ + GdaSqliteProvider *prov = GDA_SQLITE_PROVIDER (provider); + + g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL); + g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, NULL); + g_return_val_if_fail (GDA_IS_STATEMENT (stmt), NULL); + + allow_noparam = (model_usage & GDA_STATEMENT_MODEL_ALLOW_NOPARAM) && + (gda_statement_get_statement_type (stmt) == GDA_SQL_STATEMENT_SELECT); + + if (last_inserted_row) + *last_inserted_row = NULL; + + /* get SQLite's private data */ + cdata = (SqliteConnectionData*) gda_connection_internal_get_provider_data_error (cnc, error); + if (!cdata) + return NULL; + + /* get/create new prepared statement */ + ps = (GdaSqlitePStmt *) gda_connection_get_prepared_statement (cnc, stmt); + if (!ps) { + if (!gda_sqlite_provider_statement_prepare (provider, cnc, stmt, NULL)) { + /* try to use the SQL when parameters are rendered with their values, using GMT for timezones */ + gchar *sql; + int status; + sqlite3_stmt *sqlite_stmt; + char *left; + + sql = gda_sqlite_provider_statement_to_sql (provider, cnc, stmt, params, + GDA_STATEMENT_SQL_TIMEZONE_TO_GMT, NULL, error); + if (!sql) + return NULL; + + status = SQLITE3_CALL (prov, sqlite3_prepare_v2) (cdata->connection, sql, -1, + &sqlite_stmt, (const char**) &left); + if (status != SQLITE_OK) { + g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_PREPARE_STMT_ERROR, + "%s", SQLITE3_CALL (prov, sqlite3_errmsg) (cdata->connection)); + g_free (sql); + return NULL; + } + + if (left && (*left != 0)) { + g_warning ("SQlite SQL: %s (REMAIN:%s)\n", sql, left); + *left = 0; + } + + /* create a SQLitePreparedStatement */ + ps = _gda_sqlite_pstmt_new (GDA_SQLITE_PROVIDER (provider), sqlite_stmt); + gda_pstmt_set_sql (_GDA_PSTMT (ps), sql); + g_free (sql); + + new_ps = TRUE; + } + else + ps = (GdaSqlitePStmt *) gda_connection_get_prepared_statement (cnc, stmt); + } + else if (_gda_sqlite_pstmt_get_is_used (ps)) { + /* Don't use @ps => prepare stmt again */ + GdaSqlitePStmt *nps; + nps = real_prepare (provider, cnc, stmt, error); + if (!nps) + return NULL; + gda_pstmt_copy_contents ((GdaPStmt *) ps, (GdaPStmt *) nps); + ps = nps; + new_ps = TRUE; + } + + /* check that prepared stmt is not NULL, to avoid a crash */ + if (!_gda_sqlite_pstmt_get_stmt (ps)) { + GdaConnectionEvent *event; + const char *errmsg; + + errmsg = _("Empty statement"); + event = gda_connection_point_available_event (cnc, GDA_CONNECTION_EVENT_ERROR); + gda_connection_event_set_description (event, errmsg); + gda_connection_add_event (cnc, event); + gda_connection_del_prepared_statement (cnc, stmt); + g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_EMPTY_STMT_ERROR, + "%s", errmsg); + if (new_ps) + g_object_unref (ps); + return NULL; + } + + /* reset prepared stmt */ + if ((SQLITE3_CALL (prov, sqlite3_reset) (_gda_sqlite_pstmt_get_stmt (ps)) != SQLITE_OK) || + (SQLITE3_CALL (prov, sqlite3_clear_bindings) (_gda_sqlite_pstmt_get_stmt (ps)) != SQLITE_OK)) { + GdaConnectionEvent *event; + const char *errmsg; + + errmsg = SQLITE3_CALL (prov, sqlite3_errmsg) (cdata->connection); + event = gda_connection_point_available_event (cnc, GDA_CONNECTION_EVENT_ERROR); + gda_connection_event_set_description (event, errmsg); + gda_connection_add_event (cnc, event); + gda_connection_del_prepared_statement (cnc, stmt); + g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_PREPARE_STMT_ERROR, + "%s", errmsg); + if (new_ps) + g_object_unref (ps); + return NULL; + } + + /* bind statement's parameters */ + GSList *list; + GdaConnectionEvent *event = NULL; + int i; + GSList *blobs_list = NULL; /* list of PendingBlob structures */ + + for (i = 1, list = gda_pstmt_get_param_ids (_GDA_PSTMT (ps)); list; list = list->next, i++) { + const gchar *pname = (gchar *) list->data; + GdaHolder *h = NULL; + + if (!params) { + event = gda_connection_point_available_event (cnc, GDA_CONNECTION_EVENT_ERROR); + gda_connection_event_set_description (event, _("Missing parameter(s) to execute query")); + g_set_error (error, GDA_SERVER_PROVIDER_ERROR, + GDA_SERVER_PROVIDER_MISSING_PARAM_ERROR, + "%s", _("Missing parameter(s) to execute query")); + break; + } + + h = gda_set_get_holder (params, pname); + if (!h) { + gchar *tmp = gda_alphanum_to_text (g_strdup (pname + 1)); + if (tmp) { + h = gda_set_get_holder (params, tmp); + g_free (tmp); + } + } + if (!h) { + if (allow_noparam) { + /* bind param to NULL */ + SQLITE3_CALL (prov, sqlite3_bind_null) (_gda_sqlite_pstmt_get_stmt (ps), i); + empty_rs = TRUE; + continue; + } + else { + + gchar *str; + str = g_strdup_printf (_("Missing parameter '%s' to execute query"), pname); + event = gda_connection_point_available_event (cnc, GDA_CONNECTION_EVENT_ERROR); + gda_connection_event_set_description (event, str); + g_set_error (error, GDA_SERVER_PROVIDER_ERROR, + GDA_SERVER_PROVIDER_MISSING_PARAM_ERROR, "%s", str); + g_free (str); + break; + } + } + + if (!gda_holder_is_valid (h)) { + if (allow_noparam) { + /* bind param to NULL */ + SQLITE3_CALL (prov, sqlite3_bind_null) (_gda_sqlite_pstmt_get_stmt (ps), i); + empty_rs = TRUE; + continue; + } + else { + gchar *str; + str = g_strdup_printf (_("Parameter '%s' is invalid"), pname); + event = gda_connection_point_available_event (cnc, GDA_CONNECTION_EVENT_ERROR); + gda_connection_event_set_description (event, str); + g_set_error (error, GDA_SERVER_PROVIDER_ERROR, + GDA_SERVER_PROVIDER_MISSING_PARAM_ERROR, "%s", str); + g_free (str); + break; + } + } + else if (gda_holder_value_is_default (h) && !gda_holder_get_value (h)) { + /* create a new GdaStatement to handle all default values and execute it instead */ + GdaSqlStatement *sqlst = NULL; + GError *lerror = NULL; + sqlst = gda_statement_rewrite_for_default_values (stmt, params, TRUE, &lerror); + if (!sqlst) { + event = gda_connection_point_available_event (cnc, + GDA_CONNECTION_EVENT_ERROR); + gda_connection_event_set_description (event, lerror && lerror->message ? + lerror->message : + _("Can't rewrite statement handle default values")); + g_propagate_error (error, lerror); + break; + } + + GdaStatement *rstmt = NULL; + GObject *res; + rstmt = g_object_new (GDA_TYPE_STATEMENT, "structure", sqlst, NULL); + gda_sql_statement_free (sqlst); + if (new_ps) + g_object_unref (ps); + pending_blobs_free_list (blobs_list); + res = gda_sqlite_provider_statement_execute (provider, cnc, + rstmt, params, + model_usage, + col_types, last_inserted_row, error); + g_object_unref (rstmt); + return res; + } + + const GValue *value = gda_holder_get_value (h); + /*g_print ("BINDING param '%s' to GdaHolder %p, valued to [%s]\n", pname, h, gda_value_stringify (value));*/ + if (!value || gda_value_is_null (value)) { + GdaStatement *rstmt = NULL; + if (! gda_rewrite_statement_for_null_parameters (stmt, params, &rstmt, error)) + SQLITE3_CALL (prov, sqlite3_bind_null) (_gda_sqlite_pstmt_get_stmt (ps), i); + else if (rstmt == NULL) { + return NULL; + } else { + /* The strategy here is to execute @rstmt using its prepared + * statement, but with common data from @ps. Beware that + * the @param_ids attribute needs to be retained (i.e. it must not + * be the one copied from @ps) */ + GObject *obj; + GdaSqlitePStmt *tps; + GdaPStmt *gtps; + GSList *prep_param_ids, *copied_param_ids; + if (!gda_sqlite_provider_statement_prepare (provider, cnc, + rstmt, error)) + return NULL; + tps = (GdaSqlitePStmt *) + gda_connection_get_prepared_statement (cnc, rstmt); + gtps = (GdaPStmt *) tps; + + /* keep @param_ids to avoid being cleared by gda_pstmt_copy_contents() */ + prep_param_ids = gda_pstmt_get_param_ids (gtps); + gda_pstmt_set_param_ids (gtps, NULL); + + /* actual copy */ + gda_pstmt_copy_contents ((GdaPStmt *) ps, (GdaPStmt *) tps); + + /* restore previous @param_ids */ + copied_param_ids = gda_pstmt_get_param_ids (gtps); + gda_pstmt_set_param_ids (gtps, prep_param_ids); + + /* execute */ + obj = gda_sqlite_provider_statement_execute (provider, cnc, + rstmt, params, + model_usage, + col_types, + last_inserted_row, error); + /* clear original @param_ids and restore copied one */ + g_slist_free_full (prep_param_ids, (GDestroyNotify) g_free); + + gda_pstmt_set_param_ids (gtps, copied_param_ids); + + /*if (GDA_IS_DATA_MODEL (obj)) + gda_data_model_dump ((GdaDataModel*) obj, NULL);*/ + + g_object_unref (rstmt); + + if (new_ps) + g_object_unref (ps); + pending_blobs_free_list (blobs_list); + return obj; + } + } + else if (G_VALUE_TYPE (value) == G_TYPE_STRING) + SQLITE3_CALL (prov, sqlite3_bind_text) (_gda_sqlite_pstmt_get_stmt (ps), i, + g_value_get_string (value), -1, SQLITE_TRANSIENT); + else if (G_VALUE_TYPE (value) == GDA_TYPE_TEXT) { + GdaText *text = (GdaText*) g_value_get_boxed (value); + const gchar *tstr = gda_text_get_string (text); + SQLITE3_CALL (prov, sqlite3_bind_text) (_gda_sqlite_pstmt_get_stmt (ps), i, + tstr, -1, SQLITE_TRANSIENT); + } + else if (G_VALUE_TYPE (value) == G_TYPE_INT) + SQLITE3_CALL (prov, sqlite3_bind_int) (_gda_sqlite_pstmt_get_stmt (ps), i, g_value_get_int (value)); + else if (G_VALUE_TYPE (value) == G_TYPE_LONG) + SQLITE3_CALL (prov, sqlite3_bind_int) (_gda_sqlite_pstmt_get_stmt (ps), i, g_value_get_long (value)); + else if (G_VALUE_TYPE (value) == G_TYPE_DOUBLE) + SQLITE3_CALL (prov, sqlite3_bind_double) (_gda_sqlite_pstmt_get_stmt (ps), i, g_value_get_double (value)); + else if (G_VALUE_TYPE (value) == G_TYPE_FLOAT) + SQLITE3_CALL (prov, sqlite3_bind_double) (_gda_sqlite_pstmt_get_stmt (ps), i, g_value_get_float (value)); + else if (G_VALUE_TYPE (value) == G_TYPE_UINT) + SQLITE3_CALL (prov, sqlite3_bind_int) (_gda_sqlite_pstmt_get_stmt (ps), i, g_value_get_uint (value)); + else if (G_VALUE_TYPE (value) == G_TYPE_BOOLEAN) + SQLITE3_CALL (prov, sqlite3_bind_int) (_gda_sqlite_pstmt_get_stmt (ps), i, g_value_get_boolean (value) ? 1 : 0); + else if (G_VALUE_TYPE (value) == G_TYPE_INT64) + SQLITE3_CALL (prov, sqlite3_bind_int64) (_gda_sqlite_pstmt_get_stmt (ps), i, g_value_get_int64 (value)); + else if (G_VALUE_TYPE (value) == G_TYPE_UINT64) + SQLITE3_CALL (prov, sqlite3_bind_int64) (_gda_sqlite_pstmt_get_stmt (ps), i, g_value_get_uint64 (value)); + else if (G_VALUE_TYPE (value) == GDA_TYPE_SHORT) + SQLITE3_CALL (prov, sqlite3_bind_int) (_gda_sqlite_pstmt_get_stmt (ps), i, gda_value_get_short (value)); + else if (G_VALUE_TYPE (value) == GDA_TYPE_USHORT) + SQLITE3_CALL (prov, sqlite3_bind_int) (_gda_sqlite_pstmt_get_stmt (ps), i, gda_value_get_ushort (value)); + else if (G_VALUE_TYPE (value) == G_TYPE_CHAR) + SQLITE3_CALL (prov, sqlite3_bind_int) (_gda_sqlite_pstmt_get_stmt (ps), i, g_value_get_schar (value)); + else if (G_VALUE_TYPE (value) == G_TYPE_UCHAR) + SQLITE3_CALL (prov, sqlite3_bind_int) (_gda_sqlite_pstmt_get_stmt (ps), i, g_value_get_uchar (value)); + else if (G_VALUE_TYPE (value) == GDA_TYPE_BLOB) { + glong blob_len; + GdaBlob *blob = (GdaBlob*) gda_value_get_blob (value); + const gchar *str = NULL; + + /* force reading the complete BLOB into memory */ + if (gda_blob_get_op (blob)) + blob_len = gda_blob_op_get_length (gda_blob_get_op (blob)); + else + blob_len = gda_binary_get_size (gda_blob_get_binary (blob)); + if (blob_len < 0) + str = _("Can't get BLOB's length"); + else if (blob_len >= G_MAXINT) + str = _("BLOB is too big"); + + if (str) { + event = gda_connection_point_available_event (cnc, GDA_CONNECTION_EVENT_ERROR); + gda_connection_event_set_description (event, str); + g_set_error (error, GDA_SERVER_PROVIDER_ERROR, + GDA_SERVER_PROVIDER_DATA_ERROR, "%s", str); + break; + } + + PendingBlob *pb; + GError *lerror = NULL; + pb = make_pending_blob (provider, cnc, stmt, h, &lerror); + if (!pb) { + event = gda_connection_point_available_event (cnc, GDA_CONNECTION_EVENT_ERROR); + gda_connection_event_set_description (event, + lerror && lerror->message ? lerror->message : _("No detail")); + + g_propagate_error (error, lerror); + break; + } + pb->blob = blob; + blobs_list = g_slist_prepend (blobs_list, pb); + + if (SQLITE3_CALL (prov, sqlite3_bind_zeroblob) (_gda_sqlite_pstmt_get_stmt (ps), i, (int) blob_len) != + SQLITE_OK) { + event = gda_connection_point_available_event (cnc, GDA_CONNECTION_EVENT_ERROR); + gda_connection_event_set_description (event, + lerror && lerror->message ? lerror->message : _("No detail")); + + g_propagate_error (error, lerror); + break; + } + } + else if (G_VALUE_TYPE (value) == GDA_TYPE_BINARY) { + GdaBinary *bin = (GdaBinary *) gda_value_get_binary (value); + SQLITE3_CALL (prov, sqlite3_bind_blob) (_gda_sqlite_pstmt_get_stmt (ps), i, + gda_binary_get_data (bin), gda_binary_get_size (bin), SQLITE_TRANSIENT); + } + else if (G_VALUE_TYPE (value) == GDA_TYPE_TIME) { + gchar *string; + GdaTime *gtime; + + gtime = (GdaTime *) gda_value_get_time (value); + string = gda_time_to_string_utc (gtime); + + SQLITE3_CALL (prov, sqlite3_bind_text) (_gda_sqlite_pstmt_get_stmt (ps), i, string, -1, g_free); + } + else if (G_VALUE_TYPE (value) == G_TYPE_DATE) { + gchar *str; + const GDate *ts; + + ts = g_value_get_boxed (value); + str = g_strdup_printf ("%4d-%02d-%02d", g_date_get_year (ts), + g_date_get_month (ts), g_date_get_day (ts)); + SQLITE3_CALL (prov, sqlite3_bind_text) (_gda_sqlite_pstmt_get_stmt (ps), i, str, -1, g_free); + } + else if (g_type_is_a (G_VALUE_TYPE (value), G_TYPE_DATE_TIME)) { + GDateTime *timestamp; + gboolean tofree = FALSE; + + timestamp = (GDateTime *) g_value_get_boxed (value); + + if (g_date_time_get_utc_offset (timestamp) != 0) { // FIXME: This should be supported now + /* SQLite cant' store timezone information, so if timezone information is + * provided, we do our best and convert it to UTC */ + GTimeZone *tz = g_time_zone_new ("Z"); + timestamp = g_date_time_to_timezone (timestamp, tz); + tofree = TRUE; + } + gchar *string = g_date_time_format (timestamp, "%F %H:%M:%S"); + + if (tofree) + g_date_time_unref (timestamp); + + SQLITE3_CALL (prov, sqlite3_bind_text) (_gda_sqlite_pstmt_get_stmt (ps), i, string, -1, g_free); + } + else if (G_VALUE_TYPE (value) == GDA_TYPE_NUMERIC) { + const GdaNumeric *gdan; + + gdan = gda_value_get_numeric (value); + SQLITE3_CALL (prov, sqlite3_bind_text) (_gda_sqlite_pstmt_get_stmt (ps), i, gda_numeric_get_string((GdaNumeric*)gdan), -1, SQLITE_TRANSIENT); + } + else { + gchar *str; + str = g_strdup_printf (_("Non handled data type '%s'"), + g_type_name (G_VALUE_TYPE (value))); + event = gda_connection_point_available_event (cnc, GDA_CONNECTION_EVENT_ERROR); + gda_connection_event_set_description (event, str); + g_set_error (error, GDA_SERVER_PROVIDER_ERROR, + GDA_SERVER_PROVIDER_MISSING_PARAM_ERROR, "%s", str); + g_free (str); + break; + } + } + + if (event) { + gda_connection_add_event (cnc, event); + if (new_ps) + g_object_unref (ps); + pending_blobs_free_list (blobs_list); + return NULL; + } + + /* add a connection event */ + event = gda_connection_point_available_event (cnc, GDA_CONNECTION_EVENT_COMMAND); + gda_connection_event_set_description (event, gda_pstmt_get_sql (_GDA_PSTMT (ps))); + gda_connection_add_event (cnc, event); + + /* treat prepared and bound statement */ + if (! g_ascii_strncasecmp (gda_pstmt_get_sql (_GDA_PSTMT (ps)), "SELECT", 6) || + ! g_ascii_strncasecmp (gda_pstmt_get_sql (_GDA_PSTMT (ps)), "PRAGMA", 6) || + ! g_ascii_strncasecmp (gda_pstmt_get_sql (_GDA_PSTMT (ps)), "EXPLAIN", 7)) { + GObject *data_model; + GdaDataModelAccessFlags flags; + + if (model_usage & GDA_STATEMENT_MODEL_RANDOM_ACCESS) + flags = GDA_DATA_MODEL_ACCESS_RANDOM; + else if (model_usage & GDA_DATA_MODEL_ACCESS_CURSOR_BACKWARD) + flags = GDA_DATA_MODEL_ACCESS_RANDOM; + else + flags = GDA_DATA_MODEL_ACCESS_CURSOR_FORWARD; + + data_model = (GObject *) _gda_sqlite_recordset_new (cnc, ps, params, flags, col_types, empty_rs); + GError **exceptions; + exceptions = gda_data_model_get_exceptions (GDA_DATA_MODEL (data_model)); + if (exceptions && exceptions[0]) { + GError *e; + e = g_error_copy (exceptions[0]); + event = gda_connection_point_available_event (cnc, GDA_CONNECTION_EVENT_ERROR); + gda_connection_event_set_description (event, e->message ? e->message : _("No detail")); + g_propagate_error (error, e); + g_object_unref (data_model); + return NULL; + } + else { + gda_connection_internal_statement_executed (cnc, stmt, params, NULL); + if (new_ps) + g_object_unref (ps); + pending_blobs_free_list (blobs_list); + return data_model; + } + } + else { + int status, changes; + sqlite3 *handle; + gboolean transaction_started = FALSE; + + if (blobs_list) { + GError *lerror = NULL; + if (! _gda_sqlite_check_transaction_started (cnc, + &transaction_started, &lerror)) { + const gchar *errmsg = _("Could not start transaction to create BLOB"); + event = gda_connection_point_available_event (cnc, + GDA_CONNECTION_EVENT_ERROR); + if (lerror) { + gda_connection_event_set_description (event, + lerror && lerror->message ? + lerror->message : errmsg); + g_propagate_error (error, lerror); + } + else { + gda_connection_event_set_description (event, errmsg); + g_set_error (error, GDA_SERVER_PROVIDER_ERROR, + GDA_SERVER_PROVIDER_STATEMENT_EXEC_ERROR, "%s", errmsg); + } + if (new_ps) + g_object_unref (ps); + pending_blobs_free_list (blobs_list); + return NULL; + } + } + + /* actually execute the command */ + handle = SQLITE3_CALL (prov, sqlite3_db_handle) (_gda_sqlite_pstmt_get_stmt (ps)); + status = SQLITE3_CALL (prov, sqlite3_step) (_gda_sqlite_pstmt_get_stmt (ps)); + guint tries = 0; + while (status == SQLITE_BUSY) { + if (gda_statement_get_statement_type (stmt) == GDA_SQL_STATEMENT_COMMIT) { + break; + } + status = SQLITE3_CALL (prov, sqlite3_step) (_gda_sqlite_pstmt_get_stmt (ps)); + if (tries == 10) { + break; + } + tries++; + } + changes = SQLITE3_CALL (prov, sqlite3_changes) (handle); + if (status != SQLITE_DONE) { + if (SQLITE3_CALL (prov, sqlite3_errcode) (handle) != SQLITE_OK) { + const char *errmsg; + SQLITE3_CALL (prov, sqlite3_reset) (_gda_sqlite_pstmt_get_stmt (ps)); + + errmsg = SQLITE3_CALL (prov, sqlite3_errmsg) (handle); + event = gda_connection_point_available_event (cnc, GDA_CONNECTION_EVENT_ERROR); + gda_connection_event_set_description (event, errmsg); + g_set_error (error, GDA_SERVER_PROVIDER_ERROR, + GDA_SERVER_PROVIDER_STATEMENT_EXEC_ERROR, "%s", errmsg); + + gda_connection_add_event (cnc, event); + gda_connection_internal_statement_executed (cnc, stmt, params, event); + if (new_ps) + g_object_unref (ps); + pending_blobs_free_list (blobs_list); + if (transaction_started) + gda_connection_rollback_transaction (cnc, NULL, NULL); + return NULL; + } + else { + /* could be SQLITE_SCHEMA if database schema has changed and + * changes are incompatible with statement */ + TO_IMPLEMENT; + if (new_ps) + g_object_unref (ps); + pending_blobs_free_list (blobs_list); + if (transaction_started) + gda_connection_rollback_transaction (cnc, NULL, NULL); + return NULL; + } + } + else { + /* fill blobs's data */ + event = fill_blob_data (cnc, params, cdata, ps, blobs_list, error); + if (event) { + /* an error occurred */ + SQLITE3_CALL (prov, sqlite3_reset) (_gda_sqlite_pstmt_get_stmt (ps)); + if (new_ps) + g_object_unref (ps); + if (transaction_started) + gda_connection_rollback_transaction (cnc, NULL, NULL); + return NULL; + } + else if (transaction_started) + gda_connection_commit_transaction (cnc, NULL, NULL); + + gchar *str = NULL; + gboolean count_changes = FALSE; + + if (! g_ascii_strncasecmp (gda_pstmt_get_sql (_GDA_PSTMT (ps)), "DELETE", 6)) { + count_changes = TRUE; + str = g_strdup_printf ("DELETE %d (see SQLite documentation for a \"DELETE * FROM table\" query)", + changes); + } + else if (! g_ascii_strncasecmp (gda_pstmt_get_sql (_GDA_PSTMT (ps)), "INSERT", 6)) { + sqlite3_int64 last_id; + count_changes = TRUE; + last_id = SQLITE3_CALL (prov, sqlite3_last_insert_rowid) (handle); + str = g_strdup_printf ("INSERT %lld %d", last_id, changes); + if (last_inserted_row) + *last_inserted_row = make_last_inserted_set (cnc, stmt, last_id); + } + else if (!g_ascii_strncasecmp (gda_pstmt_get_sql (_GDA_PSTMT (ps)), "UPDATE", 6)) { + count_changes = TRUE; + str = g_strdup_printf ("UPDATE %d", changes); + } + else if (*(gda_pstmt_get_sql (_GDA_PSTMT (ps)))) { + gchar *tmp = g_ascii_strup (gda_pstmt_get_sql (_GDA_PSTMT (ps)), -1); + for (str = tmp; *str && (*str != ' ') && (*str != '\t') && + (*str != '\n'); str++); + *str = 0; + if (changes > 0) { + str = g_strdup_printf ("%s %d", tmp, + changes); + g_free (tmp); + } + else + str = tmp; + } + + if (str) { + event = gda_connection_point_available_event (cnc, GDA_CONNECTION_EVENT_NOTICE); + gda_connection_event_set_description (event, str); + g_free (str); + gda_connection_add_event (cnc, event); + } + gda_connection_internal_statement_executed (cnc, stmt, params, event); + SQLITE3_CALL (prov, sqlite3_reset) (_gda_sqlite_pstmt_get_stmt (ps)); + if (new_ps) + g_object_unref (ps); + + GObject *set; + if (count_changes) { + GdaHolder *holder; + GValue *value; + GSList *list; + + holder = gda_holder_new (G_TYPE_INT, "IMPACTED_ROWS"); + g_value_set_int ((value = gda_value_new (G_TYPE_INT)), changes); + gda_holder_take_value (holder, value, NULL); + list = g_slist_append (NULL, holder); + set = (GObject*) gda_set_new_read_only (list); + g_slist_free (list); + g_object_unref (holder); + } + else + set = (GObject*) gda_set_new_read_only (NULL); + + return set; + } + } +} + +/* + * Rewrites a statement in case some parameters in @params are set to DEFAULT, for INSERT or UPDATE statements + * + * Removes any default value inserted or updated + */ +static GdaSqlStatement * +gda_sqlite_provider_statement_rewrite (GdaServerProvider *provider, GdaConnection *cnc, + GdaStatement *stmt, GdaSet *params, GError **error) +{ + if (cnc) { + g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL); + g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, NULL); + } + return gda_statement_rewrite_for_default_values (stmt, params, TRUE, error); +} + +/* + * SQLite's extra functions' implementations + */ +static void +scalar_gda_file_exists_func (sqlite3_context *context, int argc, sqlite3_value **argv) +{ + const gchar *path; + + if (argc != 1) { + (s3r->sqlite3_result_error) (context, _("Function requires one argument"), -1); + return; + } + + path = (gchar *) (s3r->sqlite3_value_text) (argv [0]); + if (g_file_test (path, G_FILE_TEST_EXISTS)) + (s3r->sqlite3_result_int) (context, 1); + else + (s3r->sqlite3_result_int) (context, 0); +} + + +static void +scalar_gda_hex_print_func (sqlite3_context *context, int argc, sqlite3_value **argv) +{ + GdaBinary *bin; + GdaDataHandler *dh; + GValue *value; + gchar *str; + + if (argc != 1) { + (s3r->sqlite3_result_error) (context, _("Function requires one argument"), -1); + return; + } + + bin = gda_binary_new (); + guchar* buffer = (guchar*) (s3r->sqlite3_value_blob) (argv [0]); + if (!buffer) { + gda_binary_free (bin); + (s3r->sqlite3_result_null) (context); + return; + } + glong length = (s3r->sqlite3_value_bytes) (argv [0]); + gda_binary_set_data (bin, buffer, length); + g_free (free); + gda_value_take_binary ((value = gda_value_new (GDA_TYPE_BINARY)), bin); + dh = gda_data_handler_get_default (GDA_TYPE_BINARY); + str = gda_data_handler_get_str_from_value (dh, value); + g_object_unref (dh); + + gda_value_free (value); + (s3r->sqlite3_result_text) (context, str, -1, g_free); +} + +static void +scalar_gda_hex_print_func2 (sqlite3_context *context, int argc, sqlite3_value **argv) +{ + GdaBinary *bin; + GdaDataHandler *dh; + GValue *value; + gchar *str; + gint size; + + if (argc != 2) { + (s3r->sqlite3_result_error) (context, _("Function requires two arguments"), -1); + return; + } + + bin = gda_binary_new (); + guchar* buffer = (guchar*) (s3r->sqlite3_value_blob) (argv [0]); + if (!buffer) { + gda_binary_free (bin); + (s3r->sqlite3_result_null) (context); + return; + } + glong length = (s3r->sqlite3_value_bytes) (argv [0]); + gda_binary_set_data (bin, buffer, length); + gda_value_take_binary ((value = gda_value_new (GDA_TYPE_BINARY)), bin); + dh = gda_data_handler_get_default (GDA_TYPE_BINARY); + str = gda_data_handler_get_str_from_value (dh, value); + g_object_unref (dh); + + gda_value_free (value); + + size = (s3r->sqlite3_value_int) (argv [1]); + + (s3r->sqlite3_result_text) (context, str, size, g_free); +} + +static void +scalar_rmdiacr (sqlite3_context *context, int argc, sqlite3_value **argv) +{ + gchar *data, *tmp; + CaseModif ncase = CASE_UNCHANGED; + + if (argc == 2) { + data = (gchar*) (s3r->sqlite3_value_text) (argv [1]); + if ((*data == 'u') || (*data == 'U')) + ncase = CASE_UP; + else if ((*data == 'l') || (*data == 'l')) + ncase = CASE_DOWN; + } + else if (argc != 1) { + (s3r->sqlite3_result_error) (context, _("Function requires one or two arguments"), -1); + return; + } + + data = (gchar*) (s3r->sqlite3_value_text) (argv [0]); + if (!data) { + (s3r->sqlite3_result_null) (context); + return; + } + + tmp = remove_diacritics_and_change_case (data, -1, ncase); + (s3r->sqlite3_result_text) (context, tmp, -1, g_free); +} + +static void +scalar_lower (sqlite3_context *context, int argc, sqlite3_value **argv) +{ + gchar *data, *tmp; + + if (argc != 1) { + (s3r->sqlite3_result_error) (context, _("Function requires one argument"), -1); + return; + } + + data = (gchar*) (s3r->sqlite3_value_text) (argv [0]); + if (!data) { + (s3r->sqlite3_result_null) (context); + return; + } + + tmp = g_utf8_strdown (data, -1); + (s3r->sqlite3_result_text) (context, tmp, -1, g_free); +} + +static void +scalar_upper (sqlite3_context *context, int argc, sqlite3_value **argv) +{ + gchar *data, *tmp; + + if (argc != 1) { + (s3r->sqlite3_result_error) (context, _("Function requires one argument"), -1); + return; + } + + data = (gchar*) (s3r->sqlite3_value_text) (argv [0]); + if (!data) { + (s3r->sqlite3_result_null) (context); + return; + } + + tmp = g_utf8_strup (data, -1); + (s3r->sqlite3_result_text) (context, tmp, -1, g_free); +} + +static void +scalar_gda_hex_func (sqlite3_context *context, int argc, sqlite3_value **argv) +{ + guchar *data; + gint length; + GString *string; + gint i; + + if (argc != 1) { + (s3r->sqlite3_result_error) (context, _("Function requires one argument"), -1); + return; + } + + data = (guchar*) (s3r->sqlite3_value_blob) (argv [0]); + if (!data) { + (s3r->sqlite3_result_null) (context); + return; + } + + length = (s3r->sqlite3_value_bytes) (argv [0]); + string = g_string_new (""); + for (i = 0; i < length; i++) { + if ((i > 0) && (i % 4 == 0)) + g_string_append_c (string, ' '); + g_string_append_printf (string, "%02x", data [i]); + } + + (s3r->sqlite3_result_text) (context, string->str, -1, g_free); + g_string_free (string, FALSE); +} + +static void +scalar_gda_hex_func2 (sqlite3_context *context, int argc, sqlite3_value **argv) +{ + guchar *data; + gint length; + GString *string; + gint i; + guint size; + + if (argc != 2) { + (s3r->sqlite3_result_error) (context, _("Function requires two arguments"), -1); + return; + } + + data = (guchar*) (s3r->sqlite3_value_blob) (argv [0]); + if (!data) { + (s3r->sqlite3_result_null) (context); + return; + } + + length = (s3r->sqlite3_value_bytes) (argv [0]); + size = (s3r->sqlite3_value_int) (argv [1]); + + string = g_string_new (""); + for (i = 0; (i < length) && (string->len < (size / 2) * 2 + 2); i++) { + if ((i > 0) && (i % 4 == 0)) + g_string_append_c (string, ' '); + g_string_append_printf (string, "%02x", data [i]); + } + + if (string->len > size) + string->str[size] = 0; + (s3r->sqlite3_result_text) (context, string->str, -1, g_free); + g_string_free (string, FALSE); +} + +static void +scalar_regexp_func (sqlite3_context *context, int argc, sqlite3_value **argv) +{ + GRegex *regex = NULL; + GError *error = NULL; + const gchar *str, *pattern, *options = NULL; + GRegexCompileFlags flags = G_REGEX_OPTIMIZE; + gboolean as_boolean = TRUE; + +#define MAX_DEFINED_REGEX 10 + static GArray *re_array = NULL; /* array of signatures (pattern+option) */ + static GHashTable *re_hash = NULL; /* hash of GRegex */ + + if ((argc != 2) && (argc != 3)) { + (s3r->sqlite3_result_error) (context, _("Function requires two or three arguments"), -1); + return; + } + + str = (gchar*) (s3r->sqlite3_value_text) (argv [1]); + if (!str) { + (s3r->sqlite3_result_null) (context); + return; + } + + pattern = (gchar*) (s3r->sqlite3_value_text) (argv [0]); + if (!pattern) { + (s3r->sqlite3_result_null) (context); + return; + } + + if (argc == 3) + options = (gchar*) (s3r->sqlite3_value_text) (argv [2]); + + if (options) { + const gchar *ptr; + for (ptr = options; *ptr; ptr++) { + switch (*ptr) { + case 'i': + case 'I': + flags |= G_REGEX_CASELESS; + break; + case 'm': + case 'M': + flags |= G_REGEX_MULTILINE; + break; + case 'v': + case 'V': + as_boolean = FALSE; + break; + } + } + } + + GString *sig; + sig = g_string_new (pattern); + g_string_append_c (sig, 0x01); + if (options && *options) + g_string_append (sig, options); + + if (re_hash) + regex = g_hash_table_lookup (re_hash, sig->str); + if (regex) { + /*g_print ("FOUND GRegex %p as [%s]\n", regex, sig->str);*/ + g_string_free (sig, TRUE); + } + else { + regex = g_regex_new ((const gchar*) pattern, flags, 0, &error); + if (! regex) { + gda_log_error (_("SQLite regexp '%s' error:"), pattern, + error && error->message ? error->message : _("Invalid regular expression")); + g_clear_error (&error); + if (as_boolean) + (s3r->sqlite3_result_int) (context, 0); + else + (s3r->sqlite3_result_null) (context); + + g_string_free (sig, TRUE); + return; + } + + if (!re_array) { + re_array = g_array_new (FALSE, FALSE, sizeof (gchar*)); + re_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) g_regex_unref); + } + /*g_print ("ADDED new GRegex %p as [%s]\n", regex, sig->str);*/ + g_hash_table_insert (re_hash, sig->str, regex); + g_array_prepend_val (re_array, sig->str); + g_string_free (sig, FALSE); + if (re_array->len > MAX_DEFINED_REGEX) { + /* get rid of the 'oldest' GRexex */ + gchar *osig; + osig = g_array_index (re_array, gchar*, re_array->len - 1); + /*g_print ("REMOVED GRegex [%s]\n", osig);*/ + g_hash_table_remove (re_hash, osig); + g_array_remove_index (re_array, re_array->len - 1); + } + } + + if (as_boolean) { + if (g_regex_match (regex, str, 0, NULL)) + (s3r->sqlite3_result_int) (context, 1); + else + (s3r->sqlite3_result_int) (context, 0); + } + else { + GMatchInfo *match_info; + g_regex_match (regex, str, 0, &match_info); + if (g_match_info_matches (match_info)) { + gchar *word = g_match_info_fetch (match_info, 0); + (s3r->sqlite3_result_text) (context, word, -1, g_free); + } + else + (s3r->sqlite3_result_null) (context); + g_match_info_free (match_info); + } +} + +static void +scalar_regexp_match_func (sqlite3_context *context, int argc, sqlite3_value **argv) +{ + if ((argc != 2) && (argc != 3)) { + (s3r->sqlite3_result_error) (context, _("Function requires two or three arguments"), -1); + return; + } + + sqlite3_value **nargv; + nargv = g_new (sqlite3_value*, argc); + nargv[0] = argv[1]; + nargv[1] = argv[0]; + if (argc == 3) + nargv[2] = argv[2]; + scalar_regexp_func (context, argc, nargv); + g_free (nargv); +} + +static void +gda_sqlite_free_cnc_data (SqliteConnectionData *cdata) +{ + if (!cdata) + return; + + if (cdata->connection) { + GdaSqliteProvider *prov = g_weak_ref_get (&cdata->provider); + if (prov != NULL) { + (s3r->sqlite3_close_v2) (cdata->connection); + g_object_unref (prov); + } + } + g_free (cdata->file); + if (cdata->types_hash) + g_hash_table_destroy (cdata->types_hash); + if (cdata->types_array) + g_free (cdata->types_array); + g_free (cdata); +} + +static gchar * +gda_sqlite_provider_escape_string (G_GNUC_UNUSED GdaServerProvider *provider, G_GNUC_UNUSED GdaConnection *cnc, const gchar *string) +{ + gchar *ptr, *ret, *retptr; + gint size; + + if (!string) + return NULL; + + /* determination of the new string size */ + ptr = (gchar *) string; + size = 1; + while (*ptr) { + if (*ptr == '\'') + size += 2; + else + size += 1; + ptr++; + } + + ptr = (gchar *) string; + ret = g_new0 (gchar, size); + retptr = ret; + while (*ptr) { + if (*ptr == '\'') { + *retptr = '\''; + *(retptr+1) = *ptr; + retptr += 2; + } + else { + *retptr = *ptr; + retptr ++; + } + ptr++; + } + *retptr = '\0'; + + return ret; +} + +gchar * +gda_sqlite_provider_unescape_string (G_GNUC_UNUSED GdaServerProvider *provider, G_GNUC_UNUSED GdaConnection *cnc, const gchar *string) +{ + glong total; + gchar *ptr; + gchar *retval; + glong offset = 0; + + if (!string) + return NULL; + + total = strlen (string); + retval = g_memdup (string, total+1); + ptr = (gchar *) retval; + while (offset < total) { + if (*ptr == '\'') { + if (*(ptr+1) == '\'') { + memmove (ptr+1, ptr+2, total - offset); + offset += 2; + } + else { + g_free (retval); + return NULL; + } + } + else + offset ++; + + ptr++; + } + + return retval; +} + +/** + * gda_sqlite_provider_get_api: + * @prov: a #GdaSqliteProvider to get API loaded from library in use + * + * Returns: a pointer to internal loaded API from library + */ +gpointer +gda_sqlite_provider_get_api (GdaSqliteProvider *prov) { + GdaSqliteProviderClass *klass = GDA_SQLITE_PROVIDER_GET_CLASS (prov); + if (klass->get_api != NULL) { + return klass->get_api (prov); + } + return NULL; +} + +/* GdaProviderMeta implementations */ + +static GdaDataModel* +gda_sqlite_provider_meta_btypes (GdaProviderMeta *prov, + G_GNUC_UNUSED GError **error) +{ + g_return_val_if_fail (prov, NULL); + g_return_val_if_fail (GDA_IS_PROVIDER_META (prov), NULL); + return NULL; +} +static GdaDataModel* +gda_sqlite_provider_meta_udts (GdaProviderMeta *prov, + G_GNUC_UNUSED GError **error) +{ + g_return_val_if_fail (prov, NULL); + g_return_val_if_fail (GDA_IS_PROVIDER_META (prov), NULL); + return NULL; +} +static GdaRow* +gda_sqlite_provider_meta_udt (GdaProviderMeta *prov, + G_GNUC_UNUSED const gchar *udt_catalog, G_GNUC_UNUSED const gchar *udt_schema, + G_GNUC_UNUSED GError **error) +{ + g_return_val_if_fail (prov, NULL); + g_return_val_if_fail (GDA_IS_PROVIDER_META (prov), NULL); + return NULL; +} +static GdaDataModel* +gda_sqlite_provider_meta_udt_cols (GdaProviderMeta *prov, + G_GNUC_UNUSED GError **error) +{ + g_return_val_if_fail (prov, NULL); + g_return_val_if_fail (GDA_IS_PROVIDER_META (prov), NULL); + return NULL; +} +static GdaRow* +gda_sqlite_provider_meta_udt_col (GdaProviderMeta *prov, + G_GNUC_UNUSED const gchar *udt_catalog, G_GNUC_UNUSED const gchar *udt_schema, + G_GNUC_UNUSED const gchar *udt_name, GError **error) +{ + g_return_val_if_fail (prov, NULL); + g_return_val_if_fail (GDA_IS_PROVIDER_META (prov), NULL); + return NULL; +} +static GdaDataModel* +gda_sqlite_provider_meta_enums_type (GdaProviderMeta *prov, + G_GNUC_UNUSED GError **error) +{ + g_return_val_if_fail (prov, NULL); + g_return_val_if_fail (GDA_IS_PROVIDER_META (prov), NULL); + return NULL; +} +static GdaRow* +gda_sqlite_provider_meta_enum_type (GdaProviderMeta *prov, + G_GNUC_UNUSED const gchar *udt_catalog, + G_GNUC_UNUSED const gchar *udt_schema, G_GNUC_UNUSED const gchar *udt_name, GError **error) +{ + g_return_val_if_fail (prov, NULL); + g_return_val_if_fail (GDA_IS_PROVIDER_META (prov), NULL); + return NULL; +} +static GdaDataModel* +gda_sqlite_provider_meta_domains (GdaProviderMeta *prov, + G_GNUC_UNUSED GError **error) +{ + g_return_val_if_fail (prov, NULL); + g_return_val_if_fail (GDA_IS_PROVIDER_META (prov), NULL); + return NULL; +} +static GdaRow* +gda_sqlite_provider_meta_domain (GdaProviderMeta *prov, + G_GNUC_UNUSED const gchar *domain_catalog, G_GNUC_UNUSED const gchar *domain_schema, GError **error) +{ + g_return_val_if_fail (prov, NULL); + g_return_val_if_fail (GDA_IS_PROVIDER_META (prov), NULL); + return NULL; +} +static GdaDataModel* +gda_sqlite_provider_meta_domains_constraints (GdaProviderMeta *prov, + G_GNUC_UNUSED GError **error) +{ + g_return_val_if_fail (prov, NULL); + g_return_val_if_fail (GDA_IS_PROVIDER_META (prov), NULL); + return NULL; +} +static GdaDataModel* +gda_sqlite_provider_meta_domain_constraints (GdaProviderMeta *prov, + G_GNUC_UNUSED const gchar *domain_catalog, G_GNUC_UNUSED const gchar *domain_schema, + G_GNUC_UNUSED const gchar *domain_name, GError **error) +{ + g_return_val_if_fail (prov, NULL); + g_return_val_if_fail (GDA_IS_PROVIDER_META (prov), NULL); + return NULL; +} +static GdaRow* +gda_sqlite_provider_meta_domain_constraint (GdaProviderMeta *prov, + G_GNUC_UNUSED const gchar *domain_catalog, G_GNUC_UNUSED const gchar *domain_schema, + G_GNUC_UNUSED const gchar *domain_name, G_GNUC_UNUSED const gchar *contraint_name, + G_GNUC_UNUSED GError **error) +{ + g_return_val_if_fail (prov, NULL); + g_return_val_if_fail (GDA_IS_PROVIDER_META (prov), NULL); + return NULL; +} +static GdaDataModel* +gda_sqlite_provider_meta_element_types (GdaProviderMeta *prov, + G_GNUC_UNUSED GError **error) +{ + g_return_val_if_fail (prov, NULL); + g_return_val_if_fail (GDA_IS_PROVIDER_META (prov), NULL); + return NULL; +} +static GdaRow* +gda_sqlite_provider_meta_element_type (GdaProviderMeta *prov, + G_GNUC_UNUSED const gchar *specific_name, GError **error) +{ + g_return_val_if_fail (prov, NULL); + g_return_val_if_fail (GDA_IS_PROVIDER_META (prov), NULL); + return NULL; +} +static GdaDataModel* +gda_sqlite_provider_meta_collations (GdaProviderMeta *prov, + GError **error) +{ + g_return_val_if_fail (prov, NULL); + g_return_val_if_fail (GDA_IS_PROVIDER_META (prov), NULL); + return NULL; +} +static GdaRow* +gda_sqlite_provider_meta_collation (GdaProviderMeta *prov, + const gchar *collation_catalog, const gchar *collation_schema, + const gchar *collation_name_n, GError **error) +{ + g_return_val_if_fail (prov, NULL); + g_return_val_if_fail (GDA_IS_PROVIDER_META (prov), NULL); + return NULL; +} +static GdaDataModel* +gda_sqlite_provider_meta_character_sets (GdaProviderMeta *prov, + GError **error) +{ + g_return_val_if_fail (prov, NULL); + g_return_val_if_fail (GDA_IS_PROVIDER_META (prov), NULL); + return NULL; +} +static GdaRow* +gda_sqlite_provider_meta_character_set (GdaProviderMeta *prov, + const gchar *chset_catalog, const gchar *chset_schema, + const gchar *chset_name_n, GError **error) +{ + g_return_val_if_fail (prov, NULL); + g_return_val_if_fail (GDA_IS_PROVIDER_META (prov), NULL); + return NULL; +} +static GdaDataModel* +gda_sqlite_provider_meta_schematas (GdaProviderMeta *prov, + GError **error) +{ + g_return_val_if_fail (prov, NULL); + g_return_val_if_fail (GDA_IS_PROVIDER_META (prov), NULL); + return NULL; +} +static GdaRow* +gda_sqlite_provider_meta_schemata (GdaProviderMeta *prov, + const gchar *catalog_name, const gchar *schema_name_n, GError **error) +{ + g_return_val_if_fail (prov, NULL); + g_return_val_if_fail (GDA_IS_PROVIDER_META (prov), NULL); + return NULL; +} +static GdaDataModel* +gda_sqlite_provider_meta_tables (GdaProviderMeta *prov, + GError **error) +{ + g_return_val_if_fail (prov, NULL); + g_return_val_if_fail (GDA_IS_PROVIDER_META (prov), NULL); + + return gda_provider_meta_execute_query (prov, + "SELECT name, 'system' as 'Owner'," + " ' ' as 'Description', sql as 'Definition' " + "FROM (SELECT * FROM sqlite_master " + "UNION ALL SELECT * FROM sqlite_temp_master) " + "WHERE name not like 'sqlite_%%' AND type='table' ORDER BY name", + NULL, error); +} +static GdaRow* +gda_sqlite_provider_meta_table (GdaProviderMeta *prov, + const gchar *table_catalog, const gchar *table_schema, + const gchar *table_name_n, GError **error) +{ + g_return_val_if_fail (prov, NULL); + g_return_val_if_fail (GDA_IS_PROVIDER_META (prov), NULL); + GdaRow *row; + GdaSet *params; + + params = gda_set_new_inline (1, "name", G_TYPE_STRING, NULL); + gda_set_set_holder_value (params, error, "name", table_name_n, NULL); + if (*error != NULL) { + g_object_unref (params); + return NULL; + } + + row = gda_provider_meta_execute_query_row (prov, + "SELECT name as 'Table', 'system' as 'Owner'," + " ' ' as 'Description', sql as 'Definition' " + "FROM (SELECT * FROM sqlite_master UNION ALL " + "SELECT * FROM sqlite_temp_master) " + "WHERE name = ##name::string name not like 'sqlite_%%' ORDER BY name", + params, error); + g_object_unref (params); + return row; +} +static GdaDataModel* +gda_sqlite_provider_meta_views (GdaProviderMeta *prov, + GError **error) +{ + g_return_val_if_fail (prov, NULL); + g_return_val_if_fail (GDA_IS_PROVIDER_META (prov), NULL); + + return gda_provider_meta_execute_query (prov, + "SELECT name, 'system' as 'Owner'," + " ' ' as 'Description', sql as 'Definition' " + "FROM (SELECT * FROM sqlite_master " + "UNION ALL SELECT * FROM sqlite_temp_master) " + "WHERE name not like 'sqlite_%%' AND type='view' ORDER BY name", + NULL, error); +} +static GdaRow* +gda_sqlite_provider_meta_view (GdaProviderMeta *prov, + const gchar *table_catalog, const gchar *table_schema, + const gchar *table_name_n, GError **error) +{ + g_return_val_if_fail (prov, NULL); + g_return_val_if_fail (GDA_IS_PROVIDER_META (prov), NULL); + GdaRow *row; + GdaSet *params; + + params = gda_set_new_inline (1, "name", G_TYPE_STRING, NULL); + gda_set_set_holder_value (params, error, "name", table_name_n, NULL); + if (*error != NULL) { + g_object_unref (params); + return NULL; + } + + row = gda_provider_meta_execute_query_row (prov, + "SELECT name, 'system' as 'Owner'," + " ' ' as 'Description', sql as 'Definition' " + "FROM (SELECT * FROM sqlite_master UNION ALL " + "SELECT * FROM sqlite_temp_master) " + "WHERE name = ##name::string name not like 'sqlite_%%' AND type = 'view' ORDER BY name", + params, error); + g_object_unref (params); + return row; +} +static GdaDataModel* +gda_sqlite_provider_meta_columns (GdaProviderMeta *prov, + GError **error) +{ + g_return_val_if_fail (prov, NULL); + g_return_val_if_fail (GDA_IS_PROVIDER_META (prov), NULL); + return NULL; +} +static GdaDataModel* +gda_sqlite_provider_meta_tables_columns (GdaProviderMeta *prov, + GError **error) +{ + g_return_val_if_fail (prov, NULL); + g_return_val_if_fail (GDA_IS_PROVIDER_META (prov), NULL); + return NULL; +} +static GdaDataModel* +gda_sqlite_provider_meta_table_columns (GdaProviderMeta *prov, + const gchar *table_catalog, const gchar *table_schema, + const gchar *table_name, GError **error) +{ + g_return_val_if_fail (prov, NULL); + g_return_val_if_fail (GDA_IS_PROVIDER_META (prov), NULL); + return NULL; +} +static GdaRow* +gda_sqlite_provider_meta_table_column (GdaProviderMeta *prov, + const gchar *table_catalog, const gchar *table_schema, + const gchar *table_name, + const gchar *column_name, GError **error) +{ + g_return_val_if_fail (prov, NULL); + g_return_val_if_fail (GDA_IS_PROVIDER_META (prov), NULL); + return NULL; +} +static GdaDataModel* +gda_sqlite_provider_meta_views_columns (GdaProviderMeta *prov, + GError **error) +{ + g_return_val_if_fail (prov, NULL); + g_return_val_if_fail (GDA_IS_PROVIDER_META (prov), NULL); + return NULL; +} +static GdaDataModel* +gda_sqlite_provider_meta_view_columns (GdaProviderMeta *prov, + const gchar *view_catalog, const gchar *view_schema, + const gchar *view_name, GError **error) +{ + g_return_val_if_fail (prov, NULL); + g_return_val_if_fail (GDA_IS_PROVIDER_META (prov), NULL); + return NULL; +} +static GdaRow* +gda_sqlite_provider_meta_view_column (GdaProviderMeta *prov, + const gchar *view_catalog, const gchar *view_schema, + const gchar *view_name, + const gchar *column_name, + GError **error) +{ + g_return_val_if_fail (prov, NULL); + g_return_val_if_fail (GDA_IS_PROVIDER_META (prov), NULL); + return NULL; +} +static GdaDataModel* +gda_sqlite_provider_meta_constraints_tables (GdaProviderMeta *prov, GError **error) +{ + g_return_val_if_fail (prov, NULL); + g_return_val_if_fail (GDA_IS_PROVIDER_META (prov), NULL); + return NULL; +} +static GdaDataModel* +gda_sqlite_provider_meta_constraints_table (GdaProviderMeta *prov, + const gchar *table_catalog, const gchar *table_schema, + const gchar *table_name, + GError **error) +{ + g_return_val_if_fail (prov, NULL); + g_return_val_if_fail (GDA_IS_PROVIDER_META (prov), NULL); + return NULL; +} +static GdaRow* +gda_sqlite_provider_meta_constraint_table (GdaProviderMeta *prov, + const gchar *table_catalog, const gchar *table_schema, + const gchar *table_name, + const gchar *constraint_name_n, GError **error) +{ + g_return_val_if_fail (prov, NULL); + g_return_val_if_fail (GDA_IS_PROVIDER_META (prov), NULL); + return NULL; +} +static GdaDataModel* +gda_sqlite_provider_meta_constraints_ref (GdaProviderMeta *prov, + GError **error) +{ + g_return_val_if_fail (prov, NULL); + g_return_val_if_fail (GDA_IS_PROVIDER_META (prov), NULL); + return NULL; +} +static GdaDataModel* +gda_sqlite_provider_meta_constraints_ref_table (GdaProviderMeta *prov, + const gchar *table_catalog, + const gchar *table_schema, const gchar *table_name, + GError **error) +{ + g_return_val_if_fail (prov, NULL); + g_return_val_if_fail (GDA_IS_PROVIDER_META (prov), NULL); + return NULL; +} +static GdaRow* +gda_sqlite_provider_meta_constraint_ref (GdaProviderMeta *prov, + const gchar *table_catalog, + const gchar *table_schema, const gchar *table_name, + const gchar *constraint_name, GError **error) +{ + g_return_val_if_fail (prov, NULL); + g_return_val_if_fail (GDA_IS_PROVIDER_META (prov), NULL); + return NULL; +} +static GdaDataModel* +gda_sqlite_provider_meta_key_columns (GdaProviderMeta *prov, + GError **error) +{ + g_return_val_if_fail (prov, NULL); + g_return_val_if_fail (GDA_IS_PROVIDER_META (prov), NULL); + return NULL; +} +static GdaRow* +gda_sqlite_provider_meta_key_column (GdaProviderMeta *prov, + const gchar *table_catalog, const gchar *table_schema, + const gchar *table_name, + const gchar *constraint_name, GError **error) +{ + g_return_val_if_fail (prov, NULL); + g_return_val_if_fail (GDA_IS_PROVIDER_META (prov), NULL); + return NULL; +} +static GdaDataModel* +gda_sqlite_provider_meta_check_columns (GdaProviderMeta *prov, + GError **error) +{ + g_return_val_if_fail (prov, NULL); + g_return_val_if_fail (GDA_IS_PROVIDER_META (prov), NULL); + return NULL; +} +static GdaRow* +gda_sqlite_provider_meta_check_column (GdaProviderMeta *prov, + const gchar *table_catalog, + const gchar *table_schema, + const gchar *table_name, + const gchar *constraint_name, GError **error) +{ + g_return_val_if_fail (prov, NULL); + g_return_val_if_fail (GDA_IS_PROVIDER_META (prov), NULL); + return NULL; +} +static GdaDataModel* +gda_sqlite_provider_meta_triggers (GdaProviderMeta *prov, + GError **error) +{ + g_return_val_if_fail (prov, NULL); + g_return_val_if_fail (GDA_IS_PROVIDER_META (prov), NULL); + return NULL; +} +static GdaRow* +gda_sqlite_provider_meta_trigger (GdaProviderMeta *prov, + const gchar *table_catalog, + const gchar *table_schema, + const gchar *table_name, GError **error) +{ + g_return_val_if_fail (prov, NULL); + g_return_val_if_fail (GDA_IS_PROVIDER_META (prov), NULL); + return NULL; +} +static GdaDataModel* +gda_sqlite_provider_meta_routines (GdaProviderMeta *prov, + GError **error) +{ + g_return_val_if_fail (prov, NULL); + g_return_val_if_fail (GDA_IS_PROVIDER_META (prov), NULL); + return NULL; +} +static GdaRow* +gda_sqlite_provider_meta_routine (GdaProviderMeta *prov, + const gchar *routine_catalog, const gchar *routine_schema, + const gchar *routine_name_n, GError **error) +{ + g_return_val_if_fail (prov, NULL); + g_return_val_if_fail (GDA_IS_PROVIDER_META (prov), NULL); + return NULL; +} +static GdaDataModel* +gda_sqlite_provider_meta_routines_col (GdaProviderMeta *prov, GError **error) +{ + g_return_val_if_fail (prov, NULL); + g_return_val_if_fail (GDA_IS_PROVIDER_META (prov), NULL); + return NULL; +} +static GdaRow* +gda_sqlite_provider_meta_routine_col (GdaProviderMeta *prov, + const gchar *rout_catalog, const gchar *rout_schema, + const gchar *rout_name, GError **error) +{ + g_return_val_if_fail (prov, NULL); + g_return_val_if_fail (GDA_IS_PROVIDER_META (prov), NULL); + return NULL; +} +static GdaDataModel* +gda_sqlite_provider_meta_routines_pars (GdaProviderMeta *prov, + GError **error) +{ + g_return_val_if_fail (prov, NULL); + g_return_val_if_fail (GDA_IS_PROVIDER_META (prov), NULL); + return NULL; +} +static GdaRow* +gda_sqlite_provider_meta_routine_pars (GdaProviderMeta *prov, + const gchar *rout_catalog, const gchar *rout_schema, + const gchar *rout_name, GError **error) +{ + g_return_val_if_fail (prov, NULL); + g_return_val_if_fail (GDA_IS_PROVIDER_META (prov), NULL); + return NULL; +} +static GdaDataModel* +gda_sqlite_provider_meta_indexes_tables (GdaProviderMeta *prov, + GError **error) +{ + g_return_val_if_fail (prov, NULL); + g_return_val_if_fail (GDA_IS_PROVIDER_META (prov), NULL); + return NULL; +} +static GdaDataModel* +gda_sqlite_provider_meta_indexes_table (GdaProviderMeta *prov, + const gchar *table_catalog, const gchar *table_schema, + const gchar *table_name, GError **error) +{ + g_return_val_if_fail (prov, NULL); + g_return_val_if_fail (GDA_IS_PROVIDER_META (prov), NULL); + return NULL; +} +static GdaRow* +gda_sqlite_provider_meta_index_table (GdaProviderMeta *prov, + const gchar *table_catalog, + const gchar *table_schema, + const gchar *table_name, + const gchar *index_name_n, GError **error) +{ + g_return_val_if_fail (prov, NULL); + g_return_val_if_fail (GDA_IS_PROVIDER_META (prov), NULL); + return NULL; +} +static GdaDataModel* +gda_sqlite_provider_meta_index_cols (GdaProviderMeta *prov, + GError **error) +{ + g_return_val_if_fail (prov, NULL); + g_return_val_if_fail (GDA_IS_PROVIDER_META (prov), NULL); + return NULL; +} +static GdaRow* +gda_sqlite_provider_meta_index_col (GdaProviderMeta *prov, + const gchar *table_catalog, + const gchar *table_schema, + const gchar *table_name, + const gchar *index_name, GError **error) +{ + g_return_val_if_fail (prov, NULL); + g_return_val_if_fail (GDA_IS_PROVIDER_META (prov), NULL); + return NULL; +} + +/* GdaProvider Implementation */ + +const gchar* +gda_sqlite_provider_iface_get_name (GdaProvider *provider) { + g_return_val_if_fail (provider, NULL); + return NULL; +} +const gchar* +gda_sqlite_provider_iface_get_version (GdaProvider *provider) { + g_return_val_if_fail (provider, NULL); + return NULL; +} +const gchar* +gda_sqlite_provider_iface_get_server_version (GdaProvider *provider, GdaConnection *cnc) { + g_return_val_if_fail (provider, NULL); + return NULL; +} +gboolean +gda_sqlite_provider_iface_supports_feature (GdaProvider *provider, GdaConnection *cnc, + GdaConnectionFeature feature) { + g_return_val_if_fail (provider, TRUE); + return TRUE; +} +GdaSqlParser* +gda_sqlite_provider_iface_create_parser (GdaProvider *provider, GdaConnection *cnc) { + g_return_val_if_fail (provider, NULL); + return NULL; +} /* may be NULL */ +GdaConnection* +gda_sqlite_provider_iface_create_connection (GdaProvider *provider) { + g_return_val_if_fail (provider, NULL); + return NULL; +} +GdaDataHandler* +gda_sqlite_provider_iface_get_data_handler (GdaProvider *provider, GdaConnection *cnc, /* may be NULL */ + GType g_type, const gchar *dbms_type) { + g_return_val_if_fail (provider, NULL); + return NULL; +} +const gchar* +gda_sqlite_provider_iface_get_def_dbms_type (GdaProvider *provider, GdaConnection *cnc, + GType g_type) { + g_return_val_if_fail (provider, NULL); + return NULL; +} /* may be NULL */ +gboolean +gda_sqlite_provider_iface_supports_operation (GdaProvider *provider, GdaConnection *cnc, + GdaServerOperationType type, GdaSet *options) { + g_return_val_if_fail (provider, FALSE); + return FALSE; +} +GdaServerOperation* +gda_sqlite_provider_iface_create_operation (GdaProvider *provider, GdaConnection *cnc, + GdaServerOperationType type, GdaSet *options, + GError **error) { + g_return_val_if_fail (provider, NULL); + return NULL; +} +gchar* +gda_sqlite_provider_iface_render_operation (GdaProvider *provider, GdaConnection *cnc, + GdaServerOperation *op, GError **error) { + g_return_val_if_fail (provider, NULL); + return NULL; +} +gchar* +gda_sqlite_provider_iface_statement_to_sql (GdaProvider *provider, GdaConnection *cnc, + GdaStatement *stmt, GdaSet *params, + GdaStatementSqlFlag flags, + GSList **params_used, GError **error) { + g_return_val_if_fail (provider, NULL); + return NULL; +} +gchar* +gda_sqlite_provider_iface_identifier_quote (GdaProvider *provider, GdaConnection *cnc, /* may be NULL */ + const gchar *id, + gboolean for_meta_store, gboolean force_quotes) { + g_return_val_if_fail (provider, NULL); + return NULL; +} +GdaSqlStatement* +gda_sqlite_provider_iface_statement_rewrite (GdaProvider *provider, GdaConnection *cnc, + GdaStatement *stmt, GdaSet *params, GError **error) { + g_return_val_if_fail (provider, NULL); + return NULL; +} +gboolean +gda_sqlite_provider_iface_open_connection (GdaProvider *provider, GdaConnection *cnc, + GdaQuarkList *params, GdaQuarkList *auth) { + g_return_val_if_fail (provider, FALSE); + return FALSE; +} +gboolean +gda_sqlite_provider_iface_prepare_connection (GdaProvider *provider, GdaConnection *cnc, + GdaQuarkList *params, GdaQuarkList *auth) { + g_return_val_if_fail (provider, FALSE); + return FALSE; +} +gboolean +gda_sqlite_provider_iface_close_connection (GdaProvider *provider, GdaConnection *cnc) { + g_return_val_if_fail (provider, FALSE); + return FALSE; +} +gchar* +gda_sqlite_provider_iface_escape_string (GdaProvider *provider, GdaConnection *cnc, + const gchar *str) { + g_return_val_if_fail (provider, NULL); + return NULL; +} /* may be NULL */ +gchar* +gda_sqlite_provider_iface_unescape_string (GdaProvider *provider, GdaConnection *cnc, + const gchar *str) { + g_return_val_if_fail (provider, NULL); + return NULL; +} /* may be NULL */ +gboolean +gda_sqlite_provider_iface_perform_operation (GdaProvider *provider, GdaConnection *cnc, /* may be NULL */ + GdaServerOperation *op, GError **error) { + g_return_val_if_fail (provider, FALSE); + return FALSE; +} +gboolean +gda_sqlite_provider_iface_begin_transaction (GdaProvider *provider, GdaConnection *cnc, + const gchar *name, GdaTransactionIsolation level, + GError **error) { + g_return_val_if_fail (provider, FALSE); + return FALSE; +} +gboolean +gda_sqlite_provider_iface_commit_transaction (GdaProvider *provider, GdaConnection *cnc, + const gchar *name, GError **error) { + g_return_val_if_fail (provider, FALSE); + return FALSE; +} +gboolean +gda_sqlite_provider_iface_rollback_transaction (GdaProvider *provider, GdaConnection *cnc, + const gchar *name, GError **error) { + g_return_val_if_fail (provider, FALSE); + return FALSE; +} +gboolean +gda_sqlite_provider_iface_add_savepoint (GdaProvider *provider, GdaConnection *cnc, + const gchar *name, GError **error) { + g_return_val_if_fail (provider, FALSE); + return FALSE; +} +gboolean +gda_sqlite_provider_iface_rollback_savepoint (GdaProvider *provider, GdaConnection *cnc, + const gchar *name, GError **error) { + g_return_val_if_fail (provider, FALSE); + return FALSE; +} +gboolean +gda_sqlite_provider_iface_delete_savepoint (GdaProvider *provider, GdaConnection *cnc, + const gchar *name, GError **error) { + g_return_val_if_fail (provider, FALSE); + return FALSE; +} +gboolean +gda_sqlite_provider_iface_statement_prepare (GdaProvider *provider, GdaConnection *cnc, + GdaStatement *stmt, GError **error) { + g_return_val_if_fail (provider, FALSE); + return FALSE; +} +GObject* +gda_sqlite_provider_iface_statement_execute (GdaProvider *provider, GdaConnection *cnc, + GdaStatement *stmt, GdaSet *params, + GdaStatementModelUsage model_usage, + GType *col_types, GdaSet **last_inserted_row, + GError **error) { + g_return_val_if_fail (provider, NULL); + return NULL; +} + +GdaSet* +gda_sqlite_provider_iface_get_last_inserted (GdaProvider *provider, + GdaConnection *cnc, + GError **error) +{ + g_return_val_if_fail (provider, NULL); + return NULL; +} + +static GModule * +find_sqlite_in_dir (const gchar *dir_name, const gchar *name_part) +{ + GDir *dir; + GError *err = NULL; + const gchar *name; + GModule *handle = NULL; + +#ifdef GDA_DEBUG_NO + g_print ("Looking for '%s' in %s\n", name_part, dir_name); +#endif + dir = g_dir_open (dir_name, 0, &err); + if (err) { + gda_log_error (err->message); + g_error_free (err); + return FALSE; + } + + while ((name = g_dir_read_name (dir))) { + const gchar *ptr1, *ptr2; + ptr1 = g_strrstr (name, "." G_MODULE_SUFFIX); + if (! ptr1) + continue; + ptr2 = g_strrstr (name, name_part); + if (!ptr2) + continue; + if (ptr1 < ptr2) + continue; + + gchar *path; + + path = g_build_path (G_DIR_SEPARATOR_S, dir_name, name, NULL); + handle = g_module_open (path, G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL); + g_free (path); + if (!handle) { + /*g_warning (_("Error: %s"), g_module_error ());*/ + continue; + } + + gpointer func; + if (g_module_symbol (handle, "sqlite3_open", &func)) { +#ifdef GDA_DEBUG_NO + path = g_build_path (G_DIR_SEPARATOR_S, dir_name, name, NULL); + g_print ("'%s' found as: '%s'\n", name_part, path); + g_free (path); +#endif + break; + } + else { + g_module_close (handle); + handle = NULL; + } + + } + /* free memory */ + g_dir_close (dir); + return handle; +} + +GModule * +gda_sqlite_find_library (const gchar *name_part) +{ + GModule *handle = NULL; + const gchar *env; + + /* first use the compile time SEARCH_LIB_PATH */ + if (SEARCH_LIB_PATH) { + gchar **array; + gint i; + array = g_strsplit (SEARCH_LIB_PATH, ":", 0); + for (i = 0; array[i]; i++) { + handle = find_sqlite_in_dir (array [i], name_part); + if (handle) + break; + } + g_strfreev (array); + if (handle) + return handle; + } + + /* then try by 'normal' shared library finding */ + handle = g_module_open (name_part, G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL); + if (handle) { + gpointer func; + if (g_module_symbol (handle, "sqlite3_open", &func)) { +#ifdef GDA_DEBUG_NO + g_print ("'%s' found using default shared library finding\n", name_part); +#endif + return handle; + } + + g_module_close (handle); + handle = NULL; + } + + /* lastly, use LD_LIBRARY_PATH */ + env = g_getenv ("LD_LIBRARY_PATH"); + if (env) { + gchar **array; + gint i; + array = g_strsplit (env, ":", 0); + for (i = 0; array[i]; i++) { + handle = find_sqlite_in_dir (array [i], name_part); + if (handle) + break; + } + g_strfreev (array); + if (handle) + return handle; + } + + return NULL; +} + + +void +gda_sqlite_load_symbols (GModule *module, Sqlite3ApiRoutines** apilib) +{ + g_assert (module); + (*apilib) = g_new (Sqlite3ApiRoutines, 1); + + if (! g_module_symbol (module, "sqlite3_bind_blob", (gpointer*) &((*apilib)->sqlite3_bind_blob))) + goto onerror; + if (! g_module_symbol (module, "sqlite3_bind_double", (gpointer*) &((*apilib)->sqlite3_bind_double))) + goto onerror; + if (! g_module_symbol (module, "sqlite3_bind_int", (gpointer*) &((*apilib)->sqlite3_bind_int))) + goto onerror; + if (! g_module_symbol (module, "sqlite3_bind_int64", (gpointer*) &((*apilib)->sqlite3_bind_int64))) + goto onerror; + if (! g_module_symbol (module, "sqlite3_bind_null", (gpointer*) &((*apilib)->sqlite3_bind_null))) + goto onerror; + if (! g_module_symbol (module, "sqlite3_bind_text", (gpointer*) &((*apilib)->sqlite3_bind_text))) + goto onerror; + if (! g_module_symbol (module, "sqlite3_bind_zeroblob", (gpointer*) &((*apilib)->sqlite3_bind_zeroblob))) + goto onerror; + if (! g_module_symbol (module, "sqlite3_blob_bytes", (gpointer*) &((*apilib)->sqlite3_blob_bytes))) + goto onerror; + if (! g_module_symbol (module, "sqlite3_blob_close", (gpointer*) &((*apilib)->sqlite3_blob_close))) + goto onerror; + if (! g_module_symbol (module, "sqlite3_blob_open", (gpointer*) &((*apilib)->sqlite3_blob_open))) + goto onerror; + if (! g_module_symbol (module, "sqlite3_blob_read", (gpointer*) &((*apilib)->sqlite3_blob_read))) + goto onerror; + if (! g_module_symbol (module, "sqlite3_blob_write", (gpointer*) &((*apilib)->sqlite3_blob_write))) + goto onerror; + if (! g_module_symbol (module, "sqlite3_busy_timeout", (gpointer*) &((*apilib)->sqlite3_busy_timeout))) + goto onerror; + if (! g_module_symbol (module, "sqlite3_changes", (gpointer*) &((*apilib)->sqlite3_changes))) + goto onerror; + if (! g_module_symbol (module, "sqlite3_clear_bindings", (gpointer*) &((*apilib)->sqlite3_clear_bindings))) + goto onerror; + if (! g_module_symbol (module, "sqlite3_close", (gpointer*) &((*apilib)->sqlite3_close))) + goto onerror; + if (! g_module_symbol (module, "sqlite3_close_v2", (gpointer*) &((*apilib)->sqlite3_close_v2))) + goto onerror; + if (! g_module_symbol (module, "sqlite3_column_blob", (gpointer*) &((*apilib)->sqlite3_column_blob))) + goto onerror; + if (! g_module_symbol (module, "sqlite3_column_bytes", (gpointer*) &((*apilib)->sqlite3_column_bytes))) + goto onerror; + if (! g_module_symbol (module, "sqlite3_column_count", (gpointer*) &((*apilib)->sqlite3_column_count))) + goto onerror; + if (! g_module_symbol (module, "sqlite3_column_database_name", (gpointer*) &((*apilib)->sqlite3_column_database_name))) + goto onerror; + if (! g_module_symbol (module, "sqlite3_column_decltype", (gpointer*) &((*apilib)->sqlite3_column_decltype))) + goto onerror; + if (! g_module_symbol (module, "sqlite3_column_double", (gpointer*) &((*apilib)->sqlite3_column_double))) + goto onerror; + if (! g_module_symbol (module, "sqlite3_column_int", (gpointer*) &((*apilib)->sqlite3_column_int))) + goto onerror; + if (! g_module_symbol (module, "sqlite3_column_int64", (gpointer*) &((*apilib)->sqlite3_column_int64))) + goto onerror; + if (! g_module_symbol (module, "sqlite3_column_name", (gpointer*) &((*apilib)->sqlite3_column_name))) + goto onerror; + if (! g_module_symbol (module, "sqlite3_column_origin_name", (gpointer*) &((*apilib)->sqlite3_column_origin_name))) + goto onerror; + if (! g_module_symbol (module, "sqlite3_column_table_name", (gpointer*) &((*apilib)->sqlite3_column_table_name))) + goto onerror; + if (! g_module_symbol (module, "sqlite3_column_text", (gpointer*) &((*apilib)->sqlite3_column_text))) + goto onerror; + if (! g_module_symbol (module, "sqlite3_column_type", (gpointer*) &((*apilib)->sqlite3_column_type))) + goto onerror; + if (! g_module_symbol (module, "sqlite3_config", (gpointer*) &((*apilib)->sqlite3_config))) + goto onerror; + if (! g_module_symbol (module, "sqlite3_create_function", (gpointer*) &((*apilib)->sqlite3_create_function))) + goto onerror; + if (! g_module_symbol (module, "sqlite3_create_function_v2", (gpointer*) &((*apilib)->sqlite3_create_function_v2))) + goto onerror; + if (! g_module_symbol (module, "sqlite3_create_module", (gpointer*) &((*apilib)->sqlite3_create_module))) + goto onerror; + if (! g_module_symbol (module, "sqlite3_db_handle", (gpointer*) &((*apilib)->sqlite3_db_handle))) + goto onerror; + if (! g_module_symbol (module, "sqlite3_declare_vtab", (gpointer*) &((*apilib)->sqlite3_declare_vtab))) + goto onerror; + if (! g_module_symbol (module, "sqlite3_errcode", (gpointer*) &((*apilib)->sqlite3_errcode))) + goto onerror; + if (! g_module_symbol (module, "sqlite3_errmsg", (gpointer*) &((*apilib)->sqlite3_errmsg))) + goto onerror; + if (! g_module_symbol (module, "sqlite3_exec", (gpointer*) &((*apilib)->sqlite3_exec))) + goto onerror; + if (! g_module_symbol (module, "sqlite3_extended_result_codes", (gpointer*) &((*apilib)->sqlite3_extended_result_codes))) + goto onerror; + if (! g_module_symbol (module, "sqlite3_finalize", (gpointer*) &((*apilib)->sqlite3_finalize))) + goto onerror; + if (! g_module_symbol (module, "sqlite3_free", (gpointer*) &((*apilib)->sqlite3_free))) + goto onerror; + if (! g_module_symbol (module, "sqlite3_free_table", (gpointer*) &((*apilib)->sqlite3_free_table))) + goto onerror; + if (! g_module_symbol (module, "sqlite3_get_table", (gpointer*) &((*apilib)->sqlite3_get_table))) + goto onerror; + if (! g_module_symbol (module, "sqlite3_last_insert_rowid", (gpointer*) &((*apilib)->sqlite3_last_insert_rowid))) + goto onerror; + if (! g_module_symbol (module, "sqlite3_malloc", (gpointer*) &((*apilib)->sqlite3_malloc))) + goto onerror; + if (! g_module_symbol (module, "sqlite3_mprintf", (gpointer*) &((*apilib)->sqlite3_mprintf))) + goto onerror; + if (! g_module_symbol (module, "sqlite3_open", (gpointer*) &((*apilib)->sqlite3_open))) + goto onerror; + if (! g_module_symbol (module, "sqlite3_open_v2", (gpointer*) &((*apilib)->sqlite3_open_v2))) + goto onerror; + if (! g_module_symbol (module, "sqlite3_prepare", (gpointer*) &((*apilib)->sqlite3_prepare))) + goto onerror; + if (! g_module_symbol (module, "sqlite3_prepare_v2", (gpointer*) &((*apilib)->sqlite3_prepare_v2))) + goto onerror; + if (! g_module_symbol (module, "sqlite3_reset", (gpointer*) &((*apilib)->sqlite3_reset))) + goto onerror; + if (! g_module_symbol (module, "sqlite3_result_blob", (gpointer*) &((*apilib)->sqlite3_result_blob))) + goto onerror; + if (! g_module_symbol (module, "sqlite3_result_double", (gpointer*) &((*apilib)->sqlite3_result_double))) + goto onerror; + if (! g_module_symbol (module, "sqlite3_result_error", (gpointer*) &((*apilib)->sqlite3_result_error))) + goto onerror; + if (! g_module_symbol (module, "sqlite3_result_int", (gpointer*) &((*apilib)->sqlite3_result_int))) + goto onerror; + if (! g_module_symbol (module, "sqlite3_result_int64", (gpointer*) &((*apilib)->sqlite3_result_int64))) + goto onerror; + if (! g_module_symbol (module, "sqlite3_result_null", (gpointer*) &((*apilib)->sqlite3_result_null))) + goto onerror; + if (! g_module_symbol (module, "sqlite3_result_text", (gpointer*) &((*apilib)->sqlite3_result_text))) + goto onerror; + if (! g_module_symbol (module, "sqlite3_step", (gpointer*) &((*apilib)->sqlite3_step))) + goto onerror; + if (! g_module_symbol (module, "sqlite3_table_column_metadata", (gpointer*) &((*apilib)->sqlite3_table_column_metadata))) + goto onerror; + if (! g_module_symbol (module, "sqlite3_threadsafe", (gpointer*) &((*apilib)->sqlite3_threadsafe))) + goto onerror; + if (! g_module_symbol (module, "sqlite3_value_blob", (gpointer*) &((*apilib)->sqlite3_value_blob))) + goto onerror; + if (! g_module_symbol (module, "sqlite3_value_bytes", (gpointer*) &((*apilib)->sqlite3_value_bytes))) + goto onerror; + if (! g_module_symbol (module, "sqlite3_value_int", (gpointer*) &((*apilib)->sqlite3_value_int))) + goto onerror; + if (! g_module_symbol (module, "sqlite3_value_int64", (gpointer*) &((*apilib)->sqlite3_value_int64))) + goto onerror; + if (! g_module_symbol (module, "sqlite3_value_double", (gpointer*) &((*apilib)->sqlite3_value_double))) + goto onerror; + if (! g_module_symbol (module, "sqlite3_value_text", (gpointer*) &((*apilib)->sqlite3_value_text))) + goto onerror; + if (! g_module_symbol (module, "sqlite3_value_type", (gpointer*) &((*apilib)->sqlite3_value_type))) + goto onerror; + if (! g_module_symbol (module, "sqlite3_key", (gpointer*) &((*apilib)->sqlite3_key))) + (*apilib)->sqlite3_key = NULL; + if (! g_module_symbol (module, "sqlite3_key_v2", (gpointer*) &((*apilib)->sqlite3_key_v2))) + (*apilib)->sqlite3_key_v2 = NULL; + if (! g_module_symbol (module, "sqlite3_rekey", (gpointer*) &((*apilib)->sqlite3_key))) + (*apilib)->sqlite3_rekey = NULL; + + if (! g_module_symbol (module, "sqlite3_create_collation", (gpointer*) &((*apilib)->sqlite3_create_collation))) + goto onerror; + if (! g_module_symbol (module, "sqlite3_enable_load_extension", (gpointer*) &((*apilib)->sqlite3_enable_load_extension))) + (*apilib)->sqlite3_enable_load_extension = NULL; + return; + + onerror: + g_free ((*apilib)); + apilib = NULL; + g_module_close (module); +} + + diff --git a/.flatpak-builder/cache/objects/a7/71bef7067c410f26cac0a58deccdd941953d18586942d602232f39a265ab3f.file b/.flatpak-builder/cache/objects/a7/71bef7067c410f26cac0a58deccdd941953d18586942d602232f39a265ab3f.file new file mode 100644 index 0000000..9938bec --- /dev/null +++ b/.flatpak-builder/cache/objects/a7/71bef7067c410f26cac0a58deccdd941953d18586942d602232f39a265ab3f.file @@ -0,0 +1,53 @@ +# common.py +# +# Copyright 2022 James Westman +# +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation; either version 3 of the +# License, or (at your option) any later version. +# +# This file is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program. If not, see . +# +# SPDX-License-Identifier: LGPL-3.0-or-later + + +from .. import gir +from ..ast_utils import AstNode, validate, docs, context +from ..errors import ( + CompileError, + MultipleErrors, + UpgradeWarning, + CompileWarning, + CodeAction, +) +from ..completions_utils import * +from .. import decompiler as decompile +from ..decompiler import ( + DecompileCtx, + decompiler, + escape_quote, + truthy, + decompile_translatable, +) +from ..gir import ( + StringType, + BoolType, + IntType, + FloatType, + GirType, + Enumeration, + ExternType, +) +from ..lsp_utils import Completion, CompletionItemKind, SemanticToken, SemanticTokenType +from ..parse_tree import * + + +OBJECT_CONTENT_HOOKS = AnyOf() +LITERAL = AnyOf() diff --git a/.flatpak-builder/cache/objects/a7/c3f075d91fe2a4a7ba64cfa51638a3c383ccebead5a816a293282acd269081.file b/.flatpak-builder/cache/objects/a7/c3f075d91fe2a4a7ba64cfa51638a3c383ccebead5a816a293282acd269081.file new file mode 100644 index 0000000..1393a36 --- /dev/null +++ b/.flatpak-builder/cache/objects/a7/c3f075d91fe2a4a7ba64cfa51638a3c383ccebead5a816a293282acd269081.file @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2010 - 2012 Vivien Malerba + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GDA_SQLITE_HANDLER_BOOLEAN__ +#define __GDA_SQLITE_HANDLER_BOOLEAN__ + +#include +#include + +G_BEGIN_DECLS + +#define GDA_TYPE_SQLITE_HANDLER_BOOLEAN (gda_sqlite_handler_boolean_get_type()) +G_DECLARE_DERIVABLE_TYPE (GdaSqliteHandlerBoolean, gda_sqlite_handler_boolean, GDA, SQLITE_HANDLER_BOOLEAN, GObject) + +struct _GdaSqliteHandlerBooleanClass +{ + GObjectClass parent_class; +}; + + +GdaDataHandler *_gda_sqlite_handler_boolean_new (void); + +G_END_DECLS + +#endif diff --git a/.flatpak-builder/cache/objects/a7/d59f46002effe9ea38dcb265546e1b7e4e215af9db96e6d223fcc4bc56650a.file b/.flatpak-builder/cache/objects/a7/d59f46002effe9ea38dcb265546e1b7e4e215af9db96e6d223fcc4bc56650a.file new file mode 100644 index 0000000..0d3a62d --- /dev/null +++ b/.flatpak-builder/cache/objects/a7/d59f46002effe9ea38dcb265546e1b7e4e215af9db96e6d223fcc4bc56650a.file @@ -0,0 +1,366 @@ +/*-*- Mode: C; c-basic-offset: 8 -*-*/ + +/*** + This file is part of libcanberra. + + Copyright 2008 Lennart Poettering + + libcanberra is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation, either version 2.1 of the + License, or (at your option) any later version. + + libcanberra is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with libcanberra. If not, see + . +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "canberra.h" +#include "read-wav.h" +#include "macro.h" +#include "malloc.h" + +#define FILE_SIZE_MAX (64U*1024U*1024U) + +/* Stores the bit indexes in dwChannelMask */ +enum { + BIT_FRONT_LEFT, + BIT_FRONT_RIGHT, + BIT_FRONT_CENTER, + BIT_LOW_FREQUENCY, + BIT_BACK_LEFT, + BIT_BACK_RIGHT, + BIT_FRONT_LEFT_OF_CENTER, + BIT_FRONT_RIGHT_OF_CENTER, + BIT_BACK_CENTER, + BIT_SIDE_LEFT, + BIT_SIDE_RIGHT, + BIT_TOP_CENTER, + BIT_TOP_FRONT_LEFT, + BIT_TOP_FRONT_CENTER, + BIT_TOP_FRONT_RIGHT, + BIT_TOP_BACK_LEFT, + BIT_TOP_BACK_CENTER, + BIT_TOP_BACK_RIGHT, + _BIT_MAX +}; + +static const ca_channel_position_t channel_table[_BIT_MAX] = { + [BIT_FRONT_LEFT] = CA_CHANNEL_FRONT_LEFT, + [BIT_FRONT_RIGHT] = CA_CHANNEL_FRONT_RIGHT, + [BIT_FRONT_CENTER] = CA_CHANNEL_FRONT_CENTER, + [BIT_LOW_FREQUENCY] = CA_CHANNEL_LFE, + [BIT_BACK_LEFT] = CA_CHANNEL_REAR_LEFT, + [BIT_BACK_RIGHT] = CA_CHANNEL_REAR_RIGHT, + [BIT_FRONT_LEFT_OF_CENTER] = CA_CHANNEL_FRONT_LEFT_OF_CENTER, + [BIT_FRONT_RIGHT_OF_CENTER] = CA_CHANNEL_FRONT_RIGHT_OF_CENTER, + [BIT_BACK_CENTER] = CA_CHANNEL_REAR_CENTER, + [BIT_SIDE_LEFT] = CA_CHANNEL_SIDE_LEFT, + [BIT_SIDE_RIGHT] = CA_CHANNEL_SIDE_RIGHT, + [BIT_TOP_CENTER] = CA_CHANNEL_TOP_CENTER, + [BIT_TOP_FRONT_LEFT] = CA_CHANNEL_TOP_FRONT_LEFT, + [BIT_TOP_FRONT_CENTER] = CA_CHANNEL_TOP_FRONT_CENTER, + [BIT_TOP_FRONT_RIGHT] = CA_CHANNEL_TOP_FRONT_RIGHT, + [BIT_TOP_BACK_LEFT] = CA_CHANNEL_TOP_REAR_LEFT, + [BIT_TOP_BACK_CENTER] = CA_CHANNEL_TOP_REAR_CENTER, + [BIT_TOP_BACK_RIGHT] = CA_CHANNEL_TOP_REAR_RIGHT +}; + +struct ca_wav { + FILE *file; + + off_t data_size; + unsigned nchannels; + unsigned rate; + unsigned depth; + uint32_t channel_mask; + + ca_channel_position_t channel_map[_BIT_MAX]; +}; + +#define CHUNK_ID_DATA 0x61746164U +#define CHUNK_ID_FMT 0x20746d66U + +static const uint8_t pcm_guid[16] = { + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, + 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 +}; + +static int skip_to_chunk(ca_wav *w, uint32_t id, uint32_t *size) { + + ca_return_val_if_fail(w, CA_ERROR_INVALID); + ca_return_val_if_fail(size, CA_ERROR_INVALID); + + for (;;) { + uint32_t chunk[2]; + uint32_t s; + + if (fread(chunk, sizeof(uint32_t), CA_ELEMENTSOF(chunk), w->file) != CA_ELEMENTSOF(chunk)) + goto fail_io; + + s = CA_UINT32_FROM_LE(chunk[1]); + + if (s <= 0 || s >= FILE_SIZE_MAX) + return CA_ERROR_TOOBIG; + + if (CA_UINT32_FROM_LE(chunk[0]) == id) { + *size = s; + break; + } + + if (fseek(w->file, (long) s, SEEK_CUR) < 0) + return CA_ERROR_SYSTEM; + } + + return CA_SUCCESS; + +fail_io: + + if (feof(w->file)) + return CA_ERROR_CORRUPT; + else if (ferror(w->file)) + return CA_ERROR_SYSTEM; + + ca_assert_not_reached(); +} + +int ca_wav_open(ca_wav **_w, FILE *f) { + uint32_t header[3], fmt_chunk[10]; + int ret; + ca_wav *w; + uint32_t file_size, fmt_size, data_size; + ca_bool_t extensible; + uint32_t format; + + ca_return_val_if_fail(_w, CA_ERROR_INVALID); + ca_return_val_if_fail(f, CA_ERROR_INVALID); + + if (!(w = ca_new(ca_wav, 1))) + return CA_ERROR_OOM; + + w->file = f; + + if (fread(header, sizeof(uint32_t), CA_ELEMENTSOF(header), f) != CA_ELEMENTSOF(header)) + goto fail_io; + + if (CA_UINT32_FROM_LE(header[0]) != 0x46464952U || + CA_UINT32_FROM_LE(header[2]) != 0x45564157U) { + ret = CA_ERROR_CORRUPT; + goto fail; + } + + file_size = CA_UINT32_FROM_LE(header[1]); + + if (file_size <= 0 || file_size >= FILE_SIZE_MAX) { + ret = CA_ERROR_TOOBIG; + goto fail; + } + + /* Skip to the fmt chunk */ + if ((ret = skip_to_chunk(w, CHUNK_ID_FMT, &fmt_size)) < 0) + goto fail; + + switch (fmt_size) { + + case 14: /* WAVEFORMAT */ + case 16: + case 18: /* WAVEFORMATEX */ + extensible = FALSE; + break; + + case 40: /* WAVEFORMATEXTENSIBLE */ + extensible = TRUE; + break; + + default: + ret = CA_ERROR_NOTSUPPORTED; + goto fail; + } + + if (fread(fmt_chunk, 1, fmt_size, f) != fmt_size) + goto fail_io; + + /* PCM? or WAVEX? */ + format = (CA_UINT32_FROM_LE(fmt_chunk[0]) & 0xFFFF); + if ((!extensible && format != 0x0001) || + (extensible && format != 0xFFFE)) { + ret = CA_ERROR_NOTSUPPORTED; + goto fail; + } + + if (extensible) { + if (memcmp(fmt_chunk + 6, pcm_guid, 16) != 0) { + ret = CA_ERROR_NOTSUPPORTED; + goto fail; + } + + w->channel_mask = CA_UINT32_FROM_LE(fmt_chunk[5]); + } else + w->channel_mask = 0; + + w->nchannels = CA_UINT32_FROM_LE(fmt_chunk[0]) >> 16; + w->rate = CA_UINT32_FROM_LE(fmt_chunk[1]); + w->depth = CA_UINT32_FROM_LE(fmt_chunk[3]) >> 16; + + if (w->nchannels <= 0 || w->rate <= 0) { + ret = CA_ERROR_CORRUPT; + goto fail; + } + + if (w->depth != 16 && w->depth != 8) { + ret = CA_ERROR_NOTSUPPORTED; + goto fail; + } + + /* Skip to the data chunk */ + if ((ret = skip_to_chunk(w, CHUNK_ID_DATA, &data_size)) < 0) + goto fail; + w->data_size = (off_t) data_size; + + if ((w->data_size % (w->depth/8)) != 0) { + ret = CA_ERROR_CORRUPT; + goto fail; + } + + *_w = w; + + return CA_SUCCESS; + +fail_io: + + if (feof(f)) + ret = CA_ERROR_CORRUPT; + else if (ferror(f)) + ret = CA_ERROR_SYSTEM; + else + ca_assert_not_reached(); + +fail: + + ca_free(w); + + return ret; +} + +void ca_wav_close(ca_wav *w) { + ca_assert(w); + + fclose(w->file); + ca_free(w); +} + +unsigned ca_wav_get_nchannels(ca_wav *w) { + ca_assert(w); + + return w->nchannels; +} + +unsigned ca_wav_get_rate(ca_wav *w) { + ca_assert(w); + + return w->rate; +} + +const ca_channel_position_t* ca_wav_get_channel_map(ca_wav *w) { + unsigned c; + ca_channel_position_t *p; + + ca_assert(w); + + if (!w->channel_mask) + return NULL; + + p = w->channel_map; + + for (c = 0; c < _BIT_MAX; c++) + if ((w->channel_mask & (1 << c))) + *(p++) = channel_table[c]; + + ca_assert(p <= w->channel_map + _BIT_MAX); + + if (p != w->channel_map + w->nchannels) + return NULL; + + return w->channel_map; +} + +ca_sample_type_t ca_wav_get_sample_type(ca_wav *w) { + ca_assert(w); + + return w->depth == 16 ? +#ifdef WORDS_BIGENDIAN + CA_SAMPLE_S16RE +#else + CA_SAMPLE_S16NE +#endif + : CA_SAMPLE_U8; +} + +int ca_wav_read_s16le(ca_wav *w, int16_t *d, size_t *n) { + off_t remaining; + + ca_return_val_if_fail(w, CA_ERROR_INVALID); + ca_return_val_if_fail(w->depth == 16, CA_ERROR_INVALID); + ca_return_val_if_fail(d, CA_ERROR_INVALID); + ca_return_val_if_fail(n, CA_ERROR_INVALID); + ca_return_val_if_fail(*n > 0, CA_ERROR_INVALID); + + remaining = w->data_size / (off_t) sizeof(int16_t); + + if ((off_t) *n > remaining) + *n = (size_t) remaining; + + if (*n > 0) { + *n = fread(d, sizeof(int16_t), *n, w->file); + + if (*n <= 0 && ferror(w->file)) + return CA_ERROR_SYSTEM; + + ca_assert(w->data_size >= (off_t) *n * (off_t) sizeof(int16_t)); + w->data_size -= (off_t) *n * (off_t) sizeof(int16_t); + } + + return CA_SUCCESS; +} + +int ca_wav_read_u8(ca_wav *w, uint8_t *d, size_t *n) { + off_t remaining; + + ca_return_val_if_fail(w, CA_ERROR_INVALID); + ca_return_val_if_fail(w->depth == 8, CA_ERROR_INVALID); + ca_return_val_if_fail(d, CA_ERROR_INVALID); + ca_return_val_if_fail(n, CA_ERROR_INVALID); + ca_return_val_if_fail(*n > 0, CA_ERROR_INVALID); + + remaining = w->data_size / (off_t) sizeof(uint8_t); + + if ((off_t) *n > remaining) + *n = (size_t) remaining; + + if (*n > 0) { + *n = fread(d, sizeof(uint8_t), *n, w->file); + + if (*n <= 0 && ferror(w->file)) + return CA_ERROR_SYSTEM; + + ca_assert(w->data_size >= (off_t) *n * (off_t) sizeof(uint8_t)); + w->data_size -= (off_t) *n * (off_t) sizeof(uint8_t); + } + + return CA_SUCCESS; +} + +off_t ca_wav_get_size(ca_wav *v) { + ca_return_val_if_fail(v, (off_t) -1); + + return v->data_size; +} diff --git a/.flatpak-builder/cache/objects/a7/df9597fb0cacc10245a4d39ddf22f03b083acee01bd00191c25aaad9006374.dirtree b/.flatpak-builder/cache/objects/a7/df9597fb0cacc10245a4d39ddf22f03b083acee01bd00191c25aaad9006374.dirtree new file mode 100644 index 0000000..7259965 Binary files /dev/null and b/.flatpak-builder/cache/objects/a7/df9597fb0cacc10245a4d39ddf22f03b083acee01bd00191c25aaad9006374.dirtree differ diff --git a/.flatpak-builder/cache/objects/a7/f688cbffb11207db26827ed4797eafe2d1e44d47f5d55f4c105cb3d0e4308f.file b/.flatpak-builder/cache/objects/a7/f688cbffb11207db26827ed4797eafe2d1e44d47f5d55f4c105cb3d0e4308f.file new file mode 100644 index 0000000..de5cc9b --- /dev/null +++ b/.flatpak-builder/cache/objects/a7/f688cbffb11207db26827ed4797eafe2d1e44d47f5d55f4c105cb3d0e4308f.file @@ -0,0 +1,38 @@ + + + + +libcanberra + + + + + + + + + + + + + + + + +
+

+libcanberra

+
+
+canberra — General libcanberra API +
+
+canberra-gtk — Gtk+ libcanberra Bindings +
+
+
+ + + \ No newline at end of file diff --git a/.flatpak-builder/cache/objects/a8/0a7ef070c417a7bfd98da62645153aa0d97edfc28342175e8fb734034bc04a.commit b/.flatpak-builder/cache/objects/a8/0a7ef070c417a7bfd98da62645153aa0d97edfc28342175e8fb734034bc04a.commit new file mode 100644 index 0000000..7795bac Binary files /dev/null and b/.flatpak-builder/cache/objects/a8/0a7ef070c417a7bfd98da62645153aa0d97edfc28342175e8fb734034bc04a.commit differ diff --git a/.flatpak-builder/cache/objects/a8/64dc9be3be5b6b16b4b8fb46b53969718d908a1ef6ef2739edb1bd98d5b660.file b/.flatpak-builder/cache/objects/a8/64dc9be3be5b6b16b4b8fb46b53969718d908a1ef6ef2739edb1bd98d5b660.file new file mode 100644 index 0000000..c4ff66b --- /dev/null +++ b/.flatpak-builder/cache/objects/a8/64dc9be3be5b6b16b4b8fb46b53969718d908a1ef6ef2739edb1bd98d5b660.file @@ -0,0 +1,919 @@ +/* + * Copyright (C) 2009 - 2013 Vivien Malerba + * Copyright (C) 2010 David King + * Copyright (C) 2010 Jonh Wendell + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +#define G_LOG_DOMAIN "GDA-tree" + +#include +#include +#include +#include +#include +#include "gda-tree.h" +#include "gda-tree-manager.h" +#include "gda-tree-node.h" +#include + +typedef struct { + GSList *managers; /* list of GdaTreeManager */ + GdaTreeNode *root; +} GdaTreePrivate; +G_DEFINE_TYPE_WITH_PRIVATE (GdaTree, gda_tree, G_TYPE_OBJECT) + +static void gda_tree_class_init (GdaTreeClass *klass); +static void gda_tree_init (GdaTree *tree); +static void gda_tree_dispose (GObject *object); +static void gda_tree_set_property (GObject *object, + guint param_id, + const GValue *value, + GParamSpec *pspec); +static void gda_tree_get_property (GObject *object, + guint param_id, + GValue *value, + GParamSpec *pspec); + +static gboolean create_or_update_children (GSList *mgrlist, GdaTreeNode *parent, gboolean disable_recurs, GError **error); +static void node_changed_cb (GdaTreeNode *reporting, GdaTreeNode *node, GdaTree *tree); +static void node_inserted_cb (GdaTreeNode *reporting, GdaTreeNode *node, GdaTree *tree); +static void node_has_child_toggled_cb (GdaTreeNode *reporting, GdaTreeNode *node, GdaTree *tree); +static void node_deleted_cb (GdaTreeNode *reporting, const gchar *relative_path, GdaTree *tree); + +static void take_root_node (GdaTree *tree, GdaTreeNode *root); +static void unset_root_node (GdaTree *tree); + +enum { + NODE_CHANGED, + NODE_INSERTED, + NODE_HAS_CHILD_TOGGLED, + NODE_DELETED, + LAST_SIGNAL +}; + +static gint gda_tree_signals[LAST_SIGNAL] = { 0, 0, 0, 0 }; + +/* properties */ +enum { + PROP_0, + PROP_IS_LIST +}; + +/* + * GdaTree class implementation + * @klass: + */ +static void +gda_tree_class_init (GdaTreeClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + /* signals */ + /** + * GdaTree::node-changed: + * @tree: the #GdaTree + * @node: the #GdaTreeNode which has changed + * + * Gets emitted when a @node has changed in @tree + * + * Since: 4.2 + */ + gda_tree_signals[NODE_CHANGED] = + g_signal_new ("node_changed", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GdaTreeClass, node_changed), + NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, GDA_TYPE_TREE_NODE); + /** + * GdaTree::node-inserted: + * @tree: the #GdaTree + * @node: the #GdaTreeNode which has inserted + * + * Gets emitted when a @node has been inserted in @tree + * + * Since: 4.2 + */ + gda_tree_signals[NODE_INSERTED] = + g_signal_new ("node_inserted", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GdaTreeClass, node_inserted), + NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, GDA_TYPE_TREE_NODE); + /** + * GdaTree::node-has-child-toggled: + * @tree: the #GdaTree + * @node: the #GdaTreeNode which changed from having children to being a + * leaf or the other way around + * + * Gets emitted when a @node has has a child when it did not have any or when it + * does not have a ny children anymore when it had some + * + * Since: 4.2 + */ + gda_tree_signals[NODE_HAS_CHILD_TOGGLED] = + g_signal_new ("node_has-child-toggled", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GdaTreeClass, node_has_child_toggled), + NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, GDA_TYPE_TREE_NODE); + /** + * GdaTree::node-deleted: + * @tree: the #GdaTree + * @node_path: the position the node held in @tree as a tree path + * + * Gets emitted when a @node has been removed from @tree + * + * Since: 4.2 + */ + gda_tree_signals[NODE_DELETED] = + g_signal_new ("node_deleted", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GdaTreeClass, node_deleted), + NULL, NULL, + g_cclosure_marshal_VOID__STRING, + G_TYPE_NONE, 1, G_TYPE_STRING); + + klass->node_changed = NULL; + klass->node_inserted = NULL; + klass->node_has_child_toggled = NULL; + klass->node_deleted = NULL; + + /* Properties */ + object_class->set_property = gda_tree_set_property; + object_class->get_property = gda_tree_get_property; + + /** + * GdaTree:is-list: + * + * Tells if the GdaTree is a list or a tree. + */ + g_object_class_install_property (object_class, PROP_IS_LIST, + g_param_spec_boolean ("is-list", _("Tells if the GdaTree is a list or a tree"), NULL, + FALSE, G_PARAM_READABLE)); + + object_class->dispose = gda_tree_dispose; +} + +static void +gda_tree_init (GdaTree *tree) +{ + g_return_if_fail (GDA_IS_TREE (tree)); + GdaTreePrivate *priv = gda_tree_get_instance_private (tree); + + priv->managers = NULL; + + take_root_node (tree, gda_tree_node_new (NULL)); +} + +static void +gda_tree_dispose (GObject *object) +{ + GdaTree *tree = (GdaTree *) object; + + g_return_if_fail (GDA_IS_TREE (tree)); + GdaTreePrivate *priv = gda_tree_get_instance_private (tree); + + if (priv->root) + unset_root_node (tree); + if (priv->managers) { + g_slist_free_full (priv->managers, (GDestroyNotify) g_object_unref); + } + /* chain to parent class */ + G_OBJECT_CLASS (gda_tree_parent_class)->dispose (object); +} + + +/* module error */ +GQuark gda_tree_error_quark (void) +{ + static GQuark quark; + if (!quark) + quark = g_quark_from_static_string ("gda_tree_error"); + return quark; +} + +static void +gda_tree_set_property (GObject *object, + guint param_id, + G_GNUC_UNUSED const GValue *value, + GParamSpec *pspec) +{ + switch (param_id) { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + break; + } +} + +static void +gda_tree_get_property (GObject *object, + guint param_id, + GValue *value, + GParamSpec *pspec) +{ + GdaTree *tree; + + tree = GDA_TREE (object); + GdaTreePrivate *priv = gda_tree_get_instance_private (tree); + switch (param_id) { + case PROP_IS_LIST: { + GSList *list; + gboolean is_list = TRUE; + for (list = priv->managers; list; list = list->next) { + if (gda_tree_manager_get_managers ((GdaTreeManager*) list->data)) { + is_list = FALSE; + break; + } + } + g_value_set_boolean (value, is_list); + break; + } + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + break; + } +} + +/** + * gda_tree_new: + * + * Creates a new #GdaTree object + * + * Returns: (transfer full): a new #GdaTree object + * + * Since: 4.2 + */ +GdaTree* +gda_tree_new (void) +{ + return (GdaTree*) g_object_new (GDA_TYPE_TREE, NULL); +} + + +/** + * gda_tree_add_manager: + * @tree: a #GdaTree object + * @manager: (transfer none): a #GdaTreeManager object + * + * Sets @manager as a top #GdaTreeManager object, which will be responsible for creating top level nodes in @tree. + * + * Since: 4.2 + */ +void +gda_tree_add_manager (GdaTree *tree, GdaTreeManager *manager) +{ + g_return_if_fail (GDA_IS_TREE (tree)); + g_return_if_fail (GDA_IS_TREE_MANAGER (manager)); + GdaTreePrivate *priv = gda_tree_get_instance_private (tree); + + priv->managers = g_slist_append (priv->managers, manager); + g_object_ref (manager); +} + +#ifdef GDA_DEBUG_NO +static void +dump_attr_foreach_func (const gchar *att_name, const GValue *value, gpointer data) +{ + g_print ("%s ==> %p\n", att_name, value); +} +#endif + +/** + * gda_tree_clean: + * @tree: a #GdaTree object + * + * Removes any node in @tree + * + * Since: 4.2 + */ +void +gda_tree_clean (GdaTree *tree) +{ + GdaTreeNode *new_root; + + g_return_if_fail (GDA_IS_TREE (tree)); + TO_IMPLEMENT; /* signal changes */ + + new_root = gda_tree_node_new (NULL); + + take_root_node (tree, new_root); +} + +/** + * gda_tree_update_all: + * @tree: a #GdaTree object + * @error: (nullable): a place to store errors, or %NULL + * + * Requests that @tree be populated with nodes. If an error occurs, then @tree's contents is left + * unchanged, and otherwise @tree's previous contents is completely replaced by the new one. + * + * Returns: TRUE if no error occurred. + * + * Since: 4.2 + */ +gboolean +gda_tree_update_all (GdaTree *tree, GError **error) +{ + g_return_val_if_fail (GDA_IS_TREE (tree), FALSE); + GdaTreePrivate *priv = gda_tree_get_instance_private (tree); + return create_or_update_children (priv->managers, priv->root, FALSE, error); +} + +/** + * gda_tree_update_part: + * @tree: a #GdaTree object + * @node: a #GdaTreeNode node in @tree + * @error: (nullable): a place to store errors, or %NULL + * + * Requests that @tree be populated with nodes, starting from @node + * + * Returns: TRUE if no error occurred. + * + * Since: 4.2 + */ +gboolean +gda_tree_update_part (GdaTree *tree, GdaTreeNode *node, GError **error) +{ + GSList *mgrlist; + GdaTreeManager *mgr; + GdaTreeNode *top; + + g_return_val_if_fail (GDA_IS_TREE (tree), FALSE); + g_return_val_if_fail (GDA_IS_TREE_NODE (node), FALSE); + GdaTreePrivate *priv = gda_tree_get_instance_private (tree); + + top = gda_tree_node_get_parent (node); + if (!top) + top = priv->root; + mgr = _gda_tree_node_get_manager_for_child (top, node); + mgrlist = (GSList*) gda_tree_manager_get_managers (mgr); + + if (mgrlist) { + gboolean res; + res = create_or_update_children (mgrlist, node, FALSE, error); + return res; + } + return TRUE; +} + +/** + * gda_tree_update_children: + * @tree: a #GdaTree object + * @node: (nullable): a #GdaTreeNode node in @tree, or %NULL + * @error: (nullable): a place to store errors, or %NULL + * + * Update the children of @node in @tree (not recursively, to update recursively, use + * gda_tree_update_part()). If @node is %NULL then the top level nodes are updated. + * + * Returns: TRUE if no error occurred. + * + * Since: 4.2.8 + */ +gboolean +gda_tree_update_children (GdaTree *tree, GdaTreeNode *node, GError **error) +{ + GSList *mgrlist; + GdaTreeManager *mgr; + GdaTreeNode *top; + + g_return_val_if_fail (GDA_IS_TREE (tree), FALSE); + g_return_val_if_fail (! node || GDA_IS_TREE_NODE (node), FALSE); + GdaTreePrivate *priv = gda_tree_get_instance_private (tree); + + if (node) { + top = gda_tree_node_get_parent (node); + if (!top) + top = priv->root; + mgr = _gda_tree_node_get_manager_for_child (top, node); + mgrlist = (GSList*) gda_tree_manager_get_managers (mgr); + + if (mgrlist) { + gboolean res; + res = create_or_update_children (mgrlist, node, TRUE, error); + return res; + } + } + else { + /* update top level nodes */ + create_or_update_children (priv->managers, priv->root, TRUE, error); + } + + return TRUE; +} + +/** + * gda_tree_dump: + * @tree: a #GdaTree + * @node: (nullable): a #GdaTreeNode to start the dump from, or %NULL for a full dump + * @stream: (nullable): a stream to send the dump to, or %NULL for STDOUT + * + * Dumps the contents of @tree to @stream, using a hierarchical view. + * + * Since: 4.2 + */ +void +gda_tree_dump (GdaTree *tree, GdaTreeNode *node, FILE *stream) +{ + GdaTreeNodeClass *klass; + GString *string; + + g_return_if_fail (GDA_IS_TREE (tree)); + GdaTreePrivate *priv = gda_tree_get_instance_private (tree); + + if (!node) + node = priv->root; + + string = g_string_new (".\n"); + klass = (GdaTreeNodeClass*) G_OBJECT_GET_CLASS (node); + klass->dump_children (node, "", string); + g_fprintf (stream ? stream : stdout, "%s", string->str); + g_string_free (string, TRUE); +} + +static GSList *real_gda_tree_get_nodes_in_path (GdaTree *tree, GSList *segments, gboolean use_names, + GdaTreeNode **out_last_node); +static GSList *decompose_path_as_segments (const gchar *path, gboolean use_names); + +/** + * gda_tree_get_nodes_in_path: + * @tree: a #GdaTree object + * @tree_path: (nullable): full path to the required nodes (if @use_names is %TRUE, then it must start with '/'), or %NULL + * @use_names: if %TRUE, then @tree_path will be interpreted as a unix style path, and if %FALSE, + * then @tree_path will be interpreted similarly to the #GtkTreePath's string representation. + * + * The returned list is a list of all the #GdaTreeNode nodes below the node + * at the specified path. + * + * As a corner case if @tree_path is %NULL, then the returned list contains all the top level nodes. + * + * Returns: (transfer container) (element-type GdaTreeNode): a new list of #GdaTreeNode pointers, free it with g_slist_free() + * + * Since: 4.2 + */ +GSList * +gda_tree_get_nodes_in_path (GdaTree *tree, const gchar *tree_path, gboolean use_names) +{ + GSList *segments, *nodes; + + g_return_val_if_fail (GDA_IS_TREE (tree), NULL); + GdaTreePrivate *priv = gda_tree_get_instance_private (tree); + + if (tree_path) { + segments = decompose_path_as_segments (tree_path, use_names); + nodes = real_gda_tree_get_nodes_in_path (tree, segments, use_names, NULL); + if (segments) { + g_slist_free_full (segments, (GDestroyNotify) g_free); + } + } + else { + nodes = gda_tree_node_get_children (priv->root); +#ifdef GDA_DEBUG_NO + GSList *list; + g_print ("Top nodes:\n"); + for (list = nodes; list; list = list->next) { + g_print ("Node %s(%p)\n", + gda_value_stringify (gda_tree_node_fetch_attribute (GDA_TREE_NODE (list->data), GDA_ATTRIBUTE_NAME)), + list->data); + } +#endif + } + return nodes; +} + +/* + * if @out_last_node is NULL, then it returns the children of the node pointed by @segments; + * if @out_last_node is NOT NULL, then it returns NULL and sets @out_last_node to point to the last node encountered + * in @segments + * + */ +static GSList * +real_gda_tree_get_nodes_in_path (GdaTree *tree, GSList *segments, gboolean use_names, GdaTreeNode **out_last_node) +{ + GdaTreePrivate *priv = gda_tree_get_instance_private (tree); + if (out_last_node) + *out_last_node = NULL; + + /* handle the case where no segment (path) is specified */ + if (!segments) { + if (out_last_node) + return NULL; + else + return gda_tree_node_get_children (priv->root); + } + + /* get the GdatreeNode for @tree_path */ + GSList *seglist; + GdaTreeNode *node; + GdaTreeNode *parent; + for (seglist = segments, parent = priv->root; + seglist; + seglist = seglist->next, parent = node) { + if (use_names) + node = gda_tree_node_get_child_name (parent, (gchar *) seglist->data); + else + node = gda_tree_node_get_child_index (parent, atoi ((gchar *) seglist->data)); /* Flawfinder: ignore */ + if (!node) + return NULL; + } + + if (out_last_node) { + *out_last_node = node; + return NULL; + } + else + return gda_tree_node_get_children (node); +} + +static gboolean build_node_path (GdaTree *tree, GdaTreeNode *node, GArray *array); + +/** + * gda_tree_get_node_path: + * @tree: a #GdaTree + * @node: a #GdaTreeNode node in @tree + * + * Get the path associated to @node in @tree. + * + * Returns: (transfer full): a new string, or %NULL if @node is not in @tree + * + * Since: 4.2 + */ +gchar * +gda_tree_get_node_path (GdaTree *tree, GdaTreeNode *node) +{ + GArray *array; + gchar *str = NULL; + g_return_val_if_fail (GDA_IS_TREE (tree), NULL); + g_return_val_if_fail (GDA_IS_TREE_NODE (node), NULL); + GdaTreePrivate *priv = gda_tree_get_instance_private (tree); + + if (!priv->root) + return NULL; + + array = g_array_new (TRUE, FALSE, sizeof (gchar*)); + if (build_node_path (tree, node, array)) + str = g_strjoinv (":", (gchar **) array->data); + + gsize i; + for (i = 0; i < array->len; i++) + g_free (g_array_index (array, gchar *, i)); + g_array_free (array, TRUE); + return str; +} + +static gboolean +build_node_path (GdaTree *tree, GdaTreeNode *node, GArray *array) +{ + GdaTreeNode *parent; + GSList *list; + gint i; + GdaTreePrivate *priv = gda_tree_get_instance_private (tree); + parent = gda_tree_node_get_parent (node); + if (parent) + list = gda_tree_node_get_children (parent); + else + list = gda_tree_node_get_children (priv->root); + + i = g_slist_index (list, node); + g_slist_free (list); + + if (i < 0) + return FALSE; + else { + gchar *tmp; + tmp = g_strdup_printf ("%d", i); + g_array_prepend_val (array, tmp); + if (parent) + return build_node_path (tree, parent, array); + else + return TRUE; + } +} + +/** + * gda_tree_get_node: + * @tree: a #GdaTree object + * @tree_path: full path to the required nodes (if @use_names is %TRUE, then it must start with '/') + * @use_names: if %TRUE, then @tree_path will be interpreted as a unix style path, and if %FALSE, + * then @tree_path will be interpreted similarly to the #GtkTreePath's string representation. + * + * Locates a #GdaTreeNode using the @tree_path path. + * + * Returns: (transfer none) (nullable): the requested #GdaTreeNode pointer, or %NULL if not found + * + * Since: 4.2 + */ +GdaTreeNode * +gda_tree_get_node (GdaTree *tree, const gchar *tree_path, gboolean use_names) +{ + GSList *segments; + GdaTreeNode *node = NULL; + + g_return_val_if_fail (GDA_IS_TREE (tree), NULL); + + segments = decompose_path_as_segments (tree_path, use_names); + if (!segments) + return NULL; + + g_assert (real_gda_tree_get_nodes_in_path (tree, segments, use_names, &node) == NULL); + + if (segments) { + g_slist_free_full (segments, (GDestroyNotify) g_free); + } + + return node; +} + +/** + * gda_tree_get_node_manager: + * @tree: a #GdaTree + * @node: a #GdaTreeNode present in @tree + * + * Get the #GdaTreeManager which created @node in @tree + * + * Returns: (transfer none): the #GdaTreeManager, or %NULL if @node is not present in @tree + * + * Since: 4.2 + */ +GdaTreeManager * +gda_tree_get_node_manager (GdaTree *tree, GdaTreeNode *node) +{ + GdaTreeNode *parent; + g_return_val_if_fail (GDA_IS_TREE (tree), NULL); + g_return_val_if_fail (GDA_IS_TREE_NODE (node), NULL); + GdaTreePrivate *priv = gda_tree_get_instance_private (tree); + + parent = gda_tree_node_get_parent (node); + return _gda_tree_node_get_manager_for_child (parent ? parent : priv->root, node); +} + +static gboolean +create_or_update_children (GSList *mgrlist, GdaTreeNode *parent, gboolean disable_recurs, GError **error) +{ + GSList *list; + for (list = mgrlist; list; list = list->next) { + GdaTreeManager *manager = GDA_TREE_MANAGER (list->data); + gboolean recurs = FALSE; + if (disable_recurs) { + g_object_get (G_OBJECT (manager), "recursive", &recurs, NULL); + if (recurs) + g_object_set (G_OBJECT (manager), "recursive", FALSE, NULL); + } + + gboolean has_error = FALSE; + _gda_tree_manager_update_children (manager, parent, + _gda_tree_node_get_children_for_manager (parent, + manager), + &has_error, error); + if (has_error) + return FALSE; + if (disable_recurs && recurs) + g_object_set (G_OBJECT (manager), "recursive", TRUE, NULL); + } + return TRUE; +} + +static GSList *split_absolute_path (const gchar *path, gboolean *out_error); +static GSList *split_indexed_path (const gchar *path, gboolean *out_error); + +/** + * decompose_path_as_segments: + * @path: a path using '/' + * @use_names: + * + * Returns: a new list of allocated strings (one for each segment of @path), or %NULL + */ +static GSList * +decompose_path_as_segments (const gchar *path, gboolean use_names) +{ + GSList *segments; + gboolean path_error; + if (!path) + return NULL; + + if (use_names) { + if (*path != '/') { + g_warning (_("Path format error: %s"), path); + return NULL; + } + segments = split_absolute_path (path, &path_error); + } + else + segments = split_indexed_path (path, &path_error); + if (path_error) { + g_warning (_("Path format error: %s"), path); + return NULL; + } + return segments; +} + + +/* + * Splits @path into a list of path segments, avoiding empty ("") segments + * @path is expected to be a unix style path + * FIXME: check for errors + * Returns: a new list of allocated strings (one for each segment of @path) + */ +static GSList * +split_absolute_path (const gchar *path, gboolean *out_error) +{ + GSList *list = NULL; + gchar *copy; + gchar *start, *end; + + *out_error = FALSE; + copy = g_strdup (path); + start = copy; + for (;;) { + for (end = start; *end; end++) { + if (*end == '/') + break; + } + if (*end == '/') { + *end = 0; + if (start != end) + list = g_slist_prepend (list, g_strdup (start)); + start = end + 1; + } + else { + if (start != end) + list = g_slist_prepend (list, g_strdup (start)); + break; + } + } + g_free (copy); + + list = g_slist_reverse (list); + +#ifdef GDA_DEBUG_NO + GSList *l; + for (l = list; l; l = l->next) + g_print ("Part: #%s#\n", (gchar*) l->data); +#endif + + return list; +} + +/* + * Splits @path into a list of path segments, avoiding empty ("") segments + * @path is expected to be a GtkTreePath's string representation path (ex: "3:2") + * Returns: a new list of allocated strings (one for each segment of @path) + */ +static GSList * +split_indexed_path (const gchar *path, gboolean *out_error) +{ + GSList *list = NULL; + gchar *copy; + gchar *start, *end; + + *out_error = FALSE; + copy = g_strdup (path); + start = copy; + for (;;) { + for (end = start; *end; end++) { + if (*end == ':') + break; + if ((*end < '0') || (*end > '9')) { + /* error */ + *out_error = TRUE; + g_slist_free_full (list, (GDestroyNotify) g_free); + g_free (copy); + return NULL; + } + } + if (*end == ':') { + *end = 0; + if (start != end) + list = g_slist_prepend (list, g_strdup (start)); + start = end + 1; + } + else { + if (start != end) + list = g_slist_prepend (list, g_strdup (start)); + break; + } + } + g_free (copy); + + list = g_slist_reverse (list); + +#ifdef GDA_DEBUG_NO + GSList *l; + g_print ("Splitting path '%s' into: ", path); + for (l = list; l; l = l->next) + g_print ("%s ", (gchar*) l->data); + g_print ("\n"); +#endif + + return list; +} + +/** + * gda_tree_set_attribute: + * @tree: a #GdaTree object + * @attribute: attribute name + * @value: a #GValue, or %NULL + * @destroy: a function to be called when @attribute is not needed anymore, or %NULL + * + * Sets an attribute to @tree, which will be accessible to any node in it. + * + * Since: 4.2 + */ +void +gda_tree_set_attribute (GdaTree *tree, const gchar *attribute, const GValue *value, + GDestroyNotify destroy) +{ + g_return_if_fail (GDA_IS_TREE (tree)); + GdaTreePrivate *priv = gda_tree_get_instance_private (tree); + gda_tree_node_set_node_attribute (priv->root, attribute, value, destroy); +} + +static void +take_root_node (GdaTree *tree, GdaTreeNode *root) +{ + GdaTreePrivate *priv = gda_tree_get_instance_private (tree); + if (priv->root) + unset_root_node (tree); + priv->root = root; + g_signal_connect (priv->root, "node-changed", + G_CALLBACK (node_changed_cb), tree); + g_signal_connect (priv->root, "node-inserted", + G_CALLBACK (node_inserted_cb), tree); + g_signal_connect (priv->root, "node-has-child-toggled", + G_CALLBACK (node_has_child_toggled_cb), tree); + g_signal_connect (priv->root, "node-deleted", + G_CALLBACK (node_deleted_cb), tree); +} + +static void +unset_root_node (GdaTree *tree) +{ + GSList *list; + GdaTreePrivate *priv = gda_tree_get_instance_private (tree); + for (list = priv->managers; list; list = list->next) { + GdaTreeManager *manager = GDA_TREE_MANAGER (list->data); + + _gda_tree_node_add_children (priv->root, manager, NULL); + } + + g_signal_handlers_disconnect_by_func (priv->root, + G_CALLBACK (node_changed_cb), tree); + g_signal_handlers_disconnect_by_func (priv->root, + G_CALLBACK (node_inserted_cb), tree); + g_signal_handlers_disconnect_by_func (priv->root, + G_CALLBACK (node_has_child_toggled_cb), tree); + g_signal_handlers_disconnect_by_func (priv->root, + G_CALLBACK (node_deleted_cb), tree); + + g_object_unref (priv->root); +} + +static void +node_changed_cb (GdaTreeNode *reporting, GdaTreeNode *node, GdaTree *tree) +{ + GdaTreePrivate *priv = gda_tree_get_instance_private (tree); + if ((reporting != node) || (reporting != priv->root)) + g_signal_emit (tree, gda_tree_signals [NODE_CHANGED], 0, node); +} + +static void +node_inserted_cb (GdaTreeNode *reporting, GdaTreeNode *node, GdaTree *tree) +{ + GdaTreePrivate *priv = gda_tree_get_instance_private (tree); + if ((reporting != node) || (reporting != priv->root)) + g_signal_emit (tree, gda_tree_signals [NODE_INSERTED], 0, node); +} + +static void +node_has_child_toggled_cb (GdaTreeNode *reporting, GdaTreeNode *node, GdaTree *tree) +{ + GdaTreePrivate *priv = gda_tree_get_instance_private (tree); + if ((reporting != node) || (reporting != priv->root)) + g_signal_emit (tree, gda_tree_signals [NODE_HAS_CHILD_TOGGLED], 0, node); +} + +static void +node_deleted_cb (G_GNUC_UNUSED GdaTreeNode *reporting, const gchar *relative_path, GdaTree *tree) +{ + g_signal_emit (tree, gda_tree_signals [NODE_DELETED], 0, relative_path); +} diff --git a/.flatpak-builder/cache/objects/a8/a5019170c1411f823aed667ba6f5ecab2b80dd8beda27e8e29006e820aab33.file b/.flatpak-builder/cache/objects/a8/a5019170c1411f823aed667ba6f5ecab2b80dd8beda27e8e29006e820aab33.file new file mode 100644 index 0000000..7de197c --- /dev/null +++ b/.flatpak-builder/cache/objects/a8/a5019170c1411f823aed667ba6f5ecab2b80dd8beda27e8e29006e820aab33.file @@ -0,0 +1,125 @@ +# response_id.py +# +# Copyright 2022 Gleb Smirnov +# +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation; either version 3 of the +# License, or (at your option) any later version. +# +# This file is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program. If not, see . +# +# SPDX-License-Identifier: LGPL-3.0-or-later + + +import typing as T + +from .common import * + + +class ExtResponse(AstNode): + """Response ID of action widget.""" + + ALLOWED_PARENTS: T.List[T.Tuple[str, str]] = [("Gtk", "Dialog"), ("Gtk", "InfoBar")] + + grammar = [ + Keyword("action"), + Keyword("response"), + "=", + AnyOf( + UseIdent("response_id"), + [ + Optional(UseExact("sign", "-")), + UseNumber("response_id"), + ], + ), + Optional([Keyword("default"), UseLiteral("is_default", True)]), + ] + + @validate() + def parent_has_action_widgets(self) -> None: + """Chech that parent widget has allowed type.""" + from .gobject_object import Object + + container_type = self.parent_by_type(Object).gir_class + if container_type is None: + return + + gir = self.root.gir + + for namespace, name in ExtResponse.ALLOWED_PARENTS: + parent_type = gir.get_type(name, namespace) + if container_type.assignable_to(parent_type): + break + else: + raise CompileError( + f"{container_type.full_name} doesn't have action widgets" + ) + + @validate() + def widget_have_id(self) -> None: + """Check that action widget have ID.""" + from .gtkbuilder_child import Child + + object = self.parent_by_type(Child).object + if object.id is None: + raise CompileError(f"Action widget must have ID") + + @validate("response_id") + def correct_response_type(self) -> None: + """Validate response type. + + Response type might be GtkResponseType member + or positive number. + """ + gir = self.root.gir + response = self.tokens["response_id"] + + if self.tokens["sign"] == "-": + raise CompileError("Numeric response type can't be negative") + + if isinstance(response, float): + raise CompileError( + "Response type must be GtkResponseType member or integer," " not float" + ) + elif not isinstance(response, int): + responses = gir.get_type("ResponseType", "Gtk").members.keys() + if response not in responses: + raise CompileError(f'Response type "{response}" doesn\'t exist') + + @validate("default") + def no_multiple_default(self) -> None: + """Only one action widget in dialog can be default.""" + from .gobject_object import Object + + if not self.is_default: + return + + action_widgets = self.parent_by_type(Object).action_widgets + for widget in action_widgets: + if widget == self: + break + if widget.tokens["is_default"]: + raise CompileError("Default response is already set") + + @property + def response_id(self) -> str: + return self.tokens["response_id"] + + @property + def is_default(self) -> bool: + return self.tokens["is_default"] or False + + @property + def widget_id(self) -> str: + """Get action widget ID.""" + from .gtkbuilder_child import Child + + object = self.parent_by_type(Child).object + return object.id diff --git a/.flatpak-builder/cache/objects/a8/ca9bf04244825bbfa68016538839545e250525503061214d417c85b69d6a96.file b/.flatpak-builder/cache/objects/a8/ca9bf04244825bbfa68016538839545e250525503061214d417c85b69d6a96.file new file mode 100644 index 0000000..a81e03d --- /dev/null +++ b/.flatpak-builder/cache/objects/a8/ca9bf04244825bbfa68016538839545e250525503061214d417c85b69d6a96.file @@ -0,0 +1,152 @@ +# gtk_scale.py +# +# Copyright 2023 James Westman +# +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation; either version 3 of the +# License, or (at your option) any later version. +# +# This file is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program. If not, see . +# +# SPDX-License-Identifier: LGPL-3.0-or-later + +from .gobject_object import validate_parent_type, ObjectContent +from .common import * +from .values import StringValue + + +class ExtScaleMark(AstNode): + grammar = [ + Keyword("mark"), + Match("(").expected(), + [ + Optional(AnyOf(UseExact("sign", "-"), UseExact("sign", "+"))), + UseNumber("value"), + Optional( + [ + ",", + UseIdent("position"), + Optional([",", StringValue]), + ] + ), + ], + Match(")").expected(), + ] + + @property + def value(self) -> float: + if self.tokens["sign"] == "-": + return -self.tokens["value"] + else: + return self.tokens["value"] + + @property + def position(self) -> T.Optional[str]: + return self.tokens["position"] + + @property + def label(self) -> T.Optional[StringValue]: + if len(self.children[StringValue]) == 1: + return self.children[StringValue][0] + else: + return None + + @docs("position") + def position_docs(self) -> T.Optional[str]: + if member := self.root.gir.get_type("PositionType", "Gtk").members.get( + self.position + ): + return member.doc + else: + return None + + @validate("position") + def validate_position(self): + positions = self.root.gir.get_type("PositionType", "Gtk").members + if self.position is not None and positions.get(self.position) is None: + raise CompileError( + f"'{self.position}' is not a member of Gtk.PositionType", + did_you_mean=(self.position, positions.keys()), + ) + + +class ExtScaleMarks(AstNode): + grammar = [ + Keyword("marks"), + Match("[").expected(), + Until(ExtScaleMark, "]", ","), + ] + + @property + def marks(self) -> T.List[ExtScaleMark]: + return self.children + + @validate("marks") + def container_is_size_group(self): + validate_parent_type(self, "Gtk", "Scale", "scale marks") + + @validate("marks") + def unique_in_parent(self): + self.validate_unique_in_parent("Duplicate 'marks' block") + + +@completer( + applies_in=[ObjectContent], + applies_in_subclass=("Gtk", "Scale"), + matches=new_statement_patterns, +) +def complete_marks(ast_node, match_variables): + yield Completion("marks", CompletionItemKind.Keyword, snippet="marks [\n\t$0\n]") + + +@completer( + applies_in=[ExtScaleMarks], +) +def complete_mark(ast_node, match_variables): + yield Completion("mark", CompletionItemKind.Keyword, snippet="mark ($0),") + + +@decompiler("marks") +def decompile_marks( + ctx, + gir, +): + ctx.print("marks [") + + +@decompiler("mark", cdata=True) +def decompile_mark( + ctx: DecompileCtx, + gir, + value, + position=None, + cdata=None, + translatable="false", + comments=None, + context=None, +): + if comments is not None: + ctx.print(f"/* Translators: {comments} */") + + text = f"mark ({value}" + + if position: + text += f", {position}" + elif cdata: + text += f", bottom" + + if truthy(translatable): + comments, translatable = decompile_translatable( + cdata, translatable, context, comments + ) + text += f", {translatable}" + + text += ")," + ctx.print(text) diff --git a/.flatpak-builder/cache/objects/a8/d4273bd14a5b4293007571b4457fc67f533b501758e4c2c0f9074f1b3f122b.file b/.flatpak-builder/cache/objects/a8/d4273bd14a5b4293007571b4457fc67f533b501758e4c2c0f9074f1b3f122b.file new file mode 100644 index 0000000..dd94180 --- /dev/null +++ b/.flatpak-builder/cache/objects/a8/d4273bd14a5b4293007571b4457fc67f533b501758e4c2c0f9074f1b3f122b.file @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2000 - 2003 Rodrigo Moya + * Copyright (C) 2001 - 2011 Vivien Malerba + * Copyright (C) 2002 Gonzalo Paniagua Javier + * Copyright (C) 2008 Przemysław Grzegorczyk + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GDA_LOG_H__ +#define __GDA_LOG_H__ + +#include +#include + +G_BEGIN_DECLS + +/** + * SECTION:gda-log + * @short_description: Log functions + * @title: Logging + * @stability: Stable + * @see_also: + * + * Logging functions. + */ + +/* + * For application generating logs + */ +void gda_log_enable (void); +void gda_log_disable (void); +gboolean gda_log_is_enabled (void); + +void gda_log_message (const gchar * format, ...); +void gda_log_error (const gchar * format, ...); + +G_END_DECLS + +#endif diff --git a/.flatpak-builder/cache/objects/a9/856529b9a71567b774d6c3ac99c850edb461da081882e744f24a51b330f52b.file b/.flatpak-builder/cache/objects/a9/856529b9a71567b774d6c3ac99c850edb461da081882e744f24a51b330f52b.file new file mode 100644 index 0000000..64f464d --- /dev/null +++ b/.flatpak-builder/cache/objects/a9/856529b9a71567b774d6c3ac99c850edb461da081882e744f24a51b330f52b.file @@ -0,0 +1,47 @@ +/*-*- Mode: C; c-basic-offset: 8 -*-*/ + +/*** + This file is part of libcanberra. + + Copyright 2008 Lennart Poettering + + libcanberra is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation, either version 2.1 of the + License, or (at your option) any later version. + + libcanberra is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with libcanberra. If not, see + . +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include "canberra.h" +#include "driver-order.h" + +const char* const ca_driver_order[] = { +#ifdef HAVE_PULSE + "pulse", +#endif +#ifdef HAVE_ALSA + "alsa", +#endif +#ifdef HAVE_OSS + "oss", +#endif +#ifdef HAVE_GSTREAMER + "gstreamer", +#endif + /* ... */ + NULL +}; diff --git a/.flatpak-builder/cache/objects/a9/93c5f3675843424a64b74154f248a8f661bef822fe24f3e68b3f468cdd37a7.dirtree b/.flatpak-builder/cache/objects/a9/93c5f3675843424a64b74154f248a8f661bef822fe24f3e68b3f468cdd37a7.dirtree new file mode 100644 index 0000000..943ac9a Binary files /dev/null and b/.flatpak-builder/cache/objects/a9/93c5f3675843424a64b74154f248a8f661bef822fe24f3e68b3f468cdd37a7.dirtree differ diff --git a/.flatpak-builder/cache/objects/a9/98743da9d63e043ba1e8cc84f4cd729c37e72db3f7e49d5ac1d1292dcd2100.dirtree b/.flatpak-builder/cache/objects/a9/98743da9d63e043ba1e8cc84f4cd729c37e72db3f7e49d5ac1d1292dcd2100.dirtree new file mode 100644 index 0000000..03303fb Binary files /dev/null and b/.flatpak-builder/cache/objects/a9/98743da9d63e043ba1e8cc84f4cd729c37e72db3f7e49d5ac1d1292dcd2100.dirtree differ diff --git a/.flatpak-builder/cache/objects/a9/a613afa91ec1c3997e964507b9fa20548d4958b28e3095b80d2794e1cb7f8e.file b/.flatpak-builder/cache/objects/a9/a613afa91ec1c3997e964507b9fa20548d4958b28e3095b80d2794e1cb7f8e.file new file mode 100644 index 0000000..20f83d6 Binary files /dev/null and b/.flatpak-builder/cache/objects/a9/a613afa91ec1c3997e964507b9fa20548d4958b28e3095b80d2794e1cb7f8e.file differ diff --git a/.flatpak-builder/cache/objects/aa/2f663675ba2861fa3d4bf698e3f35289dc10772da76ca647c6e74ff5be21ab.file b/.flatpak-builder/cache/objects/aa/2f663675ba2861fa3d4bf698e3f35289dc10772da76ca647c6e74ff5be21ab.file new file mode 120000 index 0000000..b65fcb5 --- /dev/null +++ b/.flatpak-builder/cache/objects/aa/2f663675ba2861fa3d4bf698e3f35289dc10772da76ca647c6e74ff5be21ab.file @@ -0,0 +1 @@ +../../share/runtime/locale/da/share/da \ No newline at end of file diff --git a/.flatpak-builder/cache/objects/aa/52b6198e5f93921739e93780c8389dc326554536d65b0275be8c6ff6664e53.commit b/.flatpak-builder/cache/objects/aa/52b6198e5f93921739e93780c8389dc326554536d65b0275be8c6ff6664e53.commit new file mode 100644 index 0000000..39fea6a Binary files /dev/null and b/.flatpak-builder/cache/objects/aa/52b6198e5f93921739e93780c8389dc326554536d65b0275be8c6ff6664e53.commit differ diff --git a/.flatpak-builder/cache/objects/aa/9b693da36e5b12802627396dc81915768deb3851f75ab7cbf2e7cdf0e89ce7.file b/.flatpak-builder/cache/objects/aa/9b693da36e5b12802627396dc81915768deb3851f75ab7cbf2e7cdf0e89ce7.file new file mode 120000 index 0000000..f83f081 --- /dev/null +++ b/.flatpak-builder/cache/objects/aa/9b693da36e5b12802627396dc81915768deb3851f75ab7cbf2e7cdf0e89ce7.file @@ -0,0 +1 @@ +../../share/runtime/locale/ml/share/ml \ No newline at end of file diff --git a/.flatpak-builder/cache/objects/aa/bfa95980f91ad29a7fd8c2943fc0321998d5432c0593040d31348cca59df76.dirtree b/.flatpak-builder/cache/objects/aa/bfa95980f91ad29a7fd8c2943fc0321998d5432c0593040d31348cca59df76.dirtree new file mode 100644 index 0000000..132d7c2 Binary files /dev/null and b/.flatpak-builder/cache/objects/aa/bfa95980f91ad29a7fd8c2943fc0321998d5432c0593040d31348cca59df76.dirtree differ diff --git a/.flatpak-builder/cache/objects/ab/489d44adf19ba67216f0876435e0304fc2964889650f39b3c654a00e73d8c4.dirtree b/.flatpak-builder/cache/objects/ab/489d44adf19ba67216f0876435e0304fc2964889650f39b3c654a00e73d8c4.dirtree new file mode 100644 index 0000000..e640642 Binary files /dev/null and b/.flatpak-builder/cache/objects/ab/489d44adf19ba67216f0876435e0304fc2964889650f39b3c654a00e73d8c4.dirtree differ diff --git a/.flatpak-builder/cache/objects/ab/8ffaf14b41afa3d721257043cc92a03a68d6da8e1232ebd58528b3dffb5f19.file b/.flatpak-builder/cache/objects/ab/8ffaf14b41afa3d721257043cc92a03a68d6da8e1232ebd58528b3dffb5f19.file new file mode 100644 index 0000000..361dec5 --- /dev/null +++ b/.flatpak-builder/cache/objects/ab/8ffaf14b41afa3d721257043cc92a03a68d6da8e1232ebd58528b3dffb5f19.file @@ -0,0 +1,478 @@ +/* + * Copyright (C) 2019 Daniel Espinosa + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +#define G_LOG_DOMAIN "GDA-data-model-select" + +#include + +// GdaDataModel Interface +static void gda_data_model_select_data_model_init (GdaDataModelInterface *iface); + +// GdaDataModelSelect object definition + +enum +{ + PROP_VALID = 1, + N_PROPERTIES +}; + +static GParamSpec *properties[N_PROPERTIES] = { NULL, }; + +static void gda_data_model_select_dispose (GObject *object); +static void gda_data_model_select_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec); + +static void gda_data_model_select_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec); + +typedef struct { + GdaConnection *cnc; + GdaStatement *stm; + GdaDataModel *model; + GdaSet *params; +} GdaDataModelSelectPrivate; + +G_DEFINE_TYPE_WITH_CODE (GdaDataModelSelect, gda_data_model_select, G_TYPE_OBJECT, + G_ADD_PRIVATE (GdaDataModelSelect) + G_IMPLEMENT_INTERFACE (GDA_TYPE_DATA_MODEL, gda_data_model_select_data_model_init)) + + +/* signals */ +enum { + UPDATED, + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL] = { 0 }; + +static void gda_data_model_select_class_init (GdaDataModelSelectClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + object_class->dispose = gda_data_model_select_dispose; + object_class->get_property = gda_data_model_select_get_property; + object_class->set_property = gda_data_model_select_set_property; + + /** + * GdaDataModelSelect::updated: + * @model: a #GdaDataModelSelect + * + * Emmited when the data model has been updated due to parameters changes + * in statement + */ + signals[UPDATED] = g_signal_newv ("updated", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, + NULL /* closure */, + NULL /* accumulator */, + NULL /* accumulator data */, + NULL /* C marshaller */, + G_TYPE_NONE /* return_type */, + 0 /* n_params */, + NULL /* param_types */); + properties[PROP_VALID] = + g_param_spec_boolean ("valid", + "Valid", + "If last statement execution was successful this is set to TRUE", + FALSE /* default value */, + G_PARAM_READABLE); + + g_object_class_install_properties (object_class, + N_PROPERTIES, + properties); +} + +static void gda_data_model_select_init (GdaDataModelSelect *model) +{ + GdaDataModelSelectPrivate *priv = gda_data_model_select_get_instance_private (GDA_DATA_MODEL_SELECT (model)); + priv->cnc = NULL; + priv->stm = NULL; + priv->params = NULL; + priv->model = NULL; +} + +static void gda_data_model_select_dispose (GObject *object) +{ + GdaDataModelSelectPrivate *priv = gda_data_model_select_get_instance_private (GDA_DATA_MODEL_SELECT (object)); + if (priv->cnc != NULL) { + g_object_unref (priv->cnc); + priv->cnc = NULL; + } + if (priv->stm != NULL) { + g_object_unref (priv->stm); + priv->stm = NULL; + } + if (priv->params != NULL) { + g_object_unref (priv->params); + priv->params = NULL; + } + if (priv->model != NULL) { + g_object_unref (priv->model); + priv->model = NULL; + } +} + + +static void gda_data_model_select_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + switch (property_id) { + case PROP_VALID: + break; + default: + /* We don't have any other property... */ + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void gda_data_model_select_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + GdaDataModelSelectPrivate *priv = gda_data_model_select_get_instance_private (GDA_DATA_MODEL_SELECT (object)); + switch (property_id) { + case PROP_VALID: + g_value_set_boolean (value, priv->model != NULL); + break; + default: + /* We don't have any other property... */ + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void params_changed_cb (GdaSet *params, GdaHolder *holder, GdaDataModelSelect *model) +{ + GdaDataModelSelectPrivate *priv = gda_data_model_select_get_instance_private (GDA_DATA_MODEL_SELECT (model)); + if (priv->cnc != NULL && priv->stm != NULL) { + if (priv->model != NULL) { + g_object_unref (priv->model); + priv->model = NULL; + } + priv->model = gda_connection_statement_execute_select (priv->cnc, priv->stm, priv->params, NULL); + g_signal_emit (model, signals[UPDATED], 0); + } +} + +/** + * gda_data_model_select_new: + * @cnc: an opened #GdaConnection + * @stm: a SELECT SQL #GdaStatement + * @params: (nullable): a #GdaSet with the parameters to ejecute the SELECT SQL statement + * + * Returns: (transfer full): a new #GdaDataModelSelect object + */ +GdaDataModelSelect* +gda_data_model_select_new (GdaConnection *cnc, GdaStatement *stm, GdaSet *params) +{ + g_return_val_if_fail (cnc != NULL, NULL); + g_return_val_if_fail (stm != NULL, NULL); + g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL); + g_return_val_if_fail (GDA_IS_STATEMENT (stm), NULL); + + GdaDataModelSelect* model = GDA_DATA_MODEL_SELECT (g_object_new (GDA_TYPE_DATA_MODEL_SELECT, NULL)); + GdaDataModelSelectPrivate *priv = gda_data_model_select_get_instance_private (GDA_DATA_MODEL_SELECT (model)); + + priv->cnc = g_object_ref (cnc); + priv->stm = g_object_ref (stm); + if (params != NULL) { + priv->params = g_object_ref (params); + g_signal_connect (priv->params, "holder-changed", G_CALLBACK (params_changed_cb), model); + } else { + priv->params = NULL; + } + priv->model = gda_connection_statement_execute_select (priv->cnc, priv->stm, priv->params, NULL); + return model; +} +/** + * gda_data_model_select_new_from_string: + * @cnc: an opened #GdaConnection + * @sql: a string representing a SELECT SQL to execute + * + * Returns: (transfer full): a new #GdaDataModelSelect object + */ +GdaDataModelSelect* +gda_data_model_select_new_from_string (GdaConnection *cnc, const gchar *sql) +{ + g_return_val_if_fail (cnc != NULL, NULL); + g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL); + GdaStatement *stm = gda_connection_parse_sql_string (cnc, sql, NULL, NULL); + if (stm == NULL) { + return NULL; + } + + GdaSet *params = NULL; + gda_statement_get_parameters (stm, ¶ms, NULL); + + return gda_data_model_select_new (cnc, stm, params); +} + + +/** + * gda_data_model_select_is_valid: + * @model: a #GdaDataModelSelect object + * + * If at creation or after parameters change has been set, a SELECT statement + * is ejectuted, if unsuccess then this model is at invalid state. + * + * Returns: TRUE if a valid data model is present + */ +gboolean +gda_data_model_select_is_valid (GdaDataModelSelect *model) +{ + g_return_val_if_fail (model != NULL, FALSE); + g_return_val_if_fail (GDA_IS_DATA_MODEL_SELECT (model), FALSE); + GdaDataModelSelectPrivate *priv = gda_data_model_select_get_instance_private (GDA_DATA_MODEL_SELECT (model)); + return priv->model != NULL; +} + +/** + * gda_data_model_select_get_parameters: + * @model: a #GdaDataModelSelect object + * + * Returns: (transfer full): current parameters used by internal statement + */ +GdaSet* +gda_data_model_select_get_parameters (GdaDataModelSelect *model) +{ + g_return_val_if_fail (model != NULL, NULL); + g_return_val_if_fail (GDA_IS_DATA_MODEL_SELECT (model), NULL); + GdaDataModelSelectPrivate *priv = gda_data_model_select_get_instance_private (GDA_DATA_MODEL_SELECT (model)); + if (priv->params == NULL) { + gda_statement_get_parameters (priv->stm, &priv->params, NULL); + return priv->params; + } + return g_object_ref (priv->params); +} + +/** + * gda_data_model_select_set_parameters: + * @model: a #GdaDataModelSelect object + * @params: a #GdaSet with the parameters for the statement + */ +void +gda_data_model_select_set_parameters (GdaDataModelSelect *model, GdaSet *params) +{ + g_return_if_fail (model != NULL); + g_return_if_fail (GDA_IS_DATA_MODEL_SELECT (model)); + g_return_if_fail (params != NULL); + GdaDataModelSelectPrivate *priv = gda_data_model_select_get_instance_private (GDA_DATA_MODEL_SELECT (model)); + if (priv->params != NULL) { + g_object_unref (priv->params); + priv->params = NULL; + } + priv->params = g_object_ref (priv->params); + g_signal_connect (priv->params, "holder-changed", G_CALLBACK (params_changed_cb), model); + params_changed_cb (priv->params, NULL, model); +} + + +// GdaDataModel Implementation + + + +static gint +gda_data_model_select_get_n_rows (GdaDataModel *model) +{ + g_return_val_if_fail (model != NULL, -1); + g_return_val_if_fail (GDA_IS_DATA_MODEL_SELECT (model), -1); + GdaDataModelSelectPrivate *priv = gda_data_model_select_get_instance_private (GDA_DATA_MODEL_SELECT (model)); + g_return_val_if_fail (priv->model != NULL, 0); + return gda_data_model_get_n_rows (priv->model); +} +static gint +gda_data_model_select_get_n_columns (GdaDataModel *model) +{ + g_return_val_if_fail (model != NULL, -1); + g_return_val_if_fail (GDA_IS_DATA_MODEL_SELECT (model), -1); + GdaDataModelSelectPrivate *priv = gda_data_model_select_get_instance_private (GDA_DATA_MODEL_SELECT (model)); + g_return_val_if_fail (priv->model != NULL, 0); + return gda_data_model_get_n_columns (priv->model); +} +static GdaColumn* +gda_data_model_select_describe_column (GdaDataModel *model, + gint col) +{ + g_return_val_if_fail (model != NULL, NULL); + g_return_val_if_fail (GDA_IS_DATA_MODEL_SELECT (model), NULL); + GdaDataModelSelectPrivate *priv = gda_data_model_select_get_instance_private (GDA_DATA_MODEL_SELECT (model)); + g_return_val_if_fail (priv->model != NULL, NULL); + return gda_data_model_describe_column (priv->model, col); +} +static GdaDataModelAccessFlags +gda_data_model_select_get_access_flags (GdaDataModel *model) +{ + g_return_val_if_fail (model != NULL, 0); + g_return_val_if_fail (GDA_IS_DATA_MODEL_SELECT (model), 0); + GdaDataModelSelectPrivate *priv = gda_data_model_select_get_instance_private (GDA_DATA_MODEL_SELECT (model)); + g_return_val_if_fail (priv->model != NULL, 0); + return gda_data_model_get_access_flags (priv->model); +} +static const GValue* +gda_data_model_select_get_value_at (GdaDataModel *model, + gint col, + gint row, + GError **error) +{ + g_return_val_if_fail (model != NULL, NULL); + g_return_val_if_fail (GDA_IS_DATA_MODEL_SELECT (model), NULL); + GdaDataModelSelectPrivate *priv = gda_data_model_select_get_instance_private (GDA_DATA_MODEL_SELECT (model)); + g_return_val_if_fail (priv->model != NULL, NULL); + return gda_data_model_get_value_at (priv->model, col, row, error); +} +static GdaValueAttribute +gda_data_model_select_get_attributes_at (GdaDataModel *model, + gint col, + gint row) +{ + g_return_val_if_fail (model != NULL, 0); + g_return_val_if_fail (GDA_IS_DATA_MODEL_SELECT (model), 0); + GdaDataModelSelectPrivate *priv = gda_data_model_select_get_instance_private (GDA_DATA_MODEL_SELECT (model)); + g_return_val_if_fail (priv->model != NULL, 0); + return gda_data_model_get_attributes_at (priv->model, col, row); +} + +static GdaDataModelIter* +gda_data_model_select_create_iter (GdaDataModel *model) +{ + g_return_val_if_fail (model != NULL, NULL); + g_return_val_if_fail (GDA_IS_DATA_MODEL_SELECT (model), NULL); + GdaDataModelSelectPrivate *priv = gda_data_model_select_get_instance_private (GDA_DATA_MODEL_SELECT (model)); + g_return_val_if_fail (priv->model != NULL, NULL); + return gda_data_model_create_iter (priv->model); +} + +static gboolean +gda_data_model_select_set_value_at (GdaDataModel *model, + gint col, + gint row, + const GValue *value, + GError **error) +{ + g_return_val_if_fail (model != NULL, FALSE); + g_return_val_if_fail (GDA_IS_DATA_MODEL_SELECT (model), FALSE); + GdaDataModelSelectPrivate *priv = gda_data_model_select_get_instance_private (GDA_DATA_MODEL_SELECT (model)); + g_return_val_if_fail (priv->model != NULL, FALSE); + return gda_data_model_set_value_at (priv->model, col, row, value, error); +} + +static gboolean +gda_data_model_select_set_values (GdaDataModel *model, + gint row, + GList *values, + GError **error) +{ + g_return_val_if_fail (model != NULL, FALSE); + g_return_val_if_fail (GDA_IS_DATA_MODEL_SELECT (model), FALSE); + GdaDataModelSelectPrivate *priv = gda_data_model_select_get_instance_private (GDA_DATA_MODEL_SELECT (model)); + g_return_val_if_fail (priv->model != NULL, FALSE); + return gda_data_model_set_values (priv->model, row, values, error); +} +static gint +gda_data_model_select_append_values (GdaDataModel *model, + const GList *values, + GError **error) +{ + g_return_val_if_fail (model != NULL, -1); + g_return_val_if_fail (GDA_IS_DATA_MODEL_SELECT (model), -1); + GdaDataModelSelectPrivate *priv = gda_data_model_select_get_instance_private (GDA_DATA_MODEL_SELECT (model)); + g_return_val_if_fail (priv->model != NULL, -1); + return gda_data_model_append_values (priv->model, values, error); +} +static gboolean +gda_data_model_select_remove_row (GdaDataModel *model, + gint row, + GError **error) +{ + g_return_val_if_fail (model != NULL, FALSE); + g_return_val_if_fail (GDA_IS_DATA_MODEL_SELECT (model), FALSE); + GdaDataModelSelectPrivate *priv = gda_data_model_select_get_instance_private (GDA_DATA_MODEL_SELECT (model)); + g_return_val_if_fail (priv->model != NULL, FALSE); + return gda_data_model_remove_row (priv->model, row, error); +} + +static void +gda_data_model_select_freeze (GdaDataModel *model) +{ + g_return_if_fail (model != NULL); + g_return_if_fail (GDA_IS_DATA_MODEL_SELECT (model)); + GdaDataModelSelectPrivate *priv = gda_data_model_select_get_instance_private (GDA_DATA_MODEL_SELECT (model)); + g_return_if_fail (priv->model != NULL); + return gda_data_model_freeze (priv->model); +} +static void +gda_data_model_select_thaw (GdaDataModel *model) +{ + g_return_if_fail (model != NULL); + g_return_if_fail (GDA_IS_DATA_MODEL_SELECT (model)); + GdaDataModelSelectPrivate *priv = gda_data_model_select_get_instance_private (GDA_DATA_MODEL_SELECT (model)); + g_return_if_fail (priv->model != NULL); + return gda_data_model_thaw (priv->model); +} +static gboolean +gda_data_model_select_get_notify (GdaDataModel *model) +{ + g_return_val_if_fail (model != NULL, FALSE); + g_return_val_if_fail (GDA_IS_DATA_MODEL_SELECT (model), FALSE); + GdaDataModelSelectPrivate *priv = gda_data_model_select_get_instance_private (GDA_DATA_MODEL_SELECT (model)); + g_return_val_if_fail (priv->model != NULL, FALSE); + return gda_data_model_get_notify (priv->model); +} +static GError** +gda_data_model_select_get_exceptions (GdaDataModel *model) +{ + g_return_val_if_fail (model != NULL, NULL); + g_return_val_if_fail (GDA_IS_DATA_MODEL_SELECT (model), NULL); + GdaDataModelSelectPrivate *priv = gda_data_model_select_get_instance_private (GDA_DATA_MODEL_SELECT (model)); + g_return_val_if_fail (priv->model != NULL, FALSE); + return gda_data_model_get_exceptions (priv->model); +} + +static void +gda_data_model_select_data_model_init (GdaDataModelInterface *iface) +{ + iface->get_n_rows = gda_data_model_select_get_n_rows; + iface->get_n_columns = gda_data_model_select_get_n_columns; + iface->describe_column = gda_data_model_select_describe_column; + iface->get_access_flags = gda_data_model_select_get_access_flags; + iface->get_value_at = gda_data_model_select_get_value_at; + iface->get_attributes_at = gda_data_model_select_get_attributes_at; + + iface->create_iter = gda_data_model_select_create_iter; + + iface->set_value_at = gda_data_model_select_set_value_at; + iface->set_values = gda_data_model_select_set_values; + iface->append_values = gda_data_model_select_append_values; + iface->append_row = NULL; + iface->remove_row = gda_data_model_select_remove_row; + iface->find_row = NULL; + + iface->freeze = gda_data_model_select_freeze; + iface->thaw = gda_data_model_select_thaw; + iface->get_notify = gda_data_model_select_get_notify; + iface->send_hint = NULL; + + iface->get_exceptions = gda_data_model_select_get_exceptions; +} diff --git a/.flatpak-builder/cache/objects/ab/f11399c34ed18d5a6ee41836b6dc24d38c642b299a088500d31cffb557fa6c.dirtree b/.flatpak-builder/cache/objects/ab/f11399c34ed18d5a6ee41836b6dc24d38c642b299a088500d31cffb557fa6c.dirtree new file mode 100644 index 0000000..82b0d8a Binary files /dev/null and b/.flatpak-builder/cache/objects/ab/f11399c34ed18d5a6ee41836b6dc24d38c642b299a088500d31cffb557fa6c.dirtree differ diff --git a/.flatpak-builder/cache/objects/ab/f1e199937bb887e6110c19db5134c69720be66b56fd9a6ce6c358618d26c43.file b/.flatpak-builder/cache/objects/ab/f1e199937bb887e6110c19db5134c69720be66b56fd9a6ce6c358618d26c43.file new file mode 100644 index 0000000..5644174 --- /dev/null +++ b/.flatpak-builder/cache/objects/ab/f1e199937bb887e6110c19db5134c69720be66b56fd9a6ce6c358618d26c43.file @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2008 - 2011 Vivien Malerba + * Copyright (C) 2009 Murray Cumming + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef _GDA_STATEMENT_STRUCT_SELECT_H_ +#define _GDA_STATEMENT_STRUCT_SELECT_H_ + +#include +#include +#include +#include + +G_BEGIN_DECLS + +/* + * Structure definition + */ +/** + * GdaSqlStatementSelect: + * @any: + * @distinct: + * @distinct_expr: + * @expr_list: + * @from: + * @where_cond: + * @group_by: + * @having_cond: + * @order_by: + * @limit_count: + * @limit_offset: + */ +struct _GdaSqlStatementSelect { + GdaSqlAnyPart any; + gboolean distinct; + GdaSqlExpr *distinct_expr; + + GSList *expr_list; /* list of GdaSqlSelectField pointers */ + GdaSqlSelectFrom *from; + + GdaSqlExpr *where_cond; /* WHERE... */ + GSList *group_by; /* list of GdaSqlExpr pointers */ + GdaSqlExpr *having_cond; /* HAVING... */ + GSList *order_by; /* list of GdaSqlSelectOrder pointers */ + + GdaSqlExpr *limit_count; + GdaSqlExpr *limit_offset; + + /*< private >*/ + /* Padding for future expansion */ + gpointer _gda_reserved1; + gpointer _gda_reserved2; +}; + +/* + * Common operations + */ +gpointer _gda_sql_statement_select_copy (gpointer src); +void _gda_sql_statement_select_free (gpointer stmt); +gchar *_gda_sql_statement_select_serialize (gpointer stmt); +GdaSqlStatementContentsInfo *_gda_sql_statement_select_get_infos (void); + +/* + * Functions used by the parser + */ +void gda_sql_statement_select_take_distinct (GdaSqlStatement *stmt, gboolean distinct, GdaSqlExpr *distinct_expr); +void gda_sql_statement_select_take_expr_list (GdaSqlStatement *stmt, GSList *expr_list); +void gda_sql_statement_select_take_from (GdaSqlStatement *stmt, GdaSqlSelectFrom *from); +void gda_sql_statement_select_take_where_cond (GdaSqlStatement *stmt, GdaSqlExpr *expr); +void gda_sql_statement_select_take_group_by (GdaSqlStatement *stmt, GSList *group_by); +void gda_sql_statement_select_take_having_cond (GdaSqlStatement *stmt, GdaSqlExpr *expr); +void gda_sql_statement_select_take_order_by (GdaSqlStatement *stmt, GSList *order_by); +void gda_sql_statement_select_take_limits (GdaSqlStatement *stmt, GdaSqlExpr *count, GdaSqlExpr *offset); + +G_END_DECLS + +#endif diff --git a/.flatpak-builder/cache/objects/ac/22349d9fb25597bd1b95c0278437c84400f88aa32478b6eb3fdf14ad4b3837.dirtree b/.flatpak-builder/cache/objects/ac/22349d9fb25597bd1b95c0278437c84400f88aa32478b6eb3fdf14ad4b3837.dirtree new file mode 100644 index 0000000..90643f2 Binary files /dev/null and b/.flatpak-builder/cache/objects/ac/22349d9fb25597bd1b95c0278437c84400f88aa32478b6eb3fdf14ad4b3837.dirtree differ diff --git a/.flatpak-builder/cache/objects/ac/392ce43f6e99a844b4d47446b10faa582d7729f6dabfcc63c1b3cd36ce1350.dirtree b/.flatpak-builder/cache/objects/ac/392ce43f6e99a844b4d47446b10faa582d7729f6dabfcc63c1b3cd36ce1350.dirtree new file mode 100644 index 0000000..b16df5e Binary files /dev/null and b/.flatpak-builder/cache/objects/ac/392ce43f6e99a844b4d47446b10faa582d7729f6dabfcc63c1b3cd36ce1350.dirtree differ diff --git a/.flatpak-builder/cache/objects/ac/39678e5f4f80a6c3e6af9ddc3430d5c2a1e2ae96943a30b4800b532ebe4bb0.dirtree b/.flatpak-builder/cache/objects/ac/39678e5f4f80a6c3e6af9ddc3430d5c2a1e2ae96943a30b4800b532ebe4bb0.dirtree new file mode 100644 index 0000000..0d2b464 Binary files /dev/null and b/.flatpak-builder/cache/objects/ac/39678e5f4f80a6c3e6af9ddc3430d5c2a1e2ae96943a30b4800b532ebe4bb0.dirtree differ diff --git a/.flatpak-builder/cache/objects/ac/634bbb0cf7b54e7932eaced0e11fbfa01442c49bf032fac88380c245db2740.dirtree b/.flatpak-builder/cache/objects/ac/634bbb0cf7b54e7932eaced0e11fbfa01442c49bf032fac88380c245db2740.dirtree new file mode 100644 index 0000000..cad35d1 Binary files /dev/null and b/.flatpak-builder/cache/objects/ac/634bbb0cf7b54e7932eaced0e11fbfa01442c49bf032fac88380c245db2740.dirtree differ diff --git a/.flatpak-builder/cache/objects/ac/71496dcf19e2b27c1e670381fbebf420f1e2de996b55b6ef01da373f2dc1a2.file b/.flatpak-builder/cache/objects/ac/71496dcf19e2b27c1e670381fbebf420f1e2de996b55b6ef01da373f2dc1a2.file new file mode 100644 index 0000000..d3fb054 --- /dev/null +++ b/.flatpak-builder/cache/objects/ac/71496dcf19e2b27c1e670381fbebf420f1e2de996b55b6ef01da373f2dc1a2.file @@ -0,0 +1,135 @@ +/*** + This file is part of libcanberra. + + Copyright (C) 2009 Michael 'Mickey' Lauer + + libcanberra is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation, either version 2.1 of the + License, or (at your option) any later version. + + libcanberra is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with libcanberra. If not, see + . +***/ + +[CCode (cprefix = "CA_", lower_case_cprefix = "ca_", cheader_filename = "canberra.h")] +namespace Canberra { + + public const int MAJOR; + public const int MINOR; + + [CCode (cname="CA_CHECK_VERSION")] + public bool CHECK_VERSION(int major, int minor); + + public const string PROP_MEDIA_NAME; + public const string PROP_MEDIA_TITLE; + public const string PROP_MEDIA_ARTIST; + public const string PROP_MEDIA_LANGUAGE; + public const string PROP_MEDIA_FILENAME; + public const string PROP_MEDIA_ICON; + public const string PROP_MEDIA_ICON_NAME; + public const string PROP_MEDIA_ROLE; + public const string PROP_EVENT_ID; + public const string PROP_EVENT_DESCRIPTION; + public const string PROP_EVENT_MOUSE_X; + public const string PROP_EVENT_MOUSE_Y; + public const string PROP_EVENT_MOUSE_HPOS; + public const string PROP_EVENT_MOUSE_VPOS; + public const string PROP_EVENT_MOUSE_BUTTON; + public const string PROP_WINDOW_NAME; + public const string PROP_WINDOW_ID; + public const string PROP_WINDOW_ICON; + public const string PROP_WINDOW_ICON_NAME; + public const string PROP_WINDOW_X; + public const string PROP_WINDOW_Y; + public const string PROP_WINDOW_WIDTH; + public const string PROP_WINDOW_HEIGHT; + public const string PROP_WINDOW_HPOS; + public const string PROP_WINDOW_VPOS; + public const string PROP_WINDOW_DESKTOP; + public const string PROP_WINDOW_X11_DISPLAY; + public const string PROP_WINDOW_X11_SCREEN; + public const string PROP_WINDOW_X11_MONITOR; + public const string PROP_WINDOW_X11_XID; + public const string PROP_APPLICATION_NAME; + public const string PROP_APPLICATION_ID; + public const string PROP_APPLICATION_VERSION; + public const string PROP_APPLICATION_ICON; + public const string PROP_APPLICATION_ICON_NAME; + public const string PROP_APPLICATION_LANGUAGE; + public const string PROP_APPLICATION_PROCESS_ID; + public const string PROP_APPLICATION_PROCESS_BINARY; + public const string PROP_APPLICATION_PROCESS_USER; + public const string PROP_APPLICATION_PROCESS_HOST; + public const string PROP_CANBERRA_CACHE_CONTROL; + public const string PROP_CANBERRA_VOLUME; + public const string PROP_CANBERRA_XDG_THEME_NAME; + public const string PROP_CANBERRA_XDG_THEME_OUTPUT_PROFILE; + public const string PROP_CANBERRA_ENABLE; + public const string PROP_CANBERRA_FORCE_CHANNEL; + + [CCode (cname = "CA_SUCCESS")] + public const int SUCCESS; + + [CCode (cname = "int", cprefix = "CA_ERROR_")] + public enum Error { + NOTSUPPORTED, + INVALID, + STATE, + OOM, + NODRIVER, + SYSTEM, + CORRUPT, + TOOBIG, + NOTFOUND, + DESTROYED, + CANCELED, + NOTAVAILABLE, + ACCESS, + IO, + INTERNAL, + DISABLED, + FORKED, + DISCONNECTED, + + [CCode (cname = "_CA_ERROR_MAX")] + _MAX + } + + public unowned string? strerror(int code); + + public delegate void FinishCallback(Context c, uint32 id, int code); + + [Compact] + [CCode (cname = "ca_proplist", free_function = "ca_proplist_destroy")] + public class Proplist { + public static int create(out Proplist p); + public int sets(string key, string value); + [PrintfFormat] + public int setf(string key, string format, ...); + public int set(string key, void* data, size_t nbytes); + } + + [Compact] + [CCode (cname = "ca_context", free_function = "ca_context_destroy")] + public class Context { + public static int create(out Context context); + public int set_driver(string? driver = null); + public int change_device(string? device = null); + public int open(); + public int change_props(...); + public int change_props_full(Proplist p); + public int play_full(uint32 id, Proplist p, FinishCallback? cb = null); + public int play(uint32 id, ...); + public int cache_full(Proplist p); + public int cache(...); + public int cancel(uint32 id); + public int playing(uint32 id, out bool playing); + } +} diff --git a/.flatpak-builder/cache/objects/ac/a8373d70f47adc00338fb9ce7dbc2171cc3766bb1f1481adee28cf9de09dd5.dirtree b/.flatpak-builder/cache/objects/ac/a8373d70f47adc00338fb9ce7dbc2171cc3766bb1f1481adee28cf9de09dd5.dirtree new file mode 100644 index 0000000..c9bc029 Binary files /dev/null and b/.flatpak-builder/cache/objects/ac/a8373d70f47adc00338fb9ce7dbc2171cc3766bb1f1481adee28cf9de09dd5.dirtree differ diff --git a/.flatpak-builder/cache/objects/ac/ef6aa009fef5ed57e9d21222a3f6ba4d30a319caf267077895515f181cabd1.dirtree b/.flatpak-builder/cache/objects/ac/ef6aa009fef5ed57e9d21222a3f6ba4d30a319caf267077895515f181cabd1.dirtree new file mode 100644 index 0000000..a72415c Binary files /dev/null and b/.flatpak-builder/cache/objects/ac/ef6aa009fef5ed57e9d21222a3f6ba4d30a319caf267077895515f181cabd1.dirtree differ diff --git a/.flatpak-builder/cache/objects/ad/1e85435de6dabfb47bb70ab268b945cadfdc2b99db372b6aae45dea845c24d.file b/.flatpak-builder/cache/objects/ad/1e85435de6dabfb47bb70ab268b945cadfdc2b99db372b6aae45dea845c24d.file new file mode 100644 index 0000000..2008ffb --- /dev/null +++ b/.flatpak-builder/cache/objects/ad/1e85435de6dabfb47bb70ab268b945cadfdc2b99db372b6aae45dea845c24d.file @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2000 Reinhard Müller + * Copyright (C) 2000 - 2002 Rodrigo Moya + * Copyright (C) 2001 Carlos Perelló Marín + * Copyright (C) 2001 - 2012 Vivien Malerba + * Copyright (C) 2002 Gonzalo Paniagua Javier + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GDA_CONNECTION_SQLITE_H_ +#define __GDA_CONNECTION_SQLITE_H_ + +#include + +G_BEGIN_DECLS + +/* + * Opens a connection to an SQLite database. This function is intended to be used + * internally when objects require an SQLite connection, for example for the GdaMetaStore + * object + */ +GdaConnection *_gda_open_internal_sqlite_connection (const gchar *cnc_string); + +G_END_DECLS + +#endif diff --git a/.flatpak-builder/cache/objects/ad/5181209834c55c99b7c9dbe2c34da61daeb3907e7b35d85a688ee1727243e3.dirtree b/.flatpak-builder/cache/objects/ad/5181209834c55c99b7c9dbe2c34da61daeb3907e7b35d85a688ee1727243e3.dirtree new file mode 100644 index 0000000..6a9b6d1 Binary files /dev/null and b/.flatpak-builder/cache/objects/ad/5181209834c55c99b7c9dbe2c34da61daeb3907e7b35d85a688ee1727243e3.dirtree differ diff --git a/.flatpak-builder/cache/objects/ad/c99bdb941b259ec37a58f4281fbea3529f567fbba23256e402ddb57750869d.commit b/.flatpak-builder/cache/objects/ad/c99bdb941b259ec37a58f4281fbea3529f567fbba23256e402ddb57750869d.commit new file mode 100644 index 0000000..6df1607 Binary files /dev/null and b/.flatpak-builder/cache/objects/ad/c99bdb941b259ec37a58f4281fbea3529f567fbba23256e402ddb57750869d.commit differ diff --git a/.flatpak-builder/cache/objects/ad/fbe4e90ea29024785ef444d57f648b500e6692d2186f63f4ba63671bbd2e2c.dirtree b/.flatpak-builder/cache/objects/ad/fbe4e90ea29024785ef444d57f648b500e6692d2186f63f4ba63671bbd2e2c.dirtree new file mode 100644 index 0000000..8dfc575 Binary files /dev/null and b/.flatpak-builder/cache/objects/ad/fbe4e90ea29024785ef444d57f648b500e6692d2186f63f4ba63671bbd2e2c.dirtree differ diff --git a/.flatpak-builder/cache/objects/ae/60c1510722d8399573d59be8e5703a591bc67ba608b26695f09a72dc14ea75.dirtree b/.flatpak-builder/cache/objects/ae/60c1510722d8399573d59be8e5703a591bc67ba608b26695f09a72dc14ea75.dirtree new file mode 100644 index 0000000..a60b082 Binary files /dev/null and b/.flatpak-builder/cache/objects/ae/60c1510722d8399573d59be8e5703a591bc67ba608b26695f09a72dc14ea75.dirtree differ diff --git a/.flatpak-builder/cache/objects/ae/94d634c8af51591a621c9ede65e039a74ef6f4959dfbdfff5898b641c59ece.dirtree b/.flatpak-builder/cache/objects/ae/94d634c8af51591a621c9ede65e039a74ef6f4959dfbdfff5898b641c59ece.dirtree new file mode 100644 index 0000000..ea1a4b3 Binary files /dev/null and b/.flatpak-builder/cache/objects/ae/94d634c8af51591a621c9ede65e039a74ef6f4959dfbdfff5898b641c59ece.dirtree differ diff --git a/.flatpak-builder/cache/objects/ae/e8494f2713f29a1181bb68c9ae0b5891dcf69b6ae963b61397742ed51ce479.dirtree b/.flatpak-builder/cache/objects/ae/e8494f2713f29a1181bb68c9ae0b5891dcf69b6ae963b61397742ed51ce479.dirtree new file mode 100644 index 0000000..026680c Binary files /dev/null and b/.flatpak-builder/cache/objects/ae/e8494f2713f29a1181bb68c9ae0b5891dcf69b6ae963b61397742ed51ce479.dirtree differ diff --git a/.flatpak-builder/cache/objects/af/36236f6d5d1ad9a915f46f4edf907b9a09d77422c4a65f88520577d02bfb9a.file b/.flatpak-builder/cache/objects/af/36236f6d5d1ad9a915f46f4edf907b9a09d77422c4a65f88520577d02bfb9a.file new file mode 100644 index 0000000..686758c --- /dev/null +++ b/.flatpak-builder/cache/objects/af/36236f6d5d1ad9a915f46f4edf907b9a09d77422c4a65f88520577d02bfb9a.file @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2018 Pavlo Solntsev + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GDA_DB_TABLE_H__ +#define __GDA_DB_TABLE_H__ + +#include "gda-db-base.h" +#include "gda-db-column.h" +#include "gda-db-fkey.h" +#include +#include +#include "gda-server-operation.h" +#include +#include "gda-meta-struct.h" +#include "gda-db-index.h" + +G_BEGIN_DECLS + +#define GDA_TYPE_DB_TABLE (gda_db_table_get_type()) + +G_DECLARE_DERIVABLE_TYPE(GdaDbTable, gda_db_table, GDA, DB_TABLE, GdaDbBase) + +struct _GdaDbTableClass { + GdaDbBaseClass parent_class; +}; + +/** + * GdaDbTableError: + * @GDA_DB_TABLE_COLUMN_EMPTY: Table doesn't contain columns + * @GDA_DB_TABLE_CONNECTION_NOT_OPENED: Closed connection was passed as parameter + * @GDA_DB_TABLE_SERVER_OPERATION: Error related to #GdaServerOperation + */ +typedef enum { + GDA_DB_TABLE_COLUMN_EMPTY, + GDA_DB_TABLE_CONNECTION_NOT_OPENED, + GDA_DB_TABLE_SERVER_OPERATION +} GdaDbTableError; + +#define GDA_DB_TABLE_ERROR gda_db_table_error_quark() +GQuark gda_db_table_error_quark(void); + +GdaDbTable* gda_db_table_new (void); +gboolean gda_db_table_is_valid (GdaDbTable *self); +GList* gda_db_table_get_columns (GdaDbTable *self); +GList* gda_db_table_get_fkeys (GdaDbTable *self); + +void gda_db_table_append_column (GdaDbTable *self, + GdaDbColumn *column); + +gboolean gda_db_table_get_is_temp (GdaDbTable *self); +void gda_db_table_set_is_temp (GdaDbTable *self, + gboolean istemp); + +gboolean gda_db_table_prepare_create (GdaDbTable *self, + GdaServerOperation *op, + gboolean ifnotexists, + GError **error); + +gboolean gda_db_table_update (GdaDbTable *self, + GdaMetaTable *obj, + GdaConnection *cnc, + GError **error); + +void gda_db_table_append_fkey (GdaDbTable *self, + GdaDbFkey *fkey); + +void gda_db_table_append_constraint (GdaDbTable *self, + const gchar *constr); + +G_END_DECLS + +#endif /* end of include guard: GDA-DB-TABLE_H */ + + diff --git a/.flatpak-builder/cache/objects/af/3f51ad4c3571efdd179086afb2cc1ee736da19bcab28deeaa3c9fdb351941e.file b/.flatpak-builder/cache/objects/af/3f51ad4c3571efdd179086afb2cc1ee736da19bcab28deeaa3c9fdb351941e.file new file mode 100644 index 0000000..b24a6dd --- /dev/null +++ b/.flatpak-builder/cache/objects/af/3f51ad4c3571efdd179086afb2cc1ee736da19bcab28deeaa3c9fdb351941e.file @@ -0,0 +1,77 @@ +/*-*- Mode: C; c-basic-offset: 8 -*-*/ + +#ifndef foocanberrareadsoundfilehfoo +#define foocanberrareadsoundfilehfoo + +/*** + This file is part of libcanberra. + + Copyright 2008 Lennart Poettering + + libcanberra is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation, either version 2.1 of the + License, or (at your option) any later version. + + libcanberra is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with libcanberra. If not, see + . +***/ + +#include +#include + +typedef enum ca_sample_type { + CA_SAMPLE_S16NE, + CA_SAMPLE_S16RE, + CA_SAMPLE_U8 +} ca_sample_type_t; + +typedef enum ca_channel_position { + CA_CHANNEL_MONO, + CA_CHANNEL_FRONT_LEFT, + CA_CHANNEL_FRONT_RIGHT, + CA_CHANNEL_FRONT_CENTER, + CA_CHANNEL_REAR_LEFT, + CA_CHANNEL_REAR_RIGHT, + CA_CHANNEL_REAR_CENTER, + CA_CHANNEL_LFE, + CA_CHANNEL_FRONT_LEFT_OF_CENTER, + CA_CHANNEL_FRONT_RIGHT_OF_CENTER, + CA_CHANNEL_SIDE_LEFT, + CA_CHANNEL_SIDE_RIGHT, + CA_CHANNEL_TOP_CENTER, + CA_CHANNEL_TOP_FRONT_LEFT, + CA_CHANNEL_TOP_FRONT_RIGHT, + CA_CHANNEL_TOP_FRONT_CENTER, + CA_CHANNEL_TOP_REAR_LEFT, + CA_CHANNEL_TOP_REAR_RIGHT, + CA_CHANNEL_TOP_REAR_CENTER, + _CA_CHANNEL_POSITION_MAX +} ca_channel_position_t; + +typedef struct ca_sound_file ca_sound_file; + +int ca_sound_file_open(ca_sound_file **f, const char *fn); +void ca_sound_file_close(ca_sound_file *f); + +unsigned ca_sound_file_get_nchannels(ca_sound_file *f); +unsigned ca_sound_file_get_rate(ca_sound_file *f); +ca_sample_type_t ca_sound_file_get_sample_type(ca_sound_file *f); +const ca_channel_position_t* ca_sound_file_get_channel_map(ca_sound_file *f); + +off_t ca_sound_file_get_size(ca_sound_file *f); + +int ca_sound_file_read_int16(ca_sound_file *f, int16_t *d, size_t *n); +int ca_sound_file_read_uint8(ca_sound_file *f, uint8_t *d, size_t *n); + +int ca_sound_file_read_arbitrary(ca_sound_file *f, void *d, size_t *n); + +size_t ca_sound_file_frame_size(ca_sound_file *f); + +#endif diff --git a/.flatpak-builder/cache/objects/af/b51d692bfc9aec86824036690b91d10d380b62319b7438018e6e7d64da1a59.file b/.flatpak-builder/cache/objects/af/b51d692bfc9aec86824036690b91d10d380b62319b7438018e6e7d64da1a59.file new file mode 100644 index 0000000..1700361 Binary files /dev/null and b/.flatpak-builder/cache/objects/af/b51d692bfc9aec86824036690b91d10d380b62319b7438018e6e7d64da1a59.file differ diff --git a/.flatpak-builder/cache/objects/b0/07f85d1935bf24655780d70117123b44078fc921770ad8384a6dc16d47a1f5.file b/.flatpak-builder/cache/objects/b0/07f85d1935bf24655780d70117123b44078fc921770ad8384a6dc16d47a1f5.file new file mode 120000 index 0000000..ae42002 --- /dev/null +++ b/.flatpak-builder/cache/objects/b0/07f85d1935bf24655780d70117123b44078fc921770ad8384a6dc16d47a1f5.file @@ -0,0 +1 @@ +libgsound.so.0 \ No newline at end of file diff --git a/.flatpak-builder/cache/objects/b0/bb8a2e495b73969b5fc263a065405047dc579560b4322ac302028ccc9a2f1e.dirtree b/.flatpak-builder/cache/objects/b0/bb8a2e495b73969b5fc263a065405047dc579560b4322ac302028ccc9a2f1e.dirtree new file mode 100644 index 0000000..fffde00 Binary files /dev/null and b/.flatpak-builder/cache/objects/b0/bb8a2e495b73969b5fc263a065405047dc579560b4322ac302028ccc9a2f1e.dirtree differ diff --git a/.flatpak-builder/cache/objects/b0/eb2fc6f0d12d1feb8ad88aac128950ff9888d3a69d866d9fe3218e03d5978e.file b/.flatpak-builder/cache/objects/b0/eb2fc6f0d12d1feb8ad88aac128950ff9888d3a69d866d9fe3218e03d5978e.file new file mode 100644 index 0000000..0143706 Binary files /dev/null and b/.flatpak-builder/cache/objects/b0/eb2fc6f0d12d1feb8ad88aac128950ff9888d3a69d866d9fe3218e03d5978e.file differ diff --git a/.flatpak-builder/cache/objects/b1/45c109ba385863ea4a3883049db805adf9c01f37fe3fa2c2c46df7776f7cbb.file b/.flatpak-builder/cache/objects/b1/45c109ba385863ea4a3883049db805adf9c01f37fe3fa2c2c46df7776f7cbb.file new file mode 100644 index 0000000..d6f6c26 --- /dev/null +++ b/.flatpak-builder/cache/objects/b1/45c109ba385863ea4a3883049db805adf9c01f37fe3fa2c2c46df7776f7cbb.file @@ -0,0 +1,266 @@ +.synopsis, .classsynopsis +{ + /* tango:aluminium 1/2 */ + background: #eeeeec; + border: solid 1px #d3d7cf; + padding: 0.5em; +} +.programlisting +{ + /* tango:sky blue 0/1 */ + background: #e6f3ff; + border: solid 1px #729fcf; + padding: 0.5em; +} +.variablelist +{ + padding: 4px; + margin-left: 3em; +} +.variablelist td:first-child +{ + vertical-align: top; +} + +@media screen { + sup a.footnote + { + position: relative; + top: 0em ! important; + + } + /* this is needed so that the local anchors are displayed below the naviagtion */ + div.footnote a[name], div.refnamediv a[name], div.refsect1 a[name], div.refsect2 a[name], div.index a[name], div.glossary a[name], div.sect1 a[name] + { + display: inline-block; + position: relative; + top:-5em; + } + /* this seems to be a bug in the xsl style sheets when generating indexes */ + div.index div.index + { + top: 0em; + } + /* make space for the fixed navigation bar and add space at the bottom so that + * link targets appear somewhat close to top + */ + body + { + padding-top: 3.2em; + padding-bottom: 20em; + } + /* style and size the navigation bar */ + table.navigation#top + { + position: fixed; + /* tango:scarlet red 0/1 */ + background: #ffe6e6; + border: solid 1px #ef2929; + margin-top: 0; + margin-bottom: 0; + top: 0; + left: 0; + height: 3em; + z-index: 10; + } + .navigation a, .navigation a:visited + { + /* tango:scarlet red 3 */ + color: #a40000; + } + .navigation a:hover + { + /* tango:scarlet red 1 */ + color: #ef2929; + } + td.shortcuts + { + /* tango:scarlet red 1 */ + color: #ef2929; + font-size: 80%; + white-space: nowrap; + } +} +@media print { + table.navigation { + visibility: collapse; + display: none; + } + div.titlepage table.navigation { + visibility: visible; + display: table; + /* tango:scarlet red 0/1 */ + background: #ffe6e6; + border: solid 1px #ef2929; + margin-top: 0; + margin-bottom: 0; + top: 0; + left: 0; + height: 3em; + } +} + +.navigation .title +{ + font-size: 200%; +} + +div.gallery-float +{ + float: left; + padding: 10px; +} +div.gallery-float img +{ + border-style: none; +} +div.gallery-spacer +{ + clear: both; +} + +a, a:visited +{ + text-decoration: none; + /* tango:sky blue 2 */ + color: #3465a4; +} +a:hover +{ + text-decoration: underline; + /* tango:sky blue 1 */ + color: #729fcf; +} + +div.table table +{ + border-collapse: collapse; + border-spacing: 0px; + /* tango:aluminium 3 */ + border: solid 1px #babdb6; +} + +div.table table td, div.table table th +{ + /* tango:aluminium 3 */ + border: solid 1px #babdb6; + padding: 3px; + vertical-align: top; +} + +div.table table th +{ + /* tango:aluminium 2 */ + background-color: #d3d7cf; +} + +hr +{ + /* tango:aluminium 3 */ + color: #babdb6; + background: #babdb6; + border: none 0px; + height: 1px; + clear: both; +} + +.footer +{ + padding-top: 3.5em; + /* tango:aluminium 3 */ + color: #babdb6; + text-align: center; + font-size: 80%; +} + +.warning +{ + /* tango:orange 0/1 */ + background: #ffeed9; + border-color: #ffb04f; +} +.note +{ + /* tango:chameleon 0/0.5 */ + background: #d8ffb2; + border-color: #abf562; +} +.note, .warning +{ + padding: 0.5em; + border-width: 1px; + border-style: solid; +} +.note h3, .warning h3 +{ + margin-top: 0.0em +} +.note p, .warning p +{ + margin-bottom: 0.0em +} + +/* blob links */ +h2 .extralinks, h3 .extralinks +{ + float: right; + /* tango:aluminium 3 */ + color: #babdb6; + font-size: 80%; + font-weight: normal; +} + +.annotation +{ + /* tango:aluminium 5 */ + color: #555753; + font-size: 80%; + font-weight: normal; +} + +/* code listings */ + +.listing_code .programlisting .cbracket { color: #a40000; } /* tango: scarlet red 3 */ +.listing_code .programlisting .comment { color: #a1a39d; } /* tango: aluminium 4 */ +.listing_code .programlisting .function { color: #000000; font-weight: bold; } +.listing_code .programlisting .function a { color: #11326b; font-weight: bold; } /* tango: sky blue 4 */ +.listing_code .programlisting .keyword { color: #4e9a06; } /* tango: chameleon 3 */ +.listing_code .programlisting .linenum { color: #babdb6; } /* tango: aluminium 3 */ +.listing_code .programlisting .normal { color: #000000; } +.listing_code .programlisting .number { color: #75507b; } /* tango: plum 2 */ +.listing_code .programlisting .preproc { color: #204a87; } /* tango: sky blue 3 */ +.listing_code .programlisting .string { color: #c17d11; } /* tango: chocolate 2 */ +.listing_code .programlisting .type { color: #000000; } +.listing_code .programlisting .type a { color: #11326b; } /* tango: sky blue 4 */ +.listing_code .programlisting .symbol { color: #ce5c00; } /* tango: orange 3 */ + +.listing_frame { + /* tango:sky blue 1 */ + border: solid 1px #729fcf; + padding: 0px; +} + +.listing_lines, .listing_code { + margin-top: 0px; + margin-bottom: 0px; + padding: 0.5em; +} +.listing_lines { + /* tango:sky blue 0.5 */ + background: #a6c5e3; + /* tango:aluminium 6 */ + color: #2e3436; +} +.listing_code { + /* tango:sky blue 0 */ + background: #e6f3ff; +} +.listing_code .programlisting { + /* override from previous */ + border: none 0px; + padding: 0px; +} +.listing_lines pre, .listing_code pre { + margin: 0px; +} + diff --git a/.flatpak-builder/cache/objects/b1/945a69c6a318db5a47043942f34e47450ce69f8e868c3f4c6463604ef4fed2.dirtree b/.flatpak-builder/cache/objects/b1/945a69c6a318db5a47043942f34e47450ce69f8e868c3f4c6463604ef4fed2.dirtree new file mode 100644 index 0000000..35686c0 Binary files /dev/null and b/.flatpak-builder/cache/objects/b1/945a69c6a318db5a47043942f34e47450ce69f8e868c3f4c6463604ef4fed2.dirtree differ diff --git a/.flatpak-builder/cache/objects/b1/d4ed77bcefa9617ae1071b8f289ecefc3ac5b62ac378940f016846ff7c0169.dirtree b/.flatpak-builder/cache/objects/b1/d4ed77bcefa9617ae1071b8f289ecefc3ac5b62ac378940f016846ff7c0169.dirtree new file mode 100644 index 0000000..ac10357 Binary files /dev/null and b/.flatpak-builder/cache/objects/b1/d4ed77bcefa9617ae1071b8f289ecefc3ac5b62ac378940f016846ff7c0169.dirtree differ diff --git a/.flatpak-builder/cache/objects/b1/e576fe724ba82f3f577d5234183353e28abae47e45a76873b96cee045ac2d5.dirtree b/.flatpak-builder/cache/objects/b1/e576fe724ba82f3f577d5234183353e28abae47e45a76873b96cee045ac2d5.dirtree new file mode 100644 index 0000000..1d2ebc1 Binary files /dev/null and b/.flatpak-builder/cache/objects/b1/e576fe724ba82f3f577d5234183353e28abae47e45a76873b96cee045ac2d5.dirtree differ diff --git a/.flatpak-builder/cache/objects/b1/ede3c310ab54abdb3911e1b8166fe6fa9c2a44994a313387bc38d122231325.dirtree b/.flatpak-builder/cache/objects/b1/ede3c310ab54abdb3911e1b8166fe6fa9c2a44994a313387bc38d122231325.dirtree new file mode 100644 index 0000000..664240a Binary files /dev/null and b/.flatpak-builder/cache/objects/b1/ede3c310ab54abdb3911e1b8166fe6fa9c2a44994a313387bc38d122231325.dirtree differ diff --git a/.flatpak-builder/cache/objects/b2/0d81d9ff9aa0452df4762a65aa128271787185e4e7dac725340c2dc9a1bc0a.file b/.flatpak-builder/cache/objects/b2/0d81d9ff9aa0452df4762a65aa128271787185e4e7dac725340c2dc9a1bc0a.file new file mode 100644 index 0000000..88a5950 Binary files /dev/null and b/.flatpak-builder/cache/objects/b2/0d81d9ff9aa0452df4762a65aa128271787185e4e7dac725340c2dc9a1bc0a.file differ diff --git a/.flatpak-builder/cache/objects/b2/c93f93a55d3ba16a7970fec8bf461da8cff098647bcd27f7327e416d5b1c43.file b/.flatpak-builder/cache/objects/b2/c93f93a55d3ba16a7970fec8bf461da8cff098647bcd27f7327e416d5b1c43.file new file mode 100644 index 0000000..baf29d2 --- /dev/null +++ b/.flatpak-builder/cache/objects/b2/c93f93a55d3ba16a7970fec8bf461da8cff098647bcd27f7327e416d5b1c43.file @@ -0,0 +1,498 @@ +/* + * Copyright (C) 2001 - 2004 Rodrigo Moya + * Copyright (C) 2002 - 2003 Gonzalo Paniagua Javier + * Copyright (C) 2004 - 2005 Alan Knowles + * Copyright (C) 2005 Bas Driessen + * Copyright (C) 2005 - 2014 Vivien Malerba + * Copyright (C) 2006 - 2008 Murray Cumming + * Copyright (C) 2007 Armin Burgmeier + * Copyright (C) 2013 Daniel Espinosa + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GDA_SERVER_PROVIDER_IMPL_H__ +#define __GDA_SERVER_PROVIDER_IMPL_H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +G_BEGIN_DECLS + +/** + * GdaServerProviderFunctionsType: + * + * Represents the different types of sets of virtual functions which can be implemented for each provider + */ +typedef enum { + GDA_SERVER_PROVIDER_FUNCTIONS_BASE, + GDA_SERVER_PROVIDER_FUNCTIONS_META, + GDA_SERVER_PROVIDER_FUNCTIONS_XA, + + GDA_SERVER_PROVIDER_FUNCTIONS_MAX +} GdaServerProviderFunctionsType; + + +/* + * May only be called once for each value of @type */ +void gda_server_provider_set_impl_functions (GdaServerProviderClass *klass, + GdaServerProviderFunctionsType type, gpointer functions_set); +gpointer gda_server_provider_get_impl_functions_for_class (GObjectClass *klass, GdaServerProviderFunctionsType type); + +/** + * GdaServerProviderBase: + * @get_name: + * @get_version: + * + * Functions implementing basic features. + * + * A pointer to this structure is returned by _gda_server_provider_get_impl_functions() when requesting + * @GDA_SERVER_PROVIDER_FUNCTIONS_BASE functions. + */ +typedef struct { + /* functions called from any thread */ + const gchar *(* get_name) (GdaServerProvider *provider); + const gchar *(* get_version) (GdaServerProvider *provider); + const gchar *(* get_server_version) (GdaServerProvider *provider, GdaConnection *cnc); + gboolean (* supports_feature) (GdaServerProvider *provider, GdaConnection *cnc, + GdaConnectionFeature feature); + GdaWorker *(* create_worker) (GdaServerProvider *provider, gboolean for_cnc); + GdaConnection *(* create_connection) (GdaServerProvider *provider); /* may be NULL */ + GdaSqlParser *(* create_parser) (GdaServerProvider *provider, GdaConnection *cnc); /* may be NULL */ + GdaDataHandler *(* get_data_handler) (GdaServerProvider *provider, GdaConnection *cnc, /* may be NULL */ + GType g_type, const gchar *dbms_type); + const gchar *(* get_def_dbms_type) (GdaServerProvider *provider, GdaConnection *cnc, GType g_type); /* may be NULL */ + gboolean (* supports_operation) (GdaServerProvider *provider, GdaConnection *cnc, + GdaServerOperationType type, GdaSet *options); + GdaServerOperation *(* create_operation) (GdaServerProvider *provider, GdaConnection *cnc, + GdaServerOperationType type, GdaSet *options, GError **error); + gchar *(* render_operation) (GdaServerProvider *provider, GdaConnection *cnc, + GdaServerOperation *op, GError **error); + /** + * statement_to_sql: + * @provider: a #GdaServerProvider + * @cnc: a #GdaConnection + * @stmt: a #GdaStatement + * @params: (nullable): a #GdaSet object (which can be obtained using gda_statement_get_parameters()), or %NULL + * @flags: SQL rendering flags, as #GdaStatementSqlFlag OR'ed values + * @params_used: (nullable) (element-type Gda.Holder) (out) (transfer container): a place to store the list of individual #GdaHolder objects within @params which have been used + * @error: a place to store errors, or %NULL + * + * Renders @stmt as an SQL statement, adapted to the SQL dialect used by @cnc + * + * Returns: a new string, or %NULL if an error occurred + */ + gchar *(* statement_to_sql) (GdaServerProvider *provider, GdaConnection *cnc, + GdaStatement *stmt, GdaSet *params, GdaStatementSqlFlag flags, + GSList **params_used, GError **error); + /** + * identifier_quote: + * @provider: a #GdaServerProvider + * @cnc: (nullable): a #GdaConnection, or %NULL + * @id: a string + * @for_meta_store: if %TRUE, then the result have to respect the #GdaMetaStore convention + * @force_quotes: if %TRUE, then quotes have to be added + * + * Create a new string in which @id can be used in an SQL statement, for example by adding quotes if + * it is a reserved keyword, or if it is case sensitive. + * + * If not %NULL, @cnc can either be opened or closed. + * + * Returns: (transfer full): a new string + */ + gchar *(* identifier_quote) (GdaServerProvider *provider, GdaConnection *cnc, /* may be NULL */ + const gchar *id, + gboolean for_meta_store, gboolean force_quotes); + + GdaSqlStatement *(* statement_rewrite) (GdaServerProvider *provider, GdaConnection *cnc, + GdaStatement *stmt, GdaSet *params, GError **error); + /** + * open_connection: + * @provider: a #GdaServerProvider + * @cnc: a #GdaConnection + * @params: (transfer none): a #GdaQuarkList containing the connection parameters (HOST, DATABASE, etc.) + * @auth: (transfer none) (nullable): a #GdaQuarkList containing the connection authentification parameters (USERNAME, PASSWORD, etc.), or %NULL + * + * Open the connection. @params and @auth must be left unchanged. + * + * Returns: %TRUE if the connection was opened. + */ + gboolean (* open_connection) (GdaServerProvider *provider, GdaConnection *cnc, + GdaQuarkList *params, GdaQuarkList *auth); + gboolean (* prepare_connection) (GdaServerProvider *provider, GdaConnection *cnc, + GdaQuarkList *params, GdaQuarkList *auth); + gboolean (* close_connection) (GdaServerProvider *provider, GdaConnection *cnc); + gchar *(* escape_string) (GdaServerProvider *provider, GdaConnection *cnc, const gchar *str); /* may be NULL */ + gchar *(* unescape_string) (GdaServerProvider *provider, GdaConnection *cnc, const gchar *str); /* may be NULL */ + gboolean (* perform_operation) (GdaServerProvider *provider, GdaConnection *cnc, /* may be NULL */ + GdaServerOperation *op, GError **error); + gboolean (* begin_transaction) (GdaServerProvider *provider, GdaConnection *cnc, + const gchar *name, GdaTransactionIsolation level, GError **error); + gboolean (* commit_transaction) (GdaServerProvider *provider, GdaConnection *cnc, + const gchar *name, GError **error); + gboolean (* rollback_transaction) (GdaServerProvider *provider, GdaConnection *cnc, + const gchar *name, GError **error); + gboolean (* add_savepoint) (GdaServerProvider *provider, GdaConnection *cnc, + const gchar *name, GError **error); + gboolean (* rollback_savepoint) (GdaServerProvider *provider, GdaConnection *cnc, + const gchar *name, GError **error); + gboolean (* delete_savepoint) (GdaServerProvider *provider, GdaConnection *cnc, + const gchar *name, GError **error); + gboolean (* statement_prepare) (GdaServerProvider *provider, GdaConnection *cnc, + GdaStatement *stmt, GError **error); + GObject *(* statement_execute) (GdaServerProvider *provider, GdaConnection *cnc, + GdaStatement *stmt, GdaSet *params, + GdaStatementModelUsage model_usage, + GType *col_types, GdaSet **last_inserted_row, GError **error); + + /*< private >*/ + /* Padding for future expansion */ + void (*_gda_reserved11) (void); + void (*_gda_reserved12) (void); + void (*_gda_reserved13) (void); + void (*_gda_reserved14) (void); +} GdaServerProviderBase; + + +/** + * GdaServerProviderMeta: + * @_info: information_schema_catalog_name + * @_btypes: builtin_data_types + * @_udt: user defined types + * @udt: user defined types + * @_udt_cols: user defined types columns + * @udt_cols: user defined columns + * @_enums: enumerations + * @enums: enumerations + * @_domains: domains + * @domains: domains + * @_constraints_dom: domain's constraints + * @constraints_dom: domain's constraints + * @_el_types: element_types + * @el_types: element_types + * @_collations: collations + * @collations: collations + * @_character_sets: character_sets + * @character_sets: character_sets + * @_schemata: schemata + * @schemata: schemata + * @_tables_views: table views + * @tables_views: table views + * @_columns: columns + * @columns: columns + * @_view_cols: view's columns + * @view_cols: view's columns + * @_constraints_tab: table's constrainsts + * @constraints_tab: table's constrainsts + * @_constraints_ref: table's constrainsts reference + * @constraints_ref: table's constrainsts reference + * @_key_columns: table's key columns + * @key_columns: table's key columns + * @_check_columns: table's check columns + * @check_columns: table's check columns + * @_triggers: table's triggers + * @triggers: table's triggers + * @_routines: database's routines + * @routines: database's routines + * @_routine_col: database's routine's columns + * @routine_col: database's routine's columns + * @_routine_par: database's routine's parameters + * @routine_par: database's routine's parameters + * @_indexes_tab: table's indexes + * @indexes_tab: table's indexes + * @_index_cols: index column usage + * @index_cols: index column usage + * + * These methods must be implemented by providers to update a connection's associated metadata (in a + * #GdaMetaStore object), see the Virtual methods for providers/Methods - metadata + * for more information. + */ +typedef struct { + /* _information_schema_catalog_name */ + gboolean (*_info) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta, GdaMetaContext *ctx, GError **error); + + /* _builtin_data_types */ + gboolean (*_btypes) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta, GdaMetaContext *ctx, GError **error); + + /* _udt */ + gboolean (*_udt) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta, GdaMetaContext *ctx, GError **error); + gboolean (*udt) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta, GdaMetaContext *ctx, GError **error, + const GValue *udt_catalog, const GValue *udt_schema); + + /* _udt_columns */ + gboolean (*_udt_cols) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta, GdaMetaContext *ctx, GError **error); + gboolean (*udt_cols) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta, GdaMetaContext *ctx, GError **error, + const GValue *udt_catalog, const GValue *udt_schema, const GValue *udt_name); + + /* _enums */ + gboolean (*_enums) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta, GdaMetaContext *ctx, GError **error); + gboolean (*enums) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta, GdaMetaContext *ctx, GError **error, + const GValue *udt_catalog, const GValue *udt_schema, const GValue *udt_name); + + /* _domains */ + gboolean (*_domains) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta, GdaMetaContext *ctx, GError **error); + gboolean (*domains) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta, GdaMetaContext *ctx, GError **error, + const GValue *domain_catalog, const GValue *domain_schema); + + /* _domain_constraints */ + gboolean (*_constraints_dom) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta, GdaMetaContext *ctx, GError **error); + gboolean (*constraints_dom) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta, GdaMetaContext *ctx, GError **error, + const GValue *domain_catalog, const GValue *domain_schema, const GValue *domain_name); + + /* _element_types */ + gboolean (*_el_types) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta, GdaMetaContext *ctx, GError **error); + gboolean (*el_types) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta, GdaMetaContext *ctx, GError **error, + const GValue *specific_name); + + /* _collations */ + gboolean (*_collations) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta, GdaMetaContext *ctx, GError **error); + gboolean (*collations) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta, GdaMetaContext *ctx, GError **error, + const GValue *collation_catalog, const GValue *collation_schema, + const GValue *collation_name_n); + + /* _character_sets */ + gboolean (*_character_sets) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta, GdaMetaContext *ctx, GError **error); + gboolean (*character_sets) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta, GdaMetaContext *ctx, GError **error, + const GValue *chset_catalog, const GValue *chset_schema, const GValue *chset_name_n); + + /* _schemata */ + gboolean (*_schemata) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta, GdaMetaContext *ctx, GError **error); + gboolean (*schemata) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta, GdaMetaContext *ctx, GError **error, + const GValue *catalog_name, const GValue *schema_name_n); + + /* _tables or _views */ + gboolean (*_tables_views) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta, GdaMetaContext *ctx, GError **error); + gboolean (*tables_views) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta, GdaMetaContext *ctx, GError **error, + const GValue *table_catalog, const GValue *table_schema, const GValue *table_name_n); + + /* _columns */ + gboolean (*_columns) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta, GdaMetaContext *ctx, GError **error); + gboolean (*columns) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta, GdaMetaContext *ctx, GError **error, + const GValue *table_catalog, const GValue *table_schema, const GValue *table_name); + + /* _view_column_usage */ + gboolean (*_view_cols) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta, GdaMetaContext *ctx, GError **error); + gboolean (*view_cols) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta, GdaMetaContext *ctx, GError **error, + const GValue *view_catalog, const GValue *view_schema, const GValue *view_name); + + /* _table_constraints */ + gboolean (*_constraints_tab) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta, GdaMetaContext *ctx, GError **error); + gboolean (*constraints_tab) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta, GdaMetaContext *ctx, GError **error, + const GValue *table_catalog, const GValue *table_schema, const GValue *table_name, + const GValue *constraint_name_n); + + /* _referential_constraints */ + gboolean (*_constraints_ref) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta, GdaMetaContext *ctx, GError **error); + gboolean (*constraints_ref) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta, GdaMetaContext *ctx, GError **error, + const GValue *table_catalog, const GValue *table_schema, const GValue *table_name, + const GValue *constraint_name); + + /* _key_column_usage */ + gboolean (*_key_columns) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta, GdaMetaContext *ctx, GError **error); + gboolean (*key_columns) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta, GdaMetaContext *ctx, GError **error, + const GValue *table_catalog, const GValue *table_schema, const GValue *table_name, + const GValue *constraint_name); + + /* _check_column_usage */ + gboolean (*_check_columns) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta, GdaMetaContext *ctx, GError **error); + gboolean (*check_columns) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta, GdaMetaContext *ctx, GError **error, + const GValue *table_catalog, const GValue *table_schema, const GValue *table_name, + const GValue *constraint_name); + + /* _triggers */ + gboolean (*_triggers) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta, GdaMetaContext *ctx, GError **error); + gboolean (*triggers) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta, GdaMetaContext *ctx, GError **error, + const GValue *table_catalog, const GValue *table_schema, const GValue *table_name); + + /* _routines */ + gboolean (*_routines) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta, GdaMetaContext *ctx, GError **error); + gboolean (*routines) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta, GdaMetaContext *ctx, GError **error, + const GValue *routine_catalog, const GValue *routine_schema, + const GValue *routine_name_n); + + /* _routine_columns */ + gboolean (*_routine_col) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta, GdaMetaContext *ctx, GError **error); + gboolean (*routine_col) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta, GdaMetaContext *ctx, GError **error, + const GValue *rout_catalog, const GValue *rout_schema, const GValue *rout_name, const GValue *col_name, const GValue *ordinal_position); + + /* _parameters */ + gboolean (*_routine_par) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta, GdaMetaContext *ctx, GError **error); + gboolean (*routine_par) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta, GdaMetaContext *ctx, GError **error, + const GValue *rout_catalog, const GValue *rout_schema, const GValue *rout_name); + /* _table_indexes */ + gboolean (*_indexes_tab) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta, GdaMetaContext *ctx, GError **error); + gboolean (*indexes_tab) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta, GdaMetaContext *ctx, GError **error, + const GValue *table_catalog, const GValue *table_schema, const GValue *table_name, + const GValue *index_name_n); + + /* _index_column_usage */ + gboolean (*_index_cols) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta, GdaMetaContext *ctx, GError **error); + gboolean (*index_cols) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta, GdaMetaContext *ctx, GError **error, + const GValue *table_catalog, const GValue *table_schema, const GValue *table_name, const GValue *index_name); + + /*< private >*/ + /* Padding for future expansion */ + void (*_gda_reserved1) (void); + void (*_gda_reserved2) (void); + void (*_gda_reserved3) (void); + void (*_gda_reserved4) (void); + void (*_gda_reserved5) (void); + void (*_gda_reserved6) (void); + void (*_gda_reserved7) (void); + void (*_gda_reserved8) (void); + void (*_gda_reserved9) (void); + void (*_gda_reserved10) (void); + void (*_gda_reserved11) (void); + void (*_gda_reserved12) (void); +} GdaServerProviderMeta; + +typedef enum { + /* _information_schema_catalog_name */ + GDA_SERVER_META__INFO = 0, + + /* _builtin_data_types */ + GDA_SERVER_META__BTYPES = 1, + + /* _udt */ + GDA_SERVER_META__UDT = 2, + GDA_SERVER_META_UDT = 3, + + /* _udt_columns */ + GDA_SERVER_META__UDT_COLS = 4, + GDA_SERVER_META_UDT_COLS = 5, + + /* _enums */ + GDA_SERVER_META__ENUMS = 6, + GDA_SERVER_META_ENUMS = 7, + + /* _domains */ + GDA_SERVER_META__DOMAINS = 8, + GDA_SERVER_META_DOMAINS = 9, + + /* _domain_constraints */ + GDA_SERVER_META__CONSTRAINTS_DOM = 10, + GDA_SERVER_META_CONSTRAINTS_DOM = 11, + + /* _element_types */ + GDA_SERVER_META__EL_TYPES = 12, + GDA_SERVER_META_EL_TYPES = 13, + + /* _collations */ + GDA_SERVER_META__COLLATIONS = 14, + GDA_SERVER_META_COLLATIONS = 15, + + /* _character_sets */ + GDA_SERVER_META__CHARACTER_SETS = 16, + GDA_SERVER_META_CHARACTER_SETS = 17, + + /* _schemata */ + GDA_SERVER_META__SCHEMATA = 18, + GDA_SERVER_META_SCHEMATA = 19, + + /* _tables or _views */ + GDA_SERVER_META__TABLES_VIEWS = 20, + GDA_SERVER_META_TABLES_VIEWS = 21, + + /* _columns */ + GDA_SERVER_META__COLUMNS = 22, + GDA_SERVER_META_COLUMNS = 23, + + /* _view_column_usage */ + GDA_SERVER_META__VIEW_COLS = 24, + GDA_SERVER_META_VIEW_COLS = 25, + + /* _table_constraints */ + GDA_SERVER_META__CONSTRAINTS_TAB = 26, + GDA_SERVER_META_CONSTRAINTS_TAB = 27, + + /* _referential_constraints */ + GDA_SERVER_META__CONSTRAINTS_REF = 28, + GDA_SERVER_META_CONSTRAINTS_REF = 29, + + /* _key_column_usage */ + GDA_SERVER_META__KEY_COLUMNS = 30, + GDA_SERVER_META_KEY_COLUMNS = 31, + + /* _check_column_usage */ + GDA_SERVER_META__CHECK_COLUMNS = 32, + GDA_SERVER_META_CHECK_COLUMNS = 33, + + /* _triggers */ + GDA_SERVER_META__TRIGGERS = 34, + GDA_SERVER_META_TRIGGERS = 35, + + /* _routines */ + GDA_SERVER_META__ROUTINES = 36, + GDA_SERVER_META_ROUTINES = 37, + + /* _routine_columns */ + GDA_SERVER_META__ROUTINE_COL = 38, + GDA_SERVER_META_ROUTINE_COL = 39, + + /* _parameters */ + GDA_SERVER_META__ROUTINE_PAR = 40, + GDA_SERVER_META_ROUTINE_PAR = 41, + + /* _table_indexes */ + GDA_SERVER_META__INDEXES_TAB = 42, + GDA_SERVER_META_INDEXES_TAB = 43, + + /* _index_column_usage */ + GDA_SERVER_META__INDEX_COLS = 44, + GDA_SERVER_META_INDEX_COLS = 45, +} GdaServerProviderMetaType; + + +/** + * GdaServerProviderXa: + * @xa_start: start transaction + * @xa_end: end transaction + * @xa_prepare: prepare transaction + * @xa_commit: commit transaction + * @xa_rollback: rollback transaction + * @xa_recover: recover transaction's session + * + * Functions implementing distributed transactions. + */ +typedef struct { + gboolean (*xa_start) (GdaServerProvider *prov, GdaConnection *cnc, const GdaXaTransactionId *trx, GError **error); + + gboolean (*xa_end) (GdaServerProvider *prov, GdaConnection *cnc, const GdaXaTransactionId *trx, GError **error); + gboolean (*xa_prepare) (GdaServerProvider *prov, GdaConnection *cnc, const GdaXaTransactionId *trx, GError **error); + + gboolean (*xa_commit) (GdaServerProvider *prov, GdaConnection *cnc, const GdaXaTransactionId *trx, GError **error); + gboolean (*xa_rollback) (GdaServerProvider *prov, GdaConnection *cnc, const GdaXaTransactionId *trx, GError **error); + + GList *(*xa_recover) (GdaServerProvider *prov, GdaConnection *cnc, GError **error); + + /*< private >*/ + /* Padding for future expansion */ + void (*_gda_reserved1) (void); + void (*_gda_reserved2) (void); + void (*_gda_reserved3) (void); + void (*_gda_reserved4) (void); +} GdaServerProviderXa; + +G_END_DECLS + +#endif diff --git a/.flatpak-builder/cache/objects/b2/cece3a23e297c6c4fa94b1d025981bfa43d01cb6c6423129e74277554ea7cc.file b/.flatpak-builder/cache/objects/b2/cece3a23e297c6c4fa94b1d025981bfa43d01cb6c6423129e74277554ea7cc.file new file mode 100644 index 0000000..753938e --- /dev/null +++ b/.flatpak-builder/cache/objects/b2/cece3a23e297c6c4fa94b1d025981bfa43d01cb6c6423129e74277554ea7cc.file @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2006 - 2011 Vivien Malerba + * Copyright (C) 2018 Daniel Espinosa + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GDA_DATA_MODEL_IMPORT_H__ +#define __GDA_DATA_MODEL_IMPORT_H__ + +#include +#include +#include +#include + +G_BEGIN_DECLS + +#define GDA_TYPE_DATA_MODEL_IMPORT (gda_data_model_import_get_type()) +G_DECLARE_DERIVABLE_TYPE (GdaDataModelImport, gda_data_model_import, GDA, DATA_MODEL_IMPORT, GObject) +struct _GdaDataModelImportClass { + GObjectClass parent_class; + + /*< private >*/ + /* Padding for future expansion */ + void (*_gda_reserved1) (void); + void (*_gda_reserved2) (void); + void (*_gda_reserved3) (void); + void (*_gda_reserved4) (void); +}; + +/** + * SECTION:gda-data-model-import + * @short_description: Importing data from a string or a file + * @title: GdaDataModelImport + * @stability: Stable + * @see_also: #GdaDataModel + * + * The #GdaDataModelImport data model imports data from a string or a file. The data can either be + * in a CSV (comma separated values) format or in an XML format as described by the libgda-array.dtd DTD (as a side + * way it is also possible to import data from an already-build XML tree validated against that DTD). + * + * The caller must decide, upon construction, if the new #GdaDataModelImport must support random access or simply + * a cursor based access. Random access makes it easier to use the resulting data model but consumes more memory as + * all the data is copied in memory, and is thus not suitable for large data sets. Note that importing from an + * already-build XML tree will always result in a random access data model. + * + * Various import options can be specified using parameters in a #GdaSet object. The available options + * depend on the format of the imported data listed here: + * + * "SEPARATOR" (string, CVS import only): specifies the separator to consider + * "ESCAPE_CHAR" (string, CVS import only): specifies the character used to "escape" the strings + * contained between two separators + * "ENCODING" (string, CVS import only): specifies the character set used in the imported data + * "TITLE_AS_FIRST_LINE" (boolean, CVS import only): TRUE to specify that the first line of the + * imported data contains the column names + * "G_TYPE_<col number>" (GType, CVS import only): specifies the requested GType type for the column + * numbered "col number" + * + */ + + +GdaDataModel *gda_data_model_import_new_file (const gchar *filename, gboolean random_access, GdaSet *options); +GdaDataModel *gda_data_model_import_new_mem (const gchar *data, gboolean random_access, GdaSet *options); +GdaDataModel *gda_data_model_import_new_xml_node (xmlNodePtr node); + +GSList *gda_data_model_import_get_errors (GdaDataModelImport *model); +void gda_data_model_import_clean_errors (GdaDataModelImport *model); + + +#define GDA_TYPE_DATA_MODEL_IMPORT_ITER gda_data_model_import_iter_get_type() + +G_DECLARE_DERIVABLE_TYPE(GdaDataModelImportIter, gda_data_model_import_iter, GDA, DATA_MODEL_IMPORT_ITER, GdaDataModelIter) + +struct _GdaDataModelImportIterClass { + GdaDataModelIterClass parent_class; +}; + +G_END_DECLS + +#endif diff --git a/.flatpak-builder/cache/objects/b2/d02b060f98a8e13d298062412f68844971c7cb3ca4a3f2728f7b62e80dfef1.file b/.flatpak-builder/cache/objects/b2/d02b060f98a8e13d298062412f68844971c7cb3ca4a3f2728f7b62e80dfef1.file new file mode 100644 index 0000000..746c31b --- /dev/null +++ b/.flatpak-builder/cache/objects/b2/d02b060f98a8e13d298062412f68844971c7cb3ca4a3f2728f7b62e80dfef1.file @@ -0,0 +1,431 @@ +/* + * Copyright (C) 2008 - 2014 Vivien Malerba + * Copyright (C) 2009 Bas Driessen + * Copyright (C) 2009 Murray Cumming + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include +#include + +/** + * gda_sql_value_stringify + * @value: a #GValue pointer + * + * Simplified version of gda_value_stringify(). + * + * Returns: a new string + */ +gchar * +gda_sql_value_stringify (const GValue *value) +{ + if (value && !GDA_VALUE_HOLDS_NULL (value)) { + if (g_value_type_transformable (G_VALUE_TYPE (value), G_TYPE_STRING)) { + GValue *string; + gchar *str; + + string = g_value_init (g_new0 (GValue, 1), G_TYPE_STRING); + g_value_transform (value, string); + str = g_value_dup_string (string); + gda_value_free (string); + return str; + } + else { + GType type = G_VALUE_TYPE (value); + if (type == G_TYPE_DATE) { + GDate *date; + date = (GDate *) g_value_get_boxed (value); + if (date) { + if (g_date_valid (date)) + return g_strdup_printf ("%04u-%02u-%02u", + g_date_get_year (date), + g_date_get_month (date), + g_date_get_day (date)); + else + return g_strdup_printf ("%04u-%02u-%02u", + date->year, date->month, date->day); + } + else + return g_strdup ("0000-00-00"); + } + else + return g_strdup (""); + } + } + else + return g_strdup ("NULL"); +} + +/* Returns: @str */ +gchar * +_remove_quotes (gchar *str) +{ + glong total; + gchar *ptr; + glong offset = 0; + char delim; + + if (!str) + return NULL; + delim = *str; + if ((delim != '\'') && (delim != '"')) + return str; + + total = strlen (str); + if (str[total-1] == delim) { + /* string is correctly terminated by a double quote */ + memmove (str, str+1, total-2); + total -=2; + } + else { + /* string is _not_ correctly terminated by a double quote */ + memmove (str, str+1, total-1); + total -=1; + } + str[total] = 0; + + ptr = (gchar *) str; + while (offset < total) { + /* we accept the "''" as a synonym of "\'" */ + if (*ptr == delim) { + if (*(ptr+1) == delim) { + memmove (ptr+1, ptr+2, total - offset); + offset += 2; + } + else { + *str = 0; + return str; + } + } + else if (*ptr == '"') { + if (*(ptr+1) == '"') { + memmove (ptr+1, ptr+2, total - offset); + offset += 2; + } + else { + *str = 0; + return str; + } + } + else if (*ptr == '\\') { + if (*(ptr+1) == '\\') { + memmove (ptr+1, ptr+2, total - offset); + offset += 2; + } + else { + if (*(ptr+1) == delim) { + *ptr = delim; + memmove (ptr+1, ptr+2, total - offset); + offset += 2; + } + else { + *str = 0; + return str; + } + } + } + else + offset ++; + + ptr++; + } + + return str; +} + +/** + * gda_sql_identifier_force_quotes + * @str: an SQL identifier + * + * Add double quotes around the @str identifier. This function is normally used only by database provider's + * implementation. Any double quote character is replaced by two double quote characters. + * + * For other uses, see gda_sql_identifier_quote(). + * + * Since: 5.0 + */ +gchar * +gda_sql_identifier_force_quotes (const gchar *str) +{ + gchar *retval, *rptr; + const gchar *sptr; + gint len; + + if (!str) + return NULL; + + len = strlen (str); + retval = g_new (gchar, 2*len + 3); + *retval = '"'; + for (rptr = retval+1, sptr = str; *sptr; sptr++, rptr++) { + if (*sptr == '"') { + *rptr = '"'; + rptr++; + *rptr = *sptr; + } + else + *rptr = *sptr; + } + *rptr = '"'; + rptr++; + *rptr = 0; + return retval; +} + +gchar * +_json_quote_string (const gchar *str) +{ + gchar *retval, *rptr; + const gchar *sptr; + gint len; + + if (!str) + return g_strdup ("null"); + + len = strlen (str); + retval = g_new (gchar, 2*len + 3); + *retval = '"'; + for (rptr = retval+1, sptr = str; *sptr; sptr++, rptr++) { + switch (*sptr) { + case '"': + *rptr = '\\'; + rptr++; + *rptr = *sptr; + break; + case '\\': + *rptr = '\\'; + rptr++; + *rptr = *sptr; + break; + case '/': + *rptr = '\\'; + rptr++; + *rptr = *sptr; + break; + case '\b': + *rptr = '\\'; + rptr++; + *rptr = 'b'; + break; + case '\f': + *rptr = '\\'; + rptr++; + *rptr = 'f'; + break; + case '\n': + *rptr = '\\'; + rptr++; + *rptr = 'n'; + break; + case '\r': + *rptr = '\\'; + rptr++; + *rptr = 'r'; + break; + case '\t': + *rptr = '\\'; + rptr++; + *rptr = 't'; + break; + default: + *rptr = *sptr; + break; + } + } + *rptr = '"'; + rptr++; + *rptr = 0; + return retval; +} + +/* +** If X is a character that can be used in an identifier then +** IdChar(X) will be true. Otherwise it is false. +** +** For ASCII, any character with the high-order bit set is +** allowed in an identifier. For 7-bit characters, +** sqlite3IsIdChar[X] must be 1. +*/ +static const char AsciiIdChar[] = { + /* x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF */ + 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 2x */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, /* 3x */ + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 4x */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, /* 5x */ + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 6x */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, /* 7x */ +}; +#define IdChar(C) (((c=C)&0x80)!=0 || (c>0x1f && AsciiIdChar[c-0x20])) +gboolean +_string_is_identifier (const gchar *str) +{ + const gchar *ptr; + gchar *endptr; + gchar c; + + if (!str || !(*str)) + return FALSE; + if ((*str == '"') || (*str == '`')) + ptr = str + 1; + else + ptr = str; + for (; IdChar(*ptr) || + (*ptr == '*') || + (*ptr == '.') || + (*ptr == '-') || + ((*ptr == '"') && (ptr[1] == '"')) || + (((*ptr == '"') || (*ptr == '`')) && ptr[1] == 0); + ptr++) { + if ((*ptr == '"') && (ptr[1] == '"')) + ptr++; + } + if (*ptr) + return FALSE; + if (((*str == '"') && (ptr[-1] == '"')) || + ((*str == '`') && (ptr[-1] == '`'))) + return TRUE; + + /* @str is composed only of character that can be used in an identifier */ + g_ascii_strtod (str, &endptr); + if (!*endptr) + /* @str is a number */ + return FALSE; + return TRUE; +} + +/** + * gda_sql_identifier_prepare_for_compare + * @str: a quoted string + * + * Prepares @str to be compared: + * + * if surrounded by double quotes or single quotes, then just remove the quotes + * otherwise convert to lower case + * + * + * The quoted string: + * + * must start and finish with the same single or double quotes character + * can contain the delimiter character (the single or double quotes) in the string if every instance + * of it is preceeded with a backslash character or with the delimiter character itself + * + * + * This function is normally used only by database provider's implementation. + * + * WARNING: @str must NOT be a composed identifier (<part1>."<part2>" for example) + * WARNING: you may have to #include <sql-parser/gda-sql-parser.h> + * + * Returns: @str + * + * Since: 5.0 + */ +gchar * +gda_sql_identifier_prepare_for_compare (gchar *str) +{ + if (!str) + return NULL; + if ((*str == '"') || (*str == '\'')) + return _remove_quotes (str); + else { + gchar *ptr; + for (ptr = str; *ptr; ptr++) + *ptr = g_ascii_tolower (*ptr); + } + return str; +} + +/* + * Reuses @str and fills in @remain and @last + * + * @str "swallowed" by the function and must be allocated memory, and @remain and @last are + * also allocated memory. + * + * Accepted notations for each individual part: + * - aaa + * - "aaa" + * + * So "aaa".bbb, aaa.bbb, "aaa"."bbb", aaa."bbb" are Ok. + * + * Returns TRUE: + * if @str has the . form, then @last will contain and @remain will contain + * if @str has the form, then @last will contain and @remain will contain NULL + * + * Returns FALSE (in any case @str is also freed) + * if @str is NULL: + * if @str is "": + * if @str is malformed: + * @last and @remain will contain NULL + */ +gboolean +_split_identifier_string (gchar *str, gchar **remain, gchar **last) +{ + gchar *ptr; + gboolean inq = FALSE; + gint len; + + *remain = NULL; + *last = NULL; + if (!str) + return FALSE; + g_strchomp (str); + if (!*str) { + g_free (str); + return FALSE; + } + + len = strlen (str) - 1; + if (len > 1) { + if (((str[len] == '"') && (str[len-1] == '.')) || + (str[len] == '.')) { + g_free (str); + return FALSE; + } + } + + if (((str[0] == '"') && (str[1] == '.')) || + (str[0] == '.')) { + g_free (str); + return FALSE; + } + + for (ptr = str + strlen (str) - 1; ptr >= str; ptr--) { + if (*ptr == '"') { + if ((ptr > str) && (ptr[-1] == '"')) { + ptr--; + continue; + } + inq = !inq; + } + else if ((*ptr == '.') && !inq) { + *ptr = 0; + *remain = str; + *last = g_strdup (ptr+1); + break; + } + } + if (!(*last) && !(*remain)) + *last = str; + + if (*last && !_string_is_identifier (*last)) { + g_free (*last); + *last = NULL; + g_free (*remain); + *remain = NULL; + return FALSE; + } + return TRUE; +} diff --git a/.flatpak-builder/cache/objects/b3/002e38564918f9293d480a6adcd53dcb50c5a35f8f9399e6a300e1975a4e92.file b/.flatpak-builder/cache/objects/b3/002e38564918f9293d480a6adcd53dcb50c5a35f8f9399e6a300e1975a4e92.file new file mode 120000 index 0000000..baffcd9 --- /dev/null +++ b/.flatpak-builder/cache/objects/b3/002e38564918f9293d480a6adcd53dcb50c5a35f8f9399e6a300e1975a4e92.file @@ -0,0 +1 @@ +../../share/runtime/locale/zh/share/zh_TW \ No newline at end of file diff --git a/.flatpak-builder/cache/objects/b3/1c8cdcb8bb973b368c83a70763962c7e71338bc0c7f9d98f63a9ed4ce2b537.file b/.flatpak-builder/cache/objects/b3/1c8cdcb8bb973b368c83a70763962c7e71338bc0c7f9d98f63a9ed4ce2b537.file new file mode 100644 index 0000000..8513687 --- /dev/null +++ b/.flatpak-builder/cache/objects/b3/1c8cdcb8bb973b368c83a70763962c7e71338bc0c7f9d98f63a9ed4ce2b537.file @@ -0,0 +1,1706 @@ +/* + * Copyright (C) 2008 - 2011 Murray Cumming + * Copyright (C) 2008 - 2014 Vivien Malerba + * Copyright (C) 2009 Bas Driessen + * Copyright (C) 2010 David King + * Copyright (C) 2010 Jonh Wendell + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Main static functions + */ +static void gda_sql_parser_dispose (GObject *object); +static void gda_sql_parser_finalize (GObject *object); + +static void gda_sql_parser_set_property (GObject *object, + guint param_id, + const GValue *value, + GParamSpec *pspec); +static void gda_sql_parser_get_property (GObject *object, + guint param_id, + GValue *value, + GParamSpec *pspec); + +/* GdaLockable interface */ +static void gda_sql_parser_lockable_init (GdaLockableInterface *iface); +static void gda_sql_parser_lock (GdaLockable *lockable); +static gboolean gda_sql_parser_trylock (GdaLockable *lockable); +static void gda_sql_parser_unlock (GdaLockable *lockable); + +static void gda_sql_parser_reset (GdaSqlParser *parser); +static GValue *tokenizer_get_next_token (GdaSqlParser *parser); + +static void push_tokenizer_context (GdaSqlParser *parser); +static void pop_tokenizer_context (GdaSqlParser *parser); +static gint fetch_forward (GdaSqlParser *parser, gint *out_nb_pushed, ...); +static void merge_tokenizer_contexts (GdaSqlParser *parser, gint n_contexts); + +/* + * The interface to the LEMON-generated parser + */ +void *priv_gda_sql_delimiterAlloc (void*(*)(size_t)); +void priv_gda_sql_delimiterFree (void*, void(*)(void*)); +void priv_gda_sql_delimiterTrace (void*, char *); +void priv_gda_sql_delimiter (void*, int, GValue *, GdaSqlParserIface *); + +void *priv_gda_sql_parserAlloc (void*(*)(size_t)); +void priv_gda_sql_parserFree (void*, void(*)(void*)); +void priv_gda_sql_parserTrace (void*, char *); +void priv_gda_sql_parser (void*, int, GValue *, GdaSqlParserIface *); + + + +G_DEFINE_TYPE_WITH_CODE (GdaSqlParser, gda_sql_parser, G_TYPE_OBJECT, + G_ADD_PRIVATE (GdaSqlParser) + G_IMPLEMENT_INTERFACE (GDA_TYPE_LOCKABLE, gda_sql_parser_lockable_init)) + +/* signals */ +enum +{ + CHANGED, + LAST_SIGNAL +}; + +/* properties */ +enum +{ + PROP_0, + PROP_FLAVOUR, + PROP_MODE, + PROP_LINE_ERROR, + PROP_COL_ERROR +#ifdef GDA_DEBUG + ,PROP_DEBUG +#endif +}; + +/* module error */ +GQuark gda_sql_parser_error_quark (void) +{ + static GQuark quark; + if (!quark) + quark = g_quark_from_static_string ("gda_sql_parser_error"); + return quark; +} + + +static void +gda_sql_parser_class_init (GdaSqlParserClass * klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->dispose = gda_sql_parser_dispose; + object_class->finalize = gda_sql_parser_finalize; + + /* Properties */ + object_class->set_property = gda_sql_parser_set_property; + object_class->get_property = gda_sql_parser_get_property; + g_object_class_install_property (object_class, PROP_FLAVOUR, + g_param_spec_int ("tokenizer-flavour", NULL, NULL, + GDA_SQL_PARSER_FLAVOUR_STANDARD, + GDA_SQL_PARSER_FLAVOUR_POSTGRESQL, + GDA_SQL_PARSER_FLAVOUR_STANDARD, + G_PARAM_WRITABLE | G_PARAM_READABLE)); + g_object_class_install_property (object_class, PROP_MODE, + g_param_spec_int ("mode", NULL, NULL, + GDA_SQL_PARSER_MODE_PARSE, + GDA_SQL_PARSER_MODE_DELIMIT, + GDA_SQL_PARSER_MODE_PARSE, + G_PARAM_WRITABLE | G_PARAM_READABLE)); + g_object_class_install_property (object_class, PROP_LINE_ERROR, + g_param_spec_int ("line-error", NULL, NULL, + 0, G_MAXINT, 0, + G_PARAM_READABLE)); + g_object_class_install_property (object_class, PROP_COL_ERROR, + g_param_spec_int ("column-error", NULL, NULL, + 0, G_MAXINT, 0, + G_PARAM_READABLE)); +#ifdef GDA_DEBUG + g_object_class_install_property (object_class, PROP_DEBUG, + g_param_spec_boolean ("debug", NULL, NULL, + FALSE, + G_PARAM_WRITABLE)); +#endif +} + +static void +gda_sql_parser_lockable_init (GdaLockableInterface *iface) +{ + iface->lock = gda_sql_parser_lock; + iface->trylock = gda_sql_parser_trylock; + iface->unlock = gda_sql_parser_unlock; +} + +static void +gda_sql_parser_reset (GdaSqlParser *parser) +{ + GdaSqlParserPrivate *priv = gda_sql_parser_get_instance_private (parser); + if (priv->sql) + g_free (priv->sql); + priv->sql = NULL; + g_array_free (priv->passed_tokens, TRUE); + priv->passed_tokens = g_array_new (FALSE, FALSE, sizeof (gint)); + + if (priv->error_msg) + g_free (priv->error_msg); + priv->error_msg = NULL; + priv->error_line = 0; + priv->error_col = 0; + priv->error_pos = 0; + + if (priv->parsed_statements) { + g_slist_free_full (priv->parsed_statements, (GDestroyNotify) gda_sql_statement_free); + priv->parsed_statements = NULL; + } + + if (priv->pushed_contexts) { + g_slist_free_full (priv->pushed_contexts, (GDestroyNotify) g_free); + priv->pushed_contexts = NULL; + } + + priv->context->next_token_start = NULL; + priv->context->in_param_spec = FALSE; + priv->context->block_level = 0; + priv->context->last_token_start = NULL; +} + +static void +gda_sql_parser_init (GdaSqlParser *parser) +{ + GdaSqlParserClass *klass; + + klass = (GdaSqlParserClass*) G_OBJECT_GET_CLASS (parser); + + GdaSqlParserPrivate *priv = gda_sql_parser_get_instance_private (parser); + g_rec_mutex_init (& (priv->mutex)); + priv->flavour = GDA_SQL_PARSER_FLAVOUR_STANDARD; + if (klass->delim_alloc) + priv->lemon_delimiter = klass->delim_alloc ((void*(*)(size_t)) g_malloc); + else + priv->lemon_delimiter = priv_gda_sql_delimiterAlloc ((void*(*)(size_t)) g_malloc); + if (klass->parser_alloc) + priv->lemon_parser = klass->parser_alloc ((void*(*)(size_t)) g_malloc); + else + priv->lemon_parser = priv_gda_sql_parserAlloc ((void*(*)(size_t)) g_malloc); + priv->mode = GDA_SQL_PARSER_MODE_PARSE; + priv->flavour = GDA_SQL_PARSER_FLAVOUR_STANDARD; + + priv->sql = NULL; + priv->passed_tokens = g_array_new (FALSE, FALSE, sizeof (gint)); + + priv->context = g_new0 (TokenizerContext, 1); + priv->context->delimiter = ';'; + priv->context->in_param_spec = FALSE; + priv->context->block_level = 0; + priv->context->next_token_start = NULL; + priv->context->last_token_start = NULL; + + priv->error_msg = NULL; + priv->error_line = 0; + priv->error_col = 0; + priv->error_pos = 0; +} + +/** + * gda_sql_parser_new: + * + * Creates a new #GdaSqlParser object + * + * Returns: the new object + */ +GdaSqlParser* +gda_sql_parser_new (void) +{ + GObject *obj; + + obj = g_object_new (GDA_TYPE_SQL_PARSER, NULL); + return GDA_SQL_PARSER (obj); +} + +static void +gda_sql_parser_dispose (GObject *object) +{ + GdaSqlParser *parser; + + g_return_if_fail (object != NULL); + g_return_if_fail (GDA_IS_SQL_PARSER (object)); + + parser = GDA_SQL_PARSER (object); + GdaSqlParserPrivate *priv = gda_sql_parser_get_instance_private (parser); + gda_sql_parser_reset (parser); + if (priv->context) + g_free (priv->context); + priv->context = NULL; + if (priv->passed_tokens) + g_array_free (priv->passed_tokens, TRUE); + priv->passed_tokens = NULL; + + /* parent class */ + G_OBJECT_CLASS (gda_sql_parser_parent_class)->dispose (object); +} + +static void +gda_sql_parser_finalize (GObject *object) +{ + GdaSqlParser *parser; + + g_return_if_fail (object != NULL); + g_return_if_fail (GDA_IS_SQL_PARSER (object)); + + parser = GDA_SQL_PARSER (object); + GdaSqlParserPrivate *priv = gda_sql_parser_get_instance_private (parser); + + GdaSqlParserClass *klass; + + klass = (GdaSqlParserClass*) G_OBJECT_GET_CLASS (parser); + + if (klass->delim_alloc) { + g_assert (klass->delim_free); + klass->delim_free (priv->lemon_delimiter, g_free); + } + else + priv_gda_sql_delimiterFree (priv->lemon_delimiter, g_free); + if (klass->parser_alloc) { + g_assert (klass->parser_free); + klass->parser_free (priv->lemon_parser, g_free); + } + else + priv_gda_sql_parserFree (priv->lemon_parser, g_free); + + g_rec_mutex_clear (& (priv->mutex)); + + /* parent class */ + G_OBJECT_CLASS (gda_sql_parser_parent_class)->finalize (object); +} + + +static void +gda_sql_parser_set_property (GObject *object, + guint param_id, + const GValue *value, + GParamSpec *pspec) +{ + GdaSqlParser *parser; + + parser = GDA_SQL_PARSER (object); + GdaSqlParserPrivate *priv = gda_sql_parser_get_instance_private (parser); + if (priv) { + g_rec_mutex_lock (& (priv->mutex)); + switch (param_id) { + case PROP_FLAVOUR: + priv->flavour = g_value_get_int (value); + break; + case PROP_MODE: + priv->mode = g_value_get_int (value); + break; +#ifdef GDA_DEBUG + case PROP_DEBUG: { + gboolean debug = g_value_get_boolean (value); + GdaSqlParserClass *klass; + + klass = (GdaSqlParserClass*) G_OBJECT_GET_CLASS (parser); + if (klass->delim_alloc) { + g_assert (klass->delim_trace); + klass->delim_trace ((priv->mode == GDA_SQL_PARSER_MODE_DELIMIT) && debug ? + stdout : NULL, ".......DELIMITER DEBUG:"); + } + else + priv_gda_sql_delimiterTrace ((priv->mode == GDA_SQL_PARSER_MODE_DELIMIT) && debug ? + stdout : NULL, ".......DELIMITER DEBUG:"); + if (klass->parser_alloc) { + g_assert (klass->parser_trace); + klass->parser_trace ((priv->mode == GDA_SQL_PARSER_MODE_PARSE) && debug ? + stdout : NULL, ".......PARSE DEBUG:"); + } + else + priv_gda_sql_parserTrace ((priv->mode == GDA_SQL_PARSER_MODE_PARSE) && debug ? + stdout : NULL, ".......PARSE DEBUG:"); + break; + } +#endif + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + break; + } + g_rec_mutex_unlock (& (priv->mutex)); + } +} + +static void +gda_sql_parser_get_property (GObject *object, + guint param_id, + GValue *value, + GParamSpec *pspec) +{ + GdaSqlParser *parser; + parser = GDA_SQL_PARSER (object); + GdaSqlParserPrivate *priv = gda_sql_parser_get_instance_private (parser); + + if (priv) { + switch (param_id) { + case PROP_FLAVOUR: + g_value_set_int (value, priv->flavour); + break; + case PROP_MODE: + g_value_set_int (value, priv->mode); + break; + case PROP_LINE_ERROR: + g_value_set_int (value, priv->error_line); + break; + case PROP_COL_ERROR: + g_value_set_int (value, priv->error_col); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + break; + } + } +} + +/** + * gda_sql_parser_parse_string: + * @parser: a #GdaSqlParser object + * @sql: the SQL string to parse + * @remain: (out) (nullable): location to store a pointer to remaining part of @sql in case @sql has multiple statement, or %NULL + * @error: location to store error, or %NULL + * + * Parses @sql and creates a #GdaStatement statement from the first SQL statement contained in @sql: if @sql + * contains more than one statement, then the remaining part of the string is not parsed at all, and @remain (if + * not %NULL) will point at the first non parsed character. + * + * To include variables in the @sql string, see the + * GdaSqlParser's object description. + * + * Returns: (transfer full) (nullable): a new #GdaStatement object, or %NULL if an error occurred + */ +GdaStatement * +gda_sql_parser_parse_string (GdaSqlParser *parser, const gchar *sql, const gchar **remain, GError **error) +{ + GdaStatement *stmt = NULL; + GValue *value; + GdaSqlParserIface piface; + gint ntokens = 0; + GdaSqlParserMode parse_mode; + GdaSqlParserClass *klass; + void (*_delimit) (void*, int, GValue *, GdaSqlParserIface *) = priv_gda_sql_delimiter; + void (*_parse) (void*, int, GValue *, GdaSqlParserIface *) = priv_gda_sql_parser; + gint *delim_trans = delim_tokens; + gint *parser_trans= parser_tokens; + + if (remain) + *remain = NULL; + + g_return_val_if_fail (GDA_IS_SQL_PARSER (parser), NULL); + GdaSqlParserPrivate *priv = gda_sql_parser_get_instance_private (parser); + + if (!sql) + return NULL; + + g_rec_mutex_lock (& (priv->mutex)); + + klass = (GdaSqlParserClass*) G_OBJECT_GET_CLASS (parser); + if (klass->delim_alloc) { + g_assert (klass->delim_parse); + _delimit = klass->delim_parse; + g_assert (klass->delim_tokens_trans); + delim_trans = klass->delim_tokens_trans; + } + if (klass->parser_alloc) { + g_assert (klass->parser_parse); + _parse = klass->parser_parse; + g_assert (klass->parser_tokens_trans); + parser_trans = klass->parser_tokens_trans; + } + + /* re-init parser */ + gda_sql_parser_reset (parser); + priv->sql = g_strdup (sql); + priv->context->next_token_start = priv->sql; + + parse_mode = priv->mode; /* save current mode */ + /*g_print ("\t\t===== %s MODE =====\n", + parse_mode == GDA_SQL_PARSER_MODE_PARSE ? "PARSE" : "DELIMIT");*/ + piface.parser = parser; + piface.parsed_statement = NULL; + + for (value = tokenizer_get_next_token (parser); + priv->context->token_type != L_ILLEGAL; + value = tokenizer_get_next_token (parser)) { + switch (priv->context->token_type) { + case L_SQLCOMMENT: + gda_value_free (value); + value = NULL; + break; + case L_SPACE: + default: + if (priv->context->token_type == L_SPACE) { + if (priv->context->in_param_spec || + (priv->mode == GDA_SQL_PARSER_MODE_PARSE)) { + /* ignore space */ + gda_value_free (value); + value = NULL; + continue; + } + } + if (priv->mode == GDA_SQL_PARSER_MODE_DELIMIT) { + if ((priv->context->token_type == L_BEGIN) && + (priv->passed_tokens->len != 0) && + !g_ascii_strcasecmp (g_value_get_string (value), "BEGIN")) { + /* a BEGIN command increments the block level only if it's not the + * first word of statement */ + priv->context->block_level ++; + } + if (priv->context->token_type == L_LOOP) { + priv->context->block_level ++; + } + else if ((priv->context->token_type == L_END) && + (priv->passed_tokens->len != 0)) { + /* a END command decrements the block level only if it's not the + * first word of statement */ + priv->context->block_level --; + if (priv->context->block_level == 0) + priv->context->ignore_semi = FALSE; + } + else if (priv->context->token_type == L_ENDLOOP) { + priv->context->block_level --; + } + else if (priv->context->token_type == L_DECLARE) + priv->context->ignore_semi = TRUE; + else if ((priv->flavour == GDA_SQL_PARSER_FLAVOUR_ORACLE) && + ((priv->context->token_type == L_AS) || + (priv->context->token_type == L_IS))) { + /* examine tokens history to see if we have somewhere a CREATE FUNCTION or + * CREATE PROCEDURE */ + gint i; + for (i = priv->passed_tokens->len - 1; i >= 0; i --) { + gint ttype; + ttype = g_array_index (priv->passed_tokens, gint, i); + if (ttype == L_CREATE) + break; + } + if (i >= 0) + priv->context->ignore_semi = TRUE; + } + else if ((priv->flavour == GDA_SQL_PARSER_FLAVOUR_MYSQL) && + (priv->context->token_type == L_DELIMITER)) { + GValue *v; + push_tokenizer_context (parser); + v = tokenizer_get_next_token (parser); + if (priv->context->token_type == L_SPACE) { + push_tokenizer_context (parser); + g_value_reset (v); + g_free (v); + v = tokenizer_get_next_token (parser); + pop_tokenizer_context (parser); + } + pop_tokenizer_context (parser); + if (v) { + if (G_VALUE_TYPE (v) == G_TYPE_STRING) { + const gchar *str; + str = g_value_get_string (v); + if (str) + priv->context->delimiter = *str; + } + else + TO_IMPLEMENT; + g_value_reset (v); + g_free (v); + } + } + } + + /* send found tokens until end of buffer */ + g_array_append_val (priv->passed_tokens, priv->context->token_type); + + switch (priv->mode) { + case GDA_SQL_PARSER_MODE_PARSE: + /*g_print ("TRANS %d => %d\n", priv->context->token_type, + parser_trans [priv->context->token_type]);*/ + _parse (priv->lemon_parser, + parser_trans [priv->context->token_type], value, &piface); + value = NULL; + break; + case GDA_SQL_PARSER_MODE_DELIMIT: + _delimit (priv->lemon_delimiter, + delim_trans [priv->context->token_type], value, &piface); + value = NULL; + break; + default: + TO_IMPLEMENT; + } + + ntokens++; + break; + } + if ((priv->context->token_type == L_END_OF_FILE) || (priv->context->token_type == L_SEMI)) { + /* end of statement */ + break; + } + if (priv->error_pos != 0) + break; + } + if (priv->context->token_type == L_ILLEGAL) { + if (value) + gda_value_free (value); + gda_sql_parser_set_syntax_error (parser); + } + + /* send the EOF token to the LEMON parser */ + switch (priv->mode) { + case GDA_SQL_PARSER_MODE_PARSE: + _parse (priv->lemon_parser, 0, NULL, &piface); + break; + case GDA_SQL_PARSER_MODE_DELIMIT: + _delimit (priv->lemon_delimiter, 0, NULL, &piface); + break; + default: + TO_IMPLEMENT; + } + if (remain) { + if (* priv->context->next_token_start) { + gint i = priv->context->next_token_start - priv->sql; + *remain = sql + i; + while (**remain == ' ' || **remain == '\n' || **remain == '\r' || **remain == '\t') { + *remain = sql + (++i); + } + } + } + + if (piface.parsed_statement) { + gchar hold; + + hold = *priv->context->next_token_start; + *priv->context->next_token_start = 0; + piface.parsed_statement->sql = g_strdup (priv->sql); + *priv->context->next_token_start = hold; + + stmt = g_object_new (GDA_TYPE_STATEMENT, + "structure", piface.parsed_statement, NULL); + gda_sql_statement_free (piface.parsed_statement); + } + else { + if (priv->mode == GDA_SQL_PARSER_MODE_PARSE) { + /* try to create a statement using the delimiter mode */ + priv->mode = GDA_SQL_PARSER_MODE_DELIMIT; + stmt = gda_sql_parser_parse_string (parser, sql, remain, error); + } + else if (error) { + if ((ntokens <= 1) && (priv->context->token_type != L_ILLEGAL)) + g_set_error (error, GDA_SQL_PARSER_ERROR, GDA_SQL_PARSER_EMPTY_SQL_ERROR, + "%s", _("SQL code does not contain any statement")); + else + g_set_error (error, GDA_SQL_PARSER_ERROR, priv->error_type, + "%s", priv->error_msg); + } + } + + priv->mode = parse_mode; + + g_rec_mutex_unlock (& (priv->mutex)); + + return stmt; +} + +/** + * gda_sql_parser_parse_string_as_batch: + * @parser: a #GdaSqlParser object + * @sql: the SQL string to parse + * @remain: (out) (nullable): location to store a pointer to remaining part of @sql in case an error occurred while parsing @sql, or %NULL + * @error: location to store error, or %NULL + * + * Parse @sql and creates a #GdaBatch object which contains all the #GdaStatement objects created while parsing (one object + * per SQL statement). Empty statements (composed of spaces only) do not appear in the resulting object. + * + * @sql is parsed and #GdaStatement objects are created as long as no error is found in @sql. If an error is found + * at some point, then the parsing stops and @remain may contain a non %NULL pointer, @error may be set, and %NULL + * is returned. + * + * if @sql is %NULL, then the returned #GdaBatch object will contain no statement. + * + * To include variables in the @sql string, see the + * GdaSqlParser's object description. + * + * Returns: (transfer full) (nullable): a new #GdaBatch object, or %NULL if an error occurred + */ +GdaBatch * +gda_sql_parser_parse_string_as_batch (GdaSqlParser *parser, const gchar *sql, const gchar **remain, + GError **error) +{ + GdaBatch *batch; + GdaStatement *stmt; + const gchar *int_sql; + gboolean allok = TRUE; + gint n_stmt = 0; + gint n_empty = 0; + + g_return_val_if_fail (GDA_IS_SQL_PARSER (parser), NULL); + GdaSqlParserPrivate *priv = gda_sql_parser_get_instance_private (parser); + + if (remain) + *remain = NULL; + + batch = gda_batch_new (); + if (!sql) + return batch; + + g_rec_mutex_lock (& (priv->mutex)); + + int_sql = sql; + while (int_sql && allok) { + GError *lerror = NULL; + const gchar *int_remain = NULL; + + stmt = gda_sql_parser_parse_string (parser, int_sql, &int_remain, &lerror); + if (stmt) { + if (gda_statement_is_useless (stmt)) + n_empty++; + else { + gda_batch_add_statement (batch, stmt); + n_stmt++; + } + g_object_unref (stmt); + } + else if (lerror && (lerror->domain == GDA_SQL_PARSER_ERROR) && + (lerror->code == GDA_SQL_PARSER_EMPTY_SQL_ERROR)) + n_empty++; + else { + if (int_remain) + allok = FALSE; + if (lerror) { + g_propagate_error (error, lerror); + lerror = NULL; + } + } + if (lerror) + g_error_free (lerror); + int_sql = int_remain; + } + + if ((n_stmt == 0) && (n_empty != 0)) + g_set_error (error, GDA_SQL_PARSER_ERROR, GDA_SQL_PARSER_EMPTY_SQL_ERROR, + "%s", _("SQL code does not contain any statement")); + + if (!allok || (n_stmt == 0)) { + if (remain) + *remain = int_sql; + g_object_unref (batch); + batch = NULL; + } + + g_rec_mutex_unlock (& (priv->mutex)); + + return batch; +} + +/** + * gda_sql_parser_parse_file_as_batch: + * @parser: a #GdaSqlParser object + * @filename: name of the file to parse + * @error: location to store error, or %NULL + * + * Parse @filename's contents and creates a #GdaBatch object which contains all the + * #GdaStatement objects created while parsing (one object per SQL statement). + * + * @filename's contents are parsed and #GdaStatement objects are created as long as no error is found. If an error is found + * at some point, then the parsing stops, @error may be set and %NULL is returned + * + * if @sql is %NULL, then the returned #GdaBatch object will contain no statement. + * + * Returns: (transfer full) (nullable): a new #GdaBatch object, or %NULL if an error occurred + */ +GdaBatch * +gda_sql_parser_parse_file_as_batch (GdaSqlParser *parser, const gchar *filename, GError **error) +{ + gchar *contents; + + g_return_val_if_fail (GDA_IS_SQL_PARSER (parser), NULL); + g_return_val_if_fail (filename, NULL); + + if (!g_file_get_contents (filename, &contents, NULL, error)) + return NULL; + else { + GdaBatch *batch; + batch = gda_sql_parser_parse_string_as_batch (parser, contents, NULL, error); + g_free (contents); + return batch; + } +} + + +/* + * + * Private API + * + */ +static gint +get_position (GdaSqlParser *parser) +{ + GdaSqlParserPrivate *priv = gda_sql_parser_get_instance_private (parser); + gint total; + gchar *z = priv->sql; + gint i, l, c; + + total = priv->context->last_token_start - priv->sql; + for (i = 0, l = 0, c = 0; i < total; i++) { + if (z[i] == '\n') { + l++; + c = 0; + } + else + c++; + } + priv->error_line = l + 1; + priv->error_col = c + 1; + + return total + 1; +} + +void +gda_sql_parser_set_syntax_error (GdaSqlParser *parser) +{ + GdaSqlParserPrivate *priv = gda_sql_parser_get_instance_private (parser); + if (!priv->error_msg) { + priv->error_type = GDA_SQL_PARSER_SYNTAX_ERROR; + priv->error_pos = get_position (parser); + priv->error_msg = g_strdup_printf (_("Syntax error at line %d, column %d"), + priv->error_line, priv->error_col); + /*g_print ("@syntax error at line %d, col %d\n", + priv->error_line, priv->error_col);*/ + } +} + +void +gda_sql_parser_set_overflow_error (GdaSqlParser *parser) +{ + GdaSqlParserPrivate *priv = gda_sql_parser_get_instance_private (parser); + if (!priv->error_msg) { + priv->error_type = GDA_SQL_PARSER_OVERFLOW_ERROR; + priv->error_pos = get_position (parser); + priv->error_msg = g_strdup_printf (_("Overflow error at line %d, column %d"), + priv->error_line, priv->error_col); + /*g_print ("@overflow error at line %d, col %d\n", + priv->error_line, priv->error_col);*/ + } +} + + + +/* + * + * Tokenizer + * + */ +/* +** If X is a character that can be used in an identifier then +** IdChar(X) will be true. Otherwise it is false. +** +** For ASCII, any character with the high-order bit set is +** allowed in an identifier. For 7-bit characters, +** sqlite3IsIdChar[X] must be 1. +*/ +static const char AsciiIdChar[] = { + /* x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF */ + 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 2x */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, /* 3x */ + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 4x */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, /* 5x */ + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 6x */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, /* 7x */ +}; +#define IdChar(C) (((c=C)&0x80)!=0 || (c>0x1f && AsciiIdChar[c-0x20])) + +static const unsigned char UpperToLower[] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, + 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, + 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, + 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 97, 98, 99,100,101,102,103, + 104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121, + 122, 91, 92, 93, 94, 95, 96, 97, 98, 99,100,101,102,103,104,105,106,107, + 108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125, + 126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, + 144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161, + 162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179, + 180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197, + 198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215, + 216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233, + 234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251, + 252,253,254,255 +}; + +static gboolean +str_caseequal (gconstpointer v1, gconstpointer v2) +{ + const gchar *string1 = v1; + const gchar *string2 = v2; + + return strcasecmp (string1, string2) == 0; +} + +static guint +str_casehash (gconstpointer v) +{ + /* 31 bit hash function */ + const signed char *p = v; + guint32 h = UpperToLower[*p]; + + if (h) + for (p += 1; *p != '\0'; p++) + h = (h << 5) - h + UpperToLower[*p]; + + return h; +} + +static gint +keywordCode (GdaSqlParser *parser, gchar *str, gint len) +{ + static GMutex mutex; + static GHashTable *keywords = NULL; + gint type; + gchar oldc; + GdaSqlParserPrivate *priv = gda_sql_parser_get_instance_private (parser); + + g_mutex_lock (&mutex); + if (!keywords) { + /* if keyword begins with a number, it is the GdaSqlParserFlavour to which it only applies: + * for example "4start" would refer to the START keyword for PostgreSQL only */ + keywords = g_hash_table_new (str_casehash, str_caseequal); + g_hash_table_insert (keywords, "all", GINT_TO_POINTER (L_ALL)); + g_hash_table_insert (keywords, "and", GINT_TO_POINTER (L_AND)); + g_hash_table_insert (keywords, "as", GINT_TO_POINTER (L_AS)); + g_hash_table_insert (keywords, "asc", GINT_TO_POINTER (L_ASC)); + g_hash_table_insert (keywords, "3batch", GINT_TO_POINTER (L_BATCH)); + g_hash_table_insert (keywords, "begin", GINT_TO_POINTER (L_BEGIN)); + g_hash_table_insert (keywords, "between", GINT_TO_POINTER (L_BETWEEN)); + g_hash_table_insert (keywords, "by", GINT_TO_POINTER (L_BY)); + g_hash_table_insert (keywords, "case", GINT_TO_POINTER (L_CASE)); + g_hash_table_insert (keywords, "cast", GINT_TO_POINTER (L_CAST)); + g_hash_table_insert (keywords, "comment", GINT_TO_POINTER (L_COMMENT)); + g_hash_table_insert (keywords, "commit", GINT_TO_POINTER (L_COMMIT)); + g_hash_table_insert (keywords, "committed", GINT_TO_POINTER (L_COMMITTED)); + g_hash_table_insert (keywords, "create", GINT_TO_POINTER (L_CREATE)); + g_hash_table_insert (keywords, "cross", GINT_TO_POINTER (L_CROSS)); + g_hash_table_insert (keywords, "declare", GINT_TO_POINTER (L_DECLARE)); + g_hash_table_insert (keywords, "delete", GINT_TO_POINTER (L_DELETE)); + g_hash_table_insert (keywords, "deferred", GINT_TO_POINTER (L_DEFERRED)); + g_hash_table_insert (keywords, "delimiter", GINT_TO_POINTER (L_DELIMITER)); + g_hash_table_insert (keywords, "desc", GINT_TO_POINTER (L_DESC)); + g_hash_table_insert (keywords, "distinct", GINT_TO_POINTER (L_DISTINCT)); + g_hash_table_insert (keywords, "else", GINT_TO_POINTER (L_ELSE)); + g_hash_table_insert (keywords, "end", GINT_TO_POINTER (L_END)); + g_hash_table_insert (keywords, "except", GINT_TO_POINTER (L_EXCEPT)); + g_hash_table_insert (keywords, "exclusive", GINT_TO_POINTER (L_EXCLUSIVE)); + g_hash_table_insert (keywords, "3force", GINT_TO_POINTER (L_FORCE)); + g_hash_table_insert (keywords, "from", GINT_TO_POINTER (L_FROM)); + g_hash_table_insert (keywords, "full", GINT_TO_POINTER (L_FULL)); + g_hash_table_insert (keywords, "group", GINT_TO_POINTER (L_GROUP)); + g_hash_table_insert (keywords, "having", GINT_TO_POINTER (L_HAVING)); + g_hash_table_insert (keywords, "ilike", GINT_TO_POINTER (L_ILIKE)); + g_hash_table_insert (keywords, "immediate", GINT_TO_POINTER (L_IMMEDIATE)); + g_hash_table_insert (keywords, "in", GINT_TO_POINTER (L_IN)); + g_hash_table_insert (keywords, "inner", GINT_TO_POINTER (L_INNER)); + g_hash_table_insert (keywords, "insert", GINT_TO_POINTER (L_INSERT)); + g_hash_table_insert (keywords, "intersect", GINT_TO_POINTER (L_INTERSECT)); + g_hash_table_insert (keywords, "into", GINT_TO_POINTER (L_INTO)); + g_hash_table_insert (keywords, "is", GINT_TO_POINTER (L_IS)); + g_hash_table_insert (keywords, "isolation", GINT_TO_POINTER (L_ISOLATION)); + g_hash_table_insert (keywords, "join", GINT_TO_POINTER (L_JOIN)); + g_hash_table_insert (keywords, "left", GINT_TO_POINTER (L_LEFT)); + g_hash_table_insert (keywords, "level", GINT_TO_POINTER (L_LEVEL)); + g_hash_table_insert (keywords, "like", GINT_TO_POINTER (L_LIKE)); + g_hash_table_insert (keywords, "limit", GINT_TO_POINTER (L_LIMIT)); + g_hash_table_insert (keywords, "loop", GINT_TO_POINTER (L_LOOP)); + g_hash_table_insert (keywords, "natural", GINT_TO_POINTER (L_NATURAL)); + g_hash_table_insert (keywords, "not", GINT_TO_POINTER (L_NOT)); + g_hash_table_insert (keywords, "3nowait", GINT_TO_POINTER (L_NOWAIT)); + g_hash_table_insert (keywords, "null", GINT_TO_POINTER (L_NULL)); + g_hash_table_insert (keywords, "offset", GINT_TO_POINTER (L_OFFSET)); + g_hash_table_insert (keywords, "on", GINT_TO_POINTER (L_ON)); + g_hash_table_insert (keywords, "only", GINT_TO_POINTER (L_ONLY)); + g_hash_table_insert (keywords, "or", GINT_TO_POINTER (L_OR)); + g_hash_table_insert (keywords, "order", GINT_TO_POINTER (L_ORDER)); + g_hash_table_insert (keywords, "outer", GINT_TO_POINTER (L_OUTER)); + g_hash_table_insert (keywords, "right", GINT_TO_POINTER (L_RIGHT)); + g_hash_table_insert (keywords, "read", GINT_TO_POINTER (L_READ)); + g_hash_table_insert (keywords, "release", GINT_TO_POINTER (L_RELEASE)); + g_hash_table_insert (keywords, "repeatable", GINT_TO_POINTER (L_REPEATABLE)); + g_hash_table_insert (keywords, "rollback", GINT_TO_POINTER (L_ROLLBACK)); + g_hash_table_insert (keywords, "savepoint", GINT_TO_POINTER (L_SAVEPOINT)); + g_hash_table_insert (keywords, "select", GINT_TO_POINTER (L_SELECT)); + g_hash_table_insert (keywords, "serializable", GINT_TO_POINTER (L_SERIALIZABLE)); + g_hash_table_insert (keywords, "set", GINT_TO_POINTER (L_SET)); + g_hash_table_insert (keywords, "similar", GINT_TO_POINTER (L_SIMILAR)); + g_hash_table_insert (keywords, "start", GINT_TO_POINTER (L_BEGIN)); + g_hash_table_insert (keywords, "then", GINT_TO_POINTER (L_THEN)); + g_hash_table_insert (keywords, "to", GINT_TO_POINTER (L_TO)); + g_hash_table_insert (keywords, "transaction", GINT_TO_POINTER (L_TRANSACTION)); + g_hash_table_insert (keywords, "uncommitted", GINT_TO_POINTER (L_UNCOMMITTED)); + g_hash_table_insert (keywords, "union", GINT_TO_POINTER (L_UNION)); + g_hash_table_insert (keywords, "update", GINT_TO_POINTER (L_UPDATE)); + g_hash_table_insert (keywords, "using", GINT_TO_POINTER (L_USING)); + g_hash_table_insert (keywords, "values", GINT_TO_POINTER (L_VALUES)); + g_hash_table_insert (keywords, "3wait", GINT_TO_POINTER (L_WAIT)); + g_hash_table_insert (keywords, "when", GINT_TO_POINTER (L_WHEN)); + g_hash_table_insert (keywords, "where", GINT_TO_POINTER (L_WHERE)); + g_hash_table_insert (keywords, "work", GINT_TO_POINTER (L_TRANSACTION)); + g_hash_table_insert (keywords, "write", GINT_TO_POINTER (L_WRITE)); + } + g_mutex_unlock (&mutex); + + oldc = str[len]; + str[len] = 0; + type = GPOINTER_TO_INT (g_hash_table_lookup (keywords, str)); + if (type == 0) { + /* try prepending the current flavour */ + gchar *tmp; + tmp = g_strdup_printf ("%d%s", priv->flavour, str); + type = GPOINTER_TO_INT (g_hash_table_lookup (keywords, tmp)); + g_free (tmp); + if (type == 0) { + if (priv->mode == GDA_SQL_PARSER_MODE_PARSE) + type = L_ID; + else + type = L_RAWSTRING; + } + } + /*g_print ("Looking for /%s/ -> %d\n", str, type);*/ + str[len] = oldc; + + return type; +} + +static GValue * +token_as_string (gchar *ptr, gint len) +{ + gchar *end, oldc; + GValue *retval; + + end = ptr + len; + oldc = *end; + *end = 0; + + retval = g_new0 (GValue, 1); + g_value_init (retval, G_TYPE_STRING); + g_value_set_string (retval, ptr); + + *end = oldc; + + return retval; +} + +static gboolean +handle_composed_2_keywords (GdaSqlParser *parser, GValue *retval, gint second, gint replacer); + +/* + * + * Returns: the token Id, or: + * L_ILLEGAL if an error occurred + * L_END_OF_FILE if nothing more to analyze + */ +static GValue * +getToken (GdaSqlParser *parser) +{ + GdaSqlParserPrivate *priv = gda_sql_parser_get_instance_private (parser); + int i, c; + gchar *z = priv->context->next_token_start; + GValue *retval = NULL; + gint consumed_chars = 1; + + /* init to capture non treaded cases */ + priv->context->token_type = G_MININT; + + if (!*z) { + priv->context->token_type = L_END_OF_FILE; + consumed_chars = 0; + goto tok_end; + } + +#ifdef GDA_DEBUG_NO + gchar debug_hold = 0; + gboolean debugcut = FALSE; + if (strlen (z) > 50) { + debugcut = TRUE; + debug_hold = z[50]; + z[50] = 0; + } + + g_print ("TOK for `%s` (delim='%c') is: ", z, priv->context->delimiter); + if (debugcut) + z[50] = debug_hold; +#endif + + if (*z == priv->context->delimiter) { + if (!priv->context->ignore_semi && (priv->context->block_level == 0)) + priv->context->token_type = L_SEMI; + else + priv->context->token_type = L_RAWSTRING; + consumed_chars = 1; + retval = token_as_string (priv->context->next_token_start, 1); + goto tok_end; + } + + switch (*z) { + case ' ': case '\t': case '\n': case '\f': case '\r': { + for (i=1; isspace (z[i]); i++){} + if ((z[i] == '/') && (z[i+1] == '*')) { + priv->context->token_type = L_LSBRACKET; + consumed_chars = i + 2; + priv->context->in_param_spec = TRUE; + } + else { + priv->context->token_type = L_SPACE; + consumed_chars = i; + } + break; + } + case '-': + if ( z[1]=='-' ){ + for (i=2; (c=z[i])!=0 && c!='\n'; i++){} + priv->context->token_type = L_SQLCOMMENT; + consumed_chars = i; + } + else { + priv->context->token_type = L_MINUS; + consumed_chars = 1; + } + break; + + case '(': + priv->context->token_type = L_LP; + consumed_chars = 1; + break; + case ')': + priv->context->token_type = L_RP; + consumed_chars = 1; + break; + case '+': + if (priv->mode != GDA_SQL_PARSER_MODE_DELIMIT) { + priv->context->token_type = L_PLUS; + consumed_chars = 1; + } + break; + case '*': + if (z[1] == '/') { + priv->context->token_type = L_RSBRACKET; + consumed_chars = 2; + priv->context->in_param_spec = FALSE; + } + else { + priv->context->token_type = L_STAR; + consumed_chars = 1; + } + break; + case '%': + if (priv->mode != GDA_SQL_PARSER_MODE_DELIMIT) { + priv->context->token_type = L_REM; + consumed_chars = 1; + } + break; + case '/': + if (priv->mode != GDA_SQL_PARSER_MODE_DELIMIT) { + if (z[1] != '*' || z[2] == 0) { + priv->context->token_type = L_SLASH; + consumed_chars = 1; + } + } + else if (z[1] == '*') { + /* delimit mode */ + priv->context->token_type = L_LSBRACKET; + consumed_chars = 2; + priv->context->in_param_spec = TRUE; + } + break; + case '=': + if (priv->mode != GDA_SQL_PARSER_MODE_DELIMIT) { + priv->context->token_type = L_EQ; + consumed_chars = 1 + (z[1] == '='); + } + break; + case '<': + if ((c = z[1]) == '=') { + priv->context->token_type = L_LEQ; + consumed_chars = 2; + } + else if (c == '>') { + priv->context->token_type = L_DIFF; + consumed_chars = 2; + } + else if (c== '<') { + priv->context->token_type = L_LSHIFT; + consumed_chars = 2; + } + else { + priv->context->token_type = L_LT; + consumed_chars = 1; + } + break; + case '>': + if ((c = z[1]) == '=') { + priv->context->token_type = L_GEQ; + consumed_chars = 2; + } + else if (c == '>') { + priv->context->token_type = L_RSHIFT; + consumed_chars = 2; + } + else { + priv->context->token_type = L_GT; + consumed_chars = 1; + } + break; + case '!': + if (priv->mode != GDA_SQL_PARSER_MODE_DELIMIT) { + if ((c = z[1]) == '=') { + priv->context->token_type = L_DIFF; + consumed_chars = 2; + } + else if (c == '~') { + if (z[2] == '*') { + priv->context->token_type = L_NOT_REGEXP_CI; + consumed_chars = 3; + } + else { + priv->context->token_type = L_NOT_REGEXP; + consumed_chars = 2; + } + } + } + break; + case '|': + if (priv->mode != GDA_SQL_PARSER_MODE_DELIMIT) { + if (z[1] != '|') { + priv->context->token_type = L_BITOR; + consumed_chars = 1; + } else { + priv->context->token_type = L_CONCAT; + consumed_chars = 2; + } + } + else { + priv->context->token_type = L_RAWSTRING; + consumed_chars = 1; + } + break; + case ',': + priv->context->token_type = L_COMMA; + consumed_chars = 1; + break; + case '&': + if (priv->mode != GDA_SQL_PARSER_MODE_DELIMIT) { + priv->context->token_type = L_BITAND; + consumed_chars = 1; + } + break; + case '~': + if (priv->mode != GDA_SQL_PARSER_MODE_DELIMIT) { + if (z[1] == '*') { + priv->context->token_type = L_REGEXP_CI; + consumed_chars = 2; + } + else { + if (priv->flavour == GDA_SQL_PARSER_FLAVOUR_POSTGRESQL) + priv->context->token_type = L_REGEXP; + else + priv->context->token_type = L_BITNOT; + consumed_chars = 1; + } + } + break; + case '\'': + case '"': { + char delim = z[0]; + for (i = 1; (c = z[i]) != 0; i++) { + if (c == delim) { + if (z[i+1] == delim) + i++; + else + break; + } + else if (c == '\\') + i++; + } + if (c) { + if (delim == '"') + priv->context->token_type = L_TEXTUAL; + else + priv->context->token_type = L_STRING; + consumed_chars = i+1; + } + else { + priv->context->token_type = L_ILLEGAL; + consumed_chars = 0; + } + break; + } + + + case '.': case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': { + if ((*z) == '.') { + if (priv->mode != GDA_SQL_PARSER_MODE_DELIMIT) { + if (! isdigit (z[1])) { + priv->context->token_type = L_DOT; + consumed_chars = 1; + break; + } + /* If the next character is a digit, this is a floating point + ** number that begins with ".". Fall thru into the next case */ + } + } + priv->context->token_type = L_INTEGER; + if ((z[0] == '0') && ((z[1] == 'x') || (z[1] == 'X')) && (z[2] != 0)) { + /* hexadecimal */ + for (i=2; isxdigit (z[i]); i++){} + } + else { + for (i=0; isdigit (z[i]); i++){} + if (z[i] == '.') { + i++; + while (isdigit (z[i])) {i++;} + priv->context->token_type = L_FLOAT; + } + if ((z[i]=='e' || z[i]=='E') && + (isdigit (z[i+1]) || + ((z[i+1]=='+' || z[i+1]=='-') && isdigit (z[i+2])))) { + i += 2; + while (isdigit (z[i])) {i++;} + priv->context->token_type = L_FLOAT; + } + } + if (priv->mode != GDA_SQL_PARSER_MODE_DELIMIT) { + while (IdChar (z[i])) { + priv->context->token_type = L_ILLEGAL; + i++; + } + } + else { + while (IdChar (z[i])) { + priv->context->token_type = L_RAWSTRING; + i++; + } + } + consumed_chars = i; + break; + } + case '?': + if (priv->flavour == GDA_SQL_PARSER_FLAVOUR_SQLITE) { + for(i=1; isdigit(z[i]); i++){} + priv->context->token_type = L_SIMPLEPARAM; + retval = token_as_string (priv->context->next_token_start + 1, i - 1); + consumed_chars = i; + } + break; + case '#': { + if (z[1] == '#') { + /* parameter */ + for (i=2; (z[i]) && + (IdChar (z[i]) || (z[i] == '+') || (z[i] == '-') || (z[i] == '.') || (z[i] == ':') || + (z[i] == '|') || (z[i] == '@') || (z[i] == '?')) && + (z[i] != '/') && (z[i] != priv->context->delimiter) + /*(!isspace (z[i])) && (z[i] != '/') && + (z[i] != priv->context->delimiter)*/; i++) {} + if (i > 2) { + priv->context->token_type = L_SIMPLEPARAM; + retval = token_as_string (priv->context->next_token_start + 2, i - 2); + } + else + priv->context->token_type = L_UNSPECVAL; + consumed_chars = i; + } + else { + if (priv->flavour == GDA_SQL_PARSER_FLAVOUR_MYSQL) { + /* comment */ + for (i=1; (c=z[i])!=0 && c!='\n'; i++){} + priv->context->token_type = L_SQLCOMMENT; + consumed_chars = i; + } + else + priv->context->token_type = L_ILLEGAL; + } + break; + } + case '$': + if (priv->flavour == GDA_SQL_PARSER_FLAVOUR_POSTGRESQL) { + for(i=1; isalnum(z[i]) || (z[i] == '_'); i++){} + if (z[i] == '$') { + /* this is the start of the PostgreSQL's Dollar-Quoted strings */ + gchar *tag_start = z; + gint tag_len = i+1; + + /* no matching tag found => error */ + priv->context->token_type = L_ILLEGAL; + + i++; + while (z[i]) { + /* go to the next '$' */ + gint j; + for (; z[i] && (z[i] != '$'); i++); + for (j = 0; j < tag_len; j++, i++) { + if (z[i] != tag_start[j]) + break; /* for */ + } + if (j == tag_len) { + /* tags matched */ + priv->context->token_type = L_STRING; + consumed_chars = i; + + retval = token_as_string (priv->context->next_token_start, consumed_chars); + /* remove comments from returned string */ + gchar *tmp, *ptr; + tmp = (gchar*) g_value_get_string (retval); + for (ptr = tmp; *ptr; ptr++) { + if (((ptr == tmp) || (*(ptr-1) == '\n')) && (*ptr == '-') && (ptr[1] == '-')) { + /* we have a comment */ + gchar *ptr2; + for (ptr2 = ptr + 2; ptr2 && (*ptr2 != '\n'); ptr2++) {}; + memmove (ptr, ptr2, sizeof (char) * (strlen (ptr2) + 1)); + } + } + + break; /* while */ + } + i++; + } + } + } + else if (priv->flavour == GDA_SQL_PARSER_FLAVOUR_SQLITE) { + for(i=1; isalnum(z[i]); i++){} + priv->context->token_type = L_SIMPLEPARAM; + retval = token_as_string (priv->context->next_token_start + 1, i - 1); + consumed_chars = i; + } + break; + case '@': + case ':': + if (z[1] == ':') { + priv->context->token_type = L_PGCAST; + consumed_chars = 2; + } + else if (priv->flavour == GDA_SQL_PARSER_FLAVOUR_SQLITE) { + for(i=1; isalnum(z[i]) || (z[i] == '_'); i++){} + priv->context->token_type = L_SIMPLEPARAM; + retval = token_as_string (priv->context->next_token_start + 1, i - 1); + consumed_chars = i; + } + break; +#ifndef SQLITE_OMIT_BLOB_LITERAL + case 'x': case 'X': { + if ( (c=z[1])=='\'' || c=='"' ){ + int delim = c; + priv->context->token_type = L_BLOB; + for (i=2; (c=z[i])!=0; i++){ + if ( c==delim ){ + if ( i%2 ) priv->context->token_type = L_ILLEGAL; + break; + } + if ( !isxdigit (c) ){ + priv->context->token_type = L_ILLEGAL; + consumed_chars = i; + break; + } + } + if ( c ) i++; + consumed_chars = i; + } + break; + } +#endif + default: + break; + } + + if (priv->context->token_type == G_MININT) { + /* now treat non treated cases */ + if ((priv->mode != GDA_SQL_PARSER_MODE_DELIMIT) && (! priv->context->in_param_spec)) { + if (IdChar (*z)) { + for (i=1; IdChar (z[i]); i++){} + priv->context->token_type = keywordCode (parser, (char*)z, i); + consumed_chars = i; + } + } + else { + if ((! priv->context->in_param_spec) && IdChar (*z)) { + gint ttype; + + for (i=1; IdChar (z[i]); i++){} + ttype = keywordCode (parser, (char*)z, i); + if (ttype != L_RAWSTRING) { + priv->context->token_type = ttype; + consumed_chars = i; + } + } + + if (priv->context->token_type == G_MININT) { + if (!strncmp (priv->context->next_token_start, "name:", 5)) { + priv->context->next_token_start += 5; + retval = getToken (parser); + priv->context->token_type = L_PNAME; + consumed_chars = 0; + } + else if (!strncmp (priv->context->next_token_start, "type:", 5)) { + priv->context->next_token_start += 5; + retval = getToken (parser); + priv->context->token_type = L_PTYPE; + consumed_chars = 0; + } + else if (!strncmp (priv->context->next_token_start, "descr:", 6)) { + priv->context->next_token_start += 6; + retval = getToken (parser); + priv->context->token_type = L_PDESCR; + consumed_chars = 0; + } + else if (!strncmp (priv->context->next_token_start, "nullok:", 7)) { + priv->context->next_token_start += 7; + retval = getToken (parser); + priv->context->token_type = L_PNULLOK; + consumed_chars = 0; + } + else { + for (i=1; z[i] && (! isspace (z[i])) && + (z[i] != priv->context->delimiter) && (z[i] != '*') && + (z[i] != '\'') && (z[i] != '"') && (z[i] != '#'); i++){} + priv->context->token_type = L_RAWSTRING; + consumed_chars = i; + } + } + } + } + + /* fallback for the token type */ + if (priv->context->token_type == G_MININT) + priv->context->token_type = L_ILLEGAL; + + if (!retval) + retval = token_as_string (priv->context->next_token_start, consumed_chars); + tok_end: + priv->context->last_token_start = priv->context->next_token_start; + priv->context->next_token_start += consumed_chars; + + if (priv->context->token_type == L_END) + handle_composed_2_keywords (parser, retval, L_LOOP, L_ENDLOOP); + else if (priv->context->token_type == L_IS) + handle_composed_2_keywords (parser, retval, L_NULL, L_ISNULL); + else if (priv->context->token_type == L_NOT) { + if (!handle_composed_2_keywords (parser, retval, L_NULL, L_NOTNULL)) { + if (!handle_composed_2_keywords (parser, retval, L_LIKE, L_NOTLIKE)) { + handle_composed_2_keywords (parser, retval, L_ILIKE, L_NOTILIKE); + } + } + } + else if (priv->context->token_type == L_SIMILAR) + handle_composed_2_keywords (parser, retval, L_TO, L_SIMILAR); + +#ifdef GDA_DEBUG_NO + if (retval) { + gchar *str = gda_sql_value_stringify (retval); + g_print ("%d (%s)\n", priv->context->token_type, str); + g_free (str); + } + else if (priv->context->token_type == L_END_OF_FILE) + g_print ("%d (END OF FILE)\n", priv->context->token_type); + else + g_print ("%d\n", priv->context->token_type); +#endif + return retval; +} + +static gboolean +handle_composed_2_keywords (GdaSqlParser *parser, GValue *retval, gint second, gint replacer) +{ + GdaSqlParserPrivate *priv = gda_sql_parser_get_instance_private (parser); + gint npushed, nmatched; + GValue *v = NULL; + gboolean match; + nmatched = fetch_forward (parser, &npushed, second, &v, 0); + match = (nmatched == 1); + if (match) { + gchar *newstr; + merge_tokenizer_contexts (parser, npushed); + priv->context->token_type = replacer; + + newstr = g_strdup_printf ("%s %s", g_value_get_string (retval), g_value_get_string (v)); + g_value_reset (retval); + g_value_take_string (retval, newstr); + } + if (v) { + g_value_reset (v); + g_free (v); + } + return match; +} + +static GValue * +tokenizer_get_next_token (GdaSqlParser *parser) +{ + return getToken (parser); +} + +static void +push_tokenizer_context (GdaSqlParser *parser) +{ + GdaSqlParserPrivate *priv = gda_sql_parser_get_instance_private (parser); + TokenizerContext *nc; + + nc = g_new (TokenizerContext, 1); + *nc = *priv->context; + priv->pushed_contexts = g_slist_prepend (priv->pushed_contexts, priv->context); + priv->context = nc; +#ifdef GDA_DEBUG_NO + g_print ("Push context\n"); +#endif +} + +static void +pop_tokenizer_context (GdaSqlParser *parser) +{ + GdaSqlParserPrivate *priv = gda_sql_parser_get_instance_private (parser); + g_return_if_fail (priv->pushed_contexts); + g_free (priv->context); + priv->context = (TokenizerContext*) priv->pushed_contexts->data; + priv->pushed_contexts = g_slist_remove (priv->pushed_contexts, priv->context); +#ifdef GDA_DEBUG_NO + g_print ("Pop context\n"); +#endif +} + +/* + * Looks forward which tokens are available next, and returns the number of tokens corresponding to + * expected token(s) + * + * extra arguments are a list of (gint expected_type, GValue **value) followed by 0 + */ +static gint +fetch_forward (GdaSqlParser *parser, gint *out_nb_pushed, ...) +{ + GdaSqlParserPrivate *priv = gda_sql_parser_get_instance_private (parser); + gint nmatched = 0; + gint npushed = 0; + va_list ap; + + gint exp_type; + va_start (ap, out_nb_pushed); + exp_type = va_arg (ap, gint); + while (exp_type != 0) { + GValue **holder; + GValue *v1; + gint ttype; + + holder = va_arg (ap, GValue **); + if (holder) + *holder = NULL; + + push_tokenizer_context (parser); npushed++; + v1 = getToken (parser); + ttype = priv->context->token_type; + if (ttype == L_SPACE) { + GValue *v2; + push_tokenizer_context (parser); npushed++; + v2 = getToken (parser); + ttype = priv->context->token_type; + g_value_reset (v1); + g_free (v1); + v1 = v2; + } + if (ttype != exp_type) { + if (v1) { + g_value_reset (v1); + g_free (v1); + } + + /* not what was expected => pop all the contexts */ + for (; npushed > nmatched ; npushed--) + pop_tokenizer_context (parser); + break; /* while */ + } + else { + if (holder) + *holder = v1; + else { + g_value_reset (v1); + g_free (v1); + } + nmatched ++; + } + exp_type = va_arg (ap, gint); + } + va_end (ap); + + if (out_nb_pushed) + *out_nb_pushed = npushed; + return nmatched; +} + +/* merge the @n_contexts into the current context */ +static void +merge_tokenizer_contexts (GdaSqlParser *parser, gint n_contexts) +{ + GdaSqlParserPrivate *priv = gda_sql_parser_get_instance_private (parser); + TokenizerContext *c; + gint i; + g_return_if_fail (n_contexts > 0); + + c = g_slist_nth_data (priv->pushed_contexts, n_contexts - 1); + g_return_if_fail (c); + + priv->context->token_type = c->token_type; + priv->context->last_token_start = c->last_token_start; + priv->context->delimiter = c->delimiter; + for (i = 0; i < n_contexts; i++) { + g_free (priv->pushed_contexts->data); + priv->pushed_contexts = g_slist_remove (priv->pushed_contexts, + priv->pushed_contexts->data); + } +} + +static void +gda_sql_parser_lock (GdaLockable *lockable) +{ + GdaSqlParser *parser = (GdaSqlParser *) lockable; + GdaSqlParserPrivate *priv = gda_sql_parser_get_instance_private (parser); + + g_rec_mutex_lock (& (priv->mutex)); +} + +static gboolean +gda_sql_parser_trylock (GdaLockable *lockable) +{ + GdaSqlParser *parser = (GdaSqlParser *) lockable; + GdaSqlParserPrivate *priv = gda_sql_parser_get_instance_private (parser); + + return g_rec_mutex_trylock (& (priv->mutex)); +} + +static void +gda_sql_parser_unlock (GdaLockable *lockable) +{ + GdaSqlParser *parser = (GdaSqlParser *) lockable; + GdaSqlParserPrivate *priv = gda_sql_parser_get_instance_private (parser); + + g_rec_mutex_unlock (& (priv->mutex)); +} diff --git a/.flatpak-builder/cache/objects/b3/206371aa2c4857c4288b85c81d2720489ba77ce8f167783bf04de58cb8c4c4.dirtree b/.flatpak-builder/cache/objects/b3/206371aa2c4857c4288b85c81d2720489ba77ce8f167783bf04de58cb8c4c4.dirtree new file mode 100644 index 0000000..fe33e3d Binary files /dev/null and b/.flatpak-builder/cache/objects/b3/206371aa2c4857c4288b85c81d2720489ba77ce8f167783bf04de58cb8c4c4.dirtree differ diff --git a/.flatpak-builder/cache/objects/b3/3be7d628c29d77adcde013307e77d50823a11159c855ba954eea165ec4325d.dirtree b/.flatpak-builder/cache/objects/b3/3be7d628c29d77adcde013307e77d50823a11159c855ba954eea165ec4325d.dirtree new file mode 100644 index 0000000..b388f7f Binary files /dev/null and b/.flatpak-builder/cache/objects/b3/3be7d628c29d77adcde013307e77d50823a11159c855ba954eea165ec4325d.dirtree differ diff --git a/.flatpak-builder/cache/objects/b3/7df1c289309887e1d8406a015f4e5a704cf5937df5b8a64490a84ed2421ea2.commit b/.flatpak-builder/cache/objects/b3/7df1c289309887e1d8406a015f4e5a704cf5937df5b8a64490a84ed2421ea2.commit new file mode 100644 index 0000000..3510d6d Binary files /dev/null and b/.flatpak-builder/cache/objects/b3/7df1c289309887e1d8406a015f4e5a704cf5937df5b8a64490a84ed2421ea2.commit differ diff --git a/.flatpak-builder/cache/objects/b3/9f6733f20d4325843281a5364c2495f9d9815ad9393fbffc9c7217f54b04e5.dirtree b/.flatpak-builder/cache/objects/b3/9f6733f20d4325843281a5364c2495f9d9815ad9393fbffc9c7217f54b04e5.dirtree new file mode 100644 index 0000000..f17e6cf Binary files /dev/null and b/.flatpak-builder/cache/objects/b3/9f6733f20d4325843281a5364c2495f9d9815ad9393fbffc9c7217f54b04e5.dirtree differ diff --git a/.flatpak-builder/cache/objects/b4/1985f55d1a56d895b7404d6ac1559eb8f5f5a2e1836c340471597505b2757e.file b/.flatpak-builder/cache/objects/b4/1985f55d1a56d895b7404d6ac1559eb8f5f5a2e1836c340471597505b2757e.file new file mode 100644 index 0000000..3955fd8 Binary files /dev/null and b/.flatpak-builder/cache/objects/b4/1985f55d1a56d895b7404d6ac1559eb8f5f5a2e1836c340471597505b2757e.file differ diff --git a/.flatpak-builder/cache/objects/b4/56e60aa93685e652108722ae8a51105d9f33dce876196de595c060c85955ab.file b/.flatpak-builder/cache/objects/b4/56e60aa93685e652108722ae8a51105d9f33dce876196de595c060c85955ab.file new file mode 100755 index 0000000..a845acb Binary files /dev/null and b/.flatpak-builder/cache/objects/b4/56e60aa93685e652108722ae8a51105d9f33dce876196de595c060c85955ab.file differ diff --git a/.flatpak-builder/cache/objects/b5/0bb66cece5620288e902724f4f1478b83c9f88416463927cd90d647e0f4cc8.file b/.flatpak-builder/cache/objects/b5/0bb66cece5620288e902724f4f1478b83c9f88416463927cd90d647e0f4cc8.file new file mode 100755 index 0000000..3cd8678 --- /dev/null +++ b/.flatpak-builder/cache/objects/b5/0bb66cece5620288e902724f4f1478b83c9f88416463927cd90d647e0f4cc8.file @@ -0,0 +1,41 @@ +# libcanberra-multi.la - a libtool library file +# Generated by libtool (GNU libtool) 2.4.2 +# +# Please DO NOT delete this file! +# It is necessary for linking the library. + +# The name that we can dlopen(3). +dlname='libcanberra-multi.so' + +# Names of this library. +library_names='libcanberra-multi.so libcanberra-multi.so libcanberra-multi.so' + +# The name of the static archive. +old_library='' + +# Linker flags that can not go in dependency_libs. +inherited_linker_flags='' + +# Libraries that this one depends upon. +dependency_libs=' -L/app/lib /app/lib/libcanberra.la -lvorbisfile -lltdl -lm' + +# Names of additional weak libraries provided by this library +weak_library_names='' + +# Version information for libcanberra-multi. +current=0 +age=0 +revision=0 + +# Is this an already installed library? +installed=yes + +# Should we warn about portability when linking against -modules? +shouldnotlink=yes + +# Files to dlopen/dlpreopen +dlopen='' +dlpreopen='' + +# Directory that this library needs to be installed in: +libdir='/app/lib/libcanberra-0.30' diff --git a/.flatpak-builder/cache/objects/b5/0db2400970f55ebc92be3e5828d20e0e046fe0ff9c4c10ebe79231405e462c.dirtree b/.flatpak-builder/cache/objects/b5/0db2400970f55ebc92be3e5828d20e0e046fe0ff9c4c10ebe79231405e462c.dirtree new file mode 100644 index 0000000..a358b84 Binary files /dev/null and b/.flatpak-builder/cache/objects/b5/0db2400970f55ebc92be3e5828d20e0e046fe0ff9c4c10ebe79231405e462c.dirtree differ diff --git a/.flatpak-builder/cache/objects/b5/541ac49e501f64afb5287726f76dec064b06a639b3c5587db4f2df9637fa10.file b/.flatpak-builder/cache/objects/b5/541ac49e501f64afb5287726f76dec064b06a639b3c5587db4f2df9637fa10.file new file mode 100644 index 0000000..3ece6b3 --- /dev/null +++ b/.flatpak-builder/cache/objects/b5/541ac49e501f64afb5287726f76dec064b06a639b3c5587db4f2df9637fa10.file @@ -0,0 +1,2041 @@ +/* + * Copyright (C) 2008 Massimo Cora + * Copyright (C) 2008 - 2011 Murray Cumming + * Copyright (C) 2008 - 2014 Vivien Malerba + * Copyright (C) 2009 Bas Driessen + * Copyright (C) 2010 David King + * Copyright (C) 2010 Jonh Wendell + * Copyright (C) 2011 Daniel Espinosa + * Copyright (C) 2015 Corentin Noël + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +#define G_LOG_DOMAIN "GDA-holder" + +#include +#include +#include +#include "gda-holder.h" +#include "gda-statement.h" +#include "gda-data-model.h" +#include "gda-data-handler.h" +#include "gda-marshal.h" +#include "gda-util.h" +#include +#include + +/* + * Main static functions + */ +static void gda_holder_class_init (GdaHolderClass * class); +static void gda_holder_init (GdaHolder *holder); +static void gda_holder_dispose (GObject *object); +static void gda_holder_finalize (GObject *object); + +static void gda_holder_set_property (GObject *object, + guint param_id, + const GValue *value, + GParamSpec *pspec); +static void gda_holder_get_property (GObject *object, + guint param_id, + GValue *value, + GParamSpec *pspec); + +/* GdaLockable interface */ +static void gda_holder_lockable_init (GdaLockableInterface *iface); +static void gda_holder_lock (GdaLockable *lockable); +static gboolean gda_holder_trylock (GdaLockable *lockable); +static void gda_holder_unlock (GdaLockable *lockable); + + +static void bound_holder_changed_cb (GdaHolder *alias_of, GdaHolder *holder); +static void full_bound_holder_changed_cb (GdaHolder *alias_of, GdaHolder *holder); +static void gda_holder_set_full_bind (GdaHolder *holder, GdaHolder *alias_of); + +/* signals */ +enum +{ + CHANGED, + SOURCE_CHANGED, + VALIDATE_CHANGE, + TO_DEFAULT, + LAST_SIGNAL +}; + +static gint gda_holder_signals[LAST_SIGNAL] = { 0, 0, 0 }; + + +/* properties */ +enum +{ + PROP_0, + PROP_ID, + PROP_NAME, + PROP_DESCR, + PROP_SIMPLE_BIND, + PROP_FULL_BIND, + PROP_SOURCE_MODEL, + PROP_SOURCE_COLUMN, + PROP_GDA_TYPE, + PROP_NOT_NULL, + PROP_VALIDATE_CHANGES, + PROP_PLUGIN +}; + + +typedef struct { + gchar *id; + + GType g_type; + GdaHolder *full_bind; /* FULL bind to holder */ + GdaHolder *simple_bind; /* SIMPLE bind to holder */ + gulong simple_bind_type_changed_id; + + gboolean invalid_forced; + GError *invalid_error; + gboolean valid; + gboolean is_freeable; + + GValue *value; + GValue *default_value; /* CAN be either NULL or of any type */ + gboolean default_forced; + gboolean not_null; /* TRUE if 'value' must not be NULL when passed to destination fields */ + + GdaDataModel *source_model; + gint source_col; + + GRecMutex mutex; + + gboolean validate_changes; + gchar *name; + gchar *desc; + gchar *plugin; +} GdaHolderPrivate; +G_DEFINE_TYPE_WITH_CODE (GdaHolder, gda_holder, G_TYPE_OBJECT, + G_ADD_PRIVATE (GdaHolder) + G_IMPLEMENT_INTERFACE(GDA_TYPE_LOCKABLE, gda_holder_lockable_init)) +/* module error */ +GQuark gda_holder_error_quark (void) +{ + static GQuark quark; + if (!quark) + quark = g_quark_from_static_string ("gda_holder_error"); + return quark; +} + +static gboolean +validate_change_accumulator (G_GNUC_UNUSED GSignalInvocationHint *ihint, + GValue *return_accu, + const GValue *handler_return, + G_GNUC_UNUSED gpointer data) +{ + GError *error; + + error = g_value_get_boxed (handler_return); + g_value_set_boxed (return_accu, error); + + return error ? FALSE : TRUE; /* stop signal if error has been set */ +} + +static GError * +m_validate_change (G_GNUC_UNUSED GdaHolder *holder, G_GNUC_UNUSED const GValue *new_value) +{ + return NULL; +} + +static void +gda_holder_class_init (GdaHolderClass *class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (class); + + /** + * GdaHolder::source-changed: + * @holder: the #GdaHolder + * + * Gets emitted when the data model in which @holder's values should be has changed + */ + gda_holder_signals[SOURCE_CHANGED] = + g_signal_new ("source-changed", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (GdaHolderClass, source_changed), + NULL, NULL, + _gda_marshal_VOID__VOID, G_TYPE_NONE, 0); + /** + * GdaHolder::changed: + * @holder: the #GdaHolder + * + * Gets emitted when @holder's value has changed + */ + gda_holder_signals[CHANGED] = + g_signal_new ("changed", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (GdaHolderClass, changed), + NULL, NULL, + _gda_marshal_VOID__VOID, G_TYPE_NONE, 0); + + /** + * GdaHolder::validate-change: + * @holder: the object which received the signal + * @new_value: the proposed new value for @holder + * + * Gets emitted when @holder is going to change its value. One can connect to + * this signal to control which values @holder can have (for example to implement some business rules) + * + * Returns: NULL if @holder is allowed to change its value to @new_value, or a #GError + * otherwise. + */ + gda_holder_signals[VALIDATE_CHANGE] = + g_signal_new ("validate-change", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GdaHolderClass, validate_change), + validate_change_accumulator, NULL, + _gda_marshal_ERROR__VALUE, G_TYPE_ERROR, 1, G_TYPE_VALUE); + /** + * GdaHolder::to-default: + * @holder: the object which received the signal + * + * Gets emitted when @holder is set to its default value + */ + gda_holder_signals[TO_DEFAULT] = + g_signal_new ("to-default", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (GdaHolderClass, to_default), + NULL, NULL, + NULL, G_TYPE_NONE, 0); + + class->changed = NULL; + class->source_changed = NULL; + class->validate_change = m_validate_change; + class->to_default = NULL; + + /* virtual functions */ + object_class->dispose = gda_holder_dispose; + object_class->finalize = gda_holder_finalize; + + /* Properties */ + object_class->set_property = gda_holder_set_property; + object_class->get_property = gda_holder_get_property; + g_object_class_install_property (object_class, PROP_ID, + g_param_spec_string ("id", NULL, "Holder's ID", NULL, + (G_PARAM_READABLE | G_PARAM_WRITABLE))); + g_object_class_install_property (object_class, PROP_NAME, + g_param_spec_string ("name", NULL, "Holder's name", NULL, + (G_PARAM_READABLE | G_PARAM_WRITABLE))); + g_object_class_install_property (object_class, PROP_DESCR, + g_param_spec_string ("description", NULL, "Holder's description", NULL, + (G_PARAM_READABLE | G_PARAM_WRITABLE))); + g_object_class_install_property (object_class, PROP_GDA_TYPE, + g_param_spec_gtype ("g-type", NULL, "Holder's GType", G_TYPE_NONE, + (G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT))); + g_object_class_install_property (object_class, PROP_NOT_NULL, + g_param_spec_boolean ("not-null", NULL, "Can the value holder be NULL?", FALSE, + (G_PARAM_READABLE | G_PARAM_WRITABLE))); + g_object_class_install_property (object_class, PROP_SIMPLE_BIND, + g_param_spec_object ("simple-bind", NULL, + "Make value holder follow other GdaHolder's changes", + GDA_TYPE_HOLDER, + (G_PARAM_READABLE | G_PARAM_WRITABLE))); + g_object_class_install_property (object_class, PROP_FULL_BIND, + g_param_spec_object ("full-bind", NULL, + "Make value holder follow other GdaHolder's changes " + "and the other way around", + GDA_TYPE_HOLDER, + (G_PARAM_READABLE | G_PARAM_WRITABLE))); + g_object_class_install_property (object_class, PROP_SOURCE_MODEL, + g_param_spec_object ("source-model", NULL, "Data model among which the holder's " + "value should be", + GDA_TYPE_DATA_MODEL, + (G_PARAM_READABLE | G_PARAM_WRITABLE))); + g_object_class_install_property (object_class, PROP_SOURCE_COLUMN, + g_param_spec_int ("source-column", NULL, "Column number to use in coordination " + "with the source-model property", + 0, G_MAXINT, 0, + (G_PARAM_READABLE | G_PARAM_WRITABLE))); + g_object_class_install_property (object_class, PROP_PLUGIN, + g_param_spec_string ("plugin", NULL, "Holder's plugin", NULL, + (G_PARAM_READABLE | G_PARAM_WRITABLE))); + + /** + * GdaHolder:validate-changes: + * + * Defines if the "validate-change" signal gets emitted when + * the holder's value changes. + * + * Since: 5.2.0 + */ + g_object_class_install_property (object_class, PROP_VALIDATE_CHANGES, + g_param_spec_boolean ("validate-changes", NULL, "Defines if the validate-change signal is emitted on value change", TRUE, + (G_PARAM_READABLE | G_PARAM_WRITABLE))); +} + +static void +gda_holder_lockable_init (GdaLockableInterface *iface) +{ + iface->lock = gda_holder_lock; + iface->trylock = gda_holder_trylock; + iface->unlock = gda_holder_unlock; +} + +static void +gda_holder_init (GdaHolder *holder) +{ + GdaHolderPrivate *priv = gda_holder_get_instance_private (holder); + + priv->id = g_strdup ("id"); + + priv->g_type = GDA_TYPE_NULL; + priv->full_bind = NULL; + priv->simple_bind = NULL; + priv->simple_bind_type_changed_id = 0; + + priv->invalid_forced = FALSE; + priv->invalid_error = NULL; + priv->valid = TRUE; + priv->default_forced = FALSE; + priv->is_freeable = TRUE; + priv->value = NULL; + priv->default_value = NULL; + + priv->not_null = FALSE; + priv->source_model = NULL; + priv->source_col = 0; + + g_rec_mutex_init (& (priv->mutex)); + + priv->validate_changes = TRUE; + priv->name = NULL; + priv->desc = NULL; + priv->plugin = NULL; +} + +/** + * gda_holder_new: + * @type: the #GType requested + * @id: an identifiation + * + * Creates a new holder of type @type + * + * Returns: a new #GdaHolder object + */ +GdaHolder * +gda_holder_new (GType type, const gchar *id) +{ + g_return_val_if_fail (id != NULL, NULL); + return (GdaHolder*) g_object_new (GDA_TYPE_HOLDER, "g-type", type, "id", id, NULL); +} + +/** + * gda_holder_copy: + * @orig: a #GdaHolder object to copy + * + * Copy constructor. + * + * Note1: if @orig is set with a static value (see gda_holder_take_static_value()) + * its copy will have a fresh new allocated GValue, so that user should free it when done. + * + * Returns: (transfer full): a new #GdaHolder object + */ +GdaHolder * +gda_holder_copy (GdaHolder *orig) +{ + GObject *obj; + GdaHolder *holder; + gboolean allok = TRUE; + + g_return_val_if_fail (orig && GDA_IS_HOLDER (orig), NULL); + GdaHolderPrivate *priv = gda_holder_get_instance_private (orig); + + gda_holder_lock ((GdaLockable*) orig); + obj = g_object_new (GDA_TYPE_HOLDER, "g-type", priv->g_type, NULL); + holder = GDA_HOLDER (obj); + GdaHolderPrivate *cpriv = gda_holder_get_instance_private (holder); + + if (priv->id) { + g_free (cpriv->id); + cpriv->id = g_strdup (priv->id); + } + if (priv->name) + cpriv->name = g_strdup (priv->name); + if (priv->desc) + cpriv->desc = g_strdup (priv->desc); + if (priv->plugin) + cpriv->plugin = g_strdup (priv->plugin); + + if (priv->full_bind) + gda_holder_set_full_bind (holder, priv->full_bind); + if (priv->simple_bind) + allok = gda_holder_set_bind (holder, priv->simple_bind, NULL); + + if (allok && priv->source_model) { + /*g_print ("Source holder %p\n", holder);*/ + allok = gda_holder_set_source_model (holder, priv->source_model, priv->source_col, + NULL); + } + + if (allok) { + /* direct settings */ + cpriv->invalid_forced = priv->invalid_forced; + if (priv->invalid_error) + cpriv->invalid_error = g_error_copy (priv->invalid_error); + cpriv->valid = priv->valid; + cpriv->is_freeable = TRUE; + cpriv->default_forced = priv->default_forced; + if (priv->value) + cpriv->value = gda_value_copy (priv->value); + if (priv->default_value) + cpriv->default_value = gda_value_copy (priv->default_value); + cpriv->not_null = priv->not_null; + + gda_holder_unlock ((GdaLockable*) orig); + return holder; + } + else { + g_warning ("Internal error: could not copy GdaHolder (please report a bug)."); + g_object_unref (holder); + gda_holder_unlock ((GdaLockable*) orig); + return NULL; + } +} + +/** + * gda_holder_new_inline: + * @type: a valid GLib type + * @id: (nullable): the id of the holder to create, or %NULL + * @...: value to set + * + * Creates a new #GdaHolder object with an ID set to @id, of type @type, + * and containing the value passed as the last argument. + * + * Note that this function is a utility function and that only a limited set of types are supported. Trying + * to use an unsupported type will result in a warning, and the returned value holder holding a safe default + * value. + * + * Returns: a new #GdaHolder object + */ +GdaHolder * +gda_holder_new_inline (GType type, const gchar *id, ...) +{ + GdaHolder *holder; + + static guint serial = 0; + const gchar *idm = NULL; + + g_print ("Creating inline: %s", id); + + if (id != NULL) { + idm = id; + } else { + idm = g_strdup_printf ("%d", serial++); + } + + holder = gda_holder_new (type, idm); + if (holder) { + GValue *value; + va_list ap; + GError *lerror = NULL; + + va_start (ap, id); + value = gda_value_new (type); + if (type == G_TYPE_BOOLEAN) + g_value_set_boolean (value, va_arg (ap, int)); + else if (type == G_TYPE_STRING) + g_value_set_string (value, va_arg (ap, gchar *)); + else if (type == G_TYPE_OBJECT) + g_value_set_object (value, va_arg (ap, gpointer)); + else if (type == G_TYPE_INT) + g_value_set_int (value, va_arg (ap, gint)); + else if (type == G_TYPE_UINT) + g_value_set_uint (value, va_arg (ap, guint)); + else if (type == GDA_TYPE_BINARY) + gda_value_set_binary (value, va_arg (ap, GdaBinary *)); + else if (type == G_TYPE_INT64) + g_value_set_int64 (value, va_arg (ap, gint64)); + else if (type == G_TYPE_UINT64) + g_value_set_uint64 (value, va_arg (ap, guint64)); + else if (type == GDA_TYPE_SHORT) + gda_value_set_short (value, va_arg (ap, int)); + else if (type == GDA_TYPE_USHORT) + gda_value_set_ushort (value, va_arg (ap, guint)); + else if (type == G_TYPE_CHAR) + g_value_set_schar (value, va_arg (ap, int)); + else if (type == G_TYPE_UCHAR) + g_value_set_uchar (value, va_arg (ap, guint)); + else if (type == G_TYPE_FLOAT) + g_value_set_float (value, va_arg (ap, double)); + else if (type == G_TYPE_DOUBLE) + g_value_set_double (value, va_arg (ap, gdouble)); + else if (type == G_TYPE_GTYPE) + g_value_set_gtype (value, va_arg (ap, GType)); + else if (type == G_TYPE_LONG) + g_value_set_long (value, va_arg (ap, glong)); + else if (type == G_TYPE_ULONG) + g_value_set_ulong (value, va_arg (ap, gulong)); + else if (type == GDA_TYPE_NUMERIC) + gda_value_set_numeric (value, va_arg (ap, GdaNumeric *)); + else if (type == G_TYPE_DATE) + g_value_set_boxed (value, va_arg (ap, GDate *)); + else { + g_warning ("%s() does not handle values of type %s, value will not be assigned.", + __FUNCTION__, g_type_name (type)); + g_object_unref (holder); + holder = NULL; + } + va_end (ap); + + if (holder && !gda_holder_set_value (holder, value, &lerror)) { + g_warning (_("Unable to set holder's value: %s"), + lerror && lerror->message ? lerror->message : _("No detail")); + if (lerror) + g_error_free (lerror); + g_object_unref (holder); + holder = NULL; + } + gda_value_free (value); + } + + return holder; +} + +static void +gda_holder_dispose (GObject *object) +{ + GdaHolder *holder; + + holder = GDA_HOLDER (object); + GdaHolderPrivate *priv = gda_holder_get_instance_private (holder); + gda_holder_set_bind (holder, NULL, NULL); + gda_holder_set_full_bind (holder, NULL); + + if (priv->id != NULL) { + g_free (priv->id); + priv->id = NULL; + } + + if (priv->source_model) { + g_object_unref (priv->source_model); + priv->source_model = NULL; + } + + priv->g_type = G_TYPE_INVALID; + + if (priv->value) { + if (priv->is_freeable) + gda_value_free (priv->value); + priv->value = NULL; + } + + if (priv->default_value) { + gda_value_free (priv->default_value); + priv->default_value = NULL; + } + + if (priv->invalid_error) { + g_error_free (priv->invalid_error); + priv->invalid_error = NULL; + } + + /* parent class */ + G_OBJECT_CLASS (gda_holder_parent_class)->dispose (object); +} + +static void +gda_holder_finalize (GObject * object) +{ + GdaHolder *holder; + + g_return_if_fail (object != NULL); + g_return_if_fail (GDA_IS_HOLDER (object)); + + holder = GDA_HOLDER (object); + GdaHolderPrivate *priv = gda_holder_get_instance_private (holder); + if (priv->id != NULL) { + g_free (priv->id); + priv->id = NULL; + } + if (priv->name != NULL) { + g_free (priv->name); + priv->name = NULL; + } + if (priv->desc != NULL) { + g_free (priv->desc); + priv->desc = NULL; + } + if (priv->plugin != NULL) { + g_free (priv->plugin); + priv->plugin = NULL; + } + g_rec_mutex_clear (& (priv->mutex)); + + /* parent class */ + G_OBJECT_CLASS (gda_holder_parent_class)->finalize (object); +} + + +static void +gda_holder_set_property (GObject *object, + guint param_id, + const GValue *value, + GParamSpec *pspec) +{ + GdaHolder *holder; + + holder = GDA_HOLDER (object); + GdaHolderPrivate *priv = gda_holder_get_instance_private (holder); + if (priv) { + switch (param_id) { + case PROP_ID: + if (priv->id != NULL) { + g_free (priv->id); + priv->id = NULL; + } + priv->id = g_value_dup_string (value); + break; + case PROP_NAME: + if (priv->name != NULL) { + g_free (priv->name); + priv->name = NULL; + } + priv->name = g_value_dup_string (value); + g_signal_emit (holder, gda_holder_signals[CHANGED], 0); + break; + case PROP_DESCR: + if (priv->desc != NULL) { + g_free (priv->desc); + priv->desc = NULL; + } + priv->desc = g_value_dup_string (value); + g_signal_emit (holder, gda_holder_signals[CHANGED], 0); + break; + case PROP_PLUGIN: + if (priv->plugin != NULL) { + g_free (priv->plugin); + priv->plugin = NULL; + } + priv->plugin = g_value_dup_string (value); + g_signal_emit (holder, gda_holder_signals[CHANGED], 0); + break; + case PROP_GDA_TYPE: + if (priv->g_type == GDA_TYPE_NULL) { + priv->g_type = g_value_get_gtype (value); + g_object_notify ((GObject*) holder, "g-type"); + } + else + g_warning (_("The 'g-type' property cannot be changed")); + break; + case PROP_NOT_NULL: { + gboolean not_null = g_value_get_boolean (value); + if (not_null != priv->not_null) { + priv->not_null = not_null; + + /* updating the holder's validity regarding the NULL value */ + if (!not_null && + (!priv->value || GDA_VALUE_HOLDS_NULL (priv->value))) + priv->valid = TRUE; + + if (not_null && + (!priv->value || GDA_VALUE_HOLDS_NULL (priv->value))) + priv->valid = FALSE; + + g_signal_emit (holder, gda_holder_signals[CHANGED], 0); + } + break; + } + case PROP_SIMPLE_BIND: + if (!gda_holder_set_bind (holder, (GdaHolder*) g_value_get_object (value), NULL)) + g_warning ("Could not set the 'simple-bind' property"); + break; + case PROP_FULL_BIND: + gda_holder_set_full_bind (holder, (GdaHolder*) g_value_get_object (value)); + break; + case PROP_SOURCE_MODEL: { + GdaDataModel* ptr = g_value_get_object (value); + g_return_if_fail (gda_holder_set_source_model (holder, + (GdaDataModel *)ptr, -1, NULL)); + break; + } + case PROP_SOURCE_COLUMN: + priv->source_col = g_value_get_int (value); + break; + case PROP_VALIDATE_CHANGES: + priv->validate_changes = g_value_get_boolean (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + break; + } + } +} + +static void +gda_holder_get_property (GObject *object, + guint param_id, + GValue *value, + GParamSpec *pspec) +{ + GdaHolder *holder; + + holder = GDA_HOLDER (object); + GdaHolderPrivate *priv = gda_holder_get_instance_private (holder); + if (priv) { + switch (param_id) { + case PROP_ID: + g_value_set_string (value, priv->id); + break; + case PROP_NAME: + if (priv->name != NULL) + g_value_set_string (value, priv->name); + else + g_value_set_string (value, priv->id); + break; + case PROP_DESCR: + if (priv->desc != NULL) + g_value_set_string (value, priv->desc); + else + g_value_set_string (value, NULL); + break; + case PROP_PLUGIN: + if (priv->plugin != NULL) + g_value_set_string (value, priv->desc); + else + g_value_set_string (value, NULL); + break; + case PROP_GDA_TYPE: + g_value_set_gtype (value, priv->g_type); + break; + case PROP_NOT_NULL: + g_value_set_boolean (value, gda_holder_get_not_null (holder)); + break; + case PROP_SIMPLE_BIND: + g_value_set_object (value, (GObject*) priv->simple_bind); + break; + case PROP_FULL_BIND: + g_value_set_object (value, (GObject*) priv->full_bind); + break; + case PROP_SOURCE_MODEL: + g_value_set_object (value, (GObject*) priv->source_model); + break; + case PROP_SOURCE_COLUMN: + g_value_set_int (value, priv->source_col); + break; + case PROP_VALIDATE_CHANGES: + g_value_set_boolean (value, priv->validate_changes); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + break; + } + } +} + +/** + * gda_holder_get_g_type: + * @holder: a #GdaHolder object + * + * Get @holder's type + * + * Returns: the data type + */ +GType +gda_holder_get_g_type (GdaHolder *holder) +{ + g_return_val_if_fail (GDA_IS_HOLDER (holder), G_TYPE_INVALID); + GdaHolderPrivate *priv = gda_holder_get_instance_private (holder); + + return priv->g_type; +} + +/** + * gda_holder_get_id: + * @holder: a #GdaHolder object + * + * Get the ID of @holder. The ID can be set using @holder's "id" property + * + * Returns: the ID (don't modify the string). + */ +const gchar * +gda_holder_get_id (GdaHolder *holder) +{ + g_return_val_if_fail (GDA_IS_HOLDER (holder), NULL); + GdaHolderPrivate *priv = gda_holder_get_instance_private (holder); + + return priv->id; +} + + +/** + * gda_holder_get_value: + * @holder: a #GdaHolder object + * + * Get the value held into the holder. If @holder is set to use its default value + * and that default value is not of the same type as @holder, then %NULL is returned. + * + * If @holder is set to NULL, then the returned value is a #GDA_TYPE_NULL GValue. + * + * If @holder is invalid, then the returned value is %NULL. + * + * Returns: (nullable) (transfer none): the value, or %NULL + */ +const GValue * +gda_holder_get_value (GdaHolder *holder) +{ + g_return_val_if_fail (GDA_IS_HOLDER (holder), NULL); + GdaHolderPrivate *priv = gda_holder_get_instance_private (holder); + + if (priv->full_bind) + return gda_holder_get_value (priv->full_bind); + else { + if (priv->valid) { + /* return default value if possible */ + if (priv->default_forced) { + g_assert (priv->default_value); + if (G_VALUE_TYPE (priv->default_value) == priv->g_type) + return priv->default_value; + else + return NULL; + } + + if (!priv->value) + priv->value = gda_value_new_null (); + return priv->value; + } + else + return NULL; + } +} + +/** + * gda_holder_get_value_str: + * @holder: a #GdaHolder object + * @dh: (nullable): a #GdaDataHandler to use, or %NULL + * + * Same functionality as gda_holder_get_value() except that it returns the value as a string + * (the conversion is done using @dh if not %NULL, or the default data handler otherwise). + * + * Returns: (transfer full): the value, or %NULL + */ +gchar * +gda_holder_get_value_str (GdaHolder *holder, GdaDataHandler *dh) +{ + const GValue *current_val; + GdaDataHandler *dhl = NULL; + + g_return_val_if_fail (GDA_IS_HOLDER (holder), NULL); + GdaHolderPrivate *priv = gda_holder_get_instance_private (holder); + + gda_holder_lock ((GdaLockable*) holder); + current_val = gda_holder_get_value (holder); + if (!current_val || GDA_VALUE_HOLDS_NULL (current_val)) { + gda_holder_unlock ((GdaLockable*) holder); + return NULL; + } + else { + gchar *retval = NULL; + if (!dh) + dhl = gda_data_handler_get_default (priv->g_type); + else + dhl = g_object_ref (dh); + if (dhl) { + retval = gda_data_handler_get_str_from_value (dhl, current_val); + g_object_unref (dhl); + } + gda_holder_unlock ((GdaLockable*) holder); + return retval; + } +} + +static gboolean real_gda_holder_set_value (GdaHolder *holder, GValue *value, gboolean do_copy, GError **error); + +/** + * gda_holder_set_value: + * @holder: a #GdaHolder object + * @value: (nullable): a value to set the holder to, or %NULL + * @error: a place to store errors, or %NULL + * + * Sets the value within the holder. If @holder is an alias for another + * holder, then the value is also set for that other holder. + * + * On success, the action of any call to gda_holder_force_invalid() is cancelled + * as soon as this method is called (even if @holder's value does not actually change) + * + * If the value is not different from the one already contained within @holder, + * then @holder is not changed and no signal is emitted. + * + * Note1: the @value argument is treated the same way if it is %NULL or if it is a #GDA_TYPE_NULL value + * + * Note2: if @holder can't accept the @value value, then this method returns FALSE, and @holder will be left + * in an invalid state. + * + * Note3: before the change is accepted by @holder, the "validate-change" signal will be emitted (the value + * of which can prevent the change from happening) which can be connected to to have a greater control + * of which values @holder can have, or implement some business rules. + * + * Returns: TRUE if value has been set + */ +gboolean +gda_holder_set_value (GdaHolder *holder, const GValue *value, GError **error) +{ + g_return_val_if_fail (GDA_IS_HOLDER (holder), FALSE); + + return real_gda_holder_set_value (holder, (GValue*) value, TRUE, error); +} + +/** + * gda_holder_set_value_str: + * @holder: a #GdaHolder object + * @dh: a #GdaDataHandler to use, or %NULL + * @value: a value to set the holder to, as a string + * @error: a place to store errors, or %NULL + * + * Same functionality as gda_holder_set_value() except that it uses a string representation + * of the value to set, which will be converted into a GValue first (using default data handler if + * @dh is %NULL). + * + * Note1: if @value is %NULL or is the "NULL" string, then @holder's value is set to %NULL. + * Note2: if @holder can't accept the @value value, then this method returns FALSE, and @holder will be left + * in an invalid state. + * + * Returns: TRUE if value has been set + */ +gboolean +gda_holder_set_value_str (GdaHolder *holder, GdaDataHandler *dh, const gchar *value, GError **error) +{ + g_return_val_if_fail (GDA_IS_HOLDER (holder), FALSE); + g_return_val_if_fail (!dh || GDA_IS_DATA_HANDLER (dh), FALSE); + GdaHolderPrivate *priv = gda_holder_get_instance_private (holder); + + if (!value || !g_ascii_strcasecmp (value, "NULL")) + return gda_holder_set_value (holder, NULL, error); + else { + GValue *gdaval = NULL; + gboolean retval = FALSE; + GdaDataHandler *ldh = NULL; + + gda_holder_lock ((GdaLockable*) holder); + if (!dh) + ldh = gda_data_handler_get_default (priv->g_type); + else + ldh = g_object_ref (dh); + + if (ldh) { + gdaval = gda_data_handler_get_value_from_str (ldh, value, priv->g_type); + g_object_unref (ldh); + } + + if (gdaval) + retval = real_gda_holder_set_value (holder, gdaval, FALSE, error); + else + g_set_error (error, GDA_HOLDER_ERROR, GDA_HOLDER_STRING_CONVERSION_ERROR, + _("Unable to convert string to '%s' type"), + gda_g_type_to_string (priv->g_type)); + gda_holder_unlock ((GdaLockable*) holder); + return retval; + } +} + +/** + * gda_holder_take_value: + * @holder: a #GdaHolder object + * @value: (transfer full): a value to set the holder to + * @error: a place to store errors, or %NULL + * + * Sets the value within the holder. If @holder is an alias for another + * holder, then the value is also set for that other holder. + * + * On success, the action of any call to gda_holder_force_invalid() is cancelled + * as soon as this method is called (even if @holder's value does not actually change). + * + * If the value is not different from the one already contained within @holder, + * then @holder is not changed and no signal is emitted. + * + * Note1: if @holder can't accept the @value value, then this method returns FALSE, and @holder will be left + * in an invalid state. + * + * Note2: before the change is accepted by @holder, the "validate-change" signal will be emitted (the value + * of which can prevent the change from happening) which can be connected to to have a greater control + * of which values @holder can have, or implement some business rules. + * + * Note3: if user previously set this holder with gda_holder_take_static_value () the GValue + * stored internally will be forgiven and replaced by the @value. User should then + * take care of the 'old' static GValue. + * + * Note4: in any case, the caller should not use @value anymore after this function returns because it may + * have been freed. If necessary, use gda_holder_get_value() to get the real value. + * + * Returns: TRUE if value has been set + */ +gboolean +gda_holder_take_value (GdaHolder *holder, GValue *value, GError **error) +{ + g_return_val_if_fail (GDA_IS_HOLDER (holder), FALSE); + + return real_gda_holder_set_value (holder, (GValue*) value, FALSE, error); +} + +static gboolean +real_gda_holder_set_value (GdaHolder *holder, GValue *value, gboolean do_copy, GError **error) +{ + GdaHolderPrivate *priv = gda_holder_get_instance_private (holder); + gboolean changed = TRUE; + gboolean newvalid; + const GValue *current_val; + gboolean newnull; + gboolean was_valid; + GValue *new_value = NULL; +#define DEBUG_HOLDER +#undef DEBUG_HOLDER + + gda_holder_lock ((GdaLockable*) holder); + was_valid = gda_holder_is_valid (holder); + + /* if the value has been set with gda_holder_take_static_value () you'll be able + * to change the value only with another call to real_gda_holder_set_value + */ + if (!priv->is_freeable) { + gda_holder_unlock ((GdaLockable*) holder); + g_set_error (error, GDA_HOLDER_ERROR, GDA_HOLDER_VALUE_CHANGE_ERROR, + (_("Can't use this method to set value because there is already a static value"))); + return FALSE; + } + new_value = value; + // If value's type is compatible to current holder's value's type transform it + if (value && priv->g_type != G_VALUE_TYPE (value) + && g_value_type_transformable (G_VALUE_TYPE (value), priv->g_type)) + { + new_value = gda_value_new (priv->g_type); + g_value_transform (value, new_value); + } + else { + if (do_copy && value != NULL) { + new_value = gda_value_copy (value); + } + } + /* holder will be changed? */ + newnull = !new_value || GDA_VALUE_HOLDS_NULL (new_value); + current_val = gda_holder_get_value (holder); + if (current_val == new_value) + changed = FALSE; + else if ((!current_val || GDA_VALUE_HOLDS_NULL ((GValue *)current_val)) && newnull) + changed = FALSE; + else if (new_value && current_val && + (G_VALUE_TYPE (new_value) == G_VALUE_TYPE ((GValue *)current_val))) + changed = gda_value_differ (new_value, (GValue *)current_val); + + /* holder's validity */ + newvalid = TRUE; + if (newnull && priv->not_null) { + g_set_error (error, GDA_HOLDER_ERROR, GDA_HOLDER_VALUE_NULL_ERROR, + _("(%s): Holder does not allow NULL values"), + priv->id); + newvalid = FALSE; + changed = TRUE; + } + else if (!newnull && (G_VALUE_TYPE (new_value) != priv->g_type)) { + g_set_error (error, GDA_HOLDER_ERROR, GDA_HOLDER_VALUE_TYPE_ERROR, + _("(%s): Wrong Holder value type, expected type '%s' when value's type is '%s'"), + priv->id, + gda_g_type_to_string (priv->g_type), + gda_g_type_to_string (G_VALUE_TYPE (new_value))); + newvalid = FALSE; + changed = TRUE; + } + + if (was_valid != newvalid) + changed = TRUE; + +#ifdef DEBUG_HOLDER + g_print ("Holder to change %p (%s): value %s --> %s \t(type %d -> %d) VALID: %d->%d CHANGED: %d\n", + holder, priv->id, + gda_value_stringify ((GValue *)current_val), + gda_value_stringify ((new_value)), + current_val ? G_VALUE_TYPE ((GValue *)current_val) : 0, + new_value ? G_VALUE_TYPE (new_value) : 0, + was_valid, newvalid, changed); +#endif + + /* end of procedure if the value has not been changed, after calculating the holder's validity */ + if (!changed) { + if (new_value) + gda_value_free (new_value); + priv->invalid_forced = FALSE; + if (priv->invalid_error) { + g_error_free (priv->invalid_error); + priv->invalid_error = NULL; + } + priv->valid = newvalid; + gda_holder_unlock ((GdaLockable*) holder); + return TRUE; + } + + /* check if we are allowed to change value */ + if (priv->validate_changes) { + GError *lerror = NULL; + g_signal_emit (holder, gda_holder_signals[VALIDATE_CHANGE], 0, new_value, &lerror); + if (lerror) { + /* change refused by signal callback */ +#ifdef DEBUG_HOLDER + g_print ("Holder change refused %p (ERROR %s)\n", holder, + lerror->message); +#endif + g_propagate_error (error, lerror); + if (new_value) + gda_value_free (new_value); + gda_holder_unlock ((GdaLockable*) holder); + return FALSE; + } + } + + /* new valid status */ + priv->invalid_forced = FALSE; + if (priv->invalid_error) { + g_error_free (priv->invalid_error); + priv->invalid_error = NULL; + } + priv->valid = newvalid; + /* we're setting a non-static value, so be sure to flag is as freeable */ + priv->is_freeable = TRUE; + + /* check is the new value is the default one */ + priv->default_forced = FALSE; + if (priv->default_value) { + if ((G_VALUE_TYPE (priv->default_value) == GDA_TYPE_NULL) && newnull) + priv->default_forced = TRUE; + else if ((G_VALUE_TYPE (priv->default_value) == priv->g_type) && + new_value && (G_VALUE_TYPE (new_value) == priv->g_type)) + priv->default_forced = !gda_value_compare (priv->default_value, new_value); + } + + /* real setting of the value */ + if (priv->full_bind) { +#ifdef DEBUG_HOLDER + g_print ("Holder %p is alias of holder %p => propagating changes to holder %p\n", + holder, priv->full_bind, priv->full_bind); +#endif + gda_holder_unlock ((GdaLockable*) holder); + gboolean ret = real_gda_holder_set_value (priv->full_bind, new_value, do_copy, error); + if (new_value) + gda_value_free (new_value); + return ret; + } + else { + if (priv->value) { + gda_value_free (priv->value); + priv->value = NULL; + } + + if (new_value) { + if (newvalid) { + priv->value = gda_value_copy (new_value); + } + gda_value_free (new_value); + } + + gda_holder_unlock ((GdaLockable*) holder); + g_signal_emit (holder, gda_holder_signals[CHANGED], 0); + } + + return newvalid; +} + +static GValue * +real_gda_holder_set_const_value (GdaHolder *holder, const GValue *value, + gboolean *value_changed, GError **error) +{ + g_return_val_if_fail (GDA_IS_HOLDER (holder), NULL); + + GdaHolderPrivate *priv = gda_holder_get_instance_private (holder); + gboolean changed = TRUE; + gboolean newvalid; + const GValue *current_val; + GValue *value_to_return = NULL; + gboolean newnull; +#define DEBUG_HOLDER +#undef DEBUG_HOLDER + +#ifdef DEBUG_HOLDER + gboolean was_valid = gda_holder_is_valid (holder); +#endif + + /* holder will be changed? */ + newnull = !value || GDA_VALUE_HOLDS_NULL (value); + current_val = gda_holder_get_value (holder); + if (current_val == value) + changed = FALSE; + else if ((!current_val || GDA_VALUE_HOLDS_NULL (current_val)) && newnull) + changed = FALSE; + else if (value && current_val && + (G_VALUE_TYPE (value) == G_VALUE_TYPE (current_val))) + changed = gda_value_differ (value, current_val); + + /* holder's validity */ + newvalid = TRUE; + if (newnull && priv->not_null) { + g_set_error (error, GDA_HOLDER_ERROR, GDA_HOLDER_VALUE_NULL_ERROR, + _("(%s): Holder does not allow NULL values"), + priv->id); + newvalid = FALSE; + changed = TRUE; + } + else if (!newnull && (G_VALUE_TYPE (value) != priv->g_type)) { + g_set_error (error, GDA_HOLDER_ERROR, GDA_HOLDER_VALUE_TYPE_ERROR, + _("(%s): Wrong value type: expected type '%s' when value's type is '%s'"), + priv->id, + gda_g_type_to_string (priv->g_type), + gda_g_type_to_string (G_VALUE_TYPE (value))); + newvalid = FALSE; + changed = TRUE; + } + +#ifdef DEBUG_HOLDER + g_print ("Changed holder %p (%s): value %s --> %s \t(type %d -> %d) VALID: %d->%d CHANGED: %d\n", + holder, priv->id, + current_val ? gda_value_stringify ((GValue *)current_val) : "_NULL_", + value ? gda_value_stringify ((value)) : "_NULL_", + current_val ? G_VALUE_TYPE ((GValue *)current_val) : 0, + value ? G_VALUE_TYPE (value) : 0, + was_valid, newvalid, changed); +#endif + + + /* end of procedure if the value has not been changed, after calculating the holder's validity */ + if (!changed) { + priv->invalid_forced = FALSE; + if (priv->invalid_error) { + g_error_free (priv->invalid_error); + priv->invalid_error = NULL; + } + priv->valid = newvalid; +#ifdef DEBUG_HOLDER + g_print ("Holder is not changed"); +#endif + /* set the changed status */ + *value_changed = FALSE; + } + else { + *value_changed = TRUE; + } + + /* check if we are allowed to change value */ + if (priv->validate_changes) { + GError *lerror = NULL; + g_signal_emit (holder, gda_holder_signals[VALIDATE_CHANGE], 0, value, &lerror); + if (lerror) { + /* change refused by signal callback */ + g_propagate_error (error, lerror); + return NULL; + } + } + + /* new valid status */ + priv->invalid_forced = FALSE; + if (priv->invalid_error) { + g_error_free (priv->invalid_error); + priv->invalid_error = NULL; + } + priv->valid = newvalid; + /* we're setting a static value, so be sure to flag is as unfreeable */ + priv->is_freeable = FALSE; + + /* check is the new value is the default one */ + priv->default_forced = FALSE; + if (priv->default_value) { + if ((G_VALUE_TYPE (priv->default_value) == GDA_TYPE_NULL) && newnull) + priv->default_forced = TRUE; + else if ((G_VALUE_TYPE (priv->default_value) == priv->g_type) && + value && (G_VALUE_TYPE (value) == priv->g_type)) + priv->default_forced = !gda_value_compare (priv->default_value, value); + } + + /* real setting of the value */ + if (priv->full_bind) { +#ifdef DEBUG_HOLDER + g_print ("Holder %p is alias of holder %p => propagating changes to holder %p\n", + holder, priv->full_bind, priv->full_bind); +#endif + return real_gda_holder_set_const_value (priv->full_bind, value, + value_changed, error); + } + else { + if (priv->value) { + if (G_IS_VALUE (priv->value)) + value_to_return = priv->value; + else + value_to_return = NULL; + priv->value = NULL; + } + + if (value) { + if (newvalid) { + priv->value = (GValue*)value; + } + } + + g_signal_emit (holder, gda_holder_signals[CHANGED], 0); + } + +#ifdef DEBUG_HOLDER + g_print ("returning %p, wannabe was %p\n", value_to_return, + value); +#endif + + return value_to_return; +} + +/** + * gda_holder_take_static_value: + * @holder: a #GdaHolder object + * @value: a const value to set the holder to + * @value_changed: a boolean set with TRUE if the value changes, FALSE elsewhere. + * @error: a place to store errors, or %NULL + * + * Sets the const value within the holder. If @holder is an alias for another + * holder, then the value is also set for that other holder. + * + * The value will not be freed, and user should take care of it, either for its + * freeing or for its correct value at the moment of query. + * + * If the value is not different from the one already contained within @holder, + * then @holder is not changed and no signal is emitted. + * + * Note1: if @holder can't accept the @value value, then this method returns NULL, and @holder will be left + * in an invalid state. + * + * Note2: before the change is accepted by @holder, the "validate-change" signal will be emitted (the value + * of which can prevent the change from happening) which can be connected to to have a greater control + * of which values @holder can have, or implement some business rules. + * + * Returns: NULL if an error occurred or if the previous GValue was NULL itself. It returns + * the static GValue user set previously, so that he can free it. + */ +GValue * +gda_holder_take_static_value (GdaHolder *holder, const GValue *value, gboolean *value_changed, + GError **error) +{ + GValue *retvalue; + g_return_val_if_fail (GDA_IS_HOLDER (holder), FALSE); + + gda_holder_lock ((GdaLockable*) holder); + retvalue = real_gda_holder_set_const_value (holder, value, value_changed, error); + gda_holder_unlock ((GdaLockable*) holder); + + return retvalue; +} + +/** + * gda_holder_force_invalid: + * @holder: a #GdaHolder object + * + * Forces a holder to be invalid; to set it valid again, a new value must be assigned + * to it using gda_holder_set_value() or gda_holder_take_value(). + * + * @holder's value is set to %NULL. + */ +void +gda_holder_force_invalid (GdaHolder *holder) +{ + g_return_if_fail (GDA_IS_HOLDER (holder)); + gda_holder_force_invalid_e (holder, NULL); +} + +/** + * gda_holder_force_invalid_e: + * @holder: a #GdaHolder object + * @error: (nullable) (transfer full): a #GError explaining why @holder is declared invalid, or %NULL + * + * Forces a holder to be invalid; to set it valid again, a new value must be assigned + * to it using gda_holder_set_value() or gda_holder_take_value(). + * + * @holder's value is set to %NULL. + * + * Since: 4.2.10 + */ +void +gda_holder_force_invalid_e (GdaHolder *holder, GError *error) +{ + g_return_if_fail (GDA_IS_HOLDER (holder)); + GdaHolderPrivate *priv = gda_holder_get_instance_private (holder); + +#ifdef GDA_DEBUG_NO + g_print ("Holder %p (%s): declare invalid\n", holder, priv->id); +#endif + + gda_holder_lock ((GdaLockable*) holder); + if (priv->invalid_error) + g_error_free (priv->invalid_error); + priv->invalid_error = error; + + if (priv->invalid_forced) { + gda_holder_unlock ((GdaLockable*) holder); + return; + } + + priv->invalid_forced = TRUE; + priv->valid = FALSE; + if (priv->value) { + if (priv->is_freeable) + gda_value_free (priv->value); + priv->value = NULL; + } + + /* if we are an alias, then we forward the value setting to the master */ + if (priv->full_bind) { + gda_holder_force_invalid (priv->full_bind); + gda_holder_unlock ((GdaLockable*) holder); + } + else { + gda_holder_unlock ((GdaLockable*) holder); + g_signal_emit (holder, gda_holder_signals[CHANGED], 0); + } +} + +/** + * gda_holder_is_valid: + * @holder: a #GdaHolder object + * + * Get the validity of @holder (that is, of the value held by @holder) + * + * Returns: TRUE if @holder's value can safely be used + */ +gboolean +gda_holder_is_valid (GdaHolder *holder) +{ + g_return_val_if_fail (GDA_IS_HOLDER (holder), FALSE); + return gda_holder_is_valid_e (holder, NULL); +} + +/** + * gda_holder_is_valid_e: + * @holder: a #GdaHolder object + * @error: (nullable): a place to store invalid error, or %NULL + * + * Get the validity of @holder (that is, of the value held by @holder) + * + * Returns: TRUE if @holder's value can safely be used + * + * Since: 4.2.10 + */ +gboolean +gda_holder_is_valid_e (GdaHolder *holder, GError **error) +{ + gboolean retval; + g_return_val_if_fail (GDA_IS_HOLDER (holder), FALSE); + GdaHolderPrivate *priv = gda_holder_get_instance_private (holder); + + gda_holder_lock ((GdaLockable*) holder); + if (priv->full_bind) + retval = gda_holder_is_valid_e (priv->full_bind, error); + else { + if (priv->invalid_forced) + retval = FALSE; + else { + if (priv->default_forced) + retval = priv->default_value ? TRUE : FALSE; + else + retval = priv->valid; + } + if (!retval && priv->invalid_error) + g_propagate_error (error, g_error_copy (priv->invalid_error)); + } + gda_holder_unlock ((GdaLockable*) holder); + return retval; +} + +/** + * gda_holder_set_value_to_default: + * @holder: a #GdaHolder object + * + * Set @holder's value to its default value. + * + * Returns: TRUE if @holder has got a default value + */ +gboolean +gda_holder_set_value_to_default (GdaHolder *holder) +{ + g_return_val_if_fail (GDA_IS_HOLDER (holder), FALSE); + GdaHolderPrivate *priv = gda_holder_get_instance_private (holder); + + gda_holder_lock ((GdaLockable*) holder); + if (priv->default_forced) { + gda_holder_unlock ((GdaLockable*) holder); + return TRUE; + } + + if (!priv->default_value) { + gda_holder_unlock ((GdaLockable*) holder); + return FALSE; + } + else { + priv->default_forced = TRUE; + priv->invalid_forced = FALSE; + if (priv->invalid_error) { + g_error_free (priv->invalid_error); + priv->invalid_error = NULL; + } + + if (priv->value) { + if (priv->is_freeable) + gda_value_free (priv->value); + priv->value = NULL; + } + } + + g_signal_emit (holder, gda_holder_signals[CHANGED], 0); + g_signal_emit (holder, gda_holder_signals[TO_DEFAULT], 0); + + gda_holder_unlock ((GdaLockable*) holder); + return TRUE; +} + +/** + * gda_holder_value_is_default: + * @holder: a #GdaHolder object + * + * Tells if @holder's current value is the default one. + * + * Returns: TRUE if @holder @holder's current value is the default one + */ +gboolean +gda_holder_value_is_default (GdaHolder *holder) +{ + g_return_val_if_fail (GDA_IS_HOLDER (holder), FALSE); + GdaHolderPrivate *priv = gda_holder_get_instance_private (holder); + + return priv->default_forced; +} + + +/** + * gda_holder_get_default_value: + * @holder: a #GdaHolder object + * + * Get the default value held into the holder. WARNING: the default value does not need to be of + * the same type as the one required by @holder. + * + * Returns: the default value + */ +const GValue * +gda_holder_get_default_value (GdaHolder *holder) +{ + g_return_val_if_fail (GDA_IS_HOLDER (holder), NULL); + GdaHolderPrivate *priv = gda_holder_get_instance_private (holder); + + return priv->default_value; +} + + +/** + * gda_holder_set_default_value: + * @holder: a #GdaHolder object + * @value: a value to set the holder's default value, or %NULL + * + * Sets the default value within the holder. If @value is %NULL then @holder won't have a + * default value anymore. To set a default value to %NULL, then pass a #GValue created using + * gda_value_new_null(). + * + * NOTE: the default value does not need to be of the same type as the one required by @holder. + */ +void +gda_holder_set_default_value (GdaHolder *holder, const GValue *value) +{ + g_return_if_fail (GDA_IS_HOLDER (holder)); + GdaHolderPrivate *priv = gda_holder_get_instance_private (holder); + + gda_holder_lock ((GdaLockable*) holder); + if (priv->default_value) { + if (priv->default_forced) { + gda_holder_take_value (holder, priv->default_value, NULL); + priv->default_forced = FALSE; + priv->default_value = NULL; + } + else { + gda_value_free (priv->default_value); + priv->default_value = NULL; + } + } + + priv->default_forced = FALSE; + if (value) { + const GValue *current = gda_holder_get_value (holder); + + /* check if default is equal to current value */ + if (GDA_VALUE_HOLDS_NULL (value) && + (!current || GDA_VALUE_HOLDS_NULL (current))) { + priv->default_forced = TRUE; + } else if ((G_VALUE_TYPE (value) == priv->g_type) && + current && !gda_value_compare (value, current)) { + priv->default_forced = TRUE; + } + + priv->default_value = gda_value_copy ((GValue *)value); + } + + /* don't emit the "changed" signal */ + gda_holder_unlock ((GdaLockable*) holder); +} + +/** + * gda_holder_set_not_null: + * @holder: a #GdaHolder object + * @not_null: TRUE if @holder should not accept %NULL values + * + * Sets if the holder can have a NULL value. If @not_null is TRUE, then that won't be allowed + */ +void +gda_holder_set_not_null (GdaHolder *holder, gboolean not_null) +{ + g_return_if_fail (GDA_IS_HOLDER (holder)); + + g_object_set (G_OBJECT (holder), "not-null", not_null, NULL); +} + +/** + * gda_holder_get_not_null: + * @holder: a #GdaHolder object + * + * Get wether the holder can be NULL or not + * + * Returns: TRUE if the holder cannot be NULL + */ +gboolean +gda_holder_get_not_null (GdaHolder *holder) +{ + g_return_val_if_fail (GDA_IS_HOLDER (holder), FALSE); + GdaHolderPrivate *priv = gda_holder_get_instance_private (holder); + + return priv->not_null; +} + +/** + * gda_holder_set_source_model: + * @holder: a #GdaHolder object + * @model: a #GdaDataModel object or %NULL + * @col: the reference column in @model + * @error: location to store error, or %NULL + * + * Sets an hint that @holder's values should be restricted among the values + * contained in the @col column of the @model data model. Note that this is just a hint, + * meaning this policy is not enforced by @holder's implementation. + * + * If @model is %NULL, then the effect is to cancel ant previous call to gda_holder_set_source_model() + * where @model was not %NULL. + * + * Returns: TRUE if no error occurred + */ +gboolean +gda_holder_set_source_model (GdaHolder *holder, GdaDataModel *model, + gint col, GError **error) +{ + g_return_val_if_fail (GDA_IS_HOLDER (holder), FALSE); + GdaHolderPrivate *priv = gda_holder_get_instance_private (holder); + if (model != NULL) { + g_return_val_if_fail (GDA_IS_DATA_MODEL (model), FALSE); + g_return_val_if_fail (col >= 0 && col < gda_data_model_get_n_columns (model), FALSE); + } + + /* No check is done on the validity of @col or even its existance */ + /* Note: for internal implementation if @col<0, then it's ignored */ + + gda_holder_lock ((GdaLockable*) holder); + if (model && (col >= 0)) { + GType htype, ctype; + GdaColumn *gcol; + htype = gda_holder_get_g_type (holder); + gcol = gda_data_model_describe_column (model, col); + if (gcol) { + ctype = gda_column_get_g_type (gcol); + if ((htype != GDA_TYPE_NULL) && (ctype != GDA_TYPE_NULL) && + (htype != ctype)) { + g_set_error (error, GDA_HOLDER_ERROR, GDA_HOLDER_VALUE_TYPE_ERROR, + _("GdaHolder has a gda type (%s) incompatible with " + "source column %d type (%s)"), + gda_g_type_to_string (htype), + col, gda_g_type_to_string (ctype)); + gda_holder_unlock ((GdaLockable*) holder); + return FALSE; + } + } + } + + if (col >= 0) + priv->source_col = col; + + if (priv->source_model != model) { + if (priv->source_model) { + g_object_unref (priv->source_model); + priv->source_model = NULL; + } + + priv->source_model = model; + if (model) + g_object_ref (model); + else + priv->source_col = 0; + } + +#ifdef GDA_DEBUG_signal + g_print (">> 'SOURCE_CHANGED' from %p\n", holder); +#endif + g_signal_emit (holder, gda_holder_signals[SOURCE_CHANGED], 0); +#ifdef GDA_DEBUG_signal + g_print ("<< 'SOURCE_CHANGED' from %p\n", holder); +#endif + + gda_holder_unlock ((GdaLockable*) holder); + return TRUE; +} + + +/** + * gda_holder_get_source_model: + * @holder: a #GdaHolder + * @col: a place to store the column in the model sourcing the holder, or %NULL + * + * If gda_holder_set_source_model() has been used to provide a hint that @holder's value + * should be among the values contained in a column of a data model, then this method + * returns which data model, and if @col is not %NULL, then it is set to the restricting column + * as well. + * + * Otherwise, this method returns %NULL, and if @col is not %NULL, then it is set to 0. + * + * Returns: (transfer none): a pointer to a #GdaDataModel, or %NULL + */ +GdaDataModel * +gda_holder_get_source_model (GdaHolder *holder, gint *col) +{ + GdaDataModel *model; + g_return_val_if_fail (GDA_IS_HOLDER (holder), FALSE); + GdaHolderPrivate *priv = gda_holder_get_instance_private (holder); + + gda_holder_lock ((GdaLockable*) holder); + if (col) + *col = priv->source_col; + model = priv->source_model; + gda_holder_unlock ((GdaLockable*) holder); + return model; +} + +/* + * This callback is called when @priv->simple_bind's GType was GDA_TYPE_NULL at the time + * gda_holder_set_bind() was called, and it makes sure @holder's GType is the same as @priv->simple_bind's + */ +static void +bind_to_notify_cb (GdaHolder *bind_to, G_GNUC_UNUSED GParamSpec *pspec, GdaHolder *holder) +{ + g_return_if_fail (GDA_IS_HOLDER (bind_to)); + gda_holder_lock ((GdaLockable*) holder); + gda_holder_lock ((GdaLockable*) bind_to); + GdaHolderPrivate *priv = gda_holder_get_instance_private (holder); + GdaHolderPrivate *bpriv = gda_holder_get_instance_private (bind_to); + + g_signal_handler_disconnect (priv->simple_bind, + priv->simple_bind_type_changed_id); + priv->simple_bind_type_changed_id = 0; + if (priv->g_type == GDA_TYPE_NULL) { + priv->g_type = bpriv->g_type; + g_object_notify ((GObject*) holder, "g-type"); + } + else if (priv->g_type != bpriv->g_type) { + /* break holder's binding because type differ */ + g_message (_("Cannot bind holders if their type is not the same, breaking existing bind where '%s' was bound to '%s'"), + gda_holder_get_id (holder), gda_holder_get_id (bind_to)); + gda_holder_set_bind (holder, NULL, NULL); + } + + gda_holder_unlock ((GdaLockable*) holder); + gda_holder_unlock ((GdaLockable*) bind_to); +} + +/** + * gda_holder_set_bind: + * @holder: a #GdaHolder + * @bind_to: a #GdaHolder or %NULL + * @error: a place to store errors, or %NULL + * + * Sets @holder to change when @bind_to changes (and does not make @bind_to change when @holder changes). + * For the operation to succeed, the GType of @holder and @bind_to must be the same, with the exception that + * any of them can have a %GDA_TYPE_NULL type (in this situation, the GType of the two #GdaHolder objects + * involved is set to match the other when any of them sets its type to something different than GDA_TYPE_NULL). + * + * If @bind_to is %NULL, then @holder will not be bound anymore. + * + * Returns: TRUE if no error occurred + */ +gboolean +gda_holder_set_bind (GdaHolder *holder, GdaHolder *bind_to, GError **error) +{ + const GValue *cvalue; + GValue *value1 = NULL; + const GValue *value2 = NULL; + GdaHolderPrivate *priv = NULL; + GdaHolderPrivate *bpriv = NULL; + + g_return_val_if_fail (GDA_IS_HOLDER (holder), FALSE); + priv = gda_holder_get_instance_private (holder); + g_return_val_if_fail (holder != bind_to, FALSE); + + gda_holder_lock ((GdaLockable*) holder); + if (priv->simple_bind == bind_to) { + gda_holder_unlock ((GdaLockable*) holder); + return TRUE; + } + + /* get a copy of the current values of @holder and @bind_to */ + if (bind_to) { + g_return_val_if_fail (GDA_IS_HOLDER (bind_to), FALSE); + + bpriv = gda_holder_get_instance_private (bind_to); + + if ((priv->g_type != GDA_TYPE_NULL) && + (bpriv->g_type != GDA_TYPE_NULL) && + (priv->g_type != bpriv->g_type)) { + g_set_error (error, GDA_HOLDER_ERROR, GDA_HOLDER_VALUE_TYPE_ERROR, + "%s", _("Cannot bind holders if their type is not the same")); + gda_holder_unlock ((GdaLockable*) holder); + return FALSE; + } + value2 = gda_holder_get_value (bind_to); + } + + cvalue = gda_holder_get_value (holder); + if (cvalue) + value1 = gda_value_copy ((GValue*)cvalue); + + /* get rid of the old alias */ + if (priv->simple_bind) { + g_signal_handlers_disconnect_by_func (priv->simple_bind, + G_CALLBACK (bound_holder_changed_cb), holder); + + if (priv->simple_bind_type_changed_id) { + g_signal_handler_disconnect (priv->simple_bind, + priv->simple_bind_type_changed_id); + priv->simple_bind_type_changed_id = 0; + } + g_object_unref (priv->simple_bind); + priv->simple_bind = NULL; + } + + /* setting the new alias or reseting the value if there is no new alias */ + gboolean retval; + if (bind_to) { + priv->simple_bind = g_object_ref (bind_to); + g_signal_connect (priv->simple_bind, "changed", + G_CALLBACK (bound_holder_changed_cb), holder); + + if (bpriv->g_type == GDA_TYPE_NULL) + priv->simple_bind_type_changed_id = g_signal_connect (bind_to, "notify::g-type", + G_CALLBACK (bind_to_notify_cb), + holder); + else if (priv->g_type == GDA_TYPE_NULL) + g_object_set ((GObject*) holder, "g-type", bpriv->g_type , NULL); + + /* if bind_to has a different value than holder, then we set holder to the new value */ + if (value1) + gda_value_free (value1); + retval = gda_holder_set_value (holder, value2, error); + } + else + retval = gda_holder_take_value (holder, value1, error); + + gda_holder_unlock ((GdaLockable*) holder); + return retval; +} + +/* + * gda_holder_set_full_bind + * @holder: a #GdaHolder + * @alias_of: a #GdaHolder or %NULL + * + * Sets @holder to change when @alias_of changes and makes @alias_of change when @holder changes. + * The difference with gda_holder_set_bind is that when @holder changes, then @alias_of also + * changes. + */ +static void +gda_holder_set_full_bind (GdaHolder *holder, GdaHolder *alias_of) +{ + g_return_if_fail (GDA_IS_HOLDER (holder)); + const GValue *cvalue; + GValue *value1 = NULL, *value2 = NULL; + + g_return_if_fail (GDA_IS_HOLDER (holder)); + GdaHolderPrivate *priv = gda_holder_get_instance_private (holder); + + gda_holder_lock ((GdaLockable*) holder); + if (priv->full_bind == alias_of) { + gda_holder_unlock ((GdaLockable*) holder); + return; + } + + /* get a copy of the current values of @holder and @alias_of */ + if (alias_of) { + g_return_if_fail (GDA_IS_HOLDER (alias_of)); + GdaHolderPrivate *apriv = gda_holder_get_instance_private (alias_of); + g_return_if_fail (priv->g_type == apriv->g_type); + cvalue = gda_holder_get_value (alias_of); + if (cvalue && !GDA_VALUE_HOLDS_NULL ((GValue*)cvalue)) + value2 = gda_value_copy ((GValue*)cvalue); + } + + cvalue = gda_holder_get_value (holder); + if (cvalue && !GDA_VALUE_HOLDS_NULL ((GValue*)cvalue)) + value1 = gda_value_copy ((GValue*)cvalue); + + /* get rid of the old alias */ + if (priv->full_bind) { + g_signal_handlers_disconnect_by_func (priv->full_bind, + G_CALLBACK (full_bound_holder_changed_cb), holder); + g_object_unref (priv->full_bind); + priv->full_bind = NULL; + } + + /* setting the new alias or reseting the value if there is no new alias */ + if (alias_of) { + gboolean equal = FALSE; + + /* get rid of the internal holder's value */ + if (priv->value) { + if (priv->is_freeable) + gda_value_free (priv->value); + priv->value = NULL; + } + + priv->full_bind = g_object_ref (alias_of); + g_signal_connect (priv->full_bind, "changed", + G_CALLBACK (full_bound_holder_changed_cb), holder); + + /* if alias_of has a different value than holder, then we emit a CHANGED signal */ + if (value1 && value2 && + (G_VALUE_TYPE (value1) == G_VALUE_TYPE (value2))) + equal = !gda_value_compare (value1, value2); + else { + if (!value1 && !value2) + equal = TRUE; + } + + if (!equal) + g_signal_emit (holder, gda_holder_signals[CHANGED], 0); + } + else { + /* restore the value that was in the previous alias holder, + * if there was such a value, and don't emit a signal */ + g_assert (! priv->value); + if (value1) + priv->value = value1; + value1 = NULL; + } + + if (value1) gda_value_free (value1); + if (value2) gda_value_free (value2); + gda_holder_unlock ((GdaLockable*) holder); +} + +static void +full_bound_holder_changed_cb (GdaHolder *alias_of, GdaHolder *holder) +{ + gda_holder_lock ((GdaLockable*) holder); + gda_holder_lock ((GdaLockable*) alias_of); + GdaHolderPrivate *priv = gda_holder_get_instance_private (holder); + + g_assert (alias_of == priv->full_bind); + g_signal_emit (holder, gda_holder_signals [CHANGED], 0); + + gda_holder_unlock ((GdaLockable*) holder); + gda_holder_unlock ((GdaLockable*) alias_of); +} + +static void +bound_holder_changed_cb (GdaHolder *alias_of, GdaHolder *holder) +{ + gda_holder_lock ((GdaLockable*) holder); + gda_holder_lock ((GdaLockable*) alias_of); + GdaHolderPrivate *priv = gda_holder_get_instance_private (holder); + + g_assert (alias_of == priv->simple_bind); + const GValue *cvalue; + GError *lerror = NULL; + cvalue = gda_holder_get_value (alias_of); + if (! gda_holder_set_value (holder, cvalue, &lerror)) { + if (lerror && ((lerror->domain != GDA_HOLDER_ERROR) || (lerror->code != GDA_HOLDER_VALUE_NULL_ERROR))) + g_warning (_("Could not change GdaHolder to match value change in bound GdaHolder: %s"), + lerror && lerror->message ? lerror->message : _("No detail")); + g_clear_error (&lerror); + } + gda_holder_unlock ((GdaLockable*) holder); + gda_holder_unlock ((GdaLockable*) alias_of); +} + +/** + * gda_holder_get_bind: + * @holder: a #GdaHolder + * + * Get the holder which makes @holder change its value when the holder's value is changed. + * + * Returns: (transfer none): the #GdaHolder or %NULL + */ +GdaHolder * +gda_holder_get_bind (GdaHolder *holder) +{ + g_return_val_if_fail (GDA_IS_HOLDER (holder), NULL); + GdaHolderPrivate *priv = gda_holder_get_instance_private (holder); + + return priv->simple_bind; +} + +/** + * gda_holder_get_alphanum_id: + * @holder: a #GdaHolder object + * + * Get an "encoded" version of @holder's name. The "encoding" consists in replacing non + * alphanumeric character with the string "__gdaXX" where XX is the hex. representation + * of the non alphanumeric char. + * + * This method is just a wrapper around the gda_text_to_alphanum() function. + * + * Returns: (transfer full): a new string + */ +gchar * +gda_holder_get_alphanum_id (GdaHolder *holder) +{ + g_return_val_if_fail (GDA_IS_HOLDER (holder), NULL); + GdaHolderPrivate *priv = gda_holder_get_instance_private (holder); + return gda_text_to_alphanum (priv->id); +} + +static void +gda_holder_lock (GdaLockable *lockable) +{ + GdaHolder *holder = (GdaHolder *) lockable; + GdaHolderPrivate *priv = gda_holder_get_instance_private (holder); + g_rec_mutex_lock (& (priv->mutex)); +} + +static gboolean +gda_holder_trylock (GdaLockable *lockable) +{ + GdaHolder *holder = (GdaHolder *) lockable; + GdaHolderPrivate *priv = gda_holder_get_instance_private (holder); + return g_rec_mutex_trylock (& (priv->mutex)); +} + +static void +gda_holder_unlock (GdaLockable *lockable) +{ + GdaHolder *holder = (GdaHolder *) lockable; + GdaHolderPrivate *priv = gda_holder_get_instance_private (holder); + g_rec_mutex_unlock (& (priv->mutex)); +} diff --git a/.flatpak-builder/cache/objects/b5/b0399894637865017f68e8d95c4ade0208667e4feb4845430087c0bd6c2085.dirtree b/.flatpak-builder/cache/objects/b5/b0399894637865017f68e8d95c4ade0208667e4feb4845430087c0bd6c2085.dirtree new file mode 100644 index 0000000..3e48268 Binary files /dev/null and b/.flatpak-builder/cache/objects/b5/b0399894637865017f68e8d95c4ade0208667e4feb4845430087c0bd6c2085.dirtree differ diff --git a/.flatpak-builder/cache/objects/b5/c25894404a943e1c9c41fbf952767b768a178aefd290ae8e2c314f36df8ce5.file b/.flatpak-builder/cache/objects/b5/c25894404a943e1c9c41fbf952767b768a178aefd290ae8e2c314f36df8ce5.file new file mode 100644 index 0000000..8fa845d --- /dev/null +++ b/.flatpak-builder/cache/objects/b5/c25894404a943e1c9c41fbf952767b768a178aefd290ae8e2c314f36df8ce5.file @@ -0,0 +1,611 @@ +/* + * Copyright (C) 2008 Bas Driessen + * Copyright (C) 2008 - 2012 Vivien Malerba + * Copyright (C) 2009 - 2011 Murray Cumming + * Copyright (C) 2011 Daniel Espinosa + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef _GDA_STATEMENT_STRUCT_PARTS_H +#define _GDA_STATEMENT_STRUCT_PARTS_H + +#include +#include +#include +#include +#include +#include + +G_BEGIN_DECLS +/* + * GdaSqlExpr: + * + **/ +typedef struct _GdaSqlExpr GdaSqlExpr; +/* + * GdaSqlField: + * + **/ +typedef struct _GdaSqlField GdaSqlField; +/* + * GdaSqlTable: + * + **/ +typedef struct _GdaSqlTable GdaSqlTable; +/* + * GdaSqlFunction: + * + **/ +typedef struct _GdaSqlFunction GdaSqlFunction; +/* + * GdaSqlOperation: + * + **/ +typedef struct _GdaSqlOperation GdaSqlOperation; +/* + * GdaSqlCase: + * + **/ +typedef struct _GdaSqlCase GdaSqlCase; +/* + * GdaSqlSelectField: + * + **/ +typedef struct _GdaSqlSelectField GdaSqlSelectField; +/* + * GdaSqlSelectTarget: + * + **/ +typedef struct _GdaSqlSelectTarget GdaSqlSelectTarget; +/* + * GdaSqlSelectJoin: + * + **/ +typedef struct _GdaSqlSelectJoin GdaSqlSelectJoin; +/* + * GdaSqlSelectFrom: + * + **/ +typedef struct _GdaSqlSelectFrom GdaSqlSelectFrom; +/* + * GdaSqlSelectOrder: + * + **/ +typedef struct _GdaSqlSelectOrder GdaSqlSelectOrder; + +/* + * Any Expression + */ +/** + * GdaSqlExpr: + * @any: inheritance structure + * @value: (nullable): a #GValue, or %NULL. Please see specific note about this field. + * @param_spec: (nullable): a #GdaSqlParamSpec, or %NULL if this is not a variable + * @func: (nullable): not %NULL if expression is a function or aggregate + * @cond: (nullable): not %NULL if expression is a condition or an operation + * @select: (nullable): not %NULL if expression is a sub select statement (#GdaSqlStatementSelect or #GdaSqlStatementCompound) + * @case_s: (nullable): not %NULL if expression is a CASE WHEN ... expression + * @cast_as: (nullable): not %NULL if expression must be cast to another data type + * @value_is_ident: Please see specific note about the @value field + * + * This structure contains any expression, either as a value (the @value part is set), + * a variable (the @param_spec is set), or as other types of expressions. + * + * Note 1 about the @value field: if the expression represents a string value in the SQL statement, + * the string itself must be represented as it would be in the actual SQL, ie. it should be + * escaped (accordingly to the escaping rules of the database which will use the SQL). For + * example a string representing the 'joe' value should be + * "'joe'" and not "joe". + * + * Note 2 about the @value field: if the expression represents an SQL identifier (such as a table + * or field name), then the @value_is_ident should be set to %TRUE, and @value should be a string + * which may contain double quotes around SQL identifiers which also are reserved keywords or which + * are case sensitive. + */ +struct _GdaSqlExpr { + GdaSqlAnyPart any; + GValue *value; + GdaSqlParamSpec *param_spec; + GdaSqlFunction *func; + GdaSqlOperation *cond; + GdaSqlAnyPart *select; /* SELECT OR COMPOUND statements: GdaSqlStatementSelect or GdaSqlStatementCompound */ + GdaSqlCase *case_s; + + gchar *cast_as; + + gboolean value_is_ident; + + /*< private >*/ + /* Padding for future expansion */ + gpointer _gda_reserved1; + gpointer _gda_reserved2; + gpointer _gda_reserved3; + gpointer _gda_reserved4; +}; + +#define GDA_TYPE_SQL_EXPR (gda_sql_expr_get_type()) +GType gda_sql_expr_get_type (void) G_GNUC_CONST; +GdaSqlExpr *gda_sql_expr_new (GdaSqlAnyPart *parent); +void gda_sql_expr_free (GdaSqlExpr *expr); +GdaSqlExpr *gda_sql_expr_copy (GdaSqlExpr *expr); +gchar *gda_sql_expr_serialize (GdaSqlExpr *expr); +void _gda_sql_expr_check_clean (GdaSqlExpr *expr); +void gda_sql_expr_take_select (GdaSqlExpr *expr, GdaSqlStatement *stmt); + +/* + * Any Table's field + */ +/** + * GdaSqlField: + * @any: + * @field_name: + * @validity_meta_table_column: validity check with a connection + * + * This structure represents the name of a table's field. + */ +struct _GdaSqlField { + GdaSqlAnyPart any; + gchar *field_name; + + /* validity check with a connection */ + GdaMetaTableColumn *validity_meta_table_column; + + /*< private >*/ + /* Padding for future expansion */ + gpointer _gda_reserved1; + gpointer _gda_reserved2; +}; + +#define GDA_TYPE_SQL_FIELD (gda_sql_field_get_type()) + +GType gda_sql_field_get_type (void) G_GNUC_CONST; +GdaSqlField *gda_sql_field_new (GdaSqlAnyPart *parent); +void gda_sql_field_free (GdaSqlField *field); +GdaSqlField *gda_sql_field_copy (GdaSqlField *field); +gchar *gda_sql_field_serialize (GdaSqlField *field); +void _gda_sql_field_check_clean (GdaSqlField *field); + +void gda_sql_field_take_name (GdaSqlField *field, GValue *value); + +/* + * Any table + */ +/** + * GdaSqlTable: + * @any: + * @table_name: + * @validity_meta_object: + * + * This structure represents the name of a table. + */ +struct _GdaSqlTable +{ + GdaSqlAnyPart any; + gchar *table_name; + + /* validity check with a connection */ + GdaMetaDbObject *validity_meta_object; + + /*< private >*/ + /* Padding for future expansion */ + gpointer _gda_reserved1; + gpointer _gda_reserved2; +}; + +#define GDA_TYPE_SQL_TABLE (gda_sql_table_get_type()) + +GType gda_sql_table_get_type (void) G_GNUC_CONST; +GdaSqlTable *gda_sql_table_new (GdaSqlAnyPart *parent); +void gda_sql_table_free (GdaSqlTable *table); +GdaSqlTable *gda_sql_table_copy (GdaSqlTable *table); +gchar *gda_sql_table_serialize (GdaSqlTable *table); +void _gda_sql_table_check_clean (GdaSqlTable *table); + +void gda_sql_table_take_name (GdaSqlTable *table, GValue *value); + +/* + * A function with any number of arguments + */ +/** + * GdaSqlFunction: + * @any: inheritance structure + * @function_name: name of the function , in the form [[catalog.]schema.]function_name + * @args_list: list of #GdaSqlExpr expressions, one for each argument + * + * This structure represents a function or an aggregate with zero or more arguments. + */ +struct _GdaSqlFunction { + GdaSqlAnyPart any; + gchar *function_name; + GSList *args_list; + + /*< private >*/ + /* Padding for future expansion */ + gpointer _gda_reserved1; + gpointer _gda_reserved2; +}; + +#define GDA_TYPE_SQL_FUNCTION (gda_sql_function_get_type()) + +GType gda_sql_function_get_type (void) G_GNUC_CONST; +GdaSqlFunction *gda_sql_function_new (GdaSqlAnyPart *parent); +void gda_sql_function_free (GdaSqlFunction *function); +GdaSqlFunction *gda_sql_function_copy (GdaSqlFunction *function); +gchar *gda_sql_function_serialize (GdaSqlFunction *function); +void gda_sql_function_check_clean (GdaSqlFunction *function); + +void gda_sql_function_take_name (GdaSqlFunction *function, GValue *value); +void gda_sql_function_take_args_list (GdaSqlFunction *function, GSList *args); + +/* + * An operation on one or more expressions + */ +/** + * GdaSqlOperatorType: + * @GDA_SQL_OPERATOR_TYPE_AND: + * @GDA_SQL_OPERATOR_TYPE_OR: + * @GDA_SQL_OPERATOR_TYPE_EQ: + * @GDA_SQL_OPERATOR_TYPE_IS: + * @GDA_SQL_OPERATOR_TYPE_LIKE: + * @GDA_SQL_OPERATOR_TYPE_ILIKE: + * @GDA_SQL_OPERATOR_TYPE_BETWEEN: + * @GDA_SQL_OPERATOR_TYPE_GT: + * @GDA_SQL_OPERATOR_TYPE_LT: + * @GDA_SQL_OPERATOR_TYPE_GEQ: + * @GDA_SQL_OPERATOR_TYPE_LEQ: + * @GDA_SQL_OPERATOR_TYPE_DIFF: + * @GDA_SQL_OPERATOR_TYPE_REGEXP: + * @GDA_SQL_OPERATOR_TYPE_REGEXP_CI: + * @GDA_SQL_OPERATOR_TYPE_NOT_REGEXP: + * @GDA_SQL_OPERATOR_TYPE_NOT_REGEXP_CI: + * @GDA_SQL_OPERATOR_TYPE_SIMILAR: + * @GDA_SQL_OPERATOR_TYPE_ISNULL: + * @GDA_SQL_OPERATOR_TYPE_ISNOTNULL: + * @GDA_SQL_OPERATOR_TYPE_NOT: + * @GDA_SQL_OPERATOR_TYPE_IN: + * @GDA_SQL_OPERATOR_TYPE_NOTIN: + * @GDA_SQL_OPERATOR_TYPE_CONCAT: + * @GDA_SQL_OPERATOR_TYPE_PLUS: + * @GDA_SQL_OPERATOR_TYPE_MINUS: + * @GDA_SQL_OPERATOR_TYPE_STAR: + * @GDA_SQL_OPERATOR_TYPE_DIV: + * @GDA_SQL_OPERATOR_TYPE_REM: + * @GDA_SQL_OPERATOR_TYPE_BITAND: + * @GDA_SQL_OPERATOR_TYPE_BITOR: + * @GDA_SQL_OPERATOR_TYPE_BITNOT: + */ +typedef enum { + GDA_SQL_OPERATOR_TYPE_AND, + GDA_SQL_OPERATOR_TYPE_OR, + + GDA_SQL_OPERATOR_TYPE_EQ, + GDA_SQL_OPERATOR_TYPE_IS, + GDA_SQL_OPERATOR_TYPE_LIKE, + GDA_SQL_OPERATOR_TYPE_BETWEEN, + GDA_SQL_OPERATOR_TYPE_GT, + GDA_SQL_OPERATOR_TYPE_LT, + GDA_SQL_OPERATOR_TYPE_GEQ, + GDA_SQL_OPERATOR_TYPE_LEQ, + GDA_SQL_OPERATOR_TYPE_DIFF, + GDA_SQL_OPERATOR_TYPE_REGEXP, + GDA_SQL_OPERATOR_TYPE_REGEXP_CI, + GDA_SQL_OPERATOR_TYPE_NOT_REGEXP, + GDA_SQL_OPERATOR_TYPE_NOT_REGEXP_CI, + GDA_SQL_OPERATOR_TYPE_SIMILAR, + GDA_SQL_OPERATOR_TYPE_ISNULL, + GDA_SQL_OPERATOR_TYPE_ISNOTNULL, + GDA_SQL_OPERATOR_TYPE_NOT, + GDA_SQL_OPERATOR_TYPE_IN, + GDA_SQL_OPERATOR_TYPE_NOTIN, + + GDA_SQL_OPERATOR_TYPE_CONCAT, + GDA_SQL_OPERATOR_TYPE_PLUS, + GDA_SQL_OPERATOR_TYPE_MINUS, + GDA_SQL_OPERATOR_TYPE_STAR, + GDA_SQL_OPERATOR_TYPE_DIV, + GDA_SQL_OPERATOR_TYPE_REM, + GDA_SQL_OPERATOR_TYPE_BITAND, + GDA_SQL_OPERATOR_TYPE_BITOR, + GDA_SQL_OPERATOR_TYPE_BITNOT, + GDA_SQL_OPERATOR_TYPE_ILIKE, + + GDA_SQL_OPERATOR_TYPE_NOTLIKE, + GDA_SQL_OPERATOR_TYPE_NOTILIKE +} GdaSqlOperatorType; + +/** + * GdaSqlOperation: + * @any: inheritance structure + * @operator_type: operator type to be used. See #GdaSqlOperatorType + * @operands: (element-type Gda.SqlExpr) + * : list of #GdaSqlExpr operands + * + * This structure represents an operation between one or more operands. + */ +struct _GdaSqlOperation { + GdaSqlAnyPart any; + GdaSqlOperatorType operator_type; + GSList *operands; + + /*< private >*/ + /* Padding for future expansion */ + gpointer _gda_reserved1; + gpointer _gda_reserved2; +}; + +#define GDA_TYPE_SQL_OPERATION (gda_sql_operation_get_type()) + +GType gda_sql_operation_get_type (void) G_GNUC_CONST; +GdaSqlOperation *gda_sql_operation_new (GdaSqlAnyPart *parent); +void gda_sql_operation_free (GdaSqlOperation *operation); +GdaSqlOperation *gda_sql_operation_copy (GdaSqlOperation *operation); +gchar *gda_sql_operation_serialize (GdaSqlOperation *operation); +const gchar *gda_sql_operation_operator_to_string (GdaSqlOperatorType op); +GdaSqlOperatorType gda_sql_operation_operator_from_string (const gchar *op); + +/* + * A CASE expression + */ +/** + * GdaSqlCase: + * @any: inheritance structure + * @base_expr: expression to test + * @when_expr_list: list of #GdaSqlExpr, one for each WHEN clause + * @then_expr_list: list of #GdaSqlExpr, one for each THEN clause + * @else_expr: default expression for the CASE + * + * This structure represents a CASE WHEN... construct + */ +struct _GdaSqlCase +{ + GdaSqlAnyPart any; + GdaSqlExpr *base_expr; + GSList *when_expr_list; + GSList *then_expr_list; + GdaSqlExpr *else_expr; + + /*< private >*/ + /* Padding for future expansion */ + gpointer _gda_reserved1; + gpointer _gda_reserved2; +}; +#define GDA_TYPE_SQL_CASE (gda_sql_case_get_type()) + +GType gda_sql_case_get_type (void) G_GNUC_CONST; + +GdaSqlCase *gda_sql_case_new (GdaSqlAnyPart *parent); +void gda_sql_case_free (GdaSqlCase *sc); +GdaSqlCase *gda_sql_case_copy (GdaSqlCase *sc); +gchar *gda_sql_case_serialize (GdaSqlCase *sc); + +/* + * Any expression in a SELECT ... before the FROM clause + */ +/** + * GdaSqlSelectField: + * @any: inheritance structure + * @expr: expression + * @field_name: field name part of @expr if @expr represents a field + * @table_name: table name part of @expr if @expr represents a field + * @as: alias + * @validity_meta_object: + * @validity_meta_table_column: + * + * This structure represents a selected item in a SELECT statement (when executed, the returned data set + * will have one column per selected item). Note that the @table_name and + * @field_name field parts will be overwritten by &LIBGDA;, + * set the value of @expr->value instead. + */ +struct _GdaSqlSelectField +{ + GdaSqlAnyPart any; + GdaSqlExpr *expr; + gchar *field_name; /* may be NULL if expr does not refer to a table.field, can also be "*" */ + gchar *table_name; /* may be NULL if expr does not refer to a table.field */ + gchar *as; + + /* validity check with a connection */ + GdaMetaDbObject *validity_meta_object; + GdaMetaTableColumn *validity_meta_table_column; + + /*< private >*/ + /* Padding for future expansion */ + gpointer _gda_reserved1; + gpointer _gda_reserved2; +}; +#define GDA_TYPE_SQL_SELECT_FIELD (gda_sql_select_field_get_type()) + +GType gda_sql_select_field_get_type (void) G_GNUC_CONST; + +GdaSqlSelectField *gda_sql_select_field_new (GdaSqlAnyPart *parent); +void gda_sql_select_field_free (GdaSqlSelectField *field); +GdaSqlSelectField *gda_sql_select_field_copy (GdaSqlSelectField *field); +gchar *gda_sql_select_field_serialize (GdaSqlSelectField *field); +void _gda_sql_select_field_check_clean (GdaSqlSelectField *field); + +void gda_sql_select_field_take_star_value(GdaSqlSelectField *field, GValue *value); +void gda_sql_select_field_take_expr (GdaSqlSelectField *field, GdaSqlExpr *expr); +void gda_sql_select_field_take_alias (GdaSqlSelectField *field, GValue *alias); + +/* + * Any TARGET ... in a SELECT statement + */ +/** + * GdaSqlSelectTarget: + * @any: inheritance structure + * @expr: expression + * @table_name: table name part of @expr if @expr represents a table + * @as: alias + * @validity_meta_object: + * + * This structure represents a target used to fetch data from in a SELECT statement; it can represent a table or + * a sub select. Note that the @table_name + * part will be overwritten by &LIBGDA;, + * set the value of @expr->value instead. + */ +struct _GdaSqlSelectTarget +{ + GdaSqlAnyPart any; + GdaSqlExpr *expr; + gchar *table_name; /* may be NULL if expr does not refer to a table */ + gchar *as; + + /* validity check with a connection */ + GdaMetaDbObject *validity_meta_object; + + /*< private >*/ + /* Padding for future expansion */ + gpointer _gda_reserved1; + gpointer _gda_reserved2; +}; +#define GDA_TYPE_SQL_SELECT_TARGET (gda_sql_select_target_get_type()) + +GType gda_sql_select_target_get_type (void) G_GNUC_CONST; + +GdaSqlSelectTarget *gda_sql_select_target_new (GdaSqlAnyPart *parent); +void gda_sql_select_target_free (GdaSqlSelectTarget *target); +GdaSqlSelectTarget *gda_sql_select_target_copy (GdaSqlSelectTarget *target); +gchar *gda_sql_select_target_serialize (GdaSqlSelectTarget *target); +void _gda_sql_select_target_check_clean (GdaSqlSelectTarget *target); + +void gda_sql_select_target_take_table_name (GdaSqlSelectTarget *target, GValue *value); +void gda_sql_select_target_take_select (GdaSqlSelectTarget *target, GdaSqlStatement *stmt); +void gda_sql_select_target_take_alias (GdaSqlSelectTarget *target, GValue *alias); + +/* + * Any JOIN ... in a SELECT statement + */ +/** + * GdaSqlSelectJoinType: + * @GDA_SQL_SELECT_JOIN_CROSS: + * @GDA_SQL_SELECT_JOIN_NATURAL: + * @GDA_SQL_SELECT_JOIN_INNER: + * @GDA_SQL_SELECT_JOIN_LEFT: + * @GDA_SQL_SELECT_JOIN_RIGHT: + * @GDA_SQL_SELECT_JOIN_FULL: + */ +typedef enum { + GDA_SQL_SELECT_JOIN_CROSS, + GDA_SQL_SELECT_JOIN_NATURAL, + GDA_SQL_SELECT_JOIN_INNER, + GDA_SQL_SELECT_JOIN_LEFT, + GDA_SQL_SELECT_JOIN_RIGHT, + GDA_SQL_SELECT_JOIN_FULL +} GdaSqlSelectJoinType; + +/** + * GdaSqlSelectJoin: + * @any: inheritance structure + * @type: type of join + * @position: represents a join between a target at (pos < @position) and the one at @position + * @expr: (nullable): joining expression, or %NULL + * @use: (nullable): list of #GdaSqlField pointers to use when joining, or %NULL + * + * This structure represents a join between two targets in a SELECT statement. + */ +struct _GdaSqlSelectJoin +{ + GdaSqlAnyPart any; + GdaSqlSelectJoinType type; + gint position; /* between a target at (pos < @position) and the one @position */ + GdaSqlExpr *expr; + GSList *use; /* list of GdaSqlField pointers */ + + /*< private >*/ + /* Padding for future expansion */ + gpointer _gda_reserved1; + gpointer _gda_reserved2; +}; +#define GDA_TYPE_SQL_SELECT_JOIN (gda_sql_select_join_get_type()) + +GType gda_sql_select_join_get_type (void) G_GNUC_CONST; +GdaSqlSelectJoin *gda_sql_select_join_new (GdaSqlAnyPart *parent); +void gda_sql_select_join_free (GdaSqlSelectJoin *join); +GdaSqlSelectJoin *gda_sql_select_join_copy (GdaSqlSelectJoin *join); +gchar *gda_sql_select_join_serialize (GdaSqlSelectJoin *join); + +const gchar *gda_sql_select_join_type_to_string (GdaSqlSelectJoinType type); + + +/* + * Any FROM ... in a SELECT statement + */ +/** + * GdaSqlSelectFrom: + * @any: inheritance structure + * @targets: (element-type Gda.SqlSelectTarget): list of #GdaSqlSelectTarget + * @joins: (element-type Gda.SqlSelectJoin): list of #GdaSqlSelectJoin + * + * This structure represents the FROM clause of a SELECT statement, it lists targets and joins + */ +struct _GdaSqlSelectFrom +{ + GdaSqlAnyPart any; + GSList *targets; + GSList *joins; + + /*< private >*/ + /* Padding for future expansion */ + gpointer _gda_reserved1; + gpointer _gda_reserved2; +}; +#define GDA_TYPE_SQL_SELECT_FROM (gda_sql_select_from_get_type()) + +GType gda_sql_select_from_get_type (void) G_GNUC_CONST; +GdaSqlSelectFrom *gda_sql_select_from_new (GdaSqlAnyPart *parent); +void gda_sql_select_from_free (GdaSqlSelectFrom *from); +GdaSqlSelectFrom *gda_sql_select_from_copy (GdaSqlSelectFrom *from); +gchar *gda_sql_select_from_serialize (GdaSqlSelectFrom *from); + +void gda_sql_select_from_take_new_target(GdaSqlSelectFrom *from, GdaSqlSelectTarget *target); +void gda_sql_select_from_take_new_join (GdaSqlSelectFrom *from, GdaSqlSelectJoin *join); + +/* + * Any expression in a SELECT ... after the ORDER BY + */ +/** + * GdaSqlSelectOrder: + * @any: inheritance structure + * @expr: expression to order on + * @asc: TRUE is ordering is ascending + * @collation_name: name of the collation to use for ordering + * + * This structure represents the ordering of a SELECT statement. + */ +struct _GdaSqlSelectOrder +{ + GdaSqlAnyPart any; + GdaSqlExpr *expr; + gboolean asc; + gchar *collation_name; + + /*< private >*/ + /* Padding for future expansion */ + gpointer _gda_reserved1; + gpointer _gda_reserved2; +}; +#define GDA_TYPE_SQL_SELECT_ORDER (gda_sql_select_order_get_type()) + +GType gda_sql_select_order_get_type (void) G_GNUC_CONST; +GdaSqlSelectOrder *gda_sql_select_order_new (GdaSqlAnyPart *parent); +void gda_sql_select_order_free (GdaSqlSelectOrder *order); +GdaSqlSelectOrder *gda_sql_select_order_copy (GdaSqlSelectOrder *order); +gchar *gda_sql_select_order_serialize (GdaSqlSelectOrder *order); + +G_END_DECLS + +#endif diff --git a/.flatpak-builder/cache/objects/b5/c4f216ea6fbe6749a71a82ada81e8a1fad04337677fcbf8c25b2f304394a99.file b/.flatpak-builder/cache/objects/b5/c4f216ea6fbe6749a71a82ada81e8a1fad04337677fcbf8c25b2f304394a99.file new file mode 100755 index 0000000..466fadd Binary files /dev/null and b/.flatpak-builder/cache/objects/b5/c4f216ea6fbe6749a71a82ada81e8a1fad04337677fcbf8c25b2f304394a99.file differ diff --git a/.flatpak-builder/cache/objects/b5/c9c8fd4963fa4e7983f8804c425c6b9b4501f7bb19fb6e6d573b6c32c5d58c.dirtree b/.flatpak-builder/cache/objects/b5/c9c8fd4963fa4e7983f8804c425c6b9b4501f7bb19fb6e6d573b6c32c5d58c.dirtree new file mode 100644 index 0000000..e6f2fc6 Binary files /dev/null and b/.flatpak-builder/cache/objects/b5/c9c8fd4963fa4e7983f8804c425c6b9b4501f7bb19fb6e6d573b6c32c5d58c.dirtree differ diff --git a/.flatpak-builder/cache/objects/b5/dc6ba8951325eb271a7680936b628c0b29adbaae5e7b92c7af59662bfa5435.file b/.flatpak-builder/cache/objects/b5/dc6ba8951325eb271a7680936b628c0b29adbaae5e7b92c7af59662bfa5435.file new file mode 100644 index 0000000..12279b5 --- /dev/null +++ b/.flatpak-builder/cache/objects/b5/dc6ba8951325eb271a7680936b628c0b29adbaae5e7b92c7af59662bfa5435.file @@ -0,0 +1,76 @@ +/* gda-db-view.h + * + * Copyright (C) 2018-2019 Pavlo Solntsev + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +#ifndef GDA_DB_VIEW_H +#define GDA_DB_VIEW_H + +#include +#include +#include +#include "gda-db-base.h" +#include "gda-db-buildable.h" +#include "gda-meta-struct.h" +#include "gda-server-operation.h" + + +G_BEGIN_DECLS + +#define GDA_TYPE_DB_VIEW (gda_db_view_get_type()) + +G_DECLARE_DERIVABLE_TYPE (GdaDbView, gda_db_view, GDA, DB_VIEW, GdaDbBase) + +struct _GdaDbViewClass +{ + GdaDbBaseClass parent_class; +}; + +typedef enum +{ + GDA_DB_VIEW_RESTRICT = 0, + GDA_DB_VIEW_CASCADE +} GdaDbViewRefAction; + + +GdaDbView* gda_db_view_new (void); + +gboolean gda_db_view_get_istemp (GdaDbView *self); +void gda_db_view_set_istemp (GdaDbView *self, + gboolean temp); + +gboolean gda_db_view_get_ifnoexist (GdaDbView *self); +void gda_db_view_set_ifnoexist (GdaDbView *self, + gboolean noexist); + +const gchar* gda_db_view_get_defstring (GdaDbView *self); +void gda_db_view_set_defstring (GdaDbView *self, + const gchar *str); + +gboolean gda_db_view_get_replace (GdaDbView *self); +void gda_db_view_set_replace (GdaDbView *self, + gboolean replace); + +gboolean gda_db_view_prepare_create (GdaDbView *self, + GdaServerOperation *op, + GError **error); + +G_END_DECLS + +#endif /* GDA_DB_VIEW_H */ + + diff --git a/.flatpak-builder/cache/objects/b6/6e7144b5005c6c2c079f73e35c015cbfaa7758bc2601732546eef89bccb561.dirtree b/.flatpak-builder/cache/objects/b6/6e7144b5005c6c2c079f73e35c015cbfaa7758bc2601732546eef89bccb561.dirtree new file mode 100644 index 0000000..da5cbe9 Binary files /dev/null and b/.flatpak-builder/cache/objects/b6/6e7144b5005c6c2c079f73e35c015cbfaa7758bc2601732546eef89bccb561.dirtree differ diff --git a/.flatpak-builder/cache/objects/b6/d5347e5f098ebf829807275907c7579e3ebaa3ba2f075cddf0c012bd2e9c8d.file b/.flatpak-builder/cache/objects/b6/d5347e5f098ebf829807275907c7579e3ebaa3ba2f075cddf0c012bd2e9c8d.file new file mode 100644 index 0000000..56fa164 --- /dev/null +++ b/.flatpak-builder/cache/objects/b6/d5347e5f098ebf829807275907c7579e3ebaa3ba2f075cddf0c012bd2e9c8d.file @@ -0,0 +1,7351 @@ +/* + * Copyright (C) 2000 - 2001 Reinhard Müller + * Copyright (C) 2000 - 2004 Rodrigo Moya + * Copyright (C) 2001 - 2003 Gonzalo Paniagua Javier + * Copyright (C) 2001 - 2015 Vivien Malerba + * Copyright (C) 2002 Andrew Hill + * Copyright (C) 2002 Cleber Rodrigues + * Copyright (C) 2002 Zbigniew Chyla + * Copyright (C) 2003 Laurent Sansonetti + * Copyright (C) 2003 Paisa Seeluangsawat + * Copyright (C) 2004 - 2005 Alan Knowles + * Copyright (C) 2004 Dani Baeyens + * Copyright (C) 2004 José María Casanova Crespo + * Copyright (C) 2004 Szalai Ferenc + * Copyright (C) 2005 - 2009 Bas Driessen + * Copyright (C) 2005 Álvaro Peña + * Copyright (C) 2006 - 2012 Murray Cumming + * Copyright (C) 2007 Armin Burgmeier + * Copyright (C) 2007 Leonardo Boshell + * Copyright (C) 2008 Johannes Schmid + * Copyright (C) 2010 David King + * Copyright (C) 2010 Jonh Wendell + * Copyright (C) 2011, 2018-2019 Daniel Espinosa + * Copyright (C) 2013 Miguel Angel Cabrera Moya + * Copyright (C) 2014 Anders Jonsson + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#undef GDA_DISABLE_DEPRECATED +#undef GSEAL_ENABLE + +#define G_LOG_DOMAIN "GDA-connection" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "gda-marshal.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "gda-statement-priv.h" +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +static GMutex global_mutex; +static GdaSqlParser *internal_parser = NULL; +static GHashTable *all_context_hash = NULL; /* key = a #GThread, value = a #GMainContext (ref held) */ + +/* GdaLockable interface */ +static void gda_connection_lockable_init (GdaLockableInterface *iface); +static void gda_connection_lock (GdaLockable *lockable); +static gboolean gda_connection_trylock (GdaLockable *lockable); +static void gda_connection_unlock (GdaLockable *lockable); + +/* number of GdaConnectionEvent kept by each connection. Should be enough to avoid losing any + * event, considering that the events are reseted after each statement execution */ +#define EVENTS_ARRAY_SIZE 5 + +typedef struct { + GdaServerProvider *provider_obj; + GdaConnectionOptions options; /* ORed flags */ + gchar *dsn; + gchar *cnc_string; + gchar *auth_string; + + GHashTable *context_hash; /* key = a #GThread, value = a #GMainContext (ref held) */ + + GdaMetaStore *meta_store; + + gboolean auto_clear_events; /* TRUE if events_list is cleared before any statement execution */ + GdaConnectionEvent **events_array; /* circular array */ + gint events_array_size; + gboolean events_array_full; + gint events_array_next; + GList *events_list; /* for API compat */ + + GdaConnectionStatus status; + guint busy_count; + + GdaTransactionStatus *trans_status; + GHashTable *prepared_stmts; + + GdaServerProviderConnectionData *provider_data; + GThread *worker_thread; /* no ref held, used only for comparisons */ + + /* multi threading locking */ + GRecMutex rmutex; + gboolean mutex_initalized; + + /* auto meta data update */ + GArray *trans_meta_context; /* Array of GdaMetaContext pointers */ + + gboolean exec_times; + guint exec_slowdown; +} GdaConnectionPrivate; + +G_DEFINE_TYPE_WITH_CODE (GdaConnection, gda_connection, G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (GDA_TYPE_LOCKABLE, gda_connection_lockable_init) + G_ADD_PRIVATE (GdaConnection)) + + +static void add_exec_time_to_object (GObject *obj, GTimer *timer); + +static void gda_connection_class_init (GdaConnectionClass *klass); +static void gda_connection_init (GdaConnection *cnc); +static void gda_connection_dispose (GObject *object); +static void gda_connection_set_property (GObject *object, + guint param_id, + const GValue *value, + GParamSpec *pspec); +static void gda_connection_get_property (GObject *object, + guint param_id, + GValue *value, + GParamSpec *pspec); + + +static void update_meta_store_after_statement_exec (GdaConnection *cnc, GdaStatement *stmt, GdaSet *params); +static void change_events_array_max_size (GdaConnection *cnc, gint size); + +enum { + SIG_ERROR, + OPENED, + CLOSED, + DSN_CHANGED, + TRANSACTION_STATUS_CHANGED, + STATUS_CHANGED, + LAST_SIGNAL +}; + +static gint gda_connection_signals[LAST_SIGNAL] = { 0, 0, 0, 0, 0, 0 }; + +/* properties */ +enum +{ + PROP_0, + PROP_DSN, + PROP_CNC_STRING, + PROP_PROVIDER_OBJ, + PROP_AUTH_STRING, + PROP_OPTIONS, + PROP_META_STORE, + PROP_EVENTS_HISTORY_SIZE, + PROP_EXEC_TIMES, + PROP_EXEC_SLOWDOWN +}; + +extern GdaServerProvider *_gda_config_sqlite_provider; /* defined in gda-config.c */ + +static gint debug_level = -1; +static void +dump_exec_params (GdaConnection *cnc, GdaStatement *stmt, GdaSet *params) +{ + if (params && (debug_level & 8)) { + GSList *list; + gchar *sql; + sql = gda_statement_to_sql_extended (stmt, cnc, params, GDA_STATEMENT_SQL_PARAMS_SHORT, + NULL, NULL); +#ifdef GDA_DEBUG + g_print ("EVENT> COMMAND: parameters (on cnx %p) for statement [%s]\n", cnc, sql); +#endif + for (list = gda_set_get_holders (params); list; list = list->next) { + GdaHolder *holder = GDA_HOLDER (list->data); + gchar *str; + const GValue *value; + value = gda_holder_get_value (holder); + str = value ? gda_value_stringify (value) : "NULL"; +#ifdef GDA_DEBUG + g_print ("\t%s: type=>%s, value=>%s\n", gda_holder_get_id (holder), + gda_g_type_to_string (gda_holder_get_g_type (holder)), + str); +#endif + if (value) + g_free (str); + } + g_free (sql); + } +} + + +/* + * GdaConnection class implementation + * @klass: + */ +static void +gda_connection_class_init (GdaConnectionClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + /** + * GdaConnection::error: + * @cnc: the #GdaConnection + * @event: a #GdaConnectionEvent object + * + * Gets emitted whenever a connection event occurs. Check the nature of @event to + * see if it's an error or a simple notification + */ + gda_connection_signals[SIG_ERROR] = + g_signal_new ("error", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GdaConnectionClass, error), + NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, GDA_TYPE_CONNECTION_EVENT); + /** + * GdaConnection::opened: + * @cnc: the #GdaConnection + * + * Gets emitted when the connection has been opened to the database + */ + gda_connection_signals[OPENED] = + g_signal_new ("opened", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (GdaConnectionClass, opened), + NULL, NULL, + _gda_marshal_VOID__VOID, + G_TYPE_NONE, 0); + /** + * GdaConnection::closed: + * @cnc: the #GdaConnection + * + * Gets emitted when the connection to the database has been closed + */ + gda_connection_signals[CLOSED] = /* runs after user handlers */ + g_signal_new ("closed", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GdaConnectionClass, closed), + NULL, NULL, + _gda_marshal_VOID__VOID, + G_TYPE_NONE, 0); + /** + * GdaConnection::dsn-changed: + * @cnc: the #GdaConnection + * + * Gets emitted when the DSN used by @cnc has been changed + */ + gda_connection_signals[DSN_CHANGED] = + g_signal_new ("dsn-changed", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GdaConnectionClass, dsn_changed), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + /** + * GdaConnection::transaction-status-changed: + * @cnc: the #GdaConnection + * + * Gets emitted when the transaction status of @cnc has changed (a transaction has been + * started, rolled back, a savepoint added,...) + */ + gda_connection_signals[TRANSACTION_STATUS_CHANGED] = + g_signal_new ("transaction-status-changed", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GdaConnectionClass, transaction_status_changed), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + /** + * GdaConnection::status-changed: + * @cnc: the #GdaConnection + * @status: (type GdaConnectionStatus): the new connection status + * + * Gets emitted when the @cnc's status has changed (usually when a the connection is being used to execute + * a statement) + * + * Since: 6.0 + */ + gda_connection_signals[STATUS_CHANGED] = + g_signal_new ("status-changed", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GdaConnectionClass, status_changed), + NULL, NULL, + _gda_marshal_VOID__ENUM, + G_TYPE_NONE, 1, GDA_TYPE_CONNECTION_STATUS); + + /* Properties */ + object_class->set_property = gda_connection_set_property; + object_class->get_property = gda_connection_get_property; + + g_object_class_install_property (object_class, PROP_DSN, + g_param_spec_string ("dsn", NULL, _("DSN to use"), NULL, + (G_PARAM_READABLE | G_PARAM_WRITABLE))); + g_object_class_install_property (object_class, PROP_CNC_STRING, + g_param_spec_string ("cnc-string", NULL, _("Connection string to use"), NULL, + (G_PARAM_READABLE | G_PARAM_WRITABLE))); + g_object_class_install_property (object_class, PROP_PROVIDER_OBJ, + g_param_spec_object ("provider", NULL, _("Provider to use"), + GDA_TYPE_SERVER_PROVIDER, + (G_PARAM_READABLE | G_PARAM_WRITABLE))); + + g_object_class_install_property (object_class, PROP_AUTH_STRING, + g_param_spec_string ("auth-string", NULL,_("Authentication string to use"), + NULL, + (G_PARAM_READABLE | G_PARAM_WRITABLE))); + g_object_class_install_property (object_class, PROP_OPTIONS, + g_param_spec_flags ("options", NULL, _("Options"), + GDA_TYPE_CONNECTION_OPTIONS, GDA_CONNECTION_OPTIONS_NONE, + (G_PARAM_READABLE | G_PARAM_WRITABLE))); + g_object_class_install_property (object_class, PROP_META_STORE, + /* To translators: Don't translate "GdaMetaStore", it's a class name */ + g_param_spec_object ("meta-store", NULL, _ ("GdaMetaStore used by the connection"), + GDA_TYPE_META_STORE, + (G_PARAM_READABLE | G_PARAM_WRITABLE))); + + /** + * GdaConnection:events-history-size: + * + * Defines the number of #GdaConnectionEvent objects kept in memory which can + * be fetched using gda_connection_get_events(). + * + * Since: 4.2 + */ + g_object_class_install_property (object_class, PROP_EVENTS_HISTORY_SIZE, + g_param_spec_int ("events-history-size", NULL, + _("Number of history events to keep in memory"), EVENTS_ARRAY_SIZE, G_MAXINT, + EVENTS_ARRAY_SIZE, + (G_PARAM_READABLE | G_PARAM_WRITABLE))); + + /** + * GdaConnection:execution-timer: + * + * Computes execution times for each statement executed. + * + * Since: 4.2.9 + **/ + g_object_class_install_property (object_class, PROP_EXEC_TIMES, + g_param_spec_boolean ("execution-timer", NULL, + _("Computes execution delay for each executed statement"), + FALSE, + (G_PARAM_READABLE | G_PARAM_WRITABLE))); + /** + * GdaConnection:execution-slowdown: + * + * Artificially slows down the execution of queries. This property can be used to + * debug some problems. If non zero, this value is the number of microseconds waited before actually + * executing each query. + * NB: this parameter is ignored during the meta store update (it is set to 0 before the meta data update + * and restored to its state after). + * + * Since: 5.2.0 + **/ + g_object_class_install_property (object_class, PROP_EXEC_SLOWDOWN, + g_param_spec_uint ("execution-slowdown", NULL, + _("Artificially slows down the execution of queries"), + 0, G_MAXUINT, 0, + (G_PARAM_READABLE | G_PARAM_WRITABLE))); + + object_class->dispose = gda_connection_dispose; + + /* computing debug level */ + if (debug_level == -1) { + const gchar *str; + debug_level = 0; + str = getenv ("GDA_CONNECTION_EVENTS_SHOW"); /* Flawfinder: ignore */ + if (str) { + gchar **array; + guint i; + guint array_len; + array = g_strsplit_set (str, " ,/;:", 0); + array_len = g_strv_length (array); + for (i = 0; i < array_len; i++) { + if (!g_ascii_strcasecmp (array[i], "notice")) + debug_level += 1; + else if (!g_ascii_strcasecmp (array[i], "warning")) + debug_level += 2; + else if (!g_ascii_strcasecmp (array[i], "error")) + debug_level += 4; + else if (!g_ascii_strcasecmp (array[i], "command")) + debug_level += 8; + } + g_strfreev (array); + } + } +} + +static void +gda_connection_lockable_init (GdaLockableInterface *iface) +{ + iface->lock = gda_connection_lock; + iface->trylock = gda_connection_trylock; + iface->unlock = gda_connection_unlock; +} + +static void +all_context_hash_func (GThread *key, GMainContext *context, GHashTable *copyto) +{ + g_hash_table_insert (copyto, key, g_main_context_ref (context)); +} + +static void +gda_connection_init (GdaConnection *cnc) +{ + g_return_if_fail (GDA_IS_CONNECTION (cnc)); + + GdaConnectionPrivate *priv = gda_connection_get_instance_private (cnc); + g_rec_mutex_init (&priv->rmutex); + priv->mutex_initalized = TRUE; + priv->provider_obj = NULL; + priv->dsn = NULL; + priv->cnc_string = NULL; + priv->auth_string = NULL; + if (all_context_hash) { + g_mutex_lock (&global_mutex); + priv->context_hash = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify) g_main_context_unref); + g_hash_table_foreach (all_context_hash, (GHFunc) all_context_hash_func, priv->context_hash); + g_mutex_unlock (&global_mutex); + } + else + priv->context_hash = NULL; + priv->auto_clear_events = TRUE; + priv->events_array_size = EVENTS_ARRAY_SIZE; + priv->events_array = g_new0 (GdaConnectionEvent*, EVENTS_ARRAY_SIZE); + priv->events_array_full = FALSE; + priv->events_array_next = 0; + priv->status = GDA_CONNECTION_STATUS_CLOSED; + priv->busy_count = 0; + priv->trans_status = NULL; /* no transaction yet */ + priv->prepared_stmts = NULL; + + priv->trans_meta_context = NULL; + priv->provider_data = NULL; + priv->worker_thread = NULL; + + priv->exec_times = FALSE; + priv->exec_slowdown = 0; +} + +static void auto_update_meta_context_free (GdaMetaContext *context); +static void +gda_connection_dispose (GObject *object) +{ + GdaConnection *cnc = (GdaConnection *) object; + + g_return_if_fail (GDA_IS_CONNECTION (cnc)); + GdaConnectionPrivate *priv = gda_connection_get_instance_private (cnc); + + /* free memory */ + gda_connection_close (cnc, NULL); + + if (priv->context_hash) { + g_hash_table_destroy (priv->context_hash); + priv->context_hash = NULL; + } + + /* get rid of prepared statements to avoid problems */ + if (priv->prepared_stmts) { + g_hash_table_destroy (priv->prepared_stmts); + priv->prepared_stmts = NULL; + } + + if (priv->provider_obj) { + _gda_server_provider_handlers_clear_for_cnc (priv->provider_obj, cnc); + g_object_unref (G_OBJECT (priv->provider_obj)); + priv->provider_obj = NULL; + } + + if (priv->events_list) { + g_list_free_full (priv->events_list, (GDestroyNotify) g_object_unref); + priv->events_list = NULL; + } + + if (priv->events_array) { + gint i; + for (i = 0; i < priv->events_array_size ; i++) { + GdaConnectionEvent *ev; + ev = priv->events_array [i]; + if (ev) + g_object_unref (ev); + } + g_free (priv->events_array); + priv->events_array = NULL; + } + + if (priv->trans_status) { + g_object_unref (priv->trans_status); + priv->trans_status = NULL; + } + + if (priv->meta_store != NULL) { + g_object_unref (priv->meta_store); + priv->meta_store = NULL; + } + + if (priv->trans_meta_context) { + gsize i; + for (i = 0; i < priv->trans_meta_context->len; i++) { + GdaMetaContext *context; + context = g_array_index (priv->trans_meta_context, GdaMetaContext*, i); + auto_update_meta_context_free (context); + } + g_array_free (priv->trans_meta_context, TRUE); + priv->trans_meta_context = NULL; + } + if (priv->dsn) { + g_free (priv->dsn); + priv->dsn = NULL; + } + if (priv->cnc_string) { + g_free (priv->cnc_string); + priv->cnc_string = NULL; + } + if (priv->auth_string) { + g_free (priv->auth_string); + priv->auth_string = NULL; + } + if (priv->mutex_initalized) { + g_rec_mutex_clear (&priv->rmutex); + priv->mutex_initalized = FALSE; + } + + /* chain to parent class */ + G_OBJECT_CLASS (gda_connection_parent_class)->dispose (object); +} + +/* module error */ +GQuark gda_connection_error_quark (void) +{ + static GQuark quark; + if (!quark) + quark = g_quark_from_static_string ("gda_connection_error"); + return quark; +} + +static void +gda_connection_set_property (GObject *object, + guint param_id, + const GValue *value, + GParamSpec *pspec) +{ + GdaConnection *cnc; + + cnc = GDA_CONNECTION (object); + GdaConnectionPrivate *priv = gda_connection_get_instance_private (cnc); + if (priv) { + switch (param_id) { + case PROP_DSN: { + const gchar *datasource = g_value_get_string (value); + GdaDsnInfo *dsn; + + gda_connection_lock ((GdaLockable*) cnc); + if (priv->provider_data) { + g_warning (_("Can't set the '%s' property when the connection is opened"), + pspec->name); + gda_connection_unlock ((GdaLockable*) cnc); + return; + } + + dsn = gda_config_get_dsn_info (datasource); + if (!dsn) { + g_warning (_("No DSN named '%s' defined"), datasource); + gda_connection_unlock ((GdaLockable*) cnc); + return; + } + + g_free (priv->dsn); + priv->dsn = g_strdup (datasource); +#ifdef GDA_DEBUG_signal + g_print (">> 'DSN_CHANGED' from %s\n", __FUNCTION__); +#endif + g_signal_emit (G_OBJECT (cnc), gda_connection_signals[DSN_CHANGED], 0); +#ifdef GDA_DEBUG_signal + g_print ("<< 'DSN_CHANGED' from %s\n", __FUNCTION__); +#endif + gda_connection_unlock ((GdaLockable*) cnc); + break; + } + case PROP_CNC_STRING: + gda_connection_lock ((GdaLockable*) cnc); + if (priv->provider_data) { + g_warning (_("Can't set the '%s' property when the connection is opened"), + pspec->name); + gda_connection_unlock ((GdaLockable*) cnc); + return; + } + g_free (priv->cnc_string); + priv->cnc_string = NULL; + if (g_value_get_string (value)) + priv->cnc_string = g_strdup (g_value_get_string (value)); + gda_connection_unlock ((GdaLockable*) cnc); + break; + case PROP_PROVIDER_OBJ: + gda_connection_lock ((GdaLockable*) cnc); + if (priv->provider_data) { + g_warning (_("Can't set the '%s' property when the connection is opened"), + pspec->name); + gda_connection_unlock ((GdaLockable*) cnc); + return; + } + if (priv->provider_obj) + g_object_unref (priv->provider_obj); + + priv->provider_obj = g_value_get_object (value); + g_object_ref (G_OBJECT (priv->provider_obj)); + gda_connection_unlock ((GdaLockable*) cnc); + break; + case PROP_AUTH_STRING: + gda_connection_lock ((GdaLockable*) cnc); + if (priv->provider_data) { + g_warning (_("Can't set the '%s' property when the connection is opened"), + pspec->name); + gda_connection_unlock ((GdaLockable*) cnc); + return; + } + else { + const gchar *str = g_value_get_string (value); + g_free (priv->auth_string); + priv->auth_string = NULL; + if (str) + priv->auth_string = g_strdup (str); + } + gda_connection_unlock ((GdaLockable*) cnc); + break; + case PROP_OPTIONS: { + GdaConnectionOptions flags; + flags = g_value_get_flags (value); + gda_connection_lock ((GdaLockable*) cnc); + if (priv->provider_data && + ((flags & (~GDA_CONNECTION_OPTIONS_SQL_IDENTIFIERS_CASE_SENSITIVE)) != + (priv->options & (~GDA_CONNECTION_OPTIONS_SQL_IDENTIFIERS_CASE_SENSITIVE)))) { + g_warning (_("Can't set the '%s' property once the connection is opened"), + pspec->name); + gda_connection_unlock ((GdaLockable*) cnc); + return; + } + priv->options = flags; + gda_connection_unlock ((GdaLockable*) cnc); + break; + } + case PROP_META_STORE: + gda_connection_lock ((GdaLockable*) cnc); + if (priv->meta_store) { + g_object_unref (priv->meta_store); + priv->meta_store = NULL; + } + priv->meta_store = g_value_get_object (value); + if (priv->meta_store) + g_object_ref (priv->meta_store); + gda_connection_unlock ((GdaLockable*) cnc); + break; + case PROP_EVENTS_HISTORY_SIZE: + gda_connection_lock ((GdaLockable*) cnc); + change_events_array_max_size (cnc, g_value_get_int (value)); + gda_connection_unlock ((GdaLockable*) cnc); + break; + case PROP_EXEC_TIMES: + priv->exec_times = g_value_get_boolean (value); + break; + case PROP_EXEC_SLOWDOWN: + priv->exec_slowdown = g_value_get_uint (value); + break; + } + } +} + +static void +gda_connection_get_property (GObject *object, + guint param_id, + GValue *value, + GParamSpec *pspec) +{ + GdaConnection *cnc; + + cnc = GDA_CONNECTION (object); + GdaConnectionPrivate *priv = gda_connection_get_instance_private (cnc); + if (priv) { + switch (param_id) { + case PROP_DSN: + g_value_set_string (value, priv->dsn); + break; + case PROP_CNC_STRING: + g_value_set_string (value, priv->cnc_string); + break; + case PROP_PROVIDER_OBJ: + g_value_set_object (value, (GObject*) priv->provider_obj); + break; + case PROP_AUTH_STRING: + g_value_set_string (value, priv->auth_string); + break; + case PROP_OPTIONS: + g_value_set_flags (value, priv->options); + break; + case PROP_META_STORE: + g_value_set_object (value, priv->meta_store); + break; + case PROP_EVENTS_HISTORY_SIZE: + g_value_set_int (value, priv->events_array_size); + break; + case PROP_EXEC_TIMES: + g_value_set_boolean (value, priv->exec_times); + break; + case PROP_EXEC_SLOWDOWN: + g_value_set_uint (value, priv->exec_slowdown); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + break; + } + } +} + +/** + * gda_connection_set_main_context: + * @cnc: (nullable): a #GdaConnection, or %NULL + * @thread: (nullable): the #GThread in which @context will be used, or %NULL (for the current thread) + * @context: (nullable): a #GMainContext, or %NULL + * + * Defines the #GMainContext which will still process events while a potentially blocking operation is performed using + * @cnc. If @cnc is %NULL, then this function applies to all the connections, except the ones for which a different + * context has been defined (be it user defined connections or internal connections used in other objects). + * On the other hand, if @cnc is not %NULL, then the setting only applied to @cnc. + * + * For exemple if there is a GUI which needs to continue to handle events, then you can use this function to pass + * the default #GMainContext used for the UI refreshing, for example: + * + * + * + * If @context is %NULL, then potentially blocking operation will actually block any event from being processed + * while the blocking operation is being performed. + * + * Since: 6.0 + */ +void +gda_connection_set_main_context (GdaConnection *cnc, GThread *thread, GMainContext *context) +{ + if (!thread) + thread = g_thread_self (); + + g_mutex_lock (&global_mutex); + + if (cnc) { + g_return_if_fail (GDA_IS_CONNECTION (cnc)); + GdaConnectionPrivate *priv = gda_connection_get_instance_private (cnc); + if (context) { + if (! priv->context_hash) + priv->context_hash = g_hash_table_new_full (NULL, NULL, NULL, + (GDestroyNotify) g_main_context_unref); + g_main_context_ref (context); + g_hash_table_insert (priv->context_hash, thread, g_main_context_ref (context)); + g_main_context_unref (context); + } + else if (priv->context_hash) + g_hash_table_remove (priv->context_hash, thread); + } + else { + if (context) { + if (! all_context_hash) + all_context_hash = g_hash_table_new_full (NULL, NULL, NULL, + (GDestroyNotify) g_main_context_unref); + g_main_context_ref (context); + g_hash_table_insert (all_context_hash, thread, g_main_context_ref (context)); + g_main_context_unref (context); + } + else if (all_context_hash) + g_hash_table_remove (all_context_hash, thread); + } + + g_mutex_unlock (&global_mutex); +} + +/** + * gda_connection_get_main_context: + * @cnc: (nullable): a #GdaConnection, or %NULL + * @thread: (nullable): the #GThread in which @context will be used, or %NULL (for the current thread) + * + * Get the #GMainContext used while a potentially blocking operation is performed using @nc, see + * gda_connection_set_main_context(). If @cnc is %NULL, then the setting applies to all the connections for which + * no other similar setting has been set. + * + * If no main context has been defined, then some function calls (for example connection opening) may block until the + * operation has finished. + * + * Returns: (transfer none): a #GMainContext, or %NULL + * + * Since: 6.0 + */ +GMainContext * +gda_connection_get_main_context (GdaConnection *cnc, GThread *thread) +{ + if (!thread) + thread = g_thread_self (); + + GMainContext *context = NULL; + + if (cnc) { + g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL); + GdaConnectionPrivate *priv = gda_connection_get_instance_private (cnc); + g_mutex_lock (&global_mutex); + if (priv->context_hash) + context = g_hash_table_lookup (priv->context_hash, thread); + if (!context && all_context_hash) + context = g_hash_table_lookup (all_context_hash, thread); + g_mutex_unlock (&global_mutex); + } + else { + g_mutex_lock (&global_mutex); + if (all_context_hash) + context = g_hash_table_lookup (all_context_hash, thread); + g_mutex_unlock (&global_mutex); + } + + return context; +} + +/* + * Returns: a new GType array, free using g_free(), or %NULL if none to compute + */ +static GType * +merge_column_types (const GType *struct_types, const GType *user_types) +{ + if (! user_types || !struct_types) + return NULL; + GArray *array; + guint i; + array = g_array_new (TRUE, FALSE, sizeof (GType)); + for (i = 0; + (user_types [i] != G_TYPE_NONE) && (struct_types [i] != G_TYPE_NONE); + i++) { + GType type; + if (user_types [i] == 0) + type = struct_types [i]; + else + type = user_types [i]; + g_array_append_val (array, type); + } + if (user_types [i] != G_TYPE_NONE) { + for (; user_types [i] != G_TYPE_NONE; i++) { + GType type = user_types [i]; + g_array_append_val (array, type); + } + } + else { + for (; struct_types [i] != G_TYPE_NONE; i++) { + GType type = struct_types [i]; + g_array_append_val (array, type); + } + } + GType *retval; + guint len; + len = array->len; + retval = (GType*) g_array_free (array, FALSE); + retval [len] = G_TYPE_NONE; + return retval; +} + +/** + * gda_connection_new_from_dsn_name: + * @dsn_name: data source name. + * @auth_string: (nullable): authentication string, or %NULL + * @options: options for the connection (see #GdaConnectionOptions). + * @error: a place to store an error, or %NULL + * + * This function creates a new function, using a pre-defined data source (DSN) name, + * see gda_config_define_dsn() for more information about how to define a DSN. If you don't want to define + * a DSN, it is possible to use gda_connection_new_from_string() instead of this method. + * + * The @dsn string must have the following format: "[<username>[:<password>]@]<DSN>" + * (if <username> and/or <password> are provided, and @auth_string is %NULL, then these username + * and passwords will be used). Note that if provided, <username> and <password> + * must be encoded as per RFC 1738, see gda_rfc1738_encode() for more information. + * + * The @auth_string can contain the authentication information for the server + * to accept the connection. It is a string containing semi-colon separated named value, usually + * like "USERNAME=...;PASSWORD=..." where the ... are replaced by actual values. Note that each + * name and value must be encoded as per RFC 1738, see gda_rfc1738_encode() for more information. + * + * The actual named parameters required depend on the provider being used, and that list is available + * as the auth_params member of the #GdaProviderInfo structure for each installed + * provider (use gda_config_get_provider_info() to get it). Also one can use the "gda-sql-6.0 -L" command + * to list the possible named parameters. + * + * This method may fail with a GDA_CONNECTION_ERROR domain error (see the #GdaConnectionError error codes) + * or a %GDA_CONFIG_ERROR domain error (see the #GdaConfigError error codes). + * + * The returned connection is not yet opened, you need to call gda_connection_open() or gda_connection_open_async(). + * + * Returns: (transfer full): a new #GdaConnection or %NULL if there was an error. + * + * Since: 6.0 + */ +GdaConnection * +gda_connection_new_from_dsn_name (const gchar *dsn_name, + const gchar *auth_string, + GdaConnectionOptions options, + GError **error) +{ + GdaConnection *cnc = NULL; + GdaDsnInfo *dsn_info; + gchar *user, *pass, *real_dsn; + gchar *real_auth_string = NULL; + + g_return_val_if_fail (dsn_name && *dsn_name, NULL); + + gda_dsn_split (dsn_name, &real_dsn, &user, &pass); + if (!real_dsn) { + g_free (user); + g_free (pass); + g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_DSN_NOT_FOUND_ERROR, + _("Malformed data source specification '%s'"), dsn_name); + return NULL; + } + + /* get the data source info */ + dsn_info = gda_config_get_dsn_info (real_dsn); + if (!dsn_info) { + g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_DSN_NOT_FOUND_ERROR, + _("Data source %s not found in configuration"), real_dsn); + g_free (real_dsn); + g_free (user); + g_free (pass); + return NULL; + } + if (!auth_string && user) { + gchar *s1; + s1 = gda_rfc1738_encode (user); + if (pass) { + gchar *s2; + s2 = gda_rfc1738_encode (pass); + real_auth_string = g_strdup_printf ("USERNAME=%s;PASSWORD=%s", s1, s2); + g_free (s2); + } + else + real_auth_string = g_strdup_printf ("USERNAME=%s", s1); + g_free (s1); + } + + /* try to find provider */ + if (dsn_info->provider != NULL) { + GdaProviderInfo *pinfo; + GdaServerProvider *prov = NULL; + + pinfo = gda_config_get_provider_info (dsn_info->provider); + if (pinfo) + prov = gda_config_get_provider (dsn_info->provider, error); + else + g_set_error (error, GDA_CONFIG_ERROR, GDA_CONFIG_PROVIDER_NOT_FOUND_ERROR, + _("No provider '%s' installed"), dsn_info->provider); + + if (prov) + cnc = _gda_server_provider_create_connection (prov, real_dsn, NULL, + auth_string ? auth_string : real_auth_string, + options); + } + else + g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_PROVIDER_NOT_FOUND_ERROR, + "%s", _("Datasource configuration error: no provider specified")); + + g_free (real_auth_string); + g_free (real_dsn); + g_free (user); + g_free (pass); + return cnc; +} + +/** + * gda_connection_new_from_dsn: + * @dsn: data source name. + * @auth_string: (nullable): authentication string, or %NULL + * @options: options for the connection (see #GdaConnectionOptions). + * @error: a place to store an error, or %NULL + * + * This function creates a new connection, using a pre-defined data source (DSN), see + * gda_config_define_dsn() for more information about how to define a DSN. If you don't want to + * define a DSN, it is possible to use gda_connection_new_from_string() instead of this method. + * + * The @auth_string can contain the authentication information for the server + * to accept the connection. It is a string containing semi-colon seperated named value, usually + * like "USERNAME=...;PASSWORD=..." where the ... are replaced by actual values. Note that each + * name and value must be encoded as per RFC 1738, see gda_rfc1738_encode() for more information. + * + * If @auth_string is given, it wil be used, otherwise auth_string of #GdaDsnInfo will be used. + * + * The actual named parameters required depend on the provider being used, and that list is available + * as the auth_params member of the #GdaProviderInfo structure for each installed + * provider (use gda_config_get_provider_info() to get it). Also one can use the "gda-sql-6.0 -L" command + * to list the possible named parameters. + * + * This method may fail with a GDA_CONNECTION_ERROR domain error (see the #GdaConnectionError error codes) + * or a %GDA_CONFIG_ERROR domain error (see the #GdaConfigError error codes). + * + * The returned connection is not yet opened, you need to call gda_connection_open() or gda_connection_open_async(). + * + * Returns: (transfer full): a new #GdaConnection or %NULL if there was an error. + * + * Since: 6.0 + */ +GdaConnection * +gda_connection_new_from_dsn (GdaDsnInfo *dsn, + const gchar *auth_string, + GdaConnectionOptions options, + GError **error) +{ + GdaConnection *cnc = NULL; + + g_return_val_if_fail (dsn, NULL); + g_return_val_if_fail (dsn->cnc_string, NULL); + +/* try to find provider */ + if (dsn->provider) + { + GdaProviderInfo *pinfo = NULL; + GdaServerProvider *prov = NULL; + + pinfo = gda_config_get_provider_info (dsn->provider); + if (pinfo) + prov = gda_config_get_provider (dsn->provider, error); + else + g_set_error (error, GDA_CONFIG_ERROR, GDA_CONFIG_PROVIDER_NOT_FOUND_ERROR, + _("No provider '%s' installed"), dsn->provider); + + if (prov) + cnc = _gda_server_provider_create_connection (prov, NULL, dsn->cnc_string, + auth_string ? auth_string : dsn->auth_string, + options); + } + else + g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_PROVIDER_NOT_FOUND_ERROR, + "%s", _("Datasource configuration error: no provider specified")); + + return cnc; +} + +/** + * gda_connection_open_from_dsn_name: + * @dsn_name: data source name. + * @auth_string: (nullable): authentication string, or %NULL + * @options: options for the connection (see #GdaConnectionOptions). + * @error: a place to store an error, or %NULL + * + * This function creates a connection and opens it, using a DSN name. If opening fails, then no connection is created. The named DSN should be available. + * See gda_connection_new_from_dsn_name() for more information. + * + * Returns: (transfer full): a new #GdaConnection if connection opening was successful or %NULL if there was an error. + */ +GdaConnection * +gda_connection_open_from_dsn_name (const gchar *dsn_name, + const gchar *auth_string, + GdaConnectionOptions options, + GError **error) +{ + GdaConnection *cnc = NULL; + + g_return_val_if_fail (dsn_name && *dsn_name, NULL); + + cnc = gda_connection_new_from_dsn_name (dsn_name, auth_string, options, error); + + if (cnc && !gda_connection_open (cnc, error)) + g_clear_object (&cnc); + + return cnc; +} + +/** + * gda_connection_open_from_dsn: + * @dsn: data sourcename. + * @auth_string: (nullable): authentication string, or %NULL + * @options: options for the connection (see #GdaConnectionOptions). + * @error: a place to store an error, or %NULL + * + * This function creates a connection and opens it, using a DSN. If opening fails, then no connection is created. + * See gda_connection_new_from_dsn() for more information. + * + * Returns: (transfer full): a new #GdaConnection if connection opening was successful or %NULL if there was an error. + * Since: 6.0 + */ +GdaConnection * +gda_connection_open_from_dsn (GdaDsnInfo *dsn, + const gchar *auth_string, + GdaConnectionOptions options, + GError **error) +{ + GdaConnection *cnc = NULL; + + g_return_val_if_fail (dsn, NULL); + g_return_val_if_fail (dsn->cnc_string, NULL); + + cnc = gda_connection_new_from_dsn (dsn, auth_string, options, error); + + if (cnc && !gda_connection_open (cnc, error)) + g_clear_object (&cnc); + + return cnc; +} + +/** + * gda_connection_new_from_string: + * @provider_name: (nullable): provider ID to connect to, or %NULL + * @cnc_string: connection string. + * @auth_string: (nullable): authentication string, or %NULL + * @options: options for the connection (see #GdaConnectionOptions). + * @error: a place to store an error, or %NULL + * + * Opens a connection given a provider ID and a connection string. This + * allows applications to open connections without having to create + * a data source (DSN) in the configuration. The format of @cnc_string is + * similar to PostgreSQL and MySQL connection strings. It is a semicolumn-separated + * series of <key>=<value> pairs, where each key and value are encoded as per RFC 1738, + * see gda_rfc1738_encode() for more information. + * + * The possible keys depend on the provider, the "gda-sql-6.0 -L" command + * can be used to list the actual keys for each installed database provider. + * + * For example the connection string to open an SQLite connection to a database + * file named "my_data.db" in the current directory would be "DB_DIR=.;DB_NAME=my_data". + * + * The @cnc_string string must have the following format: + * "[<provider>://][<username>[:<password>]@]<connection_params>" + * (if <username> and/or <password> are provided, and @auth_string is %NULL, then these username + * and passwords will be used, and if <provider> is provided and @provider_name is %NULL then this + * provider will be used). Note that if provided, <username>, <password> and <provider> + * must be encoded as per RFC 1738, see gda_rfc1738_encode() for more information. + * + * The @auth_string must contain the authentication information for the server + * to accept the connection. It is a string containing semi-colon seperated named values, usually + * like "USERNAME=...;PASSWORD=..." where the ... are replaced by actual values. Note that each + * name and value must be encoded as per RFC 1738, see gda_rfc1738_encode() for more information. + * + * The actual named parameters required depend on the provider being used, and that list is available + * as the auth_params member of the #GdaProviderInfo structure for each installed + * provider (use gda_config_get_provider_info() to get it). Similarly to the format of the connection + * string, use the "gda-sql-6.0 -L" command to list the possible named parameters. + * + * Additionally, it is possible to have the connection string + * respect the "<provider_name>://<real cnc string>" format, in which case the provider name + * and the real connection string will be extracted from that string (note that if @provider_name + * is not %NULL then it will still be used as the provider ID).\ + * + * This method may fail with a GDA_CONNECTION_ERROR domain error (see the #GdaConnectionError error codes) + * or a %GDA_CONFIG_ERROR domain error (see the #GdaConfigError error codes). + * + * The returned connection is not yet opened, you need to call gda_connection_open() or gda_connection_open_async(). + * + * Returns: (transfer full): a new #GdaConnection or %NULL if there was an error. + * + * Since: 5.0.2 + */ +GdaConnection * +gda_connection_new_from_string (const gchar *provider_name, const gchar *cnc_string, const gchar *auth_string, + GdaConnectionOptions options, GError **error) +{ + GdaConnection *cnc = NULL; + gchar *user, *pass, *real_cnc, *real_provider; + gchar *real_auth_string = NULL; + + g_return_val_if_fail (cnc_string && *cnc_string, NULL); + + gda_connection_string_split (cnc_string, &real_cnc, &real_provider, &user, &pass); + if (!real_cnc) { + g_free (user); + g_free (pass); + g_free (real_provider); + g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_DSN_NOT_FOUND_ERROR, + _("Malformed connection string '%s'"), cnc_string); + return NULL; + } + + if (!provider_name && !real_provider) { + g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_PROVIDER_NOT_FOUND_ERROR, + "%s", _("No database driver specified")); + g_free (user); + g_free (pass); + g_free (real_cnc); + return NULL; + } + + if (!auth_string && user) { + gchar *s1; + s1 = gda_rfc1738_encode (user); + if (pass) { + gchar *s2; + s2 = gda_rfc1738_encode (pass); + real_auth_string = g_strdup_printf ("USERNAME=%s;PASSWORD=%s", s1, s2); + g_free (s2); + } + else + real_auth_string = g_strdup_printf ("USERNAME=%s", s1); + g_free (s1); + } + + /* try to find provider */ + if (provider_name || real_provider) { + GdaProviderInfo *pinfo; + GdaServerProvider *prov = NULL; + + pinfo = gda_config_get_provider_info (provider_name ? provider_name : real_provider); + if (pinfo) + prov = gda_config_get_provider (provider_name ? provider_name : real_provider, error); + else + g_set_error (error, GDA_CONFIG_ERROR, GDA_CONFIG_PROVIDER_NOT_FOUND_ERROR, + _("No provider '%s' installed"), provider_name ? provider_name : real_provider); + + if (prov) + cnc = _gda_server_provider_create_connection (prov, NULL, real_cnc, + auth_string ? auth_string : real_auth_string, options); + } + + g_free (real_auth_string); + g_free (real_cnc); + g_free (user); + g_free (pass); + g_free (real_provider); + + return cnc; +} + +/** + * gda_connection_open_from_string: + * @provider_name: (nullable): provider ID to connect to, or %NULL + * @cnc_string: connection string. + * @auth_string: (nullable): authentication string, or %NULL + * @options: options for the connection (see #GdaConnectionOptions). + * @error: a place to store an error, or %NULL + * + * This function creates a connection and opens it, using a connection string. If opening fails, then no connection is created. + * See gda_connection_new_from_string() for more information. + * + * Returns: (transfer full): a new #GdaConnection if connection opening was successful or %NULL if there was an error. + */ +GdaConnection * +gda_connection_open_from_string (const gchar *provider_name, const gchar *cnc_string, const gchar *auth_string, + GdaConnectionOptions options, GError **error) +{ + GdaConnection *cnc; + cnc = gda_connection_new_from_string (provider_name, cnc_string, auth_string, options, error); + if (cnc && !gda_connection_open (cnc, error)) { + g_object_unref (cnc); + cnc = NULL; + } + return cnc; +} + + +/* + * Uses _gda_config_sqlite_provider to open a connection + */ +GdaConnection * +_gda_open_internal_sqlite_connection (const gchar *cnc_string) +{ + GdaConnection *cnc = NULL; + GdaServerProvider *prov = _gda_config_sqlite_provider; + gchar *user, *pass, *real_cnc, *real_provider; + + /*g_print ("%s(%s)\n", __FUNCTION__, cnc_string);*/ + gda_connection_string_split (cnc_string, &real_cnc, &real_provider, &user, &pass); + g_free (user); + g_free (pass); + g_free (real_provider); + + if (!real_cnc) + return NULL; + + cnc = _gda_server_provider_create_connection (prov, NULL, real_cnc, NULL, GDA_CONNECTION_OPTIONS_NONE); + g_free (real_cnc); + + /* open the connection */ + if (!gda_connection_open (cnc, NULL)) { + g_object_unref (cnc); + cnc = NULL; + } + return cnc; +} + +static void +sqlite_connection_closed_cb (GdaConnection *cnc, G_GNUC_UNUSED gpointer data) +{ + gchar *filename; + filename = g_object_get_data (G_OBJECT (cnc), "__gda_fname"); + g_assert (filename && *filename); + g_unlink (filename); +} + +/** + * gda_connection_open_sqlite: + * @directory: (nullable): the directory the database file will be in, or %NULL for the default TMP directory + * @filename: the database file name + * @auto_unlink: if %TRUE, then the database file will be removed afterwards + * + * Opens an SQLite connection even if the SQLite provider is not installed, + * to be used by database providers which need a temporary database to store + * some information. + * + * Returns: (transfer full): a new #GdaConnection, or %NULL if an error occurred + */ +GdaConnection * +gda_connection_open_sqlite (const gchar *directory, const gchar *filename, gboolean auto_unlink) +{ + GdaConnection *cnc; + gchar *fname; + gint fd; + + if (!directory) + directory = g_get_tmp_dir(); /* Flawfinder: ignore */ + else + g_return_val_if_fail (*directory, NULL); + g_return_val_if_fail (filename && *filename, NULL); + + fname = g_build_filename (directory, filename, NULL); +#ifdef G_OS_WIN32 + fd = g_open (fname, O_WRONLY | O_CREAT | O_TRUNC, + S_IRUSR | S_IWUSR); +#else + fd = g_open (fname, O_WRONLY | O_CREAT | O_NOCTTY | O_TRUNC, + S_IRUSR | S_IWUSR); +#endif + if (fd == -1) { + g_free (fname); + return NULL; + } + close (fd); + + gchar *tmp1, *tmp2, *cncstring; + tmp1 = gda_rfc1738_encode (directory); + tmp2 = gda_rfc1738_encode (filename); + cncstring = g_strdup_printf ("SQLite://DB_DIR=%s;DB_NAME=%s", tmp1, tmp2); + g_free (tmp1); + g_free (tmp2); + + cnc = _gda_open_internal_sqlite_connection (cncstring); + g_free (cncstring); + + if (auto_unlink) { + g_object_set_data_full (G_OBJECT (cnc), "__gda_fname", fname, g_free); + g_signal_connect (cnc, "closed", + G_CALLBACK (sqlite_connection_closed_cb), NULL); + } + else + g_free (fname); + return cnc; +} +/* + * Upon return, @out_params and @out_auth point to new #GdaQuarkList + * + * Returns: %TRUE if no error occurred + */ +static gboolean +compute_params_and_auth_quarks (GdaConnection *cnc, GdaQuarkList **out_params, GdaQuarkList **out_auth, GError **error) +{ + g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE); + GdaConnectionPrivate *priv = gda_connection_get_instance_private (cnc); + GdaDsnInfo *dsn_info = NULL; + GdaQuarkList *params, *auth; + + *out_params = NULL; + *out_auth = NULL; + + gda_connection_lock ((GdaLockable*) cnc); + + /* provider test */ + if (!priv->provider_obj) { + g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_NO_PROVIDER_SPEC_ERROR, + "%s", _("No provider specified")); + gda_connection_unlock ((GdaLockable*) cnc); + return FALSE; + } + + /* connection string */ + if (priv->dsn) { + /* get the data source info */ + dsn_info = gda_config_get_dsn_info (priv->dsn); + if (!dsn_info) { + gda_log_error (_("Data source %s not found in configuration"), priv->dsn); + g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_DSN_NOT_FOUND_ERROR, + _("Data source %s not found in configuration"), priv->dsn); + gda_connection_unlock ((GdaLockable*) cnc); + return FALSE; + } + + g_free (priv->cnc_string); + priv->cnc_string = g_strdup (dsn_info->cnc_string); + } + else { + if (!priv->cnc_string) { + gda_log_error (_("No DSN or connection string specified")); + g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_NO_CNC_SPEC_ERROR, + "%s", _("No DSN or connection string specified")); + gda_connection_unlock ((GdaLockable*) cnc); + return FALSE; + } + /* try to see if connection string has the :// format */ + } + params = gda_quark_list_new_from_string (priv->cnc_string); + + /* authentication string */ + char *real_auth_string; + if (priv->auth_string) + real_auth_string = g_strdup (priv->auth_string); + else { + if (dsn_info && dsn_info->auth_string) + real_auth_string = g_strdup (dsn_info->auth_string); + else + /* look for authentication parameters in cnc string */ + real_auth_string = g_strdup (priv->cnc_string); + } + auth = gda_quark_list_new_from_string (real_auth_string); + g_free (real_auth_string); + + gda_connection_unlock ((GdaLockable*) cnc); + + *out_params = params; + *out_auth = auth; + + return TRUE; +} + +/** + * gda_connection_open: + * @cnc: a #GdaConnection object + * @error: a place to store errors, or %NULL + * + * Tries to open the connection. The function either blocks or, if a #GMaincontext has been specified using + * gda_connection_set_main_context(), processes the events for that main context until either the + * connection opening has succeeded or failed. + * + * If the connection is already opened, then this function returns %TRUE immediately. + * + * Returns: TRUE if the connection is opened, and FALSE otherwise. + */ +gboolean +gda_connection_open (GdaConnection *cnc, GError **error) +{ + g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE); + GdaConnectionPrivate *priv = gda_connection_get_instance_private (cnc); + + /* don't do anything if connection is already opened */ + if (gda_connection_is_opened (cnc)) + return TRUE; + + GdaQuarkList *params, *auth; + if (!compute_params_and_auth_quarks (cnc, ¶ms, &auth, error)) + return FALSE; + + /* try to open the connection, with the "active waiting" at this point */ + gboolean opened; + opened = _gda_server_provider_open_connection_sync (priv->provider_obj, cnc, params, auth, error); + + if (opened && !priv->provider_data && !GDA_IS_VIRTUAL_PROVIDER (priv->provider_obj)) { + g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_PROVIDER_ERROR, "Internal error: connection has been reported as opened, yet no provider's data has been setted"); + opened = FALSE; + } + + return opened; +} + +/** + * gda_connection_open_async: + * @cnc: a #GdaConnection object + * @callback: (scope notified): a #GdaConnectionOpenFunc which will be called after the connection has been opened (of failed to open) + * @data: (nullable): data to pass to @callback when called + * @error: a place to store errors, or %NULL + * + * This function requests that the connection be opened. + * + * If the connection is already opened, then this function returns an error (with the %GDA_CONNECTION_ALREADY_OPENED_ERROR code). + * + * Note: @callback function will be called when processing events from the #GMainContext defined by + * gda_connection_set_main_context(), for example when there is a main loop for that main context. + * + * Returns: a job ID + * + * Since: 6.0 + */ +guint +gda_connection_open_async (GdaConnection *cnc, GdaConnectionOpenFunc callback, gpointer data, GError **error) +{ + g_return_val_if_fail (GDA_IS_CONNECTION (cnc), 0); + GdaConnectionPrivate *priv = gda_connection_get_instance_private (cnc); + + /* return an error if connection is already opened */ + if (gda_connection_is_opened (cnc)) { + g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_ALREADY_OPENED_ERROR, + "%s", _("Connection is already opened")); + return 0; + } + + GdaQuarkList *params, *auth; + if (!compute_params_and_auth_quarks (cnc, ¶ms, &auth, error)) + return FALSE; + + /* try to open the connection */ + gboolean submitted; + guint job_id; + submitted = _gda_server_provider_open_connection_async (priv->provider_obj, cnc, params, auth, + callback, data, &job_id, error); + return submitted ? job_id : 0; +} + +static void +add_connection_event_from_error (GdaConnection *cnc, GError **error) +{ + GdaConnectionEvent *event; + gchar *str; + event = GDA_CONNECTION_EVENT (g_object_new (GDA_TYPE_CONNECTION_EVENT, + "type", (int)GDA_CONNECTION_EVENT_WARNING, NULL)); + str = g_strdup_printf (_("Error while maintaining the meta data up to date: %s"), + error && *error && (*error)->message ? (*error)->message : _("No detail")); + gda_connection_event_set_description (event, str); + g_free (str); + if (error) + g_clear_error (error); + gda_connection_add_event (cnc, event); +} + +/** + * gda_connection_close: + * @cnc: a #GdaConnection object. + * + * Closes the connection to the underlying data source. + */ +gboolean +gda_connection_close (GdaConnection *cnc, GError **error) +{ + g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE); + GdaConnectionPrivate *priv = gda_connection_get_instance_private (cnc); + + if (! priv->provider_data) + return TRUE; + + g_object_ref (cnc); + gda_connection_lock ((GdaLockable*) cnc); + + if (! priv->provider_data) { + /* connection already closed */ + gda_connection_unlock ((GdaLockable*) cnc); + g_object_unref (cnc); + return TRUE; + } + + if (priv->meta_store && + priv->trans_meta_context && + gda_connection_get_transaction_status (cnc)) { + GdaConnection *mscnc; + mscnc = gda_meta_store_get_internal_connection (priv->meta_store); + if (cnc != mscnc) { + gsize i; + for (i = 0; i < priv->trans_meta_context->len; i++) { + GdaMetaContext *context; + GError *lerror = NULL; + context = g_array_index (priv->trans_meta_context, GdaMetaContext*, i); + if (! gda_connection_update_meta_store (cnc, context, &lerror)) + add_connection_event_from_error (cnc, &lerror); + auto_update_meta_context_free (context); + } + g_array_free (priv->trans_meta_context, TRUE); + priv->trans_meta_context = NULL; + } + } + + /* get rid of prepared statements to avoid problems */ + if (priv->prepared_stmts) { + g_hash_table_destroy (priv->prepared_stmts); + priv->prepared_stmts = NULL; + } + + /* really close connection */ + gboolean retval; + retval = _gda_server_provider_close_connection (priv->provider_obj, cnc, error); + + gda_connection_unlock ((GdaLockable*) cnc); + g_object_unref (cnc); + + return retval; +} + +/* + * _gda_connection_get_worker: + * + * Returns: (transfer none): the #GdaWorker internally used by @cnc, or %NULL if connection is not yet opened + */ +GdaWorker * +_gda_connection_get_worker (GdaConnection *cnc) +{ + g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL); + GdaConnectionPrivate *priv = gda_connection_get_instance_private (cnc); + if (priv->provider_data) + return priv->provider_data->worker; + return NULL; +} + +/* + * _gda_connection_get_exec_slowdown: + * + * Returns: the number of milliseconds to wait when executing things, used for testing and debugging + */ +guint +_gda_connection_get_exec_slowdown (GdaConnection *cnc) +{ + g_return_val_if_fail (GDA_IS_CONNECTION (cnc), 0); + GdaConnectionPrivate *priv = gda_connection_get_instance_private (cnc); + return priv->exec_slowdown; +} + +static void +assert_status_transaction (GdaConnectionStatus old, GdaConnectionStatus new) +{ + if (old == new) + return; + switch (old) { + case GDA_CONNECTION_STATUS_CLOSED: + g_assert (new == GDA_CONNECTION_STATUS_OPENING); + break; + case GDA_CONNECTION_STATUS_OPENING: + g_assert ((new == GDA_CONNECTION_STATUS_IDLE) || (new == GDA_CONNECTION_STATUS_CLOSED)); + break; + case GDA_CONNECTION_STATUS_IDLE: + g_assert ((new == GDA_CONNECTION_STATUS_BUSY) || (new == GDA_CONNECTION_STATUS_CLOSED)); + break; + case GDA_CONNECTION_STATUS_BUSY: + g_assert ((new == GDA_CONNECTION_STATUS_IDLE) || (new == GDA_CONNECTION_STATUS_CLOSED)); + break; + default: + g_assert_not_reached (); + } +} + +/* + * _gda_connection_declare_closed: + * @cnc: a #GdaConnection + */ +void +_gda_connection_declare_closed (GdaConnection *cnc) +{ + g_return_if_fail (cnc != NULL); + GdaConnectionPrivate *priv = gda_connection_get_instance_private (cnc); + + g_return_if_fail (priv->status == GDA_CONNECTION_STATUS_IDLE); + + assert_status_transaction (priv->status, GDA_CONNECTION_STATUS_CLOSED); + g_signal_emit (G_OBJECT (cnc), gda_connection_signals[STATUS_CHANGED], 0, GDA_CONNECTION_STATUS_CLOSED); +} + +/* + * _gda_connection_set_status: + * This function can't be used to switch to GDA_CONNECTION_STATUS_BUSY, one must switch to + * GDA_CONNECTION_STATUS_IDLE and use gda_connection_increase/decrease_usage() functions. + * + * WARNING: @cnc _MUST_ be locked using gda_connection_lock() before this function is called + */ +void +_gda_connection_set_status (GdaConnection *cnc, GdaConnectionStatus status) +{ + g_return_if_fail (cnc != NULL); + GdaConnectionPrivate *priv = gda_connection_get_instance_private (cnc); + if (!cnc || (priv->status == status)) + return; + if ((status == GDA_CONNECTION_STATUS_CLOSED) || + (status == GDA_CONNECTION_STATUS_OPENING)) + g_return_if_fail (priv->busy_count == 0); + g_return_if_fail (status != GDA_CONNECTION_STATUS_BUSY); + assert_status_transaction (priv->status, status); + priv->status = status; + g_signal_emit (G_OBJECT (cnc), gda_connection_signals[STATUS_CHANGED], 0, status); + /*g_print ("CNC %p status is %d\n", cnc, priv->status);*/ +} + +/** + * gda_connection_increase_usage: + * @cnc: a #GdaConnection + * + * Declare that @cnc is being used, which may emit the "status-changed" signal along the way. Any call to this function + * must be followed by one single call to gda_connection_decrease_usage(). The connection's status must either be + * IDLE, BUSY, or OPENING when this function is called. If the status is IDLE, then it will be switched to BUSY. + * + * Note: This function is reserved to database provider's implementation + * + * WARNING: @cnc _MUST_ be locked using gda_lockable_lock() before this function is called + */ +void +gda_connection_increase_usage (GdaConnection *cnc) +{ + g_return_if_fail (cnc != NULL); + GdaConnectionPrivate *priv = gda_connection_get_instance_private (cnc); + + g_return_if_fail ((priv->status == GDA_CONNECTION_STATUS_IDLE) || + (priv->status == GDA_CONNECTION_STATUS_BUSY) || + (priv->status == GDA_CONNECTION_STATUS_OPENING)); + + priv->busy_count ++; + if (priv->status == GDA_CONNECTION_STATUS_IDLE) { + assert_status_transaction (priv->status, GDA_CONNECTION_STATUS_BUSY); + priv->status = GDA_CONNECTION_STATUS_BUSY; + g_signal_emit (G_OBJECT (cnc), gda_connection_signals[STATUS_CHANGED], 0, GDA_CONNECTION_STATUS_BUSY); + /*g_print ("CNC %p status is %d\n", cnc, priv->status);*/ + } +} + +/** + * gda_connection_decrease_usage: + * @cnc: a #GdaConnection + * + * Declare that @cnc is not being used, which may emit the "status-changed" signal along the way. Any call to this function + * must be following a single call to gda_connection_increase_usage(). The connection's status must either be + * BUSY or OPENING when this function is called. If it's BUSY, then it may be changed to IDLE after this call. + * + * Note: This function is reserved to database provider's implementation + * + * WARNING: @cnc _MUST_ be locked using gda_lockable_lock() before this function is called + */ +void +gda_connection_decrease_usage (GdaConnection *cnc) +{ + g_return_if_fail (cnc != NULL); + GdaConnectionPrivate *priv = gda_connection_get_instance_private (cnc); + + g_assert (priv->busy_count > 0); + g_return_if_fail ((priv->status == GDA_CONNECTION_STATUS_BUSY) || + (priv->status == GDA_CONNECTION_STATUS_OPENING)); + + priv->busy_count --; + if ((priv->busy_count == 0) && (priv->status == GDA_CONNECTION_STATUS_BUSY)) { + assert_status_transaction (priv->status, GDA_CONNECTION_STATUS_IDLE); + priv->status = GDA_CONNECTION_STATUS_IDLE; + g_signal_emit (G_OBJECT (cnc), gda_connection_signals[STATUS_CHANGED], 0, GDA_CONNECTION_STATUS_IDLE); + /*g_print ("CNC %p status is %d\n", cnc, priv->status);*/ + } +} + +/** + * gda_connection_get_status: + * @cnc: a #GdaConnection + * + * Get the current status of @cnc. Note that this function needs to lock the connection (see #GdaLockable) + * to obtain the result. + * + * Returns: the connection's status + * + * Since: 6.0 + */ +GdaConnectionStatus +gda_connection_get_status (GdaConnection *cnc) +{ + g_return_val_if_fail (GDA_IS_CONNECTION (cnc), GDA_CONNECTION_STATUS_CLOSED); + GdaConnectionPrivate *priv = gda_connection_get_instance_private (cnc); + GdaConnectionStatus status; + gda_connection_lock ((GdaLockable*) cnc); + status = priv->status; + gda_connection_unlock ((GdaLockable*) cnc); + return status; +} + +/** + * gda_connection_is_opened: + * @cnc: a #GdaConnection object. + * + * Checks whether a connection is open or not. + * + * Returns: %TRUE if the connection is open, %FALSE if it's not. + */ +gboolean +gda_connection_is_opened (GdaConnection *cnc) +{ + g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE); + GdaConnectionPrivate *priv = gda_connection_get_instance_private (cnc); + + return priv->provider_data ? TRUE : FALSE; +} + + +/** + * gda_connection_get_options: + * @cnc: a #GdaConnection object. + * + * Gets the #GdaConnectionOptions used to open this connection. + * + * Returns: the connection options. + */ +GdaConnectionOptions +gda_connection_get_options (GdaConnection *cnc) +{ + g_return_val_if_fail (GDA_IS_CONNECTION (cnc), -1); + GdaConnectionPrivate *priv = gda_connection_get_instance_private (cnc); + + return priv->options; +} + +/** + * gda_connection_get_provider: + * @cnc: a #GdaConnection object + * + * Gets a pointer to the #GdaServerProvider object used to access the database + * + * Returns: (transfer none): the #GdaServerProvider (NEVER NULL) + */ +GdaServerProvider * +gda_connection_get_provider (GdaConnection *cnc) +{ + g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL); + GdaConnectionPrivate *priv = gda_connection_get_instance_private (cnc); + + return priv->provider_obj; +} + +/** + * gda_connection_get_provider_name: + * @cnc: a #GdaConnection object + * + * Gets the name (identifier) of the database provider used by @cnc + * + * Returns: a non modifiable string + */ +const gchar * +gda_connection_get_provider_name (GdaConnection *cnc) +{ + g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL); + GdaConnectionPrivate *priv = gda_connection_get_instance_private (cnc); + if (!priv->provider_obj) + return NULL; + + return gda_server_provider_get_name (priv->provider_obj); +} + +/** + * gda_connection_get_dsn: + * @cnc: a #GdaConnection object + * + * Returns: the data source name the connection object is connected + * to. + */ +const gchar * +gda_connection_get_dsn (GdaConnection *cnc) +{ + g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL); + GdaConnectionPrivate *priv = gda_connection_get_instance_private (cnc); + + return (const gchar *) priv->dsn; +} + +/** + * gda_connection_get_cnc_string: + * @cnc: a #GdaConnection object. + * + * Gets the connection string used to open this connection. + * + * The connection string is the string sent over to the underlying + * database provider, which describes the parameters to be used + * to open a connection on the underlying data source. + * + * Returns: the connection string used when opening the connection. + */ +const gchar * +gda_connection_get_cnc_string (GdaConnection *cnc) +{ + g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL); + GdaConnectionPrivate *priv = gda_connection_get_instance_private (cnc); + + return (const gchar *) priv->cnc_string; +} + +/** + * gda_connection_get_authentication: + * @cnc: a #GdaConnection object. + * + * Gets the user name used to open this connection. + * + * Returns: the user name. + */ +const gchar * +gda_connection_get_authentication (GdaConnection *cnc) +{ + const gchar *str; + g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL); + GdaConnectionPrivate *priv = gda_connection_get_instance_private (cnc); + + str = (const gchar *) priv->auth_string; + if (!str) + str = ""; + return str; +} + +/** + * gda_connection_get_date_format: + * @cnc: a #GdaConnection object + * @out_first: (out) (nullable): the place to store the first part of the date, or %NULL + * @out_second: (out) (nullable): the place to store the second part of the date, or %NULL + * @out_third: (out) (nullable): the place to store the third part of the date, or %NULL + * @out_sep: (out) (nullable): the place to store the separator (used between year, month and day parts) part of the date, or %NULL + * @error: (nullable): a place to store errors, or %NULL + * + * This function allows you to determine the actual format for the date values. + * + * Returns: %TRUE if no error occurred + * + * Since: 5.2 + */ +gboolean +gda_connection_get_date_format (GdaConnection *cnc, GDateDMY *out_first, + GDateDMY *out_second, GDateDMY *out_third, gchar *out_sep, + GError **error) +{ + g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE); + GdaConnectionPrivate *priv = gda_connection_get_instance_private (cnc); + + GdaDataHandler *dh; + dh = gda_server_provider_get_data_handler_g_type (priv->provider_obj, cnc, G_TYPE_DATE); + if (!dh) { + g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_METHOD_NON_IMPLEMENTED_ERROR, + "%s", _("Provider does not provide a GdaDataHandler for dates")); + return FALSE; + } + + GDate *tdate; + tdate = g_date_new_dmy (15, 12, 2003); + g_assert (tdate && g_date_valid (tdate)); + + GValue *value; + value = gda_value_new (G_TYPE_DATE); + g_value_set_boxed (value, tdate); + g_date_free (tdate); + + gchar *str; + str = gda_data_handler_get_str_from_value (dh, value); + gda_value_free (value); + + /* parsing */ + guint nb; + gchar *ptr; + GDateDMY order[3]; + gchar sep; + + /* 1st part */ + for (nb = 0, ptr = str; *ptr; ptr++) { + if ((*ptr <= '9') && (*ptr >= '0')) + nb = nb * 10 + (*ptr - '0'); + else + break; + } + if (nb == 2003) + order[0] = G_DATE_YEAR; + else if (nb == 12) + order[0] = G_DATE_MONTH; + else if (nb == 15) + order[0] = G_DATE_DAY; + else { + g_free (str); + return FALSE; + } + + /* separator */ + sep = *ptr; + if (!sep) { + g_free (str); + return FALSE; + } + + /* 2nd part */ + for (nb = 0, ptr++; *ptr; ptr++) { + if ((*ptr <= '9') && (*ptr >= '0')) + nb = nb * 10 + (*ptr - '0'); + else + break; + } + if (nb == 2003) + order[1] = G_DATE_YEAR; + else if (nb == 12) + order[1] = G_DATE_MONTH; + else if (nb == 15) + order[1] = G_DATE_DAY; + else { + g_free (str); + return FALSE; + } + + if (sep != *ptr) { + g_free (str); + return FALSE; + } + + /* 3rd part */ + for (nb = 0, ptr++; *ptr; ptr++) { + if ((*ptr <= '9') && (*ptr >= '0')) + nb = nb * 10 + (*ptr - '0'); + else + break; + } + if (nb == 2003) + order[2] = G_DATE_YEAR; + else if (nb == 12) + order[2] = G_DATE_MONTH; + else if (nb == 15) + order[2] = G_DATE_DAY; + else { + g_free (str); + return FALSE; + } + g_free (str); + + /* result */ + if (out_first) + *out_first = order [0]; + if (out_second) + *out_second = order [1]; + if (out_third) + *out_third = order [2]; + if (out_sep) + *out_sep = sep; + + return TRUE; +} + +/** + * gda_connection_insert_row_into_table: + * @cnc: an opened connection + * @table: table's name to insert into + * @error: a place to store errors, or %NULL + * @...: a list of string/GValue pairs with the name of the column to use and the + * GValue pointer containing the value to insert for the column (value can be %NULL), finished by a %NULL. There must be + * at least one column name and value + * + * This is a convenience function, which creates an INSERT statement and executes it using the values + * provided. It internally relies on variables which makes it immune to SQL injection problems. + * + * The equivalent SQL command is: INSERT INTO <table> (<column_name> [,...]) VALUES (<column_name> = <new_value> [,...]). + * + * A simple example to add a row in database + * + * |[ + * + * GdaConnection *cnc; + * // Open connection here + * + * GError *error = NULL; + * + * GValue *v_first_name = gda_value_new_from_string (first_name, G_TYPE_STRING); + * GValue *v_last_name = gda_value_new_from_string (last_name, G_TYPE_STRING); + * GValue *v_email = gda_value_new_from_string (email, G_TYPE_STRING); + * GValue *v_cod = gda_value_new (G_TYPE_INT); + * + * g_value_set_int (v_cod, cod); + * + * if (!gda_connection_insert_row_into_table (cnc, "TABLE_CONTACTS", &error, + * "col_first_name", v_first_name, + * "col_last_name", v_last_name, + * "col_email", v_email, + * "col_cod", v_cod, NULL)) + * { + * g_error ("It was not possible to add a new row in the table: %s\n", + * error && error->message ? error->message : "No detail"); + * } + * + * gda_value_free (v_first_name); + * gda_value_free (v_last_name); + * gda_value_free (v_email); + * gda_value_free (v_cod); + * + * g_error_free (error); + * + * + * ]| + * + * Returns: TRUE if no error occurred + * + * Since: 4.2.3 + */ +G_GNUC_NULL_TERMINATED +gboolean +gda_connection_insert_row_into_table (GdaConnection *cnc, const gchar *table, GError **error, ...) +{ + GSList *clist = NULL; + GSList *vlist = NULL; + gboolean retval; + va_list args; + gchar *col_name; + + g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE); + g_return_val_if_fail (table && *table, FALSE); + + if (! gda_connection_is_opened (cnc)) { + g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_CLOSED_ERROR, + "%s", _("Connection is closed")); + return FALSE; + } + + va_start (args, error); + while ((col_name = va_arg (args, gchar*))) { + clist = g_slist_prepend (clist, col_name); + GValue *value; + value = va_arg (args, GValue *); + vlist = g_slist_prepend (vlist, value); + } + + va_end (args); + + if (!clist) { + g_warning ("No specified column or value"); + return FALSE; + } + + clist = g_slist_reverse (clist); + vlist = g_slist_reverse (vlist); + retval = gda_connection_insert_row_into_table_v (cnc, table, clist, vlist, error); + g_slist_free (clist); + g_slist_free (vlist); + + return retval; +} + +/** + * gda_connection_insert_row_into_table_v: + * @cnc: an opened connection + * @table: table's name to insert into + * @col_names: (element-type utf8): a list of column names (as const gchar *) + * @values: (element-type GValue): a list of values (as #GValue) + * @error: a place to store errors, or %NULL + * + * @col_names and @values must have length (>= 1). + * + * This is a convenience function, which creates an INSERT statement and executes it using the values + * provided. It internally relies on variables which makes it immune to SQL injection problems. + * + * The equivalent SQL command is: INSERT INTO <table> (<column_name> [,...]) VALUES (<column_name> = <new_value> [,...]). + * + * Returns: TRUE if no error occurred, FALSE otherwise + * + * Since: 4.2.3 + */ +gboolean +gda_connection_insert_row_into_table_v (GdaConnection *cnc, const gchar *table, + GSList *col_names, GSList *values, + GError **error) +{ + gboolean retval; + GSList *fields = NULL; + GSList *expr_values = NULL; + GdaSqlStatement *sql_stm; + GdaSqlStatementInsert *ssi; + GdaStatement *insert; + gint i; + + GSList *holders = NULL; + GSList *l1, *l2; + + g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE); + g_return_val_if_fail (table && *table, FALSE); + g_return_val_if_fail (col_names, FALSE); + g_return_val_if_fail (g_slist_length (col_names) == g_slist_length (values), FALSE); + + if (! gda_connection_is_opened (cnc)) { + g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_CLOSED_ERROR, + "%s", _("Connection is closed")); + return FALSE; + } + + /* Construct insert query and list of GdaHolders */ + sql_stm = gda_sql_statement_new (GDA_SQL_STATEMENT_INSERT); + ssi = (GdaSqlStatementInsert*) sql_stm->contents; + g_assert (GDA_SQL_ANY_PART (ssi)->type == GDA_SQL_ANY_STMT_INSERT); + + ssi->table = gda_sql_table_new (GDA_SQL_ANY_PART (ssi)); + ssi->table->table_name = gda_sql_identifier_quote (table, cnc, NULL, FALSE, FALSE); + + i = 0; + for (l1 = col_names, l2 = values; + l1; + l1 = l1->next, l2 = l2->next) { + GdaSqlField *field; + GdaSqlExpr *expr; + GValue *value = (GValue *) l2->data; + const gchar *col_name = (const gchar*) l1->data; + + /* field */ + field = gda_sql_field_new (GDA_SQL_ANY_PART (ssi)); + field->field_name = gda_sql_identifier_quote (col_name, cnc, NULL, FALSE, FALSE); + fields = g_slist_prepend (fields, field); + + /* value */ + expr = gda_sql_expr_new (GDA_SQL_ANY_PART (ssi)); + if (value && (G_VALUE_TYPE (value) != GDA_TYPE_NULL)) { + /* create a GdaSqlExpr with a parameter */ + GdaSqlParamSpec *param; + param = g_new0 (GdaSqlParamSpec, 1); + param->name = g_strdup_printf ("+%d", i); + param->g_type = G_VALUE_TYPE (value); + param->is_param = TRUE; + expr->param_spec = param; + + GdaHolder *holder; + holder = (GdaHolder*) g_object_new (GDA_TYPE_HOLDER, "g-type", G_VALUE_TYPE (value), + "id", param->name, NULL); + g_assert (gda_holder_set_value (holder, value, NULL)); + holders = g_slist_prepend (holders, holder); + } + else { + /* create a NULL GdaSqlExpr => nothing to do */ + } + expr_values = g_slist_prepend (expr_values, expr); + + i++; + } + + ssi->fields_list = g_slist_reverse (fields); + ssi->values_list = g_slist_prepend (NULL, g_slist_reverse (expr_values)); + + insert = gda_statement_new (); + g_object_set (G_OBJECT (insert), "structure", sql_stm, NULL); + gda_sql_statement_free (sql_stm); + + /* execute statement */ + GdaSet *set = NULL; + if (holders) { + set = gda_set_new (holders); + g_slist_free_full (holders, (GDestroyNotify) g_object_unref); + } + + retval = (gda_connection_statement_execute_non_select (cnc, insert, set, NULL, error) == -1) ? FALSE : TRUE; + + if (set) + g_object_unref (set); + g_object_unref (insert); + + return retval; +} + +/** + * gda_connection_update_row_in_table: + * @cnc: an opened connection + * @table: the table's name with the row's values to be updated + * @condition_column_name: the name of the column to used in the WHERE condition clause + * @condition_value: the @condition_column_type's GType + * @error: a place to store errors, or %NULL + * @...: a list of string/GValue pairs with the name of the column to use and the + * GValue pointer containing the value to update the column to (value can be %NULL), finished by a %NULL. There must be + * at least one column name and value + * + * This is a convenience function, which creates an UPDATE statement and executes it using the values + * provided. It internally relies on variables which makes it immune to SQL injection problems. + * + * The equivalent SQL command is: UPDATE <table> SET <column_name> = <new_value> [,...] WHERE <condition_column_name> = <condition_value>. + * + * A simple example for updating a specific row in the table + * + * |[ + * + * GdaConnection *cnc; + * //Open connection here + * + * GError *error = NULL; + * + * GValue *v_id = gda_value_new (G_TYPE_INT); + * GValue *v_first_name = gda_value_new_from_string (first_name, G_TYPE_STRING); + * GValue *v_last_name = gda_value_new_from_string (last_name, G_TYPE_STRING); + * GValue *v_email = gda_value_new_from_string (email, G_TYPE_STRING); + * GValue *v_cod = gda_value_new (G_TYPE_INT); + * + * g_value_set_int (v_id, id); + * g_value_set_int (v_cod, cod); + * + * if (!gda_connection_update_row_in_table (cnc, "TABLE_CONTACTS", + * "col_id", v_id, &error, + * "col_first_name", v_first_name, + * "col_last_name", v_last_name, + * "col_email", v_email, + * "col_cod", v_cod, NULL)) + * { + * g_error ("Could not update row in table: %s\n", + * error && error->message ? error->message : "No detail"); + * } + * + * gda_value_free (v_id); + * gda_value_free (v_first_name); + * gda_value_free (v_last_name); + * gda_value_free (v_email); + * gda_value_free (v_cod); + * + * g_error_free (error); + * + * + * ]| + * + * Returns: TRUE if no error occurred, FALSE otherwise + * + * Since: 4.2.3 + */ +G_GNUC_NULL_TERMINATED +gboolean +gda_connection_update_row_in_table (GdaConnection *cnc, const gchar *table, + const gchar *condition_column_name, + GValue *condition_value, GError **error, ...) +{ + GSList *clist = NULL; + GSList *vlist = NULL; + gboolean retval; + va_list args; + gchar *col_name; + + g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE); + g_return_val_if_fail (table && *table, FALSE); + + if (! gda_connection_is_opened (cnc)) { + g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_CLOSED_ERROR, + "%s", _("Connection is closed")); + return FALSE; + } + + va_start (args, error); + while ((col_name = va_arg (args, gchar*))) { + clist = g_slist_prepend (clist, col_name); + GValue *value; + value = va_arg (args, GValue *); + vlist = g_slist_prepend (vlist, value); + } + + va_end (args); + + if (!clist) { + g_warning ("No specified column or value"); + return FALSE; + } + + clist = g_slist_reverse (clist); + vlist = g_slist_reverse (vlist); + retval = gda_connection_update_row_in_table_v (cnc, table, condition_column_name, condition_value, clist, vlist, error); + g_slist_free (clist); + g_slist_free (vlist); + + return retval; +} + +/** + * gda_connection_update_row_in_table_v: + * @cnc: an opened connection + * @table: the table's name with the row's values to be updated + * @condition_column_name: the name of the column to used in the WHERE condition clause + * @condition_value: the @condition_column_type's GType + * @col_names: (element-type utf8): a list of column names (as const gchar *) + * @values: (element-type GValue): a list of values (as #GValue) + * @error: a place to store errors, or %NULL + * + * @col_names and @values must have length (>= 1). + * + * This is a convenience function, which creates an UPDATE statement and executes it using the values + * provided. It internally relies on variables which makes it immune to SQL injection problems. + * + * The equivalent SQL command is: UPDATE <table> SET <column_name> = <new_value> [,...] WHERE <condition_column_name> = <condition_value>. + * + * Returns: TRUE if no error occurred, FALSE otherwise + * + * Since: 4.2.3 + */ +gboolean +gda_connection_update_row_in_table_v (GdaConnection *cnc, const gchar *table, + const gchar *condition_column_name, + GValue *condition_value, + GSList *col_names, GSList *values, + GError **error) +{ + gboolean retval; + GSList *fields = NULL; + GSList *expr_values = NULL; + GdaSqlStatement *sql_stm; + GdaSqlStatementUpdate *ssu; + GdaStatement *update; + gint i; + + GSList *holders = NULL; + GSList *l1, *l2; + + g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE); + g_return_val_if_fail (table && *table, FALSE); + g_return_val_if_fail (col_names, FALSE); + g_return_val_if_fail (g_slist_length (col_names) == g_slist_length (values), FALSE); + + if (! gda_connection_is_opened (cnc)) { + g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_CLOSED_ERROR, + "%s", _("Connection is closed")); + return FALSE; + } + + /* Construct update query and list of GdaHolders */ + sql_stm = gda_sql_statement_new (GDA_SQL_STATEMENT_UPDATE); + ssu = (GdaSqlStatementUpdate*) sql_stm->contents; + g_assert (GDA_SQL_ANY_PART (ssu)->type == GDA_SQL_ANY_STMT_UPDATE); + + ssu->table = gda_sql_table_new (GDA_SQL_ANY_PART (ssu)); + ssu->table->table_name = gda_sql_identifier_quote (table, cnc, NULL, FALSE, FALSE); + + if (condition_column_name) { + GdaSqlExpr *where, *op; + where = gda_sql_expr_new (GDA_SQL_ANY_PART (ssu)); + ssu->cond = where; + + where->cond = gda_sql_operation_new (GDA_SQL_ANY_PART (where)); + where->cond->operator_type = GDA_SQL_OPERATOR_TYPE_EQ; + + op = gda_sql_expr_new (GDA_SQL_ANY_PART (where->cond)); + where->cond->operands = g_slist_prepend (NULL, op); + op->value = gda_value_new (G_TYPE_STRING); + g_value_take_string (op->value, gda_sql_identifier_quote (condition_column_name, cnc, NULL, + FALSE, FALSE)); + + op = gda_sql_expr_new (GDA_SQL_ANY_PART (where->cond)); + where->cond->operands = g_slist_append (where->cond->operands, op); + if (condition_value) { + GdaSqlParamSpec *param; + param = g_new0 (GdaSqlParamSpec, 1); + param->name = g_strdup ("cond"); + param->g_type = G_VALUE_TYPE (condition_value); + param->is_param = TRUE; + op->param_spec = param; + + GdaHolder *holder; + holder = (GdaHolder*) g_object_new (GDA_TYPE_HOLDER, "g-type", G_VALUE_TYPE (condition_value), + "id", param->name, NULL); + g_assert (gda_holder_set_value (holder, condition_value, NULL)); + holders = g_slist_prepend (holders, holder); + } + else { + /* nothing to do: NULL */ + } + } + + i = 0; + for (l1 = col_names, l2 = values; + l1; + l1 = l1->next, l2 = l2->next) { + GValue *value = (GValue *) l2->data; + const gchar *col_name = (const gchar*) l1->data; + GdaSqlField *field; + GdaSqlExpr *expr; + + /* field */ + field = gda_sql_field_new (GDA_SQL_ANY_PART (ssu)); + field->field_name = gda_sql_identifier_quote (col_name, cnc, NULL, FALSE, FALSE); + fields = g_slist_prepend (fields, field); + + /* value */ + expr = gda_sql_expr_new (GDA_SQL_ANY_PART (ssu)); + if (value && (G_VALUE_TYPE (value) != GDA_TYPE_NULL)) { + /* create a GdaSqlExpr with a parameter */ + GdaSqlParamSpec *param; + param = g_new0 (GdaSqlParamSpec, 1); + param->name = g_strdup_printf ("+%d", i); + param->g_type = G_VALUE_TYPE (value); + param->is_param = TRUE; + expr->param_spec = param; + + GdaHolder *holder; + holder = (GdaHolder*) g_object_new (GDA_TYPE_HOLDER, "g-type", G_VALUE_TYPE (value), + "id", param->name, NULL); + g_assert (gda_holder_set_value (holder, value, NULL)); + holders = g_slist_prepend (holders, holder); + } + else { + /* create a NULL GdaSqlExpr => nothing to do */ + } + expr_values = g_slist_prepend (expr_values, expr); + + i++; + } + + ssu->fields_list = g_slist_reverse (fields); + ssu->expr_list = g_slist_reverse (expr_values); + + update = gda_statement_new (); + g_object_set (G_OBJECT (update), "structure", sql_stm, NULL); + gda_sql_statement_free (sql_stm); + + /* execute statement */ + GdaSet *set = NULL; + if (holders) { + set = gda_set_new (holders); + g_slist_free_full (holders, (GDestroyNotify) g_object_unref); + } + + retval = (gda_connection_statement_execute_non_select (cnc, update, set, NULL, error) == -1) ? FALSE : TRUE; + + if (set) + g_object_unref (set); + g_object_unref (update); + + return retval; +} + +/** + * gda_connection_delete_row_from_table: + * @cnc: an opened connection + * @table: the table's name with the row's values to be updated + * @condition_column_name: the name of the column to used in the WHERE condition clause + * @condition_value: the @condition_column_type's GType + * @error: a place to store errors, or %NULL + * + * This is a convenience function, which creates a DELETE statement and executes it using the values + * provided. It internally relies on variables which makes it immune to SQL injection problems. + * + * The equivalent SQL command is: DELETE FROM <table> WHERE <condition_column_name> = <condition_value>. + * + * A simple example to remove a row in database. + * + * |[ + * + * GdaConnection *cnc; + * //Open connection here + * + * GError *error = NULL; + * + * GValue *v_id = gda_value_new (G_TYPE_INT); + * GValue *v_name = gda_value_new_from_string ("Aldibino Refinino", G_TYPE_STRING); + * + * //The number 10 represents a primary key record in the table + * g_value_set_int (v_id, 10); + * + * //Delete a record with a specific ID in the col_id column + * if (!gda_connection_delete_row_from_table (cnc, "TABLE_CONTACTS", + * "col_id", v_id, + * &error)) + * { + * g_error ("Could not delete row in table: %s\n", + * error && error->message ? error->message : "No detail"); + * } + * + * //Delete a record with a specific NAME in the col_name column + * if (!gda_connection_delete_row_from_table (cnc, "TABLE_CONTACTS", + * "col_name", v_name, + * &error)) + * { + * g_error ("Could not delete row in table: %s\n", + * error && error->message ? error->message : "No detail"); + * } + * + * gda_value_free (v_id); + * gda_value_free (v_name); + * + * g_error_free (error); + * + * ]| + * + * Returns: TRUE if no error occurred, FALSE otherwise + * + * Since: 4.2.3 + */ +gboolean +gda_connection_delete_row_from_table (GdaConnection *cnc, const gchar *table, + const gchar *condition_column_name, + GValue *condition_value, GError **error) +{ + gboolean retval; + GdaSqlStatement *sql_stm; + GdaSqlStatementDelete *ssd; + GdaStatement *delete; + + GSList *holders = NULL; + + g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE); + g_return_val_if_fail (table && *table, FALSE); + + if (! gda_connection_is_opened (cnc)) { + g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_CLOSED_ERROR, + "%s", _("Connection is closed")); + return FALSE; + } + + /* Construct delete query and list of GdaHolders */ + sql_stm = gda_sql_statement_new (GDA_SQL_STATEMENT_DELETE); + ssd = (GdaSqlStatementDelete*) sql_stm->contents; + g_assert (GDA_SQL_ANY_PART (ssd)->type == GDA_SQL_ANY_STMT_DELETE); + + ssd->table = gda_sql_table_new (GDA_SQL_ANY_PART (ssd)); + ssd->table->table_name = gda_sql_identifier_quote (table, cnc, NULL, FALSE, FALSE); + + if (condition_column_name) { + GdaSqlExpr *where, *op; + where = gda_sql_expr_new (GDA_SQL_ANY_PART (ssd)); + ssd->cond = where; + + where->cond = gda_sql_operation_new (GDA_SQL_ANY_PART (where)); + where->cond->operator_type = GDA_SQL_OPERATOR_TYPE_EQ; + + op = gda_sql_expr_new (GDA_SQL_ANY_PART (where->cond)); + where->cond->operands = g_slist_prepend (NULL, op); + op->value = gda_value_new (G_TYPE_STRING); + g_value_take_string (op->value, gda_sql_identifier_quote (condition_column_name, cnc, NULL, + FALSE, FALSE)); + + op = gda_sql_expr_new (GDA_SQL_ANY_PART (where->cond)); + where->cond->operands = g_slist_append (where->cond->operands, op); + if (condition_value) { + GdaSqlParamSpec *param; + param = g_new0 (GdaSqlParamSpec, 1); + param->name = g_strdup ("cond"); + param->g_type = G_VALUE_TYPE (condition_value); + param->is_param = TRUE; + op->param_spec = param; + + GdaHolder *holder; + holder = (GdaHolder*) g_object_new (GDA_TYPE_HOLDER, "g-type", G_VALUE_TYPE (condition_value), + "id", param->name, NULL); + g_assert (gda_holder_set_value (holder, condition_value, NULL)); + holders = g_slist_prepend (holders, holder); + } + else { + /* nothing to do: NULL */ + } + } + + delete = gda_statement_new (); + g_object_set (G_OBJECT (delete), "structure", sql_stm, NULL); + gda_sql_statement_free (sql_stm); + + /* execute statement */ + GdaSet *set = NULL; + if (holders) { + set = gda_set_new (holders); + g_slist_free_full (holders, (GDestroyNotify) g_object_unref); + } + + retval = (gda_connection_statement_execute_non_select (cnc, delete, set, NULL, error) == -1) ? FALSE : TRUE; + + if (set) + g_object_unref (set); + g_object_unref (delete); + + return retval; +} + +/** + * gda_connection_parse_sql_string: + * @cnc: (nullable): a #GdaConnection object, or %NULL + * @sql: an SQL command to parse, not %NULL + * @params: (out) (nullable) (transfer full): a place to store a new #GdaSet, for parameters used in SQL command, or %NULL + * @error: a place to store errors, or %NULL + * + * This function helps to parse a SQL string which uses parameters and store them at @params. + * + * Returns: (transfer full): a #GdaStatement representing the SQL command, or %NULL if an error occurred + * + * Since: 4.2.3 + */ +GdaStatement* +gda_connection_parse_sql_string (GdaConnection *cnc, const gchar *sql, GdaSet **params, GError **error) +{ + GdaStatement *stmt; + GdaSqlParser *parser = NULL; + + g_return_val_if_fail (!cnc || GDA_IS_CONNECTION (cnc), NULL); + g_return_val_if_fail (sql, NULL); + + if (params) + *params = NULL; + if (cnc) + parser = gda_connection_create_parser (cnc); + if (!parser) + parser = gda_sql_parser_new (); + + stmt = gda_sql_parser_parse_string (parser, sql, NULL, error); + g_object_unref (parser); + if (! stmt) + return NULL; + + if (params && !gda_statement_get_parameters (stmt, params, error)) { + g_object_unref (stmt); + return NULL; + } + + return stmt; +} + +/** + * gda_connection_point_available_event: + * @cnc: a #GdaConnection object + * @type: a #GdaConnectionEventType + * + * Use this method to get a pointer to the next available connection event which can then be customized + * and taken into account using gda_connection_add_event(). + * + * Returns: (transfer full): a pointer to the next available connection event, or %NULL if event should + * be ignored + * + * Since: 4.2 + */ +GdaConnectionEvent * +gda_connection_point_available_event (GdaConnection *cnc, GdaConnectionEventType type) +{ + g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL); + GdaConnectionPrivate *priv = gda_connection_get_instance_private (cnc); + + /* ownership is transfered to the caller ! */ + + GdaConnectionEvent *eev; + eev = priv->events_array [priv->events_array_next]; + if (!eev) + eev = GDA_CONNECTION_EVENT (g_object_new (GDA_TYPE_CONNECTION_EVENT, + "type", (int)type, NULL)); + else { + gda_connection_event_set_event_type (eev, type); + priv->events_array [priv->events_array_next] = NULL; + } + + return eev; +} + +#ifdef GDA_DEBUG_NO +static void +dump_events_array (GdaConnection *cnc) +{ + g_return_if_fail (GDA_IS_CONNECTION (cnc)); + GdaConnectionPrivate *priv = gda_connection_get_instance_private (cnc); + gint i; + g_print ("=== Array dump for %p ===\n", cnc); + for (i = 0; i < priv->events_array_size; i++) { + g_print (" [%d] => %p\n", i, priv->events_array [i]); + } + + const GList *list; + for (list = gda_connection_get_events (cnc); list; list = list->next) { + GdaConnectionEvent *ev = GDA_CONNECTION_EVENT (list->data); + g_print (" => %p\n", ev); + } +} +#endif + +/** + * gda_connection_add_event: + * @cnc: a #GdaConnection object. + * @event: (transfer full): is stored internally, so you don't need to unref it. + * + * Adds an event to the given connection. This function is usually + * called by providers, to inform clients of events that happened + * during some operation. + * + * As soon as a provider (or a client, it does not matter) calls this + * function with an @event object which is an error, + * the connection object emits the "error" signal, to which clients can connect to be + * informed of events. + * + * WARNING: the reference to the @event object is stolen by this function! + */ +void +gda_connection_add_event (GdaConnection *cnc, GdaConnectionEvent *event) +{ + g_return_if_fail (GDA_IS_CONNECTION (cnc)); + g_return_if_fail (GDA_IS_CONNECTION_EVENT (event)); + GdaConnectionPrivate *priv = gda_connection_get_instance_private (cnc); + + g_object_ref (cnc); + gda_connection_lock ((GdaLockable*) cnc); + + /* clear external list of events */ + if (priv->events_list) { + g_list_free_full (priv->events_list, (GDestroyNotify) g_object_unref); + priv->events_list = NULL; + } + + /* add event, ownership is transfered to @cnc */ + GdaConnectionEvent *eev; + eev = priv->events_array [priv->events_array_next]; + if (eev != event) { + if (eev) + g_object_unref (eev); + priv->events_array [priv->events_array_next] = event; + } + + /* handle indexes */ + priv->events_array_next ++; + if (priv->events_array_next == priv->events_array_size) { + priv->events_array_next = 0; + priv->events_array_full = TRUE; + } + + if (debug_level > 0) { + const gchar *str = NULL; + switch (gda_connection_event_get_event_type (event)) { + case GDA_CONNECTION_EVENT_NOTICE: + if (debug_level & 1) str = "NOTICE"; + break; + case GDA_CONNECTION_EVENT_WARNING: + if (debug_level & 2) str = "WARNING"; + break; + case GDA_CONNECTION_EVENT_ERROR: + if (debug_level & 4) str = "ERROR"; + break; + case GDA_CONNECTION_EVENT_COMMAND: + if (debug_level & 8) str = "COMMAND"; + break; + default: + break; + } + if (str) + g_print ("EVENT> %s: %s (on cnx %p, %s)\n", str, + gda_connection_event_get_description (event), cnc, + gda_connection_event_get_sqlstate (event)); + } + + if (gda_connection_event_get_event_type (event) == GDA_CONNECTION_EVENT_ERROR) + g_signal_emit (G_OBJECT (cnc), gda_connection_signals[SIG_ERROR], 0, event); + +#ifdef GDA_DEBUG_NO + dump_events_array (cnc); +#endif + + gda_connection_unlock ((GdaLockable*) cnc); + g_object_unref (cnc); +} + +/** + * gda_connection_add_event_string: + * @cnc: a #GdaConnection object. + * @str: a format string (see the printf(3) documentation). + * @...: the arguments to insert in the error message. + * + * Adds a new error to the given connection object. This is just a convenience + * function that simply creates a #GdaConnectionEvent and then calls + * #gda_server_connection_add_error. + * + * Returns: (transfer none): a new #GdaConnectionEvent object, however the caller does not hold a reference to the returned object, and if need be the caller must call g_object_ref() on it. + */ +GdaConnectionEvent * +gda_connection_add_event_string (GdaConnection *cnc, const gchar *str, ...) +{ + GdaConnectionEvent *error; + + va_list args; + gchar sz[2048]; + + g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL); + g_return_val_if_fail (str != NULL, NULL); + + /* build the message string */ + va_start (args, str); + g_vsnprintf (sz, 2048, str, args); + va_end (args); + + error = gda_connection_point_available_event (cnc, GDA_CONNECTION_EVENT_ERROR); + gda_connection_event_set_description (error, sz); + gda_connection_event_set_code (error, -1); + gda_connection_event_set_source (error, gda_connection_get_provider_name (cnc)); + gda_connection_event_set_sqlstate (error, "-1"); + + gda_connection_add_event (cnc, error); + + return error; +} + +static void +_clear_connection_events (GdaConnection *locked_cnc) +{ + g_return_if_fail (GDA_IS_CONNECTION (locked_cnc)); + GdaConnectionPrivate *priv = gda_connection_get_instance_private (locked_cnc); + if (priv->auto_clear_events) { + priv->events_array_full = FALSE; + priv->events_array_next = 0; + } +} + +/** + * gda_connection_clear_events_list: + * @cnc: a #GdaConnection object. + * + * This function lets you clear the list of #GdaConnectionEvent's of the + * given connection. + */ +void +gda_connection_clear_events_list (GdaConnection *cnc) +{ + g_return_if_fail (GDA_IS_CONNECTION (cnc)); + gda_connection_lock ((GdaLockable*) cnc); + _clear_connection_events (cnc); + gda_connection_unlock ((GdaLockable*) cnc); +} + +/** + * gda_connection_create_operation: + * @cnc: a #GdaConnection object + * @type: the type of operation requested + * @options: (nullable): an optional list of parameters + * @error: a place to store an error, or %NULL + * + * Creates a new #GdaServerOperation object which can be modified in order + * to perform the type type of action. It is a wrapper around the gda_server_provider_create_operation() + * method. + * + * Returns: (transfer full): a new #GdaServerOperation object, or %NULL in the connection's provider does not support the @type type + * of operation or if an error occurred + */ +GdaServerOperation* +gda_connection_create_operation (GdaConnection *cnc, GdaServerOperationType type, + GdaSet *options, GError **error) +{ + g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL); + GdaConnectionPrivate *priv = gda_connection_get_instance_private (cnc); + g_return_val_if_fail (priv->provider_obj, NULL); + + return gda_server_provider_create_operation (priv->provider_obj, cnc, type, options, error); +} + +/** + * gda_connection_perform_operation: + * @cnc: a #GdaConnection object + * @op: a #GdaServerOperation object + * @error: a place to store an error, or %NULL + * + * Performs the operation described by @op (which should have been created using + * gda_connection_create_operation()). It is a wrapper around the gda_server_provider_perform_operation() + * method. + * + * Returns: TRUE if no error occurred + */ +gboolean +gda_connection_perform_operation (GdaConnection *cnc, GdaServerOperation *op, GError **error) +{ + gboolean retval; + g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE); + GdaConnectionPrivate *priv = gda_connection_get_instance_private (cnc); + g_return_val_if_fail (priv->provider_obj, FALSE); + g_return_val_if_fail (GDA_IS_SERVER_OPERATION (op), FALSE); + + priv->auto_clear_events = FALSE; + retval = gda_server_provider_perform_operation (priv->provider_obj, cnc, op, error); + priv->auto_clear_events = TRUE; + return retval; +} + +/** + * gda_connection_create_parser: + * @cnc: a #GdaConnection object + * + * Creates a new parser object able to parse the SQL dialect understood by @cnc. + * If the #GdaServerProvider object internally used by @cnc does not have its own parser, + * then %NULL is returned, and a general SQL parser can be obtained + * using gda_sql_parser_new(). + * + * Returns: (transfer full): a new #GdaSqlParser object, or %NULL + */ +GdaSqlParser * +gda_connection_create_parser (GdaConnection *cnc) +{ + g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL); + GdaConnectionPrivate *priv = gda_connection_get_instance_private (cnc); + g_return_val_if_fail (priv->provider_obj, NULL); + + return gda_server_provider_create_parser (priv->provider_obj, cnc); +} + +/* + * Also resets the events list (as perceived when calling gda_connection_get_events() + */ +static void +change_events_array_max_size (GdaConnection *cnc, gint size) +{ + g_return_if_fail (GDA_IS_CONNECTION (cnc)); + GdaConnectionPrivate *priv = gda_connection_get_instance_private (cnc); + size ++; /* add 1 to compensate the "lost" slot when rotating the events array */ + if (size == priv->events_array_size) + return; + + if (size > priv->events_array_size) { + gint i; + priv->events_array = g_renew (GdaConnectionEvent*, priv->events_array, + size); + for (i = priv->events_array_size; i < size; i++) + priv->events_array [i] = NULL; + } + else if (size >= EVENTS_ARRAY_SIZE) { + gint i; + for (i = size; i < priv->events_array_size; i++) { + if (priv->events_array [i]) + g_object_unref (priv->events_array [i]); + } + priv->events_array = g_renew (GdaConnectionEvent*, priv->events_array, + size); + } + priv->events_array_size = size; + priv->events_array_full = FALSE; + priv->events_array_next = 0; +} + +/** + * gda_connection_batch_execute: + * @cnc: a #GdaConnection object + * @batch: a #GdaBatch object which contains all the statements to execute + * @params: (nullable): a #GdaSet object (which can be obtained using gda_batch_get_parameters()), or %NULL + * @model_usage: specifies how the returned data model(s) will be used, as a #GdaStatementModelUsage enum + * @error: a place to store errors, or %NULL + * + * Executes all the statements contained in @batch (in the order in which they were added to @batch), and + * returns a list of #GObject objects, at most one #GObject for each statement; see gda_connection_statement_execute() + * for details about the returned objects. + * + * If one of the statement fails, then none of the subsequent statement will be executed, and the method returns + * the list of #GObject created by the correct execution of the previous statements. If a transaction is required, + * then it should be started before calling this method. + * + * Returns: (transfer full) (element-type GObject): a new list of #GObject objects + */ +GSList * +gda_connection_batch_execute (GdaConnection *cnc, GdaBatch *batch, GdaSet *params, + GdaStatementModelUsage model_usage, GError **error) +{ + GSList *retlist = NULL, *stmt_list; + g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL); + g_return_val_if_fail (GDA_IS_BATCH (batch), NULL); + GdaConnectionPrivate *priv = gda_connection_get_instance_private (cnc); + + if (! gda_connection_is_opened (cnc)) { + g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_CLOSED_ERROR, + "%s", _("Connection is closed")); + return FALSE; + } + + gda_connection_lock ((GdaLockable*) cnc); + priv->auto_clear_events = FALSE; + + /* increase the size of priv->events_array to be able to store all the + * connection events */ + stmt_list = (GSList*) gda_batch_get_statements (batch); + change_events_array_max_size (cnc, g_slist_length (stmt_list) * 2); + + for (; stmt_list; stmt_list = stmt_list->next) { + GObject *obj; + obj = gda_connection_statement_execute (cnc, GDA_STATEMENT (stmt_list->data), params, + model_usage, NULL, error); + if (!obj) + break; + retlist = g_slist_prepend (retlist, obj); + } + priv->auto_clear_events = TRUE; + gda_connection_unlock ((GdaLockable*) cnc); + + return g_slist_reverse (retlist); +} + + +/** + * gda_connection_quote_sql_identifier: + * @cnc: a #GdaConnection object + * @id: an SQL identifier + * + * Use this method to get a correctly quoted (if necessary) SQL identifier which can be used + * in SQL statements, from @id. If @id is already correctly quoted for @cnc, then a copy of @id + * may be returned. + * + * This method may add double quotes (or other characters) around @id: + * + * if @id is a reserved SQL keyword (such as SELECT, INSERT, ...) + * if @id contains non allowed characters such as spaces, or if it starts with a digit + * in any other event as necessary for @cnc, depending on the the options passed when opening the @cnc + * connection, and specifically the + * GDA_CONNECTION_OPTIONS_SQL_IDENTIFIERS_CASE_SENSITIVE option. + * + * + * One can safely pass an already quoted @id to this method, either with quoting characters allowed by @cnc or using the + * double quote (") character. + * + * Returns: a new string, to free with g_free() once not needed anymore + * + * Since: 4.0.3 + */ +gchar * +gda_connection_quote_sql_identifier (GdaConnection *cnc, const gchar *id) +{ + g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL); + g_return_val_if_fail (id, NULL); + GdaConnectionPrivate *priv = gda_connection_get_instance_private (cnc); + + return gda_sql_identifier_quote (id, cnc, NULL, FALSE, + priv->options & GDA_CONNECTION_OPTIONS_SQL_IDENTIFIERS_CASE_SENSITIVE); +} + +/** + * gda_connection_statement_to_sql: + * @cnc: (nullable): a #GdaConnection object, or %NULL + * @stmt: a #GdaStatement object + * @params: (nullable): a #GdaSet object (which can be obtained using gda_statement_get_parameters()), or %NULL + * @flags: SQL rendering flags, as #GdaStatementSqlFlag OR'ed values + * @params_used: (nullable) (element-type Gda.Holder) (out) (transfer container): a place to store the list of individual #GdaHolder objects within @params which have been used + * @error: a place to store errors, or %NULL + * + * Renders @stmt as an SQL statement, adapted to the SQL dialect used by @cnc + * + * Returns: (transfer full): a new string, or %NULL if an error occurred + */ +gchar * +gda_connection_statement_to_sql (GdaConnection *cnc, GdaStatement *stmt, GdaSet *params, GdaStatementSqlFlag flags, + GSList **params_used, GError **error) +{ + g_return_val_if_fail (GDA_IS_STATEMENT (stmt), NULL); + + gchar *sql = NULL; + + if (cnc) { + g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL); + GdaConnectionPrivate *priv = gda_connection_get_instance_private (cnc); + g_return_val_if_fail (priv->provider_obj, NULL); + if (gda_connection_is_opened (cnc)) + sql = _gda_server_provider_statement_to_sql (priv->provider_obj, cnc, stmt, params, flags, + params_used, error); + else + sql = _gda_server_provider_statement_to_sql (priv->provider_obj, NULL, stmt, params, flags, + params_used, error); + } + return sql ? sql : gda_statement_to_sql_extended (stmt, cnc, params, flags, params_used, error); +} + +/** + * gda_connection_statement_prepare: + * @cnc: a #GdaConnection + * @stmt: a #GdaStatement object + * @error: a place to store errors, or %NULL + * + * Ask the database accessed through the @cnc connection to prepare the usage of @stmt. This is only useful + * if @stmt will be used more than once (however some database providers may always prepare statements + * before executing them). + * + * This function is also useful to make sure @stmt is fully understood by the database before actually executing it. + * + * Note however that it is also possible that gda_connection_statement_prepare() fails when + * gda_connection_statement_execute() does not fail (this will usually be the case with statements such as + * because database usually don't allow variables to be used in place of a + * table name). + * + * Returns: TRUE if no error occurred. + */ +gboolean +gda_connection_statement_prepare (GdaConnection *cnc, GdaStatement *stmt, GError **error) +{ + g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE); + GdaConnectionPrivate *priv = gda_connection_get_instance_private (cnc); + g_return_val_if_fail (priv->provider_obj, FALSE); + g_return_val_if_fail (GDA_IS_STATEMENT (stmt), FALSE); + + return _gda_server_provider_statement_prepare (priv->provider_obj, cnc, stmt, error); +} + +/* + * @args is consumed as a succession of (column number, GType) arguments + * which ends with a column number of -1. The returned array is always terminated by G_TYPE_NONE, + * and contains 0 where no column type information has been provided + */ +static GType * +make_col_types_array (va_list args) +{ + GType *types; + gint max = 10; + gint col, lastidx = 0; + + col = va_arg (args, gint); + if (col < 0) + return NULL; + + types = g_new0 (GType, max + 1); + types [max] = G_TYPE_NONE; + for (; col >= 0; col = va_arg (args, gint)) { + if (col >= max) { + gint i; + types = g_renew (GType, types, col + 5 + 1); + for (i = max; i <= col + 5; i ++) + types[i] = 0; + max = col + 5; + types [max] = G_TYPE_NONE; + } + types [col] = va_arg (args, GType); + lastidx = col+1; + } + + if (lastidx == 0) { + g_free (types); + types = NULL; + } + else + types [lastidx] = G_TYPE_NONE; + + return types; +} + +static void +add_exec_time_to_object (GObject *obj, GTimer *timer) +{ + gdouble etime; + etime = g_timer_elapsed (timer, NULL); + if (GDA_IS_DATA_SELECT (obj)) + g_object_set (obj, "execution-delay", etime, NULL); + else if (GDA_IS_SET (obj)) { + GdaHolder *holder; + holder = gda_holder_new_inline (G_TYPE_DOUBLE, "EXEC_DELAY", etime); + gda_set_add_holder ((GdaSet*) obj, holder); + g_object_unref ((GObject*) holder); + } + else + TO_IMPLEMENT; +} + +/* + * Wrapper which adds @... ellipse + */ +static GObject * +gda_connection_statement_execute_v (GdaConnection *cnc, GdaStatement *stmt, GdaSet *params, + GdaStatementModelUsage model_usage, GdaSet **last_inserted_row, GError **error, ...) +{ + g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL); + GdaConnectionPrivate *priv = gda_connection_get_instance_private (cnc); + va_list ap; + GObject *obj = NULL; + GType *types, *req_types; + GTimer *timer = NULL; + va_start (ap, error); + types = make_col_types_array (ap); + va_end (ap); + + g_object_ref ((GObject*) cnc); + + gda_connection_lock ((GdaLockable*) cnc); + _clear_connection_events (cnc); + gda_connection_unlock ((GdaLockable*) cnc); + + if (last_inserted_row) + *last_inserted_row = NULL; + + if (!priv->provider_data) { + g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_CLOSED_ERROR, + _("Connection is closed")); + g_object_unref ((GObject*) cnc); + g_free (types); + return NULL; + } + + req_types = merge_column_types (_gda_statement_get_requested_types (stmt), types); + if (req_types) { + g_free (types); + types = req_types; + req_types = NULL; + } + else if (_gda_statement_get_requested_types (stmt)) + req_types = (GType*) _gda_statement_get_requested_types (stmt); + + if (! (model_usage & GDA_STATEMENT_MODEL_RANDOM_ACCESS) && + ! (model_usage & GDA_STATEMENT_MODEL_CURSOR_FORWARD)) + model_usage |= GDA_STATEMENT_MODEL_RANDOM_ACCESS; + + dump_exec_params (cnc, stmt, params); + if (priv->exec_times) + timer = g_timer_new (); + + obj = _gda_server_provider_statement_execute (priv->provider_obj, cnc, stmt, params, model_usage, + req_types ? req_types : types, last_inserted_row, error); + if (timer) + g_timer_stop (timer); + g_free (types); + + if (obj) { + if (timer) + add_exec_time_to_object (obj, timer); + update_meta_store_after_statement_exec (cnc, stmt, params); + } + + g_object_unref ((GObject*) cnc); + + if (timer) + g_timer_destroy (timer); + + return obj; +} + + +/** + * gda_connection_execute_select_command: + * @cnc: an opened connection + * @sql: a query statement that must begin with "SELECT" + * @error: a place to store errors, or %NULL + * + * Execute a SQL SELECT command over an opened connection. + * + * Returns: (transfer full): a new #GdaDataModel if successful, %NULL otherwise + * + * Since: 4.2.3 + */ +GdaDataModel * +gda_connection_execute_select_command (GdaConnection *cnc, const gchar *sql, GError **error) +{ + GdaStatement *stmt; + GdaDataModel *model; + + g_return_val_if_fail (sql != NULL + || GDA_IS_CONNECTION (cnc) + || !gda_connection_is_opened (cnc), + NULL); + + while (isspace (*sql)) + sql++; + g_return_val_if_fail (((sql[0] == 'S') || (sql[0] == 's')) && + ((sql[1] == 'E') || (sql[1] == 'e')) && + ((sql[2] == 'L') || (sql[2] == 'l')) && + ((sql[3] == 'E') || (sql[3] == 'e')) && + ((sql[4] == 'C') || (sql[4] == 'c')) && + ((sql[5] == 'T') || (sql[5] == 't')) && + isspace (sql[6]), NULL); + + g_mutex_lock (&global_mutex); + if (!internal_parser) + internal_parser = gda_sql_parser_new (); + g_mutex_unlock (&global_mutex); + + stmt = gda_sql_parser_parse_string (internal_parser, sql, NULL, error); + if (!stmt) + return NULL; + model = gda_connection_statement_execute_select (cnc, stmt, NULL, error); + g_object_unref (stmt); + + return model; +} + +/** + * gda_connection_execute_non_select_command: + * @cnc: an opened connection + * @sql: a query statement that must not begin with "SELECT" + * @error: a place to store errors, or %NULL + * + * This is a convenience function to execute a SQL command over the opened connection. For the + * returned value, see gda_connection_statement_execute_non_select()'s documentation. + * + * Returns: the number of rows affected or -1, or -2 + * + * Since: 4.2.3 + */ +gint +gda_connection_execute_non_select_command (GdaConnection *cnc, const gchar *sql, GError **error) +{ + GdaStatement *stmt; + gint retval; + + g_return_val_if_fail (sql != NULL + || GDA_IS_CONNECTION (cnc) + || !gda_connection_is_opened (cnc), -1); + + g_mutex_lock (&global_mutex); + if (!internal_parser) + internal_parser = gda_sql_parser_new (); + g_mutex_unlock (&global_mutex); + + stmt = gda_sql_parser_parse_string (internal_parser, sql, NULL, error); + if (!stmt) + return -1; + + retval = gda_connection_statement_execute_non_select (cnc, stmt, NULL, NULL, error); + g_object_unref (stmt); + return retval; +} + +/** + * gda_connection_statement_execute: + * @cnc: a #GdaConnection + * @stmt: a #GdaStatement object + * @params: (nullable): a #GdaSet object (which can be obtained using gda_statement_get_parameters()), or %NULL + * @model_usage: in the case where @stmt is a SELECT statement, specifies how the returned data model will be used + * @last_insert_row: (out) (transfer full) (nullable): a place to store a new #GdaSet object which contains the values of the last inserted row, or %NULL + * @error: a place to store errors, or %NULL + * + * Executes @stmt. + * + * As @stmt can, by design (and if not abused), contain only one SQL statement, the + * return object will either be: + * + * a #GdaDataSelect object (which is also a #GdaDataModel) if @stmt is a SELECT statement + * (usually a GDA_SQL_STATEMENT_SELECT, see #GdaSqlStatementType) + * containing the results of the SELECT. The resulting data model is by default read only, but + * modifications can be enabled, see the #GdaDataSelect's documentation for more information. + * a #GdaSet for any other SQL statement which correctly executed. In this case + * (if the provider supports it), then the #GdaSet may contain value holders named: + * + * a (gint) #GdaHolder named "IMPACTED_ROWS" + * a (GObject) #GdaHolder named "EVENT" which contains a #GdaConnectionEvent + * + * + * + * If @last_insert_row is not %NULL and @stmt is an INSERT statement, then it will contain a new #GdaSet + * object composed of value holders named "+<column number>" + * starting at column 0 which contain the actual inserted values. For example if a table is composed of an 'id' column + * which is auto incremented and a 'name' column then the execution of a "INSERT INTO mytable (name) VALUES ('joe')" + * query will return a #GdaSet with two holders: + * + * one with the '+0' ID which may for example contain 1 (note that its "name" property should be "id") + * one with the '+1' ID which will contain 'joe' (note that its "name" property should be "name") + * + * Note that the value pointer by @last_insert_row may be %NULL after the function call if either the database provider + * does not support it, or if the last interted row could not be determined (for example with SQLite if the table + * in which the data is inserted has the WITHOUT ROWID optimization). + * + * This method may fail with a %GDA_SERVER_PROVIDER_ERROR domain error (see the #GdaServerProviderError error codes). + * + * Note1: If @stmt is a SELECT statement which has some parameters and if @params is %NULL, then the statement can't + * be executed and this method will return %NULL. + * + * Note2: If @stmt is a SELECT statement which has some parameters and if @params is not %NULL but contains some + * invalid parameters, then the statement can't be executed and this method will return %NULL, unless the + * @model_usage has the GDA_STATEMENT_MODEL_ALLOW_NOPARAM flag. + * + * Note3: If @stmt is a SELECT statement which has some parameters and if @params is not %NULL but contains some + * invalid parameters and if @model_usage has the GDA_STATEMENT_MODEL_ALLOW_NOPARAM flag, then the returned + * data model will contain no row but will have all the correct columns (even though some of the columns might + * report as GDA_TYPE_NULL). In this case, if (after this method call) any of @params' parameters change + * then the resulting data model will re-run itself, see the GdaDataSelect's + * auto-reset property for more information. + * + * Note4: if @model_usage does not contain the GDA_STATEMENT_MODEL_RANDOM_ACCESS or + * GDA_STATEMENT_MODEL_CURSOR_FORWARD flags, then the default will be to return a random access data model + * + * Note5: If @stmt is a SELECT statement which returns blob values (of type %GDA_TYPE_BLOB), then an implicit + * transaction will have been started by the database provider, and it's up to the caller to close the transaction + * (which will then be locked) once all the blob ressources have been + * liberated (when the returned data model is destroyed). See the section about + * Binary large objects (BLOBs) for more information. + * + * Also see the provider's limitations, and the + * Advanced GdaDataSelect usage sections. + * + * Returns: (transfer full): a #GObject, or %NULL if an error occurred + */ +GObject * +gda_connection_statement_execute (GdaConnection *cnc, GdaStatement *stmt, GdaSet *params, + GdaStatementModelUsage model_usage, GdaSet **last_inserted_row, GError **error) +{ + g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL); + GdaConnectionPrivate *priv = gda_connection_get_instance_private (cnc); + g_return_val_if_fail (priv->provider_obj, NULL); + g_return_val_if_fail (GDA_IS_STATEMENT (stmt), NULL); + + return gda_connection_statement_execute_v (cnc, stmt, params, model_usage, last_inserted_row, error, -1); +} + +/** + * gda_connection_statement_execute_non_select: + * @cnc: a #GdaConnection object. + * @stmt: a #GdaStatement object. + * @params: (nullable): a #GdaSet object (which can be obtained using gda_statement_get_parameters()), or %NULL + * @last_insert_row: (out) (transfer full) (nullable): a place to store a new #GdaSet object which contains the values of the last inserted row, or %NULL + * @error: a place to store an error, or %NULL + * + * Executes a non-selection statement on the given connection. + * + * This function returns the number of rows affected by the execution of @stmt, or -1 + * if an error occurred, or -2 if the connection's provider does not return the number of rows affected. + * + * This function is just a convenience function around the gda_connection_statement_execute() + * function. + * See the documentation of the gda_connection_statement_execute() for information + * about the @params list of parameters. + * + * See gda_connection_statement_execute() form more information about @last_insert_row. + * + * Returns: the number of rows affected (>=0) or -1 or -2 + */ +gint +gda_connection_statement_execute_non_select (GdaConnection *cnc, GdaStatement *stmt, + GdaSet *params, GdaSet **last_insert_row, GError **error) +{ + GdaSet *set; + g_return_val_if_fail (GDA_IS_CONNECTION (cnc), -1); + GdaConnectionPrivate *priv = gda_connection_get_instance_private (cnc); + g_return_val_if_fail (priv->provider_obj, -1); + g_return_val_if_fail (GDA_IS_STATEMENT (stmt), -1); + + if ((gda_statement_get_statement_type (stmt) == GDA_SQL_STATEMENT_SELECT) || + (gda_statement_get_statement_type (stmt) == GDA_SQL_STATEMENT_COMPOUND)) { + g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_STATEMENT_TYPE_ERROR, + "%s", _("Statement is a selection statement")); + return -1; + } + + if (last_insert_row) + *last_insert_row = NULL; + + set = (GdaSet *) gda_connection_statement_execute_v (cnc, stmt, params, + GDA_STATEMENT_MODEL_RANDOM_ACCESS, last_insert_row, + error, -1); + if (!set) + return -1; + + if (!GDA_IS_SET (set)) { + g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_STATEMENT_TYPE_ERROR, + "%s", _("Statement is a selection statement")); + g_object_unref (set); + return -1; + } + else { + GdaHolder *h; + gint retval = -2; + + h = gda_set_get_holder (set, "IMPACTED_ROWS"); + if (h) { + const GValue *value; + value = gda_holder_get_value (h); + if (value && (G_VALUE_TYPE (value) == G_TYPE_INT)) + retval = g_value_get_int (value); + } + g_object_unref (set); + return retval; + } +} + +/** + * gda_connection_statement_execute_select: + * @cnc: a #GdaConnection object. + * @stmt: a #GdaStatement object. + * @params: (nullable): a #GdaSet object (which can be obtained using gda_statement_get_parameters()), or %NULL + * @error: a place to store an error, or %NULL + * + * Executes a selection command on the given connection. + * + * This function returns a #GdaDataModel resulting from the SELECT statement, or %NULL + * if an error occurred. + * + * This function is just a convenience function around the gda_connection_statement_execute() + * function. + * + * See the documentation of the gda_connection_statement_execute() for information + * about the @params list of parameters. + * + * Returns: (transfer full): a #GdaDataModel containing the data returned by the + * data source, or %NULL if an error occurred + */ +GdaDataModel * +gda_connection_statement_execute_select (GdaConnection *cnc, GdaStatement *stmt, + GdaSet *params, GError **error) +{ + GdaDataModel *model; + + g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL); + GdaConnectionPrivate *priv = gda_connection_get_instance_private (cnc); + g_return_val_if_fail (priv->provider_obj, NULL); + g_return_val_if_fail (GDA_IS_STATEMENT (stmt), NULL); + + model = (GdaDataModel *) gda_connection_statement_execute_v (cnc, stmt, params, + GDA_STATEMENT_MODEL_RANDOM_ACCESS, NULL, + error, -1); + if (model && !GDA_IS_DATA_MODEL (model)) { + g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_STATEMENT_TYPE_ERROR, + "%s", _("Statement is not a selection statement")); + g_object_unref (model); + model = NULL; + } + return model; +} + +/** + * gda_connection_statement_execute_select_fullv: + * @cnc: a #GdaConnection object. + * @stmt: a #GdaStatement object. + * @params: (nullable): a #GdaSet object (which can be obtained using gda_statement_get_parameters()), or %NULL + * @model_usage: specifies how the returned data model will be used as a #GdaStatementModelUsage enum + * @error: a place to store an error, or %NULL + * @...: a (-1 terminated) list of (column number, GType) specifying for each column mentioned the GType + * of the column in the returned #GdaDataModel. + * + * Executes a selection command on the given connection. + * + * This function returns a #GdaDataModel resulting from the SELECT statement, or %NULL + * if an error occurred. + * + * This function is just a convenience function around the gda_connection_statement_execute() + * function. + * + * See the documentation of the gda_connection_statement_execute() for information + * about the @params list of parameters. + * + * Returns: (transfer full): a #GdaDataModel containing the data returned by the + * data source, or %NULL if an error occurred + */ +GdaDataModel * +gda_connection_statement_execute_select_fullv (GdaConnection *cnc, GdaStatement *stmt, + GdaSet *params, GdaStatementModelUsage model_usage, + GError **error, ...) +{ + g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL); + GdaConnectionPrivate *priv = gda_connection_get_instance_private (cnc); + g_return_val_if_fail (priv->provider_obj, NULL); + g_return_val_if_fail (GDA_IS_STATEMENT (stmt), NULL); + + if (! gda_connection_is_opened (cnc)) { + g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_CLOSED_ERROR, + "%s", _("Connection is closed")); + return NULL; + } + + va_list ap; + GdaDataModel *model = NULL; + GType *types, *req_types; + GTimer *timer = NULL; + + va_start (ap, error); + types = make_col_types_array (ap); + va_end (ap); + + g_object_ref ((GObject*) cnc); + + gda_connection_lock ((GdaLockable*) cnc); + _clear_connection_events (cnc); + gda_connection_unlock ((GdaLockable*) cnc); + + if (!priv->provider_data) { + g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_CLOSED_ERROR, + _("Connection is closed")); + g_object_unref ((GObject*) cnc); + g_free (types); + return NULL; + } + + req_types = merge_column_types (_gda_statement_get_requested_types (stmt), types); + if (req_types) { + g_free (types); + types = req_types; + req_types = NULL; + } + else if (_gda_statement_get_requested_types (stmt)) + req_types = (GType*) _gda_statement_get_requested_types (stmt); + + if (! (model_usage & GDA_STATEMENT_MODEL_RANDOM_ACCESS) && + ! (model_usage & GDA_STATEMENT_MODEL_CURSOR_FORWARD)) + model_usage |= GDA_STATEMENT_MODEL_RANDOM_ACCESS; + + dump_exec_params (cnc, stmt, params); + if (priv->exec_times) + timer = g_timer_new (); + + model = (GdaDataModel*) _gda_server_provider_statement_execute (priv->provider_obj, cnc, stmt, params, model_usage, + req_types ? req_types : types, NULL, error); + if (timer) + g_timer_stop (timer); + + g_object_unref ((GObject*) cnc); + g_free (types); + if (model && timer) + add_exec_time_to_object ((GObject*) model, timer); + if (timer) + g_timer_destroy (timer); + if (model && !GDA_IS_DATA_MODEL (model)) { + g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_STATEMENT_TYPE_ERROR, + "%s", _("Statement is not a selection statement")); + g_object_unref (model); + model = NULL; + update_meta_store_after_statement_exec (cnc, stmt, params); + } + return model; +} + +/** + * gda_connection_statement_execute_select_full: + * @cnc: a #GdaConnection object. + * @stmt: a #GdaStatement object. + * @params: (nullable): a #GdaSet object (which can be obtained using gda_statement_get_parameters()), or %NULL + * @model_usage: specifies how the returned data model will be used as a #GdaStatementModelUsage enum + * @col_types: (array) (nullable): an array of GType to request each returned #GdaDataModel's column's GType, terminated with the G_TYPE_NONE + * value. Any value left to 0 will make the database provider determine the real GType. @col_types can also be %NULL if no + * column type is specified. + * @error: a place to store an error, or %NULL + * + * Executes a selection command on the given connection. + * + * This function returns a #GdaDataModel resulting from the SELECT statement, or %NULL + * if an error occurred. + * + * This function is just a convenience function around the gda_connection_statement_execute() + * function. + * + * See the documentation of the gda_connection_statement_execute() for information + * about the @params list of parameters. + * + * Returns: (transfer full): a #GdaDataModel containing the data returned by the + * data source, or %NULL if an error occurred + */ +GdaDataModel * +gda_connection_statement_execute_select_full (GdaConnection *cnc, GdaStatement *stmt, + GdaSet *params, GdaStatementModelUsage model_usage, + GType *col_types, GError **error) +{ + GdaDataModel *model = NULL; + GTimer *timer = NULL; + + g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL); + GdaConnectionPrivate *priv = gda_connection_get_instance_private (cnc); + g_return_val_if_fail (priv->provider_obj, NULL); + g_return_val_if_fail (GDA_IS_STATEMENT (stmt), NULL); + + if (! gda_connection_is_opened (cnc)) { + g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_CLOSED_ERROR, + "%s", _("Connection is closed")); + return NULL; + } + + g_object_ref ((GObject*) cnc); + + gda_connection_lock ((GdaLockable*) cnc); + _clear_connection_events (cnc); + gda_connection_unlock ((GdaLockable*) cnc); + + if (!priv->provider_data) { + g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_CLOSED_ERROR, + _("Connection is closed")); + g_object_unref ((GObject*) cnc); + return NULL; + } + + GType *req_types; + req_types = merge_column_types (_gda_statement_get_requested_types (stmt), col_types); + if (!req_types && !col_types) + col_types = (GType*) _gda_statement_get_requested_types (stmt); + + if (! (model_usage & GDA_STATEMENT_MODEL_RANDOM_ACCESS) && + ! (model_usage & GDA_STATEMENT_MODEL_CURSOR_FORWARD)) + model_usage |= GDA_STATEMENT_MODEL_RANDOM_ACCESS; + + dump_exec_params (cnc, stmt, params); + if (priv->exec_times) + timer = g_timer_new (); + + model = (GdaDataModel*) _gda_server_provider_statement_execute (priv->provider_obj, cnc, stmt, params, model_usage, + req_types ? req_types : col_types, NULL, error); + if (timer) + g_timer_stop (timer); + g_free (req_types); + g_object_unref ((GObject*) cnc); + + if (model && timer) + add_exec_time_to_object ((GObject*) model, timer); + if (model && !GDA_IS_DATA_MODEL (model)) { + g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_STATEMENT_TYPE_ERROR, + "%s", _("Statement is not a selection statement")); + g_object_unref (model); + model = NULL; + update_meta_store_after_statement_exec (cnc, stmt, params); + } + if (timer) + g_timer_destroy (timer); + return model; +} + +/** + * gda_connection_repetitive_statement_execute: + * @cnc: a #GdaConnection + * @rstmt: a #GdaRepetitiveStatement object + * @model_usage: specifies how the returned data model will be used as a #GdaStatementModelUsage enum + * @col_types: (array) (nullable): an array of GType to request each returned GdaDataModel's column's GType, see gda_connection_statement_execute_select_full() for more information + * @stop_on_error: set to TRUE if the method has to stop on the first error. + * @error: a place to store errors, or %NULL + * + * Executes the statement upon which @rstmt is built. Note that as several statements can actually be executed by this + * method, it is recommended to be within a transaction. + * + * If @error is not %NULL and @stop_on_error is %FALSE, then it may contain the last error which occurred. + * + * Returns: (transfer full) (element-type GObject): a new list of #GObject pointers (see gda_connection_statement_execute() for more information about what they + * represent), one for each actual execution of the statement upon which @rstmt is built. If @stop_on_error is %FALSE, then + * the list may contain some %NULL pointers which refer to statements which failed to execute. + * + * Since: 4.2 + */ +GSList * +gda_connection_repetitive_statement_execute (GdaConnection *cnc, GdaRepetitiveStatement *rstmt, + GdaStatementModelUsage model_usage, GType *col_types, + gboolean stop_on_error, GError **error) +{ + GSList *sets_list, *list; + GSList *retlist = NULL; + GdaStatement *stmt; + + g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL); + GdaConnectionPrivate *priv = gda_connection_get_instance_private (cnc); + g_return_val_if_fail (priv->provider_obj, NULL); + g_return_val_if_fail (GDA_IS_REPETITIVE_STATEMENT (rstmt), NULL); + + if (! gda_connection_is_opened (cnc)) { + g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_CLOSED_ERROR, + "%s", _("Connection is closed")); + return NULL; + } + + g_object_get (rstmt, "statement", &stmt, NULL); + g_return_val_if_fail (stmt, NULL); + + g_object_ref ((GObject*) cnc); + + gda_connection_lock ((GdaLockable*) cnc); + _clear_connection_events (cnc); + gda_connection_unlock ((GdaLockable*) cnc); + + if (!priv->provider_data) { + g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_CLOSED_ERROR, + _("Connection is closed")); + g_object_unref ((GObject*) cnc); + return NULL; + } + + GType *req_types; + req_types = merge_column_types (_gda_statement_get_requested_types (stmt), col_types); + if (!req_types && !col_types) + col_types = (GType*) _gda_statement_get_requested_types (stmt); + + if (! (model_usage & GDA_STATEMENT_MODEL_RANDOM_ACCESS) && + ! (model_usage & GDA_STATEMENT_MODEL_CURSOR_FORWARD)) + model_usage |= GDA_STATEMENT_MODEL_RANDOM_ACCESS; + + sets_list = gda_repetitive_statement_get_all_sets (rstmt); + for (list = sets_list; list; list = list->next) { + GObject *obj = NULL; + GError *lerror = NULL; + GTimer *timer = NULL; + + dump_exec_params (cnc, stmt, (GdaSet*) list->data); + if (priv->exec_times) + timer = g_timer_new (); + + obj = _gda_server_provider_statement_execute (priv->provider_obj, cnc, stmt, GDA_SET (list->data), + model_usage, req_types ? req_types : col_types, + NULL, &lerror); + if (timer) + g_timer_stop (timer); + if (!obj) { + if (stop_on_error) { + if (timer) + g_timer_destroy (timer); + break; + } + else { + if (error && *error) { + g_error_free (*error); + *error = NULL; + } + g_propagate_error (error, lerror); + } + } + else { + if (timer) + add_exec_time_to_object (obj, timer); + update_meta_store_after_statement_exec (cnc, stmt, (GdaSet*) list->data); + + if (obj) + retlist = g_slist_prepend (retlist, obj); + } + if (timer) + g_timer_destroy (timer); + } + g_slist_free (sets_list); + g_free (req_types); + + g_object_unref ((GObject*) cnc); + g_object_unref (stmt); + + return g_slist_reverse (retlist); +} + +/** + * gda_connection_begin_transaction: + * @cnc: a #GdaConnection object. + * @name: (nullable): the name of the transation to start, or %NULL + * @level: the requested transaction level (use %GDA_TRANSACTION_ISOLATION_SERVER_DEFAULT to apply the server default) + * @error: a place to store errors, or %NULL + * + * Starts a transaction on the data source, identified by the @name parameter. + * + * Before starting a transaction, you can check whether the underlying + * provider does support transactions or not by using the gda_connection_supports_feature() function. + * + * Returns: %TRUE if the transaction was started successfully with the corresponding isolation level, %FALSE otherwise. + */ +gboolean +gda_connection_begin_transaction (GdaConnection *cnc, const gchar *name, GdaTransactionIsolation level, + GError **error) +{ + g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE); + GdaConnectionPrivate *priv = gda_connection_get_instance_private (cnc); + g_return_val_if_fail (priv->provider_obj, FALSE); + + if (! gda_connection_is_opened (cnc)) { + g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_CLOSED_ERROR, + "%s", _("Connection is closed")); + return FALSE; + } + + return _gda_server_provider_begin_transaction (priv->provider_obj, cnc, name, level, error); +} + +/** + * gda_connection_commit_transaction: + * @cnc: a #GdaConnection object. + * @name: (nullable): the name of the transation to commit, or %NULL + * @error: a place to store errors, or %NULL + * + * Commits the given transaction to the backend database. You need to call + * gda_connection_begin_transaction() first. + * + * Returns: %TRUE if the transaction was finished successfully, + * %FALSE otherwise. + */ +gboolean +gda_connection_commit_transaction (GdaConnection *cnc, const gchar *name, GError **error) +{ + g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE); + GdaConnectionPrivate *priv = gda_connection_get_instance_private (cnc); + g_return_val_if_fail (priv->provider_obj, FALSE); + + if (! gda_connection_is_opened (cnc)) { + g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_CLOSED_ERROR, + "%s", _("Connection is closed")); + return FALSE; + } + + return _gda_server_provider_commit_transaction (priv->provider_obj, cnc, name, error); +} + +/** + * gda_connection_rollback_transaction: + * @cnc: a #GdaConnection object. + * @name: (nullable): the name of the transation to commit, or %NULL + * @error: a place to store errors, or %NULL + * + * Rollbacks the given transaction. This means that all changes + * made to the underlying data source since the last call to + * #gda_connection_begin_transaction() or #gda_connection_commit_transaction() + * will be discarded. + * + * Returns: %TRUE if the operation was successful, %FALSE otherwise. + */ +gboolean +gda_connection_rollback_transaction (GdaConnection *cnc, const gchar *name, GError **error) +{ + g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE); + GdaConnectionPrivate *priv = gda_connection_get_instance_private (cnc); + g_return_val_if_fail (priv->provider_obj, FALSE); + + if (! gda_connection_is_opened (cnc)) { + g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_CLOSED_ERROR, + "%s", _("Connection is closed")); + return FALSE; + } + + return _gda_server_provider_rollback_transaction (priv->provider_obj, cnc, name, error); +} + +/** + * gda_connection_add_savepoint: + * @cnc: a #GdaConnection object + * @name: (nullable): name of the savepoint to add + * @error: a place to store errors or %NULL + * + * Adds a SAVEPOINT named @name. + * + * Returns: TRUE if no error occurred + */ +gboolean +gda_connection_add_savepoint (GdaConnection *cnc, const gchar *name, GError **error) +{ + g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE); + GdaConnectionPrivate *priv = gda_connection_get_instance_private (cnc); + g_return_val_if_fail (priv->provider_obj, FALSE); + + if (! gda_connection_is_opened (cnc)) { + g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_CLOSED_ERROR, + "%s", _("Connection is closed")); + return FALSE; + } + + return _gda_server_provider_add_savepoint (priv->provider_obj, cnc, name, error); +} + +/** + * gda_connection_rollback_savepoint: + * @cnc: a #GdaConnection object + * @name: (nullable): name of the savepoint to rollback to + * @error: a place to store errors or %NULL + * + * Rollback all the modifications made after the SAVEPOINT named @name. + * + * Returns: TRUE if no error occurred + */ +gboolean +gda_connection_rollback_savepoint (GdaConnection *cnc, const gchar *name, GError **error) +{ + g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE); + GdaConnectionPrivate *priv = gda_connection_get_instance_private (cnc); + g_return_val_if_fail (priv->provider_obj, FALSE); + + if (! gda_connection_is_opened (cnc)) { + g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_CLOSED_ERROR, + "%s", _("Connection is closed")); + return FALSE; + } + + return _gda_server_provider_rollback_savepoint (priv->provider_obj, cnc, name, error); +} + +/** + * gda_connection_delete_savepoint: + * @cnc: a #GdaConnection object + * @name: (nullable): name of the savepoint to delete + * @error: a place to store errors or %NULL + * + * Delete the SAVEPOINT named @name when not used anymore. + * + * Returns: TRUE if no error occurred + */ +gboolean +gda_connection_delete_savepoint (GdaConnection *cnc, const gchar *name, GError **error) +{ + g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE); + GdaConnectionPrivate *priv = gda_connection_get_instance_private (cnc); + g_return_val_if_fail (priv->provider_obj, FALSE); + + if (! gda_connection_is_opened (cnc)) { + g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_CLOSED_ERROR, + "%s", _("Connection is closed")); + return FALSE; + } + + return _gda_server_provider_delete_savepoint (priv->provider_obj, cnc, name, error); +} + +/** + * gda_connection_get_transaction_status: + * @cnc: a #GdaConnection object + * + * Get the status of @cnc regarding transactions. The returned object should not be modified + * or destroyed; however it may be modified or destroyed by the connection itself. + * + * If %NULL is returned, then no transaction has been associated with @cnc + * + * Returns: (transfer none): a #GdaTransactionStatus object, or %NULL + */ +GdaTransactionStatus * +gda_connection_get_transaction_status (GdaConnection *cnc) +{ + g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL); + GdaConnectionPrivate *priv = gda_connection_get_instance_private (cnc); + + return priv->trans_status; +} + +/** + * gda_connection_supports_feature: + * @cnc: a #GdaConnection object. + * @feature: feature to ask for. + * + * Asks the underlying provider for if a specific feature is supported. + * + * Returns: %TRUE if the provider supports it, %FALSE if not. + */ +gboolean +gda_connection_supports_feature (GdaConnection *cnc, GdaConnectionFeature feature) +{ + g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE); + GdaConnectionPrivate *priv = gda_connection_get_instance_private (cnc); + g_return_val_if_fail (priv->provider_obj, FALSE); + + return gda_server_provider_supports_feature (priv->provider_obj, cnc, feature); +} + +/* builds a list of #GdaMetaContext contexts templates: contexts which have a non NULL table_name, + * and empty or partially filled column names and values specifications */ +static GSList * +build_upstream_context_templates (GdaMetaStore *store, GdaMetaContext *context, GSList *elist, GError **error) +{ + GSList *depend_on_contexts; + GSList *retlist; + GError *lerror = NULL; + depend_on_contexts = _gda_meta_store_schema_get_upstream_contexts (store, context, &lerror); + if (!depend_on_contexts) { + if (lerror) { + /* error while getting dependencies */ + g_propagate_error (error, lerror); + return FALSE; + } + return elist; + } + else { + GSList *list; + retlist = NULL; + for (list = depend_on_contexts; list; list = list->next) + retlist = build_upstream_context_templates (store, (GdaMetaContext *) list->data, + retlist, error); + list = g_slist_concat (depend_on_contexts, elist); + retlist = g_slist_concat (retlist, list); + return retlist; + } +} + + +/* builds a list of #GdaMetaContext contexts templates: contexts which have a non NULL table_name, + * and empty or partially filled column names and values specifications */ +static GSList * +build_downstream_context_templates (GdaMetaStore *store, GdaMetaContext *context, GSList *elist, GError **error) +{ + GSList *depending_contexts; + GSList *retlist; + GError *lerror = NULL; + depending_contexts = _gda_meta_store_schema_get_downstream_contexts (store, context, &lerror); + if (!depending_contexts) { + if (lerror) { + /* error while getting dependencies */ + g_propagate_error (error, lerror); + return NULL; + } + return elist; + } + else { + GSList *list; + retlist = NULL; + for (list = depending_contexts; list; list = list->next) + retlist = build_downstream_context_templates (store, (GdaMetaContext *) list->data, + retlist, error); + list = g_slist_concat (elist, depending_contexts); + retlist = g_slist_concat (list, retlist); + return retlist; + } +} + +/*#define GDA_DEBUG_META_STORE_UPDATE*/ +#ifdef GDA_DEBUG_META_STORE_UPDATE +static void +meta_context_dump (GdaMetaContext *context) +{ + gchar *str; + str = gda_meta_context_stringify (context); + g_print ("GdaMetaContext for table %s: %s\n", context->table_name, str); + g_free (str); +} +#endif + +/* + * + */ +static gint +check_parameters (GdaMetaContext *context, GError **error, gint nb, ...) +{ +#define MAX_PARAMS 10 + gint i; + va_list ap; + gint retval = -1; + GValue **pvalue; + struct { + GValue **pvalue; + GType type; + } spec_array [MAX_PARAMS]; + gint nb_params = 0; + + va_start (ap, nb); + /* make a list of all the GValue pointers */ + for (pvalue = va_arg (ap, GValue **); pvalue; pvalue = va_arg (ap, GValue **), nb_params++) { + g_assert (nb_params < MAX_PARAMS); /* hard limit, recompile to change it (should never be needed) */ + spec_array[nb_params].pvalue = pvalue; + spec_array[nb_params].type = va_arg (ap, GType); + } + + /* test against each test case */ + for (i = 0; i < nb; i++) { + gchar *pname; + gboolean allfound = TRUE; + gint j; + for (j = 0; j < nb_params; j++) + *(spec_array[j].pvalue) = NULL; + + for (pname = va_arg (ap, gchar*); pname; pname = va_arg (ap, gchar*)) { + gint j; + pvalue = va_arg (ap, GValue **); + *pvalue = NULL; + for (j = 0; allfound && (j < context->size); j++) { + if (!strcmp (context->column_names[j], pname)) { + *pvalue = context->column_values[j]; + break; + } + } + if (j == context->size) + allfound = FALSE; + } + if (allfound) { + retval = i; + break; + } + } + va_end (ap); + + if (retval >= 0) { + gint j; + for (j = 0; j < nb_params; j++) { + GValue *v = *(spec_array[j].pvalue); + if (v && (gda_value_is_null (v) || (G_VALUE_TYPE (v) != spec_array[j].type))) { + g_set_error (error, GDA_CONNECTION_ERROR, + GDA_CONNECTION_META_DATA_CONTEXT_ERROR, + "%s", _("Invalid argument")); + retval = -1; + } + } + } + else { + gchar *str; + str = gda_meta_context_stringify (context); + g_set_error (error, GDA_CONNECTION_ERROR, + GDA_CONNECTION_META_DATA_CONTEXT_ERROR, + _("Missing or wrong arguments for table '%s': %s"), + context->table_name, str); + g_free (str); + retval = -1; + } + + /*g_print ("Check arguments context => found %d\n", retval);*/ + return retval; +} + +static gboolean +local_meta_update (GdaServerProvider *provider, GdaConnection *cnc, GdaMetaContext *context, GError **error) +{ + const gchar *tname = context->table_name; + GdaMetaStore *store; + gboolean retval; + + const GValue *catalog = NULL; + const GValue *schema = NULL; + const GValue *name = NULL; + gint i; + +#ifdef GDA_DEBUG_META_STORE_UPDATE + g_print ("%s() => ", __FUNCTION__); + meta_context_dump (context); +#endif + + if (*tname != '_') + return TRUE; + tname ++; + + store = gda_connection_get_meta_store (cnc); + switch (*tname) { + case 'b': { + /* _builtin_data_types, params: + * - none + */ + ASSERT_TABLE_NAME (tname, "builtin_data_types"); + retval = _gda_server_provider_meta_0arg (provider, cnc, store, context, GDA_SERVER_META__BTYPES, error); + WARN_META_UPDATE_FAILURE (retval, "_btypes"); + return retval; + } + break; + case 'c': + if ((tname[1] == 'o') && (tname[2] == 'l') && (tname[3] == 'u')) { + /* _columns, params: + * -0- @table_catalog, @table_schema, @table_name + * -1- @character_set_catalog, @character_set_schema, @character_set_name + * -2- @collation_catalog, @collation_schema, @collation_name + */ + if (gda_meta_context_get_n_columns (context) == 3) + { + i = check_parameters (context, error, 3, + &catalog, G_TYPE_STRING, + &schema, G_TYPE_STRING, + &name, G_TYPE_STRING, NULL, + "table_catalog", &catalog, "table_schema", &schema, "table_name", &name, NULL, + "character_set_catalog", &catalog, "character_set_schema", &schema, "character_set_name", &name, NULL, + "collation_catalog", &catalog, "collation_schema", &schema, "collation_name", &name, NULL); + if (i < 0) + return FALSE; + + ASSERT_TABLE_NAME (tname, "columns"); + retval = _gda_server_provider_meta_3arg (provider, cnc, store, context, + GDA_SERVER_META_COLUMNS, catalog, schema, name, error); + WARN_META_UPDATE_FAILURE (retval, "columns"); + } + else { + ASSERT_TABLE_NAME (tname, "columns"); + retval = _gda_server_provider_meta_0arg (provider, cnc, store, context, + GDA_SERVER_META__COLUMNS, error); + WARN_META_UPDATE_FAILURE (retval, "columns"); + } + return retval; + } + else if ((tname[1] == 'o') && (tname[2] == 'l')) { + /* _collations, params: + * -0- @collation_catalog, @collation_schema, @collation_name + * -1- @collation_catalog, @collation_schema + */ + i = check_parameters (context, error, 2, + &catalog, G_TYPE_STRING, + &schema, G_TYPE_STRING, + &name, G_TYPE_STRING, NULL, + "collation_catalog", &catalog, "collation_schema", &schema, "collation_name", &name, NULL, + "collation_catalog", &catalog, "collation_schema", &schema, NULL); + if (i < 0) + return FALSE; + + ASSERT_TABLE_NAME (tname, "collations"); + retval = _gda_server_provider_meta_3arg (provider, cnc, store, context, + GDA_SERVER_META_COLLATIONS, catalog, schema, name, error); + WARN_META_UPDATE_FAILURE (retval, "collations"); + return retval; + } + else if ((tname[1] == 'h') && (tname[2] == 'a')) { + /* _character_sets, params: + * -0- @character_set_catalog, @character_set_schema, @character_set_name + * -1- @character_set_catalog, @character_set_schema + */ + i = check_parameters (context, error, 2, + &catalog, G_TYPE_STRING, + &schema, G_TYPE_STRING, + &name, G_TYPE_STRING, NULL, + "character_set_catalog", &catalog, "character_set_schema", &schema, "character_set_name", &name, NULL, + "character_set_catalog", &catalog, "character_set_schema", &schema, NULL); + if (i < 0) + return FALSE; + + ASSERT_TABLE_NAME (tname, "character_sets"); + retval = _gda_server_provider_meta_3arg (provider, cnc, store, context, + GDA_SERVER_META_CHARACTER_SETS, catalog, schema, name, error); + WARN_META_UPDATE_FAILURE (retval, "character_sets"); + return retval; + } + else if ((tname[1] == 'h') && (tname[2] == 'e')) { + /* _check_column_usage, params: + * -0- @table_catalog, @table_schema, @table_name, @constraint_name + * -1- @table_catalog, @table_schema, @table_name, @column_name + */ + if (gda_meta_context_get_n_columns (context) == 0) { + ASSERT_TABLE_NAME (tname, "check_column_usage"); + retval = _gda_server_provider_meta_0arg (provider, cnc, store, context, + GDA_SERVER_META__CHECK_COLUMNS, error); + WARN_META_UPDATE_FAILURE (retval, "check_columns"); + } else { + const GValue *tabname = NULL; + const GValue *cname = NULL; + i = check_parameters (context, error, 2, + &catalog, G_TYPE_STRING, + &schema, G_TYPE_STRING, + &tabname, G_TYPE_STRING, + &cname, G_TYPE_STRING, NULL, + "table_catalog", &catalog, "table_schema", &schema, "table_name", &tabname, "constraint_name", &cname, NULL, + "table_catalog", &catalog, "table_schema", &schema, "table_name", &tabname, "column_name", &cname, NULL); + if (i < 0) + return FALSE; + + ASSERT_TABLE_NAME (tname, "check_column_usage"); + retval = _gda_server_provider_meta_4arg (provider, cnc, store, context, + GDA_SERVER_META_CHECK_COLUMNS, catalog, schema, tabname, cname, error); + WARN_META_UPDATE_FAILURE (retval, "check_columns"); + } + return retval; + } + break; + + case 'd': + if ((tname[1] == 'o') && (tname[2] == 'm') && (tname[3] == 'a') && (tname[4] == 'i') && (tname[5] == 'n') && + (tname[6] == 's')) { + /* _domains, params: + * -0- @domain_catalog, @domain_schema + */ + i = check_parameters (context, error, 1, + &catalog, G_TYPE_STRING, + &schema, G_TYPE_STRING, NULL, + "domain_catalog", &catalog, "domain_schema", &schema, NULL); + + ASSERT_TABLE_NAME (tname, "domains"); + if (i < 0) { + g_clear_error (error); + retval = _gda_server_provider_meta_0arg (provider, cnc, store, context, + GDA_SERVER_META__DOMAINS, error); + WARN_META_UPDATE_FAILURE (retval, "domains"); + } else { + retval = _gda_server_provider_meta_2arg (provider, cnc, store, context, + GDA_SERVER_META_DOMAINS, catalog, schema, error); + WARN_META_UPDATE_FAILURE (retval, "domains"); + } + return retval; + } + else { + /* _domain_constraints, params: + * -0- @domain_catalog, @domain_schema, @domain_name + * -1- @constraint_catalog, @constraint_schema + */ + if (gda_meta_context_get_n_columns (context) == 0) { + ASSERT_TABLE_NAME (tname, "domain_constraints"); + retval = _gda_server_provider_meta_0arg (provider, cnc, store, context, + GDA_SERVER_META__CONSTRAINTS_DOM, error); + WARN_META_UPDATE_FAILURE (retval, "constraints_dom"); + } else { + const GValue *domname = NULL; + i = check_parameters (context, error, 2, + &catalog, G_TYPE_STRING, + &schema, G_TYPE_STRING, + &domname, G_TYPE_STRING, NULL, + "domain_catalog", &catalog, "domain_schema", &schema, "domain_name", &domname, NULL, + "constraint_catalog", &catalog, "constraint_schema", &schema, NULL); + + if (i < 0) + return FALSE; + if (i == 1) + return TRUE; /* nothing to do */ + + ASSERT_TABLE_NAME (tname, "domain_constraints"); + retval = _gda_server_provider_meta_3arg (provider, cnc, store, context, + GDA_SERVER_META_CONSTRAINTS_DOM, catalog, schema, domname, error); + WARN_META_UPDATE_FAILURE (retval, "constraints_dom"); + } + + return retval; + } + break; + + case 'e': + if (tname[1] == 'n') { + /* _enums, params: + * -0- @udt_catalog, @udt_schema, @udt_name + */ + if (gda_meta_context_get_n_columns (context) == 0) { + ASSERT_TABLE_NAME (tname, "enums"); + retval = _gda_server_provider_meta_0arg (provider, cnc, store, context, + GDA_SERVER_META__ENUMS, error); + WARN_META_UPDATE_FAILURE (retval, "enums"); + } else { + i = check_parameters (context, error, 1, + &catalog, G_TYPE_STRING, + &schema, G_TYPE_STRING, + &name, G_TYPE_STRING, NULL, + "udt_catalog", &catalog, "udt_schema", &schema, "udt_name", &name, NULL); + if (i < 0) + return FALSE; + + ASSERT_TABLE_NAME (tname, "enums"); + retval = _gda_server_provider_meta_3arg (provider, cnc, store, context, + GDA_SERVER_META_ENUMS, catalog, schema, name, error); + WARN_META_UPDATE_FAILURE (retval, "enums"); + } + + return retval; + } + else { + /* _element_types, params: + * - none + * -0- @specific_name + */ + i = check_parameters (context, error, 1, + &name, G_TYPE_STRING, NULL, + "specific_name", &name, NULL); + + ASSERT_TABLE_NAME (tname, "element_types"); + if (i < 0) { + g_clear_error (error); + retval = _gda_server_provider_meta_0arg (provider, cnc, store, context, + GDA_SERVER_META__EL_TYPES, error); + WARN_META_UPDATE_FAILURE (retval, "_el_types"); + } else { + retval = _gda_server_provider_meta_1arg (provider, cnc, store, context, + GDA_SERVER_META_EL_TYPES, name, error); + WARN_META_UPDATE_FAILURE (retval, "el_types"); + } + return retval; + } + break; + + case 'i': + if ((tname[1] == 'n') && (tname[2] == 'f')) { + /* _information_schema_catalog_name, params: + * - none + */ + ASSERT_TABLE_NAME (tname, "information_schema_catalog_name"); + retval = _gda_server_provider_meta_0arg (provider, cnc, store, context, + GDA_SERVER_META__INFO, error); + WARN_META_UPDATE_FAILURE (retval, "_info"); + return retval; + } + else { + /* _index_column_usage, params: + * -0- @table_catalog, @table_schema, @table_name, @index_name + */ + if (gda_meta_context_get_n_columns (context) == 0) { + ASSERT_TABLE_NAME (tname, "index_column_usage"); + retval = _gda_server_provider_meta_0arg (provider, cnc, store, context, + GDA_SERVER_META__INDEX_COLS, error); + WARN_META_UPDATE_FAILURE (retval, "index_cols"); + } else { + const GValue *iname = NULL; + i = check_parameters (context, error, 1, + &catalog, G_TYPE_STRING, + &schema, G_TYPE_STRING, + &name, G_TYPE_STRING, + &iname, G_TYPE_STRING, NULL, + "table_catalog", &catalog, "table_schema", &schema, "table_name", &name, "index_name", &iname, NULL); + + if (i < 0) + return FALSE; + + ASSERT_TABLE_NAME (tname, "index_column_usage"); + retval = _gda_server_provider_meta_4arg (provider, cnc, store, context, + GDA_SERVER_META_INDEX_COLS, catalog, schema, name, iname, error); + WARN_META_UPDATE_FAILURE (retval, "index_cols"); + } + return retval; + } + break; + case 'k': { + /* _key_column_usage, params: + * -0- @table_catalog, @table_schema, @table_name, @constraint_name + * -0- @ref_table_catalog, @ref_table_schema, @ref_table_name, @ref_constraint_name + */ + if (gda_meta_context_get_n_columns (context) == 0) { + ASSERT_TABLE_NAME (tname, "key_column_usage"); + retval = _gda_server_provider_meta_0arg (provider, cnc, store, context, + GDA_SERVER_META__KEY_COLUMNS, error); + WARN_META_UPDATE_FAILURE (retval, "key_columns"); + } else { + const GValue *tabname = NULL; + const GValue *cname = NULL; + i = check_parameters (context, error, 2, + &catalog, G_TYPE_STRING, + &schema, G_TYPE_STRING, + &tabname, G_TYPE_STRING, + &cname, G_TYPE_STRING, NULL, + "table_catalog", &catalog, "table_schema", &schema, "table_name", &tabname, "constraint_name", &cname, NULL, + "table_catalog", &catalog, "table_schema", &schema, "table_name", &tabname, "column_name", &cname, NULL); + if (i < 0) + return FALSE; + + ASSERT_TABLE_NAME (tname, "key_column_usage"); + retval = _gda_server_provider_meta_4arg (provider, cnc, store, context, + GDA_SERVER_META_KEY_COLUMNS, catalog, schema, tabname, cname, error); + WARN_META_UPDATE_FAILURE (retval, "key_columns"); + } + return retval; + break; + } + + case 'p': + /* _parameters, params: + * -0- @specific_catalog, @specific_schema, @specific_name + */ + i = check_parameters (context, error, 1, + &catalog, G_TYPE_STRING, + &schema, G_TYPE_STRING, + &name, G_TYPE_STRING, NULL, + "specific_catalog", &catalog, "specific_schema", &schema, "specific_name", &name, NULL); + + ASSERT_TABLE_NAME (tname, "parameters"); + if (i < 0) { + g_clear_error (error); + retval = _gda_server_provider_meta_0arg (provider, cnc, store, context, + GDA_SERVER_META__ROUTINE_PAR, error); + WARN_META_UPDATE_FAILURE (retval, "routine_par"); + } else { + retval = _gda_server_provider_meta_3arg (provider, cnc, store, context, + GDA_SERVER_META_ROUTINE_PAR, catalog, schema, name, error); + WARN_META_UPDATE_FAILURE (retval, "routine_par"); + } + return retval; + + case 'r': + if ((tname[1] == 'e') && (tname[2] == 'f')) { + /* _referential_constraints, params: + * -0- @table_catalog, @table_schema, @table_name, @constraint_name + * -0- @ref_table_catalog, @ref_table_schema, @ref_table_name, @ref_constraint_name + */ + if (gda_meta_context_get_n_columns (context) == 0) { + ASSERT_TABLE_NAME (tname, "referential_constraints"); + retval = _gda_server_provider_meta_0arg (provider, cnc, store, context, + GDA_SERVER_META__CONSTRAINTS_REF, error); + WARN_META_UPDATE_FAILURE (retval, "constraints_ref"); + return retval; + } else { + const GValue *tabname = NULL; + const GValue *cname = NULL; + i = check_parameters (context, error, 2, + &catalog, G_TYPE_STRING, + &schema, G_TYPE_STRING, + &tabname, G_TYPE_STRING, + &cname, G_TYPE_STRING, NULL, + "table_catalog", &catalog, "table_schema", &schema, "table_name", &tabname, "constraint_name", &cname, NULL, + "ref_table_catalog", &catalog, "ref_table_schema", &schema, "ref_table_name", &tabname, "ref_constraint_name", &cname, NULL); + if (i < 0) + return FALSE; + + ASSERT_TABLE_NAME (tname, "referential_constraints"); + if (i == 0) { + retval = _gda_server_provider_meta_4arg (provider, cnc, store, context, + GDA_SERVER_META_CONSTRAINTS_REF, catalog, schema, tabname, cname, error); + WARN_META_UPDATE_FAILURE (retval, "constraints_ref"); + return retval; + } + else { + /* nothing to do */ + return TRUE; + } + } + return TRUE; + } + if ((tname[1] == 'o') && (tname[2] == 'u') && (tname[3] == 't') && (tname[4] == 'i') && + (tname[5] == 'n') && (tname[6] == 'e') && (tname[7] == 's')) { + /* _routines, params: + * -0- @specific_catalog, @specific_schema, @specific_name + * -1- @specific_catalog, @specific_schema + */ + if (gda_meta_context_get_n_columns (context) == 0) { + ASSERT_TABLE_NAME (tname, "routines"); + retval = _gda_server_provider_meta_0arg (provider, cnc, store, context, + GDA_SERVER_META__ROUTINES, error); + WARN_META_UPDATE_FAILURE (retval, "routines"); + } else { + i = check_parameters (context, error, 2, + &catalog, G_TYPE_STRING, + &schema, G_TYPE_STRING, + &name, G_TYPE_STRING, NULL, + "specific_catalog", &catalog, "specific_schema", &schema, "specific_name", &name, NULL, + "specific_catalog", &catalog, "specific_schema", &schema, NULL); + if (i < 0) + return FALSE; + + ASSERT_TABLE_NAME (tname, "routines"); + retval = _gda_server_provider_meta_3arg (provider, cnc, store, context, + GDA_SERVER_META_ROUTINES, catalog, schema, name, error); + WARN_META_UPDATE_FAILURE (retval, "routines"); + } + + return retval; + } + else { + /* _routine_columns, params: + * -0- @specific_catalog, @specific_schema, @specific_name + */ + if (gda_meta_context_get_n_columns (context) == 0) { + ASSERT_TABLE_NAME (tname, "routine_columns"); + retval = _gda_server_provider_meta_0arg (provider, cnc, store, context, + GDA_SERVER_META__ROUTINE_COL, error); + WARN_META_UPDATE_FAILURE (retval, "routine_col"); + } else { + const GValue *col_name = NULL; + const GValue *ordinal = NULL; + i = check_parameters (context, error, 1, + &catalog, G_TYPE_STRING, + &schema, G_TYPE_STRING, + &name, G_TYPE_STRING, + &col_name, G_TYPE_STRING, + &ordinal, G_TYPE_INT, NULL, + "specific_catalog", &catalog, "specific_schema", &schema, "specific_name", &name, "column_name", &col_name, "ordinal_position", &ordinal, NULL); + if (i < 0) { + g_message ("Fail _routine_columns"); + return FALSE; + } + ASSERT_TABLE_NAME (tname, "routine_columns"); + retval = _gda_server_provider_meta_5arg (provider, cnc, store, context, + GDA_SERVER_META_ROUTINE_COL, catalog, schema, name, col_name, ordinal, error); + WARN_META_UPDATE_FAILURE (retval, "routine_col"); + } + return retval; + } + break; + + case 's': { + /* _schemata, params: + * -0- @catalog_name, @schema_name + * -1- @catalog_name + */ + ASSERT_TABLE_NAME (tname, "schemata"); + if (gda_meta_context_get_n_columns (context) == 0) { + retval = _gda_server_provider_meta_0arg (provider, cnc, store, context, + GDA_SERVER_META__SCHEMATA, error); + WARN_META_UPDATE_FAILURE (retval, "schemata"); + } else { + i = check_parameters (context, error, 2, + &schema, G_TYPE_STRING, NULL, + "catalog_name", &catalog, "schema_name", &schema, NULL, + "catalog_name", &catalog, NULL); + if (i < 0) + return FALSE; + + retval = _gda_server_provider_meta_2arg (provider, cnc, store, context, + GDA_SERVER_META_SCHEMATA, catalog, schema, error); + WARN_META_UPDATE_FAILURE (retval, "schemata"); + } + return retval; + } + case 't': + if ((tname[1] == 'a') && (tname[2] == 'b') && (tname[3] == 'l') && (tname[4] == 'e') && (tname[5] == 's')) { + /* _tables, params: + * -0- @table_catalog, @table_schema, @table_name + * -1- @table_catalog, @table_schema + */ + if (gda_meta_context_get_n_columns (context) == 0) { + ASSERT_TABLE_NAME (tname, "tables"); + retval = _gda_server_provider_meta_0arg (provider, cnc, store, context, + GDA_SERVER_META__TABLES_VIEWS, error); + WARN_META_UPDATE_FAILURE (retval, "tables_views"); + } else { + i = check_parameters (context, error, 3, + &catalog, G_TYPE_STRING, + &schema, G_TYPE_STRING, + &name, G_TYPE_STRING, NULL, + "table_catalog", &catalog, "table_schema", &schema, "table_name", &name, NULL, + "table_catalog", &catalog, "table_schema", &schema, NULL, + "table_name", &name, NULL); + if (i < 0) + return FALSE; + + ASSERT_TABLE_NAME (tname, "tables"); + retval = _gda_server_provider_meta_3arg (provider, cnc, store, context, + GDA_SERVER_META_TABLES_VIEWS, catalog, schema, name, error); + WARN_META_UPDATE_FAILURE (retval, "tables_views"); + } + + return retval; + } + else if ((tname[1] == 'a') && (tname[2] == 'b') && (tname[3] == 'l') && (tname[4] == 'e') && + (tname[5] == '_') && (tname[6] == 'c')) { + /* _tables_constraints, params: + * -0- @table_catalog, @table_schema, @table_name, @constraint_name + * -1- @table_catalog, @table_schema, @table_name + */ + if (gda_meta_context_get_n_columns (context) == 0) { + retval = _gda_server_provider_meta_0arg (provider, cnc, store, context, + GDA_SERVER_META__CONSTRAINTS_TAB, error); + WARN_META_UPDATE_FAILURE (retval, "constraints_tab"); + } else { + const GValue *cname = NULL; + const GValue *tabname = NULL; + i = check_parameters (context, error, 2, + &catalog, G_TYPE_STRING, + &schema, G_TYPE_STRING, + &cname, G_TYPE_STRING, + &tabname, G_TYPE_STRING, NULL, + "table_catalog", &catalog, "table_schema", &schema, "table_name", &tabname, "constraint_name", &cname, NULL, + "table_catalog", &catalog, "table_schema", &schema, "table_name", &tabname, NULL); + + if (i < 0) + return FALSE; + + ASSERT_TABLE_NAME (tname, "table_constraints"); + retval = _gda_server_provider_meta_4arg (provider, cnc, store, context, + GDA_SERVER_META_CONSTRAINTS_TAB, catalog, schema, tabname, cname, error); + WARN_META_UPDATE_FAILURE (retval, "constraints_tab"); + } + + return retval; + } + else if ((tname[1] == 'a') && (tname[2] == 'b') && (tname[3] == 'l') && (tname[4] == 'e') && + (tname[5] == '_') && (tname[6] == 'i')) { + /* _table_indexes, params: + * -0- @table_catalog, @table_schema, @table_name, @index_name + * -1- @table_catalog, @table_schema, @table_name + */ + if (gda_meta_context_get_n_columns (context) == 0) { + ASSERT_TABLE_NAME (tname, "table_indexes"); + retval = _gda_server_provider_meta_0arg (provider, cnc, store, context, + GDA_SERVER_META__INDEXES_TAB, error); + WARN_META_UPDATE_FAILURE (retval, "indexes_tab"); + } else { + const GValue *iname = NULL; + const GValue *tabname = NULL; + i = check_parameters (context, error, 2, + &catalog, G_TYPE_STRING, + &schema, G_TYPE_STRING, + &iname, G_TYPE_STRING, + &tabname, G_TYPE_STRING, NULL, + "table_catalog", &catalog, "table_schema", &schema, "table_name", &tabname, "index_name", &iname, NULL, + "table_catalog", &catalog, "table_schema", &schema, "table_name", &tabname, NULL); + + if (i < 0) + return FALSE; + + ASSERT_TABLE_NAME (tname, "table_indexes"); + retval = _gda_server_provider_meta_4arg (provider, cnc, store, context, + GDA_SERVER_META_INDEXES_TAB, catalog, schema, tabname, iname, error); + WARN_META_UPDATE_FAILURE (retval, "indexes_tab"); + } + + return retval; + } + else if ((tname[1] == 'r') && (tname[2] == 'i')) { + /* _triggers, params: + * -0- @trigger_catalog, @trigger_schema + * -1- @event_object_catalog, @event_object_schema, @event_object_table + */ + + ASSERT_TABLE_NAME (tname, "triggers"); + if (gda_meta_context_get_n_columns (context) == 0) { + retval = _gda_server_provider_meta_0arg (provider, cnc, store, context, + GDA_SERVER_META__TRIGGERS, error); + } else { + i = check_parameters (context, error, 2, + &catalog, G_TYPE_STRING, + &schema, G_TYPE_STRING, + &name, G_TYPE_STRING, NULL, + "trigger_catalog", &catalog, "trigger_schema", &schema, NULL, + "event_object_catalog", &catalog, "event_object_schema", &schema, "event_object_table", &name, NULL); + if (i < 0) + return FALSE; + if (i == 1) { + retval = _gda_server_provider_meta_3arg (provider, cnc, store, context, + GDA_SERVER_META_TRIGGERS, catalog, schema, name, error); + WARN_META_UPDATE_FAILURE (retval, "triggers"); + return retval; + } + else { + /* nothing to do */ + return TRUE; + } + } + } + break; + + case 'u': + if ((tname[1] == 'd') && (tname[2] == 't') && (tname[3] == 0)) { + /* _udt, params: + * -0- @udt_catalog, @udt_schema + */ + if (gda_meta_context_get_n_columns (context) == 0) { + ASSERT_TABLE_NAME (tname, "udt"); + retval = _gda_server_provider_meta_0arg (provider, cnc, store, context, + GDA_SERVER_META__UDT, error); + WARN_META_UPDATE_FAILURE (retval, "udt"); + } else { + i = check_parameters (context, error, 1, + &catalog, G_TYPE_STRING, + &schema, G_TYPE_STRING, NULL, + "udt_catalog", &catalog, "udt_schema", &schema, NULL); + if (i < 0) + return FALSE; + + ASSERT_TABLE_NAME (tname, "udt"); + retval = _gda_server_provider_meta_2arg (provider, cnc, store, context, + GDA_SERVER_META_UDT, catalog, schema, error); + WARN_META_UPDATE_FAILURE (retval, "udt"); + } + return retval; + } + else if ((tname[1] == 'd') && (tname[2] == 't') && (tname[3] == '_')) { + /* _udt_columns, params: + * -0- @udt_catalog, @udt_schema, @udt_name + */ + i = check_parameters (context, error, 1, + &catalog, G_TYPE_STRING, + &schema, G_TYPE_STRING, + &name, G_TYPE_STRING, NULL, + "udt_catalog", &catalog, "udt_schema", &schema, "udt_name", &name, NULL); + if (i < 0) { + g_clear_error (error); + retval = _gda_server_provider_meta_0arg (provider, cnc, store, context, + GDA_SERVER_META__UDT_COLS, error); + WARN_META_UPDATE_FAILURE (retval, "_el_types"); + } else { + ASSERT_TABLE_NAME (tname, "udt_columns"); + retval = _gda_server_provider_meta_3arg (provider, cnc, store, context, + GDA_SERVER_META_UDT_COLS, catalog, schema, name, error); + WARN_META_UPDATE_FAILURE (retval, "udt_cols"); + } + return retval; + } + break; + + case 'v': { + /* _view_column_usage, params: + * -0- @view_catalog, @view_schema, @view_name + * -1- @table_catalog, @table_schema, @table_name, @column_name + */ + if (gda_meta_context_get_n_columns (context) == 0) { + retval = _gda_server_provider_meta_3arg (provider, cnc, store, context, + GDA_SERVER_META_VIEW_COLS, catalog, schema, name, error); + WARN_META_UPDATE_FAILURE (retval, "view_cols"); + } else { + const GValue *colname = NULL; + i = check_parameters (context, error, 2, + &catalog, G_TYPE_STRING, + &schema, G_TYPE_STRING, + &colname, G_TYPE_STRING, + &name, G_TYPE_STRING, NULL, + "view_catalog", &catalog, "view_schema", &schema, "view_name", &name, NULL, + "table_catalog", &catalog, "table_schema", &schema, "table_name", &name, + "column_name", &colname, NULL); + if (i < 0) + return FALSE; + + ASSERT_TABLE_NAME (tname, "view_column_usage"); + retval = _gda_server_provider_meta_3arg (provider, cnc, store, context, + GDA_SERVER_META_VIEW_COLS, catalog, schema, name, error); + WARN_META_UPDATE_FAILURE (retval, "view_cols"); + } + + return retval; + break; + } + default: + break; + } + return TRUE; +} + +typedef struct { + GdaServerProvider *prov; + GdaConnection *cnc; + GError *error; + GSList *context_templates; + GHashTable *context_templates_hash; +} DownstreamCallbackData; + +// UNUSED METHOD +/* static GError * */ +/* suggest_update_cb_downstream (G_GNUC_UNUSED GdaMetaStore *store, GdaMetaContext *suggest, DownstreamCallbackData *data) */ +/* { */ +/* #define MAX_CONTEXT_SIZE 10 */ +/* if (data->error) */ +/* return data->error; */ + +/* GdaMetaContext *templ_context; */ +/* GdaMetaContext loc_suggest; */ +/* gchar *column_names[MAX_CONTEXT_SIZE]; */ +/* GValue *column_values[MAX_CONTEXT_SIZE]; */ + + /* if there is no context with the same table name in the templates, then exit right now */ +/* templ_context = g_hash_table_lookup (data->context_templates_hash, suggest->table_name); */ +/* if (!templ_context) */ +/* return NULL; */ + +/* if (templ_context->size > 0) { */ + /* setup @loc_suggest */ +/* gint i, j; */ + +/* if (suggest->size > MAX_CONTEXT_SIZE) { */ +/* g_warning ("Internal limitation at %s(), limitation should be at least %d, please report a bug", */ +/* __FUNCTION__, suggest->size); */ +/* return NULL; */ +/* } */ +/* loc_suggest.size = suggest->size; */ +/* loc_suggest.table_name = suggest->table_name; */ +/* loc_suggest.column_names = column_names; */ +/* loc_suggest.column_values = column_values; */ +/* memcpy (loc_suggest.column_names, suggest->column_names, sizeof (gchar *) * suggest->size); */ /* Flawfinder: ignore */ +/* memcpy (loc_suggest.column_values, suggest->column_values, sizeof (GValue *) * suggest->size); */ /* Flawfinder: ignore */ + + /* check that any @suggest's columns which is in @templ_context's has the same values */ +/* for (j = 0; j < suggest->size; j++) { */ +/* for (i = 0; i < templ_context->size; i++) { */ +/* if (!strcmp (templ_context->column_names[i], suggest->column_names[j])) { */ + /* same column name, now check column value */ +/* if (G_VALUE_TYPE (templ_context->column_values[i]) != */ +/* G_VALUE_TYPE (suggest->column_values[j])) { */ +/* g_warning ("Internal error: column types mismatch for GdaMetaContext " */ +/* "table '%s' and column '%s' (%s/%s)", */ +/* templ_context->table_name, templ_context->column_names[i], */ +/* g_type_name (G_VALUE_TYPE (templ_context->column_values[i])), */ +/* g_type_name (G_VALUE_TYPE (suggest->column_values[j]))); */ +/* return NULL; */ +/* } */ +/* if (gda_value_compare (templ_context->column_values[i], suggest->column_values[j])) */ + /* different values */ +/* return NULL; */ +/* break; */ +/* } */ +/* } */ +/* } */ + + /* @templ_context may contain some more columns => add them to @loc_suggest */ +/* for (i = 0; i < templ_context->size; i++) { */ +/* for (j = 0; j < suggest->size; j++) { */ +/* if (!strcmp (templ_context->column_names[i], suggest->column_names[j])) { */ +/* j = -1; */ +/* break; */ +/* } */ +/* } */ +/* if (j >= 0) { */ +/* if (loc_suggest.size >= MAX_CONTEXT_SIZE) { */ +/* g_warning ("Internal limitation at %s(), limitation should be at least %d, please report a bug", */ +/* __FUNCTION__, loc_suggest.size + 1); */ +/* return NULL; */ +/* } */ +/* loc_suggest.column_names [loc_suggest.size] = templ_context->column_names [i]; */ +/* loc_suggest.column_values [loc_suggest.size] = templ_context->column_values [i]; */ +/* loc_suggest.size ++; */ +/* } */ +/* } */ + +/* suggest = &loc_suggest; */ +/* } */ + +/* GError *lerror = NULL; */ +/* if (!local_meta_update (data->prov, data->cnc, suggest, &lerror)) { */ +/* if (lerror) */ +/* data->error = lerror; */ +/* else { */ +/* g_set_error (&lerror,GDA_CONNECTION_ERROR, */ +/* GDA_CONNECTION_META_DATA_CONTEXT_ERROR, */ +/* "%s", _("Meta update error")); */ +/* data->error = lerror; */ +/* } */ + +/* return data->error; */ +/* } */ + +/* return NULL; */ +/* } */ + +/** + * gda_connection_update_meta_store: + * @cnc: a #GdaConnection object. + * @context: (nullable): description of which part of @cnc's associated #GdaMetaStore should be updated, or %NULL + * @error: a place to store errors, or %NULL + * + * Updates @cnc's associated #GdaMetaStore. If @context is not %NULL, then only the parts described by + * @context will be updated, and if it is %NULL, then the complete meta store will be updated. Detailed + * explanations follow: + * + * In order to keep the meta store's contents in a consistent state, the update process involves updating + * the contents of all the tables related to one where the contents change. For example the "_columns" + * table (which lists all the columns of a table) depends on the "_tables" table (which lists all the tables + * in a schema), so if a row is added, removed or modified in the "_tables", then the "_columns" table's contents + * needs to be updated as well regarding that row. + * + * If @context is %NULL, then the update process will simply overwrite any data that was present in all the + * meta store's tables with new (up to date) data even if nothing has changed, without having to build the + * tables' dependency tree. This is the recommended way of proceeding when dealing with a meta store which + * might be outdated. + * + * On the other hand, if @context is not %NULL, then a tree of the dependencies has to be built (depending on + * @context) and only some parts of the meta store are updated following that dependencies tree. Specifying a + * context may be useful for example in the following situations: + * + * One knows that a database object has changed (for example a table created), and + * may use the @context to request that only the information about that table be updated + * + * One is only interested in the list of views, and may request that only the information + * about views may be updated + * + * + * When @context is not %NULL, and contains specified SQL identifiers (for example the "table_name" of the "_tables" + * table), then each SQL identifier has to match the convention the #GdaMetaStore has adopted regarding + * case sensitivity, using gda_connection_quote_sql_identifier() or gda_meta_store_sql_identifier_quote(). + * + * see the + * meta data section about SQL identifiers for more information, and the documentation about the + * gda_sql_identifier_quote() function which will be most useful. + * + * Note however that usually more information will be updated than strictly requested by + * the @context argument. + * + * For more information, see the Database structure section, and + * the Update the meta data about a table howto. + * + * Returns: TRUE if no error occurred + */ +gboolean +gda_connection_update_meta_store (GdaConnection *cnc, GdaMetaContext *context, GError **error) +{ + GdaMetaStore *store; + + g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE); + GdaConnectionPrivate *priv = gda_connection_get_instance_private (cnc); + g_return_val_if_fail (priv->provider_obj, FALSE); + + if (! gda_connection_is_opened (cnc)) { + g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_CLOSED_ERROR, + "%s", _("Connection is closed")); + return FALSE; + } + gda_connection_lock ((GdaLockable*) cnc); + + /* Get or create the GdaMetaStore object */ + store = gda_connection_get_meta_store (cnc); + g_assert (store); + + guint real_slowdown = priv->exec_slowdown; + if (real_slowdown > 0) { + /* we don't honor the exec slowdown during meta data updates, it would complicate + * the code quite a lot (slowdown is done in the worker thread) and it's only + * for debug purposes */ + priv->exec_slowdown = 0; + } + + gda_connection_increase_usage (cnc); /* USAGE ++ */ + + if (context) { + GdaMetaContext *lcontext; + GSList *list; + GSList *up_templates; + GSList *dn_templates; + GError *lerror = NULL; + + lcontext = _gda_meta_store_validate_context (store, context, error); + if (!lcontext) { + gda_connection_decrease_usage (cnc); /* USAGE -- */ + gda_connection_unlock ((GdaLockable*) cnc); + priv->exec_slowdown = real_slowdown; + return FALSE; + } + /* alter local context because "_tables" and "_views" always go together so only + "_tables" should be updated and providers should always update "_tables" and "_views" + */ + if (!strcmp (lcontext->table_name, "_views")) + lcontext->table_name = "_tables"; + + /* build context templates */ + up_templates = build_upstream_context_templates (store, lcontext, NULL, &lerror); + if (!up_templates) { + if (lerror) { + gda_connection_decrease_usage (cnc); /* USAGE -- */ + gda_connection_unlock ((GdaLockable*) cnc); + g_propagate_error (error, lerror); + priv->exec_slowdown = real_slowdown; + return FALSE; + } + } + dn_templates = build_downstream_context_templates (store, lcontext, NULL, &lerror); + if (!dn_templates) { + if (lerror) { + gda_connection_decrease_usage (cnc); /* USAGE -- */ + gda_connection_unlock ((GdaLockable*) cnc); + g_propagate_error (error, lerror); + priv->exec_slowdown = real_slowdown; + return FALSE; + } + } + +#ifdef GDA_DEBUG_META_STORE_UPDATE + g_print ("\n*********** TEMPLATES:\n"); + for (list = up_templates; list; list = list->next) { + g_print ("UP: "); + meta_context_dump ((GdaMetaContext*) list->data); + } + g_print ("->: "); + meta_context_dump (lcontext); + for (list = dn_templates; list; list = list->next) { + g_print ("DN: "); + meta_context_dump ((GdaMetaContext*) list->data); + } +#endif + + DownstreamCallbackData cbd; + gboolean retval = TRUE; + + cbd.prov = priv->provider_obj; + cbd.cnc = cnc; + cbd.error = NULL; + cbd.context_templates = g_slist_concat (g_slist_append (up_templates, lcontext), dn_templates); + cbd.context_templates_hash = g_hash_table_new (g_str_hash, g_str_equal); + retval = local_meta_update (priv->provider_obj, cnc, + lcontext, error); + if (retval) { + for (list = cbd.context_templates; list; list = list->next) { + retval = local_meta_update (priv->provider_obj, cnc, + (GdaMetaContext*) (list->data), error); + if (!retval) { + break; + } + } + } + + /* free the memory associated with each template */ + for (list = cbd.context_templates; list; list = list->next) { + GdaMetaContext *c = (GdaMetaContext *) list->data; + if (c == lcontext) { + gint i; + for (i = 0; i < c->size; i++) { + g_free (c->column_names [i]); + if (c->column_values [i]) + gda_value_free (c->column_values [i]); + } + } + if (c->size > 0) { + g_free (c->column_names); + g_free (c->column_values); + } + g_free (c); + } + g_slist_free (cbd.context_templates); + g_hash_table_destroy (cbd.context_templates_hash); + + gda_connection_decrease_usage (cnc); /* USAGE -- */ + gda_connection_unlock ((GdaLockable*) cnc); + priv->exec_slowdown = real_slowdown; + return retval; + } + else { + typedef struct { + gchar *table_name; + gchar *func_name; + GdaServerProviderMetaType func_type; + } RMeta; + + GdaMetaContext lcontext; + gint nb = 0, i; + RMeta rmeta[] = { + {"_information_schema_catalog_name", "_info", GDA_SERVER_META__INFO}, + {"_builtin_data_types", "_btypes", GDA_SERVER_META__BTYPES}, + {"_udt", "_udt", GDA_SERVER_META__UDT}, + {"_udt_columns", "_udt_cols", GDA_SERVER_META__UDT_COLS}, + {"_enums", "_enums", GDA_SERVER_META__ENUMS}, + {"_domains", "_domains", GDA_SERVER_META__DOMAINS}, + {"_domain_constraints", "_constraints_dom", GDA_SERVER_META__CONSTRAINTS_DOM}, + {"_element_types", "_el_types", GDA_SERVER_META__EL_TYPES}, + {"_collations", "_collations", GDA_SERVER_META__COLLATIONS}, + {"_character_sets", "_character_sets", GDA_SERVER_META__CHARACTER_SETS}, + {"_schemata", "_schemata", GDA_SERVER_META__SCHEMATA}, + {"_tables_views", "_tables_views", GDA_SERVER_META__TABLES_VIEWS}, + {"_columns", "_columns", GDA_SERVER_META__COLUMNS}, + {"_view_column_usage", "_view_cols", GDA_SERVER_META__VIEW_COLS}, + {"_table_constraints", "_constraints_tab", GDA_SERVER_META__CONSTRAINTS_TAB}, + {"_referential_constraints", "_constraints_ref", GDA_SERVER_META__CONSTRAINTS_REF}, + {"_key_column_usage", "_key_columns", GDA_SERVER_META__KEY_COLUMNS}, + {"_check_column_usage", "_check_columns", GDA_SERVER_META__CHECK_COLUMNS}, + {"_triggers", "_triggers", GDA_SERVER_META__TRIGGERS}, + {"_routines", "_routines", GDA_SERVER_META__ROUTINES}, + {"_routine_columns", "_routine_col", GDA_SERVER_META__ROUTINE_COL}, + {"_parameters", "_routine_par", GDA_SERVER_META__ROUTINE_PAR}, + {"_table_indexes", "_indexes_tab", GDA_SERVER_META__INDEXES_TAB}, + {"_index_column_usage", "_index_cols", GDA_SERVER_META__INDEX_COLS} + }; + GdaServerProvider *provider = priv->provider_obj; + gboolean retval; + + if (! _gda_meta_store_begin_data_reset (store, error)) { + gda_connection_decrease_usage (cnc); /* USAGE -- */ + gda_connection_unlock ((GdaLockable*) cnc); + priv->exec_slowdown = real_slowdown; + return FALSE; + } + + lcontext.size = 0; + nb = sizeof (rmeta) / sizeof (RMeta); + for (i = 0; i < nb; i++) { + /*g_print ("%s() %s(cnc=>%p store=>%p)\n", __FUNCTION__, rmeta [i].func_name, cnc, store);*/ + lcontext.table_name = rmeta [i].table_name; + if (! _gda_server_provider_meta_0arg (provider, cnc, store, &lcontext, + rmeta[i].func_type, error)) { + /* + g_print ("%s() %p CNC %p ERROR, prov=%p (%s)\n", __FUNCTION__, cnc, + gda_connection_get_provider (cnc), + gda_connection_get_provider_name (cnc)); + */ + /*if (error && *error) + g_warning ("%s (Provider %s)\n", (*error)->message, + gda_connection_get_provider_name (cnc)); + */ + + WARN_META_UPDATE_FAILURE (FALSE, rmeta [i].func_name); + goto onerror; + } + } + retval = _gda_meta_store_finish_data_reset (store, error); + gda_connection_decrease_usage (cnc); /* USAGE -- */ + gda_connection_unlock ((GdaLockable*) cnc); + priv->exec_slowdown = real_slowdown; + return retval; + + onerror: + gda_connection_decrease_usage (cnc); /* USAGE -- */ + gda_connection_unlock ((GdaLockable*) cnc); + _gda_meta_store_cancel_data_reset (store, NULL); + priv->exec_slowdown = real_slowdown; + return FALSE; + } +} + +/** + * gda_connection_get_meta_store_data: (skip) + * @cnc: a #GdaConnection object. + * @meta_type: describes which data to get. + * @error: a place to store errors, or %NULL + * @nb_filters: the number of filters in the @... argument + * @...: a list of (filter name (gchar *), filter value (GValue*)) pairs specifying + * the filter to apply to the returned data model's contents (there must be @nb_filters pairs) + * + * Retrieves data stored in @cnc's associated #GdaMetaStore object. This method is useful + * to easily get some information about the meta-data associated to @cnc, such as the list of + * tables, views, and other database objects. + * + * Note: it's up to the caller to make sure the information contained within @cnc's associated #GdaMetaStore + * is up to date using gda_connection_update_meta_store() (it can become outdated if the database's schema + * is modified). + * + * For more information about the returned data model's attributes, or about the @meta_type and ... filter arguments, + * see this description. + * + * Also, when using filters involving data which are SQL identifiers, make sure each SQL identifier + * is represented using the #GdaMetaStore convention, using gda_meta_store_sql_identifier_quote() or + * gda_meta_store_sql_identifier_quote(). + * + * See the + * meta data section about SQL identifiers for more information, and the documentation about the + * gda_sql_identifier_quote() function which will be most useful. + * + * Returns: (transfer full): a #GdaDataModel containing the data required. The caller is responsible + * for freeing the returned model using g_object_unref(). + */ +GdaDataModel * +gda_connection_get_meta_store_data (GdaConnection *cnc, + GdaConnectionMetaType meta_type, + GError **error, gint nb_filters, ...) +{ + g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL); + + GList* filters = NULL; + GdaDataModel* model = NULL; + gint i; + + if (! gda_connection_is_opened (cnc)) { + g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_CLOSED_ERROR, + "%s", _("Connection is closed")); + return NULL; + } + + if (nb_filters > 0) { + va_list ap; + va_start (ap, nb_filters); + for (i = 0; (i < nb_filters); i++) { + GdaHolder *h; + GValue *v; + gchar* fname; + GError *lerror = NULL; + + fname = va_arg (ap, gchar*); + if (!fname) + break; + v = va_arg (ap, GValue*); + if (!v || gda_value_is_null (v)) + continue; + h = g_object_new (GDA_TYPE_HOLDER, "g-type", G_VALUE_TYPE (v), "id", fname, NULL); + filters = g_list_append (filters, h); + if (!gda_holder_set_value (h, v, &lerror)) { + g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_META_DATA_CONTEXT_ERROR, + _("While extracting data from Data Store: %s"), + lerror && lerror->message ? lerror->message : "No error message was set"); + g_clear_error (&lerror); + va_end (ap); + goto onerror; + } + } + va_end (ap); + } + model = gda_connection_get_meta_store_data_v (cnc, meta_type, filters, error); + + onerror: + g_list_free_full (filters, (GDestroyNotify) g_object_unref); + + return model; +} + +/** + * gda_connection_get_meta_store_data_v: (rename-to gda_connection_get_meta_store_data) + * @cnc: a #GdaConnection object. + * @meta_type: describes which data to get. + * @error: a place to store errors, or %NULL + * @filters: (element-type GdaHolder): a #GList of #GdaHolder objects + * + * see #gda_connection_get_meta_store_data + * + * Returns: (transfer full): a #GdaDataModel containing the data required. The caller is responsible + * for freeing the returned model using g_object_unref(). + */ +GdaDataModel * +gda_connection_get_meta_store_data_v (GdaConnection *cnc, GdaConnectionMetaType meta_type, + GList* filters, GError **error) +{ + GdaMetaStore *store; + GdaDataModel *model = NULL; + GdaStatement *stmt = NULL; + GdaSet *set = NULL; + GdaSqlParser *parser; + GList* node; + gchar *sql = NULL; + gboolean fail = FALSE; + GError *lerror = NULL; + gint nparams = 0; + + g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL); + GdaConnectionPrivate *priv = gda_connection_get_instance_private (cnc); + g_return_val_if_fail (priv->provider_obj, NULL); + + if (! gda_connection_is_opened (cnc)) { + g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_CLOSED_ERROR, + "%s", _("Connection is closed")); + return FALSE; + } + + /* Get or create the GdaMetaStore object */ + store = gda_connection_get_meta_store (cnc); + if (store == NULL) { + g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_INTERNAL_ERROR, + _("Internal error: No meta store in connection")); + return NULL; + } + set = GDA_SET (g_object_new (GDA_TYPE_SET, NULL)); + for (node = filters; + node; + node = node->next) { + gda_set_add_holder (set, GDA_HOLDER (node->data)); + nparams++; + } + + switch (meta_type) { + case GDA_CONNECTION_META_NAMESPACES: + sql = "SELECT schema_name, schema_owner, schema_internal FROM _schemata"; + if (nparams > 0) { + sql = "SELECT schema_name, schema_owner, schema_internal FROM _schemata WHERE schema_name=##name::string"; + if (gda_set_get_holder (set, "name") == NULL) { + g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_MISSING_PARAM_ERROR, + _("Parameter 'name' is required to filter namespaces")); + fail = TRUE; + } + } + break; + case GDA_CONNECTION_META_TYPES: + sql = "SELECT short_type_name, gtype, comments, synonyms FROM _all_types WHERE NOT internal"; + if (nparams > 0) { + sql = "SELECT short_type_name, gtype, comments, synonyms FROM _all_types WHERE NOT internal AND short_type_name=##name::string"; + if (gda_set_get_holder (set, "name") == NULL) { + g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_MISSING_PARAM_ERROR, + _("Parameter 'name' is required to filter data types")); + fail = TRUE; + } + } + break; + case GDA_CONNECTION_META_TABLES: + sql = "SELECT table_short_name, table_schema, table_full_name, table_owner, table_comments FROM _tables WHERE table_type LIKE '%TABLE%' AND table_short_name != table_full_name"; + if (nparams > 0) { + sql = "SELECT table_short_name, table_schema, table_full_name, table_owner, table_comments FROM _tables WHERE table_type LIKE '%TABLE%' AND table_short_name != table_full_name AND table_short_name=##name::string"; + if (gda_set_get_holder (set, "name") == NULL) { + g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_MISSING_PARAM_ERROR, + _("Parameter 'name' is required to filter tables")); + fail = TRUE; + } + } + break; + case GDA_CONNECTION_META_VIEWS: + sql = "SELECT t.table_short_name, t.table_schema, t.table_full_name, t.table_owner, t.table_comments, v.view_definition FROM _views as v NATURAL JOIN _tables as t WHERE t.table_short_name != t.table_full_name"; + if (nparams > 0) { + sql = "SELECT t.table_short_name, t.table_schema, t.table_full_name, t.table_owner, t.table_comments, v.view_definition FROM _views as v NATURAL JOIN _tables as t WHERE t.table_short_name != t.table_full_name AND table_short_name=##name::string"; + if (gda_set_get_holder (set, "name") == NULL) { + g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_MISSING_PARAM_ERROR, + _("Parameter 'name' is required to filter views")); + fail = TRUE; + } + } + break; + case GDA_CONNECTION_META_FIELDS: + if (nparams > 0) { + sql = "SELECT c.column_name, c.data_type, c.gtype, c.numeric_precision, c.numeric_scale, c.is_nullable AS 'Nullable', c.column_default, c.extra FROM _columns as c NATURAL JOIN _tables as t WHERE t.table_short_name=##name::string ORDER BY c.ordinal_position"; + if (gda_set_get_holder (set, "name") == NULL) { + g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_MISSING_PARAM_ERROR, + _("Parameter 'name' is required to filter fields")); + fail = TRUE; + } else if (nparams > 1) { + sql = "SELECT c.column_name, c.data_type, c.gtype, c.numeric_precision, c.numeric_scale, c.is_nullable AS 'Nullable', c.column_default, c.extra FROM _columns as c NATURAL JOIN _tables as t WHERE t.table_short_name=##name::string AND c.column_name = ##field_name::string ORDER BY c.ordinal_position"; + if (gda_set_get_holder (set, "field_name") == NULL) { + g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_MISSING_PARAM_ERROR, + _("Parameter 'field_name' is required to filter fields")); + fail = TRUE; + } + } + } else { + sql = ""; + g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_MISSING_PARAM_ERROR, + _("Parameters: 'name' and/or 'field_name' are required to filter fields")); + fail = TRUE; + } + break; + case GDA_CONNECTION_META_INDEXES: + if (nparams > 0) { + sql = "SELECT i.table_name, i.table_schema, i.index_name, d.column_name, d.ordinal_position, i.index_type FROM _table_indexes as i INNER JOIN _index_column_usage as d ON (d.table_catalog = i.table_catalog AND d.table_schema = i.table_schema AND d.table_name = i.table_name) INNER JOIN _tables t ON (t.table_catalog = i.table_catalog AND t.table_schema = i.table_schema AND t.table_name = i.table_name) WHERE t.table_short_name=##name::string"; + if (gda_set_get_holder (set, "name") == NULL) { + g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_MISSING_PARAM_ERROR, + _("Parameter 'name' is required to filter indexes")); + fail = TRUE; + } else if (nparams > 1) { + sql = "SELECT i.table_name, i.table_schema, i.index_name, d.column_name, d.ordinal_position, i.index_type FROM _table_indexes as i INNER JOIN _index_column_usage as d ON (d.table_catalog = i.table_catalog AND d.table_schema = i.table_schema AND d.table_name = i.table_name) INNER JOIN _tables t ON (t.table_catalog = i.table_catalog AND t.table_schema = i.table_schema AND t.table_name = i.table_name) WHERE t.table_short_name=##name::string AND i.index_name=##index_name::string"; + if (gda_set_get_holder (set, "index_name") == NULL) { + g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_MISSING_PARAM_ERROR, + _("Parameter 'index_name' is required to filter indexes")); + fail = TRUE; + } + } + } else { + sql = ""; + g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_MISSING_PARAM_ERROR, + _("Parameters: 'name' and/or 'index_name' are required to filter indexes")); + fail = TRUE; + } + + if (nparams > 0) { + + if (gda_set_get_holder (set, "name") == NULL) { + g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_MISSING_PARAM_ERROR, + _("Parameter 'name' is required to filter indexes")); + fail = TRUE; + } else if (gda_set_get_holder (set, "field_name") == NULL) { + g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_MISSING_PARAM_ERROR, + _("Parameter 'index_name' is required to filter indexes")); + fail = TRUE; + } + } + break; + } + if (sql == NULL) { + g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_INTERNAL_ERROR, + _("Invalid meta type to get data from store")); + fail = TRUE; + } + if (fail) { + return NULL; + } + parser = gda_sql_parser_new (); + stmt = gda_sql_parser_parse_string (parser, sql, NULL, error); + g_object_unref (parser); + if (stmt == NULL) { + g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_INTERNAL_ERROR, + _("Internal error while creating statement to retrieve data: %s"), + lerror && lerror->message ? lerror->message : "No internal error reported; please file an issue to https://gitlab.gnome.org/GNOME/libgda/issues"); + g_clear_error (&lerror); + return NULL; + } + + /* execute statement to fetch the requested result from the meta store's connection + * REM: at a latter time the data model should be specific and update itself whenever + * the meta store is updated + */ + model = gda_connection_statement_execute_select (gda_meta_store_get_internal_connection (store), + stmt, set, error); + if (set) + g_object_unref (set); + + return model; +} + + +/** + * gda_connection_get_events: + * @cnc: a #GdaConnection. + * + * Retrieves a list of the last errors occurred during the connection. The returned list is + * chronologically ordered such as that the most recent event is the #GdaConnectionEvent of the first node. + * + * Warning: the @cnc object may change the list if connection events occur + * + * Returns: (transfer none) (element-type Gda.ConnectionEvent): a #GList of #GdaConnectionEvent objects (the list should not be modified) + */ +const GList * +gda_connection_get_events (GdaConnection *cnc) +{ + g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL); + GdaConnectionPrivate *priv = gda_connection_get_instance_private (cnc); + + if (priv->events_list) + return priv->events_list; + + + /* a new list of the GdaConnectionEvent objects is created, the + * ownership of each GdaConnectionEvent object is transfered to the list */ + GList *list = NULL; + if (priv->events_array_full) { + gint i; + for (i = priv->events_array_next + 1; ; i++) { + if (i == priv->events_array_size) + i = 0; + if (i == priv->events_array_next) + break; + GdaConnectionEvent *ev; + ev = priv->events_array [i]; + priv->events_array [i] = NULL; + g_assert (ev); + list = g_list_prepend (list, ev); + } + } + else { + gint i; + for (i = 0; i < priv->events_array_next; i++) { + GdaConnectionEvent *ev; + ev = priv->events_array [i]; + g_assert (ev); + list = g_list_prepend (list, ev); + priv->events_array [i] = NULL; + } + } + priv->events_list = g_list_reverse (list); + + /* reset events */ + priv->events_array_full = FALSE; + priv->events_array_next = 0; + + return priv->events_list; +} + +/** + * gda_connection_value_to_sql_string: + * @cnc: a #GdaConnection object. + * @from: #GValue to convert from + * + * Produces a fully quoted and escaped string from a GValue + * + * Returns: escaped and quoted value or NULL if not supported. + */ +gchar * +gda_connection_value_to_sql_string (GdaConnection *cnc, GValue *from) +{ + g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE); + g_return_val_if_fail (from != NULL, FALSE); + GdaConnectionPrivate *priv = gda_connection_get_instance_private (cnc); + g_return_val_if_fail (priv->provider_obj, FALSE); + + /* execute the command on the provider */ + return gda_server_provider_value_to_sql_string (priv->provider_obj, cnc, from); +} + +/** + * gda_connection_internal_transaction_started: + * @cnc: a #GdaConnection + * @parent_trans: (nullable): name of the parent transaction, or %NULL + * @trans_name: transaction's name, or %NULL + * @isol_level: isolation level. + * + * Internal functions to be called by database providers when a transaction has been started + * to keep track of the transaction status of the connection. + * + * Note: this function should not be called if gda_connection_internal_statement_executed() + * has already been called because a statement's execution was necessary to perform + * the action. + */ +void +gda_connection_internal_transaction_started (GdaConnection *cnc, const gchar *parent_trans, const gchar *trans_name, + GdaTransactionIsolation isol_level) +{ + GdaTransactionStatus *parent, *st; + + g_return_if_fail (GDA_IS_CONNECTION (cnc)); + GdaConnectionPrivate *priv = gda_connection_get_instance_private (cnc); + + st = gda_transaction_status_new (trans_name); + gda_transaction_status_set_isolation_level (st, isol_level); + + gda_connection_lock ((GdaLockable*) cnc); + + parent = gda_transaction_status_find (priv->trans_status, parent_trans, NULL); + if (!parent) + priv->trans_status = st; + else { + gda_transaction_status_add_event_sub (parent, st); + g_object_unref (st); + } +#ifdef GDA_DEBUG_signal + g_print (">> 'TRANSACTION_STATUS_CHANGED' from %s\n", __FUNCTION__); +#endif + g_signal_emit (G_OBJECT (cnc), gda_connection_signals[TRANSACTION_STATUS_CHANGED], 0); +#ifdef GDA_DEBUG_signal + g_print ("<< 'TRANSACTION_STATUS_CHANGED' from %s\n", __FUNCTION__); +#endif + +#ifdef GDA_DEBUG_NO + if (priv->trans_status) + gda_transaction_status_dump (priv->trans_status, 5); +#endif + + gda_connection_unlock ((GdaLockable*) cnc); +} + +/** + * gda_connection_internal_transaction_rolledback: + * @cnc: a #GdaConnection + * @trans_name: (nullable): transaction's name, or %NULL + * + * Internal functions to be called by database providers when a transaction has been rolled + * back to keep track of the transaction status of the connection + * + * Note: this function should not be called if gda_connection_internal_statement_executed() + * has already been called because a statement's execution was necessary to perform + * the action. + */ +void +gda_connection_internal_transaction_rolledback (GdaConnection *cnc, const gchar *trans_name) +{ + GdaTransactionStatus *st = NULL; + GdaTransactionStatusEvent *ev = NULL; + + g_return_if_fail (GDA_IS_CONNECTION (cnc)); + GdaConnectionPrivate *priv = gda_connection_get_instance_private (cnc); + + gda_connection_lock ((GdaLockable*) cnc); + + if (priv->trans_status) + st = gda_transaction_status_find (priv->trans_status, trans_name, &ev); + if (st) { + if (ev) { + /* there is a parent transaction */ + gda_transaction_status_free_events (ev->trans, ev, TRUE); + } + else { + /* no parent transaction */ + g_object_unref (priv->trans_status); + priv->trans_status = NULL; + } +#ifdef GDA_DEBUG_signal + g_print (">> 'TRANSACTION_STATUS_CHANGED' from %s\n", __FUNCTION__); +#endif + g_signal_emit (G_OBJECT (cnc), gda_connection_signals[TRANSACTION_STATUS_CHANGED], 0); +#ifdef GDA_DEBUG_signal + g_print ("<< 'TRANSACTION_STATUS_CHANGED' from %s\n", __FUNCTION__); +#endif + } + else { + g_warning (_("Connection transaction status tracking: no transaction exists for %s"), "ROLLBACK"); + } +#ifdef GDA_DEBUG_NO + if (priv->trans_status) + gda_transaction_status_dump (priv->trans_status, 5); +#endif + + gda_connection_unlock ((GdaLockable*) cnc); +} + +/** + * gda_connection_internal_transaction_committed: + * @cnc: a #GdaConnection + * @trans_name: (nullable): transaction's name, or %NULL + * + * Internal functions to be called by database providers when a transaction has been committed + * to keep track of the transaction status of the connection + * + * Note: this function should not be called if gda_connection_internal_statement_executed() + * has already been called because a statement's execution was necessary to perform + * the action. + */ +void +gda_connection_internal_transaction_committed (GdaConnection *cnc, const gchar *trans_name) +{ + GdaTransactionStatus *st = NULL; + GdaTransactionStatusEvent *ev = NULL; + + g_return_if_fail (GDA_IS_CONNECTION (cnc)); + GdaConnectionPrivate *priv = gda_connection_get_instance_private (cnc); + + gda_connection_lock ((GdaLockable*) cnc); + + if (priv->trans_status) + st = gda_transaction_status_find (priv->trans_status, trans_name, &ev); + if (st) { + if (ev) { + /* there is a parent transaction */ + gda_transaction_status_free_events (ev->trans, ev, TRUE); + } + else { + /* no parent transaction */ + g_object_unref (priv->trans_status); + priv->trans_status = NULL; + } +#ifdef GDA_DEBUG_signal + g_print (">> 'TRANSACTION_STATUS_CHANGED' from %s\n", __FUNCTION__); +#endif + g_signal_emit (G_OBJECT (cnc), gda_connection_signals[TRANSACTION_STATUS_CHANGED], 0); +#ifdef GDA_DEBUG_signal + g_print ("<< 'TRANSACTION_STATUS_CHANGED' from %s\n", __FUNCTION__); +#endif + } + else { + g_warning (_("Connection transaction status tracking: no transaction exists for %s"), "COMMIT"); + } +#ifdef GDA_DEBUG_NO + if (priv->trans_status) + gda_transaction_status_dump (priv->trans_status, 5); +#endif + + gda_connection_unlock ((GdaLockable*) cnc); +} + +/** + * gda_connection_internal_savepoint_added: + * @cnc: a #GdaConnection + * @parent_trans: (nullable): name of the parent transaction, or %NULL + * @svp_name: savepoint's name, or %NULL + * + * Internal functions to be called by database providers when a savepoint has been added + * to keep track of the transaction status of the connection + * + * Note: this function should not be called if gda_connection_internal_statement_executed() + * has already been called because a statement's execution was necessary to perform + * the action. + */ +void +gda_connection_internal_savepoint_added (GdaConnection *cnc, const gchar *parent_trans, const gchar *svp_name) +{ + GdaTransactionStatus *st; + + g_return_if_fail (GDA_IS_CONNECTION (cnc)); + GdaConnectionPrivate *priv = gda_connection_get_instance_private (cnc); + + gda_connection_lock ((GdaLockable*) cnc); + + st = gda_transaction_status_find (priv->trans_status, parent_trans, NULL); + if (st) { + gda_transaction_status_add_event_svp (st, svp_name); +#ifdef GDA_DEBUG_signal + g_print (">> 'TRANSACTION_STATUS_CHANGED' from %s\n", __FUNCTION__); +#endif + g_signal_emit (G_OBJECT (cnc), gda_connection_signals[TRANSACTION_STATUS_CHANGED], 0); +#ifdef GDA_DEBUG_signal + g_print ("<< 'TRANSACTION_STATUS_CHANGED' from %s\n", __FUNCTION__); +#endif + } + else { + g_warning (_("Connection transaction status tracking: no transaction exists for %s"), "ADD SAVEPOINT"); + } +#ifdef GDA_DEBUG_NO + if (priv->trans_status) + gda_transaction_status_dump (priv->trans_status, 5); +#endif + + gda_connection_unlock ((GdaLockable*) cnc); +} + +/** + * gda_connection_internal_savepoint_rolledback: + * @cnc: a #GdaConnection + * @svp_name: (nullable): savepoint's name, or %NULL + * + * Internal functions to be called by database providers when a savepoint has been rolled back + * to keep track of the transaction status of the connection + * + * Note: this function should not be called if gda_connection_internal_statement_executed() + * has already been called because a statement's execution was necessary to perform + * the action. + */ +void +gda_connection_internal_savepoint_rolledback (GdaConnection *cnc, const gchar *svp_name) +{ + GdaTransactionStatus *st; + GdaTransactionStatusEvent *ev = NULL; + + g_return_if_fail (GDA_IS_CONNECTION (cnc)); + GdaConnectionPrivate *priv = gda_connection_get_instance_private (cnc); + + gda_connection_lock ((GdaLockable*) cnc); + + st = gda_transaction_status_find (priv->trans_status, svp_name, &ev); + if (st) { + gda_transaction_status_free_events (st, ev, TRUE); +#ifdef GDA_DEBUG_signal + g_print (">> 'TRANSACTION_STATUS_CHANGED' from %s\n", __FUNCTION__); +#endif + g_signal_emit (G_OBJECT (cnc), gda_connection_signals[TRANSACTION_STATUS_CHANGED], 0); +#ifdef GDA_DEBUG_signal + g_print ("<< 'TRANSACTION_STATUS_CHANGED' from %s\n", __FUNCTION__); +#endif + } + else { + g_warning (_("Connection transaction status tracking: no transaction exists for %s"), "ROLLBACK SAVEPOINT"); + } +#ifdef GDA_DEBUG_NO + if (priv->trans_status) + gda_transaction_status_dump (priv->trans_status, 5); +#endif + + gda_connection_unlock ((GdaLockable*) cnc); +} + +/** + * gda_connection_internal_savepoint_removed: + * @cnc: a #GdaConnection + * @svp_name: (nullable): savepoint's name, or %NULL + * + * Internal functions to be called by database providers when a savepoint has been removed + * to keep track of the transaction status of the connection + * + * Note: this function should not be called if gda_connection_internal_statement_executed() + * has already been called because a statement's execution was necessary to perform + * the action. + */ +void +gda_connection_internal_savepoint_removed (GdaConnection *cnc, const gchar *svp_name) +{ + GdaTransactionStatus *st; + GdaTransactionStatusEvent *ev = NULL; + + g_return_if_fail (GDA_IS_CONNECTION (cnc)); + GdaConnectionPrivate *priv = gda_connection_get_instance_private (cnc); + + gda_connection_lock ((GdaLockable*) cnc); + + st = gda_transaction_status_find (priv->trans_status, svp_name, &ev); + if (st) { + gda_transaction_status_free_events (st, ev, FALSE); +#ifdef GDA_DEBUG_signal + g_print (">> 'TRANSACTION_STATUS_CHANGED' from %s\n", __FUNCTION__); +#endif + g_signal_emit (G_OBJECT (cnc), gda_connection_signals[TRANSACTION_STATUS_CHANGED], 0); +#ifdef GDA_DEBUG_signal + g_print ("<< 'TRANSACTION_STATUS_CHANGED' from %s\n", __FUNCTION__); +#endif + } + else { + g_warning (_("Connection transaction status tracking: no transaction exists for %s"), "REMOVE SAVEPOINT"); + } +#ifdef GDA_DEBUG_NO + if (priv->trans_status) + gda_transaction_status_dump (priv->trans_status, 5); +#endif + + gda_connection_unlock ((GdaLockable*) cnc); +} + +/** + * gda_connection_internal_statement_executed: + * @cnc: a #GdaConnection + * @stmt: a #GdaStatement which has been executed + * @params: (nullable): execution's parameters + * @error: (transfer none): a #GdaConnectionEvent if the execution failed, or %NULL + * + * Internal functions to be called by database providers when a statement has been executed + * to keep track of the transaction status of the connection + */ +void +gda_connection_internal_statement_executed (GdaConnection *cnc, GdaStatement *stmt, + G_GNUC_UNUSED GdaSet *params, GdaConnectionEvent *error) +{ + g_return_if_fail (GDA_IS_CONNECTION (cnc)); + GdaConnectionPrivate *priv = gda_connection_get_instance_private (cnc); + if (!error || (error && (gda_connection_event_get_event_type (error) != GDA_CONNECTION_EVENT_ERROR))) { + const GdaSqlStatement *sqlst; + GdaSqlStatementTransaction *trans; + sqlst = _gda_statement_get_internal_struct (stmt); + trans = (GdaSqlStatementTransaction*) sqlst->contents; /* warning: this may be inaccurate if stmt_type is not + a transaction type, but the compiler does not care */ + + switch (sqlst->stmt_type) { + case GDA_SQL_STATEMENT_BEGIN: + gda_connection_internal_transaction_started (cnc, NULL, trans->trans_name, + trans->isolation_level); + break; + case GDA_SQL_STATEMENT_ROLLBACK: + gda_connection_internal_transaction_rolledback (cnc, trans->trans_name); + break; + case GDA_SQL_STATEMENT_COMMIT: + gda_connection_internal_transaction_committed (cnc, trans->trans_name); + break; + case GDA_SQL_STATEMENT_SAVEPOINT: + gda_connection_internal_savepoint_added (cnc, NULL, trans->trans_name); + break; + case GDA_SQL_STATEMENT_ROLLBACK_SAVEPOINT: + gda_connection_internal_savepoint_rolledback (cnc, trans->trans_name); + break; + case GDA_SQL_STATEMENT_DELETE_SAVEPOINT: + gda_connection_internal_savepoint_removed (cnc, trans->trans_name); + break; + default: { + GdaTransactionStatus *st = NULL; + + gda_connection_lock ((GdaLockable*) cnc); + + if (priv->trans_status) + st = gda_transaction_status_find_current (priv->trans_status, NULL, FALSE); + if (st) { + if (sqlst->sql) + gda_transaction_status_add_event_sql (st, sqlst->sql, error); + else { + gchar *sql; + sql = gda_statement_to_sql_extended (stmt, cnc, NULL, + GDA_STATEMENT_SQL_PARAMS_SHORT, + NULL, NULL); + gda_transaction_status_add_event_sql (st, sql, error); + g_free (sql); + } + } +#ifdef GDA_DEBUG_signal + g_print (">> 'TRANSACTION_STATUS_CHANGED' from %s\n", __FUNCTION__); +#endif + g_signal_emit (G_OBJECT (cnc), gda_connection_signals[TRANSACTION_STATUS_CHANGED], 0); +#ifdef GDA_DEBUG_signal + g_print ("<< 'TRANSACTION_STATUS_CHANGED' from %s\n", __FUNCTION__); +#endif +#ifdef GDA_DEBUG_NO + if (priv->trans_status) + gda_transaction_status_dump (priv->trans_status, 5); +#endif + gda_connection_unlock ((GdaLockable*) cnc); + break; + } + } + } +} + +/** + * gda_connection_internal_change_transaction_state: + * @cnc: a #GdaConnection + * @newstate: the new state + * + * Internal function to be called by database providers to force a transaction status + * change. + */ +void +gda_connection_internal_change_transaction_state (GdaConnection *cnc, + GdaTransactionStatusState newstate) +{ + g_return_if_fail (GDA_IS_CONNECTION (cnc)); + GdaConnectionPrivate *priv = gda_connection_get_instance_private (cnc); + + gda_connection_lock ((GdaLockable*) cnc); + + g_return_if_fail (priv->trans_status); + + if (gda_transaction_status_get_state (priv->trans_status) == newstate) + return; + + gda_transaction_status_set_state (priv->trans_status, newstate); +#ifdef GDA_DEBUG_signal + g_print (">> 'TRANSACTION_STATUS_CHANGED' from %s\n", __FUNCTION__); +#endif + g_signal_emit (G_OBJECT (cnc), gda_connection_signals[TRANSACTION_STATUS_CHANGED], 0); +#ifdef GDA_DEBUG_signal + g_print ("<< 'TRANSACTION_STATUS_CHANGED' from %s\n", __FUNCTION__); +#endif + gda_connection_unlock ((GdaLockable*) cnc); +} + +/** + * gda_connection_internal_reset_transaction_status: + * @cnc: a #GdaConnection + * + * Internal function to be called by database providers to reset the transaction status. + */ +void +gda_connection_internal_reset_transaction_status (GdaConnection *cnc) +{ + g_return_if_fail (GDA_IS_CONNECTION (cnc)); + GdaConnectionPrivate *priv = gda_connection_get_instance_private (cnc); + + gda_connection_lock ((GdaLockable*) cnc); + if (priv->trans_status) { + g_object_unref (priv->trans_status); + priv->trans_status = NULL; +#ifdef GDA_DEBUG_signal + g_print (">> 'TRANSACTION_STATUS_CHANGED' from %s\n", __FUNCTION__); +#endif + g_signal_emit (G_OBJECT (cnc), gda_connection_signals[TRANSACTION_STATUS_CHANGED], 0); +#ifdef GDA_DEBUG_signal + g_print ("<< 'TRANSACTION_STATUS_CHANGED' from %s\n", __FUNCTION__); +#endif + } + gda_connection_unlock ((GdaLockable*) cnc); +} + +/* + * Prepared statements handling + */ + +static void prepared_stmts_stmt_reset_cb (GdaStatement *gda_stmt, GdaConnection *cnc); + +static void +prepared_stmts_stmt_reset_cb (GdaStatement *gda_stmt, GdaConnection *cnc) +{ + g_return_if_fail (GDA_IS_CONNECTION (cnc)); + GdaConnectionPrivate *priv = gda_connection_get_instance_private (cnc); + gda_connection_lock ((GdaLockable*) cnc); + g_object_ref (gda_stmt); + + g_signal_handlers_disconnect_by_func (gda_stmt, G_CALLBACK (prepared_stmts_stmt_reset_cb), cnc); + g_assert (priv->prepared_stmts); + g_hash_table_remove (priv->prepared_stmts, gda_stmt); + g_object_unref (gda_stmt); + + gda_connection_unlock ((GdaLockable*) cnc); +} + +typedef struct { + GdaStatement *statement; + GdaPStmt *prepared_stmt; +} PreparedStatementRef; + +PreparedStatementRef* +_gda_prepared_estatement_new (GdaStatement *stmt, GdaPStmt *pstmt) { + PreparedStatementRef *nps = g_new0(PreparedStatementRef,1); + nps->statement = g_object_ref (stmt); + nps->prepared_stmt = g_object_ref (pstmt); + return nps; +} + +void +_gda_prepared_estatement_free (PreparedStatementRef *ps) { + g_object_unref (ps->statement); + g_object_unref (ps->prepared_stmt); + g_free (ps); +} + +/** + * gda_connection_add_prepared_statement: + * @cnc: a #GdaConnection object + * @gda_stmt: a #GdaStatement object + * @prepared_stmt: a prepared statement object (as a #GdaPStmt object, or more likely a descendant) + * + * Declares that @prepared_stmt is a prepared statement object associated to @gda_stmt within the connection + * (meaning the connection increments the reference counter of @prepared_stmt). + * + * If @gda_stmt changes or is destroyed, the the association will be lost and the connection will lose the + * reference it has on @prepared_stmt. + */ +void +gda_connection_add_prepared_statement (GdaConnection *cnc, GdaStatement *gda_stmt, GdaPStmt *prepared_stmt) +{ + g_return_if_fail (GDA_IS_CONNECTION (cnc)); + g_return_if_fail (GDA_IS_STATEMENT (gda_stmt)); + g_return_if_fail (GDA_IS_PSTMT (prepared_stmt)); + g_object_ref (prepared_stmt); + g_object_ref (gda_stmt); + + gda_connection_lock ((GdaLockable*) cnc); + GdaConnectionPrivate *priv = gda_connection_get_instance_private (cnc); + + if (!priv->prepared_stmts) + priv->prepared_stmts = g_hash_table_new_full (g_direct_hash, g_direct_equal, + NULL, (GDestroyNotify) _gda_prepared_estatement_free); + g_hash_table_remove (priv->prepared_stmts, gda_stmt); + PreparedStatementRef *ref = _gda_prepared_estatement_new (gda_stmt, prepared_stmt); + g_hash_table_insert (priv->prepared_stmts, gda_stmt, ref); + + g_signal_connect (G_OBJECT (gda_stmt), "reset", + G_CALLBACK (prepared_stmts_stmt_reset_cb), cnc); + + gda_connection_unlock ((GdaLockable*) cnc); + g_object_unref (prepared_stmt); + g_object_unref (gda_stmt); +} + +/** + * gda_connection_get_prepared_statement: + * @cnc: a #GdaConnection object + * @gda_stmt: a #GdaStatement object + * + * Retrieves a pointer to an object representing a prepared statement for @gda_stmt within @cnc. The + * association must have been done using gda_connection_add_prepared_statement(). + * + * Returns: (transfer none): the prepared statement, or %NULL if no association exists + */ +GdaPStmt * +gda_connection_get_prepared_statement (GdaConnection *cnc, GdaStatement *gda_stmt) +{ + GdaPStmt *retval = NULL; + + g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL); + GdaConnectionPrivate *priv = gda_connection_get_instance_private (cnc); + + gda_connection_lock ((GdaLockable*) cnc); + if (priv->prepared_stmts) { + PreparedStatementRef *ref = g_hash_table_lookup (priv->prepared_stmts, gda_stmt); + if (ref) + retval = ref->prepared_stmt; + } + gda_connection_unlock ((GdaLockable*) cnc); + + return retval; +} + +/** + * gda_connection_del_prepared_statement: + * @cnc: a #GdaConnection object + * @gda_stmt: a #GdaStatement object + * + * Removes any prepared statement associated to @gda_stmt in @cnc: this undoes what + * gda_connection_add_prepared_statement() does. + */ +void +gda_connection_del_prepared_statement (GdaConnection *cnc, GdaStatement *gda_stmt) +{ + g_return_if_fail (cnc != NULL); + + gda_connection_lock ((GdaLockable*) cnc); + GdaConnectionPrivate *priv = gda_connection_get_instance_private (cnc); + g_return_if_fail (GDA_IS_CONNECTION (cnc)); + g_object_ref (gda_stmt); + g_hash_table_remove (priv->prepared_stmts, gda_stmt); + g_object_unref (gda_stmt); + gda_connection_unlock ((GdaLockable*) cnc); +} + +/* + * Provider's specific connection data management + */ + +/** + * gda_connection_internal_set_provider_data: + * @cnc: a #GdaConnection object + * @data: a #GdaServerProviderConnectionData, which can be extended as needed by the provider for which @cnc is opened + * @destroy_func: function to call when the connection closes and @data needs to be destroyed + * + * Note: calling this function more than once will not make it call @destroy_func on any previously + * set opaque @data, you'll have to do it yourself. + * + * Note: @destroy_func, needs to free the memory associated to @data, if necessary. + */ +void +gda_connection_internal_set_provider_data (GdaConnection *cnc, GdaServerProviderConnectionData *data, GDestroyNotify destroy_func) +{ + + g_return_if_fail (GDA_IS_CONNECTION (cnc)); + g_return_if_fail ((data && destroy_func) || (!data && !destroy_func)); + GdaConnectionPrivate *priv = gda_connection_get_instance_private (cnc); + if (priv->provider_data && data) { + g_warning ("Changing the provider's data is not allowed during the lifetime of a connection"); + return; + } + + if (!data) + gda_connection_lock ((GdaLockable*) cnc); + + priv->provider_data = data; + if (data) + data->provider_data_destroy_func = destroy_func; + + if (!data) + gda_connection_unlock ((GdaLockable*) cnc); +} + +void +_gda_connection_internal_set_worker_thread (GdaConnection *cnc, GThread *thread) +{ + g_return_if_fail (GDA_IS_CONNECTION (cnc)); + GdaConnectionPrivate *priv = gda_connection_get_instance_private (cnc); + g_mutex_lock (&global_mutex); + if (priv->worker_thread && thread) + g_warning ("Trying to overwriting connection's associated internal thread"); + else + priv->worker_thread = thread; + g_mutex_unlock (&global_mutex); +} + +/** + * gda_connection_internal_get_worker: + * @data: (nullable): a #GdaServerProviderConnectionData, or %NULL + * + * Retreive a pointer to the #GdaWorker used internally by the connection. This function is reserved to + * database provider's implementation and should not be used otherwise. + * + * Returns: (transfer none): the #GdaWorker, or %NULL + */ +GdaWorker * +gda_connection_internal_get_worker (GdaServerProviderConnectionData *data) +{ + if (data) + return data->worker; + else + return NULL; +} + +/** + * gda_connection_internal_get_provider_data_error: + * @cnc: a #GdaConnection object + * @error: (nullable): a place to store errors, or %NULL + * + * Get the opaque pointer previously set using gda_connection_internal_set_provider_data(). + * If it's not set, then add a connection event and returns %NULL + * + * Returns: (nullable): the pointer to the opaque structure set using gda_connection_internal_set_provider_data(), or %NULL + * + * Since: 5.0.2 + */ +GdaServerProviderConnectionData * +gda_connection_internal_get_provider_data_error (GdaConnection *cnc, GError **error) +{ + gpointer retval; + g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL); + GdaConnectionPrivate *priv = gda_connection_get_instance_private (cnc); + + retval = priv->provider_data; + if (!retval) + g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_CLOSED_ERROR, + _("Connection is closed")); + return retval; +} + +/** + * gda_connection_get_meta_store: + * @cnc: a #GdaConnection object + * + * Get or initializes the #GdaMetaStore associated to @cnc + * + * Returns: (transfer none): a #GdaMetaStore object + */ +GdaMetaStore * +gda_connection_get_meta_store (GdaConnection *cnc) +{ + g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL); + GdaConnectionPrivate *priv = gda_connection_get_instance_private (cnc); + gda_connection_lock ((GdaLockable*) cnc); + if (!priv->meta_store) { + priv->meta_store = gda_meta_store_new (NULL); + GdaConnection *scnc; + scnc = gda_meta_store_get_internal_connection (priv->meta_store); + if ((scnc != cnc) && + gda_connection_get_main_context (cnc, NULL) && + ! gda_connection_get_main_context (scnc, NULL)) + gda_connection_set_main_context (scnc, NULL, gda_connection_get_main_context (cnc, NULL)); + } + gda_connection_unlock ((GdaLockable*) cnc); + + return priv->meta_store; +} + +/* Note about the GdaConnection's locking mechanism: + * When a thread wants to lock a #GdaConnection: + * - if it's the GdaWorker's thread then nothing needs to be done, and returns immediately + * - otherwise try to lock the GRecMutex, and if Ok, then we are done. + * - if the try_lock() did not work: + * - if there is no GMainContext associated to the current thread, then block on mutex lock + * - otherwise, we create a new main loop for that GMainContext and an ITSignaler source + * which will receive a notification from the thread which currently + * locks the GRecMutex right after it has released it. + * + * The ITSignaler is appended to the @lock_its_list list, and removed once the lock has been + * acquired by the thread + */ +static GSList *lock_its_list = NULL; + +typedef struct { + GdaLockable *lockable; + GMainLoop *loop; +} TryLockData; + +static gboolean +itsignaler_trylock (TryLockData *data) +{ + if (gda_connection_trylock (data->lockable)) { + g_main_loop_quit (data->loop); + return G_SOURCE_REMOVE; + } + else + return G_SOURCE_CONTINUE; +} + +/* + * To avoid the thread being blocked (possibly forever if the single thread which can use the + * connection is not the current thead), then it is possible to use gda_connection_trylock() instead. + */ +static void +gda_connection_lock (GdaLockable *lockable) +{ + GdaConnection *cnc = (GdaConnection *) lockable; + GdaConnectionPrivate *priv = gda_connection_get_instance_private (cnc); + + if (priv->worker_thread == g_thread_self ()) { + /* the sitation here is that the connection _has been_ locked by the + * calling thread of the GdaWorker, and as we are in the worker thread + * of the GdaWorker, we don't need to lock it again: it would be useless because + * by desing the connection object may be modified but only by the provider code, which + * is Ok, and because it would require a very complex mechanism to "transfer the lock" + * from one thread to the other */ + return; + } + + GMainContext *context; + context = gda_connection_get_main_context (cnc, NULL); + if (context) { + g_mutex_lock (&global_mutex); + if (gda_connection_trylock (lockable)) { + g_mutex_unlock (&global_mutex); + return; + } + + /* create ITSignaler and add it to the list */ + ITSignaler *its; + its = itsignaler_new (); + lock_its_list = g_slist_append (lock_its_list, its); + /*g_print ("++ ITSigaler_len is %u\n", g_slist_length (lock_its_list));*/ + g_mutex_unlock (&global_mutex); + + /* create main loop to must process events from @context */ + GMainLoop *loop; + loop = g_main_loop_new (context, FALSE); + + TryLockData lockdata; + lockdata.lockable = lockable; + lockdata.loop = loop; + + GSource *itsource; + itsource = itsignaler_create_source (its); + g_source_attach (itsource, context); + g_source_set_callback (itsource, G_SOURCE_FUNC (itsignaler_trylock), &lockdata, NULL); + g_source_unref (itsource); + + g_main_loop_run (loop); + g_main_loop_unref (loop); + + /* get rid of @its */ + g_mutex_lock (&global_mutex); + lock_its_list = g_slist_remove (lock_its_list, its); + /*g_print ("-- ITSigaler_len is %u\n", g_slist_length (lock_its_list));*/ + g_mutex_unlock (&global_mutex); + itsignaler_unref (its); + } + else + g_rec_mutex_lock (& priv->rmutex); +} + +/* + * Tries to lock @cnc for the exclusive usage of the current thread, as gda_connection_lock(), except + * that if it can't, then the calling thread is not locked by it simply returns FALSE. + * + * Returns: TRUE if successfully locked, or FALSE if lock could not be acquired + */ +static gboolean +gda_connection_trylock (GdaLockable *lockable) +{ + GdaConnection *cnc = (GdaConnection *) lockable; + GdaConnectionPrivate *priv = gda_connection_get_instance_private (cnc); + + if (priv->worker_thread == g_thread_self ()) { + /* See gda_connection_lock() for explanations */ + return TRUE; + } + + return g_rec_mutex_trylock (& priv->rmutex); +} + +/* + * Unlocks @cnc's usage. Any other thread blocked (after having called gda_connection_lock()) gets + * the opportunity to lock the connection. + */ +static void +gda_connection_unlock (GdaLockable *lockable) +{ + GdaConnection *cnc = (GdaConnection *) lockable; + GdaConnectionPrivate *priv = gda_connection_get_instance_private (cnc); + + if (priv->worker_thread == g_thread_self ()) { + /* See gda_connection_lock() for explanations */ + return; + } + + /* help other threads locking the connection */ + g_rec_mutex_unlock (& priv->rmutex); + g_mutex_lock (&global_mutex); + if (lock_its_list) { + ITSignaler *its; + its = (ITSignaler*) lock_its_list->data; + itsignaler_push_notification (its, (gpointer) 0x01, NULL); /* "wake up" the waiting thread */ + } + g_mutex_unlock (&global_mutex); +} + +/* + * REM: if @for_ident is %FALSE, then the keywords are converted to upper case + */ +static gchar * +get_next_word (gchar *str, gboolean for_ident, gchar **out_next) +{ + if (!str) { + *out_next = NULL; + return NULL; + } + + gchar *start; + gchar *ptr; + gboolean inquotes = FALSE; + for (ptr = str; *ptr; ptr++) { + if ((*ptr == ' ') || (*ptr == '\n') || (*ptr == '\t') || (*ptr == '\r')) + continue; + break; + } + start = ptr; + /*g_print ("%s ([%s]) => [%s]", __FUNCTION__, str, start);*/ + for (; *ptr; ptr++) { + if ((*ptr >= 'a') && (*ptr <= 'z')) { + if (! for_ident) + *ptr += 'A' - 'a'; + continue; + } + else if ((*ptr >= 'A') && (*ptr <= 'Z')) + continue; + else if ((*ptr >= '0') && (*ptr <= '9')) + continue; + else if (*ptr == '_') + continue; + else if (for_ident) { + if ((*ptr == '"') || (*ptr == '\'') || (*ptr == '`')) { + if (inquotes) { + *ptr = '"'; + inquotes = FALSE; + ptr++; + break; + } + else { + *ptr = '"'; + inquotes = TRUE; + } + continue; + } + } + else if (inquotes) + continue; + break; + } + if (ptr != start) { + if (*ptr) { + *ptr = 0; + *out_next = ptr + 1; + } + else + *out_next = ptr; + } + else + *out_next = NULL; + /*g_print (" -- [%s]\n", *out_next);*/ + return start; +} + + +/* + * the contexts in returned list have: + * - the @table_name attribute as a static string + * - the @column_names[x] as a static string, not the @column_names array itself which has to be freed + * + * Returns: a new list of new #GdaMetaContext + */ +static GSList * +meta_data_context_from_statement (GdaConnection *cnc, GdaStatement *stmt, GdaSet *params) +{ + g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL); + GdaConnectionPrivate *priv = gda_connection_get_instance_private (cnc); + gboolean ignore_create_drop = FALSE; + if (GDA_IS_VCONNECTION_DATA_MODEL (cnc)) + /* meta data is updated when the virtual connection emits the + * "vtable-created" or "vtable-dropped" signals + */ + ignore_create_drop = TRUE; + + GdaMetaContext *context = NULL; + gchar *sql, *current, *next; + sql = gda_statement_to_sql (stmt, params, NULL); + if (!sql) + return NULL; + + GSList *clist = NULL; + current = get_next_word (sql, FALSE, &next); + if (!current) + goto out; + + if (!strcmp (current, "ALTER") || + (!ignore_create_drop && (!strcmp (current, "CREATE") || !strcmp (current, "DROP")))) { + const gchar *tname = NULL; + const gchar *opname; + opname = current; + current = get_next_word (next, FALSE, &next); + if (current && (!strcmp (current, "TABLE") || !strcmp (current, "VIEW"))) { + tname = get_next_word (next, TRUE, &next); + if ((! strcmp (opname, "CREATE") || !strcmp (opname, "DROP")) + && !g_ascii_strcasecmp (tname, "IF")) { + gchar *tmpnext; + tmpnext = next; + if (! strcmp (opname, "CREATE")) { + const gchar *s1, *s2; + s1 = get_next_word (tmpnext, FALSE, &tmpnext); + s2 = get_next_word (tmpnext, FALSE, &tmpnext); + if (! strcmp (s1, "NOT") && + ! strcmp (s2, "EXISTS")) { + next = tmpnext; + tname = get_next_word (next, TRUE, &next); + } + } + else { + const gchar *s1; + s1 = get_next_word (tmpnext, FALSE, &tmpnext); + if (! strcmp (s1, "EXISTS")) { + next = tmpnext; + tname = get_next_word (next, TRUE, &next); + } + } + } + } + if (tname) { + gchar *tmp; + /*g_print ("CONTEXT: update for table [%s]\n", tname);*/ + context = g_new0 (GdaMetaContext, 1); + context->table_name = "_tables"; + context->size = 1; + context->column_names = g_new0 (gchar *, 1); + context->column_names[0] = "table_name"; + context->column_values = g_new0 (GValue *, 1); + tmp = gda_sql_identifier_quote (tname, cnc, priv->provider_obj, + TRUE, + priv->options & GDA_CONNECTION_OPTIONS_SQL_IDENTIFIERS_CASE_SENSITIVE); + g_value_take_string ((context->column_values[0] = gda_value_new (G_TYPE_STRING)), + tmp); + clist = g_slist_prepend (clist, context); + + /* seek RENAME TO */ + current = get_next_word (next, FALSE, &next); + if (!current || strcmp (current, "RENAME")) + goto out; + current = get_next_word (next, FALSE, &next); + if (!current || strcmp (current, "TO")) + goto out; + tname = get_next_word (next, TRUE, &next); + if (tname) { + gchar *tmp; + /*g_print ("CONTEXT: update for table [%s]\n", tname);*/ + context = g_new0 (GdaMetaContext, 1); + context->table_name = "_tables"; + context->size = 1; + context->column_names = g_new0 (gchar *, 1); + context->column_names[0] = "table_name"; + context->column_values = g_new0 (GValue *, 1); + tmp = gda_sql_identifier_quote (tname, cnc, priv->provider_obj, + TRUE, + priv->options & GDA_CONNECTION_OPTIONS_SQL_IDENTIFIERS_CASE_SENSITIVE); + g_value_take_string ((context->column_values[0] = gda_value_new (G_TYPE_STRING)), + tmp); + clist = g_slist_prepend (clist, context); + } + } + } + + out: + g_free (sql); + return clist; +} + +/* + * update_meta_store_after_statement_exec + * + * Updates the meta store associated to @cnc if it exists and if @cnc has the + * GDA_CONNECTION_OPTIONS_AUTO_META_DATA flag. + */ +static void +update_meta_store_after_statement_exec (GdaConnection *cnc, GdaStatement *stmt, GdaSet *params) +{ + g_return_if_fail (GDA_IS_CONNECTION (cnc)); + GdaConnectionPrivate *priv = gda_connection_get_instance_private (cnc); + if (! priv->meta_store || + ! (priv->options & GDA_CONNECTION_OPTIONS_AUTO_META_DATA)) + return; + + GdaSqlStatementType type; + type = gda_statement_get_statement_type (stmt); + if (type == GDA_SQL_STATEMENT_BEGIN) { + /* initialize priv->trans_meta_context if meta store's connection is not @cnc */ + GdaConnection *mscnc; + mscnc = gda_meta_store_get_internal_connection (priv->meta_store); + if (cnc != mscnc) { + g_assert (! priv->trans_meta_context); + priv->trans_meta_context = g_array_new (FALSE, FALSE, sizeof (GdaMetaContext*)); + } + return; + } + else if (type == GDA_SQL_STATEMENT_ROLLBACK) { + /* re-run all the meta store updates started since the BEGIN */ + GdaConnection *mscnc; + mscnc = gda_meta_store_get_internal_connection (priv->meta_store); + if (cnc != mscnc) { + gsize i; + g_assert (priv->trans_meta_context); + for (i = 0; i < priv->trans_meta_context->len; i++) { + GdaMetaContext *context; + GError *lerror = NULL; + context = g_array_index (priv->trans_meta_context, GdaMetaContext*, i); + if (! gda_connection_update_meta_store (cnc, context, &lerror)) + add_connection_event_from_error (cnc, &lerror); + auto_update_meta_context_free (context); + } + g_array_free (priv->trans_meta_context, TRUE); + priv->trans_meta_context = NULL; + } + return; + } + else if (type == GDA_SQL_STATEMENT_COMMIT) { + /* get rid of the meta store updates */ + GdaConnection *mscnc; + mscnc = gda_meta_store_get_internal_connection (priv->meta_store); + if (cnc != mscnc) { + gsize i; + g_assert (priv->trans_meta_context); + for (i = 0; i < priv->trans_meta_context->len; i++) { + GdaMetaContext *context; + context = g_array_index (priv->trans_meta_context, GdaMetaContext*, i); + auto_update_meta_context_free (context); + } + g_array_free (priv->trans_meta_context, TRUE); + priv->trans_meta_context = NULL; + } + return; + } + else if (type != GDA_SQL_STATEMENT_UNKNOWN) + return; + + GSList *clist, *list; + clist = meta_data_context_from_statement (cnc, stmt, params); + for (list = clist; list; list = list->next) { + GdaMetaContext *context; + context = (GdaMetaContext*) list->data; + if (context) { + GError *lerror = NULL; + if (! gda_connection_update_meta_store (cnc, context, &lerror)) + add_connection_event_from_error (cnc, &lerror); + + if (priv->trans_meta_context) + g_array_prepend_val (priv->trans_meta_context, context); + else + auto_update_meta_context_free (context); + } + } + g_slist_free (clist); +} + +void +_gda_connection_signal_meta_table_update (GdaConnection *cnc, const gchar *table_name) +{ + g_return_if_fail (GDA_IS_CONNECTION (cnc)); + GdaConnectionPrivate *priv = gda_connection_get_instance_private (cnc); + if (! priv->meta_store || + ! (priv->options & GDA_CONNECTION_OPTIONS_AUTO_META_DATA)) + return; + + GdaMetaContext *context; + gchar **split; + gchar *tmp; + /*g_print ("CONTEXT: update for table [%s]\n", table_name);*/ + split = gda_sql_identifier_split (table_name); + if (!split) + return; + if (!split [0]) { + g_strfreev (split); + return; + } + + context = g_new0 (GdaMetaContext, 1); + context->table_name = "_tables"; + + if (split [1]) { + context->size = 2; + context->column_names = g_new0 (gchar *, context->size); + context->column_names[0] = "table_schema"; + context->column_names[1] = "table_name"; + context->column_values = g_new0 (GValue *, context->size); + tmp = gda_sql_identifier_quote (split[0], cnc, priv->provider_obj, + TRUE, + priv->options & GDA_CONNECTION_OPTIONS_SQL_IDENTIFIERS_CASE_SENSITIVE); + g_value_take_string ((context->column_values[0] = gda_value_new (G_TYPE_STRING)), + tmp); + tmp = gda_sql_identifier_quote (split[1], cnc, priv->provider_obj, + TRUE, + priv->options & GDA_CONNECTION_OPTIONS_SQL_IDENTIFIERS_CASE_SENSITIVE); + g_value_take_string ((context->column_values[1] = gda_value_new (G_TYPE_STRING)), + tmp); + } + else { + context->size = 1; + context->column_names = g_new0 (gchar *, context->size); + context->column_names[0] = "table_name"; + context->column_values = g_new0 (GValue *, context->size); + tmp = gda_sql_identifier_quote (split[0], cnc, priv->provider_obj, + TRUE, + priv->options & GDA_CONNECTION_OPTIONS_SQL_IDENTIFIERS_CASE_SENSITIVE); + g_value_take_string ((context->column_values[0] = gda_value_new (G_TYPE_STRING)), + tmp); + } + + GError *lerror = NULL; + if (! gda_connection_update_meta_store (cnc, context, &lerror)) + add_connection_event_from_error (cnc, &lerror); + + if (priv->trans_meta_context) + g_array_prepend_val (priv->trans_meta_context, context); + else + auto_update_meta_context_free (context); + + g_strfreev (split); +} + +/* + * Free @context which must have been created by meta_data_context_from_statement() + */ +static void +auto_update_meta_context_free (GdaMetaContext *context) +{ + gint i; + context->table_name = NULL; /* don't free */ + g_free (context->column_names); /* don't free the strings in the array */ + for (i = 0; i < context->size; i++) + gda_value_free (context->column_values[i]); + g_free (context->column_values); + g_free (context); +} + + +/* + * _gda_connection_get_table_virtual_name + * @table_name: a non %NULL string + * + * Returns: a new string. + */ +gchar * +_gda_connection_compute_table_virtual_name (GdaConnection *cnc, const gchar *table_name) +{ + gchar **array; + + g_assert (table_name && *table_name); + array = gda_sql_identifier_split (table_name); + if (array) { + GString *string = NULL; + gint i; + gchar *tmp; + for (i = 0; ; i++) { + if (array [i]) { + tmp = gda_sql_identifier_quote (array[i], cnc, NULL, TRUE, FALSE); + if (string) { + g_string_append_c (string, '.'); + g_string_append (string, tmp); + } + else + string = g_string_new (tmp); + } + else + break; + } + g_strfreev (array); + return g_string_free (string, FALSE); + } + else { + /* + ** If X is a character that can be used in an identifier then + ** IdChar(X) will be true. Otherwise it is false. + ** + ** For ASCII, any character with the high-order bit set is + ** allowed in an identifier. For 7-bit characters, + ** sqlite3IsIdChar[X] must be 1. + */ + static const char AsciiIdChar[] = { + /* x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF */ + 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 2x */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, /* 3x */ + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 4x */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, /* 5x */ + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 6x */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, /* 7x */ + }; +#define IdChar(C) (((c=C)&0x80)!=0 || (c>0x1f && AsciiIdChar[c-0x20])) + gchar *tmp, *ptr, c; + tmp = g_strdup (table_name); + + /* first try removing some double quotes only */ + for (ptr = tmp; *ptr; ptr++) { + if (! IdChar(*ptr)) { + if ((*ptr == '"') && (ptr[1] == '"')) { + gchar *ptr2; + for (ptr2 = ptr; ptr2[2]; ptr2++) + *ptr2 = ptr2[2]; + *ptr2 = 0; + } + else if ((*ptr != '"') && (*ptr != '.')) + *ptr = '_'; + } + } + + ptr = NULL; + if (strcmp (tmp, table_name)) + ptr = _gda_connection_compute_table_virtual_name (cnc, tmp); + + /* if it dow not work, replace all non IdChar character with '_' */ + if (!ptr) { + for (ptr = tmp; *ptr; ptr++) { + if (! IdChar(*ptr)) + *ptr = '_'; + } + ptr = _gda_connection_compute_table_virtual_name (cnc, tmp); + } + g_free (tmp); + return ptr; + } +} + + +GdaServerProviderConnectionData * +gda_server_provider_connection_data_copy (GdaServerProviderConnectionData *src) { + GdaServerProviderConnectionData *cp = g_new0 (GdaServerProviderConnectionData, 1); + cp->worker = src->worker; + cp->provider_data_destroy_func = src->provider_data_destroy_func; + return cp; +} +void +gda_server_provider_connection_data_free (GdaServerProviderConnectionData *obj) { + g_free (obj); +} + +G_DEFINE_BOXED_TYPE(GdaServerProviderConnectionData, gda_server_provider_connection_data, gda_server_provider_connection_data_copy, gda_server_provider_connection_data_free) + +/** + * gda_connection_prepare_operation_create_table_v: + * @cnc: an opened connection + * @table_name: name of the table to create + * @error: a place to store errors, or %NULL + * @...: group of three arguments for column's name, column's #GType + * and a #GdaServerOperationCreateTableFlag flag, finished with %NULL + * + * Convenient funtion for table creation. + * + * For details about arguments see #gda_server_operation_prepare_create_table_v(). + * + * Returns: (transfer full) (nullable): a #GdaServerOperation if no errors; NULL and set @error otherwise + * + * Since: 6.0 + */ +G_GNUC_NULL_TERMINATED +GdaServerOperation* +gda_connection_prepare_operation_create_table_v (GdaConnection *cnc, const gchar *table_name, GError **error, ...) +{ + GdaServerOperation *op; + + g_return_val_if_fail (gda_connection_is_opened (cnc), NULL); + + va_list args; + gchar *arg; + GType type; + GdaServerOperationCreateTableFlag flag; + gint refs; + GList *arguments = NULL; + GdaServerOperationCreateTableArg* argument; + + va_start (args, error); + type = 0; + arg = NULL; + refs = -1; + + while ((arg = va_arg (args, gchar*))) { + argument = gda_server_operation_create_table_arg_new (); + /* First argument for Column's name */ + gda_server_operation_create_table_arg_set_column_name (argument, (const gchar*) arg); + + /* Second to Define column's type */ + type = va_arg (args, GType); + gda_server_operation_create_table_arg_set_column_type (argument, type); + + /* Third for column's flags */ + flag = va_arg (args, GdaServerOperationCreateTableFlag); + gda_server_operation_create_table_arg_set_flags (argument, flag); + if (flag & GDA_SERVER_OPERATION_CREATE_TABLE_FKEY_FLAG) { + gint j; + gint fields; + gchar *fkey_table; + gchar *fkey_ondelete; + gchar *fkey_onupdate; + + refs++; + GList *lfields = NULL; + + fkey_table = va_arg (args, gchar*); + gda_server_operation_create_table_arg_set_fkey_table (argument, fkey_table); + /* Get number of referenced fields */ + fields = va_arg (args, gint); + + for (j = 0; j < fields; j++) { + gchar *field; + GdaServerOperationCreateTableArgFKeyRefField *rfields; + + /* First pair arguments give local field and referenced field */ + field = va_arg (args, gchar*); + rfields = gda_server_operation_create_table_arg_fkey_ref_field_new (); + gda_server_operation_create_table_arg_fkey_ref_field_set_local_field (rfields, field); + gda_server_operation_create_table_arg_fkey_ref_field_set_referenced_field (rfields, field); + lfields = g_list_append (lfields, rfields); + } + gda_server_operation_create_table_arg_set_fkey_refs (argument, lfields); + + /* ON DELETE and ON UPDATE events constraints */ + fkey_ondelete = va_arg (args, gchar*); + gda_server_operation_create_table_arg_set_fkey_ondelete (argument, fkey_ondelete); + + fkey_onupdate = va_arg (args, gchar*); + gda_server_operation_create_table_arg_set_fkey_ondupdate (argument, fkey_onupdate); + } + + arguments = g_list_append (arguments, argument); + } + + va_end (args); + + op = gda_connection_prepare_operation_create_table (cnc, table_name, arguments, error); + g_list_free_full (arguments, (GDestroyNotify) gda_server_operation_create_table_arg_free); + return op; +} + +/** + * gda_connection_prepare_operation_create_table: + * @cnc: an opened connection + * @table_name: name of the table to create + * @arguments: (element-type GdaServerOperationCreateTableArg): list of arguments as #GdaServerOperationPrepareCreateTableArg containing column's name, + * column's #GType and a #GdaServerOperationCreateTableFlag flag + * @error: a place to store errors, or %NULL + * + * Add more arguments if the flag needs them: + * + * GDA_SERVER_OPERATION_CREATE_TABLE_FKEY_FLAG: + * + * string with the table's name referenced + * an integer with the number pairs "local_field", "referenced_field" + * used in the reference + * Pairs of "local_field", "referenced_field" to use, must match + * the number specified above. + * a string with the action for ON DELETE; can be: "RESTRICT", "CASCADE", + * "NO ACTION", "SET NULL" and "SET DEFAULT". Example: "ON UPDATE CASCADE". + * a string with the action for ON UPDATE (see above). + * + * + * Create a #GdaServerOperation object using an opened connection, taking three + * arguments, a column's name the column's GType and #GdaServerOperationCreateTableFlag + * flag, you need to finish the list using %NULL. + * + * You'll be able to modify the #GdaServerOperation object to add custom options + * to the operation. When finished call #gda_server_operation_perform_create_table + * or #gda_server_provider_perform_operation + * in order to execute the operation. + * + * Returns: (transfer full) (nullable): a #GdaServerOperation if no errors; NULL and set @error otherwise + * + * Since: 6.0 + */ +GdaServerOperation* +gda_connection_prepare_operation_create_table (GdaConnection *cnc, const gchar *table_name, GList *arguments, GError **error) +{ + GdaServerOperation *op; + GdaServerProvider *server; + + g_return_val_if_fail (gda_connection_is_opened (cnc), NULL); + + server = gda_connection_get_provider (cnc); + + if (!table_name) { + g_set_error (error, GDA_SERVER_OPERATION_ERROR, GDA_SERVER_OPERATION_OBJECT_NAME_ERROR, + "%s", _("Unspecified table name")); + return NULL; + } + + if (gda_server_provider_supports_operation (server, cnc, GDA_SERVER_OPERATION_CREATE_TABLE, NULL)) { + gchar *cname; + GType type; + gchar *dbms_type; + GdaServerOperationCreateTableFlag flag; + gint i; + gint refs; + + op = gda_server_provider_create_operation (server, cnc, + GDA_SERVER_OPERATION_CREATE_TABLE, NULL, error); + if (!GDA_IS_SERVER_OPERATION(op)) + return NULL; + if(!gda_server_operation_set_value_at (op, table_name, error, "/TABLE_DEF_P/TABLE_NAME")) { + g_object_unref (op); + return NULL; + } + + type = 0; + cname = NULL; + i = 0; + refs = -1; + + GList *l = arguments; + while (l != NULL) { + GdaServerOperationCreateTableArg *argument; + argument = (GdaServerOperationCreateTableArg*) l->data; + cname = gda_server_operation_create_table_arg_get_column_name (argument); + /* First argument for Column's name */ + if(!gda_server_operation_set_value_at (op, cname, error, "/FIELDS_A/@COLUMN_NAME/%d", i)) { + g_object_unref (op); + return NULL; + } + g_free (cname); + + /* Second to Define column's type */ + type = gda_server_operation_create_table_arg_get_column_type (argument); + if (type == 0) { + g_set_error (error, GDA_SERVER_OPERATION_ERROR, GDA_SERVER_OPERATION_INCORRECT_VALUE_ERROR, + "%s", _("Invalid type")); + g_object_unref (op); + return NULL; + } + dbms_type = (gchar *) gda_server_provider_get_default_dbms_type (server, + cnc, type); + if (!gda_server_operation_set_value_at (op, dbms_type, error, "/FIELDS_A/@COLUMN_TYPE/%d", i)){ + g_object_unref (op); + return NULL; + } + + /* Third for column's flags */ + flag = gda_server_operation_create_table_arg_get_flags (argument); + if (flag & GDA_SERVER_OPERATION_CREATE_TABLE_PKEY_FLAG) + if(!gda_server_operation_set_value_at (op, "TRUE", error, "/FIELDS_A/@COLUMN_PKEY/%d", i)){ + g_object_unref (op); + return NULL; + } + if (flag & GDA_SERVER_OPERATION_CREATE_TABLE_NOT_NULL_FLAG) + if(!gda_server_operation_set_value_at (op, "TRUE", error, "/FIELDS_A/@COLUMN_NNUL/%d", i)){ + g_object_unref (op); + return NULL; + } + if (flag & GDA_SERVER_OPERATION_CREATE_TABLE_AUTOINC_FLAG) + if (!gda_server_operation_set_value_at (op, "TRUE", error, "/FIELDS_A/@COLUMN_AUTOINC/%d", i)){ + g_object_unref (op); + return NULL; + } + if (flag & GDA_SERVER_OPERATION_CREATE_TABLE_UNIQUE_FLAG) + if(!gda_server_operation_set_value_at (op, "TRUE", error, "/FIELDS_A/@COLUMN_UNIQUE/%d", i)){ + g_object_unref (op); + return NULL; + } + if (flag & GDA_SERVER_OPERATION_CREATE_TABLE_FKEY_FLAG) { + gint j; + gchar *fkey_table; + gchar *fkey_ondelete; + gchar *fkey_onupdate; + + fkey_table = gda_server_operation_create_table_arg_get_column_name (argument); + if (!gda_server_operation_set_value_at (op, fkey_table, error, + "/FKEY_S/%d/FKEY_REF_TABLE", refs)){ + g_object_unref (op); + return NULL; + } + + refs++; + GList* lr = gda_server_operation_create_table_arg_get_fkey_refs (argument); + j = 0; + + while (lr) { + gchar *field, *rfield; + GdaServerOperationCreateTableArgFKeyRefField *ref; + ref = (GdaServerOperationCreateTableArgFKeyRefField*) l->data; + + field = gda_server_operation_create_table_arg_fkey_ref_field_get_local_field (ref); + if(!gda_server_operation_set_value_at (op, field, error, + "/FKEY_S/%d/FKEY_FIELDS_A/@FK_FIELD/%d", refs, j)){ + g_object_unref (op); + return NULL; + } + + rfield = gda_server_operation_create_table_arg_fkey_ref_field_get_referenced_field (ref); + if(!gda_server_operation_set_value_at (op, rfield, error, + "/FKEY_S/%d/FKEY_FIELDS_A/@FK_REF_PK_FIELD/%d", refs, j)){ + g_object_unref (op); + return NULL; + } + j++; + lr = g_list_next (lr); + } + + fkey_ondelete = gda_server_operation_create_table_arg_get_fkey_ondelete (argument); + if (!gda_server_operation_set_value_at (op, fkey_ondelete, error, + "/FKEY_S/%d/FKEY_ONDELETE", refs)){ + g_object_unref (op); + return NULL; + } + fkey_onupdate = gda_server_operation_create_table_arg_get_fkey_onupdate (argument); + if(!gda_server_operation_set_value_at (op, fkey_onupdate, error, + "/FKEY_S/%d/FKEY_ONUPDATE", refs)){ + g_object_unref (op); + return NULL; + } + } + + l = g_list_next (l); + i++; + } + + g_object_set_data_full (G_OBJECT (op), "_gda_connection", g_object_ref (cnc), g_object_unref); + + return op; + } + else { + g_set_error (error, GDA_SERVER_OPERATION_ERROR, GDA_SERVER_OPERATION_OBJECT_NAME_ERROR, + "%s", _("CREATE TABLE operation is not supported by the database server")); + return NULL; + } +} + +/** + * gda_connection_prepare_operation_drop_table: + * @cnc: an opened connection + * @table_name: name of the table to drop + * @error: a place to store errors, or %NULL + * + * This is just a convenient function to create a #GdaServerOperation to drop a + * table in an opened connection. + * + * Returns: (transfer full) (nullable): a new #GdaServerOperation or %NULL if couldn't create the opereration. + * + * Since: 6.0 + */ +GdaServerOperation* +gda_server_operation_prepare_drop_table (GdaConnection *cnc, const gchar *table_name, GError **error) +{ + GdaServerOperation *op; + GdaServerProvider *server; + + server = gda_connection_get_provider (cnc); + + op = gda_server_provider_create_operation (server, cnc, + GDA_SERVER_OPERATION_DROP_TABLE, NULL, error); + + if (GDA_IS_SERVER_OPERATION (op)) { + g_return_val_if_fail (table_name != NULL + || GDA_IS_CONNECTION (cnc) + || !gda_connection_is_opened (cnc), NULL); + + if (gda_server_operation_set_value_at (op, table_name, + error, "/TABLE_DESC_P/TABLE_NAME")) { + g_object_set_data_full (G_OBJECT (op), "_gda_connection", g_object_ref (cnc), g_object_unref); + return op; + } + else + return NULL; + } + else + return NULL; +} + + +/** + * gda_connection_operation_get_sql_identifier_at: + * @cnc: a #GdaConnection + * @op: a #GdaServerOperation object + * @path_format: a complete path to a node (starting with "/") + * @error: (nullable): a place to store errors, or %NULL + * @...: arguments to use with @path_format to make a complete path + * + * This method is similar to gda_server_operation_get_value_at(), but for SQL identifiers: a new string + * is returned instead of a #GValue. Also the returned string is assumed to represents an SQL identifier + * and will correctly be quoted to be used with @cnc. + * + * Returns: (transfer full) (nullable): a new string, or %NULL if the value is undefined or + * if the @path is not defined or @path does not hold any value, or if the value held is not a string + * (in that last case a warning is shown). + * + * Since: 6.0 + */ +gchar * +gda_connection_operation_get_sql_identifier_at (GdaConnection *cnc, GdaServerOperation *op, + const gchar *path_format, GError **error, ...) +{ + g_return_val_if_fail (cnc != NULL, NULL); + g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL); + g_return_val_if_fail (GDA_IS_SERVER_OPERATION (op), NULL); + + gchar *path, *ret; + va_list args; + + /* build path */ + va_start (args, error); + path = g_strdup_vprintf (path_format, args); + va_end (args); + + ret = gda_connection_operation_get_sql_identifier_at_path (cnc, op, path, error); + g_free (path); + + return ret; +} + + + +/** + * gda_connection_operation_get_sql_identifier_at_path: + * @op: a #GdaServerOperation object + * @cnc: (nullable): a #GdaConnection, or %NULL + * @path: a complete path to a node (starting with "/") + * @error: (nullable): a place to store errors, or %NULL + * + * This method is similar to gda_server_operation_get_value_at(), but for SQL identifiers: a new string + * is returned instead of a #GValue. Also the returned string is assumed to represents an SQL identifier + * and will correctly be quoted to be used with @cnc. + * + * Returns: (transfer full) (nullable): a new string, or %NULL if the value is undefined or + * if the @path is not defined or @path does not hold any value, or if the value held is not a string or + * a valid SQL identifier. + * + * Since: 6.0 + */ +gchar * +gda_connection_operation_get_sql_identifier_at_path (GdaConnection *cnc, GdaServerOperation *op, + const gchar *path, GError **error) +{ + const GValue *value = NULL; + GdaConnectionOptions cncoptions = 0; + + g_return_val_if_fail (GDA_IS_SERVER_OPERATION (op), NULL); + + value = gda_server_operation_get_value_at_path (op, path); + + if (!value || (G_VALUE_TYPE (value) == GDA_TYPE_NULL)) { + g_set_error (error, GDA_SERVER_OPERATION_ERROR, GDA_SERVER_OPERATION_INCORRECT_VALUE_ERROR, + _("Wrong SQL identifier value")); + return NULL; + } + + g_return_val_if_fail (G_VALUE_TYPE (value) == G_TYPE_STRING, NULL); + + const gchar *str; + str = g_value_get_string (value); + if (!str || !*str) { + g_set_error (error, GDA_SERVER_OPERATION_ERROR, GDA_SERVER_OPERATION_INCORRECT_VALUE_ERROR, + _("Wrong SQL identifier value")); + return NULL; + } + + if (cnc) + g_object_get (G_OBJECT (cnc), "options", &cncoptions, NULL); + return gda_sql_identifier_quote (str, cnc, gda_connection_get_provider (cnc), FALSE, + cncoptions & GDA_CONNECTION_OPTIONS_SQL_IDENTIFIERS_CASE_SENSITIVE); +} + +/** + * gda_connection_create_db_catalog: + * @cnc: A #GdaConnection object to use + * + * A convenient method to create a new #GdaDbCatalog instance and set the current @cnc as a + * property. If for some reason, this approach doesn't fit well, the same task can be achieved + * by the following code: + * + * GdaDbCatalog *catalog = gda_db_catalog_new (); + * g_object_set (catalog, "connection", cnc, NULL); + * + * Returns: (transfer full): A new instance of #GdaDbCatalog. The new object should be deallocated + * using g_object_unref(). + * + * Since: 6.0 + */ +GdaDbCatalog* +gda_connection_create_db_catalog (GdaConnection *cnc) +{ + g_return_val_if_fail (GDA_IS_CONNECTION (cnc),NULL); + + return g_object_new (GDA_TYPE_DB_CATALOG,"connection",cnc,NULL); +} diff --git a/.flatpak-builder/cache/objects/b6/f9c6844c10045368cb987043ffea77da1989fd2d937f85c649facffb62c22e.file b/.flatpak-builder/cache/objects/b6/f9c6844c10045368cb987043ffea77da1989fd2d937f85c649facffb62c22e.file new file mode 100644 index 0000000..d5c6baa --- /dev/null +++ b/.flatpak-builder/cache/objects/b6/f9c6844c10045368cb987043ffea77da1989fd2d937f85c649facffb62c22e.file @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2006 - 2012 Vivien Malerba + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GDA_TRANSACTION_STATUS_PRIVATE_H__ +#define __GDA_TRANSACTION_STATUS_PRIVATE_H__ + +#include + +G_BEGIN_DECLS + +GdaTransactionStatusEvent *gda_transaction_status_add_event_svp (GdaTransactionStatus *tstatus, const gchar *svp_name); +GdaTransactionStatusEvent *gda_transaction_status_add_event_sql (GdaTransactionStatus *tstatus, const gchar *sql, + GdaConnectionEvent *conn_event); +GdaTransactionStatusEvent *gda_transaction_status_add_event_sub (GdaTransactionStatus *tstatus, GdaTransactionStatus *sub_trans); + +void gda_transaction_status_free_events (GdaTransactionStatus *tstatus, GdaTransactionStatusEvent *event, + gboolean free_after); + +GdaTransactionStatus *gda_transaction_status_find (GdaTransactionStatus *tstatus, const gchar *str, + GdaTransactionStatusEvent **destev); + +GdaTransactionStatus *gda_transaction_status_find_current (GdaTransactionStatus *tstatus, GdaTransactionStatusEvent **destev, + gboolean unnamed_only); +#ifdef GDA_DEBUG +void gda_transaction_status_dump (GdaTransactionStatus *tstatus, guint offset); +#endif + +G_END_DECLS + +#endif diff --git a/.flatpak-builder/cache/objects/b7/055c410406d5bec12319a5bef6e8ddd3e670956e2ad900c60b39f9097885d6.file b/.flatpak-builder/cache/objects/b7/055c410406d5bec12319a5bef6e8ddd3e670956e2ad900c60b39f9097885d6.file new file mode 100644 index 0000000..fec1ec8 --- /dev/null +++ b/.flatpak-builder/cache/objects/b7/055c410406d5bec12319a5bef6e8ddd3e670956e2ad900c60b39f9097885d6.file @@ -0,0 +1,117 @@ +/* + * Copyright (C) 2000 Reinhard Müller + * Copyright (C) 2000 - 2002 Rodrigo Moya + * Copyright (C) 2001 Carlos Perelló Marín + * Copyright (C) 2001 - 2014 Vivien Malerba + * Copyright (C) 2002 Andrew Hill + * Copyright (C) 2002 - 2003 Gonzalo Paniagua Javier + * Copyright (C) 2002 Xabier Rodriguez Calvar + * Copyright (C) 2002 Zbigniew Chyla + * Copyright (C) 2003 Laurent Sansonetti + * Copyright (C) 2006 - 2011 Murray Cumming + * Copyright (C) 2007 Armin Burgmeier + * Copyright (C) 2008 Przemysław Grzegorczyk + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +#define G_LOG_DOMAIN "GDA-init" + +#include +#include +#include +#include +#ifdef HAVE_LOCALE_H +#include +#endif + +#include +#include + + +/** + * gda_init: + * + * Initializes the GDA library, must be called prior to any Libgda usage. + */ +void +gda_init (void) +{ + static GMutex init_mutex; + static gboolean initialized = FALSE; + + GType type; + gchar *file; + + g_mutex_lock (&init_mutex); + if (initialized) { + g_mutex_unlock (&init_mutex); + gda_log_error (_("Ignoring attempt to re-initialize GDA library.")); + return; + } + + file = gda_gbr_get_file_path (GDA_LOCALE_DIR, NULL); + bindtextdomain (GETTEXT_PACKAGE, file); + g_free (file); + bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); + +#if GLIB_CHECK_VERSION(2,36,0) +#else + g_type_init (); +#endif + + if (!g_module_supported ()) + g_error (_("libgda needs GModule. Finishing...")); + + /* create the required Gda types, to avoid multiple simultaneous type creation when + * multi threads are used */ + type = GDA_TYPE_NULL; + g_assert (type); + type = G_TYPE_DATE; + g_assert (type); + type = GDA_TYPE_BINARY; + g_assert (type); + type = GDA_TYPE_BLOB; + g_assert (type); + type = GDA_TYPE_GEOMETRIC_POINT; + g_assert (type); + type = GDA_TYPE_NUMERIC; + g_assert (type); + type = GDA_TYPE_SHORT; + g_assert (type); + type = GDA_TYPE_USHORT; + g_assert (type); + type = GDA_TYPE_TIME; + g_assert (type); + type = GDA_TYPE_TEXT; + g_assert (type); + type = G_TYPE_DATE; + g_assert (type); + type = G_TYPE_DATE_TIME; + g_assert (type); + type = G_TYPE_ERROR; + g_assert (type); + + /* force TZ init */ + tzset (); + + + /* binreloc */ + gda_gbr_init (); + + initialized = TRUE; + g_mutex_unlock (&init_mutex); +} + diff --git a/.flatpak-builder/cache/objects/b7/5c55dcfbc70ee82d678b0adc9a40573a3cb19b329d75ce05be6a3e56a2520a.dirtree b/.flatpak-builder/cache/objects/b7/5c55dcfbc70ee82d678b0adc9a40573a3cb19b329d75ce05be6a3e56a2520a.dirtree new file mode 100644 index 0000000..49793f6 Binary files /dev/null and b/.flatpak-builder/cache/objects/b7/5c55dcfbc70ee82d678b0adc9a40573a3cb19b329d75ce05be6a3e56a2520a.dirtree differ diff --git a/.flatpak-builder/cache/objects/b8/03dfeadf42acea684830ae2a4828f66d7aee53320969c76523f6eaf22654a4.file b/.flatpak-builder/cache/objects/b8/03dfeadf42acea684830ae2a4828f66d7aee53320969c76523f6eaf22654a4.file new file mode 100644 index 0000000..55ae0cb --- /dev/null +++ b/.flatpak-builder/cache/objects/b8/03dfeadf42acea684830ae2a4828f66d7aee53320969c76523f6eaf22654a4.file @@ -0,0 +1,195 @@ +/* + * Copyright (C) 2008 - 2012 Vivien Malerba + * Copyright (C) 2015 Corentin Noël + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GDA_STATEMENT_EXTRA__ +#define __GDA_STATEMENT_EXTRA__ + +#include + +G_BEGIN_DECLS + +/* private information to implement custom + * SQL renderers for GdaStatement objects + */ +typedef struct _GdaSqlRenderingContext GdaSqlRenderingContext; + +/** + * GdaSqlRenderingFunc: + * @node: a #GdaSqlAnyPart pointer, to be cast to the correct type depending on which part the function has to render + * @context: the rendering context + * @error: a place to store errors, or %NULL + * @Returns: a new string, or %NULL if an error occurred + * + * Function to render any #GdaSqlAnyPart. + */ +typedef gchar *(*GdaSqlRenderingFunc) (GdaSqlAnyPart *node, GdaSqlRenderingContext *context, GError **error); + +/** + * GdaSqlRenderingExpr: + * @expr: #GdaSqlExpr to render + * @context: the rendering context + * @is_default: pointer to a #gboolean which is set to TRUE if value should be considered as a default value + * @is_null: pointer to a #gboolean which is set to TRUE if value should be considered as NULL + * @error: a place to store errors, or %NULL + * @Returns: a new string, or %NULL if an error occurred + * + * Rendering function type to render a #GdaSqlExpr + */ +typedef gchar *(*GdaSqlRenderingExpr) (GdaSqlExpr *expr, GdaSqlRenderingContext *context, + gboolean *is_default, gboolean *is_null, + GError **error); + +/** + * GdaSqlRenderingPSpecFunc: + * @pspec: #GdaSqlParamSpec to render + * @expr: (nullable): #GdaSqlExpr which may hold the default value for the parameter, or %NULL + * @context: the rendering context + * @is_default: pointer to a #gboolean which is set to TRUE if value should be considered as a default value + * @is_null: pointer to a #gboolean which is set to TRUE if value should be considered as NULL + * @error: a place to store errors, or %NULL + * @Returns: a new string, or %NULL if an error occurred + * + * Rendering function type to render a #GdaSqlParamSpec + */ +typedef gchar *(*GdaSqlRenderingPSpecFunc) (GdaSqlParamSpec *pspec, GdaSqlExpr *expr, GdaSqlRenderingContext *context, + gboolean *is_default, gboolean *is_null, + GError **error); + +/** + * GdaSqlRenderingValue: + * @value: the #GValue to render + * @context: the rendering context + * @error: a place to store errors, or %NULL + * @Returns: a new string, or %NULL if an error occurred + * + * Rendering function type to render a #GValue + */ +typedef gchar *(*GdaSqlRenderingValue) (const GValue *value, GdaSqlRenderingContext *context, GError **error); + +/** + * GdaSqlRenderingContext: + * @flags: Global rendering options + * @params: Parameters to be used while doing the rendering + * @params_used: (element-type GdaHolder): When rendering is complete, contains the ordered list of parameters which have been used while doing the rendering + * @provider: Pointer to the server provider to be used + * @cnc: Pointer to the connection to be used + * @render_value: function to render a #GValue + * @render_param_spec: function to render a #GdaSqlParamSpec + * @render_expr: function to render a #GdaSqlExpr + * @render_unknown: function to render a #GdaSqlStatementUnknown + * @render_begin: function to render a BEGIN #GdaSqlStatementTransaction + * @render_rollback: function to render a ROLLBACK #GdaSqlStatementTransaction + * @render_commit: function to render a COMMIT #GdaSqlStatementTransaction + * @render_savepoint: function to render a ADD SAVEPOINT #GdaSqlStatementTransaction + * @render_rollback_savepoint: function to render a ROLBACK SAVEPOINT #GdaSqlStatementTransaction + * @render_delete_savepoint: function to render a DELETE SAVEPOINT #GdaSqlStatementTransaction + * @render_select: function to render a #GdaSqlStatementSelect + * @render_insert: function to render a #GdaSqlStatementInsert + * @render_delete: function to render a #GdaSqlStatementDelete + * @render_update: function to render a #GdaSqlStatementUpdate + * @render_compound: function to render a #GdaSqlStatementCompound + * @render_field: function to render a #GdaSqlField + * @render_table: function to render a #GdaSqlTable + * @render_function: function to render a #GdaSqlFunction + * @render_operation: function to render a #GdaSqlOperation + * @render_case: function to render a #GdaSqlCase + * @render_select_field: function to render a #GdaSqlSelectField + * @render_select_target: function to render a #GdaSqlSelectTarget + * @render_select_join: function to render a #GdaSqlSelectJoin + * @render_select_from: function to render a #GdaSqlSelectFrom + * @render_select_order: function to render a #GdaSqlSelectOrder + * @render_distinct: function to render the DISTINCT clause in a SELECT + * + * Specifies the context in which a #GdaSqlStatement is being converted to SQL. + */ +struct _GdaSqlRenderingContext { + GdaStatementSqlFlag flags; + GdaSet *params; + GSList *params_used; + GdaServerProvider *provider; /* may be NULL */ + GdaConnection *cnc; /* may be NULL */ + + /* rendering functions */ + GdaSqlRenderingValue render_value; + GdaSqlRenderingPSpecFunc render_param_spec; + GdaSqlRenderingExpr render_expr; + + GdaSqlRenderingFunc render_unknown; + + GdaSqlRenderingFunc render_begin; + GdaSqlRenderingFunc render_rollback; + GdaSqlRenderingFunc render_commit; + GdaSqlRenderingFunc render_savepoint; + GdaSqlRenderingFunc render_rollback_savepoint; + GdaSqlRenderingFunc render_delete_savepoint; + + GdaSqlRenderingFunc render_select; + GdaSqlRenderingFunc render_insert; + GdaSqlRenderingFunc render_delete; + GdaSqlRenderingFunc render_update; + GdaSqlRenderingFunc render_compound; + + GdaSqlRenderingFunc render_field; + GdaSqlRenderingFunc render_table; + GdaSqlRenderingFunc render_function; + GdaSqlRenderingFunc render_operation; + GdaSqlRenderingFunc render_case; + GdaSqlRenderingFunc render_select_field; + GdaSqlRenderingFunc render_select_target; + GdaSqlRenderingFunc render_select_join; + GdaSqlRenderingFunc render_select_from; + GdaSqlRenderingFunc render_select_order; + GdaSqlRenderingFunc render_distinct; + + /*< private >*/ + /* Padding for future expansion */ + void (*_gda_reserved1) (void); + void (*_gda_reserved2) (void); + void (*_gda_reserved3) (void); + void (*_gda_reserved4) (void); + void (*_gda_reserved5) (void); + void (*_gda_reserved6) (void); + void (*_gda_reserved7) (void); +}; + +/** + * SECTION:provider-support-sql + * @short_description: Adapting the SQL to the database's own SQL dialect + * @title: SQL rendering API + * @stability: Stable + * @see_also: + * + * &LIBGDA; is able to render a #GdaStatement statement to SQL in a generic way (as close as possible to the SQL + * standard). However as each database has ultimately its own SQL dialect, some parts of the rendering has + * to be specialized. + * + * Customization is achieved by providing custom implementations of SQL rendering functions for each kind of + * part in a #GdaSqlStatement structure, all packed in a #GdaSqlRenderingContext context structure. Functions + * which are not customized will be implemented by the default ones. + */ + +gchar *gda_statement_to_sql_real (GdaStatement *stmt, GdaSqlRenderingContext *context, GError **error); + +G_END_DECLS + +#endif + + + diff --git a/.flatpak-builder/cache/objects/b8/4beb1c2dea3a52ee226576ce0fbfadbc40dae02630408013a5134099c76366.file b/.flatpak-builder/cache/objects/b8/4beb1c2dea3a52ee226576ce0fbfadbc40dae02630408013a5134099c76366.file new file mode 100644 index 0000000..d8170d9 --- /dev/null +++ b/.flatpak-builder/cache/objects/b8/4beb1c2dea3a52ee226576ce0fbfadbc40dae02630408013a5134099c76366.file @@ -0,0 +1,418 @@ +/*-*- Mode: C; c-basic-offset: 8 -*-*/ + +/*** + This file is part of libcanberra. + + Copyright 2008 Lennart Poettering + + libcanberra is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation, either version 2.1 of the + License, or (at your option) any later version. + + libcanberra is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with libcanberra. If not, see + . +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include "canberra.h" +#include "proplist.h" +#include "macro.h" +#include "malloc.h" + +static unsigned calc_hash(const char *c) { + unsigned hash = 0; + + for (; *c; c++) + hash = 31 * hash + (unsigned) *c; + + return hash; +} + +/** + * ca_proplist_create: + * @p: A pointer where to fill in a pointer for the new property list. + * + * Allocate a new empty property list. + * + * Returns: 0 on success, negative error code on error. + */ +int ca_proplist_create(ca_proplist **_p) { + ca_proplist *p; + ca_return_val_if_fail(_p, CA_ERROR_INVALID); + + if (!(p = ca_new0(ca_proplist, 1))) + return CA_ERROR_OOM; + + if (!(p->mutex = ca_mutex_new())) { + ca_free(p); + return CA_ERROR_OOM; + } + + *_p = p; + + return CA_SUCCESS; +} + +static int _unset(ca_proplist *p, const char *key) { + ca_prop *prop, *nprop; + unsigned i; + + ca_return_val_if_fail(p, CA_ERROR_INVALID); + ca_return_val_if_fail(key, CA_ERROR_INVALID); + + i = calc_hash(key) % N_HASHTABLE; + + nprop = NULL; + for (prop = p->prop_hashtable[i]; prop; nprop = prop, prop = prop->next_in_slot) + if (strcmp(prop->key, key) == 0) + break; + + if (prop) { + if (nprop) + nprop->next_in_slot = prop->next_in_slot; + else + p->prop_hashtable[i] = prop->next_in_slot; + + if (prop->prev_item) + prop->prev_item->next_item = prop->next_item; + else + p->first_item = prop->next_item; + + if (prop->next_item) + prop->next_item->prev_item = prop->prev_item; + + ca_free(prop->key); + ca_free(prop); + } + + return CA_SUCCESS; +} + +/** + * ca_proplist_sets: + * @p: The property list to add this key/value pair to + * @key: The key for this key/value pair + * @value: The value for this key/value pair + * + * Add a new string key/value pair to the property list. + * + * Returns: 0 on success, negative error code on error. + */ + +int ca_proplist_sets(ca_proplist *p, const char *key, const char *value) { + ca_return_val_if_fail(p, CA_ERROR_INVALID); + ca_return_val_if_fail(key, CA_ERROR_INVALID); + ca_return_val_if_fail(value, CA_ERROR_INVALID); + + return ca_proplist_set(p, key, value, strlen(value)+1); +} + +/** + * ca_proplist_setf: + * @p: The property list to add this key/value pair to + * @key: The key for this key/value pair + * @format: The format string for the value for this key/value pair + * @...: The parameters for the format string + * + * Much like ca_proplist_sets(): add a new string key/value pair to + * the property list. Takes a standard C format string plus arguments + * and formats a string of it. + * + * Returns: 0 on success, negative error code on error. + */ + +int ca_proplist_setf(ca_proplist *p, const char *key, const char *format, ...) { + int ret; + char *k; + ca_prop *prop; + size_t size = 100; + unsigned h; + + ca_return_val_if_fail(p, CA_ERROR_INVALID); + ca_return_val_if_fail(key, CA_ERROR_INVALID); + ca_return_val_if_fail(format, CA_ERROR_INVALID); + + if (!(k = ca_strdup(key))) + return CA_ERROR_OOM; + + for (;;) { + va_list ap; + int r; + + if (!(prop = ca_malloc(CA_ALIGN(sizeof(ca_prop)) + size))) { + ca_free(k); + return CA_ERROR_OOM; + } + + + va_start(ap, format); + r = vsnprintf(CA_PROP_DATA(prop), size, format, ap); + va_end(ap); + + ((char*) CA_PROP_DATA(prop))[size-1] = 0; + + if (r > -1 && (size_t) r < size) { + prop->nbytes = (size_t) r+1; + break; + } + + if (r > -1) /* glibc 2.1 */ + size = (size_t) r+1; + else /* glibc 2.0 */ + size *= 2; + + ca_free(prop); + } + + prop->key = k; + + ca_mutex_lock(p->mutex); + + if ((ret = _unset(p, key)) < 0) { + ca_free(prop); + ca_free(k); + goto finish; + } + + h = calc_hash(key) % N_HASHTABLE; + + prop->next_in_slot = p->prop_hashtable[h]; + p->prop_hashtable[h] = prop; + + prop->prev_item = NULL; + if ((prop->next_item = p->first_item)) + prop->next_item->prev_item = prop; + p->first_item = prop; + +finish: + + ca_mutex_unlock(p->mutex); + + return ret; +} + +/** + * ca_proplist_set: + * @p: The property list to add this key/value pair to + * @key: The key for this key/value pair + * @data: The binary value for this key value pair + * @nbytes: The size of thebinary value for this key value pair. + * + * Add a new binary key/value pair to the property list. + * + * Returns: 0 on success, negative error code on error. + */ + +int ca_proplist_set(ca_proplist *p, const char *key, const void *data, size_t nbytes) { + int ret; + char *k; + ca_prop *prop; + unsigned h; + + ca_return_val_if_fail(p, CA_ERROR_INVALID); + ca_return_val_if_fail(key, CA_ERROR_INVALID); + ca_return_val_if_fail(!nbytes || data, CA_ERROR_INVALID); + + if (!(k = ca_strdup(key))) + return CA_ERROR_OOM; + + if (!(prop = ca_malloc(CA_ALIGN(sizeof(ca_prop)) + nbytes))) { + ca_free(k); + return CA_ERROR_OOM; + } + + prop->key = k; + prop->nbytes = nbytes; + memcpy(CA_PROP_DATA(prop), data, nbytes); + + ca_mutex_lock(p->mutex); + + if ((ret = _unset(p, key)) < 0) { + ca_free(prop); + ca_free(k); + goto finish; + } + + h = calc_hash(key) % N_HASHTABLE; + + prop->next_in_slot = p->prop_hashtable[h]; + p->prop_hashtable[h] = prop; + + prop->prev_item = NULL; + if ((prop->next_item = p->first_item)) + prop->next_item->prev_item = prop; + p->first_item = prop; + +finish: + + ca_mutex_unlock(p->mutex); + + return ret; +} + +/* Not exported, not self-locking */ +ca_prop* ca_proplist_get_unlocked(ca_proplist *p, const char *key) { + ca_prop *prop; + unsigned i; + + ca_return_val_if_fail(p, NULL); + ca_return_val_if_fail(key, NULL); + + i = calc_hash(key) % N_HASHTABLE; + + for (prop = p->prop_hashtable[i]; prop; prop = prop->next_in_slot) + if (strcmp(prop->key, key) == 0) + return prop; + + return NULL; +} + +/* Not exported, not self-locking */ +const char* ca_proplist_gets_unlocked(ca_proplist *p, const char *key) { + ca_prop *prop; + + ca_return_val_if_fail(p, NULL); + ca_return_val_if_fail(key, NULL); + + if (!(prop = ca_proplist_get_unlocked(p, key))) + return NULL; + + if (!memchr(CA_PROP_DATA(prop), 0, prop->nbytes)) + return NULL; + + return CA_PROP_DATA(prop); +} + +/** + * ca_proplist_destroy: + * @p: The property list to destroy + * + * Destroys a property list that was created with ca_proplist_create() earlier. + * + * Returns: 0 on success, negative error code on error. + */ + +int ca_proplist_destroy(ca_proplist *p) { + ca_prop *prop, *nprop; + + ca_return_val_if_fail(p, CA_ERROR_INVALID); + + for (prop = p->first_item; prop; prop = nprop) { + nprop = prop->next_item; + ca_free(prop->key); + ca_free(prop); + } + + ca_mutex_free(p->mutex); + + ca_free(p); + + return CA_SUCCESS; +} + +static int merge_into(ca_proplist *a, ca_proplist *b) { + int ret = CA_SUCCESS; + ca_prop *prop; + + ca_return_val_if_fail(a, CA_ERROR_INVALID); + ca_return_val_if_fail(b, CA_ERROR_INVALID); + + ca_mutex_lock(b->mutex); + + for (prop = b->first_item; prop; prop = prop->next_item) + if ((ret = ca_proplist_set(a, prop->key, CA_PROP_DATA(prop), prop->nbytes)) < 0) + break; + + ca_mutex_unlock(b->mutex); + + return ret; +} + +int ca_proplist_merge(ca_proplist **_a, ca_proplist *b, ca_proplist *c) { + ca_proplist *a; + int ret; + + ca_return_val_if_fail(_a, CA_ERROR_INVALID); + ca_return_val_if_fail(b, CA_ERROR_INVALID); + ca_return_val_if_fail(c, CA_ERROR_INVALID); + + if ((ret = ca_proplist_create(&a)) < 0) + return ret; + + if ((ret = merge_into(a, b)) < 0 || + (ret = merge_into(a, c)) < 0) { + ca_proplist_destroy(a); + return ret; + } + + *_a = a; + return CA_SUCCESS; +} + +ca_bool_t ca_proplist_contains(ca_proplist *p, const char *key) { + ca_bool_t b; + + ca_return_val_if_fail(p, FALSE); + ca_return_val_if_fail(key, FALSE); + + ca_mutex_lock(p->mutex); + b = !!ca_proplist_get_unlocked(p, key); + ca_mutex_unlock(p->mutex); + + return b; +} + +int ca_proplist_merge_ap(ca_proplist *p, va_list ap) { + int ret; + + ca_return_val_if_fail(p, CA_ERROR_INVALID); + + for (;;) { + const char *key, *value; + + if (!(key = va_arg(ap, const char*))) + break; + + if (!(value = va_arg(ap, const char*))) + return CA_ERROR_INVALID; + + if ((ret = ca_proplist_sets(p, key, value)) < 0) + return ret; + } + + return CA_SUCCESS; +} + +int ca_proplist_from_ap(ca_proplist **_p, va_list ap) { + int ret; + ca_proplist *p; + + ca_return_val_if_fail(_p, CA_ERROR_INVALID); + + if ((ret = ca_proplist_create(&p)) < 0) + return ret; + + if ((ret = ca_proplist_merge_ap(p, ap)) < 0) + goto fail; + + *_p = p; + + return CA_SUCCESS; + +fail: + ca_assert_se(ca_proplist_destroy(p) == CA_SUCCESS); + + return ret; +} diff --git a/.flatpak-builder/cache/objects/b8/86f819d0b2854c2f1faff6e4ff71351947d02685f75020d7410f59aedba154.dirtree b/.flatpak-builder/cache/objects/b8/86f819d0b2854c2f1faff6e4ff71351947d02685f75020d7410f59aedba154.dirtree new file mode 100644 index 0000000..446ec47 Binary files /dev/null and b/.flatpak-builder/cache/objects/b8/86f819d0b2854c2f1faff6e4ff71351947d02685f75020d7410f59aedba154.dirtree differ diff --git a/.flatpak-builder/cache/objects/b8/a551e83d8c7cfc6b32c80261a4689ce78758b46cfe4396f3b6caa12138d725.commit b/.flatpak-builder/cache/objects/b8/a551e83d8c7cfc6b32c80261a4689ce78758b46cfe4396f3b6caa12138d725.commit new file mode 100644 index 0000000..6681894 Binary files /dev/null and b/.flatpak-builder/cache/objects/b8/a551e83d8c7cfc6b32c80261a4689ce78758b46cfe4396f3b6caa12138d725.commit differ diff --git a/.flatpak-builder/cache/objects/b9/83dc8e4979b2ed360dc48be93c8bb7c8e1db3c762b65ac3f0823413bc3d450.file b/.flatpak-builder/cache/objects/b9/83dc8e4979b2ed360dc48be93c8bb7c8e1db3c762b65ac3f0823413bc3d450.file new file mode 100644 index 0000000..c5b6f31 Binary files /dev/null and b/.flatpak-builder/cache/objects/b9/83dc8e4979b2ed360dc48be93c8bb7c8e1db3c762b65ac3f0823413bc3d450.file differ diff --git a/.flatpak-builder/cache/objects/ba/4a2f91e1737f9dbcbcadb6f98ffc0b2d719720b3ecbe1fa0e51a16fee9761a.file b/.flatpak-builder/cache/objects/ba/4a2f91e1737f9dbcbcadb6f98ffc0b2d719720b3ecbe1fa0e51a16fee9761a.file new file mode 100644 index 0000000..32910fb --- /dev/null +++ b/.flatpak-builder/cache/objects/ba/4a2f91e1737f9dbcbcadb6f98ffc0b2d719720b3ecbe1fa0e51a16fee9761a.file @@ -0,0 +1,2091 @@ +/* + * Copyright (C) 2009 Bas Driessen + * Copyright (C) 2009 Johannes Schmid + * Copyright (C) 2009 - 2011 Murray Cumming + * Copyright (C) 2009 - 2015 Vivien Malerba + * Copyright (C) 2010 David King + * Copyright (C) 2010 Jonh Wendell + * Copyright (C) 2011 Daniel Espinosa + * Copyright (C) 2018 Pavlo Solntsev + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +#define G_LOG_DOMAIN "GDA-sql-builder" + +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Main static functions + */ +static void gda_sql_builder_class_init (GdaSqlBuilderClass *klass); +static void gda_sql_builder_init (GdaSqlBuilder *builder); +static void gda_sql_builder_finalize (GObject *object); + +static void gda_sql_builder_set_property (GObject *object, + guint param_id, + const GValue *value, + GParamSpec *pspec); + +static void gda_sql_builder_get_property (GObject *object, + guint param_id, + GValue *value, + GParamSpec *pspec); + + +typedef struct { + GdaSqlAnyPart *part; +} SqlPart; + +typedef struct { + GdaSqlStatement *main_stmt; + GHashTable *parts_hash; /* key = part ID as an GdaSqlBuilderId, value = SqlPart */ + GdaSqlBuilderId next_assigned_id; +} GdaSqlBuilderPrivate; + +G_DEFINE_TYPE_WITH_PRIVATE (GdaSqlBuilder,gda_sql_builder,G_TYPE_OBJECT) + +/* properties */ +enum { + PROP_0, + PROP_TYPE +}; + +/* module error */ +GQuark gda_sql_builder_error_quark (void) { + static GQuark quark; + if (!quark) + quark = g_quark_from_static_string ("gda_sql_builder_error"); + return quark; +} + +static void +gda_sql_builder_class_init (GdaSqlBuilderClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + /* Properties */ + object_class->set_property = gda_sql_builder_set_property; + object_class->get_property = gda_sql_builder_get_property; + object_class->finalize = gda_sql_builder_finalize; + + /** + * GdaSqlBuilder:stmt-type: + * + * Specifies the type of statement to be built, can only be + * GDA_SQL_STATEMENT_SELECT, GDA_SQL_STATEMENT_INSERT, GDA_SQL_STATEMENT_UPDATE + * or GDA_SQL_STATEMENT_DELETE + */ + g_object_class_install_property (object_class, PROP_TYPE, + g_param_spec_enum ("stmt-type", NULL, "Statement Type", + GDA_TYPE_SQL_STATEMENT_TYPE, + GDA_SQL_STATEMENT_UNKNOWN, + (G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY))); +} + +static void +any_part_free (SqlPart *part) +{ + switch (part->part->type) + { + case GDA_SQL_ANY_EXPR: + gda_sql_expr_free ((GdaSqlExpr*) part->part); + break; + default: + TO_IMPLEMENT; + } + + g_free (part); +} + +static void +gda_sql_builder_init (GdaSqlBuilder *builder) +{ + GdaSqlBuilderPrivate *priv= gda_sql_builder_get_instance_private (builder); + priv->main_stmt = NULL; + priv->parts_hash = g_hash_table_new_full (g_int_hash, g_int_equal, + g_free, (GDestroyNotify) any_part_free); + priv->next_assigned_id = G_MAXUINT; +} + + +/** + * gda_sql_builder_new: + * @stmt_type: the type of statement to build + * + * Create a new #GdaSqlBuilder object to build #GdaStatement or #GdaSqlStatement + * objects of type @stmt_type + * + * Returns: (transfer full): the newly created object, or %NULL if an error occurred (such as unsupported + * statement type) + * + * Since: 4.2 + */ +GdaSqlBuilder * +gda_sql_builder_new (GdaSqlStatementType stmt_type) +{ + return g_object_new (GDA_TYPE_SQL_BUILDER, "stmt-type", stmt_type, NULL); +} + +static void +gda_sql_builder_finalize (GObject *object) +{ + GdaSqlBuilder *builder = GDA_SQL_BUILDER (object); + GdaSqlBuilderPrivate *priv = gda_sql_builder_get_instance_private (builder); + + if (priv->main_stmt) + { + gda_sql_statement_free (priv->main_stmt); + priv->main_stmt = NULL; + } + if (priv->parts_hash) + { + g_hash_table_destroy (priv->parts_hash); + priv->parts_hash = NULL; + } + + /* parent class */ + G_OBJECT_CLASS(gda_sql_builder_parent_class)->finalize(object); +} + +static void +gda_sql_builder_set_property (GObject *object, + guint param_id, + const GValue *value, + GParamSpec *pspec) +{ + GdaSqlBuilder *builder = GDA_SQL_BUILDER (object); + GdaSqlBuilderPrivate *priv = gda_sql_builder_get_instance_private (builder); + GdaSqlStatementType stmt_type; + + switch (param_id) + { + case PROP_TYPE: + stmt_type = g_value_get_enum (value); + if ((stmt_type != GDA_SQL_STATEMENT_SELECT) && + (stmt_type != GDA_SQL_STATEMENT_UPDATE) && + (stmt_type != GDA_SQL_STATEMENT_INSERT) && + (stmt_type != GDA_SQL_STATEMENT_DELETE) && + (stmt_type != GDA_SQL_STATEMENT_COMPOUND)) { + g_critical ("Unsupported statement type: %d", stmt_type); + return; + } + priv->main_stmt = gda_sql_statement_new (stmt_type); + if (stmt_type == GDA_SQL_STATEMENT_COMPOUND) + gda_sql_builder_compound_set_type (builder, GDA_SQL_STATEMENT_COMPOUND_UNION); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + break; + } +} + +static void +gda_sql_builder_get_property (GObject *object, + guint param_id, + G_GNUC_UNUSED GValue *value, + GParamSpec *pspec) +{ + switch (param_id) + { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + break; + } +} + +static GdaSqlBuilderId +add_part (GdaSqlBuilder *builder, GdaSqlAnyPart *part) +{ + GdaSqlBuilderPrivate *priv = gda_sql_builder_get_instance_private (builder); + SqlPart *p; + GdaSqlBuilderId *realid = g_new0 (GdaSqlBuilderId, 1); + const GdaSqlBuilderId id = priv->next_assigned_id--; + *realid = id; + p = g_new0 (SqlPart, 1); + p->part = part; + g_hash_table_insert (priv->parts_hash, realid, p); + return id; +} + +static SqlPart * +get_part (GdaSqlBuilder *builder, GdaSqlBuilderId id, GdaSqlAnyPartType req_type) +{ + GdaSqlBuilderPrivate *priv = gda_sql_builder_get_instance_private (builder); + SqlPart *p; + GdaSqlBuilderId lid = id; + if (id == 0) + return NULL; + p = g_hash_table_lookup (priv->parts_hash, &lid); + if (!p) + { + g_warning (_("Unknown part ID %u"), id); + return NULL; + } + if (p->part->type != req_type) + { + g_warning (_("Unknown part type")); + return NULL; + } + return p; +} + +static GdaSqlAnyPart * +use_part (SqlPart *p, GdaSqlAnyPart *parent) +{ + if (!p) + return NULL; + + /* copy */ + GdaSqlAnyPart *anyp = NULL; + switch (p->part->type) + { + case GDA_SQL_ANY_EXPR: + anyp = (GdaSqlAnyPart*) gda_sql_expr_copy ((GdaSqlExpr*) p->part); + break; + default: + TO_IMPLEMENT; + return NULL; + } + if (anyp) + anyp->parent = parent; + return anyp; +} + +/** + * gda_sql_builder_get_statement: + * @builder: a #GdaSqlBuilder object + * @error: (nullable): a place to store errors, or %NULL + * + * Creates a new #GdaStatement statement from @builder's contents. + * + * Returns: (transfer full): a new #GdaStatement object, or %NULL if an error occurred + * + * Since: 4.2 + */ +GdaStatement * +gda_sql_builder_get_statement (GdaSqlBuilder *builder, GError **error) +{ + g_return_val_if_fail (GDA_IS_SQL_BUILDER (builder), NULL); + g_return_val_if_fail (error == NULL || *error == NULL,NULL); + + GdaSqlBuilderPrivate *priv = gda_sql_builder_get_instance_private (builder); + + if (!priv->main_stmt) + { + g_set_error (error, GDA_SQL_BUILDER_ERROR, GDA_SQL_BUILDER_MISUSE_ERROR, + "%s", _("SqlBuilder is empty")); + return NULL; + } + if (!gda_sql_statement_check_structure (priv->main_stmt, error)) + return NULL; + + return (GdaStatement*) g_object_new (GDA_TYPE_STATEMENT, "structure", priv->main_stmt, NULL); +} + +/** + * gda_sql_builder_get_sql_statement: + * @builder: a #GdaSqlBuilder object + * + * Creates a new #GdaSqlStatement structure from @builder's contents. + * + * The returned pointer belongs to @builder's internal representation. + * Use gda_sql_statement_copy() if you need to keep it. + * + * Returns: (transfer none) (nullable): a #GdaSqlStatement pointer + * + * Since: 4.2 + */ +GdaSqlStatement * +gda_sql_builder_get_sql_statement (GdaSqlBuilder *builder) +{ + g_return_val_if_fail (GDA_IS_SQL_BUILDER (builder), NULL); + GdaSqlBuilderPrivate *priv = gda_sql_builder_get_instance_private (builder); + if (!priv->main_stmt) + return NULL; + + return priv->main_stmt; +} + +/** + * gda_sql_builder_set_table: + * @builder: a #GdaSqlBuilder object + * @table_name: a table name + * + * Valid only for: INSERT, UPDATE, DELETE statements + * + * Sets the name of the table on which the built statement operates. + * + * Since: 4.2 + */ +void +gda_sql_builder_set_table (GdaSqlBuilder *builder, const gchar *table_name) +{ + g_return_if_fail (GDA_IS_SQL_BUILDER (builder)); + GdaSqlBuilderPrivate *priv = gda_sql_builder_get_instance_private (builder); + g_return_if_fail (priv->main_stmt); + g_return_if_fail (table_name && *table_name); + + GdaSqlTable *table = NULL; + + switch (priv->main_stmt->stmt_type) + { + case GDA_SQL_STATEMENT_DELETE: + { + GdaSqlStatementDelete *del = (GdaSqlStatementDelete*) priv->main_stmt->contents; + if (!del->table) + del->table = gda_sql_table_new (GDA_SQL_ANY_PART (del)); + table = del->table; + break; + } + case GDA_SQL_STATEMENT_UPDATE: + { + GdaSqlStatementUpdate *upd = (GdaSqlStatementUpdate*) priv->main_stmt->contents; + if (!upd->table) + upd->table = gda_sql_table_new (GDA_SQL_ANY_PART (upd)); + table = upd->table; + break; + } + case GDA_SQL_STATEMENT_INSERT: + { + GdaSqlStatementInsert *ins = (GdaSqlStatementInsert*) priv->main_stmt->contents; + if (!ins->table) + ins->table = gda_sql_table_new (GDA_SQL_ANY_PART (ins)); + table = ins->table; + break; + } + default: + g_warning (_("Wrong statement type")); + break; + } + + g_assert (table); + if (table->table_name) + g_free (table->table_name); + table->table_name = g_strdup (table_name); +} + +/** + * gda_sql_builder_set_where: + * @builder: a #GdaSqlBuilder object + * @cond_id: the ID of the expression to set as WHERE condition, or 0 to unset any previous WHERE condition + * + * Valid only for: UPDATE, DELETE, SELECT statements + * + * Sets the WHERE condition of the statement + * + * Since: 4.2 + */ +void +gda_sql_builder_set_where (GdaSqlBuilder *builder, GdaSqlBuilderId cond_id) +{ + g_return_if_fail (GDA_IS_SQL_BUILDER (builder)); + GdaSqlBuilderPrivate *priv = gda_sql_builder_get_instance_private (builder); + g_return_if_fail (priv->main_stmt); + + SqlPart *p = NULL; + if (cond_id > 0) + { + p = get_part (builder, cond_id, GDA_SQL_ANY_EXPR); + if (!p) + return; + } + + switch (priv->main_stmt->stmt_type) + { + case GDA_SQL_STATEMENT_UPDATE: + { + GdaSqlStatementUpdate *upd = (GdaSqlStatementUpdate*) priv->main_stmt->contents; + if (upd->cond) + gda_sql_expr_free (upd->cond); + upd->cond = (GdaSqlExpr*) use_part (p, GDA_SQL_ANY_PART (upd)); + break; + } + case GDA_SQL_STATEMENT_DELETE: + { + GdaSqlStatementDelete *del = (GdaSqlStatementDelete*) priv->main_stmt->contents; + if (del->cond) + gda_sql_expr_free (del->cond); + del->cond = (GdaSqlExpr*) use_part (p, GDA_SQL_ANY_PART (del)); + break; + } + case GDA_SQL_STATEMENT_SELECT: + { + GdaSqlStatementSelect *sel = (GdaSqlStatementSelect*) priv->main_stmt->contents; + if (sel->where_cond) + gda_sql_expr_free (sel->where_cond); + sel->where_cond = (GdaSqlExpr*) use_part (p, GDA_SQL_ANY_PART (sel)); + break; + } + default: + g_warning (_("Wrong statement type")); + break; + } +} + +/** + * gda_sql_builder_select_add_field: + * @builder: a #GdaSqlBuilder object + * @field_name: a field name + * @table_name: (nullable): a table name, or %NULL + * @alias: (nullable): an alias (eg. for the "AS" clause), or %NULL + * + * Valid only for: SELECT statements. + * + * Add a selected selected item to the SELECT statement. + * + * For non-SELECT statements, see gda_sql_builder_add_field_id(). + * + * Returns: the ID of the added field, or %0 if there was an error + * + * Since: 4.2 + */ +GdaSqlBuilderId +gda_sql_builder_select_add_field (GdaSqlBuilder *builder, const gchar *field_name, const gchar *table_name, const gchar *alias) +{ + gchar *tmp; + g_return_val_if_fail (GDA_IS_SQL_BUILDER (builder), 0); + GdaSqlBuilderPrivate *priv = gda_sql_builder_get_instance_private (builder); + g_return_val_if_fail (priv->main_stmt, 0); + if (priv->main_stmt->stmt_type != GDA_SQL_STATEMENT_SELECT) + { + g_warning (_("Wrong statement type")); + return 0; + } + g_return_val_if_fail (field_name && *field_name, 0); + + gboolean tmp_is_allocated = FALSE; + if (table_name && *table_name) + { + tmp = g_strdup_printf ("%s.%s", table_name, field_name); + tmp_is_allocated = TRUE; + } + else + tmp = (gchar*) field_name; + + const GdaSqlBuilderId field_id = gda_sql_builder_add_id (builder, tmp); + if (alias && *alias) + gda_sql_builder_add_field_value_id (builder, + field_id, + gda_sql_builder_add_id (builder, alias)); + else + gda_sql_builder_add_field_value_id (builder, + field_id, + 0); + + if (tmp_is_allocated) + g_free (tmp); + + return field_id; +} + +static GValue * +create_typed_value (GType type, va_list *ap) +{ + GValue *v = NULL; + if (type == G_TYPE_STRING) + g_value_set_string ((v = gda_value_new (G_TYPE_STRING)), va_arg (*ap, gchar*)); + else if (type == G_TYPE_BOOLEAN) + g_value_set_boolean ((v = gda_value_new (G_TYPE_BOOLEAN)), va_arg (*ap, gboolean)); + else if (type == G_TYPE_INT64) + g_value_set_int64 ((v = gda_value_new (G_TYPE_INT64)), va_arg (*ap, gint64)); + else if (type == G_TYPE_UINT64) + g_value_set_uint64 ((v = gda_value_new (G_TYPE_UINT64)), va_arg (*ap, guint64)); + else if (type == G_TYPE_INT) + g_value_set_int ((v = gda_value_new (G_TYPE_INT)), va_arg (*ap, gint)); + else if (type == G_TYPE_UINT) + g_value_set_uint ((v = gda_value_new (G_TYPE_UINT)), va_arg (*ap, guint)); + else if (type == GDA_TYPE_SHORT) + gda_value_set_short ((v = gda_value_new (GDA_TYPE_SHORT)), va_arg (*ap, gint)); + else if (type == GDA_TYPE_USHORT) + gda_value_set_ushort ((v = gda_value_new (GDA_TYPE_USHORT)), va_arg (*ap, guint)); + else if (type == G_TYPE_CHAR) + g_value_set_schar ((v = gda_value_new (G_TYPE_CHAR)), va_arg (*ap, gint)); + else if (type == G_TYPE_UCHAR) + g_value_set_uchar ((v = gda_value_new (G_TYPE_UCHAR)), va_arg (*ap, guint)); + else if (type == G_TYPE_FLOAT) + g_value_set_float ((v = gda_value_new (G_TYPE_FLOAT)), va_arg (*ap, gdouble)); + else if (type == G_TYPE_DOUBLE) + g_value_set_double ((v = gda_value_new (G_TYPE_DOUBLE)), va_arg (*ap, gdouble)); + else if (type == GDA_TYPE_NUMERIC) { + GdaNumeric *numeric; + numeric = va_arg (*ap, GdaNumeric *); + gda_value_set_numeric ((v = gda_value_new (GDA_TYPE_NUMERIC)), numeric); + } + else if (type == G_TYPE_DATE) { + GDate *gdate; + gdate = va_arg (*ap, GDate *); + g_value_set_boxed ((v = gda_value_new (G_TYPE_DATE)), gdate); + } + else if (type == GDA_TYPE_TIME) { + GdaTime *timegda; + timegda = va_arg (*ap, GdaTime *); + gda_value_set_time ((v = gda_value_new (GDA_TYPE_TIME)), timegda); + } + else if (type == G_TYPE_DATE_TIME) { + GDateTime *timestamp; + timestamp = va_arg (*ap, GDateTime *); + g_value_set_boxed ((v = gda_value_new (G_TYPE_DATE_TIME)), timestamp); + } + else if (type == GDA_TYPE_NULL) + v = gda_value_new_null (); + else if (type == G_TYPE_GTYPE) + g_value_set_gtype ((v = gda_value_new (G_TYPE_GTYPE)), va_arg (*ap, GType)); + else if (type == G_TYPE_ULONG) + g_value_set_ulong ((v = gda_value_new (G_TYPE_ULONG)), va_arg (*ap, gulong)); + else if (type == G_TYPE_LONG) + g_value_set_long ((v = gda_value_new (G_TYPE_LONG)), va_arg (*ap, glong)); + else if (type == GDA_TYPE_BINARY) { + GdaBinary *bin; + bin = va_arg (*ap, GdaBinary *); + gda_value_set_binary ((v = gda_value_new (GDA_TYPE_BINARY)), bin); + } + else if (type == GDA_TYPE_BLOB) { + GdaBlob *blob; + blob = va_arg (*ap, GdaBlob *); + gda_value_set_blob ((v = gda_value_new (GDA_TYPE_BLOB)), blob); + } + else + g_warning (_("Could not convert value to type '%s', value not defined"), g_type_name (type)); + return v; +} + +/** + * gda_sql_builder_add_field_value: + * @builder: a #GdaSqlBuilder object + * @field_name: a field name + * @type: the GType of the following argument + * @...: value to set the field to, of the type specified by @type + * + * Valid only for: INSERT, UPDATE statements. + * + * Specifies that the field represented by @field_name will be set to the value identified + * by @... of type @type. See gda_sql_builder_add_expr() for more information. + * + * This is a C convenience function. See also gda_sql_builder_add_field_value_as_gvalue(). + * + * Since: 4.2 + */ +void +gda_sql_builder_add_field_value (GdaSqlBuilder *builder, const gchar *field_name, GType type, ...) +{ + g_return_if_fail (GDA_IS_SQL_BUILDER (builder)); + GdaSqlBuilderPrivate *priv = gda_sql_builder_get_instance_private (builder); + g_return_if_fail (priv->main_stmt); + g_return_if_fail (field_name && *field_name); + + if ((priv->main_stmt->stmt_type != GDA_SQL_STATEMENT_UPDATE) && + (priv->main_stmt->stmt_type != GDA_SQL_STATEMENT_INSERT)) { + g_warning (_("Wrong statement type")); + return; + } + + GdaSqlBuilderId id1, id2; + GValue *value; + va_list ap; + + va_start (ap, type); + value = create_typed_value (type, &ap); + va_end (ap); + + if (!value) + return; + id1 = gda_sql_builder_add_id (builder, field_name); + id2 = gda_sql_builder_add_expr_value (builder, value); + gda_value_free (value); + gda_sql_builder_add_field_value_id (builder, id1, id2); +} + +/** + * gda_sql_builder_add_field_value_as_gvalue: + * @builder: a #GdaSqlBuilder object + * @field_name: a field name + * @value: (nullable): value to set the field to, or %NULL or a GDA_TYPE_NULL value to represent an SQL NULL + * + * Valid only for: INSERT, UPDATE statements. + * + * Specifies that the field represented by @field_name will be set to the value identified + * by @value + * + * Since: 4.2 + */ +void +gda_sql_builder_add_field_value_as_gvalue (GdaSqlBuilder *builder, const gchar *field_name, const GValue *value) +{ + g_return_if_fail (GDA_IS_SQL_BUILDER (builder)); + GdaSqlBuilderPrivate *priv = gda_sql_builder_get_instance_private (builder); + g_return_if_fail (priv->main_stmt); + g_return_if_fail (field_name && *field_name); + + if ((priv->main_stmt->stmt_type != GDA_SQL_STATEMENT_UPDATE) && + (priv->main_stmt->stmt_type != GDA_SQL_STATEMENT_INSERT)) { + g_warning (_("Wrong statement type")); + return; + } + + GdaSqlBuilderId id1, id2; + id1 = gda_sql_builder_add_id (builder, field_name); + id2 = gda_sql_builder_add_expr_value (builder, value); + gda_sql_builder_add_field_value_id (builder, id1, id2); +} + +/** + * gda_sql_builder_add_field_value_id: + * @builder: a #GdaSqlBuilder object + * @field_id: the ID of the field's name or definition + * @value_id: the ID of the value to set the field to, or %0 + * + * Valid only for: INSERT, UPDATE, SELECT statements + * + * For UPDATE: specifies that the field represented by @field_id will be set to the value identified + * by @value_id. + * For SELECT: add a selected item to the statement, and if @value_id is not %0, then use it as an + * alias + * For INSERT: if @field_id represents an SQL identifier (obtained using gda_sql_builder_add_id()): then if + * @value_id is not %0 then specifies that the field represented by @field_id will be set to the + * value identified by @value_id, otherwise just specifies a named field to be given a value. + * If @field_id represents a sub SELECT (obtained using gda_sql_builder_add_sub_select()), then + * this method call defines the sub SELECT from which values to insert are taken. + * + * + * See also gda_sql_builder_add_field_value() and gda_sql_builder_add_field_value_as_gvalue(). + * + * Since: 4.2 + */ +void +gda_sql_builder_add_field_value_id (GdaSqlBuilder *builder, GdaSqlBuilderId field_id, GdaSqlBuilderId value_id) +{ + g_return_if_fail (GDA_IS_SQL_BUILDER (builder)); + GdaSqlBuilderPrivate *priv = gda_sql_builder_get_instance_private (builder); + g_return_if_fail (priv->main_stmt); + + SqlPart *value_part, *field_part; + GdaSqlExpr *field_expr; + value_part = get_part (builder, value_id, GDA_SQL_ANY_EXPR); + field_part = get_part (builder, field_id, GDA_SQL_ANY_EXPR); + if (!field_part) + return; + field_expr = (GdaSqlExpr*) (field_part->part); + + /* checks */ + switch (priv->main_stmt->stmt_type) + { + case GDA_SQL_STATEMENT_UPDATE: + case GDA_SQL_STATEMENT_INSERT: + if (!field_expr->select) { + if (!field_expr->value || (G_VALUE_TYPE (field_expr->value) != G_TYPE_STRING)) { + g_warning (_("Wrong field format")); + return; + } + } + break; + case GDA_SQL_STATEMENT_SELECT: + /* no specific check */ + break; + default: + g_warning (_("Wrong statement type")); + return; + } + + /* work */ + switch (priv->main_stmt->stmt_type) + { + case GDA_SQL_STATEMENT_UPDATE: + { + GdaSqlStatementUpdate *upd = (GdaSqlStatementUpdate*) priv->main_stmt->contents; + GdaSqlField *field = gda_sql_field_new (GDA_SQL_ANY_PART (upd)); + field->field_name = g_value_dup_string (field_expr->value); + upd->fields_list = g_slist_append (upd->fields_list, field); + upd->expr_list = g_slist_append (upd->expr_list, use_part (value_part, GDA_SQL_ANY_PART (upd))); + break; + } + case GDA_SQL_STATEMENT_INSERT: + { + GdaSqlStatementInsert *ins = (GdaSqlStatementInsert*) priv->main_stmt->contents; + + if (field_expr->select) + { + switch (GDA_SQL_ANY_PART (field_expr->select)->type) + { + case GDA_SQL_STATEMENT_SELECT: + ins->select = _gda_sql_statement_select_copy (field_expr->select); + break; + case GDA_SQL_STATEMENT_COMPOUND: + ins->select = _gda_sql_statement_compound_copy (field_expr->select); + break; + default: + g_assert_not_reached (); + } + } + else + { + GdaSqlField *field = gda_sql_field_new (GDA_SQL_ANY_PART (ins)); + field->field_name = g_value_dup_string (field_expr->value); + + ins->fields_list = g_slist_append (ins->fields_list, field); + if (value_part) + { + if (! ins->values_list) + ins->values_list = g_slist_append (NULL, + g_slist_append (NULL, + use_part (value_part, + GDA_SQL_ANY_PART (ins)))); + else + ins->values_list->data = g_slist_append ((GSList*) ins->values_list->data, + use_part (value_part, + GDA_SQL_ANY_PART (ins))); + } + } + break; + } + case GDA_SQL_STATEMENT_SELECT: + { + GdaSqlStatementSelect *sel = (GdaSqlStatementSelect*) priv->main_stmt->contents; + GdaSqlSelectField *field; + field = gda_sql_select_field_new (GDA_SQL_ANY_PART (sel)); + field->expr = (GdaSqlExpr*) use_part (field_part, GDA_SQL_ANY_PART (field)); + if (value_part) + { + GdaSqlExpr *value_expr = (GdaSqlExpr*) (value_part->part); + if (G_VALUE_TYPE (value_expr->value) == G_TYPE_STRING) + field->as = g_value_dup_string (value_expr->value); + } + sel->expr_list = g_slist_append (sel->expr_list, field); + break; + } + default: + g_warning (_("Wrong statement type")); + break; + } +} + +/** + * gda_sql_builder_add_expr_value: + * @builder: a #GdaSqlBuilder object + * @value: (nullable): value to set the expression to, or %NULL or a GDA_TYPE_NULL value to represent an SQL NULL + * + * Defines an expression in @builder which may be reused to build other parts of a statement. + * + * The new expression will contain the value passed as the @value argument. + * + * If @value's type is a string then it is possible to customize how the value has to be interpreted by passing a + * specific #GdaDataHandler object as @dh. This feature is very rarely used and the @dh argument should generally + * be %NULL. + * + * Returns: the ID of the new expression, or %0 if there was an error + * + * Since: 4.2 + */ +GdaSqlBuilderId +gda_sql_builder_add_expr_value (GdaSqlBuilder *builder, const GValue *value) +{ + g_return_val_if_fail (GDA_IS_SQL_BUILDER (builder), 0); + GdaSqlBuilderPrivate *priv = gda_sql_builder_get_instance_private (builder); + g_return_val_if_fail (priv->main_stmt, 0); + + GdaSqlExpr *expr; + expr = gda_sql_expr_new (NULL); + if (value && (G_VALUE_TYPE (value) != GDA_TYPE_NULL)) + { + if (G_VALUE_TYPE (value) == G_TYPE_STRING) + { + GdaDataHandler *ldh; + ldh = gda_data_handler_get_default (G_TYPE_STRING); + expr->value = gda_value_new (G_TYPE_STRING); + g_value_take_string (expr->value, gda_data_handler_get_sql_from_value (ldh, value)); + g_object_unref (ldh); + } + else + expr->value = gda_value_copy (value); + } + else + { + expr->value = gda_value_new (G_TYPE_STRING); + g_value_set_string (expr->value, "NULL"); + } + return add_part (builder, (GdaSqlAnyPart *) expr); +} + +/** + * gda_sql_builder_add_expr: + * @builder: a #GdaSqlBuilder object + * @dh: (nullable): deprecated useless argument, just pass %NULL + * @type: the GType of the following argument + * @...: value to set the expression to, of the type specified by @type + * + * Defines an expression in @builder which may be reused to build other parts of a statement. + * + * The new expression will contain the value passed as the @... argument. + * + * If @type is G_TYPE_STRING then it is possible to customize how the value has to be interpreted by passing a + * specific #GdaDataHandler object as @dh. This feature is very rarely used and the @dh argument should generally + * be %NULL. + * + * Note that for composite types such as #GdaNumeric, #Gdate, #GdaTime, ... pointer to these + * structures are expected, they should no be passed by value. For example: + * + * + * will correspond in SQL to: + * + * '05-27-1972' + * 'my string' + * 25 + * + * + * Returns: the ID of the new expression, or %0 if there was an error + * + * Since: 4.2 + */ +GdaSqlBuilderId +gda_sql_builder_add_expr (GdaSqlBuilder *builder, G_GNUC_UNUSED GdaDataHandler *dh, GType type, ...) +{ + g_return_val_if_fail (GDA_IS_SQL_BUILDER (builder), 0); + GdaSqlBuilderPrivate *priv = gda_sql_builder_get_instance_private (builder); + g_return_val_if_fail (priv->main_stmt, 0); + + va_list ap; + GValue *value; + GdaSqlBuilderId retval; + + va_start (ap, type); + value = create_typed_value (type, &ap); + va_end (ap); + + if (!value) + return 0; + retval = gda_sql_builder_add_expr_value (builder, value); + + gda_value_free (value); + + return retval; +} + +/** + * gda_sql_builder_add_id: + * @builder: a #GdaSqlBuilder object + * @str: a string + * + * Defines an expression representing an identifier in @builder, + * which may be reused to build other parts of a statement, + * for instance as a parameter to gda_sql_builder_add_cond() or + * gda_sql_builder_add_field_value_id(). + * + * The new expression will contain the @str literal. + * For example: + * + * gda_sql_builder_add_id (b, "name") + * gda_sql_builder_add_id (b, "date") + * + * + * will be rendered as SQL as: + * + * name + * "date" + * + * + * because "date" is an SQL reserved keyword. + * + * For fields, see gda_sql_builder_add_field_id(). + * + * Returns: the ID of the new expression, or %0 if there was an error + * + * Since: 4.2 + */ +GdaSqlBuilderId +gda_sql_builder_add_id (GdaSqlBuilder *builder, const gchar *str) +{ + g_return_val_if_fail (GDA_IS_SQL_BUILDER (builder), 0); + GdaSqlBuilderPrivate *priv = gda_sql_builder_get_instance_private (builder); + g_return_val_if_fail (priv->main_stmt, 0); + + GdaSqlExpr *expr; + expr = gda_sql_expr_new (NULL); + if (str) + { + expr->value = gda_value_new (G_TYPE_STRING); + g_value_set_string (expr->value, str); + expr->value_is_ident = TRUE; + } + + return add_part (builder, (GdaSqlAnyPart *) expr); +} + +/** + * gda_sql_builder_add_field_id: + * @builder: a #GdaSqlBuilder object + * @field_name: a field name + * @table_name: (nullable): a table name, or %NULL + * + * Defines an expression representing a field in @builder, + * which may be reused to build other parts of a statement, + * for instance as a parameter to gda_sql_builder_add_cond() or + * gda_sql_builder_add_field_value_id(). + * + * Calling this with a %NULL @table_name is equivalent to calling gda_sql_builder_add_id(). + * + * For SELECT queries, see gda_sql_builder_select_add_field(). + * + * Returns: the ID of the new expression, or %0 if there was an error + * + * Since: 4.2 + */ +GdaSqlBuilderId +gda_sql_builder_add_field_id (GdaSqlBuilder *builder, const gchar *field_name, const gchar *table_name) +{ + gchar* tmp = 0; + gboolean tmp_is_allocated = FALSE; + if (table_name && *table_name) + { + tmp = g_strdup_printf ("%s.%s", table_name, field_name); + tmp_is_allocated = TRUE; + } + else + tmp = (gchar*) field_name; + + guint field_id = gda_sql_builder_add_id (builder, tmp); + + if (tmp_is_allocated) + g_free (tmp); + + return field_id; +} + +/** + * gda_sql_builder_add_param: + * @builder: a #GdaSqlBuilder object + * @param_name: parameter's name + * @type: parameter's type + * @nullok: TRUE if the parameter can be set to %NULL + * + * Defines a parameter in @builder which may be reused to build other parts of a statement. + * + * The new expression will contain the @string literal. + * For example: + * + * gda_sql_builder_add_param (b, "age", G_TYPE_INT, FALSE) + * + * + * will be rendered as SQL as: + * + * + * + * Returns: the ID of the new expression, or %0 if there was an error + * + * Since: 4.2 + */ +GdaSqlBuilderId +gda_sql_builder_add_param (GdaSqlBuilder *builder, const gchar *param_name, GType type, gboolean nullok) +{ + g_return_val_if_fail (GDA_IS_SQL_BUILDER (builder), 0); + GdaSqlBuilderPrivate *priv = gda_sql_builder_get_instance_private (builder); + g_return_val_if_fail (priv->main_stmt, 0); + g_return_val_if_fail (param_name && *param_name, 0); + + GdaSqlExpr *expr; + expr = gda_sql_expr_new (NULL); + expr->param_spec = g_new0 (GdaSqlParamSpec, 1); + expr->param_spec->name = g_strdup (param_name); + expr->param_spec->is_param = TRUE; + expr->param_spec->nullok = nullok; + expr->param_spec->g_type = type; + + return add_part (builder, (GdaSqlAnyPart *) expr); +} + +/** + * gda_sql_builder_add_cond: + * @builder: a #GdaSqlBuilder object + * @op: type of condition + * @op1: the ID of the 1st argument (not 0) + * @op2: the ID of the 2nd argument (may be %0 if @op needs only one operand) + * @op3: the ID of the 3rd argument (may be %0 if @op needs only one or two operand) + * + * Builds a new expression which represents a condition (or operation). + * + * Returns: the ID of the new expression, or %0 if there was an error + * + * Since: 4.2 + */ +GdaSqlBuilderId +gda_sql_builder_add_cond (GdaSqlBuilder *builder, GdaSqlOperatorType op, GdaSqlBuilderId op1, GdaSqlBuilderId op2, GdaSqlBuilderId op3) +{ + g_return_val_if_fail (GDA_IS_SQL_BUILDER (builder), 0); + GdaSqlBuilderPrivate *priv = gda_sql_builder_get_instance_private (builder); + g_return_val_if_fail (priv->main_stmt, 0); + + SqlPart *p1, *p2; + p1 = get_part (builder, op1, GDA_SQL_ANY_EXPR); + if (!p1) + return 0; + p2 = get_part (builder, op2, GDA_SQL_ANY_EXPR); + + GdaSqlExpr *expr; + expr = gda_sql_expr_new (NULL); + expr->cond = gda_sql_operation_new (GDA_SQL_ANY_PART (expr)); + expr->cond->operator_type = op; + expr->cond->operands = g_slist_append (NULL, use_part (p1, GDA_SQL_ANY_PART (expr->cond))); + if (p2) + { + SqlPart *p3; + expr->cond->operands = g_slist_append (expr->cond->operands, + use_part (p2, GDA_SQL_ANY_PART (expr->cond))); + p3 = get_part (builder, op3, GDA_SQL_ANY_EXPR); + if (p3) + expr->cond->operands = g_slist_append (expr->cond->operands, + use_part (p3, GDA_SQL_ANY_PART (expr->cond))); + } + + return add_part (builder, (GdaSqlAnyPart *) expr); +} + +/** + * gda_sql_builder_add_cond_v: + * @builder: a #GdaSqlBuilder object + * @op: type of condition + * @op_ids: (array length=op_ids_size): an array of ID for the arguments (not %0) + * @op_ids_size: size of @ops_ids + * + * Builds a new expression which represents a condition (or operation). + * + * As a side case, if @ops_ids_size is 1, + * then @op is ignored, and the returned ID represents @op_ids[0] (this avoids any problem for example + * when @op is GDA_SQL_OPERATOR_TYPE_AND and there is in fact only one operand). + * + * Returns: the ID of the new expression, or %0 if there was an error + * + * Since: 4.2 + */ +GdaSqlBuilderId +gda_sql_builder_add_cond_v (GdaSqlBuilder *builder, GdaSqlOperatorType op, + const GdaSqlBuilderId *op_ids, gint op_ids_size) +{ + gint i; + SqlPart **parts; + + g_return_val_if_fail (GDA_IS_SQL_BUILDER (builder), 0); + GdaSqlBuilderPrivate *priv = gda_sql_builder_get_instance_private (builder); + g_return_val_if_fail (priv->main_stmt, 0); + g_return_val_if_fail (op_ids, 0); + g_return_val_if_fail (op_ids_size > 0, 0); + + parts = g_new (SqlPart *, op_ids_size); + for (i = 0; i < op_ids_size; i++) + { + parts [i] = get_part (builder, op_ids [i], GDA_SQL_ANY_EXPR); + if (!parts [i]) + { + g_free (parts); + return 0; + } + } + + if (op_ids_size == 1) { + g_free (parts); + return op_ids [0]; + } + + GdaSqlExpr *expr; + expr = gda_sql_expr_new (NULL); + expr->cond = gda_sql_operation_new (GDA_SQL_ANY_PART (expr)); + expr->cond->operator_type = op; + expr->cond->operands = NULL; + for (i = 0; i < op_ids_size; i++) + expr->cond->operands = g_slist_append (expr->cond->operands, + use_part (parts [i], + GDA_SQL_ANY_PART (expr->cond))); + g_free (parts); + + return add_part (builder, (GdaSqlAnyPart *) expr); +} + + +typedef struct { + GdaSqlSelectTarget target; /* inheritance! */ + GdaSqlBuilderId part_id; /* copied from this part ID */ +} BuildTarget; + +/** + * gda_sql_builder_select_add_target_id: + * @builder: a #GdaSqlBuilder object + * @table_id: the ID of the expression holding a table reference (not %0) + * @alias: (nullable): the alias to give to the target, or %NULL + * + * Adds a new target to a SELECT statement. If there already exists a target representing + * the same table and the same alias (or with the same absence of alias) then the same target + * ID is returned instead of the ID of a new target. + * + * Returns: the ID of the new (or existing) target, or %0 if there was an error + * + * Since: 4.2 + */ +GdaSqlBuilderId +gda_sql_builder_select_add_target_id (GdaSqlBuilder *builder, GdaSqlBuilderId table_id, const gchar *alias) +{ + g_return_val_if_fail (GDA_IS_SQL_BUILDER (builder), 0); + GdaSqlBuilderPrivate *priv = gda_sql_builder_get_instance_private (builder); + g_return_val_if_fail (priv->main_stmt, 0); + + if (priv->main_stmt->stmt_type != GDA_SQL_STATEMENT_SELECT) + { + g_warning (_("Wrong statement type")); + return 0; + } + + SqlPart *p; + p = get_part (builder, table_id, GDA_SQL_ANY_EXPR); + if (!p) + return 0; + + /* check for an already existing target with the same characteristics */ + GdaSqlStatementSelect *sel = (GdaSqlStatementSelect*) priv->main_stmt->contents; + if (sel->from) + { + gchar *ser; + GSList *list; + + g_assert (p->part->type == GDA_SQL_ANY_EXPR); + ser = gda_sql_expr_serialize ((GdaSqlExpr*) p->part); + for (list = sel->from->targets; list; list = list->next) + { + BuildTarget *bt = (BuildTarget*) list->data; + GdaSqlSelectTarget *t = (GdaSqlSelectTarget*) list->data; + gboolean idalias = FALSE; + if (alias && t->as && !strcmp (t->as, alias)) + idalias = TRUE; + else if (!alias && ! t->as) + idalias = TRUE; + + gchar *tmp; + tmp = gda_sql_expr_serialize (t->expr); + if (! strcmp (ser, tmp)) + { + if (idalias) { + g_free (tmp); + g_free (ser); + return bt->part_id; + } + } + g_free (tmp); + } + g_free (ser); + } + + BuildTarget *btarget; + GdaSqlSelectTarget *target; + btarget = g_new0 (BuildTarget, 1); + GDA_SQL_ANY_PART (btarget)->type = GDA_SQL_ANY_SQL_SELECT_TARGET; + GDA_SQL_ANY_PART (btarget)->parent = GDA_SQL_ANY_PART (sel->from); + btarget->part_id = priv->next_assigned_id --; + + target = (GdaSqlSelectTarget*) btarget; + target->expr = (GdaSqlExpr*) use_part (p, GDA_SQL_ANY_PART (btarget)); + if (alias && *alias) + target->as = g_strdup (alias); + if (target->expr->value && g_value_get_string (target->expr->value)) + target->table_name = g_value_dup_string (target->expr->value); + + /* add target to sel->from. NOTE: @btarget is NOT added to the "repository" or GdaSqlAnyPart parts + * like others */ + if (!sel->from) + sel->from = gda_sql_select_from_new (GDA_SQL_ANY_PART (sel)); + sel->from->targets = g_slist_append (sel->from->targets, btarget); + + return btarget->part_id; +} + + +/** + * gda_sql_builder_select_add_target: + * @builder: a #GdaSqlBuilder object + * @table_name: the name of the target table + * @alias: (nullable): the alias to give to the target, or %NULL + * + * Adds a new target to a SELECT statement + * + * Returns: the ID of the new target, or %0 if there was an error + * + * Since: 4.2 + */ +GdaSqlBuilderId +gda_sql_builder_select_add_target (GdaSqlBuilder *builder, const gchar *table_name, const gchar *alias) +{ + GdaSqlBuilderId id; + g_return_val_if_fail (GDA_IS_SQL_BUILDER (builder), 0); + GdaSqlBuilderPrivate *priv = gda_sql_builder_get_instance_private (builder); + g_return_val_if_fail (priv->main_stmt, 0); + + if (priv->main_stmt->stmt_type != GDA_SQL_STATEMENT_SELECT) + { + g_warning (_("Wrong statement type")); + return 0; + } + g_return_val_if_fail (table_name && *table_name, 0); + + id = gda_sql_builder_select_add_target_id (builder, + gda_sql_builder_add_id (builder, table_name), + alias); + return id; +} + +typedef struct { + GdaSqlSelectJoin join; /* inheritance! */ + GdaSqlBuilderId part_id; /* copied from this part ID */ +} BuilderJoin; + +/** + * gda_sql_builder_select_join_targets: + * @builder: a #GdaSqlBuilder object + * @left_target_id: the ID of the left target to use (not %0) + * @right_target_id: the ID of the right target to use (not %0) + * @join_type: the type of join + * @join_expr: joining expression's ID, or %0 + * + * Joins two targets in a SELECT statement, using the @join_type type of join. + * + * Note: if the target represented by @left_target_id is actually situated after (on the right) of + * the target represented by @right_target_id, then the actual type of join may be switched from + * %GDA_SQL_SELECT_JOIN_LEFT to %GDA_SQL_SELECT_JOIN_RIGHT or from %GDA_SQL_SELECT_JOIN_RIGHT to + * %GDA_SQL_SELECT_JOIN_LEFT. + * + * Returns: the ID of the new join, or %0 if there was an error + * + * Since: 4.2 + */ +GdaSqlBuilderId +gda_sql_builder_select_join_targets (GdaSqlBuilder *builder, + GdaSqlBuilderId left_target_id, + GdaSqlBuilderId right_target_id, + GdaSqlSelectJoinType join_type, + GdaSqlBuilderId join_expr) +{ + g_return_val_if_fail (GDA_IS_SQL_BUILDER (builder), 0); + GdaSqlBuilderPrivate *priv = gda_sql_builder_get_instance_private (builder); + g_return_val_if_fail (priv->main_stmt, 0); + + if (priv->main_stmt->stmt_type != GDA_SQL_STATEMENT_SELECT) { + g_warning (_("Wrong statement type")); + return 0; + } + + /* determine join position */ + GdaSqlStatementSelect *sel = (GdaSqlStatementSelect*) priv->main_stmt->contents; + GSList *list; + gint left_pos = -1, right_pos = -1; + gint pos; + for (pos = 0, list = sel->from ? sel->from->targets : NULL; list; pos++, list = list->next) + { + BuildTarget *btarget = (BuildTarget*) list->data; + if (btarget->part_id == left_target_id) + left_pos = pos; + else if (btarget->part_id == right_target_id) + right_pos = pos; + if ((left_pos != -1) && (right_pos != -1)) + break; + } + + if (left_pos == -1) { + g_warning (_("Unknown left part target ID %u"), left_target_id); + return 0; + } + + if (right_pos == -1) { + g_warning (_("Unknown right part target ID %u"), right_target_id); + return 0; + } + + if (left_pos > right_pos) + { + GdaSqlSelectJoinType jt; + switch (join_type) { + case GDA_SQL_SELECT_JOIN_LEFT: + jt = GDA_SQL_SELECT_JOIN_RIGHT; + break; + case GDA_SQL_SELECT_JOIN_RIGHT: + jt = GDA_SQL_SELECT_JOIN_LEFT; + break; + default: + jt = join_type; + break; + } + return gda_sql_builder_select_join_targets (builder, right_target_id, + left_target_id, jt, join_expr); + } + + /* create join */ + BuilderJoin *bjoin; + GdaSqlSelectJoin *join; + + bjoin = g_new0 (BuilderJoin, 1); + GDA_SQL_ANY_PART (bjoin)->type = GDA_SQL_ANY_SQL_SELECT_JOIN; + GDA_SQL_ANY_PART (bjoin)->parent = GDA_SQL_ANY_PART (sel->from); + bjoin->part_id = priv->next_assigned_id --; + join = (GdaSqlSelectJoin*) bjoin; + join->type = join_type; + join->position = right_pos; + + SqlPart *ep; + ep = get_part (builder, join_expr, GDA_SQL_ANY_EXPR); + if (ep) + join->expr = (GdaSqlExpr*) use_part (ep, GDA_SQL_ANY_PART (join)); + + sel->from->joins = g_slist_append (sel->from->joins, bjoin); + + return bjoin->part_id; +} + +/** + * gda_sql_builder_join_add_field: + * @builder: a #GdaSqlBuilder object + * @join_id: the ID of the join to modify (not %0) + * @field_name: the name of the field to use in the join condition (not %NULL) + * + * Alter a join in a SELECT statement to make its condition use equal field + * values in the fields named @field_name in both tables, via the USING keyword. + * + * Since: 4.2 + */ +void +gda_sql_builder_join_add_field (GdaSqlBuilder *builder, GdaSqlBuilderId join_id, const gchar *field_name) +{ + g_return_if_fail (GDA_IS_SQL_BUILDER (builder)); + GdaSqlBuilderPrivate *priv = gda_sql_builder_get_instance_private (builder); + g_return_if_fail (priv->main_stmt); + g_return_if_fail (field_name); + + if (priv->main_stmt->stmt_type != GDA_SQL_STATEMENT_SELECT) { + g_warning (_("Wrong statement type")); + return; + } + + /* determine join */ + GdaSqlStatementSelect *sel = (GdaSqlStatementSelect*) priv->main_stmt->contents; + GdaSqlSelectJoin *join = NULL; + GSList *list; + for (list = sel->from ? sel->from->joins : NULL; list; list = list->next) + { + BuilderJoin *bjoin = (BuilderJoin*) list->data; + if (bjoin->part_id == join_id) + { + join = (GdaSqlSelectJoin*) bjoin; + break; + } + } + if (!join) { + g_warning (_("Unknown part ID %u"), join_id); + return; + } + + GdaSqlField *field; + field = gda_sql_field_new (GDA_SQL_ANY_PART (join)); + field->field_name = g_strdup (field_name); + join->use = g_slist_append (join->use, field); +} + +/** + * gda_sql_builder_select_order_by: + * @builder: a #GdaSqlBuiler + * @expr_id: the ID of the expression to use during sorting (not %0) + * @asc: %TRUE for an ascending sorting + * @collation_name: (nullable): name of the collation to use when sorting, or %NULL + * + * Adds a new ORDER BY expression to a SELECT statement. + * + * Since: 4.2 + */ +void +gda_sql_builder_select_order_by (GdaSqlBuilder *builder, GdaSqlBuilderId expr_id, + gboolean asc, const gchar *collation_name) +{ + SqlPart *part; + GdaSqlStatementSelect *sel; + GdaSqlSelectOrder *sorder; + + g_return_if_fail (GDA_IS_SQL_BUILDER (builder)); + GdaSqlBuilderPrivate *priv = gda_sql_builder_get_instance_private (builder); + g_return_if_fail (expr_id > 0); + + if (priv->main_stmt->stmt_type != GDA_SQL_STATEMENT_SELECT) { + g_warning (_("Wrong statement type")); + return; + } + + part = get_part (builder, expr_id, GDA_SQL_ANY_EXPR); + if (!part) + return; + sel = (GdaSqlStatementSelect*) priv->main_stmt->contents; + + sorder = gda_sql_select_order_new (GDA_SQL_ANY_PART (sel)); + sorder->expr = (GdaSqlExpr*) use_part (part, GDA_SQL_ANY_PART (sorder)); + sorder->asc = asc; + if (collation_name && *collation_name) + sorder->collation_name = g_strdup (collation_name); + sel->order_by = g_slist_append (sel->order_by, sorder); +} + +/** + * gda_sql_builder_select_set_distinct: + * @builder: a #GdaSqlBuilder object + * @distinct: set to %TRUE to have the DISTINCT requirement + * @expr_id: the ID of the DISTINCT ON expression, or %0 if no expression is to be used. It is ignored + * if @distinct is %FALSE. + * + * Defines (if @distinct is %TRUE) or removes (if @distinct is %FALSE) a DISTINCT clause + * for a SELECT statement. + * + * If @distinct is %TRUE, then the ID of an expression can be specified as the @expr_id argument: + * if not %0, this is the expression used to apply the DISTINCT clause on (the resuting SQL + * will then usually be "... DISTINCT ON <expression>..."). + * + * Since: 4.2 + */ +void +gda_sql_builder_select_set_distinct (GdaSqlBuilder *builder, gboolean distinct, GdaSqlBuilderId expr_id) +{ + GdaSqlBuilderPrivate *priv = gda_sql_builder_get_instance_private (builder); + GdaSqlStatementSelect *sel; + SqlPart *part = NULL; + + g_return_if_fail (GDA_IS_SQL_BUILDER (builder)); + + if (priv->main_stmt->stmt_type != GDA_SQL_STATEMENT_SELECT) { + g_warning (_("Wrong statement type")); + return; + } + + if (expr_id) + { + part = get_part (builder, expr_id, GDA_SQL_ANY_EXPR); + if (!part) + return; + } + + sel = (GdaSqlStatementSelect*) priv->main_stmt->contents; + if (sel->distinct_expr) + { + gda_sql_expr_free (sel->distinct_expr); + sel->distinct_expr = NULL; + } + + if (distinct && part) + sel->distinct_expr = (GdaSqlExpr*) use_part (part, GDA_SQL_ANY_PART (sel)); + sel->distinct = distinct; +} + +/** + * gda_sql_builder_select_set_limit: + * @builder: a #GdaSqlBuilder object + * @limit_count_expr_id: the ID of the LIMIT expression, or %0 + * @limit_offset_expr_id: the ID of the OFFSET expression, or %0 + * + * If @limit_count_expr_id is not %0, defines the maximum number of rows in the #GdaDataModel + * resulting from the execution of the built statement. In this case, the offset from which the + * rows must be collected can be defined by the @limit_offset_expr_id expression if not %0 (note that + * this feature may not be supported by all the database providers). + * + * If @limit_count_expr_id is %0, then removes any LIMIT which may have been imposed by a previous + * call to this method. + * + * Since: 4.2 + */ +void +gda_sql_builder_select_set_limit (GdaSqlBuilder *builder, + GdaSqlBuilderId limit_count_expr_id, + GdaSqlBuilderId limit_offset_expr_id) +{ + GdaSqlStatementSelect *sel; + SqlPart *part1 = NULL, *part2 = NULL; + + g_return_if_fail (GDA_IS_SQL_BUILDER (builder)); + GdaSqlBuilderPrivate *priv = gda_sql_builder_get_instance_private (builder); + + if (priv->main_stmt->stmt_type != GDA_SQL_STATEMENT_SELECT) { + g_warning (_("Wrong statement type")); + return; + } + + if (limit_count_expr_id) + { + part1 = get_part (builder, limit_count_expr_id, GDA_SQL_ANY_EXPR); + if (!part1) + return; + } + if (limit_offset_expr_id) + { + part2 = get_part (builder, limit_offset_expr_id, GDA_SQL_ANY_EXPR); + if (!part2) + return; + } + + sel = (GdaSqlStatementSelect*) priv->main_stmt->contents; + + if (sel->limit_count) + { + gda_sql_expr_free (sel->limit_count); + sel->limit_count = NULL; + } + if (sel->limit_offset) + { + gda_sql_expr_free (sel->limit_offset); + sel->limit_offset = NULL; + } + if (part1) + sel->limit_count = (GdaSqlExpr*) use_part (part1, GDA_SQL_ANY_PART (sel)); + if (part2) + sel->limit_offset = (GdaSqlExpr*) use_part (part2, GDA_SQL_ANY_PART (sel)); +} + +/** + * gda_sql_builder_select_set_having: + * @builder: a #GdaSqlBuilder object + * @cond_id: the ID of the expression to set as HAVING condition, or 0 to unset any previous HAVING condition + * + * Valid only for: SELECT statements + * + * Sets the HAVING condition of the statement + * + * Since: 4.2 + */ +void +gda_sql_builder_select_set_having (GdaSqlBuilder *builder, GdaSqlBuilderId cond_id) +{ + GdaSqlStatementSelect *sel; + + g_return_if_fail (GDA_IS_SQL_BUILDER (builder)); + GdaSqlBuilderPrivate *priv = gda_sql_builder_get_instance_private (builder); + + if (priv->main_stmt->stmt_type != GDA_SQL_STATEMENT_SELECT) { + g_warning (_("Wrong statement type")); + return; + } + + SqlPart *p = NULL; + if (cond_id > 0) { + p = get_part (builder, cond_id, GDA_SQL_ANY_EXPR); + if (!p) + return; + } + + sel = (GdaSqlStatementSelect*) priv->main_stmt->contents; + if (sel->having_cond) + gda_sql_expr_free (sel->having_cond); + sel->having_cond = (GdaSqlExpr*) use_part (p, GDA_SQL_ANY_PART (sel)); +} + +/** + * gda_sql_builder_select_group_by: + * @builder: a #GdaSqlBuilder object + * @expr_id: the ID of the expression to set use in the GROUP BY clause, or 0 to unset any previous GROUP BY clause + * + * Valid only for: SELECT statements + * + * Adds the @expr_id expression to the GROUP BY clause's expressions list + * + * Since: 4.2 + */ +void +gda_sql_builder_select_group_by (GdaSqlBuilder *builder, GdaSqlBuilderId expr_id) +{ + GdaSqlStatementSelect *sel; + + g_return_if_fail (GDA_IS_SQL_BUILDER (builder)); + GdaSqlBuilderPrivate *priv = gda_sql_builder_get_instance_private (builder); + + if (priv->main_stmt->stmt_type != GDA_SQL_STATEMENT_SELECT) { + g_warning (_("Wrong statement type")); + return; + } + + SqlPart *p = NULL; + if (expr_id > 0) + { + p = get_part (builder, expr_id, GDA_SQL_ANY_EXPR); + if (!p) + return; + } + + sel = (GdaSqlStatementSelect*) priv->main_stmt->contents; + if (p) + sel->group_by = g_slist_append (sel->group_by, + (GdaSqlExpr*) use_part (p, GDA_SQL_ANY_PART (sel))); + else if (sel->group_by) + { + g_slist_free_full (sel->group_by, (GDestroyNotify) gda_sql_expr_free); + sel->group_by = NULL; + } +} + +/** + * gda_sql_builder_add_function: + * @builder: a #GdaSqlBuilder object + * @func_name: the functions's name + * @...: a list, terminated with %0, of each function's argument's ID + * + * Builds a new expression which represents a function applied to some arguments + * + * Returns: the ID of the new expression, or %0 if there was an error + * + * Since: 4.2 + */ +GdaSqlBuilderId +gda_sql_builder_add_function (GdaSqlBuilder *builder, const gchar *func_name, ...) +{ + g_return_val_if_fail (GDA_IS_SQL_BUILDER (builder), 0); + GdaSqlBuilderPrivate *priv = gda_sql_builder_get_instance_private (builder); + g_return_val_if_fail (priv->main_stmt, 0); + g_return_val_if_fail (func_name && *func_name, 0); + + GdaSqlExpr *expr; + GSList *list = NULL; + va_list ap; + SqlPart *part; + GdaSqlBuilderId aid; + + expr = gda_sql_expr_new (NULL); + expr->func = gda_sql_function_new (GDA_SQL_ANY_PART (expr)); + expr->func->function_name = g_strdup (func_name); + + va_start (ap, func_name); + for (aid = va_arg (ap, GdaSqlBuilderId); aid; aid = va_arg (ap, GdaSqlBuilderId)) + { + part = get_part (builder, aid, GDA_SQL_ANY_EXPR); + if (!part) + { + expr->func->args_list = list; + gda_sql_expr_free (expr); + va_end (ap); + return 0; + } + list = g_slist_prepend (list, use_part (part, GDA_SQL_ANY_PART (expr->func))); + } + va_end (ap); + expr->func->args_list = g_slist_reverse (list); + + return add_part (builder, (GdaSqlAnyPart *) expr); +} + +/** + * gda_sql_builder_add_function_v: (rename-to gda_sql_builder_add_function) + * @builder: a #GdaSqlBuilder object + * @func_name: the functions's name + * @args: (array length=args_size): an array of IDs representing the function's arguments + * @args_size: @args's size + * + * Builds a new expression which represents a function applied to some arguments + * + * Returns: the ID of the new expression, or %0 if there was an error + * + * Since: 4.2 + */ +GdaSqlBuilderId +gda_sql_builder_add_function_v (GdaSqlBuilder *builder, + const gchar *func_name, + const GdaSqlBuilderId *args, + gint args_size) +{ + gint i; + g_return_val_if_fail (GDA_IS_SQL_BUILDER (builder), 0); + GdaSqlBuilderPrivate *priv = gda_sql_builder_get_instance_private (builder); + g_return_val_if_fail (priv->main_stmt, 0); + g_return_val_if_fail (func_name && *func_name, 0); + + GdaSqlExpr *expr; + GSList *list = NULL; + expr = gda_sql_expr_new (NULL); + expr->func = gda_sql_function_new (GDA_SQL_ANY_PART (expr)); + expr->func->function_name = g_strdup (func_name); + + for (i = 0; i < args_size; i++) + { + SqlPart *part; + part = get_part (builder, args[i], GDA_SQL_ANY_EXPR); + if (!part) + { + expr->func->args_list = list; + gda_sql_expr_free (expr); + return 0; + } + list = g_slist_prepend (list, use_part (part, GDA_SQL_ANY_PART (expr->func))); + } + expr->func->args_list = g_slist_reverse (list); + + return add_part (builder, (GdaSqlAnyPart *) expr); +} + +/** + * gda_sql_builder_add_sub_select: + * @builder: a #GdaSqlBuilder object + * @sqlst: a pointer to a #GdaSqlStatement, which has to be a SELECT or compound SELECT. This will be copied. + * + * Adds an expression which is a subselect. + * + * Returns: the ID of the new expression, or %0 if there was an error + * + * Since: 4.2 + */ +GdaSqlBuilderId +gda_sql_builder_add_sub_select (GdaSqlBuilder *builder, GdaSqlStatement *sqlst) +{ + g_return_val_if_fail (GDA_IS_SQL_BUILDER (builder), 0); + GdaSqlBuilderPrivate *priv = gda_sql_builder_get_instance_private (builder); + g_return_val_if_fail (priv->main_stmt, 0); + g_return_val_if_fail (sqlst, 0); + g_return_val_if_fail ((sqlst->stmt_type == GDA_SQL_STATEMENT_SELECT) || + (sqlst->stmt_type == GDA_SQL_STATEMENT_COMPOUND), 0); + + GdaSqlExpr *expr; + expr = gda_sql_expr_new (NULL); + + switch (sqlst->stmt_type) + { + case GDA_SQL_STATEMENT_SELECT: + expr->select = _gda_sql_statement_select_copy (sqlst->contents); + break; + case GDA_SQL_STATEMENT_COMPOUND: + expr->select = _gda_sql_statement_compound_copy (sqlst->contents); + break; + default: + g_assert_not_reached (); + } + + GDA_SQL_ANY_PART (expr->select)->parent = GDA_SQL_ANY_PART (expr); + + return add_part (builder, (GdaSqlAnyPart *) expr); +} + +/** + * gda_sql_builder_compound_set_type: + * @builder: a #GdaSqlBuilder object + * @compound_type: a type of compound + * + * Changes the type of compound which @builder is making, for a COMPOUND statement + * + * Since: 4.2 + */ +void +gda_sql_builder_compound_set_type (GdaSqlBuilder *builder, GdaSqlStatementCompoundType compound_type) +{ + GdaSqlStatementCompound *cstmt; + g_return_if_fail (GDA_IS_SQL_BUILDER (builder)); + GdaSqlBuilderPrivate *priv = gda_sql_builder_get_instance_private (builder); + g_return_if_fail (priv->main_stmt); + if (priv->main_stmt->stmt_type != GDA_SQL_STATEMENT_COMPOUND) { + g_warning (_("Wrong statement type")); + return; + } + + cstmt = (GdaSqlStatementCompound*) priv->main_stmt->contents; + cstmt->compound_type = compound_type; +} + +/** + * gda_sql_builder_compound_add_sub_select: + * @builder: a #GdaSqlBuilder object + * @sqlst: a pointer to a #GdaSqlStatement, which has to be a SELECT or compound SELECT. This will be copied. + * + * Add a sub select to a COMPOUND statement + * + * Since: 4.2 + */ +void +gda_sql_builder_compound_add_sub_select (GdaSqlBuilder *builder, GdaSqlStatement *sqlst) +{ + GdaSqlStatementCompound *cstmt; + GdaSqlStatement *sub; + + g_return_if_fail (GDA_IS_SQL_BUILDER (builder)); + GdaSqlBuilderPrivate *priv = gda_sql_builder_get_instance_private (builder); + g_return_if_fail (priv->main_stmt); + if (priv->main_stmt->stmt_type != GDA_SQL_STATEMENT_COMPOUND) { + g_warning (_("Wrong statement type")); + return; + } + g_return_if_fail (sqlst); + g_return_if_fail ((sqlst->stmt_type == GDA_SQL_STATEMENT_SELECT) || + (sqlst->stmt_type == GDA_SQL_STATEMENT_COMPOUND)); + + cstmt = (GdaSqlStatementCompound*) priv->main_stmt->contents; + sub = gda_sql_statement_copy (sqlst); + + cstmt->stmt_list = g_slist_append (cstmt->stmt_list, sub); +} + + +/** + * gda_sql_builder_compound_add_sub_select_from_builder: + * @builder: a #GdaSqlBuilder object + * @subselect: a #GdaSqlBuilder, which has to be a SELECT or compound SELECT. This will be copied. + * + * Add a sub select to a COMPOUND statement + * + * Since: 4.2 + */ +void +gda_sql_builder_compound_add_sub_select_from_builder (GdaSqlBuilder *builder, GdaSqlBuilder *subselect) +{ + GdaSqlStatementCompound *cstmt; + GdaSqlStatement *sqlst; + GdaSqlStatement *sub; + + g_return_if_fail (GDA_IS_SQL_BUILDER (builder)); + GdaSqlBuilderPrivate *priv = gda_sql_builder_get_instance_private (builder); + g_return_if_fail (priv->main_stmt); + g_return_if_fail (GDA_IS_SQL_BUILDER (subselect)); +// g_return_if_fail (subselect->priv->main_stmt); + if (priv->main_stmt->stmt_type != GDA_SQL_STATEMENT_COMPOUND) { + g_warning (_("Wrong statement type")); + return; + } + sqlst = gda_sql_builder_get_sql_statement(subselect); + g_return_if_fail (sqlst); + g_return_if_fail ((sqlst->stmt_type == GDA_SQL_STATEMENT_SELECT) || + (sqlst->stmt_type == GDA_SQL_STATEMENT_COMPOUND)); + + cstmt = (GdaSqlStatementCompound*) priv->main_stmt->contents; + sub = gda_sql_statement_copy (sqlst); + + cstmt->stmt_list = g_slist_append (cstmt->stmt_list, sub); +} + +/** + * gda_sql_builder_add_case: + * @builder: a #GdaSqlBuilder object + * @test_expr: the expression ID representing the test of the CASE, or %0 + * @else_expr: the expression ID representing the ELSE expression, or %0 + * @...: a list, terminated by a %0, of (WHEN expression ID, THEN expression ID) representing + * all the test cases + * + * Creates a new CASE ... WHEN ... THEN ... ELSE ... END expression. + * + * Returns: the ID of the new expression, or %0 if there was an error + * + * Since: 4.2 + */ +GdaSqlBuilderId +gda_sql_builder_add_case (GdaSqlBuilder *builder, + GdaSqlBuilderId test_expr, + GdaSqlBuilderId else_expr, ...) +{ + g_return_val_if_fail (GDA_IS_SQL_BUILDER (builder), 0); + GdaSqlBuilderPrivate *priv = gda_sql_builder_get_instance_private (builder); + g_return_val_if_fail (priv->main_stmt, 0); + + SqlPart *ptest, *pelse; + ptest = get_part (builder, test_expr, GDA_SQL_ANY_EXPR); + pelse = get_part (builder, else_expr, GDA_SQL_ANY_EXPR); + + GdaSqlExpr *expr; + expr = gda_sql_expr_new (NULL); + + expr->case_s = gda_sql_case_new (GDA_SQL_ANY_PART (expr)); + if (ptest) + expr->case_s->base_expr = (GdaSqlExpr*) use_part (ptest, GDA_SQL_ANY_PART (expr->case_s)); + if (pelse) + expr->case_s->else_expr = (GdaSqlExpr*) use_part (pelse, GDA_SQL_ANY_PART (expr->case_s)); + + va_list ap; + GdaSqlBuilderId id1; + va_start (ap, else_expr); + for (id1 = va_arg (ap, GdaSqlBuilderId); id1; id1 = va_arg (ap, GdaSqlBuilderId)) + { + GdaSqlBuilderId id2; + SqlPart *pwhen, *pthen; + id2 = va_arg (ap, GdaSqlBuilderId); + if (!id2) + goto cleanups; + pwhen = get_part (builder, id1, GDA_SQL_ANY_EXPR); + if (!pwhen) + goto cleanups; + pthen = get_part (builder, id2, GDA_SQL_ANY_EXPR); + if (!pthen) + goto cleanups; + expr->case_s->when_expr_list = g_slist_prepend (expr->case_s->when_expr_list, + use_part (pwhen, GDA_SQL_ANY_PART (expr->case_s))); + expr->case_s->then_expr_list = g_slist_prepend (expr->case_s->then_expr_list, + use_part (pthen, GDA_SQL_ANY_PART (expr->case_s))); + } + va_end (ap); + expr->case_s->when_expr_list = g_slist_reverse (expr->case_s->when_expr_list); + expr->case_s->then_expr_list = g_slist_reverse (expr->case_s->then_expr_list); + return add_part (builder, (GdaSqlAnyPart *) expr); + + cleanups: + va_end (ap); + gda_sql_expr_free (expr); + return 0; +} + +/** + * gda_sql_builder_add_case_v: (rename-to gda_sql_builder_add_case) + * @builder: a #GdaSqlBuilder object + * @test_expr: the expression ID representing the test of the CASE, or %0 + * @else_expr: the expression ID representing the ELSE expression, or %0 + * @when_array: (array length=args_size): an array containing each WHEN expression ID, having at least @args_size elements + * @then_array: (array length=args_size): an array containing each THEN expression ID, having at least @args_size elements + * @args_size: the size of @when_array and @then_array + * + * Creates a new CASE ... WHEN ... THEN ... ELSE ... END expression. The WHEN expression and the THEN + * expression IDs are taken from the @when_array and @then_array at the same index, for each index inferior to + * @args_size. + * + * Returns: the ID of the new expression, or %0 if there was an error + * + * Since: 4.2 + */ +GdaSqlBuilderId +gda_sql_builder_add_case_v (GdaSqlBuilder *builder, + GdaSqlBuilderId test_expr, + GdaSqlBuilderId else_expr, + const GdaSqlBuilderId *when_array, + const GdaSqlBuilderId *then_array, + gint args_size) +{ + g_return_val_if_fail (GDA_IS_SQL_BUILDER (builder), 0); + GdaSqlBuilderPrivate *priv = gda_sql_builder_get_instance_private (builder); + g_return_val_if_fail (priv->main_stmt, 0); + + SqlPart *ptest, *pelse; + ptest = get_part (builder, test_expr, GDA_SQL_ANY_EXPR); + pelse = get_part (builder, else_expr, GDA_SQL_ANY_EXPR); + + GdaSqlExpr *expr; + expr = gda_sql_expr_new (NULL); + + expr->case_s = gda_sql_case_new (GDA_SQL_ANY_PART (expr)); + if (ptest) + expr->case_s->base_expr = (GdaSqlExpr*) use_part (ptest, GDA_SQL_ANY_PART (expr->case_s)); + if (pelse) + expr->case_s->else_expr = (GdaSqlExpr*) use_part (pelse, GDA_SQL_ANY_PART (expr->case_s)); + + gint i; + for (i = 0; i < args_size; i++) + { + SqlPart *pwhen, *pthen; + pwhen = get_part (builder, when_array[i], GDA_SQL_ANY_EXPR); + if (!pwhen) + goto cleanups; + pthen = get_part (builder, then_array[i], GDA_SQL_ANY_EXPR); + if (!pthen) + goto cleanups; + expr->case_s->when_expr_list = g_slist_prepend (expr->case_s->when_expr_list, + use_part (pwhen, GDA_SQL_ANY_PART (expr->case_s))); + expr->case_s->then_expr_list = g_slist_prepend (expr->case_s->then_expr_list, + use_part (pthen, GDA_SQL_ANY_PART (expr->case_s))); + } + expr->case_s->when_expr_list = g_slist_reverse (expr->case_s->when_expr_list); + expr->case_s->then_expr_list = g_slist_reverse (expr->case_s->then_expr_list); + return add_part (builder, (GdaSqlAnyPart *) expr); + + cleanups: + gda_sql_expr_free (expr); + return 0; +} + +/** + * gda_sql_builder_export_expression: + * @builder: a #GdaSqlBuilder object + * @id: the ID of the expression to be exported, (must be a valid ID in @builder, not %0) + * + * Exports a part managed by @builder as a new #GdaSqlExpr, which can represent any expression + * in a statement. + * + * Returns: a pointer to a new #GdaSqlExpr structure, free using gda_sql_expr_free() when not + * needed anymore. If the part with @id as ID cannot be found, the returned value is %NULL. + * + * Since: 4.2 + */ +GdaSqlExpr * +gda_sql_builder_export_expression (GdaSqlBuilder *builder, GdaSqlBuilderId id) +{ + g_return_val_if_fail (GDA_IS_SQL_BUILDER (builder), NULL); + GdaSqlBuilderPrivate *priv = gda_sql_builder_get_instance_private (builder); + g_return_val_if_fail (priv->main_stmt, NULL); + + SqlPart *part; + part = get_part (builder, id, GDA_SQL_ANY_EXPR); + if (! part) + return NULL; + g_return_val_if_fail (part->part->type == GDA_SQL_ANY_EXPR, NULL); + return gda_sql_expr_copy ((GdaSqlExpr*) part->part); +} + +/** + * gda_sql_builder_import_expression: + * @builder: a #GdaSqlBuilder object + * @expr: a #GdaSqlExpr obtained using gda_sql_builder_export_expression() + * + * Imports the @expr into @builder. + * + * Returns: the ID of the new expression, or %0 if there was an error + * + * Since: 4.2 + */ +GdaSqlBuilderId +gda_sql_builder_import_expression (GdaSqlBuilder *builder, GdaSqlExpr *expr) +{ + g_return_val_if_fail (GDA_IS_SQL_BUILDER (builder), 0); + GdaSqlBuilderPrivate *priv = gda_sql_builder_get_instance_private (builder); + g_return_val_if_fail (priv->main_stmt, 0); + g_return_val_if_fail (expr, 0); + + g_return_val_if_fail (GDA_SQL_ANY_PART (expr)->type == GDA_SQL_ANY_EXPR, 0); + return add_part (builder, (GdaSqlAnyPart *) gda_sql_expr_copy (expr)); +} + + +/** + * gda_sql_builder_import_expression_from_builder: + * @builder: a #GdaSqlBuilder object + * @query: a #GdaSqlBuilder object to get expression from + * @expr_id: a #GdaSqlBuilderId of the expression in @query + * + * Imports the an expression located in @query into @builder. + * + * Returns: the ID of the new expression, or %0 if there was an error + * + * Since: 4.2 + */ +GdaSqlBuilderId +gda_sql_builder_import_expression_from_builder (GdaSqlBuilder *builder, + GdaSqlBuilder *query, + GdaSqlBuilderId expr_id) +{ + GdaSqlExpr *expr; + + g_return_val_if_fail (GDA_IS_SQL_BUILDER (builder), 0); + GdaSqlBuilderPrivate *priv = gda_sql_builder_get_instance_private (builder); + g_return_val_if_fail (priv->main_stmt, 0); + g_return_val_if_fail (GDA_IS_SQL_BUILDER (query), 0); + g_return_val_if_fail (expr_id, 0); + + expr = gda_sql_builder_export_expression (query, expr_id); + g_return_val_if_fail (GDA_SQL_ANY_PART (expr)->type == GDA_SQL_ANY_EXPR, 0); + return add_part (builder, (GdaSqlAnyPart *) gda_sql_expr_copy (expr)); +} + diff --git a/.flatpak-builder/cache/objects/ba/595ac818df922752c74f38abec7094fd565aa5c3b24bd7d022e5f5bfd03284.file b/.flatpak-builder/cache/objects/ba/595ac818df922752c74f38abec7094fd565aa5c3b24bd7d022e5f5bfd03284.file new file mode 100644 index 0000000..52e17bb --- /dev/null +++ b/.flatpak-builder/cache/objects/ba/595ac818df922752c74f38abec7094fd565aa5c3b24bd7d022e5f5bfd03284.file @@ -0,0 +1,328 @@ +/* + * Copyright (C) 2008 - 2013 Vivien Malerba + * Copyright (C) 2010 David King + * Copyright (C) 2019 Daniel Espinosa + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +#define G_LOG_DOMAIN "GDA-data-model-dsn-list" + +#include +#include +#include +#include +#include +#include +#include +#include + +typedef struct { + gint nb_dsn; + GSList *columns; + gint row_to_remove; + GValue *tmp_value; +} GdaDataModelDsnListPrivate; + +static void gda_data_model_dsn_list_data_model_init (GdaDataModelInterface *iface); + +G_DEFINE_TYPE_WITH_CODE (GdaDataModelDsnList, gda_data_model_dsn_list,G_TYPE_OBJECT, + G_ADD_PRIVATE (GdaDataModelDsnList) + G_IMPLEMENT_INTERFACE(GDA_TYPE_DATA_MODEL,gda_data_model_dsn_list_data_model_init)) + +static void gda_data_model_dsn_list_dispose (GObject *object); + +/* GdaDataModel interface */ +static gint gda_data_model_dsn_list_get_n_rows (GdaDataModel *model); +static gint gda_data_model_dsn_list_get_n_columns (GdaDataModel *model); +static GdaColumn *gda_data_model_dsn_list_describe_column (GdaDataModel *model, gint col); +static GdaDataModelAccessFlags gda_data_model_dsn_list_get_access_flags(GdaDataModel *model); +static const GValue *gda_data_model_dsn_list_get_value_at (GdaDataModel *model, gint col, gint row, GError **error); +static GdaValueAttribute gda_data_model_dsn_list_get_attributes_at (GdaDataModel *model, gint col, gint row); + +static void dsn_added_cb (GdaConfig *conf, GdaDsnInfo *info, GdaDataModelDsnList *model); +static void dsn_to_be_removed_cb (GdaConfig *conf, GdaDsnInfo *info, GdaDataModelDsnList *model); +static void dsn_removed_cb (GdaConfig *conf, GdaDsnInfo *info, GdaDataModelDsnList *model); +static void dsn_changed_cb (GdaConfig *conf, GdaDsnInfo *info, GdaDataModelDsnList *model); + +/* + * Object init and finalize + */ +static void +gda_data_model_dsn_list_data_model_init (GdaDataModelInterface *iface) +{ + iface->get_n_rows = gda_data_model_dsn_list_get_n_rows; + iface->get_n_columns = gda_data_model_dsn_list_get_n_columns; + iface->describe_column = gda_data_model_dsn_list_describe_column; + iface->get_access_flags = gda_data_model_dsn_list_get_access_flags; + iface->get_value_at = gda_data_model_dsn_list_get_value_at; + iface->get_attributes_at = gda_data_model_dsn_list_get_attributes_at; + + iface->create_iter = NULL; + + iface->set_value_at = NULL; + iface->set_values = NULL; + iface->append_values = NULL; + iface->append_row = NULL; + iface->remove_row = NULL; + iface->find_row = NULL; + + iface->freeze = NULL; + iface->thaw = NULL; + iface->get_notify = NULL; + iface->send_hint = NULL; +} + +static void +gda_data_model_dsn_list_init (GdaDataModelDsnList *model) +{ + GdaConfig *config; + GdaColumn *col; + GdaDataModelDsnListPrivate *priv = gda_data_model_dsn_list_get_instance_private (model); + + priv->nb_dsn = gda_config_get_nb_dsn (); + priv->row_to_remove = -1; + + col = gda_column_new (); + gda_column_set_name (col, _("DSN")); + gda_column_set_description (col, _("DSN")); + gda_column_set_g_type (col, G_TYPE_STRING); + priv->columns = g_slist_append (NULL, col); + + col = gda_column_new (); + gda_column_set_name (col, _("Provider")); + gda_column_set_description (col, _("Provider")); + gda_column_set_g_type (col, G_TYPE_STRING); + priv->columns = g_slist_append (priv->columns, col); + + col = gda_column_new (); + gda_column_set_name (col, _("Description")); + gda_column_set_description (col, _("Description")); + gda_column_set_g_type (col, G_TYPE_STRING); + priv->columns = g_slist_append (priv->columns, col); + + col = gda_column_new (); + /* To translators: a "Connection string" is a semi-colon delimited list of key=value pairs which + * define the parameters for a connection, such as "DB_NAME=thedb;HOSTNAME=moon */ + gda_column_set_name (col, _("Connection string")); + gda_column_set_description (col, _("Connection string")); + gda_column_set_g_type (col, G_TYPE_STRING); + priv->columns = g_slist_append (priv->columns, col); + + col = gda_column_new (); + gda_column_set_name (col, _("Username")); + gda_column_set_description (col, _("Username")); + gda_column_set_g_type (col, G_TYPE_STRING); + priv->columns = g_slist_append (priv->columns, col); + + col = gda_column_new (); + gda_column_set_name (col, _("Global")); + gda_column_set_description (col, _("Global")); + gda_column_set_g_type (col, G_TYPE_BOOLEAN); + priv->columns = g_slist_append (priv->columns, col); + + g_object_set_data (G_OBJECT (model), "name", _("List of defined data sources")); + + config = gda_config_get (); + g_signal_connect (G_OBJECT (config), "dsn-added", + G_CALLBACK (dsn_added_cb), model); + g_signal_connect (G_OBJECT (config), "dsn-to-be-removed", + G_CALLBACK (dsn_to_be_removed_cb), model); + g_signal_connect (G_OBJECT (config), "dsn-removed", + G_CALLBACK (dsn_removed_cb), model); + g_signal_connect (G_OBJECT (config), "dsn-changed", + G_CALLBACK (dsn_changed_cb), model); + g_object_unref (config); + + priv->tmp_value = NULL; +} + +static void +gda_data_model_dsn_list_class_init (GdaDataModelDsnListClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->dispose = gda_data_model_dsn_list_dispose; +} + +static void +gda_data_model_dsn_list_dispose (GObject *object) +{ + GdaDataModelDsnList *model = (GdaDataModelDsnList *) object; + + g_return_if_fail (GDA_IS_DATA_MODEL_DSN_LIST (model)); + GdaDataModelDsnListPrivate *priv = gda_data_model_dsn_list_get_instance_private (model); + + GdaConfig *config = gda_config_get (); + g_signal_handlers_disconnect_by_func (G_OBJECT (config), + G_CALLBACK (dsn_added_cb), model); + g_signal_handlers_disconnect_by_func (G_OBJECT (config), + G_CALLBACK (dsn_removed_cb), model); + g_signal_handlers_disconnect_by_func (G_OBJECT (config), + G_CALLBACK (dsn_to_be_removed_cb), model); + g_signal_handlers_disconnect_by_func (G_OBJECT (config), + G_CALLBACK (dsn_changed_cb), model); + g_object_unref (config); + if (priv->tmp_value) { + gda_value_free (priv->tmp_value); + priv->tmp_value = NULL; + } + + G_OBJECT_CLASS (gda_data_model_dsn_list_parent_class)->dispose (object); +} + +static void +dsn_added_cb (G_GNUC_UNUSED GdaConfig *conf, GdaDsnInfo *info, GdaDataModelDsnList *model) +{ + GdaDataModelDsnListPrivate *priv = gda_data_model_dsn_list_get_instance_private (model); + priv->nb_dsn++; + gda_data_model_row_inserted ((GdaDataModel *) model, gda_config_get_dsn_info_index (info->name)); +} + +static void +dsn_to_be_removed_cb (G_GNUC_UNUSED GdaConfig *conf, GdaDsnInfo *info, GdaDataModelDsnList *model) +{ + GdaDataModelDsnListPrivate *priv = gda_data_model_dsn_list_get_instance_private (model); + priv->row_to_remove = gda_config_get_dsn_info_index (info->name); +} + +static void +dsn_removed_cb (G_GNUC_UNUSED GdaConfig *conf, G_GNUC_UNUSED GdaDsnInfo *info, GdaDataModelDsnList *model) +{ + GdaDataModelDsnListPrivate *priv = gda_data_model_dsn_list_get_instance_private (model); + priv->nb_dsn--; + gda_data_model_row_removed ((GdaDataModel *) model, priv->row_to_remove); + priv->row_to_remove = -1; +} + +static void +dsn_changed_cb (G_GNUC_UNUSED GdaConfig *conf, GdaDsnInfo *info, GdaDataModelDsnList *model) +{ + gda_data_model_row_updated ((GdaDataModel *) model, gda_config_get_dsn_info_index (info->name)); +} + +/* + * GdaDataModel implementation + */ + +static gint +gda_data_model_dsn_list_get_n_rows (GdaDataModel *model) +{ + GdaDataModelDsnList *dmodel = GDA_DATA_MODEL_DSN_LIST (model); + GdaDataModelDsnListPrivate *priv = gda_data_model_dsn_list_get_instance_private (dmodel); + + return priv->nb_dsn; +} + +static gint +gda_data_model_dsn_list_get_n_columns (GdaDataModel *model) +{ + g_return_val_if_fail (GDA_IS_DATA_MODEL (model), -1); + GdaDataModelDsnList *dmodel = GDA_DATA_MODEL_DSN_LIST (model); + GdaDataModelDsnListPrivate *priv = gda_data_model_dsn_list_get_instance_private (dmodel); + g_return_val_if_fail (priv->columns != NULL, -1); + + return g_slist_length (priv->columns); +} + +static GdaColumn * +gda_data_model_dsn_list_describe_column (GdaDataModel *model, gint col) +{ + GdaDataModelDsnList *dmodel = GDA_DATA_MODEL_DSN_LIST (model); + GdaDataModelDsnListPrivate *priv = gda_data_model_dsn_list_get_instance_private (dmodel); + + return g_slist_nth_data (priv->columns, col); +} + +static GdaDataModelAccessFlags +gda_data_model_dsn_list_get_access_flags (G_GNUC_UNUSED GdaDataModel *model) +{ + return GDA_DATA_MODEL_ACCESS_RANDOM; +} + +static const GValue * +gda_data_model_dsn_list_get_value_at (GdaDataModel *model, gint col, gint row, GError **error) +{ + GdaDataModelDsnList *dmodel = GDA_DATA_MODEL_DSN_LIST (model); + GdaDataModelDsnListPrivate *priv = gda_data_model_dsn_list_get_instance_private (dmodel); + + if (priv->tmp_value) { + gda_value_free (priv->tmp_value); + priv->tmp_value = NULL; + } + + if ((col >= gda_data_model_dsn_list_get_n_columns (model)) || + (col < 0)) { + g_set_error (error, GDA_DATA_MODEL_ERROR, GDA_DATA_MODEL_COLUMN_OUT_OF_RANGE_ERROR, + _("Column %d out of range (0-%d)"), col, gda_data_model_dsn_list_get_n_columns (model) - 1); + return NULL; + } + if ((row < 0) || (row >= gda_data_model_dsn_list_get_n_rows (model))) { + gint n; + n = gda_data_model_dsn_list_get_n_rows (model); + if (n > 0) + g_set_error (error, GDA_DATA_MODEL_ERROR, GDA_DATA_MODEL_ROW_OUT_OF_RANGE_ERROR, + _("Row %d out of range (0-%d)"), row, n - 1); + else + g_set_error (error, GDA_DATA_MODEL_ERROR, GDA_DATA_MODEL_ROW_OUT_OF_RANGE_ERROR, + _("Row %d not found (empty data model)"), row); + return NULL; + } + + GdaDsnInfo *info = gda_config_get_dsn_info_at_index (row); + g_assert (info); + if (col != 5) + priv->tmp_value = gda_value_new (G_TYPE_STRING); + else + priv->tmp_value = gda_value_new (G_TYPE_BOOLEAN); + switch (col) { + case 0: + g_value_set_string (priv->tmp_value, info->name); + break; + case 1: + g_value_set_string (priv->tmp_value, info->provider); + break; + case 2: + g_value_set_string (priv->tmp_value, info->description); + break; + case 3: + g_value_set_string (priv->tmp_value, info->cnc_string); + break; + case 4: + if (info->auth_string) { + GdaQuarkList* ql; + ql = gda_quark_list_new_from_string (info->auth_string); + + g_value_set_string (priv->tmp_value, gda_quark_list_find (ql, "USERNAME")); + gda_quark_list_free (ql); + } + else + g_value_set_string (priv->tmp_value, ""); + break; + case 5: + g_value_set_boolean (priv->tmp_value, info->is_system); + break; + default: + g_assert_not_reached (); + } + + return priv->tmp_value; +} + +static GdaValueAttribute +gda_data_model_dsn_list_get_attributes_at (G_GNUC_UNUSED GdaDataModel *model, G_GNUC_UNUSED gint col, G_GNUC_UNUSED gint row) +{ + return GDA_VALUE_ATTR_NO_MODIF; +} diff --git a/.flatpak-builder/cache/objects/bb/1f942ac0a43a29d77d1e4e886f97f9b9bb798b6830f6eaca26e44db7229199.file b/.flatpak-builder/cache/objects/bb/1f942ac0a43a29d77d1e4e886f97f9b9bb798b6830f6eaca26e44db7229199.file new file mode 100644 index 0000000..2eba9ab Binary files /dev/null and b/.flatpak-builder/cache/objects/bb/1f942ac0a43a29d77d1e4e886f97f9b9bb798b6830f6eaca26e44db7229199.file differ diff --git a/.flatpak-builder/cache/objects/bb/3674158e924fa4e59e94f826973714decf93c141ebb74959aa514bd10c4c9b.dirtree b/.flatpak-builder/cache/objects/bb/3674158e924fa4e59e94f826973714decf93c141ebb74959aa514bd10c4c9b.dirtree new file mode 100644 index 0000000..5174a30 Binary files /dev/null and b/.flatpak-builder/cache/objects/bb/3674158e924fa4e59e94f826973714decf93c141ebb74959aa514bd10c4c9b.dirtree differ diff --git a/.flatpak-builder/cache/objects/bb/415e38999520fd37264507717d9e874dd5358f954c310f8ada5f3221657a69.file b/.flatpak-builder/cache/objects/bb/415e38999520fd37264507717d9e874dd5358f954c310f8ada5f3221657a69.file new file mode 100755 index 0000000..771c952 Binary files /dev/null and b/.flatpak-builder/cache/objects/bb/415e38999520fd37264507717d9e874dd5358f954c310f8ada5f3221657a69.file differ diff --git a/.flatpak-builder/cache/objects/bb/596c3d9290b94f44f9c4f5054baa8efb3eefa412219925fe31a2cca4dffe80.file b/.flatpak-builder/cache/objects/bb/596c3d9290b94f44f9c4f5054baa8efb3eefa412219925fe31a2cca4dffe80.file new file mode 100644 index 0000000..2921571 --- /dev/null +++ b/.flatpak-builder/cache/objects/bb/596c3d9290b94f44f9c4f5054baa8efb3eefa412219925fe31a2cca4dffe80.file @@ -0,0 +1,1478 @@ +/* gda-db-column.c + * + * Copyright (C) 2018-2019 Pavlo Solntsev + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +#define G_LOG_DOMAIN "GDA-db-column" + +#include +#include "gda-db-column.h" +#include +#include "gda-util.h" +#include "gda-db-buildable.h" +#include "gda-server-provider.h" +#include "gda-db-column-private.h" +#include "gda-ddl-modifiable.h" +#include "gda-lockable.h" + +G_DEFINE_QUARK (gda-db-column-error, gda_db_column_error) + +typedef struct +{ + gchar *mp_name; /* property */ + gchar *mp_type; + gchar *mp_comment; + gchar *mp_default; /* property */ + gchar *mp_check; + GdaDbTable *mp_table; /* Property */ + + GType m_gtype; + + guint m_size; /* Property */ + guint m_scale; + + gboolean m_nnul; /* Property */ + gboolean m_autoinc; /* property */ + gboolean m_unique; /* property */ + gboolean m_pkey; /* property */ +} GdaDbColumnPrivate; + +/** + * SECTION:gda-db-column + * @short_description: Object to represent table column + * @see_also: #GdaDbTable, #GdaDbView, #GdaDbBuildable + * @stability: Stable + * @include: libgda/libgda.h + * + * This object represents a column of a table or a view. The column can be constracted manually + * using API or generated from xml file together with other databse objects. See #GdaDbCatalog. + * #GdaDbColumn implements #GdaDbBuildable interface for parsing xml file. This is a typical example + * how the #GdaDbColumn API can be used. + * + * |[ + * GdaDbTable *tproject = gda_db_table_new (); + * gda_db_base_set_name (GDA_DB_BASE (tproject), "Project"); + * + * GdaDbColumn *pid = gda_db_column_new (); + * gda_db_column_set_name (pid, "id"); + * gda_db_column_set_type (pid, G_TYPE_INT); + * gda_db_column_set_nnul (pid, TRUE); + * gda_db_column_set_autoinc (pid, TRUE); + * gda_db_column_set_unique (pid, TRUE); + * gda_db_column_set_pkey (pid, TRUE); + * + * gda_db_table_append_column (tproject, pid); + * + * g_object_unref (pid); + * ]| + */ + +/* All nodes in xml should be accessed using enum below */ +enum { + GDA_DB_COLUMN_NODE, + GDA_DB_COLUMN_NAME, + GDA_DB_COLUMN_ATYPE, + GDA_DB_COLUMN_PKEY, + GDA_DB_COLUMN_UNIQUE, + GDA_DB_COLUMN_AUTOINC, + GDA_DB_COLUMN_NNUL, + GDA_DB_COLUMN_COMMENT, + GDA_DB_COLUMN_SIZE, + GDA_DB_COLUMN_CHECK, + GDA_DB_COLUMN_VALUE, + GDA_DB_COLUMN_SCALE, + GDA_DB_COLUMN_N_NODES +}; + +static const gchar *gdadbcolumnnode[GDA_DB_COLUMN_N_NODES] = { + "column", + "name", + "type", + "pkey", + "unique", + "autoinc", + "nnul", + "comment", + "size", + "check", + "value", + "scale" +}; + +static void +gda_db_column_buildable_interface_init (GdaDbBuildableInterface *iface); +static void gda_ddl_modifiable_interface_init (GdaDdlModifiableInterface *iface); + +static gboolean gda_db_column_create (GdaDdlModifiable *self, GdaConnection *cnc, + gpointer user_data, GError **error); +static gboolean gda_db_column_drop (GdaDdlModifiable *self, GdaConnection *cnc, + gpointer user_data, GError **error); +static gboolean gda_db_column_rename (GdaDdlModifiable *old_name, GdaConnection *cnc, + gpointer new_name, GError **error); + +G_DEFINE_TYPE_WITH_CODE (GdaDbColumn, gda_db_column, G_TYPE_OBJECT, + G_ADD_PRIVATE (GdaDbColumn) + G_IMPLEMENT_INTERFACE (GDA_TYPE_DB_BUILDABLE, + gda_db_column_buildable_interface_init) + G_IMPLEMENT_INTERFACE (GDA_TYPE_DDL_MODIFIABLE, + gda_ddl_modifiable_interface_init)) + +enum { + PROP_0, + PROP_COLUMN_NAME, + PROP_COLUMN_COMMENT, + PROP_COLUMN_SIZE, + PROP_COLUMN_NNUL, + PROP_COLUMN_AUTOINC, + PROP_COLUMN_UNIQUE, + PROP_COLUMN_PKEY, + PROP_COLUMN_DEFAULT, + PROP_COLUMN_CHECK, + PROP_COLUMN_SCALE, + PROP_COLUMN_TABLE, + /**/ + N_PROPS +}; + +static void +_gda_db_column_set_type (GdaDbColumn *self, const gchar *type, GError **error); + +static GParamSpec *properties [N_PROPS] = {NULL}; + +/** + * gda_db_column_new: + * + * Returns: New instance of #GdaDbColumn, to free with g_object_unref () once not needed anymore + * + * Stability: Stable + * Since: 6.0 + * + */ +GdaDbColumn * +gda_db_column_new (void) +{ + return g_object_new (GDA_TYPE_DB_COLUMN, NULL); +} + +static void +gda_db_column_finalize (GObject *object) +{ + GdaDbColumn *self = GDA_DB_COLUMN (object); + GdaDbColumnPrivate *priv = gda_db_column_get_instance_private (self); + + g_free (priv->mp_name); + g_free (priv->mp_type); + g_free (priv->mp_default); + g_free (priv->mp_check); + g_free (priv->mp_comment); + + G_OBJECT_CLASS (gda_db_column_parent_class)->finalize (object); +} + +static void +gda_db_column_dispose (GObject *object) +{ + GdaDbColumn *self = GDA_DB_COLUMN (object); + GdaDbColumnPrivate *priv = gda_db_column_get_instance_private (self); + + if (priv->mp_table) g_object_unref (priv->mp_table); + + G_OBJECT_CLASS (gda_db_column_parent_class)->dispose (object); +} + +static void +gda_db_column_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + GdaDbColumn *self = GDA_DB_COLUMN (object); + GdaDbColumnPrivate *priv = gda_db_column_get_instance_private (self); + + switch (prop_id) { + case PROP_COLUMN_NAME: + g_value_set_string (value, priv->mp_name); + break; + case PROP_COLUMN_SIZE: + g_value_set_uint (value, priv->m_size); + break; + case PROP_COLUMN_NNUL: + g_value_set_boolean (value, priv->m_nnul); + break; + case PROP_COLUMN_UNIQUE: + g_value_set_boolean (value, priv->m_unique); + break; + case PROP_COLUMN_PKEY: + g_value_set_boolean (value, priv->m_pkey); + break; + case PROP_COLUMN_AUTOINC: + g_value_set_boolean (value, priv->m_autoinc); + break; + case PROP_COLUMN_DEFAULT: + g_value_set_string (value, priv->mp_default); + break; + case PROP_COLUMN_CHECK: + g_value_set_string (value, priv->mp_check); + break; + case PROP_COLUMN_COMMENT: + g_value_set_string (value, priv->mp_comment); + break; + case PROP_COLUMN_SCALE: + g_value_set_uint (value, priv->m_scale); + break; + case PROP_COLUMN_TABLE: + g_value_set_object (value, priv->mp_table); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gda_db_column_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + GdaDbColumn *self = GDA_DB_COLUMN (object); + GdaDbColumnPrivate *priv = gda_db_column_get_instance_private (self); + + switch (prop_id){ + case PROP_COLUMN_NAME: + g_free (priv->mp_name); + priv->mp_name = g_value_dup_string (value); + break; + case PROP_COLUMN_SIZE: + priv->m_size = g_value_get_uint (value); + break; + case PROP_COLUMN_NNUL: + priv->m_nnul = g_value_get_boolean (value); + break; + case PROP_COLUMN_UNIQUE: + priv->m_unique = g_value_get_boolean (value); + break; + case PROP_COLUMN_AUTOINC: + priv->m_autoinc = g_value_get_boolean (value); + break; + case PROP_COLUMN_PKEY: + priv->m_pkey = g_value_get_boolean (value); + break; + case PROP_COLUMN_DEFAULT: + g_free (priv->mp_default); + priv->mp_default = g_value_dup_string (value); + break; + case PROP_COLUMN_CHECK: + g_free (priv->mp_check); + priv->mp_check = g_value_dup_string (value); + break; + case PROP_COLUMN_COMMENT: + g_free (priv->mp_comment); + priv->mp_comment = g_value_dup_string (value); + break; + case PROP_COLUMN_SCALE: + priv->m_scale = g_value_get_uint (value); + break; + case PROP_COLUMN_TABLE: + if (priv->mp_table) + g_object_unref (priv->mp_table); + priv->mp_table = g_value_dup_object (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gda_db_column_class_init (GdaDbColumnClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->finalize = gda_db_column_finalize; + object_class->dispose = gda_db_column_dispose; + object_class->get_property = gda_db_column_get_property; + object_class->set_property = gda_db_column_set_property; + + properties[PROP_COLUMN_NAME] = + g_param_spec_string ("name", "Name", "Column name", NULL, G_PARAM_READWRITE); + + properties[PROP_COLUMN_SIZE] = + g_param_spec_uint ("size", "Size", "Column size", 0, 9999, 80, G_PARAM_READWRITE); + + properties[PROP_COLUMN_NNUL] = + g_param_spec_boolean ("nnul", "NotNULL", "Can value be NULL", TRUE, G_PARAM_READWRITE); + + properties[PROP_COLUMN_AUTOINC] = + g_param_spec_boolean ("autoinc", "Autoinc", "Can value be autoincremented", FALSE, + G_PARAM_READWRITE); + + properties[PROP_COLUMN_UNIQUE] = + g_param_spec_boolean ("unique", "Unique", "Can value be unique", FALSE, G_PARAM_READWRITE); + + properties[PROP_COLUMN_PKEY] = + g_param_spec_boolean ("pkey", "Pkey", "Is is primery key", FALSE, G_PARAM_READWRITE); + + properties[PROP_COLUMN_DEFAULT] = + g_param_spec_string ("default", "Default", "Default value", NULL,G_PARAM_READWRITE); + + properties[PROP_COLUMN_CHECK] = + g_param_spec_string ("check", "Check", "Column check string", NULL, G_PARAM_READWRITE); + + properties[PROP_COLUMN_COMMENT] = + g_param_spec_string ("comment", "Comment", "Column comment", NULL, G_PARAM_READWRITE); + + properties[PROP_COLUMN_SCALE] = + g_param_spec_uint ("scale", "Scale", "Number of decimal for numeric type", 0, 64, 2, + G_PARAM_READWRITE); + + properties[PROP_COLUMN_TABLE] = + g_param_spec_object ("table", "Table", "Parent table", GDA_TYPE_DB_TABLE, G_PARAM_READWRITE); + + g_object_class_install_properties (object_class, N_PROPS, properties); +} + +static void +gda_db_column_init (GdaDbColumn *self) +{ + GdaDbColumnPrivate *priv = gda_db_column_get_instance_private (self); + + priv->mp_type = NULL; + priv->m_scale = 0; + priv->mp_check = NULL; + priv->mp_name = NULL; + priv->m_gtype = G_TYPE_INVALID; + priv->m_nnul = FALSE; + priv->m_autoinc = FALSE; + priv->m_unique = FALSE; + priv->m_pkey = FALSE; + priv->mp_default = NULL; + priv->mp_comment = NULL; + priv->mp_table = NULL; +} + +/** + * gda_db_column_parse_node: (skip) + * @self: #GdaDbColumn object to store parsed data + * @node: instance of #xmlNodePtr to parse + * @error: error container + * + * Parse @node wich should point to node + * + * Returns: %TRUE if no error, %FALSE otherwise + * + * Since: 6.0 + */ +static gboolean +gda_db_column_parse_node (GdaDbBuildable *buildable, + xmlNodePtr node, + GError **error) +{ + g_return_val_if_fail (buildable,FALSE); + g_return_val_if_fail (node,FALSE); + + /*TODO: Appropriate error should be set an returned. + * It should be added to the header file first + */ + if (g_strcmp0 ((gchar *)node->name, gdadbcolumnnode[GDA_DB_COLUMN_NODE])) + return FALSE; + + GdaDbColumn *self = GDA_DB_COLUMN (buildable); + GdaDbColumnPrivate *priv = gda_db_column_get_instance_private (self); + + xmlChar *name = xmlGetProp (node, (xmlChar *)gdadbcolumnnode[GDA_DB_COLUMN_NAME]); + g_assert (name); /* If here bug with xml validation */ + g_object_set (G_OBJECT(self),"name",(gchar*)name,NULL); + xmlFree (name); + + xmlChar *type = xmlGetProp (node,(xmlChar *)gdadbcolumnnode[GDA_DB_COLUMN_ATYPE]); + g_assert (type); /* If here buf with validation */ + _gda_db_column_set_type (self, (const gchar *)type,error); + xmlFree (type); + + xmlChar *cprop = NULL; + cprop = xmlGetProp (node,(xmlChar *)gdadbcolumnnode[GDA_DB_COLUMN_PKEY]); + if (cprop) + { + g_object_set (G_OBJECT(self), + "pkey", *cprop == 't' || *cprop == 'T' ? TRUE : FALSE, + NULL); + xmlFree (cprop); + } + + /* We need scale only for NUMBERIC data type, e.g. float, double */ + cprop = xmlGetProp (node, (xmlChar *)gdadbcolumnnode[GDA_DB_COLUMN_UNIQUE]); + + if (cprop) + { + g_object_set (G_OBJECT(self), + "unique", *cprop == 't' || *cprop == 'T' ? TRUE : FALSE, + NULL); + xmlFree (cprop); + } + + cprop = xmlGetProp (node, (xmlChar *)gdadbcolumnnode[GDA_DB_COLUMN_AUTOINC]); + + if (cprop) + { + g_object_set (G_OBJECT(self), + "autoinc", *cprop == 't' || *cprop == 'T' ? TRUE : FALSE, + NULL); + xmlFree (cprop); + } + + cprop = xmlGetProp (node, (xmlChar *)gdadbcolumnnode[GDA_DB_COLUMN_NNUL]); + + if (cprop) + { + g_object_set (G_OBJECT(self), + "nnul",*cprop == 't' || *cprop == 'T' ? TRUE : FALSE, + NULL); + xmlFree (cprop); + } + + for (xmlNodePtr it = node->children; it; it = it->next) + { + if (!g_strcmp0 ((char *)it->name,gdadbcolumnnode[GDA_DB_COLUMN_VALUE])) + { + xmlChar *value = xmlNodeGetContent (it); + + if (value) + { + g_object_set (G_OBJECT (self), "default", (gchar *)value, NULL); + xmlFree (value); + } + + xmlChar *nprop = xmlGetProp (it, BAD_CAST gdadbcolumnnode[GDA_DB_COLUMN_SIZE]); + guint64 tint = 0; + if (nprop) + { + tint = g_ascii_strtoull ((gchar*)nprop, NULL, 10); + xmlFree (nprop); + g_object_set (G_OBJECT (self), "size", tint, NULL); + } + + if (priv->m_gtype == G_TYPE_FLOAT || + priv->m_gtype == G_TYPE_DOUBLE || + priv->m_gtype == GDA_TYPE_NUMERIC) + { + nprop = xmlGetProp (it, (xmlChar *)gdadbcolumnnode[GDA_DB_COLUMN_SCALE]); + if (nprop) + { + guint64 tint = g_ascii_strtoull ((gchar*)nprop, NULL, 10); + g_object_set (G_OBJECT(self), "scale", tint, NULL); + xmlFree (nprop); + } + } + } + + if (!g_strcmp0 ((char *)it->name, gdadbcolumnnode[GDA_DB_COLUMN_CHECK])) + { + xmlChar *check = xmlNodeGetContent (it); + g_object_set (G_OBJECT (self), "check", check,NULL); + xmlFree (check); + } + + if (!g_strcmp0 ((char *)it->name, gdadbcolumnnode[GDA_DB_COLUMN_COMMENT])) + { + xmlChar *comment = xmlNodeGetContent (it); + g_object_set (G_OBJECT (self), "comment", comment,NULL); + xmlFree (comment); + } + } /* End of for loop */ + return TRUE; +} /* End of gda_db_column_parse_node */ + +static gboolean +gda_db_column_write_node (GdaDbBuildable *buildable, + xmlNodePtr rootnode, + GError **error) +{ + g_return_val_if_fail (buildable, FALSE); + g_return_val_if_fail (rootnode, FALSE); + + GdaDbColumn *self = GDA_DB_COLUMN (buildable); + + GdaDbColumnPrivate *priv = gda_db_column_get_instance_private (self); + + xmlNodePtr node = NULL; + node = xmlNewChild (rootnode, + NULL, + BAD_CAST gdadbcolumnnode[GDA_DB_COLUMN_NODE], + NULL); + + xmlNewProp (node, + BAD_CAST gdadbcolumnnode[GDA_DB_COLUMN_NAME], + BAD_CAST gda_db_column_get_name (self)); + + xmlNewProp (node, + BAD_CAST gdadbcolumnnode[GDA_DB_COLUMN_ATYPE], + BAD_CAST priv->mp_type); + + xmlNewProp (node, + BAD_CAST gdadbcolumnnode[GDA_DB_COLUMN_PKEY], + BAD_CAST GDA_BOOL_TO_STR(priv->m_pkey)); + + xmlNewProp (node, + BAD_CAST gdadbcolumnnode[GDA_DB_COLUMN_UNIQUE], + BAD_CAST GDA_BOOL_TO_STR(priv->m_unique)); + + xmlNewProp (node, + BAD_CAST gdadbcolumnnode[GDA_DB_COLUMN_AUTOINC], + BAD_CAST GDA_BOOL_TO_STR(priv->m_autoinc)); + + xmlNewProp (node, + BAD_CAST gdadbcolumnnode[GDA_DB_COLUMN_NNUL], + BAD_CAST GDA_BOOL_TO_STR(priv->m_nnul)); + + if (priv->mp_comment) + xmlNewChild (node, NULL, + BAD_CAST gdadbcolumnnode[GDA_DB_COLUMN_COMMENT], + BAD_CAST priv->mp_comment); + + xmlNodePtr nodevalue = NULL; + + if (priv->mp_default) + { + nodevalue = xmlNewChild (node, + NULL, + BAD_CAST gdadbcolumnnode[GDA_DB_COLUMN_VALUE], + BAD_CAST priv->mp_default); + + if (priv->m_size > 0) + { + /* temp string to convert gint to gchar* */ + GString *sizestr = g_string_new (NULL); + g_string_printf (sizestr, "%d", priv->m_size); + + xmlNewProp (nodevalue, + BAD_CAST gdadbcolumnnode[GDA_DB_COLUMN_SIZE], + BAD_CAST sizestr->str); + + g_string_free (sizestr,TRUE); + + /* We need to write down scale if column type is numeric */ + if (priv->m_gtype == G_TYPE_FLOAT || + priv->m_gtype == G_TYPE_DOUBLE || + priv->m_gtype == GDA_TYPE_NUMERIC) + { + GString *scale_str = g_string_new (NULL); + g_string_printf (scale_str, "%d", priv->m_scale); + + xmlNewProp (nodevalue, + BAD_CAST gdadbcolumnnode[GDA_DB_COLUMN_SCALE], + BAD_CAST scale_str->str); + + g_string_free (scale_str, TRUE); + } + } + } + + if (priv->mp_check) + xmlNewChild (node,NULL, + BAD_CAST gdadbcolumnnode[GDA_DB_COLUMN_CHECK], + BAD_CAST priv->mp_check); + + return TRUE; +} + +static void +gda_db_column_buildable_interface_init (GdaDbBuildableInterface *iface) +{ + iface->parse_node = gda_db_column_parse_node; + iface->write_node = gda_db_column_write_node; +} + +static void +gda_ddl_modifiable_interface_init (GdaDdlModifiableInterface *iface) +{ + iface->create = gda_db_column_create; + iface->drop = gda_db_column_drop; + iface->rename = gda_db_column_rename; +} + +static void +_gda_db_column_set_type (GdaDbColumn *self, + const char *type, + GError **error) +{ + g_return_if_fail (self); + g_return_if_fail (type); + // g_return_if_fail (!*error); + GdaDbColumnPrivate *priv = gda_db_column_get_instance_private (self); + GType ttype = gda_g_type_from_string (type); + if (ttype != G_TYPE_INVALID){ + priv->mp_type = g_strdup (type); + priv->m_gtype = ttype; + } + else { + g_set_error (error, + GDA_DB_COLUMN_ERROR, + GDA_DB_COLUMN_ERROR_TYPE, + _("Invalid column type %s. See API for gda_g_type_from_string ().\n"), + type); + } +} + +/** + * gda_db_column_get_name: + * @self: a #GdaDbColumn instance + * + * Returns name of the column + * + * Returns: Column name as a string or %NULL. + * + * Stability: Stable + * Since: 6.0 + */ +const gchar* +gda_db_column_get_name (GdaDbColumn *self) +{ + g_return_val_if_fail (self, NULL); + GdaDbColumnPrivate *priv = gda_db_column_get_instance_private (self); + + return priv->mp_name; +} + +/** + * gda_db_column_set_name: + * @self: a #GdaDbColumn object + * @name: name as a string + * + * Set column name. + * + * Stability: Stable + * Since: 6.0 + */ +void +gda_db_column_set_name (GdaDbColumn *self, + const gchar *name) +{ + g_return_if_fail (self); + GdaDbColumnPrivate *priv = gda_db_column_get_instance_private (self); + + g_free (priv->mp_name); + priv->mp_name = g_strdup (name); +} + +/** + * gda_db_column_get_gtype: + * @self: a #GdaDbColumn object + * + * Return of column type as #GType + * + * Stability: Stable + * Since: 6.0 + */ +GType +gda_db_column_get_gtype (GdaDbColumn *self) +{ + g_return_val_if_fail (self, GDA_TYPE_NULL); + GdaDbColumnPrivate *priv = gda_db_column_get_instance_private (self); + + return priv->m_gtype; +} + +/** + * gda_db_column_get_ctype: + * @self: a #GdaDbColumn object + * + * Returns column type as a string derivied from #GType + * + * Returns: column type as a string or %NULL + * + * Stability: Stable + * Since: 6.0 + */ +const gchar* +gda_db_column_get_ctype (GdaDbColumn *self) +{ + g_return_val_if_fail (self, NULL); + GdaDbColumnPrivate *priv = gda_db_column_get_instance_private (self); + return priv->mp_type; +} + +/** + * gda_db_column_set_type: + * @self: a #GdaDbColumn instance + * @type: #GType for column + * + * Set type of the column as a #GType. For numeric type, #GDA_TYPE_NUMERIC should be used. Other + * types, e.g. %G_TYPE_FLOAT or %G_TYPE_DOUBLE can also be used but precision and scale should not be + * set. In this case appropriate types for DB implementation will be used, e.g. float4. + * + * Stability: Stable + * Since: 6.0 + */ +void +gda_db_column_set_type (GdaDbColumn *self, + GType type) +{ + g_return_if_fail (self); + GdaDbColumnPrivate *priv = gda_db_column_get_instance_private (self); + priv->m_gtype = type; + g_free (priv->mp_type); + priv->mp_type = g_strdup (gda_g_type_to_string (type)); +} + +/** + * gda_db_column_get_scale: + * @self: a #GdaDbColumn object + * + * Scale is used for float number representation to specify a number of decimal digits. + * This value is ignore for column types except float or double. + * + * Returns: Current scale value + * + * Stability: Stable + * Since: 6.0 + */ +guint +gda_db_column_get_scale (GdaDbColumn *self) +{ + g_return_val_if_fail (self,0); + GdaDbColumnPrivate *priv = gda_db_column_get_instance_private (self); + return priv->m_scale; +} + +/** + * gda_db_column_set_scale: + * @self: a #GdaDbColumn + * @scale: scale value to set + * + * Scale is used for float number representation to specify a number of decimal digits. + * This value is ignore for column types except float or double. + * + * Stability: Stable + * Since: 6.0 + */ +void +gda_db_column_set_scale (GdaDbColumn *self, + guint scale) +{ + g_return_if_fail (self); + GdaDbColumnPrivate *priv = gda_db_column_get_instance_private (self); + priv->m_scale = scale; +} + +/** + * gda_db_column_get_pkey: + * @self: a #GdaDbColumn object + * + * Returns a primary key flag + * + * Returns: %TRUE if the column is primary key, %FALSE otherwise + * + * Stability: Stable + * Since: 6.0 + */ +gboolean +gda_db_column_get_pkey (GdaDbColumn *self) +{ + g_return_val_if_fail (self, FALSE); + GdaDbColumnPrivate *priv = gda_db_column_get_instance_private (self); + return priv->m_pkey; +} + +/** + * gda_db_column_set_pkey: + * @self: a #GdaDbColumn object + * @pkey: value to set + * + * If @pkey is %TRUE, the given column will be marked with PRIMERY KEY flag + * + * Stability: Stable + * Since: 6.0 + */ +void +gda_db_column_set_pkey (GdaDbColumn *self, + gboolean pkey) +{ + g_return_if_fail (self); + GdaDbColumnPrivate *priv = gda_db_column_get_instance_private (self); + + priv->m_pkey = pkey; +} +/** + * gda_db_column_get_nnul: + * @self: a @GdaDbColumn object + * + * Specify if the column's value can be NULL. + * + * Returns: %TRUE if value can be %NULL, %FALSE otherwise. + * + * Stability: Stable + * Since: 6.0 + */ +gboolean +gda_db_column_get_nnul (GdaDbColumn *self) +{ + g_return_val_if_fail (self, FALSE); + GdaDbColumnPrivate *priv = gda_db_column_get_instance_private (self); + return priv->m_nnul; +} + +/** + * gda_db_column_set_nnul: + * @self: a GdaDbColumn object + * @nnul: value to set for nnul + * If @nnul is %TRUE the column will be marked with NON NULL flag + * Stability: Stable + * Since: 6.0 + */ +void +gda_db_column_set_nnul (GdaDbColumn *self, + gboolean nnul) +{ + g_return_if_fail (self); + GdaDbColumnPrivate *priv = gda_db_column_get_instance_private (self); + priv->m_nnul = nnul; +} + +/** + * gda_db_column_get_autoinc: + * @self: a #GdaDbColumn object + * + * Get value for autoinc key + * + * Returns: %TRUE if column should be auto-incremented, %FALSE otherwise. + * + * Stability: Stable + * Since: 6.0 + */ +gboolean +gda_db_column_get_autoinc (GdaDbColumn *self) +{ + g_return_val_if_fail (self, FALSE); + GdaDbColumnPrivate *priv = gda_db_column_get_instance_private (self); + return priv->m_autoinc; +} + +/** + * gda_db_column_set_autoinc: + * @self: a #GdaDbColumn object + * @autoinc: value to set + * + * Set value for auto-incremented key. + * + * Stability: Stable + * Since: 6.0 + */ +void +gda_db_column_set_autoinc (GdaDbColumn *self, + gboolean autoinc) +{ + g_return_if_fail (self); + GdaDbColumnPrivate *priv = gda_db_column_get_instance_private (self); + priv->m_autoinc = autoinc; +} + +/** + * gda_db_column_get_unique: + * @self: a #GdaDbColumn object + * + * Get value for unique key + * + * Returns: %TRUE if column should have a unique value, %FALSE otherwise. + * + * Stability: Stable + * Since: 6.0 + */ +gboolean +gda_db_column_get_unique (GdaDbColumn *self) +{ + g_return_val_if_fail (self, FALSE); + GdaDbColumnPrivate *priv = gda_db_column_get_instance_private (self); + return priv->m_unique; +} + +/** + * gda_db_column_set_unique: + * @self: a #GdaDbColumn object + * @unique: value to set + * + * Set value for unique key. + * + * Stability: Stable + * Since: 6.0 + */ +void +gda_db_column_set_unique (GdaDbColumn *self, + gboolean unique) +{ + g_return_if_fail (self); + GdaDbColumnPrivate *priv = gda_db_column_get_instance_private (self); + priv->m_unique = unique; +} + +/** + * gda_db_column_get_comment: + * @self: a #GdaDbColumn object + * + * Get value for column comment. + * + * Returns: Column comment as a string. + * %NULL is returned if comment is not set. + * + * Stability: Stable + * Since: 6.0 + */ +const gchar* +gda_db_column_get_comment (GdaDbColumn *self) +{ + g_return_val_if_fail (self, NULL); + GdaDbColumnPrivate *priv = gda_db_column_get_instance_private (self); + + return priv->mp_comment; +} + +/** + * gda_db_column_set_comment: + * @self: a #GdaDbColumn object + * @comnt: comment to set + * + * Set value for column comment. + * + * Stability: Stable + * Since: 6.0 + */ +void +gda_db_column_set_comment (GdaDbColumn *self, + const gchar *comnt) +{ + g_return_if_fail (self); + GdaDbColumnPrivate *priv = gda_db_column_get_instance_private (self); + g_free (priv->mp_comment); + priv->mp_comment = g_strdup (comnt); +} + +/** + * gda_db_column_get_size: + * @self: a #GdaDbColumn instance + * + * Returns: Current value for column size. + * + * Stability: Stable + * Since: 6.0 + */ +guint +gda_db_column_get_size (GdaDbColumn *self) +{ + g_return_val_if_fail (self, 0); + GdaDbColumnPrivate *priv = gda_db_column_get_instance_private (self); + return priv->m_size; +} + +/** + * gda_db_column_set_size: + * @self: a #GdaDbColumn instance + * @size: value to set + * + * Set value for column size. This is relevant only for string column type. + * + * Stability: Stable + * Since: 6.0 + */ +void +gda_db_column_set_size (GdaDbColumn *self, + guint size) +{ + g_return_if_fail (self); + GdaDbColumnPrivate *priv = gda_db_column_get_instance_private (self); + priv->m_size = size; +} + +/** + * gda_db_column_get_default: + * @self: a #GdaDbColumn instance + * + * Returns default value for the column. Can be %NULL if the default value hasn't been set. + * + * Returns: Default value for the column as a string. + * + * Stability: Stable + * Since: 6.0 + */ +const gchar* +gda_db_column_get_default (GdaDbColumn *self) +{ + g_return_val_if_fail (self, NULL); + GdaDbColumnPrivate *priv = gda_db_column_get_instance_private (self); + return priv->mp_default; +} + +/** + * gda_db_column_set_default: + * @self: a #GdaDbColumn instance + * @value: default value to set for column as a string + * + * Stability: Stable + * Since: 6.0 + */ +void +gda_db_column_set_default (GdaDbColumn *self, + const gchar *value) +{ + g_return_if_fail (self); + GdaDbColumnPrivate *priv = gda_db_column_get_instance_private (self); + g_free(priv->mp_default); + priv->mp_default = g_strdup (value); +} + +/** + * gda_db_column_get_check: + * @self: a #GdaDbColumn instance + * + * Returns value of the check field. + * + * Returns: Column check string + * + * Stability: Stable + * Since: 6.0 + */ +const gchar* +gda_db_column_get_check (GdaDbColumn *self) +{ + g_return_val_if_fail (self,NULL); + GdaDbColumnPrivate *priv = gda_db_column_get_instance_private (self); + return priv->mp_check; +} + +/** + * gda_db_column_set_check: + * @self: a #GdaDbColumn instance + * @value: value to set + * + * Sets check string to the column. + * + * Stability: Stable + * Since: 6.0 + */ +void +gda_db_column_set_check (GdaDbColumn *self, + const gchar *value) +{ + g_return_if_fail (self); + GdaDbColumnPrivate *priv = gda_db_column_get_instance_private (self); + g_free(priv->mp_check); + priv->mp_check = g_strdup (value); +} + +/** + * gda_db_column_prepare_create: + * @self: a #GdaDbColumn instance + * @op: a #GdaServerOperation instance to update for TABLE_CREATE operation + * @order: Order number for the column + * @error: a #GError container + * + * This method populate @op with information stored in @self. + * + * Returns: %TRUE if successful, %FALSE otherwise. + * + * Stability: Stable + * Since: 6.0 + */ +gboolean +gda_db_column_prepare_create (GdaDbColumn *self, + GdaServerOperation *op, + guint order, + GError **error) +{ + GdaConnection *cnc; + const gchar *strtype; + + g_return_val_if_fail(self,FALSE); + g_return_val_if_fail(op,FALSE); + + GdaDbColumnPrivate *priv = gda_db_column_get_instance_private (self); + + if(!gda_server_operation_set_value_at (op, priv->mp_name, error, "/FIELDS_A/@COLUMN_NAME/%d", order)) + return FALSE; + + cnc = (GdaConnection*) g_object_get_data (G_OBJECT (op), "connection"); + + if (cnc == NULL) + { + g_set_error (error, GDA_DB_COLUMN_ERROR, GDA_DB_COLUMN_ERROR_TYPE, + _("Internal error: Operation should be prepared, setting a connection data")); + return FALSE; + } + + strtype = gda_server_provider_get_default_dbms_type (gda_connection_get_provider (cnc), + cnc, priv->m_gtype); + + if(!gda_server_operation_set_value_at (op, strtype, error, "/FIELDS_A/@COLUMN_TYPE/%d", order)) + return FALSE; + + gchar *numstr = NULL; + numstr = g_strdup_printf ("%d", priv->m_size); + + if (g_type_is_a (priv->m_gtype, G_TYPE_STRING)) + { + if(!gda_server_operation_set_value_at (op, numstr, error, "/FIELDS_A/@COLUMN_SIZE/%d", order)) + { + g_free (numstr); + return FALSE; + } + } + + g_free (numstr); + +/* We need to set scale only for numeric column type */ + if (priv->m_gtype == G_TYPE_FLOAT || + priv->m_gtype == G_TYPE_DOUBLE || + priv->m_gtype == GDA_TYPE_NUMERIC) + { + numstr = g_strdup_printf ("%d", priv->m_scale); + + if(!gda_server_operation_set_value_at (op, numstr, error, "/FIELDS_A/@COLUMN_SCALE/%d", order)) + { + g_free (numstr); + return FALSE; + } + + g_free (numstr); + } + + if(!gda_server_operation_set_value_at (op, GDA_BOOL_TO_STR (priv->m_nnul), error, + "/FIELDS_A/@COLUMN_NNUL/%d",order)) + return FALSE; + + if(!gda_server_operation_set_value_at (op, GDA_BOOL_TO_STR (priv->m_autoinc), error, + "/FIELDS_A/@COLUMN_AUTOINC/%d",order)) + return FALSE; + + if(!gda_server_operation_set_value_at (op, GDA_BOOL_TO_STR (priv->m_unique), error, + "/FIELDS_A/@COLUMN_UNIQUE/%d",order)) + return FALSE; + + if(!gda_server_operation_set_value_at (op, GDA_BOOL_TO_STR (priv->m_pkey), error, + "/FIELDS_A/@COLUMN_PKEY/%d",order)) + return FALSE; + + if(!gda_server_operation_set_value_at (op, priv->mp_default, error, + "/FIELDS_A/@COLUMN_DEFAULT/%d", order)) + return FALSE; + + if(!gda_server_operation_set_value_at (op, priv->mp_check,error, + "/FIELDS_A/@COLUMN_CHECK/%d", order)) + return FALSE; + + return TRUE; +} + +/** + * gda_db_column_prepare_add: + * @self: a #GdaDbColumn instance + * @op: #GdaServerOperation to add information + * @error: error storage container + * + * Populate @op with information stored in @self. This method is used to + * prepare @op for %GDA_SERVER_OPERATION_ADD_COLUMN operation. + * + * Returns: %TRUE if success, %FALSE otherwise. + * + * Stability: Stable + * Since: 6.0 + */ +gboolean +gda_db_column_prepare_add (GdaDbColumn *self, + GdaServerOperation *op, + GError **error) +{ + g_return_val_if_fail(GDA_IS_DB_COLUMN(self), FALSE); + g_return_val_if_fail(GDA_IS_SERVER_OPERATION(op), FALSE); + g_return_val_if_fail(error == NULL || *error == NULL, FALSE); + + GdaConnection *cnc; + const gchar *strtype; + + GdaServerOperationType sotype = gda_server_operation_get_op_type(op); + + if (sotype != GDA_SERVER_OPERATION_ADD_COLUMN) + { + g_set_error(error, GDA_DB_COLUMN_ERROR, GDA_DB_COLUMN_ERROR_WRONG_OPERATION, + "Wrong ServerOperation type"); + return FALSE; + } + + cnc = (GdaConnection*) g_object_get_data (G_OBJECT (op), "connection"); + + if (!cnc) + { + g_set_error (error, GDA_DB_COLUMN_ERROR, GDA_DB_COLUMN_ERROR_TYPE, + _("Internal error: Operation should be prepared, setting a connection data")); + return FALSE; + } + + GdaDbColumnPrivate *priv = gda_db_column_get_instance_private (self); + + if (!gda_server_operation_set_value_at (op, priv->mp_name, error, + "/COLUMN_DEF_P/COLUMN_NAME")) + return FALSE; + + strtype = gda_server_provider_get_default_dbms_type (gda_connection_get_provider (cnc), + cnc, priv->m_gtype); + + if (!gda_server_operation_set_value_at (op, strtype, error, + "/COLUMN_DEF_P/COLUMN_TYPE")) + return FALSE; + + gchar *sizestr = NULL; + sizestr = g_strdup_printf ("%d", priv->m_size); + + if (!gda_server_operation_set_value_at (op, sizestr, error, + "/COLUMN_DEF_P/COLUMN_SIZE")) + { + g_free (sizestr); + return FALSE; + } + else + g_free (sizestr); + + if (!gda_server_operation_set_value_at (op, GDA_BOOL_TO_STR (priv->m_nnul), error, + "/COLUMN_DEF_P/COLUMN_NNUL")) + return FALSE; + + if (!gda_server_operation_set_value_at (op, GDA_BOOL_TO_STR (priv->m_autoinc), error, + "/COLUMN_DEF_P/COLUMN_AUTOINC")) + return FALSE; + + sizestr = g_strdup_printf("%d",priv->m_scale); + + if (!gda_server_operation_set_value_at (op, sizestr, error, + "/COLUMN_DEF_P/COLUMN_SCALE")) + { + g_free (sizestr); + return FALSE; + } + else + g_free (sizestr); + + if (!gda_server_operation_set_value_at (op, priv->mp_default, error, + "/COLUMN_DEF_P/COLUMN_DEFAULT")) + return FALSE; + + if (!gda_server_operation_set_value_at (op, priv->mp_check, error, + "/COLUMN_DEF_P/COLUMN_CHECK")) + return FALSE; + + return TRUE; +} + +/** + * gda_db_column_new_from_meta: + * @column: a #GdaMetaTableColumn instance + * + * Create new #GdaDbColumn instance from the corresponding #GdaMetaTableColumn + * object. If %NULL is passed this function works exactly as + * gda_db_column_new(). + * + * Returns: New object that should be freed with g_object_unref() + */ +GdaDbColumn* +gda_db_column_new_from_meta (GdaMetaTableColumn *column) +{ + if (!column) + return gda_db_column_new (); + + GdaDbColumn *gdacolumn = gda_db_column_new (); + + g_object_set (gdacolumn, + "name", column->column_name, + "pkey", column->pkey, + "nnul", column->nullok, + "default", column->default_value, + NULL); + + gda_db_column_set_type (gdacolumn, column->gtype); + return gdacolumn; +} + +static gboolean +gda_db_column_create (GdaDdlModifiable *self, + GdaConnection *cnc, + gpointer user_data, + GError **error) +{ + + G_DEBUG_HERE(); + GdaServerOperation *op = NULL; + GdaServerProvider *provider = NULL; + gchar *buffer_str = NULL; + GdaDbTable *table = NULL; + GdaDbColumn *column = GDA_DB_COLUMN (self); + + const gchar *strtype = NULL; + + gda_lockable_lock (GDA_LOCKABLE (cnc)); + + provider = gda_connection_get_provider (cnc); + + op = gda_server_provider_create_operation (provider, cnc, GDA_SERVER_OPERATION_ADD_COLUMN, + NULL, error); + + if (!op) + goto on_error; + + g_object_get (column, "table", &table, NULL); + + if (!table) + goto on_error; + + if (!gda_server_operation_set_value_at (op, gda_db_base_get_full_name (GDA_DB_BASE (table)), + error, "/COLUMN_DEF_P/TABLE_NAME")) + goto on_error; + + g_object_unref (table); + + if (!gda_server_operation_set_value_at (op, gda_db_column_get_name (column), + error, "/COLUMN_DEF_P/COLUMN_NAME")) + goto on_error; + + strtype = gda_server_provider_get_default_dbms_type (gda_connection_get_provider (cnc), + cnc, gda_db_column_get_gtype(column)); + + if (!gda_server_operation_set_value_at (op, strtype, + error, "/COLUMN_DEF_P/COLUMN_TYPE")) + goto on_error; + + guint size = gda_db_column_get_size (column); + + buffer_str = g_strdup_printf("%d", size); + + if (!gda_server_operation_set_value_at (op, buffer_str, + error, "/COLUMN_DEF_P/COLUMN_SIZE")) + goto on_error; + + g_free (buffer_str); + buffer_str = NULL; + + guint scale = gda_db_column_get_scale (column); + + buffer_str = g_strdup_printf("%d", scale); + + if (!gda_server_operation_set_value_at (op, buffer_str, + error, "/COLUMN_DEF_P/COLUMN_SCALE")) + goto on_error; + + g_free (buffer_str); + buffer_str = NULL; + + if (!gda_server_operation_set_value_at (op, GDA_BOOL_TO_STR (gda_db_column_get_nnul (column)), + error, "/COLUMN_DEF_P/COLUMN_NNUL")) + goto on_error; + + if (!gda_server_provider_perform_operation (provider, cnc, op, error)) + goto on_error; + + g_object_unref (op); + + gda_lockable_unlock (GDA_LOCKABLE (cnc)); + + return TRUE; + +on_error: + if (op) + g_object_unref (op); + + if (buffer_str) + g_free (buffer_str); + + if (table) + g_object_unref (table); + + gda_lockable_unlock (GDA_LOCKABLE (cnc)); + + return FALSE; +} + +static gboolean +gda_db_column_drop (GdaDdlModifiable *self, + GdaConnection *cnc, + gpointer user_data, + GError **error) +{ + g_set_error (error, GDA_DDL_MODIFIABLE_ERROR, + GDA_DDL_MODIFIABLE_NOT_IMPLEMENTED, + _("Operation is not implemented for the used provider")); + + return FALSE; +} + +static gboolean +gda_db_column_rename (GdaDdlModifiable *self, + GdaConnection *cnc, + gpointer user_data, + GError **error) +{ + G_DEBUG_HERE(); + GdaServerOperation *op = NULL; + GdaServerProvider *provider = NULL; + GdaDbTable *table = NULL; + GdaDbColumn *column = GDA_DB_COLUMN (self); + GdaDbColumn *column_new = GDA_DB_COLUMN (user_data); + + gda_lockable_lock (GDA_LOCKABLE (cnc)); + + provider = gda_connection_get_provider (cnc); + + op = gda_server_provider_create_operation (provider, cnc, GDA_SERVER_OPERATION_RENAME_COLUMN, + NULL, error); + + if (!op) + goto on_error; + + g_object_get (column, "table", &table, NULL); + + if (!table) + goto on_error; + + if (!gda_server_operation_set_value_at (op, gda_db_base_get_name (GDA_DB_BASE (table)), + error, "/COLUMN_DEF_P/TABLE_NAME")) + goto on_error; + + g_object_unref (table); + + if (!gda_server_operation_set_value_at (op, gda_db_column_get_name (column), + error, "/COLUMN_DEF_P/COLUMN_NAME")) + goto on_error; + + if (!gda_server_operation_set_value_at (op, gda_db_column_get_name (column_new), + error, "/COLUMN_DEF_P/COLUMN_NAME_NEW")) + goto on_error; + + if (!gda_server_provider_perform_operation (provider, cnc, op, error)) + goto on_error; + + g_object_unref (op); + + gda_lockable_unlock (GDA_LOCKABLE (cnc)); + + return TRUE; + +on_error: + if (op) + g_object_unref (op); + + if (table) + g_object_unref (table); + + gda_lockable_unlock (GDA_LOCKABLE (cnc)); + + return FALSE; +} diff --git a/.flatpak-builder/cache/objects/bb/839de29ea48c656acafd4c0183b1ed14faf26a795736302db4d27daa28ecb2.file b/.flatpak-builder/cache/objects/bb/839de29ea48c656acafd4c0183b1ed14faf26a795736302db4d27daa28ecb2.file new file mode 100644 index 0000000..219cade --- /dev/null +++ b/.flatpak-builder/cache/objects/bb/839de29ea48c656acafd4c0183b1ed14faf26a795736302db4d27daa28ecb2.file @@ -0,0 +1,126 @@ +# lsp_enums.py +# +# Copyright 2021 James Westman +# +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation; either version 3 of the +# License, or (at your option) any later version. +# +# This file is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program. If not, see . +# +# SPDX-License-Identifier: LGPL-3.0-or-later + + +from dataclasses import dataclass +import enum +import typing as T + +from .errors import * +from .utils import * + + +class TextDocumentSyncKind(enum.IntEnum): + None_ = 0 + Full = 1 + Incremental = 2 + + +class CompletionItemTag(enum.IntEnum): + Deprecated = 1 + + +class InsertTextFormat(enum.IntEnum): + PlainText = 1 + Snippet = 2 + + +class CompletionItemKind(enum.IntEnum): + Text = 1 + Method = 2 + Function = 3 + Constructor = 4 + Field = 5 + Variable = 6 + Class = 7 + Interface = 8 + Module = 9 + Property = 10 + Unit = 11 + Value = 12 + Enum = 13 + Keyword = 14 + Snippet = 15 + Color = 16 + File = 17 + Reference = 18 + Folder = 19 + EnumMember = 20 + Constant = 21 + Struct = 22 + Event = 23 + Operator = 24 + TypeParameter = 25 + + +class ErrorCode(enum.IntEnum): + RequestFailed = -32803 + + +@dataclass +class Completion: + label: str + kind: CompletionItemKind + signature: T.Optional[str] = None + deprecated: bool = False + docs: T.Optional[str] = None + text: T.Optional[str] = None + snippet: T.Optional[str] = None + + def to_json(self, snippets: bool): + insert_text = self.text or self.label + insert_text_format = InsertTextFormat.PlainText + if snippets and self.snippet: + insert_text = self.snippet + insert_text_format = InsertTextFormat.Snippet + + result = { + "label": self.label, + "kind": self.kind, + "tags": [CompletionItemTag.Deprecated] if self.deprecated else None, + "detail": self.signature, + "documentation": { + "kind": "markdown", + "value": self.docs, + } + if self.docs + else None, + "deprecated": self.deprecated, + "insertText": insert_text, + "insertTextFormat": insert_text_format, + } + return {k: v for k, v in result.items() if v is not None} + + +class SemanticTokenType(enum.IntEnum): + EnumMember = 0 + + +class DiagnosticSeverity(enum.IntEnum): + Error = 1 + Warning = 2 + Information = 3 + Hint = 4 + + +@dataclass +class SemanticToken: + start: int + end: int + type: SemanticTokenType diff --git a/.flatpak-builder/cache/objects/bb/f3a0f51e3c3b0ac0b6f0f12bcf1e38f0441db8dbd0c6390b240c31ba9b44ef.dirtree b/.flatpak-builder/cache/objects/bb/f3a0f51e3c3b0ac0b6f0f12bcf1e38f0441db8dbd0c6390b240c31ba9b44ef.dirtree new file mode 100644 index 0000000..fc25fda Binary files /dev/null and b/.flatpak-builder/cache/objects/bb/f3a0f51e3c3b0ac0b6f0f12bcf1e38f0441db8dbd0c6390b240c31ba9b44ef.dirtree differ diff --git a/.flatpak-builder/cache/objects/bc/49ba1355a276a447df82f01e3be52eae78c7d5b46209083e901ab9402daf3d.dirtree b/.flatpak-builder/cache/objects/bc/49ba1355a276a447df82f01e3be52eae78c7d5b46209083e901ab9402daf3d.dirtree new file mode 100644 index 0000000..4b60e6b Binary files /dev/null and b/.flatpak-builder/cache/objects/bc/49ba1355a276a447df82f01e3be52eae78c7d5b46209083e901ab9402daf3d.dirtree differ diff --git a/.flatpak-builder/cache/objects/bc/c868e438c8b164399a446b3aedb9646f53c2db927ed5a8225ed96d3a56e1c9.file b/.flatpak-builder/cache/objects/bc/c868e438c8b164399a446b3aedb9646f53c2db927ed5a8225ed96d3a56e1c9.file new file mode 120000 index 0000000..d04002a --- /dev/null +++ b/.flatpak-builder/cache/objects/bc/c868e438c8b164399a446b3aedb9646f53c2db927ed5a8225ed96d3a56e1c9.file @@ -0,0 +1 @@ +device-added.oga \ No newline at end of file diff --git a/.flatpak-builder/cache/objects/bc/f646d7af197d7fecf87bc6cda5f6bb5ed32fd15684f0dbca84d3bdf9c6c1a1.dirtree b/.flatpak-builder/cache/objects/bc/f646d7af197d7fecf87bc6cda5f6bb5ed32fd15684f0dbca84d3bdf9c6c1a1.dirtree new file mode 100644 index 0000000..8e7ab85 Binary files /dev/null and b/.flatpak-builder/cache/objects/bc/f646d7af197d7fecf87bc6cda5f6bb5ed32fd15684f0dbca84d3bdf9c6c1a1.dirtree differ diff --git a/.flatpak-builder/cache/objects/bd/08b09bc086b6a9ef8f3cbc75301e014abdeb98173520ddef95aa76267bdfea.file b/.flatpak-builder/cache/objects/bd/08b09bc086b6a9ef8f3cbc75301e014abdeb98173520ddef95aa76267bdfea.file new file mode 100644 index 0000000..87358d5 --- /dev/null +++ b/.flatpak-builder/cache/objects/bd/08b09bc086b6a9ef8f3cbc75301e014abdeb98173520ddef95aa76267bdfea.file @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2005 - 2014 Vivien Malerba + * Copyright (C) 2006 - 2007 Murray Cumming + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __BACKGROUND_H__ +#define __BACKGROUND_H__ + +#include "gda-worker.h" +#include "itsignaler.h" + +G_BEGIN_DECLS + +/* IISignaler caching */ +void bg_set_spare_its (ITSignaler *its); +ITSignaler *bg_get_spare_its (void); + +/* GdaWorker caching */ +void bg_set_spare_gda_worker (GdaWorker *worker); +GdaWorker *bg_get_spare_gda_worker (void); + +/* threads joining */ +void bg_join_thread (); + + +/* stats */ +typedef enum { + BG_STATS_MIN, + + BG_CREATED_WORKER = BG_STATS_MIN, + BG_DESTROYED_WORKER, + BG_CACHED_WORKER_REQUESTS, + BG_REUSED_WORKER_FROM_CACHE, + + BG_STARTED_THREADS, + BG_JOINED_THREADS, + + BG_CREATED_ITS, + BG_DESTROYED_ITS, + BG_CACHED_ITS_REQUESTS, + BG_REUSED_ITS_FROM_CACHE, + + BG_STATS_MAX +} BackgroundStats; + +void bg_update_stats (BackgroundStats type); + +G_END_DECLS + +#endif diff --git a/.flatpak-builder/cache/objects/bd/62d952ce2281bd0e1ca2131ae81239a4f1896f7cdaf3772b61bc02882c54f5.file b/.flatpak-builder/cache/objects/bd/62d952ce2281bd0e1ca2131ae81239a4f1896f7cdaf3772b61bc02882c54f5.file new file mode 100644 index 0000000..9f026da --- /dev/null +++ b/.flatpak-builder/cache/objects/bd/62d952ce2281bd0e1ca2131ae81239a4f1896f7cdaf3772b61bc02882c54f5.file @@ -0,0 +1,210 @@ +/* + * Copyright (C) 2008 - 2012 Vivien Malerba + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GDA_SQLITE_META_H__ +#define __GDA_SQLITE_META_H__ + +#include + +G_BEGIN_DECLS + +void _gda_sqlite_provider_meta_init (GdaServerProvider *provider); + +/* _information_schema_catalog_name */ +gboolean _gda_sqlite_meta__info (GdaServerProvider *prov, GdaConnection *cnc, + GdaMetaStore *store, GdaMetaContext *context, GError **error); + +/* _builtin_data_types */ +gboolean _gda_sqlite_meta__btypes (GdaServerProvider *prov, GdaConnection *cnc, + GdaMetaStore *store, GdaMetaContext *context, GError **error); + +/* _udt */ +gboolean _gda_sqlite_meta__udt (GdaServerProvider *prov, GdaConnection *cnc, + GdaMetaStore *store, GdaMetaContext *context, GError **error); +gboolean _gda_sqlite_meta_udt (GdaServerProvider *prov, GdaConnection *cnc, + GdaMetaStore *store, GdaMetaContext *context, GError **error, + const GValue *udt_catalog, const GValue *udt_schema); + +/* _udt_columns */ +gboolean _gda_sqlite_meta__udt_cols (GdaServerProvider *prov, GdaConnection *cnc, + GdaMetaStore *store, GdaMetaContext *context, GError **error); +gboolean _gda_sqlite_meta_udt_cols (GdaServerProvider *prov, GdaConnection *cnc, + GdaMetaStore *store, GdaMetaContext *context, GError **error, + const GValue *udt_catalog, const GValue *udt_schema, const GValue *udt_name); + +/* _enums */ +gboolean _gda_sqlite_meta__enums (GdaServerProvider *prov, GdaConnection *cnc, + GdaMetaStore *store, GdaMetaContext *context, GError **error); +gboolean _gda_sqlite_meta_enums (GdaServerProvider *prov, GdaConnection *cnc, + GdaMetaStore *store, GdaMetaContext *context, GError **error, + const GValue *udt_catalog, const GValue *udt_schema, const GValue *udt_name); + +/* _domains */ +gboolean _gda_sqlite_meta__domains (GdaServerProvider *prov, GdaConnection *cnc, + GdaMetaStore *store, GdaMetaContext *context, GError **error); +gboolean _gda_sqlite_meta_domains (GdaServerProvider *prov, GdaConnection *cnc, + GdaMetaStore *store, GdaMetaContext *context, GError **error, + const GValue *domain_catalog, const GValue *domain_schema); + +/* _domain_constraints */ +gboolean _gda_sqlite_meta__constraints_dom (GdaServerProvider *prov, GdaConnection *cnc, + GdaMetaStore *store, GdaMetaContext *context, GError **error); +gboolean _gda_sqlite_meta_constraints_dom (GdaServerProvider *prov, GdaConnection *cnc, + GdaMetaStore *store, GdaMetaContext *context, GError **error, + const GValue *domain_catalog, const GValue *domain_schema, + const GValue *domain_name); + +/* _element_types */ +gboolean _gda_sqlite_meta__el_types (GdaServerProvider *prov, GdaConnection *cnc, + GdaMetaStore *store, GdaMetaContext *context, GError **error); +gboolean _gda_sqlite_meta_el_types (GdaServerProvider *prov, GdaConnection *cnc, + GdaMetaStore *store, GdaMetaContext *context, GError **error, + const GValue *specific_name); + +/* _collations */ +gboolean _gda_sqlite_meta__collations (GdaServerProvider *prov, GdaConnection *cnc, + GdaMetaStore *store, GdaMetaContext *context, GError **error); +gboolean _gda_sqlite_meta_collations (GdaServerProvider *prov, GdaConnection *cnc, + GdaMetaStore *store, GdaMetaContext *context, GError **error, + const GValue *collation_catalog, const GValue *collation_schema, + const GValue *collation_name_n); + +/* _character_sets */ +gboolean _gda_sqlite_meta__character_sets (GdaServerProvider *prov, GdaConnection *cnc, + GdaMetaStore *store, GdaMetaContext *context, GError **error); +gboolean _gda_sqlite_meta_character_sets (GdaServerProvider *prov, GdaConnection *cnc, + GdaMetaStore *store, GdaMetaContext *context, GError **error, + const GValue *chset_catalog, const GValue *chset_schema, + const GValue *chset_name_n); + +/* _schemata */ +gboolean _gda_sqlite_meta__schemata (GdaServerProvider *prov, GdaConnection *cnc, + GdaMetaStore *store, GdaMetaContext *context, GError **error); +gboolean _gda_sqlite_meta_schemata (GdaServerProvider *prov, GdaConnection *cnc, + GdaMetaStore *store, GdaMetaContext *context, GError **error, + const GValue *catalog_name, const GValue *schema_name_n); + +/* _tables or _views */ +gboolean _gda_sqlite_meta__tables_views (GdaServerProvider *prov, GdaConnection *cnc, + GdaMetaStore *store, GdaMetaContext *context, GError **error); +gboolean _gda_sqlite_meta_tables_views (GdaServerProvider *prov, GdaConnection *cnc, + GdaMetaStore *store, GdaMetaContext *context, GError **error, + const GValue *table_catalog, const GValue *table_schema, + const GValue *table_name_n); + +/* _columns */ +gboolean _gda_sqlite_meta__columns (GdaServerProvider *prov, GdaConnection *cnc, + GdaMetaStore *store, GdaMetaContext *context, GError **error); +gboolean _gda_sqlite_meta_columns (GdaServerProvider *prov, GdaConnection *cnc, + GdaMetaStore *store, GdaMetaContext *context, GError **error, + const GValue *table_catalog, const GValue *table_schema, + const GValue *table_name); + +/* _view_column_usage */ +gboolean _gda_sqlite_meta__view_cols (GdaServerProvider *prov, GdaConnection *cnc, + GdaMetaStore *store, GdaMetaContext *context, GError **error); +gboolean _gda_sqlite_meta_view_cols (GdaServerProvider *prov, GdaConnection *cnc, + GdaMetaStore *store, GdaMetaContext *context, GError **error, + const GValue *view_catalog, const GValue *view_schema, + const GValue *view_name); + +/* _table_constraints */ +gboolean _gda_sqlite_meta__constraints_tab (GdaServerProvider *prov, GdaConnection *cnc, + GdaMetaStore *store, GdaMetaContext *context, GError **error); +gboolean _gda_sqlite_meta_constraints_tab (GdaServerProvider *prov, GdaConnection *cnc, + GdaMetaStore *store, GdaMetaContext *context, GError **error, + const GValue *table_catalog, const GValue *table_schema, + const GValue *table_name, const GValue *constraint_name_n); + +/* _referential_constraints */ +gboolean _gda_sqlite_meta__constraints_ref (GdaServerProvider *prov, GdaConnection *cnc, + GdaMetaStore *store, GdaMetaContext *context, GError **error); +gboolean _gda_sqlite_meta_constraints_ref (GdaServerProvider *prov, GdaConnection *cnc, + GdaMetaStore *store, GdaMetaContext *context, GError **error, + const GValue *table_catalog, const GValue *table_schema, const GValue *table_name, + const GValue *constraint_name); + +/* _key_column_usage */ +gboolean _gda_sqlite_meta__key_columns (GdaServerProvider *prov, GdaConnection *cnc, + GdaMetaStore *store, GdaMetaContext *context, GError **error); +gboolean _gda_sqlite_meta_key_columns (GdaServerProvider *prov, GdaConnection *cnc, + GdaMetaStore *store, GdaMetaContext *context, GError **error, + const GValue *table_catalog, const GValue *table_schema, + const GValue *table_name, const GValue *constraint_name); + +/* _check_column_usage */ +gboolean _gda_sqlite_meta__check_columns (GdaServerProvider *prov, GdaConnection *cnc, + GdaMetaStore *store, GdaMetaContext *context, GError **error); +gboolean _gda_sqlite_meta_check_columns (GdaServerProvider *prov, GdaConnection *cnc, + GdaMetaStore *store, GdaMetaContext *context, GError **error, + const GValue *table_catalog, const GValue *table_schema, + const GValue *table_name, const GValue *constraint_name); + +/* _triggers */ +gboolean _gda_sqlite_meta__triggers (GdaServerProvider *prov, GdaConnection *cnc, + GdaMetaStore *store, GdaMetaContext *context, GError **error); +gboolean _gda_sqlite_meta_triggers (GdaServerProvider *prov, GdaConnection *cnc, + GdaMetaStore *store, GdaMetaContext *context, GError **error, + const GValue *table_catalog, const GValue *table_schema, + const GValue *table_name); + +/* _routines */ +gboolean _gda_sqlite_meta__routines (GdaServerProvider *prov, GdaConnection *cnc, + GdaMetaStore *store, GdaMetaContext *context, GError **error); +gboolean _gda_sqlite_meta_routines (GdaServerProvider *prov, GdaConnection *cnc, + GdaMetaStore *store, GdaMetaContext *context, GError **error, + const GValue *routine_catalog, const GValue *routine_schema, + const GValue *routine_name_n); + +/* _routine_columns */ +gboolean _gda_sqlite_meta__routine_col (GdaServerProvider *prov, GdaConnection *cnc, + GdaMetaStore *store, GdaMetaContext *context, GError **error); +gboolean _gda_sqlite_meta_routine_col (GdaServerProvider *prov, GdaConnection *cnc, + GdaMetaStore *store, GdaMetaContext *context, GError **error, + const GValue *rout_catalog, const GValue *rout_schema, + const GValue *rout_name, const GValue *col_name, const GValue *ordinal_position); + +/* _parameters */ +gboolean _gda_sqlite_meta__routine_par (GdaServerProvider *prov, GdaConnection *cnc, + GdaMetaStore *store, GdaMetaContext *context, GError **error); +gboolean _gda_sqlite_meta_routine_par (GdaServerProvider *prov, GdaConnection *cnc, + GdaMetaStore *store, GdaMetaContext *context, GError **error, + const GValue *rout_catalog, const GValue *rout_schema, + const GValue *rout_name); + +/* _table_indexes */ +gboolean _gda_sqlite_meta__indexes_tab (GdaServerProvider *prov, GdaConnection *cnc, + GdaMetaStore *store, GdaMetaContext *context, GError **error); +gboolean _gda_sqlite_meta_indexes_tab (GdaServerProvider *prov, GdaConnection *cnc, + GdaMetaStore *store, GdaMetaContext *context, GError **error, + const GValue *table_catalog, const GValue *table_schema, const GValue *table_name, + const GValue *index_name_n); + +/* _index_column_usage */ +gboolean _gda_sqlite_meta__index_cols (GdaServerProvider *prov, GdaConnection *cnc, + GdaMetaStore *store, GdaMetaContext *context, GError **error); +gboolean _gda_sqlite_meta_index_cols (GdaServerProvider *prov, GdaConnection *cnc, + GdaMetaStore *store, GdaMetaContext *context, GError **error, + const GValue *table_catalog, const GValue *table_schema, + const GValue *table_name, const GValue *index_name); + +G_END_DECLS + +#endif + diff --git a/.flatpak-builder/cache/objects/bd/76c1deb2f87f8955101927b7b0947001e0ee7531d08057753c0cd34d7e64a3.file b/.flatpak-builder/cache/objects/bd/76c1deb2f87f8955101927b7b0947001e0ee7531d08057753c0cd34d7e64a3.file new file mode 120000 index 0000000..edbed83 --- /dev/null +++ b/.flatpak-builder/cache/objects/bd/76c1deb2f87f8955101927b7b0947001e0ee7531d08057753c0cd34d7e64a3.file @@ -0,0 +1 @@ +../../share/runtime/locale/vi/share/vi \ No newline at end of file diff --git a/.flatpak-builder/cache/objects/bd/8fc02b49e4b0c95210fc8b273435b5d2e1f249f0b25a47247ff33bf3f11192.dirtree b/.flatpak-builder/cache/objects/bd/8fc02b49e4b0c95210fc8b273435b5d2e1f249f0b25a47247ff33bf3f11192.dirtree new file mode 100644 index 0000000..169fc04 Binary files /dev/null and b/.flatpak-builder/cache/objects/bd/8fc02b49e4b0c95210fc8b273435b5d2e1f249f0b25a47247ff33bf3f11192.dirtree differ diff --git a/.flatpak-builder/cache/objects/bd/9609b88294b50b0573b6d523efe7654d86598ed8e2251350244e94f076afbe.dirtree b/.flatpak-builder/cache/objects/bd/9609b88294b50b0573b6d523efe7654d86598ed8e2251350244e94f076afbe.dirtree new file mode 100644 index 0000000..aa401cd Binary files /dev/null and b/.flatpak-builder/cache/objects/bd/9609b88294b50b0573b6d523efe7654d86598ed8e2251350244e94f076afbe.dirtree differ diff --git a/.flatpak-builder/cache/objects/be/0f5608bbf1bbc642396f92f647bf8db32aaf2e3f75c0a8cb3f6671fca02a50.file b/.flatpak-builder/cache/objects/be/0f5608bbf1bbc642396f92f647bf8db32aaf2e3f75c0a8cb3f6671fca02a50.file new file mode 100755 index 0000000..c625cd2 Binary files /dev/null and b/.flatpak-builder/cache/objects/be/0f5608bbf1bbc642396f92f647bf8db32aaf2e3f75c0a8cb3f6671fca02a50.file differ diff --git a/.flatpak-builder/cache/objects/be/30d5e9362c2467c8b35b5968b5e09c35aaeb66bfe7c0a4f2b976b5e0868977.file b/.flatpak-builder/cache/objects/be/30d5e9362c2467c8b35b5968b5e09c35aaeb66bfe7c0a4f2b976b5e0868977.file new file mode 120000 index 0000000..82b67de --- /dev/null +++ b/.flatpak-builder/cache/objects/be/30d5e9362c2467c8b35b5968b5e09c35aaeb66bfe7c0a4f2b976b5e0868977.file @@ -0,0 +1 @@ +../../share/runtime/locale/uk/share/uk \ No newline at end of file diff --git a/.flatpak-builder/cache/objects/be/72f7e3f25b17c4d300452717c6fda42643974848d2acfbb28b54bb3f34faeb.dirtree b/.flatpak-builder/cache/objects/be/72f7e3f25b17c4d300452717c6fda42643974848d2acfbb28b54bb3f34faeb.dirtree new file mode 100644 index 0000000..1eefb8d Binary files /dev/null and b/.flatpak-builder/cache/objects/be/72f7e3f25b17c4d300452717c6fda42643974848d2acfbb28b54bb3f34faeb.dirtree differ diff --git a/.flatpak-builder/cache/objects/be/a1dc77d839940fc8c00343f3b43954673fc1e894367614e0c42b5c9e715187.dirtree b/.flatpak-builder/cache/objects/be/a1dc77d839940fc8c00343f3b43954673fc1e894367614e0c42b5c9e715187.dirtree new file mode 100644 index 0000000..e29a8fe Binary files /dev/null and b/.flatpak-builder/cache/objects/be/a1dc77d839940fc8c00343f3b43954673fc1e894367614e0c42b5c9e715187.dirtree differ diff --git a/.flatpak-builder/cache/objects/be/c9153bd9332f347e80cb06509a28f7f3cd2253e4645c9108f5912955097f15.dirtree b/.flatpak-builder/cache/objects/be/c9153bd9332f347e80cb06509a28f7f3cd2253e4645c9108f5912955097f15.dirtree new file mode 100644 index 0000000..334491c Binary files /dev/null and b/.flatpak-builder/cache/objects/be/c9153bd9332f347e80cb06509a28f7f3cd2253e4645c9108f5912955097f15.dirtree differ diff --git a/.flatpak-builder/cache/objects/bf/459b334a47da441bc15492a0fb1878d878150217c10dfa9d077d0a853c009e.file b/.flatpak-builder/cache/objects/bf/459b334a47da441bc15492a0fb1878d878150217c10dfa9d077d0a853c009e.file new file mode 100644 index 0000000..8ff1f0b --- /dev/null +++ b/.flatpak-builder/cache/objects/bf/459b334a47da441bc15492a0fb1878d878150217c10dfa9d077d0a853c009e.file @@ -0,0 +1,32 @@ +# attributes.py +# +# Copyright 2022 James Westman +# +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation; either version 3 of the +# License, or (at your option) any later version. +# +# This file is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program. If not, see . +# +# SPDX-License-Identifier: LGPL-3.0-or-later + + +from .common import * + + +class BaseAttribute(AstNode): + """A helper class for attribute syntax of the form `name: literal_value;`""" + + tag_name: str = "" + attr_name: str = "name" + + @property + def name(self): + return self.tokens["name"] diff --git a/.flatpak-builder/cache/objects/bf/592ebed03687942e5609e376207753374a786370344c228cc19bf2c61b39a3.dirtree b/.flatpak-builder/cache/objects/bf/592ebed03687942e5609e376207753374a786370344c228cc19bf2c61b39a3.dirtree new file mode 100644 index 0000000..3b1ff21 Binary files /dev/null and b/.flatpak-builder/cache/objects/bf/592ebed03687942e5609e376207753374a786370344c228cc19bf2c61b39a3.dirtree differ diff --git a/.flatpak-builder/cache/objects/c0/34e23198f688083f4c9649f79ebda629201d4ca945bbfd59b7e97cc9b0c901.file b/.flatpak-builder/cache/objects/c0/34e23198f688083f4c9649f79ebda629201d4ca945bbfd59b7e97cc9b0c901.file new file mode 100644 index 0000000..330c9f3 Binary files /dev/null and b/.flatpak-builder/cache/objects/c0/34e23198f688083f4c9649f79ebda629201d4ca945bbfd59b7e97cc9b0c901.file differ diff --git a/.flatpak-builder/cache/objects/c0/9edcba69b89ac0717f75efb47f3f1539b8cdf271fb19da2b4aa43dbced4198.dirtree b/.flatpak-builder/cache/objects/c0/9edcba69b89ac0717f75efb47f3f1539b8cdf271fb19da2b4aa43dbced4198.dirtree new file mode 100644 index 0000000..e871404 Binary files /dev/null and b/.flatpak-builder/cache/objects/c0/9edcba69b89ac0717f75efb47f3f1539b8cdf271fb19da2b4aa43dbced4198.dirtree differ diff --git a/.flatpak-builder/cache/objects/c1/29967a1ea82f80276153d424ffb42230f9cb4b088e845b8c210ffa7d081402.dirtree b/.flatpak-builder/cache/objects/c1/29967a1ea82f80276153d424ffb42230f9cb4b088e845b8c210ffa7d081402.dirtree new file mode 100644 index 0000000..811383d Binary files /dev/null and b/.flatpak-builder/cache/objects/c1/29967a1ea82f80276153d424ffb42230f9cb4b088e845b8c210ffa7d081402.dirtree differ diff --git a/.flatpak-builder/cache/objects/c1/562279296619c8b586c15263cd136d5fa7e6f15e1d26c6e8c3bd2ffd92bc8a.dirtree b/.flatpak-builder/cache/objects/c1/562279296619c8b586c15263cd136d5fa7e6f15e1d26c6e8c3bd2ffd92bc8a.dirtree new file mode 100644 index 0000000..6e46edb Binary files /dev/null and b/.flatpak-builder/cache/objects/c1/562279296619c8b586c15263cd136d5fa7e6f15e1d26c6e8c3bd2ffd92bc8a.dirtree differ diff --git a/.flatpak-builder/cache/objects/c1/ad3c442aa884ccce41e015011e88dc6be22c4762de131aadcd865c5e475df1.dirtree b/.flatpak-builder/cache/objects/c1/ad3c442aa884ccce41e015011e88dc6be22c4762de131aadcd865c5e475df1.dirtree new file mode 100644 index 0000000..ae6aa15 Binary files /dev/null and b/.flatpak-builder/cache/objects/c1/ad3c442aa884ccce41e015011e88dc6be22c4762de131aadcd865c5e475df1.dirtree differ diff --git a/.flatpak-builder/cache/objects/c1/cea33b7c9ba5bdc11af988ec827e9e790df84fe8e38a2eb8bf0c5717a330d1.file b/.flatpak-builder/cache/objects/c1/cea33b7c9ba5bdc11af988ec827e9e790df84fe8e38a2eb8bf0c5717a330d1.file new file mode 120000 index 0000000..6b1ed3e --- /dev/null +++ b/.flatpak-builder/cache/objects/c1/cea33b7c9ba5bdc11af988ec827e9e790df84fe8e38a2eb8bf0c5717a330d1.file @@ -0,0 +1 @@ +../../share/runtime/locale/ro/share/ro \ No newline at end of file diff --git a/.flatpak-builder/cache/objects/c2/2b1330b5fa24cf9f9f5dea3c62c513423eda6be223344855ac34079cab8066.file b/.flatpak-builder/cache/objects/c2/2b1330b5fa24cf9f9f5dea3c62c513423eda6be223344855ac34079cab8066.file new file mode 100644 index 0000000..bbb3bda --- /dev/null +++ b/.flatpak-builder/cache/objects/c2/2b1330b5fa24cf9f9f5dea3c62c513423eda6be223344855ac34079cab8066.file @@ -0,0 +1,73 @@ +from .gobject_object import ObjectContent, validate_parent_type +from ..parse_tree import Keyword +from ..ast_utils import AstNode, validate +from .common import * +from .types import TypeName +from .contexts import ScopeCtx + + +class ExtListItemFactory(AstNode): + grammar = [UseExact("id", "template"), Optional(TypeName), ObjectContent] + + @property + def type_name(self) -> T.Optional[TypeName]: + if len(self.children[TypeName]) == 1: + return self.children[TypeName][0] + else: + return None + + @property + def gir_class(self): + return self.root.gir.get_type("ListItem", "Gtk") + + @validate("template") + def container_is_builder_list(self): + validate_parent_type( + self, + "Gtk", + "BuilderListItemFactory", + "sub-templates", + ) + + @validate("template") + def unique_in_parent(self): + self.validate_unique_in_parent("Duplicate template block") + + @validate() + def type_is_list_item(self): + if self.type_name is not None: + if self.type_name.glib_type_name != "GtkListItem": + raise CompileError(f"Only Gtk.ListItem is allowed as a type here") + + @validate("template") + def type_name_upgrade(self): + if self.type_name is None: + raise UpgradeWarning( + "Expected type name after 'template' keyword", + actions=[ + CodeAction( + "Add ListItem type to template block (introduced in blueprint 0.8.0)", + "template ListItem", + ) + ], + ) + + @context(ScopeCtx) + def scope_ctx(self) -> ScopeCtx: + return ScopeCtx(node=self) + + @validate() + def unique_ids(self): + self.context[ScopeCtx].validate_unique_ids() + + @property + def content(self) -> ObjectContent: + return self.children[ObjectContent][0] + + @property + def action_widgets(self): + """ + The sub-template shouldn't have it`s own actions this is + just hear to satisfy XmlOutput._emit_object_or_template + """ + return None diff --git a/.flatpak-builder/cache/objects/c2/351cbaea8009b19b5b674f027c1ba1330539c09b8dbfabde298c0e142e6469.dirtree b/.flatpak-builder/cache/objects/c2/351cbaea8009b19b5b674f027c1ba1330539c09b8dbfabde298c0e142e6469.dirtree new file mode 100644 index 0000000..4e6d905 Binary files /dev/null and b/.flatpak-builder/cache/objects/c2/351cbaea8009b19b5b674f027c1ba1330539c09b8dbfabde298c0e142e6469.dirtree differ diff --git a/.flatpak-builder/cache/objects/c2/41be579042800669c535d123d18b7a811a079c4234289b118b3856fbef2a2c.file b/.flatpak-builder/cache/objects/c2/41be579042800669c535d123d18b7a811a079c4234289b118b3856fbef2a2c.file new file mode 100644 index 0000000..05c564a --- /dev/null +++ b/.flatpak-builder/cache/objects/c2/41be579042800669c535d123d18b7a811a079c4234289b118b3856fbef2a2c.file @@ -0,0 +1,4364 @@ +/* + * Copyright (C) 2001 - 2004 Rodrigo Moya + * Copyright (C) 2002 - 2003 Gonzalo Paniagua Javier + * Copyright (C) 2002 Holger Thon + * Copyright (C) 2003 Laurent Sansonetti + * Copyright (C) 2004 - 2005 Alan Knowles + * Copyright (C) 2004 Dani Baeyens + * Copyright (C) 2004 Julio M. Merino Vidal + * Copyright (C) 2005 - 2006 Bas Driessen + * Copyright (C) 2005 - 2015 Vivien Malerba + * Copyright (C) 2005 Álvaro Peña + * Copyright (C) 2007 Armin Burgmeier + * Copyright (C) 2008 - 2014 Murray Cumming + * Copyright (C) 2008 Przemysław Grzegorczyk + * Copyright (C) 2010 David King + * Copyright (C) 2010 Jonh Wendell + * Copyright (C) 2012, 2018 Daniel Espinosa + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#undef GSEAL_ENABLE + +#define G_LOG_DOMAIN "GDA-server-provider" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "providers-support/gda-data-select-priv.h" + +/* + * provider's private information + */ +typedef struct { + GHashTable *data_handlers; /* key = a GdaServerProviderHandlerInfo pointer, value = a GdaDataHandler */ + GdaSqlParser *parser; + + GHashTable *jobs_hash; /* key = a job ID, value = a # */ + GMutex mutex; +} GdaServerProviderPrivate; + +static void +gda_server_provider_iface_init (GdaLockableInterface *iface); + + +G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GdaServerProvider, + gda_server_provider, + G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE(GDA_TYPE_LOCKABLE, gda_server_provider_iface_init) + G_ADD_PRIVATE(GdaServerProvider)) + +#define CLASS(provider) (GDA_SERVER_PROVIDER_CLASS (G_OBJECT_GET_CLASS (provider))) +#define GDA_DEBUG_VIRTUAL +#undef GDA_DEBUG_VIRTUAL + +static void gda_server_provider_finalize (GObject *object); +static void gda_server_provider_constructed (GObject *object); + +static void gda_server_provider_set_property (GObject *object, + guint param_id, + const GValue *value, + GParamSpec *pspec); +static void gda_server_provider_get_property (GObject *object, + guint param_id, + GValue *value, + GParamSpec *pspec); + +/* properties */ +enum { + PROP_0, +}; + +/* module error */ +GQuark gda_server_provider_error_quark (void) +{ + static GQuark quark; + if (!quark) + quark = g_quark_from_static_string ("gda_server_provider_error"); + return quark; +} + +/* + * GdaServerProvider class implementation + */ + +static void +gda_server_provider_class_init (GdaServerProviderClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->finalize = gda_server_provider_finalize; + object_class->constructed = gda_server_provider_constructed; + + /* Properties */ + object_class->set_property = gda_server_provider_set_property; + object_class->get_property = gda_server_provider_get_property; +} + +static guint +gda_server_provider_handler_info_hash_func (GdaServerProviderHandlerInfo *key) +{ + guint hash; + + hash = g_int_hash (&(key->g_type)); + if (key->dbms_type) + hash += g_str_hash (key->dbms_type); + hash += GPOINTER_TO_UINT (key->cnc); + + return hash; +} + +static gboolean +gda_server_provider_handler_info_equal_func (GdaServerProviderHandlerInfo *a, GdaServerProviderHandlerInfo *b) +{ + if ((a->g_type == b->g_type) && + (a->cnc == b->cnc) && + ((!a->dbms_type && !b->dbms_type) || !strcmp (a->dbms_type, b->dbms_type))) + return TRUE; + else + return FALSE; +} + +static void +gda_server_provider_handler_info_free (GdaServerProviderHandlerInfo *info) +{ + g_free (info->dbms_type); + g_free (info); +} + +typedef struct _WorkerData WorkerData; +static void worker_data_free (WorkerData *wd); + + +static void +gda_server_provider_init (GdaServerProvider *provider) +{ + g_return_if_fail (GDA_IS_SERVER_PROVIDER (provider)); + + GdaServerProviderPrivate *priv = gda_server_provider_get_instance_private (provider); + priv->data_handlers = g_hash_table_new_full ((GHashFunc) gda_server_provider_handler_info_hash_func, + (GEqualFunc) gda_server_provider_handler_info_equal_func, + (GDestroyNotify) gda_server_provider_handler_info_free, + (GDestroyNotify) g_object_unref); + priv->jobs_hash = NULL; + g_mutex_init (&priv->mutex); +} + +static void +gda_server_provider_finalize (GObject *object) +{ + GdaServerProvider *provider = (GdaServerProvider *) object; + g_return_if_fail (GDA_IS_SERVER_PROVIDER (provider)); + GdaServerProviderPrivate *priv = gda_server_provider_get_instance_private (provider); + + /* free memory */ + g_hash_table_destroy (priv->data_handlers); + if (priv->jobs_hash) + g_hash_table_destroy (priv->jobs_hash); + if (priv->parser) + g_object_unref (priv->parser); + + g_mutex_clear (&priv->mutex); + + /* chain to parent class */ + G_OBJECT_CLASS (gda_server_provider_parent_class)->finalize (object); +} + +/* + * Check that the database provider is properly implemented + */ +static void +gda_server_provider_constructed (GObject *object) +{ + GdaServerProvider *provider = (GdaServerProvider *) object; + g_return_if_fail (GDA_IS_SERVER_PROVIDER (provider)); + GdaServerProviderPrivate *priv = gda_server_provider_get_instance_private (provider); + const char* gtype_name = G_OBJECT_TYPE_NAME (object); + + /*g_print ("Provider %p (%s) constructed\n", provider, G_OBJECT_CLASS_NAME (G_OBJECT_GET_CLASS (object)));*/ + if (!priv) + g_warning ("Internal error after creation of %s: provider's private part is missing", gtype_name); + else { + GdaServerProviderBase *fset; + fset = CLASS (provider)->functions_sets [GDA_SERVER_PROVIDER_FUNCTIONS_BASE]; + + if (! fset) + g_warning ("Internal provider implementation error for %s: general virtual functions are missing", gtype_name); + else { + if (! fset->get_name) + g_warning ("Internal error after creation of %s: %s() virtual function missing", gtype_name, "get_name"); + if (! fset->get_version) + g_warning ("Internal error after creation of %s: : %s() virtual function missing", gtype_name, "get_version"); + if (! fset->get_server_version) + g_warning ("Internal error after creation of %s: : %s() virtual function missing", gtype_name, "get_server_version"); + if (!fset->supports_feature) + g_warning ("Internal error after creation of %s: : %s() virtual function missing", gtype_name, "supports_feature"); + if (! fset->statement_to_sql) + g_warning ("Internal error after creation of %s: : %s() virtual function missing", gtype_name, "statement_to_sql"); + if (! fset->statement_rewrite) + g_warning ("Internal error after creation of %s: : %s() virtual function missing", gtype_name, "statement_rewrite"); + if (! fset->open_connection) + g_warning ("Internal error after creation of %s: : %s() virtual function missing", gtype_name, "open_connection"); + if (! fset->create_worker) + g_warning ("Internal error after creation of %s: : %s() virtual function missing", gtype_name, "create_worker"); + if (! fset->close_connection) + g_warning ("Internal error after creation of %s: : %s() virtual function missing", gtype_name, "close_connection"); + if (fset->escape_string && !fset->unescape_string) + g_warning ("Internal error after creation of %s: : virtual method %s implemented and %s _not_ implemented", + gtype_name, "escape_string()", "unescape_string()"); + else if (!fset->escape_string && fset->unescape_string) + g_warning ("Internal error after creation of %s: : virtual method %s implemented and %s _not_ implemented", + gtype_name, "unescape_string()", "escape_string()"); + if (! fset->statement_prepare) + g_warning ("Internal error after creation of %s: : %s() virtual function missing", gtype_name, "statement_prepare"); + if (! fset->statement_execute) + g_warning ("Internal error after creation of %s: : %s() virtual function missing", gtype_name, "statement_execute"); + if (fset->begin_transaction || fset->commit_transaction || fset->rollback_transaction) { + if (! fset->begin_transaction) + g_warning ("Internal error after creation of %s: : %s() virtual function missing", + gtype_name, "begin_transaction"); + if (! fset->commit_transaction) + g_warning ("Internal error after creation of %s: : %s() virtual function missing", + gtype_name, "commit_transaction"); + if (! fset->rollback_transaction) + g_warning ("Internal error after creation of %s: : %s() virtual function missing", + gtype_name, "rollback_transaction"); + } + if (fset->add_savepoint || fset->rollback_savepoint || fset->delete_savepoint) { + if (! fset->add_savepoint) + g_warning ("Internal error after creation of %s: : %s() virtual function missing", + gtype_name, "add_savepoint"); + if (! fset->rollback_savepoint) + g_warning ("Internal error after creation of %s: : %s() virtual function missing", + gtype_name, "rollback_savepoint"); + if (! fset->delete_savepoint) + g_warning ("Internal error after creation of %s: : %s() virtual function missing", + gtype_name, "delete_savepoint"); + } + } + + if (GDA_IS_SERVER_PROVIDER_CLASS (gda_server_provider_parent_class)) { + if (! CLASS (provider)->functions_sets [GDA_SERVER_PROVIDER_FUNCTIONS_META]) + CLASS (provider)->functions_sets [GDA_SERVER_PROVIDER_FUNCTIONS_META] = + GDA_SERVER_PROVIDER_CLASS (gda_server_provider_parent_class)->functions_sets [GDA_SERVER_PROVIDER_FUNCTIONS_META]; + if (! CLASS (provider)->functions_sets [GDA_SERVER_PROVIDER_FUNCTIONS_XA]) + CLASS (provider)->functions_sets [GDA_SERVER_PROVIDER_FUNCTIONS_XA] = + GDA_SERVER_PROVIDER_CLASS (gda_server_provider_parent_class)->functions_sets [GDA_SERVER_PROVIDER_FUNCTIONS_XA]; + } + + GdaServerProviderXa *xaset; + xaset = CLASS (provider)->functions_sets [GDA_SERVER_PROVIDER_FUNCTIONS_XA]; + if (xaset && (xaset->xa_start || xaset->xa_end || xaset->xa_prepare || xaset->xa_commit || + xaset->xa_rollback || xaset->xa_recover)) { + if (! xaset->xa_start) + g_warning ("Internal error after creation of %s: %s() virtual function missing", + gtype_name, "xa_start"); + if (! xaset->xa_end) + g_warning ("Internal error after creation of %s: %s() virtual function missing", + gtype_name, "xa_end"); + if (! xaset->xa_prepare) + g_warning ("Internal error after creation of %s: %s() virtual function missing", + gtype_name, "xa_prepare"); + if (! xaset->xa_commit) + g_warning ("Internal error after creation of %s: %s() virtual function missing", + gtype_name ,"xa_commit"); + if (! xaset->xa_rollback) + g_warning ("Internal error after creation of %s: %s() virtual function missing", + gtype_name, "xa_rollback"); + if (! xaset->xa_recover) + g_warning ("Internal error after creation of %s: %s() virtual function missing", + gtype_name, "xa_recover"); + } + } + + /* chain to parent class */ + G_OBJECT_CLASS (gda_server_provider_parent_class)->constructed (object); +} + + +static void +gda_server_provider_set_property (GObject *object, + guint param_id, + G_GNUC_UNUSED const GValue *value, + GParamSpec *pspec) { + + switch (param_id) { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + break; + } +} + +static void +gda_server_provider_get_property (GObject *object, + guint param_id, + G_GNUC_UNUSED GValue *value, + GParamSpec *pspec) { + + switch (param_id) { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + break; + } +} + +static void +gda_server_provider_lock (GdaLockable *iface) +{ + GdaServerProvider *provider = GDA_SERVER_PROVIDER(iface); + GdaServerProviderPrivate *priv = gda_server_provider_get_instance_private (provider); + + g_mutex_lock (&priv->mutex); +} + +static void +gda_server_provider_unlock (GdaLockable *iface) +{ + GdaServerProvider *provider = GDA_SERVER_PROVIDER(iface); + GdaServerProviderPrivate *priv = gda_server_provider_get_instance_private (provider); + + g_mutex_unlock (&priv->mutex); +} + +static gboolean +gda_server_provider_trylock (GdaLockable *iface) +{ + GdaServerProvider *provider = GDA_SERVER_PROVIDER(iface); + GdaServerProviderPrivate *priv = gda_server_provider_get_instance_private (provider); + + return g_mutex_trylock (&priv->mutex); +} + +static void +gda_server_provider_iface_init (GdaLockableInterface *iface) +{ + iface->lock = gda_server_provider_lock; + iface->unlock = gda_server_provider_unlock; + iface->trylock = gda_server_provider_trylock; +} + +/** + * gda_server_provider_set_impl_functions: + * @klass: a #GdaServerProviderClass object + * @type: a #GdaServerProviderFunctionsType type + * @functions_set: (nullable): a pointer to the function set, or %NULL + * + * Upon creation, used by provider's implementors to set the implementation functions. Passing %NULL + * as the @functions_set has no effect. + * + * If some pointers of @functions_set are %NULL, they are replaced by functions from the parent class of + * @provider. + * + * Warning: this function must only be called once for each different values of @type and for each @klass + * + * Since: 6.0 + */ +void +gda_server_provider_set_impl_functions (GdaServerProviderClass *klass, + GdaServerProviderFunctionsType type, gpointer functions_set) +{ + g_return_if_fail (GDA_IS_SERVER_PROVIDER_CLASS (klass)); + g_return_if_fail ((type >= 0) && (type < GDA_SERVER_PROVIDER_FUNCTIONS_MAX)); + +#ifdef GDA_DEBUG_VIRTUAL + static GObjectClass *parent_pclass = NULL; + parent_pclass = g_type_class_peek_parent (klass); + + g_print ("[V] %s (klass=>%p, Class=>%s, type=>%d, parent_class=>%p, parent class name=>%s )\n", __FUNCTION__, + klass, G_OBJECT_CLASS_NAME (klass), + type, parent_pclass, G_OBJECT_CLASS_NAME (parent_pclass)); +#endif + + if (!functions_set) + return; + + guint size; + typedef void (*VirtualFunc) (void); + switch (type) { + case GDA_SERVER_PROVIDER_FUNCTIONS_BASE: + size = sizeof (GdaServerProviderBase) / sizeof (VirtualFunc); + break; + case GDA_SERVER_PROVIDER_FUNCTIONS_META: + size = sizeof (GdaServerProviderMeta) / sizeof (VirtualFunc); + break; + case GDA_SERVER_PROVIDER_FUNCTIONS_XA: + size = sizeof (GdaServerProviderXa) / sizeof (VirtualFunc); + break; + default: + g_assert_not_reached (); + } + + guint i; + VirtualFunc *functions; + functions = (VirtualFunc*) klass->functions_sets [type]; + if (functions) { + VirtualFunc *new_functions; + new_functions = (VirtualFunc*) functions_set; + for (i = 0; i < size; i++) { + VirtualFunc func; + func = new_functions [i]; + if (!func && functions [i]) { + new_functions [i] = functions [i]; +#ifdef GDA_DEBUG_VIRTUAL + g_print ("[V] Virtual function @index %u replaced by %p\n", i, new_functions [i]); +#endif + } + } + } + + klass->functions_sets [type] = functions_set; +} + +/** + * _gda_server_provider_get_impl_functions: + * @provider: a #GdaServerProvider object + * @worker: a #GdaWorker + * @type: a #GdaServerProviderFunctionsType type + * + * Retreive the pointer to a functions set, as defined by gda_server_provider_set_impl_functions(). + * + * Note: @worker MUST NOT BE %NULL because this function checks that it is actually called from within its worker thread. + * + * Returns: the pointer to the function set, or %NULL + * + * Since: 6.0 + */ +gpointer +_gda_server_provider_get_impl_functions (GdaServerProvider *provider, GdaWorker *worker, GdaServerProviderFunctionsType type) +{ + g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (provider), NULL); + + g_return_val_if_fail ((type >= 0) && (type < GDA_SERVER_PROVIDER_FUNCTIONS_MAX), NULL); + g_return_val_if_fail (worker, NULL); + g_return_val_if_fail (gda_worker_thread_is_worker (worker), NULL); + + return CLASS (provider)->functions_sets [type]; +} + +/* + * gda_server_provider_get_impl_functions_for_class: + * @provider: a #GdaServerProvider object + * @type: a #GdaServerProviderFunctionsType type + * + * Reserved to database provider's implementation, to get the virtual functions of the parent implementation. + * + * NB: this function must only be calld from within a GdaWorker's worker thread! + */ +gpointer +gda_server_provider_get_impl_functions_for_class (GObjectClass *klass, GdaServerProviderFunctionsType type) +{ + g_return_val_if_fail (GDA_IS_SERVER_PROVIDER_CLASS (klass), NULL); + g_return_val_if_fail ((type >= 0) && (type < GDA_SERVER_PROVIDER_FUNCTIONS_MAX), NULL); + +#ifdef GDA_DEBUG_VIRTUAL + g_print ("[V-klass] %s (klass=>%p, Class=>%s)\n", __FUNCTION__, + klass, G_OBJECT_CLASS_NAME (klass)); +#endif + + return GDA_SERVER_PROVIDER_CLASS (klass)->functions_sets [type]; +} + +/* + * _gda_server_provider_create_worker: + * @prov: a #GdaServerProvider + * @for_cnc: if %TRUE, then the #GdaWorker will be used for a connection, and if %FALSE, it will be used for the non connection code + * (in effect the returned #GdaWorker may be the same) + * + * Have @prov create a #GdaWorker. Any connection and C API will only be manipulated by the worker's working thread, + * so if @prov can only be used by 1 thread, then it needs to always return the same object (increasing its reference count). + * + * Important Note: that this is the only code from the provider's implementation to be called by any thread. + * + * Returns: (transfer full): a new #GdaWorker + */ +static GdaWorker * +_gda_server_provider_create_worker (GdaServerProvider *provider, gboolean for_cnc) +{ + g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (provider), NULL); + + GdaServerProviderBase *fset; + fset = CLASS (provider)->functions_sets [GDA_SERVER_PROVIDER_FUNCTIONS_BASE]; /* rem: we don't use + * _gda_server_provider_get_impl_functions() + * because this would fail if not + * called from the worker thread */ + g_assert (fset->create_worker); + return (fset->create_worker) (provider, for_cnc); +} + +/** + * gda_server_provider_get_real_main_context: + * @cnc: (nullable): a #GdaConnection, or %NULL + * + * Obtain a #GMainContext on which to iterate. This function is reserved to database provider's implementations. + * + * NB: if @cnc is NOT %NULL and has a #GdaWorker associated, and if we are in its worker thread, then this function + * returns %NULL (to avoid generating contexts which are never used) + * + * Returns: a #GMainContext, or %NULL. Don't forget to call g_main_context_unref() when done + */ +GMainContext * +gda_server_provider_get_real_main_context (GdaConnection *cnc) +{ + GMainContext *context; + if (cnc) { + GdaServerProviderConnectionData *cdata; + cdata = gda_connection_internal_get_provider_data_error (cnc, NULL); + if (cdata && cdata->worker && gda_worker_thread_is_worker (cdata->worker)) + return NULL; + } + + context = gda_connection_get_main_context (cnc, NULL); + if (context) + g_main_context_ref (context); + else + context = g_main_context_new (); + return context; +} + +typedef struct { + GdaWorker *worker; + GdaServerProvider *provider; + GdaConnection *cnc; +} WorkerGetInfoData; + +/* code executed in GdaWorker's worker thread */ +static gpointer +worker_get_version (WorkerGetInfoData *data, G_GNUC_UNUSED GError **error) +{ + GdaServerProviderBase *fset; + fset = _gda_server_provider_get_impl_functions (data->provider, data->worker, GDA_SERVER_PROVIDER_FUNCTIONS_BASE); + + if (fset->get_version) + return (gpointer) fset->get_version (data->provider); + else + return NULL; +} + +/** + * gda_server_provider_get_version: + * @provider: a #GdaServerProvider object. + * + * Get the version of the provider. + * + * Returns: (transfer none): a string containing the version identification. + */ +const gchar * +gda_server_provider_get_version (GdaServerProvider *provider) +{ + g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (provider), NULL); + + GMainContext *context; + context = gda_server_provider_get_real_main_context (NULL); + + GdaWorker *worker; + worker = _gda_server_provider_create_worker (provider, FALSE); + + WorkerGetInfoData data; + data.worker = worker; + data.provider = provider; + data.cnc = NULL; + + gpointer retval; + gda_worker_do_job (worker, context, 0, &retval, NULL, + (GdaWorkerFunc) worker_get_version, (gpointer) &data, NULL, NULL, NULL); + if (context) + g_main_context_unref (context); + gda_worker_unref (worker); + return (const gchar*) retval; +} + +/* code executed in GdaWorker's worker thread */ +static gpointer +worker_get_name (WorkerGetInfoData *data, G_GNUC_UNUSED GError **error) +{ + GdaServerProviderBase *fset; + fset = _gda_server_provider_get_impl_functions (data->provider, data->worker, GDA_SERVER_PROVIDER_FUNCTIONS_BASE); + + if (fset->get_name) + return (gpointer) fset->get_name (data->provider); + else + return NULL; +} + +/** + * gda_server_provider_get_name: + * @provider: a #GdaServerProvider object. + * + * Get the name (identifier) of the provider + * + * Returns: (transfer none): a string containing the provider's name + */ +const gchar * +gda_server_provider_get_name (GdaServerProvider *provider) +{ + g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (provider), NULL); + + GMainContext *context; + context = gda_server_provider_get_real_main_context (NULL); + + GdaWorker *worker; + worker = _gda_server_provider_create_worker (provider, FALSE); + + WorkerGetInfoData data; + data.worker = worker; + data.provider = provider; + data.cnc = NULL; + + gpointer retval; + gda_worker_do_job (worker, context, 0, &retval, NULL, + (GdaWorkerFunc) worker_get_name, (gpointer) &data, NULL, NULL, NULL); + if (context) + g_main_context_unref (context); + gda_worker_unref (worker); + return (const gchar*) retval; +} + +/* code executed in GdaWorker's worker thread */ +static gpointer +worker_get_server_version (WorkerGetInfoData *data, G_GNUC_UNUSED GError **error) +{ + GdaServerProviderBase *fset; + fset = _gda_server_provider_get_impl_functions (data->provider, data->worker, GDA_SERVER_PROVIDER_FUNCTIONS_BASE); + + const gchar *retval = NULL; + if (fset->get_server_version) + retval = fset->get_server_version (data->provider, data->cnc); + return (gpointer) retval; +} + +/** + * gda_server_provider_get_server_version: + * @provider: a #GdaServerProvider object. + * @cnc: a #GdaConnection object + * + * Get the version of the database to which the connection is opened. + * + * Returns: (transfer none): a (read only) string, or %NULL if an error occurred + */ +const gchar * +gda_server_provider_get_server_version (GdaServerProvider *provider, GdaConnection *cnc) +{ + g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (provider), NULL); + g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL); + g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, NULL); + g_return_val_if_fail (gda_connection_is_opened (cnc), NULL); + + gda_lockable_lock ((GdaLockable*) cnc); /* CNC LOCK */ + + GdaServerProviderConnectionData *cdata; + cdata = gda_connection_internal_get_provider_data_error (cnc, NULL); + if (!cdata) { + gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */ + g_warning ("Internal error: connection reported as opened, yet no provider's data has been setted"); + return FALSE; + } + + GMainContext *context; + context = gda_server_provider_get_real_main_context (cnc); + + WorkerGetInfoData data; + data.worker = cdata->worker; + data.provider = provider; + data.cnc = cnc; + + gpointer retval; + gda_worker_do_job (cdata->worker, context, 0, &retval, NULL, + (GdaWorkerFunc) worker_get_server_version, (gpointer) &data, NULL, NULL, NULL); + if (context) + g_main_context_unref (context); + + gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */ + + return (const gchar*) retval; +} + +typedef struct { + GdaWorker *worker; + GdaServerProvider *provider; + GdaConnection *cnc; + GdaServerOperationType type; + GdaSet *options; +} WorkerSupportsOperationData; + +/* code executed in GdaWorker's worker thread */ +static gpointer +worker_supports_operation (WorkerSupportsOperationData *data, G_GNUC_UNUSED GError **error) +{ + GdaServerProviderBase *fset; + fset = _gda_server_provider_get_impl_functions (data->provider, data->worker, GDA_SERVER_PROVIDER_FUNCTIONS_BASE); + + gboolean retval = FALSE; + if (fset->supports_operation) + retval = fset->supports_operation (data->provider, data->cnc, data->type, data->options); + return retval ? (gpointer) 0x01 : NULL; +} + +/** + * gda_server_provider_supports_operation: + * @provider: a #GdaServerProvider object + * @cnc: (nullable): a #GdaConnection object which would be used to perform an action, or %NULL + * @type: the type of operation requested + * @options: (nullable): a list of named parameters, or %NULL + * + * Tells if @provider supports the @type of operation on the @cnc connection, using the + * (optional) @options parameters. + * + * Returns: %TRUE if the operation is supported + */ +gboolean +gda_server_provider_supports_operation (GdaServerProvider *provider, GdaConnection *cnc, + GdaServerOperationType type, GdaSet *options) +{ + GdaWorker *worker; + g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (provider), FALSE); + if (cnc) { + g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE); + g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE); + g_return_val_if_fail (gda_connection_is_opened (cnc), FALSE); + + gda_lockable_lock ((GdaLockable*) cnc); /* CNC LOCK */ + + GdaServerProviderConnectionData *cdata; + cdata = gda_connection_internal_get_provider_data_error (cnc, NULL); + if (!cdata) { + gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */ + g_warning ("Internal error: connection reported as opened, yet no provider's data has been setted"); + return FALSE; + } + worker = gda_worker_ref (cdata->worker); + } + else + worker = _gda_server_provider_create_worker (provider, FALSE); + + GMainContext *context; + context = gda_server_provider_get_real_main_context (cnc); + + WorkerSupportsOperationData data; + data.worker = worker; + data.provider = provider; + data.cnc = cnc; + data.type = type; + data.options = options; + + gpointer retval; + gda_worker_do_job (worker, context, 0, &retval, NULL, + (GdaWorkerFunc) worker_supports_operation, (gpointer) &data, NULL, NULL, NULL); + if (context) + g_main_context_unref (context); + + if (cnc) + gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */ + + gda_worker_unref (worker); + + return retval ? TRUE : FALSE; +} + +typedef struct { + gchar *path; + GdaServerOperationNodeType node_type; + GType data_type; +} OpReq; + +static OpReq op_req_CREATE_DB [] = { + {"/DB_DEF_P", GDA_SERVER_OPERATION_NODE_PARAMLIST, 0}, + {"/DB_DEF_P/DB_NAME", GDA_SERVER_OPERATION_NODE_PARAM, G_TYPE_STRING}, + {NULL, 0, 0} +}; + +static OpReq op_req_DROP_DB [] = { + {"/DB_DESC_P", GDA_SERVER_OPERATION_NODE_PARAMLIST, 0}, + {"/DB_DESC_P/DB_NAME", GDA_SERVER_OPERATION_NODE_PARAM, G_TYPE_STRING}, + {NULL, 0, 0} +}; + +static OpReq op_req_CREATE_TABLE [] = { + {"/TABLE_DEF_P", GDA_SERVER_OPERATION_NODE_PARAMLIST, 0}, + {"/TABLE_DEF_P/TABLE_NAME", GDA_SERVER_OPERATION_NODE_PARAM, G_TYPE_STRING}, + {"/FIELDS_A", GDA_SERVER_OPERATION_NODE_DATA_MODEL, 0}, + {"/FIELDS_A/@COLUMN_NAME", GDA_SERVER_OPERATION_NODE_DATA_MODEL_COLUMN, G_TYPE_STRING}, + {"/FIELDS_A/@COLUMN_TYPE", GDA_SERVER_OPERATION_NODE_DATA_MODEL_COLUMN, G_TYPE_STRING}, + {NULL, 0, 0} +}; + +static OpReq op_req_DROP_TABLE [] = { + {"/TABLE_DESC_P/TABLE_NAME", GDA_SERVER_OPERATION_NODE_PARAM, G_TYPE_STRING}, + {NULL, 0, 0} +}; + +static OpReq op_req_RENAME_TABLE [] = { + {"/TABLE_DESC_P", GDA_SERVER_OPERATION_NODE_PARAMLIST, 0}, + {"/TABLE_DESC_P/TABLE_NAME", GDA_SERVER_OPERATION_NODE_PARAM, G_TYPE_STRING}, + {"/TABLE_DESC_P/TABLE_NEW_NAME", GDA_SERVER_OPERATION_NODE_PARAM, G_TYPE_STRING}, + {NULL, 0, 0} +}; + +static OpReq op_req_COMMENT_TABLE [] = { + {"/TABLE_DESC_P", GDA_SERVER_OPERATION_NODE_PARAMLIST, 0}, + {"/TABLE_DESC_P/TABLE_NAME", GDA_SERVER_OPERATION_NODE_PARAM, G_TYPE_STRING}, + {"/TABLE_DESC_P/TABLE_COMMENT", GDA_SERVER_OPERATION_NODE_PARAM, G_TYPE_STRING}, + {NULL, 0, 0} +}; + +static OpReq op_req_ADD_COLUMN [] = { + {"/COLUMN_DEF_P", GDA_SERVER_OPERATION_NODE_PARAMLIST, 0}, + {"/COLUMN_DEF_P/TABLE_NAME", GDA_SERVER_OPERATION_NODE_PARAM, G_TYPE_STRING}, + {"/COLUMN_DEF_P/COLUMN_NAME", GDA_SERVER_OPERATION_NODE_PARAM, G_TYPE_STRING}, + {"/COLUMN_DEF_P/COLUMN_TYPE", GDA_SERVER_OPERATION_NODE_PARAM, G_TYPE_STRING}, + {NULL, 0, 0} +}; + +static OpReq op_req_DROP_COLUMN [] = { + {"/COLUMN_DESC_P", GDA_SERVER_OPERATION_NODE_PARAMLIST, 0}, + {"/COLUMN_DESC_P/TABLE_NAME", GDA_SERVER_OPERATION_NODE_PARAM, G_TYPE_STRING}, + {"/COLUMN_DESC_P/COLUMN_NAME", GDA_SERVER_OPERATION_NODE_PARAM, G_TYPE_STRING}, + {NULL, 0, 0} +}; + +static OpReq op_req_COMMENT_COLUMN [] = { + {"/COLUMN_DESC_P", GDA_SERVER_OPERATION_NODE_PARAMLIST, 0}, + {"/COLUMN_DESC_P/TABLE_NAME", GDA_SERVER_OPERATION_NODE_PARAM, G_TYPE_STRING}, + {"/COLUMN_DESC_P/COLUMN_NAME", GDA_SERVER_OPERATION_NODE_PARAM, G_TYPE_STRING}, + {"/COLUMN_DESC_P/COLUMN_COMMENT", GDA_SERVER_OPERATION_NODE_PARAM, G_TYPE_STRING}, + {NULL, 0, 0} +}; + +static OpReq op_req_RENAME_COLUMN [] = { + {"/COLUMN_DEF_P", GDA_SERVER_OPERATION_NODE_PARAMLIST, 0}, + {"/COLUMN_DEF_P/TABLE_NAME", GDA_SERVER_OPERATION_NODE_PARAM, G_TYPE_STRING}, + {"/COLUMN_DEF_P/COLUMN_NAME", GDA_SERVER_OPERATION_NODE_PARAM, G_TYPE_STRING}, + {"/COLUMN_DEF_P/COLUMN_NAME_NEW", GDA_SERVER_OPERATION_NODE_PARAM, G_TYPE_STRING}, + {NULL, 0, 0} +}; + +static OpReq op_req_CREATE_INDEX [] = { + {"/INDEX_DEF_P/INDEX_NAME", GDA_SERVER_OPERATION_NODE_PARAM, G_TYPE_STRING}, + {"/INDEX_DEF_P/INDEX_ON_TABLE", GDA_SERVER_OPERATION_NODE_PARAM, G_TYPE_STRING}, + {"/INDEX_FIELDS_S", GDA_SERVER_OPERATION_NODE_SEQUENCE, 0}, + {NULL, 0, 0} +}; + +static OpReq op_req_RENAME_INDEX [] = { + {"/INDEX_DEF_P/INDEX_NAME", GDA_SERVER_OPERATION_NODE_PARAM, G_TYPE_STRING}, + {"/INDEX_DEF_P/INDEX_ON_TABLE", GDA_SERVER_OPERATION_NODE_PARAM, G_TYPE_STRING}, + {"/INDEX_DEF_P/INDEX_NAME_NEW", GDA_SERVER_OPERATION_NODE_PARAM, G_TYPE_STRING}, + {NULL, 0, 0} +}; + +static OpReq op_req_DROP_INDEX [] = { + {"/INDEX_DESC_P/INDEX_NAME", GDA_SERVER_OPERATION_NODE_PARAM, G_TYPE_STRING}, + {NULL, 0, 0} +}; + +static OpReq op_req_CREATE_VIEW [] = { + {"/VIEW_DEF_P", GDA_SERVER_OPERATION_NODE_PARAMLIST, 0}, + {"/VIEW_DEF_P/VIEW_NAME", GDA_SERVER_OPERATION_NODE_PARAM, G_TYPE_STRING}, + {"/VIEW_DEF_P/VIEW_DEF", GDA_SERVER_OPERATION_NODE_PARAM, G_TYPE_STRING}, + {NULL, 0, 0} +}; + +static OpReq op_req_DROP_VIEW [] = { + {"/VIEW_DESC_P/VIEW_NAME", GDA_SERVER_OPERATION_NODE_PARAM, G_TYPE_STRING}, + {NULL, 0, 0} +}; + +static OpReq op_req_CREATE_USER [] = { + {"/USER_DEF_P", GDA_SERVER_OPERATION_NODE_PARAMLIST, 0}, + {"/USER_DEF_P/USER_NAME", GDA_SERVER_OPERATION_NODE_PARAM, G_TYPE_STRING}, + {NULL, 0, 0} +}; + +typedef WorkerSupportsOperationData WorkerCreateOperationData; + +/* code executed in GdaWorker's worker thread */ +static gpointer +worker_create_operation (WorkerCreateOperationData *data, GError **error) +{ + GdaServerProviderBase *fset; + fset = _gda_server_provider_get_impl_functions (data->provider, data->worker, GDA_SERVER_PROVIDER_FUNCTIONS_BASE); + + GdaServerOperation *op = NULL; + if (fset->create_operation) + op = fset->create_operation (data->provider, data->cnc, data->type, data->options, error); + return (gpointer) op; +} + + +/** + * gda_server_provider_create_operation: + * @provider: a #GdaServerProvider object + * @cnc: (nullable): a #GdaConnection object which will be used to perform an action, or %NULL + * @type: the type of operation requested + * @options: (nullable): a list of parameters or %NULL + * @error: (nullable): a place to store an error, or %NULL + * + * Creates a new #GdaServerOperation object which can be modified in order to perform the @type type of + * action. The @options can contain: + * + * named values which ID is a path in the resulting GdaServerOperation object, to initialize some value + * named values which may change the contents of the GdaServerOperation, see this section for more information + * + * + * Returns: (transfer full) (nullable): a new #GdaServerOperation object, or %NULL in the provider does not support the @type type of operation or if an error occurred + */ +GdaServerOperation * +gda_server_provider_create_operation (GdaServerProvider *provider, GdaConnection *cnc, + GdaServerOperationType type, + GdaSet *options, GError **error) +{ + static GMutex init_mutex; + static OpReq **op_req_table = NULL; + + g_mutex_lock (&init_mutex); + if (! op_req_table) { + op_req_table = g_new0 (OpReq *, GDA_SERVER_OPERATION_LAST); + + op_req_table [GDA_SERVER_OPERATION_CREATE_DB] = op_req_CREATE_DB; + op_req_table [GDA_SERVER_OPERATION_DROP_DB] = op_req_DROP_DB; + + op_req_table [GDA_SERVER_OPERATION_CREATE_TABLE] = op_req_CREATE_TABLE; + op_req_table [GDA_SERVER_OPERATION_DROP_TABLE] = op_req_DROP_TABLE; + op_req_table [GDA_SERVER_OPERATION_RENAME_TABLE] = op_req_RENAME_TABLE; + + op_req_table [GDA_SERVER_OPERATION_ADD_COLUMN] = op_req_ADD_COLUMN; + op_req_table [GDA_SERVER_OPERATION_DROP_COLUMN] = op_req_DROP_COLUMN; + op_req_table [GDA_SERVER_OPERATION_RENAME_COLUMN] = op_req_RENAME_COLUMN; + + op_req_table [GDA_SERVER_OPERATION_CREATE_INDEX] = op_req_CREATE_INDEX; + op_req_table [GDA_SERVER_OPERATION_DROP_INDEX] = op_req_DROP_INDEX; + op_req_table [GDA_SERVER_OPERATION_RENAME_INDEX] = op_req_RENAME_INDEX; + + op_req_table [GDA_SERVER_OPERATION_CREATE_VIEW] = op_req_CREATE_VIEW; + op_req_table [GDA_SERVER_OPERATION_DROP_VIEW] = op_req_DROP_VIEW; + + op_req_table [GDA_SERVER_OPERATION_COMMENT_TABLE] = op_req_COMMENT_TABLE; + op_req_table [GDA_SERVER_OPERATION_COMMENT_COLUMN] = op_req_COMMENT_COLUMN; + + op_req_table [GDA_SERVER_OPERATION_CREATE_USER] = op_req_CREATE_USER; + } + g_mutex_unlock (&init_mutex); + + GdaWorker *worker; + g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (provider), NULL); + if (cnc) { + g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL); + g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, NULL); + g_return_val_if_fail (gda_connection_is_opened (cnc), NULL); + + gda_lockable_lock ((GdaLockable*) cnc); /* CNC LOCK */ + + GdaServerProviderConnectionData *cdata; + cdata = gda_connection_internal_get_provider_data_error (cnc, NULL); + if (!cdata) { + gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */ + g_warning ("Internal error: connection reported as opened, yet no provider's data has been setted"); + return FALSE; + } + worker = gda_worker_ref (cdata->worker); + } + else + worker = _gda_server_provider_create_worker (provider, FALSE); + + GMainContext *context; + context = gda_server_provider_get_real_main_context (cnc); + + WorkerCreateOperationData data; + data.worker = worker; + data.provider = provider; + data.cnc = cnc; + data.type = type; + data.options = options; + + GdaServerOperation *op; + gda_worker_do_job (worker, context, 0, (gpointer) &op, NULL, + (GdaWorkerFunc) worker_create_operation, (gpointer) &data, NULL, NULL, NULL); + if (context) + g_main_context_unref (context); + + if (cnc) + gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */ + + gda_worker_unref (worker); + + if (op) { + /* test op's conformance */ + OpReq *opreq = op_req_table [type]; + while (opreq && opreq->path) { + GdaServerOperationNodeType node_type; + node_type = gda_server_operation_get_node_type (op, opreq->path, NULL); + if (node_type == GDA_SERVER_OPERATION_NODE_UNKNOWN) + g_warning (_("Provider %s created a GdaServerOperation without node for '%s'"), + gda_server_provider_get_name (provider), opreq->path); + else + if (node_type != opreq->node_type) + g_warning (_("Provider %s created a GdaServerOperation with wrong node type for '%s'"), + gda_server_provider_get_name (provider), opreq->path); + opreq += 1; + } + + if (options) { + /* pre-init parameters depending on the @options argument */ + GSList *list; + xmlNodePtr top, node; + + top = xmlNewNode (NULL, BAD_CAST "serv_op_data"); + for (list = gda_set_get_holders (options); list; list = list->next) { + const gchar *id; + gchar *str = NULL; + const GValue *value; + + id = gda_holder_get_id (GDA_HOLDER (list->data)); + value = gda_holder_get_value (GDA_HOLDER (list->data)); + if (value) + str = gda_value_stringify (value); + node = xmlNewTextChild (top, NULL, BAD_CAST "op_data", BAD_CAST str); + g_free (str); + xmlSetProp (node, BAD_CAST "path", BAD_CAST id); + } + + if (! gda_server_operation_load_data_from_xml (op, top, error)) + g_warning ("Incorrect options"); + xmlFreeNode (top); + } + } + + return op; +} + +typedef struct { + GdaWorker *worker; + GdaServerProvider *provider; + GdaConnection *cnc; + GdaServerOperation *op; +} WorkerRenderOperationData; + +/* code executed in GdaWorker's worker thread */ +static gpointer +worker_render_operation (WorkerRenderOperationData *data, GError **error) +{ + GdaServerProviderBase *fset; + fset = _gda_server_provider_get_impl_functions (data->provider, data->worker, GDA_SERVER_PROVIDER_FUNCTIONS_BASE); + + gchar *retval = NULL; + if (fset->render_operation) + retval = fset->render_operation (data->provider, data->cnc, data->op, error); + return (gpointer) retval; +} + +/** + * gda_server_provider_render_operation: + * @provider: a #GdaServerProvider object + * @cnc: (nullable): a #GdaConnection object which will be used to render the action, or %NULL + * @op: a #GdaServerOperation object + * @error: (nullable): a place to store an error, or %NULL + * + * Creates an SQL statement (possibly using some specific extensions of the DBMS) corresponding to the + * @op operation. Note that the returned string may actually contain more than one SQL statement. + * + * This function's purpose is mainly informative to get the actual SQL code which would be executed to perform + * the operation; to actually perform the operation, use gda_server_provider_perform_operation(). + * + * Returns: (transfer full) (nullable): a new string, or %NULL if an error occurred or operation cannot be rendered as SQL. + */ +gchar * +gda_server_provider_render_operation (GdaServerProvider *provider, GdaConnection *cnc, + GdaServerOperation *op, GError **error) +{ + GdaWorker *worker; + g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (provider), NULL); + g_return_val_if_fail (GDA_IS_SERVER_OPERATION (op), NULL); + if (cnc) { + g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL); + g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, NULL); + g_return_val_if_fail (gda_connection_is_opened (cnc), NULL); + + gda_lockable_lock ((GdaLockable*) cnc); /* CNC LOCK */ + + GdaServerProviderConnectionData *cdata; + cdata = gda_connection_internal_get_provider_data_error (cnc, NULL); + if (!cdata) { + gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */ + g_warning ("Internal error: connection reported as opened, yet no provider's data has been setted"); + return FALSE; + } + worker = gda_worker_ref (cdata->worker); + } + else + worker = _gda_server_provider_create_worker (provider, FALSE); + + GMainContext *context; + context = gda_server_provider_get_real_main_context (cnc); + + WorkerRenderOperationData data; + data.worker = worker; + data.provider = provider; + data.cnc = cnc; + data.op = op; + + gpointer retval; + gda_worker_do_job (worker, context, 0, &retval, NULL, + (GdaWorkerFunc) worker_render_operation, (gpointer) &data, NULL, NULL, NULL); + if (context) + g_main_context_unref (context); + + if (cnc) + gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */ + + gda_worker_unref (worker); + + return (gchar*) retval; +} + +typedef struct { + GdaWorker *worker; + GdaServerProvider *provider; + GdaConnection *cnc; + GdaServerOperation *op; +} WorkerPerformOperationData; + +/* code executed in GdaWorker's worker thread */ +static gpointer +worker_perform_operation (WorkerPerformOperationData *data, GError **error) +{ + GdaServerProviderBase *fset; + fset = _gda_server_provider_get_impl_functions (data->provider, data->worker, GDA_SERVER_PROVIDER_FUNCTIONS_BASE); + + gboolean result; + if (fset->perform_operation) + result = fset->perform_operation (data->provider, data->cnc, data->op, error); + else + result = gda_server_provider_perform_operation_default (data->provider, data->cnc, data->op, error); + return result ? (gpointer) 0x01 : NULL; +} + +/** + * gda_server_provider_perform_operation: + * @provider: a #GdaServerProvider object + * @cnc: (nullable): a #GdaConnection object which will be used to perform the action, or %NULL + * @op: a #GdaServerOperation object + * @error: (nullable): a place to store an error, or %NULL + * + * Performs the operation described by @op. Note that @op is not destroyed by this method + * and can be reused. + * + * Returns: %TRUE if no error occurred + */ +gboolean +gda_server_provider_perform_operation (GdaServerProvider *provider, GdaConnection *cnc, + GdaServerOperation *op, GError **error) +{ + GdaWorker *worker; + g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (provider), FALSE); + g_return_val_if_fail (GDA_IS_SERVER_OPERATION (op), FALSE); + if (cnc) { + g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE); + g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE); + g_return_val_if_fail (gda_connection_is_opened (cnc), FALSE); + + gda_lockable_lock ((GdaLockable*) cnc); /* CNC LOCK */ + + GdaServerProviderConnectionData *cdata; + cdata = gda_connection_internal_get_provider_data_error (cnc, NULL); + if (!cdata) { + gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */ + g_warning ("Internal error: connection reported as opened, yet no provider's data has been setted"); + return FALSE; + } + worker = gda_worker_ref (cdata->worker); + } + else + worker = _gda_server_provider_create_worker (provider, FALSE); + + GMainContext *context; + context = gda_server_provider_get_real_main_context (cnc); + + WorkerPerformOperationData data; + data.worker = worker; + data.provider = provider; + data.cnc = cnc; + data.op = op; + +#ifdef GDA_DEBUG_NO + { + g_print ("Perform GdaServerOperation:\n"); + xmlNodePtr node; + node = gda_server_operation_save_data_to_xml (op, NULL); + xmlDocPtr doc; + doc = xmlNewDoc ("1.0"); + xmlDocSetRootElement (doc, node); + xmlDocDump (stdout, doc); + xmlFreeDoc (doc); + } +#endif + + gpointer retval = NULL; + gda_worker_do_job (worker, context, 0, &retval, NULL, + (GdaWorkerFunc) worker_perform_operation, (gpointer) &data, NULL, NULL, error); + if (context) + g_main_context_unref (context); + + if (cnc) + gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */ + + gda_worker_unref (worker); + + return retval ? TRUE : FALSE; +} + +typedef struct { + GdaWorker *worker; + GdaServerProvider *provider; + GdaConnection *cnc; + GdaConnectionFeature feature; +} WorkerSupportsFeatureData; + +/* code executed in GdaWorker's worker thread */ +static gpointer +worker_supports_feature (WorkerSupportsFeatureData *data, G_GNUC_UNUSED GError **error) +{ + GdaServerProviderBase *fset; + fset = _gda_server_provider_get_impl_functions (data->provider, data->worker, GDA_SERVER_PROVIDER_FUNCTIONS_BASE); + + gboolean result = FALSE; + if (fset->supports_feature) { + result = fset->supports_feature (data->provider, data->cnc, data->feature); + if (result && (data->feature == GDA_CONNECTION_FEATURE_XA_TRANSACTIONS)) { + GdaServerProviderXa *xaset; + xaset = _gda_server_provider_get_impl_functions (data->provider, data->worker, + GDA_SERVER_PROVIDER_FUNCTIONS_XA); + if (!xaset->xa_start || !xaset->xa_end || !xaset->xa_prepare || !xaset->xa_commit || + !xaset->xa_rollback || !xaset->xa_recover) + result = FALSE; + } + } + return result ? (gpointer) 0x01 : NULL; +} + +/** + * gda_server_provider_supports_feature: + * @provider: a #GdaServerProvider object + * @cnc: (nullable): a #GdaConnection object, or %NULL + * @feature: #GdaConnectionFeature feature to test + * + * Tests if a feature is supported + * + * Returns: %TRUE if @feature is supported + */ +gboolean +gda_server_provider_supports_feature (GdaServerProvider *provider, GdaConnection *cnc, + GdaConnectionFeature feature) +{ + GdaWorker *worker; + g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (provider), FALSE); + if (cnc) { + g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE); + g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE); + g_return_val_if_fail (gda_connection_is_opened (cnc), FALSE); + + gda_lockable_lock ((GdaLockable*) cnc); /* CNC LOCK */ + + GdaServerProviderConnectionData *cdata; + cdata = gda_connection_internal_get_provider_data_error (cnc, NULL); + if (!cdata) { + gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */ + g_warning ("Internal error: connection reported as opened, yet no provider's data has been setted"); + return FALSE; + } + worker = gda_worker_ref (cdata->worker); + } + else + worker = _gda_server_provider_create_worker (provider, FALSE); + + GMainContext *context; + context = gda_server_provider_get_real_main_context (cnc); + + WorkerSupportsFeatureData data; + data.worker = worker; + data.provider = provider; + data.cnc = cnc; + data.feature = feature; + + gpointer retval = NULL; + gda_worker_do_job (worker, context, 0, &retval, NULL, + (GdaWorkerFunc) worker_supports_feature, (gpointer) &data, NULL, NULL, NULL); + if (context) + g_main_context_unref (context); + + if (cnc) + gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */ + + gda_worker_unref (worker); + + return retval ? TRUE : FALSE; +} + +typedef struct { + GdaWorker *worker; + GdaServerProvider *provider; + GdaConnection *cnc; + GType for_g_type; + const gchar *for_dbms_type; +} WorkerTypeData; + +/* code executed in GdaWorker's worker thread */ +static gpointer +worker_get_data_handler (WorkerTypeData *data, G_GNUC_UNUSED GError **error) +{ + GdaServerProviderBase *fset; + fset = _gda_server_provider_get_impl_functions (data->provider, data->worker, GDA_SERVER_PROVIDER_FUNCTIONS_BASE); + + GdaDataHandler *dh = NULL; + if (fset->get_data_handler) + dh = fset->get_data_handler (data->provider, data->cnc, data->for_g_type, data->for_dbms_type); + return (gpointer) dh; +} + +/** + * gda_server_provider_get_data_handler_g_type: + * @provider: a server provider. + * @cnc: (nullable): a #GdaConnection object, or %NULL + * @for_type: a #GType + * + * Find a #GdaDataHandler object to manipulate data of type @for_type. The returned object must not be modified. + * + * Returns: (transfer none): a #GdaDataHandler, or %NULL if the provider does not support the requested @for_type data type + */ +GdaDataHandler * +gda_server_provider_get_data_handler_g_type (GdaServerProvider *provider, GdaConnection *cnc, GType for_type) +{ + GdaWorker *worker; + g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (provider), NULL); + if (cnc) { + g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL); + g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, NULL); + g_return_val_if_fail (gda_connection_is_opened (cnc), NULL); + + gda_lockable_lock ((GdaLockable*) cnc); /* CNC LOCK */ + + GdaServerProviderConnectionData *cdata; + cdata = gda_connection_internal_get_provider_data_error (cnc, NULL); + if (!cdata) { + gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */ + g_warning ("Internal error: connection reported as opened, yet no provider's data has been setted"); + return FALSE; + } + worker = gda_worker_ref (cdata->worker); + } + else + worker = _gda_server_provider_create_worker (provider, FALSE); + + GMainContext *context; + context = gda_server_provider_get_real_main_context (cnc); + + WorkerTypeData data; + data.worker = worker; + data.provider = provider; + data.cnc = cnc; + data.for_g_type = for_type; + data.for_dbms_type = NULL; + + gpointer retval; + gda_worker_do_job (worker, context, 0, &retval, NULL, + (GdaWorkerFunc) worker_get_data_handler, (gpointer) &data, NULL, NULL, NULL); + if (context) + g_main_context_unref (context); + + if (cnc) + gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */ + + gda_worker_unref (worker); + + return (GdaDataHandler*) retval; +} + +/** + * gda_server_provider_get_data_handler_dbms: + * @provider: a server provider. + * @cnc: (nullable): a #GdaConnection object, or %NULL + * @for_type: a DBMS type definition + * + * Find a #GdaDataHandler object to manipulate data of type @for_type. + * + * Note: this function is currently very poorly implemented by database providers. + * + * Returns: (transfer none): a #GdaDataHandler, or %NULL if the provider does not know about the @for_type type + */ +GdaDataHandler * +gda_server_provider_get_data_handler_dbms (GdaServerProvider *provider, GdaConnection *cnc, const gchar *for_type) +{ + GdaWorker *worker; + g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (provider), NULL); + if (cnc) { + g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL); + g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, NULL); + g_return_val_if_fail (gda_connection_is_opened (cnc), NULL); + + gda_lockable_lock ((GdaLockable*) cnc); /* CNC LOCK */ + + GdaServerProviderConnectionData *cdata; + cdata = gda_connection_internal_get_provider_data_error (cnc, NULL); + if (!cdata) { + gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */ + g_warning ("Internal error: connection reported as opened, yet no provider's data has been setted"); + return FALSE; + } + worker = gda_worker_ref (cdata->worker); + } + else + worker = _gda_server_provider_create_worker (provider, FALSE); + + GMainContext *context; + context = gda_server_provider_get_real_main_context (cnc); + + WorkerTypeData data; + data.worker = worker; + data.provider = provider; + data.cnc = cnc; + data.for_g_type = G_TYPE_INVALID; + data.for_dbms_type = for_type; + + gpointer retval; + gda_worker_do_job (worker, context, 0, &retval, NULL, + (GdaWorkerFunc) worker_get_data_handler, (gpointer) &data, NULL, NULL, NULL); + if (context) + g_main_context_unref (context); + + if (cnc) + gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */ + + gda_worker_unref (worker); + + return (GdaDataHandler*) retval; +} + +/* code executed in GdaWorker's worker thread */ +static gpointer +worker_get_default_dbms_type (WorkerTypeData *data, G_GNUC_UNUSED GError **error) +{ + GdaServerProviderBase *fset; + fset = _gda_server_provider_get_impl_functions (data->provider, data->worker, GDA_SERVER_PROVIDER_FUNCTIONS_BASE); + + const gchar *def = NULL; + if (fset->get_def_dbms_type) + def = fset->get_def_dbms_type (data->provider, data->cnc, data->for_g_type); + return (gpointer) def; +} + +/** + * gda_server_provider_get_default_dbms_type: + * @provider: a server provider. + * @cnc: (nullable): a #GdaConnection object or %NULL + * @type: a #GType value type + * + * Get the name of the most common data type which has @type type. + * + * The returned value may be %NULL either if the provider does not implement that method, or if + * there is no DBMS data type which could contain data of the @g_type type (for example %NULL may be + * returned if a DBMS has integers only up to 4 bytes and a #G_TYPE_INT64 is requested). + * + * Returns: (transfer none) (nullable): the name of the DBMS type, or %NULL + */ +const gchar * +gda_server_provider_get_default_dbms_type (GdaServerProvider *provider, GdaConnection *cnc, GType type) +{ + GdaWorker *worker; + g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (provider), NULL); + if (cnc) { + g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL); + g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, NULL); + g_return_val_if_fail (gda_connection_is_opened (cnc), NULL); + + gda_lockable_lock ((GdaLockable*) cnc); /* CNC LOCK */ + + GdaServerProviderConnectionData *cdata; + cdata = gda_connection_internal_get_provider_data_error (cnc, NULL); + if (!cdata) { + gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */ + g_warning (_("Internal error: connection reported as opened, yet no provider's data has been setted")); + return FALSE; + } + worker = gda_worker_ref (cdata->worker); + } + else + worker = _gda_server_provider_create_worker (provider, FALSE); + + GMainContext *context; + context = gda_server_provider_get_real_main_context (cnc); + + WorkerTypeData data; + data.worker = worker; + data.provider = provider; + data.cnc = cnc; + data.for_g_type = type; + data.for_dbms_type = NULL; + + gpointer retval; + gda_worker_do_job (worker, context, 0, &retval, NULL, + (GdaWorkerFunc) worker_get_default_dbms_type, (gpointer) &data, NULL, NULL, NULL); + if (context) + g_main_context_unref (context); + + if (cnc) + gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */ + + gda_worker_unref (worker); + + return (const gchar*) retval; +} + + +/** + * gda_server_provider_string_to_value: + * @provider: a server provider. + * @cnc: (nullable): a #GdaConnection object, or %NULL + * @string: the SQL string to convert to a value + * @preferred_type: a #GType, or #G_TYPE_INVALID + * @dbms_type: (nullable): place to get the actual database type used if the conversion succeeded, or %NULL + * + * Use @provider to create a new #GValue from a single string representation. + * + * The @preferred_type can optionally ask @provider to return a #GValue of the requested type + * (but if such a value can't be created from @string, then %NULL is returned); + * pass #G_TYPE_INVALID if any returned type is acceptable. + * + * The returned value is either a new #GValue or %NULL in the following cases: + * - @string cannot be converted to @preferred_type type + * - the provider does not handle @preferred_type + * - the provider could not make a #GValue from @string + * + * If @dbms_type is not %NULL, then if will contain a constant string representing + * the database type used for the conversion if the conversion was successfull, or %NULL + * otherwise. + * + * Returns: (transfer full): a new #GValue, or %NULL + */ +GValue * +gda_server_provider_string_to_value (GdaServerProvider *provider, GdaConnection *cnc, const gchar *string, + GType preferred_type, gchar **dbms_type) +{ + GValue *retval = NULL; + GdaDataHandler *dh; + gsize i; + + if (dbms_type) + *dbms_type = NULL; + + g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (provider), NULL); + if (cnc) { + g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL); + g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, NULL); + gda_lockable_lock ((GdaLockable*) cnc); + } + + if (preferred_type != G_TYPE_INVALID) { + dh = gda_server_provider_get_data_handler_g_type (provider, cnc, preferred_type); + if (dh) { + retval = gda_data_handler_get_value_from_sql (dh, string, preferred_type); + if (retval) { + gchar *tmp; + + tmp = gda_data_handler_get_sql_from_value (dh, retval); + if (!tmp || strcmp (tmp, string)) { + gda_value_free (retval); + retval = NULL; + } + else { + if (dbms_type) + *dbms_type = (gchar *) gda_server_provider_get_default_dbms_type (provider, + cnc, preferred_type); + } + + g_free (tmp); + } + } + } + else { + /* test all the possible data types and see if we have a match */ + GType types[] = {G_TYPE_UCHAR, + GDA_TYPE_USHORT, + G_TYPE_UINT, + G_TYPE_UINT64, + + G_TYPE_CHAR, + GDA_TYPE_SHORT, + G_TYPE_INT, + G_TYPE_INT64, + + G_TYPE_FLOAT, + G_TYPE_DOUBLE, + GDA_TYPE_NUMERIC, + + G_TYPE_BOOLEAN, + GDA_TYPE_TIME, + G_TYPE_DATE, + G_TYPE_DATE_TIME, + GDA_TYPE_GEOMETRIC_POINT, + G_TYPE_STRING, + GDA_TYPE_BINARY}; + + for (i = 0; !retval && (i <= (sizeof(types)/sizeof (GType)) - 1); i++) { + dh = gda_server_provider_get_data_handler_g_type (provider, cnc, types [i]); + if (dh) { + retval = gda_data_handler_get_value_from_sql (dh, string, types [i]); + if (retval) { + gchar *tmp; + + tmp = gda_data_handler_get_sql_from_value (dh, retval); + if (!tmp || strcmp (tmp, string)) { + gda_value_free (retval); + retval = NULL; + } + else { + if (dbms_type) + *dbms_type = (gchar *) gda_server_provider_get_default_dbms_type (provider, + cnc, types[i]); + } + g_free (tmp); + } + } + } + } + if (cnc) + gda_lockable_unlock ((GdaLockable*) cnc); + + return retval; +} + + +/** + * gda_server_provider_value_to_sql_string: + * @provider: a server provider. + * @cnc: (nullable): a #GdaConnection object, or %NULL + * @from: #GValue to convert from + * + * Produces a fully quoted and escaped string from a GValue + * + * Returns: (transfer full): escaped and quoted value or NULL if not supported. + */ +gchar * +gda_server_provider_value_to_sql_string (GdaServerProvider *provider, + GdaConnection *cnc, + GValue *from) +{ + gchar *retval = NULL; + GdaDataHandler *dh; + + g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (provider), NULL); + g_return_val_if_fail (!cnc || (gda_connection_get_provider (cnc) == provider), NULL); + g_return_val_if_fail (from != NULL, NULL); + + if (cnc) + gda_lockable_lock ((GdaLockable*) cnc); + dh = gda_server_provider_get_data_handler_g_type (provider, cnc, G_VALUE_TYPE (from)); + if (dh) + retval = gda_data_handler_get_sql_from_value (dh, from); + if (cnc) + gda_lockable_unlock ((GdaLockable*) cnc); + return retval; +} + +typedef struct { + GdaWorker *worker; + GdaServerProvider *provider; + GdaConnection *cnc; + const gchar *str; +} WorkerEscapeData; + +static gpointer +worker_escape_string (WorkerEscapeData *data, G_GNUC_UNUSED GError **error) +{ + GdaServerProviderBase *fset; + fset = _gda_server_provider_get_impl_functions (data->provider, data->worker, GDA_SERVER_PROVIDER_FUNCTIONS_BASE); + + if (fset->escape_string) + return fset->escape_string (data->provider, data->cnc, data->str); + else + return gda_default_escape_string (data->str); +} + +/** + * gda_server_provider_escape_string: + * @provider: a server provider. + * @cnc: (nullable): a #GdaConnection object, or %NULL + * @str: a string to escape + * + * Escapes @str for use within an SQL command (to avoid SQL injection attacks). Note that the returned value still needs + * to be enclosed in single quotes before being used in an SQL statement. + * + * Returns: (transfer full): a new string suitable to use in SQL statements + */ +gchar * +gda_server_provider_escape_string (GdaServerProvider *provider, GdaConnection *cnc, const gchar *str) +{ + GdaWorker *worker; + g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (provider), NULL); + g_return_val_if_fail (str, NULL); + if (cnc) { + g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL); + g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, NULL); + g_return_val_if_fail (gda_connection_is_opened (cnc), NULL); + + gda_lockable_lock ((GdaLockable*) cnc); /* CNC LOCK */ + + GdaServerProviderConnectionData *cdata; + cdata = gda_connection_internal_get_provider_data_error (cnc, NULL); + if (!cdata) { + gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */ + g_warning ("Internal error: connection reported as opened, yet no provider's data has been setted"); + return FALSE; + } + worker = gda_worker_ref (cdata->worker); + } + else + worker = _gda_server_provider_create_worker (provider, FALSE); + + GMainContext *context; + context = gda_server_provider_get_real_main_context (cnc); + + WorkerEscapeData data; + data.worker = worker; + data.provider = provider; + data.cnc = cnc; + data.str = str; + + gpointer retval; + gda_worker_do_job (worker, context, 0, &retval, NULL, + (GdaWorkerFunc) worker_escape_string, (gpointer) &data, NULL, NULL, NULL); + if (context) + g_main_context_unref (context); + + if (cnc) + gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */ + + gda_worker_unref (worker); + + return (gchar*) retval; +} + +static gpointer +worker_unescape_string (WorkerEscapeData *data, G_GNUC_UNUSED GError **error) +{ + GdaServerProviderBase *fset; + fset = _gda_server_provider_get_impl_functions (data->provider, data->worker, GDA_SERVER_PROVIDER_FUNCTIONS_BASE); + + if (fset->unescape_string) + return fset->unescape_string (data->provider, data->cnc, data->str); + else + return gda_default_unescape_string (data->str); +} + +/** + * gda_server_provider_unescape_string: + * @provider: a server provider. + * @cnc: (nullable): a #GdaConnection object, or %NULL + * @str: a string to escape + * + * Unescapes @str for use within an SQL command. This is the exact opposite of gda_server_provider_escape_string(). + * + * Returns: (transfer full): a new string + */ +gchar * +gda_server_provider_unescape_string (GdaServerProvider *provider, GdaConnection *cnc, const gchar *str) +{ + GdaWorker *worker; + g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (provider), NULL); + g_return_val_if_fail (str, NULL); + if (cnc) { + g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL); + g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, NULL); + g_return_val_if_fail (gda_connection_is_opened (cnc), NULL); + + gda_lockable_lock ((GdaLockable*) cnc); /* CNC LOCK */ + + GdaServerProviderConnectionData *cdata; + cdata = gda_connection_internal_get_provider_data_error (cnc, NULL); + if (!cdata) { + gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */ + g_warning ("Internal error: connection reported as opened, yet no provider's data has been setted"); + return FALSE; + } + worker = gda_worker_ref (cdata->worker); + } + else + worker = _gda_server_provider_create_worker (provider, FALSE); + + GMainContext *context; + context = gda_server_provider_get_real_main_context (cnc); + + WorkerEscapeData data; + data.worker = worker; + data.provider = provider; + data.cnc = cnc; + data.str = str; + + gpointer retval; + gda_worker_do_job (worker, context, 0, &retval, NULL, + (GdaWorkerFunc) worker_unescape_string, (gpointer) &data, NULL, NULL, NULL); + if (context) + g_main_context_unref (context); + + if (cnc) + gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */ + + gda_worker_unref (worker); + + return (gchar*) retval; +} + +typedef struct { + GdaWorker *worker; + GdaServerProvider *provider; + GdaConnection *cnc; +} WorkerParserData; + +static gpointer +worker_create_parser (WorkerParserData *data, G_GNUC_UNUSED GError **error) +{ + GdaServerProviderBase *fset; + fset = _gda_server_provider_get_impl_functions (data->provider, data->worker, GDA_SERVER_PROVIDER_FUNCTIONS_BASE); + + if (fset->create_parser) + return fset->create_parser (data->provider, data->cnc); + else + return NULL; +} + +/** + * gda_server_provider_create_parser: + * @provider: a #GdaServerProvider provider object + * @cnc: (nullable): a #GdaConnection, or %NULL + * + * Creates a new #GdaSqlParser object which is adapted to @provider (and possibly depending on + * @cnc for the actual database version). + * + * If @prov does not have its own parser, then %NULL is returned, and a general SQL parser can be obtained + * using gda_sql_parser_new(). + * + * Returns: (transfer full): a new #GdaSqlParser object, or %NULL. + */ +GdaSqlParser * +gda_server_provider_create_parser (GdaServerProvider *provider, GdaConnection *cnc) +{ + GdaWorker *worker; + g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (provider), NULL); + if (cnc) { + g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL); + g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, NULL); + g_return_val_if_fail (gda_connection_is_opened (cnc), NULL); + + gda_lockable_lock ((GdaLockable*) cnc); /* CNC LOCK */ + + GdaServerProviderConnectionData *cdata; + cdata = gda_connection_internal_get_provider_data_error (cnc, NULL); + if (!cdata) { + gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */ + g_warning ("Internal error: connection reported as opened, yet no provider's data has been setted"); + return FALSE; + } + worker = gda_worker_ref (cdata->worker); + } + else + worker = _gda_server_provider_create_worker (provider, FALSE); + + GMainContext *context; + context = gda_server_provider_get_real_main_context (cnc); + + WorkerParserData data; + data.worker = worker; + data.provider = provider; + data.cnc = cnc; + + gpointer retval; + gda_worker_do_job (worker, context, 0, &retval, NULL, + (GdaWorkerFunc) worker_create_parser, (gpointer) &data, NULL, NULL, NULL); + if (context) + g_main_context_unref (context); + + if (cnc) + gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */ + + gda_worker_unref (worker); + + return (GdaSqlParser*) retval; +} + +/* + * Possible job types + */ +typedef enum { + JOB_CREATE_CONNECTION, + JOB_OPEN_CONNECTION, + JOB_CLOSE_CONNECTION, + JOB_PREPARE_STATEMENT, + JOB_EXECUTE_STATEMENT, + JOB_IDENTIFIER_QUOTE, + JOB_META, + JOB_BEGIN_TRANSACTION, + JOB_COMMIT_TRANSACTION, + JOB_ROLLBACK_TRANSACTION, + JOB_ADD_SAVEPOINT, + JOB_ROLLBACK_SAVEPOINT, + JOB_DELETE_SAVEPOINT, + JOB_XA_START, + JOB_XA_END, + JOB_XA_PREPARE, + JOB_XA_COMMIT, + JOB_XA_ROLLBACK, + JOB_XA_RECOVER, + JOB_STMT_TO_SQL, +} WorkerDataType; + +/* + * Holds information associated with any kind of job + */ +struct _WorkerData { + guint job_id; + WorkerDataType job_type; + + gpointer job_data; + GDestroyNotify job_data_destroy_func; +}; + +/* + * generic function to free the job's associated data + */ +static void +worker_data_free (WorkerData *wd) +{ + if (wd->job_data) { + g_assert (wd->job_data_destroy_func); + wd->job_data_destroy_func (wd->job_data); + } + g_slice_free (WorkerData, wd); +} + +static void server_provider_job_done_callback (GdaWorker *worker, guint job_id, gpointer result, + GError *error, GdaServerProvider *provider); + +/***********************************************************************************************************/ + +/* + * JOB_CREATE_CONNECTION + */ + +typedef struct { + GdaWorker *worker; + GdaServerProvider *provider; +} WorkerCreateConnectionData; + +static gpointer +worker_create_connection (WorkerCreateConnectionData *data, GError **error) +{ + GdaServerProviderBase *fset; + fset = _gda_server_provider_get_impl_functions (data->provider, data->worker, GDA_SERVER_PROVIDER_FUNCTIONS_BASE); + + if (fset->create_connection) + return fset->create_connection (data->provider); + else + return NULL; +} + +GdaConnection * +_gda_server_provider_create_connection (GdaServerProvider *provider, const gchar *dsn_string, const gchar *cnc_string, + const gchar *auth_string, GdaConnectionOptions options) +{ + g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (provider), FALSE); + g_return_val_if_fail (!dsn_string || !cnc_string, FALSE); + + GMainContext *context; + context = gda_server_provider_get_real_main_context (NULL); + + GdaWorker *worker; + worker = _gda_server_provider_create_worker (provider, FALSE); + + WorkerCreateConnectionData data; + data.provider = provider; + data.worker = worker; + + gpointer cnc; + gda_worker_do_job (worker, context, 0, &cnc, NULL, + (GdaWorkerFunc) worker_create_connection, (gpointer) &data, NULL, NULL, NULL); + if (context) + g_main_context_unref (context); + gda_worker_unref (worker); + + if (cnc) + g_object_set (G_OBJECT (cnc), + "provider", provider, + "auth-string", auth_string, + "options", options, NULL); + else + cnc = g_object_new (GDA_TYPE_CONNECTION, + "provider", provider, + "auth-string", auth_string, + "options", options, NULL); + + if (dsn_string) + g_object_set (G_OBJECT (cnc), + "dsn", dsn_string, NULL); + else if (cnc_string) + g_object_set (G_OBJECT (cnc), + "cnc-string", cnc_string, NULL); + return (GdaConnection*) cnc; +} + +/***********************************************************************************************************/ + +/* + * JOB_OPEN_CONNECTION + * WorkerOpenConnectionData + * + */ +typedef struct { + GdaWorker *worker; + GdaServerProvider *provider; + GdaConnection *cnc; + GdaQuarkList *params; + GdaQuarkList *auth; + GdaConnectionOpenFunc callback; + gpointer callback_data; /* FIXME: add data destroy func */ +} WorkerOpenConnectionData; + +static void +WorkerOpenConnectionData_free (WorkerOpenConnectionData *data) +{ + gda_worker_unref (data->worker); + g_object_unref (data->cnc); + gda_quark_list_free (data->params); + gda_quark_list_free (data->auth); + g_slice_free (WorkerOpenConnectionData, data); +} + +static void +compute_error (GdaConnection *cnc, GError **error) +{ + if (!error) + return; + const GList *events, *l; + events = gda_connection_get_events (cnc); + + for (l = g_list_last ((GList*) events); l; l = l->prev) { + GdaConnectionEvent *event; + + event = GDA_CONNECTION_EVENT (l->data); + if (gda_connection_event_get_event_type (event) == GDA_CONNECTION_EVENT_ERROR) { + if (!(*error)) + g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_OPEN_ERROR, + "%s", gda_connection_event_get_description (event)); + } + } +} + +static gpointer +worker_open_connection (WorkerOpenConnectionData *data, GError **error) +{ + GdaServerProviderBase *fset; + fset = _gda_server_provider_get_impl_functions (data->provider, data->worker, GDA_SERVER_PROVIDER_FUNCTIONS_BASE); + + guint delay; + delay = _gda_connection_get_exec_slowdown (data->cnc); + if (delay > 0) { + g_print (_("Delaying opening connection for %u ms\n"), delay); + g_usleep (delay); + } + + gboolean result; + result = fset->open_connection (data->provider, data->cnc, data->params, data->auth); + if (result) { + GdaServerProviderConnectionData *cdata; + cdata = gda_connection_internal_get_provider_data_error (data->cnc, NULL); + if (!cdata) { + g_warning ("Internal error: connection reported as opened, yet no provider's data has been setted"); + result = FALSE; + } + else + cdata->worker = gda_worker_ref (data->worker); + + if (fset->prepare_connection) { + result = fset->prepare_connection (data->provider, data->cnc, data->params, data->auth); + if (!result) { + compute_error (data->cnc, error); + + fset->close_connection (data->provider, data->cnc); + gda_connection_internal_set_provider_data (data->cnc, NULL, NULL); + + gda_worker_unref (cdata->worker); + cdata->worker = NULL; + + if (cdata->provider_data_destroy_func) + cdata->provider_data_destroy_func (cdata); + } + } + } + if (data->params) + gda_quark_list_protect_values (data->params); + if (data->auth) + gda_quark_list_protect_values (data->params); + + /* error computing */ + if (!result) + compute_error (data->cnc, error); + + return result ? (gpointer) 0x01 : NULL; +} + +/* + * Steals @worker + */ +static gboolean +stage2_open_connection (GdaWorker *worker, GdaConnection *cnc, gpointer result) +{ + if (result) { + GdaServerProviderConnectionData *cdata; + cdata = gda_connection_internal_get_provider_data_error (cnc, NULL); + if (!cdata) { + g_warning ("Internal error: connection reported as opened, yet no provider's data has been setted"); + result = NULL; + _gda_connection_set_status (cnc, GDA_CONNECTION_STATUS_CLOSED); + } + else { + _gda_connection_set_status (cnc, GDA_CONNECTION_STATUS_IDLE); + g_signal_emit_by_name (G_OBJECT (cnc), "opened"); + } + } + + gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */ + + gda_worker_unref (worker); + + return result ? TRUE : FALSE; +} + +/* + * _gda_server_provider_open_connection: + * @provider: a #GdaServerProvider + * @cnc: a #GdaConnection + * @params: (transfer full): parameters specifying the connection's attributes + * @auth: (nullable) (transfer full): authentification parameters, or %NULL + * @cb_func: (nullable): a #GdaConnectionOpenFunc function, or %NULL + * @data: (nullable): data to pass to @cb_func, or %NULL + * @out_job_id: (nullable): a place to store the job ID, or %NULL + * @error: (nullable): a place to store error, or %NULL + * + * Call the open_connection() in the worker thread. + * + * 2 modes: + * - sync: where @cb_func and @out_job_id are _both_ NULL, and @data is ignored + * Returns: %FALSE if an error occurred, and %TRUE if connection is then opened + * + * - async: where @cb_func and @out_job_id are _both_ NOT NULL, and @error is ignored + * Returns: %FALSE if an error occurred submitting the job, and %TRUE if job has been submitted. @error may contain the + * error when submitting the job + * + */ +gboolean +_gda_server_provider_open_connection (GdaServerProvider *provider, GdaConnection *cnc, + GdaQuarkList *params, GdaQuarkList *auth, + GdaConnectionOpenFunc cb_func, gpointer data, guint *out_job_id, + GError **error) +{ + g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (provider), FALSE); + g_return_val_if_fail (cnc && (gda_connection_get_provider (cnc) == provider), FALSE); + g_return_val_if_fail (! gda_connection_is_opened (cnc), TRUE); + g_return_val_if_fail (params, FALSE); + + GdaServerProviderPrivate *priv = gda_server_provider_get_instance_private (provider); + + if (out_job_id) + *out_job_id = 0; + g_return_val_if_fail ((cb_func && out_job_id) || (!cb_func && !out_job_id), FALSE); + + GMainContext *context; + context = gda_connection_get_main_context (cnc, NULL); + if (cb_func && !context) { + g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_NO_MAIN_CONTEXT_ERROR, + "%s", _("You need to define a GMainContext using gda_connection_set_main_context()")); + return FALSE; + } + + gda_lockable_lock ((GdaLockable*) cnc); /* CNC LOCK */ + _gda_connection_set_status (cnc, GDA_CONNECTION_STATUS_OPENING); + + GdaWorker *worker; + worker = _gda_server_provider_create_worker (provider, TRUE); + _gda_connection_internal_set_worker_thread (cnc, gda_worker_get_worker_thread (worker)); + + /* define callback if not yet done */ + if (cb_func) { + if (!gda_worker_set_callback (worker, context, + (GdaWorkerCallback) server_provider_job_done_callback, provider, error)) { + _gda_connection_set_status (cnc, GDA_CONNECTION_STATUS_CLOSED); + gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */ + gda_worker_unref (worker); + return FALSE; + } + + if (!priv->jobs_hash) + priv->jobs_hash = g_hash_table_new_full (g_int_hash, g_int_equal, + NULL, (GDestroyNotify) worker_data_free); + } + + /* preparing data required to submit job to GdaWorker */ + WorkerOpenConnectionData *jdata; + jdata = g_slice_new (WorkerOpenConnectionData); + jdata->worker = gda_worker_ref (worker); + jdata->provider = provider; + jdata->cnc = g_object_ref (cnc); + jdata->params = params; + jdata->auth = auth; + jdata->callback = cb_func; + jdata->callback_data = data; + + if (cb_func) { + guint job_id; + job_id = gda_worker_submit_job (worker, context, + (GdaWorkerFunc) worker_open_connection, + jdata, NULL, NULL, error); + if (job_id == 0) { + _gda_connection_set_status (cnc, GDA_CONNECTION_STATUS_CLOSED); + gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */ + WorkerOpenConnectionData_free (jdata); + return FALSE; /* error */ + } + else { + WorkerData *wd; + wd = g_slice_new0 (WorkerData); + wd->job_id = job_id; + wd->job_type = JOB_OPEN_CONNECTION; + wd->job_data = (gpointer) jdata; + wd->job_data_destroy_func = (GDestroyNotify) WorkerOpenConnectionData_free; + g_hash_table_insert (priv->jobs_hash, & wd->job_id, wd); + *out_job_id = job_id; + return TRUE; /* no error, LOCK on CNC is kept */ + } + } + else { + gpointer result; + if (context) + g_main_context_ref (context); + else + context = g_main_context_new (); + gda_worker_do_job (worker, context, 0, &result, NULL, + (GdaWorkerFunc) worker_open_connection, jdata, (GDestroyNotify) WorkerOpenConnectionData_free, + NULL, error); + g_main_context_unref (context); + + gboolean retval; + retval = stage2_open_connection (worker, cnc, result); /* steals @worker and unlocks @cnc */ + return retval; + } +} + +/***********************************************************************************************************/ + +/* + * JOB_CLOSE_CONNECTION + * WorkerCloseConnectionData + * + */ +typedef struct { + GdaWorker *worker; + GdaServerProvider *provider; + GdaConnection *cnc; +} WorkerCloseConnectionData; + +static void +WorkerCloseConnectionData_free (WorkerCloseConnectionData *data) +{ + //g_print ("%s() th %p %s\n", __FUNCTION__, g_thread_self(), gda_worker_thread_is_worker (data->worker) ? "Thread Worker" : "NOT thread worker"); + _gda_connection_internal_set_worker_thread (data->cnc, NULL); + gda_worker_unref (data->worker); + g_object_unref (data->cnc); + g_slice_free (WorkerCloseConnectionData, data); +} + +static gpointer +worker_close_connection (WorkerCloseConnectionData *data, GError **error) +{ + GdaServerProviderBase *fset; + fset = _gda_server_provider_get_impl_functions (data->provider, data->worker, GDA_SERVER_PROVIDER_FUNCTIONS_BASE); + + gboolean result; + result = fset->close_connection (data->provider, data->cnc); + + guint delay; + delay = _gda_connection_get_exec_slowdown (data->cnc); + if (delay > 0) { + g_print (_("Delaying closing connection for %u ms\n"), delay / 1000); + g_usleep (delay); + } + + /* error computing */ + if (!result) { + const GList *events, *l; + events = gda_connection_get_events (data->cnc); + + for (l = g_list_last ((GList*) events); l; l = l->prev) { + GdaConnectionEvent *event; + + event = GDA_CONNECTION_EVENT (l->data); + if (gda_connection_event_get_event_type (event) == GDA_CONNECTION_EVENT_ERROR) { + if (error && !(*error)) + g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_OPEN_ERROR, + "%s", gda_connection_event_get_description (event)); + } + } + } + + return result ? (gpointer) 0x01 : NULL; +} + +static gboolean +stage2_close_connection (GdaConnection *cnc, gpointer result) +{ + if (result) { + GdaServerProviderConnectionData *cdata; + cdata = gda_connection_internal_get_provider_data_error (cnc, NULL); + if (cdata) { + gda_connection_internal_set_provider_data (cnc, NULL, NULL); + + if (cdata->provider_data_destroy_func) { + cdata->provider_data_destroy_func (cdata); + } + } + _gda_connection_set_status (cnc, GDA_CONNECTION_STATUS_CLOSED); + } + + gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */ + + return result ? TRUE : FALSE; +} + +/* + * _gda_server_provider_close_connection: + * @provider: a #GdaServerProvider + * @cnc: a #GdaConnection + * @error: (nullable): a place to store error, or %NULL + * + * Call the close_connection() in the worker thread. + */ +gboolean +_gda_server_provider_close_connection (GdaServerProvider *provider, GdaConnection *cnc, GError **error) +{ + g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (provider), FALSE); + g_return_val_if_fail (cnc && (gda_connection_get_provider (cnc) == provider), FALSE); + g_return_val_if_fail (gda_connection_is_opened (cnc), TRUE); + + gda_lockable_lock ((GdaLockable*) cnc); /* CNC LOCK */ + + GdaServerProviderConnectionData *cdata; + cdata = gda_connection_internal_get_provider_data_error (cnc, NULL); + if (!cdata) { + gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */ + g_warning ("Internal error: connection reported as opened, yet no provider's data has been setted"); + return FALSE; + } + + GMainContext *context; + context = gda_server_provider_get_real_main_context (cnc); + + WorkerCloseConnectionData *jdata; + jdata = g_slice_new (WorkerCloseConnectionData); + jdata->worker = gda_worker_ref (cdata->worker); + jdata->provider = provider; + jdata->cnc = g_object_ref (cnc); + + GdaWorker *worker; + worker = cdata->worker; + + gpointer result; + gda_worker_do_job (cdata->worker, context, 0, &result, NULL, + (GdaWorkerFunc) worker_close_connection, jdata, (GDestroyNotify) WorkerCloseConnectionData_free, + NULL, error); + if (context) + g_main_context_unref (context); + + gda_worker_unref (worker); + + return stage2_close_connection (cnc, result); +} + +/***********************************************************************************************************/ + +/* + * JOB_PREPARE_STATEMENT + * WorkerPrepareStatementData + * + */ +typedef struct { + GdaWorker *worker; + GdaServerProvider *provider; + GdaConnection *cnc; + GdaStatement *stmt; +} WorkerPrepareStatementData; + +/* code executed in GdaWorker's worker thread */ +static gpointer +worker_statement_prepare (WorkerPrepareStatementData *data, GError **error) +{ + GdaServerProviderBase *fset; + fset = _gda_server_provider_get_impl_functions (data->provider, data->worker, GDA_SERVER_PROVIDER_FUNCTIONS_BASE); + + gboolean result; + result = fset->statement_prepare (data->provider, data->cnc, data->stmt, error); + return result ? (gpointer) 0x01 : NULL; +} + +/* + * _gda_server_provider_statement_prepare: + * @provider: a #GdaServerProvider + * @cnc: (nullable): a #GdaConnection + * @stmt: a #GdaStatement + * @error: (nullable): a place to store error, or %NULL + * + * Call the prepare_statement() in the worker thread + */ +gboolean +_gda_server_provider_statement_prepare (GdaServerProvider *provider, GdaConnection *cnc, + GdaStatement *stmt, GError **error) +{ + GdaWorker *worker; + g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (provider), FALSE); + g_return_val_if_fail (GDA_IS_STATEMENT (stmt), FALSE); + + g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE); + g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE); + g_return_val_if_fail (gda_connection_is_opened (cnc), FALSE); + + gda_lockable_lock ((GdaLockable*) cnc); /* CNC LOCK */ + + GdaServerProviderConnectionData *cdata; + cdata = gda_connection_internal_get_provider_data_error (cnc, NULL); + if (!cdata) { + gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */ + g_warning ("Internal error: connection reported as opened, yet no provider's data has been setted"); + return FALSE; + } + worker = gda_worker_ref (cdata->worker); + + GMainContext *context; + context = gda_server_provider_get_real_main_context (cnc); + + WorkerPrepareStatementData data; + data.worker = worker; + data.provider = provider; + data.cnc = cnc; + data.stmt = stmt; + + gda_connection_increase_usage (cnc); /* USAGE ++ */ + gpointer retval; + gda_worker_do_job (worker, context, 0, &retval, NULL, + (GdaWorkerFunc) worker_statement_prepare, (gpointer) &data, NULL, NULL, NULL); + if (context) + g_main_context_unref (context); + + gda_connection_decrease_usage (cnc); /* USAGE -- */ + gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */ + + gda_worker_unref (worker); + + return retval ? TRUE : FALSE; +} + +/***********************************************************************************************************/ + +/* + * JOB_EXECUTE_STATEMENT + * WorkerExecuteStatementData + * + */ +typedef struct { + GdaWorker *worker; + GdaServerProvider *provider; + GdaConnection *cnc; + GdaStatement *stmt; + GdaSet *params; + GdaStatementModelUsage model_usage; + GType *col_types; + GdaSet **last_inserted_row; +} WorkerExecuteStatementData; + +static gpointer +worker_statement_execute (WorkerExecuteStatementData *data, GError **error) +{ + GdaServerProviderBase *fset; + fset = _gda_server_provider_get_impl_functions (data->provider, data->worker, GDA_SERVER_PROVIDER_FUNCTIONS_BASE); + + guint delay; + delay = _gda_connection_get_exec_slowdown (data->cnc); + if (delay > 0) { + g_print (_("Delaying statement execution for %u ms\n"), delay / 1000); + g_usleep (delay); + } + + GObject *result; + result = fset->statement_execute (data->provider, data->cnc, data->stmt, data->params, data->model_usage, + data->col_types, data->last_inserted_row, error); + + if (GDA_IS_DATA_SELECT (result)) { + /* adjust flags because the providers don't necessarily do it: make sure extra flags as OFFLINE and + * ALLOW_NOPARAM are included */ + data->model_usage = data->model_usage & (GDA_STATEMENT_MODEL_OFFLINE | GDA_STATEMENT_MODEL_ALLOW_NOPARAM); + + /* if necessary honor the OFFLINE flag */ + if ((data->model_usage & GDA_STATEMENT_MODEL_OFFLINE) && + ! gda_data_select_prepare_for_offline ((GdaDataSelect*) result, error)) { + g_object_unref (result); + result = NULL; + } + } + + return (gpointer) result; +} + +/* + * _gda_server_provider_statement_execute: + * @provider: a #GdaServerProvider + * @cnc: a #GdaConnection + * @stmt: a #GdaStatement + * @params: (nullable): parameters to bind variables in @stmt, or %NULL + * @model_usage: the requested usage of the returned #GdaDataModel if @stmt is a SELECT statement + * @col_types: (nullable): requested column types of the returned #GdaDataModel if @stmt is a SELECT statement, or %NULL + * @last_inserted_row: (nullable): a place to store the last inserted row information, or %NULL + * @error: (nullable): a place to store error, or %NULL + * + * Call the prepare_statement() in the worker thread + */ +GObject * +_gda_server_provider_statement_execute (GdaServerProvider *provider, GdaConnection *cnc, + GdaStatement *stmt, GdaSet *params, + GdaStatementModelUsage model_usage, + GType *col_types, GdaSet **last_inserted_row, GError **error) +{ + if (last_inserted_row) + *last_inserted_row = NULL; + + GdaWorker *worker; + g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (provider), NULL); + g_return_val_if_fail (GDA_IS_STATEMENT (stmt), NULL); + + g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL); + g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, NULL); + g_return_val_if_fail (gda_connection_is_opened (cnc), NULL); + + gda_lockable_lock ((GdaLockable*) cnc); /* CNC LOCK */ + + GdaServerProviderConnectionData *cdata; + cdata = gda_connection_internal_get_provider_data_error (cnc, NULL); + if (!cdata) { + gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */ + g_warning ("Internal error: connection reported as opened, yet no provider's data has been setted"); + return FALSE; + } + worker = gda_worker_ref (cdata->worker); + + GMainContext *context; + context = gda_server_provider_get_real_main_context (cnc); + + WorkerExecuteStatementData data; + data.worker = worker; + data.provider = provider; + data.cnc = cnc; + data.stmt = stmt; + data.params = params; + data.model_usage = model_usage; + data.col_types = col_types; + data.last_inserted_row = last_inserted_row; + + gda_connection_increase_usage (cnc); /* USAGE ++ */ + gpointer retval; + gda_worker_do_job (worker, context, 0, &retval, NULL, + (GdaWorkerFunc) worker_statement_execute, (gpointer) &data, NULL, NULL, error); + if (context) + g_main_context_unref (context); + + gda_connection_decrease_usage (cnc); /* USAGE -- */ + gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */ + + gda_worker_unref (worker); + + return retval; +} + +/***********************************************************************************************************/ + +/* + * JOB_STMT_TO_SQL + * WorkerStmtToSQLData + * + */ +typedef struct { + GdaWorker *worker; + GdaServerProvider *provider; + GdaConnection *cnc; + GdaStatement *stmt; + GdaSet *params; + GdaStatementSqlFlag flags; + GSList **params_used; +} WorkerStmtToSQLData; + +static gpointer +worker_stmt_to_sql (WorkerStmtToSQLData *data, GError **error) +{ + GdaServerProviderBase *fset; + fset = _gda_server_provider_get_impl_functions (data->provider, data->worker, GDA_SERVER_PROVIDER_FUNCTIONS_BASE); + + if (fset->statement_to_sql) + return fset->statement_to_sql (data->provider, data->cnc, data->stmt, data->params, data->flags, + data->params_used, error); + else + return NULL; +} + +gchar * +_gda_server_provider_statement_to_sql (GdaServerProvider *provider, GdaConnection *cnc, + GdaStatement *stmt, GdaSet *params, GdaStatementSqlFlag flags, + GSList **params_used, GError **error) +{ + GdaWorker *worker; + if (params_used) + *params_used = NULL; + + g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (provider), NULL); + g_return_val_if_fail (GDA_IS_STATEMENT (stmt), NULL); + g_return_val_if_fail (!params || GDA_IS_SET (params), NULL); + if (cnc) { + g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL); + g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, NULL); + g_return_val_if_fail (gda_connection_is_opened (cnc), NULL); + + gda_lockable_lock ((GdaLockable*) cnc); /* CNC LOCK */ + + GdaServerProviderConnectionData *cdata; + cdata = gda_connection_internal_get_provider_data_error (cnc, NULL); + if (!cdata) { + gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */ + g_warning ("Internal error: connection reported as opened, yet no provider's data has been setted"); + return FALSE; + } + worker = gda_worker_ref (cdata->worker); + } + else + worker = _gda_server_provider_create_worker (provider, FALSE); + + GMainContext *context; + context = gda_server_provider_get_real_main_context (cnc); + + WorkerStmtToSQLData data; + data.worker = worker; + data.provider = provider; + data.cnc = cnc; + data.stmt = stmt; + data.params = params; + data.flags = flags; + data.params_used = params_used; + + if (cnc) + gda_connection_increase_usage (cnc); /* USAGE ++ */ + gpointer retval; + gda_worker_do_job (worker, context, 0, &retval, NULL, + (GdaWorkerFunc) worker_stmt_to_sql, (gpointer) &data, NULL, NULL, error); + if (context) + g_main_context_unref (context); + + if (cnc) { + gda_connection_decrease_usage (cnc); /* USAGE -- */ + gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */ + } + + gda_worker_unref (worker); + + return (gchar *) retval; +} + +/***********************************************************************************************************/ + +/* + * JOB_IDENTIFIER_QUOTE + * WorkerIdentifierQuoteData + * + */ +typedef struct { + GdaWorker *worker; + GdaServerProvider *provider; + GdaConnection *cnc; + const gchar *id; + gboolean for_meta_store; + gboolean force_quotes; +} WorkerIdentifierQuoteData; + +static gpointer +worker_identifier_quote (WorkerIdentifierQuoteData *data, GError **error) +{ + GdaServerProviderBase *fset; + fset = _gda_server_provider_get_impl_functions (data->provider, data->worker, GDA_SERVER_PROVIDER_FUNCTIONS_BASE); + + if (fset->identifier_quote) + return fset->identifier_quote (data->provider, data->cnc, data->id, data->for_meta_store, data->force_quotes); + else + return NULL; +} + +gchar * +_gda_server_provider_identifier_quote (GdaServerProvider *provider, GdaConnection *cnc, + const gchar *id, gboolean for_meta_store, gboolean force_quotes) +{ + GdaWorker *worker; + g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (provider), NULL); + if (cnc) { + g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL); + g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, NULL); + g_return_val_if_fail (gda_connection_is_opened (cnc), NULL); + + gda_lockable_lock ((GdaLockable*) cnc); /* CNC LOCK */ + + GdaServerProviderConnectionData *cdata; + cdata = gda_connection_internal_get_provider_data_error (cnc, NULL); + if (!cdata) { + gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */ + g_warning ("Internal error: connection reported as opened, yet no provider's data has been setted"); + return FALSE; + } + worker = gda_worker_ref (cdata->worker); + } + else + worker = _gda_server_provider_create_worker (provider, FALSE); + + GMainContext *context; + context = gda_server_provider_get_real_main_context (cnc); + + WorkerIdentifierQuoteData data; + data.worker = worker; + data.provider = provider; + data.cnc = cnc; + data.id = id; + data.for_meta_store = for_meta_store; + data.force_quotes = force_quotes; + + if (cnc) + gda_connection_increase_usage (cnc); /* USAGE ++ */ + gpointer retval; + gda_worker_do_job (worker, context, 0, &retval, NULL, + (GdaWorkerFunc) worker_identifier_quote, (gpointer) &data, NULL, NULL, NULL); + if (context) + g_main_context_unref (context); + + if (cnc) { + gda_connection_decrease_usage (cnc); /* USAGE -- */ + gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */ + } + + gda_worker_unref (worker); + + return (gchar *) retval; +} + +/***********************************************************************************************************/ + +/* + * JOB_META + * WorkerMetaData + * + */ +typedef struct { + GdaWorker *worker; + GdaServerProvider *provider; + GdaConnection *cnc; + GdaMetaStore *meta; + GdaMetaContext *ctx; + GdaServerProviderMetaType type; + guint nargs; + const GValue *values[5]; /* 5 at most */ +} WorkerMetaData; + +typedef gboolean (*Meta0Func) (GdaServerProvider *, GdaConnection *, GdaMetaStore *, GdaMetaContext *, GError **); +typedef gboolean (*Meta1Func) (GdaServerProvider *, GdaConnection *, GdaMetaStore *, GdaMetaContext *, GError **, const GValue *); +typedef gboolean (*Meta2Func) (GdaServerProvider *, GdaConnection *, GdaMetaStore *, GdaMetaContext *, GError **, const GValue *, const GValue *); +typedef gboolean (*Meta3Func) (GdaServerProvider *, GdaConnection *, GdaMetaStore *, GdaMetaContext *, GError **, const GValue *, const GValue *, const GValue *); +typedef gboolean (*Meta4Func) (GdaServerProvider *, GdaConnection *, GdaMetaStore *, GdaMetaContext *, GError **, const GValue *, const GValue *, const GValue *, const GValue *); +typedef gboolean (*Meta5Func) (GdaServerProvider *, GdaConnection *, GdaMetaStore *, GdaMetaContext *, GError **, const GValue *, const GValue *, const GValue *, const GValue *, const GValue *); + + +static gpointer +worker_meta (WorkerMetaData *data, GError **error) +{ + gpointer *fset; + fset = _gda_server_provider_get_impl_functions (data->provider, data->worker, GDA_SERVER_PROVIDER_FUNCTIONS_META); + + gboolean retval; + switch (data->nargs) { + case 0: {/* function with no argument */ + Meta0Func func; + func = (Meta0Func) fset [data->type]; + if (func) + retval = func (data->provider, data->cnc, data->meta, data->ctx, error); + else { + retval = FALSE; + g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_METHOD_NON_IMPLEMENTED_ERROR, + "%s", _("Not supported")); + } + break; + } + case 1: {/* function with 1 argument */ + Meta1Func func; + func = (Meta1Func) fset [data->type]; + if (func) + retval = func (data->provider, data->cnc, data->meta, data->ctx, error, data->values [0]); + else { + retval = FALSE; + g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_METHOD_NON_IMPLEMENTED_ERROR, + "%s", _("Not supported")); + } + break; + } + case 2: {/* function with 2 arguments */ + Meta2Func func; + func = (Meta2Func) fset [data->type]; + if (func) + retval = func (data->provider, data->cnc, data->meta, data->ctx, error, data->values [0], data->values [1]); + else { + retval = FALSE; + g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_METHOD_NON_IMPLEMENTED_ERROR, + "%s", _("Not supported")); + } + break; + } + case 3: {/* function with 3 arguments */ + Meta3Func func; + func = (Meta3Func) fset [data->type]; + if (func) + retval = func (data->provider, data->cnc, data->meta, data->ctx, error, data->values [0], data->values [1], data->values [2]); + else { + retval = FALSE; + g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_METHOD_NON_IMPLEMENTED_ERROR, + "%s", _("Not supported")); + } + break; + } + case 4: {/* function with 4 arguments */ + Meta4Func func; + func = (Meta4Func) fset [data->type]; + if (func) + retval = func (data->provider, data->cnc, data->meta, data->ctx, error, data->values [0], data->values [1], data->values [2], data->values [3]); + else { + retval = FALSE; + g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_METHOD_NON_IMPLEMENTED_ERROR, + "%s", _("Not supported")); + } + break; + } + case 5: {/* function with 5 arguments */ + Meta5Func func; + func = (Meta5Func) fset [data->type]; + if (func) + retval = func (data->provider, data->cnc, data->meta, data->ctx, error, data->values [0], data->values [1], data->values [2], data->values [3], data->values [4]); + else { + retval = FALSE; + g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_METHOD_NON_IMPLEMENTED_ERROR, + "%s", _("Not supported")); + } + break; + } + default: + g_assert_not_reached (); + } + + return retval ? (gpointer) 0x01 : NULL; +} + +static guint +get_meta_nb_values_args (GdaServerProviderMetaType type) +{ + switch (type) { + case GDA_SERVER_META__INFO: + case GDA_SERVER_META__BTYPES: + case GDA_SERVER_META__UDT: + case GDA_SERVER_META__UDT_COLS: + case GDA_SERVER_META__ENUMS: + case GDA_SERVER_META__DOMAINS: + case GDA_SERVER_META__CONSTRAINTS_DOM: + case GDA_SERVER_META__EL_TYPES: + case GDA_SERVER_META__COLLATIONS: + case GDA_SERVER_META__CHARACTER_SETS: + case GDA_SERVER_META__SCHEMATA: + case GDA_SERVER_META__TABLES_VIEWS: + case GDA_SERVER_META__COLUMNS: + case GDA_SERVER_META__VIEW_COLS: + case GDA_SERVER_META__CONSTRAINTS_TAB: + case GDA_SERVER_META__CONSTRAINTS_REF: + case GDA_SERVER_META__KEY_COLUMNS: + case GDA_SERVER_META__CHECK_COLUMNS: + case GDA_SERVER_META__TRIGGERS: + case GDA_SERVER_META__ROUTINES: + case GDA_SERVER_META__ROUTINE_COL: + case GDA_SERVER_META__ROUTINE_PAR: + case GDA_SERVER_META__INDEXES_TAB: + case GDA_SERVER_META__INDEX_COLS: + return 0; + + case GDA_SERVER_META_EL_TYPES: + return 1; + + case GDA_SERVER_META_UDT: + case GDA_SERVER_META_DOMAINS: + case GDA_SERVER_META_SCHEMATA: + return 2; + + case GDA_SERVER_META_UDT_COLS: + case GDA_SERVER_META_ENUMS: + case GDA_SERVER_META_CONSTRAINTS_DOM: + case GDA_SERVER_META_COLLATIONS: + case GDA_SERVER_META_CHARACTER_SETS: + case GDA_SERVER_META_TABLES_VIEWS: + case GDA_SERVER_META_COLUMNS: + case GDA_SERVER_META_VIEW_COLS: + case GDA_SERVER_META_TRIGGERS: + case GDA_SERVER_META_ROUTINES: + case GDA_SERVER_META_ROUTINE_PAR: + return 3; + + case GDA_SERVER_META_CONSTRAINTS_TAB: + case GDA_SERVER_META_CONSTRAINTS_REF: + case GDA_SERVER_META_KEY_COLUMNS: + case GDA_SERVER_META_CHECK_COLUMNS: + case GDA_SERVER_META_INDEXES_TAB: + case GDA_SERVER_META_INDEX_COLS: + return 4; + + case GDA_SERVER_META_ROUTINE_COL: + return 5; + + default: + g_assert_not_reached (); + } +} + +/* + * @call_error: (nullable) + * @loc_error: (nullable) + */ +static gboolean +meta_finalize_result (gpointer retval, GError **call_error, GError **loc_error) +{ + if (retval) { + g_clear_error (loc_error); + return TRUE; + } + if (loc_error && *loc_error && (*loc_error)->message) { + g_set_error (call_error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_INTERNAL_ERROR, + _("Internal error please report bug to https://gitlab.gnome.org/GNOME/libgda/issues Reported error is: %s"), + (*loc_error)->message); + } else { + g_set_error (call_error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_INTERNAL_ERROR, + _("Internal error please report bug to https://gitlab.gnome.org/GNOME/libgda/issues No error was reported")); + } + g_clear_error (loc_error); + return FALSE; +} + +gboolean +_gda_server_provider_meta_0arg (GdaServerProvider *provider, GdaConnection *cnc, + GdaMetaStore *meta, GdaMetaContext *ctx, + GdaServerProviderMetaType type, GError **error) +{ + gpointer retval = NULL; + GdaWorker *worker; + g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (provider), FALSE); + + g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE); + g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE); + g_return_val_if_fail (gda_connection_is_opened (cnc), FALSE); + + /* check that function at index @type has 0 value argument */ + if (get_meta_nb_values_args (type) != 0) { + g_warning ("Internal error: function %s() is only for meta data with no value argument", __FUNCTION__); + goto out; + } + gda_lockable_lock ((GdaLockable*) cnc); /* CNC LOCK */ + + GdaServerProviderConnectionData *cdata; + cdata = gda_connection_internal_get_provider_data_error (cnc, NULL); + if (!cdata) { + gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */ + g_warning ("Internal error: connection reported as opened, yet no provider's data has been setted"); + goto out; + } + + worker = gda_worker_ref (cdata->worker); + + GMainContext *context; + context = gda_server_provider_get_real_main_context (cnc); + + WorkerMetaData data; + data.worker = worker; + data.provider = provider; + data.cnc = cnc; + data.meta = meta; + data.ctx = ctx; + data.type = type; + data.nargs = 0; + data.values[0] = NULL; + data.values[1] = NULL; + data.values[2] = NULL; + data.values[3] = NULL; + + GError *lerror = NULL; + if (cnc) + gda_connection_increase_usage (cnc); /* USAGE ++ */ + gda_worker_do_job (worker, context, 0, &retval, NULL, + (GdaWorkerFunc) worker_meta, (gpointer) &data, NULL, NULL, &lerror); + if (context) + g_main_context_unref (context); + + if (cnc) { + gda_connection_decrease_usage (cnc); /* USAGE -- */ + gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */ + } + + gda_worker_unref (worker); + + out: + return meta_finalize_result (retval, error, &lerror); +} + +gboolean +_gda_server_provider_meta_1arg (GdaServerProvider *provider, GdaConnection *cnc, + GdaMetaStore *meta, GdaMetaContext *ctx, + GdaServerProviderMetaType type, const GValue *value0, GError **error) +{ + gpointer retval = NULL; + GdaWorker *worker; + g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (provider), FALSE); + + g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE); + g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE); + g_return_val_if_fail (gda_connection_is_opened (cnc), FALSE); + + /* check that function at index @type has 1 value argument */ + if (get_meta_nb_values_args (type) != 1) { + g_warning ("Internal error: function %s() is only for meta data with 1 value argument", __FUNCTION__); + goto out; + } + gda_lockable_lock ((GdaLockable*) cnc); /* CNC LOCK */ + + GdaServerProviderConnectionData *cdata; + cdata = gda_connection_internal_get_provider_data_error (cnc, NULL); + if (!cdata) { + gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */ + g_warning ("Internal error: connection reported as opened, yet no provider's data has been setted"); + goto out; + } + + worker = gda_worker_ref (cdata->worker); + + GMainContext *context; + context = gda_server_provider_get_real_main_context (cnc); + + WorkerMetaData data; + data.worker = worker; + data.provider = provider; + data.cnc = cnc; + data.meta = meta; + data.ctx = ctx; + data.type = type; + data.nargs = 1; + data.values[0] = value0; + data.values[1] = NULL; + data.values[2] = NULL; + data.values[3] = NULL; + + GError *lerror = NULL; + if (cnc) + gda_connection_increase_usage (cnc); /* USAGE ++ */ + gda_worker_do_job (worker, context, 0, &retval, NULL, + (GdaWorkerFunc) worker_meta, (gpointer) &data, NULL, NULL, &lerror); + if (context) + g_main_context_unref (context); + + if (cnc) { + gda_connection_decrease_usage (cnc); /* USAGE -- */ + gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */ + } + + gda_worker_unref (worker); + + out: + return meta_finalize_result (retval, error, &lerror); +} + +gboolean +_gda_server_provider_meta_2arg (GdaServerProvider *provider, GdaConnection *cnc, + GdaMetaStore *meta, GdaMetaContext *ctx, + GdaServerProviderMetaType type, const GValue *value0, const GValue *value1, GError **error) +{ + gpointer retval = NULL; + GdaWorker *worker; + g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (provider), FALSE); + + g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE); + g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE); + g_return_val_if_fail (gda_connection_is_opened (cnc), FALSE); + + /* check that function at index @type has 2 values arguments */ + if (get_meta_nb_values_args (type) != 2) { + g_warning ("Internal error: function %s() is only for meta data with 2 values arguments", __FUNCTION__); + goto out; + } + gda_lockable_lock ((GdaLockable*) cnc); /* CNC LOCK */ + + GdaServerProviderConnectionData *cdata; + cdata = gda_connection_internal_get_provider_data_error (cnc, NULL); + if (!cdata) { + gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */ + g_warning ("Internal error: connection reported as opened, yet no provider's data has been setted"); + goto out; + } + + worker = gda_worker_ref (cdata->worker); + + GMainContext *context; + context = gda_server_provider_get_real_main_context (cnc); + + WorkerMetaData data; + data.worker = worker; + data.provider = provider; + data.cnc = cnc; + data.meta = meta; + data.ctx = ctx; + data.type = type; + data.nargs = 2; + data.values[0] = value0; + data.values[1] = value1; + data.values[2] = NULL; + data.values[3] = NULL; + + GError *lerror = NULL; + if (cnc) + gda_connection_increase_usage (cnc); /* USAGE -- */ + gda_worker_do_job (worker, context, 0, &retval, NULL, + (GdaWorkerFunc) worker_meta, (gpointer) &data, NULL, NULL, &lerror); + if (context) + g_main_context_unref (context); + + if (cnc) { + gda_connection_decrease_usage (cnc); /* USAGE -- */ + gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */ + } + + gda_worker_unref (worker); + + out: + return meta_finalize_result (retval, error, &lerror); +} + +gboolean +_gda_server_provider_meta_3arg (GdaServerProvider *provider, GdaConnection *cnc, + GdaMetaStore *meta, GdaMetaContext *ctx, + GdaServerProviderMetaType type, const GValue *value0, const GValue *value1, + const GValue *value2, GError **error) +{ + gpointer retval = NULL; + GdaWorker *worker; + g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (provider), FALSE); + + g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE); + g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE); + g_return_val_if_fail (gda_connection_is_opened (cnc), FALSE); + + /* check that function at index @type has 3 values arguments */ + if (get_meta_nb_values_args (type) != 3) { + g_warning ("Internal error: function %s() is only for meta data with 3 values arguments", __FUNCTION__); + goto out; + } + gda_lockable_lock ((GdaLockable*) cnc); /* CNC LOCK */ + + GdaServerProviderConnectionData *cdata; + cdata = gda_connection_internal_get_provider_data_error (cnc, NULL); + if (!cdata) { + gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */ + g_warning ("Internal error: connection reported as opened, yet no provider's data has been setted"); + goto out; + } + + worker = gda_worker_ref (cdata->worker); + + GMainContext *context; + context = gda_server_provider_get_real_main_context (cnc); + + WorkerMetaData data; + data.worker = worker; + data.provider = provider; + data.cnc = cnc; + data.meta = meta; + data.ctx = ctx; + data.type = type; + data.nargs = 3; + data.values[0] = value0; + data.values[1] = value1; + data.values[2] = value2; + data.values[3] = NULL; + + GError *lerror = NULL; + if (cnc) + gda_connection_increase_usage (cnc); /* USAGE ++ */ + gda_worker_do_job (worker, context, 0, &retval, NULL, + (GdaWorkerFunc) worker_meta, (gpointer) &data, NULL, NULL, &lerror); + if (context) + g_main_context_unref (context); + + if (cnc) { + gda_connection_decrease_usage (cnc); /* USAGE -- */ + gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */ + } + + gda_worker_unref (worker); + out: + return meta_finalize_result (retval, error, &lerror); +} + +gboolean +_gda_server_provider_meta_4arg (GdaServerProvider *provider, GdaConnection *cnc, + GdaMetaStore *meta, GdaMetaContext *ctx, + GdaServerProviderMetaType type, const GValue *value0, const GValue *value1, + const GValue *value2, const GValue *value3, GError **error) +{ + gpointer retval = NULL; + GdaWorker *worker; + g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (provider), FALSE); + + g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE); + g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE); + g_return_val_if_fail (gda_connection_is_opened (cnc), FALSE); + + /* check that function at index @type has 4 values arguments */ + if (get_meta_nb_values_args (type) != 4) { + g_warning ("Internal error: function %s() is only for meta data with 4 values arguments", __FUNCTION__); + goto out; + } + gda_lockable_lock ((GdaLockable*) cnc); /* CNC LOCK */ + + GdaServerProviderConnectionData *cdata; + cdata = gda_connection_internal_get_provider_data_error (cnc, NULL); + if (!cdata) { + gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */ + g_warning ("Internal error: connection reported as opened, yet no provider's data has been setted"); + goto out; + } + + worker = gda_worker_ref (cdata->worker); + + GMainContext *context; + context = gda_server_provider_get_real_main_context (cnc); + + WorkerMetaData data; + data.worker = worker; + data.provider = provider; + data.cnc = cnc; + data.meta = meta; + data.ctx = ctx; + data.type = type; + data.nargs = 4; + data.values[0] = value0; + data.values[1] = value1; + data.values[2] = value2; + data.values[3] = value3; + + GError *lerror = NULL; + if (cnc) + gda_connection_increase_usage (cnc); /* USAGE ++ */ + gda_worker_do_job (worker, context, 0, &retval, NULL, + (GdaWorkerFunc) worker_meta, (gpointer) &data, NULL, NULL, &lerror); + if (context) + g_main_context_unref (context); + + if (cnc) { + gda_connection_decrease_usage (cnc); /* USAGE -- */ + gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */ + } + + gda_worker_unref (worker); + + out: + return meta_finalize_result (retval, error, &lerror); +} + + +gboolean +_gda_server_provider_meta_5arg (GdaServerProvider *provider, GdaConnection *cnc, + GdaMetaStore *meta, GdaMetaContext *ctx, + GdaServerProviderMetaType type, const GValue *value0, const GValue *value1, + const GValue *value2, const GValue *value3, const GValue *value4, GError **error) +{ + gpointer retval = NULL; + GdaWorker *worker; + g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (provider), FALSE); + + g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE); + g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE); + g_return_val_if_fail (gda_connection_is_opened (cnc), FALSE); + + /* check that function at index @type has 5 values arguments */ + if (get_meta_nb_values_args (type) != 5) { + g_warning ("Internal error: function %s() is only for meta data with 5 values arguments", __FUNCTION__); + goto out; + } + gda_lockable_lock ((GdaLockable*) cnc); /* CNC LOCK */ + + GdaServerProviderConnectionData *cdata; + cdata = gda_connection_internal_get_provider_data_error (cnc, NULL); + if (!cdata) { + gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */ + g_warning ("Internal error: connection reported as opened, yet no provider's data has been setted"); + goto out; + } + + worker = gda_worker_ref (cdata->worker); + + GMainContext *context; + context = gda_server_provider_get_real_main_context (cnc); + + WorkerMetaData data; + data.worker = worker; + data.provider = provider; + data.cnc = cnc; + data.meta = meta; + data.ctx = ctx; + data.type = type; + data.nargs = 4; + data.values[0] = value0; + data.values[1] = value1; + data.values[2] = value2; + data.values[3] = value3; + data.values[4] = value4; + + GError *lerror = NULL; + if (cnc) + gda_connection_increase_usage (cnc); /* USAGE ++ */ + gda_worker_do_job (worker, context, 0, &retval, NULL, + (GdaWorkerFunc) worker_meta, (gpointer) &data, NULL, NULL, &lerror); + if (context) + g_main_context_unref (context); + + if (cnc) { + gda_connection_decrease_usage (cnc); /* USAGE -- */ + gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */ + } + + gda_worker_unref (worker); + + out: + return meta_finalize_result (retval, error, &lerror); +} + +/***********************************************************************************************************/ + +/* + * JOB_BEGIN_TRANSACTION + * JOB_COMMIT_TRANSACTION + * JOB_ROLLBACK_TRANSACTION + * WorkerTransactionData + */ +typedef struct { + GdaWorker *worker; + GdaServerProvider *provider; + GdaConnection *cnc; + const gchar *name; + GdaTransactionIsolation level; +} WorkerTransactionData; + +static gpointer +worker_begin_transaction (WorkerTransactionData *data, GError **error) +{ + GdaServerProviderBase *fset; + fset = _gda_server_provider_get_impl_functions (data->provider, data->worker, GDA_SERVER_PROVIDER_FUNCTIONS_BASE); + + guint delay; + delay = _gda_connection_get_exec_slowdown (data->cnc); + if (delay > 0) { + g_print (_("Delaying transaction for %u ms\n"), delay / 1000); + g_usleep (delay); + } + + gboolean retval; + if (fset->begin_transaction) + retval = fset->begin_transaction (data->provider, data->cnc, data->name, data->level, error); + else { + g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_METHOD_NON_IMPLEMENTED_ERROR, + "%s", _("Database provider does not support transactions")); + retval = FALSE; + } + return retval ? (gpointer) 0x01: NULL; +} + +gboolean +_gda_server_provider_begin_transaction (GdaServerProvider *provider, GdaConnection *cnc, + const gchar *name, GdaTransactionIsolation level, GError **error) +{ + GdaWorker *worker; + g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (provider), FALSE); + g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE); + g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE); + g_return_val_if_fail (gda_connection_is_opened (cnc), FALSE); + + gda_lockable_lock ((GdaLockable*) cnc); /* CNC LOCK */ + + GdaServerProviderConnectionData *cdata; + cdata = gda_connection_internal_get_provider_data_error (cnc, FALSE); + if (!cdata) { + gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */ + g_warning ("Internal error: connection reported as opened, yet no provider's data has been setted"); + return FALSE; + } + worker = gda_worker_ref (cdata->worker); + + GMainContext *context; + context = gda_server_provider_get_real_main_context (cnc); + + WorkerTransactionData data; + data.worker = worker; + data.provider = provider; + data.cnc = cnc; + data.name = name; + data.level = level; + + gda_connection_increase_usage (cnc); /* USAGE ++ */ + gpointer retval; + gda_worker_do_job (worker, context, 0, &retval, NULL, + (GdaWorkerFunc) worker_begin_transaction, (gpointer) &data, NULL, NULL, error); + if (context) + g_main_context_unref (context); + + gda_connection_decrease_usage (cnc); /* USAGE -- */ + gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */ + + gda_worker_unref (worker); + + return retval ? TRUE : FALSE; +} + +static gpointer +worker_commit_transaction (WorkerTransactionData *data, GError **error) +{ + GdaServerProviderBase *fset; + fset = _gda_server_provider_get_impl_functions (data->provider, data->worker, GDA_SERVER_PROVIDER_FUNCTIONS_BASE); + + guint delay; + delay = _gda_connection_get_exec_slowdown (data->cnc); + if (delay > 0) { + g_print (_("Delaying transaction for %u ms\n"), delay / 1000); + g_usleep (delay); + } + + gboolean retval; + if (fset->commit_transaction) + retval = fset->commit_transaction (data->provider, data->cnc, data->name, error); + else { + g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_METHOD_NON_IMPLEMENTED_ERROR, + "%s", _("Database provider does not support transactions")); + retval = FALSE; + } + return retval ? (gpointer) 0x01: NULL; +} + +gboolean +_gda_server_provider_commit_transaction (GdaServerProvider *provider, GdaConnection *cnc, + const gchar *name, GError **error) +{ + GdaWorker *worker; + g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (provider), FALSE); + g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE); + g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE); + g_return_val_if_fail (gda_connection_is_opened (cnc), FALSE); + + gda_lockable_lock ((GdaLockable*) cnc); /* CNC LOCK */ + + GdaServerProviderConnectionData *cdata; + cdata = gda_connection_internal_get_provider_data_error (cnc, FALSE); + if (!cdata) { + gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */ + g_warning ("Internal error: connection reported as opened, yet no provider's data has been setted"); + return FALSE; + } + worker = gda_worker_ref (cdata->worker); + + GMainContext *context; + context = gda_server_provider_get_real_main_context (cnc); + + WorkerTransactionData data; + data.worker = worker; + data.provider = provider; + data.cnc = cnc; + data.name = name; + + gda_connection_increase_usage (cnc); /* USAGE ++ */ + gpointer retval; + gda_worker_do_job (worker, context, 0, &retval, NULL, + (GdaWorkerFunc) worker_commit_transaction, (gpointer) &data, NULL, NULL, error); + if (context) + g_main_context_unref (context); + + gda_connection_decrease_usage (cnc); /* USAGE -- */ + gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */ + + gda_worker_unref (worker); + + return retval ? TRUE : FALSE; +} + +static gpointer +worker_rollback_transaction (WorkerTransactionData *data, GError **error) +{ + GdaServerProviderBase *fset; + fset = _gda_server_provider_get_impl_functions (data->provider, data->worker, GDA_SERVER_PROVIDER_FUNCTIONS_BASE); + + guint delay; + delay = _gda_connection_get_exec_slowdown (data->cnc); + if (delay > 0) { + g_print (_("Delaying transaction for %u ms\n"), delay / 1000); + g_usleep (delay); + } + + gboolean retval; + if (fset->rollback_transaction) + retval = fset->rollback_transaction (data->provider, data->cnc, data->name, error); + else { + g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_METHOD_NON_IMPLEMENTED_ERROR, + "%s", _("Database provider does not support transactions")); + retval = FALSE; + } + return retval ? (gpointer) 0x01: NULL; +} + +gboolean +_gda_server_provider_rollback_transaction (GdaServerProvider *provider, GdaConnection *cnc, + const gchar *name, GError **error) +{ + GdaWorker *worker; + g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (provider), FALSE); + g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE); + g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE); + g_return_val_if_fail (gda_connection_is_opened (cnc), FALSE); + + gda_lockable_lock ((GdaLockable*) cnc); /* CNC LOCK */ + + GdaServerProviderConnectionData *cdata; + cdata = gda_connection_internal_get_provider_data_error (cnc, FALSE); + if (!cdata) { + gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */ + g_warning ("Internal error: connection reported as opened, yet no provider's data has been setted"); + return FALSE; + } + worker = gda_worker_ref (cdata->worker); + + GMainContext *context; + context = gda_server_provider_get_real_main_context (cnc); + + WorkerTransactionData data; + data.worker = worker; + data.provider = provider; + data.cnc = cnc; + data.name = name; + + gda_connection_increase_usage (cnc); /* USAGE ++ */ + gpointer retval; + gda_worker_do_job (worker, context, 0, &retval, NULL, + (GdaWorkerFunc) worker_rollback_transaction, (gpointer) &data, NULL, NULL, error); + if (context) + g_main_context_unref (context); + + gda_connection_decrease_usage (cnc); /* USAGE -- */ + gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */ + + gda_worker_unref (worker); + + return retval ? TRUE : FALSE; +} + +static gpointer +worker_add_savepoint (WorkerTransactionData *data, GError **error) +{ + GdaServerProviderBase *fset; + fset = _gda_server_provider_get_impl_functions (data->provider, data->worker, GDA_SERVER_PROVIDER_FUNCTIONS_BASE); + + gboolean retval; + if (fset->add_savepoint) + retval = fset->add_savepoint (data->provider, data->cnc, data->name, error); + else { + g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_METHOD_NON_IMPLEMENTED_ERROR, + "%s", _("Database provider does not support savepoints")); + retval = FALSE; + } + return retval ? (gpointer) 0x01: NULL; +} + +gboolean +_gda_server_provider_add_savepoint (GdaServerProvider *provider, GdaConnection *cnc, const gchar *name, GError **error) +{ + GdaWorker *worker; + g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (provider), FALSE); + g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE); + g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE); + g_return_val_if_fail (gda_connection_is_opened (cnc), FALSE); + + gda_lockable_lock ((GdaLockable*) cnc); /* CNC LOCK */ + + GdaServerProviderConnectionData *cdata; + cdata = gda_connection_internal_get_provider_data_error (cnc, FALSE); + if (!cdata) { + gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */ + g_warning ("Internal error: connection reported as opened, yet no provider's data has been setted"); + return FALSE; + } + worker = gda_worker_ref (cdata->worker); + + GMainContext *context; + context = gda_server_provider_get_real_main_context (cnc); + + WorkerTransactionData data; + data.worker = worker; + data.provider = provider; + data.cnc = cnc; + data.name = name; + + gda_connection_increase_usage (cnc); /* USAGE ++ */ + gpointer retval; + gda_worker_do_job (worker, context, 0, &retval, NULL, + (GdaWorkerFunc) worker_add_savepoint, (gpointer) &data, NULL, NULL, error); + if (context) + g_main_context_unref (context); + + gda_connection_decrease_usage (cnc); /* USAGE -- */ + gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */ + + gda_worker_unref (worker); + + return retval ? TRUE : FALSE; +} + +static gpointer +worker_rollback_savepoint (WorkerTransactionData *data, GError **error) +{ + GdaServerProviderBase *fset; + fset = _gda_server_provider_get_impl_functions (data->provider, data->worker, GDA_SERVER_PROVIDER_FUNCTIONS_BASE); + + gboolean retval; + if (fset->rollback_savepoint) + retval = fset->rollback_savepoint (data->provider, data->cnc, data->name, error); + else { + g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_METHOD_NON_IMPLEMENTED_ERROR, + "%s", _("Database provider does not support savepoints")); + retval = FALSE; + } + return retval ? (gpointer) 0x01: NULL; +} + +gboolean +_gda_server_provider_rollback_savepoint (GdaServerProvider *provider, GdaConnection *cnc, const gchar *name, GError **error) +{ + GdaWorker *worker; + g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (provider), FALSE); + g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE); + g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE); + g_return_val_if_fail (gda_connection_is_opened (cnc), FALSE); + + gda_lockable_lock ((GdaLockable*) cnc); /* CNC LOCK */ + + GdaServerProviderConnectionData *cdata; + cdata = gda_connection_internal_get_provider_data_error (cnc, FALSE); + if (!cdata) { + gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */ + g_warning ("Internal error: connection reported as opened, yet no provider's data has been setted"); + return FALSE; + } + worker = gda_worker_ref (cdata->worker); + + GMainContext *context; + context = gda_server_provider_get_real_main_context (cnc); + + WorkerTransactionData data; + data.worker = worker; + data.provider = provider; + data.cnc = cnc; + data.name = name; + + gda_connection_increase_usage (cnc); /* USAGE ++ */ + gpointer retval; + gda_worker_do_job (worker, context, 0, &retval, NULL, + (GdaWorkerFunc) worker_rollback_savepoint, (gpointer) &data, NULL, NULL, error); + if (context) + g_main_context_unref (context); + + gda_connection_decrease_usage (cnc); /* USAGE -- */ + gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */ + + gda_worker_unref (worker); + + return retval ? TRUE : FALSE; +} + +static gpointer +worker_delete_savepoint (WorkerTransactionData *data, GError **error) +{ + GdaServerProviderBase *fset; + fset = _gda_server_provider_get_impl_functions (data->provider, data->worker, GDA_SERVER_PROVIDER_FUNCTIONS_BASE); + + gboolean retval; + if (fset->delete_savepoint) + retval = fset->delete_savepoint (data->provider, data->cnc, data->name, error); + else { + g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_METHOD_NON_IMPLEMENTED_ERROR, + "%s", _("Database provider does not support savepoints")); + retval = FALSE; + } + return retval ? (gpointer) 0x01: NULL; +} + +gboolean +_gda_server_provider_delete_savepoint (GdaServerProvider *provider, GdaConnection *cnc, const gchar *name, GError **error) +{ + GdaWorker *worker; + g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (provider), FALSE); + g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE); + g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE); + g_return_val_if_fail (gda_connection_is_opened (cnc), FALSE); + + gda_lockable_lock ((GdaLockable*) cnc); /* CNC LOCK */ + + GdaServerProviderConnectionData *cdata; + cdata = gda_connection_internal_get_provider_data_error (cnc, FALSE); + if (!cdata) { + gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */ + g_warning ("Internal error: connection reported as opened, yet no provider's data has been setted"); + return FALSE; + } + worker = gda_worker_ref (cdata->worker); + + GMainContext *context; + context = gda_server_provider_get_real_main_context (cnc); + + WorkerTransactionData data; + data.worker = worker; + data.provider = provider; + data.cnc = cnc; + data.name = name; + + gda_connection_increase_usage (cnc); /* USAGE ++ */ + gpointer retval; + gda_worker_do_job (worker, context, 0, &retval, NULL, + (GdaWorkerFunc) worker_delete_savepoint, (gpointer) &data, NULL, NULL, error); + if (context) + g_main_context_unref (context); + + gda_connection_decrease_usage (cnc); /* USAGE -- */ + gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */ + + gda_worker_unref (worker); + + return retval ? TRUE : FALSE; +} + +/***********************************************************************************************************/ + +/* + * JOB_XA_START + * JOB_XA_END + * JOB_XA_PREPARE + * JOB_XA_COMMIT + * JOB_XA_ROLLBACK + * JOB_XA_RECOVER + */ + +typedef struct { + GdaWorker *worker; + GdaServerProvider *provider; + GdaConnection *cnc; + const GdaXaTransactionId *trx; + GdaXaType type; +} WorkerXAData; + +static gpointer +worker_xa (WorkerXAData *data, GError **error) +{ + GdaServerProviderXa *xaset; + xaset = _gda_server_provider_get_impl_functions (data->provider, data->worker, GDA_SERVER_PROVIDER_FUNCTIONS_XA); + + guint delay; + delay = _gda_connection_get_exec_slowdown (data->cnc); + if (delay > 0) { + g_print (_("Delaying distributed transaction for %u ms\n"), delay / 1000); + g_usleep (delay); + } + + switch (data->type) { + case GDA_XA_START: { + gboolean retval; + if (xaset->xa_start) + retval = xaset->xa_start (data->provider, data->cnc, data->trx, error); + else { + g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_METHOD_NON_IMPLEMENTED_ERROR, + "%s", _("Database provider does not support distributed transactions")); + retval = FALSE; + } + return retval ? (gpointer) 0x01: NULL; + } + case GDA_XA_END: { + gboolean retval; + if (xaset->xa_end) + retval = xaset->xa_end (data->provider, data->cnc, data->trx, error); + else { + g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_METHOD_NON_IMPLEMENTED_ERROR, + "%s", _("Database provider does not support distributed transactions")); + retval = FALSE; + } + return retval ? (gpointer) 0x01: NULL; + } + case GDA_XA_PREPARE: { + gboolean retval; + if (xaset->xa_prepare) + retval = xaset->xa_prepare (data->provider, data->cnc, data->trx, error); + else { + g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_METHOD_NON_IMPLEMENTED_ERROR, + "%s", _("Database provider does not support distributed transactions")); + retval = FALSE; + } + return retval ? (gpointer) 0x01: NULL; + } + case GDA_XA_COMMIT: { + gboolean retval; + if (xaset->xa_commit) + retval = xaset->xa_commit (data->provider, data->cnc, data->trx, error); + else { + g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_METHOD_NON_IMPLEMENTED_ERROR, + "%s", _("Database provider does not support distributed transactions")); + retval = FALSE; + } + return retval ? (gpointer) 0x01: NULL; + } + case GDA_XA_ROLLBACK: { + gboolean retval; + if (xaset->xa_rollback) + retval = xaset->xa_rollback (data->provider, data->cnc, data->trx, error); + else { + g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_METHOD_NON_IMPLEMENTED_ERROR, + "%s", _("Database provider does not support distributed transactions")); + retval = FALSE; + } + return retval ? (gpointer) 0x01: NULL; + } + case GDA_XA_RECOVER: { + GList *retval; + if (xaset->xa_recover) + retval = xaset->xa_recover (data->provider, data->cnc, error); + else { + g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_METHOD_NON_IMPLEMENTED_ERROR, + "%s", _("Database provider does not support distributed transactions")); + retval = NULL; + } + return retval; + } + default: + g_assert_not_reached (); + } + return NULL; /* never reached */ +} + +gboolean +_gda_server_provider_xa (GdaServerProvider *provider, GdaConnection *cnc, const GdaXaTransactionId *trx, + GdaXaType type, GError **error) +{ + GdaWorker *worker; + g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (provider), FALSE); + g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE); + g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE); + g_return_val_if_fail (gda_connection_is_opened (cnc), FALSE); + + gda_lockable_lock ((GdaLockable*) cnc); /* CNC LOCK */ + + GdaServerProviderConnectionData *cdata; + cdata = gda_connection_internal_get_provider_data_error (cnc, FALSE); + if (!cdata) { + gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */ + g_warning ("Internal error: connection reported as opened, yet no provider's data has been setted"); + return FALSE; + } + worker = gda_worker_ref (cdata->worker); + + GMainContext *context; + context = gda_server_provider_get_real_main_context (cnc); + + WorkerXAData data; + data.worker = worker; + data.provider = provider; + data.cnc = cnc; + data.trx = trx; + data.type = type; + + gda_connection_increase_usage (cnc); /* USAGE ++ */ + gpointer retval; + gda_worker_do_job (worker, context, 0, &retval, NULL, + (GdaWorkerFunc) worker_xa, (gpointer) &data, NULL, NULL, error); + if (context) + g_main_context_unref (context); + + gda_connection_decrease_usage (cnc); /* USAGE -- */ + gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */ + + gda_worker_unref (worker); + + return retval ? TRUE : FALSE; +} + +GList * +_gda_server_provider_xa_recover (GdaServerProvider *provider, GdaConnection *cnc, GError **error) +{ + GdaWorker *worker; + g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (provider), FALSE); + g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE); + g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE); + g_return_val_if_fail (gda_connection_is_opened (cnc), FALSE); + + gda_lockable_lock ((GdaLockable*) cnc); /* CNC LOCK */ + + GdaServerProviderConnectionData *cdata; + cdata = gda_connection_internal_get_provider_data_error (cnc, FALSE); + if (!cdata) { + gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */ + g_warning ("Internal error: connection reported as opened, yet no provider's data has been setted"); + return FALSE; + } + worker = gda_worker_ref (cdata->worker); + + GMainContext *context; + context = gda_server_provider_get_real_main_context (cnc); + + WorkerXAData data; + data.worker = worker; + data.provider = provider; + data.cnc = cnc; + data.trx = NULL; + data.type = GDA_XA_RECOVER; + + gda_connection_increase_usage (cnc); /* USAGE ++ */ + gpointer retval; + gda_worker_do_job (worker, context, 0, &retval, NULL, + (GdaWorkerFunc) worker_xa, (gpointer) &data, NULL, NULL, error); + if (context) + g_main_context_unref (context); + + gda_connection_decrease_usage (cnc); /* USAGE -- */ + gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */ + + gda_worker_unref (worker); + + return (GList*) retval; +} + +/***********************************************************************************************************/ + +/* + * server_provider_job_done_callback: + * + * Generic function called whenever a job submitted by a connection's internal GdaWorker has finished, + * with the exception of jobs submitted using gda_worker_do_job() + */ +static void +server_provider_job_done_callback (GdaWorker *worker, guint job_id, gpointer result, GError *error, GdaServerProvider *provider) +{ + GdaServerProviderPrivate *priv = gda_server_provider_get_instance_private (provider); + WorkerData *wd = NULL; + if (priv->jobs_hash) + wd = g_hash_table_lookup (priv->jobs_hash, &job_id); + g_assert (wd); + + switch (wd->job_type) { + case JOB_OPEN_CONNECTION: { + WorkerOpenConnectionData *sdata = (WorkerOpenConnectionData*) wd->job_data; + sdata->callback (sdata->cnc, wd->job_id, + stage2_open_connection (worker, sdata->cnc, result), + error, sdata->callback_data); + break; + } + default: + /* should not be reached because there is no ASYNC version of the close connection call */ + g_assert_not_reached (); + } + + g_hash_table_remove (priv->jobs_hash, &job_id); /* will call worker_data_free() */ +} + +/* Code from gda-server-provider-extra.c */ + +/** + * gda_server_provider_internal_get_parser: + * @prov: a #GdaServerProvider + * + * This is a factory method to get a unique instance of a #GdaSqlParser object + * for each #GdaServerProvider object + * Don't unref it. + * + * Returns: (transfer none): a #GdaSqlParser + */ +GdaSqlParser * +gda_server_provider_internal_get_parser (GdaServerProvider *prov) +{ + GdaServerProviderPrivate *priv = gda_server_provider_get_instance_private (prov); + g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (prov), NULL); + if (priv->parser) + return priv->parser; + priv->parser = gda_server_provider_create_parser (prov, NULL); + if (!priv->parser) + priv->parser = gda_sql_parser_new (); + return priv->parser; +} + +/** + * gda_server_provider_perform_operation_default: + * @provider: a #GdaServerProvider object + * @cnc: (nullable): a #GdaConnection object which will be used to perform an action, or %NULL + * @op: a #GdaServerOperation object + * @error: a place to store an error, or %NULL + * + * Performs the operation described by @op, using the SQL from the rendering of the operation + * + * Returns: %TRUE if no error occurred + */ +gboolean +gda_server_provider_perform_operation_default (GdaServerProvider *provider, GdaConnection *cnc, + GdaServerOperation *op, GError **error) +{ + gchar *sql; + GdaBatch *batch; + const GSList *list; + gboolean retval = TRUE; + + sql = gda_server_provider_render_operation (provider, cnc, op, error); + if (!sql) + return FALSE; + + GdaSqlParser *parser; + parser = gda_server_provider_internal_get_parser (provider); /* no ref held! */ + batch = gda_sql_parser_parse_string_as_batch (parser, sql, NULL, error); + g_free (sql); + if (!batch) + return FALSE; + + for (list = gda_batch_get_statements (batch); list; list = list->next) { + if (gda_connection_statement_execute_non_select (cnc, GDA_STATEMENT (list->data), NULL, NULL, error) == -1) { + retval = FALSE; + break; + } + } + g_object_unref (batch); + + return retval; +} + +/** + * gda_server_provider_handler_use_default: + * @provider: a server provider + * @type: a #GType + * + * Reserved to database provider's implementations. This method defines a default data handler for + * @provider, and returns that #GdaDataHandler. + * + * Returns: (transfer none): a #GdaDataHandler, or %NULL + * + * Since: 5.2 + */ +GdaDataHandler * +gda_server_provider_handler_use_default (GdaServerProvider *provider, GType type) +{ + GdaDataHandler *dh = NULL; + g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (provider), NULL); + if ((type == G_TYPE_INT64) || + (type == G_TYPE_UINT64) || + (type == G_TYPE_DOUBLE) || + (type == G_TYPE_INT) || + (type == GDA_TYPE_NUMERIC) || + (type == G_TYPE_FLOAT) || + (type == GDA_TYPE_SHORT) || + (type == GDA_TYPE_USHORT) || + (type == G_TYPE_CHAR) || + (type == G_TYPE_UCHAR) || + (type == G_TYPE_UINT) || + (type == G_TYPE_LONG) || + (type == G_TYPE_ULONG)) { + dh = gda_server_provider_handler_find (provider, NULL, type, NULL); + if (!dh) { + dh = gda_handler_numerical_new (); + gda_server_provider_handler_declare (provider, dh, NULL, G_TYPE_INT64, NULL); + gda_server_provider_handler_declare (provider, dh, NULL, G_TYPE_UINT64, NULL); + gda_server_provider_handler_declare (provider, dh, NULL, G_TYPE_DOUBLE, NULL); + gda_server_provider_handler_declare (provider, dh, NULL, G_TYPE_INT, NULL); + gda_server_provider_handler_declare (provider, dh, NULL, GDA_TYPE_NUMERIC, NULL); + gda_server_provider_handler_declare (provider, dh, NULL, G_TYPE_FLOAT, NULL); + gda_server_provider_handler_declare (provider, dh, NULL, GDA_TYPE_SHORT, NULL); + gda_server_provider_handler_declare (provider, dh, NULL, GDA_TYPE_USHORT, NULL); + gda_server_provider_handler_declare (provider, dh, NULL, G_TYPE_CHAR, NULL); + gda_server_provider_handler_declare (provider, dh, NULL, G_TYPE_UCHAR, NULL); + gda_server_provider_handler_declare (provider, dh, NULL, G_TYPE_UINT, NULL); + gda_server_provider_handler_declare (provider, dh, NULL, G_TYPE_ULONG, NULL); + gda_server_provider_handler_declare (provider, dh, NULL, G_TYPE_LONG, NULL); + g_object_unref (dh); + } + } + else if ((type == GDA_TYPE_BINARY) || + (type == GDA_TYPE_BLOB)) { + /* no default binary data handler, it's too database specific */ + dh = NULL; + } + else if (type == G_TYPE_BOOLEAN) { + dh = gda_server_provider_handler_find (provider, NULL, type, NULL); + if (!dh) { + dh = gda_handler_boolean_new (); + gda_server_provider_handler_declare (provider, dh, NULL, G_TYPE_BOOLEAN, NULL); + g_object_unref (dh); + } + } + else if ((type == GDA_TYPE_TIME) || + (type == G_TYPE_DATE_TIME) || + (type == G_TYPE_DATE)) { + /* no default time related data handler, it's too database specific */ + dh = NULL; + } + else if (type == G_TYPE_STRING) { + dh = gda_server_provider_handler_find (provider, NULL, type, NULL); + if (!dh) { + dh = gda_handler_string_new (); + gda_server_provider_handler_declare (provider, dh, NULL, G_TYPE_STRING, NULL); + g_object_unref (dh); + } + } + else if (type == GDA_TYPE_TEXT) { + dh = gda_server_provider_handler_find (provider, NULL, type, NULL); + if (!dh) { + dh = gda_handler_text_new (); + gda_server_provider_handler_declare (provider, dh, NULL, GDA_TYPE_TEXT, NULL); + g_object_unref (dh); + } + } + else if (type == G_TYPE_GTYPE) { + dh = gda_server_provider_handler_find (provider, NULL, type, NULL); + if (!dh) { + dh = gda_handler_type_new (); + gda_server_provider_handler_declare (provider, dh, NULL, G_TYPE_GTYPE, NULL); + g_object_unref (dh); + } + } + + return dh; +} + +static gboolean +param_to_null_foreach (GdaSqlAnyPart *part, G_GNUC_UNUSED gpointer data, G_GNUC_UNUSED GError **error) +{ + if (part->type == GDA_SQL_ANY_EXPR) { + GdaSqlExpr *expr = (GdaSqlExpr*) part; + if (expr->param_spec) { + GType type = expr->param_spec->g_type; + gda_sql_param_spec_free (expr->param_spec); + expr->param_spec = NULL; + + if (!expr->value) { + if (type != GDA_TYPE_NULL) + expr->value = gda_value_new_from_string ("0", type); + else + g_value_set_int ((expr->value = gda_value_new (G_TYPE_INT)), 0); + } + } + } + return TRUE; +} + +/** + * gda_select_alter_select_for_empty: + * @stmt: a SELECT #GdaStatement + * @error: (nullable): a place to store errors, or %NULL + * + * Creates a new #GdaStatement, selecting the same data as @stmt, but which always returns an + * empty (no row) data model. This is use dy database providers' implementations. + * + * Returns: (transfer full): a new #GdaStatement + */ +GdaStatement * +gda_select_alter_select_for_empty (GdaStatement *stmt, G_GNUC_UNUSED GError **error) +{ + GdaStatement *estmt; + GdaSqlStatement *sqlst; + GdaSqlStatementSelect *stsel; + + g_assert (gda_statement_get_statement_type (stmt) == GDA_SQL_STATEMENT_SELECT); + g_object_get (G_OBJECT (stmt), "structure", &sqlst, NULL); + g_assert (sqlst); + + if (sqlst->sql) { + g_free (sqlst->sql); + sqlst->sql = NULL; + } + stsel = (GdaSqlStatementSelect*) sqlst->contents; + + /* set the WHERE condition to "1 = 0" */ + GdaSqlExpr *expr, *cond = stsel->where_cond; + GdaSqlOperation *op; + if (cond) + gda_sql_expr_free (cond); + cond = gda_sql_expr_new (GDA_SQL_ANY_PART (stsel)); + stsel->where_cond = cond; + op = gda_sql_operation_new (GDA_SQL_ANY_PART (cond)); + cond->cond = op; + op->operator_type = GDA_SQL_OPERATOR_TYPE_EQ; + expr = gda_sql_expr_new (GDA_SQL_ANY_PART (op)); + op->operands = g_slist_prepend (NULL, expr); + g_value_set_int ((expr->value = gda_value_new (G_TYPE_INT)), 1); + expr = gda_sql_expr_new (GDA_SQL_ANY_PART (op)); + op->operands = g_slist_prepend (op->operands, expr); + g_value_set_int ((expr->value = gda_value_new (G_TYPE_INT)), 0); + + /* replace any selected field which has a parameter with NULL */ + gda_sql_any_part_foreach (GDA_SQL_ANY_PART (stsel), (GdaSqlForeachFunc) param_to_null_foreach, + NULL, NULL); + + /* create new statement */ + estmt = g_object_new (GDA_TYPE_STATEMENT, "structure", sqlst, NULL); + gda_sql_statement_free (sqlst); + return estmt; +} + +/** + * gda_server_provider_handler_find: + * @prov: a #GdaServerProvider + * @cnc: (nullable): a #GdaConnection + * @g_type: a #GType + * @dbms_type: (nullable): a database type + * + * Reserved to database provider's implementations: get the #GdaDataHandler associated to @prov + * for connection @cnc. You probably want to use gda_server_provider_get_data_handler_g_type(). + * + * Returns: (transfer none): the requested #GdaDataHandler, or %NULL if none found + */ +GdaDataHandler * +gda_server_provider_handler_find (GdaServerProvider *prov, GdaConnection *cnc, + GType g_type, const gchar *dbms_type) +{ + g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (prov), NULL); + GdaServerProviderPrivate *priv = gda_server_provider_get_instance_private (prov); + if (cnc) + g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL); + + GdaDataHandler *dh; + GdaServerProviderHandlerInfo info; + + info.cnc = cnc; + info.g_type = g_type; + info.dbms_type = (gchar *) dbms_type; + dh = g_hash_table_lookup (priv->data_handlers, &info); + if (!dh) { + /* try without the connection specification */ + info.cnc = NULL; + dh = g_hash_table_lookup (priv->data_handlers, &info); + } + + return dh; +} + +void +gda_server_provider_handler_declare (GdaServerProvider *prov, GdaDataHandler *dh, + GdaConnection *cnc, + GType g_type, const gchar *dbms_type) +{ + GdaServerProviderHandlerInfo *info; + g_return_if_fail (GDA_IS_SERVER_PROVIDER (prov)); + g_return_if_fail (GDA_IS_DATA_HANDLER (dh)); + GdaServerProviderPrivate *priv = gda_server_provider_get_instance_private (prov); + + info = g_new (GdaServerProviderHandlerInfo, 1); + info->cnc = cnc; + info->g_type = g_type; + info->dbms_type = dbms_type ? g_strdup (dbms_type) : NULL; + + g_hash_table_insert (priv->data_handlers, info, dh); + g_object_ref (dh); +} + +static gboolean +handlers_clear_for_cnc_fh (GdaServerProviderHandlerInfo *key, GdaDataHandler *value, GdaConnection *cnc) +{ + return (key->cnc == cnc) ? TRUE : FALSE; +} + +/* + * Removes any #GdaServerProviderHandlerInfo associated to @cnc */ +void +_gda_server_provider_handlers_clear_for_cnc (GdaServerProvider *prov, GdaConnection *cnc) +{ + g_return_if_fail (GDA_IS_SERVER_PROVIDER (prov)); + g_return_if_fail (GDA_IS_CONNECTION (cnc)); + GdaServerProviderPrivate *priv = gda_server_provider_get_instance_private (prov); + g_hash_table_foreach_remove (priv->data_handlers, (GHRFunc) handlers_clear_for_cnc_fh, cnc); +} + +/** + * gda_server_provider_load_resource_contents: + * @prov_name: the provider's name + * @resource: the name of the resource to load + * + * Loads and returns the contents of the specified resource. + * This function should only be used by database provider's implementations + * + * Returns: (transfer full): a new string containing the resource's contents, or %NULL if not found or if an error occurred + * + * Since: 6.0 + */ +gchar * +gda_server_provider_load_resource_contents (const gchar *prov_name, const gchar *resource) +{ + g_return_val_if_fail (prov_name, NULL); + g_return_val_if_fail (resource, NULL); + + gchar *rname; + rname = g_strdup_printf ("/spec/%s/%s", prov_name, resource); + + GBytes *bytes; + bytes = g_resources_lookup_data (rname, G_RESOURCE_LOOKUP_FLAGS_NONE, NULL); + g_free (rname); + if (!bytes) { + g_warning ("Resource: /spec/%s/%s, not found for provider", prov_name, resource); + return NULL; + } + + gchar *retval; + retval = g_strdup ((const gchar*) g_bytes_get_data (bytes, NULL)); + g_bytes_unref (bytes); + return retval; +} diff --git a/.flatpak-builder/cache/objects/c2/9392e01e78ab5e6023a9cebe1d2a7647dc3cc9072edfa29b5de9be7d73122c.file b/.flatpak-builder/cache/objects/c2/9392e01e78ab5e6023a9cebe1d2a7647dc3cc9072edfa29b5de9be7d73122c.file new file mode 100644 index 0000000..d3bf773 --- /dev/null +++ b/.flatpak-builder/cache/objects/c2/9392e01e78ab5e6023a9cebe1d2a7647dc3cc9072edfa29b5de9be7d73122c.file @@ -0,0 +1,377 @@ +# decompiler.py +# +# Copyright 2021 James Westman +# +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation; either version 3 of the +# License, or (at your option) any later version. +# +# This file is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program. If not, see . +# +# SPDX-License-Identifier: LGPL-3.0-or-later + +import re +from enum import Enum +import typing as T +from dataclasses import dataclass + +from .xml_reader import Element, parse, parse_string +from .gir import * +from .utils import Colors + + +__all__ = ["decompile"] + + +_DECOMPILERS: T.Dict = {} +_CLOSING = { + "{": "}", + "[": "]", +} +_NAMESPACES = [ + ("GLib", "2.0"), + ("GObject", "2.0"), + ("Gio", "2.0"), + ("Adw", "1"), +] + + +class LineType(Enum): + NONE = 1 + STMT = 2 + BLOCK_START = 3 + BLOCK_END = 4 + + +class DecompileCtx: + def __init__(self) -> None: + self._result: str = "" + self.gir = GirContext() + self._indent: int = 0 + self._blocks_need_end: T.List[str] = [] + self._last_line_type: LineType = LineType.NONE + self.template_class: T.Optional[str] = None + + self.gir.add_namespace(get_namespace("Gtk", "4.0")) + + @property + def result(self) -> str: + imports = "\n".join( + [ + f"using {ns} {namespace.version};" + for ns, namespace in self.gir.namespaces.items() + ] + ) + return imports + "\n" + self._result + + def type_by_cname(self, cname: str) -> T.Optional[GirType]: + if type := self.gir.get_type_by_cname(cname): + return type + + for ns, version in _NAMESPACES: + try: + namespace = get_namespace(ns, version) + if type := namespace.get_type_by_cname(cname): + self.gir.add_namespace(namespace) + return type + except: + pass + + return None + + def start_block(self) -> None: + self._blocks_need_end.append("") + + def end_block(self) -> None: + if close := self._blocks_need_end.pop(): + self.print(close) + + def end_block_with(self, text: str) -> None: + self._blocks_need_end[-1] = text + + def print(self, line: str, newline: bool = True) -> None: + if line == "}" or line == "]": + self._indent -= 1 + + # Add blank lines between different types of lines, for neatness + if newline: + if line == "}" or line == "]": + line_type = LineType.BLOCK_END + elif line.endswith("{") or line.endswith("]"): + line_type = LineType.BLOCK_START + elif line.endswith(";"): + line_type = LineType.STMT + else: + line_type = LineType.NONE + if ( + line_type != self._last_line_type + and self._last_line_type != LineType.BLOCK_START + and line_type != LineType.BLOCK_END + ): + self._result += "\n" + self._last_line_type = line_type + + self._result += (" " * self._indent) + line + if newline: + self._result += "\n" + + if line.endswith("{") or line.endswith("["): + if len(self._blocks_need_end): + self._blocks_need_end[-1] = _CLOSING[line[-1]] + self._indent += 1 + + def print_attribute(self, name: str, value: str, type: GirType) -> None: + def get_enum_name(value): + for member in type.members.values(): + if ( + member.nick == value + or member.c_ident == value + or str(member.value) == value + ): + return member.name + return value.replace("-", "_") + + if type is None: + self.print(f'{name}: "{escape_quote(value)}";') + elif type.assignable_to(FloatType()): + self.print(f"{name}: {value};") + elif type.assignable_to(BoolType()): + val = truthy(value) + self.print(f"{name}: {'true' if val else 'false'};") + elif ( + type.assignable_to(self.gir.namespaces["Gtk"].lookup_type("Gdk.Pixbuf")) + or type.assignable_to(self.gir.namespaces["Gtk"].lookup_type("Gdk.Texture")) + or type.assignable_to( + self.gir.namespaces["Gtk"].lookup_type("Gdk.Paintable") + ) + or type.assignable_to( + self.gir.namespaces["Gtk"].lookup_type("Gtk.ShortcutAction") + ) + or type.assignable_to( + self.gir.namespaces["Gtk"].lookup_type("Gtk.ShortcutTrigger") + ) + ): + self.print(f'{name}: "{escape_quote(value)}";') + elif value == self.template_class: + self.print(f"{name}: template;") + elif type.assignable_to( + self.gir.namespaces["Gtk"].lookup_type("GObject.Object") + ): + self.print(f"{name}: {value};") + elif isinstance(type, Bitfield): + flags = [get_enum_name(flag) for flag in value.split("|")] + self.print(f"{name}: {' | '.join(flags)};") + elif isinstance(type, Enumeration): + self.print(f"{name}: {get_enum_name(value)};") + else: + self.print(f'{name}: "{escape_quote(value)}";') + + +def _decompile_element( + ctx: DecompileCtx, gir: T.Optional[GirContext], xml: Element +) -> None: + try: + decompiler = _DECOMPILERS.get(xml.tag) + if decompiler is None: + raise UnsupportedError(f"unsupported XML tag: <{xml.tag}>") + + args: T.Dict[str, T.Optional[str]] = { + canon(name): value for name, value in xml.attrs.items() + } + if decompiler._cdata: + if len(xml.children): + args["cdata"] = None + else: + args["cdata"] = xml.cdata + + ctx.start_block() + gir = decompiler(ctx, gir, **args) + + for child in xml.children: + _decompile_element(ctx, gir, child) + + ctx.end_block() + + except UnsupportedError as e: + raise e + except TypeError as e: + raise UnsupportedError(tag=xml.tag) + + +def decompile(data: str) -> str: + ctx = DecompileCtx() + + xml = parse(data) + _decompile_element(ctx, None, xml) + + return ctx.result + + +def decompile_string(data): + ctx = DecompileCtx() + + xml = parse_string(data) + _decompile_element(ctx, None, xml) + + return ctx.result + + +def canon(string: str) -> str: + if string == "class": + return "klass" + else: + return string.replace("-", "_").lower() + + +def truthy(string: str) -> bool: + return string.lower() in ["yes", "true", "t", "y", "1"] + + +def full_name(gir) -> str: + return gir.name if gir.full_name.startswith("Gtk.") else gir.full_name + + +def lookup_by_cname(gir, cname: str) -> T.Optional[GirType]: + if isinstance(gir, GirContext): + return gir.get_type_by_cname(cname) + else: + return gir.get_containing(Repository).get_type_by_cname(cname) + + +def decompiler(tag, cdata=False): + def decorator(func): + func._cdata = cdata + _DECOMPILERS[tag] = func + return func + + return decorator + + +def escape_quote(string: str) -> str: + return ( + string.replace("\\", "\\\\") + .replace("'", "\\'") + .replace('"', '\\"') + .replace("\n", "\\n") + ) + + +@decompiler("interface") +def decompile_interface(ctx, gir): + return gir + + +@decompiler("requires") +def decompile_requires(ctx, gir, lib=None, version=None): + return gir + + +@decompiler("placeholder") +def decompile_placeholder(ctx, gir): + pass + + +def decompile_translatable( + string: str, + translatable: T.Optional[str], + context: T.Optional[str], + comments: T.Optional[str], +) -> T.Tuple[T.Optional[str], str]: + if translatable is not None and truthy(translatable): + if comments is not None: + comments = comments.replace("/*", " ").replace("*/", " ") + comments = f"/* Translators: {comments} */" + + if context is not None: + return comments, f'C_("{escape_quote(context)}", "{escape_quote(string)}")' + else: + return comments, f'_("{escape_quote(string)}")' + else: + return comments, f'"{escape_quote(string)}"' + + +@decompiler("property", cdata=True) +def decompile_property( + ctx: DecompileCtx, + gir, + name, + cdata, + bind_source=None, + bind_property=None, + bind_flags=None, + translatable="false", + comments=None, + context=None, +): + name = name.replace("_", "-") + if comments is not None: + ctx.print(f"/* Translators: {comments} */") + + if cdata is None: + ctx.print(f"{name}: ", False) + ctx.end_block_with(";") + elif bind_source: + flags = "" + bind_flags = bind_flags or [] + if "sync-create" not in bind_flags: + flags += " no-sync-create" + if "invert-boolean" in bind_flags: + flags += " inverted" + if "bidirectional" in bind_flags: + flags += " bidirectional" + ctx.print(f"{name}: bind-property {bind_source}.{bind_property}{flags};") + elif truthy(translatable): + comments, translatable = decompile_translatable( + cdata, translatable, context, comments + ) + if comments is not None: + ctx.print(comments) + ctx.print(f"{name}: {translatable};") + elif gir is None or gir.properties.get(name) is None: + ctx.print(f'{name}: "{escape_quote(cdata)}";') + else: + ctx.print_attribute(name, cdata, gir.properties.get(name).type) + return gir + + +@decompiler("attribute", cdata=True) +def decompile_attribute( + ctx, gir, name, cdata, translatable="false", comments=None, context=None +): + decompile_property( + ctx, + gir, + name, + cdata, + translatable=translatable, + comments=comments, + context=context, + ) + + +@decompiler("attributes") +def decompile_attributes(ctx, gir): + ctx.print("attributes {") + + +@dataclass +class UnsupportedError(Exception): + message: str = "unsupported feature" + tag: T.Optional[str] = None + + def print(self, filename: str): + print(f"\n{Colors.RED}{Colors.BOLD}error: {self.message}{Colors.CLEAR}") + print(f"in {Colors.UNDERLINE}{filename}{Colors.NO_UNDERLINE}") + if self.tag: + print(f"in tag {Colors.BLUE}{self.tag}{Colors.CLEAR}") + print( + f"""{Colors.FAINT}The compiler might support this feature, but the porting tool does not. You +probably need to port this file manually.{Colors.CLEAR}\n""" + ) diff --git a/.flatpak-builder/cache/objects/c2/b7c7dde3e3787384938acdfbb1deef39c9e655348aab4f1dd75bb3e53605d5.file b/.flatpak-builder/cache/objects/c2/b7c7dde3e3787384938acdfbb1deef39c9e655348aab4f1dd75bb3e53605d5.file new file mode 100644 index 0000000..6d161a5 --- /dev/null +++ b/.flatpak-builder/cache/objects/c2/b7c7dde3e3787384938acdfbb1deef39c9e655348aab4f1dd75bb3e53605d5.file @@ -0,0 +1,326 @@ +/* + * Copyright (C) 2009 - 2014 Vivien Malerba + * Copyright (C) 2010 David King + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include +#include +#include +#include "gda-sqlite.h" +#include "gda-sqlite-blob-op.h" +#include +#include "gda-sqlite-util.h" +#include + + +static void gda_sqlite_blob_op_class_init (GdaSqliteBlobOpClass *klass); +static void gda_sqlite_blob_op_init (GdaSqliteBlobOp *blob); +static void gda_sqlite_blob_op_finalize (GObject *object); + +static glong gda_sqlite_blob_op_get_length (GdaBlobOp *op); +static glong gda_sqlite_blob_op_read (GdaBlobOp *op, GdaBlob *blob, glong offset, glong size); +static glong gda_sqlite_blob_op_write (GdaBlobOp *op, GdaBlob *blob, glong offset); + +typedef struct { + GWeakRef provider; + sqlite3_blob *sblob; +} GdaSqliteBlobOpPrivate; + +G_DEFINE_TYPE_WITH_PRIVATE (GdaSqliteBlobOp, gda_sqlite_blob_op, GDA_TYPE_BLOB_OP) + +static void +gda_sqlite_blob_op_init (GdaSqliteBlobOp *op) +{ + g_return_if_fail (GDA_IS_SQLITE_BLOB_OP (op)); + GdaSqliteBlobOpPrivate *priv = gda_sqlite_blob_op_get_instance_private (op); + + priv->sblob = NULL; + g_weak_ref_init (&priv->provider, NULL); +} + +static void +gda_sqlite_blob_op_class_init (GdaSqliteBlobOpClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GdaBlobOpClass *blob_class = GDA_BLOB_OP_CLASS (klass); + + object_class->finalize = gda_sqlite_blob_op_finalize; + GDA_BLOB_OP_FUNCTIONS (blob_class->functions)->get_length = gda_sqlite_blob_op_get_length; + GDA_BLOB_OP_FUNCTIONS (blob_class->functions)->read = gda_sqlite_blob_op_read; + GDA_BLOB_OP_FUNCTIONS (blob_class->functions)->write = gda_sqlite_blob_op_write; +} + +static void +gda_sqlite_blob_op_finalize (GObject * object) +{ + GdaSqliteBlobOp *bop = (GdaSqliteBlobOp *) object; + + g_return_if_fail (GDA_IS_SQLITE_BLOB_OP (bop)); + GdaSqliteBlobOpPrivate *priv = gda_sqlite_blob_op_get_instance_private (bop); + + /* free specific information */ + if (priv->sblob) { + GdaSqliteProvider *prov = g_weak_ref_get (&priv->provider); + if (prov != NULL) { + SQLITE3_CALL (prov, sqlite3_blob_close) (priv->sblob); + g_object_unref (prov); + } +#ifdef GDA_DEBUG_NO + g_print ("CLOSED blob %p\n", bop); +#endif + } + g_weak_ref_clear (&priv->provider); + + G_OBJECT_CLASS (gda_sqlite_blob_op_parent_class)->finalize (object); +} + +GdaBlobOp * +_gda_sqlite_blob_op_new (GdaConnection *cnc, + const gchar *db_name, const gchar *table_name, + const gchar *column_name, sqlite3_int64 rowid) +{ + GdaSqliteBlobOp *bop = NULL; + int rc; + sqlite3_blob *sblob; + gchar *db, *table; + gboolean free_strings = TRUE; + gboolean transaction_started = FALSE; + + g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL); + g_return_val_if_fail (table_name, NULL); + g_return_val_if_fail (column_name, NULL); + g_return_val_if_fail (GDA_IS_SQLITE_PROVIDER (gda_connection_get_provider (cnc)), NULL); + GdaSqliteBlobOpPrivate *priv = gda_sqlite_blob_op_get_instance_private (bop); + + if (db_name) { + db = (gchar *) db_name; + table = (gchar *) table_name; + free_strings = FALSE; + } + else if (! _split_identifier_string (g_strdup (table_name), &db, &table)) + return NULL; + + SqliteConnectionData *cdata; + cdata = (SqliteConnectionData*) gda_connection_internal_get_provider_data_error (cnc, NULL); + if (!cdata || + ! _gda_sqlite_check_transaction_started (cnc, &transaction_started, NULL)) + return NULL; + + GdaSqliteProvider *prov = GDA_SQLITE_PROVIDER (gda_connection_get_provider (cnc)); + + rc = SQLITE3_CALL (prov, sqlite3_blob_open) (cdata->connection, + db ? db : "main", + table, column_name, rowid, + 1, /* Read & Write */ + &(sblob)); + if (rc != SQLITE_OK) { +#ifdef GDA_DEBUG_NO + g_print ("ERROR: %s\n", SQLITE3_CALL (prov, sqlite3_errmsg) (cdata->connection)); +#endif + if (transaction_started) + gda_connection_rollback_transaction (cnc, NULL, NULL); + goto out; + } + + bop = g_object_new (GDA_TYPE_SQLITE_BLOB_OP, "connection", cnc, NULL); + priv->sblob = sblob; + g_weak_ref_set (&priv->provider, prov); +#ifdef GDA_DEBUG_NO + g_print ("OPENED blob %p\n", bop); +#endif + + out: + if (free_strings) { + g_free (db); + g_free (table); + } + return (GdaBlobOp*) bop; +} + +/* + * Get length request + */ +static glong +gda_sqlite_blob_op_get_length (GdaBlobOp *op) +{ + GdaSqliteBlobOp *bop; + int len; + + g_return_val_if_fail (GDA_IS_SQLITE_BLOB_OP (op), -1); + bop = GDA_SQLITE_BLOB_OP (op); + GdaSqliteBlobOpPrivate *priv = gda_sqlite_blob_op_get_instance_private (bop); + g_return_val_if_fail (priv->sblob, -1); + GdaSqliteProvider *prov = g_weak_ref_get (&priv->provider); + g_return_val_if_fail (prov != NULL, -1); + + len = SQLITE3_CALL (prov, sqlite3_blob_bytes) (priv->sblob); + g_object_unref (prov); + return len >= 0 ? len : 0; +} + +/* + * Blob read request + */ +static glong +gda_sqlite_blob_op_read (GdaBlobOp *op, GdaBlob *blob, glong offset, glong size) +{ + GdaSqliteBlobOp *bop; + GdaBinary *bin; + gpointer buffer = NULL; + int rc; + + g_return_val_if_fail (GDA_IS_SQLITE_BLOB_OP (op), -1); + bop = GDA_SQLITE_BLOB_OP (op); + GdaSqliteBlobOpPrivate *priv = gda_sqlite_blob_op_get_instance_private (bop); + g_return_val_if_fail (priv->sblob, -1); + if (offset >= G_MAXINT) + return -1; + g_return_val_if_fail (blob, -1); + + if (offset > G_MAXINT) + return -1; + if (size > G_MAXINT) + return -1; + + GdaSqliteProvider *prov = g_weak_ref_get (&priv->provider); + g_return_val_if_fail (prov != NULL, -1); + + bin = gda_blob_get_binary (blob); + gda_binary_set_data (bin, (guchar*) "", 0); + + /* fetch blob data using C API into bin->data, and set bin->binary_length */ + int rsize; + int len; + + len = SQLITE3_CALL (prov, sqlite3_blob_bytes) (priv->sblob); + if (len < 0){ + g_object_unref (prov); + return -1; + } else if (len == 0) { + g_object_unref (prov); + return 0; + } + + rsize = (int) size; + if (offset >= len) { + g_object_unref (prov); + return -1; + } + + if (len - offset < rsize) + rsize = len - offset; + + rc = SQLITE3_CALL (prov, sqlite3_blob_read) (priv->sblob, buffer, rsize, offset); + if (rc != SQLITE_OK) { + gda_binary_reset_data (bin); + g_object_unref (prov); + return -1; + } + gda_binary_set_data (bin, buffer, rsize); + g_object_unref (prov); + + return gda_binary_get_size (bin); +} + +/* + * Blob write request + */ +static glong +gda_sqlite_blob_op_write (GdaBlobOp *op, GdaBlob *blob, glong offset) +{ + GdaSqliteBlobOp *bop; + GdaBinary *bin; + glong nbwritten = -1; + int len; + + g_return_val_if_fail (GDA_IS_SQLITE_BLOB_OP (op), -1); + bop = GDA_SQLITE_BLOB_OP (op); + GdaSqliteBlobOpPrivate *priv = gda_sqlite_blob_op_get_instance_private (bop); + g_return_val_if_fail (priv->sblob, -1); + g_return_val_if_fail (blob, -1); + + GdaSqliteProvider *prov = g_weak_ref_get (&priv->provider); + g_return_val_if_fail (prov != NULL, -1); + + len = SQLITE3_CALL (prov, sqlite3_blob_bytes) (priv->sblob); + if (len < 0) { + g_object_unref (prov); + return -1; + } + + if (gda_blob_get_op (blob) && (gda_blob_get_op (blob) != op)) { + /* use data through blob->op */ + #define buf_size 16384 + gint nread = 0; + GdaBlob *tmpblob = gda_blob_new (); + gda_blob_set_op (tmpblob, gda_blob_get_op (blob)); + + nbwritten = 0; + + for (nread = gda_blob_op_read (gda_blob_get_op (tmpblob), tmpblob, nbwritten, buf_size); + nread > 0; + nread = gda_blob_op_read (gda_blob_get_op (tmpblob), tmpblob, nbwritten, buf_size)) { + int tmp_written; + int rc; + int wlen; + + if (nread + offset + nbwritten > len) + wlen = len - offset - nbwritten; + else + wlen = nread; + + rc = SQLITE3_CALL (prov, sqlite3_blob_write) (priv->sblob, + gda_binary_get_data (gda_blob_get_binary (tmpblob)), wlen, offset + nbwritten); + if (rc != SQLITE_OK) + tmp_written = -1; + else + tmp_written = wlen; + + if (tmp_written < 0) { + /* treat error */ + gda_blob_free ((gpointer) tmpblob); + g_object_unref (prov); + return -1; + } + nbwritten += tmp_written; + if (nread < buf_size) + /* nothing more to read */ + break; + } + gda_blob_free ((gpointer) tmpblob); + } + else { + /* write blob using bin->data and bin->binary_length */ + int rc; + int wlen; + bin = gda_blob_get_binary (blob); + if (gda_binary_get_size (bin) + offset > len) + wlen = len - offset; + else + wlen = gda_binary_get_size (bin); + + rc = SQLITE3_CALL (prov, sqlite3_blob_write) (priv->sblob, gda_binary_get_data (bin), wlen, offset); + if (rc != SQLITE_OK) + nbwritten = -1; + else + nbwritten = wlen; + } + g_object_unref (prov); + + return nbwritten; +} diff --git a/.flatpak-builder/cache/objects/c2/cefce7529cc1f38d35a4d9f07f35b50b42db695f78b7f81cd4f2270afafdb1.dirtree b/.flatpak-builder/cache/objects/c2/cefce7529cc1f38d35a4d9f07f35b50b42db695f78b7f81cd4f2270afafdb1.dirtree new file mode 100644 index 0000000..f0dc07e Binary files /dev/null and b/.flatpak-builder/cache/objects/c2/cefce7529cc1f38d35a4d9f07f35b50b42db695f78b7f81cd4f2270afafdb1.dirtree differ diff --git a/.flatpak-builder/cache/objects/c2/ff9f600d1cdf4d50025e465f4c74f72f3f74b0a9dbb4815445aea24ff32eae.file b/.flatpak-builder/cache/objects/c2/ff9f600d1cdf4d50025e465f4c74f72f3f74b0a9dbb4815445aea24ff32eae.file new file mode 100644 index 0000000..686d1e8 --- /dev/null +++ b/.flatpak-builder/cache/objects/c2/ff9f600d1cdf4d50025e465f4c74f72f3f74b0a9dbb4815445aea24ff32eae.file @@ -0,0 +1,145 @@ +# property_binding.py +# +# Copyright 2023 James Westman +# +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation; either version 3 of the +# License, or (at your option) any later version. +# +# This file is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program. If not, see . +# +# SPDX-License-Identifier: LGPL-3.0-or-later + +from .common import * +from .contexts import ScopeCtx +from .gobject_object import Object + + +class PropertyBindingFlag(AstNode): + grammar = [ + AnyOf( + UseExact("flag", "inverted"), + UseExact("flag", "bidirectional"), + UseExact("flag", "no-sync-create"), + UseExact("flag", "sync-create"), + ) + ] + + @property + def flag(self) -> str: + return self.tokens["flag"] + + @validate() + def sync_create(self): + if self.flag == "sync-create": + raise UpgradeWarning( + "'sync-create' is now the default. Use 'no-sync-create' if this is not wanted.", + actions=[CodeAction("remove 'sync-create'", "")], + ) + + @validate() + def unique(self): + self.validate_unique_in_parent( + f"Duplicate flag '{self.flag}'", lambda x: x.flag == self.flag + ) + + +class PropertyBinding(AstNode): + grammar = AnyOf( + [ + Keyword("bind-property"), + UseIdent("source"), + ".", + UseIdent("property"), + ZeroOrMore(PropertyBindingFlag), + ], + [ + Keyword("bind"), + UseIdent("source"), + ".", + UseIdent("property"), + PropertyBindingFlag, + ZeroOrMore(PropertyBindingFlag), + ], + ) + + @property + def source(self) -> str: + return self.tokens["source"] + + @property + def source_obj(self) -> T.Optional[Object]: + if self.root.is_legacy_template(self.source): + return self.root.template + return self.context[ScopeCtx].objects.get(self.source) + + @property + def property_name(self) -> str: + return self.tokens["property"] + + @property + def flags(self) -> T.List[PropertyBindingFlag]: + return self.children[PropertyBindingFlag] + + @property + def inverted(self) -> bool: + return any([f.flag == "inverted" for f in self.flags]) + + @property + def bidirectional(self) -> bool: + return any([f.flag == "bidirectional" for f in self.flags]) + + @property + def no_sync_create(self) -> bool: + return any([f.flag == "no-sync-create" for f in self.flags]) + + @validate("source") + def source_object_exists(self) -> None: + if self.source_obj is None: + raise CompileError( + f"Could not find object with ID {self.source}", + did_you_mean=(self.source, self.context[ScopeCtx].objects.keys()), + ) + + @validate("property") + def property_exists(self) -> None: + if self.source_obj is None: + return + + gir_class = self.source_obj.gir_class + + if gir_class is None or gir_class.incomplete: + # Objects that we have no gir data on should not be validated + # This happens for classes defined by the app itself + return + + if ( + isinstance(gir_class, gir.Class) + and gir_class.properties.get(self.property_name) is None + ): + raise CompileError( + f"{gir_class.full_name} does not have a property called {self.property_name}" + ) + + @validate("bind") + def old_bind(self): + if self.tokens["bind"]: + raise UpgradeWarning( + "Use 'bind-property', introduced in blueprint 0.8.0, to use binding flags", + actions=[CodeAction("Use 'bind-property'", "bind-property")], + ) + + @validate("source") + def legacy_template(self): + if self.root.is_legacy_template(self.source): + raise UpgradeWarning( + "Use 'template' instead of the class name (introduced in 0.8.0)", + actions=[CodeAction("Use 'template'", "template")], + ) diff --git a/.flatpak-builder/cache/objects/c3/79decf38cba7e334d9f7b537dcf75c19a16d91bed2a7fce99b59973850b761.dirtree b/.flatpak-builder/cache/objects/c3/79decf38cba7e334d9f7b537dcf75c19a16d91bed2a7fce99b59973850b761.dirtree new file mode 100644 index 0000000..8208870 Binary files /dev/null and b/.flatpak-builder/cache/objects/c3/79decf38cba7e334d9f7b537dcf75c19a16d91bed2a7fce99b59973850b761.dirtree differ diff --git a/.flatpak-builder/cache/objects/c3/90d75fb7f5f8912d2661c6c34e92c33f4c73f38438be47a6fe3ca20bb672e4.file b/.flatpak-builder/cache/objects/c3/90d75fb7f5f8912d2661c6c34e92c33f4c73f38438be47a6fe3ca20bb672e4.file new file mode 120000 index 0000000..5a7db49 --- /dev/null +++ b/.flatpak-builder/cache/objects/c3/90d75fb7f5f8912d2661c6c34e92c33f4c73f38438be47a6fe3ca20bb672e4.file @@ -0,0 +1 @@ +../../share/runtime/locale/ru/share/ru \ No newline at end of file diff --git a/.flatpak-builder/cache/objects/c3/990277125b5041a01e167d786dfc01452ed67f019e0293599f39846b6d0eab.dirtree b/.flatpak-builder/cache/objects/c3/990277125b5041a01e167d786dfc01452ed67f019e0293599f39846b6d0eab.dirtree new file mode 100644 index 0000000..6f08c51 Binary files /dev/null and b/.flatpak-builder/cache/objects/c3/990277125b5041a01e167d786dfc01452ed67f019e0293599f39846b6d0eab.dirtree differ diff --git a/.flatpak-builder/cache/objects/c3/f25733b1f7e25b310d7a5ee4341db80f553f95f17ca82fd2e187845dc704ee.file b/.flatpak-builder/cache/objects/c3/f25733b1f7e25b310d7a5ee4341db80f553f95f17ca82fd2e187845dc704ee.file new file mode 100644 index 0000000..ddec499 --- /dev/null +++ b/.flatpak-builder/cache/objects/c3/f25733b1f7e25b310d7a5ee4341db80f553f95f17ca82fd2e187845dc704ee.file @@ -0,0 +1,281 @@ +/* + * Copyright (C) 2009 - 2013 Vivien Malerba + * Copyright (C) 2010 David King + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +#define G_LOG_DOMAIN "GDA-tree-mgr-schemas" + +#include +#include +#include +#include "gda-tree-mgr-schemas.h" +#include "gda-tree-node.h" + +typedef struct { + GdaConnection *cnc; + GdaMetaStore *mstore; + GdaStatement *stmt; +} GdaTreeMgrSchemasPrivate; +G_DEFINE_TYPE_WITH_PRIVATE (GdaTreeMgrSchemas, gda_tree_mgr_schemas, GDA_TYPE_TREE_MANAGER) + +static void gda_tree_mgr_schemas_dispose (GObject *object); +static void gda_tree_mgr_schemas_set_property (GObject *object, + guint param_id, + const GValue *value, + GParamSpec *pspec); +static void gda_tree_mgr_schemas_get_property (GObject *object, + guint param_id, + GValue *value, + GParamSpec *pspec); + +/* virtual methods */ +static GSList *gda_tree_mgr_schemas_update_children (GdaTreeManager *manager, GdaTreeNode *node, + const GSList *children_nodes, gboolean *out_error, GError **error); + +/* properties */ +enum { + PROP_0, + PROP_CNC, + PROP_META_STORE +}; + +/* + * GdaTreeMgrSchemas class implementation + * @klass: + */ +static void +gda_tree_mgr_schemas_class_init (GdaTreeMgrSchemasClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + /* virtual methods */ + ((GdaTreeManagerClass*) klass)->update_children = gda_tree_mgr_schemas_update_children; + + /* Properties */ + object_class->set_property = gda_tree_mgr_schemas_set_property; + object_class->get_property = gda_tree_mgr_schemas_get_property; + + /** + * GdaTreeMgrSchemas:connection: + * + * Defines the #GdaConnection to display information for. Necessary upon construction unless + * the #GdaTreeMgrSchema:meta-store property is specified instead. + */ + g_object_class_install_property (object_class, PROP_CNC, + g_param_spec_object ("connection", NULL, "Connection to use", + GDA_TYPE_CONNECTION, + G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)); + /** + * GdaTreeMgrSchemas:meta-store: + * + * Defines the #GdaMetaStore to extract information from. Necessary upon construction unless + * the #GdaTreeMgrSchema:connection property is specified instead. This property has + * priority over the GdaTreeMgrSchema:connection property. + * + * Since: 4.2.4 + */ + g_object_class_install_property (object_class, PROP_META_STORE, + g_param_spec_object ("meta-store", NULL, "GdaMetaStore to use", + GDA_TYPE_META_STORE, + G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)); + + object_class->dispose = gda_tree_mgr_schemas_dispose; +} + +static void +gda_tree_mgr_schemas_init (GdaTreeMgrSchemas *mgr) {} + +static void +gda_tree_mgr_schemas_dispose (GObject *object) +{ + GdaTreeMgrSchemas *mgr = (GdaTreeMgrSchemas *) object; + + g_return_if_fail (GDA_IS_TREE_MGR_SCHEMAS (mgr)); + GdaTreeMgrSchemasPrivate *priv = gda_tree_mgr_schemas_get_instance_private (mgr); + + if (priv->cnc) { + g_object_unref (priv->cnc); + priv->cnc = NULL; + } + if (priv->mstore) { + g_object_unref (priv->mstore); + priv->mstore = NULL; + } + if (priv->stmt) { + g_object_unref (priv->stmt); + priv->stmt = NULL; + } + + + /* chain to parent class */ + G_OBJECT_CLASS (gda_tree_mgr_schemas_parent_class)->dispose (object); +} + +static void +gda_tree_mgr_schemas_set_property (GObject *object, + guint param_id, + const GValue *value, + GParamSpec *pspec) +{ + GdaTreeMgrSchemas *mgr; + + mgr = GDA_TREE_MGR_SCHEMAS (object); + GdaTreeMgrSchemasPrivate *priv = gda_tree_mgr_schemas_get_instance_private (mgr); + switch (param_id) { + case PROP_CNC: + priv->cnc = (GdaConnection*) g_value_get_object (value); + if (priv->cnc) + g_object_ref (priv->cnc); + break; + case PROP_META_STORE: + priv->mstore = (GdaMetaStore*) g_value_get_object (value); + if (priv->mstore) + g_object_ref (priv->mstore); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + break; + } +} + +static void +gda_tree_mgr_schemas_get_property (GObject *object, + guint param_id, + GValue *value, + GParamSpec *pspec) +{ + GdaTreeMgrSchemas *mgr; + + mgr = GDA_TREE_MGR_SCHEMAS (object); + GdaTreeMgrSchemasPrivate *priv = gda_tree_mgr_schemas_get_instance_private (mgr); + switch (param_id) { + case PROP_CNC: + g_value_set_object (value, priv->cnc); + break; + case PROP_META_STORE: + g_value_set_object (value, priv->mstore); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + break; + } +} + +/** + * gda_tree_mgr_schemas_new: + * @cnc: a #GdaConnection object + * + * Creates a new #GdaTreeManager object which will add one tree node for each database schema found + * in @cnc. + * + * Returns: (transfer full): a new #GdaTreeManager object + * + * Since: 4.2 + */ +GdaTreeManager* +gda_tree_mgr_schemas_new (GdaConnection *cnc) +{ + GdaTreeMgrSchemas *mgr; + g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL); + + mgr = (GdaTreeMgrSchemas*) g_object_new (GDA_TYPE_TREE_MGR_SCHEMAS, + "connection", cnc, NULL); + return (GdaTreeManager*) mgr; +} + +static GSList * +gda_tree_mgr_schemas_update_children (GdaTreeManager *manager, GdaTreeNode *node, + G_GNUC_UNUSED const GSList *children_nodes, gboolean *out_error, + GError **error) +{ + GdaTreeMgrSchemas *mgr = GDA_TREE_MGR_SCHEMAS (manager); + GdaMetaStore *store; + GdaDataModel *model; + GSList *list = NULL; + GdaConnection *scnc; + GdaTreeMgrSchemasPrivate *priv = gda_tree_mgr_schemas_get_instance_private (mgr); + + if (!priv->cnc && !priv->mstore) { + g_set_error (error, GDA_TREE_MANAGER_ERROR, GDA_TREE_MANAGER_UNKNOWN_ERROR, + "%s", _("No connection and no GdaMetaStore specified")); + if (out_error) + *out_error = TRUE; + return NULL; + } + else if (priv->mstore) + store = priv->mstore; + else + store = gda_connection_get_meta_store (priv->cnc); + + scnc = gda_meta_store_get_internal_connection (store); + + if (!priv->stmt) { + GdaSqlParser *parser; + GdaStatement *stmt; + + parser = gda_connection_create_parser (scnc); + if (! parser) + parser = gda_sql_parser_new (); + + stmt = gda_sql_parser_parse_string (parser, + "SELECT schema_name FROM _schemata " + "WHERE schema_internal = FALSE OR schema_name LIKE 'info%' " + "ORDER BY schema_name DESC", NULL, error); + g_object_unref (parser); + if (!stmt) { + if (out_error) + *out_error = TRUE; + return NULL; + } + priv->stmt = stmt; + } + + model = gda_connection_statement_execute_select (scnc, priv->stmt, NULL, error); + if (!model) { + if (out_error) + *out_error = TRUE; + return NULL; + } + + GdaDataModelIter *iter; + iter = gda_data_model_create_iter (model); + for (; iter && gda_data_model_iter_move_next (iter);) { + GdaTreeNode* snode; + const GValue *cvalue; + + cvalue = gda_data_model_iter_get_value_at (iter, 0); + if (!cvalue) { + if (list) { + g_slist_free_full (list, (GDestroyNotify) g_object_unref); + } + if (out_error) + *out_error = TRUE; + g_set_error (error, GDA_TREE_MANAGER_ERROR, GDA_TREE_MANAGER_UNKNOWN_ERROR, + "%s", _("Unable to get schema name")); + return NULL; + } + + snode = gda_tree_manager_create_node (manager, node, g_value_get_string (cvalue)); + gda_tree_node_set_node_attribute (snode, "schema", cvalue, NULL); + list = g_slist_prepend (list, snode); + } + if (iter) + g_object_unref (iter); + g_object_unref (model); + + return list; +} diff --git a/.flatpak-builder/cache/objects/c4/8e88a36c007b393f7905a16da481dec6fa8fe7484c05d66973ff8012b77574.file b/.flatpak-builder/cache/objects/c4/8e88a36c007b393f7905a16da481dec6fa8fe7484c05d66973ff8012b77574.file new file mode 100644 index 0000000..5a337fd Binary files /dev/null and b/.flatpak-builder/cache/objects/c4/8e88a36c007b393f7905a16da481dec6fa8fe7484c05d66973ff8012b77574.file differ diff --git a/.flatpak-builder/cache/objects/c5/2beb43f87250b8e5874e57bfa5ff1a419b634f118292dc03137077f2f45b09.dirtree b/.flatpak-builder/cache/objects/c5/2beb43f87250b8e5874e57bfa5ff1a419b634f118292dc03137077f2f45b09.dirtree new file mode 100644 index 0000000..e77cd59 Binary files /dev/null and b/.flatpak-builder/cache/objects/c5/2beb43f87250b8e5874e57bfa5ff1a419b634f118292dc03137077f2f45b09.dirtree differ diff --git a/.flatpak-builder/cache/objects/c5/351486c8c43f978d38ff995dfc33105ae316e9e1731a4f7f14132ebe962429.file b/.flatpak-builder/cache/objects/c5/351486c8c43f978d38ff995dfc33105ae316e9e1731a4f7f14132ebe962429.file new file mode 100644 index 0000000..36969a9 --- /dev/null +++ b/.flatpak-builder/cache/objects/c5/351486c8c43f978d38ff995dfc33105ae316e9e1731a4f7f14132ebe962429.file @@ -0,0 +1,3113 @@ +/* + * Copyright (C) 2006 - 2008 Murray Cumming + * Copyright (C) 2006 - 2015 Vivien Malerba + * Copyright (C) 2007 Leonardo Boshell + * Copyright (C) 2008 Armin Burgmeier + * Copyright (C) 2008 Phil Longstaff + * Copyright (C) 2008 Przemysław Grzegorczyk + * Copyright (C) 2009 Bas Driessen + * Copyright (C) 2010 David King + * Copyright (C) 2010 Jonh Wendell + * Copyright (C) 2011 - 2012, 2019 Daniel Espinosa + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +#define G_LOG_DOMAIN "GDA-server-operation" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "gda-util.h" +#include +#ifdef HAVE_LOCALE_H +#include +#endif +#include +#include + +typedef struct { + GdaServerOperationType op_type; + gboolean cnc_set; + GdaConnection *cnc; + gboolean prov_set; + GdaServerProvider *prov; + + xmlDocPtr xml_spec_doc; + GSList *sources; /* list of GdaDataModel as sources for the parameters */ + + GSList *allnodes; /* list of all the Node structures, referenced here only */ + GSList *topnodes; /* list of the "/(*)" named nodes, not referenced here */ + GHashTable *info_hash; /* key = path, value = a GdaServerOperationNode */ + GHashTable *doc_hash; +} GdaServerOperationPrivate; + +G_DEFINE_TYPE_WITH_PRIVATE (GdaServerOperation, gda_server_operation, G_TYPE_OBJECT) + +static void gda_server_operation_class_init (GdaServerOperationClass *klass); +static void gda_server_operation_init (GdaServerOperation *operation); +static void gda_server_operation_dispose (GObject *object); + +static void gda_server_operation_set_property (GObject *object, + guint param_id, + const GValue *value, + GParamSpec *pspec); +static void gda_server_operation_get_property (GObject *object, + guint param_id, + GValue *value, + GParamSpec *pspec); + +/* signals */ +enum +{ + SEQUENCE_ITEM_ADDED, + SEQUENCE_ITEM_REMOVE, + LAST_SIGNAL +}; + +static gint gda_server_operation_signals[LAST_SIGNAL] = { 0, 0 }; + +/* properties */ +enum +{ + PROP_0, + PROP_CNC, + PROP_PROV, + PROP_OP_TYPE, + PROP_SPEC_FILE, + PROP_SPEC_RESOURCE +}; + +static GObjectClass *parent_class = NULL; + +typedef struct _Node { + struct _Node *parent; + GdaServerOperationNodeType type; + GdaServerOperationNodeStatus status; + gchar *path_name; /* NULL for GDA_SERVER_OPERATION_NODE_SEQUENCE_ITEM nodes */ + union { + GdaSet *plist; + GdaDataModel *model; + GdaHolder *param; + struct { + GSList *seq_tmpl; /* list of Node templates */ + guint min_items; + guint max_items; + GSList *seq_items; /* list of Node of type GDA_SERVER_OPERATION_NODE_SEQUENCE_ITEM */ + gchar *name; + gchar *descr; + xmlNodePtr xml_spec; /* references a priv->xml_spec_doc node, + for future instantiation of nodes */ + } seq; + GSList *seq_item_nodes; /* list of Node structures composing the item */ + } d; +} Node; +#define NODE(x) ((Node*)(x)) + +static void node_destroy (GdaServerOperation *op, Node *node); +static Node *node_new (Node *parent, GdaServerOperationNodeType type, const gchar *path); +static void sequence_add_item (GdaServerOperation *op, Node *node); +static Node *node_find (GdaServerOperation *op, const gchar *path); +static Node *node_find_or_create (GdaServerOperation *op, const gchar *path); +static gchar *node_get_complete_path (GdaServerOperation *op, Node *node); +static void clean_nodes_info_cache (GdaServerOperation *operation); + + + +/* + * GdaServerOperation class implementation + */ +static void +gda_server_operation_class_init (GdaServerOperationClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + parent_class = g_type_class_peek_parent (klass); + + /* signals */ + /** + * GdaServerOperation::sequence-item-added: (virtual seq_item_added) + * @op: the #GdaServerOperation + * @seq_path: the path to the new sequence item + * @item_index: the index (starting from 0) of the new sequence item in the sequence + * + * Gets emitted whenever a new sequence item (from a sequence template) has been added + */ + gda_server_operation_signals[SEQUENCE_ITEM_ADDED] = + g_signal_new ("sequence-item-added", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (GdaServerOperationClass, seq_item_added), + NULL, NULL, + _gda_marshal_VOID__STRING_INT, G_TYPE_NONE, + 2, G_TYPE_STRING, G_TYPE_INT); + /** + * GdaServerOperation::sequence-item-remove: (virtual seq_item_remove) + * @op: the #GdaServerOperation + * @seq_path: the path to the sequence item to be removed + * @item_index: the index (starting from 0) of the sequence item in the sequence + * + * Gets emitted whenever a sequence item is about to be removed + */ + gda_server_operation_signals[SEQUENCE_ITEM_REMOVE] = + g_signal_new ("sequence-item-remove", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (GdaServerOperationClass, seq_item_remove), + NULL, NULL, + _gda_marshal_VOID__STRING_INT, G_TYPE_NONE, + 2, G_TYPE_STRING, G_TYPE_INT); + + klass->seq_item_added = NULL; + klass->seq_item_remove = NULL; + + object_class->dispose = gda_server_operation_dispose; + + /* Properties */ + object_class->set_property = gda_server_operation_set_property; + object_class->get_property = gda_server_operation_get_property; + + g_object_class_install_property (object_class, PROP_CNC, + g_param_spec_object ("connection", NULL, "Connection to use", + GDA_TYPE_CONNECTION, + G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)); + g_object_class_install_property (object_class, PROP_PROV, + g_param_spec_object ("provider", NULL, + "Database provider which created the object", + GDA_TYPE_SERVER_PROVIDER, + G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)); + g_object_class_install_property (object_class, PROP_SPEC_FILE, + g_param_spec_string ("spec-filename", NULL, + "XML file which contains the object's data structure", + NULL, G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)); + g_object_class_install_property (object_class, PROP_SPEC_RESOURCE, + g_param_spec_string ("spec-resource", NULL, + "Name of the resource which contains the XML data representing the object's data structure", + NULL, G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)); + g_object_class_install_property (object_class, PROP_OP_TYPE, + g_param_spec_int ("op-type", NULL, "Type of operation to be done", + 0, GDA_SERVER_OPERATION_LAST - 1, + 0, G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)); +} + +static void +gda_server_operation_init (GdaServerOperation *operation) +{ + GdaServerOperationPrivate *priv = gda_server_operation_get_instance_private (operation); + + g_return_if_fail (GDA_IS_SERVER_OPERATION (operation)); + + priv->allnodes = NULL; + priv->info_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); + priv->doc_hash = NULL; /* key = file name, value = xmlDocPtr */ +} + +static void +clean_nodes_info_cache (GdaServerOperation *operation) +{ + GdaServerOperationPrivate *priv = gda_server_operation_get_instance_private (operation); + + if (priv->info_hash) + g_hash_table_destroy (priv->info_hash); + + priv->info_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); +} + + +static void +gda_server_operation_dispose (GObject *object) +{ + GdaServerOperation *operation = (GdaServerOperation *)object; + GdaServerOperationPrivate *priv = gda_server_operation_get_instance_private (operation); + + g_return_if_fail (GDA_IS_SERVER_OPERATION (operation)); + + if (priv->info_hash) + g_clear_pointer(&priv->info_hash, g_hash_table_destroy); + + if (priv->cnc) + g_clear_object (&priv->cnc); + if (priv->prov) + g_clear_object (&priv->prov); + + while (priv->topnodes) + node_destroy (operation, NODE (priv->topnodes->data)); + g_assert (!priv->allnodes); + + /* don't free priv->xml_spec_doc */ + + if (priv->sources) { + g_slist_free_full (priv->sources, (GDestroyNotify) g_object_unref); + priv->sources = NULL; + } + if (priv->doc_hash) { + g_hash_table_unref (priv->doc_hash); + priv->doc_hash = NULL; + } + + /* chain to parent class */ + G_OBJECT_CLASS (gda_server_operation_parent_class)->dispose (object); +} + +/* module error */ +GQuark +gda_server_operation_error_quark (void) +{ + static GQuark quark; + if (!quark) + quark = g_quark_from_static_string ("gda_server_operation_error"); + return quark; +} + +/* create a new Node structure */ +static Node * +node_new (Node *parent, GdaServerOperationNodeType type, const gchar *path) +{ + Node *node; + + node = g_new0 (Node, 1); + node->parent = parent; + node->type = type; + node->status = GDA_SERVER_OPERATION_STATUS_REQUIRED; + node->path_name = g_strdup (path); + + return node; +} + +/* destroy a Node structure */ +static void +node_destroy (GdaServerOperation *op, Node *node) +{ + + switch (node->type) { + case GDA_SERVER_OPERATION_NODE_PARAMLIST: + g_clear_object(&node->d.plist); + break; + case GDA_SERVER_OPERATION_NODE_DATA_MODEL: + g_clear_object (&node->d.model); + break; + case GDA_SERVER_OPERATION_NODE_PARAM: + g_clear_object (&node->d.param); + break; + case GDA_SERVER_OPERATION_NODE_SEQUENCE: { + GSList *list; + + for (list = node->d.seq.seq_tmpl; list; list = list->next) + node_destroy (op, NODE (list->data)); + g_clear_pointer(&node->d.seq.seq_tmpl, g_slist_free); + + for (list = node->d.seq.seq_items; list; list = list->next) + node_destroy (op, NODE (list->data)); + g_clear_pointer(&node->d.seq.seq_items, g_slist_free); + + g_clear_pointer(&node->d.seq.name, g_free); + g_clear_pointer(&node->d.seq.descr, g_free); + break; + } + case GDA_SERVER_OPERATION_NODE_SEQUENCE_ITEM: { + GSList *list; + + for (list = node->d.seq_item_nodes; list; list = list->next) + node_destroy (op, NODE (list->data)); + g_clear_pointer(&node->d.seq_item_nodes, g_slist_free); + break; + } + default: + g_assert_not_reached (); + break; + } + + g_clear_pointer(&node->path_name, g_free); + if (op) { + GdaServerOperationPrivate *priv = gda_server_operation_get_instance_private (op); + + priv->topnodes = g_slist_remove (priv->topnodes, node); + priv->allnodes = g_slist_remove (priv->allnodes, node); + } + + g_free (node); +} + +/* + * Find a Node from its full path + */ +static Node * +node_find (GdaServerOperation *op, const gchar *path) +{ + GdaServerOperationPrivate *priv = gda_server_operation_get_instance_private (op); + Node *node = NULL; + GSList *list; + + if (!path || !*path || (*path != '/')) + return NULL; + + for (list = priv->allnodes; list; list = list->next) { + gchar *str; + str = node_get_complete_path (op, NODE (list->data)); + if (!strcmp (str, path)) { + node = NODE (list->data); + g_free (str); + break; + } + g_free (str); + } + /*g_print ("%s(%s) => %p\n", __FUNCTION__, path, node);*/ + return node; +} + +/* + * Find a node from its full path and if it does not exist, tries to + * create it (for sequences' items) + */ +static Node * +node_find_or_create (GdaServerOperation *op, const gchar *path) +{ + Node *node; + + if (!path || !*path || (*path != '/')) + return NULL; + + node = node_find (op, path); + if (!node) { + gchar *cpath = g_strdup (path); + gchar *ptr; + gchar *root, *ext; + + /* separate @path to / */ + ptr = cpath + strlen (cpath) - 1; + while (*ptr && (*ptr != '/')) ptr--; + *ptr = 0; + + root = cpath; + ext = ptr+1; + + /* treatment */ + node = node_find_or_create (op, root); + if (node) + switch (node->type) { + case GDA_SERVER_OPERATION_NODE_SEQUENCE: { + gint index; + + index = strtol (ext, &ptr, 10); + if (ptr && *ptr) + index = -1; /* could not convert array[i] to an int */ + if (index >= 0) { + gint i; + + for (i = g_slist_length (node->d.seq.seq_items); i <= index; i++) + sequence_add_item (op, node); + node = node_find (op, path); + g_assert (node); + } + break; + } + case GDA_SERVER_OPERATION_NODE_SEQUENCE_ITEM: { + node = node_find (op, path); + g_assert (node); + break; + } + default: + node = NULL; + break; + } + g_free(cpath); + } + + /*g_print ("# %s (%s) => %p\n", __FUNCTION__, path, node);*/ + + return node; +} + +/* + * Computes the complete path of a node + */ +static gchar * +node_get_complete_path (G_GNUC_UNUSED GdaServerOperation *op, Node *node) +{ + GString *string; + gchar *retval; + Node *lnode; + + if (!node) + return NULL; + + string = g_string_new (""); + for (lnode = node; lnode; lnode = lnode->parent) { + if (lnode->type == GDA_SERVER_OPERATION_NODE_SEQUENCE_ITEM) { + gchar *str; + + g_assert (lnode->parent); + g_assert (lnode->parent->type == GDA_SERVER_OPERATION_NODE_SEQUENCE); + str = g_strdup_printf ("%d", g_slist_index (lnode->parent->d.seq.seq_items, lnode)); + g_string_prepend (string, str); + g_free (str); + } + else + g_string_prepend (string, lnode->path_name); + g_string_prepend_c (string, '/'); + } + + retval = string->str; + g_string_free (string, FALSE); + + /*g_print ("%s(%p) => %s\n", __FUNCTION__, node, retval);*/ + return retval; +} + +static GSList *load_xml_spec (GdaServerOperation *op, xmlNodePtr specnode, const gchar *root, GError **error); + +/* add a new item to @node and inserts it into @op's private structures */ +static void +sequence_add_item (GdaServerOperation *op, Node *node) +{ + gchar *path, *seq_path; + Node *new_node; + GSList *seq_item_nodes, *list; + GdaServerOperationPrivate *priv = gda_server_operation_get_instance_private (op); + + g_assert (node); + g_assert (node->type == GDA_SERVER_OPERATION_NODE_SEQUENCE); + + seq_path = node_get_complete_path (op, node); + path = g_strdup_printf ("%s/%d", seq_path, g_slist_length (node->d.seq.seq_items)); + + seq_item_nodes = load_xml_spec (op, node->d.seq.xml_spec, path, NULL); + g_assert (seq_item_nodes); + + new_node = node_new (node, GDA_SERVER_OPERATION_NODE_SEQUENCE_ITEM, NULL); + priv->allnodes = g_slist_append (priv->allnodes, new_node); + new_node->d.seq_item_nodes = NULL; + new_node->status = node->status; + node->d.seq.seq_items = g_slist_append (node->d.seq.seq_items, new_node); + + new_node->d.seq_item_nodes = seq_item_nodes; + for (list = seq_item_nodes; list; list = list->next) + ((Node*) list->data)->parent = new_node; + + clean_nodes_info_cache (op); +#ifdef GDA_DEBUG_signal + g_print (">> 'SEQUENCE_ITEM_ADDED' from %s\n", __FUNCTION__); +#endif + g_signal_emit (G_OBJECT (op), gda_server_operation_signals [SEQUENCE_ITEM_ADDED], 0, + seq_path, g_slist_length (node->d.seq.seq_items) - 1); +#ifdef GDA_DEBUG_signal + g_print ("<< 'SEQUENCE_ITEM_ADDED' from %s\n", __FUNCTION__); +#endif + + g_free (seq_path); + g_free (path); +} + +static void xml_validity_error_func (void *ctx, const char *msg, ...); +static gboolean use_xml_spec (GdaServerOperation *op, xmlDocPtr doc, const gchar *xmlfile); + +static void +gda_server_operation_set_property (GObject *object, + guint param_id, + const GValue *value, + GParamSpec *pspec) +{ + GdaServerOperation *op = GDA_SERVER_OPERATION (object); + GdaServerOperationPrivate *priv = gda_server_operation_get_instance_private (op); + + switch (param_id) { + case PROP_CNC: + if (priv->cnc) + g_object_unref (priv->cnc); + + priv->cnc = GDA_CONNECTION (g_value_get_object (value)); + priv->cnc_set = TRUE; + + if (priv->cnc) { + g_object_ref (priv->cnc); + + if (gda_connection_get_provider (priv->cnc)) { + if (priv->prov) + g_object_unref (priv->prov); + priv->prov = g_object_ref (gda_connection_get_provider (priv->cnc)); + priv->prov_set = TRUE; + } + } + break; + case PROP_PROV: + if (g_value_get_object (value)) { + if (priv->prov) + g_object_unref (priv->prov); + priv->prov = g_value_get_object(value); + g_object_ref (priv->prov); + } + priv->prov_set = TRUE; + break; + case PROP_OP_TYPE: + priv->op_type = g_value_get_int (value); + break; + case PROP_SPEC_FILE: { + xmlDocPtr doc; + const gchar *xmlfile; + + xmlfile = g_value_get_string (value); + if (!xmlfile) + return; + + if (priv->doc_hash) { + doc = g_hash_table_lookup (priv->doc_hash, xmlfile); + if (doc) { + priv->xml_spec_doc = doc; + break; + } + } + + if (! g_file_test (xmlfile, G_FILE_TEST_EXISTS)) { + g_warning (_("GdaServerOperation: could not find file '%s'"), xmlfile); + return; + } + + doc = xmlParseFile (xmlfile); + if (doc) { + if (!use_xml_spec (op, doc, xmlfile)) + return; + if (!priv->doc_hash) + priv->doc_hash = g_hash_table_new_full (g_str_hash, g_str_equal, + g_free, (GDestroyNotify) xmlFreeDoc); + g_hash_table_insert (priv->doc_hash, g_strdup (xmlfile), doc); + } + else { + g_warning (_("GdaServerOperation: could not load file '%s'"), xmlfile); + return; + } + break; + } + case PROP_SPEC_RESOURCE: { + const gchar *resource_name; + resource_name = g_value_get_string (value); + + if (! resource_name) + return; + + xmlDocPtr doc = NULL; + if (priv->doc_hash) { + doc = g_hash_table_lookup (priv->doc_hash, resource_name); + if (doc) { + priv->xml_spec_doc = doc; + break; + } + } + + GBytes *bytes = NULL; + if (resource_name) { + bytes = g_resources_lookup_data (resource_name, G_RESOURCE_LOOKUP_FLAGS_NONE, NULL); + if (!bytes) { + g_warning ("Resource %s not found", resource_name); + return; + } + } + + const gchar *xmldata; + xmldata = (const gchar*) g_bytes_get_data (bytes, NULL); + + doc = xmlParseMemory (xmldata, strlen (xmldata)); + g_bytes_unref (bytes); + if (doc) { + if (!use_xml_spec (op, doc, NULL)) + return; + if (!priv->doc_hash) + priv->doc_hash = g_hash_table_new_full (g_str_hash, g_str_equal, + g_free, (GDestroyNotify) xmlFreeDoc); + g_hash_table_insert (priv->doc_hash, g_strdup (resource_name), doc); + } + else { + g_warning (_("GdaServerOperation: could not load specified contents")); + return; + } + break; + } + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + break; + } + + if (!priv->topnodes && priv->xml_spec_doc && priv->cnc_set && priv->prov_set) { + /* load XML file */ + GError *lerror = NULL; + priv->topnodes = load_xml_spec (op, xmlDocGetRootElement (priv->xml_spec_doc), NULL, &lerror); + if (!priv->topnodes) { + g_warning (_("Could not load XML specifications: %s"), + lerror && lerror->message ? lerror->message : _("No detail")); + if (lerror) + g_error_free (lerror); + } + } +} + +static void +gda_server_operation_get_property (GObject *object, + guint param_id, + GValue *value, + GParamSpec *pspec) +{ + GdaServerOperation *op = GDA_SERVER_OPERATION (object); + GdaServerOperationPrivate *priv = gda_server_operation_get_instance_private (op); + + switch (param_id) { + case PROP_CNC: + g_value_set_object (value, priv->cnc); + break; + case PROP_PROV: + g_value_set_object (value, priv->prov); + break; + case PROP_OP_TYPE: + g_value_set_int (value, priv->op_type); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + break; + } +} + +G_DEFINE_BOXED_TYPE(GdaServerOperationNode, gda_server_operation_node, gda_server_operation_node_copy, gda_server_operation_node_free) + +GdaServerOperationNode* +gda_server_operation_node_copy (GdaServerOperationNode *src) { + GdaServerOperationNode* cp = g_new0 (GdaServerOperationNode, 1); + cp->type = src->type; + cp->status = src->status; + cp->plist = src->plist; + cp->model = src->model; + cp->column = src->column; + cp->param = src->param; + cp->priv = src->priv; + return cp; +} +void +gda_server_operation_node_free (GdaServerOperationNode *node) { + g_free (node); +} + +/* + * if %FALSE is returned, then @doc is freed, otherwise it's not stolen. + * @xmlfile may be %NULL + */ +static gboolean +use_xml_spec (GdaServerOperation *op, xmlDocPtr doc, const gchar *xmlfile) +{ + GdaServerOperationPrivate *priv = gda_server_operation_get_instance_private (op); + /* doc validation */ + xmlValidCtxtPtr validc; + int xmlcheck; + xmlDtdPtr old_dtd = NULL; + xmlDtdPtr _gda_server_op_dtd = NULL; + GFile *file; + gchar *path; + + validc = g_new0 (xmlValidCtxt, 1); + validc->userData = op; + validc->error = xml_validity_error_func; + validc->warning = NULL; + + xmlcheck = xmlDoValidityCheckingDefaultValue; + xmlDoValidityCheckingDefaultValue = 1; + + /* replace the DTD with ours */ + /* server operation DTD */ + path = gda_gbr_get_file_path (GDA_DATA_DIR, LIBGDA_ABI_NAME, "dtd", "libgda-server-operation.dtd", NULL); + file = g_file_new_for_path (path); + if (g_file_query_exists (file, NULL)) { + _gda_server_op_dtd = xmlParseDTD (NULL, (xmlChar*) path); + } + + if (!_gda_server_op_dtd) { + if (g_getenv ("GDA_TOP_SRC_DIR")) { + gchar *ipath; + + ipath = g_build_filename (g_getenv ("GDA_TOP_SRC_DIR"), "libgda", "libgda-server-operation.dtd", NULL); + _gda_server_op_dtd = xmlParseDTD (NULL, (xmlChar*) ipath); + g_free (ipath); + } + if (!_gda_server_op_dtd) + g_message (_("Could not parse '%s': " + "Validation for XML files for server operations will not be performed (some weird errors may occur)"), + path); + } + g_free (path); + g_object_unref (file); + + if (_gda_server_op_dtd) + _gda_server_op_dtd->name = xmlStrdup((xmlChar*) "serv_op"); + + if (_gda_server_op_dtd) { + old_dtd = doc->intSubset; + doc->intSubset = _gda_server_op_dtd; + } +#ifndef G_OS_WIN32 + if (doc->intSubset && !xmlValidateDocument (validc, doc)) { + gchar *str; + + if (_gda_server_op_dtd) + doc->intSubset = old_dtd; + xmlFreeDoc (doc); + g_free (validc); + str = g_object_get_data (G_OBJECT (op), "xmlerror"); + if (str) { + if (xmlfile) + g_warning (_("GdaServerOperation: file '%s' does not conform to DTD:\n%s"), + xmlfile, str); + else + g_warning (_("GdaServerOperation specification does not conform to DTD:\n%s"), + str); + g_free (str); + g_object_set_data (G_OBJECT (op), "xmlerror", NULL); + } + else { + if (xmlfile) + g_warning (_("GdaServerOperation: file '%s' does not conform to DTD"), + xmlfile); + else + g_warning (_("GdaServerOperation specification does not conform to DTD\n")); + } + + xmlDoValidityCheckingDefaultValue = xmlcheck; + return FALSE; + } +#endif + + xmlDoValidityCheckingDefaultValue = xmlcheck; + g_free (validc); + if (_gda_server_op_dtd) { + doc->intSubset = old_dtd; + xmlFreeDtd (_gda_server_op_dtd); + } + priv->xml_spec_doc = doc; + + return TRUE; +} + + +/* + * function called when an error occurred during the document validation + */ +static void +xml_validity_error_func (void *ctx, const char *msg, ...) +{ + GdaServerOperation *op = GDA_SERVER_OPERATION (ctx); + va_list args; + gchar *str, *str2, *newerr; + + str2 = g_object_get_data (G_OBJECT (op), "xmlerror"); + + va_start (args, msg); + str = g_strdup_vprintf (msg, args); + va_end (args); + + if (str2) { + newerr = g_strdup_printf ("%s\n%s", str2, str); + g_free (str2); + } + else + newerr = g_strdup (str); + g_free (str); + g_object_set_data (G_OBJECT (op), "xmlerror", newerr); +} + +/* + * Warning: the new nodes' parent is not set! + */ +static GSList * +load_xml_spec (GdaServerOperation *op, xmlNodePtr specnode, const gchar *root, GError **error) +{ + GdaServerOperationPrivate *priv = gda_server_operation_get_instance_private (op); + xmlNodePtr node; + const gchar *lang = setlocale(LC_ALL, NULL); + GSList *retlist = NULL; + Node *parent = NULL; + + if (root) + parent = node_find (op, root); + + g_assert (specnode); + + /* Parameters' sources, not mandatory: makes the priv->sources list */ + if (!priv->sources) { + GSList *sources = NULL; + + node = specnode->children; + while (node && (xmlNodeIsText (node) || strcmp ((gchar*)node->name, "sources"))) + node = node->next; + if (node && !strcmp ((gchar*)node->name, "sources")) { + for (node = node->xmlChildrenNode; (node != NULL); node = node->next) { + if (xmlNodeIsText (node)) + continue; + + if (!strcmp ((gchar*)node->name, "gda_array")) { + GdaDataModel *model; + GSList *errors; + + model = gda_data_model_import_new_xml_node (node); + errors = gda_data_model_import_get_errors (GDA_DATA_MODEL_IMPORT (model)); + if (errors) { + g_object_unref (model); + if (sources) { + g_slist_free_full (sources, (GDestroyNotify) g_object_unref); + return NULL; + } + } + else { + xmlChar *str; + sources = g_slist_prepend (sources, model); + str = xmlGetProp (node, (xmlChar*)"name"); + if (str) + g_object_set_data_full (G_OBJECT (model), "name", (gchar*)str, xmlFree); + } + } + } + } + priv->sources = sources; + } + + /* actual objects loading */ + node = specnode->children; + while (node) { + xmlChar *id, *this_lang; + gchar *complete_path = NULL, *path_name = NULL; + Node *opnode = NULL; + Node *old_opnode; + + if (xmlNodeIsText (node)) { + xmlNodePtr nextnode; + nextnode = node->next; + xmlUnlinkNode (node); + xmlFreeNode (node); + node = nextnode; + continue; + } + + /* don't care about entries for the wrong locale */ + this_lang = xmlGetProp(node, (xmlChar*)"lang"); + if (this_lang) { + if (strncmp ((gchar*)this_lang, lang, strlen ((gchar*)this_lang))) { + xmlNodePtr nextnode; + xmlFree (this_lang); + nextnode = node->next; + xmlUnlinkNode (node); + xmlFreeNode (node); + node = nextnode; + continue; + } + + xmlFree (this_lang); + } + + id = xmlGetProp (node, BAD_CAST "id"); + if (!id) { + node = node->next; + continue; + } + + complete_path = g_strdup_printf ("%s/%s", root ? root : "", id); + path_name = g_strdup ((gchar*)id); + xmlFree (id); + + old_opnode = node_find (op, complete_path); + if (old_opnode) { + node_destroy (op, old_opnode); + retlist = g_slist_remove (retlist, old_opnode); + } + + /* GDA_SERVER_OPERATION_NODE_PARAMLIST */ + if (!strcmp ((gchar*)node->name, "parameters")) { + GdaSet *plist; + + plist = gda_set_new_from_spec_node (node, error); + if (plist) { + opnode = node_new (parent, GDA_SERVER_OPERATION_NODE_PARAMLIST, path_name); + opnode->d.plist = plist; + } + } + /* GDA_SERVER_OPERATION_NODE_DATA_MODEL */ + else if (!strcmp ((gchar*)node->name, "gda_array")) { + GdaDataModel *import; + + import = gda_data_model_import_new_xml_node (node); + if (import) { + GdaDataModel *model; + model = (GdaDataModel*) gda_data_model_array_copy_model (import, NULL); + opnode = node_new (parent, GDA_SERVER_OPERATION_NODE_DATA_MODEL, path_name); + opnode->d.model = model; + g_object_unref (import); + } + } + + /* GDA_SERVER_OPERATION_NODE_SEQUENCE */ + else if (!strcmp ((gchar*)node->name, "sequence")) { + GSList *seq_tmpl = NULL; + xmlChar *prop; + + opnode = node_new (parent, GDA_SERVER_OPERATION_NODE_SEQUENCE, path_name); + opnode->d.seq.seq_tmpl = NULL; + opnode->d.seq.min_items = 0; + opnode->d.seq.max_items = G_MAXUINT; + opnode->d.seq.seq_items = NULL; + opnode->d.seq.xml_spec = node; + + prop = xmlGetProp(node, (xmlChar*)"name"); + if (prop) { + opnode->d.seq.name = g_strdup ((gchar*)prop); + xmlFree (prop); + } + + prop = xmlGetProp(node, (xmlChar*)"descr"); + if (prop) { + opnode->d.seq.descr = g_strdup ((gchar*)prop); + xmlFree (prop); + } + + + prop = xmlGetProp(node, (xmlChar*)"minitems"); + if (prop) { + gint tmp; + tmp = atoi ((gchar*)prop); /* Flawfinder: ignore */ + if (tmp < 0) + opnode->d.seq.min_items = 0; + else + opnode->d.seq.min_items = tmp; + xmlFree (prop); + } + + prop = xmlGetProp(node, (xmlChar*)"maxitems"); + if (prop) { + opnode->d.seq.max_items = atoi ((gchar*)prop); /* Flawfinder: ignore */ + if (opnode->d.seq.max_items < opnode->d.seq.min_items) + opnode->d.seq.max_items = opnode->d.seq.min_items; + xmlFree (prop); + } + + seq_tmpl = load_xml_spec (op, node, complete_path, error); + if (! seq_tmpl) { + node_destroy (NULL, opnode); + opnode = NULL; + } + else + opnode->d.seq.seq_tmpl = seq_tmpl; + } + + /* GDA_SERVER_OPERATION_NODE_PARAM */ + else if (!strcmp ((gchar*)node->name, "parameter")) { + GdaHolder *param = NULL; + xmlChar *gdatype; + GType gt; + + /* find data type and create GdaHolder */ + gdatype = xmlGetProp (node, BAD_CAST "gdatype"); + gt = gdatype ? gda_g_type_from_string ((gchar*) gdatype) : G_TYPE_STRING; + if (gt == G_TYPE_INVALID) + gt = GDA_TYPE_NULL; + param = GDA_HOLDER (g_object_new (GDA_TYPE_HOLDER, + "g-type", gt, + NULL)); + if (gdatype) + xmlFree (gdatype); + + /* set parameter's attributes */ + if (gda_utility_holder_load_attributes (param, node, priv->sources, error)) { + opnode = node_new (parent, GDA_SERVER_OPERATION_NODE_PARAM, path_name); + opnode->d.param = param; + } + } + else { + node = node->next; + g_free (path_name); + continue; + } + + /* really insert the new Node, and set its status */ + if (opnode) { + xmlChar *status; + + /* insert */ + priv->allnodes = g_slist_append (priv->allnodes, opnode); + retlist = g_slist_append (retlist, opnode); + /*g_print ("+ %s (node's path = %s) %p\n", complete_path, opnode->path_name, opnode);*/ + + /* status */ + status = xmlGetProp (node, BAD_CAST "status"); + if (status) { + if (!strcmp ((gchar*)status, "OPT")) + opnode->status = GDA_SERVER_OPERATION_STATUS_OPTIONAL; + xmlFree (status); + } + + if (opnode->type == GDA_SERVER_OPERATION_NODE_SEQUENCE) { + /* add sequence items if necessary */ + if (opnode->d.seq.min_items > 0) { + guint i; + + for (i = 0; i < opnode->d.seq.min_items; i++) + gda_server_operation_add_item_to_sequence (op, complete_path); + } + } + } + else { + g_free (path_name); + g_free (complete_path); + g_slist_free (retlist); + return NULL; + } + g_free (path_name); + g_free (complete_path); + node = node->next; + } + + return retlist; +} + +/* + * @xml_spec: the specifications for the GdaServerOperation object to create as a string + * Internal function + */ +GdaServerOperation * +_gda_server_operation_new_from_string (GdaServerOperationType op_type, + const gchar *xml_spec) +{ + GObject *obj; + xmlDocPtr doc; + GdaServerOperation *op; + GdaServerOperationPrivate *priv; + + doc = xmlParseMemory (xml_spec, strlen (xml_spec) + 1); + if (!doc) + return NULL; + obj = g_object_new (GDA_TYPE_SERVER_OPERATION, "op-type", op_type, NULL); + op = GDA_SERVER_OPERATION (obj); + if (use_xml_spec (op, doc, NULL)) + xmlFreeDoc (doc); + + priv = gda_server_operation_get_instance_private (op); + if (!priv->topnodes && priv->xml_spec_doc && priv->cnc_set && priv->prov_set) { + /* load XML file */ + GError *lerror = NULL; + priv->topnodes = load_xml_spec (op, xmlDocGetRootElement (priv->xml_spec_doc), NULL, &lerror); + if (!priv->topnodes) { + g_warning (_("Could not load XML specifications: %s"), + lerror && lerror->message ? lerror->message : _("No detail")); + if (lerror) + g_error_free (lerror); + } + } + + return op; +} + + +/** + * gda_server_operation_new: + * @op_type: type of operation + * @xml_file: a file which has the specifications for the GdaServerOperation object to create + * + * IMPORTANT NOTE: Using this funtion is not the recommended way of creating a #GdaServerOperation object, the + * correct way is to use gda_server_provider_create_operation(); this method is reserved for the database provider's + * implementation. + * + * Creates a new #GdaServerOperation object from the @xml_file specifications + * + * The @xml_file must respect the DTD described in the "libgda-server-operation.dtd" file: its top + * node must be a <serv_op> tag. + * + * Returns: a new #GdaServerOperation object + */ +GdaServerOperation * +gda_server_operation_new (GdaServerOperationType op_type, const gchar *xml_file) +{ + GObject *obj; + + obj = g_object_new (GDA_TYPE_SERVER_OPERATION, "op-type", op_type, + "spec-filename", xml_file, NULL); +#ifdef GDA_DEBUG_NO + { + g_print ("New GdaServerOperation:\n"); + xmlNodePtr node; + node = gda_server_operation_save_data_to_xml ((GdaServerOperation *) obj, NULL); + xmlDocPtr doc; + doc = xmlNewDoc ("1.0"); + xmlDocSetRootElement (doc, node); + xmlDocDump (stdout, doc); + xmlFreeDoc (doc); + } +#endif + return (GdaServerOperation *) obj; +} + +/** + * gda_server_operation_get_node_info: + * @op: a #GdaServerOperation object + * @path_format: a complete path to a node (starting with "/") as a format string, similar to g_strdup_printf()'s argument + * @...: the arguments to insert into the format string + * + * Get information about the node identified by @path. The returned #GdaServerOperationNode structure can be + * copied but not modified; it may change or cease to exist if @op changes + * + * Returns: (transfer none) (nullable): a #GdaServerOperationNode structure, or %NULL if the node was not found + */ +GdaServerOperationNode * +gda_server_operation_get_node_info (GdaServerOperation *op, const gchar *path_format, ...) +{ + GdaServerOperationPrivate *priv = gda_server_operation_get_instance_private (op); + GdaServerOperationNode *info_node; + Node *node; + gchar *path; + va_list args; + + g_return_val_if_fail (GDA_IS_SERVER_OPERATION (op), NULL); + + /* build path */ + va_start (args, path_format); + path = g_strdup_vprintf (path_format, args); + va_end (args); + + /* use path */ + if (priv->info_hash == NULL) { + priv->info_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); + } + info_node = g_hash_table_lookup (priv->info_hash, path); + if (info_node) { + g_free (path); + return info_node; + } + + /* compute a new GdaServerOperationNode */ + node = node_find (op, path); + if (node) { + info_node = g_new0 (GdaServerOperationNode, 1); + info_node->priv = node; + info_node->type = node->type; + info_node->status = node->status; + switch (node->type) { + case GDA_SERVER_OPERATION_NODE_PARAMLIST: + info_node->plist = node->d.plist; + break; + case GDA_SERVER_OPERATION_NODE_DATA_MODEL: + info_node->model = node->d.model; + break; + case GDA_SERVER_OPERATION_NODE_PARAM: + info_node->param = node->d.param; + break; + default: + break; + } + } + else { + /* try to see if the "parent" is a real node */ + gchar *str; + gchar *extension; + + str = gda_server_operation_get_node_parent (op, path); + if (str) { + node = node_find (op, str); + if (node && (node->type != GDA_SERVER_OPERATION_NODE_PARAMLIST) && + (node->type != GDA_SERVER_OPERATION_NODE_DATA_MODEL)) + node = NULL; /* ignore node */ + g_free (str); + } + if (node && (node->type == GDA_SERVER_OPERATION_NODE_PARAMLIST)) { + GdaHolder *param; + extension = gda_server_operation_get_node_path_portion (op, path); + param = gda_set_get_holder (node->d.plist, extension); + g_free (extension); + + if (param) { + info_node = g_new0 (GdaServerOperationNode, 1); + info_node->type = GDA_SERVER_OPERATION_NODE_PARAM; + info_node->status = node->status; + info_node->param = param; + } + } + if (node && (node->type == GDA_SERVER_OPERATION_NODE_DATA_MODEL)) { + GdaColumn *column = NULL; + + extension = gda_server_operation_get_node_path_portion (op, path); + if (extension && (*extension == '@')) { + gint i, nbcols; + GdaDataModel *model; + + model = node->d.model; + nbcols = gda_data_model_get_n_columns (model); + for (i = 0; (itype = GDA_SERVER_OPERATION_NODE_DATA_MODEL_COLUMN; + info_node->status = node->status; + info_node->column = column; + info_node->model = node->d.model; + } + } + } + + if (info_node) + g_hash_table_insert (priv->info_hash, g_strdup (path), info_node); + + g_free (path); + return info_node; +} + +/** + * gda_server_operation_get_op_type: + * @op: a #GdaServerOperation object + * + * Get the type of operation @op is for + * + * Returns: a #GdaServerOperationType enum + */ +GdaServerOperationType +gda_server_operation_get_op_type (GdaServerOperation *op) +{ + GdaServerOperationPrivate *priv = gda_server_operation_get_instance_private (op); + + g_return_val_if_fail (GDA_IS_SERVER_OPERATION (op), 0); + + return priv->op_type; +} + +/** + * gda_server_operation_op_type_to_string: + * @type: a #GdaServerOperationType value + * + * Get a string version of @type + * + * Returns: (transfer none): a non %NULL string (do not free or modify) + */ +const gchar * +gda_server_operation_op_type_to_string (GdaServerOperationType type) +{ + switch (type) { + case GDA_SERVER_OPERATION_CREATE_DB: + return "CREATE_DB"; + case GDA_SERVER_OPERATION_DROP_DB: + return "DROP_DB"; + case GDA_SERVER_OPERATION_CREATE_TABLE: + return "CREATE_TABLE"; + case GDA_SERVER_OPERATION_DROP_TABLE: + return "DROP_TABLE"; + case GDA_SERVER_OPERATION_CREATE_INDEX: + return "CREATE_INDEX"; + case GDA_SERVER_OPERATION_DROP_INDEX: + return "DROP_INDEX"; + case GDA_SERVER_OPERATION_RENAME_INDEX: + return "RENAME_INDEX"; + case GDA_SERVER_OPERATION_RENAME_TABLE: + return "RENAME_TABLE"; + case GDA_SERVER_OPERATION_COMMENT_TABLE: + return "COMMENT_TABLE"; + case GDA_SERVER_OPERATION_ADD_COLUMN: + return "ADD_COLUMN"; + case GDA_SERVER_OPERATION_DROP_COLUMN: + return "DROP_COLUMN"; + case GDA_SERVER_OPERATION_RENAME_COLUMN: + return "RENAME_COLUMN"; + case GDA_SERVER_OPERATION_COMMENT_COLUMN: + return "COMMENT_COLUMN"; + case GDA_SERVER_OPERATION_CREATE_VIEW: + return "CREATE_VIEW"; + case GDA_SERVER_OPERATION_DROP_VIEW: + return "DROP_VIEW"; + case GDA_SERVER_OPERATION_CREATE_USER: + return "CREATE_USER"; + case GDA_SERVER_OPERATION_DROP_USER: + return "DROP_USER"; + case GDA_SERVER_OPERATION_ALTER_USER: + return "ALTER_USER"; + default: + g_error (_("Non handled GdaServerOperationType, please report error to " + "http://gitlab.gnome.org/GNOME/libgda/issues")); + return ""; + } +} + +/** + * gda_server_operation_string_to_op_type: + * @str: a string + * + * Performs the reverse of gda_server_operation_op_type_to_string() + * + * Returns: the #GdaServerOperationType represented by @str, or #G_MAXINT if @str is not a valid representation + * of a #GdaServerOperationType + * + * Since: 4.2 + */ +GdaServerOperationType +gda_server_operation_string_to_op_type (const gchar *str) +{ + GdaServerOperationType operation_type = G_MAXINT; + g_return_val_if_fail (str && *str, G_MAXINT); + + if (! g_ascii_strcasecmp (str, "CREATE_DB")) + operation_type = GDA_SERVER_OPERATION_CREATE_DB; + else if (! g_ascii_strcasecmp (str, "DROP_DB")) + operation_type = GDA_SERVER_OPERATION_DROP_DB; + else if (! g_ascii_strcasecmp (str, "CREATE_TABLE")) + operation_type = GDA_SERVER_OPERATION_CREATE_TABLE; + else if (! g_ascii_strcasecmp (str, "DROP_TABLE")) + operation_type = GDA_SERVER_OPERATION_DROP_TABLE; + else if (! g_ascii_strcasecmp (str, "CREATE_INDEX")) + operation_type = GDA_SERVER_OPERATION_CREATE_INDEX; + else if (! g_ascii_strcasecmp (str, "DROP_INDEX")) + operation_type = GDA_SERVER_OPERATION_DROP_INDEX; + else if (! g_ascii_strcasecmp (str, "RENAME_TABLE")) + operation_type = GDA_SERVER_OPERATION_RENAME_TABLE; + else if (! g_ascii_strcasecmp (str, "RENAME_INDEX")) + operation_type = GDA_SERVER_OPERATION_RENAME_INDEX; + else if (! g_ascii_strcasecmp (str, "COMMENT_TABLE")) + operation_type = GDA_SERVER_OPERATION_COMMENT_TABLE; + else if (! g_ascii_strcasecmp (str, "ADD_COLUMN")) + operation_type = GDA_SERVER_OPERATION_ADD_COLUMN; + else if (! g_ascii_strcasecmp (str, "DROP_COLUMN")) + operation_type = GDA_SERVER_OPERATION_DROP_COLUMN; + else if (! g_ascii_strcasecmp (str, "COMMENT_COLUMN")) + operation_type = GDA_SERVER_OPERATION_COMMENT_COLUMN; + else if (! g_ascii_strcasecmp (str, "CREATE_VIEW")) + operation_type = GDA_SERVER_OPERATION_CREATE_VIEW; + else if (! g_ascii_strcasecmp (str, "DROP_VIEW")) + operation_type = GDA_SERVER_OPERATION_DROP_VIEW; + else if (! g_ascii_strcasecmp (str, "CREATE_USER")) + operation_type = GDA_SERVER_OPERATION_CREATE_USER; + else if (! g_ascii_strcasecmp (str, "DROP_USER")) + operation_type = GDA_SERVER_OPERATION_DROP_USER; + else if (! g_ascii_strcasecmp (str, "ALTER_USER")) + operation_type = GDA_SERVER_OPERATION_ALTER_USER; + + return operation_type; +} + +static gboolean node_save (GdaServerOperation *op, Node *opnode, xmlNodePtr parent); + +/** + * gda_server_operation_save_data_to_xml: (skip) + * @op: a #GdaServerOperation object + * @error: (nullable): a place to store errors or %NULL + * + * Creates a new #xmlNodePtr tree which can be used to save the #op object. This + * XML structure can then be saved to disk if necessary. Use xmlFreeNode to free + * the associated memory when not needed anymore. + * + * Returns: (transfer full): a new #xmlNodePtr structure, or %NULL + */ +xmlNodePtr +gda_server_operation_save_data_to_xml (GdaServerOperation *op, G_GNUC_UNUSED GError **error) +{ + GdaServerOperationPrivate *priv = gda_server_operation_get_instance_private (op); + xmlNodePtr topnode = NULL; + GSList *list; + + g_return_val_if_fail (GDA_IS_SERVER_OPERATION (op), NULL); + + topnode = xmlNewNode (NULL, BAD_CAST "serv_op_data"); + xmlSetProp (topnode, BAD_CAST "type", + BAD_CAST gda_server_operation_op_type_to_string (gda_server_operation_get_op_type (op))); + + for (list = priv->topnodes; list; list = list->next) { + if (!node_save (op, NODE (list->data), topnode)) { + xmlFreeNode (topnode); + topnode = NULL; + break; + } + } + + return topnode; +} + +/** + * gda_server_operation_save_data_to_xml_string: + * @op: a #GdaServerOperation object + * @error: (nullable): a place to store errors or %NULL + * + * Returns: (transfer full): an XML string representation of #GdaServerOperation + * + */ +gchar* +gda_server_operation_save_data_to_xml_string (GdaServerOperation *op, G_GNUC_UNUSED GError **error) { + g_return_val_if_fail (op != NULL, NULL); + + xmlNodePtr node; + xmlBufferPtr buff; + gchar *str = NULL; + + node = gda_server_operation_save_data_to_xml (op, error); + if (node == NULL) { + return NULL; + } + buff = xmlBufferCreate (); + xmlNodeDump (buff, node->doc, node, 0, 0); + str = g_strdup ((gchar*) buff->content); + xmlBufferFree (buff); + xmlFreeNode (node); + return str; +} + +static gboolean +node_save (GdaServerOperation *op, Node *opnode, xmlNodePtr parent) +{ + gboolean retval = TRUE; + xmlNodePtr node; + GSList *list; + gchar *complete_path; + g_assert (opnode); + + complete_path = node_get_complete_path (op, opnode); + switch (opnode->type) { + case GDA_SERVER_OPERATION_NODE_PARAMLIST: + for (list = gda_set_get_holders (opnode->d.plist); list; list = list->next) { + gchar *path; + const GValue *value; + gchar *str; + + value = gda_holder_get_value (GDA_HOLDER (list->data)); + if (!value || gda_value_is_null ((GValue *) value)) + str = NULL; + else { + if (G_VALUE_TYPE (value) == G_TYPE_BOOLEAN) + str = g_strdup (g_value_get_boolean (value) ? "TRUE" : "FALSE"); + else + str = gda_value_stringify (value); + } + node = xmlNewTextChild (parent, NULL, BAD_CAST "op_data", (xmlChar*)str); + g_free (str); + + path = g_strdup_printf ("%s/%s", complete_path, gda_holder_get_id (GDA_HOLDER (list->data))); + xmlSetProp(node, (xmlChar*)"path", (xmlChar*)path); + g_free (path); + } + break; + case GDA_SERVER_OPERATION_NODE_DATA_MODEL: + node = xmlNewChild (parent, NULL, BAD_CAST "op_data", NULL); + xmlSetProp(node, (xmlChar*)"path", (xmlChar*)complete_path); + if (!gda_utility_data_model_dump_data_to_xml (opnode->d.model, node, NULL, 0, NULL, 0, TRUE)) + retval = FALSE; + break; + case GDA_SERVER_OPERATION_NODE_PARAM: { + const GValue *value; + gchar *str; + + value = gda_holder_get_value (opnode->d.param); + if (!value || gda_value_is_null ((GValue *) value)) + str = NULL; + else { + if (G_VALUE_TYPE (value) == G_TYPE_BOOLEAN) + str = g_strdup (g_value_get_boolean (value) ? "TRUE" : "FALSE"); + else + str = gda_value_stringify (value); + } + node = xmlNewTextChild (parent, NULL, BAD_CAST "op_data", (xmlChar*)str); + g_free (str); + xmlSetProp(node, (xmlChar*)"path", (xmlChar*)complete_path); + break; + } + case GDA_SERVER_OPERATION_NODE_SEQUENCE: { + GSList *list; + + for (list = opnode->d.seq.seq_items; list; list = list->next) + if (!node_save (op, NODE (list->data), parent)) { + retval = FALSE; + break; + } + break; + } + case GDA_SERVER_OPERATION_NODE_SEQUENCE_ITEM: { + GSList *list; + + for (list = opnode->d.seq_item_nodes; list; list = list->next) + if (! node_save (op, NODE (list->data), parent)) { + retval = FALSE; + break; + } + break; + } + default: + g_assert_not_reached (); + } + + g_free (complete_path); + return retval; +} + +/** + * gda_server_operation_load_data_from_xml: + * @op: a #GdaServerOperation object + * @node: a #xmlNodePtr + * @error: (nullable): a place to store errors or %NULL + * + * Loads the contents of @node into @op. The XML tree passed through the @node + * argument must correspond to an XML tree saved using gda_server_operation_save_data_to_xml(). + * + * Returns: %TRUE if no error occurred + */ +gboolean +gda_server_operation_load_data_from_xml (GdaServerOperation *op, xmlNodePtr node, GError **error) +{ + GdaServerOperationPrivate *priv = gda_server_operation_get_instance_private (op); + xmlNodePtr cur; + + g_return_val_if_fail (GDA_IS_SERVER_OPERATION (op), FALSE); + if (!node) + return FALSE; + + /* remove any sequence items */ + GSList *list; + list = priv->allnodes; + while (list) { + Node *node = NODE (list->data); + if ((node->type == GDA_SERVER_OPERATION_NODE_SEQUENCE) && node->d.seq.seq_items) { + gchar *seq_path; + + seq_path = node_get_complete_path (op, node); + while (node->d.seq.seq_items) { +#ifdef GDA_DEBUG_signal + g_print (">> 'SEQUENCE_ITEM_REMOVE' from %s\n", __FUNCTION__); +#endif + g_signal_emit (G_OBJECT (op), gda_server_operation_signals [SEQUENCE_ITEM_REMOVE], 0, + seq_path, 0); +#ifdef GDA_DEBUG_signal + g_print ("<< 'SEQUENCE_ITEM_REMOVE' from %s\n", __FUNCTION__); +#endif + node_destroy (op, NODE (node->d.seq.seq_items->data)); + node->d.seq.seq_items = g_slist_delete_link (node->d.seq.seq_items, node->d.seq.seq_items); + } + g_free (seq_path); + list = priv->allnodes; + } + else + list = list->next; + } + + /* actual data loading */ + if (strcmp ((gchar*)node->name, "serv_op_data")) { + g_set_error (error, GDA_SERVER_OPERATION_ERROR, + GDA_SERVER_OPERATION_XML_ERROR, + _("Expected tag <%s>, got <%s>"), "serv_op_data", node->name); + return FALSE; + } + + cur = node->children; + while (cur) { + xmlChar *prop; + if (xmlNodeIsText (cur)) { + cur = cur->next; + continue; + } + + if (strcmp ((gchar*)cur->name, "op_data")) { + g_set_error (error, GDA_SERVER_OPERATION_ERROR, + GDA_SERVER_OPERATION_XML_ERROR, + _("Expected tag <%s>, got <%s>"), "op_data", cur->name); + return FALSE; + } + + prop = xmlGetProp(cur, (xmlChar*)"path"); + if (prop) { + Node *opnode; + gchar *extension = NULL; + gboolean allok = TRUE; + + opnode = node_find_or_create (op, (gchar*)prop); + if (!opnode) { + /* try to see if the "parent" is a real node */ + gchar *str; + + str = gda_server_operation_get_node_parent (op, (gchar*)prop); + if (str) { + opnode = node_find (op, str); + if (opnode && (opnode->type != GDA_SERVER_OPERATION_NODE_PARAMLIST)) + opnode = NULL; /* ignore opnode */ + g_free (str); + } + if (opnode) + extension = gda_server_operation_get_node_path_portion (op, (gchar*)prop); + } + + if (opnode) { + switch (opnode->type) { + case GDA_SERVER_OPERATION_NODE_PARAMLIST: + if (!extension) { + g_set_error (error, + GDA_SERVER_OPERATION_ERROR, + GDA_SERVER_OPERATION_XML_ERROR, + "%s", + _("Parameterlist values can only be set for individual parameters within it")); + allok = FALSE; + } + else { + xmlNodePtr contents; + + contents = cur->children; + if (contents && xmlNodeIsText (contents)) { + GdaHolder *param; + param = gda_set_get_holder (opnode->d.plist, extension); + if (param) { + GValue *v; + v = gda_value_new_from_string ((gchar*)contents->content, + gda_holder_get_g_type (param)); + if (!gda_holder_take_value (param, v, error)) + allok = FALSE; + } + } + } + break; + case GDA_SERVER_OPERATION_NODE_DATA_MODEL: + gda_data_model_array_clear (GDA_DATA_MODEL_ARRAY (opnode->d.model)); + if (cur->children && + ! gda_data_model_add_data_from_xml_node (opnode->d.model, + cur->children, error)) + allok = FALSE; + break; + case GDA_SERVER_OPERATION_NODE_PARAM: { + xmlNodePtr contents; + + contents = cur->children; + if (contents && xmlNodeIsText (contents)) { + GValue *v; + v = gda_value_new_from_string ((gchar*)contents->content, + gda_holder_get_g_type (opnode->d.param)); + if (!gda_holder_take_value (opnode->d.param, v, error)) + allok = FALSE; + } + break; + } + case GDA_SERVER_OPERATION_NODE_SEQUENCE: + break; + case GDA_SERVER_OPERATION_NODE_SEQUENCE_ITEM: + break; + default: + g_assert_not_reached (); + } + } + + g_free (extension); + xmlFree (prop); + + if (!allok) + return FALSE; + } + else { + g_set_error (error, GDA_SERVER_OPERATION_ERROR, + GDA_SERVER_OPERATION_XML_ERROR, + "%s", _("Missing attribute named 'path'")); + return FALSE; + } + + cur = cur->next; + } + + return TRUE; +} + +/** + * gda_server_operation_get_root_nodes: + * @op: a #GdaServerOperation object + * + * Get an array of strings containing the paths of nodes situated at the root of @op. + * + * Returns: (transfer full): a new array, which must be freed with g_strfreev(). + */ +gchar** +gda_server_operation_get_root_nodes (GdaServerOperation *op) +{ + GdaServerOperationPrivate *priv = gda_server_operation_get_instance_private (op); + gchar **retval; + GSList *list; + gint i = 0; + + g_return_val_if_fail (GDA_IS_SERVER_OPERATION (op), NULL); + + retval = g_new0 (gchar *, g_slist_length (priv->topnodes) + 1); + for (list = priv->topnodes; list; list = list->next) + retval [i++] = node_get_complete_path (op, NODE (list->data)); + + return retval; +} + +/** + * gda_server_operation_get_node_type: + * @op: a #GdaServerOperation object + * @path: a complete path to a node (starting with "/") + * @status: (nullable): a place to store the status of the node, or %NULL + * + * Convenience function to get the type of a node. + * + * Returns: the type of node, or GDA_SERVER_OPERATION_NODE_UNKNOWN if the node was not found + */ +GdaServerOperationNodeType +gda_server_operation_get_node_type (GdaServerOperation *op, const gchar *path, + GdaServerOperationNodeStatus *status) +{ + GdaServerOperationNode *node_info; + + g_return_val_if_fail (GDA_IS_SERVER_OPERATION (op), GDA_SERVER_OPERATION_NODE_UNKNOWN); + + node_info = gda_server_operation_get_node_info (op, path); + if (node_info) { + if (status) + *status = node_info->status; + return node_info->type; + } + return GDA_SERVER_OPERATION_NODE_UNKNOWN; +} + +/** + * gda_server_operation_get_node_parent: + * @op: a #GdaServerOperation object + * @path: a complete path to a node (starting with "/") + * + * Get the complete path to the parent of the node defined by @path + * + * Returns: (transfer full): a new string or %NULL if the node does not have any parent or does not exist. + */ +gchar * +gda_server_operation_get_node_parent (GdaServerOperation *op, const gchar *path) +{ + Node *node; + + g_return_val_if_fail (GDA_IS_SERVER_OPERATION (op), NULL); + g_return_val_if_fail (path && (*path == '/'), NULL); + + node = node_find (op, path); + + if (node) { + if (! node->parent) + return NULL; + else + return node_get_complete_path (op, node->parent); + } + else { + gchar *path2 = g_strdup (path); + gchar *ptr; + + ptr = path2 + strlen (path2) - 1; + while (*ptr != '/') { + *ptr = 0; + ptr --; + } + *ptr = 0; + + return path2; + } +} + +/** + * gda_server_operation_get_node_path_portion: + * @op: a #GdaServerOperation object + * @path: a complete path to a node (starting with "/") + * + * Get the last part of @path + * + * Returns: (transfer full): a new string, or %NULL if an error occurred + */ +gchar * +gda_server_operation_get_node_path_portion (GdaServerOperation *op, const gchar *path) +{ + Node *node; + + g_return_val_if_fail (GDA_IS_SERVER_OPERATION (op), NULL); + g_return_val_if_fail (path && (*path == '/'), NULL); + + node = node_find (op, path); + if (!node) { + gchar *path2 = g_strdup (path); + gchar *ptr, *retval = NULL; + + ptr = path2 + strlen (path2) - 1; + while (*ptr != '/') + ptr --; + retval = g_strdup (ptr + 1); + g_free (path2); + return retval; + } + else { + if (node->type == GDA_SERVER_OPERATION_NODE_SEQUENCE_ITEM) { + g_assert (node->parent); + g_assert (node->parent->type == GDA_SERVER_OPERATION_NODE_SEQUENCE); + return g_strdup_printf ("%d", g_slist_index (node->parent->d.seq.seq_items, node)); + } + else + return g_strdup (node->path_name); + } +} + +/** + * gda_server_operation_get_sequence_item_names: + * @op: a #GdaServerOperation object + * @path: a complete path to a sequence node (starting with "/") + * + * Fetch the contents of a sequence. @path can describe either a sequence (for example "/SEQNAME") or an item in a sequence + * (for example "/SEQNAME/3") + * + * Returns: (transfer full): a array of strings containing the complete paths of the nodes contained at @path (free with g_strfreev()) + */ +gchar ** +gda_server_operation_get_sequence_item_names (GdaServerOperation *op, const gchar *path) +{ + Node *node; + gchar **retval; + gint i; + GSList *list; + + g_return_val_if_fail (GDA_IS_SERVER_OPERATION (op), NULL); + + node = node_find (op, path); + if (!node || ((node->type != GDA_SERVER_OPERATION_NODE_SEQUENCE) && + (node->type != GDA_SERVER_OPERATION_NODE_SEQUENCE_ITEM))) + return NULL; + + if (node->type == GDA_SERVER_OPERATION_NODE_SEQUENCE) + list = node->d.seq.seq_tmpl; + else + list = node->d.seq_item_nodes; + i = 0; + retval = g_new0 (gchar *, g_slist_length (list) + 1); + for (; list; list = list->next, i++) + retval [i] = node_get_complete_path (op, NODE (list->data)); + + return retval; +} + +/** + * gda_server_operation_get_sequence_name: + * @op: a #GdaServerOperation object + * @path: a complete path to a sequence node (starting with "/") + * + * Returns: (transfer none): the name of the sequence at @path + */ +const gchar * +gda_server_operation_get_sequence_name (GdaServerOperation *op, const gchar *path) +{ + Node *node; + + g_return_val_if_fail (GDA_IS_SERVER_OPERATION (op), NULL); + + node = node_find (op, path); + if (!node || (node->type != GDA_SERVER_OPERATION_NODE_SEQUENCE)) + return NULL; + + return node->d.seq.name; +} + +/** + * gda_server_operation_get_sequence_size: + * @op: a #GdaServerOperation object + * @path: a complete path to a sequence node (starting with "/") + * + * Returns: the number of items in the sequence at @path, or 0 if @path is not a sequence node + */ +guint +gda_server_operation_get_sequence_size (GdaServerOperation *op, const gchar *path) +{ + Node *node; + + g_return_val_if_fail (GDA_IS_SERVER_OPERATION (op), 0); + + node = node_find (op, path); + if (!node || (node->type != GDA_SERVER_OPERATION_NODE_SEQUENCE)) + return 0; + + return g_slist_length (node->d.seq.seq_items); +} + +/** + * gda_server_operation_get_sequence_max_size: + * @op: a #GdaServerOperation object + * @path: a complete path to a sequence node (starting with "/") + * + * Returns: the maximum number of items in the sequence at @path, or 0 if @path is not a sequence node + */ +guint +gda_server_operation_get_sequence_max_size (GdaServerOperation *op, const gchar *path) +{ + Node *node; + + g_return_val_if_fail (GDA_IS_SERVER_OPERATION (op), 0); + + node = node_find (op, path); + if (!node || (node->type != GDA_SERVER_OPERATION_NODE_SEQUENCE)) + return 0; + + return node->d.seq.max_items; +} + +/** + * gda_server_operation_get_sequence_min_size: + * @op: a #GdaServerOperation object + * @path: a complete path to a sequence node (starting with "/") + * + * Returns: the minimum number of items in the sequence at @path, or 0 if @path is not a sequence node + */ +guint +gda_server_operation_get_sequence_min_size (GdaServerOperation *op, const gchar *path) +{ + Node *node; + + g_return_val_if_fail (GDA_IS_SERVER_OPERATION (op), 0); + + node = node_find (op, path); + if (!node || (node->type != GDA_SERVER_OPERATION_NODE_SEQUENCE)) + return 0; + + return node->d.seq.min_items; +} + + +#ifdef GDA_DEBUG_NO +static void +dump (GdaServerOperation *op) +{ + xmlNodePtr node; + node = gda_server_operation_save_data_to_xml (op, NULL); + if (node) { + xmlDocPtr doc; + xmlChar *buffer; + + doc = xmlNewDoc ("1.0"); + xmlDocSetRootElement (doc, node); + xmlIndentTreeOutput = 1; + xmlKeepBlanksDefault (0); + xmlDocDumpFormatMemory (doc, &buffer, NULL, 1); + g_print ("%s\n", buffer); + xmlFree (buffer); + xmlFreeDoc (doc); + } + else + g_warning ("Saving to XML failed!"); +} +#endif + +/** + * gda_server_operation_add_item_to_sequence: + * @op: a #GdaServerOperation object + * @seq_path: the path to the sequence to which an item must be added (like "/SEQ_NAME" for instance) + * + * Returns: the index of the new entry in the sequence (like 5 for example if a 6th item has + * been added to the sequence. + */ +guint +gda_server_operation_add_item_to_sequence (GdaServerOperation *op, const gchar *seq_path) +{ + Node *node; + + g_return_val_if_fail (GDA_IS_SERVER_OPERATION (op), 0); + + node = node_find (op, seq_path); + if (!node || (node->type != GDA_SERVER_OPERATION_NODE_SEQUENCE)) + return 0; + + if (g_slist_length (node->d.seq.seq_items) == node->d.seq.max_items) + return 0; + + sequence_add_item (op, node); + +#ifdef GDA_DEBUG_NO + dump (op); +#endif + + return g_slist_length (node->d.seq.seq_items); +} + +/** + * gda_server_operation_del_item_from_sequence: + * @op: a #GdaServerOperation object + * @item_path: the path to the sequence's item to remove (like "/SEQ_NAME/5" for instance) + * + * Returns: TRUE if the specified node has been removed from the sequence + */ +gboolean +gda_server_operation_del_item_from_sequence (GdaServerOperation *op, const gchar *item_path) +{ + Node *node, *item_node; + gchar *seq_path, *ptr; + + g_return_val_if_fail (GDA_IS_SERVER_OPERATION (op), FALSE); + + seq_path = g_strdup (item_path); + ptr = seq_path + strlen (seq_path) - 1; + while ((ptr >= seq_path) && + (((*ptr >= '0') && (*ptr <= '9')) || (*ptr == '/'))) { + *ptr = 0; + ptr--; + } + + node = node_find (op, seq_path); + if (!node || + (node->type != GDA_SERVER_OPERATION_NODE_SEQUENCE) || + (g_slist_length (node->d.seq.seq_items) == node->d.seq.min_items)) { + g_free (seq_path); + return FALSE; + } + + item_node = node_find (op, item_path); + if (!item_node || (item_node->type != GDA_SERVER_OPERATION_NODE_SEQUENCE_ITEM)) { + g_free (seq_path); + return FALSE; + } + + clean_nodes_info_cache (op); +#ifdef GDA_DEBUG_signal + g_print (">> 'SEQUENCE_ITEM_REMOVE' from %s\n", __FUNCTION__); +#endif + g_signal_emit (G_OBJECT (op), gda_server_operation_signals [SEQUENCE_ITEM_REMOVE], 0, + seq_path, g_slist_index (node->d.seq.seq_items, item_node)); +#ifdef GDA_DEBUG_signal + g_print ("<< 'SEQUENCE_ITEM_REMOVE' from %s\n", __FUNCTION__); +#endif + + g_free (seq_path); + node_destroy (op, item_node); + node->d.seq.seq_items = g_slist_remove (node->d.seq.seq_items, item_node); + +#ifdef GDA_DEBUG_NO + dump (op); +#endif + + return FALSE; +} + +/** + * gda_server_operation_get_value_at_path: (rename-to gda_server_operation_get_value_at) + * @op: a #GdaServerOperation object + * @path: a complete path to a node (starting with "/") + * + * Get the value for the node at the @path path + * + * Returns: (transfer none) (nullable): a constant #GValue if a value has been defined, or %NULL if the value is undefined or if the @path is not defined or @path does not hold any value. + * + * Since: 4.2.6 + */ +const GValue * +gda_server_operation_get_value_at_path (GdaServerOperation *op, const gchar *path) +{ + const GValue *value = NULL; + GdaServerOperationNode *node_info; + + g_return_val_if_fail (GDA_IS_SERVER_OPERATION (op), NULL); + g_return_val_if_fail (path && *path, NULL); + + /* use path */ + node_info = gda_server_operation_get_node_info (op, path); + if (node_info) { + switch (node_info->type) { + case GDA_SERVER_OPERATION_NODE_PARAM: + value = gda_holder_get_value (node_info->param); + break; + case GDA_SERVER_OPERATION_NODE_PARAMLIST: + case GDA_SERVER_OPERATION_NODE_DATA_MODEL: + case GDA_SERVER_OPERATION_NODE_SEQUENCE: + case GDA_SERVER_OPERATION_NODE_SEQUENCE_ITEM: + case GDA_SERVER_OPERATION_NODE_DATA_MODEL_COLUMN: + break; + default: + g_assert_not_reached (); + } + } + else { + /* specific syntax which does not yield to a GdaServerOperationNode */ + gchar *str; + str = gda_server_operation_get_node_parent (op, path); + if (str) { + node_info = gda_server_operation_get_node_info (op, str); + if (node_info && (node_info->type == GDA_SERVER_OPERATION_NODE_DATA_MODEL_COLUMN)) { + gchar *extension, *ptr; + gint row; + extension = gda_server_operation_get_node_path_portion (op, path); + + row = strtol (extension, &ptr, 10); + if (ptr && *ptr) + row = -1; + if (row >= 0) + value = gda_data_model_get_value_at (node_info->model, + gda_column_get_position (node_info->column), + row, NULL); + g_free(extension); + } + g_free (str); + } + } + + return value; +} + +/** + * gda_server_operation_get_value_at: + * @op: a #GdaServerOperation object + * @path_format: a complete path to a node (starting with "/") + * @...: arguments to use with @path_format to make a complete path + * + * Get the value for the node at the path formed using @path_format and ... (the rules are the same as + * for g_strdup_printf()) + * + * Returns: (transfer none): a constant #GValue if a value has been defined, or %NULL if the value is undefined or + * if the @path is not defined or @path does not hold any value. + */ +const GValue * +gda_server_operation_get_value_at (GdaServerOperation *op, const gchar *path_format, ...) +{ + const GValue *value = NULL; + gchar *path; + va_list args; + + g_return_val_if_fail (GDA_IS_SERVER_OPERATION (op), NULL); + + /* build path */ + va_start (args, path_format); + path = g_strdup_vprintf (path_format, args); + va_end (args); + + value = gda_server_operation_get_value_at_path (op, path); + g_free (path); + + return value; +} + +/** + * gda_server_operation_set_value_at_path: (rename-to gda_server_operation_set_value_at) + * @op: a #GdaServerOperation object + * @value: (nullable): a string + * @path: a complete path to a node (starting with "/") + * @error: a place to store errors or %NULL + * + * Set the value for the node at the path formed using @path_format and the ... ellipse (the rules are the same as + * for g_strdup_printf()). + * + * Note that trying to set a value for a path which is not used by the current + * provider, such as "/TABLE_OPTIONS_P/TABLE_ENGINE" for a PostgreSQL connection (this option is only supported for MySQL), + * will not generate + * any error; this allows one to give values to a superset of the parameters and thus use the same code for several providers. + * + * Here are the possible formats of @path_format: + * + * If the path corresponds to a #GdaHolder, then the parameter is set to + * If the path corresponds to a sequence item like for example "/SEQUENCE_NAME/5/NAME" for + * the "NAME" value of the 6th item of the "SEQUENCE_NAME" sequence then: + * + * if the sequence already has 6 or more items, then the value is just set to the corresponding + * value in the 6th item of the sequence + * if the sequence has less then 6 items, then items are added up to the 6th one before setting + * the value to the corresponding in the 6th item of the sequence + * + * + * If the path corresponds to a #GdaDataModel, like for example "/ARRAY/@@COLUMN/5" for the value at the + * 6th row of the "COLUMN" column of the "ARRAY" data model, then: + * + * if the data model already contains 6 or more rows, then the value is just set + * if the data model has less than 6 rows, then rows are added up to the 6th one before setting + * the value + * + * + * + * + * Returns: %TRUE if no error occurred + * + * Since: 4.2.6 + */ +gboolean +gda_server_operation_set_value_at_path (GdaServerOperation *op, const gchar *value, + const gchar *path, GError **error) +{ + Node *opnode; + gchar *extension = NULL; + gchar *colname = NULL; + gboolean allok = TRUE; + + g_return_val_if_fail (GDA_IS_SERVER_OPERATION (op), FALSE); + + /* set the value */ + opnode = node_find_or_create (op, path); + if (!opnode) { + /* try to see if the "parent" is a real node */ + gchar *str; + + str = gda_server_operation_get_node_parent (op, path); + if (str) { + opnode = node_find (op, str); + if (opnode) { + if (opnode->type != GDA_SERVER_OPERATION_NODE_PARAMLIST) + opnode = NULL; /* ignore opnode */ + } + else { + gchar *str2; + + str2 = gda_server_operation_get_node_parent (op, str); + opnode = node_find (op, str2); + if (opnode) { + if (opnode->type != GDA_SERVER_OPERATION_NODE_DATA_MODEL) + opnode = NULL; /* ignore opnode */ + else + colname = gda_server_operation_get_node_path_portion (op, str); + } + g_free (str2); + } + g_free (str); + } + if (opnode) + extension = gda_server_operation_get_node_path_portion (op, path); + } + + if (opnode) { + switch (opnode->type) { + case GDA_SERVER_OPERATION_NODE_PARAMLIST: + if (!extension) { + g_set_error (error, GDA_SERVER_OPERATION_ERROR, + GDA_SERVER_OPERATION_XML_ERROR, + "%s", + _("Parameterlist values can only be set for individual parameters within it")); + allok = FALSE; + } + else { + GdaHolder *param; + param = gda_set_get_holder (opnode->d.plist, extension); + if (param) { + GValue *v; + if (value) + v = gda_value_new_from_string (value, + gda_holder_get_g_type (param)); + else + v = gda_value_new_null (); + if (!gda_holder_take_value (param, v, error)) + allok = FALSE; + } + } + break; + case GDA_SERVER_OPERATION_NODE_DATA_MODEL: { + GdaColumn *column = NULL; + + if (colname && (*colname == '@')) { + gint i, nbcols; + + nbcols = gda_data_model_get_n_columns (opnode->d.model); + for (i = 0; (id.model, i); + g_object_get (G_OBJECT (column), "id", &colid, NULL); + if (!colid || strcmp (colid, colname +1)) + column = NULL; + g_free(colid); + } + if (column) { + gchar *ptr; + gint row; + row = strtol (extension, &ptr, 10); + if (ptr && *ptr) + row = -1; + if (row >= 0) { + gint i = gda_data_model_get_n_rows (opnode->d.model); + + if (i <= row) { + for (; allok && (i <= row); i++) + if (gda_data_model_append_row (opnode->d.model, error) < 0) + allok = FALSE; + } + + if (allok) { + GValue *gvalue; + if (value) + gvalue = gda_value_new_from_string (value, + gda_column_get_g_type (column)); + else + gvalue = gda_value_new_null (); + allok = gda_data_model_set_value_at (opnode->d.model, + gda_column_get_position (column), + row, gvalue, error); + gda_value_free (gvalue); + } + } + } + } + break; + } + case GDA_SERVER_OPERATION_NODE_PARAM: { + GValue *v; + if (value) + v = gda_value_new_from_string (value, + gda_holder_get_g_type (opnode->d.param)); + else + v = gda_value_new_null (); + if (!gda_holder_take_value (opnode->d.param, v, error)) + allok = FALSE; + break; + } + case GDA_SERVER_OPERATION_NODE_SEQUENCE: + break; + case GDA_SERVER_OPERATION_NODE_SEQUENCE_ITEM: + break; + default: + g_assert_not_reached (); + } + } + + g_free (extension); + g_free (colname); + if (!allok && (*error) == NULL) { + g_warning ("gda_server_operation_set_value_at_path: No Error set"); + } + + return allok; +} + +/** + * gda_server_operation_set_value_at: + * @op: a #GdaServerOperation object + * @value: (nullable): a string + * @error: a place to store errors or %NULL + * @path_format: a complete path to a node (starting with "/") + * @...: arguments to use with @path_format to make a complete path + * + * Set the value for the node at the path formed using @path_format and the ... ellipse (the rules are the same as + * for g_strdup_printf()). + * + * Note that trying to set a value for a path which is not used by the current + * provider, such as "/TABLE_OPTIONS_P/TABLE_ENGINE" for a PostgreSQL connection (this option is only supported for MySQL), + * will not generate + * any error; this allows one to give values to a superset of the parameters and thus use the same code for several providers. + * + * Here are the possible formats of @path_format: + * + * If the path corresponds to a #GdaHolder, then the parameter is set to + * If the path corresponds to a sequence item like for example "/SEQUENCE_NAME/5/NAME" for + * the "NAME" value of the 6th item of the "SEQUENCE_NAME" sequence then: + * + * if the sequence already has 6 or more items, then the value is just set to the corresponding + * value in the 6th item of the sequence + * if the sequence has less then 6 items, then items are added up to the 6th one before setting + * the value to the corresponding in the 6th item of the sequence + * + * + * If the path corresponds to a #GdaDataModel, like for example "/ARRAY/@@COLUMN/5" for the value at the + * 6th row of the "COLUMN" column of the "ARRAY" data model, then: + * + * if the data model already contains 6 or more rows, then the value is just set + * if the data model has less than 6 rows, then rows are added up to the 6th one before setting + * the value + * + * + * + * + * Returns: %TRUE if no error occurred + */ +gboolean +gda_server_operation_set_value_at (GdaServerOperation *op, const gchar *value, GError **error, + const gchar *path_format, ...) +{ + gchar *path; + va_list args; + gboolean ret; + + g_return_val_if_fail (GDA_IS_SERVER_OPERATION (op), FALSE); + + /* build path */ + va_start (args, path_format); + path = g_strdup_vprintf (path_format, args); + va_end (args); + + ret = gda_server_operation_set_value_at_path (op, value, path, error); + g_free (path); + + return ret; +} + +/** + * gda_server_operation_is_valid: + * @op: a #GdaServerOperation widget + * @xml_file: (nullable): an XML specification file (see gda_server_operation_new()) or %NULL + * @error: a place to store an error, or %NULL + * + * Tells if all the required values in @op have been defined. + * + * if @xml_file is not %NULL, the validity of @op is tested against that specification, + * and not against the current @op's specification. + * + * Returns: %TRUE if @op is valid + * + * Since: 6.0 + */ +gboolean +gda_server_operation_is_valid (GdaServerOperation *op, const gchar *xml_file, GError **error) +{ + GdaServerOperationPrivate *priv = gda_server_operation_get_instance_private (op); + gboolean valid = TRUE; + GSList *list; + + g_return_val_if_fail (GDA_IS_SERVER_OPERATION (op), FALSE); + + if (!xml_file) { + /* basic validity test */ + for (list = priv->allnodes; list; list = list->next) { + Node *node; + + node = NODE (list->data); + if (node->status == GDA_SERVER_OPERATION_STATUS_REQUIRED) { + if (node->type == GDA_SERVER_OPERATION_NODE_PARAM) { + const GValue *value; + gchar *path; + + path = node_get_complete_path (op, node); + value = gda_server_operation_get_value_at (op, path); + if (!value) { + valid = FALSE; + g_set_error (error, + GDA_SERVER_OPERATION_ERROR, + GDA_SERVER_OPERATION_INCORRECT_VALUE_ERROR, + _("Missing required value for '%s'"), path); + break; + } + g_free (path); + } + else if (node->type == GDA_SERVER_OPERATION_NODE_PARAMLIST) { + valid = gda_set_is_valid (node->d.plist, error); + if (!valid) + break; + } + } + } + } + else { + /* use @xml_file */ + xmlNodePtr save; + + save = gda_server_operation_save_data_to_xml (op, error); + if (save) { + GdaServerOperation *op2; + op2 = gda_server_operation_new (priv->op_type, xml_file); + if (gda_server_operation_load_data_from_xml (op2, save, error)) + valid = gda_server_operation_is_valid (op2, NULL, error); + else + valid = FALSE; + xmlFreeNode (save); + g_object_unref (op2); + } + else + valid = FALSE; + } + + return valid; +} + +/** + * gda_server_operation_is_valid_from_resource: + * @op: a #GdaServerOperation widget + * @resource: (nullable): the name of a resource containing an XML specification data (see gda_server_operation_new()) or %NULL + * @error: a place to store an error, or %NULL + * + * Tells if all the required values in @op have been defined. + * + * if @xml_data is not %NULL, the validity of @op is tested against that specification, + * and not against the current @op's specification. + * + * Returns: %TRUE if @op is valid + */ +gboolean +gda_server_operation_is_valid_from_resource (GdaServerOperation *op, const gchar *resource, GError **error) +{ + GdaServerOperationPrivate *priv = gda_server_operation_get_instance_private (op); + + g_return_val_if_fail (GDA_IS_SERVER_OPERATION (op), FALSE); + + if (resource) { + xmlNodePtr save; + gboolean valid = TRUE; + + save = gda_server_operation_save_data_to_xml (op, error); + if (save) { + GdaServerOperation *op2; + op2 = GDA_SERVER_OPERATION (g_object_new (GDA_TYPE_SERVER_OPERATION, + "op-type", priv->op_type, + "spec-resource", resource, NULL)); + if (gda_server_operation_load_data_from_xml (op2, save, error)) + valid = gda_server_operation_is_valid (op2, NULL, error); + else + valid = FALSE; + xmlFreeNode (save); + g_object_unref (op2); + } + else + valid = FALSE; + + return valid; + } + else + return gda_server_operation_is_valid (op, NULL, error); + +} + +/** + * gda_server_operation_prepare_create_database: + * @provider: the database provider to use + * @db_name: (nullable): the name of the database to create, or %NULL + * @error: a place to store errors, or %NULL + * + * Creates a new #GdaServerOperation object which contains the specifications required + * to create a database. Once these specifications are provided, use + * gda_server_operation_perform_create_database() to perform the database creation. + * + * If @db_name is left %NULL, then the name of the database to create will have to be set in the + * returned #GdaServerOperation using gda_server_operation_set_value_at(). + * + * Returns: (transfer full) (nullable): new #GdaServerOperation object, or %NULL if the provider does not support database + * creation + * + * Since: 4.2.3 + */ +GdaServerOperation * +gda_server_operation_prepare_create_database (const gchar *provider, const gchar *db_name, GError **error) +{ + GdaServerProvider *prov; + + g_return_val_if_fail (provider && *provider, NULL); + + prov = gda_config_get_provider (provider, error); + if (prov) { + GdaServerOperation *op; + op = gda_server_provider_create_operation (prov, NULL, GDA_SERVER_OPERATION_CREATE_DB, + NULL, error); + if (op) { + g_object_set_data_full (G_OBJECT (op), "_gda_provider_obj", g_object_ref (prov), g_object_unref); + if (db_name) + gda_server_operation_set_value_at (op, db_name, NULL, "/DB_DEF_P/DB_NAME"); + } + return op; + } + else + return NULL; +} + +/** + * gda_server_operation_perform_create_database: + * @provider: (nullable): the database provider to use, or %NULL if @op has been created using gda_server_operation_prepare_create_database() + * @op: a #GdaServerOperation object obtained using gda_server_operation_prepare_create_database() + * @error: a place to store en error, or %NULL + * + * Creates a new database using the specifications in @op. @op can be obtained using + * gda_server_provider_create_operation(), or gda_server_operation_prepare_create_database(). + * + * Returns: TRUE if no error occurred and the database has been created, FALSE otherwise + * + * Since: 4.2.3 + */ +gboolean +gda_server_operation_perform_create_database (GdaServerOperation *op, const gchar *provider, GError **error) +{ + GdaServerProvider *prov; + + g_return_val_if_fail (GDA_IS_SERVER_OPERATION (op), FALSE); + if (provider) + prov = gda_config_get_provider (provider, error); + else + prov = g_object_get_data (G_OBJECT (op), "_gda_provider_obj"); + if (prov) + return gda_server_provider_perform_operation (prov, NULL, op, error); + else { + g_warning (_("Could not find operation's associated provider, did you use gda_server_operation_prepare_create_database() ?")); + return FALSE; + } +} + +/** + * gda_server_operation_prepare_drop_database: + * @provider: the database provider to use + * @db_name: (nullable): the name of the database to drop, or %NULL + * @error: a place to store errors, or %NULL + * + * Creates a new #GdaServerOperation object which contains the specifications required + * to drop a database. Once these specifications provided, use + * gda_server_operation_perform_drop_database() to perform the database creation. + * + * If @db_name is left %NULL, then the name of the database to drop will have to be set in the + * returned #GdaServerOperation using gda_server_operation_set_value_at(). + * + * Returns: (transfer full) (nullable): new #GdaServerOperation object, or %NULL if the provider does not support database + * destruction + * + * Since: 4.2.3 + */ +GdaServerOperation * +gda_server_operation_prepare_drop_database (const gchar *provider, const gchar *db_name, GError **error) +{ + GdaServerProvider *prov; + + g_return_val_if_fail (provider && *provider, NULL); + + prov = gda_config_get_provider (provider, error); + if (prov) { + GdaServerOperation *op; + op = gda_server_provider_create_operation (prov, NULL, GDA_SERVER_OPERATION_DROP_DB, + NULL, error); + if (op) { + g_object_set_data_full (G_OBJECT (op), "_gda_provider_obj", g_object_ref (prov), g_object_unref); + if (db_name) + gda_server_operation_set_value_at (op, db_name, NULL, "/DB_DESC_P/DB_NAME"); + } + return op; + } + else + return NULL; +} + +/** + * gda_server_operation_perform_drop_database: + * @provider: (nullable): the database provider to use, or %NULL if @op has been created using gda_server_operation_prepare_drop_database() + * @op: a #GdaServerOperation object obtained using gda_server_operation_prepare_drop_database() + * @error: a place to store en error, or %NULL + * + * Destroys an existing database using the specifications in @op. @op can be obtained using + * gda_server_provider_create_operation(), or gda_server_operation_prepare_drop_database(). + * + * Returns: TRUE if no error occurred and the database has been destroyed + * + * Since: 4.2.3 + */ +gboolean +gda_server_operation_perform_drop_database (GdaServerOperation *op, const gchar *provider, GError **error) +{ + GdaServerProvider *prov; + + g_return_val_if_fail (GDA_IS_SERVER_OPERATION (op), FALSE); + g_return_val_if_fail (gda_server_operation_get_op_type (op) == GDA_SERVER_OPERATION_DROP_DB, FALSE); + if (provider) + prov = gda_config_get_provider (provider, error); + else + prov = g_object_get_data (G_OBJECT (op), "_gda_provider_obj"); + if (prov) + return gda_server_provider_perform_operation (prov, NULL, op, error); + else { + g_warning ("Could not find operation's associated provider, " + "did you use gda_server_operation_prepare_drop_database() ?"); + return FALSE; + } +} + +/* Arguments for for Table creation on foreign keys */ + +struct _GdaServerOperationCreateTableArgFKeyRefField { + gchar *local_field; + gchar *referenced_field; +}; + +G_DEFINE_BOXED_TYPE(GdaServerOperationCreateTableArgFKeyRefField, gda_server_operation_create_table_arg_fkey_ref_field, gda_server_operation_create_table_arg_fkey_ref_field_copy, gda_server_operation_create_table_arg_fkey_ref_field_free) + +GType +gda_server_operation_create_table_arg_get_fkey_ref_field_get_type () +{ + return gda_server_operation_create_table_arg_fkey_ref_field_get_type (); +} + + +/** + * gda_server_operation_create_table_arg_fkey_ref_field_new: + * + * Returns: a new #GdaServerOperationCreateTableArgFKeyRefField + */ +GdaServerOperationCreateTableArgFKeyRefField* +gda_server_operation_create_table_arg_fkey_ref_field_new () +{ + GdaServerOperationCreateTableArgFKeyRefField* ref = g_new0 (GdaServerOperationCreateTableArgFKeyRefField, 1); + ref->local_field = NULL; + ref->referenced_field = NULL; + return ref; +} + /** + * gda_server_operation_create_table_arg_get_fkey_ref_field_free: + * @ref: a #GdaServerOperationCreateTableArgFKeyRefField to free + */ +void +gda_server_operation_create_table_arg_fkey_ref_field_free (GdaServerOperationCreateTableArgFKeyRefField *ref) +{ + if (ref->local_field != NULL) + g_free (ref->local_field); + if (ref->referenced_field != NULL) + g_free (ref->referenced_field); + g_free (ref); +} + + /** + * gda_server_operation_create_table_arg_get_fkey_ref_field_copy: + * @ref: a source #GdaServerOperationCreateTableArgFKeyRefField to copy from + * + * Returns: a new #GdaServerOperationCreateTableArgFKeyRefField copy of + */ +GdaServerOperationCreateTableArgFKeyRefField* +gda_server_operation_create_table_arg_fkey_ref_field_copy (GdaServerOperationCreateTableArgFKeyRefField* src) +{ + GdaServerOperationCreateTableArgFKeyRefField* ref = g_new0 (GdaServerOperationCreateTableArgFKeyRefField, 1); + ref->local_field = g_strdup (src->local_field); + ref->referenced_field = g_strdup (src->referenced_field); + return ref; +} + + + /** + * gda_server_operation_create_table_arg_get_fkey_ref_field_set_local_field: + * @ref: a #GdaServerOperationCreateTableArgFKeyRefField + * @name: the local table's column's name. + * + * Sets column's name of the new table, used to reference to a foreign table's field. + */ +void +gda_server_operation_create_table_arg_fkey_ref_field_set_local_field (GdaServerOperationCreateTableArgFKeyRefField *ref, + const gchar *name) +{ + g_return_if_fail (ref != NULL); + ref->local_field = g_strdup (name); +} + + /** + * gda_server_operation_create_table_arg_get_fkey_ref_field_get_local_field: + * @arg: a #GdaServerOperationCreateTableArgFKeyRefField + * + * Returns: (transfer full): a new string with field name in the table + */ +gchar* +gda_server_operation_create_table_arg_fkey_ref_field_get_local_field (GdaServerOperationCreateTableArgFKeyRefField *ref) +{ + g_return_val_if_fail (ref != NULL, NULL); + return g_strdup (ref->local_field); +} + + + /** + * gda_server_operation_create_table_arg_get_fkey_ref_field_set_referenced_field: + * @arg: a #GdaServerOperationCreateTableArgFKeyRefField + * @name: the referenced table's column's name. + * + * Sets column name to be referenced in a given field o the new table. + */ +void +gda_server_operation_create_table_arg_fkey_ref_field_set_referenced_field (GdaServerOperationCreateTableArgFKeyRefField *ref, + const gchar *name) +{ + g_return_if_fail (ref != NULL); + ref->referenced_field = g_strdup (name); +} + + /** + * gda_server_operation_create_table_arg_get_fkey_ref_field_get_referenced_field: + * @arg: a #GdaServerOperationCreateTableArgFKeyRefField + * + * Returns: (transfer full): a new string with referenced field name in the referenced table + */ +gchar* +gda_server_operation_create_table_arg_fkey_ref_field_get_referenced_field (GdaServerOperationCreateTableArgFKeyRefField *ref) +{ + g_return_val_if_fail (ref != NULL, NULL); + return g_strdup (ref->referenced_field); +} + + +/* Arguments for prepare create table */ +struct _GdaServerOperationCreateTableArg { + gchar *column; + GType ctype; + GdaServerOperationCreateTableFlag flags; + gchar *fkey_table; + gchar *fkey_ondelete; + gchar *fkey_onupdate; + GList *fkey_fields; +}; + +G_DEFINE_BOXED_TYPE (GdaServerOperationCreateTableArg, gda_server_operation_create_table_arg, gda_server_operation_create_table_arg_copy, gda_server_operation_create_table_arg_free) + + /** + * gda_server_operation_create_table_arg_new: + * + * Returns: a new #GdaServerOperationCreateTableArg + */ +GdaServerOperationCreateTableArg* +gda_server_operation_create_table_arg_new () +{ + GdaServerOperationCreateTableArg* arg = g_new0 (GdaServerOperationCreateTableArg, 1); + arg->column = NULL; + arg->ctype = GDA_TYPE_NULL; + arg->flags = GDA_SERVER_OPERATION_CREATE_TABLE_NOTHING_FLAG; + arg->fkey_table = NULL; + arg->fkey_ondelete = NULL; + arg->fkey_onupdate = NULL; + arg->fkey_fields = NULL; + return arg; +} + /** + * gda_server_operation_prepare_create_table_arg_free: + * @arg: a #GdaServerOperationPrepareCreateTableArg to free + */ +void +gda_server_operation_create_table_arg_free (GdaServerOperationCreateTableArg *arg) +{ + if (arg->column != NULL) + g_free (arg->column); + if (arg->fkey_table != NULL) + g_free (arg->fkey_table); + if (arg->fkey_ondelete != NULL) + g_free (arg->fkey_ondelete); + if (arg->fkey_onupdate != NULL) + g_free (arg->fkey_onupdate); + if (arg->fkey_fields != NULL) { + g_list_free_full (arg->fkey_fields, (GDestroyNotify) gda_server_operation_create_table_arg_fkey_ref_field_free); + } + g_free (arg); +} + + /** + * gda_server_operation_prepare_create_table_arg_copy: + * @arg: a source #GdaServerOperationPrepareCreateTableArg to copy from + * + * Returns: a new #GdaServerOperationPrepareCreateTableArg copy of + */ +GdaServerOperationCreateTableArg* +gda_server_operation_create_table_arg_copy (GdaServerOperationCreateTableArg* src) +{ + GdaServerOperationCreateTableArg* arg = g_new0 (GdaServerOperationCreateTableArg, 1); + arg->column = g_strdup (src->column); + arg->ctype = src->ctype; + arg->flags = src->flags; + return arg; +} + + + /** + * gda_server_operation_create_table_arg_set_column_name: + * @arg: a #GdaServerOperationCreateTableArg + * @name: the table's column's name. + * + * Sets column name to be created with the new table. + */ +void +gda_server_operation_create_table_arg_set_column_name (GdaServerOperationCreateTableArg *arg, + const gchar *name) +{ + g_return_if_fail (arg != NULL); + arg->column = g_strdup (name); +} + + /** + * gda_server_operation_create_table_arg_get_column_name: + * @arg: a #GdaServerOperationCreateTableArg + * + * Returns: (transfer full): a new string with argument's column name + */ +gchar* +gda_server_operation_create_table_arg_get_column_name (GdaServerOperationCreateTableArg *arg) +{ + g_return_val_if_fail (arg != NULL, NULL); + return g_strdup (arg->column); +} + +/** + * gda_server_operation_create_table_arg_set_column_type: + * @arg: a #GdaServerOperationCreateTableArg + * @ctype: column type to be added by this operation as #GType + * + */ +void +gda_server_operation_create_table_arg_set_column_type (GdaServerOperationCreateTableArg *arg, + GType ctype) +{ + arg->ctype = ctype; +} + +/** + * gda_server_operation_create_table_arg_get_column_type: + * @arg: a #GdaServerOperationCreateTableArg + * + * Returns: type as #GType of the column to be created with this operation + */ +GType +gda_server_operation_create_table_arg_get_column_type (GdaServerOperationCreateTableArg *arg) +{ + return arg->ctype; +} + +/** + * gda_server_operation_create_table_arg_set_flags: + * @arg: a #GdaServerOperationCreateTableArg + * @flags: flags to used in this argument as #GdaServerOperationCreateTableFlag + * + * Sets flags for new column to create with the table. + */ +void +gda_server_operation_create_table_arg_set_flags (GdaServerOperationCreateTableArg *arg, + GdaServerOperationCreateTableFlag flags) +{ + arg->flags = flags; +} +/** + * gda_server_operation_create_table_arg_get_flags: + * @arg: a #GdaServerOperationCreateTableArg + * + * Returns: flags as #GdaServerOperationCreateTableFlag + */ +GdaServerOperationCreateTableFlag +gda_server_operation_create_table_arg_get_flags (GdaServerOperationCreateTableArg *arg) +{ + return arg->flags; +} + + /** + * gda_server_operation_create_table_arg_set_fkey_table: + * @arg: a #GdaServerOperationCreateTableArg + * @name: the table's name of reference. + * + * You should set this if you use a #GDA_SERVER_OPERATION_CREATE_TABLE_FKEY_FLAG flag. + */ +void +gda_server_operation_create_table_arg_set_fkey_table (GdaServerOperationCreateTableArg *arg, + const gchar *name) +{ + g_return_if_fail (arg != NULL); + arg->fkey_table = g_strdup (name); +} + + /** + * gda_server_operation_create_table_arg_get_fkey_table: + * @arg: a #GdaServerOperationCreateTableArg + * + * Returns: (transfer full): a new string with argument's referenced table's name. + */ +gchar* +gda_server_operation_create_table_arg_get_fkey_table (GdaServerOperationCreateTableArg *arg) +{ + g_return_val_if_fail (arg != NULL, NULL); + return g_strdup (arg->fkey_table); +} + + /** + * gda_server_operation_create_table_arg_set_fkey_ondelete: + * @arg: a #GdaServerOperationCreateTableArg + * @action: action to perform on delete action of the referenced field. + * + * You should set this if you use a #GDA_SERVER_OPERATION_CREATE_TABLE_FKEY_FLAG flag. + */ +void +gda_server_operation_create_table_arg_set_fkey_ondelete (GdaServerOperationCreateTableArg *arg, const gchar *action) +{ + g_return_if_fail (arg != NULL); + arg->fkey_ondelete = g_strdup (action); +} + + /** + * gda_server_operation_create_table_arg_get_fkey_ondelete: + * @arg: a #GdaServerOperationCreateTableArg + * + * Returns: (transfer full): a new string with action to take on delete. + */ +gchar* +gda_server_operation_create_table_arg_get_fkey_ondelete (GdaServerOperationCreateTableArg *arg) +{ + g_return_val_if_fail (arg != NULL, NULL); + return g_strdup (arg->fkey_ondelete); +} + + + /** + * gda_server_operation_create_table_arg_set_fkey_onupdate: + * @arg: a #GdaServerOperationCreateTableArg + * @action: action to perform on delete action of the referenced field. + * + * You should set this if you use a #GDA_SERVER_OPERATION_CREATE_TABLE_FKEY_FLAG flag. + */ +void +gda_server_operation_create_table_arg_set_fkey_ondupdate (GdaServerOperationCreateTableArg *arg, const gchar *action) +{ + g_return_if_fail (arg != NULL); + arg->fkey_onupdate = g_strdup (action); +} + + /** + * gda_server_operation_create_table_arg_get_fkey_onupdate: + * @arg: a #GdaServerOperationCreateTableArg + * + * Returns: (transfer full): a new string with action to take on delete. + */ +gchar* +gda_server_operation_create_table_arg_get_fkey_onupdate (GdaServerOperationCreateTableArg *arg) +{ + g_return_val_if_fail (arg != NULL, NULL); + return g_strdup (arg->fkey_onupdate); +} + + + /** + * gda_server_operation_create_table_arg_set_fkey_refs: + * @arg: a #GdaServerOperationCreateTableArg + * @refs: (element-type GdaServerOperationCreateTableArgFKeyRefField): list of references from local to foreign fields. + * This list is owned by @arg, then you should not free it. + * + * You should set this if you use a #GDA_SERVER_OPERATION_CREATE_TABLE_FKEY_FLAG flag. + */ +void +gda_server_operation_create_table_arg_set_fkey_refs (GdaServerOperationCreateTableArg *arg, GList *refs) +{ + g_return_if_fail (arg != NULL); + arg->fkey_fields = refs; +} + + /** + * gda_server_operation_create_table_arg_get_fkey_refs: + * @arg: a #GdaServerOperationCreateTableArg + * + * Returns: (transfer none) (element-type GdaServerOperationCreateTableArgFKeyRefField): a list + * of references from local to foreign fields type #GdaServerOperationCreateTableArgFKeyRefField. + */ +GList* +gda_server_operation_create_table_arg_get_fkey_refs (GdaServerOperationCreateTableArg *arg) +{ + g_return_val_if_fail (arg != NULL, NULL); + return arg->fkey_fields; +} + +/** + * gda_server_operation_render: + * @op: a #GdaServerOperation object + * @error: (nullable): a place to store an error, or %NULL + * + * Creates an SQL statement (possibly using some specific extensions of the DBMS) corresponding to the + * @op operation. Note that the returned string may actually contain more than one SQL statement. + * + * This function's purpose is mainly informative to get the actual SQL code which would be executed to perform + * the operation; to actually perform the operation, use gda_server_operation_perform(). + * + * Returns: (transfer full) (nullable): a new string, or %NULL if an error occurred or operation cannot be rendered as SQL. + */ +gchar * +gda_server_operation_render (GdaServerOperation *op, GError **error) +{ + GdaServerProvider *provider; + GdaConnection *cnc; + + g_return_val_if_fail (op,NULL); + g_return_val_if_fail (GDA_IS_SERVER_OPERATION(op),NULL); + + g_object_get (op,"provider",&provider,"connection",&cnc,NULL); + + g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (provider), NULL); + g_return_val_if_fail (GDA_IS_CONNECTION(cnc), NULL); + + return (gchar*) gda_server_provider_render_operation(provider,cnc,op,error); +} diff --git a/.flatpak-builder/cache/objects/c6/40b5ea70270fe3b2a110ff9567fe893a59964265e562ca87482cd904cc2c5f.file b/.flatpak-builder/cache/objects/c6/40b5ea70270fe3b2a110ff9567fe893a59964265e562ca87482cd904cc2c5f.file new file mode 100755 index 0000000..b176cf2 Binary files /dev/null and b/.flatpak-builder/cache/objects/c6/40b5ea70270fe3b2a110ff9567fe893a59964265e562ca87482cd904cc2c5f.file differ diff --git a/.flatpak-builder/cache/objects/c6/65e606b4a83ef7d4a3763cdbf0e099ce8204bb941b07a5c27409f95ca5a52d.file b/.flatpak-builder/cache/objects/c6/65e606b4a83ef7d4a3763cdbf0e099ce8204bb941b07a5c27409f95ca5a52d.file new file mode 120000 index 0000000..19b3de4 --- /dev/null +++ b/.flatpak-builder/cache/objects/c6/65e606b4a83ef7d4a3763cdbf0e099ce8204bb941b07a5c27409f95ca5a52d.file @@ -0,0 +1 @@ +../../share/runtime/locale/ms/share/ms \ No newline at end of file diff --git a/.flatpak-builder/cache/objects/c7/2bfc81fba4f645e6d39339a685ff991419c1130f5b52fa2d7930d3d79e848a.commit b/.flatpak-builder/cache/objects/c7/2bfc81fba4f645e6d39339a685ff991419c1130f5b52fa2d7930d3d79e848a.commit new file mode 100644 index 0000000..8b30d5b Binary files /dev/null and b/.flatpak-builder/cache/objects/c7/2bfc81fba4f645e6d39339a685ff991419c1130f5b52fa2d7930d3d79e848a.commit differ diff --git a/.flatpak-builder/cache/objects/c7/90abd369ed54c023df19f03e28a0d15ad73bb35025e6d7f75d569531f00a8d.file b/.flatpak-builder/cache/objects/c7/90abd369ed54c023df19f03e28a0d15ad73bb35025e6d7f75d569531f00a8d.file new file mode 100644 index 0000000..75d5d2d --- /dev/null +++ b/.flatpak-builder/cache/objects/c7/90abd369ed54c023df19f03e28a0d15ad73bb35025e6d7f75d569531f00a8d.file @@ -0,0 +1,66 @@ +#ifndef LIBCSV_H__ +#define LIBCSV_H__ +#include +#include + +#define CSV_MAJOR 2 +#define CSV_MINOR 0 +#define CSV_RELEASE 1 + +/* Error Codes */ +#define CSV_SUCCESS 0 +#define CSV_EPARSE 1 /* Parse error in strict mode */ +#define CSV_ENOMEM 2 /* Out of memory while increasing buffer size */ +#define CSV_ETOOBIG 3 /* Buffer larger than SIZE_MAX needed */ +#define CSV_EINVALID 4 /* Invalid code,should never be received from csv_error*/ + + +/* parser options */ +#define CSV_STRICT 1 /* enable strict mode */ +#define CSV_REPALL_NL 2 /* report all unquoted carriage returns and linefeeds */ +#define CSV_STRICT_FINI 4 /* causes csv_fini to return CSV_EPARSE if last + field is quoted and doesn't containg ending + quote */ + +/* Character values */ +#define CSV_TAB 0x09 +#define CSV_SPACE 0x20 +#define CSV_CR 0x0d +#define CSV_LF 0x0a +#define CSV_COMMA 0x2c +#define CSV_QUOTE 0x22 + +struct csv_parser { + int pstate; /* Parser state */ + int quoted; /* Is the current field a quoted field? */ + size_t spaces; /* Number of continious spaces after quote or in a non-quoted field */ + char * entry_buf; /* Entry buffer */ + size_t entry_pos; /* Current position in entry_buf (and current size of entry) */ + size_t entry_size; /* Size of buffer */ + int status; /* Operation status */ + unsigned char options; + char quote_char; + char delim_char; + int (*is_space)(char); + int (*is_term)(char); +}; + +int csv_init(struct csv_parser **p, unsigned char options); +int csv_fini(struct csv_parser *p, void (*cb1)(char *, size_t, void *), void (*cb2)(char, void *), void *data); +void csv_free(struct csv_parser *p); +int csv_error(struct csv_parser *p); +char * csv_strerror(int error); +size_t csv_parse(struct csv_parser *p, const char *s, size_t len, void (*cb1)(char *, size_t, void *), void (*cb2)(char, void *), void *data); +size_t csv_write(char *dest, size_t dest_size, const char *src, size_t src_size); +int csv_fwrite(FILE *fp, const char *src, size_t src_size); +size_t csv_write2(char *dest, size_t dest_size, const char *src, size_t src_size, char quote); +int csv_fwrite2(FILE *fp, const char *src, size_t src_size, char quote); +int csv_opts(struct csv_parser *p, unsigned char options); +void csv_set_delim(struct csv_parser *p, char c); +void csv_set_quote(struct csv_parser *p, char c); +char csv_get_delim(struct csv_parser *p); +char csv_get_quote(struct csv_parser *p); +void csv_set_space_func(struct csv_parser *p, int (*f)(char)); +void csv_set_term_func(struct csv_parser *p, int (*f)(char)); + +#endif diff --git a/.flatpak-builder/cache/objects/c7/94eccf17d1b723a047571f5b0e69993496f3a0487163ac038006cf83ffa69b.file b/.flatpak-builder/cache/objects/c7/94eccf17d1b723a047571f5b0e69993496f3a0487163ac038006cf83ffa69b.file new file mode 100644 index 0000000..f0b458d --- /dev/null +++ b/.flatpak-builder/cache/objects/c7/94eccf17d1b723a047571f5b0e69993496f3a0487163ac038006cf83ffa69b.file @@ -0,0 +1,50 @@ + +/* This file is generated by glib-mkenums, do not modify it. This code is licensed under the same license as the containing project. Note that it links to GLib, so must comply with the LGPL linking clauses. */ + +#pragma once + + #include + + + G_BEGIN_DECLS + +/* enumerations from "gda-connection.h" */ + + +GType gda_connection_error_get_type (void); +#define GDA_TYPE_CONNECTION_ERROR (gda_connection_error_get_type()) + + +GType gda_connection_status_get_type (void); +#define GDA_TYPE_CONNECTION_STATUS (gda_connection_status_get_type()) + + +GType gda_connection_options_get_type (void); +#define GDA_TYPE_CONNECTION_OPTIONS (gda_connection_options_get_type()) + + +GType gda_connection_feature_get_type (void); +#define GDA_TYPE_CONNECTION_FEATURE (gda_connection_feature_get_type()) + + +GType gda_connection_meta_type_get_type (void); +#define GDA_TYPE_CONNECTION_META_TYPE (gda_connection_meta_type_get_type()) + +/* enumerations from "gda-enums.h" */ + + +GType gda_transaction_isolation_get_type (void); +#define GDA_TYPE_TRANSACTION_ISOLATION (gda_transaction_isolation_get_type()) + + +GType gda_value_attribute_get_type (void); +#define GDA_TYPE_VALUE_ATTRIBUTE (gda_value_attribute_get_type()) + + +GType gda_sql_identifier_style_get_type (void); +#define GDA_TYPE_SQL_IDENTIFIER_STYLE (gda_sql_identifier_style_get_type()) + +G_END_DECLS + +/* Generated data ends here */ + diff --git a/.flatpak-builder/cache/objects/c7/96429904e66c8f692e56609e9d66ef321a3858ab650c043c1e89854441b98b.file b/.flatpak-builder/cache/objects/c7/96429904e66c8f692e56609e9d66ef321a3858ab650c043c1e89854441b98b.file new file mode 100644 index 0000000..f78a5a6 Binary files /dev/null and b/.flatpak-builder/cache/objects/c7/96429904e66c8f692e56609e9d66ef321a3858ab650c043c1e89854441b98b.file differ diff --git a/.flatpak-builder/cache/objects/c8/2b5ae4af0df7881f8ca543824079f83ab96ac71c2558c52744b709e2bd7462.file b/.flatpak-builder/cache/objects/c8/2b5ae4af0df7881f8ca543824079f83ab96ac71c2558c52744b709e2bd7462.file new file mode 100644 index 0000000..33003bc --- /dev/null +++ b/.flatpak-builder/cache/objects/c8/2b5ae4af0df7881f8ca543824079f83ab96ac71c2558c52744b709e2bd7462.file @@ -0,0 +1,403 @@ +/* + * Copyright (C) 2009 - 2013 Vivien Malerba + * Copyright (C) 2010 David King + * Copyright (C) 2018 Daniel Espinosa + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +#define G_LOG_DOMAIN "GDA-tree-mgr-columns" + +#include +#include +#include +#include "gda-tree-mgr-columns.h" +#include "gda-tree-node.h" + +typedef struct { + GdaConnection *cnc; + GdaMetaStore *mstore; + gchar *schema; /* imposed upon construction */ + gchar *table_name; /* imposed upon construction */ + + GdaStatement *stmt; + GdaSet *params; +} GdaTreeMgrColumnsPrivate; + +G_DEFINE_TYPE_WITH_PRIVATE (GdaTreeMgrColumns, gda_tree_mgr_columns, GDA_TYPE_TREE_MANAGER) + +static void gda_tree_mgr_columns_dispose (GObject *object); +static void gda_tree_mgr_columns_set_property (GObject *object, + guint param_id, + const GValue *value, + GParamSpec *pspec); +static void gda_tree_mgr_columns_get_property (GObject *object, + guint param_id, + GValue *value, + GParamSpec *pspec); + +/* virtual methods */ +static GSList *gda_tree_mgr_columns_update_children (GdaTreeManager *manager, GdaTreeNode *node, + const GSList *children_nodes, gboolean *out_error, GError **error); + +/* properties */ +enum { + PROP_0, + PROP_CNC, + PROP_SCHEMA, + PROP_TABLE, + PROP_META_STORE +}; + +/* + * GdaTreeMgrColumns class implementation + * @klass: + */ +static void +gda_tree_mgr_columns_class_init (GdaTreeMgrColumnsClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + /* virtual methods */ + ((GdaTreeManagerClass*) klass)->update_children = gda_tree_mgr_columns_update_children; + + /* Properties */ + object_class->set_property = gda_tree_mgr_columns_set_property; + object_class->get_property = gda_tree_mgr_columns_get_property; + + /** + * GdaTreeMgrColumns:connection: + * + * Defines the #GdaConnection to display information for. Necessary upon construction unless + * the #GdaTreeMgrColumns:meta-store property is specified instead. + */ + g_object_class_install_property (object_class, PROP_CNC, + g_param_spec_object ("connection", NULL, "Connection to use", + GDA_TYPE_CONNECTION, + G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)); + + /** + * GdaTreeMgrColumns:meta-store: + * + * Defines the #GdaMetaStore to extract information from. Necessary upon construction unless + * the #GdaTreeMgrColumns:connection property is specified instead. This property has + * priority over the GdaTreeMgrColumns:connection property. + * + * Since: 4.2.4 + */ + g_object_class_install_property (object_class, PROP_META_STORE, + g_param_spec_object ("meta-store", NULL, "GdaMetaStore to use", + GDA_TYPE_META_STORE, + G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)); + + /** + * GdaTreeMgrColumns:schema: + * + * If no set, then the table name will be fetched from the parent node using the "schema" attribute + */ + g_object_class_install_property (object_class, PROP_SCHEMA, + g_param_spec_string ("schema", NULL, + "Database schema'name in which the table is", + NULL, G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)); + + /** + * GdaTreeMgrColumns:table-name: + * + * If no set, then the table name will be fetched from the parent node using the "table_name" attribute + */ + g_object_class_install_property (object_class, PROP_TABLE, + g_param_spec_string ("table-name", NULL, + "Database table's name", + NULL, G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)); + + object_class->dispose = gda_tree_mgr_columns_dispose; +} + +static void +gda_tree_mgr_columns_init (GdaTreeMgrColumns *mgr) {} + +static void +gda_tree_mgr_columns_dispose (GObject *object) +{ + GdaTreeMgrColumns *mgr = (GdaTreeMgrColumns *) object; + + g_return_if_fail (GDA_IS_TREE_MGR_COLUMNS (mgr)); + GdaTreeMgrColumnsPrivate *priv = gda_tree_mgr_columns_get_instance_private (mgr); + + if (priv) { + if (priv->cnc) { + g_object_unref (priv->cnc); + priv->cnc = NULL; + } + if (priv->mstore) { + g_object_unref (priv->mstore); + priv->mstore = NULL; + } + g_free (priv->schema); + priv->schema = NULL; + g_free (priv->table_name); + priv->table_name = NULL; + + if (priv->stmt) { + g_object_unref (priv->stmt); + priv->stmt = NULL; + } + if (priv->params) { + g_object_unref (priv->params); + priv->params = NULL; + } + } + + /* chain to parent class */ + G_OBJECT_CLASS (gda_tree_mgr_columns_parent_class)->dispose (object); +} + +static void +gda_tree_mgr_columns_set_property (GObject *object, + guint param_id, + const GValue *value, + GParamSpec *pspec) +{ + GdaTreeMgrColumns *mgr; + + mgr = GDA_TREE_MGR_COLUMNS (object); + GdaTreeMgrColumnsPrivate *priv = gda_tree_mgr_columns_get_instance_private (mgr); + switch (param_id) { + case PROP_CNC: + priv->cnc = (GdaConnection*) g_value_get_object (value); + if (priv->cnc) + g_object_ref (priv->cnc); + break; + case PROP_META_STORE: + priv->mstore = (GdaMetaStore*) g_value_get_object (value); + if (priv->mstore) + g_object_ref (priv->mstore); + break; + case PROP_SCHEMA: + priv->schema = g_value_dup_string (value); + break; + case PROP_TABLE: + priv->table_name = g_value_dup_string (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + break; + } +} + +static void +gda_tree_mgr_columns_get_property (GObject *object, + guint param_id, + GValue *value, + GParamSpec *pspec) +{ + GdaTreeMgrColumns *mgr; + + mgr = GDA_TREE_MGR_COLUMNS (object); + GdaTreeMgrColumnsPrivate *priv = gda_tree_mgr_columns_get_instance_private (mgr); + switch (param_id) { + case PROP_CNC: + g_value_set_object (value, priv->cnc); + break; + case PROP_META_STORE: + g_value_set_object (value, priv->mstore); + break; + case PROP_SCHEMA: + g_value_set_string (value, priv->schema); + break; + case PROP_TABLE: + g_value_set_string (value, priv->table_name); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + break; + } +} + +/** + * gda_tree_mgr_columns_new: + * @cnc: a #GdaConnection object + * @schema: a schema name + * @table_name: the name of the table + * + * Creates a new #GdaTreeManager object which will add one tree node for each + * column in the table named @table_name in the @schema schema. + * + * Returns: (transfer full): a new #GdaTreeManager object + * + * Since: 4.2 + */ +GdaTreeManager* +gda_tree_mgr_columns_new (GdaConnection *cnc, const gchar *schema, const gchar *table_name) +{ + GdaTreeMgrColumns *mgr; + g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL); + + mgr = (GdaTreeMgrColumns*) g_object_new (GDA_TYPE_TREE_MGR_COLUMNS, + "connection", cnc, + "schema", schema, + "table-name", table_name, NULL); + return (GdaTreeManager*) mgr; +} + +static GSList * +gda_tree_mgr_columns_update_children (GdaTreeManager *manager, GdaTreeNode *node, G_GNUC_UNUSED const GSList *children_nodes, + gboolean *out_error, GError **error) +{ + GdaTreeMgrColumns *mgr = GDA_TREE_MGR_COLUMNS (manager); + GdaMetaStore *store; + GdaDataModel *model; + GSList *list = NULL; + GdaConnection *scnc; + GdaTreeMgrColumnsPrivate *priv = gda_tree_mgr_columns_get_instance_private (mgr); + + if (!priv->cnc && !priv->mstore) { + g_set_error (error, GDA_TREE_MANAGER_ERROR, GDA_TREE_MANAGER_UNKNOWN_ERROR, + "%s", _("No connection and no GdaMetaStore specified")); + if (out_error) + *out_error = TRUE; + return NULL; + } + else if (priv->mstore) + store = priv->mstore; + else + store = gda_connection_get_meta_store (priv->cnc); + + scnc = gda_meta_store_get_internal_connection (store); + + /* create statements if necessary */ + if (!priv->stmt) { + GdaSqlParser *parser; + GdaStatement *stmt; + + parser = gda_connection_create_parser (scnc); + if (! parser) + parser = gda_sql_parser_new (); + + stmt = gda_sql_parser_parse_string (parser, + "SELECT column_name FROM _columns WHERE " + "table_schema= ##schema::string AND " + "table_name= ##table_name::string " + "ORDER BY ordinal_position", NULL, error); + g_object_unref (parser); + if (!stmt) { + if (out_error) + *out_error = TRUE; + return NULL; + } + + if (!gda_statement_get_parameters (stmt, &(priv->params), error)) { + if (out_error) + *out_error = TRUE; + g_object_unref (stmt); + return NULL; + } + priv->stmt = stmt; + } + + + gboolean schema_specified = FALSE; + gboolean table_specified = FALSE; + if (priv->schema) { + schema_specified = TRUE; + g_assert (gda_set_set_holder_value (priv->params, NULL, "schema", + priv->schema)); + } + if (priv->table_name) { + table_specified = TRUE; + g_assert (gda_set_set_holder_value (priv->params, NULL, "table_name", + priv->table_name)); + } + if (!schema_specified && node) { + /* looking for a schema in @node's attributes */ + const GValue *cvalue; + cvalue = gda_tree_node_fetch_attribute (node, "schema"); + if (cvalue) { + GdaHolder *h = gda_set_get_holder (priv->params, "schema"); + if (!gda_holder_set_value (h, cvalue, error)) { + if (out_error) + *out_error = TRUE; + return NULL; + } + schema_specified = TRUE; + } + } + if (!table_specified && node) { + /* looking for a table in @node's attributes */ + const GValue *cvalue; + cvalue = gda_tree_node_fetch_attribute (node, "table_name"); + if (cvalue) { + GdaHolder *h = gda_set_get_holder (priv->params, "table_name"); + if (!gda_holder_set_value (h, cvalue, error)) { + if (out_error) + *out_error = TRUE; + return NULL; + } + table_specified = TRUE; + } + } + + if (!schema_specified) { + g_set_error (error, GDA_TREE_MANAGER_ERROR, GDA_TREE_MANAGER_UNKNOWN_ERROR, + "%s", _("No schema specified")); + if (out_error) + *out_error = TRUE; + return NULL; + } + + if (!table_specified) { + g_set_error (error, GDA_TREE_MANAGER_ERROR, GDA_TREE_MANAGER_UNKNOWN_ERROR, + "%s", _("No table specified")); + if (out_error) + *out_error = TRUE; + return NULL; + } + + model = gda_connection_statement_execute_select (scnc, priv->stmt, priv->params, error); + + if (!model) { + if (out_error) + *out_error = TRUE; + return NULL; + } + + GdaDataModelIter *iter; + iter = gda_data_model_create_iter (model); + for (; iter && gda_data_model_iter_move_next (iter);) { + GdaTreeNode* snode; + const GValue *cvalue; + + cvalue = gda_data_model_iter_get_value_at (iter, 0); + if (!cvalue) { + if (list) { + g_slist_free_full (list, (GDestroyNotify) g_object_unref); + } + if (out_error) + *out_error = TRUE; + g_set_error (error, GDA_TREE_MANAGER_ERROR, GDA_TREE_MANAGER_UNKNOWN_ERROR, + "%s", _("Unable to get column name")); + return NULL; + } + + snode = gda_tree_manager_create_node (manager, node, g_value_get_string (cvalue)); + gda_tree_node_set_node_attribute (snode, "column_name", cvalue, NULL); + list = g_slist_prepend (list, snode); + } + if (iter) + g_object_unref (iter); + g_object_unref (model); + + return list; +} diff --git a/.flatpak-builder/cache/objects/c8/84287c6e96a9770c454f9c01f69b4201628d662f87f433cc0ec0b8acb04908.dirtree b/.flatpak-builder/cache/objects/c8/84287c6e96a9770c454f9c01f69b4201628d662f87f433cc0ec0b8acb04908.dirtree new file mode 100644 index 0000000..c391a75 Binary files /dev/null and b/.flatpak-builder/cache/objects/c8/84287c6e96a9770c454f9c01f69b4201628d662f87f433cc0ec0b8acb04908.dirtree differ diff --git a/.flatpak-builder/cache/objects/c8/dc96c0ee8761e9a10c5acb33f48e6af1d3e35fbfea6cf888ba44b04b7e99b2.file b/.flatpak-builder/cache/objects/c8/dc96c0ee8761e9a10c5acb33f48e6af1d3e35fbfea6cf888ba44b04b7e99b2.file new file mode 100644 index 0000000..69163f6 Binary files /dev/null and b/.flatpak-builder/cache/objects/c8/dc96c0ee8761e9a10c5acb33f48e6af1d3e35fbfea6cf888ba44b04b7e99b2.file differ diff --git a/.flatpak-builder/cache/objects/c9/46fa0094a9ab62f6089388aec2f20f1be258fe21e6edcce290c46efcbba4d9.file b/.flatpak-builder/cache/objects/c9/46fa0094a9ab62f6089388aec2f20f1be258fe21e6edcce290c46efcbba4d9.file new file mode 100644 index 0000000..cc19742 Binary files /dev/null and b/.flatpak-builder/cache/objects/c9/46fa0094a9ab62f6089388aec2f20f1be258fe21e6edcce290c46efcbba4d9.file differ diff --git a/.flatpak-builder/cache/objects/c9/7684587e758106ee7321b2a621c27f944c9ff077fffbb3f85b1762db12336f.dirtree b/.flatpak-builder/cache/objects/c9/7684587e758106ee7321b2a621c27f944c9ff077fffbb3f85b1762db12336f.dirtree new file mode 100644 index 0000000..8778848 Binary files /dev/null and b/.flatpak-builder/cache/objects/c9/7684587e758106ee7321b2a621c27f944c9ff077fffbb3f85b1762db12336f.dirtree differ diff --git a/.flatpak-builder/cache/objects/c9/85d3154b079b8dfea518b36f10d501db06dc3d199b70ee33ee12d8c89912c4.file b/.flatpak-builder/cache/objects/c9/85d3154b079b8dfea518b36f10d501db06dc3d199b70ee33ee12d8c89912c4.file new file mode 100644 index 0000000..f8118a3 --- /dev/null +++ b/.flatpak-builder/cache/objects/c9/85d3154b079b8dfea518b36f10d501db06dc3d199b70ee33ee12d8c89912c4.file @@ -0,0 +1,519 @@ +/* gda-db-index.c + * + * Copyright (C) 2019-2020 Pavlo Solntsev + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "gda-db-index.h" +#include "gda-connection.h" +#include "gda-db-index-field.h" +#include "gda-server-operation.h" +#include "gda-server-provider.h" +#include "gda-lockable.h" +#include "gda-ddl-modifiable.h" +#include + +G_DEFINE_QUARK (gda_db_index_error, gda_db_index_error) + +typedef struct +{ + gboolean mUnique; + GSList *mFieldList; /* A list of GdaDbIndexField */ + GdaDbTable *mTable; /* A table associated with the index */ +} GdaDbIndexPrivate; + +/** + * SECTION:gda-db-index + * @short_description: Object to represent table index + * @see_also: #GdaDbTable, #GdaDbCatalog + * @stability: Stable + * @include: libgda/libgda.h + * + * The object #GdaDbIndex holds information about index in a table. Just populate the information + * using index API, set table as property, execute gda_ddl_modifiable_create() method. This + * method executes all needed DB manopulations to add the target index to the DB. This can be + * illustarted by the following example: + * + * |[ + * GdaDbTable *table = gda_db_table_new(); + * // Populate table as needed. + * GdaDbIndex *index = gda_db_index_new (); + * GdaDbIndexField *field = gda_db_index_field_new (); + * GdaDbColumn *fcol = gda_db_column_new (); + * GError *error = NULL; + * + * gda_db_index_set_unique (index, TRUE); + * gda_db_base_set_name (GDA_DB_BASE (index), "MyIndex"); + * + * gda_db_column_set_name (fcol, "name"); + * + * gda_db_index_field_set_column (field, fcol); + * gda_db_index_field_set_sort_order (field, GDA_DB_INDEX_SORT_ORDER_ASC); + * gda_db_index_append_field (index, field); + + * g_object_unref (fcol); + * g_object_unref (field); + * + * g_object_set (index, "table", table, NULL); + * + * res = gda_ddl_modifiable_create (GDA_DDL_MODIFIABLE(index), cnc, NULL, &error); + * + * if (!res) + * g_print("Error during index addition\n"); + * ]| + */ + +static void gda_ddl_modifiable_interface_init (GdaDdlModifiableInterface *iface); + +static gboolean gda_db_index_create (GdaDdlModifiable *self, GdaConnection *cnc, + gpointer user_data, GError **error); +static gboolean gda_db_index_drop (GdaDdlModifiable *self, GdaConnection *cnc, + gpointer user_data, GError **error); +static gboolean gda_db_index_rename (GdaDdlModifiable *old_name, GdaConnection *cnc, + gpointer new_name, GError **error); + + +G_DEFINE_TYPE_WITH_CODE (GdaDbIndex, gda_db_index, GDA_TYPE_DB_BASE, + G_ADD_PRIVATE(GdaDbIndex) + G_IMPLEMENT_INTERFACE (GDA_TYPE_DDL_MODIFIABLE, + gda_ddl_modifiable_interface_init)) + +enum { + PROP_0, + PROP_TABLE, + /* */ + N_PROPS +}; + +static GParamSpec *properties [N_PROPS] = {NULL}; + +GdaDbIndex * +gda_db_index_new (void) +{ + return g_object_new (GDA_TYPE_DB_INDEX, NULL); +} + +static void +gda_db_index_init (GdaDbIndex *self) +{ + GdaDbIndexPrivate *priv = gda_db_index_get_instance_private (self); + + priv->mFieldList = NULL; + priv->mUnique = TRUE; + priv->mTable = NULL; +} + +static void +gda_db_index_finalize (GObject *object) +{ + GdaDbIndex *self = GDA_DB_INDEX (object); + GdaDbIndexPrivate *priv = gda_db_index_get_instance_private (self); + + g_slist_free_full (priv->mFieldList, g_object_unref); + + G_OBJECT_CLASS (gda_db_index_parent_class)->finalize (object); +} + +static void +gda_db_index_dispose (GObject *object) +{ + GdaDbIndex *self = GDA_DB_INDEX (object); + GdaDbIndexPrivate *priv = gda_db_index_get_instance_private (self); + + if (priv->mTable) g_object_unref (priv->mTable); + + G_OBJECT_CLASS (gda_db_index_parent_class)->dispose (object); +} + +static void +gda_db_index_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + GdaDbIndex *self = GDA_DB_INDEX(object); + GdaDbIndexPrivate *priv = gda_db_index_get_instance_private (self); + + switch (prop_id) { + case PROP_TABLE: + g_value_set_object (value, priv->mTable); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +gda_db_index_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + GdaDbIndex *self = GDA_DB_INDEX(object); + GdaDbIndexPrivate *priv = gda_db_index_get_instance_private (self); + + switch (prop_id) { + case PROP_TABLE: + if (priv->mTable) + g_object_unref (priv->mTable); + + priv->mTable = g_value_dup_object (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +gda_db_index_class_init (GdaDbIndexClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->finalize = gda_db_index_finalize; + object_class->dispose = gda_db_index_dispose; + object_class->get_property = gda_db_index_get_property; + object_class->set_property = gda_db_index_set_property; + + properties[PROP_TABLE] = g_param_spec_object ("table", + "Table", + "Table associated with index", + GDA_TYPE_DB_TABLE, + G_PARAM_READWRITE); + + g_object_class_install_properties (object_class, N_PROPS, properties); +} + +static void +gda_ddl_modifiable_interface_init (GdaDdlModifiableInterface *iface) +{ + iface->create = gda_db_index_create; + iface->drop = gda_db_index_drop; + iface->rename = gda_db_index_rename; +} + +/** + * gda_db_index_set_unique: + * @self: #GdaDbIndex instance + * @val: if set to %TRUE UNIQUE index type will be used. + * + * If @val is %TRUE a "UNIQUE" will be added to the INDEX CREATE command, e.g. + * CREATE UNIQUE INDEX ... + * + * Stability: Stable + * Since: 6.0 + */ +void +gda_db_index_set_unique (GdaDbIndex *self, + gboolean val) +{ + G_DEBUG_HERE(); + g_return_if_fail (self); + + GdaDbIndexPrivate *priv = gda_db_index_get_instance_private (self); + priv->mUnique = val; +} + +/** + * gda_db_index_get_unique: + * @self: instance os #GdaDbIndex to use + * + * Returns: state for UNIQUE. This method will abort if @self is %NULL + * + * Stability: Stable + * Since: 6.0 + */ +gboolean +gda_db_index_get_unique (GdaDbIndex *self) +{ + G_DEBUG_HERE(); + GdaDbIndexPrivate *priv = gda_db_index_get_instance_private (self); + return priv->mUnique; +} + +/** + * gda_db_index_append_field: + * @self: an instance of #GdaDbIndex + * @field: a field to set + * + * Append to index filed to the current index instance, The @self object will recieve full + * ownership of the field. After this call, the reference count for @field will be increased and + * the instance of @fiels must be destroyed by calling g_object_unref() + * + * Stability: Stable + * Since: 6.0 + */ +void +gda_db_index_append_field (GdaDbIndex *self, + GdaDbIndexField *field) +{ + G_DEBUG_HERE(); + g_return_if_fail (self); + g_return_if_fail (field); + + GdaDbIndexPrivate *priv = gda_db_index_get_instance_private (self); +// Check if field name already exists, then update values, otherwise append + + if (!priv->mFieldList) + priv->mFieldList = g_slist_append (priv->mFieldList, g_object_ref (field)); + else + { + GSList *it = priv->mFieldList; + for (; it != NULL; it = it->next) + { + GdaDbColumn *current_col = gda_db_index_field_get_column (GDA_DB_INDEX_FIELD (it->data)); + GdaDbColumn *new_col = gda_db_index_field_get_column (field); + + if (gda_db_base_compare (GDA_DB_BASE (current_col), GDA_DB_BASE (new_col))) + priv->mFieldList = g_slist_append (priv->mFieldList, g_object_ref (field)); + else + { + gda_db_index_field_set_collate (GDA_DB_INDEX_FIELD (it->data), + gda_db_index_field_get_collate (field)); + gda_db_index_field_set_sort_order(GDA_DB_INDEX_FIELD (it->data), + gda_db_index_field_get_sort_order (field)); + } + } + } +} + +/** + * gda_db_index_remove_field: + * @self: instance of #GdaDbIndex + * @name: Name of the column where field should be removed. + * + * Stability: Stable + * Since: 6.0 + */ +void +gda_db_index_remove_field (GdaDbIndex *self, + const gchar *name) +{ + G_DEBUG_HERE(); + g_return_if_fail (self); + g_return_if_fail (name); + + GdaDbIndexPrivate *priv = gda_db_index_get_instance_private (self); + + GSList *it = priv->mFieldList; + for (; it != NULL; it = it->next) + { + const gchar *full_name = gda_db_base_get_full_name (GDA_DB_BASE (it->data)); + + if (!g_strcmp0 (full_name, name)) + priv->mFieldList = g_slist_remove (priv->mFieldList, it->data); + } +} + +/** + * gda_db_index_get_fields: + * @self: an instance of #GdaDbIndex + * + * This function is thread safe, that is, @cnc will be locked. + * + * Returns: (transfer none) (nullable) (element-type Gda.DbIndexField): A list of #GdaDbIndexField + * + * Stability: Stable + * Since: 6.0 + */ +GSList * +gda_db_index_get_fields (GdaDbIndex *self) +{ + G_DEBUG_HERE(); + GdaDbIndexPrivate *priv = gda_db_index_get_instance_private (self); + + return priv->mFieldList; +} + +/** + * gda_db_index_drop: + * @self: an instance of #GdaDbIndex to work to drop + * @cnc: opened connection as the #GdaConnection + * @ifexists: flag for IF EXSISTS + * @error: an error storage + * + * Drop the index from the DB. + * + * Stability: Stable + * Since: 6.0 + */ +static gboolean +gda_db_index_drop (GdaDdlModifiable *self, + GdaConnection *cnc, + gpointer user_data, + GError **error) +{ + G_DEBUG_HERE(); + g_return_val_if_fail (GDA_IS_DB_INDEX (self), FALSE); + + GdaServerProvider *provider = NULL; + GdaServerOperation *op = NULL; + + gda_lockable_lock (GDA_LOCKABLE (cnc)); + + provider = gda_connection_get_provider (cnc); + + op = gda_server_provider_create_operation (provider, + cnc, + GDA_SERVER_OPERATION_DROP_INDEX, + NULL, + error); + if (!op) + goto on_error; + + if (!gda_server_operation_set_value_at (op, gda_db_base_get_full_name (GDA_DB_BASE (self)), + error, "/INDEX_DESC_P/INDEX_NAME")) + goto on_error; + + if (!gda_server_operation_set_value_at (op, GDA_BOOL_TO_STR (TRUE), error, + "/INDEX_DESC_P/INDEX_IFEXISTS")) + goto on_error; + + if (!gda_server_provider_perform_operation (provider, cnc, op, error)) + goto on_error; + + g_object_unref (op); + + gda_lockable_unlock (GDA_LOCKABLE (cnc)); + + return TRUE; + +on_error: + if (op) g_object_unref (op); + + gda_lockable_unlock (GDA_LOCKABLE (cnc)); + + return FALSE; +} + +/** + * gda_db_index_create: + * @self is a instance of GdaDbIndex + * @cnc is a opened connection + * @user_data is ignored + * @error an error holder + * + */ +static gboolean +gda_db_index_create (GdaDdlModifiable *self, + GdaConnection *cnc, + gpointer user_data, + GError **error) +{ + G_DEBUG_HERE(); + GdaServerProvider *provider = NULL; + GdaServerOperation *op = NULL; + + GdaDbIndex *index = GDA_DB_INDEX (self); + GdaDbTable *table = NULL; + + gda_lockable_lock (GDA_LOCKABLE (cnc)); + + provider = gda_connection_get_provider (cnc); + + op = gda_server_provider_create_operation (provider, cnc, GDA_SERVER_OPERATION_CREATE_INDEX, + NULL, error); + + if (!op) + goto on_error; + + if (gda_db_index_get_unique (index)) + { + if (!gda_server_operation_set_value_at (op, "UNIQUE", error, + "/INDEX_DEF_P/INDEX_TYPE")) + goto on_error; + } + + + if (!gda_server_operation_set_value_at (op, gda_db_base_get_full_name (GDA_DB_BASE (index)), + error, "/INDEX_DEF_P/INDEX_NAME")) + goto on_error; + + g_object_get (index, "table", &table, NULL); + + if (!table) + goto on_error; + + if (!gda_server_operation_set_value_at (op, gda_db_base_get_name (GDA_DB_BASE (table)), + error, "/INDEX_DEF_P/INDEX_ON_TABLE")) + goto on_error; + + g_object_unref (table); + + if (!gda_server_operation_set_value_at (op, "TRUE", + error, "/INDEX_DEF_P/INDEX_IFNOTEXISTS")) + goto on_error; + + GSList *it = gda_db_index_get_fields (index); + gint i = 0; + + for (; it != NULL; it = it->next, i++) + { + GdaDbColumn *col = gda_db_index_field_get_column (GDA_DB_INDEX_FIELD (it->data)); + + if (!gda_server_operation_set_value_at (op, + gda_db_column_get_name (col), + error, + "/INDEX_FIELDS_S/%d/INDEX_FIELD", + i)) + goto on_error; + + if (!gda_server_operation_set_value_at (op, + gda_db_index_field_get_collate (it->data), + error, + "/INDEX_FIELDS_S/%d/INDEX_COLLATE", + i)) + goto on_error; + + if (!gda_server_operation_set_value_at (op, + gda_db_index_field_get_sort_order_str (it->data), + error, + "/INDEX_FIELDS_S/%d/INDEX_SORT_ORDER", + i)) + goto on_error; + } + + if (!gda_server_provider_perform_operation (provider, cnc, op, error)) + goto on_error; + + g_object_unref (op); + + gda_lockable_unlock (GDA_LOCKABLE (cnc)); + + return TRUE; + +on_error: + if (op) g_object_unref (op); + + if (table) g_object_unref (table); + + gda_lockable_unlock (GDA_LOCKABLE (cnc)); + + return FALSE; +} + +static gboolean +gda_db_index_rename (GdaDdlModifiable *old_name, + GdaConnection *cnc, + gpointer new_name, + GError **error) +{ + g_set_error (error, GDA_DDL_MODIFIABLE_ERROR, + GDA_DDL_MODIFIABLE_NOT_IMPLEMENTED, + _("Operation is not implemented for the used provider")); + + return FALSE; +} diff --git a/.flatpak-builder/cache/objects/c9/89d52e92b67292032e4e666dbcb9e928bc0ad84a7408a4866768616d590f81.file b/.flatpak-builder/cache/objects/c9/89d52e92b67292032e4e666dbcb9e928bc0ad84a7408a4866768616d590f81.file new file mode 100644 index 0000000..b8aa0d5 --- /dev/null +++ b/.flatpak-builder/cache/objects/c9/89d52e92b67292032e4e666dbcb9e928bc0ad84a7408a4866768616d590f81.file @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2000 Reinhard Müller + * Copyright (C) 2000 - 2002 Rodrigo Moya + * Copyright (C) 2001 Carlos Perelló Marín + * Copyright (C) 2001 - 2014 Vivien Malerba + * Copyright (C) 2002 Gonzalo Paniagua Javier + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GDA_CONNECTION_INTERNAL_H_ +#define __GDA_CONNECTION_INTERNAL_H_ + +#include +#include + +G_BEGIN_DECLS + +/* + * Warnings + */ +#ifdef GDA_DEBUG +#define ASSERT_TABLE_NAME(x,y) g_assert (!strcmp ((x), (y))) +#define WARN_META_UPDATE_FAILURE(x,method) if (!(x)) g_print ("%s:%d %s (meta method => %s) ERROR: %s\n", __FILE__, __LINE__, __FUNCTION__, (method), error && *error && (*error)->message ? (*error)->message : "???") +#else +#define ASSERT_TABLE_NAME(x,y) +#define WARN_META_UPDATE_FAILURE(x,method) +#endif + +/* + * Misc. + */ +GdaWorker *_gda_connection_get_worker (GdaConnection *cnc); +guint _gda_connection_get_exec_slowdown (GdaConnection *cnc); + +void _gda_connection_set_status (GdaConnection *cnc, GdaConnectionStatus status); +void gda_connection_increase_usage (GdaConnection *cnc); +void gda_connection_decrease_usage (GdaConnection *cnc); + +/* + * Opens a connection to an SQLite database. This function is intended to be used + * internally when objects require an SQLite connection, for example for the GdaMetaStore + * object + */ +GdaConnection *_gda_open_internal_sqlite_connection (const gchar *cnc_string); + +/* + * Used by virtual connections to keep meta data up to date when a table + * is added or removed, without using the update_meta_store_after_statement_exec() + * because it may not be called everytime + */ +void _gda_connection_signal_meta_table_update (GdaConnection *cnc, const gchar *table_name); +gchar *_gda_connection_compute_table_virtual_name (GdaConnection *cnc, const gchar *table_name); + +G_END_DECLS + +#endif diff --git a/.flatpak-builder/cache/objects/c9/a009bba47af2561243b84da64930b10e4d2bf31e6375a3e4b29144246f1a02.file b/.flatpak-builder/cache/objects/c9/a009bba47af2561243b84da64930b10e4d2bf31e6375a3e4b29144246f1a02.file new file mode 100644 index 0000000..abfd60c Binary files /dev/null and b/.flatpak-builder/cache/objects/c9/a009bba47af2561243b84da64930b10e4d2bf31e6375a3e4b29144246f1a02.file differ diff --git a/.flatpak-builder/cache/objects/ca/7f5c284ee3949bf4135545a83a138a03beabe62acd42c8ac467c60aa330928.dirtree b/.flatpak-builder/cache/objects/ca/7f5c284ee3949bf4135545a83a138a03beabe62acd42c8ac467c60aa330928.dirtree new file mode 100644 index 0000000..40594db Binary files /dev/null and b/.flatpak-builder/cache/objects/ca/7f5c284ee3949bf4135545a83a138a03beabe62acd42c8ac467c60aa330928.dirtree differ diff --git a/.flatpak-builder/cache/objects/ca/9b91a2102649e0b6b13ecfb682d317dc12c1e8fd5a15131545709097fc17b6.dirtree b/.flatpak-builder/cache/objects/ca/9b91a2102649e0b6b13ecfb682d317dc12c1e8fd5a15131545709097fc17b6.dirtree new file mode 100644 index 0000000..a955656 Binary files /dev/null and b/.flatpak-builder/cache/objects/ca/9b91a2102649e0b6b13ecfb682d317dc12c1e8fd5a15131545709097fc17b6.dirtree differ diff --git a/.flatpak-builder/cache/objects/ca/9e1dd16d1f0f2bfd1e5ec5f0faec9b9b1363ebda3ff7c916bc93fc62c504b5.dirtree b/.flatpak-builder/cache/objects/ca/9e1dd16d1f0f2bfd1e5ec5f0faec9b9b1363ebda3ff7c916bc93fc62c504b5.dirtree new file mode 100644 index 0000000..cc121e0 Binary files /dev/null and b/.flatpak-builder/cache/objects/ca/9e1dd16d1f0f2bfd1e5ec5f0faec9b9b1363ebda3ff7c916bc93fc62c504b5.dirtree differ diff --git a/.flatpak-builder/cache/objects/ca/bea7425f22b84566b11c223ad4e1d90e450f5834eba9bff1b3612c994ddee3.file b/.flatpak-builder/cache/objects/ca/bea7425f22b84566b11c223ad4e1d90e450f5834eba9bff1b3612c994ddee3.file new file mode 100644 index 0000000..aae1b66 --- /dev/null +++ b/.flatpak-builder/cache/objects/ca/bea7425f22b84566b11c223ad4e1d90e450f5834eba9bff1b3612c994ddee3.file @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2001 - 2002 Carlos Perelló Marín + * Copyright (C) 2002 Gonzalo Paniagua Javier + * Copyright (C) 2002 Rodrigo Moya + * Copyright (C) 2007 - 2012 Vivien Malerba + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GDA_SQLITE_PROVIDER_H__ +#define __GDA_SQLITE_PROVIDER_H__ + +#include + + +G_BEGIN_DECLS + +#define GDA_TYPE_SQLITE_PROVIDER (gda_sqlite_provider_get_type()) + +G_DECLARE_DERIVABLE_TYPE (GdaSqliteProvider, gda_sqlite_provider, GDA, SQLITE_PROVIDER, GdaServerProvider) + +struct _GdaSqliteProviderClass { + GdaServerProviderClass parent_class; + + gpointer (*get_api) (GdaSqliteProvider *prov); + + /* Padding for future expansion */ + void (*_gda_reserved1) (void); + void (*_gda_reserved2) (void); +}; + +gpointer gda_sqlite_provider_get_api (GdaSqliteProvider *prov); + +G_END_DECLS + +#endif diff --git a/.flatpak-builder/cache/objects/ca/d176d868e3657ee982f1ec9d690728f3d0285a086f2e1693b0db29974f4e18.dirtree b/.flatpak-builder/cache/objects/ca/d176d868e3657ee982f1ec9d690728f3d0285a086f2e1693b0db29974f4e18.dirtree new file mode 100644 index 0000000..fddbb84 Binary files /dev/null and b/.flatpak-builder/cache/objects/ca/d176d868e3657ee982f1ec9d690728f3d0285a086f2e1693b0db29974f4e18.dirtree differ diff --git a/.flatpak-builder/cache/objects/cb/93b2a7c362e756d0397da289d4f0be5b14349457f3c4edb45961f711fe974f.dirtree b/.flatpak-builder/cache/objects/cb/93b2a7c362e756d0397da289d4f0be5b14349457f3c4edb45961f711fe974f.dirtree new file mode 100644 index 0000000..b1b49a0 Binary files /dev/null and b/.flatpak-builder/cache/objects/cb/93b2a7c362e756d0397da289d4f0be5b14349457f3c4edb45961f711fe974f.dirtree differ diff --git a/.flatpak-builder/cache/objects/cb/a9aded581235e5889735bbbf4a0d118648b7f149783a3538ec3416957dd4f4.file b/.flatpak-builder/cache/objects/cb/a9aded581235e5889735bbbf4a0d118648b7f149783a3538ec3416957dd4f4.file new file mode 120000 index 0000000..df68638 --- /dev/null +++ b/.flatpak-builder/cache/objects/cb/a9aded581235e5889735bbbf4a0d118648b7f149783a3538ec3416957dd4f4.file @@ -0,0 +1 @@ +../../share/runtime/locale/sr/share/sr@latin \ No newline at end of file diff --git a/.flatpak-builder/cache/objects/cb/b517c181813792670440f6c20170a472281660ac1746b5fc16568dc2361f50.dirtree b/.flatpak-builder/cache/objects/cb/b517c181813792670440f6c20170a472281660ac1746b5fc16568dc2361f50.dirtree new file mode 100644 index 0000000..429468b Binary files /dev/null and b/.flatpak-builder/cache/objects/cb/b517c181813792670440f6c20170a472281660ac1746b5fc16568dc2361f50.dirtree differ diff --git a/.flatpak-builder/cache/objects/cb/d13efce88f1257798c0617335ee33b2ed49bef5b4a7b4eec126d1401c21a0a.dirtree b/.flatpak-builder/cache/objects/cb/d13efce88f1257798c0617335ee33b2ed49bef5b4a7b4eec126d1401c21a0a.dirtree new file mode 100644 index 0000000..27455bd Binary files /dev/null and b/.flatpak-builder/cache/objects/cb/d13efce88f1257798c0617335ee33b2ed49bef5b4a7b4eec126d1401c21a0a.dirtree differ diff --git a/.flatpak-builder/cache/objects/cc/01e394bec112c524775692f017e229337274df801dfafcd7f3bb140201ef97.dirtree b/.flatpak-builder/cache/objects/cc/01e394bec112c524775692f017e229337274df801dfafcd7f3bb140201ef97.dirtree new file mode 100644 index 0000000..26dd11c Binary files /dev/null and b/.flatpak-builder/cache/objects/cc/01e394bec112c524775692f017e229337274df801dfafcd7f3bb140201ef97.dirtree differ diff --git a/.flatpak-builder/cache/objects/cc/0c78378a310e0e7df7b0150c86f369048f350b240f5c348582f97f43dbe9fb.dirtree b/.flatpak-builder/cache/objects/cc/0c78378a310e0e7df7b0150c86f369048f350b240f5c348582f97f43dbe9fb.dirtree new file mode 100644 index 0000000..a4b1c22 Binary files /dev/null and b/.flatpak-builder/cache/objects/cc/0c78378a310e0e7df7b0150c86f369048f350b240f5c348582f97f43dbe9fb.dirtree differ diff --git a/.flatpak-builder/cache/objects/cc/193ce822d2f643b86723aba73e26b603e7aa9e398c48c861f882b345f64dfa.file b/.flatpak-builder/cache/objects/cc/193ce822d2f643b86723aba73e26b603e7aa9e398c48c861f882b345f64dfa.file new file mode 100644 index 0000000..d2e6010 Binary files /dev/null and b/.flatpak-builder/cache/objects/cc/193ce822d2f643b86723aba73e26b603e7aa9e398c48c861f882b345f64dfa.file differ diff --git a/.flatpak-builder/cache/objects/cc/22509df3d60b486f730b1965ba6e6910277614c67532a9d2a56570b47ab04e.dirtree b/.flatpak-builder/cache/objects/cc/22509df3d60b486f730b1965ba6e6910277614c67532a9d2a56570b47ab04e.dirtree new file mode 100644 index 0000000..f872b30 Binary files /dev/null and b/.flatpak-builder/cache/objects/cc/22509df3d60b486f730b1965ba6e6910277614c67532a9d2a56570b47ab04e.dirtree differ diff --git a/.flatpak-builder/cache/objects/cc/387c1e1ae9852a09bd8fbe59c98f8c475598a8ccaa7ee73196c736e763e9a8.file b/.flatpak-builder/cache/objects/cc/387c1e1ae9852a09bd8fbe59c98f8c475598a8ccaa7ee73196c736e763e9a8.file new file mode 120000 index 0000000..3a2f148 --- /dev/null +++ b/.flatpak-builder/cache/objects/cc/387c1e1ae9852a09bd8fbe59c98f8c475598a8ccaa7ee73196c736e763e9a8.file @@ -0,0 +1 @@ +../../share/runtime/locale/cs/share/cs \ No newline at end of file diff --git a/.flatpak-builder/cache/objects/cc/700d46f407c6c5ab2d5dde474366a928b7398277e61162e7f8ec06f469f07e.file b/.flatpak-builder/cache/objects/cc/700d46f407c6c5ab2d5dde474366a928b7398277e61162e7f8ec06f469f07e.file new file mode 100644 index 0000000..e69de29 diff --git a/.flatpak-builder/cache/objects/cd/007a41123ad39ad49ad64c43976aee77d637b46cba024df27053e0daed9fc6.dirtree b/.flatpak-builder/cache/objects/cd/007a41123ad39ad49ad64c43976aee77d637b46cba024df27053e0daed9fc6.dirtree new file mode 100644 index 0000000..f4c6ce7 Binary files /dev/null and b/.flatpak-builder/cache/objects/cd/007a41123ad39ad49ad64c43976aee77d637b46cba024df27053e0daed9fc6.dirtree differ diff --git a/.flatpak-builder/cache/objects/cd/037ed924d1f16d09007fcd0e3053d3610a448b1cf4232ad9543c6fd1e2925a.dirtree b/.flatpak-builder/cache/objects/cd/037ed924d1f16d09007fcd0e3053d3610a448b1cf4232ad9543c6fd1e2925a.dirtree new file mode 100644 index 0000000..99bf588 Binary files /dev/null and b/.flatpak-builder/cache/objects/cd/037ed924d1f16d09007fcd0e3053d3610a448b1cf4232ad9543c6fd1e2925a.dirtree differ diff --git a/.flatpak-builder/cache/objects/cd/0992ca4aafadfb433d11a50e5292d96b0859ee3055a591df73ca39d2f96b2d.dirtree b/.flatpak-builder/cache/objects/cd/0992ca4aafadfb433d11a50e5292d96b0859ee3055a591df73ca39d2f96b2d.dirtree new file mode 100644 index 0000000..ec7dac6 Binary files /dev/null and b/.flatpak-builder/cache/objects/cd/0992ca4aafadfb433d11a50e5292d96b0859ee3055a591df73ca39d2f96b2d.dirtree differ diff --git a/.flatpak-builder/cache/objects/cd/2c1196bc1fff5b95b4afbfe19135af26d96e7c5f3b7f1af0fb41f8a7a1f5e7.dirtree b/.flatpak-builder/cache/objects/cd/2c1196bc1fff5b95b4afbfe19135af26d96e7c5f3b7f1af0fb41f8a7a1f5e7.dirtree new file mode 100644 index 0000000..cf132c8 Binary files /dev/null and b/.flatpak-builder/cache/objects/cd/2c1196bc1fff5b95b4afbfe19135af26d96e7c5f3b7f1af0fb41f8a7a1f5e7.dirtree differ diff --git a/.flatpak-builder/cache/objects/cd/697354596cae2933dd8a3f79eaec1eab68bb5bc288a98547786b02423e4c81.dirtree b/.flatpak-builder/cache/objects/cd/697354596cae2933dd8a3f79eaec1eab68bb5bc288a98547786b02423e4c81.dirtree new file mode 100644 index 0000000..8c54b17 Binary files /dev/null and b/.flatpak-builder/cache/objects/cd/697354596cae2933dd8a3f79eaec1eab68bb5bc288a98547786b02423e4c81.dirtree differ diff --git a/.flatpak-builder/cache/objects/ce/47a8b8df566ef0081f3ab5820de7343f68d35d386e938dfff2a52df12b2cf8.commit b/.flatpak-builder/cache/objects/ce/47a8b8df566ef0081f3ab5820de7343f68d35d386e938dfff2a52df12b2cf8.commit new file mode 100644 index 0000000..713cb26 Binary files /dev/null and b/.flatpak-builder/cache/objects/ce/47a8b8df566ef0081f3ab5820de7343f68d35d386e938dfff2a52df12b2cf8.commit differ diff --git a/.flatpak-builder/cache/objects/ce/748d991432edbf0ebe47d6da92c890b32b9848a814ae2e7dd8f1eae76e7d1f.dirtree b/.flatpak-builder/cache/objects/ce/748d991432edbf0ebe47d6da92c890b32b9848a814ae2e7dd8f1eae76e7d1f.dirtree new file mode 100644 index 0000000..d0b52be Binary files /dev/null and b/.flatpak-builder/cache/objects/ce/748d991432edbf0ebe47d6da92c890b32b9848a814ae2e7dd8f1eae76e7d1f.dirtree differ diff --git a/.flatpak-builder/cache/objects/ce/b0f721593f7dd92fc05d585990acb1eef3e5855979d0d20608bc51d4d2b326.dirtree b/.flatpak-builder/cache/objects/ce/b0f721593f7dd92fc05d585990acb1eef3e5855979d0d20608bc51d4d2b326.dirtree new file mode 100644 index 0000000..7496413 Binary files /dev/null and b/.flatpak-builder/cache/objects/ce/b0f721593f7dd92fc05d585990acb1eef3e5855979d0d20608bc51d4d2b326.dirtree differ diff --git a/.flatpak-builder/cache/objects/ce/bd17bb0c2fe0e6c6e2acca9100500b82dfc7932f39462a2331c8684960ad5c.dirtree b/.flatpak-builder/cache/objects/ce/bd17bb0c2fe0e6c6e2acca9100500b82dfc7932f39462a2331c8684960ad5c.dirtree new file mode 100644 index 0000000..1835407 Binary files /dev/null and b/.flatpak-builder/cache/objects/ce/bd17bb0c2fe0e6c6e2acca9100500b82dfc7932f39462a2331c8684960ad5c.dirtree differ diff --git a/.flatpak-builder/cache/objects/ce/efc8eb06b6518cd2112feede6b91711944804a05f1ffa82b9c8c08b09ac0d8.dirtree b/.flatpak-builder/cache/objects/ce/efc8eb06b6518cd2112feede6b91711944804a05f1ffa82b9c8c08b09ac0d8.dirtree new file mode 100644 index 0000000..b31890c Binary files /dev/null and b/.flatpak-builder/cache/objects/ce/efc8eb06b6518cd2112feede6b91711944804a05f1ffa82b9c8c08b09ac0d8.dirtree differ diff --git a/.flatpak-builder/cache/objects/cf/40e0680e1e50ed27436596248a82fa2cae3c0f90841d12e041312fb171becc.file b/.flatpak-builder/cache/objects/cf/40e0680e1e50ed27436596248a82fa2cae3c0f90841d12e041312fb171becc.file new file mode 100644 index 0000000..e9a406f --- /dev/null +++ b/.flatpak-builder/cache/objects/cf/40e0680e1e50ed27436596248a82fa2cae3c0f90841d12e041312fb171becc.file @@ -0,0 +1,222 @@ +/* + * Copyright (C) 2007 - 2011 Vivien Malerba + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GDA_VCONNECTION_DATA_MODEL_H__ +#define __GDA_VCONNECTION_DATA_MODEL_H__ + +#include "gda-virtual-connection.h" +#include + +#define GDA_TYPE_VCONNECTION_DATA_MODEL (gda_vconnection_data_model_get_type()) + +G_BEGIN_DECLS + +typedef struct _GdaVconnectionDataModelSpec GdaVconnectionDataModelSpec; +typedef struct _GdaVconnectionDataModelFilter GdaVconnectionDataModelFilter; + +/** + * GdaVconnectionDataModelCreateColumnsFunc: + * @Param1: a pointer to a #GdaVconnectionDataModelSpec structure + * @Param2: a place to store errors, or %NULL + * @Returns: (element-type GdaColumn) (transfer full): a new list of #GdaColumn objects + * + * Function called to create the virtual table's columns, as #GdaColumn objects. + */ +typedef GList *(*GdaVconnectionDataModelCreateColumnsFunc) (GdaVconnectionDataModelSpec *, GError **); + +/** + * GdaVconnectionDataModelCreateModelFunc: + * @Param1: a pointer to a #GdaVconnectionDataModelSpec structure + * @Returns: (transfer full): a new #GdaDataModel + * + * Function called to create a #GdaDataModel object, called when a virtual table's data need to + * be accessed, and when optimization is not handled. + */ +typedef GdaDataModel *(*GdaVconnectionDataModelCreateModelFunc) (GdaVconnectionDataModelSpec *); + +/** + * GdaVconnectionDataModelFunc: + * @Param1: (nullable): a pointer to a #GdaDataModel + * @Param2: the name of the table represented by @Param1 + * @Param3: a data pointer, passed as last ergument to gda_vconnection_data_model_foreach() + * + * This function is called for every #GdaDataModel representing a table in a #GdaVconnectionDataModel + * connection, when using the gda_vconnection_data_model_foreach() method. + */ +typedef void (*GdaVconnectionDataModelFunc) (GdaDataModel *, const gchar *, gpointer ); + +/** + * GdaVconnectionDataModelFilter: + * + * This structure contains data which should be analysed to produce a data model (used as data + * for a virtual table) when a #GdaVconnectionDataModelCreateFModelFunc is called. The structure + * contains an input part (which should not be modified) and and output part (it is + * closely mapped with SQLite's sqlite3_index_info type). + * + * A pointer to this structure is passed to the #GdaVconnectionDataModelParseFilterFunc function + * and the function has to modify the variables in the output part (marked as *Outputs*). + * + * The @idxNum and @idxPointer are passed to the #GdaVconnectionDataModelCreateFModelFunc function call + * and they represent nothing specific except that the GdaVconnectionDataModelParseFilterFunc and + * GdaVconnectionDataModelCreateFModelFunc functions need to agree on their meaning. + * + * See the gda-vconnection-hub.c file for an usage example. + */ +struct _GdaVconnectionDataModelFilter { + /* Inputs */ + int nConstraint; /* Number of entries in aConstraint */ + struct GdaVirtualConstraint { + int iColumn; /* Column on left-hand side of constraint */ + GdaSqlOperatorType op; /* Constraint operator, among _EQ, _LT, _LEQ, _GT, _GEQ, _REGEXP */ + } *aConstraint; /* Table of WHERE clause constraints */ + int nOrderBy; /* Number of terms in the ORDER BY clause */ + struct GdaVirtualOrderby { + int iColumn; /* Column number */ + gboolean desc; /* TRUE for DESC. FALSE for ASC. */ + } *aOrderBy; /* The ORDER BY clause */ + + /* Outputs */ + struct GdaVirtualConstraintUsage { + int argvIndex; /* if >0, constraint is part of argv to xFilter */ + gboolean omit; /* Do not code a test for this constraint if TRUE */ + } *aConstraintUsage; + int idxNum; /* Number used to identify the index */ + gpointer idxPointer; /* Pointer used to identify the index */ + gboolean orderByConsumed; /* TRUE if output is already ordered */ + double estimatedCost; /* Estimated cost of using this index */ +}; + +/** + * GdaVconnectionDataModelParseFilterFunc: + * @Param1: a pointer to a #GdaVconnectionDataModelSpec structure + * @Param2: a pointer to a #GdaVconnectionDataModelFilter structure + * + * This function actually analyses the proposed optimization and modified @Param2 to tell the database + * engine how (if applicable) it implements the optimization. + */ +typedef void (*GdaVconnectionDataModelParseFilterFunc) (GdaVconnectionDataModelSpec *, GdaVconnectionDataModelFilter *); + +/** + * GdaVconnectionDataModelCreateFModelFunc: + * @Param1: a pointer to a #GdaVconnectionDataModelSpec structure + * @Param2: the index number chosen to actually execute the optimization (from #GdaVconnectionDataModelFilter's #idxNum attribute) + * @Param3: corresponds to the #GdaVconnectionDataModelFilter's #idxPointer attribute + * @Param4: size of @Param5 + * @Param5: an array of #GValue, as specified by the #GdaVconnectionDataModelFilter's #aConstraintUsage's #argvIndex value + * @Returns: (transfer full): a new #GdaDataModel + * + * Function called to create a #GdaDataModel object, called when a virtual table's data need to + * be accessed, and when optimization is handled. + */ +typedef GdaDataModel *(*GdaVconnectionDataModelCreateFModelFunc) (GdaVconnectionDataModelSpec *, int, const char *, int, GValue **); + +/** + * GdaVconnectionDataModelSpec: + * @data_model: (nullable): a #GdaDataModel, or %NULL + * @create_columns_func: (nullable): a pointer to a #GdaVconnectionDataModelCreateColumnsFunc function, or %NULL + * @create_model_func: (nullable): a pointer to a #GdaVconnectionDataModelCreateModelFunc function, or %NULL + * @create_filter_func: (nullable): a pointer to a #GdaVconnectionDataModelParseFilterFunc function, or %NULL + * @create_filtered_model_func: (nullable): a pointer to a #GdaVconnectionDataModelCreateFModelFunc function, or %NULL + * + * This structure holds all the information supplied to declare a virtual table using + * gda_vconnection_data_model_add(). You don't need to provider pointers for all the functions and + * for @data_model, but the following rules have to be respected: + * + * @data_model is not %NULL and all the function pointers are %NULL: this is the situation + * when the virtual table's contents is defined once by @data_model + * @data_model is %NULL and @create_columns_func is not %NULL: + * + * @create_filtered_model_func is not %NULL: this is the situation where the + * virtual table's associated data model handles filter optimizations. + * @create_model_func is ignored in this case. + * + * @create_model_func is not %NULL: this is the situation where the + * virtual table's associated data model does not handle filter optimizations + * + * + * + * + * + * Note that if specifying a @create_filtered_model_func, you should also specifiy a @create_filter_func + * function which is actually responsible for analysing the optimization. + */ +struct _GdaVconnectionDataModelSpec { + GdaDataModel *data_model; //FIXME: Use GWeakRef + GdaVconnectionDataModelCreateColumnsFunc create_columns_func; + GdaVconnectionDataModelCreateModelFunc create_model_func; + + GdaVconnectionDataModelParseFilterFunc create_filter_func; + GdaVconnectionDataModelCreateFModelFunc create_filtered_model_func; +}; +#define GDA_VCONNECTION_DATA_MODEL_SPEC(x) ((GdaVconnectionDataModelSpec*)(x)) + + +G_DECLARE_DERIVABLE_TYPE (GdaVconnectionDataModel, gda_vconnection_data_model, GDA, VCONNECTION_DATA_MODEL, GdaVirtualConnection) + +struct _GdaVconnectionDataModelClass { + GdaVirtualConnectionClass parent_class; + + void (*vtable_created) (GdaVconnectionDataModel *cnc, + const gchar *table_name); + void (*vtable_dropped) (GdaVconnectionDataModel *cnc, + const gchar *table_name); + + /*< private >*/ + /* Padding for future expansion */ + void (*_gda_reserved1) (void); + void (*_gda_reserved2) (void); +}; + +/** + * SECTION:gda-vconnection-data-model + * @short_description: Virtual connection based on a list of GdaDataModel + * @title: GdaVconnectionDataModel + * @stability: Stable + * @see_also: The #GdaVproviderDataModel provider to use to create such connection objects. + * + * The #GdaVconnectionDataModel is a virtual connection in which #GdaDataModel data models can be added + * or removed, each representing a table in the connection, the gda_vconnection_data_model_add_model() + * and gda_vconnection_data_model_remove() methods. + * + * Furthermore it is possible to declare tables without any associated data model yet, + * the real data model being automatically created when the + * table's data is needed. This allows more dynamic table's contents and filtering optimizations. + * See the gda_vconnection_data_model_add() and gda_vconnection_data_model_remove() methods. The + * filtering optimizations are based on SQLite's virtual table optimisations see + * SQLite's documentation + * for some background information. + */ + +gboolean gda_vconnection_data_model_add (GdaVconnectionDataModel *cnc, GdaVconnectionDataModelSpec *spec, + GDestroyNotify spec_free_func, + const gchar *table_name, GError **error); +gboolean gda_vconnection_data_model_add_model (GdaVconnectionDataModel *cnc, + GdaDataModel *model, const gchar *table_name, GError **error); +gboolean gda_vconnection_data_model_remove (GdaVconnectionDataModel *cnc, const gchar *table_name, GError **error); + +GdaVconnectionDataModelSpec *gda_vconnection_data_model_get (GdaVconnectionDataModel *cnc, const gchar *table_name); +const gchar *gda_vconnection_data_model_get_table_name (GdaVconnectionDataModel *cnc, GdaDataModel *model); +GdaDataModel *gda_vconnection_data_model_get_model (GdaVconnectionDataModel *cnc, const gchar *table_name); + +void gda_vconnection_data_model_foreach (GdaVconnectionDataModel *cnc, + GdaVconnectionDataModelFunc func, gpointer data); + +G_END_DECLS + +#endif diff --git a/.flatpak-builder/cache/objects/d0/4db04f87099da34068750bba78626e57469ec69e5f64f5494c01b050237e05.dirtree b/.flatpak-builder/cache/objects/d0/4db04f87099da34068750bba78626e57469ec69e5f64f5494c01b050237e05.dirtree new file mode 100644 index 0000000..953c900 Binary files /dev/null and b/.flatpak-builder/cache/objects/d0/4db04f87099da34068750bba78626e57469ec69e5f64f5494c01b050237e05.dirtree differ diff --git a/.flatpak-builder/cache/objects/d0/e5c344cbe5a7bc4a8a1d116e73bfae1ec0ac2e4fb889bfdca8c735510e5e35.dirtree b/.flatpak-builder/cache/objects/d0/e5c344cbe5a7bc4a8a1d116e73bfae1ec0ac2e4fb889bfdca8c735510e5e35.dirtree new file mode 100644 index 0000000..a310efb Binary files /dev/null and b/.flatpak-builder/cache/objects/d0/e5c344cbe5a7bc4a8a1d116e73bfae1ec0ac2e4fb889bfdca8c735510e5e35.dirtree differ diff --git a/.flatpak-builder/cache/objects/d1/090c08441a62a597be2e14ad734fb0d34e5b735e040243e4e8f4435ca44f15.dirtree b/.flatpak-builder/cache/objects/d1/090c08441a62a597be2e14ad734fb0d34e5b735e040243e4e8f4435ca44f15.dirtree new file mode 100644 index 0000000..6ed8ba6 Binary files /dev/null and b/.flatpak-builder/cache/objects/d1/090c08441a62a597be2e14ad734fb0d34e5b735e040243e4e8f4435ca44f15.dirtree differ diff --git a/.flatpak-builder/cache/objects/d1/8d0150a55c3da141457cda2ba931ecfec6ee287866421da9d5c8aacba2d465.file b/.flatpak-builder/cache/objects/d1/8d0150a55c3da141457cda2ba931ecfec6ee287866421da9d5c8aacba2d465.file new file mode 100644 index 0000000..f534145 --- /dev/null +++ b/.flatpak-builder/cache/objects/d1/8d0150a55c3da141457cda2ba931ecfec6ee287866421da9d5c8aacba2d465.file @@ -0,0 +1,167 @@ +/* + * Copyright (C) 2010 David King + * Copyright (C) 2010 - 2013 Vivien Malerba + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "gda-sqlite-handler-boolean.h" +#include +#include + +static void gda_sqlite_handler_boolean_class_init (GdaSqliteHandlerBooleanClass * class); +static void gda_sqlite_handler_boolean_init (GdaSqliteHandlerBoolean * wid); +static void gda_sqlite_handler_boolean_dispose (GObject * object); + + +/* GdaDataHandler interface */ +static void gda_sqlite_handler_boolean_data_handler_init (GdaDataHandlerInterface *iface); +static gchar *gda_sqlite_handler_boolean_get_sql_from_value (GdaDataHandler *dh, const GValue *value); +static gchar *gda_sqlite_handler_boolean_get_str_from_value (GdaDataHandler *dh, const GValue *value); +static GValue *gda_sqlite_handler_boolean_get_value_from_sql (GdaDataHandler *dh, const gchar *sql, + GType type); +static GValue *gda_sqlite_handler_boolean_get_value_from_str (GdaDataHandler *iface, const gchar *str, + GType type); + +static GValue *gda_sqlite_handler_boolean_get_sane_init_value (GdaDataHandler * dh, GType type); + +static gboolean gda_sqlite_handler_boolean_accepts_g_type (GdaDataHandler * dh, GType type); + +static const gchar *gda_sqlite_handler_boolean_get_descr (GdaDataHandler *dh); + +G_DEFINE_TYPE_WITH_CODE (GdaSqliteHandlerBoolean, gda_sqlite_handler_boolean, G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (GDA_TYPE_DATA_HANDLER, gda_sqlite_handler_boolean_data_handler_init)) + +static void +gda_sqlite_handler_boolean_data_handler_init (GdaDataHandlerInterface *iface) +{ + iface->get_sql_from_value = gda_sqlite_handler_boolean_get_sql_from_value; + iface->get_str_from_value = gda_sqlite_handler_boolean_get_str_from_value; + iface->get_value_from_sql = gda_sqlite_handler_boolean_get_value_from_sql; + iface->get_value_from_str = gda_sqlite_handler_boolean_get_value_from_str; + iface->get_sane_init_value = gda_sqlite_handler_boolean_get_sane_init_value; + iface->accepts_g_type = gda_sqlite_handler_boolean_accepts_g_type; + iface->get_descr = gda_sqlite_handler_boolean_get_descr; +} + + +static void +gda_sqlite_handler_boolean_class_init (GdaSqliteHandlerBooleanClass * class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (class); + + object_class->dispose = gda_sqlite_handler_boolean_dispose; +} + +static void +gda_sqlite_handler_boolean_init (GdaSqliteHandlerBoolean *hdl) +{ + /* Private structure */ + g_object_set_data (G_OBJECT (hdl), "name", "SqliteBoolean"); + g_object_set_data (G_OBJECT (hdl), "descr", _("Sqlite boolean representation")); +} + +static void +gda_sqlite_handler_boolean_dispose (GObject *object) +{ + /* for the parent class */ + G_OBJECT_CLASS (gda_sqlite_handler_boolean_parent_class)->dispose (object); +} + +/* + * _gda_sqlite_handler_boolean_new + * + * Creates a data handler for booleans + * + * Returns: the new object + */ +GdaDataHandler * +_gda_sqlite_handler_boolean_new (void) +{ + GObject *obj; + + obj = g_object_new (GDA_TYPE_SQLITE_HANDLER_BOOLEAN, NULL); + + return (GdaDataHandler *) obj; +} + +static gchar * +gda_sqlite_handler_boolean_get_sql_from_value (G_GNUC_UNUSED GdaDataHandler *iface, const GValue *value) +{ + g_assert (value); + return g_strdup (g_value_get_boolean (value) ? "1" : "0"); +} + +static gchar * +gda_sqlite_handler_boolean_get_str_from_value (G_GNUC_UNUSED GdaDataHandler *iface, const GValue *value) +{ + g_assert (value); + return g_strdup (g_value_get_boolean (value) ? "1" : "0"); +} + +static GValue * +gda_sqlite_handler_boolean_get_value_from_sql (G_GNUC_UNUSED GdaDataHandler *iface, const gchar *sql, G_GNUC_UNUSED GType type) +{ + g_assert (sql); + + GValue *value; + value = g_value_init (g_new0 (GValue, 1), G_TYPE_BOOLEAN); + if (*sql == '0') + g_value_set_boolean (value, FALSE); + else + g_value_set_boolean (value, TRUE); + return value; +} + +static GValue * +gda_sqlite_handler_boolean_get_value_from_str (G_GNUC_UNUSED GdaDataHandler *iface, const gchar *str, G_GNUC_UNUSED GType type) +{ + g_assert (str); + + GValue *value; + value = g_value_init (g_new0 (GValue, 1), G_TYPE_BOOLEAN); + if (*str == '0') + g_value_set_boolean (value, FALSE); + else + g_value_set_boolean (value, TRUE); + + return value; +} + + +static GValue * +gda_sqlite_handler_boolean_get_sane_init_value (G_GNUC_UNUSED GdaDataHandler *iface, G_GNUC_UNUSED GType type) +{ + GValue *value; + value = g_value_init (g_new0 (GValue, 1), G_TYPE_BOOLEAN); + g_value_set_boolean (value, FALSE); + + return value; +} + +static gboolean +gda_sqlite_handler_boolean_accepts_g_type (G_GNUC_UNUSED GdaDataHandler *iface, GType type) +{ + g_assert (iface); + return type == G_TYPE_BOOLEAN ? TRUE : FALSE; +} + +static const gchar * +gda_sqlite_handler_boolean_get_descr (GdaDataHandler *iface) +{ + g_return_val_if_fail (GDA_IS_SQLITE_HANDLER_BOOLEAN (iface), NULL); + return g_object_get_data (G_OBJECT (iface), "descr"); +} diff --git a/.flatpak-builder/cache/objects/d1/c1bb2b16102d8d0df433fc433ef55c23792d985d56bb2f445496f33781c841.dirtree b/.flatpak-builder/cache/objects/d1/c1bb2b16102d8d0df433fc433ef55c23792d985d56bb2f445496f33781c841.dirtree new file mode 100644 index 0000000..0856611 Binary files /dev/null and b/.flatpak-builder/cache/objects/d1/c1bb2b16102d8d0df433fc433ef55c23792d985d56bb2f445496f33781c841.dirtree differ diff --git a/.flatpak-builder/cache/objects/d2/0be124250055d4182c97334c6716115767000665f4cedf38e292bb9069db07.file b/.flatpak-builder/cache/objects/d2/0be124250055d4182c97334c6716115767000665f4cedf38e292bb9069db07.file new file mode 100644 index 0000000..5e0572a --- /dev/null +++ b/.flatpak-builder/cache/objects/d2/0be124250055d4182c97334c6716115767000665f4cedf38e292bb9069db07.file @@ -0,0 +1,583 @@ +/* + * Copyright (C) 2005 Andrew Hill + * Copyright (C) 2005 - 2013 Vivien Malerba + * Copyright (C) 2005 Álvaro Peña + * Copyright (C) 2007 - 2008 Murray Cumming + * Copyright (C) 2008 Johannes Schmid + * Copyright (C) 2008 Przemysław Grzegorczyk + * Copyright (C) 2010 David King + * Copyright (C) 2010 Jonh Wendell + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +#define G_LOG_DOMAIN "GDA-column" + +#include +#include +#include "gda-marshal.h" +#include + +#define PARENT_TYPE G_TYPE_OBJECT + +typedef struct { + gint defined_size; + gchar *id; + + gchar *dbms_type; + GType g_type; + + gboolean allow_null; + + gboolean auto_increment; + glong auto_increment_start; + glong auto_increment_step; + gint position; + GValue *default_value; + gchar *name; + gchar *desc; +} GdaColumnPrivate; + +G_DEFINE_TYPE_WITH_PRIVATE(GdaColumn,gda_column,G_TYPE_OBJECT) + +static void gda_column_class_init (GdaColumnClass *klass); +static void gda_column_init (GdaColumn *column); +static void gda_column_finalize (GObject *object); + +static void gda_column_set_property (GObject *object, + guint param_id, + const GValue *value, + GParamSpec *pspec); +static void gda_column_get_property (GObject *object, + guint param_id, + GValue *value, + GParamSpec *pspec); + +/* signals */ +enum { + NAME_CHANGED, + GDA_TYPE_CHANGED, + LAST_SIGNAL +}; + +static guint gda_column_signals[LAST_SIGNAL] = {0 , 0}; + +/* properties */ +enum +{ + PROP_0, + PROP_ID, + PROP_NAME, + PROP_DESC +}; + +static void +gda_column_class_init (GdaColumnClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + /* signals */ + /** + * GdaColumn::name-changed: + * @column: the #GdaColumn object + * @old_name: the column's previous name + * + * Gets emitted whenever @column's name has been changed + */ + gda_column_signals[NAME_CHANGED] = + g_signal_new ("name-changed", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GdaColumnClass, name_changed), + NULL, NULL, + g_cclosure_marshal_VOID__STRING, + G_TYPE_NONE, + 1, G_TYPE_STRING); + /** + * GdaColumn::g-type-changed: + * @column: the #GdaColumn object + * @old_type: the column's previous type + * @new_type: the column's new type + * + * Gets emitted whenever @column's type has been changed + */ + gda_column_signals[GDA_TYPE_CHANGED] = + g_signal_new ("g-type-changed", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GdaColumnClass, g_type_changed), + NULL, NULL, + _gda_marshal_VOID__GTYPE_GTYPE, + G_TYPE_NONE, + 2, G_TYPE_GTYPE, G_TYPE_GTYPE); + + /* properties */ + object_class->set_property = gda_column_set_property; + object_class->get_property = gda_column_get_property; + + g_object_class_install_property (object_class, PROP_ID, + g_param_spec_string ("id", NULL, + "Column's Id (warning: the column's ID is not guaranteed to be unique in a GdaDataModel)", + NULL, G_PARAM_WRITABLE | G_PARAM_READABLE)); + + + g_object_class_install_property (object_class, PROP_NAME, + g_param_spec_string ("name", NULL, + "Column's name", + NULL, G_PARAM_WRITABLE | G_PARAM_READABLE)); + + g_object_class_install_property (object_class, PROP_DESC, + g_param_spec_string ("desc", NULL, + "Column's description", + NULL, G_PARAM_WRITABLE | G_PARAM_READABLE)); + + object_class->finalize = gda_column_finalize; +} + +static void +gda_column_init (GdaColumn *column) +{ + g_return_if_fail (GDA_IS_COLUMN (column)); + + GdaColumnPrivate *priv = gda_column_get_instance_private (column); + priv->defined_size = 0; + priv->id = NULL; + priv->g_type = GDA_TYPE_NULL; + priv->allow_null = TRUE; + priv->auto_increment = FALSE; + priv->auto_increment_start = 0; + priv->auto_increment_step = 0; + priv->position = -1; + priv->default_value = NULL; + priv->name = NULL; + priv->desc = NULL; +} + +static void +gda_column_finalize (GObject *object) +{ + GdaColumn *column = (GdaColumn *) object; + + g_return_if_fail (GDA_IS_COLUMN (column)); + GdaColumnPrivate *priv = gda_column_get_instance_private (column); + + gda_value_free (priv->default_value); + + if (priv->id != NULL) { + g_free (priv->id); + priv->id = NULL; + } + if (priv->dbms_type != NULL) { + g_free (priv->dbms_type); + priv->dbms_type = NULL; + } + if (priv->name != NULL) { + g_free (priv->name); + priv->name = NULL; + } + if (priv->desc != NULL) { + g_free (priv->desc); + priv->desc = NULL; + } + + G_OBJECT_CLASS (gda_column_parent_class)->finalize (object); +} + +static void +gda_column_set_property (GObject *object, + guint param_id, + const GValue *value, + GParamSpec *pspec) +{ + GdaColumn *col; + + col = GDA_COLUMN (object); + + GdaColumnPrivate *priv = gda_column_get_instance_private (col); + switch (param_id) { + case PROP_ID: + if (priv->id != NULL) { + g_free (priv->id); + } + if (g_value_get_string (value)) + priv->id = g_strdup (g_value_get_string (value)); + else + priv->id = NULL; + break; + case PROP_NAME: + if (priv->name != NULL) { + g_free (priv->name); + } + if (g_value_get_string (value)) + priv->name = g_strdup (g_value_get_string (value)); + else + priv->name = NULL; + break; + case PROP_DESC: + if (priv->desc != NULL) { + g_free (priv->desc); + } + if (g_value_get_string (value)) + priv->desc = g_strdup (g_value_get_string (value)); + else + priv->desc = NULL; + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + break; + } +} + +static void +gda_column_get_property (GObject *object, + guint param_id, + GValue *value, + GParamSpec *pspec) +{ + GdaColumn *col; + + col = GDA_COLUMN (object); + GdaColumnPrivate *priv = gda_column_get_instance_private (col); + switch (param_id) { + case PROP_ID: + g_value_set_string (value, priv->id); + break; + case PROP_NAME: + g_value_set_string (value, priv->name); + break; + case PROP_DESC: + g_value_set_string (value, priv->desc); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + break; + } +} + +/** + * gda_column_new: + * + * Returns: a newly allocated #GdaColumn object. + */ +GdaColumn * +gda_column_new (void) +{ + return g_object_new (GDA_TYPE_COLUMN, NULL); +} + +/** + * gda_column_copy: + * @column: column to get a copy from. + * + * Creates a new #GdaColumn object from an existing one. + * + * Returns: (transfer full): a newly allocated #GdaColumn with a copy of the data + * in @column. + */ +GdaColumn * +gda_column_copy (GdaColumn *column) +{ + GdaColumn *column_copy; + + g_return_val_if_fail (GDA_IS_COLUMN (column), NULL); + GdaColumnPrivate *priv = gda_column_get_instance_private (column); + + column_copy = gda_column_new (); + GdaColumnPrivate *cpriv = gda_column_get_instance_private (column_copy); + cpriv->defined_size = priv->defined_size; + if (priv->id) + cpriv->id = g_strdup (priv->id); + if (priv->name) + cpriv->name = g_strdup (priv->name); + if (priv->desc) + cpriv->desc = g_strdup (priv->desc); + cpriv->g_type = priv->g_type; + cpriv->allow_null = priv->allow_null; + cpriv->auto_increment = priv->auto_increment; + cpriv->auto_increment_start = priv->auto_increment_start; + cpriv->auto_increment_step = priv->auto_increment_step; + cpriv->position = priv->position; + if (priv->default_value) + cpriv->default_value = gda_value_copy (priv->default_value); + + return column_copy; +} + +/** + * gda_column_get_name: + * @column: a #GdaColumn. + * + * Returns: the name of @column. + */ +const gchar * +gda_column_get_name (GdaColumn *column) +{ + g_return_val_if_fail (column != NULL, NULL); + g_return_val_if_fail (GDA_IS_COLUMN (column), NULL); + + GdaColumnPrivate *priv = gda_column_get_instance_private (column); + return priv->name; +} + +/** + * gda_column_set_name: + * @column: a #GdaColumn. + * @name: the new name of @column. + * + * Sets the name of @column to @name. + */ +void +gda_column_set_name (GdaColumn *column, const gchar *name) +{ + g_return_if_fail (column != NULL); + g_return_if_fail (name != NULL); + g_return_if_fail (GDA_IS_COLUMN (column)); + + GdaColumnPrivate *priv = gda_column_get_instance_private (column); + priv->name = g_strdup (name); +} + +/** + * gda_column_get_description: + * @column: a #GdaColumn. + * + * Returns: the column's description, in any + */ +const gchar * +gda_column_get_description (GdaColumn *column) +{ + g_return_val_if_fail (column != NULL, NULL); + g_return_val_if_fail (GDA_IS_COLUMN (column), NULL); + + GdaColumnPrivate *priv = gda_column_get_instance_private (column); + return priv->desc; +} + +/** + * gda_column_set_description: + * @column: a #GdaColumn. + * @descr: description. + * + * Sets the column's description + */ +void +gda_column_set_description (GdaColumn *column, const gchar *descr) +{ + g_return_if_fail (column != NULL); + g_return_if_fail (descr != NULL); + g_return_if_fail (GDA_IS_COLUMN (column)); + + GdaColumnPrivate *priv = gda_column_get_instance_private (column); + priv->desc = g_strdup (descr); +} + +/** + * gda_column_get_dbms_type: + * @column: a #GdaColumn. + * + * Returns: the database type of @column. + */ +const gchar* +gda_column_get_dbms_type (GdaColumn *column) +{ + g_return_val_if_fail (GDA_IS_COLUMN (column), NULL); + GdaColumnPrivate *priv = gda_column_get_instance_private (column); + return (const gchar *) priv->dbms_type; +} + +/** + * gda_column_set_dbms_type: + * @column: a #GdaColumn + * @dbms_type: a string + * + * Defines @column's database type + */ +void +gda_column_set_dbms_type (GdaColumn *column, const gchar *dbms_type) +{ + g_return_if_fail (GDA_IS_COLUMN (column)); + GdaColumnPrivate *priv = gda_column_get_instance_private (column); + + g_free (priv->dbms_type); + priv->dbms_type = NULL; + + if (dbms_type) + priv->dbms_type = g_strdup (dbms_type); +} + +/** + * gda_column_get_g_type: + * @column: a #GdaColumn. + * + * Returns: the type of @column. + */ +GType +gda_column_get_g_type (GdaColumn *column) +{ + g_return_val_if_fail (GDA_IS_COLUMN (column), GDA_TYPE_NULL); + GdaColumnPrivate *priv = gda_column_get_instance_private (column); + return priv->g_type; +} + +/** + * gda_column_set_g_type: + * @column: a #GdaColumn. + * @type: the new type of @column. + * + * Sets the type of @column to @type. + */ +void +gda_column_set_g_type (GdaColumn *column, GType type) +{ + GType old_type; + + g_return_if_fail (GDA_IS_COLUMN (column)); + GdaColumnPrivate *priv = gda_column_get_instance_private (column); + + old_type = priv->g_type; + priv->g_type = type; + + g_signal_emit (G_OBJECT (column), + gda_column_signals[GDA_TYPE_CHANGED], + 0, old_type, type); +} + +/** + * gda_column_get_allow_null: + * @column: a #GdaColumn. + * + * Gets the 'allow null' flag of the given column. + * + * Returns: whether the given column allows null values or not (%TRUE or %FALSE). + */ +gboolean +gda_column_get_allow_null (GdaColumn *column) +{ + g_return_val_if_fail (GDA_IS_COLUMN (column), FALSE); + GdaColumnPrivate *priv = gda_column_get_instance_private (column); + return priv->allow_null; +} + +/** + * gda_column_set_allow_null: + * @column: a #GdaColumn. + * @allow: whether the given column should allows null values or not. + * + * Sets the 'allow null' flag of the given column. + */ +void +gda_column_set_allow_null (GdaColumn *column, gboolean allow) +{ + g_return_if_fail (GDA_IS_COLUMN (column)); + GdaColumnPrivate *priv = gda_column_get_instance_private (column); + priv->allow_null = allow; +} + +/** + * gda_column_get_auto_increment: + * @column: a #GdaColumn. + * + * Returns: whether the given column is an auto incremented one (%TRUE or %FALSE). + */ +gboolean +gda_column_get_auto_increment (GdaColumn *column) +{ + g_return_val_if_fail (GDA_IS_COLUMN (column), FALSE); + GdaColumnPrivate *priv = gda_column_get_instance_private (column); + return priv->auto_increment; +} + +/** + * gda_column_set_auto_increment: + * @column: a #GdaColumn. + * @is_auto: auto increment status. + * + * Sets the auto increment flag for the given column. + */ +void +gda_column_set_auto_increment (GdaColumn *column, + gboolean is_auto) +{ + g_return_if_fail (GDA_IS_COLUMN (column)); + GdaColumnPrivate *priv = gda_column_get_instance_private (column); + priv->auto_increment = is_auto; +} + +/** + * gda_column_get_position: + * @column: a #GdaColumn. + * + * Returns: the position of the column refer to in the + * containing data model. + */ +gint +gda_column_get_position (GdaColumn *column) +{ + g_return_val_if_fail (GDA_IS_COLUMN (column), -1); + GdaColumnPrivate *priv = gda_column_get_instance_private (column); + return priv->position; +} + +/** + * gda_column_set_position: + * @column: a #GdaColumn. + * @position: the wanted position of the column in the containing data model. + * + * Sets the position of the column refer to in the containing + * data model. + */ +void +gda_column_set_position (GdaColumn *column, gint position) +{ + g_return_if_fail (column != NULL); + GdaColumnPrivate *priv = gda_column_get_instance_private (column); + priv->position = position; +} + + +/** + * gda_column_get_default_value: + * @column: a #GdaColumn. + * + * Returns: (nullable): @column's default value, as a #GValue object, or %NULL if column does not have a default value + */ +const GValue * +gda_column_get_default_value (GdaColumn *column) +{ + g_return_val_if_fail (GDA_IS_COLUMN (column), NULL); + GdaColumnPrivate *priv = gda_column_get_instance_private (column); + return (const GValue *) priv->default_value; +} + +/** + * gda_column_set_default_value: + * @column: a #GdaColumn. + * @default_value: (nullable): default #GValue for the column + * + * Sets @column's default #GValue. + */ +void +gda_column_set_default_value (GdaColumn *column, const GValue *default_value) +{ + g_return_if_fail (GDA_IS_COLUMN (column)); + GdaColumnPrivate *priv = gda_column_get_instance_private (column); + + gda_value_free (priv->default_value); + if (default_value) + priv->default_value = gda_value_copy ( (GValue*)default_value); + else + priv->default_value = NULL; +} + diff --git a/.flatpak-builder/cache/objects/d2/5a2ac211b699975aeb9b06bfbc0b48504ef620488d23a7d09fb635c1e13917.file b/.flatpak-builder/cache/objects/d2/5a2ac211b699975aeb9b06bfbc0b48504ef620488d23a7d09fb635c1e13917.file new file mode 100644 index 0000000..abb52e1 --- /dev/null +++ b/.flatpak-builder/cache/objects/d2/5a2ac211b699975aeb9b06bfbc0b48504ef620488d23a7d09fb635c1e13917.file @@ -0,0 +1,83 @@ +/* + * gda-ddl-modifiable.h + * + * Copyright (C) 2020 Pavlo Solntsev + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +#ifndef GDA_DDL_MODIFIABLE_H +#define GDA_DDL_MODIFIABLE_H + +#include +#include +#include "gda-connection.h" + +G_BEGIN_DECLS + +#define GDA_TYPE_DDL_MODIFIABLE gda_ddl_modifiable_get_type () + +G_DECLARE_INTERFACE (GdaDdlModifiable, gda_ddl_modifiable, GDA, DDL_MODIFIABLE, GObject) + +struct _GdaDdlModifiableInterface +{ + GTypeInterface parent_iface; + + gboolean (*create)(GdaDdlModifiable *self, + GdaConnection *cnc, + gpointer user_data, + GError **error); + + gboolean (*drop)(GdaDdlModifiable *self, + GdaConnection *cnc, + gpointer user_data, + GError **error); + + gboolean (*rename)(GdaDdlModifiable *self, + GdaConnection *cnc, + gpointer user_data, + GError **error); +}; + +typedef enum { + GDA_DDL_MODIFIABLE_NOT_IMPLEMENTED, + GDA_DDL_MODIFIABLE_CONNECTION_NOT_OPENED, + GDA_DDL_MODIFIABLE_MISSED_DATA +} GdaDdlModifiableError; + +#define GDA_DDL_MODIFIABLE_ERROR gda_ddl_modifiable_error_quark() +GQuark gda_ddl_modifiable_error_quark (void); + +gboolean gda_ddl_modifiable_create (GdaDdlModifiable *self, + GdaConnection *cnc, + gpointer user_data, + GError **error); + +gboolean gda_ddl_modifiable_drop (GdaDdlModifiable *self, + GdaConnection *cnc, + gpointer user_data, + GError **error); + +gboolean gda_ddl_modifiable_rename (GdaDdlModifiable *self, + GdaConnection *cnc, + gpointer user_data, + GError **error); + +G_END_DECLS + +#endif /* end of include guard: GDA-DB-MODIFIABLE*/ + + + diff --git a/.flatpak-builder/cache/objects/d3/91f977230526023640d64a3e9b490297350253832b2db89e9e706d4ec5bf40.dirtree b/.flatpak-builder/cache/objects/d3/91f977230526023640d64a3e9b490297350253832b2db89e9e706d4ec5bf40.dirtree new file mode 100644 index 0000000..5df1211 Binary files /dev/null and b/.flatpak-builder/cache/objects/d3/91f977230526023640d64a3e9b490297350253832b2db89e9e706d4ec5bf40.dirtree differ diff --git a/.flatpak-builder/cache/objects/d3/aa867651a065baef3f59b97b303399ad698ee691fc657928f76e691fd16cc9.dirtree b/.flatpak-builder/cache/objects/d3/aa867651a065baef3f59b97b303399ad698ee691fc657928f76e691fd16cc9.dirtree new file mode 100644 index 0000000..1e37250 Binary files /dev/null and b/.flatpak-builder/cache/objects/d3/aa867651a065baef3f59b97b303399ad698ee691fc657928f76e691fd16cc9.dirtree differ diff --git a/.flatpak-builder/cache/objects/d3/d663c62d60d045cc79ba270b46a3baf0b07f9d87ddf761f9022fdfcf07b9f0.file b/.flatpak-builder/cache/objects/d3/d663c62d60d045cc79ba270b46a3baf0b07f9d87ddf761f9022fdfcf07b9f0.file new file mode 100644 index 0000000..12289cd --- /dev/null +++ b/.flatpak-builder/cache/objects/d3/d663c62d60d045cc79ba270b46a3baf0b07f9d87ddf761f9022fdfcf07b9f0.file @@ -0,0 +1,31 @@ +/* + * Autogenerated by the Meson build system. + * Do not edit, your changes will be lost. + */ + +#pragma once + +#define GDA_ABI_MAJOR_VERSION 6 + +#define GDA_ABI_MINOR_VERSION 0 + +#define GDA_DEBUG_FLAGS + +#define HAVE_GLIB_GENMARSHAL 1 + +#define HAVE_GLIB_MKENUMS 1 + +#define LIBGDA_BDB_INC + +#define LIBGDA_BDB_TYPE + +#define VERSION 6.0.0 + +#define exec_prefix /app/libexec + +#define includedir /app/include + +#define libdir /app/lib + +#define prefix /app + diff --git a/.flatpak-builder/cache/objects/d3/ede2ce870286598a62729f71b36bc7735e48f3adaec51d59cb2b3b78a41971.file b/.flatpak-builder/cache/objects/d3/ede2ce870286598a62729f71b36bc7735e48f3adaec51d59cb2b3b78a41971.file new file mode 100644 index 0000000..144d2b3 Binary files /dev/null and b/.flatpak-builder/cache/objects/d3/ede2ce870286598a62729f71b36bc7735e48f3adaec51d59cb2b3b78a41971.file differ diff --git a/.flatpak-builder/cache/objects/d4/06c379dd703894d67d0f2e4bc0be8dc337b2e5bd85dc0c3283943ead2a8412.file b/.flatpak-builder/cache/objects/d4/06c379dd703894d67d0f2e4bc0be8dc337b2e5bd85dc0c3283943ead2a8412.file new file mode 100644 index 0000000..1457712 --- /dev/null +++ b/.flatpak-builder/cache/objects/d4/06c379dd703894d67d0f2e4bc0be8dc337b2e5bd85dc0c3283943ead2a8412.file @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2001 - 2002 Rodrigo Moya + * Copyright (C) 2001 - 2012 Vivien Malerba + * Copyright (C) 2002 Gonzalo Paniagua Javier + * Copyright (C) 2003 Laurent Sansonetti + * Copyright (C) 2008 Przemysław Grzegorczyk + * Copyright (C) 2011 Murray Cumming + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GDA_QUARK_LIST_H__ +#define __GDA_QUARK_LIST_H__ + +#include +#include + +G_BEGIN_DECLS + +typedef struct _GdaQuarkList GdaQuarkList; + +#define GDA_TYPE_QUARK_LIST (gda_quark_list_get_type()) + +/** + * SECTION:gda-quark-list + * @short_description: Manages lists of KEY=VALUE pairs + * @title: GdaQuarkList + * @stability: Stable + * @see_also: + * + * This object is used to store KEY=VALUE pairs. It is mainly used internally by Libgda to store connection + * parameters. + * + * Authentification values are kept in a mangled form in memory, and unmangled when + * they are requested using gda_quark_list_find(), and when you don't need them anymore, + * call gda_quark_list_protect_values() to remove the unmangled version. + */ + +GType gda_quark_list_get_type (void) G_GNUC_CONST; +GdaQuarkList *gda_quark_list_new (void); +GdaQuarkList *gda_quark_list_new_from_string (const gchar *string); +GdaQuarkList *gda_quark_list_copy (GdaQuarkList *qlist); +void gda_quark_list_free (GdaQuarkList *qlist); + +void gda_quark_list_add_from_string (GdaQuarkList *qlist, + const gchar *string, + gboolean cleanup); +const gchar *gda_quark_list_find (GdaQuarkList *qlist, const gchar *name); +void gda_quark_list_protect_values (GdaQuarkList *qlist); + +void gda_quark_list_remove (GdaQuarkList *qlist, const gchar *name); +void gda_quark_list_clear (GdaQuarkList *qlist); +void gda_quark_list_foreach (GdaQuarkList *qlist, GHFunc func, gpointer user_data); + +G_END_DECLS + +#endif diff --git a/.flatpak-builder/cache/objects/d4/43ec4ddb7b2fd148499f5d4edcf2a05ec442be11f46bfa6dd22ccd48403b4f.dirtree b/.flatpak-builder/cache/objects/d4/43ec4ddb7b2fd148499f5d4edcf2a05ec442be11f46bfa6dd22ccd48403b4f.dirtree new file mode 100644 index 0000000..17bcb65 Binary files /dev/null and b/.flatpak-builder/cache/objects/d4/43ec4ddb7b2fd148499f5d4edcf2a05ec442be11f46bfa6dd22ccd48403b4f.dirtree differ diff --git a/.flatpak-builder/cache/objects/d5/380c82ee6911f5427740f3fa0ce9a88abb32d33b79752e827f779f1ac909f3.dirtree b/.flatpak-builder/cache/objects/d5/380c82ee6911f5427740f3fa0ce9a88abb32d33b79752e827f779f1ac909f3.dirtree new file mode 100644 index 0000000..257e1a2 Binary files /dev/null and b/.flatpak-builder/cache/objects/d5/380c82ee6911f5427740f3fa0ce9a88abb32d33b79752e827f779f1ac909f3.dirtree differ diff --git a/.flatpak-builder/cache/objects/d5/b4666307ad47d3a9b29bab4a422624dae3e76e66a5fc27e4bb5fbf27349c1d.dirtree b/.flatpak-builder/cache/objects/d5/b4666307ad47d3a9b29bab4a422624dae3e76e66a5fc27e4bb5fbf27349c1d.dirtree new file mode 100644 index 0000000..2fab4a0 Binary files /dev/null and b/.flatpak-builder/cache/objects/d5/b4666307ad47d3a9b29bab4a422624dae3e76e66a5fc27e4bb5fbf27349c1d.dirtree differ diff --git a/.flatpak-builder/cache/objects/d5/e18b3b946b9c6838b972d34b0966497df4b9035e3fdfab9ec95ffd981a9a56.dirtree b/.flatpak-builder/cache/objects/d5/e18b3b946b9c6838b972d34b0966497df4b9035e3fdfab9ec95ffd981a9a56.dirtree new file mode 100644 index 0000000..d9a931f Binary files /dev/null and b/.flatpak-builder/cache/objects/d5/e18b3b946b9c6838b972d34b0966497df4b9035e3fdfab9ec95ffd981a9a56.dirtree differ diff --git a/.flatpak-builder/cache/objects/d5/e35efbd0f617e59f66c6d81b6f972cea0a7d05d52aaac04a1b305f1a72223f.file b/.flatpak-builder/cache/objects/d5/e35efbd0f617e59f66c6d81b6f972cea0a7d05d52aaac04a1b305f1a72223f.file new file mode 100755 index 0000000..5114e84 --- /dev/null +++ b/.flatpak-builder/cache/objects/d5/e35efbd0f617e59f66c6d81b6f972cea0a7d05d52aaac04a1b305f1a72223f.file @@ -0,0 +1,41 @@ +# libcanberra-pulse.la - a libtool library file +# Generated by libtool (GNU libtool) 2.4.2 +# +# Please DO NOT delete this file! +# It is necessary for linking the library. + +# The name that we can dlopen(3). +dlname='libcanberra-pulse.so' + +# Names of this library. +library_names='libcanberra-pulse.so libcanberra-pulse.so libcanberra-pulse.so' + +# The name of the static archive. +old_library='' + +# Linker flags that can not go in dependency_libs. +inherited_linker_flags=' -pthread' + +# Libraries that this one depends upon. +dependency_libs=' -L/app/lib -lpulse /app/lib/libcanberra.la -lvorbisfile -lltdl -lm' + +# Names of additional weak libraries provided by this library +weak_library_names='' + +# Version information for libcanberra-pulse. +current=0 +age=0 +revision=0 + +# Is this an already installed library? +installed=yes + +# Should we warn about portability when linking against -modules? +shouldnotlink=yes + +# Files to dlopen/dlpreopen +dlopen='' +dlpreopen='' + +# Directory that this library needs to be installed in: +libdir='/app/lib/libcanberra-0.30' diff --git a/.flatpak-builder/cache/objects/d6/0b5af76422d74ea320d3398923803bebd762b19607ae7c8f4ff6367b07c5de.dirtree b/.flatpak-builder/cache/objects/d6/0b5af76422d74ea320d3398923803bebd762b19607ae7c8f4ff6367b07c5de.dirtree new file mode 100644 index 0000000..7cbba91 Binary files /dev/null and b/.flatpak-builder/cache/objects/d6/0b5af76422d74ea320d3398923803bebd762b19607ae7c8f4ff6367b07c5de.dirtree differ diff --git a/.flatpak-builder/cache/objects/d6/812f0e2d7d4d5e065155f4cf2c52318a8d6ea64e9720c55366ded70eec631e.commit b/.flatpak-builder/cache/objects/d6/812f0e2d7d4d5e065155f4cf2c52318a8d6ea64e9720c55366ded70eec631e.commit new file mode 100644 index 0000000..9145fd4 Binary files /dev/null and b/.flatpak-builder/cache/objects/d6/812f0e2d7d4d5e065155f4cf2c52318a8d6ea64e9720c55366ded70eec631e.commit differ diff --git a/.flatpak-builder/cache/objects/d6/e77c9260ce40ed874acc6ac0354a01c4e0b27dab2a71084686a5fffea41e48.dirtree b/.flatpak-builder/cache/objects/d6/e77c9260ce40ed874acc6ac0354a01c4e0b27dab2a71084686a5fffea41e48.dirtree new file mode 100644 index 0000000..dc445aa Binary files /dev/null and b/.flatpak-builder/cache/objects/d6/e77c9260ce40ed874acc6ac0354a01c4e0b27dab2a71084686a5fffea41e48.dirtree differ diff --git a/.flatpak-builder/cache/objects/d6/f494a05376ca8dca032fdf45e7ded18da5f9689f1592f7625eeae1443b6536.file b/.flatpak-builder/cache/objects/d6/f494a05376ca8dca032fdf45e7ded18da5f9689f1592f7625eeae1443b6536.file new file mode 100644 index 0000000..45beb81 --- /dev/null +++ b/.flatpak-builder/cache/objects/d6/f494a05376ca8dca032fdf45e7ded18da5f9689f1592f7625eeae1443b6536.file @@ -0,0 +1,246 @@ +/*-*- Mode: C; c-basic-offset: 8 -*-*/ + +/*** + This file is part of libcanberra. + + Copyright 2008 Lennart Poettering + + libcanberra is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation, either version 2.1 of the + License, or (at your option) any later version. + + libcanberra is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with libcanberra. If not, see + . +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include "canberra.h" +#include "read-vorbis.h" +#include "macro.h" +#include "malloc.h" + +#define FILE_SIZE_MAX ((off_t) (64U*1024U*1024U)) + +struct ca_vorbis { + OggVorbis_File ovf; + off_t size; + ca_channel_position_t channel_map[8]; +}; + +static int convert_error(int or) { + switch (or) { + case OV_ENOSEEK: + case OV_EBADPACKET: + case OV_EBADLINK: + case OV_EFAULT: + case OV_EREAD: + case OV_HOLE: + return CA_ERROR_IO; + + case OV_EIMPL: + case OV_EVERSION: + case OV_ENOTAUDIO: + return CA_ERROR_NOTSUPPORTED; + + case OV_ENOTVORBIS: + case OV_EBADHEADER: + case OV_EOF: + return CA_ERROR_CORRUPT; + + case OV_EINVAL: + return CA_ERROR_INVALID; + + default: + return CA_ERROR_IO; + } +} + +int ca_vorbis_open(ca_vorbis **_v, FILE *f) { + int ret, or; + ca_vorbis *v; + int64_t n; + + ca_return_val_if_fail(_v, CA_ERROR_INVALID); + ca_return_val_if_fail(f, CA_ERROR_INVALID); + + if (!(v = ca_new0(ca_vorbis, 1))) + return CA_ERROR_OOM; + + if ((or = ov_open(f, &v->ovf, NULL, 0)) < 0) { + ret = convert_error(or); + goto fail; + } + + if ((n = ov_pcm_total(&v->ovf, -1)) < 0) { + ret = convert_error(or); + ov_clear(&v->ovf); + goto fail; + } + + if (((off_t) n * (off_t) sizeof(int16_t)) > FILE_SIZE_MAX) { + ret = CA_ERROR_TOOBIG; + ov_clear(&v->ovf); + goto fail; + } + + v->size = (off_t) n * (off_t) sizeof(int16_t) * ca_vorbis_get_nchannels(v); + + *_v = v; + + return CA_SUCCESS; + +fail: + + ca_free(v); + return ret; +} + +void ca_vorbis_close(ca_vorbis *v) { + ca_assert(v); + + ov_clear(&v->ovf); + ca_free(v); +} + +unsigned ca_vorbis_get_nchannels(ca_vorbis *v) { + const vorbis_info *vi; + ca_assert(v); + + ca_assert_se(vi = ov_info(&v->ovf, -1)); + + return (unsigned) vi->channels; +} + +unsigned ca_vorbis_get_rate(ca_vorbis *v) { + const vorbis_info *vi; + ca_assert(v); + + ca_assert_se(vi = ov_info(&v->ovf, -1)); + + return (unsigned) vi->rate; +} + +const ca_channel_position_t* ca_vorbis_get_channel_map(ca_vorbis *v) { + + /* See http://www.xiph.org/vorbis/doc/Vorbis_I_spec.html#x1-800004.3.9 */ + + switch (ca_vorbis_get_nchannels(v)) { + case 8: + v->channel_map[0] = CA_CHANNEL_FRONT_LEFT; + v->channel_map[1] = CA_CHANNEL_FRONT_CENTER; + v->channel_map[2] = CA_CHANNEL_FRONT_RIGHT; + v->channel_map[3] = CA_CHANNEL_SIDE_LEFT; + v->channel_map[4] = CA_CHANNEL_SIDE_RIGHT; + v->channel_map[5] = CA_CHANNEL_REAR_LEFT; + v->channel_map[6] = CA_CHANNEL_REAR_RIGHT; + v->channel_map[7] = CA_CHANNEL_LFE; + return v->channel_map; + + case 7: + v->channel_map[0] = CA_CHANNEL_FRONT_LEFT; + v->channel_map[1] = CA_CHANNEL_FRONT_CENTER; + v->channel_map[2] = CA_CHANNEL_FRONT_RIGHT; + v->channel_map[3] = CA_CHANNEL_SIDE_LEFT; + v->channel_map[4] = CA_CHANNEL_SIDE_RIGHT; + v->channel_map[5] = CA_CHANNEL_REAR_CENTER; + v->channel_map[6] = CA_CHANNEL_LFE; + return v->channel_map; + + case 6: + v->channel_map[5] = CA_CHANNEL_LFE; + /* fall through */ + + case 5: + v->channel_map[3] = CA_CHANNEL_REAR_LEFT; + v->channel_map[4] = CA_CHANNEL_REAR_RIGHT; + /* fall through */ + + case 3: + v->channel_map[0] = CA_CHANNEL_FRONT_LEFT; + v->channel_map[1] = CA_CHANNEL_FRONT_CENTER; + v->channel_map[2] = CA_CHANNEL_FRONT_RIGHT; + return v->channel_map; + + case 4: + v->channel_map[2] = CA_CHANNEL_REAR_LEFT; + v->channel_map[3] = CA_CHANNEL_REAR_RIGHT; + /* fall through */ + + case 2: + v->channel_map[0] = CA_CHANNEL_FRONT_LEFT; + v->channel_map[1] = CA_CHANNEL_FRONT_RIGHT; + return v->channel_map; + + case 1: + v->channel_map[0] = CA_CHANNEL_MONO; + return v->channel_map; + } + + return NULL; +} + +int ca_vorbis_read_s16ne(ca_vorbis *v, int16_t *d, size_t *n){ + long r; + int section; + int length; + size_t n_read = 0; + + ca_return_val_if_fail(v, CA_ERROR_INVALID); + ca_return_val_if_fail(d, CA_ERROR_INVALID); + ca_return_val_if_fail(n, CA_ERROR_INVALID); + ca_return_val_if_fail(*n > 0, CA_ERROR_INVALID); + + length = (int) (*n * sizeof(int16_t)); + + do { + + r = ov_read(&v->ovf, (char*) d, length, +#ifdef WORDS_BIGENDIAN + 1, +#else + 0, +#endif + 2, 1, §ion); + + if (r < 0) + return convert_error((int) r); + + if (r == 0) + break; + + /* We only read the first section */ + if (section != 0) + break; + + length -= (int) r; + d += r/sizeof(int16_t); + n_read += (size_t) r; + + } while (length >= 4096); + + ca_assert(v->size >= (off_t) n_read); + v->size -= (off_t) n_read; + + *n = n_read/sizeof(int16_t); + + return CA_SUCCESS; +} + +off_t ca_vorbis_get_size(ca_vorbis *v) { + ca_return_val_if_fail(v, (off_t) -1); + + return v->size; +} diff --git a/.flatpak-builder/cache/objects/d6/f9504aac66dcff003245d037183a8da06adf489500a9a0d17c7d54ab0a056b.file b/.flatpak-builder/cache/objects/d6/f9504aac66dcff003245d037183a8da06adf489500a9a0d17c7d54ab0a056b.file new file mode 100644 index 0000000..7779427 --- /dev/null +++ b/.flatpak-builder/cache/objects/d6/f9504aac66dcff003245d037183a8da06adf489500a9a0d17c7d54ab0a056b.file @@ -0,0 +1,527 @@ +/* + * Copyright (C) 2018 Daniel Espinosa + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +#define G_LOG_DOMAIN "GDA-provider" + +#include + +G_DEFINE_INTERFACE(GdaProvider, gda_provider, G_TYPE_OBJECT) + +static void +gda_provider_default_init (GdaProviderInterface *iface) {} + +/** + * gda_provider_get_name: + * + * Returns: (transfer none): + * Since: 6.0 + * Stability: Unstable + */ +const gchar* +gda_provider_get_name (GdaProvider *provider) { + g_return_val_if_fail (provider, NULL); + GdaProviderInterface *iface = GDA_PROVIDER_GET_IFACE (provider); + if (iface->get_name) { + return iface->get_name (provider); + } + return NULL; +} +/** + * gda_provider_get_version: + * + * Returns: (transfer none): + * Since: 6.0 + * Stability: Unstable + */ +const gchar* +gda_provider_get_version (GdaProvider *provider) { + g_return_val_if_fail (provider, NULL); + GdaProviderInterface *iface = GDA_PROVIDER_GET_IFACE (provider); + if (iface->get_version) { + return iface->get_version (provider); + } + return NULL; +} +/** + * gda_provider_get_server_version: + * + * Returns: (transfer none): + * Since: 6.0 + * Stability: Unstable + */ +const gchar* +gda_provider_get_server_version (GdaProvider *provider, GdaConnection *cnc) { + g_return_val_if_fail (provider, NULL); + GdaProviderInterface *iface = GDA_PROVIDER_GET_IFACE (provider); + if (iface->get_server_version) { + return iface->get_server_version (provider, cnc); + } + return NULL; +} +/** + * gda_provider_supports_feature: + * + * Since: 6.0 + * Stability: Unstable + */ +gboolean +gda_provider_supports_feature (GdaProvider *provider, GdaConnection *cnc, + GdaConnectionFeature feature) { + g_return_val_if_fail (provider, TRUE); + GdaProviderInterface *iface = GDA_PROVIDER_GET_IFACE (provider); + if (iface->supports_feature) { + return iface->supports_feature (provider, cnc, feature); + } + return TRUE; +} +/** + * gda_provider_create_parser: + * + * Returns: (transfer full): + * Since: 6.0 + * Stability: Unstable + */ +GdaSqlParser* +gda_provider_create_parser (GdaProvider *provider, GdaConnection *cnc) { + g_return_val_if_fail (provider, NULL); + GdaProviderInterface *iface = GDA_PROVIDER_GET_IFACE (provider); + if (iface->create_parser) { + return iface->create_parser (provider, cnc); + } + return NULL; +} /* may be NULL */ +/** + * gda_provider_create_connection: + * + * Returns: (transfer full): + * Since: 6.0 + * Stability: Unstable + */ +GdaConnection* +gda_provider_create_connection (GdaProvider *provider) { + g_return_val_if_fail (provider, NULL); + GdaProviderInterface *iface = GDA_PROVIDER_GET_IFACE (provider); + if (iface->create_connection) { + return iface->create_connection (provider); + } + return NULL; +} +/** + * gda_provider_get_data_handler: + * + * Returns: (transfer full): + * Since: 6.0 + * Stability: Unstable + */ +GdaDataHandler* +gda_provider_get_data_handler (GdaProvider *provider, GdaConnection *cnc, /* may be NULL */ + GType g_type, const gchar *dbms_type) { + g_return_val_if_fail (provider, NULL); + GdaProviderInterface *iface = GDA_PROVIDER_GET_IFACE (provider); + if (iface->get_data_handler) { + return iface->get_data_handler (provider, cnc, g_type, dbms_type); + } + return NULL; +} +/** + * gda_provider_get_def_dbms_type: + * + * Returns: (transfer full): + * Since: 6.0 + * Stability: Unstable + */ +const gchar* +gda_provider_get_def_dbms_type (GdaProvider *provider, GdaConnection *cnc, + GType g_type) { + g_return_val_if_fail (provider, NULL); + GdaProviderInterface *iface = GDA_PROVIDER_GET_IFACE (provider); + if (iface->get_def_dbms_type) { + return iface->get_def_dbms_type (provider, cnc, g_type); + } + return NULL; +} /* may be NULL */ +/** + * gda_provider_supports_operation: + * + * Since: 6.0 + * Stability: Unstable + */ +gboolean +gda_provider_supports_operation (GdaProvider *provider, GdaConnection *cnc, + GdaServerOperationType type, GdaSet *options) { + g_return_val_if_fail (provider, FALSE); + GdaProviderInterface *iface = GDA_PROVIDER_GET_IFACE (provider); + if (iface->supports_operation) { + return iface->supports_operation (provider, cnc, type, options); + } + return FALSE; +} +/** + * gda_provider_create_operation: + * + * Returns: (transfer full): + * Since: 6.0 + * Stability: Unstable + */ +GdaServerOperation* +gda_provider_create_operation (GdaProvider *provider, GdaConnection *cnc, + GdaServerOperationType type, GdaSet *options, + GError **error) { + g_return_val_if_fail (provider, NULL); + GdaProviderInterface *iface = GDA_PROVIDER_GET_IFACE (provider); + if (iface->create_operation) { + return iface->create_operation (provider, cnc, type, options, error); + } + return NULL; +} +/** + * gda_provider_render_operation: + * + * Returns: (transfer full): + * Since: 6.0 + * Stability: Unstable + */ +gchar* +gda_provider_render_operation (GdaProvider *provider, GdaConnection *cnc, + GdaServerOperation *op, GError **error) { + g_return_val_if_fail (provider, NULL); + GdaProviderInterface *iface = GDA_PROVIDER_GET_IFACE (provider); + if (iface->render_operation) { + return iface->render_operation (provider, cnc, op, error); + } + return NULL; +} +/** + * gda_provider_statement_to_sql: + * @provider: + * @cnc: + * @stmt: + * @params: (nullable): + * @flags: + * @params_used: (nullable) (element-type Gda.Holder) (out) (transfer container): + * @error: + * + * Returns: (transfer full): + * Since: 6.0 + * Stability: Unstable + */ +gchar* +gda_provider_statement_to_sql (GdaProvider *provider, GdaConnection *cnc, + GdaStatement *stmt, GdaSet *params, + GdaStatementSqlFlag flags, + GSList **params_used, GError **error) { + g_return_val_if_fail (provider, NULL); + GdaProviderInterface *iface = GDA_PROVIDER_GET_IFACE (provider); + if (iface->statement_to_sql) { + return iface->statement_to_sql (provider, cnc, stmt, params, flags, params_used, error); + } + return NULL; +} +/** + * gda_provider_identifier_quote: + * @provider: + * @cnc: (nullable): + * @id: + * @for_meta_store: + * @force_quotes: + * + * Returns: (transfer full): + * Since: 6.0 + * Stability: Unstable + */ +gchar* +gda_provider_identifier_quote (GdaProvider *provider, GdaConnection *cnc, /* may be NULL */ + const gchar *id, + gboolean for_meta_store, gboolean force_quotes) { + g_return_val_if_fail (provider, NULL); + GdaProviderInterface *iface = GDA_PROVIDER_GET_IFACE (provider); + if (iface->identifier_quote) { + return iface->identifier_quote (provider, cnc, id, for_meta_store, force_quotes); + } + return NULL; +} +/** + * gda_provider_statement_rewrite: + * + * Returns: (transfer full): + * Since: 6.0 + * Stability: Unstable + */ +GdaSqlStatement* +gda_provider_statement_rewrite (GdaProvider *provider, GdaConnection *cnc, + GdaStatement *stmt, GdaSet *params, GError **error) { + g_return_val_if_fail (provider, NULL); + GdaProviderInterface *iface = GDA_PROVIDER_GET_IFACE (provider); + if (iface->statement_rewrite) { + return iface->statement_rewrite (provider, cnc, stmt, params, error); + } + return NULL; +} +/** + * gda_provider_open_connection: + * + * Since: 6.0 + * Stability: Unstable + */ +gboolean +gda_provider_open_connection (GdaProvider *provider, GdaConnection *cnc, + GdaQuarkList *params, GdaQuarkList *auth) { + g_return_val_if_fail (provider, FALSE); + GdaProviderInterface *iface = GDA_PROVIDER_GET_IFACE (provider); + if (iface->open_connection) { + return iface->open_connection (provider, cnc, params, auth); + } + return FALSE; +} +/** + * gda_provider_prepare_connection: + * + * Since: 6.0 + * Stability: Unstable + */ +gboolean +gda_provider_prepare_connection (GdaProvider *provider, GdaConnection *cnc, + GdaQuarkList *params, GdaQuarkList *auth) { + g_return_val_if_fail (provider, FALSE); + GdaProviderInterface *iface = GDA_PROVIDER_GET_IFACE (provider); + if (iface->prepare_connection) { + return iface->prepare_connection (provider, cnc, params, auth); + } + return FALSE; +} +/** + * gda_provider_close_connection: + * + * Since: 6.0 + * Stability: Unstable + */ +gboolean +gda_provider_close_connection (GdaProvider *provider, GdaConnection *cnc) { + g_return_val_if_fail (provider, FALSE); + GdaProviderInterface *iface = GDA_PROVIDER_GET_IFACE (provider); + if (iface->close_connection) { + return iface->close_connection (provider, cnc); + } + return FALSE; +} +/** + * gda_provider_escape_string: + * + * Returns: (transfer full): + * Since: 6.0 + * Stability: Unstable + */ +gchar* +gda_provider_escape_string (GdaProvider *provider, GdaConnection *cnc, + const gchar *str) { + g_return_val_if_fail (provider, NULL); + GdaProviderInterface *iface = GDA_PROVIDER_GET_IFACE (provider); + if (iface->escape_string) { + return iface->escape_string (provider, cnc, str); + } + return NULL; +} /* may be NULL */ +/** + * gda_provider_unescape_string: + * + * Returns: (transfer full): + * Since: 6.0 + * Stability: Unstable + */ +gchar* +gda_provider_unescape_string (GdaProvider *provider, GdaConnection *cnc, + const gchar *str) { + g_return_val_if_fail (provider, NULL); + GdaProviderInterface *iface = GDA_PROVIDER_GET_IFACE (provider); + if (iface->unescape_string) { + return iface->unescape_string (provider, cnc, str); + } + return NULL; +} /* may be NULL */ +/** + * gda_provider_perform_operation: + * + * Since: 6.0 + * Stability: Unstable + */ +gboolean +gda_provider_perform_operation (GdaProvider *provider, GdaConnection *cnc, /* may be NULL */ + GdaServerOperation *op, GError **error) { + g_return_val_if_fail (provider, FALSE); + GdaProviderInterface *iface = GDA_PROVIDER_GET_IFACE (provider); + if (iface->perform_operation) { + return iface->perform_operation (provider, cnc, op, error); + } + return FALSE; +} +/** + * gda_provider_begin_transaction: + * + * Since: 6.0 + * Stability: Unstable + */ +gboolean +gda_provider_begin_transaction (GdaProvider *provider, GdaConnection *cnc, + const gchar *name, GdaTransactionIsolation level, + GError **error) { + g_return_val_if_fail (provider, FALSE); + GdaProviderInterface *iface = GDA_PROVIDER_GET_IFACE (provider); + if (iface->begin_transaction) { + return iface->begin_transaction (provider, cnc, name, level, error); + } + return FALSE; +} +/** + * gda_provider_commit_transaction: + * + * Since: 6.0 + * Stability: Unstable + */ +gboolean +gda_provider_commit_transaction (GdaProvider *provider, GdaConnection *cnc, + const gchar *name, GError **error) { + g_return_val_if_fail (provider, FALSE); + GdaProviderInterface *iface = GDA_PROVIDER_GET_IFACE (provider); + if (iface->commit_transaction) { + return iface->commit_transaction (provider, cnc, name, error); + } + return FALSE; +} +/** + * gda_provider_rollback_transaction: + * + * Since: 6.0 + * Stability: Unstable + */ +gboolean +gda_provider_rollback_transaction (GdaProvider *provider, GdaConnection *cnc, + const gchar *name, GError **error) { + g_return_val_if_fail (provider, FALSE); + GdaProviderInterface *iface = GDA_PROVIDER_GET_IFACE (provider); + if (iface->rollback_transaction) { + return iface->rollback_transaction (provider, cnc, name, error); + } + return FALSE; +} +/** + * gda_provider_add_savepoint: + * + * Since: 6.0 + * Stability: Unstable + */ +gboolean +gda_provider_add_savepoint (GdaProvider *provider, GdaConnection *cnc, + const gchar *name, GError **error) { + g_return_val_if_fail (provider, FALSE); + GdaProviderInterface *iface = GDA_PROVIDER_GET_IFACE (provider); + if (iface->add_savepoint) { + return iface->add_savepoint (provider, cnc, name, error); + } + return FALSE; +} +/** + * gda_provider_rollback_savepoint: + * + * Since: 6.0 + * Stability: Unstable + */ +gboolean +gda_provider_rollback_savepoint (GdaProvider *provider, GdaConnection *cnc, + const gchar *name, GError **error) { + g_return_val_if_fail (provider, FALSE); + GdaProviderInterface *iface = GDA_PROVIDER_GET_IFACE (provider); + if (iface->rollback_savepoint) { + return iface->rollback_savepoint (provider, cnc, name, error); + } + return FALSE; +} +/** + * gda_provider_delete_savepoint: + * + * Since: 6.0 + * Stability: Unstable + */ +gboolean +gda_provider_delete_savepoint (GdaProvider *provider, GdaConnection *cnc, + const gchar *name, GError **error) { + g_return_val_if_fail (provider, FALSE); + GdaProviderInterface *iface = GDA_PROVIDER_GET_IFACE (provider); + if (iface->delete_savepoint) { + return iface->delete_savepoint (provider, cnc, name, error); + } + return FALSE; +} +/** + * gda_provider_statement_prepare: + * + * Since: 6.0 + * Stability: Unstable + */ +gboolean +gda_provider_statement_prepare (GdaProvider *provider, GdaConnection *cnc, + GdaStatement *stmt, GError **error) { + g_return_val_if_fail (provider, FALSE); + GdaProviderInterface *iface = GDA_PROVIDER_GET_IFACE (provider); + if (iface->statement_prepare) { + return iface->statement_prepare (provider, cnc, stmt, error); + } + return FALSE; +} +/** + * gda_provider_statement_execute: + * + * Returns: (transfer full): + * Since: 6.0 + * Stability: Unstable + */ +GObject* +gda_provider_statement_execute (GdaProvider *provider, GdaConnection *cnc, + GdaStatement *stmt, GdaSet *params, + GdaStatementModelUsage model_usage, + GType *col_types, GdaSet **last_inserted_row, + GError **error) { + g_return_val_if_fail (provider, NULL); + GdaProviderInterface *iface = GDA_PROVIDER_GET_IFACE (provider); + if (iface->statement_execute) { + return iface->statement_execute (provider, cnc, stmt, params, model_usage, col_types, last_inserted_row, error); + } + return NULL; +} + +/** + * gda_provider_get_last_inserted: + * @provider: a #GdaProvider object + * @cnc: a #GdaConnection to get last inserted from + * @error: a place to put errors + * + * This command should be called inmediately called after a INSERT SQL command + * + * Return: (transfer full): a #GdaSet with all data of the last inserted row + */ +GdaSet* +gda_provider_get_last_inserted (GdaProvider *provider, + GdaConnection *cnc, + GError **error) +{ + g_return_val_if_fail (provider, NULL); + GdaProviderInterface *iface = GDA_PROVIDER_GET_IFACE (provider); + if (iface->get_last_inserted) { + return iface->get_last_inserted (provider, cnc, error); + } + return NULL; +} diff --git a/.flatpak-builder/cache/objects/d7/14a1694b8e84b9220f3f61e2329f63d0052e410cc00b62d3126818882c6113.dirtree b/.flatpak-builder/cache/objects/d7/14a1694b8e84b9220f3f61e2329f63d0052e410cc00b62d3126818882c6113.dirtree new file mode 100644 index 0000000..57c187f Binary files /dev/null and b/.flatpak-builder/cache/objects/d7/14a1694b8e84b9220f3f61e2329f63d0052e410cc00b62d3126818882c6113.dirtree differ diff --git a/.flatpak-builder/cache/objects/d7/dccf41660330dc466e4e5c6d559bf6811bf4f753c489ebcf5127bc81c64647.dirtree b/.flatpak-builder/cache/objects/d7/dccf41660330dc466e4e5c6d559bf6811bf4f753c489ebcf5127bc81c64647.dirtree new file mode 100644 index 0000000..5cd0657 Binary files /dev/null and b/.flatpak-builder/cache/objects/d7/dccf41660330dc466e4e5c6d559bf6811bf4f753c489ebcf5127bc81c64647.dirtree differ diff --git a/.flatpak-builder/cache/objects/d8/08ce5303646bc9a5fdd6527463df6d287f75fc338a1e1a2a074211b1bc28b8.file b/.flatpak-builder/cache/objects/d8/08ce5303646bc9a5fdd6527463df6d287f75fc338a1e1a2a074211b1bc28b8.file new file mode 100644 index 0000000..b302eb9 Binary files /dev/null and b/.flatpak-builder/cache/objects/d8/08ce5303646bc9a5fdd6527463df6d287f75fc338a1e1a2a074211b1bc28b8.file differ diff --git a/.flatpak-builder/cache/objects/d8/626ce329c3808c66eabd0d2b0f947241cb7e7feeab86c18ac6d0234854682a.dirtree b/.flatpak-builder/cache/objects/d8/626ce329c3808c66eabd0d2b0f947241cb7e7feeab86c18ac6d0234854682a.dirtree new file mode 100644 index 0000000..a290cd4 Binary files /dev/null and b/.flatpak-builder/cache/objects/d8/626ce329c3808c66eabd0d2b0f947241cb7e7feeab86c18ac6d0234854682a.dirtree differ diff --git a/.flatpak-builder/cache/objects/d8/b726f59abc1024858f2833e252942b9d125f0846090a25f8130cc00f3c738a.dirtree b/.flatpak-builder/cache/objects/d8/b726f59abc1024858f2833e252942b9d125f0846090a25f8130cc00f3c738a.dirtree new file mode 100644 index 0000000..2d99d0f Binary files /dev/null and b/.flatpak-builder/cache/objects/d8/b726f59abc1024858f2833e252942b9d125f0846090a25f8130cc00f3c738a.dirtree differ diff --git a/.flatpak-builder/cache/objects/d8/ca098a23cfc5b0c414c926a63f65f622351f8d84e5ab6f613fe68e75c43569.file b/.flatpak-builder/cache/objects/d8/ca098a23cfc5b0c414c926a63f65f622351f8d84e5ab6f613fe68e75c43569.file new file mode 100644 index 0000000..eb79c69 --- /dev/null +++ b/.flatpak-builder/cache/objects/d8/ca098a23cfc5b0c414c926a63f65f622351f8d84e5ab6f613fe68e75c43569.file @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2000 Reinhard Müller + * Copyright (C) 2000 - 2002 Rodrigo Moya + * Copyright (C) 2001 Carlos Perelló Marín + * Copyright (C) 2001 - 2014 Vivien Malerba + * Copyright (C) 2002 Gonzalo Paniagua Javier + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GDA_DATA_SELECT_PRIV_H__ +#define __GDA_DATA_SELECT_PRIV_H__ + +#include +#include +#include +#include +#include + +G_BEGIN_DECLS + +/** + * SECTION:gda-data-select-priv + * @short_description: Base class for all the data models returned by DBMS providers when a SELECT statement is executed + * @title: Subclassing GdaDataSelect + * @stability: Stable + * @see_also: #GdaDataModel and #GdaDataSelect + * + * All database providers should subclass this class when returning a data model after the execution of a SELECT + * statement. Specifically it has the following features: + * + * Manages its list of GdaColumn using the list exported by the prepared statement object (GdaPStmt) + * Allows random or cursor based access + * Allows for efficient memory usage allowing the subclass to finely tune its memory usage + * Provides a generic mechanism for writable data models + * + * + * See the Virtual methods for recordsets section for more information + * about how to implement the virtual methods of the subclassed object. + * + * This section documents the methods available for the database provider's implementations. + */ + +GType gda_data_select_get_type (void) G_GNUC_CONST; + +/* API reserved to provider's implementations */ +void gda_data_select_take_row (GdaDataSelect *model, GdaRow *row, gint rownum); +GdaRow *gda_data_select_get_stored_row (GdaDataSelect *model, gint rownum); +GdaConnection *gda_data_select_get_connection (GdaDataSelect *model); +void gda_data_select_set_columns (GdaDataSelect *model, GSList *columns); + +void gda_data_select_add_exception (GdaDataSelect *model, GError *error); + +/* internal API */ +void _gda_data_select_share_private_data (GdaDataSelect *master, GdaDataSelect *slave); + +G_END_DECLS + +#endif diff --git a/.flatpak-builder/cache/objects/d8/e065423428040a0057c4c0f4e30f82bb98220c9ddad6ac7dc9a36f9f80b550.dirtree b/.flatpak-builder/cache/objects/d8/e065423428040a0057c4c0f4e30f82bb98220c9ddad6ac7dc9a36f9f80b550.dirtree new file mode 100644 index 0000000..674c337 Binary files /dev/null and b/.flatpak-builder/cache/objects/d8/e065423428040a0057c4c0f4e30f82bb98220c9ddad6ac7dc9a36f9f80b550.dirtree differ diff --git a/.flatpak-builder/cache/objects/d8/e7ff7e7ec21c81290ce17a20f5b323ce07fa411be79f0e68d8bb10f20d791b.file b/.flatpak-builder/cache/objects/d8/e7ff7e7ec21c81290ce17a20f5b323ce07fa411be79f0e68d8bb10f20d791b.file new file mode 100644 index 0000000..2e6a9b8 --- /dev/null +++ b/.flatpak-builder/cache/objects/d8/e7ff7e7ec21c81290ce17a20f5b323ce07fa411be79f0e68d8bb10f20d791b.file @@ -0,0 +1,164 @@ +/* + * Copyright (C) 2008 - 2013 Vivien Malerba + * Copyright (C) 2018 Daniel Espinosa + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + + +#ifndef _GDA_STATEMENT_H_ +#define _GDA_STATEMENT_H_ + +#include +#include + +G_BEGIN_DECLS + +/* error reporting */ +extern GQuark gda_statement_error_quark (void); +#define GDA_STATEMENT_ERROR gda_statement_error_quark () + +/** + * GdaStatementError: + * @GDA_STATEMENT_PARSE_ERROR: + * @GDA_STATEMENT_SYNTAX_ERROR: + * @GDA_STATEMENT_NO_CNC_ERROR: + * @GDA_STATEMENT_CNC_CLOSED_ERROR: + * @GDA_STATEMENT_EXEC_ERROR: + * @GDA_STATEMENT_PARAM_TYPE_ERROR: + * @GDA_STATEMENT_PARAM_ERROR: + */ +typedef enum +{ + GDA_STATEMENT_PARSE_ERROR, + GDA_STATEMENT_SYNTAX_ERROR, + GDA_STATEMENT_NO_CNC_ERROR, + GDA_STATEMENT_CNC_CLOSED_ERROR, + GDA_STATEMENT_EXEC_ERROR, + GDA_STATEMENT_PARAM_TYPE_ERROR, + GDA_STATEMENT_PARAM_ERROR +} GdaStatementError; + +/** + * GdaStatementModelUsage: + * @GDA_STATEMENT_MODEL_RANDOM_ACCESS: access to the data model will be random (usually this will result in a data model completely stored in memory) + * @GDA_STATEMENT_MODEL_CURSOR_FORWARD: access to the data model will be done using a cursor moving forward + * @GDA_STATEMENT_MODEL_CURSOR_BACKWARD: access to the data model will be done using a cursor moving backward + * @GDA_STATEMENT_MODEL_CURSOR: access to the data model will be done using a cursor (moving both forward and backward) + * @GDA_STATEMENT_MODEL_ALLOW_NOPARAM: specifies that the data model should be executed even if some parameters required to execute it are invalid (in this case the data model will have no row, and will automatically be re-run when the missing parameters are once again valid) + * @GDA_STATEMENT_MODEL_OFFLINE: specifies that the data model's contents will be fully loaded into the client side (the memory of the process using Libgda), not requiring the server any more to access the data (the default behaviour is to access the server any time data is to be read, and data is cached in memory). This flag is useful only if used in conjunction with the GDA_STATEMENT_MODEL_RANDOM_ACCESS flag (otherwise an error will be returned). + * + * These flags specify how the #GdaDataModel returned when executing a #GdaStatement will be used + */ +typedef enum { + GDA_STATEMENT_MODEL_RANDOM_ACCESS = 1 << 0, + GDA_STATEMENT_MODEL_CURSOR_FORWARD = 1 << 1, + GDA_STATEMENT_MODEL_CURSOR_BACKWARD = 1 << 2, + GDA_STATEMENT_MODEL_CURSOR = GDA_STATEMENT_MODEL_CURSOR_FORWARD | GDA_STATEMENT_MODEL_CURSOR_BACKWARD, + GDA_STATEMENT_MODEL_ALLOW_NOPARAM = 1 << 3, + GDA_STATEMENT_MODEL_OFFLINE = 1 << 4 +} GdaStatementModelUsage; + +/** + * GdaStatementSqlFlag: + * @GDA_STATEMENT_SQL_PARAMS_AS_VALUES: rendering will replace parameters with their values + * @GDA_STATEMENT_SQL_PRETTY: rendering will include newlines and indentation to make it easy to read + * @GDA_STATEMENT_SQL_PARAMS_LONG: parameters will be rendered using the "/* name:<param_name> ... */" syntax + * @GDA_STATEMENT_SQL_PARAMS_SHORT: parameters will be rendered using the "##<param_name>..." syntax + * @GDA_STATEMENT_SQL_PARAMS_AS_COLON: parameters will be rendered using the ":<param_name>" syntax + * @GDA_STATEMENT_SQL_PARAMS_AS_DOLLAR: parameters will be rendered using the "$<param_number>" syntax where parameters are numbered starting from 1 + * @GDA_STATEMENT_SQL_PARAMS_AS_QMARK: parameters will be rendered using the "?<param_number>" syntax where parameters are numbered starting from 1 + * @GDA_STATEMENT_SQL_PARAMS_AS_UQMARK: parameters will be rendered using the "?" syntax + * @GDA_STATEMENT_SQL_TIMEZONE_TO_GMT: time and timestamp with a timezone information are converted to GMT before rendering, and rendering does not show the timezone information + * + * Specifies rendering options + */ +typedef enum { + GDA_STATEMENT_SQL_PARAMS_AS_VALUES = 0, + GDA_STATEMENT_SQL_PRETTY = 1 << 0, + GDA_STATEMENT_SQL_PARAMS_LONG = 1 << 1, + GDA_STATEMENT_SQL_PARAMS_SHORT = 1 << 2, + GDA_STATEMENT_SQL_PARAMS_AS_COLON = 1 << 3, + GDA_STATEMENT_SQL_PARAMS_AS_DOLLAR = 1 << 4, + GDA_STATEMENT_SQL_PARAMS_AS_QMARK = 1 << 5, + GDA_STATEMENT_SQL_PARAMS_AS_UQMARK = 1 << 6, + GDA_STATEMENT_SQL_TIMEZONE_TO_GMT = 1 << 7 +} GdaStatementSqlFlag; + + +#define GDA_TYPE_STATEMENT (gda_statement_get_type()) +G_DECLARE_DERIVABLE_TYPE(GdaStatement, gda_statement, GDA, STATEMENT, GObject) + +/* struct for the object's class */ +struct _GdaStatementClass +{ + GObjectClass parent_class; + + /* signals */ + void (*checked) (GdaStatement *stmt, GdaConnection *cnc, gboolean checked); + void (*reset) (GdaStatement *stmt); + + /*< private >*/ + /* Padding for future expansion */ + void (*_gda_reserved1) (void); + void (*_gda_reserved2) (void); + void (*_gda_reserved3) (void); + void (*_gda_reserved4) (void); +}; + +/** + * SECTION:gda-statement + * @short_description: Single SQL statement + * @title: GdaStatement + * @stability: Stable + * @see_also: #GdaBatch + * + * The #GdaStatement represents a single SQL statement (multiple statements can be grouped in a #GdaBatch object). + * + * A #GdaStatement can either be built by describing its constituing parts using a #GdaSqlBuilder object, + * or from an SQL statement using a #GdaSqlParser object. + * + * A #GdaConnection can use a #GdaStatement to: + * + * prepare it for a future execution, the preparation step involves converting the #GdaStatement + * object into a structure used by the database's own API, see gda_connection_statement_prepare() + * execute it using gda_connection_statement_execute_select() if it is known that the statement is a + * selection statement, gda_connection_statement_execute_non_select() if it is not a selection statement, or + * gda_connection_statement_execute() when the type of expected result is unknown. + * + * Note that it is possible to use the same #GdaStatement object at the same time with several #GdaConnection objects. + */ + +GdaStatement *gda_statement_new (void); +GdaStatement *gda_statement_copy (GdaStatement *orig); + +gchar *gda_statement_serialize (GdaStatement *stmt); + +gboolean gda_statement_get_parameters (GdaStatement *stmt, GdaSet **out_params, GError **error); +#define gda_statement_to_sql(stmt,params,error) gda_statement_to_sql_extended ((stmt), NULL, (params), GDA_STATEMENT_SQL_PARAMS_SHORT, NULL, (error)) +gchar *gda_statement_to_sql_extended (GdaStatement *stmt, GdaConnection *cnc, + GdaSet *params, GdaStatementSqlFlag flags, + GSList **params_used, GError **error); + +GdaSqlStatementType gda_statement_get_statement_type (GdaStatement *stmt); +gboolean gda_statement_is_useless (GdaStatement *stmt); +gboolean gda_statement_check_structure (GdaStatement *stmt, GError **error); +gboolean gda_statement_check_validity (GdaStatement *stmt, GdaConnection *cnc, GError **error); +gboolean gda_statement_normalize (GdaStatement *stmt, GdaConnection *cnc, GError **error); + +G_END_DECLS + +#endif diff --git a/.flatpak-builder/cache/objects/d9/6f3137725d9bfc49bbc53d1946015da5a2437ea00e367eeb973cf047be6d0d.file b/.flatpak-builder/cache/objects/d9/6f3137725d9bfc49bbc53d1946015da5a2437ea00e367eeb973cf047be6d0d.file new file mode 100755 index 0000000..e198da7 Binary files /dev/null and b/.flatpak-builder/cache/objects/d9/6f3137725d9bfc49bbc53d1946015da5a2437ea00e367eeb973cf047be6d0d.file differ diff --git a/.flatpak-builder/cache/objects/d9/83238c7e1852832d4d7d94bfd2966058cea7d061397d92e1691a186108b03a.dirtree b/.flatpak-builder/cache/objects/d9/83238c7e1852832d4d7d94bfd2966058cea7d061397d92e1691a186108b03a.dirtree new file mode 100644 index 0000000..7fd05cf Binary files /dev/null and b/.flatpak-builder/cache/objects/d9/83238c7e1852832d4d7d94bfd2966058cea7d061397d92e1691a186108b03a.dirtree differ diff --git a/.flatpak-builder/cache/objects/d9/a72a7556efcb4c9beddcb0f360121b7b3c755a94b86a703e7c6e4a187f21b4.dirtree b/.flatpak-builder/cache/objects/d9/a72a7556efcb4c9beddcb0f360121b7b3c755a94b86a703e7c6e4a187f21b4.dirtree new file mode 100644 index 0000000..ed68c84 Binary files /dev/null and b/.flatpak-builder/cache/objects/d9/a72a7556efcb4c9beddcb0f360121b7b3c755a94b86a703e7c6e4a187f21b4.dirtree differ diff --git a/.flatpak-builder/cache/objects/da/39f8e468dcc4a555fb1cc111286bdaed837e07269fa9a484e52de5cb88281e.file b/.flatpak-builder/cache/objects/da/39f8e468dcc4a555fb1cc111286bdaed837e07269fa9a484e52de5cb88281e.file new file mode 100644 index 0000000..2f3027a Binary files /dev/null and b/.flatpak-builder/cache/objects/da/39f8e468dcc4a555fb1cc111286bdaed837e07269fa9a484e52de5cb88281e.file differ diff --git a/.flatpak-builder/cache/objects/da/4d8a50c186c18ecef7bd4cd6bf8e87ec41311079aa51c91c755a1dba1483fb.file b/.flatpak-builder/cache/objects/da/4d8a50c186c18ecef7bd4cd6bf8e87ec41311079aa51c91c755a1dba1483fb.file new file mode 100755 index 0000000..7ff2952 Binary files /dev/null and b/.flatpak-builder/cache/objects/da/4d8a50c186c18ecef7bd4cd6bf8e87ec41311079aa51c91c755a1dba1483fb.file differ diff --git a/.flatpak-builder/cache/objects/da/637fdd0a83edd87b87f94b9cce7198f62779409ef4807f585e7433c595342d.dirtree b/.flatpak-builder/cache/objects/da/637fdd0a83edd87b87f94b9cce7198f62779409ef4807f585e7433c595342d.dirtree new file mode 100644 index 0000000..0fdfef2 Binary files /dev/null and b/.flatpak-builder/cache/objects/da/637fdd0a83edd87b87f94b9cce7198f62779409ef4807f585e7433c595342d.dirtree differ diff --git a/.flatpak-builder/cache/objects/da/8f7bed1157f441f6f8fcca356129eea2b03e4bc6ef7fdbc5cac37e536cc367.file b/.flatpak-builder/cache/objects/da/8f7bed1157f441f6f8fcca356129eea2b03e4bc6ef7fdbc5cac37e536cc367.file new file mode 100644 index 0000000..a4fea21 --- /dev/null +++ b/.flatpak-builder/cache/objects/da/8f7bed1157f441f6f8fcca356129eea2b03e4bc6ef7fdbc5cac37e536cc367.file @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2008 - 2012 Vivien Malerba + * Copyright (C) 2009 Bas Driessen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GDA_DATA_SELECT_EXTRA_H__ +#define __GDA_DATA_SELECT_EXTRA_H__ + +#include +#include +#include +#include +#include + +G_BEGIN_DECLS + +typedef enum +{ + FIRST_QUERY = 0, + INS_QUERY = 0, + UPD_QUERY = 1, + DEL_QUERY = 2, + NB_QUERIES = 3 +} ModType; + +typedef struct { + gboolean safely_locked; + GdaSqlExpr *unique_row_condition; + gint *insert_to_select_mapping; /* see compute_insert_select_params_mapping() */ + + GdaSet *exec_set; /* owned by this object (copied) */ + GdaSet *modif_set; /* owned by this object */ + GSList *modif_params[NB_QUERIES]; /* the lists point to holders in @modif_set */ + GdaStatement *modif_stmts[NB_QUERIES]; + GHashTable *upd_stmts; /* key = a gboolean vector with TRUEs when the column is used, value = an UPDATE GdaStatement */ + GHashTable *ins_stmts; /* key = a gboolean vector with TRUEs when the column is used, value = an INSERT GdaStatement */ + GdaStatement *one_row_select_stmt; /* used to retrieve one row after an UPDATE + * or INSERT operation */ + + gboolean *cols_mod[NB_QUERIES]; /* each NULL or an array of booleans the same size as + * GdaDataSelectPriv's PrivateShareable's @columns's length */ +} GdaDataSelectInternals; + +GdaDataSelectInternals *_gda_data_select_internals_steal (GdaDataSelect *model); +void _gda_data_select_internals_paste (GdaDataSelect *model, GdaDataSelectInternals *inter); +void _gda_data_select_internals_free (GdaDataSelectInternals *inter); + +G_END_DECLS + +#endif diff --git a/.flatpak-builder/cache/objects/da/9239eb6744368468a4dde8db8817dc704b33ea4c86acdda61380d130240cc9.dirtree b/.flatpak-builder/cache/objects/da/9239eb6744368468a4dde8db8817dc704b33ea4c86acdda61380d130240cc9.dirtree new file mode 100644 index 0000000..287b0e0 Binary files /dev/null and b/.flatpak-builder/cache/objects/da/9239eb6744368468a4dde8db8817dc704b33ea4c86acdda61380d130240cc9.dirtree differ diff --git a/.flatpak-builder/cache/objects/db/5141824565896050ab20c4f0e7bf095bf2b39bb9a4c6b61099669f9f3df6b9.file b/.flatpak-builder/cache/objects/db/5141824565896050ab20c4f0e7bf095bf2b39bb9a4c6b61099669f9f3df6b9.file new file mode 100755 index 0000000..e7055ad Binary files /dev/null and b/.flatpak-builder/cache/objects/db/5141824565896050ab20c4f0e7bf095bf2b39bb9a4c6b61099669f9f3df6b9.file differ diff --git a/.flatpak-builder/cache/objects/db/76883ee40d00cd93e231e0e7f96a7b31569775ee5ce0bb93059f8496765b8b.file b/.flatpak-builder/cache/objects/db/76883ee40d00cd93e231e0e7f96a7b31569775ee5ce0bb93059f8496765b8b.file new file mode 100644 index 0000000..93885a9 Binary files /dev/null and b/.flatpak-builder/cache/objects/db/76883ee40d00cd93e231e0e7f96a7b31569775ee5ce0bb93059f8496765b8b.file differ diff --git a/.flatpak-builder/cache/objects/db/eec158beac3f528e842749b27b724009be2be249f4992b8bd36d609310e150.dirtree b/.flatpak-builder/cache/objects/db/eec158beac3f528e842749b27b724009be2be249f4992b8bd36d609310e150.dirtree new file mode 100644 index 0000000..7c4e95a Binary files /dev/null and b/.flatpak-builder/cache/objects/db/eec158beac3f528e842749b27b724009be2be249f4992b8bd36d609310e150.dirtree differ diff --git a/.flatpak-builder/cache/objects/dc/11733ffb9f9af9d63c15e5b8ad557ec37142077d67ff857a9e45fed391a5e5.dirtree b/.flatpak-builder/cache/objects/dc/11733ffb9f9af9d63c15e5b8ad557ec37142077d67ff857a9e45fed391a5e5.dirtree new file mode 100644 index 0000000..7d2ec0f Binary files /dev/null and b/.flatpak-builder/cache/objects/dc/11733ffb9f9af9d63c15e5b8ad557ec37142077d67ff857a9e45fed391a5e5.dirtree differ diff --git a/.flatpak-builder/cache/objects/dc/26db2aa90eca5e10501a31b8f6547b49b2ecfa1056e449439520120141d7d7.file b/.flatpak-builder/cache/objects/dc/26db2aa90eca5e10501a31b8f6547b49b2ecfa1056e449439520120141d7d7.file new file mode 100644 index 0000000..c872169 Binary files /dev/null and b/.flatpak-builder/cache/objects/dc/26db2aa90eca5e10501a31b8f6547b49b2ecfa1056e449439520120141d7d7.file differ diff --git a/.flatpak-builder/cache/objects/dc/2a611baef2b3bba8092b71259f0c2ce39fa06959abf90a21e7b66a7673b3fd.file b/.flatpak-builder/cache/objects/dc/2a611baef2b3bba8092b71259f0c2ce39fa06959abf90a21e7b66a7673b3fd.file new file mode 100644 index 0000000..734cae7 Binary files /dev/null and b/.flatpak-builder/cache/objects/dc/2a611baef2b3bba8092b71259f0c2ce39fa06959abf90a21e7b66a7673b3fd.file differ diff --git a/.flatpak-builder/cache/objects/dc/67748a1d4036fae25fe87ccc70185606dcb7da66da1a8ddc8419429deb744b.file b/.flatpak-builder/cache/objects/dc/67748a1d4036fae25fe87ccc70185606dcb7da66da1a8ddc8419429deb744b.file new file mode 100644 index 0000000..21128f9 --- /dev/null +++ b/.flatpak-builder/cache/objects/dc/67748a1d4036fae25fe87ccc70185606dcb7da66da1a8ddc8419429deb744b.file @@ -0,0 +1,82 @@ +.TH INTLTOOL-PREPARE 8 "2003-08-02" "intltool" + +.SH NAME +intltool-prepare \- Prepare software to make use of intltool + +.SH SYNOPSIS +.B intltool-prepare +[\fIoption\fR] [\fI\s-1KEYWORD\s0\fR]... + + +.SH DESCRIPTION +.PP +For software packages that include some specific type of translatable +files (such as .desktop and .soundlist), before they make use of +\fBintltool\fR, translators have to dig through them one by one, and add +their localization into each file. This process is error prone, since +translators may include typing errors, or add their localization in wrong +encoding. Besides, translators may not alwas know other files (beside .po +files) are translatable. +.PP +.I intltool +avoids all the problems above by extracting strings inside those translatable +files into po template (.pot) file. All translators need to care about is +just translating po files. Afterwards, \fBintltool-merge\fR(8) will merge +localized strings into those files. +.PP +Before your software becomes intltool-aware, a few issues have to be sorted +out, and \fBintltool-prepare\fR tries to take care of all of them. +\fBintltool-prepare\fR will: +.IP \[bu] 2 +Extract all localized strings in .desktop style files (including ".desktop", +".soundlist", ".keys" and ".directory") into corresponding po files. +.IP \[bu] +Convert the translatable files into templates that don't contain any +localization. +.IP \[bu] +Add the list of template files above into \fBPOTFILES.in\fR. +.IP \[bu] +Add the list of old translatable files into \fB.cvsignore\fR (since they +will be generated by \fIintltool\fR later). +.IP \[bu] +Add the rules for generating these files into Makefile.am. +.PP +NOTE: You must change working directory to the top level source directory +before running \fBintltool-prepare\fR. + +.SH OPTIONS +.PP +\fIKEYWORD\fR is a list of additional keywords beside "Name", "Comment" and +"description". \fBintltool-prepare\fR will recognize any line starting with +those \fIKEYWORD\fR and extract localized strings after equal sign ("="). +.IP "\fB\-x\fR" 4 +.PD 0 +.IP "\fB\-\-verbose\fR" 4 +.PD +Be verbose to give user additional feedback. +.IP "\fB\-v\fR" 4 +.PD 0 +.IP "\fB\-\-version\fR" 4 +Show version information. +.IP "\fB\-h\fR" 4 +.PD 0 +.IP "\fB\-\-help\fR" 4 +Show usage and basic help information. + + +.SH REPORTING BUGS +Report bugs to http://bugs.launchpad.net/intltool + +.SH AUTHOR +Darin Adler +.br +Kenneth Christiansen +.br +Maciej Stachowiak + + +.SH SEE ALSO +.BR intltoolize (8), +.BR intltool-update (8), +.BR intltool-extract (8), +.BR intltool-merge (8) diff --git a/.flatpak-builder/cache/objects/dc/b259da968a01d5bf8a9e1cdf404980619f4ddf9b71c70e89d2a3e9a2664e0b.dirtree b/.flatpak-builder/cache/objects/dc/b259da968a01d5bf8a9e1cdf404980619f4ddf9b71c70e89d2a3e9a2664e0b.dirtree new file mode 100644 index 0000000..f7578ad Binary files /dev/null and b/.flatpak-builder/cache/objects/dc/b259da968a01d5bf8a9e1cdf404980619f4ddf9b71c70e89d2a3e9a2664e0b.dirtree differ diff --git a/.flatpak-builder/cache/objects/dd/208eb61af6af22f7aa6b3737e9429127704dc37d6a1f5f7d4c3d24adbf601b.file b/.flatpak-builder/cache/objects/dd/208eb61af6af22f7aa6b3737e9429127704dc37d6a1f5f7d4c3d24adbf601b.file new file mode 100644 index 0000000..3fc2666 --- /dev/null +++ b/.flatpak-builder/cache/objects/dd/208eb61af6af22f7aa6b3737e9429127704dc37d6a1f5f7d4c3d24adbf601b.file @@ -0,0 +1,186 @@ +# errors.py +# +# Copyright 2021 James Westman +# +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation; either version 3 of the +# License, or (at your option) any later version. +# +# This file is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program. If not, see . +# +# SPDX-License-Identifier: LGPL-3.0-or-later + +from dataclasses import dataclass +import typing as T +import sys, traceback +from . import utils +from .utils import Colors + + +class PrintableError(Exception): + """Parent class for errors that can be pretty-printed for the user, e.g. + compilation warnings and errors.""" + + def pretty_print(self, filename, code, stream=sys.stdout): + raise NotImplementedError() + + +@dataclass +class ErrorReference: + start: int + end: int + message: str + + +class CompileError(PrintableError): + """A PrintableError with a start/end position and optional hints""" + + category = "error" + color = Colors.RED + + def __init__( + self, + message: str, + start: T.Optional[int] = None, + end: T.Optional[int] = None, + did_you_mean: T.Optional[T.Tuple[str, T.List[str]]] = None, + hints: T.Optional[T.List[str]] = None, + actions: T.Optional[T.List["CodeAction"]] = None, + fatal: bool = False, + references: T.Optional[T.List[ErrorReference]] = None, + ) -> None: + super().__init__(message) + + self.message = message + self.start = start + self.end = end + self.hints = hints or [] + self.actions = actions or [] + self.references = references or [] + self.fatal = fatal + + if did_you_mean is not None: + self._did_you_mean(*did_you_mean) + + def hint(self, hint: str) -> "CompileError": + self.hints.append(hint) + return self + + def _did_you_mean(self, word: str, options: T.List[str]) -> None: + if word.replace("_", "-") in options: + self.hint(f"use '-', not '_': `{word.replace('_', '-')}`") + return + + recommend = utils.did_you_mean(word, options) + if recommend is not None: + if word.casefold() == recommend.casefold(): + self.hint(f"Did you mean `{recommend}` (note the capitalization)?") + else: + self.hint(f"Did you mean `{recommend}`?") + self.actions.append(CodeAction(f"Change to `{recommend}`", recommend)) + else: + self.hint("Did you check your spelling?") + self.hint("Are your dependencies up to date?") + + def pretty_print(self, filename: str, code: str, stream=sys.stdout) -> None: + assert self.start is not None + + line_num, col_num = utils.idx_to_pos(self.start + 1, code) + line = code.splitlines(True)[line_num] + + # Display 1-based line numbers + line_num += 1 + + stream.write( + f"""{self.color}{Colors.BOLD}{self.category}: {self.message}{Colors.CLEAR} +at {filename} line {line_num} column {col_num}: +{Colors.FAINT}{line_num :>4} |{Colors.CLEAR}{line.rstrip()}\n {Colors.FAINT}|{" "*(col_num-1)}^{Colors.CLEAR}\n""" + ) + + for hint in self.hints: + stream.write(f"{Colors.FAINT}hint: {hint}{Colors.CLEAR}\n") + + for ref in self.references: + line_num, col_num = utils.idx_to_pos(ref.start + 1, code) + line = code.splitlines(True)[line_num] + line_num += 1 + + stream.write( + f"""{Colors.FAINT}note: {ref.message}: +at {filename} line {line_num} column {col_num}: +{Colors.FAINT}{line_num :>4} |{line.rstrip()}\n {Colors.FAINT}|{" "*(col_num-1)}^{Colors.CLEAR}\n""" + ) + + stream.write("\n") + + +class CompileWarning(CompileError): + category = "warning" + color = Colors.YELLOW + + +class UpgradeWarning(CompileWarning): + category = "upgrade" + color = Colors.PURPLE + + +class UnexpectedTokenError(CompileError): + def __init__(self, start, end) -> None: + super().__init__("Unexpected tokens", start, end) + + +@dataclass +class CodeAction: + title: str + replace_with: str + + +class MultipleErrors(PrintableError): + """If multiple errors occur during compilation, they can be collected into + a list and re-thrown using the MultipleErrors exception. It will + pretty-print all of the errors and a count of how many errors there are.""" + + def __init__(self, errors: T.List[CompileError]) -> None: + super().__init__() + self.errors = errors + + def pretty_print(self, filename, code, stream=sys.stdout) -> None: + for error in self.errors: + error.pretty_print(filename, code, stream) + if len(self.errors) != 1: + print(f"{len(self.errors)} errors") + + +class CompilerBugError(Exception): + """Emitted on assertion errors""" + + +def assert_true(truth: bool, message: T.Optional[str] = None): + if not truth: + raise CompilerBugError(message) + + +def report_bug(): # pragma: no cover + """Report an error and ask people to report it.""" + + from . import main + + print(traceback.format_exc()) + print(f"Arguments: {sys.argv}") + print(f"Version: {main.VERSION}\n") + print( + f"""{Colors.BOLD}{Colors.RED}***** COMPILER BUG ***** +The blueprint-compiler program has crashed. Please report the above stacktrace, +along with the input file(s) if possible, on GitLab: +{Colors.BOLD}{Colors.BLUE}{Colors.UNDERLINE}https://gitlab.gnome.org/jwestman/blueprint-compiler/-/issues/new?issue +{Colors.CLEAR}""" + ) + + sys.exit(1) diff --git a/.flatpak-builder/cache/objects/dd/3b899224a746bb315e6116348aa52c3ff867463e847dbd3ca7c0b52176feb3.dirtree b/.flatpak-builder/cache/objects/dd/3b899224a746bb315e6116348aa52c3ff867463e847dbd3ca7c0b52176feb3.dirtree new file mode 100644 index 0000000..e2394d6 Binary files /dev/null and b/.flatpak-builder/cache/objects/dd/3b899224a746bb315e6116348aa52c3ff867463e847dbd3ca7c0b52176feb3.dirtree differ diff --git a/.flatpak-builder/cache/objects/dd/99220dbc3e9b6bbbd84989d2fccc1a6e99022855a5f9bedfa483cd28410938.file b/.flatpak-builder/cache/objects/dd/99220dbc3e9b6bbbd84989d2fccc1a6e99022855a5f9bedfa483cd28410938.file new file mode 100644 index 0000000..d901de4 --- /dev/null +++ b/.flatpak-builder/cache/objects/dd/99220dbc3e9b6bbbd84989d2fccc1a6e99022855a5f9bedfa483cd28410938.file @@ -0,0 +1,3473 @@ +/* libgda-6.0.vapi generated by vapigen, do not modify. */ + +[CCode (cprefix = "Gda", gir_namespace = "Gda", gir_version = "6.0", lower_case_cprefix = "gda_")] +namespace Gda { + [CCode (cheader_filename = "libgda/libgda.h", type_id = "gda_batch_get_type ()")] + public class Batch : GLib.Object { + [CCode (has_construct_function = false)] + public Batch (); + public void add_statement (owned Gda.Statement stmt); + public Gda.Batch copy (); + public static GLib.Quark error_quark (); + public bool get_parameters (out Gda.Set? out_params) throws GLib.Error; + public unowned GLib.SList get_statements (); + public void remove_statement (Gda.Statement stmt); + public string serialize (); + public virtual signal void changed (GLib.Object changed_stmt); + } + [CCode (cheader_filename = "libgda/libgda.h", copy_function = "g_boxed_copy", free_function = "g_boxed_free", type_id = "gda_binary_get_type ()")] + [Compact] + public class Binary { + [CCode (has_construct_function = false)] + [Version (since = "6.0")] + public Binary (); + public Gda.Binary copy (); + [DestroysInstance] + public void free (); + [Version (since = "6.0")] + public void* get_data (); + [Version (since = "6.0")] + public long get_size (); + [Version (since = "6.0")] + public void reset_data (); + [Version (since = "6.0")] + public void set_data ([CCode (array_length_cname = "size", array_length_pos = 1.1, array_length_type = "glong")] uint8[] val); + public void take_data ([CCode (array_length_cname = "size", array_length_pos = 1.1, array_length_type = "glong")] uint8[] val); + public string to_string (uint maxlen); + } + [CCode (cheader_filename = "libgda/libgda.h", copy_function = "g_boxed_copy", free_function = "g_boxed_free", type_id = "gda_blob_get_type ()")] + [Compact] + public class Blob { + [CCode (has_construct_function = false)] + [Version (since = "6.0")] + public Blob (); + public Gda.Blob copy (); + [DestroysInstance] + public void free (); + [Version (since = "6.0")] + public unowned Gda.Binary get_binary (); + [Version (since = "6.0")] + public unowned Gda.BlobOp get_op (); + public void set_op (Gda.BlobOp? op); + public string to_string (uint maxlen); + } + [CCode (cheader_filename = "libgda/libgda.h", type_id = "gda_blob_op_get_type ()")] + public class BlobOp : GLib.Object { + [CCode (has_construct_function = false)] + protected BlobOp (); + public long get_length (); + public long read (Gda.Blob blob, long offset, long size); + public bool read_all (Gda.Blob blob); + public long write (Gda.Blob blob, long offset); + public bool write_all (Gda.Blob blob); + [NoAccessorMethod] + public Gda.Connection connection { owned get; construct; } + } + [CCode (cheader_filename = "libgda/libgda.h", has_type_id = false)] + [Compact] + public abstract class BlobOpFunctions { + public abstract long get_length (Gda.BlobOp op); + public abstract long read (Gda.BlobOp op, Gda.Blob blob, long offset, long size); + public abstract long write (Gda.BlobOp op, Gda.Blob blob, long offset); + public abstract bool write_all (Gda.BlobOp op, Gda.Blob blob); + } + [CCode (cheader_filename = "libgda/libgda.h", type_id = "gda_column_get_type ()")] + public class Column : GLib.Object { + [CCode (has_construct_function = false)] + public Column (); + public Gda.Column copy (); + public bool get_allow_null (); + public bool get_auto_increment (); + public unowned string get_dbms_type (); + public unowned GLib.Value? get_default_value (); + public unowned string get_description (); + public GLib.Type get_g_type (); + public unowned string get_name (); + public int get_position (); + public void set_allow_null (bool allow); + public void set_auto_increment (bool is_auto); + public void set_dbms_type (string dbms_type); + public void set_default_value (GLib.Value? default_value); + public void set_description (string descr); + public void set_g_type (GLib.Type type); + public void set_name (string name); + public void set_position (int position); + [NoAccessorMethod] + public string desc { owned get; set; } + [NoAccessorMethod] + public string id { owned get; set; } + public string name { get; set; } + public virtual signal void g_type_changed (GLib.Type old_type, GLib.Type new_type); + public virtual signal void name_changed (string old_name); + } + [CCode (cheader_filename = "libgda/libgda.h", type_id = "gda_config_get_type ()")] + public class Config : GLib.Object { + [CCode (has_construct_function = false)] + protected Config (); + public static bool can_modify_system_config (); + public static bool define_dsn (Gda.DsnInfo info) throws GLib.Error; + public static bool dsn_needs_authentication (string dsn_name); + public static GLib.Quark error_quark (); + public static Gda.Config @get (); + public static unowned Gda.DsnInfo get_dsn_info (string dsn_name); + public static unowned Gda.DsnInfo get_dsn_info_at_index (int index); + public static int get_dsn_info_index (string dsn_name); + public static int get_nb_dsn (); + public static unowned Gda.ServerProvider get_provider (string provider_name) throws GLib.Error; + public static unowned Gda.ProviderInfo get_provider_info (string provider_name); + public static Gda.DataModel list_dsn (); + public static Gda.DataModel list_providers (); + public static bool remove_dsn (string dsn_name) throws GLib.Error; + [NoAccessorMethod] + public string system_filename { owned get; set; } + [NoAccessorMethod] + public string user_filename { owned get; set; } + public virtual signal void dsn_added (void* new_dsn); + public virtual signal void dsn_changed (void* dsn); + public virtual signal void dsn_removed (void* old_dsn); + public virtual signal void dsn_to_be_removed (void* old_dsn); + } + [CCode (cheader_filename = "libgda/libgda.h", type_id = "gda_connection_get_type ()")] + public class Connection : GLib.Object, Gda.Lockable { + [CCode (has_construct_function = false)] + protected Connection (); + public void add_event (owned Gda.ConnectionEvent event); + public void add_prepared_statement (Gda.Statement gda_stmt, Gda.PStmt prepared_stmt); + public bool add_savepoint (string? name) throws GLib.Error; + public GLib.SList batch_execute (Gda.Batch batch, Gda.Set? @params, Gda.StatementModelUsage model_usage) throws GLib.Error; + public bool begin_transaction (string? name, Gda.TransactionIsolation level) throws GLib.Error; + public void clear_events_list (); + public bool close () throws GLib.Error; + public bool commit_transaction (string? name) throws GLib.Error; + [Version (since = "6.0")] + public Gda.DbCatalog create_db_catalog (); + public Gda.ServerOperation create_operation (Gda.ServerOperationType type, Gda.Set? options) throws GLib.Error; + public Gda.SqlParser create_parser (); + public void del_prepared_statement (Gda.Statement gda_stmt); + [Version (since = "4.2.3")] + public bool delete_row_from_table (string table, string condition_column_name, GLib.Value condition_value) throws GLib.Error; + public bool delete_savepoint (string? name) throws GLib.Error; + public static GLib.Quark error_quark (); + [Version (since = "4.2.3")] + public int execute_non_select_command (string sql) throws GLib.Error; + [Version (since = "4.2.3")] + public Gda.DataModel execute_select_command (string sql) throws GLib.Error; + [CCode (has_construct_function = false)] + [Version (since = "6.0")] + public Connection.from_dsn (Gda.DsnInfo dsn, string? auth_string, Gda.ConnectionOptions options) throws GLib.Error; + [CCode (has_construct_function = false)] + [Version (since = "6.0")] + public Connection.from_dsn_name (string dsn_name, string? auth_string, Gda.ConnectionOptions options) throws GLib.Error; + [CCode (has_construct_function = false)] + [Version (since = "5.0.2")] + public Connection.from_string (string? provider_name, string cnc_string, string? auth_string, Gda.ConnectionOptions options) throws GLib.Error; + public unowned string get_authentication (); + public unowned string get_cnc_string (); + [Version (since = "5.2")] + public bool get_date_format (out GLib.DateDMY? out_first, out GLib.DateDMY? out_second, out GLib.DateDMY? out_third, out string? out_sep) throws GLib.Error; + public unowned string get_dsn (); + public unowned GLib.List get_events (); + [Version (since = "6.0")] + public unowned GLib.MainContext get_main_context (GLib.Thread? thread); + public unowned Gda.MetaStore get_meta_store (); + public Gda.DataModel get_meta_store_data_v (Gda.ConnectionMetaType meta_type, GLib.List filters) throws GLib.Error; + public Gda.ConnectionOptions get_options (); + public unowned Gda.PStmt get_prepared_statement (Gda.Statement gda_stmt); + public unowned Gda.ServerProvider get_provider (); + public unowned string get_provider_name (); + [Version (since = "6.0")] + public Gda.ConnectionStatus get_status (); + public unowned Gda.TransactionStatus get_transaction_status (); + [Version (since = "4.2.3")] + public bool insert_row_into_table_v (string table, GLib.SList col_names, GLib.SList values) throws GLib.Error; + public void internal_change_transaction_state (Gda.TransactionStatusState newstate); + [Version (since = "5.0.2")] + public Gda.ServerProviderConnectionData? internal_get_provider_data_error () throws GLib.Error; + public static unowned Gda.Worker internal_get_worker (Gda.ServerProviderConnectionData? data); + public void internal_reset_transaction_status (); + public void internal_savepoint_added (string? parent_trans, string svp_name); + public void internal_savepoint_removed (string? svp_name); + public void internal_savepoint_rolledback (string? svp_name); + public void internal_set_provider_data (Gda.ServerProviderConnectionData data, GLib.DestroyNotify destroy_func); + public void internal_statement_executed (Gda.Statement stmt, Gda.Set? @params, Gda.ConnectionEvent error); + public void internal_transaction_committed (string? trans_name); + public void internal_transaction_rolledback (string? trans_name); + public void internal_transaction_started (string? parent_trans, string trans_name, Gda.TransactionIsolation isol_level); + public bool is_opened (); + public bool open () throws GLib.Error; + [Version (since = "6.0")] + public uint open_async (Gda.ConnectionOpenFunc callback) throws GLib.Error; + [Version (since = "6.0")] + public static Gda.Connection open_from_dsn (Gda.DsnInfo dsn, string? auth_string, Gda.ConnectionOptions options) throws GLib.Error; + public static Gda.Connection open_from_dsn_name (string dsn_name, string? auth_string, Gda.ConnectionOptions options) throws GLib.Error; + public static Gda.Connection open_from_string (string? provider_name, string cnc_string, string? auth_string, Gda.ConnectionOptions options) throws GLib.Error; + public static Gda.Connection open_sqlite (string? directory, string filename, bool auto_unlink); + [Version (since = "6.0")] + public string? operation_get_sql_identifier_at_path (Gda.ServerOperation op, string path) throws GLib.Error; + [Version (since = "4.2.3")] + public Gda.Statement parse_sql_string (string sql, out Gda.Set? @params = null) throws GLib.Error; + public bool perform_operation (Gda.ServerOperation op) throws GLib.Error; + [Version (since = "4.2")] + public Gda.ConnectionEvent point_available_event (Gda.ConnectionEventType type); + [Version (since = "6.0")] + public Gda.ServerOperation? prepare_operation_create_table (string table_name, GLib.List arguments) throws GLib.Error; + [Version (since = "6.0")] + public Gda.ServerOperation? prepare_operation_drop_table (string table_name) throws GLib.Error; + [Version (since = "4.0.3")] + public string quote_sql_identifier (string id); + [Version (since = "4.2")] + public GLib.SList repetitive_statement_execute (Gda.RepetitiveStatement rstmt, Gda.StatementModelUsage model_usage, [CCode (array_length = false)] GLib.Type[]? col_types, bool stop_on_error) throws GLib.Error; + public bool rollback_savepoint (string? name) throws GLib.Error; + public bool rollback_transaction (string? name) throws GLib.Error; + [Version (since = "6.0")] + public void set_main_context (GLib.Thread? thread, GLib.MainContext? context); + public GLib.Object statement_execute (Gda.Statement stmt, Gda.Set? @params, Gda.StatementModelUsage model_usage, out Gda.Set? last_insert_row = null) throws GLib.Error; + public int statement_execute_non_select (Gda.Statement stmt, Gda.Set? @params = null, out Gda.Set? last_insert_row = null) throws GLib.Error; + public Gda.DataModel statement_execute_select (Gda.Statement stmt, Gda.Set? @params = null) throws GLib.Error; + public Gda.DataModel statement_execute_select_full (Gda.Statement stmt, Gda.Set? @params, Gda.StatementModelUsage model_usage, [CCode (array_length = false)] GLib.Type[]? col_types = null) throws GLib.Error; + public bool statement_prepare (Gda.Statement stmt) throws GLib.Error; + public string statement_to_sql (Gda.Statement stmt, Gda.Set? @params, Gda.StatementSqlFlag flags, out GLib.SList? params_used) throws GLib.Error; + public static void string_split (string string, out string out_cnc_params, out string out_provider, out string out_username, out string out_password); + public bool supports_feature (Gda.ConnectionFeature feature); + public bool update_meta_store (Gda.MetaContext? context) throws GLib.Error; + [Version (since = "4.2.3")] + public bool update_row_in_table_v (string table, string condition_column_name, GLib.Value condition_value, GLib.SList col_names, GLib.SList values) throws GLib.Error; + public string value_to_sql_string (GLib.Value from); + [NoAccessorMethod] + public string auth_string { owned get; set; } + [NoAccessorMethod] + public string cnc_string { owned get; set; } + [NoAccessorMethod] + public string dsn { owned get; set; } + [NoAccessorMethod] + [Version (since = "4.2")] + public int events_history_size { get; set; } + [NoAccessorMethod] + [Version (since = "5.2.0")] + public uint execution_slowdown { get; set; } + [NoAccessorMethod] + [Version (since = "4.2.9")] + public bool execution_timer { get; set; } + [NoAccessorMethod] + public Gda.MetaStore meta_store { owned get; set; } + [NoAccessorMethod] + public Gda.ServerProvider provider { owned get; set; } + public virtual signal void closed (); + public virtual signal void dsn_changed (); + public virtual signal void error (Gda.ConnectionEvent error); + public virtual signal void opened (); + [Version (since = "6.0")] + public virtual signal void status_changed (Gda.ConnectionStatus status); + public virtual signal void transaction_status_changed (); + } + [CCode (cheader_filename = "libgda/libgda.h", type_id = "gda_connection_event_get_type ()")] + public class ConnectionEvent : GLib.Object { + [CCode (has_construct_function = false)] + protected ConnectionEvent (); + public long get_code (); + public unowned string get_description (); + public Gda.ConnectionEventType get_event_type (); + public Gda.ConnectionEventCode get_gda_code (); + public unowned string get_source (); + public unowned string get_sqlstate (); + public void set_code (long code); + public void set_description (string? description); + public void set_event_type (Gda.ConnectionEventType type); + public void set_gda_code (Gda.ConnectionEventCode code); + public void set_source (string source); + public void set_sqlstate (string sqlstate); + [NoAccessorMethod] + public int type { get; set; } + } + [CCode (cheader_filename = "libgda/libgda.h", type_id = "gda_data_access_wrapper_get_type ()")] + public class DataAccessWrapper : GLib.Object, Gda.DataModel { + [CCode (has_construct_function = false)] + protected DataAccessWrapper (); + public static Gda.DataModel @new (Gda.DataModel model); + [Version (since = "5.2")] + public bool set_mapping ([CCode (array_length_cname = "mapping_size", array_length_pos = 1.1)] int[]? mapping); + [NoAccessorMethod] + public Gda.DataModel model { owned get; construct; } + } + [CCode (cheader_filename = "libgda/libgda.h", type_id = "gda_data_comparator_get_type ()")] + public class DataComparator : GLib.Object { + [CCode (has_construct_function = false, type = "GObject*")] + public DataComparator (Gda.DataModel old_model, Gda.DataModel new_model); + public bool compute_diff () throws GLib.Error; + public static GLib.Quark error_quark (); + public unowned Gda.Diff get_diff (int pos); + public int get_n_diffs (); + public void set_key_columns ([CCode (array_length_cname = "nb_cols", array_length_pos = 1.1)] int[] col_numbers); + [NoAccessorMethod] + public Gda.DataModel new_model { owned get; set; } + [NoAccessorMethod] + public Gda.DataModel old_model { owned get; set; } + public virtual signal bool diff_computed (void* diff); + } + [CCode (cheader_filename = "libgda/libgda.h", type_id = "gda_data_model_array_get_type ()")] + public class DataModelArray : GLib.Object, Gda.DataModel { + [CCode (has_construct_function = false)] + protected DataModelArray (); + public void clear (); + public unowned Gda.Row get_row (int row) throws GLib.Error; + public static Gda.DataModel @new (int cols); + [Version (since = "4.2.6")] + public static Gda.DataModel new_with_g_types_v (int cols, [CCode (array_length = false)] GLib.Type[] types); + public void set_n_columns (int cols); + [NoAccessorMethod] + public uint n_columns { get; set; } + [NoAccessorMethod] + public bool read_only { get; set; } + } + [CCode (cheader_filename = "libgda/libgda.h", type_id = "gda_data_model_dir_get_type ()")] + public class DataModelDir : GLib.Object, Gda.DataModel { + [CCode (has_construct_function = false)] + protected DataModelDir (); + public void clean_errors (); + public unowned GLib.SList get_errors (); + public static Gda.DataModel @new (string basedir); + [NoAccessorMethod] + public string basedir { owned get; construct; } + } + [CCode (cheader_filename = "libgda/libgda.h", type_id = "gda_data_model_import_get_type ()")] + public class DataModelImport : GLib.Object, Gda.DataModel { + [CCode (has_construct_function = false)] + protected DataModelImport (); + public void clean_errors (); + public unowned GLib.SList get_errors (); + public static Gda.DataModel new_file (string filename, bool random_access, Gda.Set? options); + public static Gda.DataModel new_mem (string data, bool random_access, Gda.Set? options); + public static Gda.DataModel new_xml_node ([CCode (type = "xmlNodePtr")] Xml.Node* node); + [NoAccessorMethod] + public string data_string { owned get; construct; } + [NoAccessorMethod] + public string filename { owned get; construct; } + [NoAccessorMethod] + public Gda.Set options { owned get; construct; } + [NoAccessorMethod] + public bool random_access { get; construct; } + [NoAccessorMethod] + [Version (since = "4.2.1")] + public bool strict { get; set construct; } + [NoAccessorMethod] + public void* xml_node { get; construct; } + } + [CCode (cheader_filename = "libgda/libgda.h", type_id = "gda_data_model_import_iter_get_type ()")] + public class DataModelImportIter : Gda.DataModelIter { + [CCode (has_construct_function = false)] + protected DataModelImportIter (); + } + [CCode (cheader_filename = "libgda/libgda.h", type_id = "gda_data_model_iter_get_type ()")] + public class DataModelIter : Gda.Set { + [CCode (has_construct_function = false)] + protected DataModelIter (); + public static GLib.Quark error_quark (); + public unowned Gda.Holder get_holder_for_field (int col); + public int get_row (); + public unowned GLib.Value? get_value_at (int col); + [Version (since = "4.2.10")] + public unowned GLib.Value? get_value_at_e (int col) throws GLib.Error; + public unowned GLib.Value? get_value_for_field (string field_name); + public void invalidate_contents (); + public bool is_valid (); + public virtual bool move_next (); + public virtual bool move_prev (); + public virtual bool move_to_row (int row); + public virtual bool set_value_at (int col, GLib.Value value) throws GLib.Error; + [NoAccessorMethod] + public int current_row { get; set; } + [NoAccessorMethod] + public Gda.DataModel data_model { owned get; set construct; } + [NoAccessorMethod] + public bool update_model { get; set; } + public virtual signal void end_of_data (); + public virtual signal void row_changed (int row); + } + [CCode (cheader_filename = "libgda/libgda.h", type_id = "gda_data_model_select_get_type ()")] + public class DataModelSelect : GLib.Object, Gda.DataModel { + [CCode (has_construct_function = false)] + public DataModelSelect (Gda.Connection cnc, Gda.Statement stm, Gda.Set? @params); + [CCode (has_construct_function = false)] + public DataModelSelect.from_string (Gda.Connection cnc, string sql); + public Gda.Set get_parameters (); + public bool is_valid (); + public void set_parameters (Gda.Set @params); + [NoAccessorMethod] + public bool valid { get; } + public virtual signal void updated (); + } + [CCode (cheader_filename = "libgda/libgda.h", type_id = "gda_data_pivot_get_type ()")] + public class DataPivot : GLib.Object, Gda.DataModel { + [CCode (has_construct_function = false)] + protected DataPivot (); + [Version (since = "5.0")] + public bool add_data (Gda.DataPivotAggregate aggregate_type, string field, string? alias) throws GLib.Error; + [Version (since = "5.0")] + public bool add_field (Gda.DataPivotFieldType field_type, string field, string? alias) throws GLib.Error; + public static GLib.Quark error_quark (); + public static Gda.DataModel @new (Gda.DataModel? model); + [Version (since = "5.0")] + public bool populate () throws GLib.Error; + [NoAccessorMethod] + public Gda.DataModel model { owned get; set; } + } + [CCode (cheader_filename = "libgda/libgda.h", type_id = "gda_data_proxy_get_type ()")] + public class DataProxy : GLib.Object, Gda.DataModel { + [CCode (has_construct_function = false, type = "GObject*")] + public DataProxy (Gda.DataModel model); + public void alter_value_attributes (int proxy_row, int col, Gda.ValueAttribute alter_flags); + public bool apply_all_changes () throws GLib.Error; + public bool apply_row_changes (int proxy_row) throws GLib.Error; + public bool cancel_all_changes (); + public void cancel_row_changes (int proxy_row, int col); + public void @delete (int proxy_row); + public static GLib.Quark error_quark (); + public unowned string get_filter_expr (); + public int get_filtered_n_rows (); + public int get_n_modified_rows (); + public int get_n_new_rows (); + public unowned Gda.DataModel get_proxied_model (); + public int get_proxied_model_n_cols (); + public int get_proxied_model_n_rows (); + public int get_proxied_model_row (int proxy_row); + public int get_sample_end (); + public int get_sample_size (); + public int get_sample_start (); + public Gda.ValueAttribute get_value_attributes (int proxy_row, int col); + public GLib.SList get_values (int proxy_row, [CCode (array_length_cname = "n_cols", array_length_pos = 2.1)] int[] cols_index); + public bool has_changed (); + public bool is_read_only (); + public bool row_has_changed (int proxy_row); + public bool row_is_deleted (int proxy_row); + public bool row_is_inserted (int proxy_row); + public bool set_filter_expr (string? filter_expr) throws GLib.Error; + public bool set_ordering_column (int col) throws GLib.Error; + public void set_sample_size (int sample_size); + public void set_sample_start (int sample_start); + public void undelete (int proxy_row); + [CCode (has_construct_function = false)] + [Version (since = "5.2.0")] + public DataProxy.with_data_model (Gda.DataModel model); + [NoAccessorMethod] + [Version (since = "5.2")] + public bool cache_changes { get; set; } + [NoAccessorMethod] + public bool defer_sync { get; set; } + [NoAccessorMethod] + public Gda.DataModel model { owned get; set construct; } + [NoAccessorMethod] + public bool prepend_null_entry { get; set; } + public int sample_size { get; set construct; } + public virtual signal void filter_changed (); + public virtual signal void row_changes_applied (int row, int proxied_row); + public virtual signal void row_delete_changed (int row, bool to_be_deleted); + public virtual signal void sample_changed (int sample_start, int sample_end); + public virtual signal void sample_size_changed (int sample_size); + public virtual signal GLib.Error validate_row_changes (int row, int proxied_row); + } + [CCode (cheader_filename = "libgda/libgda.h", type_id = "gda_data_select_get_type ()")] + public class DataSelect : GLib.Object, Gda.DataModel { + [CCode (has_construct_function = false)] + protected DataSelect (); + public bool compute_columns_attributes () throws GLib.Error; + public bool compute_modification_statements () throws GLib.Error; + [Version (since = "4.2.9")] + public bool compute_modification_statements_ext (Gda.DataSelectConditionType cond_type) throws GLib.Error; + public bool compute_row_selection_condition () throws GLib.Error; + public static GLib.Quark error_quark (); + [NoWrapper] + public virtual bool fetch_at (Gda.Row prow, int rownum) throws GLib.Error; + [NoWrapper] + public virtual int fetch_nb_rows (); + [NoWrapper] + public virtual bool fetch_next (Gda.Row prow, int rownum) throws GLib.Error; + [NoWrapper] + public virtual bool fetch_prev (Gda.Row prow, int rownum) throws GLib.Error; + [NoWrapper] + public virtual bool fetch_random (Gda.Row prow, int rownum) throws GLib.Error; + public int get_advertized_nrows (); + public unowned Gda.Connection get_connection (); + public int get_nb_stored_rows (); + public unowned Gda.PStmt get_prep_stmt (); + [Version (since = "5.2.0")] + public bool prepare_for_offline () throws GLib.Error; + public void set_advertized_nrows (int n); + public bool set_modification_statement (Gda.Statement mod_stmt) throws GLib.Error; + public bool set_modification_statement_sql (string sql) throws GLib.Error; + public bool set_row_selection_condition (Gda.SqlExpr expr) throws GLib.Error; + public bool set_row_selection_condition_sql (string sql_where) throws GLib.Error; + [NoWrapper] + public virtual bool store_all () throws GLib.Error; + public Gda.Connection connection { get; construct; } + [NoAccessorMethod] + public Gda.Statement delete_stmt { owned get; set; } + [NoAccessorMethod] + public Gda.Set exec_params { owned get; construct; } + [NoAccessorMethod] + [Version (since = "4.2.9")] + public double execution_delay { get; set; } + [NoAccessorMethod] + public Gda.Statement insert_stmt { owned get; set; } + [NoAccessorMethod] + public uint model_usage { get; construct; } + [NoAccessorMethod] + public Gda.PStmt prepared_stmt { owned get; set; } + [NoAccessorMethod] + public Gda.Statement select_stmt { owned get; } + [NoAccessorMethod] + public bool store_all_rows { get; set; } + [NoAccessorMethod] + public Gda.Statement update_stmt { owned get; set; } + } + [CCode (cheader_filename = "libgda/libgda.h", type_id = "gda_data_select_iter_get_type ()")] + public class DataSelectIter : Gda.DataModelIter { + [CCode (has_construct_function = false)] + protected DataSelectIter (); + } + [CCode (cheader_filename = "libgda/libgda.h", type_id = "gda_db_base_get_type ()")] + public class DbBase : GLib.Object { + [CCode (has_construct_function = false)] + public DbBase (); + [Version (since = "6.0")] + public int compare (Gda.DbBase b); + [Version (since = "6.0")] + public unowned string get_catalog (); + [Version (since = "6.0")] + public unowned string get_full_name (); + [Version (since = "6.0")] + public unowned string get_name (); + [Version (since = "6.0")] + public unowned string get_schema (); + [Version (since = "6.0")] + public void set_catalog (string catalog); + [Version (since = "6.0")] + public void set_name (string name); + [Version (since = "6.0")] + public void set_names (string? catalog, string? schema, string name); + [Version (since = "6.0")] + public void set_schema (string schema); + } + [CCode (cheader_filename = "libgda/libgda.h", type_id = "gda_db_catalog_get_type ()")] + public class DbCatalog : GLib.Object { + [CCode (has_construct_function = false)] + [Version (since = "6.0")] + public DbCatalog (); + [Version (since = "6.0")] + public void append_table (Gda.DbTable table); + [Version (since = "6.0")] + public void append_view (Gda.DbView view); + public static GLib.Quark error_quark (); + [Version (since = "6.0")] + public unowned GLib.List get_tables (); + [Version (since = "6.0")] + public unowned GLib.List get_views (); + [Version (since = "6.0")] + public bool parse_cnc () throws GLib.Error; + [Version (since = "6.0")] + public bool parse_file (GLib.File xmlfile) throws GLib.Error; + public bool parse_file_from_path (string xmlfile) throws GLib.Error; + public bool perform_operation () throws GLib.Error; + [Version (since = "6.0")] + public static bool validate_file_from_path (string xmlfile) throws GLib.Error; + [Version (since = "6.0")] + public bool write_to_file (GLib.File file) throws GLib.Error; + [Version (since = "6.0")] + public bool write_to_path (string path) throws GLib.Error; + [NoAccessorMethod] + public Gda.Connection connection { owned get; set; } + [NoAccessorMethod] + public string schema_name { owned get; set; } + } + [CCode (cheader_filename = "libgda/libgda.h", type_id = "gda_db_column_get_type ()")] + public class DbColumn : GLib.Object, Gda.DbBuildable, Gda.DdlModifiable { + [CCode (has_construct_function = false)] + [Version (since = "6.0")] + public DbColumn (); + public static GLib.Quark error_quark (); + [Version (since = "6.0")] + public bool get_autoinc (); + [Version (since = "6.0")] + public unowned string get_check (); + [Version (since = "6.0")] + public unowned string get_comment (); + [Version (since = "6.0")] + public unowned string get_ctype (); + [Version (since = "6.0")] + public unowned string get_default (); + [Version (since = "6.0")] + public GLib.Type get_gtype (); + [Version (since = "6.0")] + public unowned string get_name (); + [Version (since = "6.0")] + public bool get_nnul (); + [Version (since = "6.0")] + public bool get_pkey (); + [Version (since = "6.0")] + public uint get_scale (); + [Version (since = "6.0")] + public uint get_size (); + [Version (since = "6.0")] + public bool get_unique (); + [Version (since = "6.0")] + public bool prepare_add (Gda.ServerOperation op) throws GLib.Error; + [Version (since = "6.0")] + public bool prepare_create (Gda.ServerOperation op, uint order) throws GLib.Error; + [Version (since = "6.0")] + public void set_autoinc (bool autoinc); + [Version (since = "6.0")] + public void set_check (string value); + [Version (since = "6.0")] + public void set_comment (string comnt); + [Version (since = "6.0")] + public void set_default (string value); + [Version (since = "6.0")] + public void set_name (string name); + [Version (since = "6.0")] + public void set_nnul (bool nnul); + [Version (since = "6.0")] + public void set_pkey (bool pkey); + [Version (since = "6.0")] + public void set_scale (uint scale); + [Version (since = "6.0")] + public void set_size (uint size); + [Version (since = "6.0")] + public void set_type (GLib.Type type); + [Version (since = "6.0")] + public void set_unique (bool unique); + public bool autoinc { get; set; } + public string check { get; set; } + public string comment { get; set; } + public string @default { get; set; } + public string name { get; set; } + public bool nnul { get; set; } + public bool pkey { get; set; } + public uint scale { get; set; } + public uint size { get; set; } + [NoAccessorMethod] + public Gda.DbTable table { owned get; set; } + public bool unique { get; set; } + } + [CCode (cheader_filename = "libgda/libgda.h", type_id = "gda_db_fkey_get_type ()")] + public class DbFkey : GLib.Object, Gda.DbBuildable { + [CCode (has_construct_function = false)] + [Version (since = "6.0")] + public DbFkey (); + [Version (since = "6.0")] + public unowned GLib.List get_field_name (); + [Version (since = "6.0")] + public unowned string get_ondelete (); + [Version (since = "6.0")] + public Gda.DbFkeyReferenceAction get_ondelete_id (); + [Version (since = "6.0")] + public unowned string get_onupdate (); + [Version (since = "6.0")] + public Gda.DbFkeyReferenceAction get_onupdate_id (); + [Version (since = "6.0")] + public unowned GLib.List get_ref_field (); + [Version (since = "6.0")] + public unowned string get_ref_table (); + [Version (since = "6.0")] + public bool prepare_create (Gda.ServerOperation op, int i) throws GLib.Error; + [Version (since = "6.0")] + public void set_field (string field, string reffield); + [Version (since = "6.0")] + public void set_ondelete (Gda.DbFkeyReferenceAction id); + [Version (since = "6.0")] + public void set_onupdate (Gda.DbFkeyReferenceAction id); + [Version (since = "6.0")] + public void set_ref_table (string rtable); + } + [CCode (cheader_filename = "libgda/libgda.h", type_id = "gda_db_index_get_type ()")] + public class DbIndex : Gda.DbBase, Gda.DdlModifiable { + [CCode (has_construct_function = false)] + public DbIndex (); + [Version (since = "6.0")] + public void append_field (Gda.DbIndexField field); + public static GLib.Quark error_quark (); + [Version (since = "6.0")] + public unowned GLib.SList? get_fields (); + [Version (since = "6.0")] + public bool get_unique (); + [Version (since = "6.0")] + public void remove_field (string name); + [Version (since = "6.0")] + public void set_unique (bool val); + [NoAccessorMethod] + public Gda.DbTable table { owned get; set; } + } + [CCode (cheader_filename = "libgda/libgda.h", type_id = "gda_db_index_field_get_type ()")] + public class DbIndexField : GLib.Object { + [CCode (has_construct_function = false)] + [Version (since = "6.0")] + public DbIndexField (); + [Version (since = "6.0")] + public unowned string get_collate (); + [Version (since = "6.0")] + public unowned Gda.DbColumn get_column (); + [Version (since = "6.0")] + public Gda.DbIndexSortOrder get_sort_order (); + [Version (since = "6.0")] + public unowned string get_sort_order_str (); + [Version (since = "6.0")] + public void set_collate (string collate); + [Version (since = "6.0")] + public void set_column (Gda.DbColumn column); + [Version (since = "6.0")] + public void set_sort_order (Gda.DbIndexSortOrder sorder); + } + [CCode (cheader_filename = "libgda/libgda.h", type_id = "gda_db_table_get_type ()")] + public class DbTable : Gda.DbBase, Gda.DbBuildable, Gda.DdlModifiable { + [CCode (has_construct_function = false)] + [Version (since = "6.0")] + public DbTable (); + [Version (since = "6.0")] + public void append_column (Gda.DbColumn column); + [Version (since = "6.0")] + public void append_constraint (string constr); + [Version (since = "6.0")] + public void append_fkey (Gda.DbFkey fkey); + public static GLib.Quark error_quark (); + [Version (since = "6.0")] + public unowned GLib.List get_columns (); + [Version (since = "6.0")] + public unowned GLib.List get_fkeys (); + public bool get_is_temp (); + [Version (since = "6.0")] + public bool is_valid (); + [Version (since = "6.0")] + public bool prepare_create (Gda.ServerOperation op, bool ifnotexists) throws GLib.Error; + [Version (since = "6.0")] + public void set_is_temp (bool istemp); + public bool update (Gda.MetaTable obj, Gda.Connection cnc) throws GLib.Error; + [NoAccessorMethod] + public string comment { owned get; set; } + [NoAccessorMethod] + public string istemp { owned get; set; } + } + [CCode (cheader_filename = "libgda/libgda.h", type_id = "gda_db_view_get_type ()")] + public class DbView : Gda.DbBase, Gda.DbBuildable, Gda.DdlModifiable { + [CCode (has_construct_function = false)] + [Version (since = "6.0")] + public DbView (); + [Version (since = "6.0")] + public unowned string get_defstring (); + [Version (since = "6.0")] + public bool get_ifnoexist (); + [Version (since = "6.0")] + public bool get_istemp (); + [Version (since = "6.0")] + public bool get_replace (); + public bool prepare_create (Gda.ServerOperation op) throws GLib.Error; + [Version (since = "6.0")] + public void set_defstring (string str); + [Version (since = "6.0")] + public void set_ifnoexist (bool noexist); + [Version (since = "6.0")] + public void set_istemp (bool temp); + [Version (since = "6.0")] + public void set_replace (bool replace); + public string defstring { get; set; } + public bool ifnoexist { get; set; } + public bool istemp { get; set; } + public bool replace { get; set; } + } + [CCode (cheader_filename = "libgda/libgda.h", copy_function = "g_boxed_copy", free_function = "g_boxed_free", type_id = "gda_default_get_type ()")] + [Compact] + public class Default { + public static string? escape_string (string string); + public static string? unescape_string (string string); + } + [CCode (cheader_filename = "libgda/libgda.h", copy_function = "g_boxed_copy", free_function = "g_boxed_free", type_id = "gda_diff_get_type ()")] + [Compact] + public class Diff { + public int new_row; + public int old_row; + public Gda.DiffType type; + public weak GLib.HashTable values; + } + [CCode (cheader_filename = "libgda/libgda.h", copy_function = "g_boxed_copy", free_function = "g_boxed_free", type_id = "gda_dsn_info_get_type ()")] + [Compact] + public class DsnInfo { + public weak string auth_string; + public weak string cnc_string; + public weak string description; + public bool is_system; + public weak string name; + public weak string provider; + [CCode (has_construct_function = false)] + [Version (since = "5.2")] + public DsnInfo (); + [Version (since = "5.2")] + public Gda.DsnInfo copy (); + public bool equal (Gda.DsnInfo? dsn2); + [Version (since = "5.2")] + public void free (); + } + [CCode (cheader_filename = "libgda/libgda.h", copy_function = "g_boxed_copy", free_function = "g_boxed_free", type_id = "gda_geometric_point_get_type ()")] + [Compact] + public class GeometricPoint { + [CCode (has_construct_function = false)] + public GeometricPoint (); + public Gda.GeometricPoint copy (); + public void free (); + public double get_x (); + public double get_y (); + public void set_x (double x); + public void set_y (double y); + } + [CCode (cheader_filename = "libgda/libgda.h", type_id = "gda_handler_bin_get_type ()")] + public class HandlerBin : GLib.Object, Gda.DataHandler { + [CCode (has_construct_function = false, type = "GdaDataHandler*")] + public HandlerBin (); + } + [CCode (cheader_filename = "libgda/libgda.h", type_id = "gda_handler_boolean_get_type ()")] + public class HandlerBoolean : GLib.Object, Gda.DataHandler { + [CCode (has_construct_function = false, type = "GdaDataHandler*")] + public HandlerBoolean (); + } + [CCode (cheader_filename = "libgda/libgda.h", type_id = "gda_handler_numerical_get_type ()")] + public class HandlerNumerical : GLib.Object, Gda.DataHandler { + [CCode (has_construct_function = false, type = "GdaDataHandler*")] + public HandlerNumerical (); + } + [CCode (cheader_filename = "libgda/libgda.h", type_id = "gda_handler_string_get_type ()")] + public class HandlerString : GLib.Object, Gda.DataHandler { + [CCode (has_construct_function = false, type = "GdaDataHandler*")] + public HandlerString (); + [CCode (has_construct_function = false, type = "GdaDataHandler*")] + public HandlerString.with_provider (Gda.ServerProvider prov, Gda.Connection? cnc); + } + [CCode (cheader_filename = "libgda/libgda.h", type_id = "gda_handler_text_get_type ()")] + public class HandlerText : GLib.Object, Gda.DataHandler { + [CCode (has_construct_function = false)] + protected HandlerText (); + public static Gda.DataHandler @new (); + [CCode (has_construct_function = false, type = "GdaDataHandler*")] + public HandlerText.with_connection (Gda.Connection? cnc); + } + [CCode (cheader_filename = "libgda/libgda.h", type_id = "gda_handler_time_get_type ()")] + public class HandlerTime : GLib.Object, Gda.DataHandler { + [CCode (has_construct_function = false, type = "GdaDataHandler*")] + public HandlerTime (); + public string get_format (GLib.Type type); + [Version (since = "6.0")] + public string get_hint (GLib.Type type); + public string get_no_locale_str_from_value (GLib.Value value); + [CCode (has_construct_function = false, type = "GdaDataHandler*")] + public HandlerTime.no_locale (); + public void set_sql_spec (GLib.DateDMY first, GLib.DateDMY sec, GLib.DateDMY third, char separator, bool twodigits_years); + [Version (since = "4.2.1")] + public void set_str_spec (GLib.DateDMY first, GLib.DateDMY sec, GLib.DateDMY third, char separator, bool twodigits_years); + } + [CCode (cheader_filename = "libgda/libgda.h", type_id = "gda_handler_type_get_type ()")] + public class HandlerType : GLib.Object, Gda.DataHandler { + [CCode (has_construct_function = false, type = "GdaDataHandler*")] + public HandlerType (); + } + [CCode (cheader_filename = "libgda/libgda.h", type_id = "gda_holder_get_type ()")] + public class Holder : GLib.Object, Gda.Lockable { + [CCode (has_construct_function = false)] + public Holder (GLib.Type type, string id); + public Gda.Holder copy (); + public static GLib.Quark error_quark (); + public void force_invalid (); + [Version (since = "4.2.10")] + public void force_invalid_e (owned GLib.Error? error); + public string get_alphanum_id (); + public unowned Gda.Holder get_bind (); + public unowned GLib.Value? get_default_value (); + public GLib.Type get_g_type (); + public unowned string get_id (); + public bool get_not_null (); + public unowned Gda.DataModel get_source_model (int col); + public unowned GLib.Value? get_value (); + public string get_value_str (Gda.DataHandler? dh); + public bool is_valid (); + [Version (since = "4.2.10")] + public bool is_valid_e () throws GLib.Error; + public bool set_bind (Gda.Holder bind_to) throws GLib.Error; + public void set_default_value (GLib.Value value); + public void set_not_null (bool not_null); + public bool set_source_model (Gda.DataModel model, int col) throws GLib.Error; + public bool set_value (GLib.Value? value) throws GLib.Error; + public bool set_value_str (Gda.DataHandler dh, string value) throws GLib.Error; + public bool set_value_to_default (); + public GLib.Value? take_static_value (GLib.Value value, bool value_changed) throws GLib.Error; + public bool take_value (owned GLib.Value value) throws GLib.Error; + public bool value_is_default (); + [NoAccessorMethod] + public string description { owned get; set; } + [NoAccessorMethod] + public Gda.Holder full_bind { owned get; set; } + [NoAccessorMethod] + public GLib.Type g_type { get; set construct; } + [NoAccessorMethod] + public string id { owned get; set; } + [NoAccessorMethod] + public string name { owned get; set; } + public bool not_null { get; set; } + [NoAccessorMethod] + public string plugin { owned get; set; } + [NoAccessorMethod] + public Gda.Holder simple_bind { owned get; set; } + [NoAccessorMethod] + public int source_column { get; set; } + [NoAccessorMethod] + public Gda.DataModel source_model { owned get; set; } + [NoAccessorMethod] + [Version (since = "5.2.0")] + public bool validate_changes { get; set; } + public virtual signal void changed (); + public virtual signal void source_changed (); + public virtual signal void to_default (); + public virtual signal GLib.Error validate_change (GLib.Value new_value); + } + [CCode (cheader_filename = "libgda/libgda.h", copy_function = "g_boxed_copy", free_function = "g_boxed_free", type_id = "gda_meta_context_get_type ()")] + [Compact] + public class MetaContext { + [CCode (array_length_cname = "size")] + public weak string[] column_names; + [CCode (array_length_cname = "size")] + public weak GLib.Value[] column_values; + public weak GLib.HashTable columns; + public int size; + public weak string table_name; + [CCode (has_construct_function = false)] + [Version (since = "5.2")] + public MetaContext (); + [Version (since = "5.2")] + public Gda.MetaContext copy (); + [Version (since = "5.2")] + public void free (); + public int get_n_columns (); + [Version (since = "5.2")] + public unowned string get_table (); + [Version (since = "5.2")] + public void set_column (string column, GLib.Value value, Gda.Connection? cnc); + [Version (since = "5.2")] + public void set_columns (GLib.HashTable columns, Gda.Connection? cnc); + [Version (since = "5.2")] + public void set_table (string table); + public string stringify (); + } + [CCode (cheader_filename = "libgda/libgda.h", type_id = "gda_meta_store_get_type ()")] + public class MetaStore : GLib.Object { + [CCode (has_construct_function = false)] + public MetaStore (string? cnc_string); + public Gda.DataModel create_modify_data_model (string table_name); + public Gda.MetaStruct create_struct (Gda.MetaStructFeature features); + [Version (since = "4.2.4")] + public bool declare_foreign_key (Gda.MetaStruct? mstruct, string fk_name, string? catalog, string? schema, string table, string? ref_catalog, string? ref_schema, string ref_table, [CCode (array_length_cname = "nb_cols", array_length_pos = 8.5, array_length_type = "guint")] string[] colnames, [CCode (array_length_cname = "nb_cols", array_length_pos = 8.5, array_length_type = "guint")] string[] ref_colnames) throws GLib.Error; + public static GLib.Quark error_quark (); + [CCode (cname = "gda_meta_store_extract_v")] + [Version (since = "4.2.6")] + public Gda.DataModel extract (string select_sql, GLib.HashTable? vars) throws GLib.Error; + public bool get_attribute_value (string att_name, out string att_value) throws GLib.Error; + public unowned Gda.Connection get_internal_connection (); + public int get_version (); + [Version (since = "4.2.6")] + public bool modify_v (string table_name, Gda.DataModel? new_data, string? condition, [CCode (array_length_cname = "nvalues", array_length_pos = 3.5)] string[] value_names, [CCode (array_length_cname = "nvalues", array_length_pos = 3.5)] GLib.Value[] values) throws GLib.Error; + public bool modify_with_context (Gda.MetaContext context, Gda.DataModel? new_data) throws GLib.Error; + public bool schema_add_custom_object (string xml_description) throws GLib.Error; + public GLib.SList schema_get_all_tables (); + public GLib.SList schema_get_depend_tables (string table_name); + public Gda.MetaStruct schema_get_structure () throws GLib.Error; + public bool schema_remove_custom_object (string obj_name) throws GLib.Error; + public bool set_attribute_value (string att_name, string? att_value) throws GLib.Error; + [Version (since = "4.2")] + public void set_identifiers_style (Gda.SqlIdentifierStyle style); + [Version (since = "4.2")] + public void set_reserved_keywords_func (Gda.SqlReservedKeywordsFunc? func); + [Version (since = "4.0.3")] + public static string sql_identifier_quote (string id, Gda.Connection cnc); + [Version (since = "4.2.4")] + public bool undeclare_foreign_key (Gda.MetaStruct? mstruct, string fk_name, string? catalog, string? schema, string table, string? ref_catalog, string? ref_schema, string ref_table) throws GLib.Error; + [CCode (has_construct_function = false)] + public MetaStore.with_file (string file_name); + [NoAccessorMethod] + public string catalog { construct; } + [NoAccessorMethod] + public Gda.Connection cnc { owned get; construct; } + [NoAccessorMethod] + public string cnc_string { construct; } + [NoAccessorMethod] + public string schema { construct; } + public signal void meta_changed (GLib.SList changes); + public virtual signal void meta_reset (); + public virtual signal GLib.Error suggest_update (Gda.MetaContext suggest); + } + [CCode (cheader_filename = "libgda/libgda.h", copy_function = "g_boxed_copy", free_function = "g_boxed_free", type_id = "gda_meta_store_change_get_type ()")] + [Compact] + public class MetaStoreChange { + [CCode (has_construct_function = false)] + public MetaStoreChange (); + public Gda.MetaStoreChange copy (); + public void free (); + public Gda.MetaStoreChangeType get_change_type (); + public unowned GLib.HashTable get_keys (); + public string get_table_name (); + public void set_change_type (Gda.MetaStoreChangeType ctype); + public void set_table_name (string table_name); + } + [CCode (cheader_filename = "libgda/libgda.h", type_id = "gda_meta_struct_get_type ()")] + public class MetaStruct : GLib.Object { + [CCode (has_construct_function = false)] + protected MetaStruct (); + public unowned Gda.MetaDbObject? complement (Gda.MetaDbObjectType type, GLib.Value? catalog, GLib.Value? schema, GLib.Value name) throws GLib.Error; + public bool complement_all () throws GLib.Error; + public bool complement_default () throws GLib.Error; + public bool complement_depend (Gda.MetaDbObject dbo) throws GLib.Error; + public bool complement_schema (GLib.Value? catalog, GLib.Value? schema) throws GLib.Error; + public string? dump_as_graph (Gda.MetaGraphInfo info) throws GLib.Error; + public static GLib.Quark error_quark (); + public GLib.SList? get_all_db_objects (); + public unowned Gda.MetaDbObject? get_db_object (GLib.Value? catalog, GLib.Value? schema, GLib.Value name); + public unowned Gda.MetaTableColumn? get_table_column (Gda.MetaTable table, GLib.Value col_name); + public bool load_from_xml_file (string? catalog, string? schema, string xml_spec_file) throws GLib.Error; + public bool sort_db_objects (Gda.MetaSortType sort_type) throws GLib.Error; + [NoAccessorMethod] + public uint features { get; construct; } + [NoAccessorMethod] + public Gda.MetaStore meta_store { owned get; construct; } + } + [CCode (cheader_filename = "libgda/libgda.h", copy_function = "g_boxed_copy", free_function = "g_boxed_free", type_id = "gda_null_get_type ()")] + [Compact] + public class Null { + } + [CCode (cheader_filename = "libgda/libgda.h", copy_function = "g_boxed_copy", free_function = "g_boxed_free", type_id = "gda_numeric_get_type ()")] + [Compact] + public class Numeric { + [CCode (has_construct_function = false)] + [Version (since = "5.0.2")] + public Numeric (); + public Gda.Numeric copy (); + [DestroysInstance] + public void free (); + [Version (since = "5.0.2")] + public double get_double (); + [Version (since = "5.0.2")] + public long get_precision (); + [Version (since = "5.0.2")] + public string? get_string (); + [Version (since = "5.0.2")] + public long get_width (); + [Version (since = "5.0.2")] + public void set_double (double number); + [Version (since = "5.0.2")] + public void set_from_string (string str); + [Version (since = "5.0.2")] + public void set_precision (long precision); + [Version (since = "5.0.2")] + public void set_width (long width); + } + [CCode (cheader_filename = "libgda/libgda.h", type_id = "gda_pstmt_get_type ()")] + public class PStmt : GLib.Object { + [CCode (has_construct_function = false)] + protected PStmt (); + public void copy_contents (Gda.PStmt dest); + public Gda.Statement get_gda_statement (); + public int get_ncols (); + public unowned GLib.SList get_param_ids (); + public unowned string get_sql (); + public unowned GLib.SList get_tmpl_columns (); + [CCode (array_length = false)] + public unowned GLib.Type[] get_types (); + public void set_cols ([CCode (array_length_cname = "ncols", array_length_pos = 0.5)] owned GLib.Type[] types); + public void set_gda_statement (Gda.Statement? stmt); + public void set_param_ids (owned GLib.SList @params); + public void set_sql (string sql); + public void set_tmpl_columns (owned GLib.SList columns); + } + [CCode (cheader_filename = "libgda/libgda.h", copy_function = "g_boxed_copy", free_function = "g_boxed_free", type_id = "gda_provider_info_get_type ()")] + [Compact] + public class ProviderInfo { + public weak Gda.Set auth_params; + public weak string description; + public weak Gda.Set dsn_params; + public weak string icon_id; + public weak string id; + public weak string location; + } + [CCode (cheader_filename = "libgda/libgda.h", copy_function = "g_boxed_copy", free_function = "g_boxed_free", type_id = "gda_quark_list_get_type ()")] + [Compact] + public class QuarkList { + [CCode (has_construct_function = false)] + public QuarkList (); + public void add_from_string (string string, bool cleanup); + public void clear (); + public Gda.QuarkList copy (); + public unowned string find (string name); + public void @foreach (GLib.HFunc func); + public void free (); + [CCode (has_construct_function = false)] + public QuarkList.from_string (string string); + [Version (since = "5.2.0")] + public void protect_values (); + public void remove (string name); + } + [CCode (cheader_filename = "libgda/libgda.h", type_id = "gda_repetitive_statement_get_type ()")] + public class RepetitiveStatement : GLib.Object { + [CCode (has_construct_function = false)] + [Version (since = "4.2")] + public RepetitiveStatement (Gda.Statement stmt); + [Version (since = "4.2")] + public bool append_set (Gda.Set values, bool make_copy); + [Version (since = "4.2")] + public GLib.SList get_all_sets (); + [Version (since = "4.2")] + public bool get_template_set (Gda.Set @set) throws GLib.Error; + [NoAccessorMethod] + public Gda.Statement statement { owned get; construct; } + } + [CCode (cheader_filename = "libgda/libgda.h", type_id = "gda_row_get_type ()")] + public class Row : GLib.Object { + [CCode (has_construct_function = false)] + public Row (int count); + [CCode (has_construct_function = false)] + public Row.from_data_model (Gda.DataModel model, uint row); + public int get_length (); + public unowned GLib.Value? get_value (int num); + public void invalidate_value (GLib.Value value); + [Version (since = "4.2.10")] + public void invalidate_value_e (GLib.Value value, owned GLib.Error? error); + public bool value_is_valid (GLib.Value value); + [Version (since = "4.2.10")] + public bool value_is_valid_e (GLib.Value value) throws GLib.Error; + [NoAccessorMethod] + public Gda.DataModel model { owned get; construct; } + [NoAccessorMethod] + public int model_row { get; construct; } + [NoAccessorMethod] + public int nb_values { get; construct; } + } + [CCode (cheader_filename = "libgda/libgda.h", type_id = "gda_server_operation_get_type ()")] + public class ServerOperation : GLib.Object { + [CCode (has_construct_function = false)] + public ServerOperation (Gda.ServerOperationType op_type, string xml_file); + public uint add_item_to_sequence (string seq_path); + public bool del_item_from_sequence (string item_path); + public static GLib.Quark error_quark (); + public string get_node_parent (string path); + public string get_node_path_portion (string path); + public Gda.ServerOperationNodeType get_node_type (string path, Gda.ServerOperationNodeStatus? status); + public Gda.ServerOperationType get_op_type (); + [CCode (array_length = false, array_null_terminated = true)] + public string[] get_root_nodes (); + [CCode (array_length = false, array_null_terminated = true)] + public string[] get_sequence_item_names (string path); + public uint get_sequence_max_size (string path); + public uint get_sequence_min_size (string path); + public unowned string get_sequence_name (string path); + public uint get_sequence_size (string path); + public string get_sql_identifier_at_path (string path) throws GLib.Error; + [CCode (cname = "gda_server_operation_get_value_at_path")] + [Version (since = "4.2.6")] + public unowned GLib.Value? get_value_at (string path); + [Version (since = "6.0")] + public bool is_valid (string? xml_file) throws GLib.Error; + public bool is_valid_from_resource (string? resource) throws GLib.Error; + public bool load_data_from_xml ([CCode (type = "xmlNodePtr")] Xml.Node* node) throws GLib.Error; + [Version (since = "4.2.3")] + public bool perform_create_database (string? provider) throws GLib.Error; + [Version (since = "4.2.3")] + public bool perform_drop_database (string? provider) throws GLib.Error; + [Version (since = "4.2.3")] + public static Gda.ServerOperation? prepare_create_database (string provider, string? db_name) throws GLib.Error; + [Version (since = "4.2.3")] + public static Gda.ServerOperation? prepare_drop_database (string provider, string? db_name) throws GLib.Error; + public string? render () throws GLib.Error; + public string save_data_to_xml_string () throws GLib.Error; + [NoWrapper] + public virtual void seq_item_added (string seq_path, int item_index); + [NoWrapper] + public virtual void seq_item_remove (string seq_path, int item_index); + [CCode (cname = "gda_server_operation_set_value_at_path")] + [Version (since = "4.2.6")] + public bool set_value_at (string? value, string path) throws GLib.Error; + [NoAccessorMethod] + public Gda.Connection connection { owned get; construct; } + public int op_type { get; construct; } + [NoAccessorMethod] + public Gda.ServerProvider provider { owned get; construct; } + [NoAccessorMethod] + public string spec_filename { construct; } + [NoAccessorMethod] + public string spec_resource { construct; } + public signal void sequence_item_added (string seq_path, int item_index); + public signal void sequence_item_remove (string seq_path, int item_index); + } + [CCode (cheader_filename = "libgda/libgda.h", copy_function = "g_boxed_copy", free_function = "g_boxed_free", type_id = "gda_server_operation_create_table_arg_get_type ()")] + [Compact] + public class ServerOperationCreateTableArg { + [CCode (has_construct_function = false)] + public ServerOperationCreateTableArg (); + public Gda.ServerOperationCreateTableArg copy (); + public void free (); + public string get_column_name (); + public GLib.Type get_column_type (); + public string get_fkey_ondelete (); + public string get_fkey_onupdate (); + public static GLib.Type get_fkey_ref_field_get_type (); + public unowned GLib.List get_fkey_refs (); + public string get_fkey_table (); + public Gda.ServerOperationCreateTableFlag get_flags (); + public void set_column_name (string name); + public void set_column_type (GLib.Type ctype); + public void set_fkey_ondelete (string action); + public void set_fkey_ondupdate (string action); + public void set_fkey_refs (GLib.List refs); + public void set_fkey_table (string name); + public void set_flags (Gda.ServerOperationCreateTableFlag flags); + } + [CCode (cheader_filename = "libgda/libgda.h", copy_function = "g_boxed_copy", free_function = "g_boxed_free", type_id = "gda_server_operation_create_table_arg_fkey_ref_field_get_type ()")] + [Compact] + public class ServerOperationCreateTableArgFKeyRefField { + [CCode (has_construct_function = false)] + public ServerOperationCreateTableArgFKeyRefField (); + public Gda.ServerOperationCreateTableArgFKeyRefField copy (); + public void free (); + public string get_local_field (); + public string get_referenced_field (); + public void set_local_field (string name); + public void set_referenced_field (string name); + } + [CCode (cheader_filename = "libgda/libgda.h", copy_function = "g_boxed_copy", free_function = "g_boxed_free", type_id = "gda_server_operation_node_get_type ()")] + [Compact] + public class ServerOperationNode { + public weak Gda.Column column; + public weak Gda.DataModel model; + public weak Gda.Holder param; + public weak Gda.Set plist; + public void* priv; + public Gda.ServerOperationNodeStatus status; + public Gda.ServerOperationNodeType type; + public Gda.ServerOperationNode copy (); + public void free (); + } + [CCode (cheader_filename = "libgda/libgda.h", type_id = "gda_server_provider_get_type ()")] + public abstract class ServerProvider : GLib.Object, Gda.Lockable { + [CCode (has_construct_function = false)] + protected ServerProvider (); + public Gda.ServerOperation? create_operation (Gda.Connection? cnc, Gda.ServerOperationType type, Gda.Set? options) throws GLib.Error; + public Gda.SqlParser create_parser (Gda.Connection? cnc); + public static GLib.Quark error_quark (); + public string escape_string (Gda.Connection? cnc, string str); + public unowned Gda.DataHandler get_data_handler_dbms (Gda.Connection? cnc, string for_type); + public unowned Gda.DataHandler get_data_handler_g_type (Gda.Connection? cnc, GLib.Type for_type); + public unowned string? get_default_dbms_type (Gda.Connection? cnc, GLib.Type type); + public static void* get_impl_functions_for_class (GLib.ObjectClass klass, Gda.ServerProviderFunctionsType type); + public unowned string get_name (); + public static GLib.MainContext get_real_main_context (Gda.Connection? cnc); + public unowned string get_server_version (Gda.Connection cnc); + public unowned string get_version (); + public void handler_declare (Gda.DataHandler dh, Gda.Connection cnc, GLib.Type g_type, string dbms_type); + public unowned Gda.DataHandler handler_find (Gda.Connection? cnc, GLib.Type g_type, string? dbms_type); + [Version (since = "5.2")] + public unowned Gda.DataHandler handler_use_default (GLib.Type type); + public unowned Gda.SqlParser internal_get_parser (); + [Version (since = "6.0")] + public static string load_resource_contents (string prov_name, string resource); + public bool perform_operation (Gda.Connection? cnc, Gda.ServerOperation op) throws GLib.Error; + public bool perform_operation_default (Gda.Connection? cnc, Gda.ServerOperation op) throws GLib.Error; + public string? render_operation (Gda.Connection? cnc, Gda.ServerOperation op) throws GLib.Error; + public GLib.Value? string_to_value (Gda.Connection? cnc, string string, GLib.Type preferred_type, string? dbms_type); + public bool supports_feature (Gda.Connection? cnc, Gda.ConnectionFeature feature); + public bool supports_operation (Gda.Connection? cnc, Gda.ServerOperationType type, Gda.Set? options); + public string unescape_string (Gda.Connection? cnc, string str); + public string value_to_sql_string (Gda.Connection? cnc, GLib.Value from); + } + [CCode (cheader_filename = "libgda/libgda.h", has_type_id = false)] + [Compact] + public abstract class ServerProviderBase { + public abstract void _gda_reserved11 (); + public abstract void _gda_reserved12 (); + public abstract void _gda_reserved13 (); + public abstract void _gda_reserved14 (); + public abstract bool add_savepoint (Gda.ServerProvider provider, Gda.Connection cnc, string name) throws GLib.Error; + public abstract bool begin_transaction (Gda.ServerProvider provider, Gda.Connection cnc, string name, Gda.TransactionIsolation level) throws GLib.Error; + public abstract bool close_connection (Gda.ServerProvider provider, Gda.Connection cnc); + public abstract bool commit_transaction (Gda.ServerProvider provider, Gda.Connection cnc, string name) throws GLib.Error; + public abstract Gda.Connection create_connection (Gda.ServerProvider provider); + public abstract Gda.ServerOperation create_operation (Gda.ServerProvider provider, Gda.Connection cnc, Gda.ServerOperationType type, Gda.Set options) throws GLib.Error; + public abstract Gda.SqlParser create_parser (Gda.ServerProvider provider, Gda.Connection cnc); + public abstract Gda.Worker create_worker (Gda.ServerProvider provider, bool for_cnc); + public abstract bool delete_savepoint (Gda.ServerProvider provider, Gda.Connection cnc, string name) throws GLib.Error; + public abstract string escape_string (Gda.ServerProvider provider, Gda.Connection cnc, string str); + public abstract Gda.DataHandler get_data_handler (Gda.ServerProvider provider, Gda.Connection? cnc, GLib.Type g_type, string dbms_type); + public abstract string get_def_dbms_type (Gda.ServerProvider provider, Gda.Connection cnc, GLib.Type g_type); + public abstract string get_name (Gda.ServerProvider provider); + public abstract string get_server_version (Gda.ServerProvider provider, Gda.Connection cnc); + public abstract string get_version (Gda.ServerProvider provider); + public abstract string identifier_quote (Gda.ServerProvider provider, Gda.Connection? cnc, string id, bool for_meta_store, bool force_quotes); + public abstract bool open_connection (Gda.ServerProvider provider, Gda.Connection cnc, Gda.QuarkList @params, Gda.QuarkList auth); + public abstract bool perform_operation (Gda.ServerProvider provider, Gda.Connection? cnc, Gda.ServerOperation op) throws GLib.Error; + public abstract bool prepare_connection (Gda.ServerProvider provider, Gda.Connection cnc, Gda.QuarkList @params, Gda.QuarkList auth); + public abstract string render_operation (Gda.ServerProvider provider, Gda.Connection cnc, Gda.ServerOperation op) throws GLib.Error; + public abstract bool rollback_savepoint (Gda.ServerProvider provider, Gda.Connection cnc, string name) throws GLib.Error; + public abstract bool rollback_transaction (Gda.ServerProvider provider, Gda.Connection cnc, string name) throws GLib.Error; + public abstract GLib.Object statement_execute (Gda.ServerProvider provider, Gda.Connection cnc, Gda.Statement stmt, Gda.Set @params, Gda.StatementModelUsage model_usage, GLib.Type[] col_types, ref Gda.Set last_inserted_row) throws GLib.Error; + public abstract bool statement_prepare (Gda.ServerProvider provider, Gda.Connection cnc, Gda.Statement stmt) throws GLib.Error; + public abstract Gda.SqlStatement statement_rewrite (Gda.ServerProvider provider, Gda.Connection cnc, Gda.Statement stmt, Gda.Set @params) throws GLib.Error; + public abstract string statement_to_sql (Gda.ServerProvider provider, Gda.Connection cnc, Gda.Statement stmt, Gda.Set @params, Gda.StatementSqlFlag flags, ref GLib.SList params_used) throws GLib.Error; + public abstract bool supports_feature (Gda.ServerProvider provider, Gda.Connection cnc, Gda.ConnectionFeature feature); + public abstract bool supports_operation (Gda.ServerProvider provider, Gda.Connection cnc, Gda.ServerOperationType type, Gda.Set options); + public abstract string unescape_string (Gda.ServerProvider provider, Gda.Connection cnc, string str); + } + [CCode (cheader_filename = "libgda/libgda.h", copy_function = "g_boxed_copy", free_function = "g_boxed_free", type_id = "gda_server_provider_connection_data_get_type ()")] + [Compact] + public class ServerProviderConnectionData { + public void* pad1; + public void* pad2; + public weak GLib.DestroyNotify provider_data_destroy_func; + public weak Gda.Worker worker; + } + [CCode (cheader_filename = "libgda/libgda.h", type_id = "gda_set_get_type ()")] + public class Set : GLib.Object { + [CCode (has_construct_function = false)] + public Set (GLib.SList holders); + public bool add_holder (Gda.Holder holder); + public Gda.Set copy (); + public static GLib.Quark error_quark (); + [CCode (has_construct_function = false)] + public Set.from_spec_node ([CCode (type = "xmlNodePtr")] Xml.Node* xml_spec) throws GLib.Error; + [CCode (has_construct_function = false)] + public Set.from_spec_string (string xml_spec) throws GLib.Error; + public unowned Gda.SetGroup get_group (Gda.Holder holder); + public unowned GLib.SList get_groups (); + public unowned Gda.Holder get_holder (string holder_id); + public unowned GLib.Value? get_holder_value (string holder_id); + public unowned GLib.SList get_holders (); + public unowned Gda.SetNode get_node (Gda.Holder holder); + public unowned GLib.SList get_nodes (); + [Version (since = "4.2")] + public unowned Gda.Holder get_nth_holder (int pos); + public unowned Gda.SetSource get_source (Gda.Holder holder); + public unowned Gda.SetSource get_source_for_model (Gda.DataModel model); + public unowned GLib.SList get_sources (); + public bool is_valid () throws GLib.Error; + public void merge_with_set (Gda.Set set_to_merge); + [CCode (has_construct_function = false)] + [Version (since = "4.2")] + public Set.read_only (GLib.SList holders); + public void remove_holder (Gda.Holder holder); + [Version (since = "4.2")] + public void replace_source_model (Gda.SetSource source, Gda.DataModel model); + [NoAccessorMethod] + public string description { owned get; set; } + [NoAccessorMethod] + public void* holders { construct; } + [NoAccessorMethod] + public string id { owned get; set; } + [NoAccessorMethod] + public string name { owned get; set; } + [NoAccessorMethod] + [Version (since = "5.2.0")] + public bool validate_changes { get; set; } + public virtual signal void holder_attr_changed (Gda.Holder holder, string attr_name, GLib.Value attr_value); + public virtual signal void holder_changed (Gda.Holder holder); + [Version (since = "4.2")] + public virtual signal void holder_type_set (Gda.Holder holder); + public virtual signal void public_data_changed (); + [Version (since = "4.2")] + public virtual signal void source_model_changed (void* source); + public virtual signal GLib.Error validate_holder_change (Gda.Holder holder, GLib.Value new_value); + public virtual signal GLib.Error validate_set (); + } + [CCode (cheader_filename = "libgda/libgda.h", copy_function = "g_boxed_copy", free_function = "g_boxed_free", type_id = "gda_set_group_get_type ()")] + [Compact] + public class SetGroup { + [CCode (has_construct_function = false)] + [Version (since = "5.2")] + public SetGroup (Gda.SetNode node); + [Version (since = "5.2")] + public void add_node (Gda.SetNode node); + [Version (since = "5.2")] + public Gda.SetGroup copy (); + [Version (since = "5.2")] + public void free (); + [Version (since = "5.2")] + public int get_n_nodes (); + [Version (since = "5.2")] + public Gda.SetNode get_node (); + [Version (since = "5.2")] + public unowned GLib.SList get_nodes (); + [Version (since = "5.2")] + public Gda.SetSource get_source (); + [Version (since = "5.2")] + public void set_source (Gda.SetSource source); + } + [CCode (cheader_filename = "libgda/libgda.h", copy_function = "g_boxed_copy", free_function = "g_boxed_free", type_id = "gda_set_node_get_type ()")] + [Compact] + public class SetNode { + [CCode (has_construct_function = false)] + [Version (since = "5.2")] + public SetNode (Gda.Holder holder); + [Version (since = "5.2")] + public Gda.SetNode copy (); + [Version (since = "5.2")] + public void free (); + [Version (since = "5.2")] + public unowned Gda.DataModel get_data_model (); + [Version (since = "5.2")] + public unowned Gda.Holder get_holder (); + [Version (since = "5.2")] + public int get_source_column (); + [Version (since = "5.2")] + public void set_data_model (Gda.DataModel? model); + [Version (since = "5.2")] + public void set_holder (Gda.Holder holder); + [Version (since = "5.2")] + public void set_source_column (int column); + } + [CCode (cheader_filename = "libgda/libgda.h", copy_function = "g_boxed_copy", free_function = "g_boxed_free", type_id = "gda_set_source_get_type ()")] + [Compact] + public class SetSource { + [CCode (has_construct_function = false)] + [Version (since = "5.2")] + public SetSource (Gda.DataModel model); + [Version (since = "5.2")] + public void add_node (Gda.SetNode node); + [Version (since = "5.2")] + public Gda.SetSource copy (); + [Version (since = "5.2")] + public void free (); + [Version (since = "5.2")] + public unowned Gda.DataModel get_data_model (); + [Version (since = "5.2")] + public int get_n_nodes (); + [Version (since = "5.2")] + public unowned GLib.SList get_nodes (); + [Version (since = "5.2")] + public void set_data_model (Gda.DataModel model); + } + [CCode (cheader_filename = "libgda/libgda.h", type_id = "gda_short_get_type ()")] + public class Short { + [CCode (has_construct_function = false)] + protected Short (); + } + [CCode (cheader_filename = "libgda/libgda.h", copy_function = "g_boxed_copy", free_function = "g_boxed_free", type_id = "gda_sql_any_part_get_type ()")] + [Compact] + public class SqlAnyPart { + public weak Gda.SqlAnyPart parent; + public Gda.SqlAnyPartType type; + public bool check_structure () throws GLib.Error; + public bool @foreach (Gda.SqlForeachFunc func) throws GLib.Error; + } + [CCode (cheader_filename = "libgda/libgda.h", type_id = "gda_sql_builder_get_type ()")] + public class SqlBuilder : GLib.Object { + [CCode (has_construct_function = false)] + [Version (since = "4.2")] + public SqlBuilder (Gda.SqlStatementType stmt_type); + [Version (since = "4.2")] + public Gda.SqlBuilderId add_case_v (Gda.SqlBuilderId test_expr, Gda.SqlBuilderId else_expr, [CCode (array_length_cname = "args_size", array_length_pos = 4.1)] Gda.SqlBuilderId[] when_array, [CCode (array_length_cname = "args_size", array_length_pos = 4.1)] Gda.SqlBuilderId[] then_array); + [Version (since = "4.2")] + public Gda.SqlBuilderId add_cond (Gda.SqlOperatorType op, Gda.SqlBuilderId op1, Gda.SqlBuilderId op2, Gda.SqlBuilderId op3); + [Version (since = "4.2")] + public Gda.SqlBuilderId add_cond_v (Gda.SqlOperatorType op, [CCode (array_length_cname = "op_ids_size", array_length_pos = 2.1)] Gda.SqlBuilderId[] op_ids); + [Version (since = "4.2")] + public Gda.SqlBuilderId add_expr_value (GLib.Value? value); + [Version (since = "4.2")] + public Gda.SqlBuilderId add_field_id (string field_name, string? table_name = null); + [Version (since = "4.2")] + public void add_field_value_as_gvalue (string field_name, GLib.Value? value); + [Version (since = "4.2")] + public void add_field_value_id (Gda.SqlBuilderId field_id, Gda.SqlBuilderId value_id); + [Version (since = "4.2")] + public Gda.SqlBuilderId add_function_v (string func_name, [CCode (array_length_cname = "args_size", array_length_pos = 2.1)] Gda.SqlBuilderId[] args); + [Version (since = "4.2")] + public Gda.SqlBuilderId add_id (string str); + [Version (since = "4.2")] + public Gda.SqlBuilderId add_param (string param_name, GLib.Type type, bool nullok); + [Version (since = "4.2")] + public Gda.SqlBuilderId add_sub_select (Gda.SqlStatement sqlst); + [Version (since = "4.2")] + public void compound_add_sub_select (Gda.SqlStatement sqlst); + [Version (since = "4.2")] + public void compound_add_sub_select_from_builder (Gda.SqlBuilder subselect); + [Version (since = "4.2")] + public void compound_set_type (Gda.SqlStatementCompoundType compound_type); + public static GLib.Quark error_quark (); + [Version (since = "4.2")] + public Gda.SqlExpr export_expression (Gda.SqlBuilderId id); + [Version (since = "4.2")] + public unowned Gda.SqlStatement? get_sql_statement (); + [Version (since = "4.2")] + public Gda.Statement get_statement () throws GLib.Error; + [Version (since = "4.2")] + public Gda.SqlBuilderId import_expression (Gda.SqlExpr expr); + [Version (since = "4.2")] + public Gda.SqlBuilderId import_expression_from_builder (Gda.SqlBuilder query, Gda.SqlBuilderId expr_id); + [Version (since = "4.2")] + public void join_add_field (Gda.SqlBuilderId join_id, string field_name); + [Version (since = "4.2")] + public Gda.SqlBuilderId select_add_field (string field_name, string? table_name = null, string? alias = null); + [Version (since = "4.2")] + public Gda.SqlBuilderId select_add_target (string table_name, string? alias = null); + [Version (since = "4.2")] + public Gda.SqlBuilderId select_add_target_id (Gda.SqlBuilderId table_id, string? alias = null); + [Version (since = "4.2")] + public void select_group_by (Gda.SqlBuilderId expr_id); + [Version (since = "4.2")] + public Gda.SqlBuilderId select_join_targets (Gda.SqlBuilderId left_target_id, Gda.SqlBuilderId right_target_id, Gda.SqlSelectJoinType join_type, Gda.SqlBuilderId join_expr); + [Version (since = "4.2")] + public void select_order_by (Gda.SqlBuilderId expr_id, bool asc, string? collation_name = null); + [Version (since = "4.2")] + public void select_set_distinct (bool distinct, Gda.SqlBuilderId expr_id); + [Version (since = "4.2")] + public void select_set_having (Gda.SqlBuilderId cond_id); + [Version (since = "4.2")] + public void select_set_limit (Gda.SqlBuilderId limit_count_expr_id, Gda.SqlBuilderId limit_offset_expr_id); + [Version (since = "4.2")] + public void set_table (string table_name); + [Version (since = "4.2")] + public void set_where (Gda.SqlBuilderId cond_id); + } + [CCode (cheader_filename = "libgda/libgda.h", copy_function = "g_boxed_copy", free_function = "g_boxed_free", type_id = "gda_sql_case_get_type ()")] + [Compact] + public class SqlCase { + public weak Gda.SqlAnyPart any; + public weak Gda.SqlExpr base_expr; + public weak Gda.SqlExpr else_expr; + public weak GLib.SList then_expr_list; + public weak GLib.SList when_expr_list; + [CCode (has_construct_function = false)] + public SqlCase (Gda.SqlAnyPart parent); + public Gda.SqlCase copy (); + public void free (); + public string serialize (); + } + [CCode (cheader_filename = "libgda/libgda.h", copy_function = "g_boxed_copy", free_function = "g_boxed_free", type_id = "gda_sql_expr_get_type ()")] + [Compact] + public class SqlExpr { + public weak Gda.SqlAnyPart any; + public weak Gda.SqlCase case_s; + public weak string cast_as; + public weak Gda.SqlOperation cond; + public weak Gda.SqlFunction func; + public weak Gda.SqlParamSpec param_spec; + public weak Gda.SqlAnyPart select; + public GLib.Value value; + public bool value_is_ident; + [CCode (has_construct_function = false)] + public SqlExpr (Gda.SqlAnyPart parent); + public Gda.SqlExpr copy (); + public void free (); + public string serialize (); + public void take_select (Gda.SqlStatement stmt); + } + [CCode (cheader_filename = "libgda/libgda.h", copy_function = "g_boxed_copy", free_function = "g_boxed_free", type_id = "gda_sql_field_get_type ()")] + [Compact] + public class SqlField { + public weak Gda.SqlAnyPart any; + public weak string field_name; + public Gda.MetaTableColumn validity_meta_table_column; + [CCode (has_construct_function = false)] + public SqlField (Gda.SqlAnyPart parent); + public Gda.SqlField copy (); + public void free (); + public string serialize (); + public void take_name (GLib.Value value); + } + [CCode (cheader_filename = "libgda/libgda.h", copy_function = "g_boxed_copy", free_function = "g_boxed_free", type_id = "gda_sql_function_get_type ()")] + [Compact] + public class SqlFunction { + public weak Gda.SqlAnyPart any; + public weak GLib.SList args_list; + public weak string function_name; + [CCode (has_construct_function = false)] + public SqlFunction (Gda.SqlAnyPart parent); + public void check_clean (); + public Gda.SqlFunction copy (); + public void free (); + public string serialize (); + public void take_args_list (GLib.SList args); + public void take_name (GLib.Value value); + } + [CCode (cheader_filename = "libgda/libgda.h", copy_function = "g_boxed_copy", free_function = "g_boxed_free", type_id = "gda_sql_operation_get_type ()")] + [Compact] + public class SqlOperation { + public weak Gda.SqlAnyPart any; + public weak GLib.SList operands; + public Gda.SqlOperatorType operator_type; + [CCode (has_construct_function = false)] + public SqlOperation (Gda.SqlAnyPart parent); + public Gda.SqlOperation copy (); + public void free (); + public static Gda.SqlOperatorType operator_from_string (string op); + public static unowned string operator_to_string (Gda.SqlOperatorType op); + public string serialize (); + } + [CCode (cheader_filename = "libgda/libgda.h", copy_function = "g_boxed_copy", free_function = "g_boxed_free", type_id = "gda_sql_param_spec_get_type ()")] + [Compact] + public class SqlParamSpec { + public void* _gda_reserved1; + public void* _gda_reserved2; + public weak string descr; + public GLib.Type g_type; + public bool is_param; + public weak string name; + public bool nullok; + public void* validity_meta_dict; + [CCode (has_construct_function = false)] + public SqlParamSpec (owned GLib.Value simple_spec); + public Gda.SqlParamSpec copy (); + public void free (); + public string serialize (); + public void take_descr (owned GLib.Value value); + public void take_name (owned GLib.Value value); + public void take_nullok (owned GLib.Value value); + public void take_type (owned GLib.Value value); + } + [CCode (cheader_filename = "libgda/libgda.h", type_id = "gda_sql_parser_get_type ()")] + public class SqlParser : GLib.Object, Gda.Lockable { + [CCode (has_construct_function = false)] + public SqlParser (); + public static GLib.Quark error_quark (); + public Gda.Batch? parse_file_as_batch (string filename) throws GLib.Error; + public Gda.Statement? parse_string (string sql, out string? remain) throws GLib.Error; + public Gda.Batch? parse_string_as_batch (string sql, out string? remain) throws GLib.Error; + public void set_overflow_error (); + public void set_syntax_error (); + [NoAccessorMethod] + public int column_error { get; } + [NoAccessorMethod] + public bool debug { set; } + [NoAccessorMethod] + public int line_error { get; } + [NoAccessorMethod] + public int mode { get; set; } + [NoAccessorMethod] + public int tokenizer_flavour { get; set; } + } + [CCode (cheader_filename = "libgda/libgda.h", copy_function = "g_boxed_copy", free_function = "g_boxed_free", type_id = "gda_sql_select_field_get_type ()")] + [Compact] + public class SqlSelectField { + public weak Gda.SqlAnyPart any; + public weak string @as; + public weak Gda.SqlExpr expr; + public weak string field_name; + public weak string table_name; + public Gda.MetaDbObject validity_meta_object; + public Gda.MetaTableColumn validity_meta_table_column; + [CCode (has_construct_function = false)] + public SqlSelectField (Gda.SqlAnyPart parent); + public Gda.SqlSelectField copy (); + public void free (); + public string serialize (); + public void take_alias (GLib.Value alias); + public void take_expr (Gda.SqlExpr expr); + public void take_star_value (GLib.Value value); + } + [CCode (cheader_filename = "libgda/libgda.h", copy_function = "g_boxed_copy", free_function = "g_boxed_free", type_id = "gda_sql_select_from_get_type ()")] + [Compact] + public class SqlSelectFrom { + public weak Gda.SqlAnyPart any; + public weak GLib.SList joins; + public weak GLib.SList targets; + [CCode (has_construct_function = false)] + public SqlSelectFrom (Gda.SqlAnyPart parent); + public Gda.SqlSelectFrom copy (); + public void free (); + public string serialize (); + public void take_new_join (Gda.SqlSelectJoin join); + public void take_new_target (Gda.SqlSelectTarget target); + } + [CCode (cheader_filename = "libgda/libgda.h", copy_function = "g_boxed_copy", free_function = "g_boxed_free", type_id = "gda_sql_select_join_get_type ()")] + [Compact] + public class SqlSelectJoin { + public weak Gda.SqlAnyPart any; + public weak Gda.SqlExpr expr; + public int position; + public Gda.SqlSelectJoinType type; + public weak GLib.SList use; + [CCode (has_construct_function = false)] + public SqlSelectJoin (Gda.SqlAnyPart parent); + public Gda.SqlSelectJoin copy (); + public void free (); + public string serialize (); + public static unowned string type_to_string (Gda.SqlSelectJoinType type); + } + [CCode (cheader_filename = "libgda/libgda.h", copy_function = "g_boxed_copy", free_function = "g_boxed_free", type_id = "gda_sql_select_order_get_type ()")] + [Compact] + public class SqlSelectOrder { + public weak Gda.SqlAnyPart any; + public bool asc; + public weak string collation_name; + public weak Gda.SqlExpr expr; + [CCode (has_construct_function = false)] + public SqlSelectOrder (Gda.SqlAnyPart parent); + public Gda.SqlSelectOrder copy (); + public void free (); + public string serialize (); + } + [CCode (cheader_filename = "libgda/libgda.h", copy_function = "g_boxed_copy", free_function = "g_boxed_free", type_id = "gda_sql_select_target_get_type ()")] + [Compact] + public class SqlSelectTarget { + public weak Gda.SqlAnyPart any; + public weak string @as; + public weak Gda.SqlExpr expr; + public weak string table_name; + public Gda.MetaDbObject validity_meta_object; + [CCode (has_construct_function = false)] + public SqlSelectTarget (Gda.SqlAnyPart parent); + public Gda.SqlSelectTarget copy (); + public void free (); + public string serialize (); + public void take_alias (GLib.Value alias); + public void take_select (Gda.SqlStatement stmt); + public void take_table_name (GLib.Value value); + } + [CCode (cheader_filename = "libgda.h", copy_function = "g_boxed_copy", free_function = "g_boxed_free", type_id = "gda_sql_statement_get_type ()")] + [Compact] + public class SqlStatement { + public void* contents; + public weak string sql; + public Gda.SqlStatementType stmt_type; + public weak Gda.MetaStruct validity_meta_struct; + [CCode (has_construct_function = false)] + public SqlStatement (Gda.SqlStatementType type); + public void check_clean (); + public bool check_structure () throws GLib.Error; + public bool check_validity (Gda.Connection? cnc) throws GLib.Error; + [Version (since = "4.2")] + public bool check_validity_m (Gda.MetaStruct? mstruct) throws GLib.Error; + public void compound_set_type (Gda.SqlStatementCompoundType type); + public void compound_take_stmt (Gda.SqlStatement s); + public Gda.SqlStatement copy (); + public void delete_take_condition (Gda.SqlExpr cond); + public void delete_take_table_name (GLib.Value value); + public void free (); + public static Gda.SqlStatementContentsInfo get_contents_infos (Gda.SqlStatementType type); + public void insert_take_1_values_list (GLib.SList list); + public void insert_take_extra_values_list (GLib.SList list); + public void insert_take_fields_list (GLib.SList list); + public void insert_take_on_conflict (GLib.Value value); + public void insert_take_select (Gda.SqlStatement select); + public void insert_take_table_name (GLib.Value value); + public bool normalize (Gda.Connection? cnc) throws GLib.Error; + public void select_take_distinct (bool distinct, Gda.SqlExpr? distinct_expr); + public void select_take_expr_list (GLib.SList expr_list); + public void select_take_from (Gda.SqlSelectFrom from); + public void select_take_group_by (GLib.SList group_by); + public void select_take_having_cond (Gda.SqlExpr expr); + public void select_take_limits (Gda.SqlExpr count, Gda.SqlExpr offset); + public void select_take_order_by (GLib.SList order_by); + public void select_take_where_cond (Gda.SqlExpr expr); + public string serialize (); + public static Gda.SqlStatementType string_to_type (string type); + public void trans_set_isol_level (Gda.TransactionIsolation level); + public void trans_take_mode (owned GLib.Value value); + public void trans_take_name (owned GLib.Value value); + public static unowned string type_to_string (Gda.SqlStatementType type); + public void unknown_take_expressions (GLib.SList expressions); + public void update_take_condition (Gda.SqlExpr cond); + public void update_take_on_conflict (GLib.Value value); + public void update_take_set_value (GLib.Value fname, Gda.SqlExpr expr); + public void update_take_table_name (GLib.Value value); + } + [CCode (cheader_filename = "libgda/libgda.h", has_type_id = false)] + [Compact] + public abstract class SqlStatementContentsInfo { + public weak Gda.SqlForeachFunc check_structure_func; + public weak Gda.SqlForeachFunc check_validity_func; + public weak string name; + public Gda.SqlStatementType type; + public abstract void* _gda_reserved1 (); + public abstract void* _gda_reserved2 (); + public abstract void* _gda_reserved3 (); + public abstract void* _gda_reserved4 (); + public abstract void* @construct (); + public abstract void* copy (void* stm); + public abstract void free (void* stm); + public abstract string serialize (void* stm); + } + [CCode (cheader_filename = "libgda/libgda.h", copy_function = "g_boxed_copy", free_function = "g_boxed_free", type_id = "gda_sql_table_get_type ()")] + [Compact] + public class SqlTable { + public weak Gda.SqlAnyPart any; + public weak string table_name; + public Gda.MetaDbObject validity_meta_object; + [CCode (has_construct_function = false)] + public SqlTable (Gda.SqlAnyPart parent); + public Gda.SqlTable copy (); + public void free (); + public string serialize (); + public void take_name (GLib.Value value); + } + [CCode (cheader_filename = "libgda/libgda.h", type_id = "gda_statement_get_type ()")] + public class Statement : GLib.Object { + [CCode (has_construct_function = false)] + public Statement (); + public bool check_structure () throws GLib.Error; + public bool check_validity (Gda.Connection? cnc) throws GLib.Error; + public Gda.Statement copy (); + public static GLib.Quark error_quark (); + public bool get_parameters (out Gda.Set? out_params) throws GLib.Error; + public Gda.SqlStatementType get_statement_type (); + public bool is_useless (); + public bool normalize (Gda.Connection cnc) throws GLib.Error; + [Version (since = "4.2")] + public Gda.SqlStatement? rewrite_for_default_values (Gda.Set @params, bool remove) throws GLib.Error; + public string serialize (); + public string to_sql_extended (Gda.Connection? cnc, Gda.Set? @params, Gda.StatementSqlFlag flags, out GLib.SList? params_used) throws GLib.Error; + [NoAccessorMethod] + public Gda.SqlStatement structure { owned get; set; } + public virtual signal void checked (Gda.Connection cnc, bool checked); + public virtual signal void reset (); + } + [CCode (cheader_filename = "libgda/libgda.h", copy_function = "g_boxed_copy", free_function = "g_boxed_free", type_id = "gda_text_get_type ()")] + [Compact] + public class Text { + [CCode (has_construct_function = false)] + public Text (); + public void free (); + public unowned string get_string (); + public void set_string (string str); + public void take_string (string str); + public static string to_alphanum (string text); + } + [CCode (cheader_filename = "libgda/libgda.h", copy_function = "g_boxed_copy", free_function = "g_boxed_free", type_id = "gda_time_get_type ()")] + [Compact] + public class Time { + [CCode (has_construct_function = false)] + public Time (); + public Gda.Time copy (); + [Version (since = "6.0")] + public void free (); + [CCode (has_construct_function = false)] + [Version (since = "6.0")] + public Time.from_date_time (GLib.DateTime dt); + [CCode (has_construct_function = false)] + public Time.from_values (ushort hour, ushort minute, ushort second, ulong fraction, long timezone); + [Version (since = "6.0")] + public ulong get_fraction (); + [Version (since = "6.0")] + public ushort get_hour (); + [Version (since = "6.0")] + public ushort get_minute (); + [Version (since = "6.0")] + public ushort get_second (); + [Version (since = "6.0")] + public long get_timezone (); + [Version (since = "6.0")] + public GLib.TimeZone get_tz (); + [Version (since = "6.0")] + public void set_fraction (ulong fraction); + [Version (since = "6.0")] + public void set_hour (ushort hour); + [Version (since = "6.0")] + public void set_minute (ushort minute); + [Version (since = "6.0")] + public void set_second (ushort second); + [Version (since = "6.0")] + public void set_timezone (long timezone); + [Version (since = "6.0")] + public string to_string (); + [Version (since = "6.0")] + public string to_string_local (); + [Version (since = "6.0")] + public string to_string_utc (); + [Version (since = "6.0")] + public Gda.Time to_timezone (GLib.TimeZone ntz); + public Gda.Time to_utc (); + [Version (deprecated = true, deprecated_since = "6.0", since = "4.2")] + public bool valid (); + } + [CCode (cheader_filename = "libgda/libgda.h", type_id = "gda_transaction_status_get_type ()")] + public class TransactionStatus : GLib.Object { + [CCode (has_construct_function = false)] + public TransactionStatus (string name); + public Gda.TransactionStatusEvent add_event_sql (string sql, Gda.ConnectionEvent conn_event); + public Gda.TransactionStatusEvent add_event_sub (Gda.TransactionStatus sub_trans); + public Gda.TransactionStatusEvent add_event_svp (string svp_name); + public Gda.TransactionStatus? find (string str, Gda.TransactionStatusEvent destev); + public Gda.TransactionStatus? find_current (Gda.TransactionStatusEvent destev, bool unnamed_only); + public void free_events (Gda.TransactionStatusEvent event, bool free_after); + public Gda.TransactionIsolation get_isolation_level (); + public Gda.TransactionStatusState get_state (); + public void set_isolation_level (Gda.TransactionIsolation il); + public void set_state (Gda.TransactionStatusState state); + } + [CCode (cheader_filename = "libgda/libgda.h", copy_function = "g_boxed_copy", free_function = "g_boxed_free", type_id = "gda_transaction_status_event_get_type ()")] + [Compact] + public class TransactionStatusEvent { + public weak Gda.ConnectionEvent conn_event; + [CCode (cname = "pl.sql")] + public weak string pl_sql; + [CCode (cname = "pl.sub_trans")] + public weak Gda.TransactionStatus pl_sub_trans; + [CCode (cname = "pl.svp_name")] + public weak string pl_svp_name; + public weak Gda.TransactionStatus trans; + public Gda.TransactionStatusEventType type; + } + [CCode (cheader_filename = "libgda/libgda.h", type_id = "gda_tree_get_type ()")] + public class Tree : GLib.Object { + [CCode (has_construct_function = false)] + [Version (since = "4.2")] + public Tree (); + [Version (since = "4.2")] + public void add_manager (Gda.TreeManager manager); + [Version (since = "4.2")] + public void clean (); + [Version (since = "4.2")] + public void dump (Gda.TreeNode? node, void* stream); + public static GLib.Quark error_quark (); + [Version (since = "4.2")] + public unowned Gda.TreeNode? get_node (string tree_path, bool use_names); + [Version (since = "4.2")] + public unowned Gda.TreeManager get_node_manager (Gda.TreeNode node); + [Version (since = "4.2")] + public string get_node_path (Gda.TreeNode node); + [Version (since = "4.2")] + public GLib.SList get_nodes_in_path (string? tree_path, bool use_names); + [Version (since = "4.2")] + public void set_attribute (string attribute, GLib.Value value, GLib.DestroyNotify destroy); + [Version (since = "4.2")] + public bool update_all () throws GLib.Error; + [Version (since = "4.2.8")] + public bool update_children (Gda.TreeNode? node) throws GLib.Error; + [Version (since = "4.2")] + public bool update_part (Gda.TreeNode node) throws GLib.Error; + [NoAccessorMethod] + public bool is_list { get; } + [Version (since = "4.2")] + public virtual signal void node_changed (Gda.TreeNode node); + [Version (since = "4.2")] + public virtual signal void node_deleted (string node_path); + [Version (since = "4.2")] + public virtual signal void node_has_child_toggled (Gda.TreeNode node); + [Version (since = "4.2")] + public virtual signal void node_inserted (Gda.TreeNode node); + } + [CCode (cheader_filename = "libgda/libgda.h", type_id = "gda_tree_manager_get_type ()")] + public class TreeManager : GLib.Object { + [CCode (has_construct_function = false)] + protected TreeManager (); + [Version (since = "4.2")] + public void add_manager (Gda.TreeManager sub); + [Version (since = "4.2")] + public void add_new_node_attribute (string attribute, GLib.Value? value); + [Version (since = "4.2")] + public Gda.TreeNode create_node (Gda.TreeNode? parent, string? name); + public static GLib.Quark error_quark (); + [Version (since = "4.2")] + public unowned GLib.SList get_managers (); + [Version (since = "4.2")] + public void set_node_create_func (Gda.TreeManagerNodeFunc? func); + [CCode (has_construct_function = false)] + [Version (since = "4.2")] + public TreeManager.with_func (Gda.TreeManagerNodesFunc update_func); + [NoAccessorMethod] + public Gda.TreeManagerNodesFunc func { get; set construct; } + [NoAccessorMethod] + public bool recursive { get; set construct; } + } + [CCode (cheader_filename = "libgda/libgda.h", type_id = "gda_tree_mgr_columns_get_type ()")] + public class TreeMgrColumns : Gda.TreeManager { + [CCode (has_construct_function = false, type = "GdaTreeManager*")] + [Version (since = "4.2")] + public TreeMgrColumns (Gda.Connection cnc, string schema, string table_name); + [NoAccessorMethod] + public Gda.Connection connection { owned get; construct; } + [NoAccessorMethod] + [Version (since = "4.2.4")] + public Gda.MetaStore meta_store { owned get; construct; } + [NoAccessorMethod] + public string schema { construct; } + [NoAccessorMethod] + public string table_name { construct; } + } + [CCode (cheader_filename = "libgda/libgda.h", type_id = "gda_tree_mgr_label_get_type ()")] + public class TreeMgrLabel : Gda.TreeManager { + [CCode (has_construct_function = false, type = "GdaTreeManager*")] + [Version (since = "4.2")] + public TreeMgrLabel (string label); + [NoAccessorMethod] + public string label { construct; } + } + [CCode (cheader_filename = "libgda/libgda.h", type_id = "gda_tree_mgr_schemas_get_type ()")] + public class TreeMgrSchemas : Gda.TreeManager { + [CCode (has_construct_function = false, type = "GdaTreeManager*")] + [Version (since = "4.2")] + public TreeMgrSchemas (Gda.Connection cnc); + [NoAccessorMethod] + public Gda.Connection connection { owned get; construct; } + [NoAccessorMethod] + [Version (since = "4.2.4")] + public Gda.MetaStore meta_store { owned get; construct; } + } + [CCode (cheader_filename = "libgda/libgda.h", type_id = "gda_tree_mgr_select_get_type ()")] + public class TreeMgrSelect : Gda.TreeManager { + [CCode (has_construct_function = false, type = "GdaTreeManager*")] + [Version (since = "4.2")] + public TreeMgrSelect (Gda.Connection cnc, Gda.Statement stmt, Gda.Set @params); + [NoAccessorMethod] + public Gda.Connection connection { owned get; construct; } + [NoAccessorMethod] + public Gda.Set @params { owned get; construct; } + [NoAccessorMethod] + public Gda.Statement statement { owned get; construct; } + } + [CCode (cheader_filename = "libgda/libgda.h", type_id = "gda_tree_mgr_tables_get_type ()")] + public class TreeMgrTables : Gda.TreeManager { + [CCode (has_construct_function = false, type = "GdaTreeManager*")] + [Version (since = "4.2")] + public TreeMgrTables (Gda.Connection cnc, string? schema); + [NoAccessorMethod] + public Gda.Connection connection { owned get; construct; } + [NoAccessorMethod] + [Version (since = "4.2.4")] + public Gda.MetaStore meta_store { owned get; construct; } + [NoAccessorMethod] + public string schema { construct; } + } + [CCode (cheader_filename = "libgda/libgda.h", type_id = "gda_tree_node_get_type ()")] + public class TreeNode : GLib.Object { + [CCode (has_construct_function = false)] + [Version (since = "4.2")] + public TreeNode (string? name); + [NoWrapper] + public virtual void dump_children (string prefix, GLib.StringBuilder in_string); + [NoWrapper] + public virtual string dump_header (); + public static GLib.Quark error_quark (); + [Version (since = "4.2")] + public unowned GLib.Value? fetch_attribute (string attribute); + [Version (since = "4.2")] + public unowned Gda.TreeNode get_child_index (int index); + [Version (since = "4.2")] + public unowned Gda.TreeNode get_child_name (string name); + [Version (since = "4.2")] + public GLib.SList get_children (); + [Version (since = "4.2")] + public unowned GLib.Value? get_node_attribute (string attribute); + [Version (since = "4.2")] + public unowned Gda.TreeNode get_parent (); + [Version (since = "4.2")] + public void set_node_attribute (string attribute, GLib.Value? value, GLib.DestroyNotify destroy); + [NoAccessorMethod] + public string name { owned get; set; } + [Version (since = "4.2")] + public virtual signal void node_changed (Gda.TreeNode node); + [Version (since = "4.2")] + public virtual signal void node_deleted (string relative_path); + [Version (since = "4.2")] + public virtual signal void node_has_child_toggled (Gda.TreeNode node); + [Version (since = "4.2")] + public virtual signal void node_inserted (Gda.TreeNode node); + } + [CCode (cheader_filename = "libgda/libgda.h", type_id = "gda_ushort_get_type ()")] + public class UShort { + [CCode (has_construct_function = false)] + protected UShort (); + } + [CCode (cheader_filename = "libgda/libgda.h", ref_function = "gda_worker_ref", type_id = "gda_worker_get_type ()", unref_function = "gda_worker_unref")] + [Compact] + public class Worker { + [CCode (has_construct_function = false)] + [Version (since = "6.0")] + public Worker (); + [Version (since = "6.0")] + public bool cancel_job (uint job_id) throws GLib.Error; + [Version (since = "6.0")] + public bool do_job (GLib.MainContext? context, int timeout_ms, void* out_result, uint? out_job_id, [CCode (delegate_target_pos = 5.5, destroy_notify_pos = 6.1)] owned Gda.WorkerFunc func, GLib.DestroyNotify? data_destroy_func) throws GLib.Error; + public static GLib.Quark error_quark (); + [Version (since = "6.0")] + public bool fetch_job_result (uint job_id, void* out_result) throws GLib.Error; + [Version (since = "6.0")] + public void forget_job (uint job_id); + [Version (since = "6.0")] + public unowned GLib.Thread get_worker_thread (); + public Gda.Worker new_unique (bool allow_destroy); + [Version (since = "6.0")] + public Gda.Worker @ref (); + [Version (since = "6.0")] + public bool set_callback (GLib.MainContext? context, Gda.WorkerCallback? callback) throws GLib.Error; + [Version (since = "6.0")] + public uint submit_job (GLib.MainContext? callback_context, [CCode (delegate_target_pos = 2.5, destroy_notify_pos = 3.1)] owned Gda.WorkerFunc func, GLib.DestroyNotify? data_destroy_func) throws GLib.Error; + [Version (since = "6.0")] + public bool thread_is_worker (); + [Version (since = "6.0")] + public void unref (); + [Version (since = "6.0")] + public void* wait_job (owned Gda.WorkerFunc func) throws GLib.Error; + } + [CCode (cheader_filename = "libgda/libgda.h", type_id = "gda_xa_transaction_get_type ()")] + public class XaTransaction : GLib.Object { + [CCode (has_construct_function = false)] + public XaTransaction (uint32 format, string global_transaction_id); + public bool begin () throws GLib.Error; + public bool commit (out GLib.SList? cnc_to_recover) throws GLib.Error; + public bool commit_recovered (out GLib.SList? cnc_to_recover) throws GLib.Error; + public static GLib.Quark error_quark (); + public bool register_connection (Gda.Connection cnc, string branch) throws GLib.Error; + public bool rollback () throws GLib.Error; + public static Gda.XaTransactionId string_to_id (string str); + public void unregister_connection (Gda.Connection cnc); + [NoAccessorMethod] + public uint format_id { get; construct; } + [NoAccessorMethod] + public string transaction_id { owned get; construct; } + } + [CCode (cheader_filename = "libgda/libgda.h", copy_function = "g_boxed_copy", free_function = "g_boxed_free", type_id = "gda_xa_transaction_id_get_type ()")] + [Compact] + public class XaTransactionId { + public ushort bqual_length; + [CCode (array_length = false)] + public weak char data[128]; + public uint32 format; + public ushort gtrid_length; + public string to_string (); + } + [CCode (cheader_filename = "libgda/libgda.h", type_cname = "GdaDataHandlerInterface", type_id = "gda_data_handler_get_type ()")] + public interface DataHandler : GLib.Object { + public abstract bool accepts_g_type (GLib.Type type); + [Version (since = "4.2.3")] + public static Gda.DataHandler get_default (GLib.Type for_type); + public abstract unowned string get_descr (); + public abstract GLib.Value? get_sane_init_value (GLib.Type type); + public abstract string get_sql_from_value (GLib.Value? value); + public abstract string get_str_from_value (GLib.Value? value); + public abstract GLib.Value? get_value_from_sql (string? sql, GLib.Type type); + public abstract GLib.Value? get_value_from_str (string? str, GLib.Type type); + } + [CCode (cheader_filename = "libgda/libgda.h", type_id = "gda_data_model_get_type ()")] + public interface DataModel : GLib.Object { + public bool add_data_from_xml_node ([CCode (type = "xmlNodePtr")] Xml.Node* node) throws GLib.Error; + public int append_row () throws GLib.Error; + public int append_values (GLib.List? values) throws GLib.Error; + public Gda.DataModelArray? array_copy_model () throws GLib.Error; + [Version (since = "5.2.0")] + public Gda.DataModelArray? array_copy_model_ext ([CCode (array_length_cname = "ncols", array_length_pos = 0.5)] int[] cols) throws GLib.Error; + public Gda.DataModelIter create_iter (); + public unowned Gda.Column? describe_column (int col); + public void dump (void* to_stream); + public string dump_as_string (); + public static GLib.Quark error_quark (); + public bool export_to_file (Gda.DataModelIOFormat format, string file, [CCode (array_length_cname = "nb_cols", array_length_pos = 3.5)] int[]? cols, [CCode (array_length_cname = "nb_rows", array_length_pos = 4.5)] int[]? rows, Gda.Set options) throws GLib.Error; + public string export_to_string (Gda.DataModelIOFormat format, [CCode (array_length_cname = "nb_cols", array_length_pos = 2.5)] int[]? cols, [CCode (array_length_cname = "nb_rows", array_length_pos = 3.5)] int[]? rows, Gda.Set options); + public void freeze (); + public Gda.DataModelAccessFlags get_access_flags (); + public Gda.ValueAttribute get_attributes_at (int col, int row); + public int get_column_index (string name); + [Version (since = "3.2")] + public unowned string get_column_name (int col); + public unowned string get_column_title (int col); + [CCode (array_length = false, array_null_terminated = true)] + [Version (since = "4.2.6")] + public unowned GLib.Error[] get_exceptions (); + public int get_n_columns (); + public int get_n_rows (); + public bool get_notify (); + public int get_row_from_values (GLib.SList values, [CCode (array_length = false)] int[] cols_index); + public unowned GLib.Value? get_typed_value_at (int col, int row, GLib.Type expected_type, bool nullok) throws GLib.Error; + public unowned GLib.Value? get_value_at (int col, int row) throws GLib.Error; + public bool import_from_file (string file, GLib.HashTable? cols_trans, Gda.Set options) throws GLib.Error; + public bool import_from_model (Gda.DataModel from, bool overwrite, GLib.HashTable? cols_trans) throws GLib.Error; + public bool import_from_string (string string, GLib.HashTable? cols_trans, Gda.Set options) throws GLib.Error; + public bool iter_move_next_default (Gda.DataModelIter iter); + public bool iter_move_prev_default (Gda.DataModelIter iter); + public bool iter_move_to_row_default (Gda.DataModelIter iter, int row); + public bool remove_row (int row) throws GLib.Error; + public void send_hint (Gda.DataModelHint hint, GLib.Value? hint_value); + [Version (since = "3.2")] + public void set_column_name (int col, string name); + public void set_column_title (int col, string title); + public bool set_value_at (int col, int row, GLib.Value value) throws GLib.Error; + public bool set_values (int row, GLib.List? values) throws GLib.Error; + public void thaw (); + public signal void access_changed (); + public signal void changed (); + [HasEmitter] + public signal void reset (); + [HasEmitter] + public signal void row_inserted (int row); + [HasEmitter] + public signal void row_removed (int row); + [HasEmitter] + public signal void row_updated (int row); + } + [CCode (cheader_filename = "libgda/libgda.h", type_cname = "GdaDbBuildableInterface", type_id = "gda_db_buildable_get_type ()")] + public interface DbBuildable : GLib.Object { + [Version (since = "6.0")] + public abstract bool parse_node ([CCode (type = "xmlNodePtr")] Xml.Node* node) throws GLib.Error; + [Version (since = "6.0")] + public abstract bool write_node ([CCode (type = "xmlNodePtr")] Xml.Node* node) throws GLib.Error; + } + [CCode (cheader_filename = "libgda/libgda.h", type_cname = "GdaDdlModifiableInterface", type_id = "gda_ddl_modifiable_get_type ()")] + public interface DdlModifiable : GLib.Object { + [Version (since = "6.0")] + public abstract bool create (Gda.Connection cnc) throws GLib.Error; + [Version (since = "6.0")] + public abstract bool drop (Gda.Connection cnc) throws GLib.Error; + public static GLib.Quark error_quark (); + [Version (since = "6.0")] + public abstract bool rename (Gda.Connection cnc) throws GLib.Error; + } + [CCode (cheader_filename = "libgda/libgda.h", type_cname = "GdaLockableInterface", type_id = "gda_lockable_get_type ()")] + public interface Lockable : GLib.Object { + public abstract void @lock (); + public abstract bool trylock (); + public abstract void @unlock (); + } + [CCode (cheader_filename = "libgda/libgda.h", type_cname = "GdaProviderInterface", type_id = "gda_provider_get_type ()")] + public interface Provider : GLib.Object { + [Version (since = "6.0")] + public abstract bool add_savepoint (Gda.Connection cnc, string name) throws GLib.Error; + [Version (since = "6.0")] + public abstract bool begin_transaction (Gda.Connection cnc, string name, Gda.TransactionIsolation level) throws GLib.Error; + [Version (since = "6.0")] + public abstract bool close_connection (Gda.Connection cnc); + [Version (since = "6.0")] + public abstract bool commit_transaction (Gda.Connection cnc, string name) throws GLib.Error; + [Version (since = "6.0")] + public abstract Gda.Connection create_connection (); + [Version (since = "6.0")] + public abstract Gda.ServerOperation create_operation (Gda.Connection cnc, Gda.ServerOperationType type, Gda.Set options) throws GLib.Error; + [Version (since = "6.0")] + public abstract Gda.SqlParser create_parser (Gda.Connection cnc); + [Version (since = "6.0")] + public abstract bool delete_savepoint (Gda.Connection cnc, string name) throws GLib.Error; + [Version (since = "6.0")] + public abstract string escape_string (Gda.Connection cnc, string str); + [Version (since = "6.0")] + public abstract Gda.DataHandler get_data_handler (Gda.Connection cnc, GLib.Type g_type, string dbms_type); + [Version (since = "6.0")] + public abstract string get_def_dbms_type (Gda.Connection cnc, GLib.Type g_type); + public abstract Gda.Set get_last_inserted (Gda.Connection cnc) throws GLib.Error; + [Version (since = "6.0")] + public abstract unowned string get_name (); + [Version (since = "6.0")] + public abstract unowned string get_server_version (Gda.Connection cnc); + [Version (since = "6.0")] + public abstract unowned string get_version (); + [Version (since = "6.0")] + public abstract string identifier_quote (Gda.Connection? cnc, string id, bool for_meta_store, bool force_quotes); + [Version (since = "6.0")] + public abstract bool open_connection (Gda.Connection cnc, Gda.QuarkList @params, Gda.QuarkList auth); + [Version (since = "6.0")] + public abstract bool perform_operation (Gda.Connection cnc, Gda.ServerOperation op) throws GLib.Error; + [Version (since = "6.0")] + public abstract bool prepare_connection (Gda.Connection cnc, Gda.QuarkList @params, Gda.QuarkList auth); + [Version (since = "6.0")] + public abstract string render_operation (Gda.Connection cnc, Gda.ServerOperation op) throws GLib.Error; + [Version (since = "6.0")] + public abstract bool rollback_savepoint (Gda.Connection cnc, string name) throws GLib.Error; + [Version (since = "6.0")] + public abstract bool rollback_transaction (Gda.Connection cnc, string name) throws GLib.Error; + [Version (since = "6.0")] + public abstract GLib.Object statement_execute (Gda.Connection cnc, Gda.Statement stmt, Gda.Set @params, Gda.StatementModelUsage model_usage, GLib.Type col_types, Gda.Set last_inserted_row) throws GLib.Error; + [Version (since = "6.0")] + public abstract bool statement_prepare (Gda.Connection cnc, Gda.Statement stmt) throws GLib.Error; + [Version (since = "6.0")] + public abstract Gda.SqlStatement statement_rewrite (Gda.Connection cnc, Gda.Statement stmt, Gda.Set @params) throws GLib.Error; + [Version (since = "6.0")] + public abstract string statement_to_sql (Gda.Connection cnc, Gda.Statement stmt, Gda.Set? @params, Gda.StatementSqlFlag flags, out GLib.SList? params_used) throws GLib.Error; + [Version (since = "6.0")] + public abstract bool supports_feature (Gda.Connection cnc, Gda.ConnectionFeature feature); + [Version (since = "6.0")] + public abstract bool supports_operation (Gda.Connection cnc, Gda.ServerOperationType type, Gda.Set options); + [Version (since = "6.0")] + public abstract string unescape_string (Gda.Connection cnc, string str); + } + [CCode (cheader_filename = "libgda/libgda.h", type_cname = "GdaProviderMetaInterface", type_id = "gda_provider_meta_get_type ()")] + public interface ProviderMeta : GLib.Object { + [Version (since = "6.0")] + public abstract Gda.DataModel btypes () throws GLib.Error; + [Version (since = "6.0")] + public abstract Gda.Row character_set (string chset_catalog, string chset_schema, string chset_name_n) throws GLib.Error; + [Version (since = "6.0")] + public abstract Gda.DataModel character_sets () throws GLib.Error; + [Version (since = "6.0")] + public abstract Gda.Row check_column (string table_catalog, string table_schema, string table_name, string constraint_name) throws GLib.Error; + [Version (since = "6.0")] + public abstract Gda.DataModel check_columns () throws GLib.Error; + [Version (since = "6.0")] + public abstract Gda.Row collation (string collation_catalog, string collation_schema, string collation_name_n) throws GLib.Error; + [Version (since = "6.0")] + public abstract Gda.DataModel collations () throws GLib.Error; + [Version (since = "6.0")] + public abstract Gda.DataModel columns () throws GLib.Error; + [Version (since = "6.0")] + public abstract Gda.Row constraint_ref (string table_catalog, string table_schema, string table_name, string constraint_name) throws GLib.Error; + [Version (since = "6.0")] + public abstract Gda.Row constraint_table (string table_catalog, string table_schema, string table_name, string constraint_name_n) throws GLib.Error; + [Version (since = "6.0")] + public abstract Gda.DataModel constraints_ref () throws GLib.Error; + [Version (since = "6.0")] + public abstract Gda.DataModel constraints_ref_table (string table_catalog, string table_schema, string table_name) throws GLib.Error; + [Version (since = "6.0")] + public abstract Gda.DataModel constraints_table (string table_catalog, string table_schema, string table_name) throws GLib.Error; + [Version (since = "6.0")] + public abstract Gda.DataModel constraints_tables () throws GLib.Error; + [Version (since = "6.0")] + public abstract Gda.Row domain (string domain_catalog, string domain_schema) throws GLib.Error; + [Version (since = "6.0")] + public abstract Gda.Row domain_constraint (string domain_catalog, string domain_schema, string domain_name, string constraint_name) throws GLib.Error; + [Version (since = "6.0")] + public abstract Gda.DataModel domain_constraints (string domain_catalog, string domain_schema, string domain_name) throws GLib.Error; + [Version (since = "6.0")] + public abstract Gda.DataModel domains () throws GLib.Error; + [Version (since = "6.0")] + public abstract Gda.DataModel domains_constraints () throws GLib.Error; + [Version (since = "6.0")] + public abstract Gda.Row element_type (string specific_name) throws GLib.Error; + [Version (since = "6.0")] + public abstract Gda.DataModel element_types () throws GLib.Error; + [Version (since = "6.0")] + public abstract Gda.Row enum_type (string udt_catalog, string udt_schema, string udt_name) throws GLib.Error; + [Version (since = "6.0")] + public abstract Gda.DataModel enums_type () throws GLib.Error; + public static GLib.Quark error_quark (); + [Version (since = "6.0")] + public Gda.DataModel? execute_query (string sql, Gda.Set? @params) throws GLib.Error; + [Version (since = "6.0")] + public Gda.Row? execute_query_row (string sql, Gda.Set @params) throws GLib.Error; + [Version (since = "6.0")] + public Gda.Connection get_connection (); + [Version (since = "6.0")] + public abstract Gda.Row index_col (string table_catalog, string table_schema, string table_name, string index_name) throws GLib.Error; + [Version (since = "6.0")] + public abstract Gda.DataModel index_cols () throws GLib.Error; + [Version (since = "6.0")] + public abstract Gda.Row index_table (string table_catalog, string table_schema, string table_name, string index_name_n) throws GLib.Error; + [Version (since = "6.0")] + public abstract Gda.DataModel indexes_table (string table_catalog, string table_schema, string table_name) throws GLib.Error; + [Version (since = "6.0")] + public abstract Gda.DataModel indexes_tables () throws GLib.Error; + [Version (since = "6.0")] + public abstract Gda.Row key_column (string table_catalog, string table_schema, string table_name, string constraint_name) throws GLib.Error; + [Version (since = "6.0")] + public abstract Gda.DataModel key_columns () throws GLib.Error; + [Version (since = "6.0")] + public abstract Gda.Row routine (string routine_catalog, string routine_schema, string routine_name_n) throws GLib.Error; + [Version (since = "6.0")] + public abstract Gda.Row routine_col (string rout_catalog, string rout_schema, string rout_name) throws GLib.Error; + [Version (since = "6.0")] + public abstract Gda.Row routine_pars (string rout_catalog, string rout_schema, string rout_name) throws GLib.Error; + [Version (since = "6.0")] + public abstract Gda.DataModel routines () throws GLib.Error; + [Version (since = "6.0")] + public abstract Gda.DataModel routines_col () throws GLib.Error; + [Version (since = "6.0")] + public abstract Gda.DataModel routines_pars () throws GLib.Error; + [Version (since = "6.0")] + public abstract Gda.Row schemata (string catalog_name, string schema_name_n) throws GLib.Error; + [Version (since = "6.0")] + public abstract Gda.DataModel schematas () throws GLib.Error; + [Version (since = "6.0")] + public abstract Gda.Row table (string table_catalog, string table_schema, string table_name_n) throws GLib.Error; + [Version (since = "6.0")] + public abstract Gda.Row table_column (string table_catalog, string table_schema, string table_name, string column_name) throws GLib.Error; + [Version (since = "6.0")] + public abstract Gda.DataModel table_columns (string table_catalog, string table_schema, string table_name) throws GLib.Error; + [Version (since = "6.0")] + public abstract Gda.DataModel tables () throws GLib.Error; + [Version (since = "6.0")] + public abstract Gda.DataModel tables_columns () throws GLib.Error; + [Version (since = "6.0")] + public abstract Gda.Row trigger (string table_catalog, string table_schema, string table_name) throws GLib.Error; + [Version (since = "6.0")] + public abstract Gda.DataModel triggers () throws GLib.Error; + [Version (since = "6.0")] + public abstract Gda.Row udt (string udt_catalog, string udt_schema) throws GLib.Error; + [Version (since = "6.0")] + public abstract Gda.Row udt_col (string udt_catalog, string udt_schema, string udt_name) throws GLib.Error; + [Version (since = "6.0")] + public abstract Gda.DataModel udt_cols () throws GLib.Error; + [Version (since = "6.0")] + public abstract Gda.DataModel udts () throws GLib.Error; + [Version (since = "6.0")] + public abstract Gda.Row view (string view_catalog, string view_schema, string view_name_n) throws GLib.Error; + [Version (since = "6.0")] + public abstract Gda.Row view_column (string view_catalog, string view_schema, string view_name, string column_name) throws GLib.Error; + [Version (since = "6.0")] + public abstract Gda.DataModel view_columns (string view_catalog, string view_schema, string view_name) throws GLib.Error; + [Version (since = "6.0")] + public abstract Gda.DataModel views () throws GLib.Error; + [Version (since = "6.0")] + public abstract Gda.DataModel views_columns () throws GLib.Error; + [ConcreteAccessor] + public abstract Gda.Connection connection { owned get; construct; } + } + [CCode (cheader_filename = "libgda/libgda.h", has_type_id = false)] + public struct MetaDbObject { + public Gda.MetaDbObjectType obj_type; + public bool outdated; + public weak string obj_catalog; + public weak string obj_schema; + public weak string obj_name; + public weak string obj_short_name; + public weak string obj_full_name; + public weak string obj_owner; + public weak GLib.SList depend_list; + [CCode (cname = "extra.meta_table")] + public Gda.MetaTable extra_meta_table; + [CCode (cname = "extra.meta_view")] + public Gda.MetaView extra_meta_view; + } + [CCode (cheader_filename = "libgda/libgda.h", has_type_id = false)] + public struct MetaTable { + public weak GLib.SList columns; + public int pk_cols_array; + public int pk_cols_nb; + public weak GLib.SList reverse_fk_list; + public weak GLib.SList fk_list; + } + [CCode (cheader_filename = "libgda/libgda.h", has_type_id = false)] + public struct MetaTableColumn { + public weak string column_name; + public weak string column_type; + public GLib.Type gtype; + public bool pkey; + public bool nullok; + public weak string default_value; + public bool auto_incement; + public weak string desc; + } + [CCode (cheader_filename = "libgda/libgda.h", has_type_id = false)] + public struct MetaTableForeignKey { + public Gda.MetaDbObject meta_table; + public Gda.MetaDbObject depend_on; + public int cols_nb; + public int fk_cols_array; + public weak string fk_names_array; + public int ref_pk_cols_array; + public weak string ref_pk_names_array; + public weak string fk_name; + } + [CCode (cheader_filename = "libgda/libgda.h", has_type_id = false)] + public struct MetaView { + public Gda.MetaTable table; + public weak string view_def; + public bool is_updatable; + } + [CCode (cheader_filename = "libgda/libgda.h", has_type_id = false)] + public struct ServerProviderHandlerInfo { + public weak Gda.Connection cnc; + public GLib.Type g_type; + public weak string dbms_type; + } + [CCode (cheader_filename = "libgda/libgda.h")] + [SimpleType] + public struct SqlBuilderId : uint { + } + [CCode (cheader_filename = "libgda/libgda.h", has_type_id = false)] + public struct SqlParserIface { + public weak Gda.SqlParser parser; + public weak Gda.SqlStatement parsed_statement; + } + [CCode (cheader_filename = "libgda/libgda.h", has_type_id = false)] + public struct SqlStatementCheckValidityData { + public weak Gda.Connection cnc; + public weak Gda.MetaStore store; + public weak Gda.MetaStruct mstruct; + } + [CCode (cheader_filename = "libgda/libgda.h", has_type_id = false)] + public struct SqlStatementCompound { + public weak Gda.SqlAnyPart any; + public Gda.SqlStatementCompoundType compound_type; + public weak GLib.SList stmt_list; + } + [CCode (cheader_filename = "libgda/libgda.h", has_type_id = false)] + public struct SqlStatementDelete { + public weak Gda.SqlAnyPart any; + public weak Gda.SqlTable table; + public weak Gda.SqlExpr cond; + } + [CCode (cheader_filename = "libgda/libgda.h", has_type_id = false)] + public struct SqlStatementInsert { + public weak Gda.SqlAnyPart any; + public weak string on_conflict; + public weak Gda.SqlTable table; + public weak GLib.SList fields_list; + public weak GLib.SList values_list; + public weak Gda.SqlAnyPart select; + } + [CCode (cheader_filename = "libgda/libgda.h", has_type_id = false)] + public struct SqlStatementSelect { + public weak Gda.SqlAnyPart any; + public bool distinct; + public weak Gda.SqlExpr distinct_expr; + public weak GLib.SList expr_list; + public weak Gda.SqlSelectFrom from; + public weak Gda.SqlExpr where_cond; + public weak GLib.SList group_by; + public weak Gda.SqlExpr having_cond; + public weak GLib.SList order_by; + public weak Gda.SqlExpr limit_count; + public weak Gda.SqlExpr limit_offset; + } + [CCode (cheader_filename = "libgda/libgda.h", has_type_id = false)] + public struct SqlStatementTransaction { + public weak Gda.SqlAnyPart any; + public Gda.TransactionIsolation isolation_level; + public weak string trans_mode; + public weak string trans_name; + } + [CCode (cheader_filename = "libgda/libgda.h", has_type_id = false)] + public struct SqlStatementUnknown { + public weak Gda.SqlAnyPart any; + public weak GLib.SList expressions; + } + [CCode (cheader_filename = "libgda/libgda.h", has_type_id = false)] + public struct SqlStatementUpdate { + public weak Gda.SqlAnyPart any; + public weak string on_conflict; + public weak Gda.SqlTable table; + public weak GLib.SList fields_list; + public weak GLib.SList expr_list; + public weak Gda.SqlExpr cond; + } + [CCode (cheader_filename = "libgda/libgda.h", cprefix = "GDA_BATCH_CONFLICTING_PARAMETER_", has_type_id = false)] + public enum BatchError { + [CCode (cname = "GDA_BATCH_CONFLICTING_PARAMETER_ERROR")] + BATCH_CONFLICTING_PARAMETER_ERROR + } + [CCode (cheader_filename = "libgda/libgda.h", cprefix = "GDA_CONFIG_", has_type_id = false)] + public enum ConfigError { + DSN_NOT_FOUND_ERROR, + PERMISSION_ERROR, + PROVIDER_NOT_FOUND_ERROR, + PROVIDER_CREATION_ERROR + } + [CCode (cheader_filename = "libgda/libgda.h", cprefix = "GDA_CONNECTION_", has_type_id = false)] + public enum ConnectionError { + DSN_NOT_FOUND_ERROR, + PROVIDER_NOT_FOUND_ERROR, + PROVIDER_ERROR, + NO_CNC_SPEC_ERROR, + NO_PROVIDER_SPEC_ERROR, + OPEN_ERROR, + ALREADY_OPENED_ERROR, + STATEMENT_TYPE_ERROR, + CANT_LOCK_ERROR, + TASK_NOT_FOUND_ERROR, + CLOSED_ERROR, + META_DATA_CONTEXT_ERROR, + NO_MAIN_CONTEXT_ERROR + } + [CCode (cheader_filename = "libgda/libgda.h", cprefix = "GDA_CONNECTION_EVENT_CODE_", has_type_id = false)] + public enum ConnectionEventCode { + CONSTRAINT_VIOLATION, + RESTRICT_VIOLATION, + NOT_NULL_VIOLATION, + FOREIGN_KEY_VIOLATION, + UNIQUE_VIOLATION, + CHECK_VIOLATION, + INSUFFICIENT_PRIVILEGES, + UNDEFINED_COLUMN, + UNDEFINED_FUNCTION, + UNDEFINED_TABLE, + DUPLICATE_COLUMN, + DUPLICATE_DATABASE, + DUPLICATE_FUNCTION, + DUPLICATE_SCHEMA, + DUPLICATE_TABLE, + DUPLICATE_ALIAS, + DUPLICATE_OBJECT, + SYNTAX_ERROR, + UNKNOWN + } + [CCode (cheader_filename = "libgda/libgda.h", cprefix = "GDA_CONNECTION_EVENT_", has_type_id = false)] + public enum ConnectionEventType { + NOTICE, + WARNING, + ERROR, + COMMAND + } + [CCode (cheader_filename = "libgda/libgda.h", cprefix = "GDA_CONNECTION_FEATURE_", has_type_id = false)] + public enum ConnectionFeature { + AGGREGATES, + BLOBS, + INDEXES, + INHERITANCE, + NAMESPACES, + PROCEDURES, + SEQUENCES, + SQL, + TRANSACTIONS, + SAVEPOINTS, + SAVEPOINTS_REMOVE, + TRIGGERS, + UPDATABLE_CURSOR, + USERS, + VIEWS, + TRANSACTION_ISOLATION_READ_COMMITTED, + TRANSACTION_ISOLATION_READ_UNCOMMITTED, + TRANSACTION_ISOLATION_REPEATABLE_READ, + TRANSACTION_ISOLATION_SERIALIZABLE, + XA_TRANSACTIONS, + LAST + } + [CCode (cheader_filename = "libgda/libgda.h", cprefix = "GDA_CONNECTION_META_", has_type_id = false)] + public enum ConnectionMetaType { + NAMESPACES, + TYPES, + TABLES, + VIEWS, + FIELDS, + INDEXES + } + [CCode (cheader_filename = "libgda/libgda.h", cprefix = "GDA_CONNECTION_OPTIONS_", has_type_id = false)] + [Flags] + public enum ConnectionOptions { + NONE, + READ_ONLY, + SQL_IDENTIFIERS_CASE_SENSITIVE, + AUTO_META_DATA + } + [CCode (cheader_filename = "libgda/libgda.h", cprefix = "GDA_CONNECTION_STATUS_", has_type_id = false)] + public enum ConnectionStatus { + CLOSED, + OPENING, + IDLE, + BUSY + } + [CCode (cheader_filename = "libgda/libgda.h", cprefix = "GDA_DATA_COMPARATOR_", has_type_id = false)] + public enum DataComparatorError { + MISSING_DATA_MODEL_ERROR, + COLUMN_TYPES_MISMATCH_ERROR, + MODEL_ACCESS_ERROR, + USER_CANCELLED_ERROR + } + [CCode (cheader_filename = "libgda/libgda.h", cprefix = "GDA_DATA_MODEL_ACCESS_", has_type_id = false)] + [Flags] + public enum DataModelAccessFlags { + RANDOM, + CURSOR_FORWARD, + CURSOR_BACKWARD, + CURSOR, + INSERT, + UPDATE, + DELETE, + WRITE + } + [CCode (cheader_filename = "libgda/libgda.h", cprefix = "GDA_DATA_MODEL_HINT_", has_type_id = false)] + public enum DataModelHint { + START_BATCH_UPDATE, + END_BATCH_UPDATE, + REFRESH + } + [CCode (cheader_filename = "libgda/libgda.h", cprefix = "GDA_DATA_MODEL_IO_", has_type_id = false)] + public enum DataModelIOFormat { + DATA_ARRAY_XML, + TEXT_SEPARATED, + TEXT_TABLE + } + [CCode (cheader_filename = "libgda/libgda.h", cprefix = "GDA_DATA_MODEL_ITER_COLUMN_OUT_OF_RANGE_", has_type_id = false)] + public enum DataModelIterError { + [CCode (cname = "GDA_DATA_MODEL_ITER_COLUMN_OUT_OF_RANGE_ERROR")] + DATA_MODEL_ITER_COLUMN_OUT_OF_RANGE_ERROR + } + [CCode (cheader_filename = "libgda/libgda.h", cprefix = "GDA_DATA_PIVOT_", has_type_id = false)] + public enum DataPivotAggregate { + AVG, + COUNT, + MAX, + MIN, + SUM + } + [CCode (cheader_filename = "libgda/libgda.h", cprefix = "GDA_DATA_PIVOT_", has_type_id = false)] + public enum DataPivotError { + INTERNAL_ERROR, + SOURCE_MODEL_ERROR, + FIELD_FORMAT_ERROR, + USAGE_ERROR, + OVERFLOW_ERROR + } + [CCode (cheader_filename = "libgda/libgda.h", cprefix = "GDA_DATA_PIVOT_FIELD_", has_type_id = false)] + public enum DataPivotFieldType { + ROW, + COLUMN + } + [CCode (cheader_filename = "libgda/libgda.h", cprefix = "GDA_DATA_PROXY_", has_type_id = false)] + public enum DataProxyError { + COMMIT_ERROR, + COMMIT_CANCELLED, + READ_ONLY_VALUE, + READ_ONLY_ROW, + FILTER_ERROR + } + [CCode (cheader_filename = "libgda/libgda.h", cprefix = "GDA_DATA_SELECT_COND_", has_type_id = false)] + public enum DataSelectConditionType { + PK, + ALL_COLUMNS + } + [CCode (cheader_filename = "libgda/libgda.h", cprefix = "GDA_DATA_SELECT_", has_type_id = false)] + public enum DataSelectError { + MODIFICATION_STATEMENT_ERROR, + MISSING_MODIFICATION_STATEMENT_ERROR, + CONNECTION_ERROR, + ACCESS_ERROR, + SQL_ERROR, + SAFETY_LOCKED_ERROR + } + [CCode (cheader_filename = "libgda/libgda.h", cprefix = "GDA_DB_CATALOG_", has_type_id = false)] + public enum DbCatalogError { + CONTEXT_NULL, + DOC_NULL, + INVALID_XML, + INVALID_SCHEMA, + SERVER_OPERATION, + FILE_READ, + PARSE_CONTEXT, + PARSE, + PARSE_CHUNK, + CONNECTION_CLOSED + } + [CCode (cheader_filename = "libgda/libgda.h", cprefix = "GDA_DB_COLUMN_ERROR_", has_type_id = false)] + public enum DbColumnError { + TYPE, + WRONG_OPERATION + } + [CCode (cheader_filename = "libgda/libgda.h", cprefix = "GDA_DB_FKEY_", has_type_id = false)] + public enum DbFkeyReferenceAction { + NO_ACTION, + SET_NULL, + RESTRICT, + SET_DEFAULT, + CASCADE + } + [CCode (cheader_filename = "libgda/libgda.h", cprefix = "GDA_DB_INDEX_", has_type_id = false)] + public enum DbIndexError { + CONNECTION_NOT_OPENED, + SERVER_OPERATION + } + [CCode (cheader_filename = "libgda/libgda.h", cprefix = "GDA_DB_INDEX_SORT_ORDER_", has_type_id = false)] + public enum DbIndexSortOrder { + ASC, + DESC + } + [CCode (cheader_filename = "libgda/libgda.h", cprefix = "GDA_DB_TABLE_", has_type_id = false)] + public enum DbTableError { + COLUMN_EMPTY, + CONNECTION_NOT_OPENED, + SERVER_OPERATION + } + [CCode (cheader_filename = "libgda/libgda.h", cprefix = "GDA_DB_VIEW_", has_type_id = false)] + public enum DbViewRefAction { + RESTRICT, + CASCADE + } + [CCode (cheader_filename = "libgda/libgda.h", cprefix = "GDA_DIFF_", has_type_id = false)] + public enum DiffType { + ADD_ROW, + REMOVE_ROW, + MODIFY_ROW + } + [CCode (cheader_filename = "libgda/libgda.h", cprefix = "GDA_HOLDER_", has_type_id = false)] + public enum HolderError { + STRING_CONVERSION_ERROR, + VALUE_TYPE_ERROR, + VALUE_NULL_ERROR, + VALUE_CHANGE_ERROR + } + [CCode (cheader_filename = "libgda/libgda.h", cprefix = "GDA_META_DB_", has_type_id = false)] + public enum MetaDbObjectType { + UNKNOWN, + TABLE, + VIEW + } + [CCode (cheader_filename = "libgda/libgda.h", cprefix = "GDA_META_FOREIGN_KEY_", has_type_id = false)] + public enum MetaForeignKeyPolicy { + UNKNOWN, + NONE, + NO_ACTION, + RESTRICT, + CASCADE, + SET_NULL, + SET_DEFAULT + } + [CCode (cheader_filename = "libgda/libgda.h", cprefix = "GDA_META_GRAPH_", has_type_id = false)] + [Flags] + public enum MetaGraphInfo { + [CCode (cname = "GDA_META_GRAPH_COLUMNS")] + META_GRAPH_COLUMNS + } + [CCode (cheader_filename = "libgda/libgda.h", cprefix = "GDA_META_SORT_", has_type_id = false)] + public enum MetaSortType { + ALHAPETICAL, + DEPENDENCIES + } + [CCode (cheader_filename = "libgda/libgda.h", cprefix = "GDA_META_STORE_", has_type_id = false)] + public enum MetaStoreChangeType { + ADD, + REMOVE, + MODIFY + } + [CCode (cheader_filename = "libgda/libgda.h", cprefix = "GDA_META_STORE_", has_type_id = false)] + public enum MetaStoreError { + INCORRECT_SCHEMA_ERROR, + UNSUPPORTED_PROVIDER_ERROR, + INTERNAL_ERROR, + META_CONTEXT_ERROR, + MODIFY_CONTENTS_ERROR, + EXTRACT_SQL_ERROR, + ATTRIBUTE_NOT_FOUND_ERROR, + ATTRIBUTE_ERROR, + SCHEMA_OBJECT_NOT_FOUND_ERROR, + SCHEMA_OBJECT_CONFLICT_ERROR, + SCHEMA_OBJECT_DESCR_ERROR, + TRANSACTION_ALREADY_STARTED_ERROR + } + [CCode (cheader_filename = "libgda/libgda.h", cprefix = "GDA_META_STRUCT_", has_type_id = false)] + public enum MetaStructError { + UNKNOWN_OBJECT_ERROR, + DUPLICATE_OBJECT_ERROR, + INCOHERENCE_ERROR, + XML_ERROR + } + [CCode (cheader_filename = "libgda/libgda.h", cprefix = "GDA_META_STRUCT_FEATURE_", has_type_id = false)] + [Flags] + public enum MetaStructFeature { + NONE, + FOREIGN_KEYS, + VIEW_DEPENDENCIES, + ALL + } + [CCode (cheader_filename = "libgda/libgda.h", cprefix = "GDA_SERVER_OPERATION_CREATE_TABLE_", has_type_id = false)] + [Flags] + public enum ServerOperationCreateTableFlag { + NOTHING_FLAG, + PKEY_FLAG, + NOT_NULL_FLAG, + UNIQUE_FLAG, + AUTOINC_FLAG, + FKEY_FLAG, + PKEY_AUTOINC_FLAG + } + [CCode (cheader_filename = "libgda/libgda.h", cprefix = "GDA_SERVER_OPERATION_", has_type_id = false)] + public enum ServerOperationError { + OBJECT_NAME_ERROR, + INCORRECT_VALUE_ERROR, + XML_ERROR + } + [CCode (cheader_filename = "libgda/libgda.h", cprefix = "GDA_SERVER_OPERATION_STATUS_", has_type_id = false)] + public enum ServerOperationNodeStatus { + OPTIONAL, + REQUIRED, + UNKNOWN + } + [CCode (cheader_filename = "libgda/libgda.h", cprefix = "GDA_SERVER_OPERATION_NODE_", has_type_id = false)] + public enum ServerOperationNodeType { + PARAMLIST, + DATA_MODEL, + PARAM, + SEQUENCE, + SEQUENCE_ITEM, + DATA_MODEL_COLUMN, + UNKNOWN + } + [CCode (cheader_filename = "libgda/libgda.h", cprefix = "GDA_SERVER_OPERATION_", has_type_id = false)] + public enum ServerOperationType { + CREATE_DB, + DROP_DB, + CREATE_TABLE, + DROP_TABLE, + RENAME_TABLE, + ADD_COLUMN, + DROP_COLUMN, + RENAME_COLUMN, + CREATE_INDEX, + DROP_INDEX, + RENAME_INDEX, + CREATE_VIEW, + DROP_VIEW, + COMMENT_TABLE, + COMMENT_COLUMN, + CREATE_USER, + ALTER_USER, + DROP_USER, + LAST; + [CCode (cname = "gda_server_operation_op_type_to_string")] + public unowned string to_string (); + [CCode (cname = "gda_server_operation_string_to_op_type")] + [Version (since = "4.2")] + public static Gda.ServerOperationType from_string (string str); + } + [CCode (cheader_filename = "libgda/libgda.h", cprefix = "GDA_SERVER_PROVIDER_", has_type_id = false)] + public enum ServerProviderError { + METHOD_NON_IMPLEMENTED_ERROR, + PREPARE_STMT_ERROR, + EMPTY_STMT_ERROR, + MISSING_PARAM_ERROR, + STATEMENT_EXEC_ERROR, + OPERATION_ERROR, + INTERNAL_ERROR, + BUSY_ERROR, + NON_SUPPORTED_ERROR, + SERVER_VERSION_ERROR, + DATA_ERROR, + DEFAULT_VALUE_HANDLING_ERROR, + MISUSE_ERROR, + FILE_NOT_FOUND_ERROR + } + [CCode (cheader_filename = "libgda/libgda.h", cprefix = "GDA_SERVER_PROVIDER_FUNCTIONS_", has_type_id = false)] + public enum ServerProviderFunctionsType { + BASE, + META, + XA, + MAX + } + [CCode (cheader_filename = "libgda/libgda.h", cprefix = "GDA_SERVER_META_", has_type_id = false)] + public enum ServerProviderMetaType { + _INFO, + _BTYPES, + _UDT, + UDT, + _UDT_COLS, + UDT_COLS, + _ENUMS, + ENUMS, + _DOMAINS, + DOMAINS, + _CONSTRAINTS_DOM, + CONSTRAINTS_DOM, + _EL_TYPES, + EL_TYPES, + _COLLATIONS, + COLLATIONS, + _CHARACTER_SETS, + CHARACTER_SETS, + _SCHEMATA, + SCHEMATA, + _TABLES_VIEWS, + TABLES_VIEWS, + _COLUMNS, + COLUMNS, + _VIEW_COLS, + VIEW_COLS, + _CONSTRAINTS_TAB, + CONSTRAINTS_TAB, + _CONSTRAINTS_REF, + CONSTRAINTS_REF, + _KEY_COLUMNS, + KEY_COLUMNS, + _CHECK_COLUMNS, + CHECK_COLUMNS, + _TRIGGERS, + TRIGGERS, + _ROUTINES, + ROUTINES, + _ROUTINE_COL, + ROUTINE_COL, + _ROUTINE_PAR, + ROUTINE_PAR, + _INDEXES_TAB, + INDEXES_TAB, + _INDEX_COLS, + INDEX_COLS + } + [CCode (cheader_filename = "libgda/libgda.h", cprefix = "GDA_SET_", has_type_id = false)] + public enum SetError { + XML_SPEC_ERROR, + HOLDER_NOT_FOUND_ERROR, + INVALID_ERROR, + READ_ONLY_ERROR, + IMPLEMENTATION_ERROR + } + [CCode (cheader_filename = "libgda/libgda.h", cprefix = "GDA_SQL_ANY_", has_type_id = false)] + public enum SqlAnyPartType { + STMT_SELECT, + STMT_INSERT, + STMT_UPDATE, + STMT_DELETE, + STMT_COMPOUND, + STMT_BEGIN, + STMT_ROLLBACK, + STMT_COMMIT, + STMT_SAVEPOINT, + STMT_ROLLBACK_SAVEPOINT, + STMT_DELETE_SAVEPOINT, + STMT_UNKNOWN, + EXPR, + SQL_FIELD, + SQL_TABLE, + SQL_FUNCTION, + SQL_OPERATION, + SQL_CASE, + SQL_SELECT_FIELD, + SQL_SELECT_TARGET, + SQL_SELECT_JOIN, + SQL_SELECT_FROM, + SQL_SELECT_ORDER + } + [CCode (cheader_filename = "libgda/libgda.h", cprefix = "GDA_SQL_BUILDER_", has_type_id = false)] + public enum SqlBuilderError { + WRONG_TYPE_ERROR, + MISUSE_ERROR + } + [CCode (cheader_filename = "libgda/libgda.h", cprefix = "GDA_SQL_IDENTIFIERS_", has_type_id = false)] + [Flags] + public enum SqlIdentifierStyle { + LOWER_CASE, + UPPER_CASE + } + [CCode (cheader_filename = "libgda/libgda.h", cprefix = "GDA_SQL_OPERATOR_TYPE_", has_type_id = false)] + public enum SqlOperatorType { + AND, + OR, + EQ, + IS, + LIKE, + BETWEEN, + GT, + LT, + GEQ, + LEQ, + DIFF, + REGEXP, + REGEXP_CI, + NOT_REGEXP, + NOT_REGEXP_CI, + SIMILAR, + ISNULL, + ISNOTNULL, + NOT, + IN, + NOTIN, + CONCAT, + PLUS, + MINUS, + STAR, + DIV, + REM, + BITAND, + BITOR, + BITNOT, + ILIKE, + NOTLIKE, + NOTILIKE + } + [CCode (cheader_filename = "libgda/libgda.h", cprefix = "GDA_SQL_PARSER_", has_type_id = false)] + public enum SqlParserError { + SYNTAX_ERROR, + OVERFLOW_ERROR, + EMPTY_SQL_ERROR + } + [CCode (cheader_filename = "libgda/libgda.h", cprefix = "GDA_SQL_PARSER_FLAVOUR_", has_type_id = false)] + public enum SqlParserFlavour { + STANDARD, + SQLITE, + MYSQL, + ORACLE, + POSTGRESQL + } + [CCode (cheader_filename = "libgda/libgda.h", cprefix = "GDA_SQL_PARSER_MODE_", has_type_id = false)] + public enum SqlParserMode { + PARSE, + DELIMIT + } + [CCode (cheader_filename = "libgda/libgda.h", cprefix = "GDA_SQL_SELECT_JOIN_", has_type_id = false)] + public enum SqlSelectJoinType { + CROSS, + NATURAL, + INNER, + LEFT, + RIGHT, + FULL; + [Version (replacement = "SqlSelectJoin.type_to_string")] + public unowned string to_string (); + } + [CCode (cheader_filename = "libgda/libgda.h", cprefix = "GDA_SQL_STATEMENT_COMPOUND_", has_type_id = false)] + public enum SqlStatementCompoundType { + UNION, + UNION_ALL, + INTERSECT, + INTERSECT_ALL, + EXCEPT, + EXCEPT_ALL + } + [CCode (cheader_filename = "libgda/libgda.h", cprefix = "GDA_SQL_STATEMENT_", has_type_id = false)] + public enum SqlStatementType { + SELECT, + INSERT, + UPDATE, + DELETE, + COMPOUND, + BEGIN, + ROLLBACK, + COMMIT, + SAVEPOINT, + ROLLBACK_SAVEPOINT, + DELETE_SAVEPOINT, + UNKNOWN, + NONE; + [Version (replacement = "SqlStatement.type_to_string")] + public unowned string to_string (); + } + [CCode (cheader_filename = "libgda/libgda.h", cprefix = "GDA_STATEMENT_", has_type_id = false)] + public enum StatementError { + PARSE_ERROR, + SYNTAX_ERROR, + NO_CNC_ERROR, + CNC_CLOSED_ERROR, + EXEC_ERROR, + PARAM_TYPE_ERROR, + PARAM_ERROR + } + [CCode (cheader_filename = "libgda/libgda.h", cprefix = "GDA_STATEMENT_MODEL_", has_type_id = false)] + [Flags] + public enum StatementModelUsage { + RANDOM_ACCESS, + CURSOR_FORWARD, + CURSOR_BACKWARD, + CURSOR, + ALLOW_NOPARAM, + OFFLINE + } + [CCode (cheader_filename = "libgda/libgda.h", cprefix = "GDA_STATEMENT_SQL_", has_type_id = false)] + [Flags] + public enum StatementSqlFlag { + PARAMS_AS_VALUES, + PRETTY, + PARAMS_LONG, + PARAMS_SHORT, + PARAMS_AS_COLON, + PARAMS_AS_DOLLAR, + PARAMS_AS_QMARK, + PARAMS_AS_UQMARK, + TIMEZONE_TO_GMT + } + [CCode (cheader_filename = "libgda/libgda.h", cprefix = "GDA_TRANSACTION_ISOLATION_", has_type_id = false)] + public enum TransactionIsolation { + SERVER_DEFAULT, + READ_COMMITTED, + READ_UNCOMMITTED, + REPEATABLE_READ, + SERIALIZABLE + } + [CCode (cheader_filename = "libgda/libgda.h", cprefix = "GDA_TRANSACTION_STATUS_EVENT_", has_type_id = false)] + public enum TransactionStatusEventType { + SAVEPOINT, + SQL, + SUB_TRANSACTION + } + [CCode (cheader_filename = "libgda/libgda.h", cprefix = "GDA_TRANSACTION_STATUS_STATE_", has_type_id = false)] + public enum TransactionStatusState { + OK, + FAILED + } + [CCode (cheader_filename = "libgda/libgda.h", cprefix = "GDA_TREE_UNKNOWN_", has_type_id = false)] + public enum TreeError { + [CCode (cname = "GDA_TREE_UNKNOWN_ERROR")] + TREE_UNKNOWN_ERROR + } + [CCode (cheader_filename = "libgda/libgda.h", cprefix = "GDA_TREE_MANAGER_UNKNOWN_", has_type_id = false)] + public enum TreeManagerError { + [CCode (cname = "GDA_TREE_MANAGER_UNKNOWN_ERROR")] + TREE_MANAGER_UNKNOWN_ERROR + } + [CCode (cheader_filename = "libgda/libgda.h", cprefix = "GDA_TREE_NODE_UNKNOWN_", has_type_id = false)] + public enum TreeNodeError { + [CCode (cname = "GDA_TREE_NODE_UNKNOWN_ERROR")] + TREE_NODE_UNKNOWN_ERROR + } + [CCode (cheader_filename = "libgda/libgda.h", cprefix = "GDA_VALUE_ATTR_", has_type_id = false)] + [Flags] + public enum ValueAttribute { + NONE, + IS_NULL, + CAN_BE_NULL, + IS_DEFAULT, + CAN_BE_DEFAULT, + IS_UNCHANGED, + DATA_NON_VALID, + HAS_VALUE_ORIG, + NO_MODIF, + READ_ONLY + } + [CCode (cheader_filename = "libgda/libgda.h", cprefix = "GDA_XA_TRANSACTION_", has_type_id = false)] + public enum XaTransactionError { + ALREADY_REGISTERED_ERROR, + DTP_NOT_SUPPORTED_ERROR, + CONNECTION_BRANCH_LENGTH_ERROR + } + [CCode (cheader_filename = "libgda/libgda.h", cprefix = "GDA_XA_", has_type_id = false)] + public enum XaType { + START, + END, + PREPARE, + COMMIT, + ROLLBACK, + RECOVER + } + [CCode (cheader_filename = "libgda/libgda.h", cprefix = "GDA_DATA_MODEL_", has_type_id = false)] + public errordomain DataModelError { + ROW_OUT_OF_RANGE_ERROR, + COLUMN_OUT_OF_RANGE_ERROR, + VALUES_LIST_ERROR, + VALUE_TYPE_ERROR, + ROW_NOT_FOUND_ERROR, + ACCESS_ERROR, + FEATURE_NON_SUPPORTED_ERROR, + FILE_EXIST_ERROR, + XML_FORMAT_ERROR, + TRUNCATED_ERROR, + INVALID, + OTHER_ERROR; + [Version (replacement = "DataModel.error_quark")] + public static GLib.Quark quark (); + } + [CCode (cheader_filename = "libgda/libgda.h", cprefix = "GDA_DDL_MODIFIABLE_", has_type_id = false)] + public errordomain DdlModifiableError { + NOT_IMPLEMENTED, + CONNECTION_NOT_OPENED, + MISSED_DATA; + [Version (replacement = "DdlModifiable.error_quark")] + public static GLib.Quark quark (); + } + [CCode (cheader_filename = "libgda/libgda.h", cprefix = "GDA_PROVIDER_META_", has_type_id = false)] + public errordomain ProviderMetaError { + NO_CONNECTION_ERROR, + QUERY_ERROR; + [Version (replacement = "ProviderMeta.error_quark")] + public static GLib.Quark quark (); + } + [CCode (cheader_filename = "libgda/libgda.h", cprefix = "GDA_SQL_", has_type_id = false)] + public errordomain SqlError { + STRUCTURE_CONTENTS_ERROR, + MALFORMED_IDENTIFIER_ERROR, + MISSING_IDENTIFIER_ERROR, + VALIDATION_ERROR; + public static GLib.Quark quark (); + } + [CCode (cheader_filename = "libgda/libgda.h", cprefix = "GDA_WORKER_", has_type_id = false)] + public errordomain WorkerError { + INTER_THREAD_ERROR, + JOB_NOT_FOUND_ERROR, + JOB_QUEUED_ERROR, + JOB_BEING_PROCESSED_ERROR, + JOB_PROCESSED_ERROR, + JOB_CANCELLED_ERROR, + THREAD_KILLED; + [Version (replacement = "Worker.error_quark")] + public static GLib.Quark quark (); + } + [CCode (cheader_filename = "libgda/libgda.h", has_target = false)] + public delegate void ConnectionOpenFunc (Gda.Connection cnc, uint job_id, bool result, GLib.Error error, void* data); + [CCode (cheader_filename = "libgda/libgda.h", has_target = false)] + public delegate bool SqlForeachFunc (Gda.SqlAnyPart part, void* data) throws GLib.Error; + [CCode (cheader_filename = "libgda/libgda.h", has_target = false)] + public delegate bool SqlReservedKeywordsFunc (string word); + [CCode (cheader_filename = "libgda/libgda.h", has_target = false)] + public delegate Gda.TreeNode TreeManagerNodeFunc (Gda.TreeManager manager, Gda.TreeNode? parent, string? name); + [CCode (cheader_filename = "libgda/libgda.h", has_target = false)] + public delegate GLib.SList TreeManagerNodesFunc (Gda.TreeManager manager, Gda.TreeNode? node, GLib.SList children_nodes, out bool out_error) throws GLib.Error; + [CCode (cheader_filename = "libgda/libgda.h", instance_pos = 4.9)] + public delegate void WorkerCallback (Gda.Worker worker, uint job_id, void* result_data, GLib.Error error); + [CCode (cheader_filename = "libgda/libgda.h", instance_pos = 0.9)] + public delegate void* WorkerFunc () throws GLib.Error; + [CCode (cheader_filename = "libgda/libgda.h", cname = "GDA_ATTRIBUTE_AUTO_INCREMENT")] + public const string ATTRIBUTE_AUTO_INCREMENT; + [CCode (cheader_filename = "libgda/libgda.h", cname = "GDA_ATTRIBUTE_DESCRIPTION")] + public const string ATTRIBUTE_DESCRIPTION; + [CCode (cheader_filename = "libgda/libgda.h", cname = "GDA_ATTRIBUTE_IS_DEFAULT")] + public const string ATTRIBUTE_IS_DEFAULT; + [CCode (cheader_filename = "libgda/libgda.h", cname = "GDA_ATTRIBUTE_NAME")] + public const string ATTRIBUTE_NAME; + [CCode (cheader_filename = "libgda/libgda.h", cname = "GDA_ATTRIBUTE_NUMERIC_PRECISION")] + public const string ATTRIBUTE_NUMERIC_PRECISION; + [CCode (cheader_filename = "libgda/libgda.h", cname = "GDA_ATTRIBUTE_NUMERIC_SCALE")] + public const string ATTRIBUTE_NUMERIC_SCALE; + [CCode (cheader_filename = "libgda/libgda.h", cname = "GDA_ATTRIBUTE_TREE_NODE_UNKNOWN_CHILDREN")] + public const string ATTRIBUTE_TREE_NODE_UNKNOWN_CHILDREN; + [CCode (cheader_filename = "libgda/libgda.h", cname = "GDA_EXTRA_AUTO_INCREMENT")] + public const string EXTRA_AUTO_INCREMENT; + [CCode (cheader_filename = "libgda/libgda.h", cname = "GDA_SQLSTATE_GENERAL_ERROR")] + public const string SQLSTATE_GENERAL_ERROR; + [CCode (cheader_filename = "libgda/libgda.h", cname = "GDA_SQLSTATE_NO_ERROR")] + public const string SQLSTATE_NO_ERROR; + [CCode (cheader_filename = "libgda/libgda.h", cname = "GDA_TIMEZONE_INVALID")] + public const int TIMEZONE_INVALID; + [CCode (cheader_filename = "libgda/libgda.h")] + public static string? alphanum_to_text (string text); + [CCode (array_length = false, array_null_terminated = true, cheader_filename = "libgda/libgda.h")] + public static string[]? completion_list_get (Gda.Connection cnc, string sql, int start, int end); + [CCode (cheader_filename = "libgda/libgda.h")] + public static bool compute_dml_statements (Gda.Connection cnc, Gda.Statement select_stmt, bool require_pk, out Gda.Statement? insert_stmt, out Gda.Statement? update_stmt, out Gda.Statement? delete_stmt) throws GLib.Error; + [CCode (cheader_filename = "libgda/libgda.h")] + public static Gda.SqlStatement? compute_select_statement_from_update (Gda.Statement update_stmt) throws GLib.Error; + [CCode (cheader_filename = "libgda/libgda.h")] + public static Gda.SqlExpr? compute_unique_table_row_condition (Gda.SqlStatementSelect stsel, Gda.MetaTable mtable, bool require_pk) throws GLib.Error; + [CCode (cheader_filename = "libgda/libgda.h")] + [Version (since = "4.0.3")] + public static Gda.SqlExpr? compute_unique_table_row_condition_with_cnc (Gda.Connection? cnc, Gda.SqlStatementSelect stsel, Gda.MetaTable mtable, bool require_pk) throws GLib.Error; + [CCode (cheader_filename = "libgda/libgda.h")] + [Version (replacement = "DataHandler.get_default", since = "4.2.3")] + public static Gda.DataHandler data_handler_get_default (GLib.Type for_type); + [CCode (cheader_filename = "libgda/libgda.h")] + public static GLib.DateTime date_time_copy (GLib.DateTime ts); + [CCode (cheader_filename = "libgda/libgda.h")] + [Version (replacement = "Default.escape_string")] + public static string? default_escape_string (string string); + [CCode (cheader_filename = "libgda/libgda.h")] + [Version (replacement = "Default.unescape_string")] + public static string? default_unescape_string (string string); + [CCode (cheader_filename = "libgda/libgda.h")] + public static void dsn_split (string string, string out_dsn, string out_username, string out_password); + [CCode (cheader_filename = "libgda/libgda.h")] + public static GLib.Type g_type_from_string (string str); + [CCode (cheader_filename = "libgda/libgda.h")] + public static unowned string g_type_to_string (GLib.Type type); + [CCode (cheader_filename = "libgda/libgda.h")] + public static bool identifier_equal (string id1, string id2); + [CCode (cheader_filename = "libgda/libgda.h")] + public static uint identifier_hash (string id); + [CCode (cheader_filename = "libgda/libgda.h")] + public static void log_disable (); + [CCode (cheader_filename = "libgda/libgda.h")] + public static void log_enable (); + [CCode (cheader_filename = "libgda/libgda.h")] + public static bool log_is_enabled (); + [CCode (cheader_filename = "libgda/libgda.h")] + [Version (since = "5.2")] + public static bool parse_formatted_date (GLib.Date gdate, string value, GLib.DateDMY first, GLib.DateDMY second, GLib.DateDMY third, char sep); + [CCode (cheader_filename = "libgda/libgda.h")] + [Version (since = "6.0")] + public static Gda.Time parse_formatted_time (string value, char sep); + [CCode (cheader_filename = "libgda/libgda.h")] + [Version (since = "5.2")] + public static GLib.DateTime? parse_formatted_timestamp (string value, GLib.DateDMY first, GLib.DateDMY second, GLib.DateDMY third, char sep); + [CCode (cheader_filename = "libgda/libgda.h")] + public static bool parse_iso8601_date (GLib.Date gdate, string value); + [CCode (cheader_filename = "libgda/libgda.h")] + public static Gda.Time parse_iso8601_time (string value); + [CCode (cheader_filename = "libgda/libgda.h")] + [Version (since = "4.2.9")] + public static Gda.SqlStatement? rewrite_sql_statement_for_null_parameters (owned Gda.SqlStatement sqlst, Gda.Set @params, out bool out_modified) throws GLib.Error; + [CCode (cheader_filename = "libgda/libgda.h")] + [Version (since = "4.2.9")] + public static bool rewrite_statement_for_null_parameters (Gda.Statement stmt, Gda.Set @params, out Gda.Statement? out_stmt) throws GLib.Error; + [CCode (cheader_filename = "libgda/libgda.h")] + public static bool rfc1738_decode (string string); + [CCode (cheader_filename = "libgda/libgda.h")] + public static string? rfc1738_encode (string string); + [CCode (cheader_filename = "libgda/libgda.h")] + public static Gda.Statement select_alter_select_for_empty (Gda.Statement stmt) throws GLib.Error; + [CCode (cheader_filename = "libgda/libgda.h")] + [Version (since = "5.0")] + public static string sql_identifier_force_quotes (string str); + [CCode (cheader_filename = "libgda/libgda.h")] + [Version (since = "5.0")] + public static string sql_identifier_prepare_for_compare (string str); + [CCode (cheader_filename = "libgda/libgda.h")] + [Version (since = "4.0.3")] + public static string? sql_identifier_quote (string id, Gda.Connection? cnc, Gda.ServerProvider? prov, bool meta_store_convention, bool force_quotes); + [CCode (array_length = false, array_null_terminated = true, cheader_filename = "libgda/libgda.h")] + public static string[]? sql_identifier_split (string id); + [CCode (cheader_filename = "libgda/libgda.h")] + [Version (replacement = "SqlOperation.operator_from_string")] + public static Gda.SqlOperatorType sql_operation_operator_from_string (string op); + [CCode (cheader_filename = "libgda/libgda.h")] + [Version (replacement = "SqlOperation.operator_to_string")] + public static unowned string sql_operation_operator_to_string (Gda.SqlOperatorType op); + [CCode (cheader_filename = "libgda/libgda.h")] + [Version (replacement = "SqlStatement.string_to_type")] + public static Gda.SqlStatementType sql_statement_string_to_type (string type); + [CCode (cheader_filename = "libgda/libgda.h")] + public static string sql_value_stringify (GLib.Value value); + [CCode (cheader_filename = "libgda/libgda.h")] + public static Gda.Binary string_to_binary (string? str); + [CCode (cheader_filename = "libgda/libgda.h")] + public static Gda.Blob string_to_blob (string str); + [CCode (cheader_filename = "libgda/libgda.h")] + [Version (replacement = "Text.to_alphanum")] + public static string text_to_alphanum (string text); + [CCode (cheader_filename = "libgda/libgda.h")] + [Version (since = "4.2.6")] + public static bool utility_check_data_model_v (Gda.DataModel model, [CCode (array_length_cname = "nbcols", array_length_pos = 1.5)] GLib.Type[] types); + [CCode (cheader_filename = "libgda/libgda.h")] + public static bool utility_data_model_dump_data_to_xml (Gda.DataModel model, [CCode (type = "xmlNodePtr")] Xml.Node* parent, [CCode (array_length_cname = "nb_cols", array_length_pos = 3.5)] int[]? cols, [CCode (array_length_cname = "nb_rows", array_length_pos = 4.5)] int[]? rows, bool use_col_ids); + [CCode (cheader_filename = "libgda/libgda.h")] + public static unowned string? utility_data_model_find_column_description (Gda.DataSelect model, string field_name); + [CCode (cheader_filename = "libgda/libgda.h")] + public static bool utility_holder_load_attributes (Gda.Holder holder, [CCode (type = "xmlNodePtr")] Xml.Node* node, GLib.SList? sources) throws GLib.Error; + [CCode (cheader_filename = "libgda/libgda.h")] + public static int value_compare (GLib.Value value1, GLib.Value value2); + [CCode (cheader_filename = "libgda/libgda.h")] + public static GLib.Value? value_copy (GLib.Value value); + [CCode (cheader_filename = "libgda/libgda.h")] + public static int value_differ (GLib.Value value1, GLib.Value value2); + [CCode (cheader_filename = "libgda/libgda.h")] + public static void value_free (owned GLib.Value? value); + [CCode (cheader_filename = "libgda/libgda.h")] + public static unowned Gda.Binary value_get_binary (GLib.Value value); + [CCode (cheader_filename = "libgda/libgda.h")] + public static unowned Gda.Blob value_get_blob (GLib.Value value); + [CCode (cheader_filename = "libgda/libgda.h")] + public static unowned Gda.GeometricPoint value_get_geometric_point (GLib.Value value); + [CCode (cheader_filename = "libgda/libgda.h")] + public static unowned Gda.MetaStoreChange value_get_meta_store_change (GLib.Value value); + [CCode (cheader_filename = "libgda/libgda.h")] + public static unowned Gda.Numeric value_get_numeric (GLib.Value value); + [CCode (cheader_filename = "libgda/libgda.h")] + public static short value_get_short (GLib.Value value); + [CCode (cheader_filename = "libgda/libgda.h")] + public static unowned Gda.Time value_get_time (GLib.Value value); + [CCode (cheader_filename = "libgda/libgda.h")] + public static ushort value_get_ushort (GLib.Value value); + [CCode (cheader_filename = "libgda/libgda.h")] + public static bool value_is_null (GLib.Value value); + [CCode (cheader_filename = "libgda/libgda.h")] + public static bool value_is_number (GLib.Value value); + [CCode (cheader_filename = "libgda/libgda.h")] + public static GLib.Value? value_new (GLib.Type type); + [CCode (cheader_filename = "libgda/libgda.h")] + public static GLib.Value? value_new_binary (owned uint8 val, long size); + [CCode (cheader_filename = "libgda/libgda.h")] + public static GLib.Value? value_new_blob (uint8 val, long size); + [CCode (cheader_filename = "libgda/libgda.h")] + public static GLib.Value? value_new_blob_from_file (string filename); + [CCode (cheader_filename = "libgda/libgda.h")] + public static GLib.Value? value_new_date_time_from_timet (long val); + [CCode (cheader_filename = "libgda/libgda.h")] + [Version (since = "4.2.9")] + public static GLib.Value? value_new_default (string? default_val); + [CCode (cheader_filename = "libgda/libgda.h")] + public static GLib.Value? value_new_from_string (string as_string, GLib.Type type); + [CCode (cheader_filename = "libgda/libgda.h")] + public static GLib.Value? value_new_from_xml ([CCode (type = "const xmlNodePtr")] Xml.Node node); + [CCode (cheader_filename = "libgda/libgda.h")] + public static GLib.Value? value_new_null (); + [CCode (cheader_filename = "libgda/libgda.h")] + [Version (since = "6.0")] + public static GLib.Value? value_new_time_from_timet (long val); + [CCode (cheader_filename = "libgda/libgda.h")] + public static void value_reset_with_type (GLib.Value value, GLib.Type type); + [CCode (cheader_filename = "libgda/libgda.h")] + public static void value_set_binary (GLib.Value value, Gda.Binary binary); + [CCode (cheader_filename = "libgda/libgda.h")] + public static void value_set_blob (GLib.Value value, Gda.Blob blob); + [CCode (cheader_filename = "libgda/libgda.h")] + public static bool value_set_from_string (GLib.Value value, string as_string, GLib.Type type); + [CCode (cheader_filename = "libgda/libgda.h")] + public static bool value_set_from_value (GLib.Value value, GLib.Value from); + [CCode (cheader_filename = "libgda/libgda.h")] + public static void value_set_geometric_point (GLib.Value value, Gda.GeometricPoint val); + [CCode (cheader_filename = "libgda/libgda.h")] + public static void value_set_meta_store_change (GLib.Value value, Gda.MetaStoreChange change); + [CCode (cheader_filename = "libgda/libgda.h")] + public static void value_set_null (GLib.Value value); + [CCode (cheader_filename = "libgda/libgda.h")] + public static void value_set_numeric (GLib.Value value, Gda.Numeric val); + [CCode (cheader_filename = "libgda/libgda.h")] + public static void value_set_short (GLib.Value value, short val); + [CCode (cheader_filename = "libgda/libgda.h")] + public static void value_set_time (GLib.Value value, Gda.Time val); + [CCode (cheader_filename = "libgda/libgda.h")] + public static void value_set_ushort (GLib.Value value, ushort val); + [CCode (cheader_filename = "libgda/libgda.h")] + public static string value_stringify (GLib.Value value); + [CCode (cheader_filename = "libgda/libgda.h")] + public static void value_take_binary (GLib.Value value, owned Gda.Binary binary); + [CCode (cheader_filename = "libgda/libgda.h")] + public static void value_take_blob (GLib.Value value, owned Gda.Blob blob); + [CCode (cheader_filename = "libgda/libgda.h")] + public static string value_to_xml_string (GLib.Value value); + [CCode (cheader_filename = "libgda/libgda.h")] + [Version (replacement = "Worker.new_unique")] + public static Gda.Worker worker_new_unique (Gda.Worker location, bool allow_destroy); +} diff --git a/.flatpak-builder/cache/objects/dd/acade9df9d12e80523e1bbb526cf50aaf775ae4fc1bdcffc09b33946bc4d1f.file b/.flatpak-builder/cache/objects/dd/acade9df9d12e80523e1bbb526cf50aaf775ae4fc1bdcffc09b33946bc4d1f.file new file mode 100644 index 0000000..449a3cd Binary files /dev/null and b/.flatpak-builder/cache/objects/dd/acade9df9d12e80523e1bbb526cf50aaf775ae4fc1bdcffc09b33946bc4d1f.file differ diff --git a/.flatpak-builder/cache/objects/dd/b6210b6dc8faf7a1fb3cebe09fec645b7cf3a2dcaeaeb0a5d669b1cd5b5ef8.file b/.flatpak-builder/cache/objects/dd/b6210b6dc8faf7a1fb3cebe09fec645b7cf3a2dcaeaeb0a5d669b1cd5b5ef8.file new file mode 100644 index 0000000..3baf9d7 --- /dev/null +++ b/.flatpak-builder/cache/objects/dd/b6210b6dc8faf7a1fb3cebe09fec645b7cf3a2dcaeaeb0a5d669b1cd5b5ef8.file @@ -0,0 +1,264 @@ +/* + * Copyright (C) 2008 - 2011 Vivien Malerba + * Copyright (C) 2009 Bas Driessen + * Copyright (C) 2010 Murray Cumming + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include +#include +#include +#include +#include + +G_DEFINE_BOXED_TYPE(GdaSqlParamSpec, gda_sql_param_spec, gda_sql_param_spec_copy, gda_sql_param_spec_free) + +/** + * gda_sql_param_spec_take_name: + * @pspec: a #GdaSqlParamSpec pointer + * @value: (transfer full): a G_TYPE_STRING #GValue + * + * Sets @pspec's name. @value's ownership is transferred to + * @pspec (which means @pspec is then responsible for freeing it when no longer needed). + */ +void +gda_sql_param_spec_take_name (GdaSqlParamSpec *pspec, GValue *value) +{ + if (pspec->name) { + g_free (pspec->name); + pspec->name = NULL; + } + if (value) { + pspec->name = _remove_quotes (g_value_dup_string (value)); + gda_value_free (value); + } +} + +/** + * gda_sql_param_spec_take_descr: + * @pspec: a #GdaSqlParamSpec pointer + * @value: (transfer full): a G_TYPE_STRING #GValue + * + * Sets @pspec's description. @value's ownership is transferred to + * @pspec (which means @pspec is then responsible for freeing it when no longer needed). + */ +void +gda_sql_param_spec_take_descr (GdaSqlParamSpec *pspec, GValue *value) +{ + if (pspec->descr) { + g_free (pspec->descr); + pspec->descr = NULL; + } + if (value) { + pspec->descr = _remove_quotes (g_value_dup_string (value)); + gda_value_free (value); + } +} + +/** + * gda_sql_param_spec_take_nullok: + * @pspec: a #GdaSqlParamSpec pointer + * @value: (transfer full): a G_TYPE_STRING #GValue. + * + * Sets @pspec's ability of being NULL. @value's ownership is transferred to + * @pspec (which means @pspec is then responsible for freeing it when no longer needed). + * + * If @value's string starts by 't' or 'T' then @pspec will be allowed to be %NULL + */ +void +gda_sql_param_spec_take_nullok (GdaSqlParamSpec *pspec, GValue *value) +{ + pspec->nullok = FALSE; + if (value) { + gchar *str = (gchar *) g_value_get_string (value); + if (str) { + _remove_quotes (str); + if ((*str == 't') || (*str == 'T')) + pspec->nullok = TRUE; + } + gda_value_free (value); + } +} + +/** + * gda_sql_param_spec_take_type: + * @pspec: a #GdaSqlParamSpec pointer + * @value: (transfer full): a G_TYPE_STRING #GValue + * + * Sets @pspec's data type. @value's ownership is transferred to + * @pspec (which means @pspec is then responsible for freeing it when no longer needed). + * + * @value must represent a data type, as understood by gda_g_type_from_string(). + */ +void +gda_sql_param_spec_take_type (GdaSqlParamSpec *pspec, GValue *value) +{ + pspec->g_type = GDA_TYPE_NULL; + if (value) { + gchar *tmp; + tmp = _remove_quotes (g_value_dup_string (value)); + gda_value_free (value); + + pspec->g_type = gda_g_type_from_string (tmp); + g_free (tmp); + if (pspec->g_type == G_TYPE_INVALID) + pspec->g_type = GDA_TYPE_NULL; + } +} + +/** + * gda_sql_param_spec_new: + * @simple_spec: (transfer full): a G_TYPE_STRING #GValue + * + * @value must contain a string representing a variable, see the documentation associated to the + * #GdaSqlParser object. + * + * @value is destroyed by this function. + * + * Returns: (transfer full): a new #GdaSqlParamSpec + */ +GdaSqlParamSpec * +gda_sql_param_spec_new (GValue *simple_spec) +{ + GdaSqlParamSpec *pspec; + + pspec =g_new0 (GdaSqlParamSpec, 1); + pspec->is_param = TRUE; + pspec->nullok = FALSE; + pspec->g_type = GDA_TYPE_NULL; + + if (simple_spec) { + gchar *str = (gchar *) g_value_get_string (simple_spec); + gchar *ptr; + gint part; /* 0 for name, 1 for type and 2 for NULL */ + ptr = str; + for (part = 0; *ptr && (part < 3); part++) { + gchar old; + for (; *ptr && ((*ptr != ':') || (*(ptr+1) != ':')); ptr++); + old = *ptr; + *ptr = 0; + switch (part) { + case 0: + g_free (pspec->name); + pspec->name = g_strdup (str); + break; + case 1: + pspec->g_type = gda_g_type_from_string (str); + if (pspec->g_type == G_TYPE_INVALID) + pspec->g_type = GDA_TYPE_NULL; + break; + case 2: + pspec->nullok = (*str == 'n') || (*str == 'N') ? TRUE : FALSE; + break; + } + *ptr = old; + if (*ptr) { + ptr +=2; + str = ptr; + } + } + gda_value_free (simple_spec); + } + + return pspec; +} + +/** + * gda_sql_param_spec_copy: + * @pspec: #GdaSqlParamSpec pointer + * + * Creates a copy of @pspec. + * + * Returns: a new #GdaSqlParamSpec + */ +GdaSqlParamSpec * +gda_sql_param_spec_copy (GdaSqlParamSpec *pspec) +{ + GdaSqlParamSpec *copy; + if (!pspec) return NULL; + + copy = g_new0 (GdaSqlParamSpec, 1); + if (pspec->name) + copy->name = g_strdup (pspec->name); + if (pspec->descr) + copy->descr = g_strdup (pspec->descr); + copy->g_type = pspec->g_type; + copy->is_param = pspec->is_param; + copy->nullok = pspec->nullok; + + return copy; +} + +/** + * gda_sql_param_spec_free: + * @pspec: #GdaSqlParamSpec pointer + * + * Destroys @pspec. + */ +void +gda_sql_param_spec_free (GdaSqlParamSpec *pspec) +{ + if (!pspec) return; + + g_free (pspec->name); + g_free (pspec->descr); + g_free (pspec); +} + +/** + * gda_sql_param_spec_serialize: + * @pspec: a #GdaSqlParamSpec pointer + * + * Creates a new string representing @pspec. + * + * Returns: a new string. + */ +gchar * +gda_sql_param_spec_serialize (GdaSqlParamSpec *pspec) +{ + GString *string; + gchar *str; + + if (!pspec) + return NULL; + + string = g_string_new ("{"); + str = _json_quote_string (pspec->name); + g_string_append_printf (string, "\"name\":%s", str); + g_free (str); + + + str = _json_quote_string (pspec->descr); + g_string_append_printf (string, ",\"descr\":%s", str); + g_free (str); + + if (pspec->g_type != GDA_TYPE_NULL) { + str = _json_quote_string (gda_g_type_to_string (pspec->g_type)); + g_string_append_printf (string, ",\"type\":%s", str); + g_free (str); + } + else + g_string_append_printf (string, ",\"type\":null"); + + g_string_append_printf (string, ",\"is_param\":%s", pspec->is_param ? "true" : "false"); + g_string_append_printf (string, ",\"nullok\":%s", pspec->nullok ? "true" : "false"); + g_string_append_c (string, '}'); + str = string->str; + g_string_free (string, FALSE); + return str; +} + diff --git a/.flatpak-builder/cache/objects/dd/d6cc4a320d779036ff6f1760b85a74462b8e3812221a7193b71d7dd0d8f20b.dirtree b/.flatpak-builder/cache/objects/dd/d6cc4a320d779036ff6f1760b85a74462b8e3812221a7193b71d7dd0d8f20b.dirtree new file mode 100644 index 0000000..96de6bc Binary files /dev/null and b/.flatpak-builder/cache/objects/dd/d6cc4a320d779036ff6f1760b85a74462b8e3812221a7193b71d7dd0d8f20b.dirtree differ diff --git a/.flatpak-builder/cache/objects/de/0d92bbe830c733d833e69646e6b77c3d5504d953103895534286ec079d680b.file b/.flatpak-builder/cache/objects/de/0d92bbe830c733d833e69646e6b77c3d5504d953103895534286ec079d680b.file new file mode 100644 index 0000000..9bd302d Binary files /dev/null and b/.flatpak-builder/cache/objects/de/0d92bbe830c733d833e69646e6b77c3d5504d953103895534286ec079d680b.file differ diff --git a/.flatpak-builder/cache/objects/de/24492d992ce4aa9b8b693149c7f51706405d405204e075ae1c22fc1a09ff94.dirtree b/.flatpak-builder/cache/objects/de/24492d992ce4aa9b8b693149c7f51706405d405204e075ae1c22fc1a09ff94.dirtree new file mode 100644 index 0000000..5df76e6 Binary files /dev/null and b/.flatpak-builder/cache/objects/de/24492d992ce4aa9b8b693149c7f51706405d405204e075ae1c22fc1a09ff94.dirtree differ diff --git a/.flatpak-builder/cache/objects/de/91b9fa1123031fa62884dffa25153d15831e9445cd9afb921ba92a15278e9c.file b/.flatpak-builder/cache/objects/de/91b9fa1123031fa62884dffa25153d15831e9445cd9afb921ba92a15278e9c.file new file mode 100644 index 0000000..9065bc2 --- /dev/null +++ b/.flatpak-builder/cache/objects/de/91b9fa1123031fa62884dffa25153d15831e9445cd9afb921ba92a15278e9c.file @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2008 - 2011 Vivien Malerba + * Copyright (C) 2009 Murray Cumming + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef _GDA_STATEMENT_STRUCT_TRANS_H_ +#define _GDA_STATEMENT_STRUCT_TRANS_H_ + +#include +#include +#include +#include +#include + +G_BEGIN_DECLS + +/* + * Structure definition + */ +/** + * GdaSqlStatementTransaction: + * @any: inheritance structure + * @isolation_level: isolation level as a #GdaTransactionIsolation + * @trans_mode: transaction mode (DEFERRED, IMMEDIATE, EXCLUSIVE, READ_WRITE, READ_ONLY) + * @trans_name: transaction name + * + * The statement is a transaction management related statement (BEGIN, ROLLBACK, etc). The #GdaSqlStatementTransaction structure + * does not hold enough information to reconstruct the complete SQL statement (some information may be missing) - the aim of this + * structure is to identify a minimum set of information in the transaction statement. Note that the complete SQL which created the + * statement should be available in the #GdaSqlStatement structure which encapsulates this structure. + */ +struct _GdaSqlStatementTransaction { + GdaSqlAnyPart any; + GdaTransactionIsolation isolation_level; + gchar *trans_mode; /* DEFERRED, IMMEDIATE, EXCLUSIVE, READ_WRITE, READ_ONLY */ + gchar *trans_name; + + /*< private >*/ + /* Padding for future expansion */ + gpointer _gda_reserved1; + gpointer _gda_reserved2; +}; + +/* + * Common operations + */ +GdaSqlStatementContentsInfo *_gda_sql_statement_begin_get_infos (void); +GdaSqlStatementContentsInfo *_gda_sql_statement_commit_get_infos (void); +GdaSqlStatementContentsInfo *_gda_sql_statement_rollback_get_infos (void); + +GdaSqlStatementContentsInfo *_gda_sql_statement_savepoint_get_infos (void); +GdaSqlStatementContentsInfo *_gda_sql_statement_rollback_savepoint_get_infos (void); +GdaSqlStatementContentsInfo *_gda_sql_statement_delete_savepoint_get_infos (void); + +/* + * Functions used by the parser + */ +void gda_sql_statement_trans_take_mode (GdaSqlStatement *stmt, GValue *value); +void gda_sql_statement_trans_set_isol_level (GdaSqlStatement *stmt, GdaTransactionIsolation level); +void gda_sql_statement_trans_take_name (GdaSqlStatement *stmt, GValue *value); + +G_END_DECLS + +#endif diff --git a/.flatpak-builder/cache/objects/df/131a07185c08203c923a2d31986d14c35c6257c65c9ed609bd4b3bd5cbf078.dirtree b/.flatpak-builder/cache/objects/df/131a07185c08203c923a2d31986d14c35c6257c65c9ed609bd4b3bd5cbf078.dirtree new file mode 100644 index 0000000..d7d0444 Binary files /dev/null and b/.flatpak-builder/cache/objects/df/131a07185c08203c923a2d31986d14c35c6257c65c9ed609bd4b3bd5cbf078.dirtree differ diff --git a/.flatpak-builder/cache/objects/df/e0f2a40aa1c1241e894a3c38ccd57713b5c5b67f38ec3c5fbd871bcf3a9567.dirtree b/.flatpak-builder/cache/objects/df/e0f2a40aa1c1241e894a3c38ccd57713b5c5b67f38ec3c5fbd871bcf3a9567.dirtree new file mode 100644 index 0000000..7a7b0df Binary files /dev/null and b/.flatpak-builder/cache/objects/df/e0f2a40aa1c1241e894a3c38ccd57713b5c5b67f38ec3c5fbd871bcf3a9567.dirtree differ diff --git a/.flatpak-builder/cache/objects/df/e2607a5862b9b669bd1b810866b1b54c271ef488c9c84ca1d3e0d99b479cb0.dirtree b/.flatpak-builder/cache/objects/df/e2607a5862b9b669bd1b810866b1b54c271ef488c9c84ca1d3e0d99b479cb0.dirtree new file mode 100644 index 0000000..1b1d561 Binary files /dev/null and b/.flatpak-builder/cache/objects/df/e2607a5862b9b669bd1b810866b1b54c271ef488c9c84ca1d3e0d99b479cb0.dirtree differ diff --git a/.flatpak-builder/cache/objects/e0/3a496d02967db654f4fed72440febb805b3e33a4ad82ade85a6eddf54f8e0c.file b/.flatpak-builder/cache/objects/e0/3a496d02967db654f4fed72440febb805b3e33a4ad82ade85a6eddf54f8e0c.file new file mode 100644 index 0000000..0fba7f7 --- /dev/null +++ b/.flatpak-builder/cache/objects/e0/3a496d02967db654f4fed72440febb805b3e33a4ad82ade85a6eddf54f8e0c.file @@ -0,0 +1,223 @@ +/* + * Copyright (C) 2008 Murray Cumming + * Copyright (C) 2008 - 2013 Vivien Malerba + * Copyright (C) 2012 - 2013 Daniel Espinosa + * Copyright (C) 2013 Carl-Anton Ingmarsson + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GDA_META_STORE_H_ +#define __GDA_META_STORE_H_ + +#include +#include +#include +#include +#include + +G_BEGIN_DECLS + +#define GDA_TYPE_META_STORE (gda_meta_store_get_type()) +G_DECLARE_DERIVABLE_TYPE(GdaMetaStore, gda_meta_store, GDA, META_STORE, GObject) + +/* error reporting */ +extern GQuark gda_meta_store_error_quark (void); +#define GDA_META_STORE_ERROR gda_meta_store_error_quark () + +typedef enum { + GDA_META_STORE_INCORRECT_SCHEMA_ERROR, + GDA_META_STORE_UNSUPPORTED_PROVIDER_ERROR, + GDA_META_STORE_INTERNAL_ERROR, + GDA_META_STORE_META_CONTEXT_ERROR, + GDA_META_STORE_MODIFY_CONTENTS_ERROR, + GDA_META_STORE_EXTRACT_SQL_ERROR, + GDA_META_STORE_ATTRIBUTE_NOT_FOUND_ERROR, + GDA_META_STORE_ATTRIBUTE_ERROR, + GDA_META_STORE_SCHEMA_OBJECT_NOT_FOUND_ERROR, + GDA_META_STORE_SCHEMA_OBJECT_CONFLICT_ERROR, + GDA_META_STORE_SCHEMA_OBJECT_DESCR_ERROR, + GDA_META_STORE_TRANSACTION_ALREADY_STARTED_ERROR +} GdaMetaStoreError; + +/* + * tracking changes in the meta database + */ +typedef enum { + GDA_META_STORE_ADD, + GDA_META_STORE_REMOVE, + GDA_META_STORE_MODIFY +} GdaMetaStoreChangeType; + +/** + * GdaMetaStoreChange: (ref-func gda_meta_store_change_new) (unref-func gda_meta_store_change_free) (get-value-func gda_value_get_meta_store_change) (set-value-func gda_value_set_meta_store_change) + */ +typedef struct _GdaMetaStoreChange GdaMetaStoreChange; + +#define GDA_TYPE_META_STORE_CHANGE (gda_meta_store_change_get_type ()) + +GType gda_meta_store_change_get_type (void) G_GNUC_CONST; +GdaMetaStoreChange* gda_meta_store_change_new (void); +void gda_meta_store_change_set_change_type (GdaMetaStoreChange *change, GdaMetaStoreChangeType ctype); +GdaMetaStoreChangeType gda_meta_store_change_get_change_type (GdaMetaStoreChange *change); +void gda_meta_store_change_set_table_name (GdaMetaStoreChange *change, const gchar *table_name); +gchar* gda_meta_store_change_get_table_name (GdaMetaStoreChange *change); +GHashTable* gda_meta_store_change_get_keys (GdaMetaStoreChange *change); +GdaMetaStoreChange* gda_meta_store_change_copy (GdaMetaStoreChange *src); +void gda_meta_store_change_free (GdaMetaStoreChange *change); +void gda_value_set_meta_store_change (GValue *value, GdaMetaStoreChange *change); +GdaMetaStoreChange* gda_value_get_meta_store_change (GValue *value); + + +/* Pointer type for GdaMetaContext */ +#define GDA_TYPE_META_CONTEXT (gda_meta_context_get_type()) + +/** + * GdaMetaContext: + * @table_name: the name of the table in the GdaMetaStore's internal database + * @size: the size of the @column_names and @column_values arrays + * @column_names: (array length=size) (transfer container): an array of column names (columns of the @table_name table) + * @column_values: (array length=size) (transfer container): an array of values, one for each column named in @column_names + * @columns: (element-type utf8 GObject.Value): A #GHashTable storing columns' name as key and #GValue as column's + * value. + * + * The GdaMetaContext represents a meta data modification + * context: the how when used with gda_meta_store_modify_with_context(), + * and the what when used with gda_connection_update_meta_store(). + * + * To create a new #GdaMetaContext use #gda_meta_context_new. + * + * To add a new column/value pair use #gda_meta_context_add_column. + * + * To free a #GdaMetaContext, created by #gda_meta_context_new, use #gda_attributes_manager_free. + * + * Since 5.2, you must consider this struct as opaque. Any access to its internal must use public API. + * Don't try to use #gda_meta_context_free on a struct that was created manually. + */ +typedef struct { + gchar *table_name; + gint size; + gchar **column_names; + GValue **column_values; + GHashTable *columns;/* Added since 5.2 */ +} GdaMetaContext; + +/* struct for the object's class */ +struct _GdaMetaStoreClass +{ + GObjectClass parent_class; + + /* signals the changes */ + void (*meta_reset) (GdaMetaStore *store); + GError *(*suggest_update)(GdaMetaStore *store, GdaMetaContext *suggest); + void (*meta_changed) (GdaMetaStore *store, GSList *changes); + + /*< private >*/ + /* Padding for future expansion */ + void (*_gda_reserved1) (void); + void (*_gda_reserved2) (void); + void (*_gda_reserved3) (void); + void (*_gda_reserved4) (void); +}; + +/** + * SECTION:gda-meta-store + * @short_description: Dictionary object + * @title: GdaMetaStore + * @stability: Stable + * @see_also: #GdaMetaStruct + * + * Previous versions of &LIBGDA; relied on an XML based file to store dictionary information, such as + * the database's schema (tables, views, etc) and various other information. The problems were that it was + * difficult for an application to integrate its own data into the dictionary and that there were some + * performances problems as the XML file needed to be parsed (and converted into its own in-memory structure) + * before any data could be read out of it. + * + * The new dictionary now relies on a database structure to store its data (see the + * database schema section for a detailed description). The actual database can be a + * single file (using an SQLite database), an entirely in memory database (also using an SQLite database), or + * a more conventional backend such as a PostgreSQL database for a shared dictionary on a server. + * + * The #GdaMetaStore object is thread safe. + */ + +GdaMetaStore *gda_meta_store_new_with_file (const gchar *file_name); +GdaMetaStore *gda_meta_store_new (const gchar *cnc_string); +gint gda_meta_store_get_version (GdaMetaStore *store); + +GdaConnection *gda_meta_store_get_internal_connection (GdaMetaStore *store); +gchar *gda_meta_store_sql_identifier_quote (const gchar *id, GdaConnection *cnc); +GdaDataModel *gda_meta_store_extract (GdaMetaStore *store, const gchar *select_sql, GError **error, ...); +GdaDataModel *gda_meta_store_extract_v (GdaMetaStore *store, const gchar *select_sql, GHashTable *vars, + GError **error); +gboolean gda_meta_store_modify (GdaMetaStore *store, const gchar *table_name, + GdaDataModel *new_data, const gchar *condition, GError **error, ...); +gboolean gda_meta_store_modify_v (GdaMetaStore *store, const gchar *table_name, + GdaDataModel *new_data, const gchar *condition, + gint nvalues, const gchar **value_names, + const GValue **values, GError **error); +gboolean gda_meta_store_modify_with_context (GdaMetaStore *store, GdaMetaContext *context, + GdaDataModel *new_data, GError **error); +GdaDataModel *gda_meta_store_create_modify_data_model (GdaMetaStore *store, const gchar *table_name); + +void gda_meta_store_set_identifiers_style (GdaMetaStore *store, GdaSqlIdentifierStyle style); +void gda_meta_store_set_reserved_keywords_func(GdaMetaStore *store, GdaSqlReservedKeywordsFunc func); + +gboolean gda_meta_store_get_attribute_value (GdaMetaStore *store, const gchar *att_name, + gchar **att_value, GError **error); +gboolean gda_meta_store_set_attribute_value (GdaMetaStore *store, const gchar *att_name, + const gchar *att_value, GError **error); + +gboolean gda_meta_store_schema_add_custom_object (GdaMetaStore *store, const gchar *xml_description, + GError **error); +gboolean gda_meta_store_schema_remove_custom_object (GdaMetaStore *store, const gchar *obj_name, GError **error); + +GSList *gda_meta_store_schema_get_all_tables (GdaMetaStore *store); +GSList *gda_meta_store_schema_get_depend_tables (GdaMetaStore *store, const gchar *table_name); +GdaMetaStruct *gda_meta_store_schema_get_structure (GdaMetaStore *store, GError **error); +GdaMetaStruct *gda_meta_store_create_struct (GdaMetaStore *store, GdaMetaStructFeature features); + +gboolean gda_meta_store_declare_foreign_key (GdaMetaStore *store, GdaMetaStruct *mstruct, + const gchar *fk_name, + const gchar *catalog, const gchar *schema, const gchar *table, + const gchar *ref_catalog, const gchar *ref_schema, const gchar *ref_table, + guint nb_cols, + gchar **colnames, gchar **ref_colnames, + GError **error); + +gboolean gda_meta_store_undeclare_foreign_key (GdaMetaStore *store, GdaMetaStruct *mstruct, + const gchar *fk_name, + const gchar *catalog, const gchar *schema, const gchar *table, + const gchar *ref_catalog, const gchar *ref_schema, const gchar *ref_table, + GError **error); + +GType gda_meta_context_get_type (void) G_GNUC_CONST; +GdaMetaContext* gda_meta_context_new (void); +GdaMetaContext* gda_meta_context_copy (GdaMetaContext *ctx); + +void gda_meta_context_set_table (GdaMetaContext *ctx, const gchar *table); +const gchar* gda_meta_context_get_table (GdaMetaContext *ctx); +void gda_meta_context_set_column (GdaMetaContext *ctx, const gchar* column, + const GValue* value, GdaConnection *cnc); +void gda_meta_context_set_columns (GdaMetaContext *ctx, GHashTable *columns, + GdaConnection *cnc); +void gda_meta_context_free (GdaMetaContext *ctx); +gchar *gda_meta_context_stringify (GdaMetaContext *ctx); +gint gda_meta_context_get_n_columns (GdaMetaContext *ctx); + +G_END_DECLS + +#endif diff --git a/.flatpak-builder/cache/objects/e0/620aa2cf41249b4eb10305b36184511e3e344660719941a0c64131760302a6.file b/.flatpak-builder/cache/objects/e0/620aa2cf41249b4eb10305b36184511e3e344660719941a0c64131760302a6.file new file mode 120000 index 0000000..1004683 --- /dev/null +++ b/.flatpak-builder/cache/objects/e0/620aa2cf41249b4eb10305b36184511e3e344660719941a0c64131760302a6.file @@ -0,0 +1 @@ +../../share/runtime/locale/hr/share/hr \ No newline at end of file diff --git a/.flatpak-builder/cache/objects/e1/cdab7b5c46613d967a6fd0e5df3042ea400c9a4c5737942cc3ac6a0b87e064.dirtree b/.flatpak-builder/cache/objects/e1/cdab7b5c46613d967a6fd0e5df3042ea400c9a4c5737942cc3ac6a0b87e064.dirtree new file mode 100644 index 0000000..23f31d3 Binary files /dev/null and b/.flatpak-builder/cache/objects/e1/cdab7b5c46613d967a6fd0e5df3042ea400c9a4c5737942cc3ac6a0b87e064.dirtree differ diff --git a/.flatpak-builder/cache/objects/e1/f9391d4efa0c1093d0c6c70e725bec18705bf27c24ab202b8982808455a7a9.file b/.flatpak-builder/cache/objects/e1/f9391d4efa0c1093d0c6c70e725bec18705bf27c24ab202b8982808455a7a9.file new file mode 100644 index 0000000..898a5aa --- /dev/null +++ b/.flatpak-builder/cache/objects/e1/f9391d4efa0c1093d0c6c70e725bec18705bf27c24ab202b8982808455a7a9.file @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2007 - 2012 Vivien Malerba + * Copyright (C) 2018 Daniel Espinosa + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GDA_DIR_BLOB_OP_H__ +#define __GDA_DIR_BLOB_OP_H__ + +#ifndef __GDA_INTERNAL__ +#error Do not include this file directly +#endif + +#include +#include + +G_BEGIN_DECLS + + +/* error reporting */ +extern GQuark gda_dir_blob_op_error_quark (void); +#define GDA_DIR_BLOB_OP_ERROR gda_dir_blob_op_error_quark () + +typedef enum { + GDA_DIR_BLOB_OP_GENERAL_ERROR +} GdaDirBlobOpError; + + +#define GDA_TYPE_DIR_BLOB_OP (gda_dir_blob_op_get_type()) +G_DECLARE_DERIVABLE_TYPE(GdaDirBlobOp, gda_dir_blob_op, GDA, DIR_BLOB_OP, GdaBlobOp) + +struct _GdaDirBlobOpClass { + GdaBlobOpClass parent_class; +}; + +GdaBlobOp *_gda_dir_blob_op_new (const gchar *complete_filename); +void _gda_dir_blob_set_filename (GdaDirBlobOp *blob, const gchar *complete_filename); +const gchar *_gda_dir_blob_get_filename (GdaDirBlobOp *blob); + +G_END_DECLS + +#endif + diff --git a/.flatpak-builder/cache/objects/e2/a018e0a9c1dd26b6d63b638456e902ffe10d13a91aecbfc447c9db655d0fbf.file b/.flatpak-builder/cache/objects/e2/a018e0a9c1dd26b6d63b638456e902ffe10d13a91aecbfc447c9db655d0fbf.file new file mode 100644 index 0000000..31cf786 --- /dev/null +++ b/.flatpak-builder/cache/objects/e2/a018e0a9c1dd26b6d63b638456e902ffe10d13a91aecbfc447c9db655d0fbf.file @@ -0,0 +1,879 @@ +/* + * Copyright (C) 2001 Cleber Rodrigues + * Copyright (C) 2001 - 2005 Rodrigo Moya + * Copyright (C) 2002 Gonzalo Paniagua Javier + * Copyright (C) 2003 Laurent Sansonetti + * Copyright (C) 2004 Szalai Ferenc + * Copyright (C) 2005 Bas Driessen + * Copyright (C) 2005 - 2015 Vivien Malerba + * Copyright (C) 2005 Álvaro Peña + * Copyright (C) 2006 - 2008 Murray Cumming + * Copyright (C) 2008 Phil Longstaff + * Copyright (C) 2008 Przemysław Grzegorczyk + * Copyright (C) 2010 David King + * Copyright (C) 2010 Jonh Wendell + * Copyright (C) 2011,2019 Daniel Espinosa + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +#define G_LOG_DOMAIN "GDA-data-model-array" + +#include +#include +#include +#include +#include +#include +#include + +enum { + PROP_0, + PROP_READ_ONLY, + PROP_N_COLUMNS +}; + +static void gda_data_model_array_class_init (GdaDataModelArrayClass *klass); +static void gda_data_model_array_init (GdaDataModelArray *model); +static void gda_data_model_array_finalize (GObject *object); +static void gda_data_model_array_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec); +static void gda_data_model_array_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec); + +/* GdaDataModel interface */ +static void gda_data_model_array_data_model_init (GdaDataModelInterface *iface); +static gint gda_data_model_array_get_n_rows (GdaDataModel *model); +static gint gda_data_model_array_get_n_columns (GdaDataModel *model); +static GdaColumn *gda_data_model_array_describe_column (GdaDataModel *model, gint col); +static const GValue *gda_data_model_array_get_value_at (GdaDataModel *model, gint col, gint row, GError **error); +static GdaValueAttribute gda_data_model_array_get_attributes_at (GdaDataModel *model, gint col, gint row); +static GdaDataModelAccessFlags gda_data_model_array_get_access_flags(GdaDataModel *model); + +static gboolean gda_data_model_array_set_value_at (GdaDataModel *model, gint col, gint row, + const GValue *value, GError **error); +static gboolean gda_data_model_array_set_values (GdaDataModel *model, gint row, + GList *values, GError **error); +static gint gda_data_model_array_append_values (GdaDataModel *model, const GList *values, GError **error); +static gint gda_data_model_array_append_row (GdaDataModel *model, GError **error); +static gboolean gda_data_model_array_remove_row (GdaDataModel *model, gint row, GError **error); + +static void gda_data_model_array_freeze (GdaDataModel *model); +static void gda_data_model_array_thaw (GdaDataModel *model); +static gboolean gda_data_model_array_get_notify (GdaDataModel *model); + +/* + * GdaDataModelArray class implementation + */ + +typedef struct { + gboolean notify_changes; + GHashTable *column_spec; + + gboolean read_only; + + /* number of columns in each row */ + gint number_of_columns; + + /* the array of rows, each item is a GdaRow */ + GPtrArray *rows; +} GdaDataModelArrayPrivate; + +G_DEFINE_TYPE_WITH_CODE (GdaDataModelArray, gda_data_model_array,G_TYPE_OBJECT, + G_ADD_PRIVATE (GdaDataModelArray) + G_IMPLEMENT_INTERFACE(GDA_TYPE_DATA_MODEL,gda_data_model_array_data_model_init)) + +static void +gda_data_model_array_data_model_init (GdaDataModelInterface *iface) +{ + iface->get_n_rows = gda_data_model_array_get_n_rows; + iface->get_n_columns = gda_data_model_array_get_n_columns; + iface->describe_column = gda_data_model_array_describe_column; + iface->get_access_flags = gda_data_model_array_get_access_flags; + iface->get_value_at = gda_data_model_array_get_value_at; + iface->get_attributes_at = gda_data_model_array_get_attributes_at; + + iface->create_iter = NULL; + + iface->set_value_at = gda_data_model_array_set_value_at; + iface->set_values = gda_data_model_array_set_values; + iface->append_values = gda_data_model_array_append_values; + iface->append_row = gda_data_model_array_append_row; + iface->remove_row = gda_data_model_array_remove_row; + iface->find_row = NULL; + + iface->freeze = gda_data_model_array_freeze; + iface->thaw = gda_data_model_array_thaw; + iface->get_notify = gda_data_model_array_get_notify; + iface->send_hint = NULL; +} + +static void +gda_data_model_array_class_init (GdaDataModelArrayClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->finalize = gda_data_model_array_finalize; + object_class->set_property = gda_data_model_array_set_property; + object_class->get_property = gda_data_model_array_get_property; + + g_object_class_install_property (object_class, + PROP_N_COLUMNS, + g_param_spec_uint ("n-columns", + "Number of columns", + "The number of columns in the model", + 0, + G_MAXUINT, + 0, + G_PARAM_READWRITE)); + g_object_class_install_property (object_class, PROP_READ_ONLY, + g_param_spec_boolean ("read-only", NULL, + _("Whether data model can be modified"), + FALSE, + G_PARAM_READABLE | G_PARAM_WRITABLE)); +} + +static void +gda_data_model_array_init (GdaDataModelArray *model) +{ + g_return_if_fail (GDA_IS_DATA_MODEL_ARRAY (model)); + GdaDataModelArrayPrivate *priv = gda_data_model_array_get_instance_private (model); + + /* allocate internal structure */ + priv->notify_changes = TRUE; + priv->column_spec = g_hash_table_new_full (g_int_hash, g_int_equal, g_free, NULL); + priv->read_only = FALSE; + priv->number_of_columns = 0; + priv->rows = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); +} + +static void column_g_type_changed_cb (GdaColumn *column, GType old, GType new, GdaDataModelArray *model); + +static void +hash_free_column (G_GNUC_UNUSED gpointer key, GdaColumn *column, GdaDataModelArray *model) +{ + g_signal_handlers_disconnect_by_func (G_OBJECT (column), + G_CALLBACK (column_g_type_changed_cb), model); + g_object_unref (column); +} + +static void +gda_data_model_array_finalize (GObject *object) +{ + GdaDataModelArray *model = (GdaDataModelArray *) object; + GdaDataModelArrayPrivate *priv = gda_data_model_array_get_instance_private (model); + + g_return_if_fail (GDA_IS_DATA_MODEL_ARRAY (model)); + + /* free memory */ + gda_data_model_freeze (GDA_DATA_MODEL(model)); + gda_data_model_array_clear (model); + g_ptr_array_free (priv->rows, TRUE); + g_hash_table_foreach (priv->column_spec, (GHFunc) hash_free_column, model); + g_hash_table_destroy (priv->column_spec); + priv->column_spec = NULL; + + /* chain to parent class */ + G_OBJECT_CLASS (gda_data_model_array_parent_class)->finalize (object); +} + +static void +gda_data_model_array_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) +{ + GdaDataModelArray *model; + + g_return_if_fail (GDA_IS_DATA_MODEL_ARRAY (object)); + model = GDA_DATA_MODEL_ARRAY (object); + GdaDataModelArrayPrivate *priv = gda_data_model_array_get_instance_private (model); + + switch (prop_id) { + case PROP_READ_ONLY: + priv->read_only = g_value_get_boolean (value); + break; + case PROP_N_COLUMNS: + gda_data_model_array_set_n_columns (model, g_value_get_uint (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gda_data_model_array_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) +{ + GdaDataModelArray *model; + + g_return_if_fail (GDA_IS_DATA_MODEL_ARRAY (object)); + model = GDA_DATA_MODEL_ARRAY (object); + GdaDataModelArrayPrivate *priv = gda_data_model_array_get_instance_private (model); + + switch (prop_id) { + case PROP_READ_ONLY: + g_value_set_boolean (value, priv->read_only); + break; + case PROP_N_COLUMNS: + g_value_set_uint (value, priv->number_of_columns); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + + + +/** + * gda_data_model_array_new: + * @cols: number of columns for rows in this data model. + * + * Creates a new #GdaDataModel object without initializing the column + * types. Using gda_data_model_array_new_with_g_types() is usually better. + * + * Returns: (transfer full): a pointer to the newly created #GdaDataModel. + */ +GdaDataModel * +gda_data_model_array_new (gint cols) +{ + GdaDataModel *model; + + model = g_object_new (GDA_TYPE_DATA_MODEL_ARRAY, "n-columns", cols, NULL); + return model; +} + +/** + * gda_data_model_array_new_with_g_types: + * @cols: number of columns for rows in this data model. + * @...: types of the columns of the model to create as #GType, as many as indicated by @cols + * + * Creates a new #GdaDataModel object with the column types as + * specified. + * + * Returns: (transfer full): a pointer to the newly created #GdaDataModel. + */ +GdaDataModel * +gda_data_model_array_new_with_g_types (gint cols, ...) +{ + GdaDataModel *model; + va_list args; + gint i; + + model = gda_data_model_array_new (cols); + va_start (args, cols); + i = 0; + while (i < cols) { + GType argtype; + + argtype = va_arg (args, GType); + + gda_column_set_g_type (gda_data_model_describe_column (model, i), + argtype); + i++; + } + va_end (args); + return model; +} + +/** + * gda_data_model_array_new_with_g_types_v: (rename-to gda_data_model_array_new_with_g_types) + * @cols: number of columns for rows in this data model. + * @types: (array): array of types of the columns of the model to create as #GType, as many as indicated by @cols + * + * Creates a new #GdaDataModel object with the column types as + * specified. + * + * Returns: (transfer full): a pointer to the newly created #GdaDataModel. + * + * Since: 4.2.6 + */ +GdaDataModel * +gda_data_model_array_new_with_g_types_v (gint cols, GType *types) +{ + GdaDataModel *model; + gint i; + + model = gda_data_model_array_new (cols); + i = 0; + while (i < cols) { + GType type = types [i]; + gda_column_set_g_type (gda_data_model_describe_column (model, i), type); + i++; + } + return model; +} + +/** + * gda_data_model_array_copy_model: + * @src: a #GdaDataModel to copy data from + * @error: a place to store errors, or %NULL + * + * Makes a copy of @src into a new #GdaDataModelArray object + * + * Returns: (transfer full) (nullable): a new data model, or %NULL if an error occurred + */ +GdaDataModelArray * +gda_data_model_array_copy_model (GdaDataModel *src, GError **error) +{ + GdaDataModel *model; + gint nbfields, i; + + g_return_val_if_fail (GDA_IS_DATA_MODEL (src), NULL); + + nbfields = gda_data_model_get_n_columns (src); + model = gda_data_model_array_new (nbfields); + + if (g_object_get_data (G_OBJECT (src), "name")) + g_object_set_data_full (G_OBJECT (model), "name", g_strdup (g_object_get_data (G_OBJECT (src), "name")), g_free); + if (g_object_get_data (G_OBJECT (src), "descr")) + g_object_set_data_full (G_OBJECT (model), "descr", g_strdup (g_object_get_data (G_OBJECT (src), "descr")), g_free); + for (i = 0; i < nbfields; i++) { + GdaColumn *copycol, *srccol; + gchar *colid; + + srccol = gda_data_model_describe_column (src, i); + copycol = gda_data_model_describe_column (model, i); + + g_object_get (G_OBJECT (srccol), "id", &colid, NULL); + g_object_set (G_OBJECT (copycol), "id", colid, NULL); + g_free (colid); + gda_column_set_description (copycol, gda_column_get_description (srccol)); + gda_column_set_name (copycol, gda_column_get_name (srccol)); + gda_column_set_dbms_type (copycol, gda_column_get_dbms_type (srccol)); + gda_column_set_g_type (copycol, gda_column_get_g_type (srccol)); + gda_column_set_position (copycol, gda_column_get_position (srccol)); + gda_column_set_allow_null (copycol, gda_column_get_allow_null (srccol)); + } + + if (! gda_data_model_import_from_model (model, src, FALSE, NULL, error)) { + g_object_unref (model); + model = NULL; + } + /*else + gda_data_model_dump (model, stdout);*/ + + return (GdaDataModelArray*) model; +} + +/** + * gda_data_model_array_copy_model_ext: + * @src: a #GdaDataModel to copy data from + * @ncols: size of @cols + * @cols: (array length=ncols): array of @src's columns to copy into the new array, not %NULL + * @error: a place to store errors, or %NULL + * + * Like gda_data_model_array_copy_model(), makes a copy of @src, but copies only some + * columns. + * + * Returns: (transfer full) (nullable): a new data model, or %NULL if an error occurred + * + * Since: 5.2.0 + */ +GdaDataModelArray * +gda_data_model_array_copy_model_ext (GdaDataModel *src, gint ncols, gint *cols, GError **error) +{ + GdaDataModel *model; + gint nbfields, i; + + g_return_val_if_fail (GDA_IS_DATA_MODEL (src), NULL); + g_return_val_if_fail (cols, NULL); + g_return_val_if_fail (ncols > 0, NULL); + + /* check columns' validity */ + nbfields = gda_data_model_get_n_columns (src); + for (i = 0; i < ncols; i++) { + if ((cols[i] < 0) || (cols[i] >= nbfields)) { + g_set_error (error, GDA_DATA_MODEL_ERROR, + GDA_DATA_MODEL_COLUMN_OUT_OF_RANGE_ERROR, + _("Column %d out of range (0-%d)"), cols[i], nbfields - 1); + return NULL; + } + } + + /* initialize new model */ + model = gda_data_model_array_new (ncols); + if (g_object_get_data (G_OBJECT (src), "name")) + g_object_set_data_full (G_OBJECT (model), "name", g_strdup (g_object_get_data (G_OBJECT (src), "name")), g_free); + if (g_object_get_data (G_OBJECT (src), "descr")) + g_object_set_data_full (G_OBJECT (model), "descr", g_strdup (g_object_get_data (G_OBJECT (src), "descr")), g_free); + + + /* map new columns */ + GHashTable *hash; + hash = g_hash_table_new_full (g_int_hash, g_int_equal, g_free, NULL); + for (i = 0; i < ncols; i++) { + gint *ptr; + ptr = g_new (gint, 1); + *ptr = i; + g_hash_table_insert (hash, ptr, GINT_TO_POINTER (cols[i])); + + GdaColumn *copycol, *srccol; + gchar *colid; + + srccol = gda_data_model_describe_column (src, cols[i]); + copycol = gda_data_model_describe_column (model, i); + + g_object_get (G_OBJECT (srccol), "id", &colid, NULL); + g_object_set (G_OBJECT (copycol), "id", colid, NULL); + g_free (colid); + gda_column_set_description (copycol, gda_column_get_description (srccol)); + gda_column_set_name (copycol, gda_column_get_name (srccol)); + gda_column_set_dbms_type (copycol, gda_column_get_dbms_type (srccol)); + gda_column_set_g_type (copycol, gda_column_get_g_type (srccol)); + gda_column_set_position (copycol, gda_column_get_position (srccol)); + gda_column_set_allow_null (copycol, gda_column_get_allow_null (srccol)); + } + + if (! gda_data_model_import_from_model (model, src, FALSE, hash, error)) { + g_hash_table_destroy (hash); + g_object_unref (model); + model = NULL; + } + /*else + gda_data_model_dump (model, stdout);*/ + + g_hash_table_destroy (hash); + return (GdaDataModelArray*) model; +} + +/** + * gda_data_model_array_get_row: + * @model: a #GdaDataModelArray object + * @row: row number (starting from 0) + * @error: a place to store errors, or %NULL + * + * Get a pointer to a row in @model + * + * Returns: (transfer none): the #GdaRow, or %NULL if an error occurred + */ +GdaRow * +gda_data_model_array_get_row (GdaDataModelArray *model, gint row, GError **error) +{ + g_return_val_if_fail (GDA_IS_DATA_MODEL_ARRAY (model), NULL); + g_return_val_if_fail (row >= 0, NULL); + GdaDataModelArrayPrivate *priv = gda_data_model_array_get_instance_private (model); + + if ((guint)row >= priv->rows->len) { + if (priv->rows->len > 0) + g_set_error (error, GDA_DATA_MODEL_ERROR, GDA_DATA_MODEL_ROW_OUT_OF_RANGE_ERROR, + _("Row %d out of range (0-%d)"), row, + priv->rows->len - 1); + else + g_set_error (error, GDA_DATA_MODEL_ERROR, GDA_DATA_MODEL_ROW_OUT_OF_RANGE_ERROR, + _("Row %d not found (empty data model)"), row); + return NULL; + } + + return g_ptr_array_index (priv->rows, row); +} + +/** + * gda_data_model_array_set_n_columns: + * @model: the #GdaDataModelArray. + * @cols: number of columns for rows this data model should use. + * + * Sets the number of columns for rows inserted in this model. + * @cols must be greated than or equal to 0. + * + * Also clears @model's contents. + */ +void +gda_data_model_array_set_n_columns (GdaDataModelArray *model, gint cols) +{ + g_return_if_fail (GDA_IS_DATA_MODEL_ARRAY (model)); + GdaDataModelArrayPrivate *priv = gda_data_model_array_get_instance_private (model); + + gda_data_model_array_clear (model); + priv->number_of_columns = cols; + + g_object_notify (G_OBJECT (model), "n-columns"); +} + +/** + * gda_data_model_array_clear: + * @model: the model to clear. + * + * Frees all the rows in @model. + */ +void +gda_data_model_array_clear (GdaDataModelArray *model) +{ + g_return_if_fail (GDA_IS_DATA_MODEL_ARRAY (model)); + GdaDataModelArrayPrivate *priv = gda_data_model_array_get_instance_private (model); + + while (priv->rows->len > 0) + gda_data_model_array_remove_row ((GdaDataModel*) model, 0, NULL); +} + + +/* + * GdaDataModel interface + */ +static gint +gda_data_model_array_get_n_rows (GdaDataModel *model) +{ + g_return_val_if_fail (GDA_IS_DATA_MODEL_ARRAY (model), -1); + GdaDataModelArrayPrivate *priv = gda_data_model_array_get_instance_private (GDA_DATA_MODEL_ARRAY (model)); + return priv->rows->len; +} + +static gint +gda_data_model_array_get_n_columns (GdaDataModel *model) +{ + g_return_val_if_fail (GDA_IS_DATA_MODEL_ARRAY (model), -1); + GdaDataModelArrayPrivate *priv = gda_data_model_array_get_instance_private (GDA_DATA_MODEL_ARRAY (model)); + return priv->number_of_columns; +} + +static GdaColumn * +gda_data_model_array_describe_column (GdaDataModel *model, gint col) +{ + GdaColumn *column; + GdaDataModelArrayPrivate *priv = gda_data_model_array_get_instance_private (GDA_DATA_MODEL_ARRAY (model)); + + if (col >= gda_data_model_get_n_columns (model)) { + g_warning ("Column %d out of range (0-%d)", col, gda_data_model_get_n_columns (model) - 1); + return NULL; + } + + gint tmp; + tmp = col; + column = g_hash_table_lookup (priv->column_spec, &tmp); + if (!column) { + column = gda_column_new (); + g_signal_connect (G_OBJECT (column), "g-type-changed", + G_CALLBACK (column_g_type_changed_cb), model); + gda_column_set_position (column, col); + + gint *ptr; + ptr = g_new (gint, 1); + *ptr = col; + g_hash_table_insert (priv->column_spec, ptr, column); + } + + return column; +} + +static void +column_g_type_changed_cb (GdaColumn *column, G_GNUC_UNUSED GType old, GType new, GdaDataModelArray *model) +{ + /* emit a warning if there are GValues which are not compatible with the new type */ + gint i, nrows, col; + const GValue *value; + gchar *str; + gint nb_warnings = 0; + const gint max_warnings = 5; + GdaDataModelArrayPrivate *priv = gda_data_model_array_get_instance_private (model); + + if ((new == G_TYPE_INVALID) || (new == GDA_TYPE_NULL)) + return; + + col = gda_column_get_position (column); + nrows = priv->rows->len; + for (i = 0; (i < nrows) && (nb_warnings < max_warnings); i++) { + GType vtype; + + value = gda_data_model_get_value_at ((GdaDataModel *) model, col, i, NULL); + if (!value) + continue; + + vtype = G_VALUE_TYPE ((GValue *) value); + if ((vtype != GDA_TYPE_NULL) && (vtype != new)) { + nb_warnings ++; + if (nb_warnings < max_warnings) { + if (nb_warnings == max_warnings) + g_warning ("Max number of warning reached, " + "more incompatible types..."); + else { + str = gda_value_stringify ((GValue *) value); + g_warning ("Value of type %s not compatible with new" + " column type %s (value=%s)", + gda_g_type_to_string (G_VALUE_TYPE ((GValue *) value)), + gda_g_type_to_string (new), str); + g_free (str); + } + } + } + } +} + +static const GValue * +gda_data_model_array_get_value_at (GdaDataModel *model, gint col, gint row, GError **error) +{ + GdaRow *fields; + GdaDataModelArray *amodel = (GdaDataModelArray*) model; + GdaDataModelArrayPrivate *priv = gda_data_model_array_get_instance_private (amodel); + + g_return_val_if_fail(row >= 0, NULL); + + if (priv->rows->len == 0) { + g_set_error (error, GDA_DATA_MODEL_ERROR, GDA_DATA_MODEL_ROW_NOT_FOUND_ERROR, + "%s", _("No row in data model")); + return NULL; + } + + if ((guint)row >= priv->rows->len) { + if (priv->rows->len > 0) + g_set_error (error, GDA_DATA_MODEL_ERROR, GDA_DATA_MODEL_ROW_OUT_OF_RANGE_ERROR, + _("Row %d out of range (0-%d)"), row, priv->rows->len - 1); + else + g_set_error (error, GDA_DATA_MODEL_ERROR, GDA_DATA_MODEL_ROW_OUT_OF_RANGE_ERROR, + _("Row %d not found (empty data model)"), row); + return NULL; + } + + if (col >= priv->number_of_columns) { + g_set_error (error, GDA_DATA_MODEL_ERROR, GDA_DATA_MODEL_COLUMN_OUT_OF_RANGE_ERROR, + _("Column %d out of range (0-%d)"), col, priv->number_of_columns - 1); + return NULL; + } + + fields = g_ptr_array_index (priv->rows, row); + if (fields) { + GValue *field; + + field = gda_row_get_value (fields, col); + if (gda_row_value_is_valid (fields, field)) + return (const GValue *) field; + else + return NULL; + } + else { + g_set_error (error, GDA_DATA_MODEL_ERROR, GDA_DATA_MODEL_ROW_NOT_FOUND_ERROR, + "%s", _("Data model has no data")); + return NULL; + } +} + +static GdaValueAttribute +gda_data_model_array_get_attributes_at (GdaDataModel *model, gint col, gint row) +{ + const GValue *gdavalue; + GdaValueAttribute flags = 0; + GdaColumn *column; + GdaDataModelArrayPrivate *priv = gda_data_model_array_get_instance_private (GDA_DATA_MODEL_ARRAY (model)); + + column = gda_data_model_array_describe_column (model, col); + if (gda_column_get_allow_null (column)) + flags |= GDA_VALUE_ATTR_CAN_BE_NULL; + if (gda_column_get_default_value (column)) + flags |= GDA_VALUE_ATTR_CAN_BE_DEFAULT; + + if (row >= 0) { + gdavalue = gda_data_model_get_value_at (model, col, row, NULL); + if (!gdavalue || gda_value_is_null ((GValue *) gdavalue)) + flags |= GDA_VALUE_ATTR_IS_NULL; + } + + if (priv->read_only) + flags |= GDA_VALUE_ATTR_NO_MODIF; + + return flags; +} + + +static GdaDataModelAccessFlags +gda_data_model_array_get_access_flags (GdaDataModel *model) +{ + GdaDataModelArrayPrivate *priv = gda_data_model_array_get_instance_private (GDA_DATA_MODEL_ARRAY (model)); + GdaDataModelAccessFlags flags = GDA_DATA_MODEL_ACCESS_RANDOM | + GDA_DATA_MODEL_ACCESS_CURSOR_FORWARD | + GDA_DATA_MODEL_ACCESS_CURSOR_BACKWARD; + + if (!priv->read_only) + flags |= GDA_DATA_MODEL_ACCESS_WRITE; + + return flags; +} + +static gboolean +gda_data_model_array_set_value_at (GdaDataModel *model, gint col, gint row, + const GValue *value, GError **error) +{ + GdaRow *gdarow; + GdaDataModelArray *amodel = (GdaDataModelArray*) model; + GdaDataModelArrayPrivate *priv = gda_data_model_array_get_instance_private (amodel); + + g_return_val_if_fail (row >= 0, FALSE); + + if (priv->read_only) { + g_set_error (error, GDA_DATA_MODEL_ERROR, GDA_DATA_MODEL_ACCESS_ERROR, + "%s", _("Attempting to modify a read-only data model")); + return FALSE; + } + + if ((guint)row > priv->rows->len) { + if (priv->rows->len > 0) + g_set_error (error, GDA_DATA_MODEL_ERROR, GDA_DATA_MODEL_VALUES_LIST_ERROR, + _("Row %d out of range (0-%d)"), row, priv->rows->len - 1); + else + g_set_error (error, GDA_DATA_MODEL_ERROR, GDA_DATA_MODEL_ROW_OUT_OF_RANGE_ERROR, + _("Row %d not found (empty data model)"), row); + return FALSE; + } + + gdarow = gda_data_model_array_get_row ((GdaDataModelArray *) model, row, error); + if (gdarow) { + GValue *dest; + dest = gda_row_get_value (gdarow, col); + if (value) { + gda_value_reset_with_type (dest, G_VALUE_TYPE ((GValue *) value)); + gda_value_set_from_value (dest, value); + } + else + gda_value_set_null (dest); + gda_data_model_row_updated ((GdaDataModel *) model, row); + return TRUE; + } + else + return FALSE; +} + +static gboolean +gda_data_model_array_set_values (GdaDataModel *model, gint row, GList *values, GError **error) +{ + GdaRow *gdarow; + GdaDataModelArray *amodel = (GdaDataModelArray*) model; + GdaDataModelArrayPrivate *priv = gda_data_model_array_get_instance_private (amodel); + + g_return_val_if_fail (row >= 0, FALSE); + + if (!values) + return TRUE; + + if (priv->read_only) { + g_set_error (error, GDA_DATA_MODEL_ERROR, GDA_DATA_MODEL_ACCESS_ERROR, + "%s", _("Attempting to modify a read-only data model")); + return FALSE; + } + + if (g_list_length (values) > (guint)gda_data_model_get_n_columns (model)) { + g_set_error (error, GDA_DATA_MODEL_ERROR, GDA_DATA_MODEL_VALUES_LIST_ERROR, + "%s", _("Too many values in list")); + return FALSE; + } + + gdarow = gda_data_model_array_get_row (amodel, row, error); + if (gdarow) { + GList *list; + gint col; + for (list = values, col = 0; list; list = list->next, col++) { + GValue *dest; + dest = gda_row_get_value (gdarow, col); + if (list->data) { + gda_value_reset_with_type (dest, G_VALUE_TYPE ((GValue *) list->data)); + gda_value_set_from_value (dest, (GValue *) list->data); + } + } + gda_data_model_row_updated (model, row); + return TRUE; + } + + return FALSE; +} + +static gint +gda_data_model_array_append_values (GdaDataModel *model, const GList *values, GError **error) +{ + GdaRow *row; + const GList *list; + gint i; + GdaDataModelArray *amodel = (GdaDataModelArray *) model; + GdaDataModelArrayPrivate *priv = gda_data_model_array_get_instance_private (amodel); + + if (priv->read_only) { + g_set_error (error, GDA_DATA_MODEL_ERROR, GDA_DATA_MODEL_ACCESS_ERROR, + "%s", _("Attempting to modify a read-only data model")); + return FALSE; + } + + if (g_list_length ((GList *) values) > (guint)priv->number_of_columns) { + g_set_error (error, GDA_DATA_MODEL_ERROR, GDA_DATA_MODEL_VALUES_LIST_ERROR, + "%s", _("Too many values in list")); + return FALSE; + } + + row = gda_row_new (priv->number_of_columns); + for (i = 0, list = values; list; i++, list = list->next) { + GValue *dest; + dest = gda_row_get_value (row, i); + if (list->data) { + gda_value_reset_with_type (dest, G_VALUE_TYPE ((GValue *) list->data)); + g_assert (gda_value_set_from_value (dest, (GValue *) list->data)); + } + else + gda_value_set_null (dest); + } + + g_ptr_array_insert (priv->rows, -1, row); + gda_data_model_row_inserted (model, priv->rows->len - 1); + return priv->rows->len - 1; +} + +static gint +gda_data_model_array_append_row (GdaDataModel *model, GError **error) +{ + GdaRow *row; + GdaDataModelArray *amodel = (GdaDataModelArray *) model; + GdaDataModelArrayPrivate *priv = gda_data_model_array_get_instance_private (amodel); + + if (priv->read_only) { + g_set_error (error, GDA_DATA_MODEL_ERROR, GDA_DATA_MODEL_ACCESS_ERROR, + "%s", _("Attempting to modify a read-only data model")); + return FALSE; + } + + row = gda_row_new (priv->number_of_columns); + g_ptr_array_insert (priv->rows, -1, row); + gda_data_model_row_inserted (model, priv->rows->len - 1); + return priv->rows->len - 1; +} + +static gboolean +gda_data_model_array_remove_row (GdaDataModel *model, gint row, GError **error) +{ + GdaRow *gdarow; + GdaDataModelArray *amodel = (GdaDataModelArray *) model; + GdaDataModelArrayPrivate *priv = gda_data_model_array_get_instance_private (amodel); + + gdarow = g_ptr_array_index (priv->rows, row); + if (gdarow) { + g_ptr_array_remove_index (priv->rows, row); + gda_data_model_row_removed ((GdaDataModel *) model, row); + return TRUE; + } + + g_set_error (error, GDA_DATA_MODEL_ERROR, GDA_DATA_MODEL_ROW_NOT_FOUND_ERROR, + "%s", _("Row not found in data model")); + return FALSE; +} + +static void +gda_data_model_array_freeze (GdaDataModel *model) +{ + GdaDataModelArrayPrivate *priv = gda_data_model_array_get_instance_private (GDA_DATA_MODEL_ARRAY (model)); + priv->notify_changes = FALSE; +} + +static void +gda_data_model_array_thaw (GdaDataModel *model) +{ + GdaDataModelArrayPrivate *priv = gda_data_model_array_get_instance_private (GDA_DATA_MODEL_ARRAY (model)); + priv->notify_changes = TRUE; +} + +static gboolean +gda_data_model_array_get_notify (GdaDataModel *model) +{ + GdaDataModelArrayPrivate *priv = gda_data_model_array_get_instance_private (GDA_DATA_MODEL_ARRAY (model)); + return priv->notify_changes; +} diff --git a/.flatpak-builder/cache/objects/e2/d2b1ab10828ba4b5f89e5420fba05179f70667095d6828139158b9732792b3.file b/.flatpak-builder/cache/objects/e2/d2b1ab10828ba4b5f89e5420fba05179f70667095d6828139158b9732792b3.file new file mode 100644 index 0000000..d04e97f --- /dev/null +++ b/.flatpak-builder/cache/objects/e2/d2b1ab10828ba4b5f89e5420fba05179f70667095d6828139158b9732792b3.file @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2000 Reinhard Müller + * Copyright (C) 2000 - 2002 Rodrigo Moya + * Copyright (C) 2001 - 2002 Carlos Perelló Marín + * Copyright (C) 2001 - 2014 Vivien Malerba + * Copyright (C) 2002 Gonzalo Paniagua Javier + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GDA_SQLITE_RECORDSET_H__ +#define __GDA_SQLITE_RECORDSET_H__ + +#include +#include +#include +#include "gda-sqlite-pstmt.h" + +G_BEGIN_DECLS + +#define GDA_TYPE_SQLITE_RECORDSET (gda_sqlite_recordset_get_type()) + +G_DECLARE_DERIVABLE_TYPE(GdaSqliteRecordset, gda_sqlite_recordset, GDA, SQLITE_RECORDSET, GdaDataSelect) + +struct _GdaSqliteRecordsetClass { + GdaDataSelectClass parent_class; +}; + +GdaDataModel *_gda_sqlite_recordset_new (GdaConnection *cnc, GdaSqlitePStmt *ps, GdaSet *exec_params, + GdaDataModelAccessFlags flags, GType *col_types, + gboolean force_empty); + +G_END_DECLS + +#endif diff --git a/.flatpak-builder/cache/objects/e3/5164eb4363ba8286b85635f85da62209d136209875cfcb0e22b7a54ce0c301.dirtree b/.flatpak-builder/cache/objects/e3/5164eb4363ba8286b85635f85da62209d136209875cfcb0e22b7a54ce0c301.dirtree new file mode 100644 index 0000000..ac51a0b Binary files /dev/null and b/.flatpak-builder/cache/objects/e3/5164eb4363ba8286b85635f85da62209d136209875cfcb0e22b7a54ce0c301.dirtree differ diff --git a/.flatpak-builder/cache/objects/e3/81d1af82caf3a61c59b4fb76184efeed130a3f4738e253888deb5ef02b20f9.dirtree b/.flatpak-builder/cache/objects/e3/81d1af82caf3a61c59b4fb76184efeed130a3f4738e253888deb5ef02b20f9.dirtree new file mode 100644 index 0000000..92d7b20 Binary files /dev/null and b/.flatpak-builder/cache/objects/e3/81d1af82caf3a61c59b4fb76184efeed130a3f4738e253888deb5ef02b20f9.dirtree differ diff --git a/.flatpak-builder/cache/objects/e4/2f419f6bdc8cc6d341926432efcbbd948468f670c8e163d583b47e48ebd649.dirtree b/.flatpak-builder/cache/objects/e4/2f419f6bdc8cc6d341926432efcbbd948468f670c8e163d583b47e48ebd649.dirtree new file mode 100644 index 0000000..1939b56 Binary files /dev/null and b/.flatpak-builder/cache/objects/e4/2f419f6bdc8cc6d341926432efcbbd948468f670c8e163d583b47e48ebd649.dirtree differ diff --git a/.flatpak-builder/cache/objects/e4/5c18d345d29ccf740fcde2e689758a1160eff3ad47c1972d935cbf03229275.commit b/.flatpak-builder/cache/objects/e4/5c18d345d29ccf740fcde2e689758a1160eff3ad47c1972d935cbf03229275.commit new file mode 100644 index 0000000..733e7f5 Binary files /dev/null and b/.flatpak-builder/cache/objects/e4/5c18d345d29ccf740fcde2e689758a1160eff3ad47c1972d935cbf03229275.commit differ diff --git a/.flatpak-builder/cache/objects/e4/5c45f4211be0cb8284a7e6ed0babf3d549e7dad5e663ab5afc0e69ca481996.dirtree b/.flatpak-builder/cache/objects/e4/5c45f4211be0cb8284a7e6ed0babf3d549e7dad5e663ab5afc0e69ca481996.dirtree new file mode 100644 index 0000000..00ea288 Binary files /dev/null and b/.flatpak-builder/cache/objects/e4/5c45f4211be0cb8284a7e6ed0babf3d549e7dad5e663ab5afc0e69ca481996.dirtree differ diff --git a/.flatpak-builder/cache/objects/e4/da831467b42feb93cafe5e1b649deb612805e38da9765f08c039722c219f4a.dirtree b/.flatpak-builder/cache/objects/e4/da831467b42feb93cafe5e1b649deb612805e38da9765f08c039722c219f4a.dirtree new file mode 100644 index 0000000..00c4c48 Binary files /dev/null and b/.flatpak-builder/cache/objects/e4/da831467b42feb93cafe5e1b649deb612805e38da9765f08c039722c219f4a.dirtree differ diff --git a/.flatpak-builder/cache/objects/e5/d3081fec69ef6a0d565faa357b61ec9504d4e5e276fa0c1d53d0a019253920.dirtree b/.flatpak-builder/cache/objects/e5/d3081fec69ef6a0d565faa357b61ec9504d4e5e276fa0c1d53d0a019253920.dirtree new file mode 100644 index 0000000..b5ac418 Binary files /dev/null and b/.flatpak-builder/cache/objects/e5/d3081fec69ef6a0d565faa357b61ec9504d4e5e276fa0c1d53d0a019253920.dirtree differ diff --git a/.flatpak-builder/cache/objects/e5/f72d7fc07aa88b875f8e722a619fb80935c839bd974208a8679dcf8f01a808.dirtree b/.flatpak-builder/cache/objects/e5/f72d7fc07aa88b875f8e722a619fb80935c839bd974208a8679dcf8f01a808.dirtree new file mode 100644 index 0000000..febdb4a Binary files /dev/null and b/.flatpak-builder/cache/objects/e5/f72d7fc07aa88b875f8e722a619fb80935c839bd974208a8679dcf8f01a808.dirtree differ diff --git a/.flatpak-builder/cache/objects/e6/1086f3d662a34fed6cd533f5b1d430f22db9cec7fe8d1a4d9724a7d0ebabd3.file b/.flatpak-builder/cache/objects/e6/1086f3d662a34fed6cd533f5b1d430f22db9cec7fe8d1a4d9724a7d0ebabd3.file new file mode 100644 index 0000000..0151246 --- /dev/null +++ b/.flatpak-builder/cache/objects/e6/1086f3d662a34fed6cd533f5b1d430f22db9cec7fe8d1a4d9724a7d0ebabd3.file @@ -0,0 +1,701 @@ +/* + * BinReloc - a library for creating relocatable executables + * Written by: Hongli Lai + * http://autopackage.org/ + * + * This source code is public domain. You can relicense this code + * under whatever license you want. + * + * See http://autopackage.org/docs/binreloc/ for + * more information and how to use this. + */ + +#ifndef __BINRELOC_C__ +#define __BINRELOC_C__ + +#ifdef ENABLE_BINRELOC + #include + #include + #include +#endif /* ENABLE_BINRELOC */ +#include +#include +#include +#include +#include "binreloc.h" + +G_BEGIN_DECLS + + +/** @internal + * Find the canonical filename of the executable. Returns the filename + * (which must be freed) or NULL on error. If the parameter 'error' is + * not NULL, the error code will be stored there, if an error occurred. + */ +static char * +_br_find_exe (GbrInitError *error) +{ +#ifndef ENABLE_BINRELOC + if (error) + *error = _GDA_GBR_INIT_ERROR_DISABLED; + return NULL; +#else + char *path, *path2, *line, *result; + size_t buf_size; + ssize_t size; + struct stat stat_buf; + FILE *f; + + /* Read from /proc/self/exe (symlink) */ + if (sizeof (path) > SSIZE_MAX) + buf_size = SSIZE_MAX - 1; + else + buf_size = PATH_MAX - 1; + path = (char *) g_try_malloc (buf_size); + if (path == NULL) { + /* Cannot allocate memory. */ + if (error) + *error = _GDA_GBR_INIT_ERROR_NOMEM; + return NULL; + } + path2 = (char *) g_try_malloc (buf_size); + if (path2 == NULL) { + /* Cannot allocate memory. */ + if (error) + *error = _GDA_GBR_INIT_ERROR_NOMEM; + g_free (path); + return NULL; + } + + strncpy (path2, "/proc/self/exe", buf_size - 1); + + while (1) { + int i; + + size = readlink (path2, path, buf_size - 1); /* Flawfinder: ignore */ + if (size == -1) { + /* Error. */ + g_free (path2); + break; + } + + /* readlink() success. */ + path[size] = '\0'; + + /* Check whether the symlink's target is also a symlink. + * We want to get the final target. */ + i = stat (path, &stat_buf); + if (i == -1) { + /* Error. */ + g_free (path2); + break; + } + + /* stat() success. */ + if (!S_ISLNK (stat_buf.st_mode)) { + /* path is not a symlink. Done. */ + g_free (path2); + return path; + } + + /* path is a symlink. Continue loop and resolve this. */ + strncpy (path, path2, buf_size - 1); + } + + + /* readlink() or stat() failed; this can happen when the program is + * running in Valgrind 2.2. Read from /proc/self/maps as fallback. */ + + buf_size = PATH_MAX + 128; + line = (char *) g_try_realloc (path, buf_size); + if (line == NULL) { + /* Cannot allocate memory. */ + g_free (path); + if (error) + *error = _GDA_GBR_INIT_ERROR_NOMEM; + return NULL; + } + + f = fopen ("/proc/self/maps", "r"); /* Flawfinder: ignore */ + if (f == NULL) { + g_free (line); + if (error) + *error = _GDA_GBR_INIT_ERROR_OPEN_MAPS; + return NULL; + } + + /* The first entry should be the executable name. */ + result = fgets (line, (int) buf_size, f); + if (result == NULL) { + fclose (f); + g_free (line); + if (error) + *error = _GDA_GBR_INIT_ERROR_READ_MAPS; + return NULL; + } + + /* Get rid of newline character. */ + buf_size = strlen (line); + if (buf_size <= 0) { + /* Huh? An empty string? */ + fclose (f); + g_free (line); + if (error) + *error = _GDA_GBR_INIT_ERROR_INVALID_MAPS; + return NULL; + } + if (line[buf_size - 1] == 10) + line[buf_size - 1] = 0; + + /* Extract the filename; it is always an absolute path. */ + path = strchr (line, '/'); + + /* Sanity check. */ + if (strstr (line, " r-xp ") == NULL || path == NULL) { + fclose (f); + g_free (line); + if (error) + *error = _GDA_GBR_INIT_ERROR_INVALID_MAPS; + return NULL; + } + + path = g_strdup (path); + g_free (line); + fclose (f); + return path; +#endif /* ENABLE_BINRELOC */ +} + + +/** @internal + * Find the canonical filename of the executable which owns symbol. + * Returns a filename which must be freed, or NULL on error. + */ +static char * +_br_find_exe_for_symbol ( +#ifndef ENABLE_BINRELOC + G_GNUC_UNUSED const void *symbol, GbrInitError *error) +#else + const void *symbol, GbrInitError *error) +#endif +{ +#ifndef ENABLE_BINRELOC + if (error) + *error = _GDA_GBR_INIT_ERROR_DISABLED; + return (char *) NULL; +#else + #define SIZE PATH_MAX + 100 + FILE *f; + size_t address_string_len; + char *address_string, line[SIZE], *found; /* Flawfinder: ignore */ + + if (symbol == NULL) + return (char *) NULL; + + f = fopen ("/proc/self/maps", "r"); /* Flawfinder: ignore */ + if (f == NULL) + return (char *) NULL; + + address_string_len = 4; + address_string = (char *) g_try_malloc (address_string_len); + found = (char *) NULL; + + while (!feof (f)) { + char *start_addr, *end_addr, *end_addr_end, *file; + void *start_addr_p, *end_addr_p; + size_t len; + + if (fgets (line, SIZE, f) == NULL) + break; + + /* Sanity check. */ + if (strstr (line, " r-xp ") == NULL || strchr (line, '/') == NULL) + continue; + + /* Parse line. */ + start_addr = line; + end_addr = strchr (line, '-'); + file = strchr (line, '/'); + + /* More sanity check. */ + if (!(file > end_addr && end_addr != NULL && end_addr[0] == '-')) + continue; + + end_addr[0] = '\0'; + end_addr++; + end_addr_end = strchr (end_addr, ' '); + if (end_addr_end == NULL) + continue; + + end_addr_end[0] = '\0'; + len = strlen (file); + if (len == 0) + continue; + if (file[len - 1] == '\n') + file[len - 1] = '\0'; + + /* Get rid of "(deleted)" from the filename. */ + len = strlen (file); + if (len > 10 && strcmp (file + len - 10, " (deleted)") == 0) + file[len - 10] = '\0'; + + /* I don't know whether this can happen but better safe than sorry. */ + len = strlen (start_addr); + if (len != strlen (end_addr)) + continue; + + + /* Transform the addresses into a string in the form of 0xdeadbeef, + * then transform that into a pointer. */ + if (address_string_len < len + 3) { + address_string_len = len + 3; + address_string = (char *) g_realloc (address_string, address_string_len); + } + + memcpy (address_string, "0x", 2); /* Flawfinder: ignore */ + memcpy (address_string + 2, start_addr, len); /* Flawfinder: ignore */ + address_string[2 + len] = '\0'; + sscanf (address_string, "%p", &start_addr_p); + + memcpy (address_string, "0x", 2); /* Flawfinder: ignore */ + memcpy (address_string + 2, end_addr, len); /* Flawfinder: ignore */ + address_string[2 + len] = '\0'; + sscanf (address_string, "%p", &end_addr_p); + + + if (symbol >= start_addr_p && symbol < end_addr_p) { + found = file; + break; + } + } + + g_free (address_string); + fclose (f); + + if (found == NULL) + return (char *) NULL; + else + return g_strdup (found); +#endif /* ENABLE_BINRELOC */ +} + + +static gchar *exe = NULL; + +static void set_gerror (GError **error, GbrInitError errcode); + + +/** Initialize the BinReloc library (for applications). + * + * This function must be called before using any other BinReloc functions. + * It attempts to locate the application's canonical filename. + * + * @note If you want to use BinReloc for a library, then you should call + * _gda_gbr_init_lib() instead. + * + * @param error If BinReloc failed to initialize, then the error report will + * be stored in this variable. Set to NULL if you don't want an + * error report. See the #GbrInitError for a list of error + * codes. + * + * @returns TRUE on success, FALSE if BinReloc failed to initialize. + */ +gboolean +_gda_gbr_init (GError **error) +{ + GbrInitError errcode; + + /* Locate the application's filename. */ + exe = _br_find_exe (&errcode); + if (exe != NULL) + /* Success! */ + return TRUE; + else { + /* Failed :-( */ + set_gerror (error, errcode); + return FALSE; + } +} + + +/** Initialize the BinReloc library (for libraries). + * + * This function must be called before using any other BinReloc functions. + * It attempts to locate the calling library's canonical filename. + * + * @note The BinReloc source code MUST be included in your library, or this + * function won't work correctly. + * + * @returns TRUE on success, FALSE if a filename cannot be found. + */ +gboolean +_gda_gbr_init_lib (GError **error) +{ + GbrInitError errcode; + + exe = _br_find_exe_for_symbol ((const void *) "", &errcode); + if (exe != NULL) + /* Success! */ + return TRUE; + else { + /* Failed :-( */ + set_gerror (error, errcode); + return exe != NULL; + } +} + + +static void +set_gerror (GError **error, GbrInitError errcode) +{ + gchar *error_message; + + if (error == NULL) + return; + + switch (errcode) { + case _GDA_GBR_INIT_ERROR_NOMEM: + error_message = "Cannot allocate memory."; + break; + case _GDA_GBR_INIT_ERROR_OPEN_MAPS: + error_message = "Unable to open /proc/self/maps for reading."; + break; + case _GDA_GBR_INIT_ERROR_READ_MAPS: + error_message = "Unable to read from /proc/self/maps."; + break; + case _GDA_GBR_INIT_ERROR_INVALID_MAPS: + error_message = "The file format of /proc/self/maps is invalid."; + break; + case _GDA_GBR_INIT_ERROR_DISABLED: + error_message = "Binary relocation support is disabled."; + break; + default: + error_message = "Unknown error."; + break; + }; + g_set_error (error, g_quark_from_static_string ("GBinReloc"), + errcode, "%s", error_message); +} + + +/** Find the canonical filename of the current application. + * + * @param default_exe A default filename which will be used as fallback. + * @returns A string containing the application's canonical filename, + * which must be freed when no longer necessary. If BinReloc is + * not initialized, or if the initialization function failed, + * then a copy of default_exe will be returned. If default_exe + * is NULL, then NULL will be returned. + */ +gchar * +_gda_gbr_find_exe (const gchar *default_exe) +{ + if (exe == NULL) { + /* BinReloc is not initialized. */ + if (default_exe != NULL) + return g_strdup (default_exe); + else + return NULL; + } + return g_strdup (exe); +} + + +/** Locate the directory in which the current application is installed. + * + * The prefix is generated by the following pseudo-code evaluation: + * \code + * dirname(exename) + * \endcode + * + * @param default_dir A default directory which will used as fallback. + * @return A string containing the directory, which must be freed when no + * longer necessary. If BinReloc is not initialized, or if the + * initialization function failed, then a copy of default_dir + * will be returned. If default_dir is NULL, then NULL will be + * returned. + */ +gchar * +_gda_gbr_find_exe_dir (const gchar *default_dir) +{ + if (exe == NULL) { + /* BinReloc not initialized. */ + if (default_dir != NULL) + return g_strdup (default_dir); + else + return NULL; + } + + return g_path_get_dirname (exe); +} + + +/** Locate the prefix in which the current application is installed. + * + * The prefix is generated by the following pseudo-code evaluation: + * \code + * dirname(dirname(exename)) + * \endcode + * + * @param default_prefix A default prefix which will used as fallback. + * @return A string containing the prefix, which must be freed when no + * longer necessary. If BinReloc is not initialized, or if the + * initialization function failed, then a copy of default_prefix + * will be returned. If default_prefix is NULL, then NULL will be + * returned. + */ +gchar * +_gda_gbr_find_prefix (const gchar *default_prefix) +{ + gchar *dir1, *dir2; + + if (exe == NULL) { + /* BinReloc not initialized. */ + if (default_prefix != NULL) + return g_strdup (default_prefix); + else + return NULL; + } + + dir1 = g_path_get_dirname (exe); + dir2 = g_path_get_dirname (dir1); + g_free (dir1); + return dir2; +} + + +/** Locate the application's binary folder. + * + * The path is generated by the following pseudo-code evaluation: + * \code + * prefix + "/bin" + * \endcode + * + * @param default_bin_dir A default path which will used as fallback. + * @return A string containing the bin folder's path, which must be freed when + * no longer necessary. If BinReloc is not initialized, or if the + * initialization function failed, then a copy of default_bin_dir will + * be returned. If default_bin_dir is NULL, then NULL will be returned. + */ +gchar * +_gda_gbr_find_bin_dir (const gchar *default_bin_dir) +{ + gchar *prefix, *dir; + + prefix = _gda_gbr_find_prefix (NULL); + if (prefix == NULL) { + /* BinReloc not initialized. */ + if (default_bin_dir != NULL) + return g_strdup (default_bin_dir); + else + return NULL; + } + + dir = g_build_filename (prefix, "bin", NULL); + g_free (prefix); + return dir; +} + + +/** Locate the application's superuser binary folder. + * + * The path is generated by the following pseudo-code evaluation: + * \code + * prefix + "/sbin" + * \endcode + * + * @param default_sbin_dir A default path which will used as fallback. + * @return A string containing the sbin folder's path, which must be freed when + * no longer necessary. If BinReloc is not initialized, or if the + * initialization function failed, then a copy of default_sbin_dir will + * be returned. If default_bin_dir is NULL, then NULL will be returned. + */ +gchar * +_gda_gbr_find_sbin_dir (const gchar *default_sbin_dir) +{ + gchar *prefix, *dir; + + prefix = _gda_gbr_find_prefix (NULL); + if (prefix == NULL) { + /* BinReloc not initialized. */ + if (default_sbin_dir != NULL) + return g_strdup (default_sbin_dir); + else + return NULL; + } + + dir = g_build_filename (prefix, "sbin", NULL); + g_free (prefix); + return dir; +} + + +/** Locate the application's data folder. + * + * The path is generated by the following pseudo-code evaluation: + * \code + * prefix + "/share" + * \endcode + * + * @param default_data_dir A default path which will used as fallback. + * @return A string containing the data folder's path, which must be freed when + * no longer necessary. If BinReloc is not initialized, or if the + * initialization function failed, then a copy of default_data_dir + * will be returned. If default_data_dir is NULL, then NULL will be + * returned. + */ +gchar * +_gda_gbr_find_data_dir (const gchar *default_data_dir) +{ + gchar *prefix, *dir; + + prefix = _gda_gbr_find_prefix (NULL); + if (prefix == NULL) { + /* BinReloc not initialized. */ + if (default_data_dir != NULL) + return g_strdup (default_data_dir); + else + return NULL; + } + + dir = g_build_filename (prefix, "share", NULL); + g_free (prefix); + return dir; +} + + +/** Locate the application's localization folder. + * + * The path is generated by the following pseudo-code evaluation: + * \code + * prefix + "/share/locale" + * \endcode + * + * @param default_locale_dir A default path which will used as fallback. + * @return A string containing the localization folder's path, which must be freed when + * no longer necessary. If BinReloc is not initialized, or if the + * initialization function failed, then a copy of default_locale_dir will be returned. + * If default_locale_dir is NULL, then NULL will be returned. + */ +gchar * +_gda_gbr_find_locale_dir (const gchar *default_locale_dir) +{ + gchar *data_dir, *dir; + + data_dir = _gda_gbr_find_data_dir (NULL); + if (data_dir == NULL) { + /* BinReloc not initialized. */ + if (default_locale_dir != NULL) + return g_strdup (default_locale_dir); + else + return NULL; + } + + dir = g_build_filename (data_dir, "locale", NULL); + g_free (data_dir); + return dir; +} + + +/** Locate the application's library folder. + * + * The path is generated by the following pseudo-code evaluation: + * \code + * prefix + "/lib" + * \endcode + * + * @param default_lib_dir A default path which will used as fallback. + * @return A string containing the library folder's path, which must be freed when + * no longer necessary. If BinReloc is not initialized, or if the + * initialization function failed, then a copy of default_lib_dir will be returned. + * If default_lib_dir is NULL, then NULL will be returned. + */ +gchar * +_gda_gbr_find_lib_dir (const gchar *default_lib_dir) +{ + gchar *prefix, *dir; + + prefix = _gda_gbr_find_prefix (NULL); + if (prefix == NULL) { + /* BinReloc not initialized. */ + if (default_lib_dir != NULL) + return g_strdup (default_lib_dir); + else + return NULL; + } + + dir = g_build_filename (prefix, "lib", NULL); + g_free (prefix); + return dir; +} + + +/** Locate the application's libexec folder. + * + * The path is generated by the following pseudo-code evaluation: + * \code + * prefix + "/libexec" + * \endcode + * + * @param default_libexec_dir A default path which will used as fallback. + * @return A string containing the libexec folder's path, which must be freed when + * no longer necessary. If BinReloc is not initialized, or if the initialization + * function failed, then a copy of default_libexec_dir will be returned. + * If default_libexec_dir is NULL, then NULL will be returned. + */ +gchar * +_gda_gbr_find_libexec_dir (const gchar *default_libexec_dir) +{ + gchar *prefix, *dir; + + prefix = _gda_gbr_find_prefix (NULL); + if (prefix == NULL) { + /* BinReloc not initialized. */ + if (default_libexec_dir != NULL) + return g_strdup (default_libexec_dir); + else + return NULL; + } + + dir = g_build_filename (prefix, "libexec", NULL); + g_free (prefix); + return dir; +} + + +/** Locate the application's configuration files folder. + * + * The path is generated by the following pseudo-code evaluation: + * \code + * prefix + "/etc" + * \endcode + * + * @param default_etc_dir A default path which will used as fallback. + * @return A string containing the etc folder's path, which must be freed when + * no longer necessary. If BinReloc is not initialized, or if the initialization + * function failed, then a copy of default_etc_dir will be returned. + * If default_etc_dir is NULL, then NULL will be returned. + */ +gchar * +_gda_gbr_find_etc_dir (const gchar *default_etc_dir) +{ + gchar *prefix, *dir; + + prefix = _gda_gbr_find_prefix (NULL); + if (prefix == NULL) { + /* BinReloc not initialized. */ + if (default_etc_dir != NULL) + return g_strdup (default_etc_dir); + else + return NULL; + } + + dir = g_build_filename (prefix, "etc", NULL); + g_free (prefix); + return dir; +} + + +G_END_DECLS + +#endif /* __BINRELOC_C__ */ diff --git a/.flatpak-builder/cache/objects/e6/3fc59b6a3ccdf84f5caa5ad2a79ea041f762920cc758d015f3e52e9a32a0ed.file b/.flatpak-builder/cache/objects/e6/3fc59b6a3ccdf84f5caa5ad2a79ea041f762920cc758d015f3e52e9a32a0ed.file new file mode 100644 index 0000000..d785e56 --- /dev/null +++ b/.flatpak-builder/cache/objects/e6/3fc59b6a3ccdf84f5caa5ad2a79ea041f762920cc758d015f3e52e9a32a0ed.file @@ -0,0 +1,79 @@ +from .gtk_list_item_factory import ExtListItemFactory +from .adw_message_dialog import ExtAdwMessageDialog +from .attributes import BaseAttribute +from .adw_breakpoint import ( + AdwBreakpointSetters, + AdwBreakpointSetter, + AdwBreakpointCondition, +) +from .binding import Binding +from .contexts import ScopeCtx, ValueTypeCtx +from .expression import ( + CastExpr, + ClosureArg, + ClosureExpr, + ExprBase, + Expression, + LiteralExpr, + LookupOp, +) +from .gobject_object import Object, ObjectContent +from .gobject_property import Property +from .gobject_signal import Signal +from .gtk_a11y import ExtAccessibility +from .gtk_combo_box_text import ExtComboBoxItems +from .gtk_file_filter import ( + ext_file_filter_mime_types, + ext_file_filter_patterns, + ext_file_filter_suffixes, + Filters, +) +from .gtk_layout import ExtLayout +from .gtk_menu import menu, Menu, MenuAttribute +from .gtk_scale import ExtScaleMarks +from .gtk_size_group import ExtSizeGroupWidgets +from .gtk_string_list import ExtStringListStrings +from .gtk_styles import ExtStyles +from .gtkbuilder_child import Child, ChildType, ChildInternal, ChildExtension +from .gtkbuilder_template import Template +from .imports import GtkDirective, Import +from .property_binding import PropertyBinding +from .ui import UI +from .types import ClassName +from .values import ( + Flag, + Flags, + IdentLiteral, + Literal, + NumberLiteral, + ObjectValue, + QuotedLiteral, + StringValue, + Translated, + TypeLiteral, + Value, +) + +from .common import * + +OBJECT_CONTENT_HOOKS.children = [ + Signal, + Property, + AdwBreakpointCondition, + AdwBreakpointSetters, + ExtAccessibility, + ExtAdwMessageDialog, + ExtComboBoxItems, + ext_file_filter_mime_types, + ext_file_filter_patterns, + ext_file_filter_suffixes, + ExtLayout, + ExtListItemFactory, + ExtScaleMarks, + ExtSizeGroupWidgets, + ExtStringListStrings, + ExtStyles, + Child, +] + +LITERAL.children = [Literal] diff --git a/.flatpak-builder/cache/objects/e6/887db2919e066377c47a34075582dd85531f90dfe99ad83f113c411caf3c89.dirtree b/.flatpak-builder/cache/objects/e6/887db2919e066377c47a34075582dd85531f90dfe99ad83f113c411caf3c89.dirtree new file mode 100644 index 0000000..7781b65 Binary files /dev/null and b/.flatpak-builder/cache/objects/e6/887db2919e066377c47a34075582dd85531f90dfe99ad83f113c411caf3c89.dirtree differ diff --git a/.flatpak-builder/cache/objects/e6/ab2a47c226f85254eebfff61dae819029366baf2e8e77af33b4f4e8d05087b.dirtree b/.flatpak-builder/cache/objects/e6/ab2a47c226f85254eebfff61dae819029366baf2e8e77af33b4f4e8d05087b.dirtree new file mode 100644 index 0000000..9dbf564 Binary files /dev/null and b/.flatpak-builder/cache/objects/e6/ab2a47c226f85254eebfff61dae819029366baf2e8e77af33b4f4e8d05087b.dirtree differ diff --git a/.flatpak-builder/cache/objects/e7/541ba0e8fe66d0a2cc0e0c9c6cf885a731a60c32ddc920d4d0c79c28151dd0.file b/.flatpak-builder/cache/objects/e7/541ba0e8fe66d0a2cc0e0c9c6cf885a731a60c32ddc920d4d0c79c28151dd0.file new file mode 120000 index 0000000..fed0629 --- /dev/null +++ b/.flatpak-builder/cache/objects/e7/541ba0e8fe66d0a2cc0e0c9c6cf885a731a60c32ddc920d4d0c79c28151dd0.file @@ -0,0 +1 @@ +../../share/runtime/locale/sl/share/sl \ No newline at end of file diff --git a/.flatpak-builder/cache/objects/e7/917bdc66a18f83015d5ef834815aa2de5f27a2a110366a9adb752f1917575b.commit b/.flatpak-builder/cache/objects/e7/917bdc66a18f83015d5ef834815aa2de5f27a2a110366a9adb752f1917575b.commit new file mode 100644 index 0000000..6832c27 Binary files /dev/null and b/.flatpak-builder/cache/objects/e7/917bdc66a18f83015d5ef834815aa2de5f27a2a110366a9adb752f1917575b.commit differ diff --git a/.flatpak-builder/cache/objects/e8/592f4be5d063f3e5e6aa5adba8eadd5066cd9f59e463a2c58c773912a2086f.file b/.flatpak-builder/cache/objects/e8/592f4be5d063f3e5e6aa5adba8eadd5066cd9f59e463a2c58c773912a2086f.file new file mode 100755 index 0000000..c8d7f14 Binary files /dev/null and b/.flatpak-builder/cache/objects/e8/592f4be5d063f3e5e6aa5adba8eadd5066cd9f59e463a2c58c773912a2086f.file differ diff --git a/.flatpak-builder/cache/objects/e8/5d3bfc859d8ad282cec05c8a20ea52a77d0e46106218eae88c9e8d496974a7.file b/.flatpak-builder/cache/objects/e8/5d3bfc859d8ad282cec05c8a20ea52a77d0e46106218eae88c9e8d496974a7.file new file mode 100644 index 0000000..5c31393 --- /dev/null +++ b/.flatpak-builder/cache/objects/e8/5d3bfc859d8ad282cec05c8a20ea52a77d0e46106218eae88c9e8d496974a7.file @@ -0,0 +1,32 @@ +/* gda-db-fkey-private.h + * + * Copyright (C) 2020 Pavlo Solntsev + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef GDA_DB_FKEY_PRIVATE_H +#define GDA_DB_FKEY_PRIVATE_H + +#include "gda-db-fkey.h" +#include "gda-meta-struct.h" + +GdaDbFkey *gda_db_fkey_new_from_meta (GdaMetaTableForeignKey *metafkey); + +#endif /* end of include guard: GDA_DB_FKEY_PRIVATE_H_RX2KUYCG */ + + + diff --git a/.flatpak-builder/cache/objects/e8/7e27305ac87b75f6843bb558d2c2673e1c4e36c2bfa633d0624623f3c6b57d.commit b/.flatpak-builder/cache/objects/e8/7e27305ac87b75f6843bb558d2c2673e1c4e36c2bfa633d0624623f3c6b57d.commit new file mode 100644 index 0000000..a33af78 Binary files /dev/null and b/.flatpak-builder/cache/objects/e8/7e27305ac87b75f6843bb558d2c2673e1c4e36c2bfa633d0624623f3c6b57d.commit differ diff --git a/.flatpak-builder/cache/objects/e8/b78769cb9d9ef259a1b44008d072b48f69334d11b4b109c25aa2e041667e5b.file b/.flatpak-builder/cache/objects/e8/b78769cb9d9ef259a1b44008d072b48f69334d11b4b109c25aa2e041667e5b.file new file mode 100644 index 0000000..1286f0b --- /dev/null +++ b/.flatpak-builder/cache/objects/e8/b78769cb9d9ef259a1b44008d072b48f69334d11b4b109c25aa2e041667e5b.file @@ -0,0 +1,344 @@ +# interactive_port.py +# +# Copyright 2021 James Westman +# +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation; either version 3 of the +# License, or (at your option) any later version. +# +# This file is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program. If not, see . +# +# SPDX-License-Identifier: LGPL-3.0-or-later + + +import typing as T +import difflib +import os + +from . import decompiler, tokenizer, parser +from .outputs.xml import XmlOutput +from .errors import MultipleErrors, PrintableError, CompilerBugError +from .utils import Colors + + +# A tool to interactively port projects to blueprints. + + +class CouldNotPort: + def __init__(self, message: str): + self.message = message + + +def change_suffix(f): + return f.removesuffix(".ui") + ".blp" + + +def decompile_file(in_file, out_file) -> T.Union[str, CouldNotPort]: + if os.path.exists(out_file): + return CouldNotPort("already exists") + + try: + decompiled = decompiler.decompile(in_file) + + try: + # make sure the output compiles + tokens = tokenizer.tokenize(decompiled) + ast, errors, warnings = parser.parse(tokens) + + for warning in warnings: + warning.pretty_print(out_file, decompiled) + + if errors: + raise errors + if not ast: + raise CompilerBugError() + + output = XmlOutput() + output.emit(ast) + except PrintableError as e: + e.pretty_print(out_file, decompiled) + + print( + f"{Colors.RED}{Colors.BOLD}error: the generated file does not compile{Colors.CLEAR}" + ) + print(f"in {Colors.UNDERLINE}{out_file}{Colors.NO_UNDERLINE}") + print( + f"""{Colors.FAINT}Either the original XML file had an error, or there is a bug in the +porting tool. If you think it's a bug (which is likely), please file an issue on GitLab: +{Colors.BLUE}{Colors.UNDERLINE}https://gitlab.gnome.org/jwestman/blueprint-compiler/-/issues/new?issue{Colors.CLEAR}\n""" + ) + + return CouldNotPort("does not compile") + + return decompiled + + except decompiler.UnsupportedError as e: + e.print(in_file) + return CouldNotPort("could not convert") + + +def listdir_recursive(subdir): + files = os.listdir(subdir) + for file in files: + if file in ["_build", "build"]: + continue + if file.startswith("."): + continue + full = os.path.join(subdir, file) + if full == "./subprojects": + # skip the subprojects directory + continue + if os.path.isfile(full): + yield full + elif os.path.isdir(full): + yield from listdir_recursive(full) + + +def yesno(prompt): + while True: + response = input(f"{Colors.BOLD}{prompt} [y/n] {Colors.CLEAR}") + if response.lower() in ["yes", "y"]: + return True + elif response.lower() in ["no", "n"]: + return False + + +def enter(): + input(f"{Colors.BOLD}Press Enter when you have done that: {Colors.CLEAR}") + + +def step1(): + print( + f"{Colors.BOLD}STEP 1: Create subprojects/blueprint-compiler.wrap{Colors.CLEAR}" + ) + + if os.path.exists("subprojects/blueprint-compiler.wrap"): + print("subprojects/blueprint-compiler.wrap already exists, skipping\n") + return + + if yesno("Create subprojects/blueprint-compiler.wrap?"): + try: + os.mkdir("subprojects") + except: + pass + + from .main import VERSION + + VERSION = "main" if VERSION == "uninstalled" else "v" + VERSION + + with open("subprojects/blueprint-compiler.wrap", "w") as wrap: + wrap.write( + f"""[wrap-git] +directory = blueprint-compiler +url = https://gitlab.gnome.org/jwestman/blueprint-compiler.git +revision = {VERSION} +depth = 1 + +[provide] +program_names = blueprint-compiler""" + ) + + print() + + +def step2(): + print(f"{Colors.BOLD}STEP 2: Set up .gitignore{Colors.CLEAR}") + + if os.path.exists(".gitignore"): + with open(".gitignore", "r+") as gitignore: + ignored = [line.strip() for line in gitignore.readlines()] + if "/subprojects/blueprint-compiler" not in ignored: + if yesno("Add '/subprojects/blueprint-compiler' to .gitignore?"): + gitignore.write("\n/subprojects/blueprint-compiler\n") + else: + print( + "'/subprojects/blueprint-compiler' already in .gitignore, skipping" + ) + else: + if yesno("Create .gitignore with '/subprojects/blueprint-compiler'?"): + with open(".gitignore", "w") as gitignore: + gitignore.write("/subprojects/blueprint-compiler\n") + + print() + + +def step3(): + print(f"{Colors.BOLD}STEP 3: Convert UI files{Colors.CLEAR}") + + files = [ + (file, change_suffix(file), decompile_file(file, change_suffix(file))) + for file in listdir_recursive(".") + if file.endswith(".ui") + ] + + success = 0 + for in_file, out_file, result in files: + if isinstance(result, CouldNotPort): + if result.message == "already exists": + print(Colors.FAINT, end="") + print( + f"{Colors.RED}will not port {Colors.UNDERLINE}{in_file}{Colors.NO_UNDERLINE} -> {Colors.UNDERLINE}{out_file}{Colors.NO_UNDERLINE} [{result.message}]{Colors.CLEAR}" + ) + else: + print( + f"will port {Colors.UNDERLINE}{in_file}{Colors.CLEAR} -> {Colors.UNDERLINE}{out_file}{Colors.CLEAR}" + ) + success += 1 + + print() + if len(files) == 0: + print(f"{Colors.RED}No UI files found.{Colors.CLEAR}") + elif success == len(files): + print(f"{Colors.GREEN}All files were converted.{Colors.CLEAR}") + elif success > 0: + print( + f"{Colors.RED}{success} file(s) were converted, {len(files) - success} were not.{Colors.CLEAR}" + ) + else: + print(f"{Colors.RED}None of the files could be converted.{Colors.CLEAR}") + + if success > 0 and yesno("Save these changes?"): + for in_file, out_file, result in files: + if not isinstance(result, CouldNotPort): + with open(out_file, "x") as file: + file.write(result) + + print() + results = [ + (in_file, out_file) + for in_file, out_file, result in files + if not isinstance(result, CouldNotPort) or result.message == "already exists" + ] + if len(results): + return zip(*results) + else: + return ([], []) + + +def step4(ported): + print(f"{Colors.BOLD}STEP 4: Set up meson.build{Colors.CLEAR}") + print( + f"{Colors.BOLD}{Colors.YELLOW}NOTE: Depending on your build system setup, you may need to make some adjustments to this step.{Colors.CLEAR}" + ) + + meson_files = [ + file + for file in listdir_recursive(".") + if os.path.basename(file) == "meson.build" + ] + for meson_file in meson_files: + with open(meson_file, "r") as f: + if "gnome.compile_resources" in f.read(): + parent = os.path.dirname(meson_file) + file_list = "\n ".join( + [ + f"'{os.path.relpath(file, parent)}'," + for file in ported + if file.startswith(parent) + ] + ) + + if len(file_list): + print( + f"{Colors.BOLD}Paste the following into {Colors.UNDERLINE}{meson_file}{Colors.NO_UNDERLINE}:{Colors.CLEAR}" + ) + print( + f""" +blueprints = custom_target('blueprints', + input: files( + {file_list} + ), + output: '.', + command: [find_program('blueprint-compiler'), 'batch-compile', '@OUTPUT@', '@CURRENT_SOURCE_DIR@', '@INPUT@'], +) +""" + ) + enter() + + print( + f"""{Colors.BOLD}Paste the following into the 'gnome.compile_resources()' +arguments in {Colors.UNDERLINE}{meson_file}{Colors.NO_UNDERLINE}:{Colors.CLEAR} + +dependencies: blueprints, + """ + ) + enter() + + print() + + +def step5(in_files): + print(f"{Colors.BOLD}STEP 5: Update POTFILES.in{Colors.CLEAR}") + + if not os.path.exists("po/POTFILES.in"): + print( + f"{Colors.UNDERLINE}po/POTFILES.in{Colors.NO_UNDERLINE} does not exist, skipping\n" + ) + return + + with open("po/POTFILES.in", "r") as potfiles: + old_lines = potfiles.readlines() + lines = old_lines.copy() + for in_file in in_files: + for i, line in enumerate(lines): + if line.strip() == in_file.removeprefix("./"): + lines[i] = change_suffix(line.strip()) + "\n" + + new_data = "".join(lines) + + print( + f"{Colors.BOLD}Will make the following changes to {Colors.UNDERLINE}po/POTFILES.in{Colors.CLEAR}" + ) + print( + "".join( + [ + ( + Colors.GREEN + if line.startswith("+") + else Colors.RED + Colors.FAINT + if line.startswith("-") + else "" + ) + + line + + Colors.CLEAR + for line in difflib.unified_diff(old_lines, lines) + ] + ) + ) + + if yesno("Is this ok?"): + with open("po/POTFILES.in", "w") as potfiles: + potfiles.writelines(lines) + + print() + + +def step6(in_files): + print(f"{Colors.BOLD}STEP 6: Clean up{Colors.CLEAR}") + + if yesno("Delete old XML files?"): + for file in in_files: + try: + os.remove(file) + except: + pass + + +def run(opts): + step1() + step2() + in_files, out_files = step3() + step4(out_files) + step5(in_files) + step6(in_files) + + print( + f"{Colors.BOLD}STEP 6: Done! Make sure your app still builds and runs correctly.{Colors.CLEAR}" + ) diff --git a/.flatpak-builder/cache/objects/e8/be58c0d968d9a5afa4f167ec7e89e88c9d4ea0fc10b1ab8d8e0110d841e844.dirtree b/.flatpak-builder/cache/objects/e8/be58c0d968d9a5afa4f167ec7e89e88c9d4ea0fc10b1ab8d8e0110d841e844.dirtree new file mode 100644 index 0000000..535b7cb Binary files /dev/null and b/.flatpak-builder/cache/objects/e8/be58c0d968d9a5afa4f167ec7e89e88c9d4ea0fc10b1ab8d8e0110d841e844.dirtree differ diff --git a/.flatpak-builder/cache/objects/e8/cc229bb628979cdf0f23449f7bf6ba93d7ecfe688592c4e6a7d4b1dd960fd4.file b/.flatpak-builder/cache/objects/e8/cc229bb628979cdf0f23449f7bf6ba93d7ecfe688592c4e6a7d4b1dd960fd4.file new file mode 100644 index 0000000..703f8c9 Binary files /dev/null and b/.flatpak-builder/cache/objects/e8/cc229bb628979cdf0f23449f7bf6ba93d7ecfe688592c4e6a7d4b1dd960fd4.file differ diff --git a/.flatpak-builder/cache/objects/e9/00c88af32c046a4835c236105db899b7b16dfbc29578c2f93358f341a2e359.file b/.flatpak-builder/cache/objects/e9/00c88af32c046a4835c236105db899b7b16dfbc29578c2f93358f341a2e359.file new file mode 100644 index 0000000..154085f --- /dev/null +++ b/.flatpak-builder/cache/objects/e9/00c88af32c046a4835c236105db899b7b16dfbc29578c2f93358f341a2e359.file @@ -0,0 +1,114 @@ +/* gda-db-column.h + * + * Copyright (C) 2018 Pavlo Solntsev + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +#ifndef GDA_DB_COLUMN_H +#define GDA_DB_COLUMN_H + +#include +#include +#include +#include "gda-db-buildable.h" +#include "gda-server-operation.h" +#include "gda-meta-struct.h" + +G_BEGIN_DECLS + +#define GDA_TYPE_DB_COLUMN (gda_db_column_get_type()) + +G_DECLARE_DERIVABLE_TYPE (GdaDbColumn, gda_db_column, GDA, DB_COLUMN, GObject) + +struct _GdaDbColumnClass +{ + GObjectClass parent; +}; + +/** + * GdaDbColumnError: + * @GDA_DB_COLUMN_ERROR_TYPE: Set if wrong column type was given in the xml file. + * @GDA_DB_COLUMN_ERROR_WRONG_OPERATION: Wrong operation requested + * + * Values used to describe the source of the error. + */ +typedef enum +{ + GDA_DB_COLUMN_ERROR_TYPE, + GDA_DB_COLUMN_ERROR_WRONG_OPERATION +} GdaDbColumnError; + +#define GDA_DB_COLUMN_ERROR gda_db_column_error_quark() +GQuark gda_db_column_error_quark (void); + +GdaDbColumn* gda_db_column_new (void); + +const gchar* gda_db_column_get_name (GdaDbColumn *self); +void gda_db_column_set_name (GdaDbColumn *self, const gchar *name); + +GType gda_db_column_get_gtype (GdaDbColumn *self); +const gchar* gda_db_column_get_ctype (GdaDbColumn *self); +void gda_db_column_set_type (GdaDbColumn *self, GType type); + +guint gda_db_column_get_scale (GdaDbColumn *self); +void gda_db_column_set_scale (GdaDbColumn *self, + guint scale); + +gboolean gda_db_column_get_pkey (GdaDbColumn *self); +void gda_db_column_set_pkey (GdaDbColumn *self, + gboolean pkey); + +gboolean gda_db_column_get_nnul (GdaDbColumn *self); +void gda_db_column_set_nnul (GdaDbColumn *self, + gboolean nnul); + +gboolean gda_db_column_get_autoinc (GdaDbColumn *self); +void gda_db_column_set_autoinc (GdaDbColumn *self, + gboolean autoinc); + +gboolean gda_db_column_get_unique (GdaDbColumn *self); +void gda_db_column_set_unique (GdaDbColumn *self, + gboolean unique); + +const gchar* gda_db_column_get_comment (GdaDbColumn *self); +void gda_db_column_set_comment (GdaDbColumn *self, + const gchar *comnt); + +guint gda_db_column_get_size (GdaDbColumn *self); +void gda_db_column_set_size (GdaDbColumn *self, + guint size); + +const gchar* gda_db_column_get_default (GdaDbColumn *self); +void gda_db_column_set_default (GdaDbColumn *self, + const gchar *value); + +const gchar* gda_db_column_get_check (GdaDbColumn *self); +void gda_db_column_set_check (GdaDbColumn *self, + const gchar *value); + +gboolean gda_db_column_prepare_create (GdaDbColumn *self, + GdaServerOperation *op, + guint order, + GError **error); + +gboolean gda_db_column_prepare_add (GdaDbColumn *self, + GdaServerOperation *op, + GError **error); + +G_END_DECLS + +#endif /* GDA_DB_COLUMN_H */ + diff --git a/.flatpak-builder/cache/objects/e9/3e8b4743a90076409fee6422d8da6e3316125abe13bf0c5efa739b53e00e94.file b/.flatpak-builder/cache/objects/e9/3e8b4743a90076409fee6422d8da6e3316125abe13bf0c5efa739b53e00e94.file new file mode 100644 index 0000000..54500dc --- /dev/null +++ b/.flatpak-builder/cache/objects/e9/3e8b4743a90076409fee6422d8da6e3316125abe13bf0c5efa739b53e00e94.file @@ -0,0 +1,380 @@ +/*-*- Mode: C; c-basic-offset: 8 -*-*/ + +/*** + This file is part of libcanberra. + + Copyright 2008 Lennart Poettering + + libcanberra is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation, either version 2.1 of the + License, or (at your option) any later version. + + libcanberra is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with libcanberra. If not, see + . +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#include "driver.h" +#include "common.h" +#include "malloc.h" +#include "driver-order.h" + +struct private_dso { + lt_dlhandle module; + ca_bool_t ltdl_initialized; + + int (*driver_open)(ca_context *c); + int (*driver_destroy)(ca_context *c); + int (*driver_change_device)(ca_context *c, const char *device); + int (*driver_change_props)(ca_context *c, ca_proplist *changed, ca_proplist *merged); + int (*driver_play)(ca_context *c, uint32_t id, ca_proplist *p, ca_finish_callback_t cb, void *userdata); + int (*driver_cancel)(ca_context *c, uint32_t id); + int (*driver_cache)(ca_context *c, ca_proplist *p); + int (*driver_playing)(ca_context *c, uint32_t id, int *playing); +}; + +#define PRIVATE_DSO(c) ((struct private_dso *) ((c)->private_dso)) + +static int ca_error_from_lt_error(int code) { + + static const int table[] = { + [LT_ERROR_UNKNOWN] = CA_ERROR_INTERNAL, + [LT_ERROR_DLOPEN_NOT_SUPPORTED] = CA_ERROR_NOTSUPPORTED, + [LT_ERROR_INVALID_LOADER] = CA_ERROR_INTERNAL, + [LT_ERROR_INIT_LOADER] = CA_ERROR_INTERNAL, + [LT_ERROR_REMOVE_LOADER] = CA_ERROR_INTERNAL, + [LT_ERROR_FILE_NOT_FOUND] = CA_ERROR_NOTFOUND, + [LT_ERROR_DEPLIB_NOT_FOUND] = CA_ERROR_NOTFOUND, + [LT_ERROR_NO_SYMBOLS] = CA_ERROR_NOTFOUND, + [LT_ERROR_CANNOT_OPEN] = CA_ERROR_ACCESS, + [LT_ERROR_CANNOT_CLOSE] = CA_ERROR_INTERNAL, + [LT_ERROR_SYMBOL_NOT_FOUND] = CA_ERROR_NOTFOUND, + [LT_ERROR_NO_MEMORY] = CA_ERROR_OOM, + [LT_ERROR_INVALID_HANDLE] = CA_ERROR_INVALID, + [LT_ERROR_BUFFER_OVERFLOW] = CA_ERROR_TOOBIG, + [LT_ERROR_INVALID_ERRORCODE] = CA_ERROR_INVALID, + [LT_ERROR_SHUTDOWN] = CA_ERROR_INTERNAL, + [LT_ERROR_CLOSE_RESIDENT_MODULE] = CA_ERROR_INTERNAL, + [LT_ERROR_INVALID_MUTEX_ARGS] = CA_ERROR_INTERNAL, + [LT_ERROR_INVALID_POSITION] = CA_ERROR_INTERNAL +#ifdef LT_ERROR_CONFLICTING_FLAGS + , [LT_ERROR_CONFLICTING_FLAGS] = CA_ERROR_INTERNAL +#endif + }; + + if (code < 0 || code >= (int) CA_ELEMENTSOF(table)) + return CA_ERROR_INTERNAL; + + return table[code]; +} + +static int lt_error_from_string(const char *t) { + + struct lt_error_code { + int code; + const char *text; + }; + + static const struct lt_error_code lt_error_codes[] = { + /* This is so disgustingly ugly, it makes me vomit. But that's + * all ltdl's fault. */ +#define LT_ERROR(u, s) { .code = LT_ERROR_ ## u, .text = s }, + lt_dlerror_table +#undef LT_ERROR + + { .code = 0, .text = NULL } + }; + + const struct lt_error_code *c; + + for (c = lt_error_codes; c->text; c++) + if (ca_streq(t, c->text)) + return c->code; + + return -1; +} + +static int ca_error_from_string(const char *t) { + int err; + + if ((err = lt_error_from_string(t)) < 0) + return CA_ERROR_INTERNAL; + + return ca_error_from_lt_error(err); +} + +static int try_open(ca_context *c, const char *t) { + char *mn; + struct private_dso *p; + + p = PRIVATE_DSO(c); + + if (!(mn = ca_sprintf_malloc(CA_PLUGIN_PATH "/libcanberra-%s", t))) + return CA_ERROR_OOM; + + errno = 0; + p->module = lt_dlopenext(mn); + ca_free(mn); + + if (!p->module) { + int ret; + + if (errno == ENOENT) + ret = CA_ERROR_NOTFOUND; + else + ret = ca_error_from_string(lt_dlerror()); + + if (ret == CA_ERROR_NOTFOUND) + ret = CA_ERROR_NODRIVER; + + return ret; + } + + return CA_SUCCESS; +} + +static void* real_dlsym(lt_module m, const char *name, const char *symbol) { + char sn[256]; + char *s; + void *r; + + ca_return_null_if_fail(m); + ca_return_null_if_fail(name); + ca_return_null_if_fail(symbol); + + snprintf(sn, sizeof(sn), "%s_%s", name, symbol); + sn[sizeof(sn)-1] = 0; + + for (s = sn; *s; s++) { + if (*s >= 'a' && *s <= 'z') + continue; + if (*s >= 'A' && *s <= 'Z') + continue; + if (*s >= '0' && *s <= '9') + continue; + + *s = '_'; + } + + if ((r = lt_dlsym(m, sn))) + return r; + + return lt_dlsym(m, symbol); +} + +#define MAKE_FUNC_PTR(ret, args, x) ((ret (*) args ) (size_t) (x)) +#define GET_FUNC_PTR(module, name, symbol, ret, args) MAKE_FUNC_PTR(ret, args, real_dlsym((module), (name), (symbol))) + +int driver_open(ca_context *c) { + int ret; + struct private_dso *p; + char *driver; + + ca_return_val_if_fail(c, CA_ERROR_INVALID); + ca_return_val_if_fail(!PRIVATE_DSO(c), CA_ERROR_STATE); + + if (!(c->private_dso = p = ca_new0(struct private_dso, 1))) + return CA_ERROR_OOM; + + if (lt_dlinit() != 0) { + ret = ca_error_from_string(lt_dlerror()); + driver_destroy(c); + return ret; + } + + p->ltdl_initialized = TRUE; + + if (c->driver) { + char *e; + size_t n; + + if (!(e = ca_strdup(c->driver))) { + driver_destroy(c); + return CA_ERROR_OOM; + } + + n = strcspn(e, ",:"); + e[n] = 0; + + if (n == 0) { + driver_destroy(c); + ca_free(e); + return CA_ERROR_INVALID; + } + + if ((ret = try_open(c, e)) < 0) { + driver_destroy(c); + ca_free(e); + return ret; + } + + driver = e; + + } else { + const char *const * e; + + for (e = ca_driver_order; *e; e++) { + + if ((ret = try_open(c, *e)) == CA_SUCCESS) + break; + + if (ret != CA_ERROR_NODRIVER && + ret != CA_ERROR_NOTAVAILABLE && + ret != CA_ERROR_NOTFOUND) { + + driver_destroy(c); + return ret; + } + } + + if (!*e) { + driver_destroy(c); + return CA_ERROR_NODRIVER; + } + + if (!(driver = ca_strdup(*e))) { + driver_destroy(c); + return CA_ERROR_OOM; + } + } + + ca_assert(p->module); + + if (!(p->driver_open = GET_FUNC_PTR(p->module, driver, "driver_open", int, (ca_context*))) || + !(p->driver_destroy = GET_FUNC_PTR(p->module, driver, "driver_destroy", int, (ca_context*))) || + !(p->driver_change_device = GET_FUNC_PTR(p->module, driver, "driver_change_device", int, (ca_context*, const char *))) || + !(p->driver_change_props = GET_FUNC_PTR(p->module, driver, "driver_change_props", int, (ca_context *, ca_proplist *, ca_proplist *))) || + !(p->driver_play = GET_FUNC_PTR(p->module, driver, "driver_play", int, (ca_context*, uint32_t, ca_proplist *, ca_finish_callback_t, void *))) || + !(p->driver_cancel = GET_FUNC_PTR(p->module, driver, "driver_cancel", int, (ca_context*, uint32_t))) || + !(p->driver_cache = GET_FUNC_PTR(p->module, driver, "driver_cache", int, (ca_context*, ca_proplist *))) || + !(p->driver_playing = GET_FUNC_PTR(p->module, driver, "driver_playing", int, (ca_context*, uint32_t, int*)))) { + + ca_free(driver); + driver_destroy(c); + return CA_ERROR_CORRUPT; + } + + ca_free(driver); + + if ((ret = p->driver_open(c)) < 0) { + p->driver_destroy = NULL; + driver_destroy(c); + return ret; + } + + return CA_SUCCESS; +} + +int driver_destroy(ca_context *c) { + struct private_dso *p; + int ret = CA_SUCCESS; + + ca_return_val_if_fail(c, CA_ERROR_INVALID); + ca_return_val_if_fail(c->private_dso, CA_ERROR_STATE); + + p = PRIVATE_DSO(c); + + if (p->driver_destroy) + ret = p->driver_destroy(c); + + if (p->module) + lt_dlclose(p->module); + + if (p->ltdl_initialized) { + lt_dlexit(); + p->ltdl_initialized = FALSE; + } + + ca_free(p); + + c->private_dso = NULL; + + return ret; +} + +int driver_change_device(ca_context *c, const char *device) { + struct private_dso *p; + + ca_return_val_if_fail(c, CA_ERROR_INVALID); + ca_return_val_if_fail(c->private_dso, CA_ERROR_STATE); + + p = PRIVATE_DSO(c); + ca_return_val_if_fail(p->driver_change_device, CA_ERROR_STATE); + + return p->driver_change_device(c, device); +} + +int driver_change_props(ca_context *c, ca_proplist *changed, ca_proplist *merged) { + struct private_dso *p; + + ca_return_val_if_fail(c, CA_ERROR_INVALID); + ca_return_val_if_fail(c->private_dso, CA_ERROR_STATE); + + p = PRIVATE_DSO(c); + ca_return_val_if_fail(p->driver_change_props, CA_ERROR_STATE); + + return p->driver_change_props(c, changed, merged); +} + +int driver_play(ca_context *c, uint32_t id, ca_proplist *pl, ca_finish_callback_t cb, void *userdata) { + struct private_dso *p; + + ca_return_val_if_fail(c, CA_ERROR_INVALID); + ca_return_val_if_fail(c->private_dso, CA_ERROR_STATE); + + p = PRIVATE_DSO(c); + ca_return_val_if_fail(p->driver_play, CA_ERROR_STATE); + + return p->driver_play(c, id, pl, cb, userdata); +} + +int driver_cancel(ca_context *c, uint32_t id) { + struct private_dso *p; + + ca_return_val_if_fail(c, CA_ERROR_INVALID); + ca_return_val_if_fail(c->private_dso, CA_ERROR_STATE); + + p = PRIVATE_DSO(c); + ca_return_val_if_fail(p->driver_cancel, CA_ERROR_STATE); + + return p->driver_cancel(c, id); +} + +int driver_cache(ca_context *c, ca_proplist *pl) { + struct private_dso *p; + + ca_return_val_if_fail(c, CA_ERROR_INVALID); + ca_return_val_if_fail(c->private_dso, CA_ERROR_STATE); + + p = PRIVATE_DSO(c); + ca_return_val_if_fail(p->driver_cache, CA_ERROR_STATE); + + return p->driver_cache(c, pl); +} + +int driver_playing(ca_context *c, uint32_t id, int *playing) { + struct private_dso *p; + + ca_return_val_if_fail(c, CA_ERROR_INVALID); + ca_return_val_if_fail(c->private_dso, CA_ERROR_STATE); + ca_return_val_if_fail(playing, CA_ERROR_INVALID); + + p = PRIVATE_DSO(c); + ca_return_val_if_fail(p->driver_playing, CA_ERROR_STATE); + + return p->driver_playing(c, id, playing); +} diff --git a/.flatpak-builder/cache/objects/e9/9129c09d27830f5b17b72e5fca422ebe7613c397f46372f9516a846f040824.file b/.flatpak-builder/cache/objects/e9/9129c09d27830f5b17b72e5fca422ebe7613c397f46372f9516a846f040824.file new file mode 100644 index 0000000..b51a467 Binary files /dev/null and b/.flatpak-builder/cache/objects/e9/9129c09d27830f5b17b72e5fca422ebe7613c397f46372f9516a846f040824.file differ diff --git a/.flatpak-builder/cache/objects/e9/ca10fec05b11a19cd9f2da6a045b117701e83be98c8cb1e9456c7818adf0b4.file b/.flatpak-builder/cache/objects/e9/ca10fec05b11a19cd9f2da6a045b117701e83be98c8cb1e9456c7818adf0b4.file new file mode 100644 index 0000000..6acf159 --- /dev/null +++ b/.flatpak-builder/cache/objects/e9/ca10fec05b11a19cd9f2da6a045b117701e83be98c8cb1e9456c7818adf0b4.file @@ -0,0 +1,28 @@ +/*-*- Mode: C; c-basic-offset: 8 -*-*/ + +#ifndef foocanberraforkdetecth +#define foocanberraforkdetecth + +/*** + This file is part of libcanberra. + + Copyright 2009 Lennart Poettering + + libcanberra is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation, either version 2.1 of the + License, or (at your option) any later version. + + libcanberra is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with libcanberra. If not, see + . +***/ + +int ca_detect_fork(void); + +#endif diff --git a/.flatpak-builder/cache/objects/ea/1b59b1a76b9b4f8c743c7f68b43bbd08c78e9c03c66f61bee1bf40df3007ad.file b/.flatpak-builder/cache/objects/ea/1b59b1a76b9b4f8c743c7f68b43bbd08c78e9c03c66f61bee1bf40df3007ad.file new file mode 120000 index 0000000..99f56a3 --- /dev/null +++ b/.flatpak-builder/cache/objects/ea/1b59b1a76b9b4f8c743c7f68b43bbd08c78e9c03c66f61bee1bf40df3007ad.file @@ -0,0 +1 @@ +../../share/runtime/locale/nb/share/nb \ No newline at end of file diff --git a/.flatpak-builder/cache/objects/ea/f10335e9cbe9707897530f2c984814b843f03ddba46da8a461337661e7d913.file b/.flatpak-builder/cache/objects/ea/f10335e9cbe9707897530f2c984814b843f03ddba46da8a461337661e7d913.file new file mode 100644 index 0000000..0687fcd --- /dev/null +++ b/.flatpak-builder/cache/objects/ea/f10335e9cbe9707897530f2c984814b843f03ddba46da8a461337661e7d913.file @@ -0,0 +1,24 @@ + + + +%paramlist-dtd; + + + + + + + diff --git a/.flatpak-builder/cache/objects/eb/49129c27b152fa1cc258862a73717f5f9f606c835a5834aec43a06f212e6d6.file b/.flatpak-builder/cache/objects/eb/49129c27b152fa1cc258862a73717f5f9f606c835a5834aec43a06f212e6d6.file new file mode 100644 index 0000000..d4205e6 --- /dev/null +++ b/.flatpak-builder/cache/objects/eb/49129c27b152fa1cc258862a73717f5f9f606c835a5834aec43a06f212e6d6.file @@ -0,0 +1,178 @@ +/* + * This file is generated by the gen_def program (see the gen_def.c file + * for some explanations) + * DO NOT EDIT MANUALLY + */ + + +#define L_ILLEGAL 0 +#define L_SQLCOMMENT 1 +#define L_SPACE 2 +#define L_ID 3 +#define L_ABORT 4 +#define L_AFTER 5 +#define L_ANALYZE 6 +#define L_ASC 7 +#define L_ATTACH 8 +#define L_BEFORE 9 +#define L_BEGIN 10 +#define L_CASCADE 11 +#define L_CAST 12 +#define L_CONFLICT 13 +#define L_DATABASE 14 +#define L_DEFERRED 15 +#define L_DESC 16 +#define L_DETACH 17 +#define L_EACH 18 +#define L_END 19 +#define L_EXCLUSIVE 20 +#define L_EXPLAIN 21 +#define L_FAIL 22 +#define L_FOR 23 +#define L_IGNORE 24 +#define L_IMMEDIATE 25 +#define L_INITIALLY 26 +#define L_INSTEAD 27 +#define L_LIKE 28 +#define L_ILIKE 29 +#define L_MATCH 30 +#define L_PLAN 31 +#define L_QUERY 32 +#define L_KEY 33 +#define L_OF 34 +#define L_OFFSET 35 +#define L_PRAGMA 36 +#define L_RAISE 37 +#define L_REPLACE 38 +#define L_RESTRICT 39 +#define L_ROW 40 +#define L_TEMP 41 +#define L_TRIGGER 42 +#define L_VACUUM 43 +#define L_VIEW 44 +#define L_VIRTUAL 45 +#define L_REINDEX 46 +#define L_RENAME 47 +#define L_CTIME_KW 48 +#define L_IF 49 +#define L_DELIMITER 50 +#define L_COMMIT 51 +#define L_ROLLBACK 52 +#define L_ISOLATION 53 +#define L_LEVEL 54 +#define L_SERIALIZABLE 55 +#define L_READ 56 +#define L_COMMITTED 57 +#define L_UNCOMMITTED 58 +#define L_REPEATABLE 59 +#define L_WRITE 60 +#define L_ONLY 61 +#define L_SAVEPOINT 62 +#define L_RELEASE 63 +#define L_COMMENT 64 +#define L_FORCE 65 +#define L_WAIT 66 +#define L_NOWAIT 67 +#define L_BATCH 68 +#define L_TEXTUAL 69 +#define L_STRING 70 +#define L_OR 71 +#define L_AND 72 +#define L_NOT 73 +#define L_IS 74 +#define L_NOTLIKE 75 +#define L_NOTILIKE 76 +#define L_IN 77 +#define L_ISNULL 78 +#define L_NOTNULL 79 +#define L_DIFF 80 +#define L_EQ 81 +#define L_BETWEEN 82 +#define L_GT 83 +#define L_LEQ 84 +#define L_LT 85 +#define L_GEQ 86 +#define L_REGEXP 87 +#define L_REGEXP_CI 88 +#define L_NOT_REGEXP 89 +#define L_NOT_REGEXP_CI 90 +#define L_SIMILAR 91 +#define L_ESCAPE 92 +#define L_BITAND 93 +#define L_BITOR 94 +#define L_LSHIFT 95 +#define L_RSHIFT 96 +#define L_PLUS 97 +#define L_MINUS 98 +#define L_STAR 99 +#define L_SLASH 100 +#define L_REM 101 +#define L_CONCAT 102 +#define L_COLLATE 103 +#define L_UMINUS 104 +#define L_UPLUS 105 +#define L_BITNOT 106 +#define L_LP 107 +#define L_RP 108 +#define L_JOIN 109 +#define L_INNER 110 +#define L_NATURAL 111 +#define L_LEFT 112 +#define L_RIGHT 113 +#define L_FULL 114 +#define L_CROSS 115 +#define L_UNION 116 +#define L_EXCEPT 117 +#define L_INTERSECT 118 +#define L_PGCAST 119 +#define L_SEMI 120 +#define L_END_OF_FILE 121 +#define L_TRANSACTION 122 +#define L_COMMA 123 +#define L_INTEGER 124 +#define L_TO 125 +#define L_INSERT 126 +#define L_INTO 127 +#define L_VALUES 128 +#define L_DELETE 129 +#define L_FROM 130 +#define L_WHERE 131 +#define L_UPDATE 132 +#define L_SET 133 +#define L_ALL 134 +#define L_SELECT 135 +#define L_LIMIT 136 +#define L_ORDER 137 +#define L_BY 138 +#define L_HAVING 139 +#define L_GROUP 140 +#define L_USING 141 +#define L_ON 142 +#define L_OUTER 143 +#define L_DOT 144 +#define L_AS 145 +#define L_DISTINCT 146 +#define L_CASE 147 +#define L_WHEN 148 +#define L_THEN 149 +#define L_ELSE 150 +#define L_NULL 151 +#define L_FLOAT 152 +#define L_UNSPECVAL 153 +#define L_LSBRACKET 154 +#define L_RSBRACKET 155 +#define L_SIMPLEPARAM 156 +#define L_PNAME 157 +#define L_PDESCR 158 +#define L_PTYPE 159 +#define L_PNULLOK 160 +#define L_RAWSTRING 161 +#define L_LOOP 162 +#define L_ENDLOOP 163 +#define L_DECLARE 164 +#define L_CREATE 165 +#define L_BLOB 166 +gint parser_tokens[] = { +118,119,118,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,118,118,118,118,118,118}; +gint delim_tokens[] = { +7,8,11,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,13,12,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,9,10,1,1,14,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,15,16,17,18,19,20,21,22,23,1,2,3,4,5,6}; diff --git a/.flatpak-builder/cache/objects/eb/609c8a383b172dcd84ff46ad66b00e0d0c221d33fbf5fb69185464ef052db3.file b/.flatpak-builder/cache/objects/eb/609c8a383b172dcd84ff46ad66b00e0d0c221d33fbf5fb69185464ef052db3.file new file mode 100644 index 0000000..cdb4380 --- /dev/null +++ b/.flatpak-builder/cache/objects/eb/609c8a383b172dcd84ff46ad66b00e0d0c221d33fbf5fb69185464ef052db3.file @@ -0,0 +1,3387 @@ +/* + * Copyright (C) 2001 - 2003 Rodrigo Moya + * Copyright (C) 2002 - 2003 Gonzalo Paniagua Javier + * Copyright (C) 2003 - 2004 Laurent Sansonetti + * Copyright (C) 2003 Paisa Seeluangsawat + * Copyright (C) 2004 Caolan McNamara + * Copyright (C) 2004 Jürg Billeter + * Copyright (C) 2004 - 2013 Murray Cumming + * Copyright (C) 2005 - 2015 Vivien Malerba + * Copyright (C) 2007 - 2009 Armin Burgmeier + * Copyright (C) 2008 - 2009 Bas Driessen + * Copyright (C) 2008 Phil Longstaff + * Copyright (C) 2008 Przemysław Grzegorczyk + * Copyright (C) 2010 David King + * Copyright (C) 2010 Jonh Wendell + * Copyright (C) 2011-2018 Daniel Espinosa + * Copyright (C) 2018 - 2019 Pavlo Solntsev + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#undef GDA_DISABLE_DEPRECATED + +#define G_LOG_DOMAIN "GDA-util" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef HAVE_LOCALE_H +#include +#endif +#include +#include +#include +#include +#include +#include +#include + +#define KEYWORDS_HASH_NO_STATIC +#include +#include "keywords_hash.code" /* this one is dynamically generated */ + +/* + * Win32 adaptations + */ +#ifdef G_OS_WIN32 +#define strtok_r(s,d,p) strtok(s,d) +#endif + + +/** + * gda_g_type_to_string: + * @type: Type to convert from. + * + * Converts a GType to its string representation (use gda_g_type_from_string() for the + * operation in the other direction). + * + * This function wraps g_type_name() but for common types it provides an easier to + * understand and remember name. For Example the G_TYPE_STRING is converted to "string" + * whereas g_type_name() converts it to "gchararray". + * + * Returns: (transfer none): the GDA's string representing the given #GType or the name + * returned by #g_type_name. + */ +const gchar * +gda_g_type_to_string (GType type) +{ + if (type == G_TYPE_INVALID) + return "null"; + else if (type == GDA_TYPE_NULL) + return "null"; + else if (type == G_TYPE_INT) + return "int"; + else if (type == G_TYPE_STRING) + return "string"; + else if (type == G_TYPE_DATE) + return "date"; + else if (type == GDA_TYPE_TIME) + return "time"; + else if (type == G_TYPE_DATE_TIME) + return "timestamp"; + else if (type == G_TYPE_BOOLEAN) + return "boolean"; + else if (type == GDA_TYPE_BLOB) + return "blob"; + else if (type == GDA_TYPE_BINARY) + return "binary"; + else if (type == GDA_TYPE_TEXT) + return "text"; + else + return g_type_name (type); +} + +/** + * gda_g_type_from_string: + * @str: the name of a #GType, as returned by gda_g_type_to_string(). + * + * Converts a named type to ts GType type (also see the gda_g_type_to_string() function). + * + * This function is a wrapper around the g_type_from_name() function, but also recognizes + * some type synonyms such as: + * + * "int" for G_TYPE_INT + * "uint" for G_TYPE_UINT + * "int64" for G_TYPE_INT64 + * "uint64" for G_TYPE_UINT64 + * "char" for G_TYPE_CHAR + * "uchar" for G_TYPE_UCHAR + * "short" for GDA_TYPE_SHORT + * "ushort" for GDA_TYPE_USHORT + * "string" for G_TYPE_STRING + * "date" for G_TYPE_DATE + * "time" for GDA_TYPE_TIME + * "timestamp" for G_TYPE_DATE_TIME + * "boolean" for G_TYPE_BOOLEAN + * "blob" for GDA_TYPE_BLOB + * "binary" for GDA_TYPE_BINARY + * "null" for GDA_TYPE_NULL + * + * + * Returns: the #GType represented by the given @str, or #G_TYPE_INVALID if not found + */ +GType +gda_g_type_from_string (const gchar *str) +{ + GType type; + g_return_val_if_fail (str != NULL, G_TYPE_INVALID); + + type = g_type_from_name (str); + if (type == 0) { + if (!g_ascii_strcasecmp (str, "int")) + type = G_TYPE_INT; + else if (!g_ascii_strcasecmp (str, "uint")) + type = G_TYPE_UINT; + else if (!g_ascii_strcasecmp (str, "string")) + type = G_TYPE_STRING; + else if (!g_ascii_strcasecmp (str, "text")) + type = GDA_TYPE_TEXT; + else if (!g_ascii_strcasecmp (str, "date")) + type = G_TYPE_DATE; + else if (!g_ascii_strcasecmp (str, "time")) + type = GDA_TYPE_TIME; + else if (!g_ascii_strcasecmp (str, "timestamp")) + type = G_TYPE_DATE_TIME; + else if (!strcmp (str, "boolean")) + type = G_TYPE_BOOLEAN; + else if (!strcmp (str, "blob")) + type = GDA_TYPE_BLOB; + else if (!strcmp (str, "binary")) + type = GDA_TYPE_BINARY; + else if (!strcmp (str, "null")) + type = GDA_TYPE_NULL; + else if (!strcmp (str, "short")) + type = GDA_TYPE_SHORT; + else if (!strcmp (str, "ushort")) + type = GDA_TYPE_USHORT; + else if (!g_ascii_strcasecmp (str, "int64")) + type = G_TYPE_INT64; + else if (!g_ascii_strcasecmp (str, "uint64")) + type = G_TYPE_UINT64; + else if (!g_ascii_strcasecmp (str, "char")) + type = G_TYPE_CHAR; + else if (!g_ascii_strcasecmp (str, "uchar")) + type = G_TYPE_UCHAR; + else if (!g_ascii_strcasecmp (str, "gshort")) + type = GDA_TYPE_SHORT; + else if (!g_ascii_strcasecmp (str, "gushort")) + type = GDA_TYPE_USHORT; + else + /* could not find a valid GType for @str */ + type = G_TYPE_INVALID; + } + + return type; +} + +/** + * gda_default_escape_string: + * @string: string to escape + * + * Escapes @string to make it understandable by a DBMS. The escape method is very common and replaces any + * occurrence of "'" with "''" and "\" with "\\" + * + * Returns: (transfer full) (nullable): a new string + */ +gchar * +gda_default_escape_string (const gchar *string) +{ + gchar *ptr, *ret, *retptr; + gint size; + + if (!string) + return NULL; + + /* determination of the new string size */ + ptr = (gchar *) string; + size = 1; + while (*ptr) { + if ((*ptr == '\'') ||(*ptr == '\\')) + size += 2; + else + size += 1; + ptr++; + } + + ptr = (gchar *) string; + ret = g_new0 (gchar, size); + retptr = ret; + while (*ptr) { + if (*ptr == '\'') { + *retptr = '\''; + *(retptr+1) = *ptr; + retptr += 2; + } + else if (*ptr == '\\') { + *retptr = '\\'; + *(retptr+1) = *ptr; + retptr += 2; + } + else { + *retptr = *ptr; + retptr ++; + } + ptr++; + } + *retptr = '\0'; + + return ret; +} + +/** + * gda_default_unescape_string: + * @string: string to unescape + * + * Do the reverse of gda_default_escape_string(): transforms any "''" into "'", any + * "\\" into "\" and any "\'" into "'". + * + * Returns: (transfer full) (nullable): a new unescaped string, or %NULL in an error was found in @string + */ +gchar * +gda_default_unescape_string (const gchar *string) +{ + glong total; + gchar *ptr; + gchar *retval; + glong offset = 0; + + if (!string) + return NULL; + + total = strlen (string); + retval = g_memdup (string, total+1); + ptr = (gchar *) retval; + while (offset < total) { + /* we accept the "''" as a synonym of "\'" */ + if (*ptr == '\'') { + if (*(ptr+1) == '\'') { + memmove (ptr+1, ptr+2, total - offset); + offset += 2; + } + else { + g_free (retval); + return NULL; + } + } + if (*ptr == '\\') { + if (*(ptr+1) == '\\') { + memmove (ptr+1, ptr+2, total - offset); + offset += 2; + } + else { + if (*(ptr+1) == '\'') { + *ptr = '\''; + memmove (ptr+1, ptr+2, total - offset); + offset += 2; + } + else { + g_free (retval); + return NULL; + } + } + } + else + offset ++; + + ptr++; + } + + return retval; +} + +/** + * gda_utility_check_data_model_v: (rename-to gda_utility_check_data_model) + * @model: a #GdaDataModel object + * @nbcols: the minimum requested number of columns. Lenght of @types + * @types: (array length=nbcols): array with @nbcols length of type GType or null (if any data type is accepted) + * + * Check the column types of a GdaDataModel. + * + * Returns: %TRUE if the data model's columns match the provided data types and number + * + * Since: 4.2.6 + */ +gboolean +gda_utility_check_data_model_v (GdaDataModel *model, gint nbcols, GType* types) +{ + gboolean retval = TRUE; + gint i; + + g_return_val_if_fail (model && GDA_IS_DATA_MODEL (model), FALSE); + + /* number of columns */ + if (gda_data_model_get_n_columns (model) < nbcols) + return FALSE; + + /* type of each column */ + if (nbcols > 0) { + GdaColumn *att; + GType mtype, rtype; + i = 0; + while ((i 0) { + GdaColumn *att; + GType mtype, rtype; + gint argtype; + va_list ap; + + va_start (ap, nbcols); + i = 0; + while ((i= 0) { + rtype = (GType) argtype; + if (mtype != rtype) { + retval = FALSE; +#ifdef GDA_DEBUG + g_print ("Column %d: Expected %s, got %s\n", + i, gda_g_type_to_string (rtype), gda_g_type_to_string (mtype)); +#endif + } + } + + i++; + } + va_end (ap); + } + + return retval; + +} + +/** + * gda_utility_data_model_dump_data_to_xml: + * @model: a #GdaDataModel + * @parent: the parent XML node + * @cols: (nullable) (array length=nb_cols): an array containing which columns of @model will be exported, or %NULL for all columns + * @nb_cols: the number of columns in @cols + * @rows: (nullable) (array length=nb_rows): an array containing which rows of @model will be exported, or %NULL for all rows + * @nb_rows: the number of rows in @rows + * @use_col_ids: set to %TRUE to add column ID information + * + * Dump the data in a #GdaDataModel into a xmlNodePtr (as used in libxml). + * + * Warning: this function uses a #GdaDataModelIter iterator, and if @model does not offer a random access + * (check using gda_data_model_get_access_flags()), the iterator will be the same as normally used + * to access data in @model previously to calling this method, and this iterator will be moved (point to + * another row). + * + * Returns: %TRUE if no error occurred + */ +gboolean +gda_utility_data_model_dump_data_to_xml (GdaDataModel *model, xmlNodePtr parent, + const gint *cols, gint nb_cols, + const gint *rows, gint nb_rows, + gboolean use_col_ids) +{ + gboolean retval = TRUE; + gint *rcols, rnb_cols; + gchar **col_ids = NULL; + xmlNodePtr data = NULL; + GdaDataModelIter *iter; + + /* compute columns if not provided */ + if (!cols) { + gint i; + rnb_cols = gda_data_model_get_n_columns (model); + rcols = g_new (gint, rnb_cols); + for (i = 0; i < rnb_cols; i++) + rcols [i] = i; + } + else { + rcols = (gint *) cols; + rnb_cols = nb_cols; + } + + if (use_col_ids) { + gint c; + col_ids = g_new0 (gchar *, rnb_cols); + for (c = 0; c < rnb_cols; c++) { + GdaColumn *column; + gchar *id; + + column = gda_data_model_describe_column (model, rcols [c]); + g_object_get (G_OBJECT (column), "id", &id, NULL); + + if (id && *id) + col_ids [c] = g_strdup (id); + else + col_ids [c] = g_strdup_printf ("_%d", c); + + g_free (id); + } + } + + /* add the model data to the XML output */ + iter = gda_data_model_create_iter (model); + if (iter && (gda_data_model_iter_get_row (iter) == -1) && ! gda_data_model_iter_move_next (iter)) { + g_object_unref (iter); + iter = NULL; + } + if (iter) { + xmlNodePtr row; + + data = xmlNewChild (parent, NULL, (xmlChar*)"gda_array_data", NULL); + for (; retval && gda_data_model_iter_is_valid (iter); gda_data_model_iter_move_next (iter)) { + gint c; + if (rows) { + gint r; + for (r = 0; r < nb_rows; r++) { + if (gda_data_model_iter_get_row (iter) == rows[r]) + break; + } + if (r == nb_rows) + continue; + } + + row = xmlNewChild (data, NULL, (xmlChar*)"gda_array_row", NULL); + for (c = 0; c < rnb_cols; c++) { + GValue *value; + gchar *str = NULL; + xmlNodePtr field = NULL; + + value = (GValue*) gda_data_model_iter_get_value_at (iter, rcols[c]); + if (value && !gda_value_is_null ((GValue *) value)) { + if (G_VALUE_TYPE (value) == G_TYPE_BOOLEAN) + str = g_strdup (g_value_get_boolean (value) ? "TRUE" : "FALSE"); + else if (G_VALUE_TYPE (value) == G_TYPE_STRING) { + if (g_value_get_string (value)) + str = gda_value_stringify (value); + } + else if (G_VALUE_TYPE (value) == GDA_TYPE_BLOB) { + /* force reading the whole blob */ + GdaBlob *blob = (GdaBlob*)gda_value_get_blob (value); + if (blob) { + GdaBinary *bin = gda_blob_get_binary (blob); + if (gda_blob_get_op (blob) && + (gda_binary_get_size (bin) != gda_blob_op_get_length (gda_blob_get_op (blob)))) + gda_blob_op_read_all (gda_blob_get_op (blob), (GdaBlob*) blob); + } + str = gda_value_stringify (value); + } + else + str = gda_value_stringify (value); + } + if (!use_col_ids) { + if (str && *str) + field = xmlNewTextChild (row, NULL, (xmlChar*)"gda_value", (xmlChar*)str); + else + field = xmlNewChild (row, NULL, (xmlChar*)"gda_value", NULL); + } + else { + field = xmlNewTextChild (row, NULL, (xmlChar*)"gda_array_value", (xmlChar*)str); + xmlSetProp(field, (xmlChar*)"colid", (xmlChar*)col_ids [c]); + } + + if (!str) + xmlSetProp(field, (xmlChar*)"isnull", (xmlChar*)"t"); + + g_free (str); + } + } + g_object_unref (iter); + } + + if (!cols) + g_free (rcols); + + if (use_col_ids) { + gint c; + for (c = 0; c < rnb_cols; c++) + g_free (col_ids [c]); + g_free (col_ids); + } + + if (!retval) { + xmlUnlinkNode (data); + xmlFreeNode (data); + } + + return retval; +} + + +/** + * gda_utility_data_model_find_column_description: + * @model: a #GdaDataSelect data model + * @field_name: field name + * + * Finds the description of a field into Metadata from a #GdaDataModel. + * + * Returns: (transfer none) (nullable): The field's description, or NULL if description is not set + */ +const gchar * +gda_utility_data_model_find_column_description (GdaDataSelect *model, const gchar *field_name) +{ + g_return_val_if_fail (GDA_IS_DATA_SELECT (model), NULL); + g_return_val_if_fail (field_name, NULL); + + GdaConnection *connection = gda_data_select_get_connection ((GdaDataSelect *) model); + + GdaStatement *statement; + g_object_get (G_OBJECT (model), "select-stmt", &statement, NULL); + if (!statement) + return NULL; + + GdaSqlStatement *sql_statement; + g_object_get (G_OBJECT (statement), "structure", &sql_statement, NULL); + g_object_unref (statement); + + if (!gda_sql_statement_check_validity (sql_statement, connection, NULL)) { + gda_sql_statement_free (sql_statement); + return NULL; + } + + GSList *fields; + for (fields = ((GdaSqlStatementSelect *) sql_statement->contents)->expr_list; + fields; + fields = fields->next) { + + GdaSqlSelectField *select_field = fields->data; + if (select_field->validity_meta_table_column) { + GdaMetaTableColumn *meta_table_column = select_field->validity_meta_table_column; + + if (! strcmp (meta_table_column->column_name, field_name)) { + gda_sql_statement_free (sql_statement); + return meta_table_column->desc; + } + } + } + + gda_sql_statement_free (sql_statement); + return NULL; +} + +/** + * gda_utility_holder_load_attributes: + * @holder: a #GdaHolder + * @node: an xmlNodePtr with a <parameter> tag + * @sources: (element-type Gda.DataModel) (nullable): a list of #GdaDataModel + * @error: a place to store errors, or %NULL + * + * Note: this method may set the "source" custom string property + * + * Returns: %TRUE if no error occurred + */ +gboolean +gda_utility_holder_load_attributes (GdaHolder *holder, xmlNodePtr node, GSList *sources, GError **error) +{ + xmlChar *str; + xmlNodePtr vnode; + gboolean retval = TRUE; + + /* set properties from the XML spec */ + str = xmlGetProp (node, BAD_CAST "id"); + if (str) { + g_object_set (G_OBJECT (holder), "id", (gchar*)str, NULL); + xmlFree (str); + } + + str = xmlGetProp (node, BAD_CAST "name"); + if (str) { + g_object_set (G_OBJECT (holder), "name", (gchar*)str, NULL); + xmlFree (str); + } + str = xmlGetProp (node, BAD_CAST "descr"); + if (str) { + g_object_set (G_OBJECT (holder), "description", (gchar*)str, NULL); + xmlFree (str); + } + str = xmlGetProp (node, BAD_CAST "nullok"); + if (str) { + gda_holder_set_not_null (holder, (*str == 'T') || (*str == 't') ? FALSE : TRUE); + xmlFree (str); + } + else + gda_holder_set_not_null (holder, TRUE); + + str = xmlGetProp (node, BAD_CAST "plugin"); + if (str) { + GValue *value; +#define GDAUI_ATTRIBUTE_PLUGIN "__gdaui_attr_plugin" + value = gda_value_new_from_string ((gchar*) str, G_TYPE_STRING); + g_object_set (holder, "plugin", value, NULL); + gda_value_free (value); + xmlFree (str); + } + + str = xmlGetProp (node, BAD_CAST "source"); + if (str) + g_object_set_data_full (G_OBJECT (holder), "source", str, xmlFree); + + /* set restricting source if specified */ + if (str && sources) { + gchar *ptr1, *ptr2 = NULL, *tok = NULL; + gchar *source; + + source = g_strdup ((gchar*)str); + ptr1 = strtok_r (source, ":", &tok); + if (ptr1) + ptr2 = strtok_r (NULL, ":", &tok); + + if (ptr1 && ptr2) { + GSList *tmp = sources; + GdaDataModel *model = NULL; + while (tmp && !model) { + gchar *mname = g_object_get_data (G_OBJECT (tmp->data), "name"); + if (mname && !strcmp (mname, ptr1)) + model = GDA_DATA_MODEL (tmp->data); + tmp = g_slist_next (tmp); + } + + if (model) { + gint fno; + + fno = atoi (ptr2); /* Flawfinder: ignore */ + if ((fno < 0) || + (fno >= gda_data_model_get_n_columns (model))) + g_warning (_("Field number %d not found in source named '%s'"), fno, ptr1); + else { + if (gda_holder_set_source_model (holder, model, fno, error)) { + gchar *str; + /* rename the wrapper with the current holder's name */ + g_object_get (G_OBJECT (holder), "name", &str, NULL); + g_object_set_data_full (G_OBJECT (model), "newname", str, g_free); + g_object_get (G_OBJECT (holder), "description", &str, NULL); + g_object_set_data_full (G_OBJECT (model), "newdescr", str, g_free); + } + else + retval = FALSE; + } + } + } + g_free (source); + } + + /* specified value */ + vnode = node->children; + if (vnode) { + xmlChar *this_lang, *isnull; + const gchar *lang = setlocale(LC_ALL, NULL); + + while (vnode) { + if (xmlNodeIsText (vnode)) { + vnode = vnode->next; + continue; + } + + if (!strcmp ((gchar*)vnode->name, "attribute")) { + xmlChar *att_name; + att_name = xmlGetProp (vnode, (xmlChar*) "name"); + if (att_name) { + g_object_set_data_full ((GObject*) holder, (const gchar*) att_name, g_strdup ((gchar*) xmlNodeGetContent (vnode)), (GDestroyNotify) g_free); + } + vnode = vnode->next; + continue; + } + if (strcmp ((gchar*)vnode->name, "gda_value")) { + vnode = vnode->next; + continue; + } + + /* don't care about entries for the wrong locale */ + this_lang = xmlGetProp (vnode, (xmlChar*)"lang"); + if (this_lang && strncmp ((gchar*)this_lang, lang, strlen ((gchar*)this_lang))) { + xmlFree (this_lang); + vnode = vnode->next; + continue; + } + + isnull = xmlGetProp(vnode, (xmlChar*)"isnull"); + if (isnull) { + if ((*isnull == 'f') || (*isnull == 'F')) { + xmlFree (isnull); + isnull = NULL; + } + } + + if (!isnull) { + gchar* nodeval = (gchar*)xmlNodeGetContent (vnode); + + if (! gda_holder_set_value_str (holder, NULL, nodeval, error)) + retval = FALSE; + xmlFree(nodeval); + } + else { + xmlFree (isnull); + if (! gda_holder_set_value (holder, NULL, error)) + retval = FALSE; + } + + vnode = vnode->next; + } + } + + return retval; +} + + +#define GDA_PARAM_ENCODE_TOKEN "__gda" +/** + * gda_text_to_alphanum: + * @text: the text to convert + * + * The "encoding" consists in replacing non + * alphanumeric character with the string "__gdaXX" where XX is the hex. representation + * of the non alphanumeric char. + * + * Returns: (transfer full): a new string + */ +gchar * +gda_text_to_alphanum (const gchar *text) +{ + GString *string; + const gchar* ptr = text; + + /*g_print ("%s (%s) ", __FUNCTION__, text);*/ + string = g_string_new (""); + for (ptr = text; ptr && *ptr; ptr++) { + if (! (((*ptr >= '0') && (*ptr <= '9')) || + ((*ptr >= 'A') && (*ptr <= 'Z')) || + ((*ptr >= 'a') && (*ptr <= 'z')))) { + g_string_append (string, GDA_PARAM_ENCODE_TOKEN); + g_string_append_printf (string, "%0x", *ptr); + } + else + g_string_append_c (string, *ptr); + } + + return g_string_free (string, FALSE); +} + +/** + * gda_alphanum_to_text: + * @text: a string + * + * Does the opposite of gda_text_to_alphanum(), in the same string + * + * Returns: (transfer full) (nullable): @text if conversion succeeded or %NULL if an error occurred + */ +gchar * +gda_alphanum_to_text (gchar *text) +{ + gchar* ptr = text; + gint length = strlen (text); + static gint toklength = 0; + + if (toklength == 0) + toklength = strlen (GDA_PARAM_ENCODE_TOKEN); + /*g_print ("%s (%s) ", __FUNCTION__, text);*/ + for (ptr = text; ptr && *ptr; ) { + if ((length >= toklength + 2) && !strncmp (ptr, GDA_PARAM_ENCODE_TOKEN, toklength)) { + gchar *ptr2 = ptr + toklength; + char c = *ptr2; + gchar val; + if ((c >= 'a') && (c <= 'f')) + val = (c - 'a' + 10) * 16; + else if ((c >= '0') && (c <= '9')) + val = (c - '0') * 16; + else + return NULL; + c = *(ptr2+1); + if ((c >= 'a') && (c <= 'f')) + val += c - 'a' + 10; + else if ((c >= '0') && (c <= '9')) + val += c - '0'; + else + return NULL; + *ptr = val; + ptr++; + length -= toklength + 1; + memmove (ptr, ptr + toklength + 1, length); + } + else { + ptr ++; + length --; + } + } + /*g_print ("=>#%s#\n", text);*/ + return text; +} + +/* + * Checks related to the structure of the SELECT statement before computing the INSERT, UPDATE and DELETE + * corresponding statements. + */ +static gboolean +dml_statements_check_select_structure (GdaConnection *cnc, GdaSqlStatement *sel_struct, GError **error) +{ + GdaSqlStatementSelect *stsel; + stsel = (GdaSqlStatementSelect*) sel_struct->contents; + if (!stsel->from) { + g_set_error (error, GDA_SQL_ERROR, GDA_SQL_STRUCTURE_CONTENTS_ERROR, + "%s", _("SELECT statement has no FROM part")); + return FALSE; + } + if (stsel->from->targets && stsel->from->targets->next) { + g_set_error (error, GDA_SQL_ERROR, GDA_SQL_STRUCTURE_CONTENTS_ERROR, + "%s", _("SELECT statement involves more than one table or expression")); + return FALSE; + } + GdaSqlSelectTarget *target; + target = (GdaSqlSelectTarget*) stsel->from->targets->data; + if (!target->table_name) { + g_set_error (error, GDA_SQL_ERROR, GDA_SQL_STRUCTURE_CONTENTS_ERROR, + "%s", _("SELECT statement involves more than one table or expression")); + return FALSE; + } + if (!gda_sql_statement_check_validity (sel_struct, cnc, error)) + return FALSE; + + /* check that we want to modify a table */ + g_assert (target->validity_meta_object); /* because gda_sql_statement_check_validity() returned TRUE */ + if (target->validity_meta_object->obj_type != GDA_META_DB_TABLE) { + g_set_error (error, GDA_SQL_ERROR, GDA_SQL_STRUCTURE_CONTENTS_ERROR, + "%s", _("Can only build modification statement for tables")); + return FALSE; + } + + return TRUE; +} + +/** + * gda_compute_unique_table_row_condition_with_cnc: + * @cnc: (nullable): a #GdaConnection, or %NULL + * @stsel: a #GdaSqlSelectStatement + * @mtable: a #GdaMetaTable + * @require_pk: set to %TRUE if a primary key is required + * @error: a place to store errors, or %NULL + * + * Computes a #GdaSqlExpr expression which can be used in the WHERE clause of an UPDATE + * or DELETE statement when a row from the result of the @stsel statement has to be modified. + * + * If @require_pk is %TRUE then this function will return a non %NULL #GdaSqlExpr only if it can + * use a primary key of @mtable. If @require_pk is %FALSE, then it will try to use a primary key of @mtable, + * and if none is available, it will use all the columns of @mtable to compute a condition statement. + * + * Returns: (transfer full) (nullable): a new #GdaSqlExpr, or %NULL if an error occurred. + * + * Since: 4.0.3 + */ +GdaSqlExpr* +gda_compute_unique_table_row_condition_with_cnc (GdaConnection *cnc, GdaSqlStatementSelect *stsel, + GdaMetaTable *mtable, gboolean require_pk, GError **error) +{ + gint i; + GdaSqlExpr *expr; + GdaSqlOperation *and_cond = NULL; + + g_return_val_if_fail (!cnc || GDA_IS_CONNECTION (cnc), NULL); + + expr = gda_sql_expr_new (NULL); /* no parent */ + + if (mtable->pk_cols_nb == 0) { + g_set_error (error, GDA_SQL_ERROR, GDA_SQL_STRUCTURE_CONTENTS_ERROR, + "%s", _("Table does not have any primary key")); + if (require_pk) + goto onerror; + else + goto allcolums; + } + else if (mtable->pk_cols_nb > 1) { + and_cond = gda_sql_operation_new (GDA_SQL_ANY_PART (expr)); + and_cond->operator_type = GDA_SQL_OPERATOR_TYPE_AND; + expr->cond = and_cond; + } + for (i = 0; i < mtable->pk_cols_nb; i++) { + GdaSqlSelectField *sfield = NULL; + GdaMetaTableColumn *tcol; + GSList *list; + gint index; + + tcol = (GdaMetaTableColumn *) g_slist_nth_data (mtable->columns, mtable->pk_cols_array[i]); + for (index = 0, list = stsel->expr_list; + list; + index++, list = list->next) { + sfield = (GdaSqlSelectField *) list->data; + if (sfield->validity_meta_table_column == tcol) + break; + else + sfield = NULL; + } + if (!sfield) { + g_set_error (error, GDA_SQL_ERROR, GDA_SQL_STRUCTURE_CONTENTS_ERROR, + "%s", _("Table's primary key is not part of SELECT")); + if (require_pk) + goto onerror; + else + goto allcolums; + } + else { + GdaSqlOperation *op; + GdaSqlExpr *opexpr; + GdaSqlParamSpec *pspec; + + /* equal condition */ + if (and_cond) { + opexpr = gda_sql_expr_new (GDA_SQL_ANY_PART (and_cond)); + op = gda_sql_operation_new (GDA_SQL_ANY_PART (opexpr)); + opexpr->cond = op; + and_cond->operands = g_slist_append (and_cond->operands, opexpr); + } + else { + op = gda_sql_operation_new (GDA_SQL_ANY_PART (expr)); + expr->cond = op; + } + op->operator_type = GDA_SQL_OPERATOR_TYPE_EQ; + /* left operand */ + gchar *str; + opexpr = gda_sql_expr_new (GDA_SQL_ANY_PART (op)); + str = gda_sql_identifier_quote (tcol->column_name, cnc, NULL, FALSE, FALSE); + g_value_take_string (opexpr->value = gda_value_new (G_TYPE_STRING), str); + + op->operands = g_slist_append (op->operands, opexpr); + + /* right operand */ + opexpr = gda_sql_expr_new (GDA_SQL_ANY_PART (op)); + pspec = g_new0 (GdaSqlParamSpec, 1); + pspec->name = g_strdup_printf ("-%d", index); + pspec->g_type = (tcol->gtype != GDA_TYPE_NULL) ? tcol->gtype: G_TYPE_STRING; + pspec->nullok = tcol->nullok; + opexpr->param_spec = pspec; + op->operands = g_slist_append (op->operands, opexpr); + } + } + return expr; + + allcolums: + + gda_sql_expr_free (expr); + expr = gda_sql_expr_new (NULL); /* no parent */ + + GSList *columns; + if (! mtable->columns) { + g_set_error (error, GDA_SQL_ERROR, GDA_SQL_STRUCTURE_CONTENTS_ERROR, + "%s", _("Table does not have any column")); + goto onerror; + } + else if (mtable->columns->next) { + and_cond = gda_sql_operation_new (GDA_SQL_ANY_PART (expr)); + and_cond->operator_type = GDA_SQL_OPERATOR_TYPE_AND; + expr->cond = and_cond; + } + for (columns = mtable->columns; columns; columns = columns->next) { + GdaSqlSelectField *sfield = NULL; + GdaMetaTableColumn *tcol; + GSList *list; + gint index; + + tcol = (GdaMetaTableColumn *) columns->data; + for (index = 0, list = stsel->expr_list; + list; + index++, list = list->next) { + sfield = (GdaSqlSelectField *) list->data; + if (sfield->validity_meta_table_column == tcol) + break; + else + sfield = NULL; + } + if (!sfield) { + g_set_error (error, GDA_SQL_ERROR, GDA_SQL_STRUCTURE_CONTENTS_ERROR, + _("Table's column '%s' is not part of SELECT"), + tcol->column_name); + goto onerror; + } + else { + GdaSqlOperation *op; + GdaSqlExpr *opexpr; + GdaSqlParamSpec *pspec; + + /* equal condition */ + if (and_cond) { + opexpr = gda_sql_expr_new (GDA_SQL_ANY_PART (and_cond)); + op = gda_sql_operation_new (GDA_SQL_ANY_PART (opexpr)); + opexpr->cond = op; + and_cond->operands = g_slist_append (and_cond->operands, opexpr); + } + else { + op = gda_sql_operation_new (GDA_SQL_ANY_PART (expr)); + expr->cond = op; + } + op->operator_type = GDA_SQL_OPERATOR_TYPE_EQ; + /* left operand */ + gchar *str; + opexpr = gda_sql_expr_new (GDA_SQL_ANY_PART (op)); + str = gda_sql_identifier_quote (tcol->column_name, cnc, NULL, FALSE, FALSE); + g_value_take_string (opexpr->value = gda_value_new (G_TYPE_STRING), str); + + op->operands = g_slist_append (op->operands, opexpr); + + /* right operand */ + opexpr = gda_sql_expr_new (GDA_SQL_ANY_PART (op)); + pspec = g_new0 (GdaSqlParamSpec, 1); + pspec->name = g_strdup_printf ("-%d", index); + pspec->g_type = (tcol->gtype != GDA_TYPE_NULL) ? tcol->gtype: G_TYPE_STRING; + pspec->nullok = tcol->nullok; + opexpr->param_spec = pspec; + op->operands = g_slist_append (op->operands, opexpr); + } + } + return expr; + + onerror: + gda_sql_expr_free (expr); + return NULL; +} + +/** + * gda_compute_unique_table_row_condition: + * @stsel: a #GdaSqlSelectStatement + * @mtable: a #GdaMetaTable + * @require_pk: set to TRUE if a primary key ir required + * @error: a place to store errors, or %NULL + * + * Computes a #GdaSqlExpr expression which can be used in the WHERE clause of an UPDATE + * or DELETE statement when a row from the result of the @stsel statement has to be modified. + * + * Returns: (transfer full) (nullable): a new #GdaSqlExpr, or %NULL if an error occurred. + */ +GdaSqlExpr* +gda_compute_unique_table_row_condition (GdaSqlStatementSelect *stsel, GdaMetaTable *mtable, gboolean require_pk, GError **error) +{ + return gda_compute_unique_table_row_condition_with_cnc (NULL, stsel, mtable, require_pk, error); +} + +/** + * gda_compute_dml_statements: + * @cnc: a #GdaConnection + * @select_stmt: a SELECT #GdaStatement (compound statements not handled) + * @require_pk: TRUE if the created statement have to use a primary key + * @insert_stmt: (nullable) (out callee-allocates): a place to store the created INSERT statement, or %NULL + * @update_stmt: (nullable) (out callee-allocates): a place to store the created UPDATE statement, or %NULL + * @delete_stmt: (nullable) (out callee-allocates): a place to store the created DELETE statement, or %NULL + * @error: (nullable): a place to store errors, or %NULL + * + * Creates an INSERT, an UPDATE and a DELETE statement from a SELECT statement + * using the database metadata available in @cnc's meta store. Each statements are computed only if + * the corresponding place to store the created statement is not %NULL. + * + * returns: %TRUE if no error occurred + */ +gboolean +gda_compute_dml_statements (GdaConnection *cnc, GdaStatement *select_stmt, gboolean require_pk, + GdaStatement **insert_stmt, GdaStatement **update_stmt, GdaStatement **delete_stmt, GError **error) +{ + GdaSqlStatement *sel_struct; + GdaSqlStatementSelect *stsel; + GdaStatement *ret_insert = NULL; + GdaStatement *ret_update = NULL; + GdaStatement *ret_delete = NULL; + GdaMetaStruct *mstruct; + gboolean retval = TRUE; + GdaSqlSelectTarget *target; + + GdaSqlStatement *sql_ist = NULL; + GdaSqlStatementInsert *ist = NULL; + GdaSqlStatement *sql_ust = NULL; + GdaSqlStatementUpdate *ust = NULL; + GdaSqlStatement *sql_dst = NULL; + GdaSqlStatementDelete *dst = NULL; + + g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE); + g_return_val_if_fail (GDA_IS_STATEMENT (select_stmt), FALSE); + g_return_val_if_fail (gda_statement_get_statement_type (select_stmt) == GDA_SQL_STATEMENT_SELECT, FALSE); + + /*g_print ("*** %s\n", gda_statement_serialize (select_stmt));*/ + + g_object_get (G_OBJECT (select_stmt), "structure", &sel_struct, NULL); + if (!dml_statements_check_select_structure (cnc, sel_struct, error)) { + retval = FALSE; + goto cleanup; + } + + /* normalize the statement */ + if (!gda_sql_statement_normalize (sel_struct, cnc, error)) { + retval = FALSE; + goto cleanup; + } + + mstruct = sel_struct->validity_meta_struct; + g_assert (mstruct); /* because gda_sql_statement_check_validity() returned TRUE */ + + /* check that the condition will be buildable */ + stsel = (GdaSqlStatementSelect*) sel_struct->contents; + target = (GdaSqlSelectTarget*) stsel->from->targets->data; + + /* actual statement structure's computation */ + gchar *tmp; + tmp = gda_sql_identifier_quote (target->table_name, cnc, NULL, FALSE, FALSE); + if (insert_stmt) { + sql_ist = gda_sql_statement_new (GDA_SQL_STATEMENT_INSERT); + ist = (GdaSqlStatementInsert*) sql_ist->contents; + g_assert (GDA_SQL_ANY_PART (ist)->type == GDA_SQL_ANY_STMT_INSERT); + + ist->table = gda_sql_table_new (GDA_SQL_ANY_PART (ist)); + ist->table->table_name = g_strdup ((gchar *) target->table_name); + } + + if (update_stmt) { + sql_ust = gda_sql_statement_new (GDA_SQL_STATEMENT_UPDATE); + ust = (GdaSqlStatementUpdate*) sql_ust->contents; + g_assert (GDA_SQL_ANY_PART (ust)->type == GDA_SQL_ANY_STMT_UPDATE); + + ust->table = gda_sql_table_new (GDA_SQL_ANY_PART (ust)); + ust->table->table_name = g_strdup (tmp); + ust->cond = gda_compute_unique_table_row_condition_with_cnc (cnc, stsel, + GDA_META_TABLE (target->validity_meta_object), + require_pk, error); + if (!ust->cond) { + retval = FALSE; + *update_stmt = NULL; + update_stmt = NULL; /* don't try anymore to build UPDATE statement */ + } + else + GDA_SQL_ANY_PART (ust->cond)->parent = GDA_SQL_ANY_PART (ust); + } + + if (retval && delete_stmt) { + sql_dst = gda_sql_statement_new (GDA_SQL_STATEMENT_DELETE); + dst = (GdaSqlStatementDelete*) sql_dst->contents; + g_assert (GDA_SQL_ANY_PART (dst)->type == GDA_SQL_ANY_STMT_DELETE); + + dst->table = gda_sql_table_new (GDA_SQL_ANY_PART (dst)); + dst->table->table_name = g_strdup (tmp); + if (update_stmt && ust->cond) + dst->cond = gda_sql_expr_copy (ust->cond); + else + dst->cond = gda_compute_unique_table_row_condition_with_cnc (cnc, stsel, + GDA_META_TABLE (target->validity_meta_object), + require_pk, error); + if (!dst->cond) { + retval = FALSE; + *delete_stmt = NULL; + delete_stmt = NULL; /* don't try anymore to build DELETE statement */ + } + else + GDA_SQL_ANY_PART (dst->cond)->parent = GDA_SQL_ANY_PART (dst); + } + g_free (tmp); + if (!retval) + goto cleanup; + + GSList *expr_list; + gint colindex; + GSList *insert_values_list = NULL; + GHashTable *fields_hash; /* key = a table's field's name, value = we don't care */ + fields_hash = g_hash_table_new ((GHashFunc) gda_identifier_hash, (GEqualFunc) gda_identifier_equal); + for (expr_list = stsel->expr_list, colindex = 0; + expr_list; + expr_list = expr_list->next, colindex++) { + GdaSqlSelectField *selfield = (GdaSqlSelectField *) expr_list->data; + if ((selfield->validity_meta_object != target->validity_meta_object) || + !selfield->validity_meta_table_column) + continue; + + /* field to insert into */ + if (g_hash_table_lookup (fields_hash, selfield->field_name)) + continue; + g_hash_table_insert (fields_hash, selfield->field_name, GINT_TO_POINTER (1)); + + if (insert_stmt) { + GdaSqlField *field; + field = gda_sql_field_new (GDA_SQL_ANY_PART (ist)); + field->field_name = g_strdup (selfield->field_name); + ist->fields_list = g_slist_append (ist->fields_list, field); + } + if (update_stmt) { + GdaSqlField *field; + field = gda_sql_field_new (GDA_SQL_ANY_PART (ust)); + field->field_name = g_strdup (selfield->field_name); + ust->fields_list = g_slist_append (ust->fields_list, field); + } + + /* parameter for the inserted value */ + GdaSqlExpr *expr; + GdaMetaTableColumn *tcol; + + tcol = selfield->validity_meta_table_column; + if (insert_stmt) { + GdaSqlParamSpec *pspec = g_new0 (GdaSqlParamSpec, 1); + pspec->name = g_strdup_printf ("+%d", colindex); + pspec->g_type = (tcol->gtype != GDA_TYPE_NULL) ? tcol->gtype: G_TYPE_STRING; + pspec->nullok = tcol->nullok; + expr = gda_sql_expr_new (GDA_SQL_ANY_PART (ist)); + if (tcol->default_value) + g_value_set_string ((expr->value = gda_value_new (G_TYPE_STRING)), + tcol->default_value); + else if (tcol->auto_incement) + expr->value = gda_value_new_default (GDA_EXTRA_AUTO_INCREMENT); + + expr->param_spec = pspec; + insert_values_list = g_slist_append (insert_values_list, expr); + } + if (update_stmt) { + GdaSqlParamSpec *pspec = g_new0 (GdaSqlParamSpec, 1); + pspec->name = g_strdup_printf ("+%d", colindex); + pspec->g_type = (tcol->gtype != GDA_TYPE_NULL) ? tcol->gtype: G_TYPE_STRING; + pspec->nullok = tcol->nullok; + expr = gda_sql_expr_new (GDA_SQL_ANY_PART (ust)); + if (tcol->default_value) + g_value_set_string ((expr->value = gda_value_new (G_TYPE_STRING)), + tcol->default_value); + else if (tcol->auto_incement) + expr->value = gda_value_new_default (GDA_EXTRA_AUTO_INCREMENT); + expr->param_spec = pspec; + ust->expr_list = g_slist_append (ust->expr_list, expr); + } + } + g_hash_table_destroy (fields_hash); + + /* finish the statements */ + if (insert_stmt) { + if (!ist->fields_list) { + /* nothing to insert => don't create statement */ + g_set_error (error, GDA_SQL_ERROR, GDA_SQL_STRUCTURE_CONTENTS_ERROR, + /* To translators: this error message occurs when no "INSERT INTO (field1, ...)..." + * SQL statement can be computed because no table field can be used */ + "%s", _("Could not compute any field to insert into")); + retval = FALSE; + } + else { + ist->values_list = g_slist_append (NULL, insert_values_list); + ret_insert = g_object_new (GDA_TYPE_STATEMENT, "structure", sql_ist, NULL); + } + } + if (update_stmt) + ret_update = g_object_new (GDA_TYPE_STATEMENT, "structure", sql_ust, NULL); + if (delete_stmt) + ret_delete = g_object_new (GDA_TYPE_STATEMENT, "structure", sql_dst, NULL); + + cleanup: + gda_sql_statement_free (sel_struct); + if (sql_ist) + gda_sql_statement_free (sql_ist); + if (sql_ust) + gda_sql_statement_free (sql_ust); + if (sql_dst) + gda_sql_statement_free (sql_dst); + + if (insert_stmt) + *insert_stmt = ret_insert; + if (update_stmt) + *update_stmt = ret_update; + if (delete_stmt) + *delete_stmt = ret_delete; + return retval; +} + +/** + * gda_compute_select_statement_from_update: + * @update_stmt: an UPDATE statement + * @error: a place to store errors, or %NULL + * + * Computes a SELECT statement which selects all the rows the @update_stmt would update. Beware + * however that this #GdaSqlStatement does not select anything (ie it would be rendered as "SELECT FROM ... WHERE ...") + * and before being usable, one needs to add some fields to actually select. + * + * Returns: (transfer full) (nullable): a new #GdaStatement if no error occurred, or %NULL otherwise + */ +GdaSqlStatement * +gda_compute_select_statement_from_update (GdaStatement *update_stmt, GError **error) +{ + GdaSqlStatement *upd_stmt; + GdaSqlStatement *sel_stmt; + GdaSqlStatementUpdate *ust; + GdaSqlStatementSelect *sst; + + g_return_val_if_fail (update_stmt, NULL); + g_object_get (G_OBJECT (update_stmt), "structure", &upd_stmt, NULL); + g_return_val_if_fail (upd_stmt, NULL); + g_return_val_if_fail (upd_stmt->stmt_type == GDA_SQL_STATEMENT_UPDATE, NULL); + + ust = (GdaSqlStatementUpdate*) upd_stmt->contents; + + sel_stmt = gda_sql_statement_new (GDA_SQL_STATEMENT_SELECT); + sst = (GdaSqlStatementSelect*) sel_stmt->contents; + g_assert (GDA_SQL_ANY_PART (sst)->type == GDA_SQL_ANY_STMT_SELECT); + + if (!ust->table || !ust->table->table_name) { + g_set_error (error, GDA_SQL_ERROR, GDA_SQL_STRUCTURE_CONTENTS_ERROR, + "%s", _("Missing table name in UPDATE statement")); + return NULL; + } + + /* FROM */ + GdaSqlSelectTarget *target; + sst->from = gda_sql_select_from_new (GDA_SQL_ANY_PART (sst)); + target = gda_sql_select_target_new (GDA_SQL_ANY_PART (sst->from)); + sst->from->targets = g_slist_prepend (NULL, target); + target->expr = gda_sql_expr_new (GDA_SQL_ANY_PART (target)); + g_value_set_string ((target->expr->value = gda_value_new (G_TYPE_STRING)), ust->table->table_name); + + /* WHERE */ + if (ust->cond) { + sst->where_cond = gda_sql_expr_copy (ust->cond); + GDA_SQL_ANY_PART (sst->where_cond)->parent = GDA_SQL_ANY_PART (sst); + } + + gda_sql_statement_free (upd_stmt); + + return sel_stmt; +} + +typedef struct { + GdaSqlAnyPart *contents; + GdaSet *params; + GSList *expr_list; /* contains a list of #GdaSqlExpr after + * gda_sql_any_part_foreach has been called */ +} NullData; + +static gboolean +null_param_foreach_func (GdaSqlAnyPart *part, NullData *data , GError **error) +{ + if ((part->type != GDA_SQL_ANY_EXPR) || !((GdaSqlExpr*) part)->param_spec) + return TRUE; + + if (!part->parent || + (part->parent->type != GDA_SQL_ANY_SQL_OPERATION) || + ((((GdaSqlOperation*) part->parent)->operator_type != GDA_SQL_OPERATOR_TYPE_EQ) && + (((GdaSqlOperation*) part->parent)->operator_type != GDA_SQL_OPERATOR_TYPE_DIFF))) + return TRUE; + + GdaHolder *holder; + GdaSqlParamSpec *pspec = ((GdaSqlExpr*) part)->param_spec; + holder = gda_set_get_holder (data->params, pspec->name); + if (!holder) + return TRUE; + + const GValue *cvalue; + cvalue = gda_holder_get_value (holder); + if (!cvalue || (G_VALUE_TYPE (cvalue) != GDA_TYPE_NULL)) + return TRUE; + + GdaSqlOperation *op; + GdaSqlExpr *oexpr = NULL; + op = (GdaSqlOperation*) part->parent; + if (op->operands->data == part) { + if (op->operands->next) + oexpr = (GdaSqlExpr*) op->operands->next->data; + } + else + oexpr = (GdaSqlExpr*) op->operands->data; + if (oexpr && !g_slist_find (data->expr_list, oexpr)) /* handle situations where ##p1==##p2 + * and both p1 and p2 are set to NULL */ + data->expr_list = g_slist_prepend (data->expr_list, part); + return TRUE; +} + +static GdaSqlExpr * +get_prev_expr (GSList *expr_list, GdaSqlAnyPart *expr) +{ + GSList *list; + for (list = expr_list; list && list->next; list = list->next) { + if ((GdaSqlAnyPart*) list->next->data == expr) + return (GdaSqlExpr*) list->data; + } + return NULL; +} + +static gboolean +null_param_unknown_foreach_func (GdaSqlAnyPart *part, NullData *data, GError **error) +{ + GdaSqlExpr *expr; + if ((part->type != GDA_SQL_ANY_EXPR) || !((GdaSqlExpr*) part)->param_spec) + return TRUE; + + if (!part->parent || part->parent != data->contents) + return TRUE; + + GdaHolder *holder; + GdaSqlParamSpec *pspec = ((GdaSqlExpr*) part)->param_spec; + holder = gda_set_get_holder (data->params, pspec->name); + if (!holder) + return TRUE; + + const GValue *cvalue; + cvalue = gda_holder_get_value (holder); + if (!cvalue || (G_VALUE_TYPE (cvalue) != GDA_TYPE_NULL)) + return TRUE; + + GSList *tmplist = NULL; + for (expr = get_prev_expr (((GdaSqlStatementUnknown*) data->contents)->expressions, part); + expr; + expr = get_prev_expr (((GdaSqlStatementUnknown*) data->contents)->expressions, (GdaSqlAnyPart*) expr)) { + gchar *str, *tmp; + if (!expr->value || (G_VALUE_TYPE (expr->value) != G_TYPE_STRING)) + goto out; + + str = (gchar*) g_value_get_string (expr->value); + if (!str || !*str) { + tmplist = g_slist_prepend (tmplist, expr); + continue; + } + for (tmp = str + strlen (str) - 1; tmp >= str; tmp --) { + if ((*tmp == ' ') || (*tmp == '\t') || (*tmp == '\n') || (*tmp == '\r')) + continue; + if (*tmp == '=') { + gchar *dup; + if ((tmp > str) && (*(tmp-1) == '!')) { + *(tmp-1) = 0; + dup = g_strdup_printf ("%s IS NOT NULL", str); + } + else { + *tmp = 0; + dup = g_strdup_printf ("%s IS NULL", str); + } + g_value_take_string (expr->value, dup); + if (tmplist) { + data->expr_list = g_slist_concat (tmplist, data->expr_list); + tmplist = NULL; + } + data->expr_list = g_slist_prepend (data->expr_list, part); + goto out; + } + else + goto out; + } + tmplist = g_slist_prepend (tmplist, expr); + } + out: + g_slist_free (tmplist); + + return TRUE; +} + +/** + * gda_rewrite_sql_statement_for_null_parameters: + * @sqlst: (transfer full): a #GdaSqlStatement + * @params: a #GdaSet to be used as parameters when executing @stmt + * @out_modified: (nullable) (out): a place to store the boolean which tells if @stmt has been modified or not, or %NULL + * @error: a place to store errors, or %NULL + * + * Modifies @sqlst to take into account any parameter which might be %NULL: if @sqlst contains the + * equivalent of "xxx = <parameter definition>" and if that parameter is in @params and + * its value is of type GDA_TYPE_NUL, then that part is replaced with "xxx IS NULL". It also + * handles the "xxx IS NOT NULL" transformation. + * + * If @out_modified is not %NULL, then it will be set to %TRUE if @sqlst has been modified + * by this function, and to %FALSE otherwise. + * + * This function is used by provider's implementations to make sure one can use parameters with + * NULL values in statements without having to rewrite statements, as database usually don't + * consider that "xxx = NULL" is the same as "xxx IS NULL" when using parameters. + * + * Returns: (transfer full) (nullable): the modified @sqlst statement, or %NULL if an error occurred + * + * Since: 4.2.9 + */ +GdaSqlStatement * +gda_rewrite_sql_statement_for_null_parameters (GdaSqlStatement *sqlst, GdaSet *params, + gboolean *out_modified, GError **error) +{ + if (out_modified) + *out_modified = FALSE; + g_return_val_if_fail (sqlst, sqlst); + + if (!params) + return sqlst; + GSList *list; + for (list = gda_set_get_holders (params); list; list = list->next) { + const GValue *cvalue; + cvalue = gda_holder_get_value ((GdaHolder*) list->data); + if (cvalue && (G_VALUE_TYPE (cvalue) == GDA_TYPE_NULL)) + break; + } + if (!list || (sqlst->stmt_type == GDA_SQL_STATEMENT_NONE)) + return sqlst; /* no modifications necessary */ + + NullData data; + data.contents = GDA_SQL_ANY_PART (sqlst->contents); + data.params = params; + data.expr_list = NULL; + + if (sqlst->stmt_type == GDA_SQL_STATEMENT_UNKNOWN) { + if (! gda_sql_any_part_foreach (GDA_SQL_ANY_PART (sqlst->contents), + (GdaSqlForeachFunc) null_param_unknown_foreach_func, + &data, error)) { + gda_sql_statement_free (sqlst); + return NULL; + } + if (out_modified) + *out_modified = data.expr_list ? TRUE : FALSE; + for (list = data.expr_list; list; list = list->next) { + ((GdaSqlStatementUnknown*) data.contents)->expressions = + g_slist_remove (((GdaSqlStatementUnknown*) data.contents)->expressions, + list->data); + gda_sql_expr_free ((GdaSqlExpr*) list->data); + } + } + else { + if (! gda_sql_any_part_foreach (GDA_SQL_ANY_PART (sqlst->contents), + (GdaSqlForeachFunc) null_param_foreach_func, + &data, error)) { + gda_sql_statement_free (sqlst); + return NULL; + } + if (out_modified) + *out_modified = data.expr_list ? TRUE : FALSE; + for (list = data.expr_list; list; list = list->next) { + GdaSqlOperation *op; + op = (GdaSqlOperation*) (((GdaSqlAnyPart*) list->data)->parent); + op->operands = g_slist_remove (op->operands, list->data); + if (op->operator_type == GDA_SQL_OPERATOR_TYPE_EQ) + op->operator_type = GDA_SQL_OPERATOR_TYPE_ISNULL; + else + op->operator_type = GDA_SQL_OPERATOR_TYPE_ISNOTNULL; + gda_sql_expr_free ((GdaSqlExpr*) list->data); + } + } + g_slist_free (data.expr_list); + return sqlst; +} + +/** + * gda_rewrite_statement_for_null_parameters: + * @stmt: (transfer none): a #GdaStatement + * @params: a #GdaSet to be used as parameters when executing @stmt + * @out_stmt: (transfer full) (nullable) (out): a place to store the new #GdaStatement, or %NULL + * @error: a place to store errors, or %NULL + * + * Modifies @stmt to take into account any parameter which might be %NULL: if @stmt contains the + * equivalent of "xxx = <parameter definition>" and if that parameter is in @params and + * its value is of type GDA_TYPE_NUL, then that part is replaced with "xxx IS NULL". It also + * handles the "xxx IS NOT NULL" transformation. + * + * For example the following SELECT: + * SELECT * FROM data WHERE id = ##id::int::null AND name = ##name::string + * in case the "id" parameter is set to NULL, is converted to: + * SELECT * FROM data WHERE id IS NULL AND name = ##name::string + * + * if @out_stmt is not %NULL, then it will contain: + * + * the modified statement if some modifications were required and no error occured (the function returns %TRUE) + * %NULL if no modification to @stmt were required and no erro occurred (the function returns %FALSE) + * %NULL if an error occured (the function returns %TRUE) + * + * + * This function is used by provider's implementations to make sure one can use parameters with + * NULL values in statements without having to rewrite statements, as database usually don't + * consider that "xxx = NULL" is the same as "xxx IS NULL" when using parameters. + * + * Returns: %TRUE if @stmt needs to be transformed to handle NULL parameters, and %FALSE otherwise + * + * Since: 4.2.9 + */ +gboolean +gda_rewrite_statement_for_null_parameters (GdaStatement *stmt, GdaSet *params, + GdaStatement **out_stmt, GError **error) +{ + GdaSqlStatement *sqlst; + gboolean mod = FALSE; + gboolean ret = FALSE; + g_return_val_if_fail (GDA_IS_STATEMENT (stmt), FALSE); + g_return_val_if_fail (!params || GDA_IS_SET (params), FALSE); + + if (out_stmt) + *out_stmt = NULL; + if (!params) + return FALSE; + + g_object_get ((GObject*) stmt, "structure", &sqlst, NULL); + if (gda_rewrite_sql_statement_for_null_parameters (sqlst, params, &mod, error)) { + if (out_stmt) { + if (mod) { + *out_stmt = g_object_new (GDA_TYPE_STATEMENT, "structure", sqlst, NULL); + ret = mod; + } + } + } + gda_sql_statement_free (sqlst); + /* error => leave *out_stmt to %NULL */ + return ret; +} + + + +static gboolean stmt_rewrite_insert_remove (GdaSqlStatementInsert *ins, GdaSet *params, GError **error); +static gboolean stmt_rewrite_insert_default_keyword (GdaSqlStatementInsert *ins, GdaSet *params, GError **error); +static gboolean stmt_rewrite_update_default_keyword (GdaSqlStatementUpdate *upd, GdaSet *params, GError **error); + + +/** + * gda_statement_rewrite_for_default_values: + * @stmt: a #GdaStatement object + * @params: a #GdaSet containing the variable's values to be bound when executing @stmt + * @remove: set to %TRUE if DEFAULT fields are removed, of %FALSE if the "DEFAULT" keyword is used + * @error: a place to store errors, or %NULL + * + * Rewrites @stmt and creates a new #GdaSqlStatement where all the variables which are to a DEFAULT value + * (as returned by gda_holder_value_is_default()) are either removed from the statement (if @remove + * is %TRUE) or replaced by the "DEFAULT" keyword (if @remove is %FALSE). + * + * This function is only useful for database providers' implementations which have to deal with default + * values when executing statements, and is only relevant in the case of INSERT or UPDATE statements + * (in the latter case an error is returned if @remove is %TRUE). + * + * For example the + * is re-written into + * if @remove is %FALSE and into + * if @remove is %TRUE. + * + * Returns: (transfer full) (nullable): a new #GdaSqlStatement, or %NULL if an error occurred + * + * Since: 4.2 + */ +GdaSqlStatement * +gda_statement_rewrite_for_default_values (GdaStatement *stmt, GdaSet *params, gboolean remove, GError **error) +{ + GdaSqlStatement *sqlst; + GdaSqlStatementType type; + gboolean ok = FALSE; + g_return_val_if_fail (GDA_IS_STATEMENT (stmt), NULL); + g_return_val_if_fail (GDA_IS_SET (params), NULL); + type = gda_statement_get_statement_type (stmt); + + g_object_get (stmt, "structure", &sqlst, NULL); + if (! gda_sql_statement_check_structure (sqlst, error)) { + gda_sql_statement_free (sqlst); + return NULL; + } + + switch (type) { + case GDA_SQL_STATEMENT_INSERT: + if (remove) + ok = stmt_rewrite_insert_remove ((GdaSqlStatementInsert*) sqlst->contents, + params, error); + else + ok = stmt_rewrite_insert_default_keyword ((GdaSqlStatementInsert*) sqlst->contents, + params, error); + break; + case GDA_SQL_STATEMENT_UPDATE: + if (remove) + g_set_error (error, GDA_SERVER_PROVIDER_ERROR, + GDA_SERVER_PROVIDER_DEFAULT_VALUE_HANDLING_ERROR, + "%s", _("Can't rewrite UPDATE statement to handle default values")); + else + ok = stmt_rewrite_update_default_keyword ((GdaSqlStatementUpdate*) sqlst->contents, + params, error); + break; + default: + g_set_error (error, GDA_SERVER_PROVIDER_ERROR, + GDA_SERVER_PROVIDER_DEFAULT_VALUE_HANDLING_ERROR, + "%s", _("Can't rewrite statement which is not INSERT or UPDATE")); + break; + } + + if (ok) + return sqlst; + else { + gda_sql_statement_free (sqlst); + return NULL; + } +} + +/* + * Modifies @ins + * Returns: TRUE if rewrite is Ok + */ +static gboolean +stmt_rewrite_insert_remove (GdaSqlStatementInsert *ins, GdaSet *params, GError **error) +{ + if (!ins->values_list) + /* nothing to do */ + return TRUE; + + if (ins->values_list->next) { + TO_IMPLEMENT; + g_set_error (error, GDA_SERVER_PROVIDER_ERROR, + GDA_SERVER_PROVIDER_DEFAULT_VALUE_HANDLING_ERROR, + "%s", "Not yet implemented"); + return FALSE; + } + + GSList *fields, *values; + for (fields = ins->fields_list, values = (GSList*) ins->values_list->data; + fields && values; ){ + GdaHolder *h; + GdaSqlExpr *expr = (GdaSqlExpr*) values->data; + if (! expr->param_spec || ! expr->param_spec->is_param) { + fields = fields->next; + values = values->next; + continue; + } + h = gda_set_get_holder (params, expr->param_spec->name); + if (!h) { + gchar *str; + str = g_strdup_printf (_("Missing parameter '%s' to execute query"), + expr->param_spec->name); + g_set_error (error, GDA_SERVER_PROVIDER_ERROR, + GDA_SERVER_PROVIDER_MISSING_PARAM_ERROR, + "%s", str); + g_free (str); + return FALSE; + } + + if (gda_holder_value_is_default (h)) { + GSList *tmp; + + gda_sql_field_free ((GdaSqlField*) fields->data); + tmp = fields->next; + ins->fields_list = g_slist_delete_link (ins->fields_list, fields); + fields = tmp; + + gda_sql_expr_free (expr); + tmp = values->next; + ins->values_list->data = g_slist_delete_link ((GSList*) ins->values_list->data, + values); + values = tmp; + } + else { + fields = fields->next; + values = values->next; + } + } + + if (! ins->values_list->data) { + g_slist_free (ins->values_list); + ins->values_list = NULL; + } + + return TRUE; +} + +/* + * Modifies @ins + * Returns: TRUE if rewrite is Ok + */ +static gboolean +stmt_rewrite_insert_default_keyword (GdaSqlStatementInsert *ins, GdaSet *params, GError **error) +{ + GSList *llist; + for (llist = ins->values_list; llist; llist = llist->next) { + GSList *values; + for (values = (GSList*) llist->data; + values; + values = values->next){ + GdaHolder *h; + GdaSqlExpr *expr = (GdaSqlExpr*) values->data; + if (! expr->param_spec || ! expr->param_spec->is_param) + continue; + h = gda_set_get_holder (params, expr->param_spec->name); + if (!h) { + gchar *str; + str = g_strdup_printf (_("Missing parameter '%s' to execute query"), + expr->param_spec->name); + g_set_error (error, GDA_SERVER_PROVIDER_ERROR, + GDA_SERVER_PROVIDER_MISSING_PARAM_ERROR, + "%s", str); + g_free (str); + return FALSE; + } + + if (gda_holder_value_is_default (h)) { + GdaSqlExpr *nexpr; + nexpr = gda_sql_expr_new (GDA_SQL_ANY_PART (ins)); + g_value_set_string ((nexpr->value = gda_value_new (G_TYPE_STRING)), + "DEFAULT"); + gda_sql_expr_free ((GdaSqlExpr*) values->data); + values->data = nexpr; + } + } + } + + if (! ins->values_list->data) { + g_slist_free (ins->values_list); + ins->values_list = NULL; + } + + return TRUE; +} + +static gboolean +stmt_rewrite_update_default_keyword (GdaSqlStatementUpdate *upd, GdaSet *params, GError **error) +{ + GSList *values; + for (values = upd->expr_list; values; values = values->next) { + GdaHolder *h; + GdaSqlExpr *expr = (GdaSqlExpr*) values->data; + if (! expr->param_spec || ! expr->param_spec->is_param) + continue; + h = gda_set_get_holder (params, expr->param_spec->name); + if (!h) { + gchar *str; + str = g_strdup_printf (_("Missing parameter '%s' to execute query"), + expr->param_spec->name); + g_set_error (error, GDA_SERVER_PROVIDER_ERROR, + GDA_SERVER_PROVIDER_MISSING_PARAM_ERROR, + "%s", str); + g_free (str); + return FALSE; + } + + if (gda_holder_value_is_default (h)) { + GdaSqlExpr *nexpr; + nexpr = gda_sql_expr_new (GDA_SQL_ANY_PART (upd)); + g_value_set_string ((nexpr->value = gda_value_new (G_TYPE_STRING)), + "DEFAULT"); + gda_sql_expr_free ((GdaSqlExpr*) values->data); + values->data = nexpr; + } + } + + return TRUE; +} + + +static gboolean +foreach_modify_param_type (GdaSqlAnyPart *part, GdaDataModel *model, G_GNUC_UNUSED GError **error) +{ + if (part->type != GDA_SQL_ANY_EXPR) + return TRUE; + + GdaSqlParamSpec *pspec; + pspec = ((GdaSqlExpr*) part)->param_spec; + if (!pspec || !pspec->name) + return TRUE; + + if ((pspec->name [0] == '+') || (pspec->name [0] == '-')) { + long int li; + char *end; + li = strtol ((pspec->name) + 1, &end, 10); + if ((! *end) && (li <= G_MAXINT) && (li >= G_MININT) && (li < gda_data_model_get_n_columns (model))) { + GdaColumn *col; + col = gda_data_model_describe_column (model, (gint) li); + if (col && (gda_column_get_g_type (col) != GDA_TYPE_NULL)) + pspec->g_type = gda_column_get_g_type (col); + } + } + return TRUE; +} + +/* + * _gda_modify_statement_param_types: + * @stmt: a #GdaStatement + * @model: a #GdaDataModel + * + * Modifies the parameters in @stmt which will be mapped to columns in @model (using the +<colindex> or + * -<colindex> syntax) to map the column types of @model. + * + * Since: 5.2 + */ +void +_gda_modify_statement_param_types (GdaStatement *stmt, GdaDataModel *model) +{ + g_return_if_fail (GDA_IS_STATEMENT (stmt)); + g_return_if_fail (GDA_IS_DATA_MODEL (model)); + GdaSqlStatement *sqlst; + + sqlst = _gda_statement_get_internal_struct (stmt); + if (!sqlst || !sqlst->contents) + return; + + if ((sqlst->stmt_type == GDA_SQL_STATEMENT_INSERT) || + (sqlst->stmt_type == GDA_SQL_STATEMENT_UPDATE) || + (sqlst->stmt_type == GDA_SQL_STATEMENT_DELETE)) { + GdaSqlAnyPart *top; + top = (GdaSqlAnyPart*) sqlst->contents; + gda_sql_any_part_foreach (top, (GdaSqlForeachFunc) foreach_modify_param_type, model, NULL); + } +} + +/** + * gda_identifier_hash: + * @id: an identifier string + * + * computes a hash string from @id, to be used in hash tables as a #GHashFunc + * + * Returns: a new hash + */ +guint +gda_identifier_hash (const gchar *id) +{ + const signed char *p = (signed char *) id; + guint32 h = 0; + gboolean lower = FALSE; + + if (*p != '"') { + lower = TRUE; + h = g_ascii_tolower (*p); + } + + for (p += 1; *p && *p != '"'; p++) { + if (lower) + h = (h << 5) - h + g_ascii_tolower (*p); + else + h = (h << 5) - h + *p; + } + if (*p == '"' && *(p+1)) + g_warning ("Argument passed to %s() is not an SQL identifier", __FUNCTION__); + + return h; +} + +/** + * gda_identifier_equal: + * @id1: an identifier string + * @id2: an identifier string + * + * Does the same as strcmp(@id1, @id2), but handles the case where id1 and/or id2 are enclosed in double quotes. + * can also be used in hash tables as a #GEqualFunc. + * + * Returns: %TRUE if @id1 and @id2 are equal. + */ +gboolean +gda_identifier_equal (const gchar *id1, const gchar *id2) +{ + const gchar *ptr1, *ptr2; + gboolean dq1 = FALSE, dq2 = FALSE; + + if ((!id1 && id2) || (id1 && !id2)) + return FALSE; + if (!id1 && !id2) + return TRUE; + + ptr1 = id1; + if (*ptr1 == '"') { + ptr1++; + dq1 = TRUE; + } + ptr2 = id2; + if (*ptr2 == '"') { + ptr2++; + dq2 = TRUE; + } + for (; *ptr1 && *ptr2; ptr1++, ptr2++) { + gchar c1, c2; + c1 = *ptr1; + c2 = *ptr2; + if (!dq1) + c1 = g_ascii_tolower (c1); + if (!dq2) + c2 = g_ascii_tolower (c2); + if (c1 != c2) + return FALSE; + } + if (*ptr1 || *ptr2) { + if (*ptr1 && (*ptr1 == '"')) + return TRUE; + if (*ptr2 && (*ptr2 == '"')) + return TRUE; + return FALSE; + } + return TRUE; +} + + +static char *concat_ident (const gchar *prefix, const gchar *ident); + +static const gchar *sql_start_words[] = { + "ALTER", + "SELECT", + "INSERT", + "DELETE", + "UPDATE", + "CREATE", + "DROP", + "ALTER", + "COMMENT", + "BEGIN", + "COMMIT", + "ROLLBACK" +}; + +static const gchar *sql_middle_words[] = { + "FROM", + "INNER", + "JOIN", + "LEFT", + "OUTER", + "RIGHT", + "OUTER", + "WHERE", + "HAVING", + "LIMIT", + "AND", + "OR", + "NOT", + "SET" +}; + +static gchar * +prepare_sql_identifier_for_compare (gchar *str) +{ + if (!str || (*str == '"')) + return str; + else { + gchar *ptr; + for (ptr = str; *ptr; ptr++) + *ptr = g_ascii_tolower (*ptr); + return str; + } +} + +static gint +cmp_func (gconstpointer a, gconstpointer b) +{ + return g_strcmp0 (*((gchar**) a), *((gchar**) b)); +} + +/** + * gda_completion_list_get: + * @cnc: a #GdaConnection object + * @sql: a partial SQL statement which is the context of the completion proposal, may also start with a "." for + * Gda's tools which use internal commands + * @start: starting position within @sql of the "token" to complete (starts at 0) + * @end: ending position within @sql of the "token" to complete + * + * Creates an array of strings (terminated by a %NULL) corresponding to possible completions. + * If no completion is available, then the returned array contains just one NULL entry, and + * if it was not possible to try to compute a completions list, then %NULL is returned. + * + * Returns: (transfer full) (array zero-terminated=1) (nullable): a new array of strings, or %NULL (use g_strfreev() to free the returned array) + */ +gchar ** +gda_completion_list_get (GdaConnection *cnc, const gchar *sql, gint start, gint end) +{ + GArray *compl = NULL; + gchar *text; + const GValue *cvalue; + + if (!cnc) + return NULL; + g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL); + if (!sql || !(*sql)) + return NULL; + if (end < start) + return NULL; + + /* init */ + compl = g_array_new (TRUE, TRUE, sizeof (gchar *)); + text = g_new (gchar, end - start + 2); + memcpy (text, sql + start, end - start + 1); /* Flawfinder: ignore */ + text [end - start + 1] = 0; + + if (start == 0) { + /* + * start of a statement => complete with SQL start of statement words + */ + gsize len; + gsize i; + len = strlen (text); + for (i = 0; i < G_N_ELEMENTS (sql_start_words); i++) { + gsize clen = strlen (sql_start_words[i]); + if (!g_ascii_strncasecmp (sql_start_words[i], text, MIN (clen, len))) { + gchar *str; + str = g_strdup (sql_start_words[i]); + g_array_append_val (compl, str); + } + } + goto compl_finished; + } + + if (!*text) + goto compl_finished; + + gchar *obj_schema, *obj_name; + GValue *schema_value = NULL; + + if (!_split_identifier_string (g_strdup (text), &obj_schema, &obj_name) && + !_split_identifier_string (g_strdup_printf ("%s\"", text), &obj_schema, &obj_name)) { + if (text [strlen(text) - 1] == '.') { + obj_schema = g_strdup (text); + obj_schema [strlen(text) - 1] = 0; + obj_name = g_strdup (""); + } + else + goto compl_finished; + } + + prepare_sql_identifier_for_compare (obj_name); + if (obj_schema) + g_value_take_string ((schema_value = gda_value_new (G_TYPE_STRING)), + prepare_sql_identifier_for_compare (obj_schema)); + + /* + * complete with "table" or "schema.table" + */ + GdaDataModel *model; + GdaMetaStore *store; + store = gda_connection_get_meta_store (cnc); + if (schema_value) + model = gda_meta_store_extract (store, + "SELECT table_name FROM _tables WHERE table_schema = ##schema::string", + NULL, "schema", schema_value, NULL); + else + model = gda_meta_store_extract (store, + "SELECT table_name FROM _tables WHERE table_short_name != table_full_name", + NULL); + if (model) { + gint i, nrows; + gint len = strlen (obj_name); + + nrows = gda_data_model_get_n_rows (model); + for (i = 0; i < nrows; i++) { + cvalue = gda_data_model_get_value_at (model, 0, i, NULL); + if (cvalue) { + const gchar *tname; + tname = g_value_get_string (cvalue); + if (!strncmp (tname, obj_name, len)) { + gchar *str; + if (schema_value) + str = concat_ident (obj_schema, tname); + else + str = g_strdup (tname); + g_array_append_val (compl, str); + } + } + } + g_object_unref (model); + } + + /* + * complete with "schema.table" + */ + model = NULL; + if (! schema_value) + model = gda_meta_store_extract (store, "SELECT schema_name FROM _schemata", NULL); + if (model) { + gint i, nrows; + gint len = strlen (obj_name); + + nrows = gda_data_model_get_n_rows (model); + for (i = 0; i < nrows; i++) { + cvalue = gda_data_model_get_value_at (model, 0, i, NULL); + if (cvalue) { + const gchar *tname; + tname = g_value_get_string (cvalue); + if (!strncmp (tname, obj_name, len)) { + char *str; + GdaDataModel *m2; + str = g_strdup (tname); + + m2 = gda_meta_store_extract (store, + "SELECT table_name FROM _tables WHERE table_schema = ##schema::string", + NULL, "schema", cvalue, NULL); + if (m2) { + gint i2, nrows2; + nrows2 = gda_data_model_get_n_rows (m2); + for (i2 = 0; i2 < nrows2; i2++) { + cvalue = gda_data_model_get_value_at (m2, 0, i2, NULL); + if (cvalue) { + gchar *str2; + tname = g_value_get_string (cvalue); + str2 = concat_ident (str, tname); + g_array_append_val (compl, str2); + } + } + + g_object_unref (m2); + } + g_free (str); + } + } + } + g_object_unref (model); + if (compl->len > 0) + goto compl_finished; + } + + if (schema_value) + gda_value_free (schema_value); + g_free (obj_name); + + /* + * middle of a statement and no completion yet => complete with SQL statement words + */ + { + gsize len; + gsize i; + len = strlen (text); + for (i = 0; i < G_N_ELEMENTS (sql_middle_words); i++) { + gsize clen = strlen (sql_middle_words[i]); + if (!g_ascii_strncasecmp (sql_middle_words[i], text, MIN (clen, len))) { + gchar *str; + str = g_strdup (sql_middle_words[i]); + g_array_append_val (compl, str); + } + } + } + + compl_finished: + g_free (text); + if (compl) { + if (compl->len >= 1) { + /* sort */ + gsize i; + g_array_sort (compl, cmp_func); + + /* remove duplicates if any */ + for (i = 1; i < compl->len; ) { + gchar *current, *before; + current = g_array_index (compl, gchar*, i); + before = g_array_index (compl, gchar*, i - 1); + if (!strcmp (current, before)) { + g_free (current); + g_array_remove_index (compl, i); + } + else + i++; + } + + gchar **ptr; + ptr = (gchar**) compl->data; + g_array_free (compl, FALSE); + return ptr; + } + else { + g_array_free (compl, TRUE); + return NULL; + } + } + else + return NULL; +} + +static char * +concat_ident (const char *prefix, const gchar *ident) +{ + char *str; + gint tlen = strlen (ident); + gint plen = 0; + + if (prefix) + plen = strlen (prefix) + 1; + + str = malloc (sizeof (char) * (plen + tlen + 1)); + if (prefix) { + strcpy (str, prefix); /* Flawfinder: ignore */ + str [plen - 1] = '.'; + strcpy (str + plen, ident); /* Flawfinder: ignore */ + } + else + strcpy (str, ident); /* Flawfinder: ignore */ + return str; +} + +/** + * gda_sql_identifier_split: + * @id: an SQL identifier + * + * Splits @id into an array of it sub parts. @id's format has to be "<part>[.<part>[...]]" where + * each part is either a text surrounded by double quotes which can contain upper and lower cases or + * an SQL identifier in lower case. + * + * For example the string will result in the array: + * + * Returns: (transfer full) (array zero-terminated=1) (nullable): a new %NULL-terminated array of strings, or NULL (use g_strfreev() to free the returned array) + */ +gchar ** +gda_sql_identifier_split (const gchar *id) +{ + gchar *copy; + gchar *remain, *last; + GArray *array = NULL; + + g_return_val_if_fail (id && *id, NULL); + + for (copy = g_strdup (id); copy; copy = remain) { + if (_split_identifier_string (copy, &remain, &last)) { + if (!array) + array = g_array_new (TRUE, TRUE, sizeof (gchar *)); + g_array_prepend_val (array, last); + } + } + + if (array) + return (gchar **) g_array_free (array, FALSE); + else + return NULL; +} + +static gboolean _sql_identifier_needs_quotes (const gchar *str); + +/** + * gda_sql_identifier_quote: + * @id: an SQL identifier + * @cnc: (nullable): a #GdaConnection object, or %NULL + * @prov: (nullable): a #GdaServerProvider object, or %NULL + * @for_meta_store set to %TRUE if the returned string will be used in a #GdaMetaStore + * @force_quotes: set to %TRUE to force the returned string to be quoted + * + * Use this function for any SQL identifier to make sure that: + * + * + * it is correctly formatted + * to be used with @cnc (if @cnc is %NULL, then some default SQL quoting rules will be applied, + * similar to PostgreSQL's way) if @for_meta_store is %FALSE; + * + * + * + * it is correctly formatted to be used with the #GdaMetaStore's object associated to @cnc + * is @for_meta_store is %TRUE. + * + * + * + * + * The @force_quotes allow some control of how to interpret @id: if %FALSE, then @id will be left + * unchanged most of the time (except for example if it's a reserved keyword), otherwise + * if @force_quotes is %TRUE, then the returned string will most probably have quotes around it + * to request that the database keep the case sensitiveness (but again, this may vary depending + * on the database being accessed through @cnc). + * + * For example, the following table gives the result of this function depending on the arguments + * when @cnc is %NULL (and @prov is also %NULL): + *
+ * + * + * + * id + * for_meta_store=%FALSE, force_quotes=%FALSE + * for_meta_store=%TRUE, force_quotes=%FALSE + * for_meta_store=%FALSE, force_quotes=%TRUE + * for_meta_store=%TRUE, force_quotes=%TRUE + * remark + * + * + * + * + * "double word" + * "double word" + * "double word" + * "double word" + * "double word" + * non allowed character in SQL identifier + * + * + * "CapitalTest" + * "CapitalTest" + * "CapitalTest" + * "CapitalTest" + * "CapitalTest" + * Mixed case SQL identifier, already quoted + * + * + * CapitalTest + * CapitalTest + * capitaltest + * "CapitalTest" + * "CapitalTest" + * Mixed case SQL identifier, non quoted + * + * + * "mytable" + * "mytable" + * mytable + * "mytable" + * mytable + * All lowser case, quoted + * + * + * mytable + * mytable + * mytable + * "mytable" + * mytable + * All lowser case + * + * + * MYTABLE + * MYTABLE + * mytable + * "MYTABLE" + * "MYTABLE" + * All upper case + * + * + * "MYTABLE" + * "MYTABLE" + * "MYTABLE" + * "MYTABLE" + * "MYTABLE" + * All upper case, quoted + * + * + * desc + * "desc" + * "desc" + * "desc" + * "desc" + * SQL reserved keyword + * + * + * 5ive + * "5ive" + * "5ive" + * "5ive" + * "5ive" + * SQL identifier starting with a digit + * + * + * + *
+ * + * Here are a few examples of when and how to use this function: + * + * + * + * When creating a table, the user has entered the table name, this function can be used to + * create a valid SQL identifier from the user provided table name: + * + * gchar *user_sqlid=... + * gchar *valid_sqlid = gda_sql_identifier_quote (user_sqlid, cnc, NULL, FALSE, FALSE); + * gchar *sql = g_strdup_printf ("CREATE TABLE %s ...", valid_sqlid); + * g_free (valid_sqlid); + * + * Note that this is an illustration and creating a table should be sone using a #GdaServerOperation + * object. + * + * + * + * + * When updating the meta data associated to a table which has been created with the code + * above: + * + * GValue table_name_value = { 0 }; + * gchar* column_names[] = { (gchar*)"table_name" }; + * GValue* column_values[] = { &table_name_value }; + * GdaMetaContext mcontext = { (gchar*)"_tables", 1, column_names, column_values }; + * g_value_init (&table_name_value, G_TYPE_STRING); + * g_value_take_string (&table_name_value, gda_sql_identifier_quote (user_sqlid, cnc, NULL, TRUE, FALSE); + * gda_connection_update_meta_store (cnc, &mcontext, NULL); + * g_value_reset (&table_name_value); + * + * + * + * + * + * When using a #GdaMetaStruct object to fetch information about a table (which has been created with + * the code above): + * + * GValue table_name_value = { 0 }; + * g_value_init (&table_name_value, G_TYPE_STRING); + * g_value_take_string (&table_name_value, gda_sql_identifier_quote (user_sqlid, cnc, NULL, TRUE, FALSE); + * GdaMetaDbObject *dbo; + * dbo = gda_meta_struct_complement (mstruct, GDA_META_DB_TABLE, NULL, NULL, &table_name_value, NULL); + * g_value_reset (&table_name_value); + * + * + * + * + * + * + * Note that @id must not be a composed SQL identifier (such as "mytable.mycolumn" which should be + * treated as the "mytable" and "mycolumn" SQL identifiers). If unsure, use gda_sql_identifier_split(). + * + * Also note that if @cnc is %NULL, then it's possible to pass an non %NULL @prov to have a result specific + * to @prov. + * + * For more information, see the SQL identifiers and abstraction and + * SQL identifiers in meta data sections. + * + * Returns: (transfer full) (nullable): the representation of @id ready to be used in SQL statement, as a new string, + * or %NULL if @id is in a wrong format + * + * Since: 4.0.3 + */ +gchar * +gda_sql_identifier_quote (const gchar *id, GdaConnection *cnc, GdaServerProvider *prov, + gboolean for_meta_store, gboolean force_quotes) +{ +#if GDA_DEBUG + test_keywords (); +#endif + g_return_val_if_fail (id && *id, NULL); + if (prov) + g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (prov), NULL); + if (cnc) { + g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL); + if (prov) + g_return_val_if_fail (gda_connection_get_provider (cnc) == prov, NULL); + else + prov = gda_connection_get_provider (cnc); + } + + if ((*id == '*') && (! id [1])) + return g_strdup (id); + + if (prov) { + gchar *quoted; + quoted = _gda_server_provider_identifier_quote (prov, cnc, id, for_meta_store, force_quotes); + if (quoted) + return quoted; + } + + if (for_meta_store) { + gchar *tmp, *ptr; + tmp = _remove_quotes (g_strdup (id)); + if (is_keyword (tmp)) { + ptr = gda_sql_identifier_force_quotes (tmp); + g_free (tmp); + return ptr; + } + else if (force_quotes) { + /* quote if non LC characters or digits at the 1st char or non allowed characters */ + for (ptr = tmp; *ptr; ptr++) { + if (((*ptr >= 'a') && (*ptr <= 'z')) || + ((*ptr >= '0') && (*ptr <= '9') && (ptr != tmp)) || + (*ptr == '_')) + continue; + else { + ptr = gda_sql_identifier_force_quotes (tmp); + g_free (tmp); + return ptr; + } + } + return tmp; + } + else { + for (ptr = tmp; *ptr; ptr++) { + if (*id == '"') { + if (((*ptr >= 'a') && (*ptr <= 'z')) || + ((*ptr >= '0') && (*ptr <= '9') && (ptr != tmp)) || + (*ptr == '_')) + continue; + else { + ptr = gda_sql_identifier_force_quotes (tmp); + g_free (tmp); + return ptr; + } + } + else if ((*ptr >= 'A') && (*ptr <= 'Z')) + *ptr += 'a' - 'A'; + else if ((*ptr >= '0') && (*ptr <= '9') && (ptr == tmp)) { + ptr = gda_sql_identifier_force_quotes (tmp); + g_free (tmp); + return ptr; + } + } + return tmp; + } + } + else { + /* default SQL standard */ + if (*id == '"') { + /* there are already some quotes */ + return g_strdup (id); + } + if (is_keyword (id) || _sql_identifier_needs_quotes (id) || force_quotes) + return gda_sql_identifier_force_quotes (id); + + /* nothing to do */ + return g_strdup (id); + } +} + +static gboolean +_sql_identifier_needs_quotes (const gchar *str) +{ + const gchar *ptr; + + g_return_val_if_fail (str, FALSE); + for (ptr = str; *ptr; ptr++) { + /* quote if 1st char is a number */ + if ((*ptr <= '9') && (*ptr >= '0')) { + if (ptr == str) + return TRUE; + continue; + } + if (((*ptr >= 'A') && (*ptr <= 'Z')) || + ((*ptr >= 'a') && (*ptr <= 'z'))) + continue; + + if ((*ptr != '$') && (*ptr != '_') && (*ptr != '#')) + return TRUE; + } + return FALSE; +} + +/* + * RFC 1738 defines that these characters should be escaped, as well + * any non-US-ASCII character or anything between 0x00 - 0x1F. + */ +static const char rfc1738_unsafe_chars[] = +{ + (char) 0x3C, /* < */ + (char) 0x3E, /* > */ + (char) 0x22, /* " */ + (char) 0x23, /* # */ + (char) 0x25, /* % */ + (char) 0x7B, /* { */ + (char) 0x7D, /* } */ + (char) 0x7C, /* | */ + (char) 0x5C, /* \ */ + (char) 0x5E, /* ^ */ + (char) 0x7E, /* ~ */ + (char) 0x5B, /* [ */ + (char) 0x5D, /* ] */ + (char) 0x60, /* ` */ + (char) 0x27, /* ' */ + (char) 0x20 /* space */ +}; + +static const char rfc1738_reserved_chars[] = +{ + (char) 0x3b, /* ; */ + (char) 0x2f, /* / */ + (char) 0x3f, /* ? */ + (char) 0x3a, /* : */ + (char) 0x40, /* @ */ + (char) 0x3d, /* = */ + (char) 0x26 /* & */ +}; + +/** + * gda_rfc1738_encode: + * @string: a string to encode + * + * Encodes @string using the RFC 1738 recommendations: the + * <>"#%{}|\^~[]'`;/?:@=& and space characters are replaced by + * "%%ab" where + * ab is the hexadecimal number corresponding to the character. + * + * Returns: (transfer full) (nullable): a new string or %NULL + */ +gchar * +gda_rfc1738_encode (const gchar *string) +{ + if (!string) + return NULL; + + if (!*string) + return g_strdup (""); + + gchar *ret, *wptr; + const gchar *rptr; + gsize i; + + ret = g_new0 (gchar, (strlen (string) * 3) + 1); + for (wptr = ret, rptr = string; *rptr; rptr++) { + gboolean enc = FALSE; + + /* RFC 1738 defines these chars as unsafe */ + for (i = 0; i < G_N_ELEMENTS (rfc1738_reserved_chars); i++) { + if (*rptr == rfc1738_reserved_chars [i]) { + enc = TRUE; + break; + } + } + if (!enc) { + for (i = 0; i < G_N_ELEMENTS (rfc1738_unsafe_chars); i++) { + if (*rptr == rfc1738_unsafe_chars [i]) { + enc = TRUE; + break; + } + } + } + if (!enc) { + /* RFC 1738 says any control chars (0x00-0x1F) are encoded */ + if ((unsigned char) *rptr <= (unsigned char) 0x1F) + enc = TRUE; + /* RFC 1738 says 0x7f is encoded */ + else if (*rptr == (char) 0x7F) + enc = TRUE; + /* RFC 1738 says any non-US-ASCII are encoded */ + else if (((unsigned char) *rptr >= (unsigned char) 0x80)) + enc = TRUE; + } + if (!enc && (*rptr == '=')) { + /* also encode the '=' */ + enc = TRUE; + } + + if (enc) { + sprintf (wptr, "%%%02x", (unsigned char) *rptr); /* Flawfinder: ignore */ + wptr += 3; + } + else { + *wptr = *rptr; + wptr++; + } + } + return ret; +} + +/** + * gda_rfc1738_decode: + * @string: a string to decode + * + * Decodes @string using the RFC 1738 recommendations: the + * <>"#%{}|\^~[]'`;/?:@=& and space characters are replaced by + * "%%ab" where + * ab is the hexadecimal number corresponding to the character. + * + * @string should respect the RFC 1738 encoding. If this is not the case (for example if there + * is a "%2z" because 2z is not an hexadecimal value), then the part with the problem + * is not decoded, and the function returns FALSE. + * + * @string is decoded in place, no new string gets created. + * + * Returns: %TRUE if no error occurred. + */ +gboolean +gda_rfc1738_decode (gchar *string) +{ + gchar *wptr, *rptr; + + if (!string || !*string) + return TRUE; + + for (wptr = rptr = string; *rptr; wptr++, rptr++) { + *wptr = *rptr; + if (*rptr == '%') { + rptr++; + if ((((*rptr >= 'A') && (*rptr <= 'F')) || + ((*rptr >= 'a') && (*rptr <= 'f')) || + ((*rptr >= '0') && (*rptr <= '9'))) && + (((rptr[1] >= 'A') && (rptr[1] <= 'F')) || + ((rptr[1] >= 'a') && (rptr[1] <= 'f')) || + ((rptr[1] >= '0') && (rptr[1] <= '9')))) { + *wptr = 0; + if ((*rptr >= 'A') && (*rptr <= 'F')) + *wptr = *rptr - 'A' + 10; + else if ((*rptr >= 'a') && (*rptr <= 'f')) + *wptr = *rptr - 'a' + 10; + else + *wptr = *rptr - '0'; + rptr++; + *wptr = *wptr << 4; /* multiply by 16 */ + if (((*rptr >= 'A') && (*rptr <= 'F')) || + ((*rptr >= 'a') && (*rptr <= 'f')) || + ((*rptr >= '0') && (*rptr <= '9'))) { + if ((*rptr >= 'A') && (*rptr <= 'F')) + *wptr += *rptr - 'A' + 10; + else if ((*rptr >= 'a') && (*rptr <= 'f')) + *wptr += *rptr - 'a' + 10; + else + *wptr += *rptr - '0'; + } + } + else { + /* error */ + /* TODO: Actually return this? retval = FALSE; murrayc */ + rptr--; + } + } + } + *wptr = 0; + return TRUE; +} + + +/** + * gda_dsn_split: + * @string: a string in the "[<username>[:<password>]@]<DSN>" form + * @out_dsn: a place to store the new string containing the <DSN> part + * @out_username: a place to store the new string containing the <username> part + * @out_password: a place to store the new string containing the <password> part + * + * Extract the DSN, username and password from @string. in @string, the various parts are strings + * which are expected to be encoded using an RFC 1738 compliant encoding. If they are specified, + * the returned username and password strings are correctly decoded. + * + * @out_username and @out_password may be set to %NULL depending on @string's format. + */ +void +gda_dsn_split (const gchar *string, gchar **out_dsn, gchar **out_username, gchar **out_password) +{ + const gchar *ptr; + g_return_if_fail (string); + g_return_if_fail (out_dsn); + g_return_if_fail (out_username); + g_return_if_fail (out_password); + + *out_dsn = NULL; + *out_username = NULL; + *out_password = NULL; + for (ptr = string; *ptr; ptr++) { + if (*ptr == '@') { + const gchar *tmp = ptr; + *out_dsn = g_strdup (ptr+1); + for (ptr = string; ptr < tmp; ptr++) { + if (*ptr == ':') { + *out_username = g_strndup (string, ptr - string); + *out_password = g_strndup (ptr+1, tmp - ptr - 1); + } + } + if (!*out_username) + *out_username = g_strndup (string, tmp - string); + break; + } + } + if (!*out_dsn) + *out_dsn = g_strdup (string); + + /* RFC 1738 decode username and password strings */ + gda_rfc1738_decode (*out_username); + gda_rfc1738_decode (*out_password); +} + +/** + * gda_connection_string_split: + * @string: a string in the "[<provider>://][<username>[:<password>]@]<connection_params>" form + * @out_cnc_params: (out): a place to store the new string containing the <connection_params> part + * @out_provider: (out): a place to store the new string containing the <provider> part + * @out_username: (out): a place to store the new string containing the <username> part + * @out_password: (out): (nullable): a place to store the new string containing the <password> part, or %NULL + * + * Extract the provider, connection parameters, username and password from @string. + * in @string, the various parts are strings + * which are expected to be encoded using an RFC 1738 compliant encoding. If they are specified, + * the returned provider, username and password strings are correctly decoded. + * + * For example all the following connection strings: + * + * + * will return the following new strings (double quotes added here to delimit strings): + * + */ +void +gda_connection_string_split (const gchar *string, gchar **out_cnc_params, gchar **out_provider, + gchar **out_username, gchar **out_password) +{ + const gchar *ptr; + const gchar *ap; + g_return_if_fail (string); + g_return_if_fail (out_cnc_params); + g_return_if_fail (out_provider); + g_return_if_fail (out_username); + + *out_cnc_params = NULL; + *out_provider = NULL; + *out_username = NULL; + if (out_password) + *out_password = NULL; + for (ap = ptr = string; *ptr; ptr++) { + if ((ap == string) && (*ptr == '/') && (ptr[1] == '/')) { + if ((ptr == string) || (ptr[-1] != ':')) { + g_free (*out_cnc_params); *out_cnc_params = NULL; + g_free (*out_provider); *out_provider = NULL; + g_free (*out_username); *out_username = NULL; + if (out_password) { + g_free (*out_password); + *out_password = NULL; + } + return; + } + *out_provider = g_strndup (string, ptr - string - 1); + ap = ptr+2; + ptr++; + } + + if (*ptr == '@') { + const gchar *tmp = ptr; + *out_cnc_params = g_strdup (ptr+1); + for (ptr = ap; ptr < tmp; ptr++) { + if (*ptr == ':') { + *out_username = g_strndup (ap, ptr - ap); + if (out_password) + *out_password = g_strndup (ptr+1, tmp - ptr - 1); + } + } + if (!*out_username) + *out_username = g_strndup (ap, tmp - ap); + break; + } + } + if (!*out_cnc_params) + *out_cnc_params = g_strdup (ap); + + if (*out_cnc_params) { + gchar *pos; + + pos = strstr (*out_cnc_params, "USERNAME="); + while (pos) { + if (((pos > *out_cnc_params) && (*(pos-1) == ';')) || + (pos == *out_cnc_params)) { + for (ptr = pos + 9; ptr && *ptr != '\0' && *ptr != ';'; ptr++); + if (ptr != pos + 9) + *out_username = g_strndup (pos + 9, ptr - (pos + 9)); + + if (*ptr) + memmove (pos, ptr + 1, strlen (ptr)); + else + *pos = 0; + gchar *tmp; + gint len; + tmp = *out_cnc_params; + len = strlen (tmp) - 1; + if (tmp [len] == ';') + tmp [len] = 0; + break; + } + pos = strstr (pos + 9, "USERNAME="); + } + + pos = strstr (*out_cnc_params, "PASSWORD="); + while (pos) { + if (((pos > *out_cnc_params) && (*(pos-1) == ';')) || + (pos == *out_cnc_params)) { + for (ptr = pos + 9; ptr && *ptr != '\0' && *ptr != ';'; ptr++); + if (ptr != pos + 9) { + if (out_password) + *out_password = g_strndup (pos + 9, ptr - (pos + 9)); + } + + if (*ptr) + memmove (pos, ptr + 1, strlen (ptr)); + else + *pos = 0; + gchar *tmp; + gint len; + tmp = *out_cnc_params; + len = strlen (tmp) - 1; + if (tmp [len] == ';') + tmp [len] = 0; + break; + } + pos = strstr (pos + 9, "PASSWORD="); + } + } + + /* RFC 1738 decode provider, username and password strings */ + gda_rfc1738_decode (*out_provider); + gda_rfc1738_decode (*out_username); + if (out_password) + gda_rfc1738_decode (*out_password); +} + +/* + * NB: @sep must not be zero + */ +static gboolean +_parse_formatted_date (GDate *gdate, const gchar *value, GDateDMY first, GDateDMY second, GDateDMY third, gchar sep, + const char **out_endptr) +{ + GDateYear year = G_DATE_BAD_YEAR; + GDateMonth month = G_DATE_BAD_MONTH; + GDateDay day = G_DATE_BAD_DAY; + unsigned long int tmp; + const char *endptr; + guint8 iter; + guint16 parsed_values [3] = {0, 0, 0}; + + g_date_clear (gdate, 1); + + /* checks */ + if ((first == second) || (first == third) || (second == third)) { + g_warning (_("The 'first', 'second' and 'third' arguments must be different")); + return FALSE; + } + if ((sep >= '0') && (sep <= '9')) { + if (sep) + g_warning (_("Invalid separator '%c'"), sep); + else + g_warning (_("Invalid null separator")); + return FALSE; + } + + /* 1st number */ + for (endptr = value, tmp = 0, iter = 0; (*endptr >= '0') && (*endptr <= '9') && (iter < 4); endptr++) + tmp = tmp * 10 + *endptr - '0'; + parsed_values[0] = tmp; + if (*endptr != sep) + return FALSE; + + /* 2nd number */ + endptr++; + for (tmp = 0, iter = 0; (*endptr >= '0') && (*endptr <= '9') && (iter < 4); endptr++) + tmp = tmp * 10 + *endptr - '0'; + parsed_values[1] = tmp; + if (*endptr != sep) + return FALSE; + + /* 3rd number */ + endptr++; + for (tmp = 0, iter = 0; (*endptr >= '0') && (*endptr <= '9') && (iter < 4); endptr++) + tmp = tmp * 10 + *endptr - '0'; + parsed_values[2] = tmp; + + /* reordering */ + guint16 rmonth = 0, rday = 0; + switch (first) { + case G_DATE_YEAR: + year = parsed_values[0]; + break; + case G_DATE_MONTH: + rmonth = parsed_values[0]; + break; + case G_DATE_DAY: + rday = parsed_values[0]; + break; + default: + g_warning (_("Unknown GDateDMY value %u"), first); + return FALSE; + } + + switch (second) { + case G_DATE_YEAR: + year = parsed_values[1]; + break; + case G_DATE_MONTH: + rmonth = parsed_values[1]; + break; + case G_DATE_DAY: + rday = parsed_values[1]; + break; + default: + g_warning (_("Unknown GDateDMY value %u"), second); + return FALSE; + } + + switch (third) { + case G_DATE_YEAR: + year = parsed_values[2]; + break; + case G_DATE_MONTH: + rmonth = parsed_values[2]; + break; + case G_DATE_DAY: + rday = parsed_values[2]; + break; + default: + g_warning (_("Unknown GDateDMY value %u"), third); + return FALSE; + } + + /* checks */ + month = rmonth > 0 ? (rmonth <= G_DATE_DECEMBER ? rmonth : G_DATE_BAD_MONTH) : G_DATE_BAD_MONTH; + if (month == G_DATE_BAD_MONTH) + return FALSE; + day = rday > 0 ? (rday <= G_MAXUINT8 ? rday : G_DATE_BAD_DAY) : G_DATE_BAD_DAY; + if (day == G_DATE_BAD_DAY) + return FALSE; + + if (g_date_valid_dmy (day, month, year)) { + g_date_set_dmy (gdate, day, month, year); + if (out_endptr) + *out_endptr = endptr; + return TRUE; + } + else + return FALSE; +} + +static gboolean +_parse_iso8601_date (GDate *gdate, const gchar *value, const char **out_endptr) +{ + return _parse_formatted_date (gdate, value, G_DATE_YEAR, G_DATE_MONTH, G_DATE_DAY, '-', out_endptr); +} + +/** + * gda_parse_iso8601_date: + * @gdate: a pointer to a #GDate structure which will be filled + * @value: a string + * + * Extracts date parts from @value, and sets @gdate's contents + * + * Accepted date format is "YYYY-MM-DD" (more or less than 4 digits for years and + * less than 2 digits for month and day are accepted). Years must be in the 1-65535 range, + * a limitation imposed by #GDate. + * + * Returns: %TRUE if @value has been sucessfuly parsed as a valid date (see g_date_valid()). + */ +gboolean +gda_parse_iso8601_date (GDate *gdate, const gchar *value) +{ + g_return_val_if_fail (gdate, FALSE); + + const char *endptr; + if (!value) + return FALSE; + + if (! _parse_iso8601_date (gdate, value, &endptr) || *endptr) + return FALSE; + else + return TRUE; +} + +/** + * gda_parse_formatted_date: + * @gdate: a pointer to a #GDate structure which will be filled + * @value: a string to be parsed + * @first: a #GDateDMY specifying which of year, month or day appears first (in the first bytes) in @value + * @second: a #GDateDMY specifying which of year, month or day appears second (in the first bytes) in @value + * @third: a #GDateDMY specifying which of year, month or day appears third (in the first bytes) in @value + * @sep: spcifies the expected separator character bewteen year, month and day (for example '-') + * + * This function is similar to gda_parse_iso8601_date() (with @first being @G_DATE_YEAR, @second being @G_DATE_MONTH, + * @third being @G_DATE_DAY and @sep being '-') but allows one to specify the expected date format. + * + * Returns: %TRUE if @value has been sucessfuly parsed as a valid date (see g_date_valid()). + * + * Since: 5.2 + */ +gboolean +gda_parse_formatted_date (GDate *gdate, const gchar *value, GDateDMY first, GDateDMY second, GDateDMY third, gchar sep) +{ + g_return_val_if_fail (gdate, FALSE); + + const char *endptr; + if (!value) + return FALSE; + + if (! _parse_formatted_date (gdate, value, first, second, third, sep, &endptr)) + return FALSE; + if (*endptr) + return FALSE; + return TRUE; +} + + +static GdaTime * +_parse_iso8601_time (const gchar *value, gchar sep, glong timezone, const char **out_endptr) +{ + unsigned long int tmp; + const char *endptr; + gchar *stz = NULL; + gdouble seconds = 0.0; + int h, m; + GTimeZone *tz; + + + if ((*value < '0') || (*value > '9')) + return NULL; + + /* hour */ + guint8 iter; + for (iter = 0, tmp = 0, endptr = value; (*endptr >= '0') && (*endptr <= '9') && (iter < 2); iter++, endptr++) { + tmp = tmp * 10 + *endptr - '0'; + if (tmp > 23) + return NULL; + } + h = tmp; + if ((sep && *endptr != sep) || !*endptr) + return NULL; + + /* minutes */ + if (sep) + endptr++; + for (tmp = 0, iter = 0 ; (*endptr >= '0') && (*endptr <= '9') && (iter < 2); iter ++, endptr++) { + tmp = tmp * 10 + *endptr - '0'; + if (tmp > 59) + return NULL; + } + m = tmp; + if ((sep && *endptr != sep) || !*endptr) + return NULL; + + /* seconds */ + if (sep) + endptr++; + if (sep == 0 && (*endptr == ' ' || *endptr == ':')) + return NULL; + seconds = g_strtod ((const gchar*) endptr, &stz); + if (seconds >= 60.0) { + *out_endptr = stz; + return NULL; + } + tz = g_time_zone_new_utc (); + if (stz != NULL) { + g_time_zone_unref (tz); + tz = g_time_zone_new (stz); + if (tz == NULL) { + tz = g_time_zone_new_utc (); + } + for (; *endptr; endptr++); + } + GDateTime *dt = g_date_time_new (tz, 1978, 1, 1, h, m, seconds); + + g_time_zone_unref (tz); + + *out_endptr = endptr; + if (dt != NULL) { + return (GdaTime*) dt; + } + + return NULL; +} + +/** + * gda_parse_iso8601_time: + * @value: a string + * + * Extracts time parts from @value, and sets @timegda's contents + * + * Accepted date format is "HH:MM:SS[.ms][TZ]" where TZ is +hour or -hour. + * If no time zone is given UTC is used. + * + * Returns: (transfer full): a new parsed #GdaTime + */ +GdaTime * +gda_parse_iso8601_time (const gchar *value) +{ + g_return_val_if_fail (value != NULL, FALSE); + gchar *str = g_strdup_printf ("1970-01-01T%s", value); + GDateTime *dt; + GTimeZone *tz = g_time_zone_new_utc (); + dt = g_date_time_new_from_iso8601 (str, tz); + g_time_zone_unref (tz); + g_free (str); + if (dt != NULL) { + return (GdaTime*) dt; + } + return NULL; +} + +/** + * gda_parse_formatted_time: + * @value: a string + * @sep: the time separator, usually ':'. If equal to @0, then the expexted format will be HHMMSS... + * + * Returns: (transfer full): a new parsed #GdaTime + * + * Since: 6.0 + */ +GdaTime * +gda_parse_formatted_time (const gchar *value, gchar sep) +{ + if (!value) + return NULL; + const char *endptr; + return _parse_iso8601_time (value, sep, 0, &endptr); +} + +/** + * gda_parse_formatted_timestamp: + * @value: a string to be parsed + * @first: a #GDateDMY specifying which of year, month or day appears first (in the first bytes) in @value + * @second: a #GDateDMY specifying which of year, month or day appears second (in the first bytes) in @value + * @third: a #GDateDMY specifying which of year, month or day appears third (in the first bytes) in @value + * @sep: specifies the expected separator character between year, month and day (for example '-') + * + * This function is similar to g_date_time_new_from_iso8601() (with @first being @G_DATE_YEAR, @second being @G_DATE_MONTH, + * @third being @G_DATE_DAY and @sep being '-') but allows one to specify the expected date format. + * + * Returns: (nullable) (transfer full): a new #GDateTime if @value has been successfully parsed as a valid date (see g_date_valid()). + * + * Since: 5.2 + */ +GDateTime* +gda_parse_formatted_timestamp (const gchar *value, + GDateDMY first, GDateDMY second, GDateDMY third, gchar sep) +{ + g_return_val_if_fail (value != NULL, NULL); + + const char *endptr; + GDate gdate; + GdaTime* timegda = NULL; + + if (!value) + return NULL; + + /* date part */ + if (! _parse_formatted_date (&gdate, value, first, second, third, sep, &endptr)) { + return NULL; + } + if (endptr != NULL) { + /* separator */ + if (*endptr != 'T' && *endptr != ' ') { + return NULL; + } + value = endptr + 1; + if (value != NULL) { + /* time part */ + timegda = _parse_iso8601_time (value, ':', 0, &endptr); + if (timegda == NULL || *endptr) + return NULL; + } + } + + gchar *stz; + gint ts = gda_time_get_timezone (timegda); + if (ts < 0) ts *= -1; + gint h = ts/60/60; + gint m = ts - h * 60; + gint s = ts - h * 60 * 60 - m * 60; + stz = g_strdup_printf ("%s%02d:%02d:%02d", + gda_time_get_timezone (timegda) >= 0 ? "+" : "-", + h, m, s); + GTimeZone* tz = g_time_zone_new (stz); + g_free (stz); + if (tz == NULL) + return NULL; + gdouble seconds; + seconds = (gdouble) gda_time_get_second (timegda) + gda_time_get_fraction (timegda) / 1000000; + GDateTime *ret = g_date_time_new (tz, + g_date_get_year (&gdate), + g_date_get_month (&gdate), + g_date_get_day (&gdate), + gda_time_get_hour (timegda), + gda_time_get_minute (timegda), + seconds); + gda_time_free (timegda); + return ret; +} diff --git a/.flatpak-builder/cache/objects/eb/b857c4d6fc43bff07dbdb126b41bbfce3cc0236d113d7ce93e96419ad51393.dirtree b/.flatpak-builder/cache/objects/eb/b857c4d6fc43bff07dbdb126b41bbfce3cc0236d113d7ce93e96419ad51393.dirtree new file mode 100644 index 0000000..d34c3cd Binary files /dev/null and b/.flatpak-builder/cache/objects/eb/b857c4d6fc43bff07dbdb126b41bbfce3cc0236d113d7ce93e96419ad51393.dirtree differ diff --git a/.flatpak-builder/cache/objects/eb/e61257a19571d9911c57e45d8ea894e9a8171679261a3b4828fa60ccfb01ee.file b/.flatpak-builder/cache/objects/eb/e61257a19571d9911c57e45d8ea894e9a8171679261a3b4828fa60ccfb01ee.file new file mode 120000 index 0000000..3aeb89b --- /dev/null +++ b/.flatpak-builder/cache/objects/eb/e61257a19571d9911c57e45d8ea894e9a8171679261a3b4828fa60ccfb01ee.file @@ -0,0 +1 @@ +../../share/runtime/locale/sk/share/sk \ No newline at end of file diff --git a/.flatpak-builder/cache/objects/eb/e71ae931008b3f60349a80fc88c95108d94bc66709d3a07d042c69a3cbe729.dirtree b/.flatpak-builder/cache/objects/eb/e71ae931008b3f60349a80fc88c95108d94bc66709d3a07d042c69a3cbe729.dirtree new file mode 100644 index 0000000..8992eca Binary files /dev/null and b/.flatpak-builder/cache/objects/eb/e71ae931008b3f60349a80fc88c95108d94bc66709d3a07d042c69a3cbe729.dirtree differ diff --git a/.flatpak-builder/cache/objects/eb/ff5f8d8cc6d11560178d3c2ed401bb7f73649ede934991808ca1e68840e29c.file b/.flatpak-builder/cache/objects/eb/ff5f8d8cc6d11560178d3c2ed401bb7f73649ede934991808ca1e68840e29c.file new file mode 100644 index 0000000..b32a7e2 --- /dev/null +++ b/.flatpak-builder/cache/objects/eb/ff5f8d8cc6d11560178d3c2ed401bb7f73649ede934991808ca1e68840e29c.file @@ -0,0 +1,369 @@ +/* + * Copyright (C) 2005 - 2013 Vivien Malerba + * Copyright (C) 2009 Bas Driessen + * Copyright (C) 2010 David King + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +#define G_LOG_DOMAIN "GDA-connection-event" + +#include +#include + +typedef struct { + gchar *description; + glong provider_code; + GdaConnectionEventCode gda_code; + gchar *source; + gchar *sqlstate; + GdaConnectionEventType type; /* default is GDA_CONNECTION_EVENT_ERROR */ +} GdaConnectionEventPrivate; + +enum { + PROP_0, + + PROP_TYPE +}; + +static void gda_connection_event_dispose (GObject *object); +static void gda_connection_event_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec); +static void gda_connection_event_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec); + +/* + * GdaConnectionEvent class implementation + */ + +G_DEFINE_TYPE_WITH_PRIVATE (GdaConnectionEvent, gda_connection_event, G_TYPE_OBJECT) + + +static void +gda_connection_event_class_init (GdaConnectionEventClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->dispose = gda_connection_event_dispose; + object_class->set_property = gda_connection_event_set_property; + object_class->get_property = gda_connection_event_get_property; + + g_object_class_install_property(object_class, + PROP_TYPE, + g_param_spec_int("type", + "Type", + "Connection event type", + 0, + GDA_CONNECTION_EVENT_COMMAND, + GDA_CONNECTION_EVENT_ERROR, + G_PARAM_READWRITE)); +} + +static void +gda_connection_event_init (GdaConnectionEvent *event) +{ + GdaConnectionEventPrivate *priv = gda_connection_event_get_instance_private (event); + priv->type = GDA_CONNECTION_EVENT_ERROR; + priv->gda_code = GDA_CONNECTION_EVENT_CODE_UNKNOWN; +} + +static void +gda_connection_event_dispose (GObject *object) +{ + GdaConnectionEvent *event = (GdaConnectionEvent *) object; + + g_return_if_fail (GDA_IS_CONNECTION_EVENT (event)); + GdaConnectionEventPrivate *priv = gda_connection_event_get_instance_private (event); + + /* free memory */ + if (priv->description) { + g_free (priv->description); + priv->description = NULL; + } + if (priv->source) { + g_free (priv->source); + priv->source = NULL; + } + if (priv->sqlstate) { + g_free (priv->sqlstate); + priv->sqlstate = NULL; + } + + /* chain to parent class */ + G_OBJECT_CLASS (gda_connection_event_parent_class)->dispose (object); +} + +static void gda_connection_event_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) +{ + GdaConnectionEvent *event; + + g_return_if_fail (GDA_IS_CONNECTION_EVENT (object)); + event = GDA_CONNECTION_EVENT (object); + + switch(prop_id) { + case PROP_TYPE: + gda_connection_event_set_event_type (event, g_value_get_int (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void gda_connection_event_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) +{ + GdaConnectionEvent *event; + + g_return_if_fail (GDA_IS_CONNECTION_EVENT (object)); + event = GDA_CONNECTION_EVENT (object); + GdaConnectionEventPrivate *priv = gda_connection_event_get_instance_private (event); + + switch(prop_id) { + case PROP_TYPE: + g_value_set_int (value, priv->type); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +/** + * gda_connection_event_set_event_type: + * @event: a #GdaConnectionEvent object + * @type: the severity of the event + * + * Sets @event's severity (from a simple notice to a fatal event) + * This function should not be called directly. + */ +void +gda_connection_event_set_event_type (GdaConnectionEvent *event, GdaConnectionEventType type) +{ + g_return_if_fail (GDA_IS_CONNECTION_EVENT (event)); + GdaConnectionEventPrivate *priv = gda_connection_event_get_instance_private (event); + + if (priv->type == type) + return; + + priv->type = type; + if (!priv->sqlstate && (priv->type == GDA_CONNECTION_EVENT_ERROR)) + gda_connection_event_set_sqlstate (event, GDA_SQLSTATE_GENERAL_ERROR); + else if (((priv->type == GDA_CONNECTION_EVENT_NOTICE) || + (priv->type == GDA_CONNECTION_EVENT_COMMAND)) && + priv->sqlstate) + gda_connection_event_set_sqlstate (event, NULL); +} + +/** + * gda_connection_event_get_event_type: + * @event: a #GdaConnectionEvent object + * + * Get @event's severity (from a simple notice to a fatal event) + * + * Returns: the event type + */ +GdaConnectionEventType +gda_connection_event_get_event_type (GdaConnectionEvent *event) +{ + g_return_val_if_fail (GDA_IS_CONNECTION_EVENT (event), GDA_CONNECTION_EVENT_ERROR); + GdaConnectionEventPrivate *priv = gda_connection_event_get_instance_private (event); + g_return_val_if_fail (priv, GDA_CONNECTION_EVENT_ERROR); + + return priv->type; +} + +/** + * gda_connection_event_get_description: + * @event: a #GdaConnectionEvent. + * + * Get the description of the event. Note that is @event's type is GDA_CONNECTION_EVENT_COMMAND, + * the the description is the SQL of the command. + * + * Returns: @event's description. + */ +const gchar * +gda_connection_event_get_description (GdaConnectionEvent *event) +{ + g_return_val_if_fail (GDA_IS_CONNECTION_EVENT (event), NULL); + GdaConnectionEventPrivate *priv = gda_connection_event_get_instance_private (event); + return priv->description; +} + +/** + * gda_connection_event_set_description: + * @event: a #GdaConnectionEvent. + * @description: (nullable): a description, or %NULL (to unset current description if any) + * + * Sets @event's @description. This function should not be called directly. + */ +void +gda_connection_event_set_description (GdaConnectionEvent *event, const gchar *description) +{ + g_return_if_fail (GDA_IS_CONNECTION_EVENT (event)); + GdaConnectionEventPrivate *priv = gda_connection_event_get_instance_private (event); + + if (priv->description) + g_free (priv->description); + if (description) + priv->description = g_strdup (description); + else + priv->description = NULL; +} + +/** + * gda_connection_event_get_code: + * @event: a #GdaConnectionEvent. + * + * Returns: @event's code (the code is specific to the provider being used) + */ +glong +gda_connection_event_get_code (GdaConnectionEvent * event) +{ + g_return_val_if_fail (GDA_IS_CONNECTION_EVENT (event), -1); + GdaConnectionEventPrivate *priv = gda_connection_event_get_instance_private (event); + return priv->provider_code; +} + +/** + * gda_connection_event_set_code: + * @event: a #GdaConnectionEvent. + * @code: a code. + * + * Sets @event's code: the code is specific to the provider being used. + * If you want to have a common understanding of the event codes, use + * gda_connection_event_get_gda_code() instead. + * + * This function should not be called directly + */ +void +gda_connection_event_set_code (GdaConnectionEvent *event, glong code) +{ + g_return_if_fail (GDA_IS_CONNECTION_EVENT (event)); + GdaConnectionEventPrivate *priv = gda_connection_event_get_instance_private (event); + priv->provider_code = code; +} + +/** + * gda_connection_event_get_gda_code: + * @event: a #GdaConnectionEvent + * + * Retrieve the code associated to @event. + * + * Returns: the #GdaConnectionEventCode event's code + */ +GdaConnectionEventCode +gda_connection_event_get_gda_code (GdaConnectionEvent *event) +{ + g_return_val_if_fail (GDA_IS_CONNECTION_EVENT (event), GDA_CONNECTION_EVENT_CODE_UNKNOWN); + GdaConnectionEventPrivate *priv = gda_connection_event_get_instance_private (event); + return priv->gda_code; +} + +/** + * gda_connection_event_set_gda_code: + * @event: a #GdaConnectionEvent + * @code: a code + * + * Sets @event's gda code: that code is standardized by the libgda + * library. If you want to specify the corresponding provider specific code, + * use gda_connection_event_get_code() or gda_connection_event_get_sqlstate() instead. + * + * This function should not be called directly + */ +void +gda_connection_event_set_gda_code (GdaConnectionEvent *event, GdaConnectionEventCode code) +{ + g_return_if_fail (GDA_IS_CONNECTION_EVENT (event)); + GdaConnectionEventPrivate *priv = gda_connection_event_get_instance_private (event); + priv->gda_code = code; +} + + +/** + * gda_connection_event_get_source: + * @event: a #GdaConnectionEvent. + * + * Returns: @event's source. + */ +const gchar * +gda_connection_event_get_source (GdaConnectionEvent *event) +{ + g_return_val_if_fail (GDA_IS_CONNECTION_EVENT (event), 0); + GdaConnectionEventPrivate *priv = gda_connection_event_get_instance_private (event); + return priv->source; +} + +/** + * gda_connection_event_set_source: + * @event: a #GdaConnectionEvent. + * @source: a source. + * + * Sets @event's @source; this function should not be called directly + */ +void +gda_connection_event_set_source (GdaConnectionEvent *event, const gchar *source) +{ + g_return_if_fail (GDA_IS_CONNECTION_EVENT (event)); + GdaConnectionEventPrivate *priv = gda_connection_event_get_instance_private (event); + + if (priv->source) + g_free (priv->source); + priv->source = g_strdup (source); +} + +/** + * gda_connection_event_get_sqlstate: + * @event: a #GdaConnectionEvent. + * + * Get the SQLSTATE value of @event. Even though the SQLSTATE values are specified by ANSI SQL and ODBC, + * consult each DBMS for the possible values. However, the "00000" (success) value means that there is no error, + * and the "HY000" (general error) value means an error but no better error code available. + * + * Returns: @event's SQL state. + */ +const gchar * +gda_connection_event_get_sqlstate (GdaConnectionEvent *event) +{ + g_return_val_if_fail (GDA_IS_CONNECTION_EVENT (event), NULL); + GdaConnectionEventPrivate *priv = gda_connection_event_get_instance_private (event); + + return priv->sqlstate ? priv->sqlstate : GDA_SQLSTATE_NO_ERROR; +} + +/** + * gda_connection_event_set_sqlstate: + * @event: a #GdaConnectionEvent. + * @sqlstate: SQL state. + * + * Changes the SQLSTATE code of @event, this function should not be called directly + * + * Sets @event's SQL state. + */ +void +gda_connection_event_set_sqlstate (GdaConnectionEvent *event, const gchar *sqlstate) +{ + g_return_if_fail (GDA_IS_CONNECTION_EVENT (event)); + GdaConnectionEventPrivate *priv = gda_connection_event_get_instance_private (event); + + if (priv->sqlstate) + g_free (priv->sqlstate); + + if (sqlstate) + priv->sqlstate = g_strdup (sqlstate); + else { + priv->sqlstate = NULL; + if (priv->type == GDA_CONNECTION_EVENT_ERROR) + priv->sqlstate = g_strdup (GDA_SQLSTATE_GENERAL_ERROR); + } +} + diff --git a/.flatpak-builder/cache/objects/ec/0ef2f96c48dca5a773467aff15908fb0e4a2ef2d385e68f3956cdff6a27411.dirtree b/.flatpak-builder/cache/objects/ec/0ef2f96c48dca5a773467aff15908fb0e4a2ef2d385e68f3956cdff6a27411.dirtree new file mode 100644 index 0000000..826165e Binary files /dev/null and b/.flatpak-builder/cache/objects/ec/0ef2f96c48dca5a773467aff15908fb0e4a2ef2d385e68f3956cdff6a27411.dirtree differ diff --git a/.flatpak-builder/cache/objects/ec/476285f4737766dad480c782fc292a86ef4ae4afee87cc0a1f129214236b35.file b/.flatpak-builder/cache/objects/ec/476285f4737766dad480c782fc292a86ef4ae4afee87cc0a1f129214236b35.file new file mode 100644 index 0000000..9ee2c11 --- /dev/null +++ b/.flatpak-builder/cache/objects/ec/476285f4737766dad480c782fc292a86ef4ae4afee87cc0a1f129214236b35.file @@ -0,0 +1,1278 @@ + + + + + + + + + Binary icon data in PNG format for the application this sound event +is triggered by. + + + + + An icon name for the application this sound event is triggered by, +as defined in the XDG icon naming specification. + + + + + An identifier for the program this sound event was triggered +by. (e.g. "org.gnu.emacs"). + +> This attribute will automatically be added to the #GSoundContext with +> the #GApplication:application-id if you are using #GApplication, so you +> normally do not need to supply this yourself. + + + + + The locale string the application that is triggering this sound +event is running in. A POSIX locale string such as de_DE@euro. + + + + + The name of the application this sound event was triggered by as +human readable string. (e.g. "GNU Emacs") Localized if possible and +applicable. + +> This attribute will automatically be added to the #GSoundContext if +> it has previously been set with g_set_application_name(), so you normally +> do not need to supply this yourself. + + + + + The path to the process binary of the process that is triggering this sound event. + + + + + The host name of the host the process that is triggering this sound event runs on. + + + + + The unix PID of the process that is triggering this sound event, formatted as string. + + + + + The user that owns the process that is triggering this sound event. + + + + + A version number for the program this sound event was triggered +by. (e.g. "22.2") + + + + + A special attribute that can be used to control the automatic sound +caching of sounds in the sound server. One of "permanent", +"volatile", "never". "permanent" will cause this sample to be +cached in the server permanently. This is useful for very +frequently used sound events such as those used for input +feedback. "volatile" may be used for cacheing sounds in the sound +server temporarily. They will expire after some time or on cache +pressure. Finally, "never" may be used for sounds that should never +be cached, because they are only generated very seldomly or even +only once at most (such as desktop login sounds). + +If this attribute is not explicitly passed to gsound_context_play_simple() +or gsound_context_play_full() it will default to "never". If it is not +explicitly passed to gsound_context_cache() it will default to "permanent". + +If the list of attributes is handed on to the sound server this +attribute is stripped from it. + + + + + A special attribute that can be used to control whether any sounds +are played at all. If this attribute is "1" or unset sounds are +played as normal. However, if it is "0" all calls to +gsound_context_play_simple() or `play_full()` will fail with +GSOUND_ERROR_DISABLED. + +If the list of attributes is handed on to the sound server this +attribute is stripped from it. + + + + + A special attribute that can be used to control on which channel a +sound is played. The value should be one of mono, front-left, +front-right, front-center, rear-left, rear-right, rear-center, lfe, +front-left-of-center, front-right-of-center, side-left, side-right, +top-center, top-front-left, top-front-right, top-front-center, +top-rear-left, top-rear-right, top-rear-center. This attribute is +only honoured by some backends, other backends may choose to ignore +it completely. + +If the list of attributes is handed on to the sound server this +attribute is stripped from it. + + + + + A special attribute that can be used to control the volume this +sound event is played in if the backend supports it. A floating +point value for the decibel multiplier for the sound. 0 dB relates +to zero gain, and is the default volume these sounds are played in. + +If the list of attributes is handed on to the sound server this +attribute is stripped from it. + + + + + A special attribute that can be used to control the XDG sound theme that +is used for this sample. + +If the list of attributes is handed on to the sound server this +attribute is stripped from it. + + + + + A special attribute that can be used to control the XDG sound theme +output profile that is used for this sample. + +If the list of attributes is handed on to the sound server this +attribute is stripped from it. + + + + + A descriptive string for the sound event. Localized if possible and applicable. + + + + + A textual id for an event sound, as mandated by the XDG sound naming specification. + + + + + If this sound event was triggered by a mouse input event, the +number of the mouse button that triggered it, formatted as string. 1 +for left mouse button, 3 for right, 2 for middle. + + + + + If this sound event was triggered by a mouse input event, the X +position of the mouse cursor as fractional value between 0 and 1, +formatted as string, 0 reflecting the left side of the screen, 1 +the right side. + + + + + If this sound event was triggered by a mouse input event, the Y +position of the mouse cursor as fractional value between 0 and 1, +formatted as string, 0 reflecting the top end of the screen, 1 +the bottom end. + + + + + If this sound event was triggered by a mouse input event, the X +position of the mouse cursor on the screen, formatted as string. + + + + + If this sound event was triggered by a mouse input event, the Y +position of the mouse cursor on the screen, formatted as string. + + + + + The artist of this media. Localized if possible and applicable. + + + + + The file name this media was or can be loaded from. + + + + + An icon for this media in binary PNG format. + + + + + An icon name as defined in the XDG icon naming specifcation. + + + + + The language this media is in, in some standard POSIX locale string, such as "de_DE". + + + + + A name describing the media being played. Localized if possible and applicable. + + + + + The "role" this media is played in. For event sounds the string +"event". For other cases strings like "music", "video", "game", ... + + + + + A (song) title describing the media being played. Localized if possible and applicable. + + + + + If this sound event was triggered by a window on the screen and the +windowing system supports multiple desktops, a comma seperated list +of indexes of the desktops this window is visible on. If this +attribute is an empty string, it is visible on all desktops +(i.e. 'sticky'). The first desktop is 0. (e.g. "0,2,3") + + + + + If this sound event was triggered by a window on the screen, the +pixel height of the window. + + + + + If this sound event was triggered by a window on the screen, the X +position of the center of the window as fractional value between 0 +and 1, formatted as string, 0 reflecting the left side of the +screen, 1 the right side. + + + + + If this sound event was triggered by a window on the screen, binary +icon data in PNG format for this window. + + + + + If this sound event was triggered by a window on the screen, an +icon name for this window, as defined in the XDG icon naming +specification. + + + + + If this sound event was triggered by a window on the screen, some +identification string for this window, so that the sound system can +recognize specific windows. + + + + + If this sound event was triggered by a window on the screen, the +name of this window as human readable string. + + + + + If this sound event was triggered by a window on the screen, the Y +position of the center of the window as fractional value between 0 +and 1, formatted as string, 0 reflecting the top side of the +screen, 1 the bottom side. + + + + + If this sound event was triggered by a window on the screen, the +pixel width of the window. + + + + + If this sound event was triggered by a window on the screen, the X +position of the window measured from the top left corner of the +screen to the top left corner of the window. + + + + + If this sound event was triggered by a window on the screen and the +windowing system is X11, the X display name of the window (e.g. ":0"). + + + + + If this sound event was triggered by a window on the screen and the +windowing system is X11, the X monitor id of the window formatted as +string (e.g. "0"). + + + + + If this sound event was triggered by a window on the screen and the +windowing system is X11, the X screen id of the window formatted as +string (e.g. "0"). + + + + + If this sound event was triggered by a window on the screen and the +windowing system is X11, the XID of the window formatted as string. + + + + + If this sound event was triggered by a window on the screen, the y +position of the window measured from the top left corner of the +screen to the top left corner of the window. + + + + + + + + + + + + + + + + + + + + + + + + + + ca: the wrapped context +Wrapper for ca_context. + + + + Creates and initializes a new #GSoundContext. If the an error occured +during initialization, #NULL is returned and @error will be set +appropriately. + + + A new #GSoundContext + + + + + A #GCancellable, or %NULL + + + + + + Requests that a sound be cached on the server. See [#caching][gsound-GSound-Context#caching]. + + + %TRUE on success + + + + + A #GSoundContext + + + + Return location for error + + + + A %NULL-terminated list of attribute-value pairs + + + + + + Requests that a sound be cached on the server. See [#caching][gsound-GSound-Context#caching]. + +This function is intented to be used by language bindings. + + + + + + + A #GSoundContext + + + + Hash table of attrerties + + + + + + + + + Attempts to open a connection to the backend sound driver. It is recommended +that you set context attributes with gsound_context_set_attributes() before +calling this function. + +> A connection is automatically opened before playing or caching sounds, +> so you rarely need to call this yourself. + + + %TRUE if the output device was opened successfully, or %FALSE + (populating @error) + + + + + A #GSoundContext + + + + + + Asynchronously request a sound to be played. When playback is finished +(or if an error occurs) then @callback will be called, following the +normal GIO async pattern. + +If playback is cancelled via @cancellable, then @callback will be called +with #G_IO_ERROR_CANCELLED. + +If you do not need notification of when playback is complete, you should +use gsound_context_play_simple(). + + + + + + + A #GSoundContext + + + + A #GCancellable, or %NULL + + + + callback + + + + User data passed to @callback + + + + A %NULL-terminated list of attribute-value pairs + + + + + + Finish an async operation started by gsound_context_play_full(). You +must call this function in the callback to free memory and receive any +errors which occurred. + + + %TRUE if playing finished successfully + + + + + A #GSoundContext + + + + Result object passed to the callback of + gsound_context_play_full() + + + + + + Asynchronously request a sound to be played. When playback is finished +(or if an error occurs) then @callback will be called, following the +normal GIO async pattern. + +If playback is cancelled via @cancellable, then @callback will be called +with #G_IO_ERROR_CANCELLED. + +If you do not need notification of when playback is complete, you should +use gsound_context_play_simple(). + +This function is intented to be used by language bindings. + + + + + + + A #GSoundContext + + + + Attributes + + + + + + + A #GCancellable, or %NULL + + + + callback + + + + user_data + + + + + + The basic "fire-and-forget" play command. This function will not block, and +just sends a request to the sound server before immediately returning. + +If you need to know when a sound finishes playing then you should call +gsound_context_play_full() instead. + +You can cancel playback at any time by calling g_cancellable_cancel() on +@cancellable, if supplied. + + + %TRUE on success, or %FALSE, populating @error + + + + + A #GSoundContext + + + + A #GCancellable, or %NULL + + + + Return location for error, or %NULL + + + + A %NULL-terminated list of attribute-value pairs + + + + + + The basic "fire-and-forget" play command. This function will not block, and +just sends a request to the sound server before immediately returning. + +If you need to know when a sound finishes playing then you should call +gsound_context_play_full() instead. + +You can cancel playback at any time by calling g_cancellable_cancel() on +@cancellable, if supplied. + +This function is intented to be used by language bindings. + + + %TRUE on success, %FALSE on error + + + + + A #GSoundContext + + + + Attributes + + + + + + + A #GCancellable + + + + + + Set attributes or change attributes on @context. Subsequent calls to this +function calling the same attributes will override the earlier values. + +Note that GSound will set the #GSOUND_ATTR_APPLICATION_NAME and +#GSOUND_ATTR_APPLICATION_ID for you if using #GApplication, so you do +not normally need to set these yourself. + + + %TRUE if attributes were updated successfully + + + + + A #GSoundContext + + + + Return location for error + + + + %NULL terminated list of attribute name-value pairs + + + + + + Set attributes or change attributes on @context. Subsequent calls to this +function calling the same attributes will override the earlier values. + +Note that GSound will set the #GSOUND_ATTR_APPLICATION_NAME and +#GSOUND_ATTR_APPLICATION_ID for you if using #GApplication, so you do +not normally need to set these yourself. + +This function is intented to be used by language bindings. + + + %TRUE if attributes were updated successfully + + + + + A #GSoundContext + + + + Hash table of attributes to set + + + + + + + + + Sets the libcanberra driver to @driver, for example "pulse", "alsa" or "null". +You normally do not need to set this yourself. + +Note that this function may return %TRUE even if the specified driver is +not available: see the libcanberra documentation for details. + + + %TRUE if the libcanberra driver was set successfully + + + + + A #GSoundContext + + + + libcanberra driver to use + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Attributes which can be applied to a #GSoundContext or passed to one of +the `play()` or `cache()` methods. + + + A #GSoundContext is used for playing system sounds. The typical use pattern +is: + +* Initialize the #GSoundContext +* [Optional] Set any global attributes using gsound_context_set_attributes() +* [Optional] Cache any frequently-used sounds (for example, sound + effects for a game) using gsound_context_cache() +* Play sounds using gsound_context_play_simple() or gsound_context_play_full() +* Close the connection to the sound server and clean up the context using + g_object_unref() + +#GSoundContext implements the #GInitable interface, so if created with +g_object_new() (as typically happens with language bindings) then you must +call the g_initable_init() method before attempting to use it. + +# Simple Examples + +In C: + +|[<!-- language="C" --> +GSoundContext *ctx = NULL; +GCancellable *cancellable = g_cancellable_new(); +GError *error = NULL; + +ctx = gsound_context_new(cancellable, &error); +if (error) { + // handle error +} + +gsound_context_play_simple(ctx, cancellable, &error, + GSOUND_ATTR_EVENT_ID, "phone-incoming-call", + // other attributes... + NULL); +]| + +or, using Python via GObject Introspection: + +|[<!-- language="Python" --> +from gi.repository import GSound + +ctx = GSound.Context() + +try: + ctx.init(); + ctx.play_simple({ GSound.ATTR_EVENT_ID : "phone-incoming-call" }) +except: + # Handle error + pass +]| + +or using Vala: + +|[<!-- language="Vala" --> +try { + var ctx = new GSound.Context(); + ctx.play_simple(null, GSound.Attribute.EVENT_ID, "phone-incoming-call"); +} catch (Error e) { + // handle error +} +]| + +# `play_simple()` versus `play_full()` + +The above examples use the gsound_context_play_simple() method for +playing sounds. This is a "fire and forget" method which returns +immediately and does not block your program, and is suitable for most use +cases. + +If you need to find out when the sound finished (for example to repeat the +sound) then you can use the gsound_context_play_full() version. This +is an asynchronous method using the standard GIO async pattern, which will +run the supplied #GAsyncReadyCallback when the sound server has finished. +It is guaranteed that the callback will be run exactly once. + +Note that calling gsound_context_play_full() with a %NULL callback is not +equivalent to calling gsound_context_play_simple(). When calling +play_simple(), errors which occur before the sound is passed to the sound +server are reported immediately, whereas with `play_full()` these are reported +in the callback. If you pass a %NULL callback to gsound_context_play_full() +you will not be able to receive these errors, so it is strongly recommended +to avoid doing this and use gsound_context_play_simple() in the case when +you don't need to be notified when the sound has finished. + +# Passing Attributes + +GSound supplies information to the sound server by means of attributes. +Attributes can be set on the #GSoundContext itself using +gsound_context_set_attributes(), or supplied in a `play()` call. Attributes +set on the context will automatically applied to any subsequent `play()` +calls, unless overridden by that call. + +In C and Vala, attributes are passed as %NULL-terminated list of +(attribute, value) pairs. When using GObject introspection, attributes are +typically passed using a language-specific associated array, for example +a dict in Python or an object in JavaScript. + +For the list of attributes supported by GSound, see +[GSound Attributes][gsound-GSound-Attributes]. + +# Caching # {#caching} + +If supported by the sound server, frequently-used sounds may be cached. This +may be useful, for example, for sound effects in a game. To cache a sound, +either call gsound_context_cache(), or pass the special +#GSOUND_ATTR_CANBERRA_CACHE_CONTROL attribute to one of the `play()` +functions. + +For example, in the startup code for a game you might include something +like the following (error checking omitted): + +|[ <-- language="C" --> +GSoundContext *ctx = gsound_context_new (NULL, NULL); +gsound_context_cache(ctx, NULL, + GSOUND_ATTR_MEDIA_FILENAME, + "/path/to/player-spaceship-fire-laser.ogg", + NULL); +]| + +There are three caching modes available, "permanent", "volatile" and "never". +The default mode when calling gsound_context_cache() is "permanent", and +the default mode for gsound_context_play_simple() and `play_full()` is +"never". + +See the documentation for #GSOUND_ATTR_CANBERRA_CACHE_CONTROL for more +details. + + + diff --git a/.flatpak-builder/cache/objects/ec/610df5efe51532839ca76b53839dda151b9ffb0a0478c40266536425865068.dirtree b/.flatpak-builder/cache/objects/ec/610df5efe51532839ca76b53839dda151b9ffb0a0478c40266536425865068.dirtree new file mode 100644 index 0000000..59a0bd0 Binary files /dev/null and b/.flatpak-builder/cache/objects/ec/610df5efe51532839ca76b53839dda151b9ffb0a0478c40266536425865068.dirtree differ diff --git a/.flatpak-builder/cache/objects/ec/7677417546945648eeaff1ba022a55e111e073a5f096777b8d39066e8607e3.dirtree b/.flatpak-builder/cache/objects/ec/7677417546945648eeaff1ba022a55e111e073a5f096777b8d39066e8607e3.dirtree new file mode 100644 index 0000000..cc5c200 Binary files /dev/null and b/.flatpak-builder/cache/objects/ec/7677417546945648eeaff1ba022a55e111e073a5f096777b8d39066e8607e3.dirtree differ diff --git a/.flatpak-builder/cache/objects/ec/95112c8eb22c44646ebda27f53639480cbf154d91077fd2521b587a0ab0d1e.file b/.flatpak-builder/cache/objects/ec/95112c8eb22c44646ebda27f53639480cbf154d91077fd2521b587a0ab0d1e.file new file mode 100644 index 0000000..4eca7f8 --- /dev/null +++ b/.flatpak-builder/cache/objects/ec/95112c8eb22c44646ebda27f53639480cbf154d91077fd2521b587a0ab0d1e.file @@ -0,0 +1,751 @@ +/* + * Copyright (C) 2001 - 2002 Carlos Perelló Marín + * Copyright (C) 2002 - 2003 Gonzalo Paniagua Javier + * Copyright (C) 2002 - 2005 Rodrigo Moya + * Copyright (C) 2005 Denis Fortin + * Copyright (C) 2005 - 2014 Vivien Malerba + * Copyright (C) 2005 Álvaro Peña + * Copyright (C) 2006 - 2008 Murray Cumming + * Copyright (C) 2007 Armin Burgmeier + * Copyright (C) 2009 Bas Driessen + * Copyright (C) 2010 David King + * Copyright (C) 2011 Marco Ciampa + * Copyright (C) 2017 Daniel Espinosa + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include +#include +#include +#include "gda-sqlite.h" +#include "gda-sqlite-util.h" +#include "gda-sqlite-recordset.h" +#include "gda-sqlite-provider.h" +#include "gda-sqlite-blob-op.h" +#include +#include +#include + +#include "virtual/gda-vconnection-data-model.h" +#include "virtual/gda-vconnection-data-model-private.h" + +#define _GDA_PSTMT(x) ((GdaPStmt*)(x)) + +static void gda_sqlite_recordset_class_init (GdaSqliteRecordsetClass *klass); +static void gda_sqlite_recordset_init (GdaSqliteRecordset *recset); +static void gda_sqlite_recordset_dispose (GObject *object); + +/* virtual methods */ +static gint gda_sqlite_recordset_fetch_nb_rows (GdaDataSelect *model); +static gboolean gda_sqlite_recordset_fetch_random (GdaDataSelect *model, GdaRow **prow, gint rownum, GError **error); + +static gboolean gda_sqlite_recordset_fetch_next (GdaDataSelect *model, GdaRow **prow, gint rownum, GError **error); + + +static GdaRow *fetch_next_sqlite_row (GdaSqliteRecordset *model, gboolean do_store, GError **error); + +static void virt_cnc_set_working_obj (GdaConnection *cnc, GdaSqliteRecordset *model); + +typedef struct { + GWeakRef provider; + gboolean empty_forced; + gint next_row_num; + GdaRow *tmp_row; /* used in cursor mode */ +} GdaSqliteRecordsetPrivate; + +G_DEFINE_TYPE_WITH_PRIVATE(GdaSqliteRecordset, gda_sqlite_recordset, GDA_TYPE_DATA_SELECT) + +GHashTable *error_blobs_hash = NULL; + +/* + * Object init and finalize + */ +static void +gda_sqlite_recordset_init (GdaSqliteRecordset *recset) +{ + g_return_if_fail (GDA_IS_SQLITE_RECORDSET (recset)); + GdaSqliteRecordsetPrivate *priv = gda_sqlite_recordset_get_instance_private (recset); + priv->next_row_num = 0; + priv->empty_forced = FALSE; + g_weak_ref_init (&priv->provider, NULL); +} + +static void +gda_sqlite_recordset_class_init (GdaSqliteRecordsetClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GdaDataSelectClass *pmodel_class = GDA_DATA_SELECT_CLASS (klass); + + object_class->dispose = gda_sqlite_recordset_dispose; + pmodel_class->fetch_nb_rows = gda_sqlite_recordset_fetch_nb_rows; + pmodel_class->fetch_random = gda_sqlite_recordset_fetch_random; + + pmodel_class->fetch_next = gda_sqlite_recordset_fetch_next; + pmodel_class->fetch_prev = NULL; + pmodel_class->fetch_at = NULL; + + g_assert (!error_blobs_hash); + error_blobs_hash = g_hash_table_new (NULL, NULL); +} + +static void +gda_sqlite_recordset_dispose (GObject *object) +{ + GdaSqliteRecordset *recset = (GdaSqliteRecordset *) object; + + g_return_if_fail (GDA_IS_SQLITE_RECORDSET (recset)); + GdaSqliteRecordsetPrivate *priv = gda_sqlite_recordset_get_instance_private (recset); + + GdaSqlitePStmt *ps; + ps = GDA_SQLITE_PSTMT (gda_data_select_get_prep_stmt (GDA_DATA_SELECT (object))); + if (ps != NULL) { + _gda_sqlite_pstmt_set_is_used (ps, FALSE); + virt_cnc_set_working_obj (gda_data_select_get_connection ((GdaDataSelect*) recset), recset); + GdaSqliteProvider *prov = g_weak_ref_get (&priv->provider); + if (prov != NULL) { + SQLITE3_CALL (prov, sqlite3_reset) (_gda_sqlite_pstmt_get_stmt (ps)); + g_object_unref (prov); + } + virt_cnc_set_working_obj (gda_data_select_get_connection ((GdaDataSelect*) recset), NULL); + } + + if (priv->tmp_row) { + g_object_unref (priv->tmp_row); + priv->tmp_row = NULL; + } + g_weak_ref_clear (&priv->provider); + + G_OBJECT_CLASS (gda_sqlite_recordset_parent_class)->dispose (object); +} + +static void +read_rows_to_init_col_types (GdaSqliteRecordset *model) +{ + gint i; + gint *missing_cols, nb_missing; + GdaDataSelect *pmodel = (GdaDataSelect*) model; + + missing_cols = g_new (gint, gda_pstmt_get_ncols (gda_data_select_get_prep_stmt(pmodel))); + for (nb_missing = 0, i = 0; i < gda_pstmt_get_ncols (gda_data_select_get_prep_stmt(pmodel)); i++) { + if ( gda_pstmt_get_types (gda_data_select_get_prep_stmt(pmodel))[i] == GDA_TYPE_NULL) + missing_cols [nb_missing++] = i; + } + +#ifdef GDA_DEBUG_NO + if (nb_missing == 0) + g_print ("All columns are known for model %p\n", pmodel); +#endif + + for (; nb_missing > 0; ) { + GdaRow *prow; + prow = fetch_next_sqlite_row (model, TRUE, NULL); + if (!prow) + break; +#ifdef GDA_DEBUG_NO + g_print ("Prefetched row %d of model %p\n", model->priv->next_row_num - 1, pmodel); +#endif + for (i = nb_missing - 1; i >= 0; i--) { + if ( gda_pstmt_get_types (gda_data_select_get_prep_stmt(pmodel)) [missing_cols [i]] != GDA_TYPE_NULL) { +#ifdef GDA_DEBUG_NO + g_print ("Found type '%s' for col %d\n", + g_type_name ( gda_pstmt_get_types (gda_data_select_get_prep_stmt(pmodel)) [missing_cols [i]]), + missing_cols [i]); +#endif + memmove (missing_cols + i, missing_cols + i + 1, sizeof (gint) * (nb_missing - i - 1)); + nb_missing --; + } + } + } + +#ifdef GDA_DEBUG_NO + if (nb_missing > 0) + g_print ("Hey!, some columns are still not known for prep stmt %p\n", pmodel->prep_stmt); +#endif + + g_free (missing_cols); +} + +/* + * the @ps struct is modified and transferred to the new data model created in + * this function + */ +GdaDataModel * +_gda_sqlite_recordset_new (GdaConnection *cnc, GdaSqlitePStmt *ps, GdaSet *exec_params, + GdaDataModelAccessFlags flags, GType *col_types, gboolean force_empty) +{ + GdaSqliteRecordset *model; + SqliteConnectionData *cdata; + gint i; + GdaDataModelAccessFlags rflags; + + g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL); + g_return_val_if_fail (ps != NULL, NULL); + + cdata = (SqliteConnectionData*) gda_connection_internal_get_provider_data_error (cnc, NULL); + if (!cdata) + return NULL; + + if (!cdata->types_hash) + _gda_sqlite_compute_types_hash (cdata); + GdaSqliteProvider *prov = GDA_SQLITE_PROVIDER (gda_connection_get_provider (cnc)); + + /* make sure @ps reports the correct number of columns */ + if (gda_pstmt_get_ncols (_GDA_PSTMT (ps)) < 0) + gda_pstmt_set_cols (_GDA_PSTMT (ps), SQLITE3_CALL (prov, sqlite3_column_count) (_gda_sqlite_pstmt_get_stmt (ps)) - + _gda_sqlite_pstmt_get_nb_rowid_columns (ps), gda_pstmt_get_types (_GDA_PSTMT (ps))); + + /* completing ps */ + g_assert (! _gda_sqlite_pstmt_get_is_used (ps)); + _gda_sqlite_pstmt_set_is_used (ps, TRUE); + if (!gda_pstmt_get_types (_GDA_PSTMT (ps)) && (gda_pstmt_get_ncols (_GDA_PSTMT (ps)) > 0)) { + /* create prepared statement's columns */ + GSList *list; + for (i = 0; i < gda_pstmt_get_ncols (_GDA_PSTMT (ps)); i++) + gda_pstmt_set_tmpl_columns (_GDA_PSTMT (ps), g_slist_prepend (gda_pstmt_get_tmpl_columns (_GDA_PSTMT (ps)), + gda_column_new ())); + gda_pstmt_set_tmpl_columns (_GDA_PSTMT (ps), g_slist_reverse (gda_pstmt_get_tmpl_columns (_GDA_PSTMT (ps)))); + + /* create prepared statement's types, all types are initialized to GDA_TYPE_NULL */ + gda_pstmt_set_cols (_GDA_PSTMT (ps), gda_pstmt_get_ncols (_GDA_PSTMT (ps)), g_new (GType, gda_pstmt_get_ncols (_GDA_PSTMT (ps)))); + for (i = 0; i < gda_pstmt_get_ncols (_GDA_PSTMT (ps)); i++) + gda_pstmt_get_types (_GDA_PSTMT (ps)) [i] = GDA_TYPE_NULL; + + if (col_types) { + for (i = 0; ; i++) { + if (col_types [i] > 0) { + if (col_types [i] == G_TYPE_NONE) + break; + if (i >= gda_pstmt_get_ncols (_GDA_PSTMT (ps))) + g_warning (_("Column %d out of range (0-%d), ignoring its specified type"), i, + gda_pstmt_get_ncols (_GDA_PSTMT (ps)) - 1); + else + gda_pstmt_get_types (_GDA_PSTMT (ps)) [i] = col_types [i]; + } + } + } + + /* fill GdaColumn's data */ + for (i=0, list = gda_pstmt_get_tmpl_columns (_GDA_PSTMT (ps)); + i < gda_pstmt_get_ncols (_GDA_PSTMT (ps)); + i++, list = list->next) { + GdaColumn *column; + gint real_col = i + _gda_sqlite_pstmt_get_nb_rowid_columns (ps); + + column = GDA_COLUMN (list->data); + gda_column_set_description (column, SQLITE3_CALL (prov, sqlite3_column_name) (_gda_sqlite_pstmt_get_stmt (ps), real_col)); + gda_column_set_name (column, SQLITE3_CALL (prov, sqlite3_column_name) (_gda_sqlite_pstmt_get_stmt (ps), real_col)); + gda_column_set_dbms_type (column, SQLITE3_CALL (prov, sqlite3_column_decltype) (_gda_sqlite_pstmt_get_stmt (ps), real_col)); + if (gda_pstmt_get_types (_GDA_PSTMT (ps)) [i] != GDA_TYPE_NULL) + gda_column_set_g_type (column, gda_pstmt_get_types (_GDA_PSTMT (ps)) [i]); + } + } + + /* determine access mode: RANDOM or CURSOR FORWARD are the only supported; if CURSOR BACKWARD + * is requested, then we need RANDOM mode */ + if (flags & GDA_DATA_MODEL_ACCESS_RANDOM) + rflags = GDA_DATA_MODEL_ACCESS_RANDOM; + else if (flags & GDA_DATA_MODEL_ACCESS_CURSOR_BACKWARD) + rflags = GDA_DATA_MODEL_ACCESS_RANDOM; + else + rflags = GDA_DATA_MODEL_ACCESS_CURSOR_FORWARD; + + /* create data model */ + model = g_object_new (GDA_TYPE_SQLITE_RECORDSET, + "connection", cnc, + "prepared-stmt", ps, "model-usage", rflags, + "exec-params", exec_params, NULL); + gboolean is_virt; + is_virt = GDA_IS_VCONNECTION_DATA_MODEL (cnc) ? TRUE : FALSE; + if (is_virt) { + /* steal the lock */ + _gda_vconnection_change_working_obj ((GdaVconnectionDataModel*) cnc, (GObject*) model); + _gda_vconnection_set_working_obj ((GdaVconnectionDataModel*) cnc, NULL); + } + + /* fill the data model */ + read_rows_to_init_col_types (model); + + return GDA_DATA_MODEL (model); +} + +static GType +fuzzy_get_gtype (SqliteConnectionData *cdata, GdaSqlitePStmt *ps, gint colnum) +{ + const gchar *ctype; + GType gtype = GDA_TYPE_NULL; + gint real_col = colnum + _gda_sqlite_pstmt_get_nb_rowid_columns (ps); + + if (gda_pstmt_get_types (_GDA_PSTMT (ps)) [colnum] != GDA_TYPE_NULL) + return gda_pstmt_get_types (_GDA_PSTMT (ps)) [colnum]; + + GdaSqliteProvider *prov = _gda_sqlite_pstmt_get_provider (ps); + g_return_val_if_fail (prov != NULL, G_TYPE_INVALID); + + ctype = SQLITE3_CALL (prov, sqlite3_column_origin_name) (_gda_sqlite_pstmt_get_stmt (ps), real_col); + if (ctype && !strcmp (ctype, "rowid")) + gtype = G_TYPE_INT64; + else { + ctype = SQLITE3_CALL (prov, sqlite3_column_decltype) (_gda_sqlite_pstmt_get_stmt (ps), real_col); + + if (ctype) { + GType *pg; + pg = g_hash_table_lookup (cdata->types_hash, ctype); + gtype = pg ? *pg : GDA_TYPE_NULL; + } + if (gtype == GDA_TYPE_NULL) + gtype = _gda_sqlite_compute_g_type (SQLITE3_CALL (prov, sqlite3_column_type) (_gda_sqlite_pstmt_get_stmt (ps), real_col)); + } + + return gtype; +} + +static void +virt_cnc_set_working_obj (GdaConnection *cnc, GdaSqliteRecordset *model) +{ + gboolean is_virt; + is_virt = GDA_IS_VCONNECTION_DATA_MODEL (cnc) ? TRUE : FALSE; + if (is_virt) + _gda_vconnection_set_working_obj ((GdaVconnectionDataModel*) cnc, (GObject*) model); +} + +static GdaRow * +fetch_next_sqlite_row (GdaSqliteRecordset *model, gboolean do_store, GError **error) +{ + int rc; + SqliteConnectionData *cdata; + GdaSqlitePStmt *ps; + GdaRow *prow = NULL; + GdaConnection *cnc; + GdaSqliteProvider *prov; + glong length; + + cnc = gda_data_select_get_connection ((GdaDataSelect*) model); + prov = GDA_SQLITE_PROVIDER (gda_connection_get_provider (cnc)); + cdata = (SqliteConnectionData*) gda_connection_internal_get_provider_data_error (cnc, error); + if (!cdata) + return NULL; + ps = GDA_SQLITE_PSTMT ( gda_data_select_get_prep_stmt(GDA_DATA_SELECT (model))); + + virt_cnc_set_working_obj (gda_data_select_get_connection ((GdaDataSelect*) model), model); + + GdaSqliteRecordsetPrivate *priv = gda_sqlite_recordset_get_instance_private (model); + + if (priv->empty_forced) + rc = SQLITE_DONE; + else + rc = SQLITE3_CALL (prov, sqlite3_step) (_gda_sqlite_pstmt_get_stmt (ps)); + switch (rc) { + case SQLITE_ROW: { + gint col, real_col; + prow = gda_row_new (gda_pstmt_get_ncols (_GDA_PSTMT (ps))); + for (col = 0; col < gda_pstmt_get_ncols (_GDA_PSTMT (ps)); col++) { + GValue *value; + GType type = gda_pstmt_get_types (_GDA_PSTMT (ps)) [col]; + + real_col = col + _gda_sqlite_pstmt_get_nb_rowid_columns (ps); + + if (type == GDA_TYPE_NULL) { + type = fuzzy_get_gtype (cdata, ps, col); + if (type == GDA_TYPE_BLOB) { + /* extra check: make sure we have a rowid for this blob, or fallback to binary */ + if (_gda_sqlite_pstmt_get_rowid_hash (ps)) { + gint oidcol = 0; + const char *ctable; + ctable = SQLITE3_CALL (prov, sqlite3_column_name) (_gda_sqlite_pstmt_get_stmt (ps), real_col); + if (ctable) + oidcol = GPOINTER_TO_INT (g_hash_table_lookup (_gda_sqlite_pstmt_get_rowid_hash (ps), + ctable)); + if (oidcol == 0) { + ctable = SQLITE3_CALL (prov, sqlite3_column_table_name) (_gda_sqlite_pstmt_get_stmt (ps), real_col); + if (ctable) + oidcol = GPOINTER_TO_INT (g_hash_table_lookup (_gda_sqlite_pstmt_get_rowid_hash (ps), + ctable)); + } + if (oidcol == 0) + type = GDA_TYPE_BINARY; + } + else + type = GDA_TYPE_BINARY; + } + if (type != GDA_TYPE_NULL) { + GdaColumn *column; + + gda_pstmt_get_types (_GDA_PSTMT (ps)) [col] = type; + column = gda_data_model_describe_column (GDA_DATA_MODEL (model), col); + gda_column_set_g_type (column, type); + column = (GdaColumn *) g_slist_nth_data (gda_pstmt_get_tmpl_columns (_GDA_PSTMT (ps)), col); + gda_column_set_g_type (column, type); + } + } + + /* fill GValue */ + value = gda_row_get_value (prow, col); + GError *may_error; + may_error = (GError*) SQLITE3_CALL (prov, sqlite3_column_blob) (_gda_sqlite_pstmt_get_stmt (ps), real_col); + if (may_error && g_hash_table_lookup (error_blobs_hash, may_error)) { + /*g_print ("Row invalidated: [%s]\n", may_error->message);*/ + gda_row_invalidate_value_e (prow, value, may_error); + g_hash_table_remove (error_blobs_hash, may_error); + } + else if (SQLITE3_CALL (prov, sqlite3_column_text) (_gda_sqlite_pstmt_get_stmt (ps), real_col) == NULL) { + /* we have a NULL value */ + gda_value_set_null (value); + } + else { + gda_value_reset_with_type (value, type); + + if (type == GDA_TYPE_NULL) + ; + else if (type == G_TYPE_INT) { + gint64 i; + i = SQLITE3_CALL (prov, sqlite3_column_int64) (_gda_sqlite_pstmt_get_stmt (ps), real_col); + if ((i > G_MAXINT) || (i < G_MININT)) { + GError *lerror = NULL; + g_set_error (&lerror, GDA_SERVER_PROVIDER_ERROR, + GDA_SERVER_PROVIDER_DATA_ERROR, + "%s", _("Integer value is too big")); + gda_row_invalidate_value_e (prow, value, lerror); + } + else + g_value_set_int (value, (gint) i); + } + else if (type == G_TYPE_UINT) { + guint64 i; + i = (gint64) SQLITE3_CALL (prov, sqlite3_column_int64) (_gda_sqlite_pstmt_get_stmt (ps), real_col); + if (i > G_MAXUINT) { + GError *lerror = NULL; + g_set_error (&lerror, GDA_SERVER_PROVIDER_ERROR, + GDA_SERVER_PROVIDER_DATA_ERROR, + "%s", _("Integer value is too big")); + gda_row_invalidate_value_e (prow, value, lerror); + } + else + g_value_set_uint (value, (gint) i); + } + else if (type == G_TYPE_INT64) + g_value_set_int64 (value, SQLITE3_CALL (prov, sqlite3_column_int64) (_gda_sqlite_pstmt_get_stmt (ps), real_col)); + else if (type == G_TYPE_UINT64) + g_value_set_uint64 (value, (guint64) SQLITE3_CALL (prov, sqlite3_column_int64) (_gda_sqlite_pstmt_get_stmt (ps), + real_col)); + else if (type == G_TYPE_DOUBLE) + g_value_set_double (value, SQLITE3_CALL (prov, sqlite3_column_double) (_gda_sqlite_pstmt_get_stmt (ps), + real_col)); + else if (type == G_TYPE_STRING) + g_value_set_string (value, (gchar *) SQLITE3_CALL (prov, sqlite3_column_text) (_gda_sqlite_pstmt_get_stmt (ps), + real_col)); + else if (type == GDA_TYPE_TEXT) { + GdaText *text = gda_text_new (); + gda_text_set_string (text, (const gchar *) SQLITE3_CALL (prov, sqlite3_column_text) (_gda_sqlite_pstmt_get_stmt (ps), + real_col)); + g_value_take_boxed (value, text); + } + else if (type == GDA_TYPE_BINARY) { + GdaBinary *bin; + + bin = gda_binary_new (); + length = SQLITE3_CALL (prov, sqlite3_column_bytes) (_gda_sqlite_pstmt_get_stmt (ps), real_col); + if (length > 0) { + gda_binary_set_data (bin, SQLITE3_CALL (prov, sqlite3_column_blob) (_gda_sqlite_pstmt_get_stmt (ps), /* Flawfinder: ignore */ + real_col), length); + } + gda_value_take_binary (value, bin); + } + else if (type == GDA_TYPE_BLOB) { + GdaBlobOp *bop = NULL; + gint oidcol = 0; + + if (_gda_sqlite_pstmt_get_rowid_hash (ps)) { + const char *ctable; + ctable = SQLITE3_CALL (prov, sqlite3_column_name) (_gda_sqlite_pstmt_get_stmt (ps), real_col); + if (ctable) + oidcol = GPOINTER_TO_INT (g_hash_table_lookup (_gda_sqlite_pstmt_get_rowid_hash (ps), + ctable)); + if (oidcol == 0) { + ctable = SQLITE3_CALL (prov, sqlite3_column_table_name) (_gda_sqlite_pstmt_get_stmt (ps), real_col); + if (ctable) + oidcol = GPOINTER_TO_INT (g_hash_table_lookup (_gda_sqlite_pstmt_get_rowid_hash (ps), + ctable)); + } + } + if (oidcol != 0) { + gint64 rowid; + rowid = SQLITE3_CALL (prov, sqlite3_column_int64) (_gda_sqlite_pstmt_get_stmt (ps), oidcol - 1); /* remove 1 + because it was added in the first place */ + bop = _gda_sqlite_blob_op_new (cnc, + SQLITE3_CALL (prov, sqlite3_column_database_name) (_gda_sqlite_pstmt_get_stmt (ps), + real_col), + SQLITE3_CALL (prov, sqlite3_column_table_name) (_gda_sqlite_pstmt_get_stmt (ps), + real_col), + SQLITE3_CALL (prov, sqlite3_column_origin_name) (_gda_sqlite_pstmt_get_stmt (ps), + real_col), + rowid); + } + if (!bop) { + GError *lerror = NULL; + g_set_error (&lerror, GDA_SERVER_PROVIDER_ERROR, + GDA_SERVER_PROVIDER_DATA_ERROR, + "%s", _("Unable to open BLOB")); + gda_row_invalidate_value_e (prow, value, lerror); + } + else { + GdaBlob *blob; + blob = gda_blob_new (); + gda_blob_set_op (blob, bop); + g_object_unref (bop); + gda_value_take_blob (value, blob); + } + } + else if (type == G_TYPE_BOOLEAN) + g_value_set_boolean (value, SQLITE3_CALL (prov, sqlite3_column_int) (_gda_sqlite_pstmt_get_stmt (ps), real_col) == 0 ? FALSE : TRUE); + else if (type == G_TYPE_DATE) { + GDate date; + if (!gda_parse_iso8601_date (&date, + (gchar *) SQLITE3_CALL (prov, sqlite3_column_text) (_gda_sqlite_pstmt_get_stmt (ps), + real_col))) { + GError *lerror = NULL; + g_set_error (&lerror, GDA_SERVER_PROVIDER_ERROR, + GDA_SERVER_PROVIDER_DATA_ERROR, + _("Invalid date '%s' (date format should be YYYY-MM-DD)"), + (gchar *) SQLITE3_CALL (prov, sqlite3_column_text) (_gda_sqlite_pstmt_get_stmt (ps), real_col)); + gda_row_invalidate_value_e (prow, value, lerror); + } + else + g_value_set_boxed (value, &date); + } + else if (type == GDA_TYPE_TIME) { + const gchar *str = (const gchar *) SQLITE3_CALL (prov, sqlite3_column_text) (_gda_sqlite_pstmt_get_stmt (ps), + real_col); + GdaTime* timegda = gda_parse_iso8601_time ( + str); + if (timegda == NULL) { + GError *lerror = NULL; + g_set_error (&lerror, GDA_SERVER_PROVIDER_ERROR, + GDA_SERVER_PROVIDER_DATA_ERROR, + _("Invalid time '%s' (time format should be HH:MM:SS[.ms][+HH:mm])"), + (gchar *) SQLITE3_CALL (prov, sqlite3_column_text) (_gda_sqlite_pstmt_get_stmt (ps), real_col)); + gda_row_invalidate_value_e (prow, value, lerror); + } + else { + g_value_take_boxed (value, timegda); + } + } + else if (g_type_is_a (type, G_TYPE_DATE_TIME)) { + GTimeZone *tz = g_time_zone_new_utc (); + GDateTime* timestamp = g_date_time_new_from_iso8601 ( + (gchar *) SQLITE3_CALL (prov, sqlite3_column_text) (_gda_sqlite_pstmt_get_stmt (ps), + real_col), tz); + g_time_zone_unref (tz); + if (timestamp == NULL) { + GError *lerror = NULL; + g_set_error (&lerror, GDA_SERVER_PROVIDER_ERROR, + GDA_SERVER_PROVIDER_DATA_ERROR, + _("Invalid timestamp '%s' (format should be YYYY-MM-DDTHH:MM:SS[.ms])"), + (gchar *) SQLITE3_CALL (prov, sqlite3_column_text) (_gda_sqlite_pstmt_get_stmt (ps), real_col)); + gda_row_invalidate_value_e (prow, value, lerror); + } + else { + g_value_take_boxed (value, timestamp); + } + } + else if (type == G_TYPE_CHAR) { + gint64 i; + i = (gint64) SQLITE3_CALL (prov, sqlite3_column_int64) (_gda_sqlite_pstmt_get_stmt (ps), real_col); + if ((i > G_MAXINT8) || (i < G_MININT8)) { + GError *lerror = NULL; + g_set_error (&lerror, GDA_SERVER_PROVIDER_ERROR, + GDA_SERVER_PROVIDER_DATA_ERROR, + "%s", _("Integer value is too big")); + gda_row_invalidate_value_e (prow, value, lerror); + } + else + g_value_set_schar (value, (gchar) i); + } + else if (type == G_TYPE_UCHAR) { + gint64 i; + i = (gint64) SQLITE3_CALL (prov, sqlite3_column_int64) (_gda_sqlite_pstmt_get_stmt (ps), real_col); + if ((i > G_MAXUINT8) || (i < 0)) { + GError *lerror = NULL; + g_set_error (&lerror, GDA_SERVER_PROVIDER_ERROR, + GDA_SERVER_PROVIDER_DATA_ERROR, + "%s", _("Integer value is too big")); + gda_row_invalidate_value_e (prow, value, lerror); + } + else + g_value_set_uchar (value, (guchar) i); + } + else if (type == GDA_TYPE_SHORT) { + gint64 i; + i = (gint64) SQLITE3_CALL (prov, sqlite3_column_int64) (_gda_sqlite_pstmt_get_stmt (ps), real_col); + if ((i > G_MAXSHORT) || (i < G_MINSHORT)) { + GError *lerror = NULL; + g_set_error (&lerror, GDA_SERVER_PROVIDER_ERROR, + GDA_SERVER_PROVIDER_DATA_ERROR, + "%s", _("Integer value is too big")); + gda_row_invalidate_value_e (prow, value, lerror); + } + else + gda_value_set_short (value, (guchar) i); + } + else if (type == GDA_TYPE_USHORT) { + gint64 i; + i = (gint64) SQLITE3_CALL (prov, sqlite3_column_int64) (_gda_sqlite_pstmt_get_stmt (ps), real_col); + if ((i > G_MAXUSHORT) || (i < 0)) { + GError *lerror = NULL; + g_set_error (&lerror, GDA_SERVER_PROVIDER_ERROR, + GDA_SERVER_PROVIDER_DATA_ERROR, + "%s", _("Integer value is too big")); + gda_row_invalidate_value_e (prow, value, lerror); + } + else + gda_value_set_ushort (value, (guchar) i); + } + else { + GError *lerror = NULL; + g_set_error (&lerror, GDA_SERVER_PROVIDER_ERROR, + GDA_SERVER_PROVIDER_DATA_ERROR, + "Unhandled type '%s' in SQLite recordset", + gda_g_type_to_string (gda_pstmt_get_types (_GDA_PSTMT (ps)) [col])); + gda_row_invalidate_value_e (prow, value, lerror); + } + } + } + + if (do_store) { + /* insert row */ + gda_data_select_take_row (GDA_DATA_SELECT (model), prow, priv->next_row_num); + } + priv->next_row_num ++; + break; + } + case SQLITE_BUSY: + /* nothing to do */ + break; + case SQLITE_DONE: + gda_data_select_set_advertized_nrows (GDA_DATA_SELECT (model), priv->next_row_num); + SQLITE3_CALL (prov, sqlite3_reset) (_gda_sqlite_pstmt_get_stmt (ps)); + break; + case SQLITE_READONLY: + case SQLITE_MISUSE: + g_set_error (error, GDA_SERVER_PROVIDER_ERROR, + GDA_SERVER_PROVIDER_INTERNAL_ERROR, + "%s", _("SQLite provider fatal internal error")); + break; + case SQLITE_ERROR: + default: { + GError *lerror = NULL; + SQLITE3_CALL (prov, sqlite3_reset) (_gda_sqlite_pstmt_get_stmt (ps)); + if (rc == SQLITE_IOERR_TRUNCATE) + g_set_error (&lerror, GDA_DATA_MODEL_ERROR, + GDA_DATA_MODEL_TRUNCATED_ERROR, "%s", _("Truncated data")); + else + g_set_error (&lerror, GDA_SERVER_PROVIDER_ERROR, + GDA_SERVER_PROVIDER_INTERNAL_ERROR, + "%s", SQLITE3_CALL (prov, sqlite3_errmsg) (cdata->connection)); + gda_data_select_add_exception (GDA_DATA_SELECT (model), lerror); + if (rc == SQLITE_ERROR) + g_propagate_error (error, g_error_copy (lerror)); + gda_data_select_set_advertized_nrows (GDA_DATA_SELECT (model), priv->next_row_num); + break; + } + } + + virt_cnc_set_working_obj (gda_data_select_get_connection ((GdaDataSelect*) model), NULL); + + return prow; +} + + +/* + * GdaDataSelect virtual methods + */ +static gint +gda_sqlite_recordset_fetch_nb_rows (GdaDataSelect *model) +{ + GdaSqliteRecordset *imodel; + GdaRow *prow = NULL; + + imodel = GDA_SQLITE_RECORDSET (model); + if (gda_data_select_get_advertized_nrows (model) >= 0) + return gda_data_select_get_advertized_nrows (model); + + for (prow = fetch_next_sqlite_row (imodel, TRUE, NULL); + prow; + prow = fetch_next_sqlite_row (imodel, TRUE, NULL)); + return gda_data_select_get_advertized_nrows (model); +} + +/* + * Create a new filled #GdaRow object for the row at position @rownum. + * + * Each new #GdaRow created needs to be "given" to the #GdaDataSelect implementation using + * gda_data_select_take_row() because backward iterating is not supported. + */ +static gboolean +gda_sqlite_recordset_fetch_random (GdaDataSelect *model, GdaRow **prow, gint rownum, GError **error) +{ + GdaSqliteRecordset *imodel; + + imodel = GDA_SQLITE_RECORDSET (model); + + GdaSqliteRecordsetPrivate *priv = gda_sqlite_recordset_get_instance_private (imodel); + + if (priv->next_row_num >= rownum) { + g_set_error (error, GDA_SERVER_PROVIDER_ERROR, + GDA_SERVER_PROVIDER_INTERNAL_ERROR, + "%s", _("Requested row could not be found")); + return TRUE; + } + for (*prow = fetch_next_sqlite_row (imodel, TRUE, error); + *prow && (priv->next_row_num < rownum); + *prow = fetch_next_sqlite_row (imodel, TRUE, error)); + + return TRUE; +} + +/* + * Create a new filled #GdaRow object for the next cursor row + * + * Each new #GdaRow created is referenced only by ipriv->tmp_row (the #GdaDataSelect implementation + * never keeps a reference to it). + * Before a new #GdaRow gets created, the previous one, if set, is discarded. + */ +static gboolean +gda_sqlite_recordset_fetch_next (GdaDataSelect *model, GdaRow **prow, gint rownum, GError **error) +{ + GdaSqliteRecordset *imodel = (GdaSqliteRecordset*) model; + GdaSqliteRecordsetPrivate *priv = gda_sqlite_recordset_get_instance_private (imodel); + + if (priv->tmp_row) { + g_object_unref (priv->tmp_row); + priv->tmp_row = NULL; + } + if (priv->next_row_num != rownum) { + GError *lerror = NULL; + *prow = NULL; + g_set_error (&lerror, GDA_DATA_MODEL_ERROR, + GDA_DATA_MODEL_ROW_NOT_FOUND_ERROR, + "%s", _("Can't set iterator on requested row")); + gda_data_select_add_exception (GDA_DATA_SELECT (model), lerror); + if (error) + g_propagate_error (error, g_error_copy (lerror)); + return FALSE; + } + *prow = fetch_next_sqlite_row (imodel, FALSE, error); + priv->tmp_row = *prow; + + return TRUE; +} diff --git a/.flatpak-builder/cache/objects/ec/9aeb72fea325b6d54eb30d9238b614986f6baf8b1583e2845aadf7950547fa.file b/.flatpak-builder/cache/objects/ec/9aeb72fea325b6d54eb30d9238b614986f6baf8b1583e2845aadf7950547fa.file new file mode 100644 index 0000000..addbd8a --- /dev/null +++ b/.flatpak-builder/cache/objects/ec/9aeb72fea325b6d54eb30d9238b614986f6baf8b1583e2845aadf7950547fa.file @@ -0,0 +1,127 @@ +# adw_breakpoint.py +# +# Copyright 2023 James Westman +# +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation; either version 3 of the +# License, or (at your option) any later version. +# +# This file is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program. If not, see . +# +# SPDX-License-Identifier: LGPL-3.0-or-later + +from .common import * +from .contexts import ScopeCtx, ValueTypeCtx +from .gobject_object import Object, validate_parent_type +from .values import Value + + +class AdwBreakpointCondition(AstNode): + grammar = ["condition", "(", UseQuoted("condition"), Match(")").expected()] + + @property + def condition(self) -> str: + return self.tokens["condition"] + + @validate() + def unique(self): + self.validate_unique_in_parent("Duplicate condition statement") + + +class AdwBreakpointSetter(AstNode): + grammar = Statement( + UseIdent("object"), + Match(".").expected(), + UseIdent("property"), + Match(":").expected(), + Value, + ) + + @property + def object_id(self) -> str: + return self.tokens["object"] + + @property + def object(self) -> T.Optional[Object]: + return self.context[ScopeCtx].objects.get(self.object_id) + + @property + def property_name(self) -> T.Optional[str]: + return self.tokens["property"] + + @property + def value(self) -> Value: + return self.children[Value][0] + + @property + def gir_class(self) -> T.Optional[GirType]: + if self.object is not None: + return self.object.gir_class + else: + return None + + @property + def gir_property(self): + if self.gir_class is not None and not isinstance(self.gir_class, ExternType): + return self.gir_class.properties.get(self.property_name) + + @context(ValueTypeCtx) + def value_type(self) -> ValueTypeCtx: + if self.gir_property is not None: + type = self.gir_property.type + else: + type = None + + return ValueTypeCtx(type, allow_null=True) + + @validate("object") + def object_exists(self): + if self.object is None: + raise CompileError( + f"Could not find object with ID {self.object_id}", + did_you_mean=(self.object_id, self.context[ScopeCtx].objects.keys()), + ) + + @validate("property") + def property_exists(self): + if self.gir_class is None or self.gir_class.incomplete: + # Objects that we have no gir data on should not be validated + # This happens for classes defined by the app itself + return + + if self.gir_property is None and self.property_name is not None: + raise CompileError( + f"Class {self.gir_class.full_name} does not have a property called {self.property_name}", + did_you_mean=(self.property_name, self.gir_class.properties.keys()), + ) + + @validate() + def unique(self): + self.validate_unique_in_parent( + f"Duplicate setter for {self.object_id}.{self.property_name}", + lambda x: x.object_id == self.object_id + and x.property_name == self.property_name, + ) + + +class AdwBreakpointSetters(AstNode): + grammar = ["setters", Match("{").expected(), Until(AdwBreakpointSetter, "}")] + + @property + def setters(self) -> T.List[AdwBreakpointSetter]: + return self.children[AdwBreakpointSetter] + + @validate() + def container_is_breakpoint(self): + validate_parent_type(self, "Adw", "Breakpoint", "breakpoint setters") + + @validate() + def unique(self): + self.validate_unique_in_parent("Duplicate setters block") diff --git a/.flatpak-builder/cache/objects/ec/aa987c53c141fb29daca9bd568e37d0b4e0d6e67ea3e91c6da4453ad0614e0.file b/.flatpak-builder/cache/objects/ec/aa987c53c141fb29daca9bd568e37d0b4e0d6e67ea3e91c6da4453ad0614e0.file new file mode 100644 index 0000000..6505785 Binary files /dev/null and b/.flatpak-builder/cache/objects/ec/aa987c53c141fb29daca9bd568e37d0b4e0d6e67ea3e91c6da4453ad0614e0.file differ diff --git a/.flatpak-builder/cache/objects/ec/cb91da5ce1164169007a7baa783f51d0ed538b23e93346be453763f7ec44f1.file b/.flatpak-builder/cache/objects/ec/cb91da5ce1164169007a7baa783f51d0ed538b23e93346be453763f7ec44f1.file new file mode 100644 index 0000000..21fbde2 --- /dev/null +++ b/.flatpak-builder/cache/objects/ec/cb91da5ce1164169007a7baa783f51d0ed538b23e93346be453763f7ec44f1.file @@ -0,0 +1,172 @@ +/* + * Copyright (C) 2006 - 2007 Murray Cumming + * Copyright (C) 2006 - 2013 Vivien Malerba + * Copyright (C) 2009 Bas Driessen + * Copyright (C) 2010 David King + * Copyright (C) 2010 Jonh Wendell + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "gda-handler-type.h" +#include +#include +#include + +struct _GdaHandlerType +{ + GObject parent_instance; +}; + +static void data_handler_iface_init (GdaDataHandlerInterface *iface); + +G_DEFINE_TYPE_EXTENDED (GdaHandlerType, gda_handler_type, G_TYPE_OBJECT, 0, + G_IMPLEMENT_INTERFACE (GDA_TYPE_DATA_HANDLER, data_handler_iface_init)) + +/** + * gda_handler_type_new: + * + * Creates a data handler for Gda types + * + * Returns: (type GdaHandlerType) (transfer full): the new object + */ +GdaDataHandler * +gda_handler_type_new (void) +{ + GObject *obj; + + obj = g_object_new (GDA_TYPE_HANDLER_TYPE, NULL); + + return (GdaDataHandler *) obj; +} + +static gchar * +gda_handler_type_get_sql_from_value (G_GNUC_UNUSED GdaDataHandler *iface, const GValue *value) +{ + g_assert (value); + + gchar *retval; + GTypeQuery tq; + g_type_query (g_value_get_gtype (value), &tq); + if (tq.type != 0) { + const gchar *str; + str = gda_g_type_to_string (g_value_get_gtype (value)); + retval = g_strdup_printf ("'%s'", str); + } + else + retval = g_strdup ("NULL"); + + return retval; +} + +static gchar * +gda_handler_type_get_str_from_value (G_GNUC_UNUSED GdaDataHandler *iface, const GValue *value) +{ + g_assert (value); + + gchar *retval; + GTypeQuery tq; + + g_type_query (g_value_get_gtype (value), &tq); + if (tq.type != 0) + retval = g_strdup (gda_g_type_to_string (g_value_get_gtype (value))); + else + retval = NULL; + + return retval; +} + +static GValue * +gda_handler_type_get_value_from_sql (G_GNUC_UNUSED GdaDataHandler *iface, const gchar *sql, G_GNUC_UNUSED GType type) +{ + g_assert (sql); + + GValue *value = NULL; + if (*sql) { + gint i = strlen (sql); + if ((i>=2) && (*sql=='\'') && (sql[i-1]=='\'')) { + gchar *str = g_strdup (sql); + GType type; + str[i-1] = 0; + type = gda_g_type_from_string (str+1); + g_free (str); + if (type != G_TYPE_INVALID) { + value = g_value_init (g_new0 (GValue, 1), G_TYPE_GTYPE); + g_value_set_gtype (value, type); + } + } + } + else + value = gda_value_new_null (); + return value; +} + +static GValue * +gda_handler_type_get_value_from_str (G_GNUC_UNUSED GdaDataHandler *iface, const gchar *str, G_GNUC_UNUSED GType type) +{ + g_assert (str); + + GValue *value = NULL; + GType vtype; + + vtype = gda_g_type_from_string (str); + if (vtype != G_TYPE_INVALID) { + value = g_value_init (g_new0 (GValue, 1), G_TYPE_GTYPE); + g_value_set_gtype (value, vtype); + } + + return value; +} + +static gboolean +gda_handler_type_accepts_g_type (GdaDataHandler *iface, GType type) +{ + g_assert (iface); + return type == G_TYPE_GTYPE ? TRUE : FALSE; +} + +static const gchar * +gda_handler_type_get_descr (GdaDataHandler *iface) +{ + g_return_val_if_fail (GDA_IS_HANDLER_TYPE (iface), NULL); + return g_object_get_data (G_OBJECT (iface), "descr"); +} + +static void +gda_handler_type_init (GdaHandlerType * hdl) +{ + g_object_set_data (G_OBJECT (hdl), "descr", "InternalType"); + g_object_set_data (G_OBJECT (hdl), "descr", _("Gda type representation")); +} + +static void +data_handler_iface_init (GdaDataHandlerInterface *iface) +{ + iface->get_sql_from_value = gda_handler_type_get_sql_from_value; + iface->get_str_from_value = gda_handler_type_get_str_from_value; + iface->get_value_from_sql = gda_handler_type_get_value_from_sql; + iface->get_value_from_str = gda_handler_type_get_value_from_str; + iface->get_sane_init_value = NULL; + iface->accepts_g_type = gda_handler_type_accepts_g_type; + iface->get_descr = gda_handler_type_get_descr; +} + + +static void +gda_handler_type_class_init (GdaHandlerTypeClass * class) +{ + +} diff --git a/.flatpak-builder/cache/objects/ec/d3d57a1ccddc4ff56d1813771ae4d0f80941f7d970fb5a59f1c35dde2e51bc.dirtree b/.flatpak-builder/cache/objects/ec/d3d57a1ccddc4ff56d1813771ae4d0f80941f7d970fb5a59f1c35dde2e51bc.dirtree new file mode 100644 index 0000000..211bd50 Binary files /dev/null and b/.flatpak-builder/cache/objects/ec/d3d57a1ccddc4ff56d1813771ae4d0f80941f7d970fb5a59f1c35dde2e51bc.dirtree differ diff --git a/.flatpak-builder/cache/objects/ec/eb56def93794ea1237c9382093d465630516dca21d9c39ef81f080167946db.dirtree b/.flatpak-builder/cache/objects/ec/eb56def93794ea1237c9382093d465630516dca21d9c39ef81f080167946db.dirtree new file mode 100644 index 0000000..f904c27 Binary files /dev/null and b/.flatpak-builder/cache/objects/ec/eb56def93794ea1237c9382093d465630516dca21d9c39ef81f080167946db.dirtree differ diff --git a/.flatpak-builder/cache/objects/ed/0ee0728217ef0810b281d5dc0fe76185f98e9fc912e4281511a1307a2d56f4.file b/.flatpak-builder/cache/objects/ed/0ee0728217ef0810b281d5dc0fe76185f98e9fc912e4281511a1307a2d56f4.file new file mode 100644 index 0000000..954d50e --- /dev/null +++ b/.flatpak-builder/cache/objects/ed/0ee0728217ef0810b281d5dc0fe76185f98e9fc912e4281511a1307a2d56f4.file @@ -0,0 +1,1091 @@ +/* + * Copyright (C) 2006 - 2015 Vivien Malerba + * Copyright (C) 2007 Murray Cumming + * Copyright (C) 2009 Bas Driessen + * Copyright (C) 2010 David King + * Copyright (C) 2010 Jonh Wendell + * Copyright (C) 2011-2017 Daniel Espinosa + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "gda-handler-time.h" +#include +#include +#include +#include +#include + +typedef struct _LocaleSetting { + GDateDMY dmy_order[3]; + gboolean twodigit_years; + gint current_offset; /* 1900, 2000, etc... */ + gchar separator; +} LocaleSetting; + +struct _GdaHandlerTime +{ + GObject parent_instance; + + guint nb_g_types; + GType *valid_g_types; + + /* for locale setting */ + LocaleSetting *sql_locale; + LocaleSetting *str_locale; +}; + +/* General notes: + * about months representations: + * ----------------------------- + * GtkCalendar gets months in [0-11] + * GDate represents months in [1-12] + * struct tm represents months in [0-11] + * + * about date localization: + * ------------------------ + * see how this aspect is handled in glib: function g_date_prepare_to_parse() + * in file gdate.c + */ + +static void data_handler_iface_init (GdaDataHandlerInterface *iface); +static gchar *render_date_locale (const GDate *date, LocaleSetting *locale); +static void handler_compute_locale (GdaHandlerTime *hdl); + +G_DEFINE_TYPE_EXTENDED (GdaHandlerTime, gda_handler_time, G_TYPE_OBJECT, 0, + G_IMPLEMENT_INTERFACE (GDA_TYPE_DATA_HANDLER, data_handler_iface_init)) + +/** + * gda_handler_time_new: + * + * Creates a data handler for time values + * + * Returns: (type GdaHandlerTime) (transfer full): the new object + */ +GdaDataHandler * +gda_handler_time_new (void) +{ + GObject *obj; + + obj = g_object_new (GDA_TYPE_HANDLER_TIME, NULL); + handler_compute_locale (GDA_HANDLER_TIME (obj)); + + return (GdaDataHandler *) obj; +} + +/** + * gda_handler_time_new_no_locale: + * + * Creates a data handler for time values, but using the default C locale + * instead of the current user locale. + * + * Returns: (type GdaHandlerTime) (transfer full): the new object + */ +GdaDataHandler * +gda_handler_time_new_no_locale (void) +{ + GObject *obj; + + obj = g_object_new (GDA_TYPE_HANDLER_TIME, NULL); + + return (GdaDataHandler *) obj; +} + +/** + * gda_handler_time_set_sql_spec: + * @dh: a #GdaHandlerTime object + * @first: what comes first in the date representation + * @sec: what comes second in the date representation + * @third: what comes third in the date representation + * @separator: separator character used between year, month and day + * @twodigits_years: TRUE if year part of date must be rendered on 2 digits + * + * Specifies the SQL output style of the @dh data handler. The general format is "FIRSTsSECsTHIRD" + * where FIRST, SEC and THIRD are specified by @first, @sec and @trird and 's' is the separator, + * specified by @separator. + * + * The default implementation is @first=G_DATE_MONTH, @sec=G_DATE_DAY and @third=G_DATE_YEAR + * (the year is rendered on 4 digits) and the separator is '-' + */ +void +gda_handler_time_set_sql_spec (GdaHandlerTime *dh, GDateDMY first, GDateDMY sec, + GDateDMY third, gchar separator, gboolean twodigits_years) +{ + g_return_if_fail (GDA_IS_HANDLER_TIME (dh)); + g_return_if_fail (first != sec); + g_return_if_fail (sec != third); + g_return_if_fail (first != third); + + dh->sql_locale->dmy_order[0] = first; + dh->sql_locale->dmy_order[1] = sec; + dh->sql_locale->dmy_order[2] = third; + dh->sql_locale->twodigit_years = twodigits_years; + dh->sql_locale->separator = separator; +} + +/** + * gda_handler_time_set_str_spec: + * @dh: a #GdaHandlerTime object + * @first: what comes first in the date representation + * @sec: what comes second in the date representation + * @third: what comes third in the date representation + * @separator: separator character used between year, month and day + * @twodigits_years: TRUE if year part of date must be rendered on 2 digits + * + * Specifies the human readable output style of the @dh data handler. + * The general format is "FIRSTsSECsTHIRD" + * where FIRST, SEC and THIRD are specified by @first, @sec and @trird and 's' is the separator, + * specified by @separator. + * + * The default implementation depends on the current locale, except if @dh was created + * using gda_handler_time_new_no_locale(). + * + * Since: 4.2.1 + */ +void +gda_handler_time_set_str_spec (GdaHandlerTime *dh, GDateDMY first, GDateDMY sec, + GDateDMY third, gchar separator, gboolean twodigits_years) +{ + g_return_if_fail (GDA_IS_HANDLER_TIME (dh)); + g_return_if_fail (first != sec); + g_return_if_fail (sec != third); + g_return_if_fail (first != third); + + dh->str_locale->dmy_order[0] = first; + dh->str_locale->dmy_order[1] = sec; + dh->str_locale->dmy_order[2] = third; + dh->str_locale->twodigit_years = twodigits_years; + dh->str_locale->separator = separator; +} + +static void +handler_compute_locale (GdaHandlerTime *hdl) +{ + GDate *date; + gchar buf[128], *ptr, *numstart; + gint nums[3]; + gboolean error = FALSE; + + date = g_date_new_dmy (4, 7, 1976); /* Same date used by GLib */ + g_date_strftime (buf, 127, "%x", date); + g_date_free (date); + + /* 1st number */ + ptr = buf; + numstart = ptr; + while (*ptr && g_ascii_isdigit (*ptr)) + ptr++; + if (*ptr) { + hdl->str_locale->separator = *ptr; + *ptr = 0; + nums[0] = atoi (numstart); /* Flawfinder: ignore */ + } + else + error = TRUE; + + /* 2nd number */ + if (!error) { + ptr++; + numstart = ptr; + while (*ptr && g_ascii_isdigit (*ptr)) + ptr++; + if (*ptr) { + *ptr = 0; + nums[1] = atoi (numstart); /* Flawfinder: ignore */ + } + else + error = TRUE; + } + + /* 3rd number */ + if (!error) { + ptr++; + numstart = ptr; + while (*ptr && g_ascii_isdigit (*ptr)) + ptr++; + *ptr = 0; + nums[2] = atoi (numstart); /* Flawfinder: ignore */ + } + + /* computations */ + if (!error) { +#ifdef GDA_DEBUG_NO + gchar *strings[3]; +#endif + gint i; + time_t now; + struct tm *now_tm; + + for (i=0; i < 3; i++) { + switch (nums[i]) { + case 7: + hdl->str_locale->dmy_order[i] = G_DATE_MONTH; + break; + case 4: + hdl->str_locale->dmy_order[i] = G_DATE_DAY; + break; + case 76: + hdl->str_locale->twodigit_years = TRUE; + hdl->str_locale->dmy_order[i] = G_DATE_YEAR; + break; + case 1976: + hdl->str_locale->dmy_order[i] = G_DATE_YEAR; + break; + default: + break; + } + } + + now = time (NULL); +#ifdef HAVE_LOCALTIME_R + struct tm tmpstm; + now_tm = localtime_r (&now, &tmpstm); +#elif HAVE_LOCALTIME_S + struct tm tmpstm; + g_assert (localtime_s (&tmpstm, &now) == 0); + now_tm = &tmpstm; +#else + now_tm = localtime (&now); +#endif + hdl->str_locale->current_offset = ((now_tm->tm_year + 1900) / 100) * 100; + +#ifdef GDA_DEBUG_NO + for (i=0; i<3; i++) { + switch (hdl->str_locale->dmy_order[i]) { + case G_DATE_MONTH: + strings[i] = "Month"; + break; + case G_DATE_YEAR: + strings[i] = "Year"; + break; + case G_DATE_DAY: + strings[i] = "Day"; + break; + default: + strings[i] = NULL; + break; + } + } + g_print ("GdaHandlerTime %p\n", hdl); + g_print ("\tlocale order = %s %s %s, separator = %c\n", + strings[0], strings[1], strings[2], hdl->str_locale->separator); + if (hdl->str_locale->twodigit_years) + g_print ("\tlocale has 2 digits year, using %d as offset\n", hdl->str_locale->current_offset); + else + g_print ("\tlocale has 4 digits year\n"); +#endif + } + else { + TO_IMPLEMENT; + } +} + +/** + * gda_handler_time_get_no_locale_str_from_value: + * @dh: a #GdaHandlerTime object + * @value: a #GValue value + * + * Returns: a new string representing @value without taking the current + * locale into account (i.e. in the "C" locale) + */ +gchar * +gda_handler_time_get_no_locale_str_from_value (GdaHandlerTime *dh, const GValue *value) +{ + gchar *retval = NULL, *str; + GType type; + + g_return_val_if_fail (GDA_IS_HANDLER_TIME (dh), NULL); + type = G_VALUE_TYPE (value); + + if (type == G_TYPE_DATE) { + const GDate *date; + + date = (GDate *) g_value_get_boxed (value); + str = render_date_locale (date, dh->sql_locale); + if (!str) + retval = g_strdup ("NULL"); + else + retval = str; + } + else if (type == GDA_TYPE_TIME) { + const GdaTime *tim; + GString *string; + string = g_string_new (""); + g_string_append_c (string, '\''); + tim = gda_value_get_time ((GValue *) value); + g_string_append_printf (string, "%02d:%02d:%02d", + gda_time_get_hour (tim), + gda_time_get_minute (tim), + gda_time_get_second (tim)); + if (gda_time_get_timezone (tim) != GDA_TIMEZONE_INVALID) + g_string_append_printf (string, "%+02d", + (int) gda_time_get_timezone (tim) / 3600); + g_string_append_c (string, '\''); + retval = g_string_free (string, FALSE); + } + else if (type == G_TYPE_DATE_TIME) { + GDateTime *gdats; + + gdats = (GDateTime*) g_value_get_boxed ((GValue *) value); + if (gdats != NULL) + retval = g_date_time_format (gdats, "%FT%H:%M:%S%:::z"); + else + retval = g_strdup ("NULL"); + } + else if (type == G_TYPE_DATE_TIME) { + GDateTime *ts; + GDate *vdate; + + ts = g_value_get_boxed ((GValue *) value); + if (ts) { + gint y, m, d; + g_date_time_get_ymd (ts, &y, &m, &d); + vdate = g_date_new_dmy (d, m, y); + str = render_date_locale (vdate, dh->sql_locale); + g_date_free (vdate); + + if (str) { + GString *string; + string = g_string_new (""); + g_string_append_printf (string, "%02u:%02u:%02u", + g_date_time_get_hour (ts), + g_date_time_get_minute (ts), + g_date_time_get_second (ts)); + if (g_date_time_get_microsecond (ts) != 0) + g_string_append_printf (string, ".%d", g_date_time_get_microsecond (ts)); + + GTimeSpan span; + span = g_date_time_get_utc_offset (ts); + if (span > 0) + g_string_append_printf (string, "+%02d", + (int) (span / G_TIME_SPAN_HOUR)); + else + g_string_append_printf (string, "-%02d", + (int) (-span / G_TIME_SPAN_HOUR)); + + retval = g_strdup_printf ("%s %s", str, string->str); + g_free (str); + g_string_free (string, TRUE); + } + else + retval = g_strdup ("NULL"); + } + else + retval = g_strdup ("NULL"); + } + else + g_assert_not_reached (); + + return retval; +} + +/** + * gda_handler_time_get_format: + * @dh: a #GdaHandlerTime object + * @type: the type of data being handled + * + * Get a string representing the locale-dependent way to enter a date/time/datetime, using + * a syntax suitable for the #GdauiFormatEntry widget + * + * Returns: a new string + */ +gchar * +gda_handler_time_get_format (GdaHandlerTime *dh, GType type) +{ + gchar *str; + GString *string; + gint i; + + g_return_val_if_fail (GDA_IS_HANDLER_TIME (dh), NULL); + + string = g_string_new (""); + if ((type == G_TYPE_DATE) || (type == G_TYPE_DATE_TIME) || (type == G_TYPE_DATE_TIME)) { + for (i=0; i<3; i++) { + if (i > 0) + g_string_append_c (string, dh->str_locale->separator); + switch (dh->str_locale->dmy_order[i]) { + case G_DATE_DAY: + case G_DATE_MONTH: + g_string_append (string, "00"); + break; + case G_DATE_YEAR: + if (dh->str_locale->twodigit_years) + g_string_append (string, "00"); + else + g_string_append (string, "0000"); + break; + default: + g_assert_not_reached (); + break; + } + } + } + if (type == G_TYPE_DATE_TIME) + g_string_append_c (string, ' '); + + if ((type == GDA_TYPE_TIME) || (type == G_TYPE_DATE_TIME) || (type == G_TYPE_DATE_TIME)) + g_string_append (string, "00:00:00"); + + str = string->str; + g_string_free (string, FALSE); + return str; +} + +/** + * gda_handler_time_get_hint: + * @dh: a #GdaHandlerTime object + * @type: the type of data being handled + * + * Get a string giving the user a hint about the locale-dependent requested format. + * + * Returns: a new string + * + * Since: 6.0 + */ +gchar * +gda_handler_time_get_hint (GdaHandlerTime *dh, GType type) +{ + gchar *str; + GString *string; + gint i; + + g_return_val_if_fail (GDA_IS_HANDLER_TIME (dh), NULL); + + string = g_string_new (""); + if ((type == G_TYPE_DATE) || (type == G_TYPE_DATE_TIME) || (type == G_TYPE_DATE_TIME)) { + for (i=0; i<3; i++) { + if (i > 0) + g_string_append_c (string, dh->str_locale->separator); + switch (dh->str_locale->dmy_order[i]) { + case G_DATE_DAY: + /* To translators: DD represents a place holder in a date string. For example in the "YYYY-MM-DD" format, one knows that she has to replace DD by a day number */ + g_string_append (string, _("DD")); + break; + case G_DATE_MONTH: + /* To translators: MM represents a place holder in a date string. For example in the "YYYY-MM-DD" format, one knows that she has to replace MM by a month number */ + g_string_append (string, _("MM")); + break; + case G_DATE_YEAR: + if (dh->str_locale->twodigit_years) + /* To translators: YY represents a place holder in a date string. For example in the "YY-MM-DD" format, one knows that she has to replace YY by a year number, on 2 digits */ + g_string_append (string, _("YY")); + else + /* To translators: YYYY represents a place holder in a date string. For example in the "YYYY-MM-DD" format, one knows that she has to replace YYYY by a year number, on 4 digits */ + g_string_append (string, _("YYYY")); + break; + default: + g_assert_not_reached (); + break; + } + } + } + if (type == G_TYPE_DATE_TIME) + g_string_append_c (string, ' '); + + if ((type == GDA_TYPE_TIME) || (type == G_TYPE_DATE_TIME)) + /* To translators: HH:MM:SS represents a time format. For example in the "HH:MM:SS" format, one knows that she has to replace HH by a number of hours, and so on */ + g_string_append (string, "HH:MM:SS"); + + str = string->str; + g_string_free (string, FALSE); + return str; +} + +/* Interface implementation */ + +/* REM: SQL date format is always returned using the MM-DD-YYY format, it's up to the + * provider to be correctly set up to accept this format. + */ +static gchar * +gda_handler_time_get_sql_from_value (GdaDataHandler *iface, const GValue *value) +{ + g_assert (value); + + gchar *retval = NULL, *str; + GdaHandlerTime *hdl; + GType type; + + g_return_val_if_fail (GDA_IS_HANDLER_TIME (iface), NULL); + hdl = (GdaHandlerTime*) (iface); + type = G_VALUE_TYPE (value); + + if (type == G_TYPE_DATE) { + const GDate *date; + + date = (GDate *) g_value_get_boxed (value); + str = render_date_locale (date, hdl->sql_locale); + if (!str) + retval = g_strdup ("NULL"); + else { + retval = g_strdup_printf ("'%s'", str); + g_free (str); + } + } + else if (type == GDA_TYPE_TIME) { + GdaTime *gdat; + gchar *str; + + gdat = (GdaTime*) g_value_get_boxed ((GValue *) value); + str = gda_time_to_string_utc (gdat); + retval = g_strdup_printf ("'%s'", str); + g_free (str); + } + else if (g_type_is_a (type, G_TYPE_DATE_TIME)) { + GDateTime *gdats; + + gdats = (GDateTime*) g_value_get_boxed ((GValue *) value); + if (gdats != NULL) + retval = g_date_time_format (gdats, "'%FT%H:%M:%S%:::z'"); + else + retval = g_strdup ("NULL"); + } + else { + g_warning (_("Time data handler can create an SQL representation of a value not holding time type.")); + retval = g_strdup ("NULL"); + } + + return retval; +} + +static gchar *strip_quotes (const gchar *str); +static gchar * +gda_handler_time_get_str_from_value (GdaDataHandler *iface, const GValue *value) +{ + g_assert (value); + + GdaHandlerTime *hdl; + gchar *retval = NULL, *str; + GType type; + + g_return_val_if_fail (GDA_IS_HANDLER_TIME (iface), NULL); + hdl = (GdaHandlerTime*) (iface); + type = G_VALUE_TYPE (value); + + if (type == G_TYPE_DATE) { + const GDate *date; + GTimeZone *tz = g_time_zone_new_utc (); + GDateTime *dt; + date = (GDate *) g_value_get_boxed (value); + dt = g_date_time_new (tz, g_date_get_year (date), + g_date_get_month (date), + g_date_get_day (date), + 0, 0, 0.0); + retval = g_date_time_format (dt, "%F"); + if (!retval) + retval = g_strdup (""); + } + else if (type == GDA_TYPE_TIME) { + str = gda_handler_time_get_sql_from_value (iface, value); + retval = strip_quotes (str); + g_free (str); + } + else if (type == G_TYPE_DATE_TIME) { + GDateTime *gdats; + + gdats = (GDateTime*) g_value_get_boxed ((GValue *) value); + if (gdats != NULL) + retval = g_date_time_format (gdats, "%FT%H:%M:%S%:::z"); + else + retval = g_strdup (""); + } + else if (type == G_TYPE_DATE_TIME) { // FIXME: Remove + GDateTime *ts; + GDate *vdate; + + ts = g_value_get_boxed ((GValue *) value); + if (ts) { + gint y, m, d; + g_date_time_get_ymd (ts, &y, &m, &d); + vdate = g_date_new_dmy (d, m, y); + str = render_date_locale (vdate, hdl->str_locale); + g_date_free (vdate); + + if (str) { + GString *string; + string = g_string_new (""); + g_string_append_printf (string, "%02u:%02u:%02u", + g_date_time_get_hour (ts), + g_date_time_get_minute (ts), + g_date_time_get_second (ts)); + if (g_date_time_get_microsecond (ts) != 0) + g_string_append_printf (string, ".%d", g_date_time_get_microsecond (ts)); + + GTimeSpan span; + span = g_date_time_get_utc_offset (ts); + if (span > 0) + g_string_append_printf (string, "+%02d", + (int) (span / G_TIME_SPAN_HOUR)); + else + g_string_append_printf (string, "-%02d", + (int) (-span / G_TIME_SPAN_HOUR)); + + retval = g_strdup_printf ("%sT%s", str, string->str); + g_free (str); + g_string_free (string, TRUE); + } + else + retval = g_strdup ("NULL"); + } + else + retval = g_strdup ("NULL"); + } + else + g_assert_not_reached (); + + return retval; +} + +static gchar * +render_date_locale (const GDate *date, LocaleSetting *locale) +{ + GString *string; + gchar *retval; + gint i; + + if (!date) + return NULL; + + string = g_string_new (""); + for (i=0; i<3; i++) { + if (i) + g_string_append_c (string, locale->separator); + + switch (locale->dmy_order[i]) { + case G_DATE_DAY: + g_string_append_printf (string, "%02d", g_date_get_day (date)); + break; + case G_DATE_MONTH: + g_string_append_printf (string, "%02d", g_date_get_month (date)); + break; + case G_DATE_YEAR: + if (locale->twodigit_years) { + GDateYear year = g_date_get_year (date); + if ((year >= locale->current_offset) && (year < locale->current_offset + 100)) + g_string_append_printf (string, "%02d", year - locale->current_offset); + else + g_string_append_printf (string, "%04d", year); + } + else + g_string_append_printf (string, "%04d", g_date_get_year (date)); + break; + } + } + + retval = string->str; + g_string_free (string, FALSE); + return retval; +} + +static gchar * +strip_quotes (const gchar *str) +{ + gchar *ptr = g_strdup (str); + gchar *to_free = ptr, *retval; + + if (*ptr == '\'') { + ptr++; + } + + if (*(ptr+(strlen (ptr)-1)) == '\'') { + *(ptr+(strlen (ptr)-1)) = 0; + } + + retval = g_strdup (ptr); + g_free (to_free); + return retval; +} + +static GValue *gda_handler_time_get_value_from_locale (GdaDataHandler *iface, const gchar *sql, + GType type, LocaleSetting *locale); + +static GValue * +gda_handler_time_get_value_from_sql (GdaDataHandler *iface, const gchar *sql, GType type) +{ + g_assert (sql); + + GdaHandlerTime *hdl; + GValue *value = NULL; + + g_return_val_if_fail (GDA_IS_HANDLER_TIME (iface), NULL); + hdl = (GdaHandlerTime*) (iface); + + if (*sql) { + gint i = strlen (sql); + if ((i>=2) && (*sql=='\'') && (sql[i-1]=='\'')) { + gchar *str = g_strdup (sql); + str[i-1] = 0; + value = gda_handler_time_get_value_from_locale (iface, str+1, type, hdl->sql_locale); + g_free (str); + } + } + else + value = gda_value_new_null (); + + return value; +} + +static GValue * +gda_handler_time_get_value_from_str (GdaDataHandler *iface, const gchar *str, GType type) +{ + g_assert (str); + GdaHandlerTime *hdl; + + g_return_val_if_fail (GDA_IS_HANDLER_TIME (iface), NULL); + hdl = (GdaHandlerTime*) (iface); + + if (*str == '\'') + return NULL; + else + return gda_handler_time_get_value_from_locale (iface, str, type, hdl->str_locale); +} + + + +static GDateTime * make_timestamp (GdaHandlerTime *hdl, + const gchar *value, LocaleSetting *locale); +static gboolean make_date (GdaHandlerTime *hdl, GDate *date, const gchar *value, + LocaleSetting *locale, const gchar **out_endptr); +static GdaTime * make_time (GdaHandlerTime *hdl, const gchar *value); +static GValue * +gda_handler_time_get_value_from_locale (GdaDataHandler *iface, const gchar *sql, + GType type, LocaleSetting *locale) +{ + GdaHandlerTime *hdl; + GValue *value = NULL; + + g_return_val_if_fail (GDA_IS_HANDLER_TIME (iface), NULL); + hdl = (GdaHandlerTime*) (iface); + + if (type == G_TYPE_DATE) { + GDate date; + if (make_date (hdl, &date, sql, locale, NULL)) { + value = g_value_init (g_new0 (GValue, 1), G_TYPE_DATE); + g_value_set_boxed (value, (gconstpointer) &date); + } + } + else if (type == GDA_TYPE_TIME) { + GdaTime* timegda =make_time (hdl, sql); + if (timegda != NULL) { + value = g_value_init (g_new0 (GValue, 1), GDA_TYPE_TIME); + g_value_take_boxed (value, timegda); + } + } + else if (g_type_is_a (type, G_TYPE_DATE_TIME)) { + GDateTime* timestamp = make_timestamp (hdl, sql, locale); + if (timestamp != NULL) { + value = g_value_init (g_new0 (GValue, 1), G_TYPE_DATE_TIME); + g_value_set_boxed (value, timestamp); + g_date_time_unref (timestamp); + } + } + else + return NULL; + + return value; +} + + +/* Makes a GDateTime from a string like "24-12-2003T13:12:01.12+01", + * taken from libgda/gda-value.h + * with a modification for the date format + */ +static GDateTime* +make_timestamp (GdaHandlerTime *hdl, const gchar *value, LocaleSetting *locale) +{ + GTimeZone *default_tz = g_time_zone_new_local (); + GDateTime* dt = g_date_time_new_from_iso8601 (value, default_tz); + g_time_zone_unref (default_tz); + return dt; +} + +static gboolean +get_uint_from_string (const gchar *str, guint16 *out_int) +{ + long int li; + char *endptr = NULL; + li = strtol (str, &endptr, 10); + if (!*endptr && (li >= 0) && (li <= G_MAXUINT16)) { + *out_int = (guint16) li; + return TRUE; + } + else { + *out_int = 0; + return FALSE; + } +} + +/* Makes a GDate from a string like "24-12-2003" + * If @out_endptr is %NULL, then all the @value has to be consumed and there must not + * be any character left. If it's not %NULL, then it will point on the first unused character + * of @value. + */ +static gboolean +make_date (G_GNUC_UNUSED GdaHandlerTime *hdl, GDate *date, const gchar *value, + LocaleSetting *locale, const gchar **out_endptr) +{ + gboolean retval = TRUE; + guint16 nums[3]; + gboolean error = FALSE; + gchar *ptr, *numstart, *tofree; + gint i; + + if (out_endptr) + *out_endptr = NULL; + + if (!value) + return FALSE; + + g_date_clear (date, 1); + + /* 1st number */ + ptr = g_strdup (value); + tofree = ptr; + numstart = ptr; + while (*ptr && g_ascii_isdigit (*ptr)) + ptr++; + if ((ptr != numstart) && *ptr) { + *ptr = 0; + if (! get_uint_from_string (numstart, &(nums[0]))) + error = TRUE; + } + else + error = TRUE; + + /* 2nd number */ + if (!error) { + if (value [ptr-tofree] != locale->separator) + error = TRUE; + else { + ptr++; + numstart = ptr; + while (*ptr && g_ascii_isdigit (*ptr)) + ptr++; + if ((ptr != numstart) && *ptr) { + *ptr = 0; + if (! get_uint_from_string (numstart, &(nums[1]))) + error = TRUE; + } + else + error = TRUE; + } + } + + /* 3rd number */ + if (!error) { + if (value [ptr-tofree] != locale->separator) + error = TRUE; + else { + ptr++; + numstart = ptr; + while (*ptr && g_ascii_isdigit (*ptr)) + ptr++; + *ptr = 0; + if (ptr != numstart) { + if (! get_uint_from_string (numstart, &(nums[2]))) + error = TRUE; + } + else + error = TRUE; + } + } + + /* test if there are some characters left */ + if (!error) { + if (out_endptr) + *out_endptr = value + (ptr-tofree); + else if (value [ptr-tofree]) + error = TRUE; + } + GDateDay day = 1; + GDateMonth month = 1; + GDateYear year = 1; + + /* analyse what's parsed */ + if (!error) { + for (i=0; i<3; i++) { + switch (locale->dmy_order[i]) { + case G_DATE_DAY: + day = nums[i]; + break; + case G_DATE_MONTH: + month = nums[i]; + break; + case G_DATE_YEAR: + year = nums[i] < 100 ? nums[i] + locale->current_offset : nums[i]; + break; + } + } + if (!g_date_valid_dmy (day, month, year)) { + retval = FALSE; + } else { + g_date_set_dmy (date, day, month, year); + retval = TRUE; + } + } + else + retval = FALSE; + + g_free (tofree); + + return retval; +} + +/* Makes a GdaTime from a string like: + * 12:30:15+01 + * 12:30:15-02 + * 12:30:15.123 + * 123015+01 + * 123015-02 + * 123015.123 + * taken from libgda/gda-value.h + * + * Also works if there is only 0 or 1 digit instead of 2 + */ +static GdaTime * +make_time (G_GNUC_UNUSED GdaHandlerTime *hdl, const gchar *value) +{ + GdaTime *ret = NULL; + ret = gda_parse_iso8601_time (value); + if (ret == NULL) + return gda_parse_formatted_time (value, 0); + return ret; +} + + +static GValue * +gda_handler_time_get_sane_init_value (G_GNUC_UNUSED GdaDataHandler *iface, GType type) +{ + GValue *value = NULL; + GDateTime *gdate; + + gdate = g_date_time_new_now_utc (); + + if (type == G_TYPE_DATE) { + GDate *date = g_date_new_dmy ((GDateDay) g_date_time_get_day_of_month (gdate), + (GDateMonth) g_date_time_get_month (gdate), + (GDateYear) g_date_time_get_year (gdate)); + value = g_value_init (g_new0 (GValue, 1), G_TYPE_DATE); + g_value_take_boxed (value, date); + } + else if (type == GDA_TYPE_TIME) { + value = g_value_init (g_new0 (GValue, 1), GDA_TYPE_TIME); + g_value_set_boxed (value, gdate); + } + else if (g_type_is_a (type, G_TYPE_DATE_TIME)) { + value = g_value_init (g_new0 (GValue, 1), G_TYPE_DATE_TIME); + g_value_set_boxed (value, gdate); + } + else + value = gda_value_new_null (); + + g_date_time_unref (gdate); + + return value; +} + +static gboolean +gda_handler_time_accepts_g_type (GdaDataHandler *iface, GType type) +{ + GdaHandlerTime *hdl; + guint i; + + g_assert (iface); + hdl = (GdaHandlerTime*) (iface); + + for (i = 0; i < hdl->nb_g_types; i++) { + if (hdl->valid_g_types [i] == type) + return TRUE; + } + + return FALSE; +} + +static const gchar * +gda_handler_time_get_descr (GdaDataHandler *iface) +{ + g_return_val_if_fail (GDA_IS_HANDLER_TIME (iface), NULL); + return g_object_get_data (G_OBJECT (iface), "descr"); +} + +static void +data_handler_iface_init (GdaDataHandlerInterface *iface) +{ + iface->get_sql_from_value = gda_handler_time_get_sql_from_value; + iface->get_str_from_value = gda_handler_time_get_str_from_value; + iface->get_value_from_sql = gda_handler_time_get_value_from_sql; + iface->get_value_from_str = gda_handler_time_get_value_from_str; + iface->get_sane_init_value = gda_handler_time_get_sane_init_value; + iface->accepts_g_type = gda_handler_time_accepts_g_type; + iface->get_descr = gda_handler_time_get_descr; +} + +static void +gda_handler_time_init (GdaHandlerTime *hdl) +{ + /* Private structure */ + hdl->nb_g_types = 4; + hdl->valid_g_types = g_new0 (GType, 7); + hdl->valid_g_types[0] = G_TYPE_DATE; + hdl->valid_g_types[1] = GDA_TYPE_TIME; + hdl->valid_g_types[2] = G_TYPE_DATE_TIME; + hdl->valid_g_types[3] = G_TYPE_DATE_TIME; + + /* taking into accout the locale */ + hdl->sql_locale = g_new0 (LocaleSetting, 1); + hdl->sql_locale->dmy_order[0] = G_DATE_MONTH; + hdl->sql_locale->dmy_order[1] = G_DATE_DAY; + hdl->sql_locale->dmy_order[2] = G_DATE_YEAR; + hdl->sql_locale->twodigit_years = FALSE; + hdl->sql_locale->current_offset = 0; + hdl->sql_locale->separator = '-'; + + hdl->str_locale = g_new0 (LocaleSetting, 1); + hdl->str_locale->dmy_order[0] = G_DATE_MONTH; + hdl->str_locale->dmy_order[1] = G_DATE_DAY; + hdl->str_locale->dmy_order[2] = G_DATE_YEAR; + hdl->str_locale->twodigit_years = FALSE; + hdl->str_locale->current_offset = 0; + hdl->str_locale->separator = '-'; + + g_object_set_data (G_OBJECT (hdl), "name", "InternalTime"); + g_object_set_data (G_OBJECT (hdl), "descr", _("Time, Date and TimeStamp representation")); +} + +static void +gda_handler_time_dispose (GObject *object) +{ + GdaHandlerTime *hdl; + + g_return_if_fail (object != NULL); + g_return_if_fail (GDA_IS_HANDLER_TIME (object)); + + hdl = GDA_HANDLER_TIME (object); + + g_clear_pointer(&hdl->valid_g_types, g_free); + g_clear_pointer(&hdl->str_locale, g_free); + g_clear_pointer(&hdl->sql_locale, g_free); + + /* for the parent class */ + G_OBJECT_CLASS (gda_handler_time_parent_class)->dispose (object); +} + +static void +gda_handler_time_class_init (GdaHandlerTimeClass * class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (class); + + object_class->dispose = gda_handler_time_dispose; +} diff --git a/.flatpak-builder/cache/objects/ed/805a623cfe2fd61ef4e413f4357c302378bbb3abdf8d5773b11e77debd35eb.file b/.flatpak-builder/cache/objects/ed/805a623cfe2fd61ef4e413f4357c302378bbb3abdf8d5773b11e77debd35eb.file new file mode 100644 index 0000000..57ee251 --- /dev/null +++ b/.flatpak-builder/cache/objects/ed/805a623cfe2fd61ef4e413f4357c302378bbb3abdf8d5773b11e77debd35eb.file @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2006 - 2014 Vivien Malerba + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GDA_CONNECTION_PRIVATE_H_ +#define __GDA_CONNECTION_PRIVATE_H_ + +#include +#include +#include +#include +#include +#include + +G_BEGIN_DECLS + +/* + * Provider's specific connection data management + */ +/** + * GdaServerProviderConnectionData: + * + * Opaque structure extended by database providers to store per-connection information (usually C handles + * to the connection as required by the C API they use). + * + * Note: @worker part is created in _gda_server_provider_open_connection() by the provider itself, which allows it to + * either create a #GdaWorker for each connection, or create only one #GdaWorker for all connections (if the underlying + * for example does not support multi-threading at all) + */ +typedef struct { + GdaWorker * worker; + GDestroyNotify provider_data_destroy_func; + gpointer pad1; + gpointer pad2; +} GdaServerProviderConnectionData; +#define GDA_TYPE_SERVER_PROVIDER_CONNECTION_DATA (gda_server_provider_connection_data_get_type()) + +GType gda_server_provider_connection_data_get_type (void) G_GNUC_CONST; + +void gda_connection_internal_set_provider_data (GdaConnection *cnc, + GdaServerProviderConnectionData *data, + GDestroyNotify destroy_func); +GdaServerProviderConnectionData *gda_connection_internal_get_provider_data_error (GdaConnection *cnc, GError **error); +void _gda_connection_internal_set_worker_thread (GdaConnection *cnc, GThread *thread); +GdaWorker *gda_connection_internal_get_worker (GdaServerProviderConnectionData *data); + +/* + * Connection's events + */ +GdaConnectionEvent *gda_connection_point_available_event(GdaConnection *cnc, GdaConnectionEventType type); +void gda_connection_add_event (GdaConnection *cnc, GdaConnectionEvent *event); +GdaConnectionEvent *gda_connection_add_event_string (GdaConnection *cnc, const gchar *str, ...); +void gda_connection_clear_events_list (GdaConnection *cnc); + +/* + * Transaction related + */ +void gda_connection_internal_transaction_started (GdaConnection *cnc, const gchar *parent_trans, const gchar *trans_name, + GdaTransactionIsolation isol_level); +void gda_connection_internal_transaction_rolledback (GdaConnection *cnc, const gchar *trans_name); +void gda_connection_internal_transaction_committed (GdaConnection *cnc, const gchar *trans_name); + +void gda_connection_internal_statement_executed (GdaConnection *cnc, GdaStatement *stmt, GdaSet *params, GdaConnectionEvent *error); + +void gda_connection_internal_savepoint_added (GdaConnection *cnc, const gchar *parent_trans, const gchar *svp_name); +void gda_connection_internal_savepoint_rolledback (GdaConnection *cnc, const gchar *svp_name); +void gda_connection_internal_savepoint_removed (GdaConnection *cnc, const gchar *svp_name); +void gda_connection_internal_change_transaction_state (GdaConnection *cnc, + GdaTransactionStatusState newstate); +void gda_connection_internal_reset_transaction_status (GdaConnection *cnc); + +/* + * prepared statements support + */ +void gda_connection_add_prepared_statement (GdaConnection *cnc, GdaStatement *gda_stmt, GdaPStmt *prepared_stmt); +void gda_connection_del_prepared_statement (GdaConnection *cnc, GdaStatement *gda_stmt); +GdaPStmt *gda_connection_get_prepared_statement (GdaConnection *cnc, GdaStatement *gda_stmt); + +/* + * Open an SQLite connection even if the SQLite provider is not installed + */ +GdaConnection *gda_connection_open_sqlite (const gchar *directory, const gchar *filename, gboolean auto_unlink); + +G_END_DECLS + +#endif diff --git a/.flatpak-builder/cache/objects/ed/e5c25602222c9d901e473729df16193208321ea8f0cc18ffbda29e0e2d1caa.dirtree b/.flatpak-builder/cache/objects/ed/e5c25602222c9d901e473729df16193208321ea8f0cc18ffbda29e0e2d1caa.dirtree new file mode 100644 index 0000000..d07b0d1 Binary files /dev/null and b/.flatpak-builder/cache/objects/ed/e5c25602222c9d901e473729df16193208321ea8f0cc18ffbda29e0e2d1caa.dirtree differ diff --git a/.flatpak-builder/cache/objects/ed/eae431e33582d4318724ecdbd4dd6d878eee42ce6452e04eec76a2353a97d9.file b/.flatpak-builder/cache/objects/ed/eae431e33582d4318724ecdbd4dd6d878eee42ce6452e04eec76a2353a97d9.file new file mode 100644 index 0000000..b260d4b --- /dev/null +++ b/.flatpak-builder/cache/objects/ed/eae431e33582d4318724ecdbd4dd6d878eee42ce6452e04eec76a2353a97d9.file @@ -0,0 +1,791 @@ +/* gsound-context.c + * + * Copyright (C) 2013 Tristan Brindle + * + * This file is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of the + * License, or (at your option) any later version. + * + * This file is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +/** + * SECTION: gsound-context + * @title: GSoundContext + * @short_description: GSound context object + * @see_also: #ca_context + * + * A #GSoundContext is used for playing system sounds. The typical use pattern + * is: + * + * * Initialize the #GSoundContext + * * [Optional] Set any global attributes using gsound_context_set_attributes() + * * [Optional] Cache any frequently-used sounds (for example, sound + * effects for a game) using gsound_context_cache() + * * Play sounds using gsound_context_play_simple() or gsound_context_play_full() + * * Close the connection to the sound server and clean up the context using + * g_object_unref() + * + * #GSoundContext implements the #GInitable interface, so if created with + * g_object_new() (as typically happens with language bindings) then you must + * call the g_initable_init() method before attempting to use it. + * + * # Simple Examples + * + * In C: + * + * |[ + * GSoundContext *ctx = NULL; + * GCancellable *cancellable = g_cancellable_new(); + * GError *error = NULL; + * + * ctx = gsound_context_new(cancellable, &error); + * if (error) { + * // handle error + * } + * + * gsound_context_play_simple(ctx, cancellable, &error, + * GSOUND_ATTR_EVENT_ID, "phone-incoming-call", + * // other attributes... + * NULL); + * ]| + * + * or, using Python via GObject Introspection: + * + * |[ + * from gi.repository import GSound + * + * ctx = GSound.Context() + * + * try: + * ctx.init(); + * ctx.play_simple({ GSound.ATTR_EVENT_ID : "phone-incoming-call" }) + * except: + * # Handle error + * pass + * ]| + * + * or using Vala: + * + * |[ + * try { + * var ctx = new GSound.Context(); + * ctx.play_simple(null, GSound.Attribute.EVENT_ID, "phone-incoming-call"); + * } catch (Error e) { + * // handle error + * } + * ]| + * + * # `play_simple()` versus `play_full()` + * + * The above examples use the gsound_context_play_simple() method for + * playing sounds. This is a "fire and forget" method which returns + * immediately and does not block your program, and is suitable for most use + * cases. + * + * If you need to find out when the sound finished (for example to repeat the + * sound) then you can use the gsound_context_play_full() version. This + * is an asynchronous method using the standard GIO async pattern, which will + * run the supplied #GAsyncReadyCallback when the sound server has finished. + * It is guaranteed that the callback will be run exactly once. + * + * Note that calling gsound_context_play_full() with a %NULL callback is not + * equivalent to calling gsound_context_play_simple(). When calling + * play_simple(), errors which occur before the sound is passed to the sound + * server are reported immediately, whereas with `play_full()` these are reported + * in the callback. If you pass a %NULL callback to gsound_context_play_full() + * you will not be able to receive these errors, so it is strongly recommended + * to avoid doing this and use gsound_context_play_simple() in the case when + * you don't need to be notified when the sound has finished. + * + * # Passing Attributes + * + * GSound supplies information to the sound server by means of attributes. + * Attributes can be set on the #GSoundContext itself using + * gsound_context_set_attributes(), or supplied in a `play()` call. Attributes + * set on the context will automatically applied to any subsequent `play()` + * calls, unless overridden by that call. + * + * In C and Vala, attributes are passed as %NULL-terminated list of + * (attribute, value) pairs. When using GObject introspection, attributes are + * typically passed using a language-specific associated array, for example + * a dict in Python or an object in JavaScript. + * + * For the list of attributes supported by GSound, see + * [GSound Attributes][gsound-GSound-Attributes]. + * + * # Caching # {#caching} + * + * If supported by the sound server, frequently-used sounds may be cached. This + * may be useful, for example, for sound effects in a game. To cache a sound, + * either call gsound_context_cache(), or pass the special + * #GSOUND_ATTR_CANBERRA_CACHE_CONTROL attribute to one of the `play()` + * functions. + * + * For example, in the startup code for a game you might include something + * like the following (error checking omitted): + * + * |[ <-- language="C" --> + * GSoundContext *ctx = gsound_context_new (NULL, NULL); + * gsound_context_cache(ctx, NULL, + * GSOUND_ATTR_MEDIA_FILENAME, + * "/path/to/player-spaceship-fire-laser.ogg", + * NULL); + * ]| + * + * There are three caching modes available, "permanent", "volatile" and "never". + * The default mode when calling gsound_context_cache() is "permanent", and + * the default mode for gsound_context_play_simple() and `play_full()` is + * "never". + * + * See the documentation for #GSOUND_ATTR_CANBERRA_CACHE_CONTROL for more + * details. + * + */ + +#include "gsound-context.h" + +#include + +#include + +static void gsound_context_initable_init (GInitableIface *iface); + +struct _GSoundContext +{ + GObject parent; + + ca_context *ca; +}; + +struct _GSoundContextClass +{ + GObjectClass parent_class; +}; + +G_DEFINE_TYPE_WITH_CODE (GSoundContext, gsound_context, G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, + gsound_context_initable_init)) + +G_DEFINE_QUARK (gsound - error - quark, gsound_error); + +static gboolean +test_return (int code, GError **error) +{ + if (code == CA_SUCCESS) + return TRUE; + + g_set_error_literal (error, GSOUND_ERROR, code, ca_strerror (code)); + return FALSE; +} + +static void +hash_table_to_prop_list (GHashTable *ht, ca_proplist *pl) +{ + gpointer key, value; + GHashTableIter iter; + + g_hash_table_ref (ht); + + g_hash_table_iter_init (&iter, ht); + while (g_hash_table_iter_next (&iter, &key, &value)) + ca_proplist_sets (pl, key, value); + + g_hash_table_unref (ht); +} + +static int +var_args_to_prop_list (va_list args, ca_proplist *pl) +{ + while (TRUE) + { + const char *key; + const char *val; + int res; + + key = va_arg (args, const char*); + if (!key) + return CA_SUCCESS; + + val = va_arg (args, const char*); + if (!val) + return CA_ERROR_INVALID; + + res = ca_proplist_sets (pl, key, val); + if (res != CA_SUCCESS) + return res; + } + + return CA_SUCCESS; +} + +static void +on_ca_play_full_finished (ca_context *ca, + guint32 id, + int error_code, + gpointer user_data) +{ + GTask *task = user_data; + + if (error_code != CA_SUCCESS) + { + g_task_return_new_error (task, + GSOUND_ERROR, + error_code, + "%s", + ca_strerror (error_code)); + } + else + g_task_return_boolean (task, TRUE); + + g_object_unref (task); +} + +static void +on_cancellable_cancelled (GCancellable *cancellable, + GSoundContext *self) +{ + ca_context_cancel (self->ca, g_direct_hash (cancellable)); +} + +/** + * gsound_context_new: + * @cancellable: (allow-none): A #GCancellable, or %NULL + * @error: Return location for error + * + * Creates and initializes a new #GSoundContext. If the an error occured + * during initialization, #NULL is returned and @error will be set + * appropriately. + * + * Returns: (transfer full): A new #GSoundContext + */ +GSoundContext * +gsound_context_new (GCancellable *cancellable, GError **error) +{ + return GSOUND_CONTEXT (g_initable_new (GSOUND_TYPE_CONTEXT, + cancellable, + error, + NULL)); +} + +/** + * gsound_context_open: + * @context: A #GSoundContext + * @error: Return location for error + * + * Attempts to open a connection to the backend sound driver. It is recommended + * that you set context attributes with gsound_context_set_attributes() before + * calling this function. + * + * > A connection is automatically opened before playing or caching sounds, + * > so you rarely need to call this yourself. + * + * Returns: %TRUE if the output device was opened successfully, or %FALSE + * (populating @error) + */ +gboolean +gsound_context_open (GSoundContext *self, GError **error) +{ + g_return_val_if_fail (GSOUND_IS_CONTEXT (self), FALSE); + + return test_return (ca_context_open (self->ca), error); +} + +/** + * gsound_context_set_driver: + * @context: A #GSoundContext + * @driver: libcanberra driver to use + * @error: Return location for error, or %NULL + * + * Sets the libcanberra driver to @driver, for example "pulse", "alsa" or "null". + * You normally do not need to set this yourself. + * + * Note that this function may return %TRUE even if the specified driver is + * not available: see the libcanberra documentation for details. + * + * Returns: %TRUE if the libcanberra driver was set successfully + */ +gboolean +gsound_context_set_driver (GSoundContext *self, + const char *driver, + GError **error) +{ + g_return_val_if_fail (GSOUND_IS_CONTEXT (self), FALSE); + + return test_return (ca_context_set_driver (self->ca, driver), error); +} + +/** + * gsound_context_set_attributes: (skip) + * @context: A #GSoundContext + * @error: Return location for error + * @...: %NULL terminated list of attribute name-value pairs + * + * Set attributes or change attributes on @context. Subsequent calls to this + * function calling the same attributes will override the earlier values. + * + * Note that GSound will set the #GSOUND_ATTR_APPLICATION_NAME and + * #GSOUND_ATTR_APPLICATION_ID for you if using #GApplication, so you do + * not normally need to set these yourself. + * + * Returns: %TRUE if attributes were updated successfully + */ +gboolean +gsound_context_set_attributes (GSoundContext *self, + GError **error, + ...) +{ + ca_proplist *pl; + va_list args; + int res; + + g_return_val_if_fail (GSOUND_IS_CONTEXT (self), FALSE); + + if ((res = ca_proplist_create (&pl)) != CA_SUCCESS) + return test_return (res, error); + + va_start (args, error); + var_args_to_prop_list (args, pl); + va_end (args); + + res = ca_context_change_props_full (self->ca, pl); + + g_clear_pointer (&pl, ca_proplist_destroy); + + return test_return (res, error); +} + +/** + * gsound_context_set_attributesv: (rename-to gsound_context_set_attributes) + * @context: A #GSoundContext + * @attrs: (element-type utf8 utf8): Hash table of attributes to set + * @error: Return location for error, or %NULL + * + * Set attributes or change attributes on @context. Subsequent calls to this + * function calling the same attributes will override the earlier values. + * + * Note that GSound will set the #GSOUND_ATTR_APPLICATION_NAME and + * #GSOUND_ATTR_APPLICATION_ID for you if using #GApplication, so you do + * not normally need to set these yourself. + * + * This function is intented to be used by language bindings. + * + * Returns: %TRUE if attributes were updated successfully + */ +gboolean +gsound_context_set_attributesv (GSoundContext *self, + GHashTable *attrs, + GError **error) +{ + ca_proplist *pl; + int res; + + g_return_val_if_fail (GSOUND_IS_CONTEXT (self), FALSE); + + res = ca_proplist_create (&pl); + if (!test_return (res, error)) + return FALSE; + + hash_table_to_prop_list (attrs, pl); + + res = ca_context_change_props_full (self->ca, pl); + + g_clear_pointer (&pl, ca_proplist_destroy); + + return test_return (res, error); +} + +/** + * gsound_context_play_simple: (skip) + * @context: A #GSoundContext + * @cancellable: (allow-none): A #GCancellable, or %NULL + * @error: Return location for error, or %NULL + * @...: A %NULL-terminated list of attribute-value pairs + * + * The basic "fire-and-forget" play command. This function will not block, and + * just sends a request to the sound server before immediately returning. + * + * If you need to know when a sound finishes playing then you should call + * gsound_context_play_full() instead. + * + * You can cancel playback at any time by calling g_cancellable_cancel() on + * @cancellable, if supplied. + * + * Returns: %TRUE on success, or %FALSE, populating @error + */ +gboolean +gsound_context_play_simple (GSoundContext *self, + GCancellable *cancellable, + GError **error, + ...) +{ + ca_proplist *pl; + va_list args; + int res; + + g_return_val_if_fail (GSOUND_IS_CONTEXT (self), FALSE); + + if ((res = ca_proplist_create (&pl)) != CA_SUCCESS) + return test_return (res, error); + + va_start (args, error); + var_args_to_prop_list (args, pl); + va_end (args); + + res = ca_context_play_full (self->ca, + g_direct_hash (cancellable), + pl, NULL, NULL); + + if (cancellable) + g_cancellable_connect (cancellable, + G_CALLBACK (on_cancellable_cancelled), + g_object_ref (self), + g_object_unref); + + g_clear_pointer (&pl, ca_proplist_destroy); + + return test_return (res, error); +} + +/** + * gsound_context_play_simplev: (rename-to gsound_context_play_simple) + * @context: A #GSoundContext + * @attrs: (element-type utf8 utf8): Attributes + * @cancellable: (allow-none): A #GCancellable + * @error: Return location for error + * + * The basic "fire-and-forget" play command. This function will not block, and + * just sends a request to the sound server before immediately returning. + * + * If you need to know when a sound finishes playing then you should call + * gsound_context_play_full() instead. + * + * You can cancel playback at any time by calling g_cancellable_cancel() on + * @cancellable, if supplied. + * + * This function is intented to be used by language bindings. + * + * Returns: %TRUE on success, %FALSE on error + * + */ +gboolean +gsound_context_play_simplev (GSoundContext *self, + GHashTable *attrs, + GCancellable *cancellable, + GError **error) +{ + ca_proplist *pl; + int res = ca_proplist_create (&pl); + + if (!test_return (res, error)) + return FALSE; + + hash_table_to_prop_list (attrs, pl); + + res = ca_context_play_full (self->ca, + g_direct_hash (cancellable), + pl, NULL, NULL); + + if (cancellable) + g_cancellable_connect (cancellable, + G_CALLBACK (on_cancellable_cancelled), + g_object_ref (self), + g_object_unref); + + g_clear_pointer (&pl, ca_proplist_destroy); + + return test_return (res, error); +} + +/** + * gsound_context_play_full: (skip) + * @context: A #GSoundContext + * @cancellable: (allow-none): A #GCancellable, or %NULL + * @callback: (scope async): callback + * @user_data: User data passed to @callback + * @...: A %NULL-terminated list of attribute-value pairs + * + * Asynchronously request a sound to be played. When playback is finished + * (or if an error occurs) then @callback will be called, following the + * normal GIO async pattern. + * + * If playback is cancelled via @cancellable, then @callback will be called + * with #G_IO_ERROR_CANCELLED. + * + * If you do not need notification of when playback is complete, you should + * use gsound_context_play_simple(). + */ +void +gsound_context_play_full (GSoundContext *self, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data, + ...) +{ + GError *inner_error = NULL; + ca_proplist *proplist; + va_list args; + GTask *task; + int res; + + task = g_task_new (self, cancellable, callback, user_data); + + res = ca_proplist_create (&proplist); + if (!test_return (res, &inner_error)) + { + g_task_return_error (task, inner_error); + g_object_unref (task); + return; + } + + va_start (args, user_data); + var_args_to_prop_list (args, proplist); + va_end (args); + + res = ca_context_play_full (self->ca, + g_direct_hash (cancellable), + proplist, + on_ca_play_full_finished, + task); + + if (cancellable) + g_cancellable_connect (cancellable, + G_CALLBACK (on_cancellable_cancelled), + g_object_ref (self), + g_object_unref); + + g_clear_pointer (&proplist, ca_proplist_destroy); + + if (!test_return (res, &inner_error)) + { + g_task_return_error (task, inner_error); + g_object_unref (task); + } +} + +/** + * gsound_context_play_fullv: (rename-to gsound_context_play_full) + * @context: A #GSoundContext + * @attrs: (element-type utf8 utf8): Attributes + * @cancellable: (allow-none): A #GCancellable, or %NULL + * @callback: (scope async): callback + * @user_data: user_data + * + * Asynchronously request a sound to be played. When playback is finished + * (or if an error occurs) then @callback will be called, following the + * normal GIO async pattern. + * + * If playback is cancelled via @cancellable, then @callback will be called + * with #G_IO_ERROR_CANCELLED. + * + * If you do not need notification of when playback is complete, you should + * use gsound_context_play_simple(). + * + * This function is intented to be used by language bindings. + */ +void +gsound_context_play_fullv (GSoundContext *self, + GHashTable *attrs, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GError *inner_error = NULL; + ca_proplist *proplist; + GTask *task; + int res; + + task = g_task_new (self, cancellable, callback, user_data); + + res = ca_proplist_create (&proplist); + if (!test_return (res, &inner_error)) + { + g_task_return_error (task, inner_error); + g_object_unref (task); + return; + } + + hash_table_to_prop_list (attrs, proplist); + + res = ca_context_play_full (self->ca, + g_direct_hash (cancellable), + proplist, + on_ca_play_full_finished, + task); + + if (cancellable) + g_cancellable_connect (cancellable, + G_CALLBACK (on_cancellable_cancelled), + g_object_ref (self), + g_object_unref); + + g_clear_pointer (&proplist, ca_proplist_destroy); + + if (!test_return (res, &inner_error)) + { + g_task_return_error (task, inner_error); + g_object_unref (task); + } +} + +/** + * gsound_context_play_full_finish: + * @context: A #GSoundContext + * @result: Result object passed to the callback of + * gsound_context_play_full() + * @error: Return location for error + * + * Finish an async operation started by gsound_context_play_full(). You + * must call this function in the callback to free memory and receive any + * errors which occurred. + * + * Returns: %TRUE if playing finished successfully + */ +gboolean +gsound_context_play_full_finish (GSoundContext *self, + GAsyncResult *result, + GError **error) +{ + g_return_val_if_fail (g_task_is_valid (result, self), FALSE); + + return g_task_propagate_boolean (G_TASK (result), error); +} + +/** + * gsound_context_cache: (skip) + * @context: A #GSoundContext + * @error: Return location for error + * @...: A %NULL-terminated list of attribute-value pairs + * + * Requests that a sound be cached on the server. See [#caching][gsound-GSound-Context#caching]. + * + * Returns: %TRUE on success + */ +gboolean +gsound_context_cache (GSoundContext *self, + GError **error, + ...) +{ + ca_proplist *pl; + va_list args; + int res; + + g_return_val_if_fail (GSOUND_IS_CONTEXT (self), FALSE); + + if ((res = ca_proplist_create (&pl)) != CA_SUCCESS) + return test_return (res, error); + + va_start (args, error); + var_args_to_prop_list (args, pl); + va_end (args); + + res = ca_context_cache_full (self->ca, pl); + + g_clear_pointer (&pl, ca_proplist_destroy); + + return test_return (res, error); +} + +/** + * gsound_context_cachev: (rename-to gsound_context_cache) + * @context: A #GSoundContext + * @attrs: (element-type utf8 utf8): Hash table of attrerties + * @error: Return location for error, or %NULL + * + * Requests that a sound be cached on the server. See [#caching][gsound-GSound-Context#caching]. + * + * This function is intented to be used by language bindings. + */ +gboolean +gsound_context_cachev (GSoundContext *self, + GHashTable *attrs, + GError **error) +{ + ca_proplist *proplist; + int res = ca_proplist_create (&proplist); + + if (!test_return (res, error)) + return FALSE; + + hash_table_to_prop_list (attrs, proplist); + + res = ca_context_cache_full (self->ca, proplist); + + g_clear_pointer (&proplist, ca_proplist_destroy); + + return test_return (res, error); +} + +static gboolean +gsound_context_real_init (GInitable *initable, + GCancellable *cancellable, + GError **error) +{ + GSoundContext *self = GSOUND_CONTEXT (initable); + int success; + ca_proplist *pl; + + if (self->ca) + return TRUE; + + success = ca_context_create (&self->ca); + + if (!test_return (success, error)) + return FALSE; + + /* Set a couple of attributes here if we can */ + ca_proplist_create (&pl); + + ca_proplist_sets (pl, CA_PROP_APPLICATION_NAME, g_get_application_name ()); + if (g_application_get_default ()) + { + GApplication *app = g_application_get_default (); + ca_proplist_sets (pl, CA_PROP_APPLICATION_ID, + g_application_get_application_id (app)); + } + + success = ca_context_change_props_full (self->ca, pl); + + g_clear_pointer (&pl, ca_proplist_destroy); + + if (!test_return (success, error)) + g_clear_pointer (&self->ca, ca_context_destroy); + + return TRUE; +} + +static void +gsound_context_finalize (GObject *obj) +{ + GSoundContext *self = GSOUND_CONTEXT (obj); + + g_clear_pointer (&self->ca, ca_context_destroy); + + G_OBJECT_CLASS (gsound_context_parent_class)->finalize (obj); +} + +static void +gsound_context_class_init (GSoundContextClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + + gobject_class->finalize = gsound_context_finalize; +} + +static void +gsound_context_init (GSoundContext *self) +{ +} + +static void +gsound_context_initable_init (GInitableIface *iface) +{ + iface->init = gsound_context_real_init; +} + diff --git a/.flatpak-builder/cache/objects/ee/2cd9eb42a64cee24eb25c25d12d3cdaf8193a3c2648e58d25627e543d2b4f3.file b/.flatpak-builder/cache/objects/ee/2cd9eb42a64cee24eb25c25d12d3cdaf8193a3c2648e58d25627e543d2b4f3.file new file mode 100644 index 0000000..31e7530 --- /dev/null +++ b/.flatpak-builder/cache/objects/ee/2cd9eb42a64cee24eb25c25d12d3cdaf8193a3c2648e58d25627e543d2b4f3.file @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2008 - 2012 Vivien Malerba + * Copyright (C) 2009 Murray Cumming + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef _GDA_STATEMENT_STRUCT_PSPEC_H +#define _GDA_STATEMENT_STRUCT_PSPEC_H + +#include +#include + +G_BEGIN_DECLS + +typedef struct _GdaSqlParamSpec GdaSqlParamSpec; + +/* + * Structure to hold one parameter specification + */ +struct _GdaSqlParamSpec +{ + gchar *name; + gchar *descr; + gboolean is_param; + gboolean nullok; + + GType g_type; + gpointer validity_meta_dict; /* to be replaced with a pointer to a structure representing a DBMS data type in GdaMetaStruct */ + + /* Padding for future expansion */ + gpointer _gda_reserved1; + gpointer _gda_reserved2; +}; +#define GDA_TYPE_SQL_PARAM_SPEC gda_sql_param_get_type() +GType gda_sql_param_spec_get_type(void) G_GNUC_CONST; + +GdaSqlParamSpec *gda_sql_param_spec_new (GValue *simple_spec); +GdaSqlParamSpec *gda_sql_param_spec_copy (GdaSqlParamSpec *pspec); +void gda_sql_param_spec_take_name (GdaSqlParamSpec *pspec, GValue *value); +void gda_sql_param_spec_take_type (GdaSqlParamSpec *pspec, GValue *value); +void gda_sql_param_spec_take_descr (GdaSqlParamSpec *pspec, GValue *value); +void gda_sql_param_spec_take_nullok(GdaSqlParamSpec *pspec, GValue *value); + +void gda_sql_param_spec_free (GdaSqlParamSpec *pspec); +gchar *gda_sql_param_spec_serialize (GdaSqlParamSpec *pspec); + +G_END_DECLS + +#endif diff --git a/.flatpak-builder/cache/objects/ee/7eb3a1dd55c269dc86216b82639d92ae21de5893f32b69057582ef9c533110.dirtree b/.flatpak-builder/cache/objects/ee/7eb3a1dd55c269dc86216b82639d92ae21de5893f32b69057582ef9c533110.dirtree new file mode 100644 index 0000000..525af4a Binary files /dev/null and b/.flatpak-builder/cache/objects/ee/7eb3a1dd55c269dc86216b82639d92ae21de5893f32b69057582ef9c533110.dirtree differ diff --git a/.flatpak-builder/cache/objects/ee/ced7914a57f42955c9db4309ad220c32d2505c064eaccd8d22c5a4b726b476.file b/.flatpak-builder/cache/objects/ee/ced7914a57f42955c9db4309ad220c32d2505c064eaccd8d22c5a4b726b476.file new file mode 100644 index 0000000..b44d631 --- /dev/null +++ b/.flatpak-builder/cache/objects/ee/ced7914a57f42955c9db4309ad220c32d2505c064eaccd8d22c5a4b726b476.file @@ -0,0 +1,406 @@ +# lsp.py +# +# Copyright 2021 James Westman +# +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation; either version 3 of the +# License, or (at your option) any later version. +# +# This file is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program. If not, see . +# +# SPDX-License-Identifier: LGPL-3.0-or-later + + +import typing as T +import json, sys, traceback + +from .completions import complete +from .errors import PrintableError, CompileError, MultipleErrors +from .lsp_utils import * +from .outputs.xml import XmlOutput +from . import tokenizer, parser, utils, xml_reader, decompiler + + +def printerr(*args, **kwargs): + print(*args, file=sys.stderr, **kwargs) + + +def command(json_method: str): + def decorator(func): + func._json_method = json_method + return func + + return decorator + + +class OpenFile: + def __init__(self, uri: str, text: str, version: int): + self.uri = uri + self.text = text + self.version = version + self.ast = None + self.tokens = None + + self._update() + + def apply_changes(self, changes): + for change in changes: + if "range" not in change: + self.text = change["text"] + continue + start = utils.pos_to_idx( + change["range"]["start"]["line"], + change["range"]["start"]["character"], + self.text, + ) + end = utils.pos_to_idx( + change["range"]["end"]["line"], + change["range"]["end"]["character"], + self.text, + ) + self.text = self.text[:start] + change["text"] + self.text[end:] + self._update() + + def _update(self): + self.diagnostics = [] + try: + self.tokens = tokenizer.tokenize(self.text) + self.ast, errors, warnings = parser.parse(self.tokens) + self.diagnostics += warnings + if errors is not None: + self.diagnostics += errors.errors + except MultipleErrors as e: + self.diagnostics += e.errors + except CompileError as e: + self.diagnostics.append(e) + + def calc_semantic_tokens(self) -> T.List[int]: + if self.ast is None: + return [] + + tokens = list(self.ast.get_semantic_tokens()) + token_lists = [ + [ + *utils.idx_to_pos(token.start, self.text), # line and column + token.end - token.start, # length + token.type, + 0, # token modifiers + ] + for token in tokens + ] + + # convert line, column numbers to deltas + for i, token_list in enumerate(token_lists[1:]): + token_list[0] -= token_lists[i][0] + if token_list[0] == 0: + token_list[1] -= token_lists[i][1] + + # flatten the list + return [x for y in token_lists for x in y] + + +class LanguageServer: + commands: T.Dict[str, T.Callable] = {} + + def __init__(self): + self.client_capabilities = {} + self._open_files: T.Dict[str, OpenFile] = {} + + def run(self): + # Read tags from gir files. During normal compilation these are + # ignored. + xml_reader.PARSE_GIR.add("doc") + + try: + while True: + line = "" + content_len = -1 + while content_len == -1 or (line != "\n" and line != "\r\n"): + line = sys.stdin.buffer.readline().decode() + if line == "": + return + if line.startswith("Content-Length:"): + content_len = int(line.split("Content-Length:")[1].strip()) + line = sys.stdin.buffer.read(content_len).decode() + printerr("input: " + line) + + data = json.loads(line) + method = data.get("method") + id = data.get("id") + params = data.get("params") + + if method in self.commands: + self.commands[method](self, id, params) + except Exception as e: + printerr(traceback.format_exc()) + + def _send(self, data): + data["jsonrpc"] = "2.0" + line = json.dumps(data, separators=(",", ":")) + "\r\n" + printerr("output: " + line) + sys.stdout.write( + f"Content-Length: {len(line.encode())}\r\nContent-Type: application/vscode-jsonrpc; charset=utf-8\r\n\r\n{line}" + ) + sys.stdout.flush() + + def _send_error(self, id, code, message, data=None): + self._send( + { + "id": id, + "error": { + "code": code, + "message": message, + "data": data, + }, + } + ) + + def _send_response(self, id, result): + self._send( + { + "id": id, + "result": result, + } + ) + + def _send_notification(self, method, params): + self._send( + { + "method": method, + "params": params, + } + ) + + @command("initialize") + def initialize(self, id, params): + from . import main + + self.client_capabilities = params.get("capabilities", {}) + self._send_response( + id, + { + "capabilities": { + "textDocumentSync": { + "openClose": True, + "change": TextDocumentSyncKind.Incremental, + }, + "semanticTokensProvider": { + "legend": { + "tokenTypes": ["enumMember"], + }, + "full": True, + }, + "completionProvider": {}, + "codeActionProvider": {}, + "hoverProvider": True, + }, + "serverInfo": { + "name": "Blueprint", + "version": main.VERSION, + }, + }, + ) + + @command("textDocument/didOpen") + def didOpen(self, id, params): + doc = params.get("textDocument") + uri = doc.get("uri") + version = doc.get("version") + text = doc.get("text") + + open_file = OpenFile(uri, text, version) + self._open_files[uri] = open_file + self._send_file_updates(open_file) + + @command("textDocument/didChange") + def didChange(self, id, params): + if params is not None: + open_file = self._open_files[params["textDocument"]["uri"]] + open_file.apply_changes(params["contentChanges"]) + self._send_file_updates(open_file) + + @command("textDocument/didClose") + def didClose(self, id, params): + del self._open_files[params["textDocument"]["uri"]] + + @command("textDocument/hover") + def hover(self, id, params): + open_file = self._open_files[params["textDocument"]["uri"]] + docs = open_file.ast and open_file.ast.get_docs( + utils.pos_to_idx( + params["position"]["line"], + params["position"]["character"], + open_file.text, + ) + ) + if docs: + self._send_response( + id, + { + "contents": { + "kind": "markdown", + "value": docs, + } + }, + ) + else: + self._send_response(id, None) + + @command("textDocument/completion") + def completion(self, id, params): + open_file = self._open_files[params["textDocument"]["uri"]] + + if open_file.ast is None: + self._send_response(id, []) + return + + idx = utils.pos_to_idx( + params["position"]["line"], params["position"]["character"], open_file.text + ) + completions = complete(open_file.ast, open_file.tokens, idx) + self._send_response( + id, [completion.to_json(True) for completion in completions] + ) + + @command("textDocument/x-blueprint-compile") + def compile(self, id, params): + open_file = self._open_files[params["textDocument"]["uri"]] + + if open_file.ast is None: + self._send_error(id, ErrorCode.RequestFailed, "Document is not open") + return + + xml = None + try: + output = XmlOutput() + xml = output.emit(open_file.ast) + except: + printerr(traceback.format_exc()) + self._send_error(id, ErrorCode.RequestFailed, "Could not compile document") + return + self._send_response(id, {"xml": xml}) + + @command("x-blueprint/decompile") + def decompile(self, id, params): + text = params.get("text") + blp = None + + try: + blp = decompiler.decompile_string(text) + except decompiler.UnsupportedError as e: + self._send_error(id, ErrorCode.RequestFailed, e.message) + return + except: + printerr(traceback.format_exc()) + self._send_error(id, ErrorCode.RequestFailed, "Invalid input") + return + + self._send_response(id, {"blp": blp}) + + @command("textDocument/semanticTokens/full") + def semantic_tokens(self, id, params): + open_file = self._open_files[params["textDocument"]["uri"]] + + self._send_response( + id, + { + "data": open_file.calc_semantic_tokens(), + }, + ) + + @command("textDocument/codeAction") + def code_actions(self, id, params): + open_file = self._open_files[params["textDocument"]["uri"]] + + range_start = utils.pos_to_idx( + params["range"]["start"]["line"], + params["range"]["start"]["character"], + open_file.text, + ) + range_end = utils.pos_to_idx( + params["range"]["end"]["line"], + params["range"]["end"]["character"], + open_file.text, + ) + + actions = [ + { + "title": action.title, + "kind": "quickfix", + "diagnostics": [ + self._create_diagnostic(open_file.text, open_file.uri, diagnostic) + ], + "edit": { + "changes": { + open_file.uri: [ + { + "range": utils.idxs_to_range( + diagnostic.start, diagnostic.end, open_file.text + ), + "newText": action.replace_with, + } + ] + } + }, + } + for diagnostic in open_file.diagnostics + if not (diagnostic.end < range_start or diagnostic.start > range_end) + for action in diagnostic.actions + ] + + self._send_response(id, actions) + + def _send_file_updates(self, open_file: OpenFile): + self._send_notification( + "textDocument/publishDiagnostics", + { + "uri": open_file.uri, + "diagnostics": [ + self._create_diagnostic(open_file.text, open_file.uri, err) + for err in open_file.diagnostics + ], + }, + ) + + def _create_diagnostic(self, text: str, uri: str, err: CompileError): + message = err.message + + assert err.start is not None and err.end is not None + + for hint in err.hints: + message += "\nhint: " + hint + + result = { + "range": utils.idxs_to_range(err.start, err.end, text), + "message": message, + "severity": DiagnosticSeverity.Warning + if isinstance(err, CompileWarning) + else DiagnosticSeverity.Error, + } + + if len(err.references) > 0: + result["relatedInformation"] = [ + { + "location": { + "uri": uri, + "range": utils.idxs_to_range(ref.start, ref.end, text), + }, + "message": ref.message, + } + for ref in err.references + ] + + return result + + +for name in dir(LanguageServer): + item = getattr(LanguageServer, name) + if callable(item) and hasattr(item, "_json_method"): + LanguageServer.commands[item._json_method] = item diff --git a/.flatpak-builder/cache/objects/ee/cede6c1a181da1d1dfed7b05dac5a41adf0acf5a9a93c3ae294dfde2a7d2bc.dirtree b/.flatpak-builder/cache/objects/ee/cede6c1a181da1d1dfed7b05dac5a41adf0acf5a9a93c3ae294dfde2a7d2bc.dirtree new file mode 100644 index 0000000..2143a7c Binary files /dev/null and b/.flatpak-builder/cache/objects/ee/cede6c1a181da1d1dfed7b05dac5a41adf0acf5a9a93c3ae294dfde2a7d2bc.dirtree differ diff --git a/.flatpak-builder/cache/objects/ee/d1d1a12c68d1338fce2924126b711cafa8c327adfca5907b30cc1c76d44e23.file b/.flatpak-builder/cache/objects/ee/d1d1a12c68d1338fce2924126b711cafa8c327adfca5907b30cc1c76d44e23.file new file mode 100644 index 0000000..8902e49 --- /dev/null +++ b/.flatpak-builder/cache/objects/ee/d1d1a12c68d1338fce2924126b711cafa8c327adfca5907b30cc1c76d44e23.file @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.flatpak-builder/cache/objects/ee/e7a50fe3c43d3edf30397c5cdeb4ac6491a95597729ac4e8338b2c883f04f0.file b/.flatpak-builder/cache/objects/ee/e7a50fe3c43d3edf30397c5cdeb4ac6491a95597729ac4e8338b2c883f04f0.file new file mode 100644 index 0000000..04f48d5 --- /dev/null +++ b/.flatpak-builder/cache/objects/ee/e7a50fe3c43d3edf30397c5cdeb4ac6491a95597729ac4e8338b2c883f04f0.file @@ -0,0 +1,4099 @@ +/* + * Copyright (C) 2008 - 2009 Bas Driessen + * Copyright (C) 2008 - 2011 Murray Cumming + * Copyright (C) 2008 - 2014 Vivien Malerba + * Copyright (C) 2010 David King + * Copyright (C) 2010 Jonh Wendell + * Copyright (C) 2013 Miguel Angel Cabrera Moya + * Copyright (C) 2012,2018-2019 Daniel Espinosa + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +#define G_LOG_DOMAIN "GDA-data-select" + +#undef GDA_DISABLE_DEPRECATED +#include +#include +#include +#include +#include +#include +#include "gda-data-select.h" +#include "providers-support/gda-data-select-priv.h" +#include "gda-data-select-extra.h" +#include "gda-row.h" +#include "providers-support/gda-pstmt.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include /* for gda_server_provider_get_real_main_context () */ + +#define CLASS(x) (GDA_DATA_SELECT_CLASS (G_OBJECT_GET_CLASS (x))) + +typedef struct { + GdaStatement *select; + GdaSet *params; + GdaRow *row; /* non NULL once @select has been executed */ + GError *exec_error; /* NULL if an execution error occurred */ +} DelayedSelectStmt; + +static void delayed_select_stmt_free (DelayedSelectStmt *dstmt); + +/* + * To go from an "external" row number to an "internal" row number and then to a GdaRow, + * the following steps are required: + * - use @del_rows to determine if the row has been removed (if it's in the array), and otherwise + * get an "internal" row number + * - use the @upd_rows index to see if the row has been modified, and if it has, then use + * the associated DelayedSelectStmt to retrieve the GdaRow + * - use the virtual methods to actually retrieve the requested GdaRow + */ +static gint external_to_internal_row (GdaDataSelect *model, gint ext_row, GError **error); + +typedef struct { + GSList *columns; /* list of GdaColumn objects */ + GPtrArray *rows; /* Array of GdaRow pointers */ + GHashTable *index; /* key = model row number, value = index in @rows array*/ + + /* Internal iterator's information, if GDA_DATA_MODEL_CURSOR_* based access */ + gint iter_row; /* G_MININT if at start, G_MAXINT if at end, "external" row number */ + + GdaStatement *sel_stmt; + GdaSet *ext_params; + GdaDataModelAccessFlags usage_flags; + + /* attributes specific to data model modifications */ + GdaDataSelectInternals *modif_internals; + + /* Global overriding data when the data model has been modified */ + GArray *del_rows; /* array[index] = number of the index'th deleted row, + * sorted by row number (row numbers are internal row numbers )*/ + GHashTable *upd_rows; /* key = internal row number + 1, value = a DelayedSelectStmt pointer */ + + gboolean notify_changes; + gboolean ref_count; /* when drop to 0 => free can be done */ + + /* data used to re-sync iter */ + GdaRow *current_prow; + gint current_prow_row; +} PrivateShareable; + + +/* GdaDataModel interface */ +static void gda_data_select_data_model_init (GdaDataModelInterface *iface); +static gint gda_data_select_get_n_rows (GdaDataModel *model); +static gint gda_data_select_get_n_columns (GdaDataModel *model); +static GdaColumn *gda_data_select_describe_column (GdaDataModel *model, gint col); +static GdaDataModelAccessFlags gda_data_select_get_access_flags(GdaDataModel *model); +static const GValue *gda_data_select_get_value_at (GdaDataModel *model, gint col, gint row, GError **error); +static GdaValueAttribute gda_data_select_get_attributes_at (GdaDataModel *model, gint col, gint row); + +static GdaDataModelIter *gda_data_select_create_iter (GdaDataModel *model); +static gboolean gda_data_select_iter_next (GdaDataModel *model, GdaDataModelIter *iter); +static gboolean gda_data_select_iter_prev (GdaDataModel *model, GdaDataModelIter *iter); +static gboolean gda_data_select_iter_at_row (GdaDataModel *model, GdaDataModelIter *iter, gint row); + +static gboolean gda_data_select_set_value_at (GdaDataModel *model, gint col, gint row, + const GValue *value, GError **error); +static gboolean gda_data_select_set_values (GdaDataModel *model, gint row, GList *values, + GError **error); +static gint gda_data_select_append_values (GdaDataModel *model, const GList *values, GError **error); +static gboolean gda_data_select_remove_row (GdaDataModel *model, gint row, GError **error); + +static void gda_data_select_freeze (GdaDataModel *model); +static void gda_data_select_thaw (GdaDataModel *model); +static gboolean gda_data_select_get_notify (GdaDataModel *model); +static GError **gda_data_select_get_exceptions (GdaDataModel *model); + + +/* + * Getting a GdaRow from a model row: + * [model row] ==(model->index)==> [index in model->rows] ==(model->rows)==> [GdaRow pointer] + */ +typedef struct { + GdaConnection *cnc; + GdaWorker *worker; + GdaDataModelIter *iter; + GPtrArray *exceptions; /* array of #GError pointers */ + PrivateShareable *sh; + gulong ext_params_changed_sig_id; + gdouble exec_time; + GdaPStmt *prep_stmt; /* use the "prepared-stmt" property to set this */ + gint nb_stored_rows; /* number of GdaRow objects currently stored */ + gint advertized_nrows; /* set when the number of rows becomes known, -1 until then */ +} GdaDataSelectPrivate; + +G_DEFINE_TYPE_WITH_CODE (GdaDataSelect, gda_data_select, G_TYPE_OBJECT, + G_ADD_PRIVATE (GdaDataSelect) + G_IMPLEMENT_INTERFACE (GDA_TYPE_DATA_MODEL, gda_data_select_data_model_init)) + +/* properties */ +enum +{ + PROP_0, + PROP_CNC, + PROP_PREP_STMT, + PROP_FLAGS, + PROP_ALL_STORED, + PROP_PARAMS, + PROP_INS_QUERY, + PROP_UPD_QUERY, + PROP_DEL_QUERY, + PROP_SEL_STMT, + PROP_EXEC_DELAY +}; + +/* API to handle using a GdaWorker */ +static gint _gda_data_select_fetch_nb_rows (GdaDataSelect *model); +static gboolean _gda_data_select_fetch_random (GdaDataSelect *model, GdaRow **prow, gint rownum, GError **error); +static gboolean _gda_data_select_store_all (GdaDataSelect *model, GError **error); +static gboolean _gda_data_select_fetch_next (GdaDataSelect *model, GdaRow **prow, gint rownum, GError **error); +static gboolean _gda_data_select_fetch_prev (GdaDataSelect *model, GdaRow **prow, gint rownum, GError **error); +static gboolean _gda_data_select_fetch_at (GdaDataSelect *model, GdaRow **prow, gint rownum, GError **error); + +/* module error */ +GQuark gda_data_select_error_quark (void) +{ + static GQuark quark; + if (!quark) + quark = g_quark_from_static_string ("gda_data_select_error"); + return quark; +} + +static void gda_data_select_class_init (GdaDataSelectClass *klass); +static void gda_data_select_dispose (GObject *object); +static void gda_data_select_finalize (GObject *object); + +static void gda_data_select_set_property (GObject *object, + guint param_id, + const GValue *value, + GParamSpec *pspec); +static void gda_data_select_get_property (GObject *object, + guint param_id, + GValue *value, + GParamSpec *pspec); + +/* utility functions */ +typedef struct { + gint size; /* number of elements in the @data array */ + guchar *data; /* data[0] to data[@size-1] are valid */ +} BVector; +static GdaStatement *check_acceptable_statement (GdaDataSelect *model, GError **error); +static GdaStatement *compute_single_update_stmt (GdaDataSelect *model, BVector *bv, GError **error); +static GdaStatement *compute_single_insert_stmt (GdaDataSelect *model, BVector *bv, GError **error); +static GdaStatement *compute_single_select_stmt (GdaDataSelect *model, GError **error); +static gint *compute_insert_select_params_mapping (GdaSet *sel_params, GdaSet *ins_values, GdaSqlExpr *row_cond); + +static gboolean check_data_model_for_updates (GdaDataSelect *imodel, + gint col, + const GValue *value, + GError **error); +static gboolean vector_set_value_at (GdaDataSelect *imodel, BVector *bv, + GdaDataModelIter *iter, gint row, + GError **error); + + +G_DEFINE_TYPE(GdaDataSelectIter, gda_data_select_iter, GDA_TYPE_DATA_MODEL_ITER) + +static gboolean gda_data_select_iter_move_to_row (GdaDataModelIter *iter, gint row); +static gboolean gda_data_select_iter_move_next (GdaDataModelIter *iter); +static gboolean gda_data_select_iter_move_prev (GdaDataModelIter *iter); +static gboolean gda_data_select_iter_set_value_at (GdaDataModelIter *iter, gint col, + const GValue *value, GError **error); + +static void gda_data_select_iter_init (GdaDataSelectIter *iter) {} +static void gda_data_select_iter_class_init (GdaDataSelectIterClass *klass) { + GdaDataModelIterClass *model_iter_class = GDA_DATA_MODEL_ITER_CLASS (klass); + model_iter_class->move_to_row = gda_data_select_iter_move_to_row; + model_iter_class->move_next = gda_data_select_iter_move_next; + model_iter_class->move_prev = gda_data_select_iter_move_prev; + model_iter_class->set_value_at = gda_data_select_iter_set_value_at; +} + +static gboolean +gda_data_select_iter_move_to_row (GdaDataModelIter *iter, gint row) { + GdaDataModel *model; + g_object_get (G_OBJECT (iter), "data-model", &model, NULL); + g_return_val_if_fail (model, FALSE); + return gda_data_select_iter_at_row (model, iter, row); +} + +static gboolean +gda_data_select_iter_move_next (GdaDataModelIter *iter) { + GdaDataModel *model; + g_object_get (G_OBJECT (iter), "data-model", &model, NULL); + g_return_val_if_fail (model, FALSE); + return gda_data_select_iter_next (model, iter); +} + +static gboolean +gda_data_select_iter_move_prev (GdaDataModelIter *iter) { + GdaDataModel *model; + g_object_get (G_OBJECT (iter), "data-model", &model, NULL); + g_return_val_if_fail (model, FALSE); + return gda_data_select_iter_prev (model, iter); +} + +static gboolean +gda_data_select_iter_set_value_at (GdaDataModelIter *iter, gint col, + const GValue *value, GError **error) +{ + GdaDataSelect *imodel; + + g_object_get (G_OBJECT (iter), "data-model", &imodel, NULL); + g_return_val_if_fail (imodel, FALSE); + g_return_val_if_fail (GDA_IS_DATA_MODEL (imodel), FALSE); + + if (!check_data_model_for_updates (imodel, col, value, error)) { + return FALSE; + } + + /* BVector */ + BVector *bv; + bv = g_new (BVector, 1); + bv->size = col + 1; + bv->data = g_new0 (guchar, bv->size); + bv->data[col] = 1; + + return vector_set_value_at (imodel, bv, iter, G_MININT, error); +} + +static void +gda_data_select_class_init (GdaDataSelectClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + /* properties */ + object_class->set_property = gda_data_select_set_property; + object_class->get_property = gda_data_select_get_property; + g_object_class_install_property (object_class, PROP_CNC, + g_param_spec_object ("connection", NULL, + "Connection from which this data model is created", + GDA_TYPE_CONNECTION, + G_PARAM_WRITABLE | G_PARAM_READABLE | G_PARAM_CONSTRUCT_ONLY)); + g_object_class_install_property (object_class, PROP_PREP_STMT, + g_param_spec_object ("prepared-stmt", NULL, + "Associated prepared statement (for internal usage)", + GDA_TYPE_PSTMT, + G_PARAM_WRITABLE | G_PARAM_READABLE)); + g_object_class_install_property (object_class, PROP_FLAGS, + g_param_spec_uint ("model-usage", NULL, + "Determines how the data model may be used", + GDA_DATA_MODEL_ACCESS_RANDOM, G_MAXUINT, + GDA_DATA_MODEL_ACCESS_RANDOM, + G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)); + g_object_class_install_property (object_class, PROP_ALL_STORED, + g_param_spec_boolean ("store-all-rows", "Store all the rows", + "Tells if model has analyzed all the rows", FALSE, + G_PARAM_READABLE | G_PARAM_WRITABLE)); + g_object_class_install_property (object_class, PROP_PARAMS, + g_param_spec_object ("exec-params", NULL, + "GdaSet used when the SELECT statement was executed", + GDA_TYPE_SET, + G_PARAM_WRITABLE | G_PARAM_READABLE | G_PARAM_CONSTRUCT_ONLY)); + g_object_class_install_property (object_class, PROP_INS_QUERY, + g_param_spec_object ("insert-stmt", "INSERT statement", + "INSERT Statement to be executed to add data", + GDA_TYPE_STATEMENT, + G_PARAM_READABLE | G_PARAM_WRITABLE)); + + g_object_class_install_property (object_class, PROP_UPD_QUERY, + g_param_spec_object ("update-stmt", "UPDATE statement", + "UPDATE Statement to be executed to update data", + GDA_TYPE_STATEMENT, + G_PARAM_READABLE | G_PARAM_WRITABLE)); + + g_object_class_install_property (object_class, PROP_DEL_QUERY, + g_param_spec_object ("delete-stmt", "DELETE statement", + "DELETE Statement to be executed to remove data", + GDA_TYPE_STATEMENT, + G_PARAM_READABLE | G_PARAM_WRITABLE)); + + g_object_class_install_property (object_class, PROP_SEL_STMT, + g_param_spec_object ("select-stmt", "SELECT statement", + "SELECT statement which was executed to yield to the data model", + GDA_TYPE_STATEMENT, G_PARAM_READABLE)); + + /** + * GdaDataSelect:execution-delay: + * + * This property stores the execution delay which has been necessary to obtain the data + * + * Since: 4.2.9 + */ + g_object_class_install_property (object_class, PROP_EXEC_DELAY, + g_param_spec_double ("execution-delay", NULL, NULL, + 0., G_MAXDOUBLE, 0., + G_PARAM_READABLE | G_PARAM_WRITABLE)); + + /* virtual functions */ + object_class->dispose = gda_data_select_dispose; + object_class->finalize = gda_data_select_finalize; +} + +static void +gda_data_select_data_model_init (GdaDataModelInterface *iface) +{ + iface->get_n_rows = gda_data_select_get_n_rows; + iface->get_n_columns = gda_data_select_get_n_columns; + iface->describe_column = gda_data_select_describe_column; + iface->get_access_flags = gda_data_select_get_access_flags; + iface->get_value_at = gda_data_select_get_value_at; + iface->get_attributes_at = gda_data_select_get_attributes_at; + + iface->create_iter = gda_data_select_create_iter; + + iface->set_value_at = gda_data_select_set_value_at; + iface->set_values = gda_data_select_set_values; + iface->append_values = gda_data_select_append_values; + iface->append_row = NULL; + iface->remove_row = gda_data_select_remove_row; + iface->find_row = NULL; + + iface->freeze = gda_data_select_freeze; + iface->thaw = gda_data_select_thaw; + iface->get_notify = gda_data_select_get_notify; + iface->send_hint = NULL; + + iface->get_exceptions = gda_data_select_get_exceptions; +} + +static void +gda_data_select_init (GdaDataSelect *model) +{ + ModType i; + GdaDataSelectPrivate *priv = gda_data_select_get_instance_private (model); + + priv->cnc = NULL; + priv->worker = NULL; + priv->exceptions = NULL; + priv->sh = g_new0 (PrivateShareable, 1); + priv->sh-> notify_changes = TRUE; + priv->sh->rows = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); + priv->sh->index = g_hash_table_new_full (g_int_hash, g_int_equal, g_free, NULL); + priv->prep_stmt = NULL; + priv->sh->columns = NULL; + priv->nb_stored_rows = 0; + priv->advertized_nrows = -1; /* unknown number of rows */ + + priv->sh->sel_stmt = NULL; + priv->sh->ext_params = NULL; + + priv->sh->iter_row = G_MININT; + priv->ext_params_changed_sig_id = 0; + priv->iter = NULL; + + priv->sh->modif_internals = g_new0 (GdaDataSelectInternals, 1); + priv->sh->modif_internals->safely_locked = FALSE; + priv->sh->modif_internals->unique_row_condition = NULL; + priv->sh->modif_internals->insert_to_select_mapping = NULL; + priv->sh->modif_internals->modif_set = NULL; + priv->sh->modif_internals->exec_set = NULL; + for (i = FIRST_QUERY; i < NB_QUERIES; i++) { + priv->sh->modif_internals->modif_params[i] = NULL; + priv->sh->modif_internals->modif_stmts[i] = NULL; + priv->sh->modif_internals->cols_mod[i] = NULL; + } + priv->sh->modif_internals->upd_stmts = NULL; + priv->sh->modif_internals->ins_stmts = NULL; + priv->sh->modif_internals->one_row_select_stmt = NULL; + + priv->sh->upd_rows = NULL; + priv->sh->del_rows = NULL; + + priv->sh->ref_count = 1; + + priv->sh->current_prow = NULL; + priv->sh->current_prow_row = -1; +} + + +static void +free_private_shared_data (GdaDataSelect *model) +{ + GdaDataSelectPrivate *priv = gda_data_select_get_instance_private (model); + if (priv->sh == NULL) + return; + + priv->sh->ref_count --; + if (priv->sh->ref_count == 0) { + + if (priv->sh->sel_stmt) { + g_object_unref (priv->sh->sel_stmt); + priv->sh->sel_stmt = NULL; + } + + if (priv->sh->ext_params) { + if (priv->ext_params_changed_sig_id) { + g_signal_handler_disconnect (priv->sh->ext_params, + priv->ext_params_changed_sig_id); + priv->ext_params_changed_sig_id = 0; + } + + g_object_unref (priv->sh->ext_params); + priv->sh->ext_params = NULL; + } + + if (priv->sh->modif_internals) { + _gda_data_select_internals_free (priv->sh->modif_internals); + priv->sh->modif_internals = NULL; + } + + if (priv->sh->upd_rows) { + g_hash_table_destroy (priv->sh->upd_rows); + priv->sh->upd_rows = NULL; + } + + if (priv->sh->del_rows) { + g_array_free (priv->sh->del_rows, TRUE); + priv->sh->del_rows = NULL; + } + if (priv->sh->rows) { + g_ptr_array_unref (priv->sh->rows); + priv->sh->rows = NULL; + } + if (priv->sh->index) { + g_hash_table_destroy (priv->sh->index); + priv->sh->index = NULL; + } + if (priv->sh->columns) { + g_slist_free_full (priv->sh->columns, (GDestroyNotify) g_object_unref); + priv->sh->columns = NULL; + } + + if (priv->sh->current_prow) { + g_object_unref (priv->sh->current_prow); + priv->sh->current_prow = NULL; + } + + g_free (priv->sh); + priv->sh = NULL; + } +} + +static void +gda_data_select_dispose (GObject *object) +{ + GdaDataSelect *model = (GdaDataSelect *) object; + GdaDataSelectPrivate *priv = gda_data_select_get_instance_private (model); + + /* free memory */ + if (priv) { + if (priv->exceptions) { + g_ptr_array_unref (priv->exceptions); + priv->exceptions = NULL; + } + if (priv->worker) { + gda_worker_unref (priv->worker); + priv->worker = NULL; + } + if (priv->iter) { + g_object_unref (priv->iter); + priv->iter = NULL; + } + if (priv->prep_stmt) { + g_object_unref (priv->prep_stmt); + priv->prep_stmt = NULL; + } + if (priv->ext_params_changed_sig_id) { + g_signal_handler_disconnect (priv->sh->ext_params, + priv->ext_params_changed_sig_id); + priv->ext_params_changed_sig_id = 0; + } + free_private_shared_data (model); + if (priv->cnc) { + g_object_unref (priv->cnc); + priv->cnc = NULL; + } + } + + /* chain to parent class */ + G_OBJECT_CLASS(gda_data_select_parent_class)->dispose (object); +} + +/* + * Allows 2 GdaDataSelect objects to safely share the same private data (PrivateShareable pointer). + * NOTE: nothing is done to prevent the master and the slave to modify the provate data at the same + * time: this must be done by the user implementing the GdaDataSelect objects. + * + * This API is used by the GdaThreadRecordset object + * + * On the master side (the one from which the private data is shared), nothing special happens, except + * that master->priv->sh->ref_count is increased by 1. + * + * On the slave side, what happens is: + * - "free" slave->priv->sh + * - slave->priv->sh = master->priv->sh + * FIXME: this features should be removed to improve thread safety + */ +void +_gda_data_select_share_private_data (GdaDataSelect *model, GdaDataSelect *slave) +{ + GdaDataSelectPrivate *priv = gda_data_select_get_instance_private (model); + GdaDataSelectPrivate *privs = gda_data_select_get_instance_private (slave); + priv->sh->ref_count ++; + free_private_shared_data (slave); + privs->sh = priv->sh; +} + + +void +_gda_data_select_internals_free (GdaDataSelectInternals *inter) +{ + g_return_if_fail (inter != NULL); + + ModType i; + + if (inter->unique_row_condition) { + gda_sql_expr_free (inter->unique_row_condition); + inter->unique_row_condition = NULL; + } + + if (inter->insert_to_select_mapping) { + g_free (inter->insert_to_select_mapping); + inter->insert_to_select_mapping = NULL; + } + + if (inter->modif_set) { + g_object_unref (inter->modif_set); + inter->modif_set = NULL; + } + for (i = 0; i < NB_QUERIES; i++) { + if (inter->modif_params [i]) { + g_slist_free (inter->modif_params [i]); + inter->modif_params [i] = NULL; + } + } + + if (inter->exec_set) { + g_object_unref (inter->exec_set); + inter->exec_set = NULL; + } + + for (i = FIRST_QUERY; i < NB_QUERIES; i++) { + if (inter->modif_stmts [i]) { + g_object_unref (inter->modif_stmts [i]); + inter->modif_stmts [i] = NULL; + } + if (inter->modif_params [i]) { + g_slist_free (inter->modif_params [i]); + inter->modif_params [i] = NULL; + } + g_free (inter->cols_mod[i]); + } + if (inter->upd_stmts) { + g_hash_table_destroy (inter->upd_stmts); + inter->upd_stmts = NULL; + } + if (inter->ins_stmts) { + g_hash_table_destroy (inter->ins_stmts); + inter->ins_stmts = NULL; + } + + if (inter->one_row_select_stmt) { + g_object_unref (inter->one_row_select_stmt); + inter->one_row_select_stmt = NULL; + } + + g_free (inter); +} + +static void +gda_data_select_finalize (GObject *object) +{ + /* chain to parent class */ + G_OBJECT_CLASS (gda_data_select_parent_class)->finalize (object); +} + +GdaDataSelectInternals * +_gda_data_select_internals_steal (GdaDataSelect *model) +{ + GdaDataSelectInternals *inter; + GdaDataSelectPrivate *priv = gda_data_select_get_instance_private (model); + inter = priv->sh->modif_internals; + priv->sh->modif_internals = NULL; + + return inter; +} + +void +_gda_data_select_internals_paste (GdaDataSelect *model, GdaDataSelectInternals *inter) +{ + GdaDataSelectPrivate *priv = gda_data_select_get_instance_private (model); + if (priv->sh->modif_internals) + _gda_data_select_internals_free (priv->sh->modif_internals); + priv->sh->modif_internals = inter; +} + +static void +create_columns (GdaDataSelect *model) +{ + GdaDataSelectPrivate *priv = gda_data_select_get_instance_private (model); + gint i; + ModType m; + if (priv->sh->columns) { + g_slist_free_full (priv->sh->columns, (GDestroyNotify) g_object_unref); + priv->sh->columns = NULL; + } + for (m = FIRST_QUERY; m < NB_QUERIES; m++) { + g_free (priv->sh->modif_internals->cols_mod[m]); + priv->sh->modif_internals->cols_mod[m] = NULL; + } + if (!priv->prep_stmt) + return; + + if (gda_pstmt_get_ncols (priv->prep_stmt) < 0) + g_error (_("INTERNAL implementation error: unknown number of columns in GdaPStmt, \nset number of columns before using with GdaDataSelect")); + if (gda_pstmt_get_tmpl_columns (priv->prep_stmt)) { + /* copy template columns */ + GSList *list; + for (list = gda_pstmt_get_tmpl_columns (priv->prep_stmt); list; list = list->next) + priv->sh->columns = g_slist_append (priv->sh->columns, g_object_ref (list->data)); + } + else { + /* create columns */ + for (i = 0; i < gda_pstmt_get_ncols (priv->prep_stmt); i++) { + GdaColumn *gda_col; + gda_col = gda_column_new (); + if (gda_pstmt_get_types (priv->prep_stmt)) + gda_column_set_g_type (gda_col, gda_pstmt_get_types (priv->prep_stmt) [i]); + priv->sh->columns = g_slist_append (priv->sh->columns, gda_col); + } + } +} + +static void +gda_data_select_set_property (GObject *object, + guint param_id, + const GValue *value, + GParamSpec *pspec) +{ + GdaDataSelectPrivate *priv = gda_data_select_get_instance_private (GDA_DATA_SELECT (object)); + if (priv) { + switch (param_id) { + case PROP_CNC: + priv->cnc = g_value_get_object (value); + if (priv->cnc) { + g_object_ref (priv->cnc); + priv->worker = _gda_connection_get_worker (priv->cnc); + g_assert (priv->worker); + gda_worker_ref (priv->worker); + } + break; + case PROP_PREP_STMT: + if (priv->prep_stmt) + g_object_unref (priv->prep_stmt); + priv->prep_stmt = g_value_get_object (value); + if (priv->prep_stmt) { + GdaStatement *sel_stmt; + g_object_ref (priv->prep_stmt); + sel_stmt = gda_pstmt_get_gda_statement (priv->prep_stmt); + if (sel_stmt && + gda_statement_get_statement_type (sel_stmt) == GDA_SQL_STATEMENT_SELECT) { + priv->sh->sel_stmt = gda_statement_copy (sel_stmt); + g_object_unref (sel_stmt); + } + } + create_columns (GDA_DATA_SELECT (object)); + break; + case PROP_FLAGS: { + GdaDataModelAccessFlags flags = g_value_get_uint (value); + if (!(flags & GDA_DATA_MODEL_ACCESS_RANDOM) && + (flags & GDA_DATA_MODEL_ACCESS_CURSOR_BACKWARD)) { + flags = GDA_DATA_MODEL_ACCESS_CURSOR; + } + priv->sh->usage_flags = flags; + } + break; + case PROP_ALL_STORED: + if (g_value_get_boolean (value)) + gda_data_select_prepare_for_offline (GDA_DATA_SELECT (object), NULL); + break; + case PROP_PARAMS: { + GdaSet *set; + set = g_value_get_object (value); + if (set) { + priv->sh->ext_params = g_object_ref (set); + priv->sh->modif_internals->exec_set = gda_set_copy (set); + } + break; + } + case PROP_INS_QUERY: + if (priv->sh->modif_internals->modif_stmts [INS_QUERY]) + g_object_unref (priv->sh->modif_internals->modif_stmts [INS_QUERY]); + priv->sh->modif_internals->modif_stmts [INS_QUERY] = g_value_get_object (value); + if (priv->sh->modif_internals->modif_stmts [INS_QUERY]) + g_object_ref (priv->sh->modif_internals->modif_stmts [INS_QUERY]); + g_free (priv->sh->modif_internals->cols_mod [INS_QUERY]); + priv->sh->modif_internals->cols_mod[INS_QUERY] = NULL; + break; + case PROP_DEL_QUERY: + if (priv->sh->modif_internals->modif_stmts [DEL_QUERY]) + g_object_unref (priv->sh->modif_internals->modif_stmts [DEL_QUERY]); + priv->sh->modif_internals->modif_stmts [DEL_QUERY] = g_value_get_object (value); + if (priv->sh->modif_internals->modif_stmts [DEL_QUERY]) + g_object_ref (priv->sh->modif_internals->modif_stmts [DEL_QUERY]); + g_free (priv->sh->modif_internals->cols_mod[DEL_QUERY]); + priv->sh->modif_internals->cols_mod[DEL_QUERY] = NULL; + break; + case PROP_UPD_QUERY: + if (priv->sh->modif_internals->modif_stmts [UPD_QUERY]) + g_object_unref (priv->sh->modif_internals->modif_stmts [UPD_QUERY]); + priv->sh->modif_internals->modif_stmts [UPD_QUERY] = g_value_get_object (value); + if (priv->sh->modif_internals->modif_stmts [UPD_QUERY]) + g_object_ref (priv->sh->modif_internals->modif_stmts [UPD_QUERY]); + g_free (priv->sh->modif_internals->cols_mod[UPD_QUERY]); + priv->sh->modif_internals->cols_mod[UPD_QUERY] = NULL; + break; + case PROP_EXEC_DELAY: + priv->exec_time = g_value_get_double (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + break; + } + } +} + +static void +gda_data_select_get_property (GObject *object, + guint param_id, + GValue *value, + GParamSpec *pspec) +{ + GdaDataSelect *model = (GdaDataSelect *) object; + GdaDataSelectPrivate *priv = gda_data_select_get_instance_private (model); + if (priv) { + switch (param_id) { + case PROP_CNC: + g_value_set_object (value, priv->cnc); + break; + case PROP_PREP_STMT: + g_value_set_object (value, priv->prep_stmt); + break; + case PROP_FLAGS: + g_value_set_uint (value, priv->sh->usage_flags); + break; + case PROP_ALL_STORED: + if (!(priv->sh->usage_flags & GDA_DATA_MODEL_ACCESS_RANDOM)) + g_warning ("Cannot set the 'store-all-rows' property when access mode is cursor based"); + else { + if ((priv->advertized_nrows < 0) && CLASS (model)->fetch_nb_rows) + _gda_data_select_fetch_nb_rows (model); + g_value_set_boolean (value, priv->nb_stored_rows == priv->advertized_nrows); + } + break; + case PROP_PARAMS: + g_value_set_object (value, priv->sh->modif_internals->exec_set); + break; + case PROP_INS_QUERY: + g_value_set_object (value, priv->sh->modif_internals->modif_stmts [INS_QUERY]); + break; + case PROP_DEL_QUERY: + g_value_set_object (value, priv->sh->modif_internals->modif_stmts [DEL_QUERY]); + break; + case PROP_UPD_QUERY: + g_value_set_object (value, priv->sh->modif_internals->modif_stmts [UPD_QUERY]); + break; + case PROP_SEL_STMT: + g_value_set_object (value, check_acceptable_statement (model, NULL)); + break; + case PROP_EXEC_DELAY: + g_value_set_double (value, priv->exec_time); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + break; + } + } +} + +/** + * gda_data_select_take_row: + * @model: a #GdaDataSelect data model + * @row: (transfer full): a #GdaRow row + * @rownum: "external" advertized row number + * + * Stores @row into @model, externally advertized at row number @rownum (if no row has been removed). + * The reference to @row is stolen. + * + * This function is used by database provider's implementations + */ +void +gda_data_select_take_row (GdaDataSelect *model, GdaRow *row, gint rownum) +{ + g_return_if_fail (GDA_IS_DATA_SELECT (model)); + g_return_if_fail (GDA_IS_ROW (row)); + GdaDataSelectPrivate *priv = gda_data_select_get_instance_private (model); + + gint tmp, *ptr; + GdaRow *erow; + g_return_if_fail (GDA_IS_DATA_SELECT (model)); + g_return_if_fail (GDA_IS_ROW (row)); + + tmp = rownum; + erow = g_hash_table_lookup (priv->sh->index, &tmp); + if (erow) { + if (row != erow) + g_object_unref (row); + return; + } + + ptr = g_new (gint, 2); + ptr [0] = rownum; + ptr [1] = priv->sh->rows->len; + g_hash_table_insert (priv->sh->index, ptr, ptr+1); + g_ptr_array_add (priv->sh->rows, row); + priv->nb_stored_rows = priv->sh->rows->len; +} + +/** + * gda_data_select_get_stored_row: + * @model: a #GdaDataSelect data model + * @rownum: "external" advertized row number + * + * Get the #GdaRow object stored within @model at row @rownum (without taking care of removed rows) + * + * Returns: (transfer none): the requested #GdaRow, or %NULL if not found + */ +GdaRow * +gda_data_select_get_stored_row (GdaDataSelect *model, gint rownum) +{ + gint irow, *ptr; + g_return_val_if_fail (GDA_IS_DATA_SELECT (model), NULL); + GdaDataSelectPrivate *priv = gda_data_select_get_instance_private (model); + + irow = rownum; + ptr = g_hash_table_lookup (priv->sh->index, &irow); + if (ptr) + return g_ptr_array_index (priv->sh->rows, *ptr); + else + return NULL; +} + +/** + * gda_data_select_get_connection: + * @model: a #GdaDataSelect data model + * + * Get a pointer to the #GdaConnection object which was used when @model was created + * (and which may be used internally by @model). + * + * Returns: (transfer none): a pointer to the #GdaConnection, or %NULL + */ +GdaConnection * +gda_data_select_get_connection (GdaDataSelect *model) +{ + g_return_val_if_fail (GDA_IS_DATA_SELECT (model), NULL); + GdaDataSelectPrivate *priv = gda_data_select_get_instance_private (model); + + return priv->cnc; +} + +/** + * gda_data_select_set_columns: + * @model: a #GdaDataSelect data model + * @columns: (transfer full): a lis of #GdaColumn objects + * + * Makes @columns the list of columns for @model. Both the list and each #GdaColumn object in the + * list are 'stolen' by @model (ie. when this function returns the caller should not use anymore + * the list or each column object in it). This method should not be used directly, it is used by + * database provider's implementations. + * + * Since: 4.2.1 + */ +void +gda_data_select_set_columns (GdaDataSelect *model, GSList *columns) +{ + ModType m; + g_return_if_fail (GDA_IS_DATA_SELECT (model)); + GdaDataSelectPrivate *priv = gda_data_select_get_instance_private (model); + + if (priv->sh->columns) { + g_slist_free_full (priv->sh->columns, (GDestroyNotify) g_object_unref); + priv->sh->columns = NULL; + } + for (m = FIRST_QUERY; m < NB_QUERIES; m++) { + g_free (priv->sh->modif_internals->cols_mod[m]); + priv->sh->modif_internals->cols_mod[m] = NULL; + } + priv->sh->columns = columns; +} + +/* + * Add the +/- holders to priv->sh->modif_internals->modif_set + */ +static gboolean +compute_modif_set (GdaDataSelect *model, GError **error) +{ + GdaDataSelectPrivate *priv = gda_data_select_get_instance_private (model); + gint i; + + if (priv->sh->modif_internals->modif_set) { + g_object_unref (priv->sh->modif_internals->modif_set); + priv->sh->modif_internals->modif_set = NULL; + } + if (priv->sh->modif_internals->exec_set) + priv->sh->modif_internals->modif_set = gda_set_copy (priv->sh->modif_internals->exec_set); + else + priv->sh->modif_internals->modif_set = gda_set_new (NULL); + + for (i = 0; i < NB_QUERIES; i++) { + if (priv->sh->modif_internals->modif_params [i]) { + g_slist_free (priv->sh->modif_internals->modif_params [i]); + priv->sh->modif_internals->modif_params [i] = NULL; + } + } + + for (i = 0; i < NB_QUERIES; i++) { + GdaSet *set; + if (! priv->sh->modif_internals->modif_stmts [i]) + continue; + if (! gda_statement_get_parameters (priv->sh->modif_internals->modif_stmts [i], &set, error)) { + g_object_unref (priv->sh->modif_internals->modif_set); + priv->sh->modif_internals->modif_set = NULL; + return FALSE; + } + + gda_set_merge_with_set (priv->sh->modif_internals->modif_set, set); + + GSList *list; + for (list = gda_set_get_holders (set); list; list = list->next) { + GdaHolder *holder; + holder = gda_set_get_holder (priv->sh->modif_internals->modif_set, + gda_holder_get_id ((GdaHolder*) list->data)); + priv->sh->modif_internals->modif_params [i] = + g_slist_prepend (priv->sh->modif_internals->modif_params [i], holder); + } + g_object_unref (set); + } + +#ifdef GDA_DEBUG_NO + GSList *list; + g_print ("-------\n"); + for (list = priv->sh->modif_internals->modif_set->holders; list; list = list->next) { + GdaHolder *h = GDA_HOLDER (list->data); + g_print ("=> holder '%s'\n", gda_holder_get_id (h)); + } + for (i = 0; i < NB_QUERIES; i++) { + g_print (" MOD %d\n", i); + for (list = priv->sh->modif_internals->modif_params [i]; list; list = list->next) { + GdaHolder *h = GDA_HOLDER (list->data); + g_print ("\t=> holder '%s'\n", gda_holder_get_id (h)); + } + } +#endif + + return TRUE; +} + +/* + * converts "[+-]" to and returns FALSE if @pname is not like + * "[+-]". is stored in @result, and the +/- signed is stored in @old_val + * (@old_val is set to TRUE if there is a "-") + */ +static gboolean +param_name_to_int (const gchar *pname, gint *result, gboolean *old_val) +{ + gint sum = 0; + const gchar *ptr; + + if (!pname || ((*pname != '-') && (*pname != '+'))) + return FALSE; + + ptr = pname + 1; + while (*ptr) { + if ((*ptr > '9') || (*ptr < '0')) + return FALSE; + sum = sum * 10 + *ptr - '0'; + ptr++; + } + + if (result) + *result = sum; + if (old_val) + *old_val = (*pname == '-') ? TRUE : FALSE; + + return TRUE; +} + +/** + * gda_data_select_set_modification_statement_sql: + * @model: a #GdaDataSelect data model + * @sql: an SQL text + * @error: (nullable): a place to store errors, or %NULL + * + * Offers the same feature as gda_data_select_set_modification_statement() but using an SQL statement. + * + * Returns: TRUE if no error occurred. + */ +gboolean +gda_data_select_set_modification_statement_sql (GdaDataSelect *model, const gchar *sql, GError **error) +{ + GdaSqlParser *parser; + GdaStatement *stmt; + const gchar *remain = NULL; + gboolean retval; + + g_return_val_if_fail (GDA_IS_DATA_SELECT (model), FALSE); + GdaDataSelectPrivate *priv = gda_data_select_get_instance_private (model); + + /* check the original SELECT statement which was executed is not a compound statement */ + if (! check_acceptable_statement (model, error)) + return FALSE; + + parser = gda_connection_create_parser (priv->cnc); + if (!parser) + parser = gda_sql_parser_new (); + + stmt = gda_sql_parser_parse_string (parser, sql, &remain, error); + g_object_unref (parser); + if (!stmt) + return FALSE; + if (remain) { + g_object_unref (stmt); + g_set_error (error, GDA_DATA_SELECT_ERROR, GDA_DATA_SELECT_SQL_ERROR, + "%s", _("Incorrect SQL expression, only one modification statement is accepted")); + return FALSE; + } + + retval = gda_data_select_set_modification_statement (model, stmt, error); + g_object_unref (stmt); + + return retval; +} + +/* + * Checks that the SELECT statement which created @model exists and is correct. + * + * Returns: the SELECT #GdaStatement, or %NULL if an error occurred. + */ +static GdaStatement * +check_acceptable_statement (GdaDataSelect *model, GError **error) +{ + GdaStatement *sel_stmt; + GdaDataSelectPrivate *priv = gda_data_select_get_instance_private (model); + + if (priv->sh->sel_stmt) + return priv->sh->sel_stmt; + + if (! priv->prep_stmt) { + g_set_error (error, GDA_DATA_SELECT_ERROR, GDA_DATA_SELECT_MODIFICATION_STATEMENT_ERROR, + "%s", _("Internal error: the \"prepared-stmt\" property has not been set")); + return NULL; + } + + sel_stmt = gda_pstmt_get_gda_statement (priv->prep_stmt); + if (! sel_stmt) { + g_set_error (error, GDA_DATA_SELECT_ERROR, GDA_DATA_SELECT_MODIFICATION_STATEMENT_ERROR, + "%s", _("Can't get the prepared statement's actual statement")); + return NULL; + } + + if (gda_statement_get_statement_type (sel_stmt) != GDA_SQL_STATEMENT_SELECT) { + g_set_error (error, GDA_DATA_SELECT_ERROR, GDA_DATA_SELECT_MODIFICATION_STATEMENT_ERROR, + "%s", _("Unsupported type of SELECT statement")); + return NULL; + } + + priv->sh->sel_stmt = gda_statement_copy (sel_stmt); + g_object_unref (sel_stmt); + return priv->sh->sel_stmt; +} + +/** + * gda_data_select_set_modification_statement: + * @model: a #GdaDataSelect data model + * @mod_stmt: a #GdaStatement (INSERT, UPDATE or DELETE) + * @error: (nullable): a place to store errors, or %NULL + * + * Informs @model that it should allow modifications to the data in some columns and some rows + * using @mod_stmt to propagate those modifications into the database. + * + * If @mod_stmt is: + * + * an UPDATE statement, then all the rows in @model will be writable + * a DELETE statement, then it will be possible to delete rows in @model + * in INSERT statement, then it will be possible to add some rows to @model + * any other statement, then this method will return an error + * + * + * This method can be called several times to specify different types of modification statements. + * + * Each modification statement will be executed when one or more values are modified in the data model; + * each statement should then include variables which will be set to either the old value or the + * new value of a column at the specified modified row (but can also contain other variables). Each variable + * named as "+<number>" will be mapped to the new value of the number'th column (starting at 0), and + * each variable named as "-<number>" will be mapped to the old value of the number'th column. + * + * Examples of the SQL equivalent of each statement are (for example if "mytable" has the "id" field as + * primary key, and if that field is auto incremented and if the data model is the result of + * executing ""). + * + * + * "": the column ID can not be set + * for new rows + * "" + * "": the column ID cannot be + * modified + * + * + * Also see the gda_data_select_set_row_selection_condition_sql() for more information about the WHERE + * part of the UPDATE and DELETE statement types. + * + * If @mod_stmt is an UPDATE or DELETE statement then it should have a WHERE part which identifies + * a unique row in @model (please note that this property can't be checked but may result + * in @model behaving in an unpredictable way). + * + * NOTE1: However, if the gda_data_select_set_row_selection_condition() + * or gda_data_select_set_row_selection_condition_sql() have been successfully be called before, the WHERE + * part of @mod_stmt WILL be modified to use the row selection condition specified through one of + * these methods (please not that it is then possible to avoid specifying a WHERE part in @mod_stmt then). + * + * NOTE2: if gda_data_select_set_row_selection_condition() + * or gda_data_select_set_row_selection_condition_sql() have not yet been successfully be called before, then + * the WHERE part of @mod_stmt will be used as if one of these functions had been called. + * + * Returns: %TRUE if no error occurred. + */ +gboolean +gda_data_select_set_modification_statement (GdaDataSelect *model, GdaStatement *mod_stmt, GError **error) +{ + ModType mtype = NB_QUERIES; + gboolean coltypeschanged = FALSE; + + g_return_val_if_fail (GDA_IS_DATA_SELECT (model), FALSE); + g_return_val_if_fail (GDA_IS_STATEMENT (mod_stmt), FALSE); + GdaDataSelectPrivate *priv = gda_data_select_get_instance_private (model); + + /* check the original SELECT statement which was executed is not a compound statement */ + if (! check_acceptable_statement (model, error)) + return FALSE; + + /* checks on the actual modification statement */ + switch (gda_statement_get_statement_type (mod_stmt)) { + case GDA_SQL_STATEMENT_INSERT: { + GdaSqlStatement *sqlst; + GdaSqlStatementInsert *ins; + + mtype = INS_QUERY; + + /* check that we have only one list of values (<=> only one row will be inserted) */ + g_object_get (G_OBJECT (mod_stmt), "structure", &sqlst, NULL); + g_assert (sqlst); + ins = (GdaSqlStatementInsert*) sqlst->contents; + if (!ins->values_list || ! ins->values_list->data) { + g_set_error (error, GDA_DATA_SELECT_ERROR, GDA_DATA_SELECT_MODIFICATION_STATEMENT_ERROR, + "%s", _("INSERT statement must contain values to insert")); + gda_sql_statement_free (sqlst); + return FALSE; + } + if (ins->values_list->next) { + g_set_error (error, GDA_DATA_SELECT_ERROR, GDA_DATA_SELECT_MODIFICATION_STATEMENT_ERROR, + "%s", _("INSERT statement must insert only one row")); + gda_sql_statement_free (sqlst); + return FALSE; + } + + gda_sql_statement_free (sqlst); + break; + } + case GDA_SQL_STATEMENT_DELETE: { + GdaSqlStatement *sqlst; + GdaSqlStatementDelete *del; + + mtype = DEL_QUERY; + + /* if there is no WHERE part, then use priv->sh->modif_internals->unique_row_condition if set */ + g_object_get (G_OBJECT (mod_stmt), "structure", &sqlst, NULL); + g_assert (sqlst); + del = (GdaSqlStatementDelete*) sqlst->contents; + if (!del->cond) { + if (priv->sh->modif_internals->unique_row_condition) { + /* copy priv->sh->modif_internals->unique_row_condition */ + del->cond = gda_sql_expr_copy (priv->sh->modif_internals->unique_row_condition); + GDA_SQL_ANY_PART (del->cond)->parent = GDA_SQL_ANY_PART (del); + g_object_set (G_OBJECT (mod_stmt), "structure", sqlst, NULL); + } + else { + g_set_error (error, GDA_DATA_SELECT_ERROR, GDA_DATA_SELECT_MODIFICATION_STATEMENT_ERROR, + "%s", _("DELETE statement must have a WHERE part")); + gda_sql_statement_free (sqlst); + return FALSE; + } + } + else { + if (priv->sh->modif_internals->unique_row_condition) { + /* replace WHERE with priv->sh->modif_internals->unique_row_condition */ + gda_sql_expr_free (del->cond); + del->cond = gda_sql_expr_copy (priv->sh->modif_internals->unique_row_condition); + GDA_SQL_ANY_PART (del->cond)->parent = GDA_SQL_ANY_PART (del); + g_object_set (G_OBJECT (mod_stmt), "structure", sqlst, NULL); + } + else if (! gda_data_select_set_row_selection_condition (model, del->cond, error)) { + gda_sql_statement_free (sqlst); + return FALSE; + } + } + gda_sql_statement_free (sqlst); + break; + } + case GDA_SQL_STATEMENT_UPDATE: { + GdaSqlStatement *sqlst; + GdaSqlStatementUpdate *upd; + + mtype = UPD_QUERY; + + /* if there is no WHERE part, then use priv->sh->modif_internals->unique_row_condition if set */ + g_object_get (G_OBJECT (mod_stmt), "structure", &sqlst, NULL); + g_assert (sqlst); + upd = (GdaSqlStatementUpdate*) sqlst->contents; + if (!upd->cond) { + if (priv->sh->modif_internals->unique_row_condition) { + /* copy priv->sh->modif_internals->unique_row_condition */ + upd->cond = gda_sql_expr_copy (priv->sh->modif_internals->unique_row_condition); + GDA_SQL_ANY_PART (upd->cond)->parent = GDA_SQL_ANY_PART (upd); + g_object_set (G_OBJECT (mod_stmt), "structure", sqlst, NULL); + } + else { + g_set_error (error, GDA_DATA_SELECT_ERROR, GDA_DATA_SELECT_MODIFICATION_STATEMENT_ERROR, + "%s", _("UPDATE statement must have a WHERE part")); + gda_sql_statement_free (sqlst); + return FALSE; + } + } + else { + if (priv->sh->modif_internals->unique_row_condition) { + /* replace WHERE with priv->sh->modif_internals->unique_row_condition */ + gda_sql_expr_free (upd->cond); + upd->cond = gda_sql_expr_copy (priv->sh->modif_internals->unique_row_condition); + GDA_SQL_ANY_PART (upd->cond)->parent = GDA_SQL_ANY_PART (upd); + g_object_set (G_OBJECT (mod_stmt), "structure", sqlst, NULL); + } + else if (! gda_data_select_set_row_selection_condition (model, upd->cond, error)) { + gda_sql_statement_free (sqlst); + return FALSE; + } + } + gda_sql_statement_free (sqlst); + break; + } + default: + break; + } + + if (mtype != NB_QUERIES) { + if (! gda_statement_check_structure (mod_stmt, error)) + return FALSE; + + /* check that all the parameters required to execute @mod_stmt are in + * priv->sh->modif_internals->modif_set */ + GdaSet *params; + GSList *list, *params_to_add = NULL; + if (! gda_statement_get_parameters (mod_stmt, ¶ms, error)) + return FALSE; + if (! priv->sh->modif_internals->modif_set) { + if (priv->sh->modif_internals->exec_set) + priv->sh->modif_internals->modif_set = gda_set_copy (priv->sh->modif_internals->exec_set); + else + priv->sh->modif_internals->modif_set = gda_set_new (NULL); + } + + for (list = gda_set_get_holders (params); list; list = list->next) { + GdaHolder *holder = GDA_HOLDER (list->data); + GdaHolder *eholder; + eholder = gda_set_get_holder (priv->sh->modif_internals->modif_set, + gda_holder_get_id (holder)); + if (!eholder) { + gint num; + gboolean is_old; + + if (!param_name_to_int (gda_holder_get_id (holder), &num, &is_old)) { + g_set_error (error, GDA_DATA_SELECT_ERROR, + GDA_DATA_SELECT_MODIFICATION_STATEMENT_ERROR, + _("Modification statement uses an unknown '%s' parameter"), + gda_holder_get_id (holder)); + g_object_unref (params); + if (params_to_add) + g_slist_free (params_to_add); + return FALSE; + } + if (num > gda_data_select_get_n_columns ((GdaDataModel*) model)) { + g_set_error (error, GDA_DATA_SELECT_ERROR, + GDA_DATA_SELECT_MISSING_MODIFICATION_STATEMENT_ERROR, + _("Column %d out of range (0-%d)"), num, + gda_data_select_get_n_columns ((GdaDataModel*) model)-1); + g_object_unref (params); + if (params_to_add) + g_slist_free (params_to_add); + return FALSE; + } + params_to_add = g_slist_prepend (params_to_add, holder); + } + else if (gda_holder_get_g_type (holder) != gda_holder_get_g_type (eholder)) { + g_set_error (error, GDA_DATA_SELECT_ERROR, + GDA_DATA_SELECT_MODIFICATION_STATEMENT_ERROR, + _("Modification statement's '%s' parameter is a %s when it should be a %s"), + gda_holder_get_id (holder), + gda_g_type_to_string (gda_holder_get_g_type (holder)), + gda_g_type_to_string (gda_holder_get_g_type (eholder))); + g_object_unref (params); + if (params_to_add) + g_slist_free (params_to_add); + return FALSE; + } + } + + /* update GdaDataSelect's column attributes with GdaHolder's attributes */ + for (list = gda_set_get_holders (params); list; list = list->next) { + GdaHolder *holder = GDA_HOLDER (list->data); + gint num; + gboolean is_old; + if (param_name_to_int (gda_holder_get_id (holder), &num, &is_old) && + !is_old) { + GdaColumn *gdacol; + gdacol = gda_data_model_describe_column ((GdaDataModel*) model, num); + if (!gdacol) + continue; + if (mtype == INS_QUERY) + gda_column_set_default_value (gdacol, + gda_holder_get_default_value (holder)); + if (gda_column_get_g_type (gdacol) == GDA_TYPE_NULL) { + gda_column_set_g_type (gdacol, gda_holder_get_g_type (holder)); + coltypeschanged = TRUE; + } + if (priv->prep_stmt && gda_pstmt_get_types (priv->prep_stmt) && + (gda_pstmt_get_types (priv->prep_stmt) [num] == GDA_TYPE_NULL)) + gda_pstmt_get_types (priv->prep_stmt) [num] = gda_holder_get_g_type (holder); + } + } + + /* all ok, accept the modif statement */ + if (priv->sh->modif_internals->modif_stmts[mtype]) { + g_object_unref (priv->sh->modif_internals->modif_stmts[mtype]); + priv->sh->modif_internals->modif_stmts[mtype] = NULL; + } + priv->sh->modif_internals->modif_stmts[mtype] = mod_stmt; + g_object_ref (mod_stmt); + ModType m; + for (m = FIRST_QUERY; m < NB_QUERIES; m++) { + g_free (priv->sh->modif_internals->cols_mod[m]); + priv->sh->modif_internals->cols_mod[m] = NULL; + } + + if (params_to_add) { + for (list = params_to_add; list; list = list->next) { + gda_set_add_holder (priv->sh->modif_internals->modif_set, + GDA_HOLDER (list->data)); + priv->sh->modif_internals->modif_params[mtype] = + g_slist_prepend (priv->sh->modif_internals->modif_params[mtype], + list->data); + } + g_slist_free (params_to_add); + } + g_object_unref (params); + + /* prepare priv->sh->modif_internals->modif_set */ + if (!compute_modif_set (model, error)) + return FALSE; + } + else { + g_set_error (error, GDA_DATA_SELECT_ERROR, GDA_DATA_SELECT_MODIFICATION_STATEMENT_ERROR, + "%s", _("Modification statement must be an INSERT, UPDATE or DELETE statement")); + return FALSE; + } + +#ifdef GDA_DEBUG_NO + GSList *hlist; + g_print ("SET MODIF QUERY\n"); + if (priv->sh->modif_internals->modif_set) { + for (hlist = priv->sh->modif_internals->modif_set->holders; hlist; + hlist = hlist->next) { + GdaHolder *h = GDA_HOLDER (hlist->data); + const GValue *defval; + defval = gda_holder_get_default_value (h); + g_print (" %s type=> %s (%d)", gda_holder_get_id (h), + g_type_name (gda_holder_get_g_type (h)), + gda_holder_get_g_type (h)); + if (defval) { + gchar *tmp; + tmp = gda_value_stringify (defval); + g_print (" defaults [%s]", tmp); + g_free (tmp); + } + g_print ("\n"); + } + } +#endif + + if (coltypeschanged) + gda_data_model_reset (GDA_DATA_MODEL (model)); + g_signal_emit_by_name (GDA_DATA_MODEL (model), "access-changed"); + + return TRUE; +} + +/** + * gda_data_select_compute_modification_statements: + * @model: a #GdaDataSelect data model + * @error: (nullable): a place to store errors, or %NULL + * + * Makes @model try to compute INSERT, UPDATE and DELETE statements to be used when modifying @model's contents. + * Note: any modification statement set using gda_data_select_set_modification_statement() will first be unset + * + * This function is similar to calling gda_data_select_compute_modification_statements_ext() with + * @cond_type set to %GDA_DATA_SELECT_COND_PK + * + * Returns: %TRUE if no error occurred. If %FALSE is returned, then some modification statement may still have been computed + */ +gboolean +gda_data_select_compute_modification_statements (GdaDataSelect *model, GError **error) +{ + return gda_data_select_compute_modification_statements_ext (model, GDA_DATA_SELECT_COND_PK, + error); +} + +/** + * gda_data_select_compute_modification_statements_ext: + * @model: a #GdaDataSelect data model + * @cond_type: the type of condition for the modifications where one row only should be identified + * @error: (nullable): a place to store errors, or %NULL + * + * Makes @model try to compute INSERT, UPDATE and DELETE statements to be used when modifying @model's contents. + * Note: any modification statement set using gda_data_select_set_modification_statement() will first be unset + * + * Returns: %TRUE if no error occurred. If %FALSE is returned, then some modification statement may still have been computed + * + * Since: 4.2.9 + */ +gboolean +gda_data_select_compute_modification_statements_ext (GdaDataSelect *model, + GdaDataSelectConditionType cond_type, + GError **error) +{ + GdaStatement *stmt; + ModType mtype; + gboolean retval = TRUE; + GdaStatement *modif_stmts[NB_QUERIES]; + g_return_val_if_fail (GDA_IS_DATA_SELECT (model), FALSE); + GdaDataSelectPrivate *priv = gda_data_select_get_instance_private (model); + + stmt = check_acceptable_statement (model, error); + if (!stmt) + return FALSE; + + if (!priv->cnc) { + g_set_error (error, GDA_DATA_SELECT_ERROR, GDA_DATA_SELECT_CONNECTION_ERROR, + "%s", _("No connection to use")); + return FALSE; + } + for (mtype = FIRST_QUERY; mtype < NB_QUERIES; mtype++) { + if (priv->sh->modif_internals->modif_stmts[mtype]) { + g_object_unref (priv->sh->modif_internals->modif_stmts[mtype]); + priv->sh->modif_internals->modif_stmts[mtype] = NULL; + } + g_free (priv->sh->modif_internals->cols_mod[mtype]); + priv->sh->modif_internals->cols_mod[mtype] = NULL; + } + + retval = gda_compute_dml_statements (priv->cnc, stmt, + cond_type == GDA_DATA_SELECT_COND_PK ? TRUE : FALSE, + &(modif_stmts[INS_QUERY]), + NULL, NULL, error); + retval = gda_compute_dml_statements (priv->cnc, stmt, + cond_type == GDA_DATA_SELECT_COND_PK ? TRUE : FALSE, + NULL, + &(modif_stmts[UPD_QUERY]), + &(modif_stmts[DEL_QUERY]), error) && retval; + for (mtype = FIRST_QUERY; mtype < NB_QUERIES; mtype++) { + /* take into account the column type of "[+-]xxx" parameters */ + if (modif_stmts[mtype]) + _gda_modify_statement_param_types (modif_stmts[mtype], (GdaDataModel*) model); +#ifdef GDA_DEBUG_NO + if (modif_stmts[mtype]) { + gchar *sql; + sql = gda_statement_to_sql (modif_stmts[mtype], NULL, NULL); + g_print ("type %d => %s\n", mtype, sql); + g_free (sql); + } +#endif + if (modif_stmts[mtype] && + ! gda_data_select_set_modification_statement (model, modif_stmts[mtype], error)) { + retval = FALSE; + } + } + + for (mtype = FIRST_QUERY; mtype < NB_QUERIES; mtype++) { + if (modif_stmts[mtype]) { + g_object_unref (modif_stmts[mtype]); + modif_stmts[mtype] = NULL; + } + g_free (priv->sh->modif_internals->cols_mod[mtype]); + priv->sh->modif_internals->cols_mod[mtype] = NULL; + } + + return retval; +} + + +static gboolean +row_selection_condition_foreach_func (GdaSqlAnyPart *part, G_GNUC_UNUSED gpointer data, GError **error) +{ + if (part->type != GDA_SQL_ANY_SQL_OPERATION) + return TRUE; + + GdaSqlOperation *op = (GdaSqlOperation*) part; + if ((op->operator_type != GDA_SQL_OPERATOR_TYPE_EQ) && + (op->operator_type != GDA_SQL_OPERATOR_TYPE_AND)) { + g_set_error (error, GDA_DATA_SELECT_ERROR, GDA_DATA_SELECT_MODIFICATION_STATEMENT_ERROR, + "%s", _("Invalid unique row condition (only equal operators are allowed)")); + return FALSE; + } + + return TRUE; +} + +/** + * gda_data_select_set_row_selection_condition: + * @model: a #GdaDataSelect data model + * @expr: (transfer none): a #GdaSqlExpr expression + * @error: (nullable): a place to store errors, or %NULL + * + * Offers the same features as gda_data_select_set_row_selection_condition_sql() but using a #GdaSqlExpr + * structure instead of an SQL syntax. + * + * Returns: TRUE if no error occurred + */ +gboolean +gda_data_select_set_row_selection_condition (GdaDataSelect *model, GdaSqlExpr *expr, GError **error) +{ + gboolean valid; + + g_return_val_if_fail (GDA_IS_DATA_SELECT (model), FALSE); + g_return_val_if_fail (expr, FALSE); + GdaDataSelectPrivate *priv = gda_data_select_get_instance_private (model); + + if (!check_acceptable_statement (model, error)) + return FALSE; + + if (priv->sh->modif_internals->unique_row_condition) { + g_set_error (error, GDA_DATA_SELECT_ERROR, GDA_DATA_SELECT_MODIFICATION_STATEMENT_ERROR, + "%s", _("Unique row condition has already been specified")); + return FALSE; + } + + valid = gda_sql_any_part_foreach (GDA_SQL_ANY_PART (expr), + (GdaSqlForeachFunc) row_selection_condition_foreach_func, + NULL, error); + if (!valid) + return FALSE; + + priv->sh->modif_internals->unique_row_condition = gda_sql_expr_copy (expr); + return TRUE; +} + +/** + * gda_data_select_set_row_selection_condition_sql: + * @model: a #GdaDataSelect data model + * @sql_where: an SQL condition (without the WHERE keyword) + * @error: (nullable): a place to store errors, or %NULL + * + * Specifies the SQL condition corresponding to the WHERE part of a SELECT statement which would + * return only 1 row (the expression of the primary key). + * + * For example for a table created as , and if @pmodel corresponds to the execution of the + * , then the sensible value for @sql_where would be + * because the values of the 'part1' field are located + * in @pmodel's column number 1 and the values of the 'part2' field are located + * in @pmodel's column number 2 and the primary key is composed of (part1, part2). + * + * For more information about the syntax of the parameters (named for example), see the + * GdaSqlParser documentation, and + * gda_data_select_set_modification_statement(). + * + * Returns: TRUE if no error occurred + */ +gboolean +gda_data_select_set_row_selection_condition_sql (GdaDataSelect *model, const gchar *sql_where, GError **error) +{ + GdaSqlParser *parser; + GdaStatement *stmt; + gchar *sql; + const gchar *remain = NULL; + gboolean retval; + GdaSqlStatement *sqlst; + GdaSqlStatementSelect *selstmt; + + g_return_val_if_fail (GDA_IS_DATA_SELECT (model), FALSE); + GdaDataSelectPrivate *priv = gda_data_select_get_instance_private (model); + + if (!check_acceptable_statement (model, error)) + return FALSE; + + if (priv->sh->modif_internals->unique_row_condition) { + g_set_error (error, GDA_DATA_SELECT_ERROR, GDA_DATA_SELECT_MODIFICATION_STATEMENT_ERROR, + "%s", _("Unique row condition has already been specified")); + return FALSE; + } + + parser = gda_connection_create_parser (priv->cnc); + if (!parser) + parser = gda_sql_parser_new (); + + sql= g_strdup_printf ("SELECT * FROM table WHERE %s", sql_where); + stmt = gda_sql_parser_parse_string (parser, sql, &remain, error); + g_object_unref (parser); + if (!stmt) { + g_free (sql); + return FALSE; + } + if (remain) { + g_object_unref (stmt); + g_set_error (error, GDA_DATA_SELECT_ERROR, GDA_DATA_SELECT_SQL_ERROR, + "%s", _("Incorrect filter expression")); + g_free (sql); + return FALSE; + } + g_free (sql); + + + g_object_get (stmt, "structure", &sqlst, NULL); + selstmt = (GdaSqlStatementSelect *) sqlst->contents; + + retval = gda_data_select_set_row_selection_condition (model, selstmt->where_cond, error); + gda_sql_statement_free (sqlst); + + g_object_unref (stmt); + return retval; +} + +/** + * gda_data_select_compute_row_selection_condition: + * @model: a #GdaDataSelect object + * @error: (nullable): a place to store errors, or %NULL + * + * Offers the same features as gda_data_select_set_row_selection_condition() but the expression + * is computed from the meta data associated to the connection being used when @model was created. + * + * NOTE1: make sure the meta data associated to the connection is up to date before using this + * method, see gda_connection_update_meta_store(). + * + * NOTE2: if the SELECT statement from which @model has been created uses more than one table, or + * if the table used does not have any primary key, then this method will fail + * + * Returns: TRUE if no error occurred. + */ +gboolean +gda_data_select_compute_row_selection_condition (GdaDataSelect *model, GError **error) +{ + GdaSqlExpr *expr; + gboolean retval = FALSE; + GdaStatement *stmt; + const GdaSqlStatement *sqlst = NULL; + GdaSqlStatementSelect *select; + GdaSqlSelectTarget *target; + GdaMetaStruct *mstruct = NULL; + GdaMetaDbObject *dbo; + GValue *nvalue = NULL; + + g_return_val_if_fail (GDA_IS_DATA_SELECT (model), FALSE); + GdaDataSelectPrivate *priv = gda_data_select_get_instance_private (model); + + stmt = check_acceptable_statement (model, error); + if (!stmt) + return FALSE; + + if (!priv->cnc) { + g_set_error (error, GDA_DATA_SELECT_ERROR, GDA_DATA_SELECT_CONNECTION_ERROR, + "%s", _("No connection to use")); + return FALSE; + } + + sqlst = _gda_statement_get_internal_struct (stmt); + g_assert (sqlst->stmt_type == GDA_SQL_STATEMENT_SELECT); + select = (GdaSqlStatementSelect*) sqlst->contents; + if (!select->from || ! select->from->targets || ! select->from->targets->data) { + g_set_error (error, GDA_DATA_SELECT_ERROR, GDA_DATA_SELECT_SQL_ERROR, + "%s", _("No table to select from in SELECT statement")); + goto out; + } + if (select->from->targets->next) { + g_set_error (error, GDA_DATA_SELECT_ERROR, GDA_DATA_SELECT_SQL_ERROR, + "%s", _("SELECT statement uses more than one table to select from")); + goto out; + } + target = (GdaSqlSelectTarget *) select->from->targets->data; + if (!target->table_name) { + g_set_error (error, GDA_DATA_SELECT_ERROR, GDA_DATA_SELECT_SQL_ERROR, + "%s", _("No table to select from in SELECT statement")); + goto out; + } + g_value_set_string ((nvalue = gda_value_new (G_TYPE_STRING)), target->table_name); + mstruct = (GdaMetaStruct*) g_object_new (GDA_TYPE_META_STRUCT, "meta-store", gda_connection_get_meta_store (priv->cnc), "features", GDA_META_STRUCT_FEATURE_NONE, NULL); + dbo = gda_meta_struct_complement (mstruct, GDA_META_DB_TABLE, NULL, NULL, nvalue, error); + if (!dbo) + goto out; + + expr = gda_compute_unique_table_row_condition (select, GDA_META_TABLE (dbo), TRUE, error); + retval = gda_data_select_set_row_selection_condition (model, expr, error); + + out: + if (mstruct) + g_object_unref (mstruct); + if (nvalue) + gda_value_free (nvalue); + + return retval; +} + +/* + * GdaDataModel interface implementation + */ +static gint +gda_data_select_get_n_rows (GdaDataModel *model) +{ + gint retval; + + GdaDataSelectPrivate *priv = gda_data_select_get_instance_private (GDA_DATA_SELECT (model)); + + retval = priv->advertized_nrows; + if ((priv->advertized_nrows < 0) && + (priv->sh->usage_flags & GDA_DATA_MODEL_ACCESS_RANDOM) && + CLASS (model)->fetch_nb_rows) + retval = _gda_data_select_fetch_nb_rows (GDA_DATA_SELECT (model)); + + if ((retval > 0) && (priv->sh->del_rows)) + retval -= priv->sh->del_rows->len; + return retval; +} + +static gint +gda_data_select_get_n_columns (GdaDataModel *model) +{ + GdaDataSelectPrivate *priv = gda_data_select_get_instance_private (GDA_DATA_SELECT (model)); + + if (priv->prep_stmt) + return gda_pstmt_get_ncols (priv->prep_stmt); + + return g_slist_length (priv->sh->columns); +} + +static GdaColumn * +gda_data_select_describe_column (GdaDataModel *model, gint col) +{ + GdaDataSelectPrivate *priv = gda_data_select_get_instance_private (GDA_DATA_SELECT (model)); + + return g_slist_nth_data (priv->sh->columns, col); +} + +static GdaDataModelAccessFlags +gda_data_select_get_access_flags (GdaDataModel *model) +{ + GdaDataSelectPrivate *priv = gda_data_select_get_instance_private (GDA_DATA_SELECT (model)); + GdaDataModelAccessFlags flags = 0; + + g_return_val_if_fail (priv, 0); + + if (priv->sh->usage_flags & GDA_DATA_MODEL_ACCESS_RANDOM) + flags = GDA_DATA_MODEL_ACCESS_RANDOM; + else if (priv->sh->usage_flags & GDA_DATA_MODEL_ACCESS_CURSOR_FORWARD) { + if (priv->sh->usage_flags & GDA_DATA_MODEL_ACCESS_CURSOR_BACKWARD) + flags = GDA_DATA_MODEL_ACCESS_CURSOR; + else + flags = GDA_DATA_MODEL_ACCESS_CURSOR_FORWARD; + } + + if (! priv->sh->modif_internals->safely_locked && + (priv->sh->usage_flags & GDA_DATA_MODEL_ACCESS_RANDOM)) { + if (priv->sh->modif_internals->modif_stmts [UPD_QUERY]) + flags |= GDA_DATA_MODEL_ACCESS_UPDATE; + if (priv->sh->modif_internals->modif_stmts [INS_QUERY]) + flags |= GDA_DATA_MODEL_ACCESS_INSERT; + if (priv->sh->modif_internals->modif_stmts [DEL_QUERY]) + flags |= GDA_DATA_MODEL_ACCESS_DELETE; + } + + return flags; +} + +/* + * Converts an external row number to an internal row number + * Returns: a row number, or -1 if row number does not exist + */ +static gint +external_to_internal_row (GdaDataSelect *model, gint ext_row, GError **error) +{ + gint nrows; + gint int_row = ext_row; + GdaDataSelectPrivate *priv = gda_data_select_get_instance_private (model); + + /* row number alteration: deleted rows */ + if (priv->sh->del_rows) { + gint i; + for (i = 0; (guint)i < priv->sh->del_rows->len; i++) { + gint indexed = g_array_index (priv->sh->del_rows, gint, i); + if (indexed <= ext_row + i) + int_row += 1; + else + break; + } + } + + /* check row number validity */ + nrows = priv->advertized_nrows < 0 ? gda_data_select_get_n_rows ((GdaDataModel*) model) : + priv->advertized_nrows; + if ((ext_row < 0) || ((nrows >= 0) && (int_row >= nrows))) { + gint n; + n = gda_data_select_get_n_rows ((GdaDataModel*) model); + if (n > 0) + g_set_error (error, GDA_DATA_MODEL_ERROR, GDA_DATA_MODEL_ROW_OUT_OF_RANGE_ERROR, + _("Row %d out of range (0-%d)"), ext_row, n - 1); + else + g_set_error (error, GDA_DATA_MODEL_ERROR, GDA_DATA_MODEL_ROW_OUT_OF_RANGE_ERROR, + _("Row %d not found (empty data model)"), ext_row); + return -1; + } + + return int_row; +} + +#ifdef GDA_DEBUG_NO +static void foreach_func_dump (gpointer key, gpointer value, gpointer dummy) +{ + g_print (" row %d => %p\n", *(const gint*) key, value); + DelayedSelectStmt *dstmt; + dstmt = (DelayedSelectStmt *) value; + gchar *sql; + sql = gda_statement_to_sql_extended (dstmt->select, NULL, dstmt->params, + GDA_STATEMENT_SQL_PARAMS_AS_VALUES, NULL, NULL); + g_print ("\tSQL: [%s]\n", sql); + g_free (sql); +} +static void dump_d (GdaDataSelect *model) +{ + GdaDataSelectPrivate *priv = gda_data_select_get_instance_private (model); + if (priv->sh->upd_rows) { + g_print ("Delayed SELECT for data model %p:\n", model); + g_hash_table_foreach (priv->sh->upd_rows, foreach_func_dump, NULL); + } +} +#endif + +static const GValue * +gda_data_select_get_value_at (GdaDataModel *model, gint col, gint row, GError **error) +{ + g_return_val_if_fail (model != NULL, NULL); + g_return_val_if_fail (GDA_IS_DATA_SELECT (model), NULL); + + GdaRow *prow; + gint int_row; + GdaDataSelectPrivate *priv = gda_data_select_get_instance_private (GDA_DATA_SELECT (model)); + + + /* available only if GDA_DATA_MODEL_ACCESS_RANDOM */ + if (! (priv->sh->usage_flags & GDA_DATA_MODEL_ACCESS_RANDOM)) { + g_set_error (error, GDA_DATA_MODEL_ERROR, GDA_DATA_MODEL_ACCESS_ERROR, + "%s", _("Data model does only support random access")); + return NULL; + } + + if ((col >= gda_data_select_get_n_columns (model)) || + (col < 0)) { + g_set_error (error, GDA_DATA_MODEL_ERROR, GDA_DATA_MODEL_COLUMN_OUT_OF_RANGE_ERROR, + _("Column %d out of range (0-%d)"), col, gda_data_select_get_n_columns (model) - 1); + return NULL; + } + + int_row = external_to_internal_row (GDA_DATA_SELECT (model), row, NULL); + if (int_row < 0) { + gint n; + n = gda_data_select_get_n_rows ( model); + if (n > 0) + g_set_error (error, GDA_DATA_MODEL_ERROR, GDA_DATA_MODEL_ROW_OUT_OF_RANGE_ERROR, + _("Row %d out of range (0-%d)"), row, n - 1); + else + g_set_error (error, GDA_DATA_MODEL_ERROR, GDA_DATA_MODEL_ROW_OUT_OF_RANGE_ERROR, + _("Row %d not found (empty data model)"), row); + return NULL; + } + + DelayedSelectStmt *dstmt = NULL; +#ifdef GDA_DEBUG_NO + dump_d (imodel); +#endif + if (priv->sh->upd_rows) + dstmt = g_hash_table_lookup (priv->sh->upd_rows, &int_row); + if (dstmt) { + if (! dstmt->row) { + if (dstmt->exec_error) { + if (error) + g_propagate_error (error, g_error_copy (dstmt->exec_error)); + return NULL; + } + GdaDataModel *tmpmodel; + if (!dstmt->select || !dstmt->params) { + g_set_error (&(dstmt->exec_error), + GDA_DATA_MODEL_ERROR, GDA_DATA_MODEL_ACCESS_ERROR, + "%s", _("Unable to retrieve data after modifications")); + if (error) + g_propagate_error (error, g_error_copy (dstmt->exec_error)); + return NULL; + } + GType *types = NULL; + if (priv->prep_stmt && gda_pstmt_get_types (priv->prep_stmt)) { + types = g_new (GType, gda_pstmt_get_ncols (priv->prep_stmt) + 1); + memcpy (types, gda_pstmt_get_types (priv->prep_stmt), /* Flawfinder: ignore */ + sizeof (GType) * gda_pstmt_get_ncols (priv->prep_stmt)); + types [gda_pstmt_get_ncols (priv->prep_stmt)] = G_TYPE_NONE; + } + /*g_print ("*** Executing DelayedSelectStmt %p\n", dstmt);*/ + tmpmodel = gda_connection_statement_execute_select_full (priv->cnc, + dstmt->select, + dstmt->params, + GDA_STATEMENT_MODEL_RANDOM_ACCESS, + types, + NULL); + g_free (types); + + if (!tmpmodel) { + g_set_error (&(dstmt->exec_error), + GDA_DATA_MODEL_ERROR, GDA_DATA_MODEL_ACCESS_ERROR, + "%s", _("Unable to retrieve data after modifications, no further modification will be allowed")); + if (error) + g_propagate_error (error, g_error_copy (dstmt->exec_error)); + priv->sh->modif_internals->safely_locked = TRUE; + return NULL; + } + + if (gda_data_model_get_n_rows (tmpmodel) != 1) { + g_object_unref (tmpmodel); + g_set_error (&(dstmt->exec_error), + GDA_DATA_MODEL_ERROR, GDA_DATA_MODEL_ACCESS_ERROR, + "%s", _("Unable to retrieve data after modifications, no further modification will be allowed")); + if (error) + g_propagate_error (error, g_error_copy (dstmt->exec_error)); + priv->sh->modif_internals->safely_locked = TRUE; + return NULL; + } + + gint i, ncols; + ncols = gda_data_model_get_n_columns (tmpmodel); + prow = gda_row_new (ncols); + for (i = 0; i < ncols; i++) { + GValue *value; + const GValue *cvalue; + value = gda_row_get_value (prow, i); + cvalue = gda_data_model_get_value_at (tmpmodel, i, 0, + &(dstmt->exec_error)); + if (!cvalue) { + if (error) + g_propagate_error (error, + g_error_copy (dstmt->exec_error)); + return NULL; + } + + if (!gda_value_is_null (cvalue)) { + gda_value_reset_with_type (value, G_VALUE_TYPE (cvalue)); + if (! gda_value_set_from_value (value, cvalue)) { + g_object_unref (tmpmodel); + g_object_unref (prow); + g_set_error (&(dstmt->exec_error), + GDA_DATA_MODEL_ERROR, GDA_DATA_MODEL_ACCESS_ERROR, + "%s", _("Unable to retrieve data after modifications, no further modification will be allowed")); + if (error) + g_propagate_error (error, + g_error_copy (dstmt->exec_error)); + priv->sh->modif_internals->safely_locked = TRUE; + return NULL; + } + } + else + gda_value_set_null (value); + } + dstmt->row = prow; + //gda_data_model_dump (tmpmodel, stdout); + g_object_unref (tmpmodel); + } + else + prow = dstmt->row; + } + else { + prow = gda_data_select_get_stored_row (GDA_DATA_SELECT (model), int_row); + if (!prow && CLASS (model)->fetch_random) + _gda_data_select_fetch_random (GDA_DATA_SELECT (model), &prow, int_row, error); + } + if (!prow) + return NULL; + + GValue *retval = gda_row_get_value (prow, col); + if (gda_row_value_is_valid_e (prow, retval, error)) + return retval; + else + return NULL; +} + +static GdaValueAttribute +gda_data_select_get_attributes_at (GdaDataModel *model, gint col, gint row) +{ + GdaValueAttribute flags = GDA_VALUE_ATTR_IS_UNCHANGED; + GdaDataSelectPrivate *priv = gda_data_select_get_instance_private (GDA_DATA_SELECT (model)); + + GdaColumn *gdacol = g_slist_nth_data (priv->sh->columns, col); + + if (priv->sh->modif_internals->safely_locked) + flags = GDA_VALUE_ATTR_NO_MODIF; + else { + GdaStatement *stmt = NULL; + ModType m; + if (row == -1) { + /* this is for a "would be inserted" row */ + m = INS_QUERY; + } + else + m = UPD_QUERY; + stmt = priv->sh->modif_internals->modif_stmts [m]; + gboolean nomod = TRUE; + if (stmt) { + if (! priv->sh->modif_internals->cols_mod [m]) { + GdaSet *set; + gint ncols; + ncols = g_slist_length (priv->sh->columns); + priv->sh->modif_internals->cols_mod[m] = g_new0 (gboolean, ncols); + if (gda_statement_get_parameters (stmt, &set, NULL) && set) { + gchar *tmp; + gint i; + for (i = 0; i < ncols; i++) { + tmp = g_strdup_printf ("+%d", i); + if (gda_set_get_holder (set, tmp)) + priv->sh->modif_internals->cols_mod[m][i] = TRUE; + g_free (tmp); + } + g_object_unref (set); + } + } + if (gdacol) + nomod = ! priv->sh->modif_internals->cols_mod[m][col]; + } + if (nomod) + flags |= GDA_VALUE_ATTR_NO_MODIF; + } + + if (gdacol) { + if (gda_column_get_allow_null (gdacol)) + flags |= GDA_VALUE_ATTR_CAN_BE_NULL; + } + + /*g_print ("%s (%p, %d, %d) => %d\n", __FUNCTION__, model, col, row, flags);*/ + return flags; +} + +static GdaDataModelIter * +gda_data_select_create_iter (GdaDataModel *model) +{ + GdaDataSelectPrivate *priv = gda_data_select_get_instance_private (GDA_DATA_SELECT (model)); + + if (priv->sh->usage_flags & GDA_DATA_MODEL_ACCESS_RANDOM) { + return GDA_DATA_MODEL_ITER (g_object_new (GDA_TYPE_DATA_SELECT_ITER, + "data-model", model, NULL)); + } + /* Create the iter if necessary, or just return the existing iter: */ + if (priv->iter == NULL) { + priv->iter = GDA_DATA_MODEL_ITER (g_object_new (GDA_TYPE_DATA_SELECT_ITER, + "data-model", model, NULL)); + priv->sh->iter_row = -1; + } + return g_object_ref (priv->iter); +} + +static void update_iter (GdaDataSelect *imodel, GdaRow *prow); +static gboolean +gda_data_select_iter_next (GdaDataModel *model, GdaDataModelIter *iter) +{ + GdaRow *prow = NULL; + gint target_iter_row; + gint int_row; + GError *error = NULL; + GdaDataSelectPrivate *priv = gda_data_select_get_instance_private (GDA_DATA_SELECT (model)); + + if (priv->sh->usage_flags & GDA_DATA_MODEL_ACCESS_RANDOM) + return gda_data_model_iter_move_next_default (model, iter); + + g_return_val_if_fail (CLASS (model)->fetch_next, FALSE); + g_return_val_if_fail (iter, FALSE); + + if (gda_data_model_get_n_rows (model) == 0) { + priv->sh->iter_row = G_MAXINT; + gda_data_model_iter_invalidate_contents (iter); + return FALSE; + } + + if (priv->sh->iter_row == G_MAXINT) { + gda_data_model_iter_invalidate_contents (iter); + return FALSE; + } + else if (priv->sh->iter_row == G_MININT) + target_iter_row = 0; + else + target_iter_row = priv->sh->iter_row + 1; + + int_row = external_to_internal_row (GDA_DATA_SELECT (model), target_iter_row, &error); + if (int_row < 0) { + g_warning (_("Can't calculate internal row number: %s"), + error && error->message ? error->message : "No error was set"); + g_clear_error (&error); + gda_data_model_iter_invalidate_contents (iter); + return FALSE; + } + prow = gda_data_select_get_stored_row (GDA_DATA_SELECT (model), int_row); + if (!prow) { + if (!_gda_data_select_fetch_next (GDA_DATA_SELECT (model), &prow, int_row, &error)) { + g_warning (_("Can't fetch next row: %s"), + error && error->message ? error->message : "No error was set"); + g_clear_error (&error); + gda_data_model_iter_invalidate_contents (iter); + return FALSE; + } + } + + if (prow) { + priv->sh->iter_row = target_iter_row; + update_iter (GDA_DATA_SELECT (model), prow); + return TRUE; + } + else { + gda_data_model_iter_invalidate_contents (iter); + priv->sh->iter_row = G_MAXINT; + g_object_set (G_OBJECT (iter), "current-row", -1, NULL); + g_signal_emit_by_name (iter, "end-of-data"); + return FALSE; + } +} + +static gboolean +gda_data_select_iter_prev (GdaDataModel *model, GdaDataModelIter *iter) +{ + GdaRow *prow = NULL; + gint target_iter_row; + gint int_row; + GError *error = NULL; + GdaDataSelectPrivate *priv = gda_data_select_get_instance_private (GDA_DATA_SELECT (model)); + + if (priv->sh->usage_flags & GDA_DATA_MODEL_ACCESS_RANDOM) + return gda_data_model_iter_move_prev_default (model, iter); + + g_return_val_if_fail (iter, FALSE); + + if (priv->sh->iter_row <= 0) + goto prev_error; + else if (priv->sh->iter_row == G_MAXINT) { + g_assert (priv->advertized_nrows >= 0); + target_iter_row = priv->advertized_nrows - 1; + } + else + target_iter_row = priv->sh->iter_row - 1; + + if (priv->sh->iter_row < 0) { + gda_data_model_iter_invalidate_contents (iter); + return FALSE; + } + + int_row = external_to_internal_row (GDA_DATA_SELECT (model), target_iter_row, &error); + if (int_row < 0) { + g_warning (_("Can't move back iter at row: %s"), + error && error->message ? error->message : "No error was set"); + g_clear_error (&error); + gda_data_model_iter_invalidate_contents (iter); + return FALSE; + } + prow = gda_data_select_get_stored_row (GDA_DATA_SELECT (model), int_row); + if (!prow) { + if (! CLASS (model)->fetch_prev) { + g_warning (_("Internal error: No fetch_prev() method implementation for data model")); + gda_data_model_iter_invalidate_contents (iter); + return FALSE; + } + if (!_gda_data_select_fetch_prev (GDA_DATA_SELECT (model), &prow, int_row, &error)) { + g_warning (_("Can't fetch previous row: %s"), + error && error->message ? error->message : "No error was set"); + g_clear_error (&error); + gda_data_model_iter_invalidate_contents (iter); + return FALSE; + } + } + + if (prow) { + priv->sh->iter_row = target_iter_row; + update_iter (GDA_DATA_SELECT (model), prow); + return TRUE; + } + + prev_error: + g_object_set (G_OBJECT (iter), "current-row", -1, NULL); + priv->sh->iter_row = G_MININT; + gda_data_model_iter_invalidate_contents (iter); + return FALSE; +} + +static gboolean +gda_data_select_iter_at_row (GdaDataModel *model, GdaDataModelIter *iter, gint row) +{ + GdaRow *prow = NULL; + gint int_row; + GError *error = NULL; + GdaDataSelectPrivate *priv = gda_data_select_get_instance_private (GDA_DATA_SELECT (model)); + + g_return_val_if_fail (iter, FALSE); + + if (priv->sh->usage_flags & GDA_DATA_MODEL_ACCESS_RANDOM) + return gda_data_model_iter_move_to_row_default (model, iter, row); + + if (row >= gda_data_model_get_n_rows (model)) { + priv->sh->iter_row = -1; + gda_data_model_iter_invalidate_contents (iter); + return FALSE; + } + + int_row = external_to_internal_row (GDA_DATA_SELECT (model), row, &error); + if (int_row < 0) { + g_warning (_("Can't move iter at row '%d': %s"), row, + error && error->message ? error->message : "No error was set"); + g_clear_error (&error); + gda_data_model_iter_invalidate_contents (iter); + return FALSE; + } + if (priv->sh->current_prow && (priv->sh->current_prow_row == row)) + prow = priv->sh->current_prow; + else + prow = gda_data_select_get_stored_row (GDA_DATA_SELECT (model), int_row); + + if (prow) { + priv->sh->iter_row = row; + update_iter (GDA_DATA_SELECT (model), prow); + return TRUE; + } + else { + if (CLASS (model)->fetch_at) { + if (!_gda_data_select_fetch_at (GDA_DATA_SELECT (model), &prow, int_row, &error)) { + g_warning (_("Can't fetch row '%d': %s"), row, + error && error->message ? error->message : "No error was set"); + g_clear_error (&error); + gda_data_model_iter_invalidate_contents (iter); + return FALSE; + } + if (prow) { + priv->sh->iter_row = row; + update_iter (GDA_DATA_SELECT (model), prow); + return TRUE; + } + else { + g_object_set (G_OBJECT (iter), "current-row", -1, NULL); + priv->sh->iter_row = G_MININT; + gda_data_model_iter_invalidate_contents (iter); + return FALSE; + } + } + else { + /* implementation of fetch_at() is optional */ + if (priv->sh->iter_row < row) { + for (; gda_data_model_iter_get_row (iter) < row; ) { + if (! gda_data_model_iter_move_next (iter)) + return FALSE; + } + return gda_data_model_iter_get_row (iter) == row ? TRUE : FALSE; + } + else if (priv->sh->iter_row > row) { + for (; gda_data_model_iter_get_row (iter) > row; ) { + if (! gda_data_model_iter_move_prev (iter)) + return FALSE; + } + return gda_data_model_iter_get_row (iter) == row ? TRUE : FALSE; + } + else + return TRUE; + } + } +} + +static void +update_iter (GdaDataSelect *imodel, GdaRow *prow) +{ + GdaDataSelectPrivate *priv = gda_data_select_get_instance_private (GDA_DATA_SELECT (imodel)); + gint i; + GdaDataModelIter *iter = priv->iter; + GSList *plist; + gboolean update_model; + if (iter == NULL) { + return; + } + + g_object_get (G_OBJECT (iter), "update-model", &update_model, NULL); + if (update_model) + g_object_set (G_OBJECT (iter), "update-model", FALSE, NULL); + + for (i = 0, plist = gda_set_get_holders (GDA_SET (iter)); + plist; + i++, plist = plist->next) { + GValue *value; + GError *lerror = NULL; + value = gda_row_get_value (prow, i); + + if (!gda_row_value_is_valid_e (prow, value, &lerror)) { + /*g_print (_("%s(%p) [%d] Could not change iter's value for column %d: %s"), + __FUNCTION__, iter, priv->sh->iter_row, i, + lerror && lerror->message ? lerror->message : _("No detail"));*/ + gda_holder_force_invalid_e ((GdaHolder*) plist->data, lerror); + } + else if (! gda_holder_set_value ((GdaHolder*) plist->data, value, &lerror)) { + if (gda_holder_get_not_null ((GdaHolder*) plist->data) && + gda_value_is_null (value)) { + gda_holder_set_not_null ((GdaHolder*) plist->data, FALSE); + if (! gda_holder_set_value ((GdaHolder*) plist->data, value, NULL)) { + gda_holder_force_invalid_e ((GdaHolder*) plist->data, lerror); + g_warning (_("Could not change iter's value for column %d: %s"), i, + lerror && lerror->message ? lerror->message : _("No detail")); + gda_holder_set_not_null ((GdaHolder*) plist->data, TRUE); + } + else + g_warning (_("Allowed GdaHolder's value to be NULL for the iterator " + "to be updated")); + } + else { + gda_holder_force_invalid_e ((GdaHolder*) plist->data, lerror); + g_warning (_("Could not change iter's value for column %d: %s"), i, + lerror && lerror->message ? lerror->message : _("No detail")); + } + } + } + + g_object_set (G_OBJECT (iter), "current-row", priv->sh->iter_row, NULL); + if (update_model) + g_object_set (G_OBJECT (iter), "update-model", update_model, NULL); + + if (prow != priv->sh->current_prow) { + if (priv->sh->current_prow) { + g_object_unref (priv->sh->current_prow); + priv->sh->current_prow = NULL; + } + priv->sh->current_prow = g_object_ref (prow); + } + priv->sh->current_prow_row = priv->sh->iter_row; + + /*g_print ("%s(%p), current-row =>%d advertized_nrows => %d\n", __FUNCTION__, imodel, priv->sh->iter_row, iadvertized_nrows);*/ +} + +/* + * creates a derivative of the priv->sh->modif_internals->modif_stmts [UPD_QUERY] statement + * where only the columns where @bv->data[colnum] is not 0 are updated. + * + * Returns: a new #GdaStatement, or %NULL + */ +static GdaStatement * +compute_single_update_stmt (GdaDataSelect *model, BVector *bv, GError **error) +{ + GdaSqlStatement *sqlst; + GdaSqlStatementUpdate *upd; + GdaStatement *updstmt = NULL; + GdaDataSelectPrivate *priv = gda_data_select_get_instance_private (model); + + /* get a copy of complete UPDATE stmt */ + g_assert (priv->sh->modif_internals->modif_stmts [UPD_QUERY]); + g_object_get (G_OBJECT (priv->sh->modif_internals->modif_stmts [UPD_QUERY]), "structure", &sqlst, NULL); + g_assert (sqlst); + g_free (sqlst->sql); + sqlst->sql = NULL; + g_assert (sqlst->stmt_type == GDA_SQL_STATEMENT_UPDATE); + upd = (GdaSqlStatementUpdate*) sqlst->contents; + + /* remove non necessary fields to update */ + GSList *elist, *flist; + gboolean field_found = FALSE; + for (elist = upd->expr_list, flist = upd->fields_list; elist && flist; ) { + GdaSqlExpr *expr = (GdaSqlExpr *) elist->data; + gint num; + gboolean old_val; + if (! expr->param_spec || !param_name_to_int (expr->param_spec->name, &num, &old_val) || old_val) { + /* ignore this field to be updated */ + elist = elist->next; + flist = flist->next; + continue; + } + if ((num < bv->size) && bv->data[num]) { + /* this field is a field to be updated */ + field_found = TRUE; + elist = elist->next; + flist = flist->next; + continue; + } + /* remove that field */ + GSList *nelist, *nflist; + nelist = elist->next; + nflist = flist->next; + gda_sql_expr_free (expr); + gda_sql_field_free ((GdaSqlField*) flist->data); + + upd->expr_list = g_slist_delete_link (upd->expr_list, elist); + upd->fields_list = g_slist_delete_link (upd->fields_list, flist); + elist = nelist; + flist = nflist; + } + + /* create a new GdaStatement */ + if (field_found) + updstmt = (GdaStatement *) g_object_new (GDA_TYPE_STATEMENT, "structure", sqlst, NULL); + else + g_set_error (error, GDA_DATA_SELECT_ERROR, GDA_DATA_SELECT_MISSING_MODIFICATION_STATEMENT_ERROR, + "%s", _("Some columns can't be modified")); + gda_sql_statement_free (sqlst); + +#ifdef GDA_DEBUG_NO + GString *bvstr; + gint i; + gboolean first = TRUE; + bvstr = g_string_new ("("); + for (i = 0; i < bv->size; i++) { + if (bv->data[i]) { + if (first) + first = FALSE; + else + g_string_append (bvstr, ", "); + g_string_append_printf (bvstr, "%d", i); + } + } + g_string_append_c (bvstr, ')'); + + if (updstmt) { + gchar *sql; + sql = gda_statement_serialize (updstmt); + g_print ("UPDATE for columns %s => %s\n", bvstr->str, sql); + g_free (sql); + } + else + g_print ("UPDATE for columns %s: ERROR\n", bvstr->str); + g_string_free (bvstr, TRUE); +#endif + + return updstmt; +} + +/* + * creates a derivative of the priv->sh->modif_internals->modif_stmts [INS_QUERY] statement + * where only the columns where @bv->data[colnum] is not 0 are not mentioned. + * + * Returns: a new #GdaStatement, or %NULL + */ +static GdaStatement * +compute_single_insert_stmt (GdaDataSelect *model, BVector *bv, GError **error) +{ + GdaSqlStatement *sqlst; + GdaSqlStatementInsert *ins; + GdaStatement *insstmt = NULL; + GdaDataSelectPrivate *priv = gda_data_select_get_instance_private (model); + + /* get a copy of complete INSERT stmt */ + g_assert (priv->sh->modif_internals->modif_stmts [INS_QUERY]); + g_object_get (G_OBJECT (priv->sh->modif_internals->modif_stmts [INS_QUERY]), "structure", &sqlst, NULL); + g_assert (sqlst); + g_free (sqlst->sql); + sqlst->sql = NULL; + g_assert (sqlst->stmt_type == GDA_SQL_STATEMENT_INSERT); + ins = (GdaSqlStatementInsert*) sqlst->contents; + + /* remove fields to insert for which we don't have any value (the default value will be used) */ + GSList *elist, *flist; + gboolean field_found = FALSE; + for (elist = (GSList*) ins->values_list->data, flist = ins->fields_list; elist && flist; ) { + GdaSqlExpr *expr = (GdaSqlExpr *) elist->data; + gint num; + gboolean old_val; + if (! expr->param_spec || !param_name_to_int (expr->param_spec->name, &num, &old_val) || old_val) { + /* ignore this field to be inserted */ + elist = elist->next; + flist = flist->next; + continue; + } + if ((num < bv->size) && bv->data[num]) { + /* this field is a field to be inserted */ + field_found = TRUE; + elist = elist->next; + flist = flist->next; + continue; + } + /* remove that field */ + GSList *nelist, *nflist; + nelist = elist->next; + nflist = flist->next; + gda_sql_expr_free (expr); + gda_sql_field_free ((GdaSqlField*) flist->data); + + ins->values_list->data = g_slist_delete_link ((GSList*) ins->values_list->data, elist); + ins->fields_list = g_slist_delete_link (ins->fields_list, flist); + elist = nelist; + flist = nflist; + } + + /* create a new GdaStatement */ + if (field_found) + insstmt = (GdaStatement *) g_object_new (GDA_TYPE_STATEMENT, "structure", sqlst, NULL); + else + g_set_error (error, GDA_DATA_SELECT_ERROR, GDA_DATA_SELECT_MISSING_MODIFICATION_STATEMENT_ERROR, + "%s", _("Some columns can't be modified")); + gda_sql_statement_free (sqlst); + +#ifdef GDA_DEBUG_NO + GString *bvstr; + gint i; + gboolean first = TRUE; + bvstr = g_string_new ("("); + for (i = 0; i < bv->size; i++) { + if (bv->data[i]) { + if (first) + first = FALSE; + else + g_string_append (bvstr, ", "); + g_string_append_printf (bvstr, "%d", i); + } + } + g_string_append_c (bvstr, ')'); + + if (insstmt) { + gchar *sql; + sql = gda_statement_serialize (insstmt); + g_print ("INSERT for columns %s => %s\n", bvstr->str, sql); + g_free (sql); + } + else + g_print ("INSERT for columns %s: ERROR\n", bvstr->str); + g_string_free (bvstr, TRUE); +#endif + + return insstmt; +} + +/* + * creates a derivative of the SELECT statement from which @model has been created, + * but to select only one single row (this statement is executed when a GdaRow is requested + * after an UPDATE or INSERT statement has been run) + * + * The new created statement is merely the copy of the SELECT statement where the WHERE part + * has been altered as "" + * + * Returns: a new #GdaStatement, or %NULL + */ +static GdaStatement * +compute_single_select_stmt (GdaDataSelect *model, GError **error) +{ + GdaStatement *sel_stmt; + GdaStatement *ret_stmt = NULL; + GdaSqlStatement *sel_sqlst; + GdaSqlExpr *row_cond = NULL; + GdaDataSelectPrivate *priv = gda_data_select_get_instance_private (model); + + sel_stmt = priv->sh->sel_stmt; + if (! sel_stmt) { + g_set_error (error, GDA_DATA_SELECT_ERROR, GDA_DATA_SELECT_MODIFICATION_STATEMENT_ERROR, + "%s", _("Internal error: can't get the prepared statement's actual statement")); + return NULL; + } + + if (priv->sh->modif_internals->unique_row_condition) + row_cond = gda_sql_expr_copy (priv->sh->modif_internals->unique_row_condition); + else if (priv->sh->modif_internals->modif_stmts [DEL_QUERY]) { + GdaStatement *del_stmt; + GdaSqlStatement *del_sqlst; + GdaSqlStatementDelete *del; + del_stmt = priv->sh->modif_internals->modif_stmts [DEL_QUERY]; + + g_object_get (G_OBJECT (del_stmt), "structure", &del_sqlst, NULL); + del = (GdaSqlStatementDelete*) del_sqlst->contents; + row_cond = del->cond; + del->cond = NULL; + gda_sql_statement_free (del_sqlst); + if (!gda_data_select_set_row_selection_condition (model, row_cond, NULL)) { + gda_sql_expr_free (row_cond); + row_cond = NULL; + } + } + else if (priv->sh->modif_internals->modif_stmts [UPD_QUERY]) { + GdaStatement *upd_stmt; + GdaSqlStatement *upd_sqlst; + GdaSqlStatementUpdate *upd; + upd_stmt = priv->sh->modif_internals->modif_stmts [UPD_QUERY]; + + g_object_get (G_OBJECT (upd_stmt), "structure", &upd_sqlst, NULL); + upd = (GdaSqlStatementUpdate*) upd_sqlst->contents; + row_cond = upd->cond; + upd->cond = NULL; + gda_sql_statement_free (upd_sqlst); + if (!gda_data_select_set_row_selection_condition (model, row_cond, NULL)) { + gda_sql_expr_free (row_cond); + row_cond = NULL; + } + } + if (!row_cond) { + g_set_error (error, GDA_DATA_SELECT_ERROR, GDA_DATA_SELECT_MODIFICATION_STATEMENT_ERROR, + "%s", _("Unable to identify a way to fetch a single row")); + return NULL; + } + + g_object_get (G_OBJECT (sel_stmt), "structure", &sel_sqlst, NULL); + if (sel_sqlst->stmt_type != GDA_SQL_STATEMENT_SELECT) { + g_set_error (error, GDA_DATA_SELECT_ERROR, GDA_DATA_SELECT_MODIFICATION_STATEMENT_ERROR, + "%s", _("Can only operate on non compound SELECT statements")); + gda_sql_statement_free (sel_sqlst); + gda_sql_expr_free (row_cond); + return NULL; + } + + GdaSqlStatementSelect *sel; + + sel = (GdaSqlStatementSelect*) sel_sqlst->contents; + g_free (sel_sqlst->sql); + sel_sqlst->sql = NULL; + if (sel->where_cond) + gda_sql_expr_free (sel->where_cond); + sel->where_cond = row_cond; + GDA_SQL_ANY_PART (row_cond)->parent = GDA_SQL_ANY_PART (sel); + + ret_stmt = (GdaStatement *) g_object_new (GDA_TYPE_STATEMENT, "structure", sel_sqlst, NULL); + + gda_sql_statement_free (sel_sqlst); + +#ifdef GDA_DEBUG_NO + gchar *sql; + sql = gda_statement_serialize (ret_stmt); + g_print ("SINGLE ROW SELECT => %s\n", sql); + g_free (sql); + sql = gda_statement_to_sql (ret_stmt, NULL, NULL); + g_print ("SINGLE ROW SELECT => %s\n", sql); + g_free (sql); +#endif + + return ret_stmt; +} + +/* + * Hash and Equal functions for usage in a GHashTable + * The comparison is made of BVector vectors + */ +static guint +bvector_hash (BVector *key) +{ + gint i; + guint ret = 0; + for (i = 0; i < key->size; i++) { + ret += key->data [i]; + ret <<= 1; + } + return ret; +} + +static gboolean +bvector_equal (BVector *key1, BVector *key2) +{ + if (key1->size != key2->size) + return FALSE; + return memcmp (key1->data, key2->data, sizeof (guchar) * key1->size) == 0 ? TRUE : FALSE; +} + +static void +bvector_free (BVector *key) +{ + g_free (key->data); + g_free (key); +} + +/* + * REM: @bv is stolen here + */ +static gboolean +vector_set_value_at (GdaDataSelect *imodel, BVector *bv, GdaDataModelIter *iter, gint row, GError **error) +{ + gint int_row, i, ncols; + GdaHolder *holder; + gchar *str; + GdaStatement *stmt; + gboolean free_bv = TRUE; + GdaDataSelectPrivate *priv = gda_data_select_get_instance_private (GDA_DATA_SELECT (imodel)); + + /* arguments check */ + g_assert (bv); + + if (priv->sh->modif_internals->safely_locked) { + g_set_error (error, GDA_DATA_SELECT_ERROR, GDA_DATA_SELECT_SAFETY_LOCKED_ERROR, + "%s", _("Modifications are not allowed anymore")); + return FALSE; + } + if (!iter && ! (priv->sh->usage_flags & GDA_DATA_MODEL_ACCESS_RANDOM)) { + g_set_error (error, GDA_DATA_MODEL_ERROR, GDA_DATA_MODEL_ACCESS_ERROR, + "%s", _("Data model does only support random access")); + return FALSE; + } + if (! priv->sh->modif_internals->modif_stmts [UPD_QUERY]) { + g_set_error (error, GDA_DATA_SELECT_ERROR, GDA_DATA_SELECT_MISSING_MODIFICATION_STATEMENT_ERROR, + "%s", _("No UPDATE statement provided")); + return FALSE; + } + + if (iter) + row = gda_data_model_iter_get_row (iter); + + int_row = external_to_internal_row (imodel, row, error); + if (int_row < 0) + return FALSE; + + /* compute UPDATE statement */ + if (! priv->sh->modif_internals->upd_stmts) + priv->sh->modif_internals->upd_stmts = g_hash_table_new_full ((GHashFunc) bvector_hash, (GEqualFunc) bvector_equal, + (GDestroyNotify) bvector_free, g_object_unref); + stmt = g_hash_table_lookup (priv->sh->modif_internals->upd_stmts, bv); + if (! stmt) { + stmt = compute_single_update_stmt (imodel, bv, error); + if (stmt) { + free_bv = FALSE; + g_hash_table_insert (priv->sh->modif_internals->upd_stmts, bv, stmt); + } + else { + bvector_free (bv); + return FALSE; + } + } + + /* give values to params for old values */ + ncols = gda_data_select_get_n_columns ((GdaDataModel*) imodel); + for (i = 0; i < ncols; i++) { + str = g_strdup_printf ("-%d", i); + holder = gda_set_get_holder (priv->sh->modif_internals->modif_set, str); + g_free (str); + if (holder) { + const GValue *cvalue; + if (iter) { + cvalue = gda_data_model_iter_get_value_at (iter, i); + if (!cvalue) { + g_set_error (error, GDA_DATA_MODEL_ERROR, GDA_DATA_MODEL_ACCESS_ERROR, + "%s", _("Could not get iterator's value")); + return FALSE; + } + } + else { + cvalue = gda_data_model_get_value_at ((GdaDataModel*) imodel, i, row, error); + if (!cvalue) + return FALSE; + } + + if (! gda_holder_set_value (holder, cvalue, error)) + return FALSE; + } + } + + if (free_bv) + bvector_free (bv); + + /* actually execute UPDATE statement */ +#ifdef GDA_DEBUG_NO + gchar *sql; + GError *lerror = NULL; + sql = gda_statement_to_sql_extended (stmt, + priv->cnc, + priv->sh->modif_internals->modif_set, + GDA_STATEMENT_SQL_PRETTY, NULL, + &lerror); + g_print ("%s(): SQL=> %s\n", __FUNCTION__, sql); + if (!sql) + g_print ("\tERR: %s\n", lerror && lerror->message ? lerror->message : "No detail"); + g_free (sql); +#endif + + if (gda_connection_statement_execute_non_select (priv->cnc, stmt, + priv->sh->modif_internals->modif_set, + NULL, error) == -1) + return FALSE; + + /* mark that this row has been modified */ + DelayedSelectStmt *dstmt; + dstmt = g_new0 (DelayedSelectStmt, 1); + if (! priv->sh->modif_internals->one_row_select_stmt) + priv->sh->modif_internals->one_row_select_stmt = compute_single_select_stmt (imodel, error); + if (priv->sh->modif_internals->one_row_select_stmt) { + dstmt->select = g_object_ref (priv->sh->modif_internals->one_row_select_stmt); + gda_statement_get_parameters (dstmt->select, &(dstmt->params), NULL); + if (dstmt->params) { + GSList *list; + gboolean allok = TRUE; + + /* overwrite old values with new values if some have been provided */ + for (list = gda_set_get_holders (priv->sh->modif_internals->modif_set); list; + list = list->next) { + GdaHolder *h = (GdaHolder*) list->data; + gint res; + gboolean old; + if (gda_holder_is_valid ((GdaHolder*) list->data) && + param_name_to_int (gda_holder_get_id (h), &res, &old) && + !old) { + str = g_strdup_printf ("-%d", res); + holder = gda_set_get_holder (priv->sh->modif_internals->modif_set, + str); + g_free (str); + if (holder && + ! gda_holder_set_value (holder, gda_holder_get_value (h), error)) { + allok = FALSE; + break; + } + } + } + + for (list = gda_set_get_holders (dstmt->params); list && allok; list = list->next) { + GdaHolder *holder = GDA_HOLDER (list->data); + GdaHolder *eholder; + eholder = gda_set_get_holder (priv->sh->modif_internals->modif_set, + gda_holder_get_id (holder)); + if (!eholder || + ! gda_holder_set_value (holder, gda_holder_get_value (eholder), NULL)) { + allok = FALSE; + break; + } + } + + if (!allok) { + g_object_unref (dstmt->params); + dstmt->params = NULL; + } + } + } + dstmt->row = NULL; + if (! priv->sh->upd_rows) + priv->sh->upd_rows = g_hash_table_new_full (g_int_hash, g_int_equal, + g_free, + (GDestroyNotify) delayed_select_stmt_free); + gint *tmp = g_new (gint, 1); + *tmp = int_row; + g_hash_table_insert (priv->sh->upd_rows, tmp, dstmt); +#ifdef GDA_DEBUG_NO + dump_d (imodel); +#endif + + gda_data_model_row_updated ((GdaDataModel *) imodel, row); + + return TRUE; + +} + +static gboolean +check_data_model_for_updates (GdaDataSelect *imodel, + gint col, + const GValue *value, + GError **error) +{ + gint ncols; + GdaHolder *holder; + gchar *str; + GdaDataSelectPrivate *priv = gda_data_select_get_instance_private (GDA_DATA_SELECT (imodel)); + + if (priv->sh->modif_internals->safely_locked) { + g_set_error (error, GDA_DATA_SELECT_ERROR, GDA_DATA_SELECT_SAFETY_LOCKED_ERROR, + "%s", _("Modifications are not allowed anymore")); + return FALSE; + } + if (! priv->sh->modif_internals->modif_stmts [UPD_QUERY]) { + g_set_error (error, GDA_DATA_SELECT_ERROR, GDA_DATA_SELECT_MISSING_MODIFICATION_STATEMENT_ERROR, + "%s", _("No UPDATE statement provided")); + return FALSE; + } + /* arguments check */ + ncols = gda_data_select_get_n_columns (GDA_DATA_MODEL (imodel)); + if (col >= ncols) { + g_set_error (error, GDA_DATA_SELECT_ERROR, GDA_DATA_SELECT_MISSING_MODIFICATION_STATEMENT_ERROR, + _("Column %d out of range (0-%d)"), col, ncols-1); + return FALSE; + } + /* invalidate all the priv->sh->modif_internals->modif_set's value holders */ + GSList *list; + for (list = gda_set_get_holders (priv->sh->modif_internals->modif_set); list; list = list->next) { + GdaHolder *h = (GdaHolder*) list->data; + if (param_name_to_int (gda_holder_get_id (h), NULL, NULL)) + gda_holder_force_invalid ((GdaHolder*) list->data); + } + /* give values to params for new value */ + str = g_strdup_printf ("+%d", col); + holder = gda_set_get_holder (priv->sh->modif_internals->modif_set, str); + g_free (str); + if (! holder) { + g_set_error (error, GDA_DATA_SELECT_ERROR, + GDA_DATA_SELECT_MISSING_MODIFICATION_STATEMENT_ERROR, + _("Column %d can't be modified"), col); + return FALSE; + } + if (g_slist_find (priv->sh->modif_internals->modif_params[UPD_QUERY], holder)) { + if (!gda_holder_set_value (holder, value, error)) + return FALSE; + } + else + gda_holder_force_invalid (holder); + return TRUE; +} +static gboolean +gda_data_select_set_value_at (GdaDataModel *model, gint col, gint row, const GValue *value, GError **error) +{ + GdaDataSelectPrivate *priv = gda_data_select_get_instance_private (GDA_DATA_SELECT (model)); + + g_return_val_if_fail (priv, FALSE); + if (!check_data_model_for_updates (GDA_DATA_SELECT (model), col, value, error)) { + return FALSE; + } + if (! (priv->sh->usage_flags & GDA_DATA_MODEL_ACCESS_RANDOM)) { + g_set_error (error, GDA_DATA_MODEL_ERROR, GDA_DATA_MODEL_ACCESS_ERROR, + "%s", _("Data model does only support random access")); + return FALSE; + } + + /* BVector */ + BVector *bv; + bv = g_new (BVector, 1); + bv->size = col + 1; + bv->data = g_new0 (guchar, bv->size); + bv->data[col] = 1; + + return vector_set_value_at (GDA_DATA_SELECT (model), bv, NULL, row, error); +} + +static void +delayed_select_stmt_free (DelayedSelectStmt *dstmt) +{ + if (dstmt->select) + g_object_unref (dstmt->select); + if (dstmt->params) + g_object_unref (dstmt->params); + if (dstmt->row) + g_object_unref (dstmt->row); + if (dstmt->exec_error) + g_error_free (dstmt->exec_error); + g_free (dstmt); +} + +static gboolean +gda_data_select_set_values (GdaDataModel *model, gint row, GList *values, GError **error) +{ + gint i, ncols, nvalues; + GdaHolder *holder; + gchar *str; + GList *list; + GdaDataSelectPrivate *priv = gda_data_select_get_instance_private (GDA_DATA_SELECT (model)); + + + /* arguments check */ + g_return_val_if_fail (priv, FALSE); + + if (! (priv->sh->usage_flags & GDA_DATA_MODEL_ACCESS_RANDOM)) { + g_set_error (error, GDA_DATA_MODEL_ERROR, GDA_DATA_MODEL_ACCESS_ERROR, + "%s", _("Data model does only support random access")); + return FALSE; + } + + ncols = gda_data_select_get_n_columns (model); + nvalues = g_list_length (values); + if (nvalues > ncols) { + g_set_error (error, GDA_DATA_SELECT_ERROR, GDA_DATA_SELECT_MISSING_MODIFICATION_STATEMENT_ERROR, + _("Too many values (%d as maximum)"), ncols); + return FALSE; + } + + /* BVector */ + BVector *bv; + gboolean has_mods = FALSE; + + bv = g_new (BVector, 1); + bv->size = nvalues; + bv->data = g_new0 (guchar, bv->size); + for (i = 0, list = values; list; i++, list = list->next) { + if (list->data) { + bv->data[i] = 1; + has_mods = TRUE; + } + } + if (!has_mods) { + /* no actual modification to do */ + bvector_free (bv); + return TRUE; + } + + /* invalidate all the priv->sh->modif_internals->modif_set's value holders */ + GSList *slist; + for (slist = gda_set_get_holders (priv->sh->modif_internals->modif_set); slist; slist = slist->next) { + GdaHolder *h = (GdaHolder*) slist->data; + if (param_name_to_int (gda_holder_get_id (h), NULL, NULL)) + gda_holder_force_invalid ((GdaHolder*) slist->data); + } + + /* give values to params for new values */ + for (i = 0, list = values; list; i++, list = list->next) { + if (!bv->data[i]) + continue; + + str = g_strdup_printf ("+%d", i); + holder = gda_set_get_holder (priv->sh->modif_internals->modif_set, str); + g_free (str); + if (!holder) + continue; + + if (g_slist_find (priv->sh->modif_internals->modif_params[UPD_QUERY], holder)) { + if (!gda_holder_set_value (holder, (GValue *) list->data, error)) { + bvector_free (bv); + return FALSE; + } + } + else + gda_holder_force_invalid (holder); + } + + return vector_set_value_at (GDA_DATA_SELECT (model), bv, NULL, row, error); +} + +static gint +gda_data_select_append_values (GdaDataModel *model, const GList *values, GError **error) +{ + gint row, int_row, i; + GdaHolder *holder; + gchar *str; + const GList *list; + GdaDataSelectPrivate *priv = gda_data_select_get_instance_private (GDA_DATA_SELECT (model)); + + + g_return_val_if_fail (priv, -1); + + if (priv->sh->modif_internals->safely_locked) { + g_set_error (error, GDA_DATA_SELECT_ERROR, GDA_DATA_SELECT_SAFETY_LOCKED_ERROR, + "%s", _("Modifications are not allowed anymore")); + return -1; + } + if (! (priv->sh->usage_flags & GDA_DATA_MODEL_ACCESS_RANDOM)) { + g_set_error (error, GDA_DATA_MODEL_ERROR, GDA_DATA_MODEL_ACCESS_ERROR, + "%s", _("Data model does only support random access")); + return -1; + } + if (! priv->sh->modif_internals->modif_stmts [INS_QUERY]) { + g_set_error (error, GDA_DATA_SELECT_ERROR, GDA_DATA_SELECT_MISSING_MODIFICATION_STATEMENT_ERROR, + "%s", _("No INSERT statement provided")); + return -1; + } + if (gda_data_select_get_n_rows (model) < 0) { + g_set_error (error, GDA_DATA_SELECT_ERROR, GDA_DATA_SELECT_ACCESS_ERROR, + "%s", _("Cannot add a row because the number of rows is unknown")); + return -1; + } + + /* compute added row's number */ + row = priv->advertized_nrows; + if (priv->sh->del_rows) + row -= priv->sh->del_rows->len; + priv->advertized_nrows++; + int_row = external_to_internal_row (GDA_DATA_SELECT (model), row, error); + priv->advertized_nrows--; + + /* BVector */ + BVector *bv; + gboolean has_mods = FALSE, free_bv = TRUE; + + bv = g_new (BVector, 1); + bv->size = g_list_length ((GList*) values); + bv->data = g_new0 (guchar, bv->size); + for (i = 0, list = values; list; i++, list = list->next) { + if (list->data) { + bv->data[i] = 1; + has_mods = TRUE; + } + } + if (!has_mods) { + /* no actual modification to do */ + bvector_free (bv); + g_set_error (error, GDA_DATA_SELECT_ERROR, GDA_DATA_SELECT_MODIFICATION_STATEMENT_ERROR, + "%s", _("Missing values to insert in INSERT statement")); + + return -1; + } + + /* compute INSERT statement */ + GdaStatement *stmt; + if (! priv->sh->modif_internals->ins_stmts) + priv->sh->modif_internals->ins_stmts = g_hash_table_new_full ((GHashFunc) bvector_hash, + (GEqualFunc) bvector_equal, + (GDestroyNotify) bvector_free, + g_object_unref); + stmt = g_hash_table_lookup (priv->sh->modif_internals->ins_stmts, bv); + if (! stmt) { + stmt = compute_single_insert_stmt (GDA_DATA_SELECT (model), bv, error); + if (stmt) { + free_bv = FALSE; + g_hash_table_insert (priv->sh->modif_internals->ins_stmts, bv, stmt); + } + else { + bvector_free (bv); + return -1; + } + } + + /* give values to params for new values */ + for (i = 0, list = values; list; i++, list = list->next) { + if (!bv->data[i]) + continue; + + str = g_strdup_printf ("+%d", i); + holder = gda_set_get_holder (priv->sh->modif_internals->modif_set, str); + g_free (str); + if (! holder) { + /* ignore this value as it won't be used */ + continue; + } + if (!g_slist_find (priv->sh->modif_internals->modif_params[INS_QUERY], holder)) { + gda_holder_force_invalid (holder); + continue; + } + + if (! gda_holder_set_value (holder, (GValue *) list->data, error)) { + if (free_bv) + bvector_free (bv); + return -1; + } + } + + if (free_bv) + bvector_free (bv); + + /* actually execute INSERT statement */ +#ifdef GDA_DEBUG_NO + gchar *sql; + GError *lerror = NULL; + sql = gda_statement_to_sql_extended (stmt, + priv->cnc, + priv->sh->modif_internals->modif_set, + GDA_STATEMENT_SQL_PRETTY, NULL, + &lerror); + g_print ("%s(): SQL=> %s\n", __FUNCTION__, sql); + if (!sql) { + gchar *tmp; + g_print ("\tERR: %s\n", lerror && lerror->message ? lerror->message : "No detail"); + tmp = gda_statement_serialize (stmt); + g_print ("\tSER: %s\n", tmp); + g_free (tmp); + } + g_free (sql); +#endif + + if (! priv->sh->modif_internals->one_row_select_stmt) { + priv->sh->modif_internals->one_row_select_stmt = + compute_single_select_stmt (GDA_DATA_SELECT (model), error); + } + + GdaSet *last_insert; + if (gda_connection_statement_execute_non_select (priv->cnc, stmt, + priv->sh->modif_internals->modif_set, + &last_insert, error) == -1) + return -1; + + /* mark that this row has been modified */ + DelayedSelectStmt *dstmt; + dstmt = g_new0 (DelayedSelectStmt, 1); + if (last_insert && priv->sh->modif_internals->one_row_select_stmt) { + dstmt->select = g_object_ref (priv->sh->modif_internals->one_row_select_stmt); + gda_statement_get_parameters (dstmt->select, &(dstmt->params), NULL); + if (dstmt->params) { + GSList *list; + if (! priv->sh->modif_internals->insert_to_select_mapping) + priv->sh->modif_internals->insert_to_select_mapping = + compute_insert_select_params_mapping (dstmt->params, last_insert, + priv->sh->modif_internals->unique_row_condition); + if (priv->sh->modif_internals->insert_to_select_mapping) { + for (list = gda_set_get_holders (dstmt->params); list; list = list->next) { + GdaHolder *holder = GDA_HOLDER (list->data); + GdaHolder *eholder; + gint pos; + + g_assert (param_name_to_int (gda_holder_get_id (holder), &pos, NULL)); + + eholder = g_slist_nth_data (gda_set_get_holders (last_insert), + priv->sh->modif_internals->insert_to_select_mapping[pos]); + if (!eholder || + ! gda_holder_set_value (holder, gda_holder_get_value (eholder), error)) { + g_object_unref (dstmt->params); + dstmt->params = NULL; + break; + } + } + } + } + } + if (last_insert) { + g_object_unref (last_insert); + last_insert = NULL; + } + + dstmt->row = NULL; + if (! priv->sh->upd_rows) + priv->sh->upd_rows = g_hash_table_new_full (g_int_hash, g_int_equal, + g_free, + (GDestroyNotify) delayed_select_stmt_free); + gint *tmp = g_new (gint, 1); + *tmp = int_row; + g_hash_table_insert (priv->sh->upd_rows, tmp, dstmt); +#ifdef GDA_DEBUG_NO + dump_d (GDA_DATA_SELECT (model)); +#endif + priv->advertized_nrows++; + gda_data_model_row_inserted ((GdaDataModel *) GDA_DATA_SELECT (model), row); + + return row; +} + + +static gboolean +gda_data_select_remove_row (GdaDataModel *model, gint row, GError **error) +{ + guint i, ncols; + gint int_row, index; + GdaHolder *holder; + gchar *str; + GdaDataSelectPrivate *priv = gda_data_select_get_instance_private (GDA_DATA_SELECT (model)); + + g_return_val_if_fail (priv, FALSE); + + if (priv->sh->modif_internals->safely_locked) { + g_set_error (error, GDA_DATA_SELECT_ERROR, GDA_DATA_SELECT_SAFETY_LOCKED_ERROR, + "%s", _("Modifications are not allowed anymore")); + return FALSE; + } + if (! (priv->sh->usage_flags & GDA_DATA_MODEL_ACCESS_RANDOM)) { + g_set_error (error, GDA_DATA_MODEL_ERROR, GDA_DATA_MODEL_ACCESS_ERROR, + "%s", _("Data model does only support random access")); + return FALSE; + } + if (! priv->sh->modif_internals->modif_stmts [DEL_QUERY]) { + g_set_error (error, GDA_DATA_SELECT_ERROR, GDA_DATA_SELECT_MISSING_MODIFICATION_STATEMENT_ERROR, + "%s", _("No DELETE statement provided")); + return FALSE; + } + + int_row = external_to_internal_row (GDA_DATA_SELECT (model), row, error); + if (int_row < 0) + return FALSE; + + ncols = gda_data_select_get_n_columns (model); + for (i = 0; i < ncols; i++) { + str = g_strdup_printf ("-%d", i); + holder = gda_set_get_holder (priv->sh->modif_internals->modif_set, str); + g_free (str); + if (holder) { + if (!g_slist_find (priv->sh->modif_internals->modif_params[DEL_QUERY], + holder)) { + gda_holder_force_invalid (holder); + continue; + } + const GValue *cvalue; + cvalue = gda_data_model_get_value_at (model, i, row, error); + if (!cvalue) + return FALSE; + if (! gda_holder_set_value (holder, cvalue, error)) + return FALSE; + } + } + +#ifdef GDA_DEBUG_NO + gchar *sql; + GError *lerror = NULL; + sql = gda_statement_to_sql_extended (priv->sh->modif_internals->modif_stmts [DEL_QUERY], + priv->cnc, + priv->sh->modif_internals->modif_set, + GDA_STATEMENT_SQL_PRETTY, NULL, + &lerror); + g_print ("%s(): SQL=> %s\n", __FUNCTION__, sql); + if (!sql) + g_print ("\tERR: %s\n", lerror && lerror->message ? lerror->message : "No detail"); + g_free (sql); +#endif + if (gda_connection_statement_execute_non_select (priv->cnc, + priv->sh->modif_internals->modif_stmts [DEL_QUERY], + priv->sh->modif_internals->modif_set, NULL, error) == -1) + return FALSE; + + /* mark that this row has been removed */ + if (!priv->sh->del_rows) + priv->sh->del_rows = g_array_new (FALSE, FALSE, sizeof (gint)); + for (index = 0, i = 0; i < priv->sh->del_rows->len; i++, index++) { + if (g_array_index (priv->sh->del_rows, gint, i) >= int_row) + break; + } + + g_array_insert_val (priv->sh->del_rows, index, int_row); + gda_data_model_row_removed (model, row); + + return TRUE; +} + +static void +gda_data_select_freeze (GdaDataModel *model) +{ + GdaDataSelectPrivate *priv = gda_data_select_get_instance_private (GDA_DATA_SELECT (model)); + priv->sh->notify_changes = FALSE; +} + +static void +gda_data_select_thaw (GdaDataModel *model) +{ + GdaDataSelectPrivate *priv = gda_data_select_get_instance_private (GDA_DATA_SELECT (model)); + priv->sh->notify_changes = TRUE; +} + +static gboolean +gda_data_select_get_notify (GdaDataModel *model) +{ + GdaDataSelectPrivate *priv = gda_data_select_get_instance_private (GDA_DATA_SELECT (model)); + return priv->sh->notify_changes; +} + +static GError ** +gda_data_select_get_exceptions (GdaDataModel *model) +{ + GdaDataSelectPrivate *priv = gda_data_select_get_instance_private (GDA_DATA_SELECT (model)); + + if (priv->exceptions && (priv->exceptions->len > 0)) + return (GError **) priv->exceptions->pdata; + else + return NULL; +} + +/** + * gda_data_select_add_exception: + * @model: a #GdaDataSelect + * @error: (transfer full): an error to add as exception + * + * Add an exception to @model. + * + * Since: 4.2.6 + */ +void +gda_data_select_add_exception (GdaDataSelect *model, GError *error) +{ + GdaDataSelectPrivate *priv = gda_data_select_get_instance_private (GDA_DATA_SELECT (model)); + + g_return_if_fail (GDA_IS_DATA_SELECT (model)); + g_return_if_fail (error); + g_return_if_fail (error->message); + + if (priv->exceptions == NULL) + priv->exceptions = g_ptr_array_new_with_free_func ((GDestroyNotify) g_error_free); + g_ptr_array_add (priv->exceptions, error); +} + +/* + * The following function creates a correspondance between the parameters required to + * execute the one_row_select_stmt statement (GdaHolders named "-", in ), and the GdaHolder + * returned after having executed the modif_stmts[INS_QUERY] INSERT statement. + * + * The way of preceeding is: + * - for each parameter required by one_row_select_stmt statement (the @sel_params argument), + * use the priv->sh->modif_internals->unique_row_condition to get the name of the corresponding column (the GdaHolder's ID + * is "-" ) + * - from the column name get the GdaHolder in the GdaSet retruned after the INSERT statement (the + * @ins_values argument) using the "name" property of each GdaHolder in the GdaSet (the GdaHolder's ID + * is "+" ) + * - add an entry in the returned array: array[num1] = num2 + */ +typedef struct { + const gchar *hid; + const gchar *colid; +} CorrespData; +static gboolean compute_insert_select_params_mapping_foreach_func (GdaSqlAnyPart *part, CorrespData *data, GError **error); +static gint * +compute_insert_select_params_mapping (GdaSet *sel_params, GdaSet *ins_values, GdaSqlExpr *row_cond) +{ + GArray *array; + gint *retval; + GSList *sel_list; + + array = g_array_new (FALSE, TRUE, sizeof (gint)); + for (sel_list = gda_set_get_holders (sel_params); sel_list; sel_list = sel_list->next) { + CorrespData cdata; + const gchar *pid = gda_holder_get_id (GDA_HOLDER (sel_list->data)); + cdata.hid = pid; + cdata.colid = NULL; + + gint spnum, ipnum; + gboolean spold, ipold; + if (! param_name_to_int (pid, &spnum, &spold) || !spold) + continue; + + if (gda_sql_any_part_foreach (GDA_SQL_ANY_PART (row_cond), + (GdaSqlForeachFunc) compute_insert_select_params_mapping_foreach_func, + &cdata, NULL)) { + g_warning ("Could not find column for parameter '%s'", cdata.hid); + goto onerror; + } + g_assert (cdata.colid); + if ((*(cdata.colid) == '"') || (*(cdata.colid) == '`')) + gda_sql_identifier_prepare_for_compare ((gchar*) cdata.colid); + /*g_print ("SEL param '%s' <=> column named '%s'\n", cdata.hid, cdata.colid);*/ + + GSList *ins_list; + cdata.hid = NULL; + for (ins_list = gda_set_get_holders (ins_values); ins_list; ins_list = ins_list->next) { + gchar *name; + g_object_get (G_OBJECT (ins_list->data), "name", &name, NULL); + if (!name) { + g_warning ("Provider does not report column names"); + goto onerror; + } + if (!strcmp (name, cdata.colid)) { + cdata.hid = gda_holder_get_id (GDA_HOLDER (ins_list->data)); + g_free (name); + break; + } + g_free (name); + } + + if (!cdata.hid) { + g_warning ("Could not find column named '%s'", cdata.colid); + goto onerror; + } + + /*g_print ("column named '%s' <=> INS param '%s'\n", cdata.colid, cdata.hid);*/ + + if (! param_name_to_int (cdata.hid, &ipnum, &ipold) || ipold) { + g_warning ("Provider reported a malformed parameter named '%s'", cdata.hid); + goto onerror; + } + + g_array_insert_val (array, spnum, ipnum); + } + + retval = (gint *) array->data; + g_array_free (array, FALSE); + return retval; + + onerror: + g_array_free (array, TRUE); + return NULL; +} + +static gboolean +compute_insert_select_params_mapping_foreach_func (GdaSqlAnyPart *part, CorrespData *data, + G_GNUC_UNUSED GError **error) +{ + if (part->type != GDA_SQL_ANY_SQL_OPERATION) + return TRUE; + + GdaSqlOperation *op = (GdaSqlOperation*) part; + if (op->operator_type != GDA_SQL_OPERATOR_TYPE_EQ) + return TRUE; + + if (!op->operands || !op->operands->data || !op->operands->next || !op->operands->next->data || + op->operands->next->next) + return TRUE; + + GdaSqlExpr *e1, *e2; + e1 = (GdaSqlExpr *) op->operands->data; + e2 = (GdaSqlExpr *) op->operands->next->data; + if (e2->value && e1->param_spec) { + /* swap e1 and e2 */ + GdaSqlExpr *ex = e1; + e1 = e2; + e2 = ex; + } + if (e1->value && e2->param_spec) { + /* e1->value should be a column name */ + /* e2->param_spec should be a parameter */ + if (e2->param_spec->name && !strcmp (e2->param_spec->name, data->hid)) { + if (G_VALUE_TYPE (e1->value) != G_TYPE_STRING) + return TRUE; + data->colid = g_value_get_string (e1->value); + if (* data->colid) + return FALSE; + data->colid = NULL; + return TRUE; + } + } + return TRUE; +} + +static void +set_column_properties_from_select_stmt (GdaDataSelect *model, GdaConnection *cnc, GdaStatement *sel_stmt) +{ + GdaSqlStatement *sqlst = NULL; + GdaSqlStatementSelect *select; + GdaSqlSelectTarget *target; + GSList *fields, *columns; + GdaDataSelectPrivate *priv = gda_data_select_get_instance_private (model); + + g_object_get (G_OBJECT (sel_stmt), "structure", &sqlst, NULL); + g_assert (sqlst->stmt_type == GDA_SQL_STATEMENT_SELECT); + select = (GdaSqlStatementSelect*) sqlst->contents; + + /* we only want a single target */ + if (!select->from || !select->from->targets || select->from->targets->next) + goto out; + + target = (GdaSqlSelectTarget *) select->from->targets->data; + if (!target || !target->table_name) + goto out; + + if (! gda_sql_statement_check_validity (sqlst, cnc, NULL)) + goto out; + + if (!target->validity_meta_object) { + g_warning ("Internal gda_sql_statement_check_validity() error: target->validity_meta_object is not set"); + goto out; + } + + /* FIXME: also set some column attributes using gda_column_set_attribute() */ + + for (fields = select->expr_list, columns = priv->sh->columns; + fields && columns; + fields = fields->next) { + GdaSqlSelectField *selfield = (GdaSqlSelectField*) fields->data; + if (selfield->validity_meta_table_column) { + GdaMetaTableColumn *tcol = selfield->validity_meta_table_column; + + /*g_print ("==> %s\n", tcol->column_name);*/ + gda_column_set_allow_null (GDA_COLUMN (columns->data), tcol->nullok); + if (tcol->default_value) { + GValue *dvalue; + g_value_set_string ((dvalue = gda_value_new (G_TYPE_STRING)), tcol->default_value); + gda_column_set_default_value (GDA_COLUMN (columns->data), dvalue); + gda_value_free (dvalue); + } + columns = columns->next; + } + else if (selfield->validity_meta_object && + (selfield->validity_meta_object->obj_type == GDA_META_DB_TABLE) && + selfield->expr && selfield->expr->value && !selfield->expr->param_spec && + (G_VALUE_TYPE (selfield->expr->value) == G_TYPE_STRING) && + !strcmp (g_value_get_string (selfield->expr->value), "*")) { + /* expand all the fields */ + GdaMetaTable *mtable = GDA_META_TABLE (selfield->validity_meta_object); + GSList *tmplist; + for (tmplist = mtable->columns; tmplist; tmplist = tmplist->next) { + GdaMetaTableColumn *tcol = (GdaMetaTableColumn*) tmplist->data; + /*g_print ("*==> %s\n", tcol->column_name);*/ + gda_column_set_allow_null (GDA_COLUMN (columns->data), tcol->nullok); + if (tcol->default_value) { + GValue *dvalue; + g_value_set_string ((dvalue = gda_value_new (G_TYPE_STRING)), tcol->default_value); + gda_column_set_default_value (GDA_COLUMN (columns->data), dvalue); + gda_value_free (dvalue); + } + if (tmplist) + columns = columns->next; + } + } + else + columns = columns->next; + } + if (fields || columns) + g_warning (_("Internal error: GdaDataSelect has %d GdaColumns, and SELECT statement has %d expressions"), + g_slist_length (priv->sh->columns), g_slist_length (select->expr_list)); + + out: + gda_sql_statement_free (sqlst); +} + + +/** + * gda_data_select_compute_columns_attributes: + * @model: a #GdaDataSelect data model + * @error: (nullable): a place to store errors, or %NULL + * + * Computes correct attributes for each of @model's columns, which includes the "NOT NULL" attribute, the + * default value, the precision and scale for numeric values. + * + * Returns: TRUE if no error occurred + */ +gboolean +gda_data_select_compute_columns_attributes (GdaDataSelect *model, GError **error) +{ + GdaStatement *sel_stmt; + + g_return_val_if_fail (GDA_IS_DATA_SELECT (model), FALSE); + GdaDataSelectPrivate *priv = gda_data_select_get_instance_private (model); + + sel_stmt = check_acceptable_statement (model, error); + if (! sel_stmt) + return FALSE; + + if (!priv->cnc) { + g_set_error (error, GDA_DATA_SELECT_ERROR, GDA_DATA_SELECT_CONNECTION_ERROR, + "%s", _("No connection to use")); + return FALSE; + } + + set_column_properties_from_select_stmt (model, priv->cnc, sel_stmt); + + return TRUE; +} + +/** + * gda_data_select_rerun: + * @model: a #GdaDataSelect data model + * @error: (nullable): a place to store errors, or %NULL + * + * Requests that @model be re-run to have an updated result. If an error occurs, + * then @model will not be changed. + * + * Returns: %TRUE if no error occurred + * + * Since: 4.2 + */ +gboolean +gda_data_select_rerun (GdaDataSelect *model, GError **error) +{ + g_return_val_if_fail (GDA_IS_DATA_SELECT (model), FALSE); + + GdaDataSelect *new_model; + GdaStatement *select; + GdaDataSelectPrivate *priv = gda_data_select_get_instance_private (model); + + select = check_acceptable_statement (model, error); + if (!select) + return FALSE; + g_assert (priv->prep_stmt); + GType *types = NULL; + + if (gda_pstmt_get_types (priv->prep_stmt)) { + types = g_new (GType, gda_pstmt_get_ncols (priv->prep_stmt) + 1); + memcpy (types, gda_pstmt_get_types (priv->prep_stmt), /* Flawfinder: ignore */ + sizeof (GType) * gda_pstmt_get_ncols (priv->prep_stmt)); + types [gda_pstmt_get_ncols (priv->prep_stmt)] = G_TYPE_NONE; + } + new_model = (GdaDataSelect*) gda_connection_statement_execute_select_full (priv->cnc, select, + priv->sh->ext_params, + priv->sh->usage_flags | GDA_STATEMENT_MODEL_ALLOW_NOPARAM, + types, + error); + g_free (types); + + if (!new_model) { + /* FIXME: clear all the rows in @model, and emit the "reset" signal */ + return FALSE; + } + + g_assert (G_OBJECT_TYPE (model) == G_OBJECT_TYPE (new_model)); + + /* Raw model and new_model contents swap (except for the GObject part) */ + GdaDataSelect *old_model = new_model; /* renamed for code's readability */ + GdaDataSelectPrivate *old_priv = gda_data_select_get_instance_private (old_model); + if (old_priv->ext_params_changed_sig_id) { + g_signal_handler_disconnect (old_priv->sh->ext_params, + old_priv->ext_params_changed_sig_id); + old_priv->ext_params_changed_sig_id = 0; + } + if (priv->ext_params_changed_sig_id) { + g_signal_handler_disconnect (priv->sh->ext_params, + priv->ext_params_changed_sig_id); + priv->ext_params_changed_sig_id = 0; + } + + GTypeQuery tq; + gpointer copy; + gint offset = sizeof (GObject); + gint size; + g_type_query (G_OBJECT_TYPE (model), &tq); + size = tq.instance_size - offset; + copy = g_malloc (size); + memcpy (copy, (gint8*) new_model + offset, size); /* Flawfinder: ignore */ + memcpy ((gint8*) new_model + offset, (gint8*) model + offset, size); /* Flawfinder: ignore */ + memcpy ((gint8*) model + offset, copy, size); /* Flawfinder: ignore */ + g_free (copy); + + /* we need to keep some data from the old model */ + GdaDataSelectInternals *mi; + + priv->sh->notify_changes = old_priv->sh->notify_changes; + mi = old_priv->sh->modif_internals; + old_priv->sh->modif_internals = priv->sh->modif_internals; + priv->sh->modif_internals = mi; + + copy = old_priv->sh->sel_stmt; + old_priv->sh->sel_stmt = priv->sh->sel_stmt; + priv->sh->sel_stmt = (GdaStatement*) copy; + + /* keep the same GdaColumn pointers */ + GSList *l1, *l2; + l1 = old_priv->sh->columns; + old_priv->sh->columns = priv->sh->columns; + priv->sh->columns = l1; + for (l1 = priv->sh->columns, l2 = old_priv->sh->columns; + l1 && l2; + l1 = l1->next, l2 = l2->next) { + if ((gda_column_get_g_type ((GdaColumn*) l1->data) == GDA_TYPE_NULL) && + (gda_column_get_g_type ((GdaColumn*) l2->data) != GDA_TYPE_NULL)) + gda_column_set_g_type ((GdaColumn*) l1->data, + gda_column_get_g_type ((GdaColumn*) l2->data)); + } + + g_object_unref (old_model); + + /* copy all the param's holders' values from priv->sh->ext_params to + to priv->sh->modif_internals->exec_set */ + GSList *list; + if (priv->sh->ext_params) { + for (list = gda_set_get_holders (priv->sh->ext_params); list; list = list->next) { + GdaHolder *h; + h = gda_set_get_holder (priv->sh->modif_internals->exec_set, + gda_holder_get_id (list->data)); + if (h) { + GError *lerror = NULL; + if (!gda_holder_is_valid (GDA_HOLDER (list->data))) + gda_holder_set_value (h, gda_holder_get_value (GDA_HOLDER (list->data)), NULL); + else if (! gda_holder_set_value (h, gda_holder_get_value (GDA_HOLDER (list->data)), + &lerror)) { + g_warning (_("An error has occurred, the value returned by the \"exec-params\" " + "property will be wrong: %s"), + lerror && lerror->message ? lerror->message : _("No detail")); + g_clear_error (&lerror); + } + } + } + } + + /* signal a reset */ + gda_data_model_reset ((GdaDataModel*) model); + + return TRUE; +} + +/** + * gda_data_select_prepare_for_offline: + * @model: a #GdaDataSelect object + * @error: (nullable): a place to store errors, or %NULL + * + * Use this method to make sure all the data contained in the data model are stored on the client + * side (and that no subsquent call to the server will be necessary to access that data), at the cost of + * a higher memory consumption. + * + * This method is useful in the following situations: + * + * You need to disconnect from the server and continue to use the data in the data model + * You need to make sure the data in the data model can be used even though the connection to the server may be used for other purposes (for example executing other queries) + * + * + * Note that this method will fail if: + * + * the data model contains any blobs (because blobs reading requires acces to the server); + * binary values are Ok, though. + * the data model has been modified since it was created + * + * + * Returns: %TRUE if no error occurred + * + * Since: 5.2.0 + */ +gboolean +gda_data_select_prepare_for_offline (GdaDataSelect *model, GError **error) +{ + g_return_val_if_fail (GDA_IS_DATA_SELECT (model), FALSE); + GdaDataSelectPrivate *priv = gda_data_select_get_instance_private (model); + + /* checks */ + gint i, ncols; + if (! (priv->sh->usage_flags & GDA_STATEMENT_MODEL_RANDOM_ACCESS)) { + g_set_error (error, GDA_DATA_SELECT_ERROR, GDA_DATA_SELECT_ACCESS_ERROR, + "%s", _("Data model does not support random access")); + return FALSE; + } + if (priv->sh->upd_rows || priv->sh->del_rows) { + g_set_error (error, GDA_DATA_SELECT_ERROR, GDA_DATA_SELECT_ACCESS_ERROR, + "%s", _("Data model has been modified")); + return FALSE; + } + ncols = gda_data_model_get_n_columns ((GdaDataModel*) model); + for (i = 0; i < ncols; i++) { + GdaColumn *gdacol; + gdacol = gda_data_model_describe_column ((GdaDataModel*) model, i); + if (gda_column_get_g_type (gdacol) == GDA_TYPE_BLOB) { + g_set_error (error, GDA_DATA_SELECT_ERROR, GDA_DATA_SELECT_ACCESS_ERROR, + "%s", _("Data model contains BLOBs")); + return FALSE; + } + } + + /* fetching data */ + if (priv->advertized_nrows < 0) { + if (CLASS (model)->fetch_nb_rows) + _gda_data_select_fetch_nb_rows (model); + if (priv->advertized_nrows < 0) { + g_set_error (error, GDA_DATA_SELECT_ERROR, GDA_DATA_SELECT_ACCESS_ERROR, + "%s", _("Can't get the number of rows of data model")); + return FALSE; + } + } + + if (priv->nb_stored_rows != priv->advertized_nrows) { + if (CLASS (model)->store_all) { + if (! _gda_data_select_store_all (model, error)) + return FALSE; + } + } + + /* final check/complement */ + for (i = 0; i < priv->advertized_nrows; i++) { + if (!g_hash_table_lookup (priv->sh->index, &i)) { + GdaRow *prow; + if (! _gda_data_select_fetch_at (model, &prow, i, error)) + return FALSE; + g_assert (prow); + gda_data_select_take_row (model, prow, i); + } + } + return TRUE; +} + + +/* + * Implementation using GdaWorker + */ + +static gpointer +worker_fetch_nb_rows (GdaDataSelect *model, GError **error) +{ + gint *nbrows; + nbrows = g_slice_new (gint); + if (CLASS (model)->fetch_nb_rows) + *nbrows = CLASS (model)->fetch_nb_rows (model); + else + *nbrows = -1; + + return (gpointer) nbrows; +} + +static gint +_gda_data_select_fetch_nb_rows (GdaDataSelect *model) +{ + GdaDataSelectPrivate *priv = gda_data_select_get_instance_private (model); + GMainContext *context; + context = gda_server_provider_get_real_main_context (priv->cnc); + + gint nbrows = -1; + gint *result; + if (gda_worker_do_job (priv->worker, context, 0, (gpointer) &result, NULL, + (GdaWorkerFunc) worker_fetch_nb_rows, model, NULL, NULL, NULL)) { + nbrows = *result; + g_slice_free (gint, result); + } + if (context) + g_main_context_unref (context); + + return nbrows; +} + +/***********************************************************************************************************/ + +typedef struct { + GdaDataSelect *model; + GdaRow **prow; + gint rownum; +} WorkerData; + +static gpointer +worker_fetch_random (WorkerData *data, GError **error) +{ + gboolean res; + if (CLASS (data->model)->fetch_random) + res = CLASS (data->model)->fetch_random (data->model, data->prow, data->rownum, error); + else + res = FALSE; + + return res ? (gpointer) 0x01 : NULL; +} + +static gboolean +_gda_data_select_fetch_random (GdaDataSelect *model, GdaRow **prow, gint rownum, GError **error) +{ + GdaDataSelectPrivate *priv = gda_data_select_get_instance_private (model); + GMainContext *context; + context = gda_server_provider_get_real_main_context (priv->cnc); + + WorkerData jdata; + jdata.model = model; + jdata.prow = prow; + jdata.rownum = rownum; + + gpointer result; + gda_worker_do_job (priv->worker, context, 0, &result, NULL, + (GdaWorkerFunc) worker_fetch_random, &jdata, NULL, NULL, error); + if (context) + g_main_context_unref (context); + return result ? TRUE : FALSE; +} + +/***********************************************************************************************************/ + +static gpointer +worker_store_all (GdaDataSelect *model, GError **error) +{ + gboolean res; + if (CLASS (model)->store_all) + res = CLASS (model)->store_all (model, error); + else + res = FALSE; + + return res ? (gpointer) 0x01 : NULL; +} + +static gboolean +_gda_data_select_store_all (GdaDataSelect *model, GError **error) +{ + GdaDataSelectPrivate *priv = gda_data_select_get_instance_private (model); + GMainContext *context; + context = gda_server_provider_get_real_main_context (priv->cnc); + + gpointer result; + gda_worker_do_job (priv->worker, context, 0, (gpointer) &result, NULL, + (GdaWorkerFunc) worker_store_all, model, NULL, NULL, NULL); + if (context) + g_main_context_unref (context); + return result ? TRUE : FALSE; +} + +/***********************************************************************************************************/ + +static gpointer +worker_fetch_next (WorkerData *data, GError **error) +{ + gboolean res; + if (CLASS (data->model)->fetch_next) + res = CLASS (data->model)->fetch_next (data->model, data->prow, data->rownum, error); + else + res = FALSE; + + return res ? (gpointer) 0x01 : NULL; +} + +static gboolean +_gda_data_select_fetch_next (GdaDataSelect *model, GdaRow **prow, gint rownum, GError **error) +{ + GdaDataSelectPrivate *priv = gda_data_select_get_instance_private (model); + GMainContext *context; + context = gda_server_provider_get_real_main_context (priv->cnc); + + WorkerData jdata; + jdata.model = model; + jdata.prow = prow; + jdata.rownum = rownum; + + gpointer result; + gda_worker_do_job (priv->worker, context, 0, &result, NULL, + (GdaWorkerFunc) worker_fetch_next, &jdata, NULL, NULL, error); + if (context) + g_main_context_unref (context); + return result ? TRUE : FALSE; +} + +/***********************************************************************************************************/ + +static gpointer +worker_fetch_prev (WorkerData *data, GError **error) +{ + gboolean res; + if (CLASS (data->model)->fetch_prev) + res = CLASS (data->model)->fetch_prev (data->model, data->prow, data->rownum, error); + else + res = FALSE; + + return res ? (gpointer) 0x01 : NULL; +} + +static gboolean +_gda_data_select_fetch_prev (GdaDataSelect *model, GdaRow **prow, gint rownum, GError **error) +{ + GdaDataSelectPrivate *priv = gda_data_select_get_instance_private (model); + GMainContext *context; + context = gda_server_provider_get_real_main_context (priv->cnc); + + WorkerData jdata; + jdata.model = model; + jdata.prow = prow; + jdata.rownum = rownum; + + gpointer result; + gda_worker_do_job (priv->worker, context, 0, &result, NULL, + (GdaWorkerFunc) worker_fetch_prev, &jdata, NULL, NULL, error); + if (context) + g_main_context_unref (context); + return result ? TRUE : FALSE; +} + +/***********************************************************************************************************/ + +static gpointer +worker_fetch_at (WorkerData *data, GError **error) +{ + gboolean res; + if (CLASS (data->model)->fetch_at) + res = CLASS (data->model)->fetch_at (data->model, data->prow, data->rownum, error); + else + res = FALSE; + + return res ? (gpointer) 0x01 : NULL; +} + +static gboolean +_gda_data_select_fetch_at (GdaDataSelect *model, GdaRow **prow, gint rownum, GError **error) +{ + GdaDataSelectPrivate *priv = gda_data_select_get_instance_private (model); + GMainContext *context; + context = gda_server_provider_get_real_main_context (priv->cnc); + + WorkerData jdata; + jdata.model = model; + jdata.prow = prow; + jdata.rownum = rownum; + + gpointer result; + gda_worker_do_job (priv->worker, context, 0, &result, NULL, + (GdaWorkerFunc) worker_fetch_at, &jdata, NULL, NULL, error); + if (context) + g_main_context_unref (context); + return result ? TRUE : FALSE; +} + +/* Private API for providers */ +GdaPStmt* +gda_data_select_get_prep_stmt (GdaDataSelect *model) +{ + GdaDataSelectPrivate *priv = gda_data_select_get_instance_private (model); + return priv->prep_stmt; +} + +gint +gda_data_select_get_nb_stored_rows (GdaDataSelect *model) +{ + GdaDataSelectPrivate *priv = gda_data_select_get_instance_private (model); + return priv->nb_stored_rows; +} + +gint +gda_data_select_get_advertized_nrows (GdaDataSelect *model) +{ + GdaDataSelectPrivate *priv = gda_data_select_get_instance_private (model); + return priv->advertized_nrows; +} + +void +gda_data_select_set_advertized_nrows (GdaDataSelect *model, gint n) +{ + GdaDataSelectPrivate *priv = gda_data_select_get_instance_private (model); + priv->advertized_nrows = n; +} diff --git a/.flatpak-builder/cache/objects/ef/085dd09fc9201b53d2d1fc8b2fabad6c5b4611a904e12b235064d9bc27093c.commit b/.flatpak-builder/cache/objects/ef/085dd09fc9201b53d2d1fc8b2fabad6c5b4611a904e12b235064d9bc27093c.commit new file mode 100644 index 0000000..bd82dc7 Binary files /dev/null and b/.flatpak-builder/cache/objects/ef/085dd09fc9201b53d2d1fc8b2fabad6c5b4611a904e12b235064d9bc27093c.commit differ diff --git a/.flatpak-builder/cache/objects/ef/f46b2535d9ca0f9e42b1c778e4f5805c6491fd1084970d80eb42a7785b7143.dirtree b/.flatpak-builder/cache/objects/ef/f46b2535d9ca0f9e42b1c778e4f5805c6491fd1084970d80eb42a7785b7143.dirtree new file mode 100644 index 0000000..f65668c Binary files /dev/null and b/.flatpak-builder/cache/objects/ef/f46b2535d9ca0f9e42b1c778e4f5805c6491fd1084970d80eb42a7785b7143.dirtree differ diff --git a/.flatpak-builder/cache/objects/f0/89232141a96328d7cad39b341597f76042eef04f7fc3111c0471ee0b04c587.dirtree b/.flatpak-builder/cache/objects/f0/89232141a96328d7cad39b341597f76042eef04f7fc3111c0471ee0b04c587.dirtree new file mode 100644 index 0000000..c8c0c5a Binary files /dev/null and b/.flatpak-builder/cache/objects/f0/89232141a96328d7cad39b341597f76042eef04f7fc3111c0471ee0b04c587.dirtree differ diff --git a/.flatpak-builder/cache/objects/f0/a7fa4cbe2e1b13ba12785c1f6b980e2bfc35afcccd1b9786dc59232db8f23d.commit b/.flatpak-builder/cache/objects/f0/a7fa4cbe2e1b13ba12785c1f6b980e2bfc35afcccd1b9786dc59232db8f23d.commit new file mode 100644 index 0000000..0220d09 Binary files /dev/null and b/.flatpak-builder/cache/objects/f0/a7fa4cbe2e1b13ba12785c1f6b980e2bfc35afcccd1b9786dc59232db8f23d.commit differ diff --git a/.flatpak-builder/cache/objects/f0/bb54846758b201283013abf2ed6f68fe2df3a7e83bdd71e520fd58c9e62274.dirtree b/.flatpak-builder/cache/objects/f0/bb54846758b201283013abf2ed6f68fe2df3a7e83bdd71e520fd58c9e62274.dirtree new file mode 100644 index 0000000..5b45933 Binary files /dev/null and b/.flatpak-builder/cache/objects/f0/bb54846758b201283013abf2ed6f68fe2df3a7e83bdd71e520fd58c9e62274.dirtree differ diff --git a/.flatpak-builder/cache/objects/f0/c2680e9089ef8cd338a2d163a6f489a7e8ca0407c3f56992d6686871de6474.file b/.flatpak-builder/cache/objects/f0/c2680e9089ef8cd338a2d163a6f489a7e8ca0407c3f56992d6686871de6474.file new file mode 100644 index 0000000..f2afe69 --- /dev/null +++ b/.flatpak-builder/cache/objects/f0/c2680e9089ef8cd338a2d163a6f489a7e8ca0407c3f56992d6686871de6474.file @@ -0,0 +1,50 @@ +/*-*- Mode: C; c-basic-offset: 8 -*-*/ + +#ifndef foocanberragtkhfoo +#define foocanberragtkhfoo + +/*** + This file is part of libcanberra. + + Copyright 2008 Lennart Poettering + + libcanberra is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation, either version 2.1 of the + License, or (at your option) any later version. + + libcanberra is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with libcanberra. If not, see + . +***/ + +#include +#include +#include + +G_BEGIN_DECLS + +#ifndef GDK_MULTIHEAD_SAFE +ca_context *ca_gtk_context_get(void); +#endif + +ca_context *ca_gtk_context_get_for_screen(GdkScreen *screen); + +int ca_gtk_proplist_set_for_widget(ca_proplist *p, GtkWidget *w); + +int ca_gtk_play_for_widget(GtkWidget *w, uint32_t id, ...) G_GNUC_NULL_TERMINATED; + +int ca_gtk_proplist_set_for_event(ca_proplist *p, GdkEvent *e); + +int ca_gtk_play_for_event(GdkEvent *e, uint32_t id, ...) G_GNUC_NULL_TERMINATED; + +void ca_gtk_widget_disable_sounds(GtkWidget *w, gboolean enable); + +G_END_DECLS + +#endif diff --git a/.flatpak-builder/cache/objects/f1/2b1abcc59b5997e0bed64649c79ae3e2af8c92366db9dfc7418e378c3d0344.dirtree b/.flatpak-builder/cache/objects/f1/2b1abcc59b5997e0bed64649c79ae3e2af8c92366db9dfc7418e378c3d0344.dirtree new file mode 100644 index 0000000..db74b12 Binary files /dev/null and b/.flatpak-builder/cache/objects/f1/2b1abcc59b5997e0bed64649c79ae3e2af8c92366db9dfc7418e378c3d0344.dirtree differ diff --git a/.flatpak-builder/cache/objects/f1/9781d6c23bd27a86852abed52f243c656ffa1f9c67ce1966183c11072be350.file b/.flatpak-builder/cache/objects/f1/9781d6c23bd27a86852abed52f243c656ffa1f9c67ce1966183c11072be350.file new file mode 100644 index 0000000..e4a33dc Binary files /dev/null and b/.flatpak-builder/cache/objects/f1/9781d6c23bd27a86852abed52f243c656ffa1f9c67ce1966183c11072be350.file differ diff --git a/.flatpak-builder/cache/objects/f1/d11e3fab9a1aceb96d4d0275716f1e8f5fe8ace156c8d418e9f13f7db265df.file b/.flatpak-builder/cache/objects/f1/d11e3fab9a1aceb96d4d0275716f1e8f5fe8ace156c8d418e9f13f7db265df.file new file mode 100644 index 0000000..3f82adc Binary files /dev/null and b/.flatpak-builder/cache/objects/f1/d11e3fab9a1aceb96d4d0275716f1e8f5fe8ace156c8d418e9f13f7db265df.file differ diff --git a/.flatpak-builder/cache/objects/f1/dead25c1623c14a5629f23249255da02d10243e4b8aa14b4cb7abf53da3e96.file b/.flatpak-builder/cache/objects/f1/dead25c1623c14a5629f23249255da02d10243e4b8aa14b4cb7abf53da3e96.file new file mode 100644 index 0000000..113562c --- /dev/null +++ b/.flatpak-builder/cache/objects/f1/dead25c1623c14a5629f23249255da02d10243e4b8aa14b4cb7abf53da3e96.file @@ -0,0 +1,444 @@ +/* + * Copyright (C) 2007 Armin Burgmeier + * Copyright (C) 2007 - 2014 Murray Cumming + * Copyright (C) 2007 - 2014 Vivien Malerba + * Copyright (C) 2010 David King + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +/* + * BLOB (Binary Large OBject) handling functions specific to each provider. + */ +#define G_LOG_DOMAIN "GDA-blob-op" + +#include "gda-blob-op.h" +#include "gda-blob-op-impl.h" +#include "gda-lockable.h" +#include "gda-connection.h" +#include "gda-connection-internal.h" +#include "gda-server-provider-private.h" +#include "thread-wrapper/gda-worker.h" +#include "gda-value.h" + +#define PARENT_TYPE G_TYPE_OBJECT +#define CLASS(blob) (GDA_BLOB_OP_CLASS (G_OBJECT_GET_CLASS (blob))) +#define VFUNCTIONS(blob) (GDA_BLOB_OP_FUNCTIONS (CLASS(blob)->functions)) +static void gda_blob_op_dispose (GObject *object); + + +static void gda_blob_op_set_property (GObject *object, + guint param_id, + const GValue *value, + GParamSpec *pspec); +static void gda_blob_op_get_property (GObject *object, + guint param_id, + GValue *value, + GParamSpec *pspec); + +typedef struct { + GdaConnection *cnc; + GdaWorker *worker; +} GdaBlobOpPrivate; + +G_DEFINE_TYPE_WITH_PRIVATE (GdaBlobOp, gda_blob_op, G_TYPE_OBJECT) + +/* properties */ +enum +{ + PROP_0, + PROP_CNC, +}; + + +static void +gda_blob_op_class_init (GdaBlobOpClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + /* properties */ + object_class->set_property = gda_blob_op_set_property; + object_class->get_property = gda_blob_op_get_property; + g_object_class_install_property (object_class, PROP_CNC, + g_param_spec_object ("connection", NULL, + "Connection used to fetch and write data", + GDA_TYPE_CONNECTION, + G_PARAM_WRITABLE | G_PARAM_READABLE | G_PARAM_CONSTRUCT_ONLY)); + + /* virtual functions */ + object_class->dispose = gda_blob_op_dispose; + klass->functions = g_new0 (GdaBlobOpFunctions, 1); +} + +static void +gda_blob_op_init (GdaBlobOp *op) +{ +} + +static void +gda_blob_op_dispose (GObject *object) +{ + GdaBlobOp *op = (GdaBlobOp *) object; + GdaBlobOpPrivate *priv = gda_blob_op_get_instance_private (op); + + if (priv->worker) { + gda_worker_unref (priv->worker); + priv->worker = NULL; + } + if (priv->cnc) { + g_object_unref (priv->cnc); + priv->cnc = NULL; + } + + /* chain to parent class */ + G_OBJECT_CLASS (gda_blob_op_parent_class)->dispose (object); +} + +static void +gda_blob_op_set_property (GObject *object, + guint param_id, + const GValue *value, + GParamSpec *pspec) +{ + GdaBlobOp *op = (GdaBlobOp *) object; + GdaBlobOpPrivate *priv = gda_blob_op_get_instance_private (op); + switch (param_id) { + case PROP_CNC: + priv->cnc = g_value_get_object (value); + if (priv->cnc) { + g_object_ref (priv->cnc); + priv->worker = _gda_connection_get_worker (priv->cnc); + g_assert (priv->worker); + gda_worker_ref (priv->worker); + } + else + g_warning ("GdaBlobOp created without any associated connection!"); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + break; + } +} + +static void +gda_blob_op_get_property (GObject *object, + guint param_id, + GValue *value, + GParamSpec *pspec) +{ + GdaBlobOp *op = (GdaBlobOp *) object; + GdaBlobOpPrivate *priv = gda_blob_op_get_instance_private (op); + switch (param_id) { + case PROP_CNC: + g_value_set_object (value, priv->cnc); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + break; + } +} + +typedef struct { + GdaBlobOp *op; + GdaBlob *blob; + glong offset; + glong size; + + glong retval; +} WorkerData; + +static gpointer +worker_get_length (WorkerData *data, GError **error) +{ + if (VFUNCTIONS (data->op)->get_length != NULL) + data->retval = VFUNCTIONS (data->op)->get_length (data->op); + else + data->retval = -1; + return (gpointer) 0x01; +} + +/** + * gda_blob_op_get_length: + * @op: an existing #GdaBlobOp + * + * Returns: the length of the blob in bytes. In case of error, -1 is returned and the + * provider should have added an error (a #GdaConnectionEvent) to the connection. + */ +glong +gda_blob_op_get_length (GdaBlobOp *op) +{ + g_return_val_if_fail (GDA_IS_BLOB_OP (op), -1); + GdaBlobOpPrivate *priv = gda_blob_op_get_instance_private (op); + if (priv) { + if (! priv->cnc || !priv->worker) { + g_warning ("Internal error: no connection of GdaWorker associated to blob operations object"); + return -1; + } + + gda_lockable_lock ((GdaLockable*) priv->cnc); /* CNC LOCK */ + + GMainContext *context; + context = gda_server_provider_get_real_main_context (priv->cnc); + + WorkerData data; + data.op = op; + data.retval = -1; + + gpointer callval; + gda_worker_do_job (priv->worker, context, 0, &callval, NULL, + (GdaWorkerFunc) worker_get_length, (gpointer) &data, NULL, NULL, NULL); + if (context) + g_main_context_unref (context); + + gda_lockable_unlock ((GdaLockable*) priv->cnc); /* CNC UNLOCK */ + + if (callval == (gpointer) 0x01) + return data.retval; + else + return -1; + } + else { + if (VFUNCTIONS (op)->get_length != NULL) + return VFUNCTIONS (op)->get_length (op); + else + return -1; + } +} + +static gpointer +worker_read (WorkerData *data, GError **error) +{ + if (VFUNCTIONS (data->op)->read != NULL) + data->retval = VFUNCTIONS (data->op)->read (data->op, data->blob, data->offset, data->size); + else + data->retval = -1; + return (gpointer) 0x01; +} + +/** + * gda_blob_op_read: + * @op: a #GdaBlobOp + * @blob: a #GdaBlob to read data to + * @offset: offset to read from the start of the blob (starts at 0) + * @size: maximum number of bytes to read. + * + * Reads a chunk of bytes from the BLOB accessible through @op into @blob. + * + * Returns: the number of bytes actually read. In case of error, -1 is returned and the + * provider should have added an error to the connection. + */ +glong +gda_blob_op_read (GdaBlobOp *op, GdaBlob *blob, glong offset, glong size) +{ + g_return_val_if_fail (GDA_IS_BLOB_OP (op), -1); + GdaBlobOpPrivate *priv = gda_blob_op_get_instance_private (op); + + if (priv) { + if (! priv->cnc || !priv->worker) { + g_warning ("Internal error: no connection of GdaWorker associated to blob operations object"); + return -1; + } + + gda_lockable_lock ((GdaLockable*) priv->cnc); /* CNC LOCK */ + + GMainContext *context; + context = gda_server_provider_get_real_main_context (priv->cnc); + + WorkerData data; + data.op = op; + data.blob = blob; + data.offset = offset; + data.size = size; + data.retval = -1; + + gpointer callval; + gda_worker_do_job (priv->worker, context, 0, &callval, NULL, + (GdaWorkerFunc) worker_read, (gpointer) &data, NULL, NULL, NULL); + if (context) + g_main_context_unref (context); + + gda_lockable_unlock ((GdaLockable*) priv->cnc); /* CNC UNLOCK */ + + if (callval == (gpointer) 0x01) + return data.retval; + else + return -1; + } + else { + if (VFUNCTIONS (op)->read != NULL) + return VFUNCTIONS (op)->read (op, blob, offset, size); + else + return -1; + } +} + +/** + * gda_blob_op_read_all: + * @op: a #GdaBlobOp + * @blob: a #GdaBlob to read data to + * + * Reads the whole contents of the blob manipulated by @op into @blob + * + * Returns: TRUE if @blob->data contains the whole BLOB manipulated by @op + */ +gboolean +gda_blob_op_read_all (GdaBlobOp *op, GdaBlob *blob) +{ + glong len; + g_return_val_if_fail (GDA_IS_BLOB_OP (op), FALSE); + g_return_val_if_fail (blob, FALSE); + + len = gda_blob_op_get_length (gda_blob_get_op (blob)); + if (len >= 0) + return (gda_blob_op_read (gda_blob_get_op (blob), blob, 0, len) < 0) ? FALSE : TRUE; + else + return FALSE; +} + +static gpointer +worker_write (WorkerData *data, GError **error) +{ + if (VFUNCTIONS (data->op)->write != NULL) + data->retval = VFUNCTIONS (data->op)->write (data->op, data->blob, data->offset); + else + data->retval = -1; + return (gpointer) 0x01; +} + +/** + * gda_blob_op_write: + * @op: a #GdaBlobOp + * @blob: a #GdaBlob which contains the data to write + * @offset: offset to write from the start of the blob (starts at 0) + * + * Writes a chunk of bytes from a @blob to the BLOB accessible through @op, @blob is unchanged after + * this call. + * + * If @blob has an associated #GdaBlobOp (ie. if @blob->op is not %NULL) then the data to be written + * using @op is the data fetched using @blob->op. + * + * Returns: the number of bytes written. In case of error, -1 is returned and the + * provider should have added an error to the connection. + */ +glong +gda_blob_op_write (GdaBlobOp *op, GdaBlob *blob, glong offset) +{ + g_return_val_if_fail (GDA_IS_BLOB_OP (op), -1); + GdaBlobOpPrivate *priv = gda_blob_op_get_instance_private (op); + + if (priv) { + if (! priv->cnc || !priv->worker) { + g_warning ("Internal error: no connection of GdaWorker associated to blob operations object"); + return -1; + } + + gda_lockable_lock ((GdaLockable*) priv->cnc); /* CNC LOCK */ + + GMainContext *context; + context = gda_server_provider_get_real_main_context (priv->cnc); + + WorkerData data; + data.op = op; + data.blob = blob; + data.offset = offset; + data.retval = -1; + + gpointer callval; + gda_worker_do_job (priv->worker, context, 0, &callval, NULL, + (GdaWorkerFunc) worker_write, (gpointer) &data, NULL, NULL, NULL); + if (context) + g_main_context_unref (context); + + gda_lockable_unlock ((GdaLockable*) priv->cnc); /* CNC UNLOCK */ + + if (callval == (gpointer) 0x01) + return data.retval; + else + return -1; + } + else { + if (VFUNCTIONS (op)->write != NULL) + return VFUNCTIONS (op)->write (op, blob, offset); + else + return -1; + } +} + +static gpointer +worker_write_all (WorkerData *data, GError **error) +{ + if (VFUNCTIONS (data->op)->write_all != NULL) + data->retval = VFUNCTIONS (data->op)->write_all (data->op, data->blob) ? 1 : 0; + else + data->retval = 0; + return (gpointer) 0x01; +} + +/** + * gda_blob_op_write_all: + * @op: a #GdaBlobOp + * @blob: a #GdaBlob which contains the data to write + * + * Writes the whole contents of @blob into the blob manipulated by @op. If necessary the resulting + * blob is truncated from its previous length. + * + * Returns: TRUE on success + */ +gboolean +gda_blob_op_write_all (GdaBlobOp *op, GdaBlob *blob) +{ + g_return_val_if_fail (GDA_IS_BLOB_OP (op), FALSE); + GdaBlobOpPrivate *priv = gda_blob_op_get_instance_private (op); + + if (VFUNCTIONS (op)->write_all != NULL) { + if (priv) { + if (! priv->cnc || !priv->worker) { + g_warning ("Internal error: no connection of GdaWorker associated to blob operations object"); + return -1; + } + + gda_lockable_lock ((GdaLockable*) priv->cnc); /* CNC LOCK */ + + GMainContext *context; + context = gda_server_provider_get_real_main_context (priv->cnc); + + WorkerData data; + data.op = op; + data.blob = blob; + data.retval = -1; + + gpointer callval; + gda_worker_do_job (priv->worker, context, 0, &callval, NULL, + (GdaWorkerFunc) worker_write_all, (gpointer) &data, NULL, NULL, NULL); + if (context) + g_main_context_unref (context); + + gda_lockable_unlock ((GdaLockable*) priv->cnc); /* CNC UNLOCK */ + + if (callval == (gpointer) 0x01) + return data.retval ? TRUE : FALSE; + else + return FALSE; + } + else + return VFUNCTIONS (op)->write_all (op, blob); + } + else { + glong res; + res = gda_blob_op_write (op, blob, 0); + return res >= 0 ? TRUE : FALSE; + } +} diff --git a/.flatpak-builder/cache/objects/f1/e2eb2e778e17e93cac62c52d77ca54516025562ceb3ed5f908e07fbb5f3566.dirtree b/.flatpak-builder/cache/objects/f1/e2eb2e778e17e93cac62c52d77ca54516025562ceb3ed5f908e07fbb5f3566.dirtree new file mode 100644 index 0000000..eaa9cc6 Binary files /dev/null and b/.flatpak-builder/cache/objects/f1/e2eb2e778e17e93cac62c52d77ca54516025562ceb3ed5f908e07fbb5f3566.dirtree differ diff --git a/.flatpak-builder/cache/objects/f1/fbe0bb34673e39c47f865d838b2be198c690a4bb4fd4bfda0384ccfcb8fe4b.dirtree b/.flatpak-builder/cache/objects/f1/fbe0bb34673e39c47f865d838b2be198c690a4bb4fd4bfda0384ccfcb8fe4b.dirtree new file mode 100644 index 0000000..2c94f71 Binary files /dev/null and b/.flatpak-builder/cache/objects/f1/fbe0bb34673e39c47f865d838b2be198c690a4bb4fd4bfda0384ccfcb8fe4b.dirtree differ diff --git a/.flatpak-builder/cache/objects/f2/20930e1e90799c62e8238b5fd63827a4843d2d2151474ccbf298cfafe6cd4d.dirtree b/.flatpak-builder/cache/objects/f2/20930e1e90799c62e8238b5fd63827a4843d2d2151474ccbf298cfafe6cd4d.dirtree new file mode 100644 index 0000000..0ecde7a Binary files /dev/null and b/.flatpak-builder/cache/objects/f2/20930e1e90799c62e8238b5fd63827a4843d2d2151474ccbf298cfafe6cd4d.dirtree differ diff --git a/.flatpak-builder/cache/objects/f2/432eb3d03ae821f066095048b17f1b5a087585b6be54ff53b0c2477b7cfe97.file b/.flatpak-builder/cache/objects/f2/432eb3d03ae821f066095048b17f1b5a087585b6be54ff53b0c2477b7cfe97.file new file mode 120000 index 0000000..624aef5 --- /dev/null +++ b/.flatpak-builder/cache/objects/f2/432eb3d03ae821f066095048b17f1b5a087585b6be54ff53b0c2477b7cfe97.file @@ -0,0 +1 @@ +../../share/runtime/locale/de/share/de \ No newline at end of file diff --git a/.flatpak-builder/cache/objects/f2/616204246e2daf3ba1968c11ef6f10986534232887de0d47f2a4a023dcfc35.file b/.flatpak-builder/cache/objects/f2/616204246e2daf3ba1968c11ef6f10986534232887de0d47f2a4a023dcfc35.file new file mode 100644 index 0000000..3caf7d0 Binary files /dev/null and b/.flatpak-builder/cache/objects/f2/616204246e2daf3ba1968c11ef6f10986534232887de0d47f2a4a023dcfc35.file differ diff --git a/.flatpak-builder/cache/objects/f2/95188efaa290747cd432d0e09eb35fc9e66fbf4a7a43395ce3b9a987aaec4a.file b/.flatpak-builder/cache/objects/f2/95188efaa290747cd432d0e09eb35fc9e66fbf4a7a43395ce3b9a987aaec4a.file new file mode 100644 index 0000000..570d538 --- /dev/null +++ b/.flatpak-builder/cache/objects/f2/95188efaa290747cd432d0e09eb35fc9e66fbf4a7a43395ce3b9a987aaec4a.file @@ -0,0 +1,765 @@ +/* + * Copyright (C) 2006 - 2008 Murray Cumming + * Copyright (C) 2006 - 2013 Vivien Malerba + * Copyright (C) 2009 Bas Driessen + * Copyright (C) 2010 David King + * Copyright (C) 2010 Jonh Wendell + * Copyright (C) 2018-2019 Daniel Espinosa + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +#define G_LOG_DOMAIN "GDA-data-access-wrapper" + +#include "gda-data-access-wrapper.h" + +#include +#include +#include +#include +#include +#include +#include +#include + + +/* GdaDataModel interface */ +static void gda_data_access_wrapper_data_model_init (GdaDataModelInterface *iface); +static gint gda_data_access_wrapper_get_n_rows (GdaDataModel *model); +static gint gda_data_access_wrapper_get_n_columns (GdaDataModel *model); +static GdaColumn *gda_data_access_wrapper_describe_column (GdaDataModel *model, gint col); +static GdaDataModelAccessFlags gda_data_access_wrapper_get_access_flags(GdaDataModel *model); +static const GValue *gda_data_access_wrapper_get_value_at (GdaDataModel *model, gint col, gint row, GError **error); +static GdaValueAttribute gda_data_access_wrapper_get_attributes_at (GdaDataModel *model, gint col, gint row); +static GError **gda_data_access_wrapper_get_exceptions (GdaDataModel *model); + +#define ROWS_POOL_SIZE 50 +typedef struct { + GdaDataModel *model; + GdaDataModelAccessFlags model_access_flags; + + GdaDataModelIter *iter; /* iterator on @model, NULL if @model already is random access */ + gint iter_row;/* current row of @iter, starting at 0 when created */ + + GHashTable *rows; /* NULL if @model already is random access */ + gint nb_rows; /* number of rows of @wrapper */ + gint nb_cols; /* number of columns of @wrapper */ + gint last_row;/* row number of the last row which has been read */ + gboolean end_of_data; /* TRUE if the end of the data model has been reached by the iterator */ + + GArray *rows_buffer_array; /* Array of GdaRow */ + GArray *rows_buffer_index; /* Array of indexes: GdaRow at index i in @rows_buffer_array + * is indexed in @rows with key rows_buffer_index[i] */ + + /* rows mapping */ + GSList *columns; /* not NULL if a mapping exists */ + gint *rows_mapping; /* @nb_cols is set when @rows_mapping is set, and @rows_mapping's size is @nb_cols */ +} GdaDataAccessWrapperPrivate; + +G_DEFINE_TYPE_WITH_CODE (GdaDataAccessWrapper, gda_data_access_wrapper, G_TYPE_OBJECT, + G_ADD_PRIVATE (GdaDataAccessWrapper) + G_IMPLEMENT_INTERFACE(GDA_TYPE_DATA_MODEL, gda_data_access_wrapper_data_model_init)) + +/* properties */ +enum +{ + PROP_0, + PROP_MODEL, +}; + +static void gda_data_access_wrapper_dispose (GObject *object); + +static void gda_data_access_wrapper_set_property (GObject *object, + guint param_id, + const GValue *value, + GParamSpec *pspec); +static void gda_data_access_wrapper_get_property (GObject *object, + guint param_id, + GValue *value, + GParamSpec *pspec); + +static void iter_row_changed_cb (GdaDataModelIter *iter, gint row, GdaDataAccessWrapper *model); +static void iter_end_of_data_cb (GdaDataModelIter *iter, GdaDataAccessWrapper *model); + +static GdaRow *create_new_row (GdaDataAccessWrapper *model); + +static void +gda_data_access_wrapper_class_init (GdaDataAccessWrapperClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + /* properties */ + object_class->set_property = gda_data_access_wrapper_set_property; + object_class->get_property = gda_data_access_wrapper_get_property; + g_object_class_install_property (object_class, PROP_MODEL, + g_param_spec_object ("model", NULL, "Data model being wrapped", + GDA_TYPE_DATA_MODEL, + G_PARAM_READABLE | G_PARAM_WRITABLE | + G_PARAM_CONSTRUCT_ONLY)); + + /* virtual functions */ + object_class->dispose = gda_data_access_wrapper_dispose; +} + +static void +gda_data_access_wrapper_data_model_init (GdaDataModelInterface *iface) +{ + iface->get_n_rows = gda_data_access_wrapper_get_n_rows; + iface->get_n_columns = gda_data_access_wrapper_get_n_columns; + iface->describe_column = gda_data_access_wrapper_describe_column; + iface->get_access_flags = gda_data_access_wrapper_get_access_flags; + iface->get_value_at = gda_data_access_wrapper_get_value_at; + iface->get_attributes_at = gda_data_access_wrapper_get_attributes_at; + + iface->create_iter = NULL; + + iface->set_value_at = NULL; + iface->set_values = NULL; + iface->append_values = NULL; + iface->append_row = NULL; + iface->remove_row = NULL; + iface->find_row = NULL; + + iface->freeze = NULL; + iface->thaw = NULL; + iface->get_notify = NULL; + iface->send_hint = NULL; + + iface->get_exceptions = gda_data_access_wrapper_get_exceptions; +} + +static void +gda_data_access_wrapper_init (GdaDataAccessWrapper *model) +{ + GdaDataAccessWrapperPrivate *priv = gda_data_access_wrapper_get_instance_private (model); + priv->iter_row = -1; /* because priv->iter does not yet exist */ + priv->rows = NULL; + priv->nb_rows = -1; + priv->end_of_data = FALSE; + priv->last_row = -1; + + priv->rows_buffer_array = NULL; + priv->rows_buffer_index = NULL; +} + +static void +model_row_inserted_cb (G_GNUC_UNUSED GdaDataModel *mod, gint row, GdaDataAccessWrapper *model) +{ + gda_data_model_row_inserted ((GdaDataModel*) model, row); +} + +static void +model_row_updated_cb (G_GNUC_UNUSED GdaDataModel *mod, gint row, GdaDataAccessWrapper *model) +{ + gda_data_model_row_updated ((GdaDataModel*) model, row); +} + +static void +model_row_removed_cb (G_GNUC_UNUSED GdaDataModel *mod, gint row, GdaDataAccessWrapper *model) +{ + gda_data_model_row_removed ((GdaDataModel*) model, row); +} + +static void +model_reset_cb (G_GNUC_UNUSED GdaDataModel *mod, GdaDataAccessWrapper *model) +{ + gda_data_model_reset ((GdaDataModel*) model); +} + +static void +clear_internal_state (GdaDataAccessWrapper *model) +{ + GdaDataAccessWrapperPrivate *priv = gda_data_access_wrapper_get_instance_private (model); + if (priv) { + if (priv->columns) { + g_slist_free_full (priv->columns, (GDestroyNotify) g_object_unref); + priv->columns = NULL; + } + + priv->nb_cols = 0; + + if (priv->rows_buffer_array) { + g_array_free (priv->rows_buffer_array, TRUE); + priv->rows_buffer_array = NULL; + } + + if (priv->rows_buffer_index) { + g_array_free (priv->rows_buffer_index, TRUE); + priv->rows_buffer_index = NULL; + } + } +} + +static void +gda_data_access_wrapper_dispose (GObject *object) +{ + GdaDataAccessWrapper *model = (GdaDataAccessWrapper *) object; + + g_return_if_fail (GDA_IS_DATA_ACCESS_WRAPPER (model)); + GdaDataAccessWrapperPrivate *priv = gda_data_access_wrapper_get_instance_private (model); + + /* free memory */ + if (priv) { + /* random access model free */ + clear_internal_state (model); + + if (priv->iter) { + g_signal_handlers_disconnect_by_func (G_OBJECT (priv->iter), + G_CALLBACK (iter_row_changed_cb), model); + g_signal_handlers_disconnect_by_func (G_OBJECT (priv->iter), + G_CALLBACK (iter_end_of_data_cb), model); + + g_object_unref (priv->iter); + priv->iter = NULL; + } + + if (priv->model) { + if (priv->rows) { + g_hash_table_destroy (priv->rows); + priv->rows = NULL; + } + else { + g_signal_handlers_disconnect_by_func (G_OBJECT (priv->model), + G_CALLBACK (model_row_inserted_cb), model); + g_signal_handlers_disconnect_by_func (G_OBJECT (priv->model), + G_CALLBACK (model_row_updated_cb), model); + g_signal_handlers_disconnect_by_func (G_OBJECT (priv->model), + G_CALLBACK (model_row_removed_cb), model); + g_signal_handlers_disconnect_by_func (G_OBJECT (priv->model), + G_CALLBACK (model_reset_cb), model); + } + g_object_unref (priv->model); + priv->model = NULL; + } + } + + /* chain to parent class */ + G_OBJECT_CLASS (gda_data_access_wrapper_parent_class)->dispose (object); +} + +static void +compute_columns (GdaDataAccessWrapper *model) +{ + GdaDataAccessWrapperPrivate *priv = gda_data_access_wrapper_get_instance_private (model); + if (priv->rows_mapping) { + /* use priv->rows_mapping to create columns, and correct it if + * needed to remove out of range columns */ + gint *nmapping; + gint i, j, nb_cols; + g_assert (!priv->columns); + nmapping = g_new (gint, priv->nb_cols); + nb_cols = gda_data_model_get_n_columns (priv->model); + for (i = 0, j = 0; i < priv->nb_cols; i++) { + gint nb = priv->rows_mapping [i]; + if (nb >= nb_cols) + continue; + GdaColumn *column; + column = gda_data_model_describe_column (priv->model, nb); + if (!column) + continue; + priv->columns = g_slist_append (priv->columns, + gda_column_copy (column)); + nmapping [j] = nb; + j++; + } + priv->nb_cols = j; + g_free (priv->rows_mapping); + priv->rows_mapping = nmapping; + } + else + priv->nb_cols = gda_data_model_get_n_columns (priv->model); +} + +static void +gda_data_access_wrapper_set_property (GObject *object, + guint param_id, + const GValue *value, + GParamSpec *pspec) +{ + GdaDataAccessWrapper *model; + + model = GDA_DATA_ACCESS_WRAPPER (object); + GdaDataAccessWrapperPrivate *priv = gda_data_access_wrapper_get_instance_private (model); + if (priv) { + switch (param_id) { + case PROP_MODEL: { + GdaDataModel *mod = g_value_get_object (value); + if (mod) { + g_return_if_fail (GDA_IS_DATA_MODEL (mod)); + priv->model_access_flags = gda_data_model_get_access_flags (mod); + + if (priv->model_access_flags & GDA_DATA_MODEL_ACCESS_RANDOM) { + g_signal_connect (G_OBJECT (mod), "row-inserted", + G_CALLBACK (model_row_inserted_cb), model); + g_signal_connect (G_OBJECT (mod), "row-updated", + G_CALLBACK (model_row_updated_cb), model); + g_signal_connect (G_OBJECT (mod), "row-removed", + G_CALLBACK (model_row_removed_cb), model); + g_signal_connect (G_OBJECT (mod), "reset", + G_CALLBACK (model_reset_cb), model); + } + else { + priv->iter = gda_data_model_create_iter (mod); + g_return_if_fail (priv->iter); + g_object_set (priv->iter, "validate-changes", FALSE, + NULL); + g_signal_connect (G_OBJECT (priv->iter), "row-changed", + G_CALLBACK (iter_row_changed_cb), model); + g_signal_connect (G_OBJECT (priv->iter), "end-of-data", + G_CALLBACK (iter_end_of_data_cb), model); + priv->iter_row = -1; /* because priv->iter is invalid */ + priv->rows = g_hash_table_new_full (g_int_hash, g_int_equal, + g_free, + (GDestroyNotify) g_object_unref); + } + + if (priv->model) + g_object_unref (priv->model); + + priv->model = mod; + g_object_ref (mod); + + compute_columns (model); + } + break; + } + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + break; + } + } +} + +static void +gda_data_access_wrapper_get_property (GObject *object, + guint param_id, + GValue *value, + GParamSpec *pspec) +{ + GdaDataAccessWrapper *model; + + model = GDA_DATA_ACCESS_WRAPPER (object); + GdaDataAccessWrapperPrivate *priv = gda_data_access_wrapper_get_instance_private (model); + if (priv) { + switch (param_id) { + case PROP_MODEL: + g_value_set_object (value, G_OBJECT (priv->model)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + break; + } + } +} + +/** + * gda_data_access_wrapper_new: + * @model: a #GdaDataModel + * + * Creates a new #GdaDataModel object which buffers the rows of @model. This object is useful + * only if @model can only be accessed using cursor based method. + * + * Returns: (transfer full): a pointer to the newly created #GdaDataModel. + */ +GdaDataModel * +gda_data_access_wrapper_new (GdaDataModel *model) +{ + GdaDataAccessWrapper *retmodel; + + g_return_val_if_fail (GDA_IS_DATA_MODEL (model), NULL); + + retmodel = g_object_new (GDA_TYPE_DATA_ACCESS_WRAPPER, + "model", model, NULL); + + return GDA_DATA_MODEL (retmodel); +} + +/** + * gda_data_access_wrapper_set_mapping: + * @wrapper: a #GdaDataAccessWrapper object + * @mapping: (nullable) (array length=mapping_size): an array of #gint which represents the mapping between @wrapper's columns + * and the columns of the wrapped data model + * @mapping_size: the size of @mapping. + * + * @wrapper will report as many columns as @mapping_size, and for each value at position 'i' in @mapping, + * @wrapper will report the 'i'th column, mapped to the wrapped data model column at position mapping[i]. + * For example if mapping is {3, 4, 0}, then @wrapper will report 3 columns, respectively mapped to the 4th, + * 5th and 1st columns of the wrapped data model (as column numbers start at 0). + * + * If @mapping is %NULL, then no mapping is done and @wrapper's columns will be the same as the wrapped + * data model. + * + * If a column in @mapping does not exist in the wrapped data model, then it is simply ignored (no error + * reported). + * + * Please note that if @wrapper has already been used and if the wrapped data model offers a cursor forward + * access mode, then this method will return %FALSE and no action will be done. + * + * If the mapping is applied, then any existing iterator will be invalid, and @wrapper is reset as if it + * had just been created. + * + * Returns: %TRUE if the mapping actually changed + * + * Since: 5.2 + */ +gboolean +gda_data_access_wrapper_set_mapping (GdaDataAccessWrapper *wrapper, const gint *mapping, gint mapping_size) +{ + g_return_val_if_fail (GDA_IS_DATA_ACCESS_WRAPPER (wrapper), FALSE); + GdaDataAccessWrapperPrivate *priv = gda_data_access_wrapper_get_instance_private (wrapper); + + if ((! (priv->model_access_flags & GDA_DATA_MODEL_ACCESS_CURSOR_BACKWARD)) && + (priv->iter_row >= 0)) { + /* error */ + return FALSE; + } + + clear_internal_state (wrapper); + + if (mapping) { + /* define mapping */ + priv->rows_mapping = g_new (gint, mapping_size); + memcpy (priv->rows_mapping, mapping, mapping_size * sizeof (gint)); + priv->nb_cols = mapping_size; + } + else { + if (priv->rows_mapping) { + g_free (priv->rows_mapping); + priv->rows_mapping = NULL; + } + } + + compute_columns (wrapper); + gda_data_model_reset ((GdaDataModel*) wrapper); + + return TRUE; +} + +/* + * GdaDataModel interface implementation + */ +static gint +gda_data_access_wrapper_get_n_rows (GdaDataModel *model) +{ + GdaDataAccessWrapper *imodel; + g_return_val_if_fail (GDA_IS_DATA_ACCESS_WRAPPER (model), 0); + imodel = (GdaDataAccessWrapper*) model; + GdaDataAccessWrapperPrivate *priv = gda_data_access_wrapper_get_instance_private (imodel); + + if (priv->nb_rows >= 0) + return priv->nb_rows; + + if (priv->model_access_flags & GDA_DATA_MODEL_ACCESS_RANDOM) + /* priv->mode is a random access model, use it */ + priv->nb_rows = gda_data_model_get_n_rows (priv->model); + else { + /* go at the end */ + while (!priv->end_of_data) { + if (! gda_data_model_iter_move_next (priv->iter)) + break; + } + if (priv->end_of_data) + priv->nb_rows = priv->last_row +1; + else + priv->nb_rows = -1; + } + + return priv->nb_rows; +} + +static gint +gda_data_access_wrapper_get_n_columns (GdaDataModel *model) +{ + GdaDataAccessWrapper *imodel; + g_return_val_if_fail (GDA_IS_DATA_ACCESS_WRAPPER (model), 0); + imodel = (GdaDataAccessWrapper*) model; + GdaDataAccessWrapperPrivate *priv = gda_data_access_wrapper_get_instance_private (imodel); + + if (priv->model) + return priv->nb_cols; + else + return 0; +} + +static GdaColumn * +gda_data_access_wrapper_describe_column (GdaDataModel *model, gint col) +{ + GdaDataAccessWrapper *imodel; + g_return_val_if_fail (GDA_IS_DATA_ACCESS_WRAPPER (model), NULL); + imodel = (GdaDataAccessWrapper*) model; + GdaDataAccessWrapperPrivate *priv = gda_data_access_wrapper_get_instance_private (imodel); + + if (priv->model) { + if (priv->columns) + return g_slist_nth_data (priv->columns, col); + else + return gda_data_model_describe_column (priv->model, col); + } + else + return NULL; +} + +static GdaDataModelAccessFlags +gda_data_access_wrapper_get_access_flags (GdaDataModel *model) +{ + GdaDataAccessWrapper *imodel; + + g_return_val_if_fail (GDA_IS_DATA_ACCESS_WRAPPER (model), 0); + imodel = (GdaDataAccessWrapper*) model; + GdaDataAccessWrapperPrivate *priv = gda_data_access_wrapper_get_instance_private (imodel); + g_return_val_if_fail (priv, 0); + + return GDA_DATA_MODEL_ACCESS_RANDOM; +} + +static GdaRow * +create_new_row (GdaDataAccessWrapper *model) +{ + GdaDataAccessWrapperPrivate *priv = gda_data_access_wrapper_get_instance_private (model); + gint i; + GdaRow *row; + + row = gda_row_new (priv->nb_cols); + for (i = 0; i < priv->nb_cols; i++) { + GdaHolder *holder; + GValue *dest; + dest = gda_row_get_value (row, i); + if (priv->rows_mapping) + holder = gda_set_get_nth_holder ((GdaSet *) priv->iter, priv->rows_mapping [i]); + else + holder = gda_set_get_nth_holder ((GdaSet *) priv->iter, i); + if (holder) { + const GValue *cvalue = gda_holder_get_value (holder); + if (cvalue) { + gda_value_reset_with_type (dest, G_VALUE_TYPE ((GValue *) cvalue)); + g_value_copy (cvalue, dest); + } + else + gda_value_set_null (dest); + } + else + gda_row_invalidate_value (row, dest); + } + + gint *ptr; + ptr = g_new (gint, 1); + *ptr = priv->iter_row; + g_hash_table_insert (priv->rows, ptr, row); + /*g_print ("%s(%d)\n", __FUNCTION__, priv->iter_row);*/ + + return row; +} + +static const GValue * +gda_data_access_wrapper_get_value_at (GdaDataModel *model, gint col, gint row, GError **error) +{ + GdaDataAccessWrapper *imodel; + + g_return_val_if_fail (GDA_IS_DATA_ACCESS_WRAPPER (model), NULL); + imodel = (GdaDataAccessWrapper*) model; + GdaDataAccessWrapperPrivate *priv = gda_data_access_wrapper_get_instance_private (imodel); + g_return_val_if_fail (priv->model, NULL); + g_return_val_if_fail (row >= 0, NULL); + + if (col >= priv->nb_cols) { + g_set_error (error, GDA_DATA_MODEL_ERROR, GDA_DATA_MODEL_COLUMN_OUT_OF_RANGE_ERROR, + _("Column %d out of range (0-%d)"), col, priv->nb_cols - 1); + return NULL; + } + + if (!priv->rows) { + /* priv->model is a random access model, use it */ + if (priv->rows_mapping) + return gda_data_model_get_value_at (priv->model, priv->rows_mapping [col], + row, error); + else + return gda_data_model_get_value_at (priv->model, col, row, error); + } + else { + GdaRow *gda_row; + gint tmp; + tmp = row; + gda_row = g_hash_table_lookup (priv->rows, &tmp); + if (gda_row) { + GValue *val = gda_row_get_value (gda_row, col); + if (gda_row_value_is_valid (gda_row, val)) + return val; + else + return NULL; + } + else { + g_assert (priv->iter); + if (priv->iter_row < 0) { + if (gda_data_model_iter_move_next (priv->iter)) { + tmp = row; + gda_row = g_hash_table_lookup (priv->rows, &tmp); + if (row == priv->iter_row) { + GValue *val = gda_row_get_value (gda_row, col); + if (gda_row_value_is_valid (gda_row, val)) + return val; + else + return NULL; + } + } + else { + g_set_error (error, GDA_DATA_MODEL_ERROR, GDA_DATA_MODEL_ACCESS_ERROR, + "%s", _("Can't set iterator's position")); + return NULL; + } + } + + gda_row = NULL; + if (row != priv->iter_row) { + if (row > priv->iter_row) { + /* need to move forward */ + while ((priv->iter_row < row) && + gda_data_model_iter_move_next (priv->iter)); + } + else { + /* need to move backwards */ + g_assert (priv->model_access_flags & GDA_DATA_MODEL_ACCESS_CURSOR_BACKWARD); + while ((priv->iter_row > row) && + gda_data_model_iter_move_prev (priv->iter)) ; + } + } + + if (! (priv->model_access_flags & GDA_DATA_MODEL_ACCESS_CURSOR_BACKWARD) || + ! (priv->model_access_flags & GDA_DATA_MODEL_ACCESS_CURSOR_FORWARD)) { + tmp = row; + gda_row = g_hash_table_lookup (priv->rows, &tmp); + + if (gda_row) { + GValue *val = gda_row_get_value (gda_row, col); + if (gda_row_value_is_valid (gda_row, val)) + return val; + else + return NULL; + } + } + else { + /* in this case iter can be moved forward and backward at will => we only + * need to keep a pool of GdaRow for performances reasons */ + tmp = row; + gda_row = g_hash_table_lookup (priv->rows, &tmp); + + if (!gda_row) { + if (! priv->rows_buffer_array) { + priv->rows_buffer_array = g_array_sized_new (FALSE, FALSE, + sizeof (GdaRow*), + ROWS_POOL_SIZE); + priv->rows_buffer_index = g_array_sized_new (FALSE, FALSE, + sizeof (gint), + ROWS_POOL_SIZE); + } + else if (priv->rows_buffer_array->len == ROWS_POOL_SIZE) { + /* get rid of the oldest row (was model's index_row row)*/ + gint index_row; + + index_row = g_array_index (priv->rows_buffer_index, gint, + ROWS_POOL_SIZE - 1); + g_array_remove_index (priv->rows_buffer_array, + ROWS_POOL_SIZE - 1); + g_array_remove_index (priv->rows_buffer_index, + ROWS_POOL_SIZE - 1); + g_hash_table_remove (priv->rows, &index_row); + } + if (gda_data_model_iter_move_to_row (priv->iter, row)) { + gda_row = create_new_row (imodel); + g_array_prepend_val (priv->rows_buffer_array, gda_row); + g_array_prepend_val (priv->rows_buffer_index, priv->iter_row); + } + } + + GValue *val; + val = gda_row ? gda_row_get_value (gda_row, col) : NULL; + if (gda_row && gda_row_value_is_valid (gda_row, val)) + return val; + else + return NULL; + } + } + } + + g_set_error (error, GDA_DATA_MODEL_ERROR, GDA_DATA_MODEL_ACCESS_ERROR, + "%s", _("Can't access data")); + return NULL; +} + +static void +iter_row_changed_cb (GdaDataModelIter *iter, gint row, GdaDataAccessWrapper *model) +{ + GdaDataAccessWrapperPrivate *priv = gda_data_access_wrapper_get_instance_private (model); + g_assert (priv->rows); + + /*g_print ("%s(%d)\n", __FUNCTION__, row);*/ + if (gda_data_model_iter_is_valid (iter)) { + priv->iter_row = row; + if (priv->last_row < row) + priv->last_row = row; + + if (! (priv->model_access_flags & GDA_DATA_MODEL_ACCESS_CURSOR_BACKWARD) || + ! (priv->model_access_flags & GDA_DATA_MODEL_ACCESS_CURSOR_FORWARD)) { + /* keep the changes in rows */ + GdaRow *gda_row; + gint tmp; + tmp = row; + gda_row = g_hash_table_lookup (priv->rows, &tmp); + if (!gda_row) + create_new_row (model); + } + } +} + +static void +iter_end_of_data_cb (G_GNUC_UNUSED GdaDataModelIter *iter, GdaDataAccessWrapper *model) +{ + g_assert (GDA_IS_DATA_ACCESS_WRAPPER (model)); + GdaDataAccessWrapperPrivate *priv = gda_data_access_wrapper_get_instance_private (model); + priv->end_of_data = TRUE; +} + +static GdaValueAttribute +gda_data_access_wrapper_get_attributes_at (GdaDataModel *model, gint col, gint row) +{ + GdaValueAttribute flags = 0; + GdaDataAccessWrapper *imodel; + + g_return_val_if_fail (GDA_IS_DATA_ACCESS_WRAPPER (model), 0); + imodel = (GdaDataAccessWrapper *) model; + GdaDataAccessWrapperPrivate *priv = gda_data_access_wrapper_get_instance_private (imodel); + + if (priv->model) { + if (priv->rows_mapping) + flags = gda_data_model_get_attributes_at (priv->model, priv->rows_mapping [col], + row); + else + flags = gda_data_model_get_attributes_at (priv->model, col, row); + } + + flags |= GDA_VALUE_ATTR_NO_MODIF; + + return flags; +} + +static GError ** +gda_data_access_wrapper_get_exceptions (GdaDataModel *model) +{ + GdaDataAccessWrapper *imodel; + + g_return_val_if_fail (GDA_IS_DATA_ACCESS_WRAPPER (model), NULL); + imodel = (GdaDataAccessWrapper *) model; + GdaDataAccessWrapperPrivate *priv = gda_data_access_wrapper_get_instance_private (imodel); + return gda_data_model_get_exceptions (priv->model); +} diff --git a/.flatpak-builder/cache/objects/f2/ddd89af615bb3d0ff3060126060c27d732893726368fd196bcad14fcb1f5d6.file b/.flatpak-builder/cache/objects/f2/ddd89af615bb3d0ff3060126060c27d732893726368fd196bcad14fcb1f5d6.file new file mode 120000 index 0000000..767908b --- /dev/null +++ b/.flatpak-builder/cache/objects/f2/ddd89af615bb3d0ff3060126060c27d732893726368fd196bcad14fcb1f5d6.file @@ -0,0 +1 @@ +../../share/runtime/locale/dz/share/dz \ No newline at end of file diff --git a/.flatpak-builder/cache/objects/f2/de8f9b195aa35a1e22a4fd97958c19537bc4ad6fa44ccccf043f657cb6e77f.file b/.flatpak-builder/cache/objects/f2/de8f9b195aa35a1e22a4fd97958c19537bc4ad6fa44ccccf043f657cb6e77f.file new file mode 100644 index 0000000..334ac19 --- /dev/null +++ b/.flatpak-builder/cache/objects/f2/de8f9b195aa35a1e22a4fd97958c19537bc4ad6fa44ccccf043f657cb6e77f.file @@ -0,0 +1,336 @@ +/* + * Copyright (C) 2009 - 2013 Vivien Malerba + * Copyright (C) 2010 David King + * Copyright (C) 2018 Daniel Espinosa + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +#define G_LOG_DOMAIN "GDA-tree-mgr-select" + +#include +#include +#include +#include "gda-tree-mgr-select.h" +#include "gda-tree-node.h" + +typedef struct { + GdaConnection *cnc; + GdaStatement *stmt; + GdaSet *params; /* set by the constructor, may not contain values for all @stmt's params */ + GdaSet *priv_params; + GSList *non_bound_params; +} GdaTreeMgrSelectPrivate; +G_DEFINE_TYPE_WITH_PRIVATE (GdaTreeMgrSelect, gda_tree_mgr_select, GDA_TYPE_TREE_MANAGER) + +static void gda_tree_mgr_select_dispose (GObject *object); +static void gda_tree_mgr_select_set_property (GObject *object, + guint param_id, + const GValue *value, + GParamSpec *pspec); +static void gda_tree_mgr_select_get_property (GObject *object, + guint param_id, + GValue *value, + GParamSpec *pspec); + +/* virtual methods */ +static GSList *gda_tree_mgr_select_update_children (GdaTreeManager *manager, GdaTreeNode *node, const GSList *children_nodes, + gboolean *out_error, GError **error); + +/* properties */ +enum { + PROP_0, + PROP_CNC, + PROP_STMT, + PROP_PARAMS +}; + +/* + * GdaTreeMgrSelect class implementation + * @klass: + */ +static void +gda_tree_mgr_select_class_init (GdaTreeMgrSelectClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + /* virtual methods */ + ((GdaTreeManagerClass*) klass)->update_children = gda_tree_mgr_select_update_children; + + /* Properties */ + object_class->set_property = gda_tree_mgr_select_set_property; + object_class->get_property = gda_tree_mgr_select_get_property; + + g_object_class_install_property (object_class, PROP_CNC, + g_param_spec_object ("connection", NULL, "Connection to use", + GDA_TYPE_CONNECTION, + G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)); + g_object_class_install_property (object_class, PROP_STMT, + g_param_spec_object ("statement", NULL, "SELECT statement", + GDA_TYPE_STATEMENT, + G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)); + g_object_class_install_property (object_class, PROP_PARAMS, + g_param_spec_object ("params", NULL, "Parameters for the SELECT statement", + GDA_TYPE_SET, + G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)); + + object_class->dispose = gda_tree_mgr_select_dispose; +} + +static void +gda_tree_mgr_select_init (GdaTreeMgrSelect *mgr) {} + +static void +gda_tree_mgr_select_dispose (GObject *object) +{ + GdaTreeMgrSelect *mgr = (GdaTreeMgrSelect *) object; + + g_return_if_fail (GDA_IS_TREE_MGR_SELECT (mgr)); + GdaTreeMgrSelectPrivate *priv = gda_tree_mgr_select_get_instance_private (mgr); + + if (priv->cnc) + g_object_unref (priv->cnc); + if (priv->stmt) + g_object_unref (priv->stmt); + if (priv->params) + g_object_unref (priv->params); + if (priv->priv_params) + g_object_unref (priv->priv_params); + if (priv->non_bound_params) + g_slist_free (priv->non_bound_params); + + + /* chain to parent class */ + G_OBJECT_CLASS (gda_tree_mgr_select_parent_class)->dispose (object); +} + +static void +gda_tree_mgr_select_set_property (GObject *object, + guint param_id, + const GValue *value, + GParamSpec *pspec) +{ + GdaTreeMgrSelect *mgr; + + mgr = GDA_TREE_MGR_SELECT (object); + GdaTreeMgrSelectPrivate *priv = gda_tree_mgr_select_get_instance_private (mgr); + switch (param_id) { + case PROP_CNC: + priv->cnc = (GdaConnection*) g_value_get_object (value); + if (priv->cnc) + g_object_ref (priv->cnc); + break; + case PROP_STMT: + priv->stmt = (GdaStatement*) g_value_get_object (value); + if (priv->stmt) { + GError *lerror = NULL; + g_object_ref (priv->stmt); + if (!gda_statement_get_parameters (priv->stmt, &(priv->priv_params), &lerror)) { + g_warning (_("Could not get SELECT statement's parameters: %s"), + lerror && lerror->message ? lerror->message : _("No detail")); + if (lerror) + g_error_free (lerror); + } + if (priv->priv_params && gda_set_get_holders (priv->priv_params)) + priv->non_bound_params = g_slist_copy (gda_set_get_holders (priv->priv_params)); + } + break; + case PROP_PARAMS: + priv->params = (GdaSet*) g_value_get_object (value); + if (priv->params) + g_object_ref (priv->params); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + break; + } + + if (priv->priv_params && priv->params) { + /* bind holders in priv->priv_params to the ones in priv->params + * if they exist */ + GSList *params; + GSList *non_bound_params = NULL; + + g_slist_free (priv->non_bound_params); + for (params = gda_set_get_holders (priv->priv_params); params; params = params->next) { + GdaHolder *frh = GDA_HOLDER (params->data); + GdaHolder *toh = gda_set_get_holder (priv->params, gda_holder_get_id (frh)); + if (toh) { + GError *lerror = NULL; + if (!gda_holder_set_bind (frh, toh, &lerror)) { + g_warning (_("Could not bind SELECT statement's parameter '%s' " + "to provided parameters: %s"), + gda_holder_get_id (frh), + lerror && lerror->message ? lerror->message : _("No detail")); + if (lerror) + g_error_free (lerror); + non_bound_params = g_slist_prepend (non_bound_params, frh); + } + } + else + non_bound_params = g_slist_prepend (non_bound_params, frh); + } + priv->non_bound_params = non_bound_params; + } +} + +static void +gda_tree_mgr_select_get_property (GObject *object, + guint param_id, + GValue *value, + GParamSpec *pspec) +{ + GdaTreeMgrSelect *mgr; + + mgr = GDA_TREE_MGR_SELECT (object); + GdaTreeMgrSelectPrivate *priv = gda_tree_mgr_select_get_instance_private (mgr); + switch (param_id) { + case PROP_CNC: + g_value_set_object (value, priv->cnc); + break; + case PROP_STMT: + g_value_set_object (value, priv->stmt); + break; + case PROP_PARAMS: + g_value_set_object (value, priv->params); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + break; + } +} + +/** + * gda_tree_mgr_select_new: + * @cnc: a #GdaConnection object + * @stmt: a #GdaStatement object representing a SELECT statement + * @params: a #GdaSet object representing fixed parameters which are to be used when executing @stmt + * + * Creates a new #GdaTreeMgrSelect object which will add one tree node for each row in + * the #GdaDataModel resulting from the execution of @stmt. + * + * Returns: (transfer full): a new #GdaTreeManager object + * + * Since: 4.2 + */ +GdaTreeManager* +gda_tree_mgr_select_new (GdaConnection *cnc, GdaStatement *stmt, GdaSet *params) +{ + g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL); + g_return_val_if_fail (GDA_IS_STATEMENT (stmt), NULL); + g_return_val_if_fail (gda_statement_get_statement_type (stmt) == GDA_SQL_STATEMENT_SELECT, NULL); + g_return_val_if_fail (!params || GDA_IS_SET (params), NULL); + + return (GdaTreeManager*) g_object_new (GDA_TYPE_TREE_MGR_SELECT, + "connection", cnc, + "statement", stmt, + "params", params, NULL); +} + +static GSList * +gda_tree_mgr_select_update_children (GdaTreeManager *manager, GdaTreeNode *node, + G_GNUC_UNUSED const GSList *children_nodes, gboolean *out_error, + GError **error) +{ + GdaTreeMgrSelect *mgr = GDA_TREE_MGR_SELECT (manager); + GdaDataModel *model; + GSList *list = NULL; + GdaTreeMgrSelectPrivate *priv = gda_tree_mgr_select_get_instance_private (mgr); + + if (!priv->cnc) { + g_set_error (error, GDA_TREE_MANAGER_ERROR, GDA_TREE_MANAGER_UNKNOWN_ERROR, + "%s", _("No connection specified")); + if (out_error) + *out_error = TRUE; + return NULL; + } + + if (!priv->stmt) { + g_set_error (error, GDA_TREE_MANAGER_ERROR, GDA_TREE_MANAGER_UNKNOWN_ERROR, + "%s", _("No SELECT statement specified")); + if (out_error) + *out_error = TRUE; + return NULL; + } + + if (node && priv->non_bound_params) { + /* looking for values in @node's attributes */ + GSList *nbplist; + for (nbplist = priv->non_bound_params; nbplist; nbplist = nbplist->next) { + const GValue *cvalue; + GdaHolder *holder = (GdaHolder*) nbplist->data; + cvalue = gda_tree_node_fetch_attribute (node, gda_holder_get_id (holder)); + if (cvalue) { + if (!gda_holder_set_value (holder, cvalue, error)) { + if (out_error) + *out_error = TRUE; + return NULL; + } + } + else { + g_set_error (error, GDA_TREE_MANAGER_ERROR, GDA_TREE_MANAGER_UNKNOWN_ERROR, + _("No value specified for parameter '%s'"), gda_holder_get_id (holder)); + if (out_error) + *out_error = TRUE; + return NULL; + } + } + } + + model = gda_connection_statement_execute_select (priv->cnc, priv->stmt, priv->priv_params, error); + if (!model) { + if (out_error) + *out_error = TRUE; + return NULL; + } + + GdaDataModelIter *iter; + iter = gda_data_model_create_iter (model); + for (; iter && gda_data_model_iter_move_next (iter);) { + GdaTreeNode* snode = NULL; + const GValue *cvalue; + GSList *iholders; + + for (iholders = gda_set_get_holders (GDA_SET (iter)); iholders; iholders = iholders->next) { + GdaHolder *holder = (GdaHolder*) iholders->data; + + if (!gda_holder_is_valid (holder) || !(cvalue = gda_holder_get_value (holder))) { + if (list) { + g_slist_free_full (list, (GDestroyNotify) g_object_unref); + } + + if (out_error) + *out_error = TRUE; + g_set_error (error, GDA_TREE_MANAGER_ERROR, GDA_TREE_MANAGER_UNKNOWN_ERROR, + "%s", _("Unable to get iterator's value")); + return NULL; + } + + if (!snode) { + gchar *str = gda_value_stringify (cvalue); + snode = gda_tree_manager_create_node (manager, node, str); + g_free (str); + list = g_slist_prepend (list, snode); + } + + gda_tree_node_set_node_attribute (snode, g_strdup (gda_holder_get_id (holder)), cvalue, g_free); + } + } + if (iter) + g_object_unref (iter); + g_object_unref (model); + + return list; +} diff --git a/.flatpak-builder/cache/objects/f2/e2c974f1e771991a3ac217ebd8549852d0d84aaf2f0e36d8b23fc28f4a996f.file b/.flatpak-builder/cache/objects/f2/e2c974f1e771991a3ac217ebd8549852d0d84aaf2f0e36d8b23fc28f4a996f.file new file mode 120000 index 0000000..ca42fa5 --- /dev/null +++ b/.flatpak-builder/cache/objects/f2/e2c974f1e771991a3ac217ebd8549852d0d84aaf2f0e36d8b23fc28f4a996f.file @@ -0,0 +1 @@ +../../share/runtime/locale/sr/share/sr \ No newline at end of file diff --git a/.flatpak-builder/cache/objects/f3/45d42b6be66bcd07037db2cd3b43b473765eb23c3721cb805da560b372f97f.file b/.flatpak-builder/cache/objects/f3/45d42b6be66bcd07037db2cd3b43b473765eb23c3721cb805da560b372f97f.file new file mode 100644 index 0000000..259dae6 --- /dev/null +++ b/.flatpak-builder/cache/objects/f3/45d42b6be66bcd07037db2cd3b43b473765eb23c3721cb805da560b372f97f.file @@ -0,0 +1,467 @@ +/* gsound-attr.h + * + * Copyright (C) 2014 Tristan Brindle + * + * Adapted from canberra.h, + * + * Copyright 2008 Lennart Poettering + * + * This file is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of the + * License, or (at your option) any later version. + * + * This file is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef GSOUND_ATTR_H +#define GSOUND_ATTR_H + +#include + +G_BEGIN_DECLS + +/** + * SECTION:gsound-attr + * @title: GSound Attributes + * @short_description: Attributes recognized by GSound + * @see_also: #GSoundContext + * + * Attributes which can be applied to a #GSoundContext or passed to one of + * the `play()` or `cache()` methods. + */ + +/** + * GSOUND_ATTR_MEDIA_NAME: + * + * A name describing the media being played. Localized if possible and applicable. + */ +#define GSOUND_ATTR_MEDIA_NAME "media.name" + +/** + * GSOUND_ATTR_MEDIA_TITLE: + * + * A (song) title describing the media being played. Localized if possible and applicable. + */ +#define GSOUND_ATTR_MEDIA_TITLE "media.title" + +/** + * GSOUND_ATTR_MEDIA_ARTIST: + * + * The artist of this media. Localized if possible and applicable. + */ +#define GSOUND_ATTR_MEDIA_ARTIST "media.artist" + +/** + * GSOUND_ATTR_MEDIA_LANGUAGE: + * + * The language this media is in, in some standard POSIX locale string, such as "de_DE". + */ +#define GSOUND_ATTR_MEDIA_LANGUAGE "media.language" + +/** + * GSOUND_ATTR_MEDIA_FILENAME: + * + * The file name this media was or can be loaded from. + */ +#define GSOUND_ATTR_MEDIA_FILENAME "media.filename" + +/** + * GSOUND_ATTR_MEDIA_ICON: + * + * An icon for this media in binary PNG format. + */ +#define GSOUND_ATTR_MEDIA_ICON "media.icon" + +/** + * GSOUND_ATTR_MEDIA_ICON_NAME: + * + * An icon name as defined in the XDG icon naming specifcation. + */ +#define GSOUND_ATTR_MEDIA_ICON_NAME "media.icon_name" + +/** + * GSOUND_ATTR_MEDIA_ROLE: + * + * The "role" this media is played in. For event sounds the string + * "event". For other cases strings like "music", "video", "game", ... + */ +#define GSOUND_ATTR_MEDIA_ROLE "media.role" + +/** + * GSOUND_ATTR_EVENT_ID: + * + * A textual id for an event sound, as mandated by the XDG sound naming specification. + */ +#define GSOUND_ATTR_EVENT_ID "event.id" + +/** + * GSOUND_ATTR_EVENT_DESCRIPTION: + * + * A descriptive string for the sound event. Localized if possible and applicable. + */ +#define GSOUND_ATTR_EVENT_DESCRIPTION "event.description" + +/** + * GSOUND_ATTR_EVENT_MOUSE_X: + * + * If this sound event was triggered by a mouse input event, the X + * position of the mouse cursor on the screen, formatted as string. + */ +#define GSOUND_ATTR_EVENT_MOUSE_X "event.mouse.x" + +/** + * GSOUND_ATTR_EVENT_MOUSE_Y: + * + * If this sound event was triggered by a mouse input event, the Y + * position of the mouse cursor on the screen, formatted as string. + */ +#define GSOUND_ATTR_EVENT_MOUSE_Y "event.mouse.y" + +/** + * GSOUND_ATTR_EVENT_MOUSE_HPOS: + * + * If this sound event was triggered by a mouse input event, the X + * position of the mouse cursor as fractional value between 0 and 1, + * formatted as string, 0 reflecting the left side of the screen, 1 + * the right side. + */ +#define GSOUND_ATTR_EVENT_MOUSE_HPOS "event.mouse.hpos" + +/** + * GSOUND_ATTR_EVENT_MOUSE_VPOS: + * + * If this sound event was triggered by a mouse input event, the Y + * position of the mouse cursor as fractional value between 0 and 1, + * formatted as string, 0 reflecting the top end of the screen, 1 + * the bottom end. + */ +#define GSOUND_ATTR_EVENT_MOUSE_VPOS "event.mouse.vpos" + +/** + * GSOUND_ATTR_EVENT_MOUSE_BUTTON: + * + * If this sound event was triggered by a mouse input event, the + * number of the mouse button that triggered it, formatted as string. 1 + * for left mouse button, 3 for right, 2 for middle. + */ +#define GSOUND_ATTR_EVENT_MOUSE_BUTTON "event.mouse.button" + +/** + * GSOUND_ATTR_WINDOW_NAME: + * + * If this sound event was triggered by a window on the screen, the + * name of this window as human readable string. + */ +#define GSOUND_ATTR_WINDOW_NAME "window.name" + +/** + * GSOUND_ATTR_WINDOW_ID: + * + * If this sound event was triggered by a window on the screen, some + * identification string for this window, so that the sound system can + * recognize specific windows. + */ +#define GSOUND_ATTR_WINDOW_ID "window.id" + +/** + * GSOUND_ATTR_WINDOW_ICON: + * + * If this sound event was triggered by a window on the screen, binary + * icon data in PNG format for this window. + */ +#define GSOUND_ATTR_WINDOW_ICON "window.icon" + +/** + * GSOUND_ATTR_WINDOW_ICON_NAME: + * + * If this sound event was triggered by a window on the screen, an + * icon name for this window, as defined in the XDG icon naming + * specification. + */ +#define GSOUND_ATTR_WINDOW_ICON_NAME "window.icon_name" + +/** + * GSOUND_ATTR_WINDOW_X: + * + * If this sound event was triggered by a window on the screen, the X + * position of the window measured from the top left corner of the + * screen to the top left corner of the window. + */ +#define GSOUND_ATTR_WINDOW_X "window.x" + +/** + * GSOUND_ATTR_WINDOW_Y: + * + * If this sound event was triggered by a window on the screen, the y + * position of the window measured from the top left corner of the + * screen to the top left corner of the window. + */ +#define GSOUND_ATTR_WINDOW_Y "window.y" + +/** + * GSOUND_ATTR_WINDOW_WIDTH: + * + * If this sound event was triggered by a window on the screen, the + * pixel width of the window. + */ +#define GSOUND_ATTR_WINDOW_WIDTH "window.width" + +/** + * GSOUND_ATTR_WINDOW_HEIGHT: + * + * If this sound event was triggered by a window on the screen, the + * pixel height of the window. + */ +#define GSOUND_ATTR_WINDOW_HEIGHT "window.height" + +/** + * GSOUND_ATTR_WINDOW_HPOS: + * + * If this sound event was triggered by a window on the screen, the X + * position of the center of the window as fractional value between 0 + * and 1, formatted as string, 0 reflecting the left side of the + * screen, 1 the right side. + */ +#define GSOUND_ATTR_WINDOW_HPOS "window.hpos" + +/** + * GSOUND_ATTR_WINDOW_VPOS: + * + * If this sound event was triggered by a window on the screen, the Y + * position of the center of the window as fractional value between 0 + * and 1, formatted as string, 0 reflecting the top side of the + * screen, 1 the bottom side. + */ +#define GSOUND_ATTR_WINDOW_VPOS "window.vpos" + +/** + * GSOUND_ATTR_WINDOW_DESKTOP: + * + * If this sound event was triggered by a window on the screen and the + * windowing system supports multiple desktops, a comma seperated list + * of indexes of the desktops this window is visible on. If this + * attribute is an empty string, it is visible on all desktops + * (i.e. 'sticky'). The first desktop is 0. (e.g. "0,2,3") + */ +#define GSOUND_ATTR_WINDOW_DESKTOP "window.desktop" + +/** + * GSOUND_ATTR_WINDOW_X11_DISPLAY: + * + * If this sound event was triggered by a window on the screen and the + * windowing system is X11, the X display name of the window (e.g. ":0"). + */ +#define GSOUND_ATTR_WINDOW_X11_DISPLAY "window.x11.display" + +/** + * GSOUND_ATTR_WINDOW_X11_SCREEN: + * + * If this sound event was triggered by a window on the screen and the + * windowing system is X11, the X screen id of the window formatted as + * string (e.g. "0"). + */ +#define GSOUND_ATTR_WINDOW_X11_SCREEN "window.x11.screen" + +/** + * GSOUND_ATTR_WINDOW_X11_MONITOR: + * + * If this sound event was triggered by a window on the screen and the + * windowing system is X11, the X monitor id of the window formatted as + * string (e.g. "0"). + */ +#define GSOUND_ATTR_WINDOW_X11_MONITOR "window.x11.monitor" + +/** + * GSOUND_ATTR_WINDOW_X11_XID: + * + * If this sound event was triggered by a window on the screen and the + * windowing system is X11, the XID of the window formatted as string. + */ +#define GSOUND_ATTR_WINDOW_X11_XID "window.x11.xid" + +/** + * GSOUND_ATTR_APPLICATION_NAME: + * + * The name of the application this sound event was triggered by as + * human readable string. (e.g. "GNU Emacs") Localized if possible and + * applicable. + * + * > This attribute will automatically be added to the #GSoundContext if + * > it has previously been set with g_set_application_name(), so you normally + * > do not need to supply this yourself. + */ +#define GSOUND_ATTR_APPLICATION_NAME "application.name" + +/** + * GSOUND_ATTR_APPLICATION_ID: + * + * An identifier for the program this sound event was triggered + * by. (e.g. "org.gnu.emacs"). + * + * > This attribute will automatically be added to the #GSoundContext with + * > the #GApplication:application-id if you are using #GApplication, so you + * > normally do not need to supply this yourself. + */ +#define GSOUND_ATTR_APPLICATION_ID "application.id" + +/** + * GSOUND_ATTR_APPLICATION_VERSION: + * + * A version number for the program this sound event was triggered + * by. (e.g. "22.2") + */ +#define GSOUND_ATTR_APPLICATION_VERSION "application.version" + +/** + * GSOUND_ATTR_APPLICATION_ICON: + * + * Binary icon data in PNG format for the application this sound event + * is triggered by. + */ +#define GSOUND_ATTR_APPLICATION_ICON "application.icon" + +/** + * GSOUND_ATTR_APPLICATION_ICON_NAME: + * + * An icon name for the application this sound event is triggered by, + * as defined in the XDG icon naming specification. + */ +#define GSOUND_ATTR_APPLICATION_ICON_NAME "application.icon_name" + +/** + * GSOUND_ATTR_APPLICATION_LANGUAGE: + * + * The locale string the application that is triggering this sound + * event is running in. A POSIX locale string such as de_DE@euro. + */ +#define GSOUND_ATTR_APPLICATION_LANGUAGE "application.language" + +/** + * GSOUND_ATTR_APPLICATION_PROCESS_ID: + * + * The unix PID of the process that is triggering this sound event, formatted as string. + */ +#define GSOUND_ATTR_APPLICATION_PROCESS_ID "application.process.id" + +/** + * GSOUND_ATTR_APPLICATION_PROCESS_BINARY: + * + * The path to the process binary of the process that is triggering this sound event. + */ +#define GSOUND_ATTR_APPLICATION_PROCESS_BINARY "application.process.binary" + +/** + * GSOUND_ATTR_APPLICATION_PROCESS_USER: + * + * The user that owns the process that is triggering this sound event. + */ +#define GSOUND_ATTR_APPLICATION_PROCESS_USER "application.process.user" + +/** + * GSOUND_ATTR_APPLICATION_PROCESS_HOST: + * + * The host name of the host the process that is triggering this sound event runs on. + */ +#define GSOUND_ATTR_APPLICATION_PROCESS_HOST "application.process.host" + +/** + * GSOUND_ATTR_CANBERRA_CACHE_CONTROL: + * + * A special attribute that can be used to control the automatic sound + * caching of sounds in the sound server. One of "permanent", + * "volatile", "never". "permanent" will cause this sample to be + * cached in the server permanently. This is useful for very + * frequently used sound events such as those used for input + * feedback. "volatile" may be used for cacheing sounds in the sound + * server temporarily. They will expire after some time or on cache + * pressure. Finally, "never" may be used for sounds that should never + * be cached, because they are only generated very seldomly or even + * only once at most (such as desktop login sounds). + * + * If this attribute is not explicitly passed to gsound_context_play_simple() + * or gsound_context_play_full() it will default to "never". If it is not + * explicitly passed to gsound_context_cache() it will default to "permanent". + * + * If the list of attributes is handed on to the sound server this + * attribute is stripped from it. + */ +#define GSOUND_ATTR_CANBERRA_CACHE_CONTROL "canberra.cache-control" + +/** + * GSOUND_ATTR_CANBERRA_VOLUME: + * + * A special attribute that can be used to control the volume this + * sound event is played in if the backend supports it. A floating + * point value for the decibel multiplier for the sound. 0 dB relates + * to zero gain, and is the default volume these sounds are played in. + * + * If the list of attributes is handed on to the sound server this + * attribute is stripped from it. + */ +#define GSOUND_ATTR_CANBERRA_VOLUME "canberra.volume" + +/** + * GSOUND_ATTR_CANBERRA_XDG_THEME_NAME: + * + * A special attribute that can be used to control the XDG sound theme that + * is used for this sample. + * + * If the list of attributes is handed on to the sound server this + * attribute is stripped from it. + */ +#define GSOUND_ATTR_CANBERRA_XDG_THEME_NAME "canberra.xdg-theme.name" + +/** + * GSOUND_ATTR_CANBERRA_XDG_THEME_OUTPUT_PROFILE: + * + * A special attribute that can be used to control the XDG sound theme + * output profile that is used for this sample. + * + * If the list of attributes is handed on to the sound server this + * attribute is stripped from it. + */ +#define GSOUND_ATTR_CANBERRA_XDG_THEME_OUTPUT_PROFILE "canberra.xdg-theme.output-profile" + +/** + * GSOUND_ATTR_CANBERRA_ENABLE: + * + * A special attribute that can be used to control whether any sounds + * are played at all. If this attribute is "1" or unset sounds are + * played as normal. However, if it is "0" all calls to + * gsound_context_play_simple() or `play_full()` will fail with + * GSOUND_ERROR_DISABLED. + * + * If the list of attributes is handed on to the sound server this + * attribute is stripped from it. + */ +#define GSOUND_ATTR_CANBERRA_ENABLE "canberra.enable" + +/** + * GSOUND_ATTR_CANBERRA_FORCE_CHANNEL: + * + * A special attribute that can be used to control on which channel a + * sound is played. The value should be one of mono, front-left, + * front-right, front-center, rear-left, rear-right, rear-center, lfe, + * front-left-of-center, front-right-of-center, side-left, side-right, + * top-center, top-front-left, top-front-right, top-front-center, + * top-rear-left, top-rear-right, top-rear-center. This attribute is + * only honoured by some backends, other backends may choose to ignore + * it completely. + * + * If the list of attributes is handed on to the sound server this + * attribute is stripped from it. + */ +#define GSOUND_ATTR_CANBERRA_FORCE_CHANNEL "canberra.force_channel" + + + +G_END_DECLS + +#endif /* GSOUND_ATTR_H */ diff --git a/.flatpak-builder/cache/objects/f3/83b0941456813073fbd03c8059affc3c42febce4247482f00162b1eb4988a5.dirtree b/.flatpak-builder/cache/objects/f3/83b0941456813073fbd03c8059affc3c42febce4247482f00162b1eb4988a5.dirtree new file mode 100644 index 0000000..a7dacf2 Binary files /dev/null and b/.flatpak-builder/cache/objects/f3/83b0941456813073fbd03c8059affc3c42febce4247482f00162b1eb4988a5.dirtree differ diff --git a/.flatpak-builder/cache/objects/f3/a2a374322c03d4ed5e8753ced05eb7ac5870c2818be1b84301b42d9f9554ff.dirtree b/.flatpak-builder/cache/objects/f3/a2a374322c03d4ed5e8753ced05eb7ac5870c2818be1b84301b42d9f9554ff.dirtree new file mode 100644 index 0000000..22872f6 Binary files /dev/null and b/.flatpak-builder/cache/objects/f3/a2a374322c03d4ed5e8753ced05eb7ac5870c2818be1b84301b42d9f9554ff.dirtree differ diff --git a/.flatpak-builder/cache/objects/f3/bb4acd20305404dbc01f863cd27bc8b95477503ab18589a952f21c800806aa.file b/.flatpak-builder/cache/objects/f3/bb4acd20305404dbc01f863cd27bc8b95477503ab18589a952f21c800806aa.file new file mode 100644 index 0000000..0819ac7 --- /dev/null +++ b/.flatpak-builder/cache/objects/f3/bb4acd20305404dbc01f863cd27bc8b95477503ab18589a952f21c800806aa.file @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2009 - 2011 Vivien Malerba + * Copyright (C) 2018 Daniel Espinosa + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GDA_TREE_MGR_COLUMNS_H__ +#define __GDA_TREE_MGR_COLUMNS_H__ + +#include +#include "gda-tree-manager.h" + +G_BEGIN_DECLS + +#define GDA_TYPE_TREE_MGR_COLUMNS (gda_tree_mgr_columns_get_type()) +G_DECLARE_DERIVABLE_TYPE(GdaTreeMgrColumns, gda_tree_mgr_columns, GDA, TREE_MGR_COLUMNS, GdaTreeManager) +struct _GdaTreeMgrColumnsClass { + GdaTreeManagerClass object_class; +}; + +/** + * SECTION:gda-tree-mgr-columns + * @short_description: A tree manager which creates a node for each column of a table + * @title: GdaTreeMgrColumns + * @stability: Stable + * @see_also: + * + * The #GdaTreeMgrColumns is a #GdaTreeManager object which creates a node for + * each column in a table. + * + * It uses the #GdaMetaStore associated to a #GdaConnection to get the columns list + * for a table designated by its name and the database schema it is in; it's up to the + * caller to make sure the data in the #GdaMetaStore is up to date. + * + * The #GdaConnection to be used needs to be specified when the object is created. The table + * name and schema can however be specified when the object is created, and if not, are + * fetched from the #GdaTreeNode below which the nodes will be placed (using + * gda_tree_node_fetch_attribute()). + */ + +GdaTreeManager* gda_tree_mgr_columns_new (GdaConnection *cnc, const gchar *schema, + const gchar *table_name); + +G_END_DECLS + +#endif diff --git a/.flatpak-builder/cache/objects/f3/fa8ca99d700cb186655925d37d5ece1fcb7a5b0dbac1ff6f7e0b60ac8242e2.file b/.flatpak-builder/cache/objects/f3/fa8ca99d700cb186655925d37d5ece1fcb7a5b0dbac1ff6f7e0b60ac8242e2.file new file mode 100644 index 0000000..b0d6fec --- /dev/null +++ b/.flatpak-builder/cache/objects/f3/fa8ca99d700cb186655925d37d5ece1fcb7a5b0dbac1ff6f7e0b60ac8242e2.file @@ -0,0 +1,658 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ + + + + + + + + + +
+ + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + +
+ + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + +
+ + + SELECT short_type_name AS short_type_name, gtype, full_type_name AS full_type_name, comments, internal AS internal, synonyms, + NULL AS domain_catalog, NULL AS domain_schema, NULL AS domain_name, + NULL AS udt_catalog, NULL AS udt_schema, NULL AS udt_name + FROM _builtin_data_types +UNION +SELECT udt_short_name, udt_gtype, udt_full_name, udt_comments, udt_internal, NULL, + NULL, NULL, NULL, udt_catalog, udt_schema, udt_name FROM _udt +UNION +SELECT domain_short_name, domain_gtype, domain_full_name, domain_comments, domain_internal, NULL, + domain_catalog, domain_schema, domain_name , NULL, NULL, NULL FROM _domains + + + + SELECT rc.table_catalog as fk_table_catalog, rc.table_schema as fk_table_schema, rc.table_name as fk_table_name, kc1.column_name as fk_column, + rc.ref_table_catalog as ref_table_catalog, rc.ref_table_schema as ref_table_schema, rc.ref_table_name as ref_table_name, kc2.column_name as ref_column, + rc.constraint_name as fk_constraint_name, kc1.ordinal_position as ordinal_position + FROM _referential_constraints rc + INNER JOIN _key_column_usage kc2 ON (rc.ref_table_catalog=kc2.table_catalog AND rc.ref_table_schema=kc2.table_schema AND rc.ref_table_name=kc2.table_name AND rc.ref_constraint_name=kc2.constraint_name) + INNER JOIN _key_column_usage kc1 ON (rc.table_catalog=kc1.table_catalog AND rc.table_schema=kc1.table_schema AND rc.table_name=kc1.table_name AND rc.constraint_name=kc1.constraint_name) + WHERE kc1.ordinal_position = kc2.ordinal_position + ORDER BY rc.table_catalog, rc.table_schema, rc.table_name, kc1.ordinal_position + + + +
diff --git a/.flatpak-builder/cache/objects/f4/23c67800542470ee47718284b0451a92ead2933055bb370de60f0541ecbcaa.file b/.flatpak-builder/cache/objects/f4/23c67800542470ee47718284b0451a92ead2933055bb370de60f0541ecbcaa.file new file mode 100644 index 0000000..914ee7a --- /dev/null +++ b/.flatpak-builder/cache/objects/f4/23c67800542470ee47718284b0451a92ead2933055bb370de60f0541ecbcaa.file @@ -0,0 +1,1343 @@ + + + + +canberra + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+

canberra

+

canberra — General libcanberra API

+
+
+

Synopsis

+
#define             CA_PROP_MEDIA_NAME
+#define             CA_PROP_MEDIA_TITLE
+#define             CA_PROP_MEDIA_ARTIST
+#define             CA_PROP_MEDIA_LANGUAGE
+#define             CA_PROP_MEDIA_FILENAME
+#define             CA_PROP_MEDIA_ICON
+#define             CA_PROP_MEDIA_ICON_NAME
+#define             CA_PROP_MEDIA_ROLE
+#define             CA_PROP_EVENT_ID
+#define             CA_PROP_EVENT_DESCRIPTION
+#define             CA_PROP_EVENT_MOUSE_X
+#define             CA_PROP_EVENT_MOUSE_Y
+#define             CA_PROP_EVENT_MOUSE_HPOS
+#define             CA_PROP_EVENT_MOUSE_VPOS
+#define             CA_PROP_EVENT_MOUSE_BUTTON
+#define             CA_PROP_WINDOW_NAME
+#define             CA_PROP_WINDOW_ID
+#define             CA_PROP_WINDOW_ICON
+#define             CA_PROP_WINDOW_ICON_NAME
+#define             CA_PROP_WINDOW_X11_DISPLAY
+#define             CA_PROP_WINDOW_X11_SCREEN
+#define             CA_PROP_WINDOW_X11_MONITOR
+#define             CA_PROP_WINDOW_X11_XID
+#define             CA_PROP_APPLICATION_NAME
+#define             CA_PROP_APPLICATION_ID
+#define             CA_PROP_APPLICATION_VERSION
+#define             CA_PROP_APPLICATION_ICON
+#define             CA_PROP_APPLICATION_ICON_NAME
+#define             CA_PROP_APPLICATION_LANGUAGE
+#define             CA_PROP_APPLICATION_PROCESS_ID
+#define             CA_PROP_APPLICATION_PROCESS_BINARY
+#define             CA_PROP_APPLICATION_PROCESS_USER
+#define             CA_PROP_APPLICATION_PROCESS_HOST
+#define             CA_PROP_CANBERRA_CACHE_CONTROL
+#define             CA_PROP_CANBERRA_VOLUME
+#define             CA_PROP_CANBERRA_XDG_THEME_NAME
+#define             CA_PROP_CANBERRA_XDG_THEME_OUTPUT_PROFILE
+
+typedef             ca_context;
+void                (*ca_finish_callback_t)             (ca_context *c,
+                                                         uint32_t id,
+                                                         int error_code,
+                                                         void *userdata);
+int                 ca_context_create                   (ca_context **c);
+int                 ca_context_destroy                  (ca_context *c);
+int                 ca_context_open                     (ca_context *c);
+int                 ca_context_set_driver               (ca_context *c,
+                                                         const char *driver);
+int                 ca_context_change_device            (ca_context *c,
+                                                         const char *device);
+int                 ca_context_change_props             (ca_context *c,
+                                                         ...);
+int                 ca_context_change_props_full        (ca_context *c,
+                                                         ca_proplist *p);
+int                 ca_context_play                     (ca_context *c,
+                                                         uint32_t id,
+                                                         ...);
+int                 ca_context_play_full                (ca_context *c,
+                                                         uint32_t id,
+                                                         ca_proplist *p,
+                                                         ca_finish_callback_t cb,
+                                                         void *userdata);
+int                 ca_context_cancel                   (ca_context *c,
+                                                         uint32_t id);
+int                 ca_context_cache                    (ca_context *c,
+                                                         ...);
+int                 ca_context_cache_full               (ca_context *c,
+                                                         ca_proplist *p);
+int                 ca_context_playing                  (ca_context *c,
+                                                         uint32_t id,
+                                                         int *playing);
+
+const char *        ca_strerror                         (int code);
+
+typedef             ca_proplist;
+int                 ca_proplist_create                  (ca_proplist **p);
+int                 ca_proplist_destroy                 (ca_proplist *p);
+int                 ca_proplist_sets                    (ca_proplist *p,
+                                                         const char *key,
+                                                         const char *value);
+int                 ca_proplist_setf                    (ca_proplist *p,
+                                                         const char *key,
+                                                         const char *format,
+                                                         ...);
+int                 ca_proplist_set                     (ca_proplist *p,
+                                                         const char *key,
+                                                         const void *data,
+                                                         size_t nbytes);
+
+
+
+

Description

+

+libcanberra defines a simple abstract interface for playing event sounds. +

+

+libcanberra relies on the XDG sound naming specification for +identifying event sounds. On Unix/Linux the right sound to play is +found via the mechanisms defined in the XDG sound themeing +specification. On other systems the XDG sound name is translated to +the native sound id for the operating system. +

+

+An event sound is triggered via libcanberra by calling the +ca_context_play() function on a previously created ca_context +object. The ca_context_play() takes a list of key-value pairs that +describe the event sound to generate as closely as possible. The +most important property is CA_PROP_EVENT_ID which defines the XDG +sound name for the sound to play. +

+

+libcanberra is not a generic event abstraction system. It's only +purpose is playing sounds -- however in a very elaborate way. As +much information about the context the sound is triggered from +shall be supplied to the sound system as possible, so that it can +replace the sound with some other kind of feedback for a11y +cases. Also this additional information can be used to enhance user +experience (e.g. by positioning sounds in space depending on the +place on the screen the sound was triggered from, and similar +uses). +

+

+The set of properties defined for event sounds is extensible and +shared with other audio systems, such as PulseAudio. Some of +the properties that may be set are specific to an application, to a +window, to an input event or to the media being played back. +

+

+The user can attach a set of properties to the context itself, +which is than automatically inherited by each sample being played +back. (ca_context_change_props()). +

+

+Some of the properties can be filled in by libcanberra or one of +its backends automatically and thus need not be be filled in by the +application (such as CA_PROP_APPLICATION_PROCESS_ID and +friends). However the application can always overwrite any of these +implicit properties. +

+

+libcanberra is thread-safe and OOM-safe (as far as the backend +allows this). It is not async-signal safe. +

+

+Most libcanberra functions return an integer that indicates success +when 0 (CA_SUCCESS) or an error when negative. In the latter case +ca_strerror() can be used to convert this code into a human +readable string. +

+

+libcanberra property names need to be in 7bit ASCII, string +property values UTF8. +

+

+Optionally a libcanberra backend can support caching of sounds in a +sound system. If this functionality is used, the latencies for +event sound playback can be much smaller and fewer resources are +needed to start playback. If a backend does not support cacheing, +the respective functions will return an error code of +CA_ERROR_NOTSUPPORTED. +

+

+It is highly recommended that the application sets the +CA_PROP_APPLICATION_NAME, CA_PROP_APPLICATION_ID, +CA_PROP_APPLICATION_ICON_NAME/CA_PROP_APPLICATION_ICON properties +immediately after creating the ca_context, before calling +ca_context_open() or ca_context_play(). +

+

+Its is highly recommended to pass at least CA_PROP_EVENT_ID, +CA_PROP_EVENT_DESCRIPTION to ca_context_play() for each event +sound generated. For sound events based on mouse inputs events +CA_PROP_EVENT_MOUSE_X, CA_PROP_EVENT_MOUSE_Y, CA_PROP_EVENT_MOUSE_HPOS, +CA_PROP_EVENT_MOUSE_VPOS, CA_PROP_EVENT_MOUSE_BUTTON should be +passed. For sound events attached to a widget on the screen, the +CA_PROP_WINDOW_xxx properties should be set. +

+
+
+

Details

+
+

CA_PROP_MEDIA_NAME

+
#define CA_PROP_MEDIA_NAME                         "media.name"
+
+

+A name describing the media being played. Localized if possible and applicable. +

+
+
+
+

CA_PROP_MEDIA_TITLE

+
#define CA_PROP_MEDIA_TITLE                        "media.title"
+
+

+A (song) title describing the media being played. Localized if possible and applicable. +

+
+
+
+

CA_PROP_MEDIA_ARTIST

+
#define CA_PROP_MEDIA_ARTIST                       "media.artist"
+
+

+The artist of this media. Localized if possible and applicable. +

+
+
+
+

CA_PROP_MEDIA_LANGUAGE

+
#define CA_PROP_MEDIA_LANGUAGE                     "media.language"
+
+

+The language this media is in, in some standard POSIX locale string, such as "de_DE". +

+
+
+
+

CA_PROP_MEDIA_FILENAME

+
#define CA_PROP_MEDIA_FILENAME                     "media.filename"
+
+

+The file name this media was or can be loaded from. +

+
+
+
+

CA_PROP_MEDIA_ICON

+
#define CA_PROP_MEDIA_ICON                         "media.icon"
+
+

+An icon for this media in binary PNG format. +

+
+
+
+

CA_PROP_MEDIA_ICON_NAME

+
#define CA_PROP_MEDIA_ICON_NAME                    "media.icon_name"
+
+

+An icon name as defined in the XDG icon naming specifcation. +

+
+
+
+

CA_PROP_MEDIA_ROLE

+
#define CA_PROP_MEDIA_ROLE                         "media.role"
+
+

+The "role" this media is played in. For event sounds the string +"event". For other cases strings like "music", "video", "game", ... +

+
+
+
+

CA_PROP_EVENT_ID

+
#define CA_PROP_EVENT_ID                           "event.id"
+
+

+A textual id for an event sound, as mandated by the XDG sound naming specification. +

+
+
+
+

CA_PROP_EVENT_DESCRIPTION

+
#define CA_PROP_EVENT_DESCRIPTION                  "event.description"
+
+

+A descriptive string for the sound event. Localized if possible and applicable. +

+
+
+
+

CA_PROP_EVENT_MOUSE_X

+
#define CA_PROP_EVENT_MOUSE_X                      "event.mouse.x"
+
+

+If this sound event was triggered by a mouse input event, the X +position of the mouse cursor on the screen, formatted as string. +

+
+
+
+

CA_PROP_EVENT_MOUSE_Y

+
#define CA_PROP_EVENT_MOUSE_Y                      "event.mouse.y"
+
+

+If this sound event was triggered by a mouse input event, the Y +position of the mouse cursor on the screen, formatted as string. +

+
+
+
+

CA_PROP_EVENT_MOUSE_HPOS

+
#define CA_PROP_EVENT_MOUSE_HPOS                   "event.mouse.hpos"
+
+

+If this sound event was triggered by a mouse input event, the X +position of the mouse cursor as fractional value between 0 and 1, +formatted as string, 0 reflecting the left side of the screen, 1 +the right side. +

+
+
+
+

CA_PROP_EVENT_MOUSE_VPOS

+
#define CA_PROP_EVENT_MOUSE_VPOS                   "event.mouse.vpos"
+
+

+If this sound event was triggered by a mouse input event, the Y +position of the mouse cursor as fractional value between 0 and 1, +formatted as string, 0 reflecting the top end of the screen, 1 +the bottom end. +

+
+
+
+

CA_PROP_EVENT_MOUSE_BUTTON

+
#define CA_PROP_EVENT_MOUSE_BUTTON                 "event.mouse.button"
+
+

+If this sound event was triggered by a mouse input event, the +number of the mouse button that triggered it, formatted as string. 1 +for left mouse button, 3 for right, 2 for middle. +

+
+
+
+

CA_PROP_WINDOW_NAME

+
#define CA_PROP_WINDOW_NAME                        "window.name"
+
+

+If this sound event was triggered by a window on the screen, the +name of this window as human readable string. +

+
+
+
+

CA_PROP_WINDOW_ID

+
#define CA_PROP_WINDOW_ID                          "window.id"
+
+

+If this sound event was triggered by a window on the screen, some +identification string for this window, so that the sound system can +recognize specific windows. +

+
+
+
+

CA_PROP_WINDOW_ICON

+
#define CA_PROP_WINDOW_ICON                        "window.icon"
+
+

+If this sound event was triggered by a window on the screen, binary +icon data in PNG format for this window. +

+
+
+
+

CA_PROP_WINDOW_ICON_NAME

+
#define CA_PROP_WINDOW_ICON_NAME                   "window.icon_name"
+
+

+If this sound event was triggered by a window on the screen, an +icon name for this window, as defined in the XDG icon naming +specification. +

+
+
+
+

CA_PROP_WINDOW_X11_DISPLAY

+
#define CA_PROP_WINDOW_X11_DISPLAY                 "window.x11.display"
+
+

+If this sound event was triggered by a window on the screen and the +windowing system is X11, the X display name of the window (e.g. ":0"). +

+
+
+
+

CA_PROP_WINDOW_X11_SCREEN

+
#define CA_PROP_WINDOW_X11_SCREEN                  "window.x11.screen"
+
+

+If this sound event was triggered by a window on the screen and the +windowing system is X11, the X screen id of the window formatted as +string (e.g. "0"). +

+
+
+
+

CA_PROP_WINDOW_X11_MONITOR

+
#define CA_PROP_WINDOW_X11_MONITOR                 "window.x11.monitor"
+
+

+If this sound event was triggered by a window on the screen and the +windowing system is X11, the X monitor id of the window formatted as +string (e.g. "0"). +

+
+
+
+

CA_PROP_WINDOW_X11_XID

+
#define CA_PROP_WINDOW_X11_XID                     "window.x11.xid"
+
+

+If this sound event was triggered by a window on the screen and the +windowing system is X11, the XID of the window formatted as string. +

+
+
+
+

CA_PROP_APPLICATION_NAME

+
#define CA_PROP_APPLICATION_NAME                   "application.name"
+
+

+The name of the application this sound event was triggered by as +human readable string. (e.g. "GNU Emacs") Localized if possible and +applicable. +

+
+
+
+

CA_PROP_APPLICATION_ID

+
#define CA_PROP_APPLICATION_ID                     "application.id"
+
+

+An identifier for the program this sound event was triggered +by. (e.g. "org.gnu.emacs"). +

+
+
+
+

CA_PROP_APPLICATION_VERSION

+
#define CA_PROP_APPLICATION_VERSION                "application.version"
+
+

+A version number for the program this sound event was triggered +by. (e.g. "22.2") +

+
+
+
+

CA_PROP_APPLICATION_ICON

+
#define CA_PROP_APPLICATION_ICON                   "application.icon"
+
+

+Binary icon data in PNG format for the application this sound event +is triggered by. +

+
+
+
+

CA_PROP_APPLICATION_ICON_NAME

+
#define CA_PROP_APPLICATION_ICON_NAME              "application.icon_name"
+
+

+An icon name for the application this sound event is triggered by, +as defined in the XDG icon naming specification. +

+
+
+
+

CA_PROP_APPLICATION_LANGUAGE

+
#define CA_PROP_APPLICATION_LANGUAGE               "application.language"
+
+

+The locale string the application that is triggering this sound +event is running in. A POSIX locale string such as de_DEeuro. +

+
+
+
+

CA_PROP_APPLICATION_PROCESS_ID

+
#define CA_PROP_APPLICATION_PROCESS_ID             "application.process.id"
+
+

+The unix PID of the process that is triggering this sound event, formatted as string. +

+
+
+
+

CA_PROP_APPLICATION_PROCESS_BINARY

+
#define CA_PROP_APPLICATION_PROCESS_BINARY         "application.process.binary"
+
+

+The path to the process binary of the process that is triggering this sound event. +

+
+
+
+

CA_PROP_APPLICATION_PROCESS_USER

+
#define CA_PROP_APPLICATION_PROCESS_USER           "application.process.user"
+
+

+The user that owns the process that is triggering this sound event. +

+
+
+
+

CA_PROP_APPLICATION_PROCESS_HOST

+
#define CA_PROP_APPLICATION_PROCESS_HOST           "application.process.host"
+
+

+The host name of the host the process that is triggering this sound event runs on. +

+
+
+
+

CA_PROP_CANBERRA_CACHE_CONTROL

+
#define CA_PROP_CANBERRA_CACHE_CONTROL             "canberra.cache-control"
+
+

+A special property that can be used to control the automatic sound +caching of sounds in the sound server. One of "permanent", +"volatile", "never". "permanent" will cause this sample to be +cached in the server permanently. This is useful for very +frequently used sound events such as those used for input +feedback. "volatile" may be used for cacheing sounds in the sound +server temporarily. They will expire after some time or on cache +pressure. Finally, "never" may be used for sounds that should never +be cached, because they are only generated very seldomly or even +only once at most (such as desktop login sounds). +

+

+If this property is not explicitly passed to ca_context_play() it +will default to "never". If it is not explicitly passed to +ca_context_cache() it will default to "permanent". +

+

+If the list of properties is handed on to the sound server this +property is stripped from it. +

+
+
+
+

CA_PROP_CANBERRA_VOLUME

+
#define CA_PROP_CANBERRA_VOLUME                    "canberra.volume"
+
+

+A special property that can be used to control the volume this +sound event is played in if the backend supports it. A floating +point value for the decibel multiplier for the sound. 0 dB relates +to zero gain, and is the default volume these sounds are played in. +

+

+If the list of properties is handed on to the sound server this +property is stripped from it. +

+
+
+
+

CA_PROP_CANBERRA_XDG_THEME_NAME

+
#define CA_PROP_CANBERRA_XDG_THEME_NAME            "canberra.xdg-theme.name"
+
+

+A special property that can be used to control the XDG sound theme that +is used for this sample. +

+

+If the list of properties is handed on to the sound server this +property is stripped from it. +

+
+
+
+

CA_PROP_CANBERRA_XDG_THEME_OUTPUT_PROFILE

+
#define CA_PROP_CANBERRA_XDG_THEME_OUTPUT_PROFILE  "canberra.xdg-theme.output-profile"
+
+

+A special property that can be used to control the XDG sound theme +output profile that is used for this sample. +

+

+If the list of properties is handed on to the sound server this +property is stripped from it. +

+
+
+
+

ca_context

+
typedef struct ca_context ca_context;
+
+

+A libcanberra context object. +

+
+
+
+

ca_finish_callback_t ()

+
void                (*ca_finish_callback_t)             (ca_context *c,
+                                                         uint32_t id,
+                                                         int error_code,
+                                                         void *userdata);
+

+Playback completion event callback. The context this callback is +called in is undefined, it might or might not be called from a +background thread, and from any stack frame. The code implementing +this function may not call any libcanberra API call from this +callback -- this might result in a deadlock. Instead it may only be +used to asynchronously signal some kind of notification object +(semaphore, message queue, ...). +

+
++++ + + + + + + + + + + + + + + + + + + +

c :

The libcanberra context this callback is called for

id :

The numerical id passed to the ca_context_play_full() when starting the event sound playback.

error_code :

A numerical error code describing the reason this callback is called. If CA_SUCCESS is passed in the playback of the event sound was successfully completed.

userdata :

Some arbitrary user data the caller of ca_context_play_full() passed in.
+
+
+
+

ca_context_create ()

+
int                 ca_context_create                   (ca_context **c);
+

+Create an (unconnected) context object. This call will not connect +to the sound system, calling this function might even suceed if no +working driver backend is available. To find out if one is +available call ca_context_open(). +

+
++++ + + + + + + + + + + +

c :

A pointer wheere to fill in the newly created context object.

Returns :

0 on success, negative error code on error.
+
+
+
+

ca_context_destroy ()

+
int                 ca_context_destroy                  (ca_context *c);
+

+Destroy a (connected or unconnected) context object. +

+
++++ + + + + + + + + + + +

c :

the context to destroy.

Returns :

0 on success, negative error code on error.
+
+
+
+

ca_context_open ()

+
int                 ca_context_open                     (ca_context *c);
+

+Connect the context to the sound system. This call is implicitly +called in ca_context_play() or ca_context_cache() if not called +explicitly. It is recommended to initialize application properties +with ca_context_change_props() before calling this function. +

+
++++ + + + + + + + + + + +

c :

the context to connect.

Returns :

0 on success, negative error code on error.
+
+
+
+

ca_context_set_driver ()

+
int                 ca_context_set_driver               (ca_context *c,
+                                                         const char *driver);
+

+Specify the backend driver used. This function may not be called again after +ca_context_open() suceeded. This function might suceed even when +the specified driver backend is not available. Use +ca_context_open() to find out whether the backend is available. +

+
++++ + + + + + + + + + + + + + + +

c :

the context to change the backend driver for

driver :

the backend driver to use (e.g. "alsa", "pulse", "null", ...)

Returns :

0 on success, negative error code on error.
+
+
+
+

ca_context_change_device ()

+
int                 ca_context_change_device            (ca_context *c,
+                                                         const char *device);
+

+Specify the backend device to use. This function may be called not be called after +ca_context_open() suceeded. This function might suceed even when +the specified driver backend is not available. Use +ca_context_open() to find out whether the backend is available +

+

+Depending on the backend use this might or might not cause all +currently playing event sounds to be moved to the new device.. +

+
++++ + + + + + + + + + + + + + + +

c :

the context to change the backend device for

device :

the backend device to use, in a format that is specific to the backend.

Returns :

0 on success, negative error code on error.
+
+
+
+

ca_context_change_props ()

+
int                 ca_context_change_props             (ca_context *c,
+                                                         ...);
+

+Write one or more string properties to the context object. Requires +final NULL sentinel. Properties set like this will be attached to +both the client object of the sound server and to all event sounds +played or cached. It is recommended to call this function at least +once before calling ca_context_open(), so that the initial +application properties are set properly before the initial +connection to the sound system. This function can be called both +before and after the ca_context_open() call. Properties that have +already been set before will be overwritten. +

+
++++ + + + + + + + + + + + + + + +

c :

the context to set the properties on.

... :

the list of string pairs for the properties. Needs to be a NULL terminated list.

Returns :

0 on success, negative error code on error.
+
+
+
+

ca_context_change_props_full ()

+
int                 ca_context_change_props_full        (ca_context *c,
+                                                         ca_proplist *p);
+

+Similar to ca_context_change_props(), but takes a ca_proplist +instead of a variable list of properties. Can be used to set binary +properties such as CA_PROP_APPLICATION_ICON. +

+
++++ + + + + + + + + + + + + + + +

c :

the context to set the properties on.

p :

the property list to set.

Returns :

0 on success, negative error code on error.
+
+
+
+

ca_context_play ()

+
int                 ca_context_play                     (ca_context *c,
+                                                         uint32_t id,
+                                                         ...);
+

+Play one event sound. id can be any numeric value which later can +be used to cancel an event sound that is currently being +played. You may use the same id twice or more times if you want to +cancel multiple event sounds with a single ca_context_cancel() call +at once. It is recommended to pass 0 for the id if the event sound +shall never be canceled. If the requested sound is not cached in +the server yet this call might result in the sample being uploaded +temporarily or permanently (this may be controlled with CA_PROP_CANBERRA_CACHE_CONTROL). This function will start playback +in the background. It will not wait until playback +completed. Depending on the backend used a sound that is started +shortly before your application terminates might or might not continue to +play after your application terminated. If you want to make sure +that all sounds finish to play you need to wait synchronously for +the callback function of ca_context_play_full() to be called before you +terminate your application. +

+

+The sample to play is identified by the CA_PROP_EVENT_ID +property. If it is already cached in the server the cached version +is played. The properties passed in this call are merged with the +properties supplied when the sample was cached (if applicable) +and the context properties as set with ca_context_change_props(). +

+

+If CA_PROP_EVENT_ID is not defined the sound file passed in the +CA_PROP_MEDIA_FILENAME is played. +

+

+On Linux/Unix the right sound to play is determined according to +CA_PROP_EVENT_ID, +CA_PROP_APPLICATION_LANGUAGE/CA_PROP_MEDIA_LANGUAGE, the system +locale, CA_PROP_CANBERRA_XDG_THEME_NAME and +CA_PROP_CANBERRA_XDG_THEME_OUTPUT_PROFILE, following the XDG Sound +Theming Specification. On non-Unix systems the native event sound +that matches the XDG sound name in CA_PROP_EVENT_ID is played. +

+
++++ + + + + + + + + + + + + + + + + + + +

c :

the context to play the event sound on

id :

an integer id this sound can later be identified with when calling ca_context_cancel() +

... :

additional properties for this sound event.

Returns :

0 on success, negative error code on error.
+
+
+
+

ca_context_play_full ()

+
int                 ca_context_play_full                (ca_context *c,
+                                                         uint32_t id,
+                                                         ca_proplist *p,
+                                                         ca_finish_callback_t cb,
+                                                         void *userdata);
+

+Play one event sound, and call the specified callback function when +completed. See ca_finish_callback_t for the semantics the callback +is called in. Also see ca_context_play(). +

+

+It is guaranteed that the callback is called exactly once if +ca_context_play_full() returns CA_SUCCESS. You thus may safely pass +allocated memory to the callback and assume that it is freed +properly. +

+
++++ + + + + + + + + + + + + + + + + + + + + + + +

c :

the context to play the event sound on

id :

an integer id this sound can be later be identified with when calling ca_context_cancel() or when the callback is called.

p :

A property list of properties for this event sound

cb :

A callback to call when this sound event sucessfully finished playing or when an error occured during playback.

Returns :

0 on success, negative error code on error.
+
+
+
+

ca_context_cancel ()

+
int                 ca_context_cancel                   (ca_context *c,
+                                                         uint32_t id);
+

+Cancel one or more event sounds that have been started via +ca_context_play(). If the sound was started with +ca_context_play_full() and a callback function was passed this +might cause this function to be called with CA_ERROR_CANCELED as +error code. +

+
++++ + + + + + + + + + + + + + + +

c :

the context to cancel the sounds on

id :

the id that identify the sounds to cancel.

Returns :

0 on success, negative error code on error.
+
+
+
+

ca_context_cache ()

+
int                 ca_context_cache                    (ca_context *c,
+                                                         ...);
+

+Upload the specified sample into the audio server and attach the +specified properties to it. This function will only return after +the sample upload was finished. +

+

+The sound to cache is found with the same algorithm that is used to +find the sounds for ca_context_play(). +

+

+If the backend doesn't support caching sound samples this function +will return CA_ERROR_NOTSUPPORTED. +

+
++++ + + + + + + + + + + + + + + +

c :

The context to use for uploading.

... :

The properties for this event sound. Terminated with NULL.

Returns :

0 on success, negative error code on error.
+
+
+
+

ca_context_cache_full ()

+
int                 ca_context_cache_full               (ca_context *c,
+                                                         ca_proplist *p);
+

+Upload the specified sample into the server and attach the +specified properties to it. Similar to ca_context_cache() but takes +a ca_proplist instead of a variable number of arguments. +

+

+If the backend doesn't support caching sound samples this function +will return CA_ERROR_NOTSUPPORTED. +

+
++++ + + + + + + + + + + + + + + +

c :

The context to use for uploading.

p :

The property list for this event sound.

Returns :

0 on success, negative error code on error.
+
+
+
+

ca_context_playing ()

+
int                 ca_context_playing                  (ca_context *c,
+                                                         uint32_t id,
+                                                         int *playing);
+

+Check if at least one sound with the specified id is still +playing. Returns 0 in *playing if no sound with this id is playing +anymore or non-zero if there is at least one playing. +

+
++++ + + + + + + + + + + + + + + + + + + +

c :

the context to check if sound is still playing

id :

the id that identify the sounds to check

playing :

a pointer to a boolean that will be updated with the play status

Returns :

0 on success, negative error code on error.
+

Since 0.16

+
+
+
+

ca_strerror ()

+
const char *        ca_strerror                         (int code);
+

+Converts a numerical error code as returned by most libcanberra API functions into a human readable error string. +

+
++++ + + + + + + + + + + +

code :

Numerical error code as returned by a libcanberra API function

Returns :

a human readable error string.
+
+
+
+

ca_proplist

+
typedef struct ca_proplist ca_proplist;
+
+

+A canberra property list object. Basically a hashtable. +

+
+
+
+

ca_proplist_create ()

+
int                 ca_proplist_create                  (ca_proplist **p);
+

+Allocate a new empty property list. +

+
++++ + + + + + + + + + + +

p :

A pointer where to fill in a pointer for the new property list.

Returns :

0 on success, negative error code on error.
+
+
+
+

ca_proplist_destroy ()

+
int                 ca_proplist_destroy                 (ca_proplist *p);
+

+Destroys a property list that was created with ca_proplist_create() earlier. +

+
++++ + + + + + + + + + + +

p :

The property list to destroy

Returns :

0 on success, negative error code on error.
+
+
+
+

ca_proplist_sets ()

+
int                 ca_proplist_sets                    (ca_proplist *p,
+                                                         const char *key,
+                                                         const char *value);
+

+Add a new string key/value pair to the property list. +

+
++++ + + + + + + + + + + + + + + + + + + +

p :

The property list to add this key/value pair to

key :

The key for this key/value pair

value :

The value for this key/value pair

Returns :

0 on success, negative error code on error.
+
+
+
+

ca_proplist_setf ()

+
int                 ca_proplist_setf                    (ca_proplist *p,
+                                                         const char *key,
+                                                         const char *format,
+                                                         ...);
+

+Much like ca_proplist_sets(): add a new string key/value pair to +the property list. Takes a standard C format string plus arguments +and formats a string of it. +

+
++++ + + + + + + + + + + + + + + + + + + + + + + +

p :

The property list to add this key/value pair to

key :

The key for this key/value pair

format :

The format string for the value for this key/value pair

... :

The parameters for the format string

Returns :

0 on success, negative error code on error.
+
+
+
+

ca_proplist_set ()

+
int                 ca_proplist_set                     (ca_proplist *p,
+                                                         const char *key,
+                                                         const void *data,
+                                                         size_t nbytes);
+

+Add a new binary key/value pair to the property list. +

+
++++ + + + + + + + + + + + + + + + + + + + + + + +

p :

The property list to add this key/value pair to

key :

The key for this key/value pair

data :

The binary value for this key value pair

nbytes :

The size of thebinary value for this key value pair.

Returns :

0 on success, negative error code on error.
+
+
+
+ + + \ No newline at end of file diff --git a/.flatpak-builder/cache/objects/f4/2e050ffeceb0d6a77cb2246228719c0e2cf779729115d8ae2a1e9d7ce99849.file b/.flatpak-builder/cache/objects/f4/2e050ffeceb0d6a77cb2246228719c0e2cf779729115d8ae2a1e9d7ce99849.file new file mode 100644 index 0000000..4c4b44a --- /dev/null +++ b/.flatpak-builder/cache/objects/f4/2e050ffeceb0d6a77cb2246228719c0e2cf779729115d8ae2a1e9d7ce99849.file @@ -0,0 +1,100 @@ +# utils.py +# +# Copyright 2021 James Westman +# +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation; either version 3 of the +# License, or (at your option) any later version. +# +# This file is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program. If not, see . +# +# SPDX-License-Identifier: LGPL-3.0-or-later + +import typing as T + + +class Colors: + RED = "\033[91m" + GREEN = "\033[92m" + YELLOW = "\033[33m" + PURPLE = "\033[35m" + FAINT = "\033[2m" + BOLD = "\033[1m" + BLUE = "\033[34m" + UNDERLINE = "\033[4m" + NO_UNDERLINE = "\033[24m" + CLEAR = "\033[0m" + + +def did_you_mean(word: str, options: T.List[str]) -> T.Optional[str]: + if len(options) == 0: + return None + + def levenshtein(a, b): + # see https://en.wikipedia.org/wiki/Levenshtein_distance + m = len(a) + n = len(b) + + distances = [[0 for j in range(n)] for i in range(m)] + + for i in range(m): + distances[i][0] = i + for j in range(n): + distances[0][j] = j + + for j in range(1, n): + for i in range(1, m): + cost = 0 + if a[i] != b[j]: + if a[i].casefold() == b[j].casefold(): + cost = 1 + else: + cost = 2 + distances[i][j] = min( + distances[i - 1][j] + 2, + distances[i][j - 1] + 2, + distances[i - 1][j - 1] + cost, + ) + + return distances[m - 1][n - 1] + + distances = [(option, levenshtein(word, option)) for option in options] + closest = min(distances, key=lambda item: item[1]) + if closest[1] <= 5: + return closest[0] + return None + + +def idx_to_pos(idx: int, text: str) -> T.Tuple[int, int]: + if idx == 0 or len(text) == 0: + return (0, 0) + line_num = text.count("\n", 0, idx) + 1 + col_num = idx - text.rfind("\n", 0, idx) - 1 + return (line_num - 1, col_num) + + +def pos_to_idx(line: int, col: int, text: str) -> int: + lines = text.splitlines(keepends=True) + return sum([len(line) for line in lines[:line]]) + col + + +def idxs_to_range(start: int, end: int, text: str): + start_l, start_c = idx_to_pos(start, text) + end_l, end_c = idx_to_pos(end, text) + return { + "start": { + "line": start_l, + "character": start_c, + }, + "end": { + "line": end_l, + "character": end_c, + }, + } diff --git a/.flatpak-builder/cache/objects/f4/46031d32b4e2c31521e1e9a61ec27493aab8e43a96078111fe5f491d7b476a.dirtree b/.flatpak-builder/cache/objects/f4/46031d32b4e2c31521e1e9a61ec27493aab8e43a96078111fe5f491d7b476a.dirtree new file mode 100644 index 0000000..b68443b Binary files /dev/null and b/.flatpak-builder/cache/objects/f4/46031d32b4e2c31521e1e9a61ec27493aab8e43a96078111fe5f491d7b476a.dirtree differ diff --git a/.flatpak-builder/cache/objects/f4/9a7d9c529dfa5c6a0114026da187cb2bb622a9a95d2b2159f8dcc5932eec15.file b/.flatpak-builder/cache/objects/f4/9a7d9c529dfa5c6a0114026da187cb2bb622a9a95d2b2159f8dcc5932eec15.file new file mode 100644 index 0000000..ac4dbf0 --- /dev/null +++ b/.flatpak-builder/cache/objects/f4/9a7d9c529dfa5c6a0114026da187cb2bb622a9a95d2b2159f8dcc5932eec15.file @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2008 - 2012 Vivien Malerba + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GDA_DATA_MODEL_DSN_LIST_H__ +#define __GDA_DATA_MODEL_DSN_LIST_H__ + +#include "gda-decl.h" +#include + +G_BEGIN_DECLS + +#define GDA_TYPE_DATA_MODEL_DSN_LIST (gda_data_model_dsn_list_get_type()) + +G_DECLARE_DERIVABLE_TYPE(GdaDataModelDsnList, gda_data_model_dsn_list, GDA, DATA_MODEL_DSN_LIST, GObject) +struct _GdaDataModelDsnListClass { + GObjectClass object_class; + + /* Padding for future expansion */ + void (*_gda_reserved1) (void); + void (*_gda_reserved2) (void); + void (*_gda_reserved3) (void); + void (*_gda_reserved4) (void); +}; + +G_END_DECLS + +#endif diff --git a/.flatpak-builder/cache/objects/f4/bee47379e1a3303ad5a1262300e2ad315f4ee7dfcefb8399f05df2e2fd275d.dirtree b/.flatpak-builder/cache/objects/f4/bee47379e1a3303ad5a1262300e2ad315f4ee7dfcefb8399f05df2e2fd275d.dirtree new file mode 100644 index 0000000..4b4a72d Binary files /dev/null and b/.flatpak-builder/cache/objects/f4/bee47379e1a3303ad5a1262300e2ad315f4ee7dfcefb8399f05df2e2fd275d.dirtree differ diff --git a/.flatpak-builder/cache/objects/f4/df599c68ccf57c5129d408708728d37c33b3f4c863d730d576fcf9f4ab0cad.file b/.flatpak-builder/cache/objects/f4/df599c68ccf57c5129d408708728d37c33b3f4c863d730d576fcf9f4ab0cad.file new file mode 100644 index 0000000..2d05b3d Binary files /dev/null and b/.flatpak-builder/cache/objects/f4/df599c68ccf57c5129d408708728d37c33b3f4c863d730d576fcf9f4ab0cad.file differ diff --git a/.flatpak-builder/cache/objects/f5/6c41aa66cf1a1d33142935c76cd67559c28c140e13b5214c386695f105b967.file b/.flatpak-builder/cache/objects/f5/6c41aa66cf1a1d33142935c76cd67559c28c140e13b5214c386695f105b967.file new file mode 100644 index 0000000..8aff4e9 Binary files /dev/null and b/.flatpak-builder/cache/objects/f5/6c41aa66cf1a1d33142935c76cd67559c28c140e13b5214c386695f105b967.file differ diff --git a/.flatpak-builder/cache/objects/f5/909a9d11900d4f6b1a1eb4cd9dfdcab802d25c17ac84deb0da31f5cc473b9c.dirtree b/.flatpak-builder/cache/objects/f5/909a9d11900d4f6b1a1eb4cd9dfdcab802d25c17ac84deb0da31f5cc473b9c.dirtree new file mode 100644 index 0000000..d8eb9c0 Binary files /dev/null and b/.flatpak-builder/cache/objects/f5/909a9d11900d4f6b1a1eb4cd9dfdcab802d25c17ac84deb0da31f5cc473b9c.dirtree differ diff --git a/.flatpak-builder/cache/objects/f5/a43a3f491892eea02f2819764b8a1a23a36f219c27198ac6acad01c093826d.dirtree b/.flatpak-builder/cache/objects/f5/a43a3f491892eea02f2819764b8a1a23a36f219c27198ac6acad01c093826d.dirtree new file mode 100644 index 0000000..e4b771e Binary files /dev/null and b/.flatpak-builder/cache/objects/f5/a43a3f491892eea02f2819764b8a1a23a36f219c27198ac6acad01c093826d.dirtree differ diff --git a/.flatpak-builder/cache/objects/f5/b66050db1193e76887aac0045cbd3d9d9f1208b35b3d6a49cf65800cd86052.dirtree b/.flatpak-builder/cache/objects/f5/b66050db1193e76887aac0045cbd3d9d9f1208b35b3d6a49cf65800cd86052.dirtree new file mode 100644 index 0000000..c3221c2 Binary files /dev/null and b/.flatpak-builder/cache/objects/f5/b66050db1193e76887aac0045cbd3d9d9f1208b35b3d6a49cf65800cd86052.dirtree differ diff --git a/.flatpak-builder/cache/objects/f5/da9f15d980a50c6a47a555032c0a881739e59536e4716538237f079a1d8f6f.dirtree b/.flatpak-builder/cache/objects/f5/da9f15d980a50c6a47a555032c0a881739e59536e4716538237f079a1d8f6f.dirtree new file mode 100644 index 0000000..d59cf40 Binary files /dev/null and b/.flatpak-builder/cache/objects/f5/da9f15d980a50c6a47a555032c0a881739e59536e4716538237f079a1d8f6f.dirtree differ diff --git a/.flatpak-builder/cache/objects/f6/73b93be57effcbac0f41285408371d1648b3a2851deb91aaede2ff8d3a8964.dirtree b/.flatpak-builder/cache/objects/f6/73b93be57effcbac0f41285408371d1648b3a2851deb91aaede2ff8d3a8964.dirtree new file mode 100644 index 0000000..a37470f Binary files /dev/null and b/.flatpak-builder/cache/objects/f6/73b93be57effcbac0f41285408371d1648b3a2851deb91aaede2ff8d3a8964.dirtree differ diff --git a/.flatpak-builder/cache/objects/f6/7e75e51085250fc77ce84180d040a4d424216e0bbf226c87e37c2f3a9b6bf4.file b/.flatpak-builder/cache/objects/f6/7e75e51085250fc77ce84180d040a4d424216e0bbf226c87e37c2f3a9b6bf4.file new file mode 100644 index 0000000..e230663 --- /dev/null +++ b/.flatpak-builder/cache/objects/f6/7e75e51085250fc77ce84180d040a4d424216e0bbf226c87e37c2f3a9b6bf4.file @@ -0,0 +1,50229 @@ + + + + + + + + + + + + + + + The corresponding attribute specifies if the object it refers to is auto incremented (value has a G_TYPE_BOOLEAN type). + + + + + The corresponding attribute is the description of the object it refers to (value has a G_TYPE_STRING type). + + + + + The corresponding attribute specifies if the object it refers to has its value to default (value has a G_TYPE_BOOLEAN type). + + + + + The corresponding attribute is the name of the object it refers to (value has a G_TYPE_STRING type). + + + + + The corresponding attribute is the number of significant digits of the object it refers to (value has a G_TYPE_INT type). + + + + + The corresponding attribute is the number of significant digits to the right of the decimal point of the object it refers to (value has a G_TYPE_INT type). + + + + + This attribute, if %TRUE specifies that a tree node may or may not have any children nodes (value has a G_TYPE_BOOLEAN type). + + + + + + + + + + + + + + + + + + + + + Creates a new #GdaBatch object + + + the new object + + + + + + + + + + + + + + + + + + + + + + + + Add @stmt to the list of statements managed by @batch. A #GdaStatement object can be +added multiple times to a #GdaBatch object. The @batch increases reference count for @stmt and +the @stmt instance can be freed using g_object_unref(). + + + + + + + a #GdaBatch object + + + + a statement to add to @batch's statements list + + + + + + Copy constructor + + + a the new copy of @orig + + + + + a #GdaBatch to make a copy of + + + + + + Get a new #GdaSet object which groups all the execution parameters +which @batch needs for all the statements it includes. +This new object is returned though @out_params. + +Note that if @batch does not need any parameter, then @out_params is set to %NULL. + + + TRUE if no error occurred. + + + + + a #GdaBatch object + + + + a place to store a new #GdaSet object, or %NULL + + + + + + Get a list of the #GdaStatement objects contained in @batch + + + a list of #GdaStatement which should not be modified. + + + + + + + a #GdaBatch object + + + + + + Removes @stmt from the list of statements managed by @batch. If @stmt is present several +times in @batch's statements' list, then only the first one is removed. + + + + + + + a #GdaBatch object + + + + a statement to remove from @batch's statements list + + + + + + Creates a string representing the contents of @batch. + + + a string containing the serialized version of @batch + + + + + a #GdaBatch object + + + + + + + + + Gets emitted whenever a #GdaStatement in the @batch object changes + + + + + + the statement which has been changed + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Creates a new #GdaBinary coping data. + + + the newly created #GdaBinary. + + + + + Creates a new #GdaBinary structure from an existing one. + + + a newly allocated #GdaBinary which contains a copy of information in @boxed. + + + + + source to get a copy from. + + + + + + Deallocates all memory associated to the given #GdaBinary. + + + + + + + #GdaBinary to free. + + + + + + + + associated data to #GdaBinary. + + + + + a #GdaBinary pointer + + + + + + + + size of associated data to #GdaBinary or -1 in case of error. + + + + + + + + + + Frees data referenced by #GdaBinary + + + + + + + a #GdaBinary pointer + + + + + + Set binary data to a #GdaBinary, holding a copy of the data. + + + + + + + a #GdaBinary pointer + + + + value to be copied by #GdaBinary. + + + + + + the size of the memory pool pointer to by @val. + + + + + + Set binary data to a #GdaBinary, directly holding @val (no copy made). + + + + + + + + + + value to be taken by #GdaBinary. + + + + + + the size of the memory pool pointer to by @val. + + + + + + Converts all the non printable characters of bin->data into the "\xyz" representation +where "xyz" is the octal representation of the byte, and the '\' (backslash) character +is converted to "\\". Printable characters (defined by g_ascii_isprint()) as well as newline +character are not converted. + +Note that the backslash and newline characters are considered as printable characters and +will not be represented by the "\xyz" representation. + +Use this function to get a representation as much readable by humans as possible of a binary +chunk. Note that this function is internally called when transforming a binary value to +a string for example when using g_value_transform() or gda_value_stringify(). + + + a new string from @bin + + + + + a correctly filled @GdaBinary structure + + + + a maximum len used to truncate, or %0 for no maximum length + + + + + + + Represents some binary data, accessed through a #GdaBlobOp object. +@op is generally set up by database providers when giving access to an existing BLOB in +a database, but can be modified if needed using gda_blob_set_op(). + + + Creates a new #GdaBlob. + + + a newly allocated #GdaBlob. + + + + + Creates a new #GdaBlob structure from an existing one. + + + a newly allocated #GdaBlob which contains a copy of information in @boxed. + + + + + source to get a copy from. + + + + + + Deallocates all memory associated to the given #GdaBlob. + + + + + + + #GdaBlob to free. + + + + + + + + associated #GdaBinary. + + + + + a #GdaBlob pointer + + + + + + + + associated #GdaBlobOp. + + + + + a #GdaBlob pointer + + + + + + Correctly assigns @op to @blob (increases @op's reference count) + + + + + + + a #GdaBlob value + + + + a #GdaBlobOp object, or %NULL + + + + + + Converts all the non printable characters of blob->data into the \xxx representation +where xxx is the octal representation of the byte, and the '\' (backslash) character +is converted to "\\". + + + a new string from @blob + + + + + a correctly filled @GdaBlob structure + + + + a maximum len used to truncate, or 0 for no maximum length + + + + + + + + + + + the length of the blob in bytes. In case of error, -1 is returned and the +provider should have added an error (a #GdaConnectionEvent) to the connection. + + + + + an existing #GdaBlobOp + + + + + + Reads a chunk of bytes from the BLOB accessible through @op into @blob. + + + the number of bytes actually read. In case of error, -1 is returned and the +provider should have added an error to the connection. + + + + + a #GdaBlobOp + + + + a #GdaBlob to read data to + + + + offset to read from the start of the blob (starts at 0) + + + + maximum number of bytes to read. + + + + + + Reads the whole contents of the blob manipulated by @op into @blob + + + TRUE if @blob->data contains the whole BLOB manipulated by @op + + + + + a #GdaBlobOp + + + + a #GdaBlob to read data to + + + + + + Writes a chunk of bytes from a @blob to the BLOB accessible through @op, @blob is unchanged after +this call. + +If @blob has an associated #GdaBlobOp (ie. if @blob->op is not %NULL) then the data to be written +using @op is the data fetched using @blob->op. + + + the number of bytes written. In case of error, -1 is returned and the +provider should have added an error to the connection. + + + + + a #GdaBlobOp + + + + a #GdaBlob which contains the data to write + + + + offset to write from the start of the blob (starts at 0) + + + + + + Writes the whole contents of @blob into the blob manipulated by @op. If necessary the resulting +blob is truncated from its previous length. + + + TRUE on success + + + + + a #GdaBlobOp + + + + a #GdaBlob which contains the data to write + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a newly allocated #GdaColumn object. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Creates a new #GdaColumn object from an existing one. + + + a newly allocated #GdaColumn with a copy of the data +in @column. + + + + + column to get a copy from. + + + + + + Gets the 'allow null' flag of the given column. + + + whether the given column allows null values or not (%TRUE or %FALSE). + + + + + a #GdaColumn. + + + + + + + + whether the given column is an auto incremented one (%TRUE or %FALSE). + + + + + a #GdaColumn. + + + + + + + + the database type of @column. + + + + + a #GdaColumn. + + + + + + + + @column's default value, as a #GValue object, or %NULL if column does not have a default value + + + + + a #GdaColumn. + + + + + + + + the column's description, in any + + + + + a #GdaColumn. + + + + + + + + the type of @column. + + + + + a #GdaColumn. + + + + + + + + the name of @column. + + + + + a #GdaColumn. + + + + + + + + the position of the column refer to in the +containing data model. + + + + + a #GdaColumn. + + + + + + Sets the 'allow null' flag of the given column. + + + + + + + a #GdaColumn. + + + + whether the given column should allows null values or not. + + + + + + Sets the auto increment flag for the given column. + + + + + + + a #GdaColumn. + + + + auto increment status. + + + + + + Defines @column's database type + + + + + + + a #GdaColumn + + + + a string + + + + + + Sets @column's default #GValue. + + + + + + + a #GdaColumn. + + + + default #GValue for the column + + + + + + Sets the column's description + + + + + + + a #GdaColumn. + + + + description. + + + + + + Sets the type of @column to @type. + + + + + + + a #GdaColumn. + + + + the new type of @column. + + + + + + Sets the name of @column to @name. + + + + + + + a #GdaColumn. + + + + the new name of @column. + + + + + + Sets the position of the column refer to in the containing +data model. + + + + + + + a #GdaColumn. + + + + the wanted position of the column in the containing data model. + + + + + + + + + + + + + + + + + + Gets emitted whenever @column's type has been changed + + + + + + the column's previous type + + + + the column's new type + + + + + + Gets emitted whenever @column's name has been changed + + + + + + the column's previous name + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Tells if the global (system) configuration can be modified (considering +system permissions and settings) + + + TRUE if system-wide configuration can be modified + + + + + Add or update a DSN from the definition in @info. + +This method may fail with a %GDA_CONFIG_ERROR domain error (see the #GdaConfigError error codes). + + + TRUE if no error occurred + + + + + a pointer to a filled GdaDsnInfo structure + + + + + + Tells if the data source identified as @dsn_name needs any authentication. If a &lt;username&gt; +and optionally a &lt;password&gt; are specified, they are ignored. + + + TRUE if an authentication is needed + + + + + the name of a DSN, in the "[&lt;username&gt;[:&lt;password&gt;]@]&lt;DSN&gt;" format + + + + + + + + + + + Get a pointer to the global (unique) #GdaConfig object. This functions increments +the reference count of the object, so you need to call g_object_unref() on it once finished. + + + a non %NULL pointer to the unique #GdaConfig + + + + + Get information about the DSN named @dsn_name. + +@dsn_name's format is "[&lt;username&gt;[:&lt;password&gt;]@]&lt;DSN&gt;" (if &lt;username&gt; +and optionally &lt;password&gt; are provided, they are ignored). Also see the gda_dsn_split() utility +function. + + + a pointer to read-only #GdaDsnInfo structure, or %NULL if not found + + + + + the name of the DSN to look for + + + + + + Get a pointer to a read-only #GdaDsnInfo at the @index position + + + the pointer or %NULL if no DSN exists at position @index + + + + + an index + + + + + + Get the index (starting at 0) of the DSN named @dsn_name + + + the index or -1 if not found + + + + + a DSN + + + + + + Get the number of defined DSN + + + the number of defined DSN + + + + + Get a pointer to the session-wide #GdaServerProvider for the +provider named @provider_name. The caller must not call g_object_unref() on the +returned object. + +This method may fail with a %GDA_CONFIG_ERROR domain error (see the #GdaConfigError error codes). + + + a pointer to the #GdaServerProvider, or %NULL if an error occurred + + + + + a database provider + + + + + + Get some information about the a database provider (adapter) named + + + a pointer to read-only #GdaProviderInfo structure, or %NULL if not found + + + + + a database provider + + + + + + Get a #GdaDataModel representing all the configured DSN, and keeping itself up to date with +the changes in the declared DSN. + +The returned data model is composed of the following columns: +<itemizedlist> + <listitem><para>DSN name</para></listitem> + <listitem><para>Provider name</para></listitem> + <listitem><para>Description</para></listitem> + <listitem><para>Connection string</para></listitem> + <listitem><para>Username if it exists</para></listitem> +</itemizedlist> + + + a new #GdaDataModel + + + + + Get a #GdaDataModel representing all the installed database providers. + +The returned data model is composed of the following columns: +<itemizedlist> + <listitem><para>Provider name</para></listitem> + <listitem><para>Description</para></listitem> + <listitem><para>DSN parameters</para></listitem> + <listitem><para>Authentication parameters</para></listitem> + <listitem><para>File name of the plugin</para></listitem> +</itemizedlist> + + + a new #GdaDataModel + + + + + Remove the DSN named @dsn_name. + +This method may fail with a %GDA_CONFIG_ERROR domain error (see the #GdaConfigError error codes). + + + TRUE if no error occurred + + + + + the name of the DSN to remove + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + File to use for system-wide DSN list. When changed, the whole list of DSN will be reloaded. + + + + File to use for per-user DSN list. When changed, the whole list of DSN will be reloaded. + + + + + + + Gets emitted whenever a new DSN has been defined + + + + + + a #GdaDsnInfo + + + + + + Gets emitted whenever a DSN's definition has been changed + + + + + + a #GdaDsnInfo + + + + + + Gets emitted whenever a DSN has been removed + + + + + + a #GdaDsnInfo + + + + + + Gets emitted whenever a DSN is about to be removed + + + + + + a #GdaDsnInfo + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + This function creates a new connection, using a pre-defined data source (DSN), see +gda_config_define_dsn() for more information about how to define a DSN. If you don't want to +define a DSN, it is possible to use gda_connection_new_from_string() instead of this method. + +The @auth_string can contain the authentication information for the server +to accept the connection. It is a string containing semi-colon seperated named value, usually +like "USERNAME=...;PASSWORD=..." where the ... are replaced by actual values. Note that each +name and value must be encoded as per RFC 1738, see gda_rfc1738_encode() for more information. + +If @auth_string is given, it wil be used, otherwise auth_string of #GdaDsnInfo will be used. + +The actual named parameters required depend on the provider being used, and that list is available +as the <parameter>auth_params</parameter> member of the #GdaProviderInfo structure for each installed +provider (use gda_config_get_provider_info() to get it). Also one can use the "gda-sql-6.0 -L" command +to list the possible named parameters. + +This method may fail with a GDA_CONNECTION_ERROR domain error (see the #GdaConnectionError error codes) +or a %GDA_CONFIG_ERROR domain error (see the #GdaConfigError error codes). + +The returned connection is not yet opened, you need to call gda_connection_open() or gda_connection_open_async(). + + + a new #GdaConnection or %NULL if there was an error. + + + + + data source name. + + + + authentication string, or %NULL + + + + options for the connection (see #GdaConnectionOptions). + + + + + + This function creates a new function, using a pre-defined data source (DSN) name, +see gda_config_define_dsn() for more information about how to define a DSN. If you don't want to define +a DSN, it is possible to use gda_connection_new_from_string() instead of this method. + +The @dsn string must have the following format: "[&lt;username&gt;[:&lt;password&gt;]@]&lt;DSN&gt;" +(if &lt;username&gt; and/or &lt;password&gt; are provided, and @auth_string is %NULL, then these username +and passwords will be used). Note that if provided, &lt;username&gt; and &lt;password&gt; +must be encoded as per RFC 1738, see gda_rfc1738_encode() for more information. + +The @auth_string can contain the authentication information for the server +to accept the connection. It is a string containing semi-colon separated named value, usually +like "USERNAME=...;PASSWORD=..." where the ... are replaced by actual values. Note that each +name and value must be encoded as per RFC 1738, see gda_rfc1738_encode() for more information. + +The actual named parameters required depend on the provider being used, and that list is available +as the <parameter>auth_params</parameter> member of the #GdaProviderInfo structure for each installed +provider (use gda_config_get_provider_info() to get it). Also one can use the "gda-sql-6.0 -L" command +to list the possible named parameters. + +This method may fail with a GDA_CONNECTION_ERROR domain error (see the #GdaConnectionError error codes) +or a %GDA_CONFIG_ERROR domain error (see the #GdaConfigError error codes). + +The returned connection is not yet opened, you need to call gda_connection_open() or gda_connection_open_async(). + + + a new #GdaConnection or %NULL if there was an error. + + + + + data source name. + + + + authentication string, or %NULL + + + + options for the connection (see #GdaConnectionOptions). + + + + + + Opens a connection given a provider ID and a connection string. This +allows applications to open connections without having to create +a data source (DSN) in the configuration. The format of @cnc_string is +similar to PostgreSQL and MySQL connection strings. It is a semicolumn-separated +series of &lt;key&gt;=&lt;value&gt; pairs, where each key and value are encoded as per RFC 1738, +see gda_rfc1738_encode() for more information. + +The possible keys depend on the provider, the "gda-sql-6.0 -L" command +can be used to list the actual keys for each installed database provider. + +For example the connection string to open an SQLite connection to a database +file named "my_data.db" in the current directory would be <constant>"DB_DIR=.;DB_NAME=my_data"</constant>. + +The @cnc_string string must have the following format: +"[&lt;provider&gt;://][&lt;username&gt;[:&lt;password&gt;]@]&lt;connection_params&gt;" +(if &lt;username&gt; and/or &lt;password&gt; are provided, and @auth_string is %NULL, then these username +and passwords will be used, and if &lt;provider&gt; is provided and @provider_name is %NULL then this +provider will be used). Note that if provided, &lt;username&gt;, &lt;password&gt; and &lt;provider&gt; +must be encoded as per RFC 1738, see gda_rfc1738_encode() for more information. + +The @auth_string must contain the authentication information for the server +to accept the connection. It is a string containing semi-colon seperated named values, usually +like "USERNAME=...;PASSWORD=..." where the ... are replaced by actual values. Note that each +name and value must be encoded as per RFC 1738, see gda_rfc1738_encode() for more information. + +The actual named parameters required depend on the provider being used, and that list is available +as the <parameter>auth_params</parameter> member of the #GdaProviderInfo structure for each installed +provider (use gda_config_get_provider_info() to get it). Similarly to the format of the connection +string, use the "gda-sql-6.0 -L" command to list the possible named parameters. + +Additionally, it is possible to have the connection string +respect the "&lt;provider_name&gt;://&lt;real cnc string&gt;" format, in which case the provider name +and the real connection string will be extracted from that string (note that if @provider_name +is not %NULL then it will still be used as the provider ID).\ + +This method may fail with a GDA_CONNECTION_ERROR domain error (see the #GdaConnectionError error codes) +or a %GDA_CONFIG_ERROR domain error (see the #GdaConfigError error codes). + +The returned connection is not yet opened, you need to call gda_connection_open() or gda_connection_open_async(). + + + a new #GdaConnection or %NULL if there was an error. + + + + + provider ID to connect to, or %NULL + + + + connection string. + + + + authentication string, or %NULL + + + + options for the connection (see #GdaConnectionOptions). + + + + + + + + + + + Retreive a pointer to the #GdaWorker used internally by the connection. This function is reserved to +database provider's implementation and should not be used otherwise. + + + the #GdaWorker, or %NULL + + + + + a #GdaServerProviderConnectionData, or %NULL + + + + + + This function creates a connection and opens it, using a DSN. If opening fails, then no connection is created. +See gda_connection_new_from_dsn() for more information. + + + a new #GdaConnection if connection opening was successful or %NULL if there was an error. + + + + + data sourcename. + + + + authentication string, or %NULL + + + + options for the connection (see #GdaConnectionOptions). + + + + + + This function creates a connection and opens it, using a DSN name. If opening fails, then no connection is created. The named DSN should be available. +See gda_connection_new_from_dsn_name() for more information. + + + a new #GdaConnection if connection opening was successful or %NULL if there was an error. + + + + + data source name. + + + + authentication string, or %NULL + + + + options for the connection (see #GdaConnectionOptions). + + + + + + This function creates a connection and opens it, using a connection string. If opening fails, then no connection is created. +See gda_connection_new_from_string() for more information. + + + a new #GdaConnection if connection opening was successful or %NULL if there was an error. + + + + + provider ID to connect to, or %NULL + + + + connection string. + + + + authentication string, or %NULL + + + + options for the connection (see #GdaConnectionOptions). + + + + + + Opens an SQLite connection even if the SQLite provider is not installed, +to be used by database providers which need a temporary database to store +some information. + + + a new #GdaConnection, or %NULL if an error occurred + + + + + the directory the database file will be in, or %NULL for the default TMP directory + + + + the database file name + + + + if %TRUE, then the database file will be removed afterwards + + + + + + Extract the provider, connection parameters, username and password from @string. +in @string, the various parts are strings +which are expected to be encoded using an RFC 1738 compliant encoding. If they are specified, +the returned provider, username and password strings are correctly decoded. + +For example all the following connection strings: +<programlisting><![CDATA[ +PostgreSQL://meme:pass@DB_NAME=mydb;HOST=server +PostgreSQL://meme@DB_NAME=mydb;HOST=server;PASSWORD=pass +PostgreSQL://meme@DB_NAME=mydb;PASSWORD=pass;HOST=server +PostgreSQL://meme@PASSWORD=pass;DB_NAME=mydb;HOST=server +PostgreSQL://DB_NAME=mydb;HOST=server;USERNAME=meme;PASSWORD=pass +PostgreSQL://DB_NAME=mydb;HOST=server;PASSWORD=pass;USERNAME=meme +PostgreSQL://DB_NAME=mydb;USERNAME=meme;PASSWORD=pass;HOST=server +PostgreSQL://PASSWORD=pass;USERNAME=meme;DB_NAME=mydb;HOST=server +PostgreSQL://:pass@USERNAME=meme;DB_NAME=mydb;HOST=server +PostgreSQL://:pass@DB_NAME=mydb;HOST=server;USERNAME=meme]]></programlisting> + +will return the following new strings (double quotes added here to delimit strings): +<programlisting><![CDATA[ +out_cnc_params: "DB_NAME=mydb;HOST=server" +out_provider: "PostgreSQL" +out_username: "meme" +out_password: "pass"]]></programlisting> + + + + + + + a string in the "[&lt;provider&gt;://][&lt;username&gt;[:&lt;password&gt;]@]&lt;connection_params&gt;" form + + + + a place to store the new string containing the &lt;connection_params&gt; part + + + + a place to store the new string containing the &lt;provider&gt; part + + + + a place to store the new string containing the &lt;username&gt; part + + + + (nullable): a place to store the new string containing the &lt;password&gt; part, or %NULL + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Adds an event to the given connection. This function is usually +called by providers, to inform clients of events that happened +during some operation. + +As soon as a provider (or a client, it does not matter) calls this +function with an @event object which is an error, +the connection object emits the "error" signal, to which clients can connect to be +informed of events. + +WARNING: the reference to the @event object is stolen by this function! + + + + + + + a #GdaConnection object. + + + + is stored internally, so you don't need to unref it. + + + + + + Adds a new error to the given connection object. This is just a convenience +function that simply creates a #GdaConnectionEvent and then calls +#gda_server_connection_add_error. + + + a new #GdaConnectionEvent object, however the caller does not hold a reference to the returned object, and if need be the caller must call g_object_ref() on it. + + + + + a #GdaConnection object. + + + + a format string (see the printf(3) documentation). + + + + the arguments to insert in the error message. + + + + + + Declares that @prepared_stmt is a prepared statement object associated to @gda_stmt within the connection +(meaning the connection increments the reference counter of @prepared_stmt). + +If @gda_stmt changes or is destroyed, the the association will be lost and the connection will lose the +reference it has on @prepared_stmt. + + + + + + + a #GdaConnection object + + + + a #GdaStatement object + + + + a prepared statement object (as a #GdaPStmt object, or more likely a descendant) + + + + + + Adds a SAVEPOINT named @name. + + + TRUE if no error occurred + + + + + a #GdaConnection object + + + + name of the savepoint to add + + + + + + Executes all the statements contained in @batch (in the order in which they were added to @batch), and +returns a list of #GObject objects, at most one #GObject for each statement; see gda_connection_statement_execute() +for details about the returned objects. + +If one of the statement fails, then none of the subsequent statement will be executed, and the method returns +the list of #GObject created by the correct execution of the previous statements. If a transaction is required, +then it should be started before calling this method. + + + a new list of #GObject objects + + + + + + + a #GdaConnection object + + + + a #GdaBatch object which contains all the statements to execute + + + + a #GdaSet object (which can be obtained using gda_batch_get_parameters()), or %NULL + + + + specifies how the returned data model(s) will be used, as a #GdaStatementModelUsage enum + + + + + + Starts a transaction on the data source, identified by the @name parameter. + +Before starting a transaction, you can check whether the underlying +provider does support transactions or not by using the gda_connection_supports_feature() function. + + + %TRUE if the transaction was started successfully with the corresponding isolation level, %FALSE otherwise. + + + + + a #GdaConnection object. + + + + the name of the transation to start, or %NULL + + + + the requested transaction level (use %GDA_TRANSACTION_ISOLATION_SERVER_DEFAULT to apply the server default) + + + + + + This function lets you clear the list of #GdaConnectionEvent's of the +given connection. + + + + + + + a #GdaConnection object. + + + + + + Closes the connection to the underlying data source. + + + + + + + a #GdaConnection object. + + + + + + Commits the given transaction to the backend database. You need to call +gda_connection_begin_transaction() first. + + + %TRUE if the transaction was finished successfully, +%FALSE otherwise. + + + + + a #GdaConnection object. + + + + the name of the transation to commit, or %NULL + + + + + + A convenient method to create a new #GdaDbCatalog instance and set the current @cnc as a +property. If for some reason, this approach doesn't fit well, the same task can be achieved +by the following code: + +GdaDbCatalog *catalog = gda_db_catalog_new (); +g_object_set (catalog, "connection", cnc, NULL); + + + A new instance of #GdaDbCatalog. The new object should be deallocated +using g_object_unref(). + + + + + A #GdaConnection object to use + + + + + + Creates a new #GdaServerOperation object which can be modified in order +to perform the type type of action. It is a wrapper around the gda_server_provider_create_operation() +method. + + + a new #GdaServerOperation object, or %NULL in the connection's provider does not support the @type type +of operation or if an error occurred + + + + + a #GdaConnection object + + + + the type of operation requested + + + + an optional list of parameters + + + + + + Creates a new parser object able to parse the SQL dialect understood by @cnc. +If the #GdaServerProvider object internally used by @cnc does not have its own parser, +then %NULL is returned, and a general SQL parser can be obtained +using gda_sql_parser_new(). + + + a new #GdaSqlParser object, or %NULL + + + + + a #GdaConnection object + + + + + + Removes any prepared statement associated to @gda_stmt in @cnc: this undoes what +gda_connection_add_prepared_statement() does. + + + + + + + a #GdaConnection object + + + + a #GdaStatement object + + + + + + This is a convenience function, which creates a DELETE statement and executes it using the values +provided. It internally relies on variables which makes it immune to SQL injection problems. + +The equivalent SQL command is: DELETE FROM &lt;table&gt; WHERE &lt;condition_column_name&gt; = &lt;condition_value&gt;. + +A simple example to remove a row in database. + +|[<!-- language="C" --> + +GdaConnection *cnc; +//Open connection here + +GError *error = NULL; + +GValue *v_id = gda_value_new (G_TYPE_INT); +GValue *v_name = gda_value_new_from_string ("Aldibino Refinino", G_TYPE_STRING); + +//The number 10 represents a primary key record in the table +g_value_set_int (v_id, 10); + +//Delete a record with a specific ID in the col_id column +if (!gda_connection_delete_row_from_table (cnc, "TABLE_CONTACTS", + "col_id", v_id, + &error)) +{ + g_error ("Could not delete row in table: %s\n", + error && error->message ? error->message : "No detail"); +} + +//Delete a record with a specific NAME in the col_name column +if (!gda_connection_delete_row_from_table (cnc, "TABLE_CONTACTS", + "col_name", v_name, + &error)) +{ + g_error ("Could not delete row in table: %s\n", + error && error->message ? error->message : "No detail"); +} + +gda_value_free (v_id); +gda_value_free (v_name); + +g_error_free (error); + +]| + + + TRUE if no error occurred, FALSE otherwise + + + + + an opened connection + + + + the table's name with the row's values to be updated + + + + the name of the column to used in the WHERE condition clause + + + + the @condition_column_type's GType + + + + + + Delete the SAVEPOINT named @name when not used anymore. + + + TRUE if no error occurred + + + + + a #GdaConnection object + + + + name of the savepoint to delete + + + + + + This is a convenience function to execute a SQL command over the opened connection. For the +returned value, see gda_connection_statement_execute_non_select()'s documentation. + + + the number of rows affected or -1, or -2 + + + + + an opened connection + + + + a query statement that must not begin with "SELECT" + + + + + + Execute a SQL SELECT command over an opened connection. + + + a new #GdaDataModel if successful, %NULL otherwise + + + + + an opened connection + + + + a query statement that must begin with "SELECT" + + + + + + Gets the user name used to open this connection. + + + the user name. + + + + + a #GdaConnection object. + + + + + + Gets the connection string used to open this connection. + +The connection string is the string sent over to the underlying +database provider, which describes the parameters to be used +to open a connection on the underlying data source. + + + the connection string used when opening the connection. + + + + + a #GdaConnection object. + + + + + + This function allows you to determine the actual format for the date values. + + + %TRUE if no error occurred + + + + + a #GdaConnection object + + + + the place to store the first part of the date, or %NULL + + + + the place to store the second part of the date, or %NULL + + + + the place to store the third part of the date, or %NULL + + + + the place to store the separator (used between year, month and day parts) part of the date, or %NULL + + + + + + + + the data source name the connection object is connected +to. + + + + + a #GdaConnection object + + + + + + Retrieves a list of the last errors occurred during the connection. The returned list is +chronologically ordered such as that the most recent event is the #GdaConnectionEvent of the first node. + +Warning: the @cnc object may change the list if connection events occur + + + a #GList of #GdaConnectionEvent objects (the list should not be modified) + + + + + + + a #GdaConnection. + + + + + + Get the #GMainContext used while a potentially blocking operation is performed using @nc, see +gda_connection_set_main_context(). If @cnc is %NULL, then the setting applies to all the connections for which +no other similar setting has been set. + +If no main context has been defined, then some function calls (for example connection opening) may block until the +operation has finished. + + + a #GMainContext, or %NULL + + + + + a #GdaConnection, or %NULL + + + + the #GThread in which @context will be used, or %NULL (for the current thread) + + + + + + Get or initializes the #GdaMetaStore associated to @cnc + + + a #GdaMetaStore object + + + + + a #GdaConnection object + + + + + + Retrieves data stored in @cnc's associated #GdaMetaStore object. This method is useful +to easily get some information about the meta-data associated to @cnc, such as the list of +tables, views, and other database objects. + +Note: it's up to the caller to make sure the information contained within @cnc's associated #GdaMetaStore +is up to date using gda_connection_update_meta_store() (it can become outdated if the database's schema +is modified). + +For more information about the returned data model's attributes, or about the @meta_type and ... filter arguments, +see <link linkend="GdaConnectionMetaTypeHead">this description</link>. + +Also, when using filters involving data which are SQL identifiers, make sure each SQL identifier +is represented using the #GdaMetaStore convention, using gda_meta_store_sql_identifier_quote() or +gda_meta_store_sql_identifier_quote(). + +See the <link linkend="information_schema:sql_identifiers"> +meta data section about SQL identifiers</link> for more information, and the documentation about the +gda_sql_identifier_quote() function which will be most useful. + + + a #GdaDataModel containing the data required. The caller is responsible +for freeing the returned model using g_object_unref(). + + + + + a #GdaConnection object. + + + + describes which data to get. + + + + a place to store errors, or %NULL + + + + the number of filters in the @... argument + + + + a list of (filter name (gchar *), filter value (GValue*)) pairs specifying +the filter to apply to the returned data model's contents (there must be @nb_filters pairs) + + + + + + see #gda_connection_get_meta_store_data + + + a #GdaDataModel containing the data required. The caller is responsible +for freeing the returned model using g_object_unref(). + + + + + a #GdaConnection object. + + + + describes which data to get. + + + + a #GList of #GdaHolder objects + + + + + + + + Gets the #GdaConnectionOptions used to open this connection. + + + the connection options. + + + + + a #GdaConnection object. + + + + + + Retrieves a pointer to an object representing a prepared statement for @gda_stmt within @cnc. The +association must have been done using gda_connection_add_prepared_statement(). + + + the prepared statement, or %NULL if no association exists + + + + + a #GdaConnection object + + + + a #GdaStatement object + + + + + + Gets a pointer to the #GdaServerProvider object used to access the database + + + the #GdaServerProvider (NEVER NULL) + + + + + a #GdaConnection object + + + + + + Gets the name (identifier) of the database provider used by @cnc + + + a non modifiable string + + + + + a #GdaConnection object + + + + + + Get the current status of @cnc. Note that this function needs to lock the connection (see #GdaLockable) +to obtain the result. + + + the connection's status + + + + + a #GdaConnection + + + + + + Get the status of @cnc regarding transactions. The returned object should not be modified +or destroyed; however it may be modified or destroyed by the connection itself. + +If %NULL is returned, then no transaction has been associated with @cnc + + + a #GdaTransactionStatus object, or %NULL + + + + + a #GdaConnection object + + + + + + This is a convenience function, which creates an INSERT statement and executes it using the values +provided. It internally relies on variables which makes it immune to SQL injection problems. + +The equivalent SQL command is: INSERT INTO &lt;table&gt; (&lt;column_name&gt; [,...]) VALUES (&lt;column_name&gt; = &lt;new_value&gt; [,...]). + +A simple example to add a row in database + +|[<!-- language="C" --> + +GdaConnection *cnc; +// Open connection here + +GError *error = NULL; + +GValue *v_first_name = gda_value_new_from_string (first_name, G_TYPE_STRING); +GValue *v_last_name = gda_value_new_from_string (last_name, G_TYPE_STRING); +GValue *v_email = gda_value_new_from_string (email, G_TYPE_STRING); +GValue *v_cod = gda_value_new (G_TYPE_INT); + +g_value_set_int (v_cod, cod); + +if (!gda_connection_insert_row_into_table (cnc, "TABLE_CONTACTS", &error, + "col_first_name", v_first_name, + "col_last_name", v_last_name, + "col_email", v_email, + "col_cod", v_cod, NULL)) +{ + g_error ("It was not possible to add a new row in the table: %s\n", + error && error->message ? error->message : "No detail"); +} + +gda_value_free (v_first_name); +gda_value_free (v_last_name); +gda_value_free (v_email); +gda_value_free (v_cod); + +g_error_free (error); + + +]| + + + TRUE if no error occurred + + + + + an opened connection + + + + table's name to insert into + + + + a place to store errors, or %NULL + + + + a list of string/GValue pairs with the name of the column to use and the +GValue pointer containing the value to insert for the column (value can be %NULL), finished by a %NULL. There must be +at least one column name and value + + + + + + @col_names and @values must have length (&gt;= 1). + +This is a convenience function, which creates an INSERT statement and executes it using the values +provided. It internally relies on variables which makes it immune to SQL injection problems. + +The equivalent SQL command is: INSERT INTO &lt;table&gt; (&lt;column_name&gt; [,...]) VALUES (&lt;column_name&gt; = &lt;new_value&gt; [,...]). + + + TRUE if no error occurred, FALSE otherwise + + + + + an opened connection + + + + table's name to insert into + + + + a list of column names (as const gchar *) + + + + + + a list of values (as #GValue) + + + + + + + + Internal function to be called by database providers to force a transaction status +change. + + + + + + + a #GdaConnection + + + + the new state + + + + + + Get the opaque pointer previously set using gda_connection_internal_set_provider_data(). +If it's not set, then add a connection event and returns %NULL + + + the pointer to the opaque structure set using gda_connection_internal_set_provider_data(), or %NULL + + + + + a #GdaConnection object + + + + + + Internal function to be called by database providers to reset the transaction status. + + + + + + + a #GdaConnection + + + + + + Internal functions to be called by database providers when a savepoint has been added +to keep track of the transaction status of the connection + +Note: this function should not be called if gda_connection_internal_statement_executed() +has already been called because a statement's execution was necessary to perform +the action. + + + + + + + a #GdaConnection + + + + name of the parent transaction, or %NULL + + + + savepoint's name, or %NULL + + + + + + Internal functions to be called by database providers when a savepoint has been removed +to keep track of the transaction status of the connection + +Note: this function should not be called if gda_connection_internal_statement_executed() +has already been called because a statement's execution was necessary to perform +the action. + + + + + + + a #GdaConnection + + + + savepoint's name, or %NULL + + + + + + Internal functions to be called by database providers when a savepoint has been rolled back +to keep track of the transaction status of the connection + +Note: this function should not be called if gda_connection_internal_statement_executed() +has already been called because a statement's execution was necessary to perform +the action. + + + + + + + a #GdaConnection + + + + savepoint's name, or %NULL + + + + + + Note: calling this function more than once will not make it call @destroy_func on any previously +set opaque @data, you'll have to do it yourself. + +Note: @destroy_func, needs to free the memory associated to @data, if necessary. + + + + + + + a #GdaConnection object + + + + a #GdaServerProviderConnectionData, which can be extended as needed by the provider for which @cnc is opened + + + + function to call when the connection closes and @data needs to be destroyed + + + + + + Internal functions to be called by database providers when a statement has been executed +to keep track of the transaction status of the connection + + + + + + + a #GdaConnection + + + + a #GdaStatement which has been executed + + + + execution's parameters + + + + a #GdaConnectionEvent if the execution failed, or %NULL + + + + + + Internal functions to be called by database providers when a transaction has been committed +to keep track of the transaction status of the connection + +Note: this function should not be called if gda_connection_internal_statement_executed() +has already been called because a statement's execution was necessary to perform +the action. + + + + + + + a #GdaConnection + + + + transaction's name, or %NULL + + + + + + Internal functions to be called by database providers when a transaction has been rolled +back to keep track of the transaction status of the connection + +Note: this function should not be called if gda_connection_internal_statement_executed() +has already been called because a statement's execution was necessary to perform +the action. + + + + + + + a #GdaConnection + + + + transaction's name, or %NULL + + + + + + Internal functions to be called by database providers when a transaction has been started +to keep track of the transaction status of the connection. + +Note: this function should not be called if gda_connection_internal_statement_executed() +has already been called because a statement's execution was necessary to perform +the action. + + + + + + + a #GdaConnection + + + + name of the parent transaction, or %NULL + + + + transaction's name, or %NULL + + + + isolation level. + + + + + + Checks whether a connection is open or not. + + + %TRUE if the connection is open, %FALSE if it's not. + + + + + a #GdaConnection object. + + + + + + Tries to open the connection. The function either blocks or, if a #GMaincontext has been specified using +gda_connection_set_main_context(), processes the events for that main context until either the +connection opening has succeeded or failed. + +If the connection is already opened, then this function returns %TRUE immediately. + + + TRUE if the connection is opened, and FALSE otherwise. + + + + + a #GdaConnection object + + + + + + This function requests that the connection be opened. + +If the connection is already opened, then this function returns an error (with the %GDA_CONNECTION_ALREADY_OPENED_ERROR code). + +Note: @callback function will be called when processing events from the #GMainContext defined by +gda_connection_set_main_context(), for example when there is a main loop for that main context. + + + a job ID + + + + + a #GdaConnection object + + + + a #GdaConnectionOpenFunc which will be called after the connection has been opened (of failed to open) + + + + data to pass to @callback when called + + + + + + This method is similar to gda_server_operation_get_value_at(), but for SQL identifiers: a new string +is returned instead of a #GValue. Also the returned string is assumed to represents an SQL identifier +and will correctly be quoted to be used with @cnc. + + + a new string, or %NULL if the value is undefined or +if the @path is not defined or @path does not hold any value, or if the value held is not a string +(in that last case a warning is shown). + + + + + a #GdaConnection + + + + a #GdaServerOperation object + + + + a complete path to a node (starting with "/") + + + + a place to store errors, or %NULL + + + + arguments to use with @path_format to make a complete path + + + + + + This method is similar to gda_server_operation_get_value_at(), but for SQL identifiers: a new string +is returned instead of a #GValue. Also the returned string is assumed to represents an SQL identifier +and will correctly be quoted to be used with @cnc. + + + a new string, or %NULL if the value is undefined or +if the @path is not defined or @path does not hold any value, or if the value held is not a string or +a valid SQL identifier. + + + + + a #GdaConnection, or %NULL + + + + a #GdaServerOperation object + + + + a complete path to a node (starting with "/") + + + + + + This function helps to parse a SQL string which uses parameters and store them at @params. + + + a #GdaStatement representing the SQL command, or %NULL if an error occurred + + + + + a #GdaConnection object, or %NULL + + + + an SQL command to parse, not %NULL + + + + a place to store a new #GdaSet, for parameters used in SQL command, or %NULL + + + + + + Performs the operation described by @op (which should have been created using +gda_connection_create_operation()). It is a wrapper around the gda_server_provider_perform_operation() +method. + + + TRUE if no error occurred + + + + + a #GdaConnection object + + + + a #GdaServerOperation object + + + + + + Use this method to get a pointer to the next available connection event which can then be customized +and taken into account using gda_connection_add_event(). + + + a pointer to the next available connection event, or %NULL if event should +be ignored + + + + + a #GdaConnection object + + + + a #GdaConnectionEventType + + + + + + Add more arguments if the flag needs them: + +GDA_SERVER_OPERATION_CREATE_TABLE_FKEY_FLAG: +<itemizedlist> + <listitem><para>string with the table's name referenced</para></listitem> + <listitem><para>an integer with the number pairs "local_field", "referenced_field" + used in the reference</para></listitem> + <listitem><para>Pairs of "local_field", "referenced_field" to use, must match + the number specified above.</para></listitem> + <listitem><para>a string with the action for ON DELETE; can be: "RESTRICT", "CASCADE", + "NO ACTION", "SET NULL" and "SET DEFAULT". Example: "ON UPDATE CASCADE".</para></listitem> + <listitem><para>a string with the action for ON UPDATE (see above).</para></listitem> +</itemizedlist> + +Create a #GdaServerOperation object using an opened connection, taking three +arguments, a column's name the column's GType and #GdaServerOperationCreateTableFlag +flag, you need to finish the list using %NULL. + +You'll be able to modify the #GdaServerOperation object to add custom options +to the operation. When finished call #gda_server_operation_perform_create_table +or #gda_server_provider_perform_operation +in order to execute the operation. + + + a #GdaServerOperation if no errors; NULL and set @error otherwise + + + + + an opened connection + + + + name of the table to create + + + + list of arguments as #GdaServerOperationPrepareCreateTableArg containing column's name, +column's #GType and a #GdaServerOperationCreateTableFlag flag + + + + + + + + Convenient funtion for table creation. + +For details about arguments see #gda_server_operation_prepare_create_table_v(). + + + a #GdaServerOperation if no errors; NULL and set @error otherwise + + + + + an opened connection + + + + name of the table to create + + + + a place to store errors, or %NULL + + + + group of three arguments for column's name, column's #GType +and a #GdaServerOperationCreateTableFlag flag, finished with %NULL + + + + + + This is just a convenient function to create a #GdaServerOperation to drop a +table in an opened connection. + + + a new #GdaServerOperation or %NULL if couldn't create the opereration. + + + + + an opened connection + + + + name of the table to drop + + + + + + Use this method to get a correctly quoted (if necessary) SQL identifier which can be used +in SQL statements, from @id. If @id is already correctly quoted for @cnc, then a copy of @id +may be returned. + +This method may add double quotes (or other characters) around @id: +<itemizedlist> + <listitem><para>if @id is a reserved SQL keyword (such as SELECT, INSERT, ...)</para></listitem> + <listitem><para>if @id contains non allowed characters such as spaces, or if it starts with a digit</para></listitem> + <listitem><para>in any other event as necessary for @cnc, depending on the the options passed when opening the @cnc + connection, and specifically the <link linkend="GDA-CONNECTION-OPTIONS-SQL-IDENTIFIERS-CASE-SENSITIVE:CAPS"> + GDA_CONNECTION_OPTIONS_SQL_IDENTIFIERS_CASE_SENSITIVE</link> option.</para></listitem> +</itemizedlist> + +One can safely pass an already quoted @id to this method, either with quoting characters allowed by @cnc or using the +double quote (") character. + + + a new string, to free with g_free() once not needed anymore + + + + + a #GdaConnection object + + + + an SQL identifier + + + + + + Executes the statement upon which @rstmt is built. Note that as several statements can actually be executed by this +method, it is recommended to be within a transaction. + +If @error is not %NULL and @stop_on_error is %FALSE, then it may contain the last error which occurred. + + + a new list of #GObject pointers (see gda_connection_statement_execute() for more information about what they +represent), one for each actual execution of the statement upon which @rstmt is built. If @stop_on_error is %FALSE, then +the list may contain some %NULL pointers which refer to statements which failed to execute. + + + + + + + a #GdaConnection + + + + a #GdaRepetitiveStatement object + + + + specifies how the returned data model will be used as a #GdaStatementModelUsage enum + + + + an array of GType to request each returned GdaDataModel's column's GType, see gda_connection_statement_execute_select_full() for more information + + + + + + set to TRUE if the method has to stop on the first error. + + + + + + Rollback all the modifications made after the SAVEPOINT named @name. + + + TRUE if no error occurred + + + + + a #GdaConnection object + + + + name of the savepoint to rollback to + + + + + + Rollbacks the given transaction. This means that all changes +made to the underlying data source since the last call to +#gda_connection_begin_transaction() or #gda_connection_commit_transaction() +will be discarded. + + + %TRUE if the operation was successful, %FALSE otherwise. + + + + + a #GdaConnection object. + + + + the name of the transation to commit, or %NULL + + + + + + Defines the #GMainContext which will still process events while a potentially blocking operation is performed using +@cnc. If @cnc is %NULL, then this function applies to all the connections, except the ones for which a different +context has been defined (be it user defined connections or internal connections used in other objects). +On the other hand, if @cnc is not %NULL, then the setting only applied to @cnc. + +For exemple if there is a GUI which needs to continue to handle events, then you can use this function to pass +the default #GMainContext used for the UI refreshing, for example: + +<programlisting><![CDATA[GMainContext *context; +cnc = gda_connection_new_...; +context = g_main_context_ref_thread_default (); +gda_connection_set_main_context (cnc, NULL, context); +g_main_context_unref (context); +GError *error = NULL; +if (! gda_connection_open (cnc, &error)) + ... +]]></programlisting> + +If @context is %NULL, then potentially blocking operation will actually block any event from being processed +while the blocking operation is being performed. + + + + + + + a #GdaConnection, or %NULL + + + + the #GThread in which @context will be used, or %NULL (for the current thread) + + + + a #GMainContext, or %NULL + + + + + + Executes @stmt. + +As @stmt can, by design (and if not abused), contain only one SQL statement, the +return object will either be: +<itemizedlist> + <listitem><para>a #GdaDataSelect object (which is also a #GdaDataModel) if @stmt is a SELECT statement + (usually a GDA_SQL_STATEMENT_SELECT, see #GdaSqlStatementType) + containing the results of the SELECT. The resulting data model is by default read only, but + modifications can be enabled, see the #GdaDataSelect's documentation for more information.</para></listitem> + <listitem><para>a #GdaSet for any other SQL statement which correctly executed. In this case + (if the provider supports it), then the #GdaSet may contain value holders named: + <itemizedlist> + <listitem><para>a (gint) #GdaHolder named "IMPACTED_ROWS"</para></listitem> + <listitem><para>a (GObject) #GdaHolder named "EVENT" which contains a #GdaConnectionEvent</para></listitem> + </itemizedlist></para></listitem> +</itemizedlist> + +If @last_insert_row is not %NULL and @stmt is an INSERT statement, then it will contain a new #GdaSet +object composed of value holders named "+&lt;column number&gt;" +starting at column 0 which contain the actual inserted values. For example if a table is composed of an 'id' column +which is auto incremented and a 'name' column then the execution of a "INSERT INTO mytable (name) VALUES ('joe')" +query will return a #GdaSet with two holders: +<itemizedlist> + <listitem><para>one with the '+0' ID which may for example contain 1 (note that its "name" property should be "id")</para></listitem> + <listitem><para>one with the '+1' ID which will contain 'joe' (note that its "name" property should be "name")</para></listitem> +</itemizedlist> +Note that the value pointer by @last_insert_row may be %NULL after the function call if either the database provider +does not support it, or if the last interted row could not be determined (for example with SQLite if the table +in which the data is inserted has the WITHOUT ROWID optimization). + +This method may fail with a %GDA_SERVER_PROVIDER_ERROR domain error (see the #GdaServerProviderError error codes). + +Note1: If @stmt is a SELECT statement which has some parameters and if @params is %NULL, then the statement can't +be executed and this method will return %NULL. + +Note2: If @stmt is a SELECT statement which has some parameters and if @params is not %NULL but contains some +invalid parameters, then the statement can't be executed and this method will return %NULL, unless the +@model_usage has the GDA_STATEMENT_MODEL_ALLOW_NOPARAM flag. + +Note3: If @stmt is a SELECT statement which has some parameters and if @params is not %NULL but contains some +invalid parameters and if @model_usage has the GDA_STATEMENT_MODEL_ALLOW_NOPARAM flag, then the returned +data model will contain no row but will have all the correct columns (even though some of the columns might +report as GDA_TYPE_NULL). In this case, if (after this method call) any of @params' parameters change +then the resulting data model will re-run itself, see the GdaDataSelect's +<link linkend="GdaDataSelect--auto-reset">auto-reset</link> property for more information. + +Note4: if @model_usage does not contain the GDA_STATEMENT_MODEL_RANDOM_ACCESS or +GDA_STATEMENT_MODEL_CURSOR_FORWARD flags, then the default will be to return a random access data model + +Note5: If @stmt is a SELECT statement which returns blob values (of type %GDA_TYPE_BLOB), then an implicit +transaction will have been started by the database provider, and it's up to the caller to close the transaction +(which will then be locked) once all the blob ressources have been +liberated (when the returned data model is destroyed). See the section about +<link linkend="gen:blobs">Binary large objects (BLOBs)</link> for more information. + +Also see the <link linkend="limitations">provider's limitations</link>, and the +<link linkend="data-select">Advanced GdaDataSelect usage</link> sections. + + + a #GObject, or %NULL if an error occurred + + + + + a #GdaConnection + + + + a #GdaStatement object + + + + a #GdaSet object (which can be obtained using gda_statement_get_parameters()), or %NULL + + + + in the case where @stmt is a SELECT statement, specifies how the returned data model will be used + + + + a place to store a new #GdaSet object which contains the values of the last inserted row, or %NULL + + + + + + Executes a non-selection statement on the given connection. + +This function returns the number of rows affected by the execution of @stmt, or -1 +if an error occurred, or -2 if the connection's provider does not return the number of rows affected. + +This function is just a convenience function around the gda_connection_statement_execute() +function. +See the documentation of the gda_connection_statement_execute() for information +about the @params list of parameters. + +See gda_connection_statement_execute() form more information about @last_insert_row. + + + the number of rows affected (&gt;=0) or -1 or -2 + + + + + a #GdaConnection object. + + + + a #GdaStatement object. + + + + a #GdaSet object (which can be obtained using gda_statement_get_parameters()), or %NULL + + + + a place to store a new #GdaSet object which contains the values of the last inserted row, or %NULL + + + + + + Executes a selection command on the given connection. + +This function returns a #GdaDataModel resulting from the SELECT statement, or %NULL +if an error occurred. + +This function is just a convenience function around the gda_connection_statement_execute() +function. + +See the documentation of the gda_connection_statement_execute() for information +about the @params list of parameters. + + + a #GdaDataModel containing the data returned by the +data source, or %NULL if an error occurred + + + + + a #GdaConnection object. + + + + a #GdaStatement object. + + + + a #GdaSet object (which can be obtained using gda_statement_get_parameters()), or %NULL + + + + + + Executes a selection command on the given connection. + +This function returns a #GdaDataModel resulting from the SELECT statement, or %NULL +if an error occurred. + +This function is just a convenience function around the gda_connection_statement_execute() +function. + +See the documentation of the gda_connection_statement_execute() for information +about the @params list of parameters. + + + a #GdaDataModel containing the data returned by the +data source, or %NULL if an error occurred + + + + + a #GdaConnection object. + + + + a #GdaStatement object. + + + + a #GdaSet object (which can be obtained using gda_statement_get_parameters()), or %NULL + + + + specifies how the returned data model will be used as a #GdaStatementModelUsage enum + + + + an array of GType to request each returned #GdaDataModel's column's GType, terminated with the G_TYPE_NONE +value. Any value left to 0 will make the database provider determine the real GType. @col_types can also be %NULL if no +column type is specified. + + + + + + + + Executes a selection command on the given connection. + +This function returns a #GdaDataModel resulting from the SELECT statement, or %NULL +if an error occurred. + +This function is just a convenience function around the gda_connection_statement_execute() +function. + +See the documentation of the gda_connection_statement_execute() for information +about the @params list of parameters. + + + a #GdaDataModel containing the data returned by the +data source, or %NULL if an error occurred + + + + + a #GdaConnection object. + + + + a #GdaStatement object. + + + + a #GdaSet object (which can be obtained using gda_statement_get_parameters()), or %NULL + + + + specifies how the returned data model will be used as a #GdaStatementModelUsage enum + + + + a place to store an error, or %NULL + + + + a (-1 terminated) list of (column number, GType) specifying for each column mentioned the GType +of the column in the returned #GdaDataModel. + + + + + + Ask the database accessed through the @cnc connection to prepare the usage of @stmt. This is only useful +if @stmt will be used more than once (however some database providers may always prepare statements +before executing them). + +This function is also useful to make sure @stmt is fully understood by the database before actually executing it. + +Note however that it is also possible that gda_connection_statement_prepare() fails when +gda_connection_statement_execute() does not fail (this will usually be the case with statements such as +<![CDATA["SELECT * FROM ##tablename::string"]]> because database usually don't allow variables to be used in place of a +table name). + + + TRUE if no error occurred. + + + + + a #GdaConnection + + + + a #GdaStatement object + + + + + + Renders @stmt as an SQL statement, adapted to the SQL dialect used by @cnc + + + a new string, or %NULL if an error occurred + + + + + a #GdaConnection object, or %NULL + + + + a #GdaStatement object + + + + a #GdaSet object (which can be obtained using gda_statement_get_parameters()), or %NULL + + + + SQL rendering flags, as #GdaStatementSqlFlag OR'ed values + + + + a place to store the list of individual #GdaHolder objects within @params which have been used + + + + + + + + Asks the underlying provider for if a specific feature is supported. + + + %TRUE if the provider supports it, %FALSE if not. + + + + + a #GdaConnection object. + + + + feature to ask for. + + + + + + Updates @cnc's associated #GdaMetaStore. If @context is not %NULL, then only the parts described by +@context will be updated, and if it is %NULL, then the complete meta store will be updated. Detailed +explanations follow: + +In order to keep the meta store's contents in a consistent state, the update process involves updating +the contents of all the tables related to one where the contents change. For example the "_columns" +table (which lists all the columns of a table) depends on the "_tables" table (which lists all the tables +in a schema), so if a row is added, removed or modified in the "_tables", then the "_columns" table's contents +needs to be updated as well regarding that row. + +If @context is %NULL, then the update process will simply overwrite any data that was present in all the +meta store's tables with new (up to date) data even if nothing has changed, without having to build the +tables' dependency tree. This is the recommended way of proceeding when dealing with a meta store which +might be outdated. + +On the other hand, if @context is not %NULL, then a tree of the dependencies has to be built (depending on +@context) and only some parts of the meta store are updated following that dependencies tree. Specifying a +context may be useful for example in the following situations: +<itemizedlist> + <listitem><para>One knows that a database object has changed (for example a table created), and + may use the @context to request that only the information about that table be updated + </para></listitem> + <listitem><para>One is only interested in the list of views, and may request that only the information + about views may be updated</para></listitem> +</itemizedlist> + +When @context is not %NULL, and contains specified SQL identifiers (for example the "table_name" of the "_tables" +table), then each SQL identifier has to match the convention the #GdaMetaStore has adopted regarding +case sensitivity, using gda_connection_quote_sql_identifier() or gda_meta_store_sql_identifier_quote(). + +see the <link linkend="information_schema:sql_identifiers"> +meta data section about SQL identifiers</link> for more information, and the documentation about the +gda_sql_identifier_quote() function which will be most useful. + +Note however that usually <emphasis>more</emphasis> information will be updated than strictly requested by +the @context argument. + +For more information, see the <link linkend="information_schema">Database structure</link> section, and +the <link linkend="howto-meta2">Update the meta data about a table</link> howto. + + + TRUE if no error occurred + + + + + a #GdaConnection object. + + + + description of which part of @cnc's associated #GdaMetaStore should be updated, or %NULL + + + + + + This is a convenience function, which creates an UPDATE statement and executes it using the values +provided. It internally relies on variables which makes it immune to SQL injection problems. + +The equivalent SQL command is: UPDATE &lt;table&gt; SET &lt;column_name&gt; = &lt;new_value&gt; [,...] WHERE &lt;condition_column_name&gt; = &lt;condition_value&gt;. + +A simple example for updating a specific row in the table + +|[<!-- language="C" --> + +GdaConnection *cnc; +//Open connection here + +GError *error = NULL; + +GValue *v_id = gda_value_new (G_TYPE_INT); +GValue *v_first_name = gda_value_new_from_string (first_name, G_TYPE_STRING); +GValue *v_last_name = gda_value_new_from_string (last_name, G_TYPE_STRING); +GValue *v_email = gda_value_new_from_string (email, G_TYPE_STRING); +GValue *v_cod = gda_value_new (G_TYPE_INT); + +g_value_set_int (v_id, id); +g_value_set_int (v_cod, cod); + +if (!gda_connection_update_row_in_table (cnc, "TABLE_CONTACTS", + "col_id", v_id, &error, + "col_first_name", v_first_name, + "col_last_name", v_last_name, + "col_email", v_email, + "col_cod", v_cod, NULL)) +{ + g_error ("Could not update row in table: %s\n", + error && error->message ? error->message : "No detail"); +} + +gda_value_free (v_id); +gda_value_free (v_first_name); +gda_value_free (v_last_name); +gda_value_free (v_email); +gda_value_free (v_cod); + +g_error_free (error); + + +]| + + + TRUE if no error occurred, FALSE otherwise + + + + + an opened connection + + + + the table's name with the row's values to be updated + + + + the name of the column to used in the WHERE condition clause + + + + the @condition_column_type's GType + + + + a place to store errors, or %NULL + + + + a list of string/GValue pairs with the name of the column to use and the +GValue pointer containing the value to update the column to (value can be %NULL), finished by a %NULL. There must be +at least one column name and value + + + + + + @col_names and @values must have length (&gt;= 1). + +This is a convenience function, which creates an UPDATE statement and executes it using the values +provided. It internally relies on variables which makes it immune to SQL injection problems. + +The equivalent SQL command is: UPDATE &lt;table&gt; SET &lt;column_name&gt; = &lt;new_value&gt; [,...] WHERE &lt;condition_column_name&gt; = &lt;condition_value&gt;. + + + TRUE if no error occurred, FALSE otherwise + + + + + an opened connection + + + + the table's name with the row's values to be updated + + + + the name of the column to used in the WHERE condition clause + + + + the @condition_column_type's GType + + + + a list of column names (as const gchar *) + + + + + + a list of values (as #GValue) + + + + + + + + Produces a fully quoted and escaped string from a GValue + + + escaped and quoted value or NULL if not supported. + + + + + a #GdaConnection object. + + + + #GValue to convert from + + + + + + + + + + + + + + + Defines the number of #GdaConnectionEvent objects kept in memory which can +be fetched using gda_connection_get_events(). + + + + Artificially slows down the execution of queries. This property can be used to +debug some problems. If non zero, this value is the number of microseconds waited before actually +executing each query. +NB: this parameter is ignored during the meta store update (it is set to 0 before the meta data update +and restored to its state after). + + + + Computes execution times for each statement executed. + + + + + + + + + + + + + + + + Gets emitted when the connection to the database has been closed + + + + + + Gets emitted when the DSN used by @cnc has been changed + + + + + + Gets emitted whenever a connection event occurs. Check the nature of @event to +see if it's an error or a simple notification + + + + + + a #GdaConnectionEvent object + + + + + + Gets emitted when the connection has been opened to the database + + + + + + Gets emitted when the @cnc's status has changed (usually when a the connection is being used to execute +a statement) + + + + + + the new connection status + + + + + + Gets emitted when the transaction status of @cnc has changed (a transaction has been +started, rolled back, a savepoint added,...) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @event's code (the code is specific to the provider being used) + + + + + a #GdaConnectionEvent. + + + + + + Get the description of the event. Note that is @event's type is GDA_CONNECTION_EVENT_COMMAND, +the the description is the SQL of the command. + + + @event's description. + + + + + a #GdaConnectionEvent. + + + + + + Get @event's severity (from a simple notice to a fatal event) + + + the event type + + + + + a #GdaConnectionEvent object + + + + + + Retrieve the code associated to @event. + + + the #GdaConnectionEventCode event's code + + + + + a #GdaConnectionEvent + + + + + + + + @event's source. + + + + + a #GdaConnectionEvent. + + + + + + Get the SQLSTATE value of @event. Even though the SQLSTATE values are specified by ANSI SQL and ODBC, +consult each DBMS for the possible values. However, the "00000" (success) value means that there is no error, +and the "HY000" (general error) value means an error but no better error code available. + + + @event's SQL state. + + + + + a #GdaConnectionEvent. + + + + + + Sets @event's code: the code is specific to the provider being used. +If you want to have a common understanding of the event codes, use +gda_connection_event_get_gda_code() instead. + +This function should not be called directly + + + + + + + a #GdaConnectionEvent. + + + + a code. + + + + + + Sets @event's @description. This function should not be called directly. + + + + + + + a #GdaConnectionEvent. + + + + a description, or %NULL (to unset current description if any) + + + + + + Sets @event's severity (from a simple notice to a fatal event) +This function should not be called directly. + + + + + + + a #GdaConnectionEvent object + + + + the severity of the event + + + + + + Sets @event's gda code: that code is standardized by the libgda +library. If you want to specify the corresponding provider specific code, +use gda_connection_event_get_code() or gda_connection_event_get_sqlstate() instead. + +This function should not be called directly + + + + + + + a #GdaConnectionEvent + + + + a code + + + + + + Sets @event's @source; this function should not be called directly + + + + + + + a #GdaConnectionEvent. + + + + a source. + + + + + + Changes the SQLSTATE code of @event, this function should not be called directly + +Sets @event's SQL state. + + + + + + + a #GdaConnectionEvent. + + + + SQL state. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Used in gda_connection_supports_feature() and gda_server_provider_supports_feature() to test if a connection +or a database provider supports some specific feature. + + + test for aggregates support + + + test for BLOBS (binary large objects) support + + + test for indexes support + + + test for tables inheritance support + + + test for namespaces support + + + test for functions support + + + test for sequences support + + + test for SQL language (even specific to the database) support + + + test for transactions support + + + test for savepoints within transactions support + + + test if savepoints can be removed + + + test for triggers support + + + test for updatable cursors support + + + test for users support + + + test for views support + + + test for READ COMMITTED transaction isolation level + + + test for READ UNCOMMITTED transaction isolation level + + + test for REPEATABLE READ transaction isolation level + + + test for SERIALIZABLE transaction isolation level + + + test for distributed transactions support + + + not used + + + + Used with gda_connection_get_meta_store_data() to describe what meta data to extract from +a connection's associated #GdaMetaStore. + + + lists the <link linkend="GdaConnectionMetaTypeGDA_CONNECTION_META_NAMESPACES">namespaces</link> (or schemas for PostgreSQL) + + + lists the <link linkend="GdaConnectionMetaTypeGDA_CONNECTION_META_TYPES">database types</link> + + + lists the <link linkend="GdaConnectionMetaTypeGDA_CONNECTION_META_TABLES">tables</link> + + + lists the <link linkend="GdaConnectionMetaTypeGDA_CONNECTION_META_VIEWS">views</link> + + + lists the <link linkend="GdaConnectionMetaTypeGDA_CONNECTION_META_FIELDS">table's or view's fields</link> + + + lists the <link linkend="GdaConnectionMetaTypeGDA_CONNECTION_META_INDEXES">table's indexes</link> + + + + + + + + + + + + + + + + + + + + + + + + + + + Specifies some aspects of a connection when opening it. + +Additional information about the GDA_CONNECTION_OPTIONS_SQL_IDENTIFIERS_CASE_SENSITIVE flag: +<itemizedlist> + <listitem><para>For example without this flag, if the table + name specified in a #GdaServerOperation to create a table is + <emphasis>MyTable</emphasis>, then usually the database will create a table named + <emphasis>mytable</emphasis>, whereas with this flag, the table will be created + as <emphasis>MyTable</emphasis> (note that in the end the database may still decide + to name the table <emphasis>mytable</emphasis> or differently if it can't do + otherwise).</para></listitem> + <listitem><para>Libgda will not apply this rule when parsing SQL code, the SQL code being parsed + has to be conform to the database it will be used with</para></listitem> +</itemizedlist> + +Note about the @GDA_CONNECTION_OPTIONS_AUTO_META_DATA flag: +<itemizedlist> + <listitem><para>Every time a DDL statement is successfully executed, the associated meta data, if + defined, will be updated, which has a impact on performances</para></listitem> + <listitem><para>If a transaction is started and some DDL statements are executed and the transaction + is not rolled back or committed, then the meta data may end up being wrong</para></listitem> +</itemizedlist> + + + no specific aspect + + + this flag specifies that the connection to open should be in a read-only mode + (this policy is not correctly enforced at the moment) + + + this flag specifies that SQL identifiers submitted as input + to Libgda have to keep their case sensitivity. + + + this flags specifies that if a #GdaMetaStore has been associated + to the connection, then it is kept up to date with the evolutions in the + database's structure. Be aware however that there are some drawbacks + explained below. + + + + Indicates the current status of a connection. The possible status and the transitions between those status +are indicated in the diagram below: + <mediaobject> + <imageobject role="html"> + <imagedata fileref="connection-status.png" format="PNG" contentwidth="50mm"/> + </imageobject> + <textobject> + <phrase>GdaConnection's status and transitions between different status</phrase> + </textobject> + </mediaobject> + + + the connection is closed (default status upon creation) + + + the connection is currently being opened + + + the connection is opened but not currently used + + + the connection is opened and currently being used + + + + + + + Creates a new #GdaDataModel object which buffers the rows of @model. This object is useful +only if @model can only be accessed using cursor based method. + + + a pointer to the newly created #GdaDataModel. + + + + + a #GdaDataModel + + + + + + @wrapper will report as many columns as @mapping_size, and for each value at position 'i' in @mapping, +@wrapper will report the 'i'th column, mapped to the wrapped data model column at position mapping[i]. +For example if mapping is {3, 4, 0}, then @wrapper will report 3 columns, respectively mapped to the 4th, +5th and 1st columns of the wrapped data model (as column numbers start at 0). + +If @mapping is %NULL, then no mapping is done and @wrapper's columns will be the same as the wrapped +data model. + +If a column in @mapping does not exist in the wrapped data model, then it is simply ignored (no error +reported). + +Please note that if @wrapper has already been used and if the wrapped data model offers a cursor forward +access mode, then this method will return %FALSE and no action will be done. + +If the mapping is applied, then any existing iterator will be invalid, and @wrapper is reset as if it +had just been created. + + + %TRUE if the mapping actually changed + + + + + a #GdaDataAccessWrapper object + + + + an array of #gint which represents the mapping between @wrapper's columns +and the columns of the wrapped data model + + + + + + the size of @mapping. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Creates a new comparator to compute the differences from @old_model to @new_model: if one applies +all the computed differences (as #GdaDiff structures) to @old_model, the resulting data model +should have the same contents as @new_model. + + + a new #GdaDataComparator object + + + + + Data model to which the modifications should be applied + + + + Target data model. + + + + + + + + + + + + + + + + + + + + + + + + + Actually computes the differences between the data models for which @comp is defined. + +For each difference computed, stored in a #GdaDiff structure, the "diff-computed" signal is emitted. +If one connects to this signal and returns FALSE in the signal handler, then computing differences will be +stopped and an error will be returned. + + + TRUE if all the differences have been successfully computed, and FALSE if an error occurred + + + + + a #GdaDataComparator object + + + + + + Get a pointer to the #GdaDiff structure representing the difference which number is @pos + + + a pointer to a #GdaDiff, or %NULL if @pos is invalid + + + + + a #GdaDataComparator object + + + + the requested difference number (starting at 0) + + + + + + Get the number of differences as computed by the last time gda_data_comparator_compute_diff() was called. + + + the number of computed differences + + + + + a #GdaDataComparator object + + + + + + Defines the columns which will be used as a key when searching data. This is not mandatory but +will speed things up as less data will be processed. + + + + + + + a #GdaDataComparator object + + + + an array of @nb_cols values + + + + + + the size of the @col_numbers array + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Obtain a pointer to a #GdaDataHandler which can manage #GValue values of type @for_type. The returned +data handler will be adapted to use the current locale information (for example dates will be formatted +taking into account the locale). + +The returned pointer is %NULL if there is no default data handler available for the @for_type data type + + + a #GdaDataHandler which must be destroyed using g_object_unref() + + + + + a #GType type + + + + + + Checks wether the GdaDataHandler is able to handle the gda type given as argument. + + + %TRUE if the gda type can be handled + + + + + an object which implements the #GdaDataHandler interface + + + + a #GType + + + + + + Get a short description of the GdaDataHandler + + + the description + + + + + an object which implements the #GdaDataHandler interface + + + + + + Creates a new GValue which holds a sane initial value to be used if no value is specifically +provided. For example for a simple string, this would return a new value containing the "" string. + + + the new #GValue, or %NULL if no such value can be created. + + + + + an object which implements the #GdaDataHandler interface + + + + a #GType + + + + + + Creates a new string which is an SQL representation of the given value, the returned string +can be used directly in an SQL statement. For example if @value is a G_TYPE_STRING, then +the returned string will be correctly quoted. Note however that it is a better practice +to use variables in statements instead of value literals, see +the <link linkend="GdaSqlParser.description">GdaSqlParser</link> for more information. + +If the value is NULL or is of type GDA_TYPE_NULL, +or is a G_TYPE_STRING and g_value_get_string() returns %NULL, the returned string is "NULL". + + + the new string, or %NULL if an error occurred + + + + + an object which implements the #GdaDataHandler interface + + + + the value to be converted to a string, or %NULL + + + + + + Creates a new string which is a "user friendly" representation of the given value +(in the user's locale, specially for the dates). If the value is +NULL or is of type GDA_TYPE_NULL, the returned string is a copy of "" (empty string). + +Note: the returned value will be in the current locale representation. + + + the new string, or %NULL if an error occurred + + + + + an object which implements the #GdaDataHandler interface + + + + the value to be converted to a string, or %NULL + + + + + + Creates a new GValue which represents the SQL value given as argument. This is +the opposite of the function gda_data_handler_get_sql_from_value(). The type argument +is used to determine the real data type requested for the returned value. + +If the @sql string is %NULL, then the returned GValue is of type GDA_TYPE_NULL; +if the @sql string does not correspond to a valid SQL string for the requested type, then +the %NULL is returned. + + + the new #GValue or %NULL on error + + + + + an object which implements the #GdaDataHandler interface + + + + an SQL string, or %NULL + + + + a GType + + + + + + Creates a new GValue which represents the @str value given as argument. This is +the opposite of the function gda_data_handler_get_str_from_value(). The type argument +is used to determine the real data type requested for the returned value. + +If the @str string is %NULL, then the returned GValue is of type GDA_TYPE_NULL; +if the @str string does not correspond to a valid string for the requested type, then +%NULL is returned. + +Note: the @str string must be in the current locale representation + + + the new #GValue or %NULL on error + + + + + an object which implements the #GdaDataHandler interface + + + + a string or %NULL + + + + a GType + + + + + + Checks wether the GdaDataHandler is able to handle the gda type given as argument. + + + %TRUE if the gda type can be handled + + + + + an object which implements the #GdaDataHandler interface + + + + a #GType + + + + + + Get a short description of the GdaDataHandler + + + the description + + + + + an object which implements the #GdaDataHandler interface + + + + + + Creates a new GValue which holds a sane initial value to be used if no value is specifically +provided. For example for a simple string, this would return a new value containing the "" string. + + + the new #GValue, or %NULL if no such value can be created. + + + + + an object which implements the #GdaDataHandler interface + + + + a #GType + + + + + + Creates a new string which is an SQL representation of the given value, the returned string +can be used directly in an SQL statement. For example if @value is a G_TYPE_STRING, then +the returned string will be correctly quoted. Note however that it is a better practice +to use variables in statements instead of value literals, see +the <link linkend="GdaSqlParser.description">GdaSqlParser</link> for more information. + +If the value is NULL or is of type GDA_TYPE_NULL, +or is a G_TYPE_STRING and g_value_get_string() returns %NULL, the returned string is "NULL". + + + the new string, or %NULL if an error occurred + + + + + an object which implements the #GdaDataHandler interface + + + + the value to be converted to a string, or %NULL + + + + + + Creates a new string which is a "user friendly" representation of the given value +(in the user's locale, specially for the dates). If the value is +NULL or is of type GDA_TYPE_NULL, the returned string is a copy of "" (empty string). + +Note: the returned value will be in the current locale representation. + + + the new string, or %NULL if an error occurred + + + + + an object which implements the #GdaDataHandler interface + + + + the value to be converted to a string, or %NULL + + + + + + Creates a new GValue which represents the SQL value given as argument. This is +the opposite of the function gda_data_handler_get_sql_from_value(). The type argument +is used to determine the real data type requested for the returned value. + +If the @sql string is %NULL, then the returned GValue is of type GDA_TYPE_NULL; +if the @sql string does not correspond to a valid SQL string for the requested type, then +the %NULL is returned. + + + the new #GValue or %NULL on error + + + + + an object which implements the #GdaDataHandler interface + + + + an SQL string, or %NULL + + + + a GType + + + + + + Creates a new GValue which represents the @str value given as argument. This is +the opposite of the function gda_data_handler_get_str_from_value(). The type argument +is used to determine the real data type requested for the returned value. + +If the @str string is %NULL, then the returned GValue is of type GDA_TYPE_NULL; +if the @str string does not correspond to a valid string for the requested type, then +%NULL is returned. + +Note: the @str string must be in the current locale representation + + + the new #GValue or %NULL on error + + + + + an object which implements the #GdaDataHandler interface + + + + a string or %NULL + + + + a GType + + + + + + + + + + + + + + + the new string, or %NULL if an error occurred + + + + + an object which implements the #GdaDataHandler interface + + + + the value to be converted to a string, or %NULL + + + + + + + + + + the new string, or %NULL if an error occurred + + + + + an object which implements the #GdaDataHandler interface + + + + the value to be converted to a string, or %NULL + + + + + + + + + + the new #GValue or %NULL on error + + + + + an object which implements the #GdaDataHandler interface + + + + an SQL string, or %NULL + + + + a GType + + + + + + + + + + the new #GValue or %NULL on error + + + + + an object which implements the #GdaDataHandler interface + + + + a string or %NULL + + + + a GType + + + + + + + + + + the new #GValue, or %NULL if no such value can be created. + + + + + an object which implements the #GdaDataHandler interface + + + + a #GType + + + + + + + + + + %TRUE if the gda type can be handled + + + + + an object which implements the #GdaDataHandler interface + + + + a #GType + + + + + + + + + + the description + + + + + an object which implements the #GdaDataHandler interface + + + + + + + + + + + + + + + Adds the data from an XML node to the given data model (see the DTD for that node +in the $prefix/share/libgda/dtd/libgda-array.dtd file). + +Upon errors FALSE will be returned and @error will be assigned a +#GError from the #GDA_DATA_MODEL_ERROR domain. + + + %TRUE if successful, %FALSE otherwise. + + + + + a #GdaDataModel. + + + + an XML node representing a &lt;gda_array_data&gt; XML node. + + + + + + Appends a row to the data model (the new row will possibly have NULL values for all columns, +or some other values depending on the data model implementation) + +Upon errors -1 will be returned and @error will be assigned a +#GError from the #GDA_DATA_MODEL_ERROR domain. + + + the number of the added row, or -1 if an error occurred + + + + + a #GdaDataModel object. + + + + + + Appends a row to the given data model. If any value in @values is actually %NULL, then +it is considered as a default value. If @values is %NULL then all values are set to their default value. + +Upon errors -1 will be returned and @error will be assigned a +#GError from the #GDA_DATA_MODEL_ERROR domain. + + + the number of the added row, or -1 if an error occurred + + + + + a #GdaDataModel object. + + + + #GList of #GValue* representing the row to add. The + length must match model's column count. These #GValue + are value-copied (the user is still responsible for freeing them). + + + + + + + + Makes a copy of @src into a new #GdaDataModelArray object + + + a new data model, or %NULL if an error occurred + + + + + a #GdaDataModel to copy data from + + + + + + Like gda_data_model_array_copy_model(), makes a copy of @src, but copies only some +columns. + + + a new data model, or %NULL if an error occurred + + + + + a #GdaDataModel to copy data from + + + + size of @cols + + + + array of @src's columns to copy into the new array, not %NULL + + + + + + + + Creates a new iterator object #GdaDataModelIter object which can be used to iterate through +rows in @model. The new #GdaDataModelIter does not hold any reference to @model (ie. if @model +is destroyed at some point, the new iterator will become useless but in any case it will not prevent +the data model from being destroyed). + +Depending on the data model's implementation, a new #GdaDataModelIter object may be created, +or a reference to an already existing #GdaDataModelIter may be returned. For example if @model only +supports being accessed using a forward moving cursor (say a the result of a SELECT executed by SQLite +with a cursor access mode specified), then this method will always return the same iterator. + +If a new #GdaDataModelIter is created, then the row it represents is undefined. + +For models which can be accessed +randomly, any row can be set using gda_data_model_iter_move_to_row(), +and for models which are accessible sequentially only then use +gda_data_model_iter_move_next() (and gda_data_model_iter_move_prev() if +supported). + +Note: for the #GdaDataProxy data model (which proxies any #GdaDataModel for modifications and +has twice the number of columns of the proxied data model), this method will create an iterator +in which only the columns of the proxied data model appear. If you need to have a #GdaDataModelIter +in which all the proxy's columns appear, create it using: +<programlisting><![CDATA[iter = g_object_new (GDA_TYPE_DATA_MODEL_ITER, "data-model", proxy, NULL);]]></programlisting> + + + a #GdaDataModelIter object, or %NULL if an error occurred + + + + + a #GdaDataModel object. + + + + + + Queries the underlying data model implementation for a description +of a given column. That description is returned in the form of +a #GdaColumn structure, which contains all the information +about the given column in the data model. + +WARNING: the returned #GdaColumn object belongs to the @model model and +and should not be destroyed; any modification will affect the whole data model. + + + the description of the column. + + + + + a #GdaDataModel object. + + + + column number. + + + + + + Dumps a textual representation of the @model to the @to_stream stream + +The following environment variables can affect the resulting output: +<itemizedlist> + <listitem><para>GDA_DATA_MODEL_DUMP_ROW_NUMBERS: if set, the first column of the output will contain row numbers</para></listitem> + <listitem><para>GDA_DATA_MODEL_DUMP_ATTRIBUTES: if set, also dump the data model's columns' types and value's attributes</para></listitem> + <listitem><para>GDA_DATA_MODEL_DUMP_TITLE: if set, also dump the data model's title</para></listitem> + <listitem><para>GDA_DATA_MODEL_NULL_AS_EMPTY: if set, replace the 'NULL' string with an empty string for NULL values </para></listitem> + <listitem><para>GDA_DATA_MODEL_DUMP_TRUNCATE: if set to a numeric value, truncates the output to the width specified by the value. If the value is -1 then the actual terminal size (if it can be determined) is used</para></listitem> +</itemizedlist> + + + + + + + a #GdaDataModel. + + + + where to dump the data model + + + + + + Dumps a textual representation of the @model into a new string. The main differences with gda_data_model_export_to_string() are that +the formatting options are passed using environment variables, and that the data is dumped regardless of the user locale (e.g. dates +are not formatted according to the locale). + +The following environment variables can affect the resulting output: +<itemizedlist> + <listitem><para>GDA_DATA_MODEL_DUMP_ROW_NUMBERS: if set, the first column of the output will contain row numbers</para></listitem> + <listitem><para>GDA_DATA_MODEL_DUMP_TITLE: if set, also dump the data model's title</para></listitem> + <listitem><para>GDA_DATA_MODEL_NULL_AS_EMPTY: if set, replace the 'NULL' string with an empty string for NULL values </para></listitem> + <listitem><para>GDA_DATA_MODEL_DUMP_TRUNCATE: if set to a numeric value, truncates the output to the width specified by the value. If the value is -1 then the actual terminal size (if it can be determined) is used</para></listitem> +</itemizedlist> + + + a new string. + + + + + a #GdaDataModel. + + + + + + Exports data contained in @model to the @file file; the format is specified using the @format argument. Note that +the date format used is the one used by the connection from which the data model has been made (as the result of a +SELECT statement), or, for other kinds of data models, the default format (refer to gda_data_handler_get_default()) unless +the "cnc" property has been set and points to a #GdaConnection to use that connection's date format. + +Specifically, the parameters in the @options list can be: +<itemizedlist> + <listitem><para>"SEPARATOR": a string value of which the first character is used as a separator in case of CSV export + </para></listitem> + <listitem><para>"QUOTE": a string value of which the first character is used as a quote character in case of CSV export. The + default if not specified is the double quote character</para></listitem> + <listitem><para>"FIELD_QUOTE": a boolean value which can be set to FALSE if no quote around the individual fields + is requeted, in case of CSV export</para></listitem> + <listitem><para>"NAMES_ON_FIRST_LINE": a boolean value which, if set to %TRUE and in case of a CSV or %GDA_DATA_MODEL_IO_TEXT_TABLE export, will add a first line with the name each exported field (note that "FIELDS_NAME" is also accepted as a synonym)</para></listitem> + <listitem><para>"NAME": a string value used to name the exported data if the export format is XML or %GDA_DATA_MODEL_IO_TEXT_TABLE</para></listitem> + <listitem><para>"OVERWRITE": a boolean value which tells if the file must be over-written if it already exists.</para></listitem> + <listitem><para>"NULL_AS_EMPTY": a boolean value which, if set to %TRUE and in case of a CSV or %GDA_DATA_MODEL_IO_TEXT_TABLE export, will render and NULL value as the empty string (instead of the 'NULL' string)</para></listitem> + <listitem><para>"INVALID_AS_NULL": a boolean value which, if set to %TRUE, considers any invalid data (for example for the date related values) as NULL</para></listitem> + <listitem><para>"COLUMN_SEPARATORS": a boolean value which, if set to %TRUE, adds a separators lines between each column, if the export format is %GDA_DATA_MODEL_IO_TEXT_TABLE + </para></listitem> + <listitem><para>"SEPARATOR_LINE": a boolean value which, if set to %TRUE, adds an horizontal line between column titles and values, if the export format is %GDA_DATA_MODEL_IO_TEXT_TABLE + </para></listitem> + <listitem><para>"ROW_NUMBERS": a boolean value which, if set to %TRUE, prepends a column with row numbers, if the export format is %GDA_DATA_MODEL_IO_TEXT_TABLE + </para></listitem> + <listitem><para>"MAX_WIDTH": an integer value which, if greater than 0, makes all the lines truncated to have at most that number of characters, if the export format is %GDA_DATA_MODEL_IO_TEXT_TABLE + </para></listitem> +</itemizedlist> + +Warning: this function uses a #GdaDataModelIter iterator, and if @model does not offer a random access +(check using gda_data_model_get_access_flags()), the iterator will be the same as normally used +to access data in @model previously to calling this method, and this iterator will be moved (point to +another row). + +Upon errors %FALSE will be returned and @error will be assigned a +#GError from the #GDA_DATA_MODEL_ERROR domain. + + + TRUE if no error occurred + + + + + a #GdaDataModel + + + + the format in which to export data + + + + the filename to export to + + + + an array containing which columns of @model will be exported, or %NULL for all columns + + + + + + the number of columns in @cols + + + + an array containing which rows of @model will be exported, or %NULL for all rows + + + + + + the number of rows in @rows + + + + list of options for the export + + + + + + Exports data contained in @model to a string; the format is specified using the @format argument, see the +gda_data_model_export_to_file() documentation for more information about the @options argument (except for the +"OVERWRITE" option). + +Warning: this function uses a #GdaDataModelIter iterator, and if @model does not offer a random access +(check using gda_data_model_get_access_flags()), the iterator will be the same as normally used +to access data in @model previously to calling this method, and this iterator will be moved (point to +another row). + +See also gda_data_model_dump_as_string(); + + + a new string, use g_free() when no longer needed + + + + + a #GdaDataModel + + + + the format in which to export data + + + + an array containing which columns of @model will be exported, or %NULL for all columns + + + + + + the number of columns in @cols + + + + an array containing which rows of @model will be exported, or %NULL for all rows + + + + + + the number of rows in @rows + + + + list of options for the export + + + + + + Disables notifications of changes on the given data model. To +re-enable notifications again, you should call the +#gda_data_model_thaw function. + + + + + + + a #GdaDataModel object. + + + + + + Get the attributes of @model such as how to access the data it contains if it's modifiable, etc. + + + an ORed value of #GdaDataModelAccessFlags flags + + + + + a #GdaDataModel object. + + + + + + Get the attributes of the value stored at (row, col) in @model, which +is an ORed value of #GdaValueAttribute flags. As a special case, if +@row is -1, then the attributes returned correspond to a "would be" value +if a row was added to @model. + + + the attributes as an ORed value of #GdaValueAttribute + + + + + a #GdaDataModel object + + + + a valid column number + + + + a valid row number, or -1 + + + + + + Get the index of the first column named @name in @model. + + + the column index, or -1 if no column named @name was found + + + + + a #GdaDataModel object. + + + + a column name + + + + + + + + the name for the given column in a data model object. + + + + + a #GdaDataModel object. + + + + column number. + + + + + + + + the title for the given column in a data model object. + + + + + a #GdaDataModel object. + + + + column number. + + + + + + Get the global data model exception(s) that occurred when using @model. +This is useful for example for the LDAP related +data models where some rows may be missing because the LDAP search has reached a limit +imposed by the LDAP server. + + + a pointer to a %NULL terminated array of #GError, or %NULL. + + + + + + + a #GdaDataModel + + + + + + + + the number of columns in the given data model, or -1 if unknown. + + + + + a #GdaDataModel object. + + + + + + + + the number of rows in the given data model, or -1 if the number of rows is not known + + + + + a #GdaDataModel object. + + + + + + Returns the status of notifications changes on the given data model. + + + + + + + a #GdaDataModel object. + + + + + + Returns the first row where all the values in @values at the columns identified at +@cols_index match. If the row can't be identified, then returns -1; + +NOTE: the @cols_index array MUST contain a column index for each value in @values + + + the requested row number, of -1 if not found + + + + + a #GdaDataModel object. + + + + a list of #GValue values (no %NULL is allowed) + + + + + + an array of #gint containing the column number to match each value of @values + + + + + + + + Upon errors %NULL will be returned and @error will be assigned a +#GError from the #GDA_DATA_MODEL_ERROR domain. + +This method is similar to gda_data_model_get_value_at(), except that it also allows one to specify the expected +#GType of the value to get: if the data model returned a #GValue of a type different than the expected one, then +this method returns %NULL and an error code. + +Note: the same limitations and usage instructions apply as for gda_data_model_get_value_at(). + +Upon errors %NULL will be returned and @error will be assigned a +#GError from the #GDA_DATA_MODEL_ERROR domain. + + + a #GValue containing the value stored in the given +position, or %NULL on error (out-of-bound position, wrong data type, etc). + + + + + a #GdaDataModel object. + + + + a valid column number. + + + + a valid row number. + + + + the expected data type of the returned value + + + + if TRUE, then NULL values (value of type %GDA_TYPE_NULL) will not generate any error + + + + + + Retrieves the data stored in the given position (identified by +the @col and @row parameters) on a data model. + +Upon errors %NULL will be returned and @error will be assigned a +#GError from the #GDA_DATA_MODEL_ERROR domain. + +This is the main function for accessing data in a model which allows random access to its data. +To access data in a data model using a cursor, use a #GdaDataModelIter object, obtained using +gda_data_model_create_iter(). + +Note1: the returned #GValue must not be modified directly (unexpected behaviours may +occur if you do so). + +Note2: the returned value may become invalid as soon as any Libgda part is executed again, +which means if you want to keep the value, a copy must be made, however it will remain valid +as long as the only Libgda usage is calling gda_data_model_get_value_at() for different values +of the same row. + +If you want to modify a value stored in a #GdaDataModel, use the gda_data_model_set_value_at() or +gda_data_model_set_values() methods. + +Upon errors %NULL will be returned and @error will be assigned a +#GError from the #GDA_DATA_MODEL_ERROR domain. + + + a #GValue containing the value stored in the given +position, or %NULL on error (out-of-bound position, etc). + + + + + a #GdaDataModel object. + + + + a valid column number. + + + + a valid row number. + + + + + + Imports data contained in the @file file into @model; the format is detected. + +Upon errors FALSE will be returned and @error will be assigned a +#GError from the #GDA_DATA_MODEL_ERROR domain. + + + TRUE if no error occurred + + + + + a #GdaDataModel + + + + the filename to import from + + + + a #GHashTable for columns translating, or %NULL, see gda_data_model_import_from_model() + + + + + + + list of options for the export + + + + + + Copy the contents of the @from data model to the @to data model. The copy stops as soon as an error +orrurs. + +The @cols_trans is a hash table for which keys are @to columns numbers and the values are +the corresponding column numbers in the @from data model. To set the values of a column in @to to NULL, +create an entry in the hash table with a negative value. For example: +<programlisting><![CDATA[GHashTable *hash; +gint *ptr; +hash = g_hash_table_new_full (g_int_hash, g_int_equal, g_free, NULL); +ptr = g_new (gint, 1); +*ptr = 2; +g_hash_table_insert (hash, ptr, GINT_TO_POINTER (3)); +gda_data_model_import_from_model (...); +g_hash_table_free (hash); +]]></programlisting> + +Upon errors FALSE will be returned and @error will be assigned a +#GError from the #GDA_DATA_MODEL_ERROR domain. + + + TRUE if no error occurred. + + + + + the destination #GdaDataModel + + + + the source #GdaDataModel + + + + TRUE if @to is completely overwritten by @from's data, and FALSE if @from's data is appended to @to + + + + a #GHashTable for columns translating, or %NULL + + + + + + + + + Loads the data from @string into @model. + +Upon errors FALSE will be returned and @error will be assigned a +#GError from the #GDA_DATA_MODEL_ERROR domain. + + + TRUE if no error occurred. + + + + + a #GdaDataModel + + + + the string to import data from + + + + a hash table containing which columns of @model will be imported, or %NULL for all columns, see gda_data_model_import_from_model() + + + + + + + list of options for the export + + + + + + Method reserved to #GdaDataModelIter implementations, should not be called directly. + + + %TRUE if @iter was moved correctly. + + + + + a #GdaDataModel + + + + a #GdaDataModelIter iterating in @model + + + + + + Method reserved to #GdaDataModelIter implementations, should not be called directly. + + + %TRUE if @iter was moved correctly. + + + + + a #GdaDataModel + + + + a #GdaDataModelIter iterating in @model + + + + + + Method reserved to #GdaDataModelIter implementations, should not be called directly. + + + %TRUE if @iter was moved correctly. + + + + + a #GdaDataModel + + + + a #GdaDataModelIter iterating in @model + + + + the requested row + + + + + + Removes a row from the data model. + +Upon errors FALSE will be returned and @error will be assigned a +#GError from the #GDA_DATA_MODEL_ERROR domain. + + + %TRUE if successful, %FALSE otherwise. + + + + + a #GdaDataModel object. + + + + the row number to be removed. + + + + + + Emits the 'reset' and 'changed' signal on @model. + + + + + + + a #GdaDataModel object. + + + + + + Emits the 'row_inserted' and 'changed' signals on @model. + +This method should only be used by #GdaDataModel implementations to +signal that a row has been inserted. + + + + + + + a #GdaDataModel object. + + + + row number. + + + + + + Emits the 'row_removed' and 'changed' signal on @model. + +This method should only be used by #GdaDataModel implementations to +signal that a row has been removed + + + + + + + a #GdaDataModel object. + + + + row number. + + + + + + Emits the 'row_updated' and 'changed' signals on @model. + +This method should only be used by #GdaDataModel implementations to +signal that a row has been updated. + + + + + + + a #GdaDataModel object. + + + + row number. + + + + + + Sends a hint to the data model. The hint may or may not be handled by the data +model, depending on its implementation + + + + + + + a #GdaDataModel + + + + a hint to send to the model + + + + an optional value to specify the hint, or %NULL + + + + + + Sets the @name of the given @col in @model, and if its title is not set, also sets the +title to @name. + + + + + + + a #GdaDataModel object. + + + + column number + + + + name for the given column. + + + + + + Sets the @title of the given @col in @model. + + + + + + + a #GdaDataModel object. + + + + column number + + + + title for the given column. + + + + + + Modifies a value in @model, at (@col, @row). + +Upon errors FALSE will be returned and @error will be assigned a +#GError from the #GDA_DATA_MODEL_ERROR domain. + + + TRUE if the value in the data model has been updated and no error occurred + + + + + a #GdaDataModel object. + + + + column number. + + + + row number. + + + + a #GValue (not %NULL) + + + + + + In a similar way to gda_data_model_set_value_at(), this method modifies a data model's contents +by setting several values at once. + +If any value in @values is actually %NULL, then the value in the corresponding column is left +unchanged. + +Upon errors FALSE will be returned and @error will be assigned a +#GError from the #GDA_DATA_MODEL_ERROR domain. + + + %TRUE if the value in the data model has been updated and no error occurred + + + + + a #GdaDataModel object. + + + + row number. + + + + a list of #GValue (or %NULL), one for at most the number of columns of @model + + + + + + + + Re-enables notifications of changes on the given data model. + + + + + + + a #GdaDataModel object. + + + + + + Gets emitted when @model's access flags have changed. Use +gda_data_model_get_access_flags() to get the access flags. + + + + + + Gets emitted when any value in @model has been changed + + + + + + Gets emitted when @model's contents has been completely reset (the number and +type of columns may also have changed) + + + + + + Gets emitted when a row has been inserted in @model + + + + + + the row number + + + + + + Gets emitted when a row has been removed from @model + + + + + + the row number + + + + + + Gets emitted when a row has been modified in @model + + + + + + the row number + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Creates a new #GdaDataModel object without initializing the column +types. Using gda_data_model_array_new_with_g_types() is usually better. + + + a pointer to the newly created #GdaDataModel. + + + + + number of columns for rows in this data model. + + + + + + Creates a new #GdaDataModel object with the column types as +specified. + + + a pointer to the newly created #GdaDataModel. + + + + + number of columns for rows in this data model. + + + + types of the columns of the model to create as #GType, as many as indicated by @cols + + + + + + Creates a new #GdaDataModel object with the column types as +specified. + + + a pointer to the newly created #GdaDataModel. + + + + + number of columns for rows in this data model. + + + + array of types of the columns of the model to create as #GType, as many as indicated by @cols + + + + + + + + Frees all the rows in @model. + + + + + + + the model to clear. + + + + + + Get a pointer to a row in @model + + + the #GdaRow, or %NULL if an error occurred + + + + + a #GdaDataModelArray object + + + + row number (starting from 0) + + + + + + Sets the number of columns for rows inserted in this model. +@cols must be greated than or equal to 0. + +Also clears @model's contents. + + + + + + + the #GdaDataModelArray. + + + + number of columns for rows this data model should use. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Creates a new #GdaDataModel object to list all the files starting from @basedir + + + a new #GdaDataModel + + + + + a directory + + + + + + Reset the list of errors which have occurred while using @model + + + + + + + a #GdaDataModelDir object + + + + + + Get the list of errors which have occurred while using @model + + + a read-only list of #GError pointers, or %NULL if no error has occurred + + + + + + + a #GdaDataModelDir object + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Format to use when exporting a data model, see gda_data_model_export_to_string() and gda_data_model_export_to_file() + + + data is exported as an XML structure + + + data is exported as CSV + + + data is exported as a human readable table + + + + + + + + + + Creates a new #GdaDataModel object which contains the data stored within the @filename file. + +The options are the following ones: +<itemizedlist> + <listitem><para>For the CSV format: + <itemizedlist> + <listitem><para>ENCODING (string): specifies the encoding of the data in the file</para></listitem> + <listitem><para>SEPARATOR (string): specifies the CSV separator (comma as default)</para></listitem> + <listitem><para>QUOTE (string): specifies the character used as quote (double quote as default)</para></listitem> + <listitem><para>NAMES_ON_FIRST_LINE (boolean): consider that the first line of the file contains columns' titles (note that the TITLE_AS_FIRST_LINE option is also accepted as a synonym)</para></listitem> + <listitem><para>G_TYPE_&lt;column number&gt; (GType): specifies the type of value expected in column &lt;column number&gt;</para></listitem> + </itemizedlist> + </para></listitem> + <listitem><para>Other formats: no option</para></listitem> +</itemizedlist> + +Note: after the creation, please use gda_data_model_import_get_errors() to check any error. + + + a pointer to the newly created #GdaDataModel. + + + + + the file to import data from + + + + TRUE if random access will be required + + + + importing options + + + + + + Creates a new #GdaDataModel object which contains the data stored in the @data string. + +Important note: the @data string is not copied for memory efficiency reasons and should not +therefore be altered in any way as long as the returned data model exists. + + + a pointer to the newly created #GdaDataModel. + + + + + a string containing the data to import + + + + TRUE if random access will be required + + + + importing options, see gda_data_model_import_new_file() for more information + + + + + + Creates a new #GdaDataModel and loads the data in @node. The resulting data model +can be accessed in a random way. + + + a pointer to the newly created #GdaDataModel. + + + + + an XML node corresponding to a &lt;data-array&gt; tag + + + + + + Clears the history of errors @model has to report + + + + + + + a #GdaDataModelImport object + + + + + + Get the list of errors which @model has to report. The returned list is a list of +#GError structures, and must not be modified + + + the list of errors (which must not be modified), or %NULL + + + + + + + a #GdaDataModelImport object + + + + + + Data to import, as a string. + + + + Name of the file to import. + + + + Data model options. + + + + Defines if the data model will be accessed randomly or through a cursor. If set to %FALSE, +access will have to be done using a cursor. + + + + Defines the behaviour in case the imported data contains recoverable errors (usually too +many or too few data per row). If set to %TRUE, an error will be reported and the import +will stop, and if set to %FALSE, then the error will be reported but the import will not stop. + + + + Data to import, as a pointer to an XML node (a #xmlNodePtr). + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Moves @iter one row further than where it already is +(synchronizes the values of the parameters in @iter with the values at the new row). + +If the iterator was on the data model's last row, then it can't be moved forward +anymore, and the returned value is %FALSE; note also that the "current-row" property +is set to -1 (which means that gda_data_model_iter_is_valid() would return %FALSE) + +This function can return %FALSE if it was not allowed to be moved (as it emits the +"validate-set" signal before being moved). + +When this function returns %TRUE, then @iter has actually been moved to the next row, +but some values may not have been read correctly in the row, in which case the +correcsponding #GdaHolder will be left invalid. + + + %TRUE if the iterator is now at the next row + + + + + a #GdaDataModelIter object + + + + + + Moves @iter one row before where it already is (synchronizes the values of the parameters in @iter +with the values at the new row). + +If the iterator was on the data model's first row, then it can't be moved backwards +anymore, and the returned value is %FALSE; note also that the "current-row" property +is set to -1 (which means that gda_data_model_iter_is_valid() would return %FALSE). + +This function can return %FALSE if it was not allowed to be moved (as it emits the +"validate-set" signal before being moved). + +When this function returns %TRUE, then @iter has actually been moved to the next row, +but some values may not have been read correctly in the row, in which case the +correcsponding #GdaHolder will be left invalid. + + + %TRUE if the iterator is now at the previous row + + + + + a #GdaDataModelIter object + + + + + + Synchronizes the values of the parameters in @iter with the values at the @row row. + +If @row is not a valid row, then the returned value is %FALSE, and the "current-row" +property is set to -1 (which means that gda_data_model_iter_is_valid() would return %FALSE), +with the exception that if @row is -1, then the returned value is %TRUE. + +This function can return %FALSE if it was not allowed to be moved (as it emits the +"validate-set" signal before being moved). + +When this function returns %TRUE, then @iter has actually been moved to the next row, +but some values may not have been read correctly in the row, in which case the +correcsponding #GdaHolder will be left invalid. + + + %TRUE if no error occurred + + + + + a #GdaDataModelIter object + + + + the row to set @iter to + + + + + + + + + + + + + + + + + + + + Sets a value in @iter, at the column specified by @col + + + TRUE if no error occurred + + + + + a #GdaDataModelIter object + + + + the column number + + + + a #GValue (not %NULL) + + + + + + Fetch a pointer to the #GdaHolder object which is synchronized with data at +column @col + + + the #GdaHolder, or %NULL if an error occurred + + + + + a #GdaDataModelIter object + + + + the requested column + + + + + + Get the row which @iter represents in the data model + + + the row number, or -1 if @iter is invalid + + + + + a #GdaDataModelIter object + + + + + + Get the value stored at the column @col in @iter. The returned value must not be modified. + + + the #GValue, or %NULL if the value could not be fetched + + + + + a #GdaDataModelIter object + + + + the requested column + + + + + + Get the value stored at the column @col in @iter. The returned value must not be modified. + + + the #GValue, or %NULL if the value could not be fetched + + + + + a #GdaDataModelIter object + + + + the requested column + + + + + + Get the value stored at the column @field_name in @iter + + + the #GValue, or %NULL + + + + + a #GdaDataModelIter object + + + + the requested column name + + + + + + Declare all the parameters in @iter invalid, without modifying the +#GdaDataModel @iter is for or changing the row it represents. This method +is for internal usage. Note that for gda_data_model_iter_is_valid() to return %FALSE, +it is also necessary to set the "current-row" property to -1. + + + + + + + a #GdaDataModelIter object + + + + + + Tells if @iter is a valid iterator (if it actually corresponds to a valid row in the model) + + + TRUE if @iter is valid + + + + + a #GdaDataModelIter object + + + + + + Moves @iter one row further than where it already is +(synchronizes the values of the parameters in @iter with the values at the new row). + +If the iterator was on the data model's last row, then it can't be moved forward +anymore, and the returned value is %FALSE; note also that the "current-row" property +is set to -1 (which means that gda_data_model_iter_is_valid() would return %FALSE) + +This function can return %FALSE if it was not allowed to be moved (as it emits the +"validate-set" signal before being moved). + +When this function returns %TRUE, then @iter has actually been moved to the next row, +but some values may not have been read correctly in the row, in which case the +correcsponding #GdaHolder will be left invalid. + + + %TRUE if the iterator is now at the next row + + + + + a #GdaDataModelIter object + + + + + + Moves @iter one row before where it already is (synchronizes the values of the parameters in @iter +with the values at the new row). + +If the iterator was on the data model's first row, then it can't be moved backwards +anymore, and the returned value is %FALSE; note also that the "current-row" property +is set to -1 (which means that gda_data_model_iter_is_valid() would return %FALSE). + +This function can return %FALSE if it was not allowed to be moved (as it emits the +"validate-set" signal before being moved). + +When this function returns %TRUE, then @iter has actually been moved to the next row, +but some values may not have been read correctly in the row, in which case the +correcsponding #GdaHolder will be left invalid. + + + %TRUE if the iterator is now at the previous row + + + + + a #GdaDataModelIter object + + + + + + Synchronizes the values of the parameters in @iter with the values at the @row row. + +If @row is not a valid row, then the returned value is %FALSE, and the "current-row" +property is set to -1 (which means that gda_data_model_iter_is_valid() would return %FALSE), +with the exception that if @row is -1, then the returned value is %TRUE. + +This function can return %FALSE if it was not allowed to be moved (as it emits the +"validate-set" signal before being moved). + +When this function returns %TRUE, then @iter has actually been moved to the next row, +but some values may not have been read correctly in the row, in which case the +correcsponding #GdaHolder will be left invalid. + + + %TRUE if no error occurred + + + + + a #GdaDataModelIter object + + + + the row to set @iter to + + + + + + Sets a value in @iter, at the column specified by @col + + + TRUE if no error occurred + + + + + a #GdaDataModelIter object + + + + the column number + + + + a #GValue (not %NULL) + + + + + + + + + + + + + + + + + + Gets emitted when @iter has reached the end of available data (which means the previous +row it was on was the last one). + + + + + + Gets emitted when the row @iter is currently pointing has changed + + + + + + the new iter's row + + + + + + + + + + + + + + + %TRUE if no error occurred + + + + + a #GdaDataModelIter object + + + + the row to set @iter to + + + + + + + + + + %TRUE if the iterator is now at the next row + + + + + a #GdaDataModelIter object + + + + + + + + + + %TRUE if the iterator is now at the previous row + + + + + a #GdaDataModelIter object + + + + + + + + + + TRUE if no error occurred + + + + + a #GdaDataModelIter object + + + + the column number + + + + a #GValue (not %NULL) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a new #GdaDataModelSelect object + + + + + an opened #GdaConnection + + + + a SELECT SQL #GdaStatement + + + + a #GdaSet with the parameters to ejecute the SELECT SQL statement + + + + + + + + a new #GdaDataModelSelect object + + + + + an opened #GdaConnection + + + + a string representing a SELECT SQL to execute + + + + + + + + + + + + + + + + + + + current parameters used by internal statement + + + + + a #GdaDataModelSelect object + + + + + + If at creation or after parameters change has been set, a SELECT statement +is ejectuted, if unsuccess then this model is at invalid state. + + + TRUE if a valid data model is present + + + + + a #GdaDataModelSelect object + + + + + + + + + + + + a #GdaDataModelSelect object + + + + a #GdaSet with the parameters for the statement + + + + + + + + + + + + Emmited when the data model has been updated due to parameters changes +in statement + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Creates a new #GdaDataModel which will contain analysed data from @model. + + + a pointer to the newly created #GdaDataModel. + + + + + a #GdaDataModel to analyse data from, or %NULL + + + + + + Specifies that @field has to be included in the analysis. +@field is a field specification with the following accepted syntaxes: +<itemizedlist> + <listitem><para>a column name in the source data model (see <link linkend="gda-data-model-get-column-index">gda_data_model_get_column_index()</link>); or</para></listitem> + <listitem><para>an SQL expression involving a column name in the source data model, for examples: + <programlisting> +price +firstname || ' ' || lastname +nb BETWEEN 5 AND 10</programlisting> +</para></listitem> +</itemizedlist> + +It is also possible to specify several fields to be added, while separating them by a comma (in effect +still forming a valid SQL syntax). + + + %TRUE if no error occurred + + + + + a #GdaDataPivot object + + + + the type of aggregate operation to perform + + + + the field description, see below + + + + the field alias, or %NULL + + + + + + Specifies that @field has to be included in the analysis. +@field is a field specification with the following accepted syntaxes: +<itemizedlist> + <listitem><para>a column name in the source data model (see <link linkend="gda-data-model-get-column-index">gda_data_model_get_column_index()</link>); or</para></listitem> + <listitem><para>an SQL expression involving a column name in the source data model, for example: + <programlisting> +price +firstname || ' ' || lastname +nb BETWEEN 5 AND 10</programlisting> +</para></listitem> +</itemizedlist> + +It is also possible to specify several fields to be added, while separating them by a comma (in effect +still forming a valid SQL syntax). + + + %TRUE if no error occurred + + + + + a #GdaDataPivot object + + + + the type of field to add + + + + the field description, see below + + + + the field alias, or %NULL + + + + + + Acutally populates @pivot by analysing the data from the provided data model. + + + %TRUE if no error occurred. + + + + + a #GdaDataPivot object + + + + + + + + + + + + + Possible operations for the data fields. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Possible #GdaDataPivot related errors. + + + + + + + + + + + + + + Define types of field to be used when defining a #GdaDataPivot analysis. + + + + + + + + + + + Creates a new proxy for @model. For bindings use @gda_data_proxy_new_with_data_model. + + + a new #GdaDataProxy object + + + + + Data model to be proxied + + + + + + Creates a new proxy for @model. This is the preferred method to create +#GdaDataProxy objects by bindings. + + + a new #GdaDataProxy object + + + + + Data model to be proxied + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Alters the attributes of the value stored at (proxy_row, col) in @proxy. the @alter_flags +can only contain the GDA_VALUE_ATTR_IS_NULL, GDA_VALUE_ATTR_IS_DEFAULT and GDA_VALUE_ATTR_IS_UNCHANGED +flags (other flags are ignored). + + + + + + + a #GdaDataProxy object + + + + A proxy row number + + + + a valid column number + + + + flags to alter the attributes + + + + + + Apply all the changes stored in the proxy to the proxied data model. The changes are done row +after row, and if an error +occurs, then it is possible that not all the changes to all the rows have been applied. + + + TRUE if no error occurred + + + + + a #GdaDataProxy object + + + + + + Commits the modified data in the proxy back into the #GdaDataModel. + + + TRUE if no error occurred. + + + + + a #GdaDataProxy object + + + + the row number to commit + + + + + + Cancel all the changes stored in the proxy (the @proxy will be reset to its state +as it was just after creation). Note that if there are some cached changes (i.e. not applied +to the current proxied data model), then these cached changes are not cleared (set the "cache-changes" +property to %FALSE for this). + + + TRUE if no error occurred + + + + + a #GdaDataProxy object + + + + + + Resets data at the corresponding row and column. If @proxy_row corresponds to a new row, then +that new row is deleted from @proxy. + + + + + + + a #GdaDataProxy object + + + + the row to cancel changes + + + + the column to cancel changes, or less than 0 to cancel any change on the @row row + + + + + + Marks the row @proxy_row to be deleted + + + + + + + a #GdaDataProxy object + + + + A proxy row number + + + + + + Get the current filter expression used by @proxy. + + + the current filter expression or %NULL if no filter has been set + + + + + a #GdaDataProxy object + + + + + + Get the total number of filtered rows in @proxy if a filter has been applied. As new rows +(rows added to the proxy and not yet added to the proxied data model) and rows to remove +(rows marked for removal but not yet removed from the proxied data model) are also filtered, +the returned number also contains references to new rows and rows to be removed. + + + the number of filtered rows in @proxy, or -1 if no filter has been applied + + + + + a #GdaDataProxy object + + + + + + Get the number of rows which have been modified in the proxy (the sum of rows existing in +the proxied data model which have been modified, and new rows). + + + the number of modified rows + + + + + a #GdaDataProxy object + + + + + + Get the number of rows which have been added to @proxy and which are not part of +the proxied data model. + + + the number of new rows + + + + + a #GdaDataProxy object + + + + + + Fetch the #GdaDataModel which @proxy does proxy + + + the proxied data model + + + + + a #GdaDataProxy object + + + + + + Get the number of columns in the proxied data model + + + the number of columns, or -1 if an error occurred + + + + + a #GdaDataProxy object + + + + + + Get the number of rows in the proxied data model + + + the number of rows, or -1 if the number of rows is not known + + + + + a #GdaDataProxy object + + + + + + Get the @proxy's proxied model row corresponding to @proxy_row + + + the proxied model's row, or -1 if @proxy row which only exists @proxy + + + + + a #GdaDataProxy object + + + + A proxy row number + + + + + + Get the number of the last row to be available in @proxy (in reference to the proxied data model) + + + the number of the last proxied model's row. + + + + + a #GdaDataProxy object + + + + + + Get the size of each chunk of data displayed at a time. + + + the chunk (or sample) size, or 0 if chunking is disabled. + + + + + a #GdaDataProxy object + + + + + + Get the number of the first row to be available in @proxy (in reference to the proxied data model) + + + the number of the first proxied model's row. + + + + + a #GdaDataProxy object + + + + + + Get the attributes of the value stored at (proxy_row, col) in @proxy, which +is an ORed value of #GdaValueAttribute flags + + + a #GdaValueAttribute with the value's attributes at given position + + + + + a #GdaDataProxy object + + + + a proxy row + + + + a valid proxy column + + + + + + Retrieve a whole list of values from the @proxy data model. This function +calls gda_data_proxy_get_value() +for each column index specified in @cols_index, and generates a #GSList on the way. + + + a new list of values (the list must be freed, not the values), +or %NULL if an error occurred + + + + + + + a #GdaDataProxy object + + + + a proxy row + + + + array containing the columns for which the values are requested + + + + + + size of @cols_index + + + + + + Tells if @proxy contains any modifications not applied to the proxied data model. + + + TRUE if there are some modifications in @proxy + + + + + a #GdaDataProxy object + + + + + + + + TRUE if the proxied data model is itself read-only + + + + + a #GdaDataProxy object + + + + + + Tells if the row number @proxy_row has changed + + + TRUE if the row has changed + + + + + a #GdaDataProxy object + + + + A proxy row number + + + + + + Tells if the row number @proxy_row is marked to be deleted. + + + TRUE if the row is marked to be deleted + + + + + a #GdaDataProxy object + + + + A proxy row number + + + + + + Tells if the row number @proxy_row is a row which has been inserted in @proxy +(and is thus not in the proxied data model). + + + TRUE if the row is an inserted row + + + + + a #GdaDataProxy object + + + + A proxy row number + + + + + + Sets a filter among the rows presented by @proxy. The filter is defined by a filter expression +which can be any SQL valid expression using @proxy's columns. For instance if @proxy has the "id" and +"name" columns, then a filter can be "length(name) < 5" to filter only the rows where the length of the +name is strictly inferior to 5, or "id >= 1000 and id < 2000 order by name limit 50" to filter only the rows where the id +is between 1000 and 2000, ordered by name and limited to 50 rows. + +Note about column names: real column names can be used (double quoted if necessary), but columns can also be named +"_&lt;column number&gt;" with column numbers starting at 1. + +Note that any previous filter expression is replaced with the new @filter_expr if no error occurs +(if an error occurs, then any previous filter is left unchanged). + + + TRUE if no error occurred + + + + + a #GdaDataProxy object + + + + an SQL based expression which will filter the contents of @proxy, or %NULL to remove any previous filter + + + + + + Orders by the @col column + + + TRUE if no error occurred + + + + + a #GdaDataProxy object + + + + the column number to order from + + + + + + Sets the size of each chunk of data to display: the maximum number of rows which +can be "displayed" at a time (the maximum number of rows which @proxy pretends to have). +The default value is arbitrary 300 as it is big enough to +be able to display quite a lot of data, but small enough to avoid too much data +displayed at the same time. + +Note: the rows which have been added but not yet committed will always be displayed +regardless of the current chunk of data, and the modified rows which are not visible +when the displayed chunk of data changes are still held as modified rows. + +To remove the chunking of the data to display, simply pass @sample_size the %0 value. + + + + + + + a #GdaDataProxy object + + + + the requested size of a chunk, or 0 + + + + + + Sets the number of the first row to be available in @proxy (in reference to the proxied data model) + + + + + + + a #GdaDataProxy object + + + + the number of the first row to be displayed + + + + + + Remove the "to be deleted" mark at the row @proxy_row, if it existed. + + + + + + + a #GdaDataProxy object + + + + A proxy row number + + + + + + Defines how changes kept in the data proxy are handled when the proxied data model +is changed (using the "model" property). The default is to silently discard all the +changes, but if this property is set to %TRUE, then the changes are cached. + +If set to %TRUE, each cached change will be re-applied to a newly set proxied data model if +the change's number of columns match the proxied data model's number of columns and based on: +<itemizedlist> + <listitem><para>the contents of the proxied data model's modified row for updates and deletes</para></listitem> + <listitem><para>the inserts are always kept</para></listitem> +</itemizedlist> + + + + + + + + + + + + + + + + + + + Gets emitted when @proxy's filter has been changed + + + + + + Gets emitted when @proxy has committed a row change to the proxied data model. + + + + + + the proxy's row + + + + the proxied data model's row + + + + + + Gets emitted whenever a row has been marked to be deleted, or has been unmarked to be deleted + + + + + + the concerned @proxy's row + + + + tells if the @row is marked to be deleted + + + + + + Gets emitted whenever @proxy's sample size has been changed. @sample_start and @sample_end are +in reference to the proxied data model. + + + + + + the first row of the sample + + + + the last row of the sample + + + + + + Gets emitted whenever @proxy's sample size has been changed + + + + + + the new sample size + + + + + + Gets emitted when @proxy is about to commit a row change to the proxied data model. If any +callback returns a non %NULL value, then the change commit fails with the returned #GError + + a new #GError if validation failed, or %NULL + + + + + the proxy's row + + + + the proxied data model's row + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Computes correct attributes for each of @model's columns, which includes the "NOT NULL" attribute, the +default value, the precision and scale for numeric values. + + + TRUE if no error occurred + + + + + a #GdaDataSelect data model + + + + + + Makes @model try to compute INSERT, UPDATE and DELETE statements to be used when modifying @model's contents. +Note: any modification statement set using gda_data_select_set_modification_statement() will first be unset + +This function is similar to calling gda_data_select_compute_modification_statements_ext() with +@cond_type set to %GDA_DATA_SELECT_COND_PK + + + %TRUE if no error occurred. If %FALSE is returned, then some modification statement may still have been computed + + + + + a #GdaDataSelect data model + + + + + + Makes @model try to compute INSERT, UPDATE and DELETE statements to be used when modifying @model's contents. +Note: any modification statement set using gda_data_select_set_modification_statement() will first be unset + + + %TRUE if no error occurred. If %FALSE is returned, then some modification statement may still have been computed + + + + + a #GdaDataSelect data model + + + + the type of condition for the modifications where one row only should be identified + + + + + + Offers the same features as gda_data_select_set_row_selection_condition() but the expression +is computed from the meta data associated to the connection being used when @model was created. + +NOTE1: make sure the meta data associated to the connection is up to date before using this +method, see gda_connection_update_meta_store(). + +NOTE2: if the SELECT statement from which @model has been created uses more than one table, or +if the table used does not have any primary key, then this method will fail + + + TRUE if no error occurred. + + + + + a #GdaDataSelect object + + + + + + + + + + + + + + + + + Get a pointer to the #GdaConnection object which was used when @model was created +(and which may be used internally by @model). + + + a pointer to the #GdaConnection, or %NULL + + + + + a #GdaDataSelect data model + + + + + + + + + + + + + + + + + + + + + + + + + + + + Use this method to make sure all the data contained in the data model are stored on the client +side (and that no subsquent call to the server will be necessary to access that data), at the cost of +a higher memory consumption. + +This method is useful in the following situations: +<itemizedlist> + <listitem><para>You need to disconnect from the server and continue to use the data in the data model</para></listitem> + <listitem><para>You need to make sure the data in the data model can be used even though the connection to the server may be used for other purposes (for example executing other queries)</para></listitem> +</itemizedlist> + +Note that this method will fail if: +<itemizedlist> + <listitem><para>the data model contains any blobs (because blobs reading requires acces to the server); + binary values are Ok, though.</para></listitem> + <listitem><para>the data model has been modified since it was created</para></listitem> +</itemizedlist> + + + %TRUE if no error occurred + + + + + a #GdaDataSelect object + + + + + + + + + + + + + + + + + + + + Informs @model that it should allow modifications to the data in some columns and some rows +using @mod_stmt to propagate those modifications into the database. + +If @mod_stmt is: +<itemizedlist> + <listitem><para>an UPDATE statement, then all the rows in @model will be writable</para></listitem> + <listitem><para>a DELETE statement, then it will be possible to delete rows in @model</para></listitem> + <listitem><para>in INSERT statement, then it will be possible to add some rows to @model</para></listitem> + <listitem><para>any other statement, then this method will return an error</para></listitem> +</itemizedlist> + +This method can be called several times to specify different types of modification statements. + +Each modification statement will be executed when one or more values are modified in the data model; +each statement should then include variables which will be set to either the old value or the +new value of a column at the specified modified row (but can also contain other variables). Each variable +named as "+&lt;number&gt;" will be mapped to the new value of the number'th column (starting at 0), and +each variable named as "-&lt;number&gt;" will be mapped to the old value of the number'th column. + +Examples of the SQL equivalent of each statement are (for example if "mytable" has the "id" field as +primary key, and if that field is auto incremented and if the data model is the result of +executing "<![CDATA[SELECT * from mytable]]>"). + +<itemizedlist> + <listitem><para>"<![CDATA[INSERT INTO mytable (name) VALUES (##+1::string)]]>": the column ID can not be set + for new rows</para></listitem> + <listitem><para>"<![CDATA[DELETE FROM mytable WHERE id=##-0::int]]>"</para></listitem> + <listitem><para>"<![CDATA[UPDATE mytable SET name=##+1::string WHERE id=##-0::int]]>": the column ID cannot be + modified</para></listitem> +</itemizedlist> + +Also see the gda_data_select_set_row_selection_condition_sql() for more information about the WHERE +part of the UPDATE and DELETE statement types. + +If @mod_stmt is an UPDATE or DELETE statement then it should have a WHERE part which identifies +a unique row in @model (please note that this property can't be checked but may result +in @model behaving in an unpredictable way). + +NOTE1: However, if the gda_data_select_set_row_selection_condition() +or gda_data_select_set_row_selection_condition_sql() have been successfully be called before, the WHERE +part of @mod_stmt <emphasis>WILL</emphasis> be modified to use the row selection condition specified through one of +these methods (please not that it is then possible to avoid specifying a WHERE part in @mod_stmt then). + +NOTE2: if gda_data_select_set_row_selection_condition() +or gda_data_select_set_row_selection_condition_sql() have not yet been successfully be called before, then +the WHERE part of @mod_stmt will be used as if one of these functions had been called. + + + %TRUE if no error occurred. + + + + + a #GdaDataSelect data model + + + + a #GdaStatement (INSERT, UPDATE or DELETE) + + + + + + Offers the same feature as gda_data_select_set_modification_statement() but using an SQL statement. + + + TRUE if no error occurred. + + + + + a #GdaDataSelect data model + + + + an SQL text + + + + + + Offers the same features as gda_data_select_set_row_selection_condition_sql() but using a #GdaSqlExpr +structure instead of an SQL syntax. + + + TRUE if no error occurred + + + + + a #GdaDataSelect data model + + + + a #GdaSqlExpr expression + + + + + + Specifies the SQL condition corresponding to the WHERE part of a SELECT statement which would +return only 1 row (the expression of the primary key). + +For example for a table created as <![CDATA["CREATE TABLE mytable (part1 int NOT NULL, part2 string NOT NULL, +name string, PRIMARY KEY (part1, part2))"]]>, and if @pmodel corresponds to the execution of the +<![CDATA["SELECT name, part1, part2 FROM mytable"]]>, then the sensible value for @sql_where would be +<![CDATA["part1 = ##-1::int AND part2 = ##-2::string"]]> because the values of the 'part1' field are located +in @pmodel's column number 1 and the values of the 'part2' field are located +in @pmodel's column number 2 and the primary key is composed of (part1, part2). + +For more information about the syntax of the parameters (named <![CDATA["##-1::int"]]> for example), see the +<link linkend="GdaSqlParser.description">GdaSqlParser</link> documentation, and +gda_data_select_set_modification_statement(). + + + TRUE if no error occurred + + + + + a #GdaDataSelect data model + + + + an SQL condition (without the WHERE keyword) + + + + + + + + + + + + + + + This property stores the execution delay which has been necessary to obtain the data + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Defines what criteria gda_data_select_compute_modification_statements_ext() uses +to uniquely identify a single row in a table when creating modification statements. + + + only primary key fields are used + + + all the columns of the tables are used + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Create a new #GdaDbBase instance + + + a new #GdaDbBase instance + + + + + Compares two objects similar to g_strcmp(). + + + 0 if catalog, schema and name are the same + + + + + first #GdaDbBase object + + + + second #GdaDbBase object + + + + + + Returns current catalog name. The returned string should not be freed. + + + Current catalog or %NULL + + + + + a #GdaDbBase object + + + + + + This method returns a full name in the format catalog.schema.name. +If schema is %NULL but catalog and name are not, then only name is +returned. If catalog is %NULL then full name will be in the format: +schema.name. If all three components are not set, then %NULL is returned. + + + Full name of the database object or %NULL. + + + + + an instance of #GdaDbBase + + + + + + Returns current object name. The returned string should not be freed. + + + Current object name or %NULL + + + + + GdaDbBase object + + + + + + Returns current schema name. The returned string should not be freed. + + + Current scheme or %NULL + + + + + GdaDbBase object + + + + + + Set catalog name + + + + + + + a #GdaDbBase instance + + + + Catalog name as a string + + + + + + Set object name. If @name is %NULL the function just returns. + + + + + + + a #GdaDbBase instance + + + + Object name as a string + + + + + + Sets database object names. @catalog and @schema can be %NULL but +@name always should be a valid, not %NULL string. The @name must be +set. If @catalog is %NULL @schema may not be %NULL but if @schema is +%NULL @catalog also should be %NULL. + + + + + + + a #GdaDbBase object + + + + a catalog name associated with the table + + + + a schema name associated with the table + + + + a table name associated with the table + + + + + + Set object schema. If @schema is %NULL the function just returns. + + + + + + + a #GdaDbBase instance + + + + Schema name as a string + + + + + + + + + + + + + + + + + + This method parse XML node and populate @self object. + + + %TRUE on success, %FALSE if an error occurred + + + + + an instance of #GdaDbBuildable where parsed data should be storred + + + + a node to parse + + + + + + Write content from the @self to the @node + + + %TRUE on success, %FALSE if an error occurred + + + + + an instance of #GdaDbBuildable where data should be taken + + + + a node to write data in + + + + + + This method parse XML node and populate @self object. + + + %TRUE on success, %FALSE if an error occurred + + + + + an instance of #GdaDbBuildable where parsed data should be storred + + + + a node to parse + + + + + + Write content from the @self to the @node + + + %TRUE on success, %FALSE if an error occurred + + + + + an instance of #GdaDbBuildable where data should be taken + + + + a node to write data in + + + + + + + + + + + + + + + %TRUE on success, %FALSE if an error occurred + + + + + an instance of #GdaDbBuildable where parsed data should be storred + + + + a node to parse + + + + + + + + + + %TRUE on success, %FALSE if an error occurred + + + + + an instance of #GdaDbBuildable where data should be taken + + + + a node to write data in + + + + + + + + + + Create new instance of #GdaDbCatalog. + + + a new instance of #GdaDbCatalog + + + + + + + + + + Convenient method to varify xmlfile before prsing it. + + + %TRUE if @xmlfile is valid, %FALSE otherwise + + + + + xml file to validate + + + + + + This method append @table to the total list of all tables stored in @self. This method increase +reference count for @table. + + + + + + + a #GdaDbCatalog instance + + + + table to append + + + + + + This method append @view to the total list of all views stored in @self. This method increase +reference count for @view. + + + + + + + a #GdaDbCatalog instance + + + + view to append + + + + + + + + a list of tables as #GdaDbTable or %NULL. + + + + + + + a #GdaDbCatalog object + + + + + + + + a list of views as #GdaDbView or %NULL + + + + + + + a #GdaDbCatalog object + + + + + + Parse internal cnc to populate @self object. This method should be called every time after +database was modified or @self was just created using gda_connection_create_db_catalog(). The +method will return %FALSE if no internal #GdaConnection available. + + + Returns %TRUE if succeeded, %FALSE otherwise. + + + + + a #GdaDbCatalog instance + + + + + + For detailed description see gda_db_catalog_parse_file_from_path() + + + + + + + an instance of #GdaDbCatalog + + + + xml file as #GFile instance + + + + + + This method reads information from @xmlfile and populate @self object. +The @xmlfile should correspond to the following DTD format: + +|[<!-- language="DTD" --> +<!ELEMENT schema (table+, view*)> +<!ATTLIST schema name CDATA #IMPLIED> + +<!ELEMENT table (comment?,column+, fkey*, constraint*)> +<!ATTLIST table temptable (TRUE|FALSE) "FALSE"> +<!ATTLIST table name CDATA #REQUIRED> +<!ATTLIST table space CDATA #IMPLIED> + +<!ELEMENT column (comment?, value?, check?)> +<!ATTLIST column name CDATA #REQUIRED> +<!ATTLIST column type CDATA #REQUIRED> +<!ATTLIST column pkey (TRUE|FALSE) "FALSE"> +<!ATTLIST column unique (TRUE|FALSE) "FALSE"> +<!ATTLIST column autoinc (TRUE|FALSE) "FALSE"> +<!ATTLIST column nnul (TRUE|FALSE) "FALSE"> + +<!ELEMENT comment (#PCDATA)> +<!ELEMENT value (#PCDATA)> +<!ATTLIST value size CDATA #IMPLIED> +<!ATTLIST value scale CDATA #IMPLIED> + +<!ELEMENT check (#PCDATA)> + +<!ELEMENT constraint (#PCDATA)> + +<!ELEMENT fkey (fk_field?)> +<!ATTLIST fkey reftable CDATA #IMPLIED> +<!ATTLIST fkey onupdate (RESTRICT|CASCADE|SET_NULL|NO_ACTION|SET_DEFAULT) #IMPLIED> +<!ATTLIST fkey ondelete (RESTRICT|CASCADE|SET_NULL|NO_ACTION|SET_DEFAULT) #IMPLIED> + +<!ELEMENT fk_field (#PCDATA)> +<!ATTLIST fk_field name CDATA #REQUIRED> +<!ATTLIST fk_field reffield CDATA #REQUIRED> + +<!ELEMENT view (definition)> +<!ATTLIST view name CDATA #REQUIRED> +<!ATTLIST view replace (TRUE|FALSE) "FALSE"> +<!ATTLIST view temp (TRUE|FALSE) "FALSE"> +<!ATTLIST view ifnotexists (TRUE|FALSE) "TRUE"> + +<!ELEMENT definition (#PCDATA)> +]| + +Up to day description of the xml file schema can be found in DTD file +[libgda-db-catalog.dtd](https://gitlab.gnome.org/GNOME/libgda/blob/master/libgda/libgda-db-catalog.dtd) + +The given @xmlfile will be checked before parsing and %FALSE will be +returned if fails. The @xmlfile will be validated internally using +gda_db_catalog_validate_file_from_path(). he same method can be used to validate xmlfile +before parsing it. + + + + + + + an instance of #GdaDbCatalog + + + + xml file to parse + + + + + + After population @self with all data this method may be +called to trigger code and modify user database. This is the main +method to work with database. For retrieving information from database to an +xml file use gda_db_catalog_parse_cnc() and gda_db_buildable_write_node(). + +Connection can be added as a property using g_object_set() call and should be opened to use +this method. See gda_connection_open() method for reference. + +Only table can be created. Views are ignored + +Each table from database compared with each table in the #GdaDbCatalog +instance. If the table doesn't exist in database, it will be created (CREATE_TABLE). +If table exists in the database and xml file, all columns will be checked. If columns +are present in xml file but not in the database it will be created (ADD_COLUMN). If +column exists but has different parameters, e.g. nonnull it will not be +modified. + +Note: Pkeys are not checked. This is a limitation that should be removed. The corresponding +issue was open on gitlab page. + + + + + + + a #GdaDbCatalog object + + + + + + This method writes database description as xml file. +Similar to gda_db_catalog_write_to_path() + + + %TRUE if no error occurred, %FALSE otherwise. + + + + + a #GdaDbCatalog instance + + + + a #GFile to write database description + + + + + + Save content of @self to a user friendly xml file. + + + %TRUE is no error, %FALSE otherwise. + + + + + a #GdaDbCatalog instance + + + + path to xml file to save #GdaDbCatalog + + + + + + + + + + + + + + + + + + + + + + These error are primary for developers to troubleshoot the problem rather than for user. + + + Context is %NULL. Should not be %NULL for normal operation. + + + #xmlDocPtr is %NULL. + + + Sets if xml check fails. Xml file structure doesn't match with DTD +file + + + Sets if the used schema is invalid. + + + Sets if server operation is %NULL. + + + Sets if xml file is not readable + + + Sets if an error with context during parsing an xml file + + + Sets if parsing reports an error + + + If set, error with parse chunk algorithm. + + + Connection is not open. + + + + + + + + + + New instance of #GdaDbColumn, to free with g_object_unref () once not needed anymore + + + + + + + + + + Get value for autoinc key + + + %TRUE if column should be auto-incremented, %FALSE otherwise. + + + + + a #GdaDbColumn object + + + + + + Returns value of the check field. + + + Column check string + + + + + a #GdaDbColumn instance + + + + + + Get value for column comment. + + + Column comment as a string. +%NULL is returned if comment is not set. + + + + + a #GdaDbColumn object + + + + + + Returns column type as a string derivied from #GType + + + column type as a string or %NULL + + + + + a #GdaDbColumn object + + + + + + Returns default value for the column. Can be %NULL if the default value hasn't been set. + + + Default value for the column as a string. + + + + + a #GdaDbColumn instance + + + + + + Return of column type as #GType + + + + + + + a #GdaDbColumn object + + + + + + Returns name of the column + + + Column name as a string or %NULL. + + + + + a #GdaDbColumn instance + + + + + + Specify if the column's value can be NULL. + + + %TRUE if value can be %NULL, %FALSE otherwise. + + + + + a @GdaDbColumn object + + + + + + Returns a primary key flag + + + %TRUE if the column is primary key, %FALSE otherwise + + + + + a #GdaDbColumn object + + + + + + Scale is used for float number representation to specify a number of decimal digits. +This value is ignore for column types except float or double. + + + Current scale value + + + + + a #GdaDbColumn object + + + + + + + + Current value for column size. + + + + + a #GdaDbColumn instance + + + + + + Get value for unique key + + + %TRUE if column should have a unique value, %FALSE otherwise. + + + + + a #GdaDbColumn object + + + + + + Populate @op with information stored in @self. This method is used to +prepare @op for %GDA_SERVER_OPERATION_ADD_COLUMN operation. + + + %TRUE if success, %FALSE otherwise. + + + + + a #GdaDbColumn instance + + + + #GdaServerOperation to add information + + + + + + This method populate @op with information stored in @self. + + + %TRUE if successful, %FALSE otherwise. + + + + + a #GdaDbColumn instance + + + + a #GdaServerOperation instance to update for TABLE_CREATE operation + + + + Order number for the column + + + + + + Set value for auto-incremented key. + + + + + + + a #GdaDbColumn object + + + + value to set + + + + + + Sets check string to the column. + + + + + + + a #GdaDbColumn instance + + + + value to set + + + + + + Set value for column comment. + + + + + + + a #GdaDbColumn object + + + + comment to set + + + + + + + + + + + + a #GdaDbColumn instance + + + + default value to set for column as a string + + + + + + Set column name. + + + + + + + a #GdaDbColumn object + + + + name as a string + + + + + + + + + + + + a GdaDbColumn object + + + + value to set for nnul +If @nnul is %TRUE the column will be marked with NON NULL flag + + + + + + If @pkey is %TRUE, the given column will be marked with PRIMERY KEY flag + + + + + + + a #GdaDbColumn object + + + + value to set + + + + + + Scale is used for float number representation to specify a number of decimal digits. +This value is ignore for column types except float or double. + + + + + + + a #GdaDbColumn + + + + scale value to set + + + + + + Set value for column size. This is relevant only for string column type. + + + + + + + a #GdaDbColumn instance + + + + value to set + + + + + + Set type of the column as a #GType. For numeric type, #GDA_TYPE_NUMERIC should be used. Other +types, e.g. %G_TYPE_FLOAT or %G_TYPE_DOUBLE can also be used but precision and scale should not be +set. In this case appropriate types for DB implementation will be used, e.g. float4. + + + + + + + a #GdaDbColumn instance + + + + #GType for column + + + + + + Set value for unique key. + + + + + + + a #GdaDbColumn object + + + + value to set + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Values used to describe the source of the error. + + + Set if wrong column type was given in the xml file. + + + Wrong operation requested + + + + + + + Create a new #GdaDbFkey object. + + + + + + + + + A const #GList of strings where each string +corresponds to a foreign key field or %NULL. + + + + + + + a #GdaDbFkey object + + + + + + + + ON DELETE action as a string. If the action is not set then the string corresponding to +NO_ACTION is returned. + + + + + An object #GdaDbFkey + + + + + + The default value is %NO_ACTION + + + ON DELETE action as a #GdaDbFkeyReferenceAction. + + + + + a #GdaDbFkey object + + + + + + + + ON_UPDATE action as a string. Never %NULL + + + + + a #GdaDbFkey instance + + + + + + + + ON_UPDATE action as a #GdaDbFkeyReferenceAction + + + + + a #GdaDbFkey instance + + + + + + + + A #GList of strings where each string corresponds +to a foreign key reference field or %NULL. + + + + + + + a #GdaDbFkey object + + + + + + + + Returns reference table name as a string or %NULL if table name +hasn't been set. + + + + + a #GdaDbFkey object + + + + + + Prepare @op object for execution by populating with information stored in @self. + + + %TRUE if no error or %FALSE otherwise. + + + + + a #GdaDbFkey instance + + + + a #GdaServerOperation to populate + + + + Order number + + + + + + All arguments should be valid strings. + + + + + + + An object #GdaDbFkey + + + + Field name as a string + + + + A reference field name as a string + + + + + + Set action for ON_DELETE + + + + + + + An object #GdaDbFkey + + + + #GdaDbFkeyReferenceAction action to set + + + + + + Set action for ON_UPDATE + + + + + + + An object #GdaDbFkey + + + + #GdaDbFkeyReferenceAction action to set + + + + + + Set reference table + + + + + + + #GdaDbFkey object + + + + reference table name + + + + + + + + + + + + + + + + Specify numeric value for the actions, e.g. "ON DELETE" and "ON UPDATE" + + + Action is not specified. + + + Action value is set to %NULL + + + Value is set to "RESTRICT" + + + Value is set to default behavior + + + Value is set to cascade + + + + + + + + + + + + + + + + + + Append to index filed to the current index instance, The @self object will recieve full +ownership of the field. After this call, the reference count for @field will be increased and +the instance of @fiels must be destroyed by calling g_object_unref() + + + + + + + an instance of #GdaDbIndex + + + + a field to set + + + + + + This function is thread safe, that is, @cnc will be locked. + + + A list of #GdaDbIndexField + + + + + + + an instance of #GdaDbIndex + + + + + + + + state for UNIQUE. This method will abort if @self is %NULL + + + + + instance os #GdaDbIndex to use + + + + + + + + + + + + instance of #GdaDbIndex + + + + Name of the column where field should be removed. + + + + + + If @val is %TRUE a "UNIQUE" will be added to the INDEX CREATE command, e.g. +CREATE UNIQUE INDEX ... + + + + + + + #GdaDbIndex instance + + + + if set to %TRUE UNIQUE index type will be used. + + + + + + + + + + + + + + + + + + + + + + + + + + + + Create a new instance of #GdaDbIndexField + + + A new instance of #GdaDbIndexField + + + + + + + Collate value + + + + + instance of #GdaDbIndexField + + + + + + Returns an active column that was asigned to #GdaDbIndexField instance + + + A #GdaDbColumn where index should be added + + + + + a #GdaDbIndexField instance + + + + + + + + sort order as a #GdaDbIndexSortOrder object + + + + + object to use + + + + + + + + SORT ORDER string or %NULL + + + + + an instance of #GdaDbIndexField + + + + + + Unfortunately, collate can vary from provider to provider. This method accepts collate name as a +string but user should provide valid values. For instance, SQLite3 accepts only "BINARY", +"NOCASE", and "RTRIM" values. PostgreSQL, on the other hand expects a name of a callable object, +e.g. function. + + + + + + + instance of #GdaDbIndexField + + + + collate to set + + + + + + Only full name will be extracted from @column. The @column instance should be freed using +g_object_unref(). The instance @self take a copy of the @column object by increasing its +referecne count. + + + + + + + an instance of #GdaDbIndexField + + + + column to add index to + + + + + + + + + + + + object to use + + + + sort order to set + + + + + + + + + + + + + + + + Enum values to specify the sorting + + + ascending sorting + + + descending sorting + + + + + + + + + + New instance of #GdaDbTable, to free with g_object_unref () once not needed anymore + + + + + + + + + + Append @column to the internal list of columns + + + + + + + a #GdaDbTable instance + + + + column to add + + + + + + Adds global table constraint. It will be added to the sql string by the provider implementation +if it supports it. Usually, table constraint is very complex and the current method just append +a list of constraints to the sql string. + + + + + + + a #GdaDbTable instance + + + + a constraint string to append + + + + + + Append @fkey to the internal list of columns + + + + + + + a #GdaDbTable instance + + + + fkry to add + + + + + + Use this method to obtain internal list of all columns. The internal list +should not be freed. + + + A list of #GdaDbColumn objects or %NULL +if the internal list is not set or if %NULL is passed. + + + + + + + an #GdaDbTable object + + + + + + Use this method to obtain internal list of all fkeys. The internal list +should not be freed. + + + A list of #GdaDbFkey objects or %NULL if +the internal list is not set or %NULL is passed + + + + + + + A #GdaDbTable object + + + + + + + + + + + + + + + + + This method returns %TRUE if at least one column is added to the table. It ruturns %FALSE if the +table has no columns. + + + %TRUE or %FALSE + + + + + a #GdaDbTable instance + + + + + + Populate @op with information stored in @self. This method sets @op to execute CREATE_TABLE +operation. + + + %TRUE if no error occured and %FALSE otherwise. + + + + + a #GdaDbTable instance + + + + an instance of #GdaServerOperation to populate. + + + + Set it to TRUE if "IF NOT EXISTS" should be added + + + + + + Set if the table should be temporary or not. %FALSE is set by default. + + + + + + + a #GdaDbTable object + + + + Set if the table should be temporary + + + + + + With this method object @obj in the database available through @cnc will be updated using +ADD_COLUMN operation with information stored in @self. This method is designed for internal use +only and should not be used for the new code. It will be obsolete. + + + %TRUE if no error and %FALSE otherwise + + + + + a #GdaDbTable instance + + + + The corresponding meta object to take data from + + + + opened connection + + + + + + + + + + + + + + + + + + + + + + + + Table doesn't contain columns + + + Closed connection was passed as parameter + + + Error related to #GdaServerOperation + + + + + + + + + + A new instance of #GdaDbView. + + + + + + + view definition string + + + + + a #GdaDbView object + + + + + + + + %TRUE if th view should be created with "IF NOT EXISTS" key, %FALSE +otherwise + + + + + a #GdaDbView object + + + + + + + + %TRUE if the view is temporary, %FALSE otherwise + + + + + a #GdaDbView object + + + + + + + + %TRUE if the current view should replace the existing one in the +database, %FALSE otherwise. + + + + + a #GdaDbView object + + + + + + Populate @op with information needed to perform CREATE_VIEW operation. This method was desgned +for internal use and will be obsolete in the future. Do not use it for the new code. + + + %TRUE if succeeded and %FALSE otherwise. + + + + + a #GdaDbView instance + + + + #GdaServerOperation instance to populate + + + + + + + + + + + + a #GdaDbView object + + + + view definition string to set. Should be valid SQL string + + + + + + + + + + + + a #GdaDbView object + + + + a value to set + + + + + + + + + + + + a #GdaDbView object + + + + value to set + + + + + + + + + + + + a #GdaDbView object + + + + a value to set + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + This method executes CREATE operation. That is, #GdaDbTable, #GdaDbIndex, and #GdaDbView +implement corresponding CREATE TABLE | CREATE INDEX | CREATE VIEW operations. #GdaDbColumn +implements ADD COLUMN operation as part of ALTER TABLE operation. + + + + + + + Instance of #GdaDdlModifiable + + + + Opened connection + + + + Additional information provided by the user + + + + + + Execute corresponding DROP operation + + + + + + + Instance of #GdaDdlModifiable + + + + Opened connection + + + + Additional information provided by the user + + + + + + Execute corresponding RENAME operation. A lot of RENAME operations are not implemented by +SQLite3 provider. In this case, the SQL object must be deleted and a new one should be created. + + + + + + + Instance of #GdaDdlModifiable + + + + Opened connection + + + + Additional information provided by the user + + + + + + This method executes CREATE operation. That is, #GdaDbTable, #GdaDbIndex, and #GdaDbView +implement corresponding CREATE TABLE | CREATE INDEX | CREATE VIEW operations. #GdaDbColumn +implements ADD COLUMN operation as part of ALTER TABLE operation. + + + + + + + Instance of #GdaDdlModifiable + + + + Opened connection + + + + Additional information provided by the user + + + + + + Execute corresponding DROP operation + + + + + + + Instance of #GdaDdlModifiable + + + + Opened connection + + + + Additional information provided by the user + + + + + + Execute corresponding RENAME operation. A lot of RENAME operations are not implemented by +SQLite3 provider. In this case, the SQL object must be deleted and a new one should be created. + + + + + + + Instance of #GdaDdlModifiable + + + + Opened connection + + + + Additional information provided by the user + + + + + + + + + + + + + + + + + + + + + + + + + + + + Instance of #GdaDdlModifiable + + + + Opened connection + + + + Additional information provided by the user + + + + + + + + + + + + + + Instance of #GdaDdlModifiable + + + + Opened connection + + + + Additional information provided by the user + + + + + + + + + + + + + + Instance of #GdaDdlModifiable + + + + Opened connection + + + + Additional information provided by the user + + + + + + + + + Escapes @string to make it understandable by a DBMS. The escape method is very common and replaces any +occurrence of "'" with "''" and "\" with "\\" + + + a new string + + + + + string to escape + + + + + + Do the reverse of gda_default_escape_string(): transforms any "''" into "'", any +"\\" into "\" and any "\'" into "'". + + + a new unescaped string, or %NULL in an error was found in @string + + + + + string to unescape + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + This structure defines the properties of a named data source (DSN). + + + the (unique) name of the DSN (plain text, not RFC 1738 encoded) + + + + the ID of the database provider to be used (plain text, not RFC 1738 encoded) + + + + a descriptive string (plain text, not RFC 1738 encoded), can be %NULL. + + + + the connection string, a semi-colon separated &lt;key>=&lt;value&gt; list where &lt;key&gt; and &lt;value&gt; are RFC 1738 encoded + + + + the authentication string, a semi-colon separated &lt;key>=&lt;value&gt; list where &lt;key&gt; and &lt;value&gt; are RFC 1738 encoded. Can be %NULL. + + + + %TRUE if the DSN is a system wide defined data source + + + + + + + + + + + + + + + + Creates a new empty #GdaDsnInfo struct. + + + a new #GdaDsnInfo struct. + + + + + Copy constructor. + + + a new #GdaDsnInfo + + + + + a #GdaDsnInfo to copy from + + + + + + Compares @dsn1 and @dsn2. + +If both @dsn1 and @dsn2 are %NULL, then the function returns %TRUE. +If only one of @dsn1 or @dsn2 is %NULL, then the function return %FALSE. + + + %TRUE if they are equal. + + + + + a #GdaDsnInfo + + + + a #GdaDsnInfo + + + + + + Frees any resources taken by @dsn struct. If @dsn is %NULL, then nothing happens. + + + + + + + a #GdaDsnInfo struct to free + + + + + + + + + + + + + + + a new #GdaGeometricPoint + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Creates a data handler for binary values + + + the new object + + + + + + + + + + + + + + + Creates a data handler for booleans + + + the new object + + + + + + + + + + + + + + + Creates a data handler for numerical values + + + the new object + + + + + + + + + + + + + + + Creates a data handler for strings + + + the new object + + + + + Creates a data handler for strings, which will use some specific methods implemented +by the @prov object (possibly also @cnc). + + + the new object + + + + + a #GdaServerProvider object + + + + a #GdaConnection object, or %NULL + + + + + + + + + + + + + + + + Creates a data handler for strings, which will use some specific methods implemented +by the provider object associated with @cnc. + + + the new object + + + + + a #GdaConnection object + + + + + + Creates a data handler for large strings + + + the new object + + + + + + + + + + + + + + + + + + Creates a data handler for time values + + + the new object + + + + + Creates a data handler for time values, but using the default C locale +instead of the current user locale. + + + the new object + + + + + Get a string representing the locale-dependent way to enter a date/time/datetime, using +a syntax suitable for the #GdauiFormatEntry widget + + + a new string + + + + + a #GdaHandlerTime object + + + + the type of data being handled + + + + + + Get a string giving the user a hint about the locale-dependent requested format. + + + a new string + + + + + a #GdaHandlerTime object + + + + the type of data being handled + + + + + + + + a new string representing @value without taking the current +locale into account (i.e. in the "C" locale) + + + + + a #GdaHandlerTime object + + + + a #GValue value + + + + + + Specifies the SQL output style of the @dh data handler. The general format is "FIRSTsSECsTHIRD" +where FIRST, SEC and THIRD are specified by @first, @sec and @trird and 's' is the separator, +specified by @separator. + +The default implementation is @first=G_DATE_MONTH, @sec=G_DATE_DAY and @third=G_DATE_YEAR +(the year is rendered on 4 digits) and the separator is '-' + + + + + + + a #GdaHandlerTime object + + + + what comes first in the date representation + + + + what comes second in the date representation + + + + what comes third in the date representation + + + + separator character used between year, month and day + + + + TRUE if year part of date must be rendered on 2 digits + + + + + + Specifies the human readable output style of the @dh data handler. +The general format is "FIRSTsSECsTHIRD" +where FIRST, SEC and THIRD are specified by @first, @sec and @trird and 's' is the separator, +specified by @separator. + +The default implementation depends on the current locale, except if @dh was created +using gda_handler_time_new_no_locale(). + + + + + + + a #GdaHandlerTime object + + + + what comes first in the date representation + + + + what comes second in the date representation + + + + what comes third in the date representation + + + + separator character used between year, month and day + + + + TRUE if year part of date must be rendered on 2 digits + + + + + + + + + + + + + + + + Creates a data handler for Gda types + + + the new object + + + + + + + + + + + + + + + Creates a new holder of type @type + + + a new #GdaHolder object + + + + + the #GType requested + + + + an identifiation + + + + + + Creates a new #GdaHolder object with an ID set to @id, of type @type, +and containing the value passed as the last argument. + +Note that this function is a utility function and that only a limited set of types are supported. Trying +to use an unsupported type will result in a warning, and the returned value holder holding a safe default +value. + + + a new #GdaHolder object + + + + + a valid GLib type + + + + the id of the holder to create, or %NULL + + + + value to set + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Copy constructor. + +Note1: if @orig is set with a static value (see gda_holder_take_static_value()) +its copy will have a fresh new allocated GValue, so that user should free it when done. + + + a new #GdaHolder object + + + + + a #GdaHolder object to copy + + + + + + Forces a holder to be invalid; to set it valid again, a new value must be assigned +to it using gda_holder_set_value() or gda_holder_take_value(). + +@holder's value is set to %NULL. + + + + + + + a #GdaHolder object + + + + + + Forces a holder to be invalid; to set it valid again, a new value must be assigned +to it using gda_holder_set_value() or gda_holder_take_value(). + +@holder's value is set to %NULL. + + + + + + + a #GdaHolder object + + + + a #GError explaining why @holder is declared invalid, or %NULL + + + + + + Get an "encoded" version of @holder's name. The "encoding" consists in replacing non +alphanumeric character with the string "__gdaXX" where XX is the hex. representation +of the non alphanumeric char. + +This method is just a wrapper around the gda_text_to_alphanum() function. + + + a new string + + + + + a #GdaHolder object + + + + + + Get the holder which makes @holder change its value when the holder's value is changed. + + + the #GdaHolder or %NULL + + + + + a #GdaHolder + + + + + + Get the default value held into the holder. WARNING: the default value does not need to be of +the same type as the one required by @holder. + + + the default value + + + + + a #GdaHolder object + + + + + + Get @holder's type + + + the data type + + + + + a #GdaHolder object + + + + + + Get the ID of @holder. The ID can be set using @holder's "id" property + + + the ID (don't modify the string). + + + + + a #GdaHolder object + + + + + + Get wether the holder can be NULL or not + + + TRUE if the holder cannot be NULL + + + + + a #GdaHolder object + + + + + + If gda_holder_set_source_model() has been used to provide a hint that @holder's value +should be among the values contained in a column of a data model, then this method +returns which data model, and if @col is not %NULL, then it is set to the restricting column +as well. + +Otherwise, this method returns %NULL, and if @col is not %NULL, then it is set to 0. + + + a pointer to a #GdaDataModel, or %NULL + + + + + a #GdaHolder + + + + a place to store the column in the model sourcing the holder, or %NULL + + + + + + Get the value held into the holder. If @holder is set to use its default value +and that default value is not of the same type as @holder, then %NULL is returned. + +If @holder is set to NULL, then the returned value is a #GDA_TYPE_NULL GValue. + +If @holder is invalid, then the returned value is %NULL. + + + the value, or %NULL + + + + + a #GdaHolder object + + + + + + Same functionality as gda_holder_get_value() except that it returns the value as a string +(the conversion is done using @dh if not %NULL, or the default data handler otherwise). + + + the value, or %NULL + + + + + a #GdaHolder object + + + + a #GdaDataHandler to use, or %NULL + + + + + + Get the validity of @holder (that is, of the value held by @holder) + + + TRUE if @holder's value can safely be used + + + + + a #GdaHolder object + + + + + + Get the validity of @holder (that is, of the value held by @holder) + + + TRUE if @holder's value can safely be used + + + + + a #GdaHolder object + + + + + + Sets @holder to change when @bind_to changes (and does not make @bind_to change when @holder changes). +For the operation to succeed, the GType of @holder and @bind_to must be the same, with the exception that +any of them can have a %GDA_TYPE_NULL type (in this situation, the GType of the two #GdaHolder objects +involved is set to match the other when any of them sets its type to something different than GDA_TYPE_NULL). + +If @bind_to is %NULL, then @holder will not be bound anymore. + + + TRUE if no error occurred + + + + + a #GdaHolder + + + + a #GdaHolder or %NULL + + + + + + Sets the default value within the holder. If @value is %NULL then @holder won't have a +default value anymore. To set a default value to %NULL, then pass a #GValue created using +gda_value_new_null(). + +NOTE: the default value does not need to be of the same type as the one required by @holder. + + + + + + + a #GdaHolder object + + + + a value to set the holder's default value, or %NULL + + + + + + Sets if the holder can have a NULL value. If @not_null is TRUE, then that won't be allowed + + + + + + + a #GdaHolder object + + + + TRUE if @holder should not accept %NULL values + + + + + + Sets an hint that @holder's values should be restricted among the values +contained in the @col column of the @model data model. Note that this is just a hint, +meaning this policy is not enforced by @holder's implementation. + +If @model is %NULL, then the effect is to cancel ant previous call to gda_holder_set_source_model() +where @model was not %NULL. + + + TRUE if no error occurred + + + + + a #GdaHolder object + + + + a #GdaDataModel object or %NULL + + + + the reference column in @model + + + + + + Sets the value within the holder. If @holder is an alias for another +holder, then the value is also set for that other holder. + +On success, the action of any call to gda_holder_force_invalid() is cancelled +as soon as this method is called (even if @holder's value does not actually change) + +If the value is not different from the one already contained within @holder, +then @holder is not changed and no signal is emitted. + +Note1: the @value argument is treated the same way if it is %NULL or if it is a #GDA_TYPE_NULL value + +Note2: if @holder can't accept the @value value, then this method returns FALSE, and @holder will be left +in an invalid state. + +Note3: before the change is accepted by @holder, the "validate-change" signal will be emitted (the value +of which can prevent the change from happening) which can be connected to to have a greater control +of which values @holder can have, or implement some business rules. + + + TRUE if value has been set + + + + + a #GdaHolder object + + + + a value to set the holder to, or %NULL + + + + + + Same functionality as gda_holder_set_value() except that it uses a string representation +of the value to set, which will be converted into a GValue first (using default data handler if +@dh is %NULL). + +Note1: if @value is %NULL or is the "NULL" string, then @holder's value is set to %NULL. +Note2: if @holder can't accept the @value value, then this method returns FALSE, and @holder will be left +in an invalid state. + + + TRUE if value has been set + + + + + a #GdaHolder object + + + + a #GdaDataHandler to use, or %NULL + + + + a value to set the holder to, as a string + + + + + + Set @holder's value to its default value. + + + TRUE if @holder has got a default value + + + + + a #GdaHolder object + + + + + + Sets the const value within the holder. If @holder is an alias for another +holder, then the value is also set for that other holder. + +The value will not be freed, and user should take care of it, either for its +freeing or for its correct value at the moment of query. + +If the value is not different from the one already contained within @holder, +then @holder is not changed and no signal is emitted. + +Note1: if @holder can't accept the @value value, then this method returns NULL, and @holder will be left +in an invalid state. + +Note2: before the change is accepted by @holder, the "validate-change" signal will be emitted (the value +of which can prevent the change from happening) which can be connected to to have a greater control +of which values @holder can have, or implement some business rules. + + + NULL if an error occurred or if the previous GValue was NULL itself. It returns +the static GValue user set previously, so that he can free it. + + + + + a #GdaHolder object + + + + a const value to set the holder to + + + + a boolean set with TRUE if the value changes, FALSE elsewhere. + + + + + + Sets the value within the holder. If @holder is an alias for another +holder, then the value is also set for that other holder. + +On success, the action of any call to gda_holder_force_invalid() is cancelled +as soon as this method is called (even if @holder's value does not actually change). + +If the value is not different from the one already contained within @holder, +then @holder is not changed and no signal is emitted. + +Note1: if @holder can't accept the @value value, then this method returns FALSE, and @holder will be left +in an invalid state. + +Note2: before the change is accepted by @holder, the "validate-change" signal will be emitted (the value +of which can prevent the change from happening) which can be connected to to have a greater control +of which values @holder can have, or implement some business rules. + +Note3: if user previously set this holder with gda_holder_take_static_value () the GValue +stored internally will be forgiven and replaced by the @value. User should then +take care of the 'old' static GValue. + +Note4: in any case, the caller should not use @value anymore after this function returns because it may +have been freed. If necessary, use gda_holder_get_value() to get the real value. + + + TRUE if value has been set + + + + + a #GdaHolder object + + + + a value to set the holder to + + + + + + Tells if @holder's current value is the default one. + + + TRUE if @holder @holder's current value is the default one + + + + + a #GdaHolder object + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Defines if the "validate-change" signal gets emitted when +the holder's value changes. + + + + + + + Gets emitted when @holder's value has changed + + + + + + Gets emitted when the data model in which @holder's values should be has changed + + + + + + Gets emitted when @holder is set to its default value + + + + + + Gets emitted when @holder is going to change its value. One can connect to +this signal to control which values @holder can have (for example to implement some business rules) + + NULL if @holder is allowed to change its value to @new_value, or a #GError +otherwise. + + + + + the proposed new value for @holder + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Locks @lockable. If it is already locked by another thread, the current thread will block until it is unlocked +by the other thread. + +Note: unlike g_mutex_lock(), this method recursive, which means a thread can lock @lockable several times +(and has to unlock it as many times to actually unlock it). + + + + + + + a #GdaLockable object. + + + + + + Tries to lock @lockable. If it is already locked by another thread, then it immediately returns FALSE, otherwise +it locks @lockable. + +Note: unlike g_mutex_lock(), this method recursive, which means a thread can lock @lockable several times +(and has to unlock it as many times to actually unlock it). + + + TRUE if the object has successfully been locked. + + + + + a #GdaLockable object. + + + + + + Unlocks @lockable. This method should not be called if the current does not already holds a lock on @lockable (having +used gda_lockable_lock() or gda_lockable_trylock()). + + + + + + + a #GdaLockable object. + + + + + + Locks @lockable. If it is already locked by another thread, the current thread will block until it is unlocked +by the other thread. + +Note: unlike g_mutex_lock(), this method recursive, which means a thread can lock @lockable several times +(and has to unlock it as many times to actually unlock it). + + + + + + + a #GdaLockable object. + + + + + + Tries to lock @lockable. If it is already locked by another thread, then it immediately returns FALSE, otherwise +it locks @lockable. + +Note: unlike g_mutex_lock(), this method recursive, which means a thread can lock @lockable several times +(and has to unlock it as many times to actually unlock it). + + + TRUE if the object has successfully been locked. + + + + + a #GdaLockable object. + + + + + + Unlocks @lockable. This method should not be called if the current does not already holds a lock on @lockable (having +used gda_lockable_lock() or gda_lockable_trylock()). + + + + + + + a #GdaLockable object. + + + + + + + + + + + + + + + + + + + a #GdaLockable object. + + + + + + + + + + TRUE if the object has successfully been locked. + + + + + a #GdaLockable object. + + + + + + + + + + + + + + a #GdaLockable object. + + + + + + + + Casts @dbo to a #GdaMetaDbObject, no check is made on the validity of @dbo + + + + a pointer + + + + + Casts @dbo to a #GdaMetaTable, no check is made on the validity of @dbo + + + + + + + + Casts @col to a #GdaMetaTableColumn, no check is made + + + + a pointer + + + + + Casts @fk to a #GdaMetaTableForeignKey (no check is actuelly being done on @fk's validity) + + + + a pointer + + + + + Tells if @fk is an actual foreign key defined in the database's schema, or if it is an indication which +has been added to help Libgda understand the database schema. + + + + a pointer to a #GdaMetaTableForeignKey + + + + + Tells the actual policy implemented by @fk when used in the context of a DELETE. + + + + a pointer to a #GdaMetaTableForeignKey + + + + + Tells the actual policy implemented by @fk when used in the context of an UPDATE. + + + + a pointer to a #GdaMetaTableForeignKey + + + + + Casts @dbo to a #GdaMetaView, no check is made on the validity of @dbo + + + + + + + + The <structname>GdaMetaContext</structname> represents a meta data modification +context: the <emphasis>how</emphasis> when used with gda_meta_store_modify_with_context(), +and the <emphasis>what</emphasis> when used with gda_connection_update_meta_store(). + +To create a new #GdaMetaContext use #gda_meta_context_new. + +To add a new column/value pair use #gda_meta_context_add_column. + +To free a #GdaMetaContext, created by #gda_meta_context_new, use #gda_attributes_manager_free. + +Since 5.2, you must consider this struct as opaque. Any access to its internal must use public API. +Don't try to use #gda_meta_context_free on a struct that was created manually. + + + the name of the table <emphasis>in the GdaMetaStore's internal database</emphasis> + + + + the size of the @column_names and @column_values arrays + + + + an array of column names (columns of the @table_name table) + + + + + + an array of values, one for each column named in @column_names + + + + + + A #GHashTable storing columns' name as key and #GValue as column's +value. + + + + + + + Creates a new #GdaMetaContext struct with a #GHashTable to store column/value pairs. + + + a new #GdaMetaContext struct with a new created hash to +store column name/value pairs. + + + + + Copy constructor. + + + a new #GdaMetaContext + + + + + a #GdaMetaContext + + + + + + Frees any resources taken by @ctx struct. If @ctx is %NULL, then nothing happens. + + + + + + + a #GdaMetaContext struct to free + + + + + + + + the number of columns in the context + + + + + a #GdaMetaContext + + + + + + Get table's name to used in the context. + + + A string with the table's name used in the context. + + + + + a #GdaMetaContext struct to get table's name from + + + + + + Sets a new column/value pair to the given context @ctx. Column, must be a column in the given table's +name setted by #gda_meta_context_set_table () (a table in the <link linkend="information_schema">database +schema</link>). If the given @column already exists it's value is overwrited. + +Column's name and value is copied and destroyed when #gda_meta_context_free is called. + + + + + + + a #GdaMetaContext struct to add column/value pais to + + + + the column's name + + + + the column's value + + + + a #GdaConnection to be used when identifier are normalized, or NULL + + + + + + Set columns to use in the context. The #GHashTable use column's name as key and a #GValue as value, +to represent its value. + +@columns incements its reference counting. Is recommended to use #gda_meta_context_free in order to free them. + + + + + + + a #GdaMetaContext struct to set colums to + + + + a #GHashTable with the table's columns' name and their values +to use in context. + + + + + + + a #GdaConnection to used to normalize identifiers quoting, or NULL + + + + + + Set table's name to use in the context. The table is one of <link linkend="information_schema">database +schema</link> used to store meta information about the database. Use "_tables" to update meta information +about database's tables. + + + + + + + a #GdaMetaContext struct to set table to + + + + a string with the table's name to use in context + + + + + + Creates a string representation of given context. + + + a new string with the representation of the context + + + + + a #GdaMetaContext + + + + + + + Struture to hold information about each database object (tables, views, ...), +its contents must not be modified. + +Note: @obj_catalog, @obj_schema, @obj_name, @obj_short_name and @obj_full_name respect the +<link linkend="information_schema:sql_identifiers">SQL identifiers</link> convention used in +#GdaMetaStore objects. Before using these SQL identifiers, you should check the +gda_sql_identifier_quote() to know if is it is necessary to surround by double quotes +before using in an SQL statement. + + + + + + + + + + + + the type of object (table, view) + + + + set to %TRUE if the information in this #GdaMetaDbObject may be outdated because the #GdaMetaStore has been updated + + + + the catalog the object is in + + + + the schema the object is in + + + + the object's name + + + + the shortest way to name the object + + + + the full name of the object (in the &lt;schema&gt;.&lt;nameagt; notation + + + + object's owner + + + + list of #GdaMetaDbObject pointers on which this object depends (through foreign keys + or tables used for views) + + + + + + + + + + + + + + + + + + + Type of database object which can be handled as a #GdaMetaDbObject + + + unknown type + + + represents a table + + + represents a view + + + + Defines the filtering policy of a foreign key when invoked on an UPDATE +or DELETE operation. + + + unspecified policy + + + not enforced policy + + + return an error, no action taken + + + same as @GDA_META_FOREIGN_KEY_NO_ACTION, not deferrable + + + policy is to delete any rows referencing the deleted row, or update the value of the referencing column to the new value of the referenced column, respectively + + + policy is to set the referencing column to NULL + + + policy is to set the referencing column to its default value + + + + + + + + + Types of sorting + + + sort alphabetically + + + sort by dependencies + + + + + + Create a new #GdaMetaStore object. + + + the newly created object, or %NULL if an error occurred + + + + + a connection string, or %NULL for an in-memory internal database + + + + + + Create a new #GdaMetaStore object using @file_name as its internal +database + + + the newly created object, or %NULL if an error occurred + + + + + a file name + + + + + + + + + + + Use this method to get a correctly quoted (if necessary) SQL identifier which can be used +to retrieve or filter information in a #GdaMetaStore which stores meta data about @cnc. + +The returned SQL identifier can be used in conjunction with gda_connection_update_meta_store(), +gda_connection_get_meta_store_data(), gda_connection_get_meta_store_data_v() and +gda_meta_store_extract(). + + + a new string, to free with g_free() once not needed anymore + + + + + an SQL identifier + + + + a #GdaConnection + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Creates a new #GdaDataModelArray data model which can be used, after being correctly filled, +with the gda_meta_store_modify*() methods.* + +To be used by provider's implementation + + + a new #GdaDataModel + + + + + a #GdaMetaStore object + + + + the name of a table present in @store + + + + + + + + a new #GdaMetaStruct using @store + + + + + a #GdaMetaStore + + + + features of new struct + + + + + + Defines a new declared foreign key into @store. If another declared foreign key is already defined +between the two tables and with the same name, then it is first removed. + +This method begins a transaction if possible (ie. none is already started), and if it can't, +then if there is an error, the job may be partially done. + +A check is always performed to make sure all the database objects actually +exist and returns an error if not. The check is performed using @mstruct if it's not %NULL (in +this case only the tables already represented in @mstruct will be considered, in other words: @mstruct +will not be modified), and using an internal #GdaMetaStruct is %NULL. + +The @catalog, @schema, @table, @ref_catalog, @ref_schema and @ref_table must follow the SQL +identifiers naming convention, see the <link linkend="gen:sql_identifiers">SQL identifiers</link> +section. The same convention needs to be respected for the strings in @conames and @ref_colnames. + +If @catalog is not %NULL, then @schema must also be not %NULL (the same restriction applies to +@ref_catalog and @ref_schema). + + + %TRUE if no error occurred + + + + + a #GdaMetaStore + + + + a #GdaMetaStruct, or %NULL + + + + the name of the foreign key to declare + + + + the catalog in which the table (for which the foreign key is for) is, or %NULL + + + + the schema in which the table (for which the foreign key is for) is, or %NULL + + + + the name of the table (for which the foreign key is for) + + + + the catalog in which the referenced table is, or %NULL + + + + the schema in which the referenced table is, or %NULL + + + + the name of the referenced table + + + + the number of columns involved (>0) + + + + an array of column names from the table for which the foreign key is for + + + + + + an array of column names from the referenced table + + + + + + + + Extracts some data stored in @store using a custom SELECT query. If the @select_sql filter involves +SQL identifiers (such as table or column names), then the values should have been adapted using +gda_meta_store_sql_identifier_quote(). + +For more information about +SQL identifiers are represented in @store, see the +<link linkend="information_schema:sql_identifiers">meta data section about SQL identifiers</link>. + + + a new #GdaDataModel, or %NULL if an error occurred + + + + + a #GdaMetaStore object + + + + a SELECT statement + + + + a place to store errors, or %NULL + + + + a list of (variable name (gchar *), GValue *value) terminated with NULL, representing values for all the +variables mentioned in @select_sql. If there is no variable then this part can be omitted. + + + + + + Extracts some data stored in @store using a custom SELECT query. If the @select_sql filter involves +SQL identifiers (such as table or column names), then the values should have been adapted using +gda_meta_store_sql_identifier_quote(). + +For more information about +SQL identifiers are represented in @store, see the +<link linkend="information_schema:sql_identifiers">meta data section about SQL identifiers</link>. + + + a new #GdaDataModel, or %NULL if an error occurred + + + + + a #GdaMetaStore object + + + + a SELECT statement + + + + a hash table with all variables names as keys and GValue* as +value, representing values for all the variables mentioned in @select_sql. If there is no variable then this part can be +omitted. + + + + + + + + + The #GdaMetaStore object maintains a list of (name,value) attributes (attributes names starting with a '_' +character are for internal use only and cannot be altered). This method and the gda_meta_store_set_attribute_value() +method allows the user to add, set or remove attributes specific to their usage. + +This method allows to get the value of a attribute stored in @store. The returned attribute value is +placed at @att_value, the caller is responsible for free that string. + +If there is no attribute named @att_name then @att_value is set to %NULL +and @error will contain the GDA_META_STORE_ATTRIBUTE_NOT_FOUND_ERROR error code, and FALSE is returned. + + + TRUE if no error occurred + + + + + a #GdaMetaStore object + + + + name of the attribute to get + + + + the place to store the attribute value + + + + + + Get a pointer to the #GdaConnection object internally used by @store to store +its contents. + +The returned connection can be used to access some other data than the one managed by @store +itself. The returned object is not owned by the caller (if you need to keep it, then use g_object_ref()). +Do not close the connection. + + + a #GdaConnection, or %NULL + + + + + a #GdaMetaStore object + + + + + + Get @store's internal schema's version + + + the version (incremented each time the schema changes, backward compatible) + + + + + a #GdaMetaStore object + + + + + + Propagates an update to @store, the update's contents is represented by @new_data, this function is +primarily reserved to database providers. + +For example tell @store to update its list of tables, @new_data should contain the same columns as the "_tables" +table of @store, and contain one row per table in the store; there should not be any more argument after the @error +argument. + +Now, to update only one table, the @new_data data model should have one row for the table to update (or no row +at all if the table does not exist anymore), and have values for the primary key of the "_tables" table of +@store, namely "table_catalog", "table_schema" and "table_name". + + + TRUE if no error occurred + + + + + a #GdaMetaStore object + + + + the name of the table to modify within @store + + + + a #GdaDataModel containing the new data to set in @table_name, or %NULL (treated as a data model +with no row at all) + + + + SQL expression (which may contain variables) defining the rows which are being obsoleted by @new_data, or %NULL + + + + a place to store errors, or %NULL + + + + a list of (variable name (gchar *), GValue *value) terminated with NULL, representing values for all the +variables mentioned in @condition. + + + + + + Propagates an update to @store, the update's contents is represented by @new_data, this function is +primarily reserved to database providers. + + + %TRUE if no error occurred + + + + + a #GdaMetaStore object + + + + the name of the table to modify within @store + + + + a #GdaDataModel containing the new data to set in @table_name, or %NULL (treated as a data model +with no row at all) + + + + SQL expression (which may contain variables) defining the rows which are being obsoleted by @new_data, or %NULL + + + + number of values in @value_names and @values + + + + names of values + + + + + + values + + + + + + + + Propagates an update to @store, the update's contents is represented by @new_data, this function is +primarily reserved to database providers. + + + TRUE if no error occurred + + + + + a #GdaMetaStore object + + + + a #GdaMetaContext context describing what to modify in @store + + + + a #GdaDataModel containing the new data to set in @table_name, or %NULL (treated as a data model +with no row at all) + + + + + + The internal database used by @store can be 'augmented' with some user-defined database objects +(such as tables or views). This method allows one to add a new database object. + +If the internal database already contains the object, then: +<itemizedlist> + <listitem><para>if the object is equal to the provided description then TRUE is returned</para></listitem> + <listitem><para>if the object exists but differs from the provided description, then FALSE is returned, + with the GDA_META_STORE_SCHEMA_OBJECT_CONFLICT_ERROR error code</para></listitem> +</itemizedlist> + +The @xml_description defines the table of view's definition, for example: +<programlisting><![CDATA[<table name="mytable"> + <column name="id" pkey="TRUE"/> + <column name="value"/> +</table>]]></programlisting> + +The partial DTD for this XML description of the object to add is the following (the top node must be +a &lt;table&gt; or a &lt;view&gt;): +<programlisting><![CDATA[<!ELEMENT table (column*,check*,fkey*)> +<!ATTLIST table + name NMTOKEN #REQUIRED> + +<!ELEMENT column EMPTY> +<!ATTLIST column + name NMTOKEN #REQUIRED + type CDATA #IMPLIED + pkey (TRUE|FALSE) #IMPLIED + autoinc (TRUE|FALSE) #IMPLIED + nullok (TRUE|FALSE) #IMPLIED> + +<!ELEMENT check (#PCDATA)> + +<!ELEMENT fkey (part+)> +<!ATTLIST fkey + ref_table NMTOKEN #REQUIRED> + +<!ELEMENT part EMPTY> +<!ATTLIST part + column NMTOKEN #IMPLIED + ref_column NMTOKEN #IMPLIED> + +<!ELEMENT view (definition)> +<!ATTLIST view + name NMTOKEN #REQUIRED + descr CDATA #IMPLIED> + +<!ELEMENT definition (#PCDATA)>]]></programlisting> + + + TRUE if the new object has successfully been added + + + + + a #GdaMetaStore object + + + + an XML description of the table or view to add to @store + + + + + + Get an ordered list of the tables @store knows about. The tables are ordered in a way that tables dependencies +are respected: if table B has a foreign key on table A, then table A will be listed before table B in the returned +list. + + + a new list of tables names (as gchar*), the list must be freed when no longer needed, but the strings present in the list must not be modified. + + + + + + + a #GdaMetaStore object + + + + + + Get an ordered list of the tables @store knows about on which the @table_name table depends (recursively). +The tables are ordered in a way that tables dependencies +are respected: if table B has a foreign key on table A, then table A will be listed before table B in the returned +list. + + + a new list of tables names (as gchar*), the list must be freed when no longer needed, but the strings present in the list must not be modified. + + + + + + + a #GdaMetaStore object + + + + the name of the table for which all the dependencies must be listed + + + + + + Creates a new #GdaMetaStruct object representing @store's internal database structure. + + + a new #GdaMetaStruct object, or %NULL if an error occurred + + + + + a #GdaMetaStore object + + + + + + Removes the custom database object named @obj_name. + + + TRUE if the custom object has successfully been removed + + + + + a #GdaMetaStore object + + + + name of the custom object to remove + + + + + + Set the value of the attribute named @att_name to @att_value; see gda_meta_store_get_attribute_value() for +more information. + + + TRUE if no error occurred + + + + + a #GdaMetaStore object + + + + name of the attribute to set + + + + value of the attribute to set, or %NULL to unset the attribute + + + + + + Specifies how @store must handle SQL identifiers it has to store. This method is mainly used by +database providers. + + + + + + + a #GdaMetaStore object + + + + a style + + + + + + Specifies a function which @store will use to determine if a keyword is an SQL reserved +keyword or not. + +This method is mainly used by database providers. + + + + + + + a #GdaMetaStore object + + + + a #GdaSqlReservedKeywordsFunc function, or %NULL + + + + + + Removes a declared foreign key from @store. + +This method begins a transaction if possible (ie. none is already started), and if it can't, then if there +is an error, the job may be partially done. + +A check is always performed to make sure all the database objects actually +exist and returns an error if not. The check is performed using @mstruct if it's not %NULL (in +this case only the tables already represented in @mstruct will be considered, in other words: @mstruct +will not be modified), and using an internal #GdaMetaStruct is %NULL. + +See gda_meta_store_declare_foreign_key() for more information anout the @catalog, @schema, @name, +@ref_catalog, @ref_schema and @ref_name arguments. + + + %TRUE if no error occurred + + + + + a #GdaMetaStore + + + + a #GdaMetaStruct, or %NULL + + + + the name of the foreign key to declare + + + + the catalog in which the table (for which the foreign key is for) is, or %NULL + + + + the schema in which the table (for which the foreign key is for) is, or %NULL + + + + the name of the table (for which the foreign key is for) + + + + the catalog in which the referenced table is, or %NULL + + + + the schema in which the referenced table is, or %NULL + + + + the name of the referenced table + + + + + + + + + + + + + + + + + + + + + This signal is emitted when the @store's contents have changed (the changes are in the @changes list) + + + + + + a list of changes made, as a #GSList of pointers to #GdaMetaStoreChange (which must not be modified) + + + + + + + + This signal is emitted when the @store's contents have been reset completely and when +no detailed changes are available + + + + + + This signal is emitted when the contents of a table should be updated (data to update or insert only; +deleting data is done automatically). This signal is used for internal purposes by the #GdaConnection +object. + + a new #GError error structure if there was an error when processing the +signal, or %NULL if signal propagation should continue + + + + + the suggested update, as a #GdaMetaContext structure + + + + + + + + + Creates a new #GdaMetaStoreChange + + + + + + + + + a new #GdaMetaStoreChange + + + + + a #GdaMetaStoreChange + + + + + + + + + + + + a #GdaMetaStoreChange to be freed + + + + + + + + + + + + + + + + + + + hash table with string key key = ('+' or '-') and a column position in @table (string) starting at 0 and value as #GValue pointer + + + + + + + + a #GdaMetaStoreChange + + + + + + + + a string with the table name + + + + + a #GdaMetaStoreChange + + + + + + + + + + + + + + + + + + + + + + + + + + a #GdaMetaStoreChange + + + + name of the table + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Creates a new #GdaMetaDbObject structure in @mstruct to represent the database object (of type @type) +which can be uniquely identified as @catalog.@schema.@name. + +If @catalog is not %NULL, then @schema should not be %NULL. + +If both @catalog and @schema are %NULL, then the database object will be the one which is +"visible" by default (that is which can be accessed only by its short @name name). + +If @catalog is %NULL and @schema is not %NULL, then the database object will be the one which +can be accessed by its @schema.@name name. + +Important note: @catalog, @schema and @name will be used using the following convention: +<itemizedlist> + <listitem><para>be surrounded by double quotes for a case sensitive search</para></listitem> + <listitem><para>otherwise for case insensitive search</para></listitem> +</itemizedlist> + +For more information, see the <link linkend="information_schema:sql_identifiers"> +meta data section about SQL identifiers</link>. + + + the #GdaMetaDbObject corresponding to the database object if no error occurred, or %NULL + + + + + a #GdaMetaStruct object + + + + the type of object to add (which can be GDA_META_DB_UNKNOWN) + + + + the catalog the object belongs to (as a G_TYPE_STRING GValue), or %NULL + + + + the schema the object belongs to (as a G_TYPE_STRING GValue), or %NULL + + + + the object's name (as a G_TYPE_STRING GValue), not %NULL + + + + + + This method is similar to gda_meta_struct_complement() and gda_meta_struct_complement_default() +but creates #GdaMetaDbObject for all the database object. + +Please refer to gda_meta_struct_complement() form more information. + + + TRUE if no error occurred + + + + + a #GdaMetaStruct object + + + + + + This method is similar to gda_meta_struct_complement() and gda_meta_struct_complement_all() +but creates #GdaMetaDbObject for all the +database object which are usable using only their short name (that is which do not need to be prefixed by +the schema in which they are to be used). + +Please refer to gda_meta_struct_complement() form more information. + + + TRUE if no error occurred + + + + + a #GdaMetaStruct object + + + + + + This method is similar to gda_meta_struct_complement() but creates #GdaMetaDbObject for all the dependencies +of @dbo. + +Please refer to gda_meta_struct_complement() form more information. + + + TRUE if no error occurred + + + + + a #GdaMetaStruct object + + + + a #GdaMetaDbObject part of @mstruct + + + + + + This method is similar to gda_meta_struct_complement() but creates #GdaMetaDbObject for all the +database object which are in the @schema schema (and in the @catalog catalog). +If @catalog is %NULL, then any catalog will be used, and +if @schema is %NULL then any schema will be used (if @schema is %NULL then catalog must also be %NULL). + +Please refer to gda_meta_struct_complement() form more information. + + + TRUE if no error occurred + + + + + a #GdaMetaStruct object + + + + name of a catalog, or %NULL + + + + name of a schema, or %NULL + + + + + + Creates a new graph (in the GraphViz syntax) representation of @mstruct. + + + a new string, or %NULL if an error occurred. + + + + + a #GdaMetaStruct object + + + + informs what kind of information to show in the resulting graph + + + + + + Get a list of all the #GdaMetaDbObject structures representing database objects in @mstruct. Note that +no #GdaMetaDbObject structure must not be modified. + + + a new #GSList list of pointers to +#GdaMetaDbObject structures which must be destroyed after usage using g_slist_free(). The individual +#GdaMetaDbObject must not be modified. + + + + + + + a #GdaMetaStruct object + + + + + + Tries to locate the #GdaMetaDbObject structure representing the database object named after +@catalog, @schema and @name. + +If one or both of @catalog and @schema are %NULL, and more than one database object matches the name, then +the return value is also %NULL. + + + the #GdaMetaDbObject or %NULL if not found + + + + + a #GdaMetaStruct object + + + + the catalog the object belongs to (as a G_TYPE_STRING GValue), or %NULL + + + + the schema the object belongs to (as a G_TYPE_STRING GValue), or %NULL + + + + the object's name (as a G_TYPE_STRING GValue), not %NULL + + + + + + Tries to find the #GdaMetaTableColumn representing the column named @col_name in @table. + + + the #GdaMetaTableColumn or %NULL if not found + + + + + a #GdaMetaStruct object + + + + the #GdaMetaTable structure to find the column for + + + + the name of the column to find (as a G_TYPE_STRING GValue) + + + + + + Loads an XML description into @mstruct. This method is still experimental and no description +the XML file structure is given, and no guarantee that it will remain as it is given. + + + TRUE if no error has occurred + + + + + a #GdaMetaStruct object + + + + the catalog name, or %NULL + + + + the schema name, or %NULL + + + + the specifications as the name of an XML file + + + + + + Reorders the list of database objects within @mstruct in a way specified by @sort_type. + + + TRUE if no error occurred + + + + + a #GdaMetaStruct object + + + + the kind of sorting requested + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Controls which features are computed about database objects. + + + database objects only have their own attributes + + + foreign keys are computed for tables + + + for views, the tables they use are also computed + + + all the features are computed + + + + This structure specifies a #GdaMetaDbObject to represent a table's specific attributes, +its contents must not be modified. + +Note that in some cases, the columns cannot be determined for views, and in this case the +@columns will be %NULL (this can be the case for example with SQLite where a view +uses a function which is not natively provided by SQLite. + + + list of #GdaMetaTableColumn structures, one for each column in the table + + + + + + index of the columns part of the primary key for the table (WARNING: columns numbering + here start at 0) + + + + size of the @pk_cols_array array + + + + list of #GdaMetaTableForeignKey where the referenced table is this table + + + + + + list of #GdaMetaTableForeignKey for this table + + + + + + + + + + + + + + + + + + + This structure represents a table of view's column, its contents must not be modified. + + + the column's name + + + + the column's DBMS's type + + + + the detected column's #GType + + + + tells if the column is part of a primary key + + + + tells if the column can be %NULL + + + + the column's default value, represented as a valid SQL value (surrounded by simple quotes for strings, ...), or %NULL if column has no default value + + + + + + + + + + + + + + + + + + + + + + + This structure represents a foreign key constraint, its contents must not be modified. + + + the #GdaMetaDbObject for which this structure represents a foreign key + + + + the #GdaMetaDbObject which is referenced by the foreign key + + + + the size of the @fk_cols_array, @fk_names_array, @ref_pk_cols_array and @ref_pk_names_array arrays + + + + the columns' indexes in @meta_table which participate in the constraint (WARNING: columns numbering + here start at 1) + + + + the columns' names in @meta_table which participate in the constraint + + + + the columns' indexes in @depend_on which participate in the constraint (WARNING: columns numbering + here start at 1) + + + + the columns' names in @depend_on which participate in the constraint + + + + + + + + + + + + + + + + + + + + + + + + + + + + + This structure specifies a #GdaMetaDbObject to represent a view's specific attributes, +its contents must not be modified. + + + a view is also a table as it has columns + + + + views' definition + + + + tells if the view's contents can be updated + + + + + + + + + + + + + + + + + + + Holds numbers represented as strings. + +This struct must be considered as opaque. Any access to its members must use its +accessors added since version 5.0.2. + + + Creates a new #GdaNumeric with defaults. + + + a new #GdaNumeric. + + + + + Creates a new #GdaNumeric structure from an existing one. + + + a newly allocated #GdaNumeric which contains a copy of information in @boxed. + +Free-function: gda_numeric_free + + + + + source to get a copy from. + + + + + + Deallocates all memory associated to the given @boxed + + + + + + + a #GdaNumeric pointer + + + + + + + + a #gdouble representation of @numeric + + + + + a #GdaNumeric + + + + + + Gets the precision of a #GdaNumeric. + + + an integer with the precision of a #GdaNumeric. + + + + + a #GdaNumeric + + + + + + Get the string representation of @numeric, in the C locale format (dot as a fraction separator). + + + a new string representing the stored valued in @numeric + + + + + a #GdaNumeric + + + + + + Gets the width of a #GdaNumeric. (Not yet implemented). + + + an integer with the width of a #GdaNumeric. (Not jet implemented). + + + + + a #GdaNumeric + + + + + + Sets @numeric using a #gdouble represented by @number. + + + + + + + a #GdaNumeric + + + + a #gdouble + + + + + + Sets @numeric with a number represented by @str, in the C locale format (dot as a fraction separator). + + + + + + + a #GdaNumeric + + + + a string representing a number, in the C locale format + + + + + + Sets the precision of a #GdaNumeric. + + + + + + + a #GdaNumeric + + + + a #glong + + + + + + Sets the width of a #GdaNumeric. (Not yet implemented). + + + + + + + a #GdaNumeric + + + + a #glong + + + + + + + + + Copies @src's data to @dest + + + + + + + a #GdaPStmt object + + + + a #GdaPStmt object + + + + + + Get a pointer to the #GdaStatement which led to the creation of this prepared statement. + +Note: if that statement has been modified since the creation of @pstmt, then this method +will return %NULL + + + the #GdaStatement + + + + + a #GdaPStmt object + + + + + + + + number of columns or -1 if something is wrong + + + + + + + + + + List of parameters' IDs (as gchar *) + + + a list of string with parameters ID's + + + + + + + + + + + + Actual SQL code used for this prepared statement, mem freed by GdaPStmt + + + SQL command used + + + + + + + + + + List of #GdaColumn objects which data models created from this +prepared statement can copy + + + a list of #GdaColumn objects + + + + + + + + + + + + Set column's types for statement. @types will be stolen and should +no be modified anymore. + + + an array of #GType used in the columns + + + + + + + + + + + + Set column's types for statement. @types is stalen and should +no be modified + + + + + + + a #GdaPStmt + + + + number of columns and size of given array + + + + an array of types to use for each column + + + + + + + + Informs @pstmt that it corresponds to the preparation of the @stmt statement + + + + + + + a #GdaPStmt object + + + + a #GdaStatement object, or %NULL + + + + + + List of parameters' IDs (as gchar *), list is stolen + + + + + + + a #GdaPStmt + + + + a list of strings with ID's to set + + + + + + + + Set SQL code used for this prepared statement, mem freed by GdaPStmt + + + + + + + + + + + + + + + Set the list of #GdaColumn objects which data models created from this +prepared statement can copy. The list is stolen, so you should not +free it. + + + + + + + a #GdaPStmt + + + + a list of #GdaColumn + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + This command should be called inmediately called after a INSERT SQL command + + + a #GdaSet with all data of the last inserted row + + + + + a #GdaProvider object + + + + a #GdaConnection to get last inserted from + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + This command should be called inmediately called after a INSERT SQL command + + + a #GdaSet with all data of the last inserted row + + + + + a #GdaProvider object + + + + a #GdaConnection to get last inserted from + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + This structure holds the information associated to a database provider as discovered by Libgda. + + + the unique identifier of the database provider + + + + the complete path to the shared library implementing the database provider + + + + provider's description + + + + a #GdaSet containing all the parameters which can/must be specified when opening a connection or defining a named data source (DSN) + + + + a #GdaSet containing all the authentication parameters + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a #GdaSet with all data of the last inserted row + + + + + a #GdaProvider object + + + + a #GdaConnection to get last inserted from + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SQL is specific for current provider. + + + a new #GdaDataModel with as a result of the query + + + + + a #GdaProviderMeta + + + + a string with the SQL to execute on provider + + + + a #GdaSet with all paramaters to use in query + + + + + + SQL is specific for current provider. + + + a new #GdaDataModel with as a result of the query + + + + + a #GdaProviderMeta + + + + a string with the SQL to execute on provider + + + + + + + + + + + a #GdaConnection used by this object. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Creates a new #GdaQuarkList, which is a set of key->value pairs, +very similar to GLib's GHashTable, but with the only purpose to +make easier the parsing and creation of data source connection +strings. + + + the newly created #GdaQuarkList. + +Free-function: gda_quark_list_free + + + + + Creates a new #GdaQuarkList given a string. + +@string must be a semi-colon separated list of "&lt;key&gt;=&lt;value&gt;" strings (for example +"DB_NAME=notes;USERNAME=alfred"). Each key and value must respect the RFC 1738 recommendations: the +<constant>&lt;&gt;&quot;#%{}|\^~[]&apos;`;/?:@=&amp;</constant> and space characters are replaced by +<constant>&quot;%%ab&quot;</constant> where +<constant>ab</constant> is the hexadecimal number corresponding to the character (for example the +"DB_NAME=notes;USERNAME=al%%20fred" string will specify a username as "al fred"). If this formalism +is not respected, then some unexpected results may occur. + + + the newly created #GdaQuarkList. + +Free-function: gda_quark_list_free + + + + + a string. + + + + + + @string must be a semi-colon separated list of "&lt;key&gt;=&lt;value&gt;" strings (for example +"DB_NAME=notes;USERNAME=alfred"). Each key and value must respect the RFC 1738 recommendations: the +<constant>&lt;&gt;&quot;#%{}|\^~[]&apos;`;/?:@=&amp;</constant> and space characters are replaced by +<constant>&quot;%%ab&quot;</constant> where +<constant>ab</constant> is the hexadecimal number corresponding to the character (for example the +"DB_NAME=notes;USERNAME=al%%20fred" string will specify a username as "al fred"). If this formalism +is not respected, then some unexpected results may occur. + +Some corner cases for any string part (delimited by the semi-colon): +<itemizedlist> + <listitem><para>If it does not respect the "&lt;key&gt;=&lt;value&gt;" format then it will be ignored.</para></listitem> + <listitem><para>Only the 1st equal character is used to separate the key from the value part (which means + any other equal sign will be part of the value)</para></listitem> +</itemizedlist> + + +Adds new key->value pairs from the given @string. If @cleanup is +set to %TRUE, the previous contents will be discarded before adding +the new pairs. + + + + + + + a #GdaQuarkList. + + + + a string. + + + + whether to cleanup the previous content or not. + + + + + + Removes all strings in the given #GdaQuarkList. + + + + + + + a #GdaQuarkList. + + + + + + Creates a new #GdaQuarkList from an existing one. + + + a newly allocated #GdaQuarkList with a copy of the data in @qlist. + + + + + quark_list to get a copy from. + + + + + + Searches for the value identified by @name in the given #GdaQuarkList. For protected values +(authentification data), don't forget to call gda_quark_list_protect_values() when you +don't need them anymore (when needed again, they will be unmangled again). + + + the value associated with the given key if found, or %NULL if not found. + + + + + a #GdaQuarkList. + + + + the name of the value to search for. + + + + + + Calls the given function for each of the key/value pairs in @qlist. The function is passed the key and value +of each pair, and the given user_data parameter. @qlist may not be modified while iterating over it. + + + + + + + a #GdaQuarkList structure. + + + + the function to call for each key/value pair + + + + user data to pass to the function + + + + + + Releases all memory occupied by the given #GdaQuarkList. + + + + + + + a #GdaQuarkList, or %NULL + + + + + + Call this function to get rid of the clear version of all the values stored in @qlist. If @qlist is %NULL, +then this function does nothing. + + + + + + + a #GdaQuarkList, or %NULL + + + + + + Removes an entry from the #GdaQuarkList, given its name. + + + + + + + a #GdaQuarkList structure. + + + + an entry name. + + + + + + + + + Creates a new #GdaRepetitiveStatement object which, when executed, will execute @stmt once for all +the values set which will have been defined using gda_repetitive_statement_append_set(). +Use gda_connection_repetitive_statement_execute() to actually execute it. + + + a new #GdaRepetitiveStatement object + + + + + a #GdaStatement object + + + + + + Specifies that @rstmt be executed one time with the values contained in @values. + +A new #GdaSet to be used as the @values argument can be obtained using +gda_repetitive_statement_get_template_set(). + + + a new #GdaRepetitiveStatement object + + + + + a #GdaRepetitiveStatement object + + + + a #GdaSet object with the values to be used + + + + %TRUE if @values is copied, and %FALSE if @values is only ref'ed + + + + + + Get all the values sets which will have been added using gda_repetitive_statement_append_set(). + + + a new #GSList of #GdaSet objects (free with g_slist_free()). + + + + + + + a #GdaRepetitiveStatement object + + + + + + Gets a new #GdaSet object with the parameters used by the template statement in the +@rstmt object. + +Use this object with gda_repetitive_statement_append_set(). + + + %TRUE on success, %FALSE on error + + + + + a #GdaRepetitiveStatement object + + + + a place to store the returned template set + + + + + + + + + + + + + + + + + + + + + Creates a #GdaRow which can hold @count #GValue values. + + + a newly allocated #GdaRow object. + + + + + number of #GValue in the new #GdaRow. + + + + + + Creates a #GdaRow which represent a row in a #GdaDataModel + + + a newly allocated #GdaRow object. + + + + + a #GdaDataModel to get data from. + + + + row at #GdaDataModel to get data from + + + + + + + + the number of columns that the @row has. + + + + + a #GdaRow. + + + + + + Gets a pointer to a #GValue stored in a #GdaRow. + +This is a pointer to the internal array of values. Don't try to free +or modify it (modifying is reserved to database provider's implementations). + + + a pointer to the #GValue in the position @num of @row. + + + + + a #GdaRow + + + + field index. + + + + + + Marks @value as being invalid. This method is mainly used by database +providers' implementations to report any error while reading a value from the database. + + + + + + + a #GdaRow + + + + a #GValue belonging to @row (obtained with gda_row_get_value()). + + + + + + Marks @value as being invalid. This method is mainly used by database +providers' implementations to report any error while reading a value from the database. + + + + + + + a #GdaRow + + + + a #GValue belonging to @row (obtained with gda_row_get_value()). + + + + the error which lead to the invalidation + + + + + + Tells if @value has been marked as being invalid by gda_row_invalidate_value(). +This method is mainly used by database +providers' implementations to report any error while reading a value from the database. + + + %TRUE if @value is valid + + + + + a #GdaRow. + + + + a #GValue belonging to @row (obtained with gda_row_get_value()). + + + + + + Tells if @value has been marked as being invalid by gda_row_invalidate_value(). +This method is mainly used by database +providers' implementations to report any error while reading a value from the database. + + + %TRUE if @value is valid + + + + + a #GdaRow. + + + + a #GValue belonging to @row (obtained with gda_row_get_value()). + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + IMPORTANT NOTE: Using this funtion is not the recommended way of creating a #GdaServerOperation object, the +correct way is to use gda_server_provider_create_operation(); this method is reserved for the database provider's +implementation. + +Creates a new #GdaServerOperation object from the @xml_file specifications + +The @xml_file must respect the DTD described in the "libgda-server-operation.dtd" file: its top +node must be a &lt;serv_op&gt; tag. + + + a new #GdaServerOperation object + + + + + type of operation + + + + a file which has the specifications for the GdaServerOperation object to create + + + + + + + + + + + Get a string version of @type + + + a non %NULL string (do not free or modify) + + + + + a #GdaServerOperationType value + + + + + + Creates a new #GdaServerOperation object which contains the specifications required +to create a database. Once these specifications are provided, use +gda_server_operation_perform_create_database() to perform the database creation. + +If @db_name is left %NULL, then the name of the database to create will have to be set in the +returned #GdaServerOperation using gda_server_operation_set_value_at(). + + + new #GdaServerOperation object, or %NULL if the provider does not support database +creation + + + + + the database provider to use + + + + the name of the database to create, or %NULL + + + + + + Creates a new #GdaServerOperation object which contains the specifications required +to drop a database. Once these specifications provided, use +gda_server_operation_perform_drop_database() to perform the database creation. + +If @db_name is left %NULL, then the name of the database to drop will have to be set in the +returned #GdaServerOperation using gda_server_operation_set_value_at(). + + + new #GdaServerOperation object, or %NULL if the provider does not support database +destruction + + + + + the database provider to use + + + + the name of the database to drop, or %NULL + + + + + + Performs the reverse of gda_server_operation_op_type_to_string() + + + the #GdaServerOperationType represented by @str, or #G_MAXINT if @str is not a valid representation +of a #GdaServerOperationType + + + + + a string + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + the index of the new entry in the sequence (like 5 for example if a 6th item has + been added to the sequence. + + + + + a #GdaServerOperation object + + + + the path to the sequence to which an item must be added (like "/SEQ_NAME" for instance) + + + + + + + + TRUE if the specified node has been removed from the sequence + + + + + a #GdaServerOperation object + + + + the path to the sequence's item to remove (like "/SEQ_NAME/5" for instance) + + + + + + Get information about the node identified by @path. The returned #GdaServerOperationNode structure can be +copied but not modified; it may change or cease to exist if @op changes + + + a #GdaServerOperationNode structure, or %NULL if the node was not found + + + + + a #GdaServerOperation object + + + + a complete path to a node (starting with "/") as a format string, similar to g_strdup_printf()'s argument + + + + the arguments to insert into the format string + + + + + + Get the complete path to the parent of the node defined by @path + + + a new string or %NULL if the node does not have any parent or does not exist. + + + + + a #GdaServerOperation object + + + + a complete path to a node (starting with "/") + + + + + + Get the last part of @path + + + a new string, or %NULL if an error occurred + + + + + a #GdaServerOperation object + + + + a complete path to a node (starting with "/") + + + + + + Convenience function to get the type of a node. + + + the type of node, or GDA_SERVER_OPERATION_NODE_UNKNOWN if the node was not found + + + + + a #GdaServerOperation object + + + + a complete path to a node (starting with "/") + + + + a place to store the status of the node, or %NULL + + + + + + Get the type of operation @op is for + + + a #GdaServerOperationType enum + + + + + a #GdaServerOperation object + + + + + + Get an array of strings containing the paths of nodes situated at the root of @op. + + + a new array, which must be freed with g_strfreev(). + + + + + + + a #GdaServerOperation object + + + + + + Fetch the contents of a sequence. @path can describe either a sequence (for example "/SEQNAME") or an item in a sequence +(for example "/SEQNAME/3") + + + a array of strings containing the complete paths of the nodes contained at @path (free with g_strfreev()) + + + + + + + a #GdaServerOperation object + + + + a complete path to a sequence node (starting with "/") + + + + + + + + the maximum number of items in the sequence at @path, or 0 if @path is not a sequence node + + + + + a #GdaServerOperation object + + + + a complete path to a sequence node (starting with "/") + + + + + + + + the minimum number of items in the sequence at @path, or 0 if @path is not a sequence node + + + + + a #GdaServerOperation object + + + + a complete path to a sequence node (starting with "/") + + + + + + + + the name of the sequence at @path + + + + + a #GdaServerOperation object + + + + a complete path to a sequence node (starting with "/") + + + + + + + + the number of items in the sequence at @path, or 0 if @path is not a sequence node + + + + + a #GdaServerOperation object + + + + a complete path to a sequence node (starting with "/") + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Get the value for the node at the path formed using @path_format and ... (the rules are the same as +for g_strdup_printf()) + + + a constant #GValue if a value has been defined, or %NULL if the value is undefined or +if the @path is not defined or @path does not hold any value. + + + + + a #GdaServerOperation object + + + + a complete path to a node (starting with "/") + + + + arguments to use with @path_format to make a complete path + + + + + + Get the value for the node at the @path path + + + a constant #GValue if a value has been defined, or %NULL if the value is undefined or if the @path is not defined or @path does not hold any value. + + + + + a #GdaServerOperation object + + + + a complete path to a node (starting with "/") + + + + + + Tells if all the required values in @op have been defined. + +if @xml_file is not %NULL, the validity of @op is tested against that specification, +and not against the current @op's specification. + + + %TRUE if @op is valid + + + + + a #GdaServerOperation widget + + + + an XML specification file (see gda_server_operation_new()) or %NULL + + + + + + Tells if all the required values in @op have been defined. + +if @xml_data is not %NULL, the validity of @op is tested against that specification, +and not against the current @op's specification. + + + %TRUE if @op is valid + + + + + a #GdaServerOperation widget + + + + the name of a resource containing an XML specification data (see gda_server_operation_new()) or %NULL + + + + + + Loads the contents of @node into @op. The XML tree passed through the @node +argument must correspond to an XML tree saved using gda_server_operation_save_data_to_xml(). + + + %TRUE if no error occurred + + + + + a #GdaServerOperation object + + + + a #xmlNodePtr + + + + + + Creates a new database using the specifications in @op. @op can be obtained using +gda_server_provider_create_operation(), or gda_server_operation_prepare_create_database(). + + + TRUE if no error occurred and the database has been created, FALSE otherwise + + + + + a #GdaServerOperation object obtained using gda_server_operation_prepare_create_database() + + + + the database provider to use, or %NULL if @op has been created using gda_server_operation_prepare_create_database() + + + + + + Destroys an existing database using the specifications in @op. @op can be obtained using +gda_server_provider_create_operation(), or gda_server_operation_prepare_drop_database(). + + + TRUE if no error occurred and the database has been destroyed + + + + + a #GdaServerOperation object obtained using gda_server_operation_prepare_drop_database() + + + + the database provider to use, or %NULL if @op has been created using gda_server_operation_prepare_drop_database() + + + + + + Creates an SQL statement (possibly using some specific extensions of the DBMS) corresponding to the +@op operation. Note that the returned string may actually contain more than one SQL statement. + +This function's purpose is mainly informative to get the actual SQL code which would be executed to perform +the operation; to actually perform the operation, use gda_server_operation_perform(). + + + a new string, or %NULL if an error occurred or operation cannot be rendered as SQL. + + + + + a #GdaServerOperation object + + + + + + Creates a new #xmlNodePtr tree which can be used to save the #op object. This +XML structure can then be saved to disk if necessary. Use xmlFreeNode to free +the associated memory when not needed anymore. + + + a new #xmlNodePtr structure, or %NULL + + + + + a #GdaServerOperation object + + + + + + + + an XML string representation of #GdaServerOperation + + + + + a #GdaServerOperation object + + + + + + Set the value for the node at the path formed using @path_format and the ... ellipse (the rules are the same as +for g_strdup_printf()). + +Note that trying to set a value for a path which is not used by the current +provider, such as "/TABLE_OPTIONS_P/TABLE_ENGINE" for a PostgreSQL connection (this option is only supported for MySQL), +will <emphasis>not</emphasis> generate +any error; this allows one to give values to a superset of the parameters and thus use the same code for several providers. + +Here are the possible formats of @path_format: +<itemizedlist> + <listitem><para>If the path corresponds to a #GdaHolder, then the parameter is set to <![CDATA["@value"]]></para></listitem> + <listitem><para>If the path corresponds to a sequence item like for example "/SEQUENCE_NAME/5/NAME" for + the "NAME" value of the 6th item of the "SEQUENCE_NAME" sequence then: + <itemizedlist> + <listitem><para>if the sequence already has 6 or more items, then the value is just set to the corresponding + value in the 6th item of the sequence</para></listitem> + <listitem><para>if the sequence has less then 6 items, then items are added up to the 6th one before setting + the value to the corresponding in the 6th item of the sequence</para></listitem> + </itemizedlist> + </para></listitem> + <listitem><para>If the path corresponds to a #GdaDataModel, like for example "/ARRAY/@@COLUMN/5" for the value at the + 6th row of the "COLUMN" column of the "ARRAY" data model, then: + <itemizedlist> + <listitem><para>if the data model already contains 6 or more rows, then the value is just set</para></listitem> + <listitem><para>if the data model has less than 6 rows, then rows are added up to the 6th one before setting + the value</para></listitem> + </itemizedlist> + </para></listitem> +</itemizedlist> + + + %TRUE if no error occurred + + + + + a #GdaServerOperation object + + + + a string + + + + a place to store errors or %NULL + + + + a complete path to a node (starting with "/") + + + + arguments to use with @path_format to make a complete path + + + + + + Set the value for the node at the path formed using @path_format and the ... ellipse (the rules are the same as +for g_strdup_printf()). + +Note that trying to set a value for a path which is not used by the current +provider, such as "/TABLE_OPTIONS_P/TABLE_ENGINE" for a PostgreSQL connection (this option is only supported for MySQL), +will <emphasis>not</emphasis> generate +any error; this allows one to give values to a superset of the parameters and thus use the same code for several providers. + +Here are the possible formats of @path_format: +<itemizedlist> + <listitem><para>If the path corresponds to a #GdaHolder, then the parameter is set to <![CDATA["@value"]]></para></listitem> + <listitem><para>If the path corresponds to a sequence item like for example "/SEQUENCE_NAME/5/NAME" for + the "NAME" value of the 6th item of the "SEQUENCE_NAME" sequence then: + <itemizedlist> + <listitem><para>if the sequence already has 6 or more items, then the value is just set to the corresponding + value in the 6th item of the sequence</para></listitem> + <listitem><para>if the sequence has less then 6 items, then items are added up to the 6th one before setting + the value to the corresponding in the 6th item of the sequence</para></listitem> + </itemizedlist> + </para></listitem> + <listitem><para>If the path corresponds to a #GdaDataModel, like for example "/ARRAY/@@COLUMN/5" for the value at the + 6th row of the "COLUMN" column of the "ARRAY" data model, then: + <itemizedlist> + <listitem><para>if the data model already contains 6 or more rows, then the value is just set</para></listitem> + <listitem><para>if the data model has less than 6 rows, then rows are added up to the 6th one before setting + the value</para></listitem> + </itemizedlist> + </para></listitem> +</itemizedlist> + + + %TRUE if no error occurred + + + + + a #GdaServerOperation object + + + + a string + + + + a complete path to a node (starting with "/") + + + + + + + + + + + + + + + + + + + + + + + + Gets emitted whenever a new sequence item (from a sequence template) has been added + + + + + + the path to the new sequence item + + + + the index (starting from 0) of the new sequence item in the sequence + + + + + + Gets emitted whenever a sequence item is about to be removed + + + + + + the path to the sequence item to be removed + + + + the index (starting from 0) of the sequence item in the sequence + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a new #GdaServerOperationCreateTableArg + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a new string with argument's column name + + + + + a #GdaServerOperationCreateTableArg + + + + + + + + type as #GType of the column to be created with this operation + + + + + a #GdaServerOperationCreateTableArg + + + + + + + + a new string with action to take on delete. + + + + + a #GdaServerOperationCreateTableArg + + + + + + + + a new string with action to take on delete. + + + + + a #GdaServerOperationCreateTableArg + + + + + + + + a list +of references from local to foreign fields type #GdaServerOperationCreateTableArgFKeyRefField. + + + + + + + a #GdaServerOperationCreateTableArg + + + + + + + + a new string with argument's referenced table's name. + + + + + a #GdaServerOperationCreateTableArg + + + + + + + + flags as #GdaServerOperationCreateTableFlag + + + + + a #GdaServerOperationCreateTableArg + + + + + + Sets column name to be created with the new table. + + + + + + + a #GdaServerOperationCreateTableArg + + + + the table's column's name. + + + + + + + + + + + + a #GdaServerOperationCreateTableArg + + + + column type to be added by this operation as #GType + + + + + + You should set this if you use a #GDA_SERVER_OPERATION_CREATE_TABLE_FKEY_FLAG flag. + + + + + + + a #GdaServerOperationCreateTableArg + + + + action to perform on delete action of the referenced field. + + + + + + + + + + + + + + + + + + + + You should set this if you use a #GDA_SERVER_OPERATION_CREATE_TABLE_FKEY_FLAG flag. + + + + + + + a #GdaServerOperationCreateTableArg + + + + list of references from local to foreign fields. +This list is owned by @arg, then you should not free it. + + + + + + + + You should set this if you use a #GDA_SERVER_OPERATION_CREATE_TABLE_FKEY_FLAG flag. + + + + + + + a #GdaServerOperationCreateTableArg + + + + the table's name of reference. + + + + + + Sets flags for new column to create with the table. + + + + + + + a #GdaServerOperationCreateTableArg + + + + flags to used in this argument as #GdaServerOperationCreateTableFlag + + + + + + + + + + + a new #GdaServerOperationCreateTableArgFKeyRefField + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Obtain a #GMainContext on which to iterate. This function is reserved to database provider's implementations. + +NB: if @cnc is NOT %NULL and has a #GdaWorker associated, and if we are in its worker thread, then this function + returns %NULL (to avoid generating contexts which are never used) + + + a #GMainContext, or %NULL. Don't forget to call g_main_context_unref() when done + + + + + a #GdaConnection, or %NULL + + + + + + Loads and returns the contents of the specified resource. +This function should only be used by database provider's implementations + + + a new string containing the resource's contents, or %NULL if not found or if an error occurred + + + + + the provider's name + + + + the name of the resource to load + + + + + + Upon creation, used by provider's implementors to set the implementation functions. Passing %NULL +as the @functions_set has no effect. + +If some pointers of @functions_set are %NULL, they are replaced by functions from the parent class of +@provider. + +Warning: this function must only be called once for each different values of @type and for each @klass + + + + + + + a #GdaServerProviderClass object + + + + a #GdaServerProviderFunctionsType type + + + + a pointer to the function set, or %NULL + + + + + + Creates a new #GdaServerOperation object which can be modified in order to perform the @type type of +action. The @options can contain: +<itemizedlist> + <listitem>named values which ID is a path in the resulting GdaServerOperation object, to initialize some value</listitem> + <listitem>named values which may change the contents of the GdaServerOperation, see <link linkend="gda-server-op-information-std">this section</link> for more information</listitem> +</itemizedlist> + + + a new #GdaServerOperation object, or %NULL in the provider does not support the @type type of operation or if an error occurred + + + + + a #GdaServerProvider object + + + + a #GdaConnection object which will be used to perform an action, or %NULL + + + + the type of operation requested + + + + a list of parameters or %NULL + + + + + + Creates a new #GdaSqlParser object which is adapted to @provider (and possibly depending on +@cnc for the actual database version). + +If @prov does not have its own parser, then %NULL is returned, and a general SQL parser can be obtained +using gda_sql_parser_new(). + + + a new #GdaSqlParser object, or %NULL. + + + + + a #GdaServerProvider provider object + + + + a #GdaConnection, or %NULL + + + + + + Escapes @str for use within an SQL command (to avoid SQL injection attacks). Note that the returned value still needs +to be enclosed in single quotes before being used in an SQL statement. + + + a new string suitable to use in SQL statements + + + + + a server provider. + + + + a #GdaConnection object, or %NULL + + + + a string to escape + + + + + + Find a #GdaDataHandler object to manipulate data of type @for_type. + +Note: this function is currently very poorly implemented by database providers. + + + a #GdaDataHandler, or %NULL if the provider does not know about the @for_type type + + + + + a server provider. + + + + a #GdaConnection object, or %NULL + + + + a DBMS type definition + + + + + + Find a #GdaDataHandler object to manipulate data of type @for_type. The returned object must not be modified. + + + a #GdaDataHandler, or %NULL if the provider does not support the requested @for_type data type + + + + + a server provider. + + + + a #GdaConnection object, or %NULL + + + + a #GType + + + + + + Get the name of the most common data type which has @type type. + +The returned value may be %NULL either if the provider does not implement that method, or if +there is no DBMS data type which could contain data of the @g_type type (for example %NULL may be +returned if a DBMS has integers only up to 4 bytes and a #G_TYPE_INT64 is requested). + + + the name of the DBMS type, or %NULL + + + + + a server provider. + + + + a #GdaConnection object or %NULL + + + + a #GType value type + + + + + + Get the name (identifier) of the provider + + + a string containing the provider's name + + + + + a #GdaServerProvider object. + + + + + + Get the version of the database to which the connection is opened. + + + a (read only) string, or %NULL if an error occurred + + + + + a #GdaServerProvider object. + + + + a #GdaConnection object + + + + + + Get the version of the provider. + + + a string containing the version identification. + + + + + a #GdaServerProvider object. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Reserved to database provider's implementations: get the #GdaDataHandler associated to @prov +for connection @cnc. You probably want to use gda_server_provider_get_data_handler_g_type(). + + + the requested #GdaDataHandler, or %NULL if none found + + + + + a #GdaServerProvider + + + + a #GdaConnection + + + + a #GType + + + + a database type + + + + + + Reserved to database provider's implementations. This method defines a default data handler for +@provider, and returns that #GdaDataHandler. + + + a #GdaDataHandler, or %NULL + + + + + a server provider + + + + a #GType + + + + + + This is a factory method to get a unique instance of a #GdaSqlParser object +for each #GdaServerProvider object +Don't unref it. + + + a #GdaSqlParser + + + + + a #GdaServerProvider + + + + + + Performs the operation described by @op. Note that @op is not destroyed by this method +and can be reused. + + + %TRUE if no error occurred + + + + + a #GdaServerProvider object + + + + a #GdaConnection object which will be used to perform the action, or %NULL + + + + a #GdaServerOperation object + + + + + + Performs the operation described by @op, using the SQL from the rendering of the operation + + + %TRUE if no error occurred + + + + + a #GdaServerProvider object + + + + a #GdaConnection object which will be used to perform an action, or %NULL + + + + a #GdaServerOperation object + + + + + + Creates an SQL statement (possibly using some specific extensions of the DBMS) corresponding to the +@op operation. Note that the returned string may actually contain more than one SQL statement. + +This function's purpose is mainly informative to get the actual SQL code which would be executed to perform +the operation; to actually perform the operation, use gda_server_provider_perform_operation(). + + + a new string, or %NULL if an error occurred or operation cannot be rendered as SQL. + + + + + a #GdaServerProvider object + + + + a #GdaConnection object which will be used to render the action, or %NULL + + + + a #GdaServerOperation object + + + + + + Use @provider to create a new #GValue from a single string representation. + +The @preferred_type can optionally ask @provider to return a #GValue of the requested type +(but if such a value can't be created from @string, then %NULL is returned); +pass #G_TYPE_INVALID if any returned type is acceptable. + +The returned value is either a new #GValue or %NULL in the following cases: +- @string cannot be converted to @preferred_type type +- the provider does not handle @preferred_type +- the provider could not make a #GValue from @string + +If @dbms_type is not %NULL, then if will contain a constant string representing +the database type used for the conversion if the conversion was successfull, or %NULL +otherwise. + + + a new #GValue, or %NULL + + + + + a server provider. + + + + a #GdaConnection object, or %NULL + + + + the SQL string to convert to a value + + + + a #GType, or #G_TYPE_INVALID + + + + place to get the actual database type used if the conversion succeeded, or %NULL + + + + + + Tests if a feature is supported + + + %TRUE if @feature is supported + + + + + a #GdaServerProvider object + + + + a #GdaConnection object, or %NULL + + + + #GdaConnectionFeature feature to test + + + + + + Tells if @provider supports the @type of operation on the @cnc connection, using the +(optional) @options parameters. + + + %TRUE if the operation is supported + + + + + a #GdaServerProvider object + + + + a #GdaConnection object which would be used to perform an action, or %NULL + + + + the type of operation requested + + + + a list of named parameters, or %NULL + + + + + + Unescapes @str for use within an SQL command. This is the exact opposite of gda_server_provider_escape_string(). + + + a new string + + + + + a server provider. + + + + a #GdaConnection object, or %NULL + + + + a string to escape + + + + + + Produces a fully quoted and escaped string from a GValue + + + escaped and quoted value or NULL if not supported. + + + + + a server provider. + + + + a #GdaConnection object, or %NULL + + + + #GValue to convert from + + + + + + + + + + Functions implementing basic features. + +A pointer to this structure is returned by _gda_server_provider_get_impl_functions() when requesting +@GDA_SERVER_PROVIDER_FUNCTIONS_BASE functions. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Opaque structure extended by database providers to store per-connection information (usually C handles +to the connection as required by the C API they use). + +Note: @worker part is created in _gda_server_provider_open_connection() by the provider itself, which allows it to +either create a #GdaWorker for each connection, or create only one #GdaWorker for all connections (if the underlying +for example does not support multi-threading at all) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Represents the different types of sets of virtual functions which can be implemented for each provider + + + + + + + + + + + + + + + + + + + + + + + + These methods must be implemented by providers to update a connection's associated metadata (in a +#GdaMetaStore object), see the <link linkend="prov-metadata">Virtual methods for providers/Methods - metadata</link> +for more information. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Functions implementing distributed transactions. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Creates a new #GdaSet object, and populates it with the list given as argument. +The list can then be freed as it is copied. All the value holders in @holders are referenced counted +and modified, so they should not be used anymore afterwards. + + + a new #GdaSet object + + + + + a list of #GdaHolder objects + + + + + + + + Creates a new #GdaSet object from the @xml_spec +specifications + + + a new object, or %NULL if an error occurred + + + + + a #xmlNodePtr for a &lt;parameters&gt; tag + + + + + + Creates a new #GdaSet object from the @xml_spec +specifications + + + a new object, or %NULL if an error occurred + + + + + a string + + + + + + Creates a new #GdaSet containing holders defined by each triplet in ... +For each triplet (id, Glib type and value), +the value must be of the correct type (gchar * if type is G_STRING, ...) + +Note that this function is a utility function and that only a limited set of types are supported. Trying +to use an unsupported type will result in a warning, and the returned value holder holding a safe default +value. + + + a new #GdaSet object + + + + + the number of value holders which will be contained in the new #GdaSet + + + + a serie of a (const gchar*) id, (GType) type, and value + + + + + + Creates a new #GdaSet like gda_set_new(), but does not allow modifications to any of the #GdaHolder +object in @holders. This function is used for Libgda's database providers' implementation. + + + a new #GdaSet object + + + + + a list of #GdaHolder objects + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Adds @holder to the list of holders managed within @set. + +NOTE: if @set already has a #GdaHolder with the same ID as @holder, then @holder +will not be added to the set (even if @holder's type or value is not the same as the +one already in @set). + + + %TRUE if @holder has been added to @set (and FALSE if it has not been added because there is another #GdaHolder +with the same ID) + + + + + a #GdaSet object + + + + a #GdaHolder object + + + + + + Creates a new #GdaSet object, copy of @set + + + a new #GdaSet object + + + + + a #GdaSet object + + + + + + Finds a #GdaSetGroup which lists a #GdaSetNode containing @holder, +don't modify the returned structure. + + + the requested #GdaSetGroup or %NULL + + + + + a #GdaSet object + + + + a #GdaHolder object + + + + + + + + a list of #GdaSetGroup objects in the set + + + + + + + + + + + + Finds a #GdaHolder using its ID + + + the requested #GdaHolder or %NULL + + + + + a #GdaSet object + + + + the ID of the requested value holder + + + + + + Get the value of the #GdaHolder which ID is @holder_id + + + the requested GValue, or %NULL (see gda_holder_get_value()) + + + + + a #GdaSet object + + + + the ID of the holder to set the value + + + + + + + + a list of #GdaHolder objects in the set + + + + + + + + + + + + Finds a #GdaSetNode holding information for @holder, don't modify the returned structure + + + the requested #GdaSetNode or %NULL + + + + + a #GdaSet object + + + + a #GdaHolder object + + + + + + + + a list of #GdaSetNode objects in the set + + + + + + + + + + + + Finds a #GdaHolder using its position + + + the requested #GdaHolder or %NULL + + + + + a #GdaSet object + + + + the position of the requested #GdaHolder, starting at %0 + + + + + + Finds a #GdaSetSource which contains the #GdaDataModel restricting the possible values of +@holder, don't modify the returned structure. + + + the requested #GdaSetSource or %NULL + + + + + a #GdaSet object + + + + a #GdaHolder object + + + + + + Finds the #GdaSetSource structure used in @set for which @model is a +the data model (the returned structure should not be modified). + + + the requested #GdaSetSource pointer or %NULL. + + + + + a #GdaSet object + + + + a #GdaDataModel object + + + + + + + + a list of #GdaSetSource objects in the set + + + + + + + + + + + + This method tells if all @set's #GdaHolder objects are valid, and if +they represent a valid combination of values, as defined by rules +external to Libgda: the "validate-set" signal is emitted and if none of the signal handlers return an +error, then the returned value is TRUE, otherwise the return value is FALSE as soon as a signal handler +returns an error. + + + TRUE if the set is valid + + + + + a #GdaSet object + + + + + + Add to @set all the holders of @set_to_merge. +Note1: only the #GdaHolder of @set_to_merge for which no holder in @set has the same ID are merged +Note2: all the #GdaHolder merged in @set are still used by @set_to_merge. + + + + + + + a #GdaSet object + + + + a #GdaSet object + + + + + + Removes a #GdaHolder from the list of holders managed by @set + + + + + + + a #GdaSet object + + + + the #GdaHolder to remove from @set + + + + + + Replaces @source->data_model with @model, which must have the same +characteristics as @source->data_model (same column types) + +Also for each #GdaHolder for which @source->data_model is a source model, +this method calls gda_holder_set_source_model() with @model to replace +the source by the new model + + + + + + + a #GdaSet object + + + + a pointer to a #GdaSetSource in @set + + + + a #GdaDataModel + + + + + + Set the value of the #GdaHolder which ID is @holder_id to a specified value + + + %TRUE if no error occurred and the value was set correctly + + + + + a #GdaSet object + + + + a place to store errors, or %NULL + + + + the ID of the holder to set the value + + + + value, of the correct type, depending on the requested holder's type (not NULL) + + + + + + + + + + + + + + + + + + Defines if the "validate-set" signal gets emitted when +any holder in the data set changes. This property also affects the +GdaHolder:validate-changes property. + + + + + + + Gets emitted when an attribute for any of the #GdaHolder objects managed by @set has changed + + + + + + the GdaHolder for which an attribute changed + + + + attribute's name + + + + attribute's value + + + + + + + + + + + + + + + + Gets emitted when @holder in @set has its type finally set, in case +it was #GDA_TYPE_NULL + + + + + + the #GdaHolder for which the #GType has been set + + + + + + Gets emitted when @set's public data (#GdaSetNode, #GdaSetGroup or #GdaSetSource values) have changed + + + + + + Gets emitted when the data model in @source has changed + + + + + + the #GdaSetSource for which the @data_model attribute has changed + + + + + + Gets emitted when a #GdaHolder's in @set is going to change its value. One can connect to +this signal to control which values @holder can have (for example to implement some business rules) + + NULL if @holder is allowed to change its value to @new_value, or a #GError +otherwise. + + + + + the #GdaHolder which is going to change + + + + the proposed new value for @holder + + + + + + Gets emitted when gda_set_is_valid() is called, use +this signal to control which combination of values @set's holder can have (for example to implement some business rules) + + NULL if @set's contents has been validated, or a #GError +otherwise. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Since 5.2, you must consider this struct as opaque. Any access to its internal must use public API. +Don't try to use #gda_set_group_free on a struct that was created manually. + + + Creates a new #GdaSetGroup struct. If @source is %NULL then new group contains +just one #GdaSetNode. + + + a new #GdaSetGroup struct. + + + + + a #GdaSetNode struct + + + + + + + + + + + + a #GdaSetGroup + + + + a #GdaSetNode to set + + + + + + Copy constructor. + + + a new #GdaSetGroup + + + + + a #GdaSetGroup + + + + + + Frees any resources taken by @sg struct. If @sg is %NULL, then nothing happens. + + + + + + + a #GdaSetGroup struct to free + + + + + + + + number of nodes in @sg. + + + + + a #GdaSetGroup + + + + + + This method always return first #GdaSetNode in @sg. + + + first #GdaSetNode in @sg. + + + + + a #GdaSetGroup + + + + + + Returns a #GSList with the #GdaSetNode grouped by @sg. You must use +#g_slist_free on returned list. + + + a #GSList with all nodes in @sg. + + + + + + + a #GdaSetGroup + + + + + + + + a #GdaSetSource. If %NULL then @sg contains just one element. + + + + + a #GdaSetGroup + + + + + + + + + + + + a #GdaSetGroup + + + + a #GdaSetSource to set + + + + + + + Since 5.2, you must consider this struct as opaque. Any access to its internal must use public API. +Don't try to use #gda_set_node_free on a struct that was created manually. + + + Creates a new #GdaSetNode struct. + + + a new #GdaSetNode struct. + + + + + a #GdaHolder to used by new #GdaSetNode + + + + + + Copy constructor. + + + a new #GdaSetNode + + + + + a #GdaSetNode to copy from + + + + + + Frees any resources taken by @node struct. If @node is %NULL, then nothing happens. + + + + + + + a #GdaSetNode struct to free + + + + + + + + the #GdaDataModel used by @node + + + + + a #GdaSetNode struct to get holder from + + + + + + + + the #GdaHolder used by @node + + + + + a #GdaSetNode struct to get holder from + + + + + + + + the number of column referenced in a given #GdaDataModel. If negative +no column is referenced or no #GdaDataModel is used by @node. + + + + + a #GdaSetNode struct to get column source from + + + + + + Set a #GdaDataModel to be used by @node. @model increment its reference +counting when set. Internally referenced column number is set to first column +in @model. + + + + + + + a #GdaSetNode struct to set data model to + + + + a #GdaDataModel to be used by @node + + + + + + Set a #GdaHolder to @node. + + + + + + + a #GdaSetNode struct to set holder to + + + + + + + + + Set column number in the #GdaDataModel used @node. If no #GdaDataModel is set +then column is set to invalid (-1); + + + + + + + a #GdaSetNode struct to set column source to, from an used data model + + + + + + + + + + Since 5.2, you must consider this struct as opaque. Any access to its internal must use public API. +Don't try to use #gda_set_source_free on a struct that was created manually. + + + Creates a new #GdaSetSource struct. + + + a new #GdaSetSource struct. + + + + + a #GdaDataModel + + + + + + Set a #GdaDataModel + + + + + + + a #GdaSetSource + + + + a #GdaSetNode to add + + + + + + Copy constructor. + + + a new #GdaSetSource + + + + + a #GdaSetGroup + + + + + + Frees any resources taken by @s struct. If @s is %NULL, then nothing happens. + + + + + + + a #GdaSetSource struct to free + + + + + + + + a #GdaDataModel used by @s + + + + + a #GdaSetSource + + + + + + + + number of nodes in @sg. + + + + + a #GdaSetSource + + + + + + + + a list of #GdaSetNode structs + + + + + + + a #GdaSetSource + + + + + + Set a #GdaDataModel + + + + + + + a #GdaSetSource struct to free + + + + a #GdaDataModel + + + + + + + + + Base structure of which all structures (except #GdaSqlStatement) "inherit". It identifies, for each structure, +its type and its parent in the structure hierarchy. + + + type of structure, as a #GdaSqlAnyPartType enum. + + + + pointer to the parent #GdaSqlAnyPart structure + + + + Checks for any error in @node's structure to make sure it is valid. This +is the same as gda_sql_statement_check_structure() but for individual #GdaSqlAnyPart +parts. This function is mainly for database provider's implementations + + + TRUE if no error occurred + + + + + a #GdaSqlAnyPart pointer + + + + + + Calls a function for each element of a #GdaSqlAnyPart node + + + TRUE if @func has been called for any sub node of @node and always returned TRUE, or FALSE +otherwise. + + + + + the stat node + + + + function to call for each sub node + + + + data to pass to @func each time it is called + + + + + + + Type of part. + + + structure is a #GdaSqlStatementSelect + + + structure is a #GdaSqlStatementInsert + + + structure is a #GdaSqlStatementUpdate + + + structure is a #GdaSqlStatementDelete + + + structure is a #GdaSqlStatementCompound + + + structure is a #GdaSqlStatementTransaction + + + structure is a #GdaSqlStatementTransaction + + + structure is a #GdaSqlStatementTransaction + + + structure is a #GdaSqlStatementTransaction + + + structure is a #GdaSqlStatementTransaction + + + structure is a #GdaSqlStatementTransaction + + + structure is a #GdaSqlStatementUnknown + + + structure is a #GdaSqlExpr + + + structure is a #GdaSqlField + + + structure is a #GdaSqlTable + + + structure is a #GdaSqlFunction + + + structure is a #GdaSqlOperation + + + structure is a #GdaSqlCase + + + structure is a #GdaSqlSelectField + + + structure is a #GdaSqlSelectTarget + + + structure is a #GdaSqlSelectJoin + + + structure is a #GdaSqlSelectFrom + + + structure is a #GdaSqlSelectOrder + + + + + + Create a new #GdaSqlBuilder object to build #GdaStatement or #GdaSqlStatement +objects of type @stmt_type + + + the newly created object, or %NULL if an error occurred (such as unsupported +statement type) + + + + + the type of statement to build + + + + + + + + + + + Creates a new CASE ... WHEN ... THEN ... ELSE ... END expression. + + + the ID of the new expression, or %0 if there was an error + + + + + a #GdaSqlBuilder object + + + + the expression ID representing the test of the CASE, or %0 + + + + the expression ID representing the ELSE expression, or %0 + + + + a list, terminated by a %0, of (WHEN expression ID, THEN expression ID) representing + all the test cases + + + + + + Creates a new CASE ... WHEN ... THEN ... ELSE ... END expression. The WHEN expression and the THEN +expression IDs are taken from the @when_array and @then_array at the same index, for each index inferior to +@args_size. + + + the ID of the new expression, or %0 if there was an error + + + + + a #GdaSqlBuilder object + + + + the expression ID representing the test of the CASE, or %0 + + + + the expression ID representing the ELSE expression, or %0 + + + + an array containing each WHEN expression ID, having at least @args_size elements + + + + + + an array containing each THEN expression ID, having at least @args_size elements + + + + + + the size of @when_array and @then_array + + + + + + Builds a new expression which represents a condition (or operation). + + + the ID of the new expression, or %0 if there was an error + + + + + a #GdaSqlBuilder object + + + + type of condition + + + + the ID of the 1st argument (not 0) + + + + the ID of the 2nd argument (may be %0 if @op needs only one operand) + + + + the ID of the 3rd argument (may be %0 if @op needs only one or two operand) + + + + + + Builds a new expression which represents a condition (or operation). + +As a side case, if @ops_ids_size is 1, +then @op is ignored, and the returned ID represents @op_ids[0] (this avoids any problem for example +when @op is GDA_SQL_OPERATOR_TYPE_AND and there is in fact only one operand). + + + the ID of the new expression, or %0 if there was an error + + + + + a #GdaSqlBuilder object + + + + type of condition + + + + an array of ID for the arguments (not %0) + + + + + + size of @ops_ids + + + + + + Defines an expression in @builder which may be reused to build other parts of a statement. + +The new expression will contain the value passed as the @... argument. + +If @type is G_TYPE_STRING then it is possible to customize how the value has to be interpreted by passing a +specific #GdaDataHandler object as @dh. This feature is very rarely used and the @dh argument should generally +be %NULL. + +Note that for composite types such as #GdaNumeric, #Gdate, #GdaTime, ... pointer to these +structures are expected, they should no be passed by value. For example: +<programlisting><![CDATA[GDate *date = g_date_new_dmy (27, G_DATE_MAY, 1972); +id = gda_sql_builder_add_expr (b, NULL, G_TYPE_DATE, date); +g_date_free (date); + +id = gda_sql_builder_add_expr (b, NULL, G_TYPE_STRING, "my string"); +id = gda_sql_builder_add_expr (b, NULL, G_TYPE_INT, 25); +]]></programlisting> + +will correspond in SQL to: +<programlisting> +'05-27-1972' +'my string' +25 +</programlisting> + + + the ID of the new expression, or %0 if there was an error + + + + + a #GdaSqlBuilder object + + + + deprecated useless argument, just pass %NULL + + + + the GType of the following argument + + + + value to set the expression to, of the type specified by @type + + + + + + Defines an expression in @builder which may be reused to build other parts of a statement. + +The new expression will contain the value passed as the @value argument. + +If @value's type is a string then it is possible to customize how the value has to be interpreted by passing a +specific #GdaDataHandler object as @dh. This feature is very rarely used and the @dh argument should generally +be %NULL. + + + the ID of the new expression, or %0 if there was an error + + + + + a #GdaSqlBuilder object + + + + value to set the expression to, or %NULL or a GDA_TYPE_NULL value to represent an SQL NULL + + + + + + Defines an expression representing a field in @builder, +which may be reused to build other parts of a statement, +for instance as a parameter to gda_sql_builder_add_cond() or +gda_sql_builder_add_field_value_id(). + +Calling this with a %NULL @table_name is equivalent to calling gda_sql_builder_add_id(). + +For SELECT queries, see gda_sql_builder_select_add_field(). + + + the ID of the new expression, or %0 if there was an error + + + + + a #GdaSqlBuilder object + + + + a field name + + + + a table name, or %NULL + + + + + + Valid only for: INSERT, UPDATE statements. + +Specifies that the field represented by @field_name will be set to the value identified +by @... of type @type. See gda_sql_builder_add_expr() for more information. + +This is a C convenience function. See also gda_sql_builder_add_field_value_as_gvalue(). + + + + + + + a #GdaSqlBuilder object + + + + a field name + + + + the GType of the following argument + + + + value to set the field to, of the type specified by @type + + + + + + Valid only for: INSERT, UPDATE statements. + +Specifies that the field represented by @field_name will be set to the value identified +by @value + + + + + + + a #GdaSqlBuilder object + + + + a field name + + + + value to set the field to, or %NULL or a GDA_TYPE_NULL value to represent an SQL NULL + + + + + + Valid only for: INSERT, UPDATE, SELECT statements +<itemizedlist> +<listitem><para>For UPDATE: specifies that the field represented by @field_id will be set to the value identified + by @value_id.</para></listitem> +<listitem><para>For SELECT: add a selected item to the statement, and if @value_id is not %0, then use it as an + alias</para></listitem> +<listitem><para>For INSERT: if @field_id represents an SQL identifier (obtained using gda_sql_builder_add_id()): then if + @value_id is not %0 then specifies that the field represented by @field_id will be set to the + value identified by @value_id, otherwise just specifies a named field to be given a value. + If @field_id represents a sub SELECT (obtained using gda_sql_builder_add_sub_select()), then + this method call defines the sub SELECT from which values to insert are taken.</para></listitem> +</itemizedlist> + +See also gda_sql_builder_add_field_value() and gda_sql_builder_add_field_value_as_gvalue(). + + + + + + + a #GdaSqlBuilder object + + + + the ID of the field's name or definition + + + + the ID of the value to set the field to, or %0 + + + + + + Builds a new expression which represents a function applied to some arguments + + + the ID of the new expression, or %0 if there was an error + + + + + a #GdaSqlBuilder object + + + + the functions's name + + + + a list, terminated with %0, of each function's argument's ID + + + + + + Builds a new expression which represents a function applied to some arguments + + + the ID of the new expression, or %0 if there was an error + + + + + a #GdaSqlBuilder object + + + + the functions's name + + + + an array of IDs representing the function's arguments + + + + + + @args's size + + + + + + Defines an expression representing an identifier in @builder, +which may be reused to build other parts of a statement, +for instance as a parameter to gda_sql_builder_add_cond() or +gda_sql_builder_add_field_value_id(). + +The new expression will contain the @str literal. +For example: +<programlisting> +gda_sql_builder_add_id (b, "name") +gda_sql_builder_add_id (b, "date") +</programlisting> + +will be rendered as SQL as: +<programlisting> +name +"date" +</programlisting> + +because "date" is an SQL reserved keyword. + +For fields, see gda_sql_builder_add_field_id(). + + + the ID of the new expression, or %0 if there was an error + + + + + a #GdaSqlBuilder object + + + + a string + + + + + + Defines a parameter in @builder which may be reused to build other parts of a statement. + +The new expression will contain the @string literal. +For example: +<programlisting> +gda_sql_builder_add_param (b, "age", G_TYPE_INT, FALSE) +</programlisting> + +will be rendered as SQL as: +<programlisting><![CDATA[ +##age::int +]]> +</programlisting> + + + the ID of the new expression, or %0 if there was an error + + + + + a #GdaSqlBuilder object + + + + parameter's name + + + + parameter's type + + + + TRUE if the parameter can be set to %NULL + + + + + + Adds an expression which is a subselect. + + + the ID of the new expression, or %0 if there was an error + + + + + a #GdaSqlBuilder object + + + + a pointer to a #GdaSqlStatement, which has to be a SELECT or compound SELECT. This will be copied. + + + + + + Add a sub select to a COMPOUND statement + + + + + + + a #GdaSqlBuilder object + + + + a pointer to a #GdaSqlStatement, which has to be a SELECT or compound SELECT. This will be copied. + + + + + + Add a sub select to a COMPOUND statement + + + + + + + a #GdaSqlBuilder object + + + + a #GdaSqlBuilder, which has to be a SELECT or compound SELECT. This will be copied. + + + + + + Changes the type of compound which @builder is making, for a COMPOUND statement + + + + + + + a #GdaSqlBuilder object + + + + a type of compound + + + + + + Exports a part managed by @builder as a new #GdaSqlExpr, which can represent any expression +in a statement. + + + a pointer to a new #GdaSqlExpr structure, free using gda_sql_expr_free() when not +needed anymore. If the part with @id as ID cannot be found, the returned value is %NULL. + + + + + a #GdaSqlBuilder object + + + + the ID of the expression to be exported, (must be a valid ID in @builder, not %0) + + + + + + Creates a new #GdaSqlStatement structure from @builder's contents. + +The returned pointer belongs to @builder's internal representation. +Use gda_sql_statement_copy() if you need to keep it. + + + a #GdaSqlStatement pointer + + + + + a #GdaSqlBuilder object + + + + + + Creates a new #GdaStatement statement from @builder's contents. + + + a new #GdaStatement object, or %NULL if an error occurred + + + + + a #GdaSqlBuilder object + + + + + + Imports the @expr into @builder. + + + the ID of the new expression, or %0 if there was an error + + + + + a #GdaSqlBuilder object + + + + a #GdaSqlExpr obtained using gda_sql_builder_export_expression() + + + + + + Imports the an expression located in @query into @builder. + + + the ID of the new expression, or %0 if there was an error + + + + + a #GdaSqlBuilder object + + + + a #GdaSqlBuilder object to get expression from + + + + a #GdaSqlBuilderId of the expression in @query + + + + + + Alter a join in a SELECT statement to make its condition use equal field +values in the fields named @field_name in both tables, via the USING keyword. + + + + + + + a #GdaSqlBuilder object + + + + the ID of the join to modify (not %0) + + + + the name of the field to use in the join condition (not %NULL) + + + + + + Valid only for: SELECT statements. + +Add a selected selected item to the SELECT statement. + +For non-SELECT statements, see gda_sql_builder_add_field_id(). + + + the ID of the added field, or %0 if there was an error + + + + + a #GdaSqlBuilder object + + + + a field name + + + + a table name, or %NULL + + + + an alias (eg. for the "AS" clause), or %NULL + + + + + + Adds a new target to a SELECT statement + + + the ID of the new target, or %0 if there was an error + + + + + a #GdaSqlBuilder object + + + + the name of the target table + + + + the alias to give to the target, or %NULL + + + + + + Adds a new target to a SELECT statement. If there already exists a target representing +the same table and the same alias (or with the same absence of alias) then the same target +ID is returned instead of the ID of a new target. + + + the ID of the new (or existing) target, or %0 if there was an error + + + + + a #GdaSqlBuilder object + + + + the ID of the expression holding a table reference (not %0) + + + + the alias to give to the target, or %NULL + + + + + + Valid only for: SELECT statements + +Adds the @expr_id expression to the GROUP BY clause's expressions list + + + + + + + a #GdaSqlBuilder object + + + + the ID of the expression to set use in the GROUP BY clause, or 0 to unset any previous GROUP BY clause + + + + + + Joins two targets in a SELECT statement, using the @join_type type of join. + +Note: if the target represented by @left_target_id is actually situated after (on the right) of +the target represented by @right_target_id, then the actual type of join may be switched from +%GDA_SQL_SELECT_JOIN_LEFT to %GDA_SQL_SELECT_JOIN_RIGHT or from %GDA_SQL_SELECT_JOIN_RIGHT to +%GDA_SQL_SELECT_JOIN_LEFT. + + + the ID of the new join, or %0 if there was an error + + + + + a #GdaSqlBuilder object + + + + the ID of the left target to use (not %0) + + + + the ID of the right target to use (not %0) + + + + the type of join + + + + joining expression's ID, or %0 + + + + + + Adds a new ORDER BY expression to a SELECT statement. + + + + + + + a #GdaSqlBuiler + + + + the ID of the expression to use during sorting (not %0) + + + + %TRUE for an ascending sorting + + + + name of the collation to use when sorting, or %NULL + + + + + + Defines (if @distinct is %TRUE) or removes (if @distinct is %FALSE) a DISTINCT clause +for a SELECT statement. + +If @distinct is %TRUE, then the ID of an expression can be specified as the @expr_id argument: +if not %0, this is the expression used to apply the DISTINCT clause on (the resuting SQL +will then usually be "... DISTINCT ON &lt;expression&gt;..."). + + + + + + + a #GdaSqlBuilder object + + + + set to %TRUE to have the DISTINCT requirement + + + + the ID of the DISTINCT ON expression, or %0 if no expression is to be used. It is ignored + if @distinct is %FALSE. + + + + + + Valid only for: SELECT statements + +Sets the HAVING condition of the statement + + + + + + + a #GdaSqlBuilder object + + + + the ID of the expression to set as HAVING condition, or 0 to unset any previous HAVING condition + + + + + + If @limit_count_expr_id is not %0, defines the maximum number of rows in the #GdaDataModel +resulting from the execution of the built statement. In this case, the offset from which the +rows must be collected can be defined by the @limit_offset_expr_id expression if not %0 (note that +this feature may not be supported by all the database providers). + +If @limit_count_expr_id is %0, then removes any LIMIT which may have been imposed by a previous +call to this method. + + + + + + + a #GdaSqlBuilder object + + + + the ID of the LIMIT expression, or %0 + + + + the ID of the OFFSET expression, or %0 + + + + + + Valid only for: INSERT, UPDATE, DELETE statements + +Sets the name of the table on which the built statement operates. + + + + + + + a #GdaSqlBuilder object + + + + a table name + + + + + + Valid only for: UPDATE, DELETE, SELECT statements + +Sets the WHERE condition of the statement + + + + + + + a #GdaSqlBuilder object + + + + the ID of the expression to set as WHERE condition, or 0 to unset any previous WHERE condition + + + + + + Specifies the type of statement to be built, can only be +GDA_SQL_STATEMENT_SELECT, GDA_SQL_STATEMENT_INSERT, GDA_SQL_STATEMENT_UPDATE +or GDA_SQL_STATEMENT_DELETE + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + This structure represents a CASE WHEN... construct + + + inheritance structure + + + + expression to test + + + + list of #GdaSqlExpr, one for each WHEN clause + + + + + + list of #GdaSqlExpr, one for each THEN clause + + + + + + default expression for the CASE + + + + + + + + + + Creates a new #GdaSqlCase structure and sets its parent to @parent. + + + a new #GdaSqlCase structure. + + + + + a #GdaSqlAnyPart structure + + + + + + Creates a new #GdaSqlCase structure initiated with the values stored in @sc. + + + a new #GdaSqlCase structure. + + + + + a #GdaSqlCase structure to be copied + + + + + + Frees a #GdaSqlCase structure and its members. + + + + + + + a #GdaSqlCase structure to be freed + + + + + + Creates a new string representing a CASE clause. You need to free the returned string +using g_free(); + + + a new string with the description of the CASE clause or "null" in case @sc is invalid. + + + + + a #GdaSqlCase structure + + + + + + + + + + + + + + + + + + This structure contains any expression, either as a value (the @value part is set), +a variable (the @param_spec is set), or as other types of expressions. + +Note 1 about the @value field: if the expression represents a string value in the SQL statement, +the string itself must be represented as it would be in the actual SQL, ie. it should be +escaped (accordingly to the escaping rules of the database which will use the SQL). For +example a string representing the <userinput>'joe'</userinput> value should be +<userinput>"'joe'"</userinput> and not <userinput>"joe"</userinput>. + +Note 2 about the @value field: if the expression represents an SQL identifier (such as a table +or field name), then the @value_is_ident should be set to %TRUE, and @value should be a string +which may contain double quotes around SQL identifiers which also are reserved keywords or which +are case sensitive. + + + inheritance structure + + + + a #GValue, or %NULL. Please see specific note about this field. + + + + a #GdaSqlParamSpec, or %NULL if this is not a variable + + + + not %NULL if expression is a function or aggregate + + + + not %NULL if expression is a condition or an operation + + + + not %NULL if expression is a sub select statement (#GdaSqlStatementSelect or #GdaSqlStatementCompound) + + + + not %NULL if expression is a CASE WHEN ... expression + + + + not %NULL if expression must be cast to another data type + + + + Please see specific note about the @value field + + + + + + + + + + + + + + + + Creates a new #GdaSqlField structure, using @parent as its parent part. + + + a new #GdaSqlField structure. + + + + + a #GdaSqlStatementInsert, #GdaSqlStatementUpdate, #GdaSqlSelectField, #GdaSqlSelectTarget, #GdaSqlOperation + + + + + + Creates a new #GdaSqlExpr structure initiated with the values stored in @expr. + + + a new #GdaSqlExpr structure. + + + + + a #GdaSqlExpr + + + + + + Frees a #GdaSqlExpr structure and its members. + + + + + + + a #GdaSqlExpr to be freed. + + + + + + Creates a new string representation of the SQL expression. You need to free the returned string +using g_free(); + + + a new string with the SQL expression or "null" in case @expr is invalid. + + + + + a #GdaSqlExpr structure + + + + + + Sets the expression's parent to the #GdaSqlStatementSelect held by @stmt. After +calling this function @stmt is freed. + + + + + + + a #GdaSqlExpr structure + + + + a #GdaSqlStatement holding the #GdaSqlStatementSelect to take from + + + + + + + This structure represents the name of a table's field. + + + + + + + + + validity check with a connection + + + + + + + + + + Creates a new #GdaSqlField structure, using @parent as its parent part. + + + a new #GdaSqlField structure. + + + + + a #GdaSqlStatementSelect, #GdaSqlStatementInsert, #GdaSqlStatementDelete, #GdaSqlStatementUpdate + + + + + + Creates a new GdaSqlField structure initiated with the values stored in @field. + + + a new #GdaSqlField structure. + + + + + a #GdaSqlAnyPart + + + + + + Frees a #GdaSqlField structure and its members. + + + + + + + a #GdaSqlField to be freed. + + + + + + Creates a new string representing a field. You need to free the returned string +using g_free(); + + + a new string with the name of the field or "null" in case @field is invalid. + + + + + a #GdaSqlField structure + + + + + + Sets the field's name using the string held by @value. When call, @value is freed using +#gda_value_free(). + + + + + + + a #GdaSqlField structure + + + + a #GValue holding a string to take from + + + + + + + Specifies the type of functions passed to gda_sql_any_part_foreach(). + + + FALSE if the gda_sql_any_part_foreach() should stop at this point and fail + + + + + the current #GdaSqlAnyPart node + + + + user data passed to gda_sql_any_part_foreach(). + + + + + + This structure represents a function or an aggregate with zero or more arguments. + + + inheritance structure + + + + name of the function , in the form [[catalog.]schema.]function_name + + + + list of #GdaSqlExpr expressions, one for each argument + + + + + + + + + + + + Creates a new #GdaSqlFunction structure initiated. + + + a new #GdaSqlFunction structure. + + + + + a #GdaSqlAnyPart structure + + + + + + + + + + + + + + + + + Creates a new #GdaSqlFunction structure initiated with the values stored in @function. + + + a new #GdaSqlFunction structure. + + + + + a #GdaSqlFunction structure to be copied + + + + + + Frees a #GdaSqlFunction structure and its members. + + + + + + + a #GdaSqlFunction structure to be freed + + + + + + Creates a new string representing a function. You need to free the returned string +using g_free(); + + + a new string with the description of the function or "null" in case @function is invalid. + + + + + a #GdaSqlFunction structure + + + + + + Sets the function's arguments to point to @args, then sets the +list's data elements' parent to @function. + + + + + + + a #GdaSqlFunction structure + + + + a #GSList to take from + + + + + + + + Sets the function's name using the string held by @value. When call, @value is freed using +#gda_value_free(). + + + + + + + a #GdaSqlFunction structure + + + + a #GValue holding a string to take from + + + + + + + Specifies how SQL identifiers are represented by a specific database + + + case insensitive SQL identifiers are represented in lower case (meaning that any SQL identifier which has a non lower case character is case sensitive) + + + case insensitive SQL identifiers are represented in upper case (meaning that any SQL identifier which has a non upper case character is case sensitive) + + + + This structure represents an operation between one or more operands. + + + inheritance structure + + + + operator type to be used. See #GdaSqlOperatorType + + + + +: list of #GdaSqlExpr operands + + + + + + + + + + + + Creates a new #GdaSqlOperation structure and sets its parent to @parent. + + + a new #GdaSqlOperation structure. + + + + + a #GdaSqlAnyPart structure + + + + + + Creates a new #GdaSqlOperation structure initiated with the values stored in @operation. + + + a new #GdaSqlOperation structure. + + + + + a #GdaSqlOperation structure to be copied + + + + + + Frees a #GdaSqlOperation structure and its members. + + + + + + + a #GdaSqlOperation structure to be freed + + + + + + Creates a new string representing an operator. You need to free the returned string +using g_free(); + + + a new string with the description of the operator or "null" in case @operation is invalid. + + + + + a #GdaSqlOperation structure + + + + + + Returns #GdaSqlOperatorType that correspond with the string @op. + + + #GdaSqlOperatorType + + + + + a #GdaSqlOperation structure + + + + + + Returns a constant string representing a operator name. You don't need to free +the returned string. + + + a string with the operator's name or NULL in case @op is invalid. + + + + + a #GdaSqlOperation structure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @value must contain a string representing a variable, see the documentation associated to the +#GdaSqlParser object. + +@value is destroyed by this function. + + + a new #GdaSqlParamSpec + + + + + a G_TYPE_STRING #GValue + + + + + + Creates a copy of @pspec. + + + a new #GdaSqlParamSpec + + + + + #GdaSqlParamSpec pointer + + + + + + Destroys @pspec. + + + + + + + #GdaSqlParamSpec pointer + + + + + + Creates a new string representing @pspec. + + + a new string. + + + + + a #GdaSqlParamSpec pointer + + + + + + Sets @pspec's description. @value's ownership is transferred to +@pspec (which means @pspec is then responsible for freeing it when no longer needed). + + + + + + + a #GdaSqlParamSpec pointer + + + + a G_TYPE_STRING #GValue + + + + + + Sets @pspec's name. @value's ownership is transferred to +@pspec (which means @pspec is then responsible for freeing it when no longer needed). + + + + + + + a #GdaSqlParamSpec pointer + + + + a G_TYPE_STRING #GValue + + + + + + Sets @pspec's ability of being NULL. @value's ownership is transferred to +@pspec (which means @pspec is then responsible for freeing it when no longer needed). + +If @value's string starts by 't' or 'T' then @pspec will be allowed to be %NULL + + + + + + + a #GdaSqlParamSpec pointer + + + + a G_TYPE_STRING #GValue. + + + + + + Sets @pspec's data type. @value's ownership is transferred to +@pspec (which means @pspec is then responsible for freeing it when no longer needed). + +@value must represent a data type, as understood by gda_g_type_from_string(). + + + + + + + a #GdaSqlParamSpec pointer + + + + a G_TYPE_STRING #GValue + + + + + + + + + + Creates a new #GdaSqlParser object + + + the new object + + + + + + + + + + Parse @filename's contents and creates a #GdaBatch object which contains all the + #GdaStatement objects created while parsing (one object per SQL statement). + +@filename's contents are parsed and #GdaStatement objects are created as long as no error is found. If an error is found +at some point, then the parsing stops, @error may be set and %NULL is returned + +if @sql is %NULL, then the returned #GdaBatch object will contain no statement. + + + a new #GdaBatch object, or %NULL if an error occurred + + + + + a #GdaSqlParser object + + + + name of the file to parse + + + + + + Parses @sql and creates a #GdaStatement statement from the first SQL statement contained in @sql: if @sql +contains more than one statement, then the remaining part of the string is not parsed at all, and @remain (if +not %NULL) will point at the first non parsed character. + +To include variables in the @sql string, see the +<link linkend="GdaSqlParser.description">GdaSqlParser's object description</link>. + + + a new #GdaStatement object, or %NULL if an error occurred + + + + + a #GdaSqlParser object + + + + the SQL string to parse + + + + location to store a pointer to remaining part of @sql in case @sql has multiple statement, or %NULL + + + + + + Parse @sql and creates a #GdaBatch object which contains all the #GdaStatement objects created while parsing (one object +per SQL statement). Empty statements (composed of spaces only) do not appear in the resulting object. + +@sql is parsed and #GdaStatement objects are created as long as no error is found in @sql. If an error is found +at some point, then the parsing stops and @remain may contain a non %NULL pointer, @error may be set, and %NULL +is returned. + +if @sql is %NULL, then the returned #GdaBatch object will contain no statement. + +To include variables in the @sql string, see the +<link linkend="GdaSqlParser.description">GdaSqlParser's object description</link>. + + + a new #GdaBatch object, or %NULL if an error occurred + + + + + a #GdaSqlParser object + + + + the SQL string to parse + + + + location to store a pointer to remaining part of @sql in case an error occurred while parsing @sql, or %NULL + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + This structure represents a selected item in a SELECT statement (when executed, the returned data set +will have one column per selected item). Note that the @table_name and +@field_name field parts <emphasis>will be</emphasis> overwritten by &LIBGDA;, +set the value of @expr->value instead. + + + inheritance structure + + + + expression + + + + field name part of @expr if @expr represents a field + + + + table name part of @expr if @expr represents a field + + + + alias + + + + + + + + + + + + + + + + Creates a new #GdaSqlSelectField structure and sets its parent to @parent. A +#GdaSqlSelectField is any expression in SELECT statements before the FROM clause. + + + a new #GdaSqlSelectField structure. + + + + + a #GdaSqlStatementSelect structure + + + + + + Creates a new #GdaSqlSelectField structure initiated with the values stored in @field. + + + a new #GdaSqlSelectField structure. + + + + + a #GdaSqlSelectField structure to be copied + + + + + + Frees a #GdaSqlSelectField structure and its members. + + + + + + + a #GdaSqlSelectField structure to be freed + + + + + + Creates a new string representing an expression used as field in a SELECT statement +before the FROM clause. + + + a new string with the description of the expression or "null" in case @field is invalid. + + + + + a #GdaSqlSelectField structure + + + + + + Sets the 'as' field's string in the #GdaSqlSelectField structure. @alias is freed +after call this function. + + + + + + + a #GdaSqlSelectField structure + + + + a #GValue to take from + + + + + + Sets the expression field in the #GdaSqlSelectField structure to point to @expr +and modify it to sets its parent to @field. + + + + + + + a #GdaSqlSelectField structure + + + + a #GdaSqlExpr to take from + + + + + + Sets the expression field's value in the #GdaSqlSelectField structure to point to @value; +after this @field is the owner of @value. + + + + + + + a #GdaSqlSelectField structure + + + + a #GValue to take from + + + + + + + This structure represents the FROM clause of a SELECT statement, it lists targets and joins + + + inheritance structure + + + + list of #GdaSqlSelectTarget + + + + + + list of #GdaSqlSelectJoin + + + + + + + + + + + + Creates a new #GdaSqlSelectFrom structure and sets its parent to @parent. + + + a new #GdaSqlSelectFrom structure + + + + + a #GdaSqlStatementSelect + + + + + + Creates a new #GdaSqlSelectFrom structure initiated with the values stored in @from. + + + a new #GdaSqlSelectFrom structure. + + + + + a #GdaSqlSelectFrom structure to be copied + + + + + + Frees a #GdaSqlSelectFrom structure and its members. + + + + + + + a #GdaSqlSelectFrom structure to be freed + + + + + + Creates a new string description of the FROM clause used in a SELECT statement. + + + a new string with the description of the FROM or "null" in case @from is invalid. + + + + + a #GdaSqlSelectFrom structure + + + + + + Append @join to the joins in the FROM clause and set @join's parent to +@from; after call this function @from owns @join then you must not free it. + + + + + + + a #GdaSqlSelectFrom structure + + + + a #GdaSqlSelectJoin to take from + + + + + + Append @target to the targets in the FROM clause and set @target's parent to +@from; after call this function @from owns @target then you must not free it. + + + + + + + a #GdaSqlSelectFrom structure + + + + a #GdaSqlSelectTarget to take from + + + + + + + This structure represents a join between two targets in a SELECT statement. + + + inheritance structure + + + + type of join + + + + represents a join between a target at (pos &lt; @position) and the one at @position + + + + joining expression, or %NULL + + + + list of #GdaSqlField pointers to use when joining, or %NULL + + + + + + + + + + + + Creates a new #GdaSqlSelectJoin structure and sets its parent to @parent. + + + a new #GdaSqlSelectJoin structure + + + + + a #GdaSqlSelectFrom + + + + + + Creates a new #GdaSqlSelectJoin structure initiated with the values stored in @join. + + + a new #GdaSqlSelectJoin structure. + + + + + a #GdaSqlSelectJoin structure to be copied + + + + + + Frees a #GdaSqlSelectJoin structure and its members. + + + + + + + a #GdaSqlSelectJoin structure to be freed + + + + + + Creates a new string description of the join used in a SELECT statement. + + + a new string with the description of the join or "null" in case @join is invalid. + + + + + a #GdaSqlSelectJoin structure + + + + + + Creates a new string representing the join type. + + + a string representing the Join type. + + + + + a #GdaSqlSelectJoinType structure to be copied + + + + + + + + + + + + + + + + + + + + + + This structure represents the ordering of a SELECT statement. + + + inheritance structure + + + + expression to order on + + + + TRUE is ordering is ascending + + + + name of the collation to use for ordering + + + + + + + + + + Creates a new #GdaSqlSelectOrder structure and sets its parent to @parent. + + + a new #GdaSqlSelectOrder structure + + + + + a #GdaSqlStatementSelect + + + + + + Creates a new #GdaSqlSelectOrder structure initiated with the values stored in @order. + + + a new #GdaSqlSelectOrder structure. + + + + + a #GdaSqlSelectOrder structure to be copied + + + + + + Frees a #GdaSqlSelectOrder structure and its members. + + + + + + + a #GdaSqlSelectOrder structure to be freed + + + + + + Creates a new string description of the ORDER BY clause used in a SELECT statement. + + + a new string with the description of the ORDER BY or "null" in case @order is invalid. + + + + + a #GdaSqlSelectOrder structure + + + + + + + This structure represents a target used to fetch data from in a SELECT statement; it can represent a table or +a sub select. Note that the @table_name +part <emphasis>will be</emphasis> overwritten by &LIBGDA;, +set the value of @expr->value instead. + + + inheritance structure + + + + expression + + + + table name part of @expr if @expr represents a table + + + + alias + + + + + + + + + + + + + Creates a new #GdaSqlSelectTarget structure and sets its parent to @parent. A +#GdaSqlSelectTarget is the table in a SELECT statement. + + + a new #GdaSqlSelectTarget structure. + + + + + a #GdaSqlSelectFrom + + + + + + Creates a new #GdaSqlSelectTarget structure initiated with the values stored in @target. + + + a new #GdaSqlSelectTarget structure. + + + + + a #GdaSqlSelectTarget structure to be copied + + + + + + Frees a #GdaSqlSelectTarget structure and its members. + + + + + + + a #GdaSqlSelectTarget structure to be freed + + + + + + Creates a new string representing a target used in a SELECT statement +after the FROM clause. + + + a new string with the description of the expression or "null" in case @field is invalid. + + + + + a #GdaSqlSelectTarget structure + + + + + + + + + + + + + + + + + + + + Sets the target to be a SELECT subquery setting target's expression to use +@stmt; after call this function the target owns @stmt, then you must not free it. + + + + + + + a #GdaSqlSelectTarget structure + + + + a #GValue to take from + + + + + + Sets the target's name using the string stored in @value and the expression +to set its value to point to value; after call this function the target owns +@value, then you must not free it. + + + + + + + a #GdaSqlSelectTarget structure + + + + a #GValue to take from + + + + + + + This structure is the top level structure encapsulating several type of statements. + + + + + + type of statement + + + + contents, cast it depending on @stmt_type (for example to a #GdaSqlStatementSelect). + + + + + + + + + + + + + Use this function to create a #GdaSqlStatement of the specified @type type. + + + a new #GdaSqlStatement + + + + + type of statement to create + + + + + + Cleans any data set by a previous call to gda_sql_statement_check_validity(). + + + + + + + a pinter to a #GdaSqlStatement structure + + + + + + Checks for any error in @stmt's structure to make sure the statement is valid +(for example a SELECT statement must at least return a column, a DELETE statement must specify which table +is targeted). + + + TRUE if no error occurred + + + + + a #GdaSqlStatement pointer + + + + + + If @cnc is not %NULL, then checks that all the database objects referenced in the statement actually +exist in the connection's database (for example the table being updated in a UPDATE statement must exist in the +connection's database for the check to succeed). This method fills the @stmt-&gt;validity_meta_struct attribute. + +If @cnc is %NULL, then remove any information from a previous call to this method stored in @stmt. In this case, +the @stmt-&gt;validity_meta_struct attribute is cleared. + +Also note that some parts of @stmt may be modified: for example leading and trailing spaces in aliases or +objects names will be removed. + + + TRUE if no error occurred + + + + + a #GdaSqlStatement pointer + + + + a #GdaConnection object, or %NULL + + + + + + If @mstruct is not %NULL, then checks that all the database objects referenced in the statement i +actually referenced in @mstruct + (for example the table being updated in a UPDATE statement must exist in the +connection's database for the check to succeed). +This method sets the @stmt-&gt;validity_meta_struct attribute to @mstruct. + +If @mstruct is %NULL, then remove any information from a previous call to this method stored in @stmt. In this case, +the @stmt-&gt;validity_meta_struct attribute is cleared. + +Also note that some parts of @stmt may be modified: for example leading and trailing spaces in aliases or +objects names will be removed. + + + TRUE if no error occurred + + + + + a #GdaSqlStatement pointer + + + + a #GdaMetaStruct object, or %NULL + + + + + + Specifies @stmt's type of compound + + + + + + + a #GdaSqlStatement pointer + + + + a #GdaSqlStatementCompoundType value + + + + + + Adds the @s sub-statement to the @stmt compound statement. @s's reference is transferred to +@stmt (which means @stmt is then responsible for freeing it when no longer needed). + + + + + + + a #GdaSqlStatement pointer + + + + a #GdaSqlStatement pointer + + + + + + Creates a copy of @stmt. + + + a new #GdaSqlStatement + + + + + a #GdaSqlStatement pointer + + + + + + Sets the WHERE condition of @stmt. @cond's ownership is transferred to +@stmt (which means @stmt is then responsible for freeing it when no longer needed). + + + + + + + a #GdaSqlStatement pointer + + + + the WHERE condition of the DELETE statement, as a #GdaSqlExpr + + + + + + Sets the name of the table to delete from in @stmt. @value's ownership is transferred to +@stmt (which means @stmt is then responsible for freeing it when no longer needed). + + + + + + + a #GdaSqlStatement pointer + + + + a table name as a G_TYPE_STRING #GValue + + + + + + Releases any memory associated to @stmt. + + + + + + + a #GdaSqlStatement pointer + + + + + + Sets a list of values to be inserted by @stmt. @list's +ownership is transferred to +@stmt (which means @stmt is then responsible for freeing it when no longer needed). + + + + + + + a #GdaSqlStatement pointer + + + + a list of #GdaSqlExpr pointers + + + + + + + + Sets a list of list of values to be inserted by @stmt. @list's +ownership is transferred to +@stmt (which means @stmt is then responsible for freeing it when no longer needed). + + + + + + + a #GdaSqlStatement pointer + + + + a list of #GSList of #GdaSqlExpr pointers + + + + + + + + Sets the list of fields for which values will be specified in @stmt. @list's +ownership is transferred to +@stmt (which means @stmt is then responsible for freeing it when no longer needed). + + + + + + + a #GdaSqlStatement pointer + + + + a list of #GdaSqlField pointers + + + + + + + + Sets the name of the resolution conflict algorithm used by @stmt. @value's ownership is transferred to +@stmt (which means @stmt is then responsible for freeing it when no longer needed). + + + + + + + a #GdaSqlStatement pointer + + + + name of the resolution conflict algorithm, as a G_TYPE_STRING #GValue + + + + + + Specifies a SELECT statement, the values inserted will be the result set of @select. @select's +ownership is transferred to +@stmt (which means @stmt is then responsible for freeing it when no longer needed). + + + + + + + a #GdaSqlStatement pointer + + + + a SELECT or COMPOUND #GdaSqlStatement pointer + + + + + + Sets the name of the table to insert into in @stmt. @value's ownership is transferred to +@stmt (which means @stmt is then responsible for freeing it when no longer needed). + + + + + + + a #GdaSqlStatement pointer + + + + name of the table to insert into, as a G_TYPE_STRING #GValue + + + + + + "Normalizes" (in place) some parts of @stmt, which means @stmt may be modified. +At the moment any "*" field in a SELECT statement will be replaced by one +#GdaSqlSelectField structure for each field in the referenced table. + + + TRUE if no error occurred + + + + + a pointer to a #GdaSqlStatement structure + + + + a #GdaConnection object, or %NULL + + + + + + Sets the DISTINCT clause of @stmt. + +@distinct_expr's ownership is transferred to +@stmt (which means @stmt is then responsible for freeing it when no longer needed). + + + + + + + a #GdaSqlStatement pointer + + + + a TRUE/FALSE value + + + + a #GdaSqlExpr pointer representing what the DISTINCT is on, or %NULL + + + + + + Sets list of expressions selected by @stmt + +@expr_list's ownership is transferred to +@stmt (which means @stmt is then responsible for freeing it when no longer needed). + + + + + + + a #GdaSqlStatement pointer + + + + a list of #GdaSqlSelectField pointers + + + + + + + + Sets the FROM clause of @stmt + +@from's ownership is transferred to +@stmt (which means @stmt is then responsible for freeing it when no longer needed). + + + + + + + a #GdaSqlStatement pointer + + + + a #GdaSqlSelectFrom pointer + + + + + + Sets the GROUP BY clause of @stmt + +@group_by's ownership is transferred to +@stmt (which means @stmt is then responsible for freeing it when no longer needed). + + + + + + + a #GdaSqlStatement pointer + + + + a list of #GdaSqlExpr pointer + + + + + + + + Sets the HAVING clause of @stmt + +@expr's ownership is transferred to +@stmt (which means @stmt is then responsible for freeing it when no longer needed). + + + + + + + a #GdaSqlStatement pointer + + + + a #GdaSqlExpr pointer + + + + + + Sets the LIMIT clause of @stmt + +@count and @offset's responsibility are transferred to +@stmt (which means @stmt is then responsible for freeing them when no longer needed). + + + + + + + a #GdaSqlStatement pointer + + + + a #GdaSqlExpr pointer + + + + a #GdaSqlExpr pointer + + + + + + Sets the ORDER BY clause of @stmt + +@order_by's ownership is transferred to +@stmt (which means @stmt is then responsible for freeing it when no longer needed). + + + + + + + a #GdaSqlStatement pointer + + + + a list of #GdaSqlSelectOrder pointer + + + + + + + + Sets the WHERE clause of @stmt + +@expr's ownership is transferred to +@stmt (which means @stmt is then responsible for freeing it when no longer needed). + + + + + + + a #GdaSqlStatement pointer + + + + a #GdaSqlExpr pointer + + + + + + Creates a string representation of @stmt. + + + a new string + + + + + a #GdaSqlStatement pointer + + + + + + + + + + + + + + + + + + + + Sets the model of the transaction + +@value's ownership is transferred to +@stmt (which means @stmt is then responsible for freeing it when no longer needed). + + + + + + + a #GdaSqlStatement pointer + + + + a G_TYPE_STRING value + + + + + + Sets the name of the transaction + +@value's ownership is transferred to +@stmt (which means @stmt is then responsible for freeing it when no longer needed). + + + + + + + a #GdaSqlStatement pointer + + + + a G_TYPE_STRING value + + + + + + Sets @stmt's list of expressions + +@expressions's +ownership is transferred to +@stmt (which means @stmt is then responsible for freeing it when no longer needed). + + + + + + + a #GdaSqlStatement pointer + + + + a list of #GdaSqlExpr pointers + + + + + + + + Sets the WHERE clause of @stmt + +@expr's ownership is transferred to +@stmt (which means @stmt is then responsible for freeing it when no longer needed). + + + + + + + a #GdaSqlStatement pointer + + + + a #GdaSqlExpr pointer + + + + + + Sets the name of the resolution conflict algorithm used by @stmt. @value's ownership is transferred to +@stmt (which means @stmt is then responsible for freeing it when no longer needed). + + + + + + + a #GdaSqlStatement pointer + + + + name of the resolution conflict algorithm, as a G_TYPE_STRING #GValue + + + + + + Specifies that the field named @fname will be updated with the expression @expr. + +@fname and @expr's responsibility are transferred to +@stmt (which means @stmt is then responsible for freeing them when no longer needed). + + + + + + + a #GdaSqlStatement pointer + + + + a field name, as a G_TYPE_STRING #GValue + + + + a #GdaSqlExpr pointer + + + + + + Sets the name of the table to delete from in @stmt. + +@value's ownership is transferred to +@stmt (which means @stmt is then responsible for freeing it when no longer needed). + + + + + + + a #GdaSqlStatement pointer + + + + a table name, as a G_TYPE_STRING #GValue + + + + + + + + + + + + + + + + + Converts a string to a #GdaSqlStatementType value, see also gda_sql_statement_type_to_string() + + + a #GdaSqlStatementType value + + + + + a string representing a #GdaSqlStatementType type + + + + + + Converts a #GdaSqlStatementType to a string, see also gda_sql_statement_string_to_type() + + + a constant string + + + + + a #GdaSqlStatementType value + + + + + + + Validation against a dictionary + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Contents' infos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + The statement is an INSERT statement, any kind of INSERT statement can be represented using this structure +(if this is not the case +then report a bug). +<mediaobject> + <imageobject role="html"> + <imagedata fileref="stmt-insert1.png" format="PNG"/> + </imageobject> + <caption> + <para> +Example of a #GdaSqlStatement having a #GdaSqlStatementInsert as its contents with 2 lists of values +to insert. + </para> + </caption> +</mediaobject> +<mediaobject> + <imageobject role="html"> + <imagedata fileref="stmt-insert2.png" format="PNG"/> + </imageobject> + <caption> + <para> +Another example of a #GdaSqlStatement having a #GdaSqlStatementInsert as its contents, using a SELECT +to express the values to insert. + </para> + </caption> +</mediaobject> + + + inheritance structure + + + + conflict resolution clause if there is one (such as "OR REPLACE") + + + + name of the table to which data is inserted + + + + list of #GdaSqlField fields which are valued for insertion + + + + + + list of list of #GdaSqlExpr expressions (this is a list of list, not a simple list) + + + + + + a #GdaSqlStatementSelect or #GdaSqlStatementCompound structure representing the values to insert + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + The statement is a transaction management related statement (BEGIN, ROLLBACK, etc). The #GdaSqlStatementTransaction structure +does not hold enough information to reconstruct the complete SQL statement (some information may be missing) - the aim of this +structure is to identify a minimum set of information in the transaction statement. Note that the complete SQL which created the +statement should be available in the #GdaSqlStatement structure which encapsulates this structure. + + + inheritance structure + + + + isolation level as a #GdaTransactionIsolation + + + + transaction mode (DEFERRED, IMMEDIATE, EXCLUSIVE, READ_WRITE, READ_ONLY) + + + + transaction name + + + + + + + + + + + Known types of statements + + + a SELECT statement + + + an INSERT statement + + + an UPDATE statement + + + a DELETE statement + + + a compound statement: multiple SELECT statements grouped together using an operator + + + start of transaction statement + + + transaction abort statement + + + transaction commit statement + + + new savepoint definition statement + + + return to savepoint statement + + + savepoint deletion statement + + + unknown statement, only identifies variables + + + not used + + + + Represents any statement which type is not identified (any DDL statement or database specific dialect) + + + + + + a list of #GdaSqlExpr pointers + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + This structure represents the name of a table. + + + + + + + + + + + + + + + + + + Creates a new #GdaSqlTable structure, using @parent as its parent part. + + + a new #GdaSqlTable structure. + + + + + a #GdaSqlStatementSelect, #GdaSqlStatementInsert, #GdaSqlStatementDelete, #GdaSqlStatementUpdate + + + + + + Creates a new #GdaSqlTable structure initiated with the values stored in @table. + + + a new #GdaSqlTable structure. + + + + + a #GdaSqlTable structure to be copied + + + + + + Frees a #GdaSqlTable structure and its members. + + + + + + + a #GdaSqlTable structure to be freed + + + + + + Creates a new string representing a table. You need to free the returned string +using g_free(); + + + a new string with the name of the field or "null" in case @table is invalid. + + + + + a #GdaSqlTable structure + + + + + + Sets the table's name using the string held by @value. When call, @value is freed using +gda_value_free(). + + + + + + + a #GdaSqlTable structure + + + + a #GValue holding a string to take from + + + + + + + + + Creates a new #GdaStatement object + + + the new object + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Checks that @stmt's structure is correct. + + + TRUE if @stmt's structure is correct + + + + + a #GdaStatement object + + + + + + If @cnc is not %NULL then checks that every object (table, field, function) used in @stmt +actually exists in @cnc's database + +If @cnc is %NULL, then cleans anything related to @cnc in @stmt. + +See gda_sql_statement_check_validity() for more information. + + + TRUE if every object actually exists in @cnc's database + + + + + a #GdaStatement object + + + + a #GdaConnection object, or %NULL + + + + + + Copy constructor + + + a the new copy of @orig + + + + + a #GdaStatement to make a copy of + + + + + + Get a new #GdaSet object which groups all the execution parameters +which @stmt needs. This new object is returned though @out_params. + +Note that if @stmt does not need any parameter, then @out_params is set to %NULL. + + + TRUE if no error occurred. + + + + + a #GdaStatement object + + + + a place to store a new #GdaSet object, or %NULL + + + + + + Get the type of statement held by @stmt. It returns GDA_SQL_STATEMENT_NONE if +@stmt does not hold any statement + + + the statement type + + + + + a #GdaStatement object + + + + + + Tells if @stmt is composed only of spaces (that is it has no real SQL code), and is completely +useless as such. + + + TRUE if executing @stmt does nothing + + + + + a #GdaStatement object + + + + + + "Normalizes" some parts of @stmt, see gda_sql_statement_normalize() for more +information. + + + TRUE if no error occurred + + + + + a #GdaStatement object + + + + a #GdaConnection object + + + + + + Rewrites @stmt and creates a new #GdaSqlStatement where all the variables which are to a DEFAULT value +(as returned by gda_holder_value_is_default()) are either removed from the statement (if @remove +is %TRUE) or replaced by the "DEFAULT" keyword (if @remove is %FALSE). + +This function is only useful for database providers' implementations which have to deal with default +values when executing statements, and is only relevant in the case of INSERT or UPDATE statements +(in the latter case an error is returned if @remove is %TRUE). + +For example the <programlisting><![CDATA[INSERT INTO mytable (id, name) VALUES (23, ##name::string)]]></programlisting> +is re-written into <programlisting><![CDATA[INSERT INTO mytable (id, name) VALUES (23, DEFAULT)]]></programlisting> +if @remove is %FALSE and into <programlisting><![CDATA[INSERT INTO mytable (id) VALUES (23)]]></programlisting> +if @remove is %TRUE. + + + a new #GdaSqlStatement, or %NULL if an error occurred + + + + + a #GdaStatement object + + + + a #GdaSet containing the variable's values to be bound when executing @stmt + + + + set to %TRUE if DEFAULT fields are removed, of %FALSE if the "DEFAULT" keyword is used + + + + + + Creates a string representing the contents of @stmt. + + + a string containing the serialized version of @stmt + + + + + a #GdaStatement object + + + + + + Renders @stmt as an SQL statement, with some control on how it is rendered. + +If @cnc is not %NULL, then the rendered SQL will better be suited to be used by @cnc (in particular +it may include some SQL tweaks and/or proprietary extensions specific to the database engine used by @cnc): +in this case the result is similar to calling gda_connection_statement_to_sql(). + + + a new string if no error occurred + + + + + a #GdaStatement object + + + + a #GdaConnection object, or %NULL + + + + parameters contained in a single #GdaSet object, or %NULL + + + + a set of flags to control the rendering + + + + a place to store the list of actual #GdaHolder objects in @params used to do the rendering, or %NULL + + + + + + + + + + + + + + Gets emitted whenever the structure and contents +of @stmt have been verified (emitted after gda_statement_check_validity()). + + + + + + a #GdaConnection + + + + whether @stmt have been verified + + + + + + Gets emitted whenever the @stmt has changed + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + These flags specify how the #GdaDataModel returned when executing a #GdaStatement will be used + + + access to the data model will be random (usually this will result in a data model completely stored in memory) + + + access to the data model will be done using a cursor moving forward + + + access to the data model will be done using a cursor moving backward + + + access to the data model will be done using a cursor (moving both forward and backward) + + + specifies that the data model should be executed even if some parameters required to execute it are invalid (in this case the data model will have no row, and will automatically be re-run when the missing parameters are once again valid) + + + specifies that the data model's contents will be fully loaded into the client side (the memory of the process using Libgda), not requiring the server any more to access the data (the default behaviour is to access the server any time data is to be read, and data is cached in memory). This flag is useful only if used in conjunction with the GDA_STATEMENT_MODEL_RANDOM_ACCESS flag (otherwise an error will be returned). + + + + Specifies rendering options + + + rendering will replace parameters with their values + + + rendering will include newlines and indentation to make it easy to read + + + parameters will be rendered using the "/&ast; name:&lt;param_name&gt; ... &ast;/" syntax + + + parameters will be rendered using the "##&lt;param_name&gt;..." syntax + + + parameters will be rendered using the ":&lt;param_name&gt;" syntax + + + parameters will be rendered using the "$&lt;param_number&gt;" syntax where parameters are numbered starting from 1 + + + parameters will be rendered using the "?&lt;param_number&gt;" syntax where parameters are numbered starting from 1 + + + parameters will be rendered using the "?" syntax + + + time and timestamp with a timezone information are converted to GMT before rendering, and rendering does not show the timezone information + + + + + + + + + + Creates a new #GdaText object, initialy with no string. +Use #gda_text_set_string() to set a string to. + + + a new #GdaText object + + + + + Free resources on #GdaText object. + + + + + + + a #GdaText object + + + + + + + + a string represented by #GdaText + + + + + a #GdaText object + + + + + + Set string. The string is duplicated. + + + + + + + a #GdaText object + + + + a string to set from + + + + + + Takes ownership on a given string, so you don't need to free it. + + + + + + + a #GdaText object + + + + a string to take ownership on + + + + + + The "encoding" consists in replacing non +alphanumeric character with the string "__gdaXX" where XX is the hex. representation +of the non alphanumeric char. + + + a new string + + + + + the text to convert + + + + + + + Represents a time information. + + + Creates a new #GdaTime with time now local. + + + a new #GdaTime structure + + + + + Creates new instcne of #GdaTime from #GDateTime. + + + the a new value storing a time + + + + + a #GDateTime to get time from + + + + + + Create new instance of #GdaTime from the provided values. + + + the a new value storing a time + + + + + hours + + + + minutes + + + + seconds + + + + fraction of seconds + + + + timezone in seconds added to UTC + + + + + + Create a copy of #GdaTime + + + a pointer to a new #GdaTime struct + + + + + an instance of #GdaTime to copy + + + + + + Free resources holded by the #GdaTime instance + + + + + + + a #GdaTime to free + + + + + + Extract fraction of seconds from the instance of #GdaTime + + + fraction of seconds + + + + + a #GdaTime value to get fraction of seconds from + + + + + + Get hours from the #GdaTime instance + + + + + + + a #GdaTime value to get hours from + + + + + + Get minutes from the #GdaTime instance + + + + + + + a #GdaTime value to get minutes from + + + + + + Get second component from #GdaTime + + + + + + + a #GdaTime value to get seconds from + + + + + + Returns number of seconds to be added to UTC time. + + + + + + + a #GdaTime value to get time zone from + + + + + + Returns a #GTimeZone in use in this @time. + + + + + + + a #GdaTime value to get time zone from + + + + + + Set new value for the second fraction + + + + + + + a #GdaTime value to set hours to + + + + new second fraction to set to. + + + + + + Set hour component to the #GdaTime instance. + + + + + + + a #GdaTime value to set hours to + + + + new hours to set to + + + + + + Set minutes to the #GdaTime instance + + + + + + + a #GdaTime value to set hours to + + + + new minutes to set to + + + + + + Set second component + + + + + + + a #GdaTime value to set hours to + + + + new seconds to set to + + + + + + Set timezone component for the instance of #GdaTime + + + + + + + a #GdaTime value to set time zone to + + + + new time zone to set to. See #gda_time_change_timezone + + + + + + Creates a string representation of a #GdaTime in local time +with the timezone designation. + + + a new string + + + + + #GdaTime instance to convert to string + + + + + + Creates a string representation of a #GdaTime in local time +without timezone designation. + + + a new string + + + + + #GdaTime instance to convert to string + + + + + + Creates a string representation of a #GdaTime in UTC time +with time zone indication. + + + a new string + + + + + #GdaTime instance to convert to string + + + + + + Translate @time's to give timezone + + + + + + + a valid #GdaTime + + + + a new #GTimeZone to use + + + + + + Change time zone to UTC. + + + + + + + a #GdaTime + + + + + + A time is always valid, so this method has been deprecated. + + + #TRUE if #GdaTime is valid; %FALSE otherwise. + + + + + a #GdaTime value to check if it is valid + + + + + + + Describes transactions' isolation level + + + isolation level defined by the server + + + + + + + + + + + + + + Creates a new #GdaTransactionStatus object, which allows a fine-tune and +full control of transactions to be used with providers. + + + the newly created object. + + + + + name for the transaction + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Find a pointer to the "current" _unnamed_ transaction, which is the last +transaction if there are several nested transactions + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Creates a new #GdaTree object + + + a new #GdaTree object + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Sets @manager as a top #GdaTreeManager object, which will be responsible for creating top level nodes in @tree. + + + + + + + a #GdaTree object + + + + a #GdaTreeManager object + + + + + + Removes any node in @tree + + + + + + + a #GdaTree object + + + + + + Dumps the contents of @tree to @stream, using a hierarchical view. + + + + + + + a #GdaTree + + + + a #GdaTreeNode to start the dump from, or %NULL for a full dump + + + + a stream to send the dump to, or %NULL for STDOUT + + + + + + Locates a #GdaTreeNode using the @tree_path path. + + + the requested #GdaTreeNode pointer, or %NULL if not found + + + + + a #GdaTree object + + + + full path to the required nodes (if @use_names is %TRUE, then it must start with '/') + + + + if %TRUE, then @tree_path will be interpreted as a unix style path, and if %FALSE, + then @tree_path will be interpreted similarly to the #GtkTreePath's string representation. + + + + + + Get the #GdaTreeManager which created @node in @tree + + + the #GdaTreeManager, or %NULL if @node is not present in @tree + + + + + a #GdaTree + + + + a #GdaTreeNode present in @tree + + + + + + Get the path associated to @node in @tree. + + + a new string, or %NULL if @node is not in @tree + + + + + a #GdaTree + + + + a #GdaTreeNode node in @tree + + + + + + The returned list is a list of all the #GdaTreeNode nodes <emphasis>below</emphasis> the node +at the specified path. + +As a corner case if @tree_path is %NULL, then the returned list contains all the top level nodes. + + + a new list of #GdaTreeNode pointers, free it with g_slist_free() + + + + + + + a #GdaTree object + + + + full path to the required nodes (if @use_names is %TRUE, then it must start with '/'), or %NULL + + + + if %TRUE, then @tree_path will be interpreted as a unix style path, and if %FALSE, + then @tree_path will be interpreted similarly to the #GtkTreePath's string representation. + + + + + + Sets an attribute to @tree, which will be accessible to any node in it. + + + + + + + a #GdaTree object + + + + attribute name + + + + a #GValue, or %NULL + + + + a function to be called when @attribute is not needed anymore, or %NULL + + + + + + Requests that @tree be populated with nodes. If an error occurs, then @tree's contents is left +unchanged, and otherwise @tree's previous contents is completely replaced by the new one. + + + TRUE if no error occurred. + + + + + a #GdaTree object + + + + + + Update the children of @node in @tree (not recursively, to update recursively, use +gda_tree_update_part()). If @node is %NULL then the top level nodes are updated. + + + TRUE if no error occurred. + + + + + a #GdaTree object + + + + a #GdaTreeNode node in @tree, or %NULL + + + + + + Requests that @tree be populated with nodes, starting from @node + + + TRUE if no error occurred. + + + + + a #GdaTree object + + + + a #GdaTreeNode node in @tree + + + + + + Tells if the GdaTree is a list or a tree. + + + + + + + Gets emitted when a @node has changed in @tree + + + + + + the #GdaTreeNode which has changed + + + + + + Gets emitted when a @node has been removed from @tree + + + + + + the position the node held in @tree as a tree path + + + + + + Gets emitted when a @node has has a child when it did not have any or when it +does not have a ny children anymore when it had some + + + + + + the #GdaTreeNode which changed from having children to being a + leaf or the other way around + + + + + + Gets emitted when a @node has been inserted in @tree + + + + + + the #GdaTreeNode which has inserted + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Use this method to create a new #GdaTreeManager if it's more convenient than subclassing; all is needed +is the @update_func function which is responsible for creating or updating the children nodes of a specified #GdaTreeNode. + + + a new #GdaTreeManager + + + + + the function to call when the manager object is requested to create or update its list of +#GdaTreeNode nodes + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Adds a sub manager to @manager. Use this method to create the skeleton structure +of a #GdaTree. Note that a single #GdaTreeManager can be used by several #GdaTree objects +or several times in the same #GdaTree's structure. + +Please note that it's possible for @mgr and @sub to be the same object, but beware of the possible +infinite recursive behaviour in this case when creating children nodes +(depending on the actual implementation of the #GdaTreeManager). + + + + + + + a #GdaTreeManager object + + + + a #GdaTreeManager object to add + + + + + + Requests that for any new node managed (eg. created) by @manager, a new attribute will be set. This allows +one to customize the attributes of new nodes created by an existing #GdaTreeManager. + +As a side effect, if @value is %NULL, then the corresponding attribute, if it was set, is unset. + + + + + + + a #GdaTreeManager + + + + an attribute name + + + + the attribute's value, or %NULL + + + + + + Requests that @manager creates a new #GdaTreeNode. The new node is not in any +way linked to @manager yet, consider this method as a #GdaTreeNode factory. + +This method is usually used when implementing a #GdaTreeManagerNodesFunc function (to create nodes), +or when subclassing the #GdaTreeManager. + + + a new #GdaTreeNode + + + + + a #GdaTreeManager + + + + the parent the new node may have, or %NULL + + + + name given to the new node, or %NULL + + + + + + Get the list of sub managers which have already been added using gda_tree_manager_add_manager() + + + a list of #GdaTreeMenager which should not be modified. + + + + + + + a #GdaTreeManager object + + + + + + Get the function used by @manager when creating new #GdaTreeNode nodes + + + the #GdaTreeManagerNodeFunc function, or %NULL if the default function is used + + + + + a #GdaTreeManager tree manager object + + + + + + Sets the function to be called when a new node is being created by @manager. If @func is %NULL +then each created node will be a #GdaTreeNode object. + +Specifying a custom #GdaTreeManagerNodeFunc function for example allows one to use +specialized sub-classed #GdaTreeNode objects. + + + + + + + a #GdaTreeManager tree manager object + + + + a #GdaTreeManagerNodeFunc function pointer, or %NULL + + + + + + This property specifies the function which needs to be called when the list of #GdaTreeNode nodes +managed has to be updated + + + + This property specifies if, when initially creating nodes or updating the list of nodes, +the tree manager shoud also request that each node it has created or updated also +initially create or update their children. + +This property can typically set to FALSE if the process of creating children nodes is lenghty +and needs to be postponed while an event occurs. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a new #GdaTreeNode + + + + + a #GdaTreeManager + + + + the parent the new node may have, or %NULL + + + + name given to the new node, or %NULL + + + + + + + + a new list of #GdaTreeNode objects. + + + + + + + a #GdaTreeManager + + + + a #GdaTreeNode object, or %NULL + + + + a list of #GdaTreeNode nodes which have previously been created by a similar call and +need to be updated ore moved + + + + + + a boolean to store if there was an error (can be %NULL) + + + + + + + + Creates a new #GdaTreeManager object which will add one tree node for each +column in the table named @table_name in the @schema schema. + + + a new #GdaTreeManager object + + + + + a #GdaConnection object + + + + a schema name + + + + the name of the table + + + + + + Defines the #GdaConnection to display information for. Necessary upon construction unless +the #GdaTreeMgrColumns:meta-store property is specified instead. + + + + Defines the #GdaMetaStore to extract information from. Necessary upon construction unless +the #GdaTreeMgrColumns:connection property is specified instead. This property has +priority over the GdaTreeMgrColumns:connection property. + + + + If no set, then the table name will be fetched from the parent node using the "schema" attribute + + + + If no set, then the table name will be fetched from the parent node using the "table_name" attribute + + + + + + + + + + + + + + + + Creates a new #GdaTreeManager object which will add one tree node labelled @label + + + a new #GdaTreeManager object + + + + + a label string + + + + + + + + + + + + + + + + + + + + + Creates a new #GdaTreeManager object which will add one tree node for each database schema found +in @cnc. + + + a new #GdaTreeManager object + + + + + a #GdaConnection object + + + + + + Defines the #GdaConnection to display information for. Necessary upon construction unless +the #GdaTreeMgrSchema:meta-store property is specified instead. + + + + Defines the #GdaMetaStore to extract information from. Necessary upon construction unless +the #GdaTreeMgrSchema:connection property is specified instead. This property has +priority over the GdaTreeMgrSchema:connection property. + + + + + + + + + + + + + + + + Creates a new #GdaTreeMgrSelect object which will add one tree node for each row in +the #GdaDataModel resulting from the execution of @stmt. + + + a new #GdaTreeManager object + + + + + a #GdaConnection object + + + + a #GdaStatement object representing a SELECT statement + + + + a #GdaSet object representing fixed parameters which are to be used when executing @stmt + + + + + + + + + + + + + + + + + + + + + + + + + + + Creates a new #GdaTreeManager object which will add one tree node for each table found in the +@schema if it is not %NULL, or for each table visible by default in @cnc. + + + a new #GdaTreeManager object + + + + + a #GdaConnection object + + + + a schema name or %NULL + + + + + + Defines the #GdaConnection to display information for. Necessary upon construction unless +the #GdaTreeMgrTables:meta-store property is specified instead. + + + + Defines the #GdaMetaStore to extract information from. Necessary upon construction unless +the #GdaTreeMgrTables:connection property is specified instead. This property has +priority over the GdaTreeMgrTables:connection property. + + + + If no set, then the table name will be fetched from the parent node using the "schema" attribute. If not +found that way, then the list of visible tables (tables which can be identified without having to specify +a schema) will be used + + + + + + + + + + + + + + + + Creates a new #GdaTreeNode object + + + a new #GdaTreeNode + + + + + a name, or %NULL + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Get the value associated to the attribute named @attribute for @node. If the attribute is not set, +then @node's parents is queries (recursively up to the top level node). + +Attributes can have any name, but Libgda proposes some default names, +see <link linkend="libgda-40-Attributes-manager.synopsis">this section</link>. + + + a read-only #GValue, or %NULL if not attribute named @attribute has been set for @node + + + + + a #GdaTreeNode + + + + attribute name as a string + + + + + + Get the #GdaTreeNode child of @node at position @index (starting at 0). + + + the #GdaTreeNode, or %NULL if not found + + + + + a #GdaTreeNode object + + + + a index + + + + + + Get the #GdaTreeNode child of @node which has the #GDA_ATTRIBUTE_NAME set to @name + + + the #GdaTreeNode, or %NULL if not found + + + + + a #GdaTreeNode object + + + + requested node's name + + + + + + Get a list of all @node's children, free it with g_slist_free() after usage + + + a new #GSList of #GdaTreeNode objects, or %NULL if @node does not have any child + + + + + + + a #GdaTreeNode object + + + + + + Get the value associated to the attribute named @attribute for @node. The difference with gda_tree_node_fetch_attribute() +is that gda_tree_node_fetch_attribute() will also query @node's parents (recursively up to the top level node) if +the attribute is not set for @node. + +Attributes can have any name, but Libgda proposes some default names, +see <link linkend="libgda-40-Attributes-manager.synopsis">this section</link>. + + + a read-only #GValue, or %NULL if not attribute named @attribute has been set for @node + + + + + a #GdaTreeNode + + + + attribute name as a string + + + + + + Get the #GdaTreeNode parent of @node in the #GdaTree node belongs to. If @node is at the top level, +then this method return %NULL. + + + the parent #GdaTreeNode + + + + + a #GdaTreeNode object + + + + + + Set the value associated to a named attribute. The @attribute string is used AS IT IS by this method (eg. +no copy of it is made), and +the memory it uses will be freed using the @destroy function when no longer needed (if @destroy is %NULL, +then the string will not be freed at all). + +Attributes can have any name, but Libgda proposes some default names, +see <link linkend="libgda-40-Attributes-manager.synopsis">this section</link>. + +For example one would use it as: + +<code> +gda_tree_node_set_node_attribute (node, g_strdup (my_attribute), my_value, g_free); +gda_tree_node_set_node_attribute (node, GDA_ATTRIBUTE_NAME, my_value, NULL); +</code> + +If there is already an attribute named @attribute set, then its value is replaced with the new value (@value is +copied), except if @value is %NULL, in which case the attribute is removed. + + + + + + + a #GdaTreeNode + + + + attribute name + + + + a #GValue, or %NULL + + + + a function to be called when @attribute is not needed anymore, or %NULL + + + + + + + + + + + + Gets emitted when a @node has changed + + + + + + the #GdaTreeNode which has changed + + + + + + Gets emitted when a @node has been removed + + + + + + the path the node held, relative to @reporting + + + + + + Gets emitted when a @node has has a child when it did not have any or when it +does not have a ny children anymore when it had some + + + + + + the #GdaTreeNode which changed from having children to being a + leaf or the other way around + + + + + + Gets emitted when a @node has been inserted + + + + + + the #GdaTreeNode which has been inserted + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Attributes of a value, used internally by Libgda in different contexts. Values can be OR'ed. + + + no specific attribute + + + value is NULL (in the SQL sense) + + + value can be set to NULL (in the SQL sense) + + + value is defined as the default value (the value itself is not specified) + + + a default value (not specified) exists for the value + + + the value has not been changed (in the context of the attribute usage) + + + the value is not valid (with regards to the context) + + + the value can be resetted to its "original" value (i.e. before it was modified) + + + + + the value can't be modified + + + + + + Creates a new #GdaWorker object. + + + a new #GdaWorker, or %NULL if an error occurred + + + + + Cancels a job which has not yet been processed. If the job cannot be found, is being processed or has already been processed, +then this function returns %FALSE. + +This function can be called on already cancelled jobs, and simply returns %TRUE in that case. + + + %TRUE if the job was cancelled + + + + + a #GdaWorker object + + + + the ID of the job, as returned by gda_worker_submit_job() + + + + + + Request that the worker thread call @func with the @data argument, much like gda_worker_submit_job(), +but waits (starting a #GMainLoop) for a maximum of @timeout_ms miliseconds for @func to be executed. + +If this function is called from within @worker's worker thread, then this function simply calls @func with @data and does not +use @context. + +The following cases are possible if this function is not called from within @worker's worker thread: +<itemizedlist> + <listitem><para>the call to @func took less than @timeout_ms miliseconds: the return value is %TRUE and + @out_result contains the result of the @func's execution, and @out_job_id contains %NULL. Note in this + case that @error may still contain an error code if @func's execution produced an error. Also note that in this case + any setting defined by gda_worker_set_callback() is not applied (as the result is immediately returned)</para></listitem> + <listitem><para>The call to @func takes more then @timeout_ms miliseconds: the return value is %TRUE and + @out_result is %NULL and @out_job_id contains the ID of the job as if it had been submitted using gda_worker_submit_job(). + If @out_job_id is %NULL, and if no setting has been defined using gda_worker_set_callback(), then the job will be discarded + (as if gda_worker_forget_job() had been called). + </para></listitem> + <listitem><para>The call to @func could not be done (some kind of plumbing error for instance): the returned value is %FALSE + and @out_result and @out_job_id are set to %NULL (if they are not %NULL)</para></listitem> +</itemizedlist> + +Notes: +<itemizedlist> + <listitem><para>@result_destroy_func is needed in case @out_result is %NULL (to avoid memory leaks)</para></listitem> + <listitem><para>passing %NULL for @context is similar to passing the result of g_main_context_ref_thread_default()</para></listitem> +</itemizedlist> + + + %TRUE if no error occurred + + + + + a #GdaWorker object + + + + a #GMainContext to execute a main loop in (while waiting), or %NULL + + + + the maximum number of milisecons to wait before returning, or %0 for unlimited wait + + + + a place to store the result, if any, of @func's execution, or %NULL + + + + a place to store the ID of the job having been submitted, or %NULL + + + + the function to call from the worker thread + + + + the data to pass to @func, or %NULL + + + + a function to destroy @data, or %NULL + + + + a function to destroy the result, if any, of @func's execution, or %NULL + + + + + + Fetch the value returned by execution the @job_id job. + +Warning: if an error occurred during the +execution of the requested function within the worker thread, then it will show as @error, while the return value +of this function will be %TRUE. + +Note: if there is a result, it will be stored in @out_result, and it's up to the caller to free +the result, the #GdaWorker object will not do it (ownership of the result is transfered to the caller). + + + %TRUE if the jobs has completed + + + + + a #GdaWorker object + + + + the ID of the job, as returned by gda_worker_submit_job() + + + + a place to store the value returned by the execution of the requested function within the worker thread, or %NULL + + + + + + Forget all about the job with ID @job_id. As opposed to gda_worker_cancel_job(), this function can be used to tell +@worker that whatever happens to the specific job, you are not interrested anymore (i.e. that @worker can +do whatever is possible to simple discard everything related to that job). + + + + + + + a #GdaWorker object + + + + the ID of the job, as returned by gda_worker_submit_job() + + + + + + Get a pointer to @worker's inner worker thread + + + the #GThread + + + + + a #GdaWorker + + + + + + Increases @worker's reference count. + + + @worker + + + + + a #GdaWorker + + + + + + Declare a callback function to be called when a job has been processed. If @callback is %NULL, then any previously +effect of this function is removed. If the same function is called with a different @callback value, then the previous one +is simply replaced. + +Since this function adds a new source of events to the specified #GMainContext (or the default one if @context is %NULL), + +Notes: +<itemizedlist> + <listitem><para>before calling this function, @worker internally gets rid of the job, so the @jib_id passed + to @callback does not actually designate a known job ID, and so calling gda_worker_fetch_job_result() for that + job ID will fail</para></listitem> + <listitem><para>the job's result, if any, has to be freed by @callback (@worker does not do it)</para></listitem> + <listitem><para>any call to this function will only be honored for the jobs submitted _after_ calling it, the ones + submitted before are not affected</para></listitem> + <listitem><para>passing %NULL for @context is similar to passing the result of g_main_context_ref_thread_default()</para></listitem> +</itemizedlist> + + + %TRUE if no error occurred. + + + + + a #GdaWorker object + + + + a #GMainContext, or %NULL + + + + the function to call when a job submitted from within the calling thread using gda_worker_submit_job() has finished being processed. + + + + argument passed to @callback + + + + + + Request that the worker thread call @func with the @data argument. + +Notes: +<itemizedlist> + <listitem><para>if @data_destroy_func is not %NULL, then it will be called to destroy @data when the job is removed, + which can occur within the context of the worker thread, or within the context of any thread using @worker.</para></listitem> + <listitem><para>if @result_destroy_func is not %NULL, then it will be called to destroy the result produced by @func. + Similarly to @data_destroy_func, if it is not %NULL (and if there is a non %NULL result), then that function can be + called in the context of any thread.</para></listitem> + <listitem><para>the error here can only report failures while executing gda_worker_submit_job(), not any error which may occur + while executing @func from the worker thread.</para></listitem> + <listitem><para>when this function returns, the job may already have been completed, so you should not assume that the job + is in any specific state.</para></listitem> + <listitem><para>passing %NULL for @callback_context is similar to passing the result of g_main_context_ref_thread_default()</para></listitem> +</itemizedlist> + + + a job ID, or %0 if an error occurred + + + + + a #GdaWorker object + + + + a #GMainContext, or %NULL (ignored if no setting has been defined with gda_worker_set_callback()) + + + + the function to call from the worker thread + + + + the data to pass to @func, or %NULL + + + + a function to destroy @data, or %NULL + + + + a function to destroy the result, if any, of the execution of @func, or %NULL + + + + + + Tells if the thread from which this function is called is @worker's worker thread. + + + %TRUE if this function is called is @worker's worker thread + + + + + a #GdaWorker + + + + + + Decreases @worker's reference count. When reference count reaches %0, then the +object is destroyed, note that in this case this function only returns when the +worker thread actually has terminated, which can take some time if it's busy. + +If @worker is %NULL, then nothing happens. + + + + + + + a #GdaWorker, or %NULL + + + + + + Request that the worker thread call @func with the @data argument, much like gda_worker_submit_job(), +but waits (blocks) until @func has been executed. + +Note: it's up to the caller to free the result, the #GdaWorker object will not do it (ownership of the result is +transfered to the caller). + + + the result of @func's execution + + + + + a #GdaWorker object + + + + the function to call from the worker thread + + + + the data to pass to @func, or %NULL + + + + a function to destroy @data, or %NULL + + + + + + + + + + + This function creates a new #GdaWorker, or reuses the one at @location. Specifically: +<orderedlist> + <listitem><para>if *@location is %NULL, then a new #GdaWorker is created. In this case if @allow_destroy is %FALSE, then the returned + #GdaWorker's reference count is 2, thus preventing it form ever being destroyed (unless gda_worker_unref() is called somewhere else)</para></listitem> + <listitem><para>if *@location is not %NULL, the the #GdaWorker it points to is returned, its reference count increased by 1</para></listitem> +</orderedlist> + +When the returned #GdaWorker's reference count reaches 0, then it is destroyed, and *@location is set to %NULL. + +In any case, the returned value is the same as *@location. + + + a #GdaWorker + + + + + a place to store and test for existence, not %NULL + + + + defines if the created @GdaWorker (see case 1 below) will allow its reference to drop to 0 and be destroyed + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Specifies the type of function to be passed to gda_worker_submit_job(), gda_worker_do_job() and gda_worker_wait_job(). + + + a pointer to some data which will be returned by gda_worker_fetch_job_result() + + + + + pointer to the data (which is the argument passed to gda_worker_submit_job()) + + + + + + + + Creates a new #GdaXaTransaction object, which will control the process of +performing a distributed transaction across several connections. + + + the newly created object. + + + + + a format ID + + + + the global transaction ID + + + + + + + + + + + Creates a new #GdaXaTransactionId structure from its string representation, it's the opposite +of gda_xa_transaction_id_to_string(). + + + a new #GdaXaTransactionId structure, or %NULL in @str has a wrong format + +Free-function: g_free + + + + + a string representation of a #GdaXaTransactionId, in the "gtrid,bqual,formatID" format + + + + + + Begins a distributed transaction (managed by @xa_trans). Please note that this phase may fail +for some connections if a (normal) transaction is already started (this depends on the database +provider being used), so it's better to avoid starting any (normal) transaction on any of the +connections registered with @xa_trans. + + + TRUE if no error occurred + + + + + a #GdaXaTransaction object + + + + + + Commits a distributed transaction (managed by @xa_trans). The commit is composed of two phases: +<itemizedlist> + <listitem><para>a PREPARE phase where all the connections are required to store their transaction data to a + permanent place (to be able to complete the commit should a problem occur afterwards)</para></listitem> + <listitem><para>a COMMIT phase where the transaction data is actually written to the database</para></listitem> +</itemizedlist> + +If the PREPARE phase fails for any of the connection registered with @xa_trans, then the distributed commit +fails and FALSE is returned. During the COMMIT phase, some commit may actually fail but the transaction can +still be completed because the PREPARE phase succeeded (through the recover method). + + + TRUE if no error occurred (there may be some connections to recover, though) + + + + + a #GdaXaTransaction object + + + + a place to store the list of connections for which the commit phase failed, or %NULL + + + + + + + + Tries to commit the data prepared but which failed to commit (see gda_xa_transaction_commit()). This +method allows one to terminate a distributed transaction which succeeded but for which some +connections needed to be recovered. + + + %TRUE if all the data which was still uncommitted has been committed + + + + + a #GdaXaTransaction object + + + + a place to store the list of connections for which the there were data to recover and which failed to be actually committed, or %NULL + + + + + + + + Registers @cnc to be used by @xa_trans to create a distributed transaction. + +Note: any #GdaConnection object can only be registered with at most one #GdaXaTransaction object; also +some connections may not be registered at all with a #GdaXaTransaction object because the database +provider being used does not support it. + + + %TRUE if no error occurred + + + + + a #GdaXaTransaction object + + + + the connection to add to @xa_trans + + + + the branch qualifier + + + + + + Cancels a distributed transaction (managed by @xa_trans). + + + %TRUE if no error occurred + + + + + a #GdaXaTransaction object + + + + + + Unregisters @cnc to be used by @xa_trans to create a distributed transaction. This is +the opposite of gda_xa_transaction_register_connection(). + + + + + + + a #GdaXaTransaction object + + + + the connection to add to @xa_trans + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + any number + + + + number between 1 and 64 + + + + number between 1 and 64 + + + + + + + + + Creates a string representation of @xid, in the format &lt;gtrid&gt;,&lt;bqual&gt;,&lt;formatID&gt; the +&lt;gtrid&gt; and &lt;bqual&gt; strings contain alphanumeric characters, and non alphanumeric characters +are converted to "%ab" where ab is the hexadecimal representation of the character. + + + a new string representation of @xid + + + + + a #GdaXaTransactionId pointer + + + + + + + + + + + + + + + + + + + + + + Does the opposite of gda_text_to_alphanum(), in the same string + + + @text if conversion succeeded or %NULL if an error occurred + + + + + a string + + + + + + This function is similar to gda_column_set_attribute() but for static strings + + + + a #GdaHolder + + + attribute's name + + + the value to set the attribute to, or %NULL + + + + + Creates an array of strings (terminated by a %NULL) corresponding to possible completions. +If no completion is available, then the returned array contains just one NULL entry, and +if it was not possible to try to compute a completions list, then %NULL is returned. + + + a new array of strings, or %NULL (use g_strfreev() to free the returned array) + + + + + + + a #GdaConnection object + + + + a partial SQL statement which is the context of the completion proposal, may also start with a "." for + Gda's tools which use internal commands + + + + starting position within @sql of the "token" to complete (starts at 0) + + + + ending position within @sql of the "token" to complete + + + + + + Creates an INSERT, an UPDATE and a DELETE statement from a SELECT statement +using the database metadata available in @cnc's meta store. Each statements are computed only if +the corresponding place to store the created statement is not %NULL. + + + %TRUE if no error occurred + + + + + a #GdaConnection + + + + a SELECT #GdaStatement (compound statements not handled) + + + + TRUE if the created statement have to use a primary key + + + + a place to store the created INSERT statement, or %NULL + + + + a place to store the created UPDATE statement, or %NULL + + + + a place to store the created DELETE statement, or %NULL + + + + + + Computes a SELECT statement which selects all the rows the @update_stmt would update. Beware +however that this #GdaSqlStatement does not select anything (ie it would be rendered as "SELECT FROM ... WHERE ...") +and before being usable, one needs to add some fields to actually select. + + + a new #GdaStatement if no error occurred, or %NULL otherwise + + + + + an UPDATE statement + + + + + + Computes a #GdaSqlExpr expression which can be used in the WHERE clause of an UPDATE +or DELETE statement when a row from the result of the @stsel statement has to be modified. + + + a new #GdaSqlExpr, or %NULL if an error occurred. + + + + + a #GdaSqlSelectStatement + + + + a #GdaMetaTable + + + + set to TRUE if a primary key ir required + + + + + + Computes a #GdaSqlExpr expression which can be used in the WHERE clause of an UPDATE +or DELETE statement when a row from the result of the @stsel statement has to be modified. + +If @require_pk is %TRUE then this function will return a non %NULL #GdaSqlExpr only if it can +use a primary key of @mtable. If @require_pk is %FALSE, then it will try to use a primary key of @mtable, +and if none is available, it will use all the columns of @mtable to compute a condition statement. + + + a new #GdaSqlExpr, or %NULL if an error occurred. + + + + + a #GdaConnection, or %NULL + + + + a #GdaSqlSelectStatement + + + + a #GdaMetaTable + + + + set to %TRUE if a primary key is required + + + + + + Obtain a pointer to a #GdaDataHandler which can manage #GValue values of type @for_type. The returned +data handler will be adapted to use the current locale information (for example dates will be formatted +taking into account the locale). + +The returned pointer is %NULL if there is no default data handler available for the @for_type data type + + + a #GdaDataHandler which must be destroyed using g_object_unref() + + + + + a #GType type + + + + + + + + + + + + + + + + + + + + + + + + + + + Escapes @string to make it understandable by a DBMS. The escape method is very common and replaces any +occurrence of "'" with "''" and "\" with "\\" + + + a new string + + + + + string to escape + + + + + + Do the reverse of gda_default_escape_string(): transforms any "''" into "'", any +"\\" into "\" and any "\'" into "'". + + + a new unescaped string, or %NULL in an error was found in @string + + + + + string to unescape + + + + + + Extract the DSN, username and password from @string. in @string, the various parts are strings +which are expected to be encoded using an RFC 1738 compliant encoding. If they are specified, +the returned username and password strings are correctly decoded. + +@out_username and @out_password may be set to %NULL depending on @string's format. + + + + + + + a string in the "[&lt;username&gt;[:&lt;password&gt;]@]&lt;DSN&gt;" form + + + + a place to store the new string containing the &lt;DSN&gt; part + + + + a place to store the new string containing the &lt;username&gt; part + + + + a place to store the new string containing the &lt;password&gt; part + + + + + + Converts a named type to ts GType type (also see the gda_g_type_to_string() function). + +This function is a wrapper around the g_type_from_name() function, but also recognizes +some type synonyms such as: +<itemizedlist> + <listitem><para>"int" for G_TYPE_INT</para></listitem> + <listitem><para>"uint" for G_TYPE_UINT</para></listitem> + <listitem><para>"int64" for G_TYPE_INT64</para></listitem> + <listitem><para>"uint64" for G_TYPE_UINT64</para></listitem> + <listitem><para>"char" for G_TYPE_CHAR</para></listitem> + <listitem><para>"uchar" for G_TYPE_UCHAR</para></listitem> + <listitem><para>"short" for GDA_TYPE_SHORT</para></listitem> + <listitem><para>"ushort" for GDA_TYPE_USHORT</para></listitem> + <listitem><para>"string" for G_TYPE_STRING</para></listitem> + <listitem><para>"date" for G_TYPE_DATE</para></listitem> + <listitem><para>"time" for GDA_TYPE_TIME</para></listitem> + <listitem><para>"timestamp" for G_TYPE_DATE_TIME</para></listitem> + <listitem><para>"boolean" for G_TYPE_BOOLEAN</para></listitem> + <listitem><para>"blob" for GDA_TYPE_BLOB</para></listitem> + <listitem><para>"binary" for GDA_TYPE_BINARY</para></listitem> + <listitem><para>"null" for GDA_TYPE_NULL</para></listitem> +</itemizedlist> + + + the #GType represented by the given @str, or #G_TYPE_INVALID if not found + + + + + the name of a #GType, as returned by gda_g_type_to_string(). + + + + + + Converts a GType to its string representation (use gda_g_type_from_string() for the +operation in the other direction). + +This function wraps g_type_name() but for common types it provides an easier to +understand and remember name. For Example the G_TYPE_STRING is converted to "string" +whereas g_type_name() converts it to "gchararray". + + + the GDA's string representing the given #GType or the name +returned by #g_type_name. + + + + + Type to convert from. + + + + + + he #GdaAttributesManager manages lists of named values (attributes) for the benefit of +others (objects or resources for which only a pointer is known). It is used internally by &LIBGDA; +whenever an object or a simple structure may have several attributes. + +The features are similar to those of the <link linkend="g-object-set-data">g_object_set_data()</link> and similar +but with the following major differences: +<itemizedlist> + <listitem><para>it works with GObject objects and also with simple pointers to data</para></listitem> + <listitem><para>attributes names are considered static (they are not copied) and so they must either be static strings or allocated strings which exist (unchanged) while an attribute uses it as name</para></listitem> + <listitem><para>it is possible to iterate through the attributes</para></listitem> + <listitem><para>the associated values are expected to be #GValue values</para></listitem> +</itemizedlist> + +Attibute names can be any string, but &LIBGDA; reserves some for its own usage, see below. + +The #GdaAttributesManager implements its own locking mechanism so it is thread-safe. + + + The #GdaBatch object represents one or more SQL statements (as #GdaStatement objects) in a single object. + +A #GdaBatch can either be built "manually" by assembling together several #GdaStatement objects, +or from an SQL string using a #GdaSqlParser object. + + + This object is a base class for individual database providers which support BLOB types. It supports +operations to read and write data in a BLOB value (of type GDA_BLOB_TYPE). + +Libgda offers two methods to manipulate binary values as two containers: <link linkend="GdaBinary">GdaBinary</link> +and <link linkend="GdaBlob">GdaBlob</link>: +<itemizedlist> + <listitem><para>When reading from a data model returned by &LIBGDA; binary data will often be in a GdaBlob + object, and the associated <link linkend="GdaBlobOp">GdaBlobOp</link> object can be used to manipulate the + binary object (in a database for example)</para></listitem> + <listitem><para>When the binary value is created by the user, then there is no point in using a GdaBlob as + there can not be any <link linkend="GdaBlobOp">GdaBlobOp</link> object, so the GdaBinary container is + enough.</para></listitem> +</itemizedlist> + +Note that a <link linkend="GdaBlob">GdaBlob</link> value (the "data" attribute) will often not contain any data +(or only some part of the actual BLOB) +and that it's up to the user to use the associated <link linkend="GdaBlobOp">GdaBlobOp</link> object to +"load" the data into the container (into the actual process heap). + +For example to load the 1st 40 bytes of a blob: + <programlisting> +GValue *blob_value = ... +GdaBlob *blob; + +blob = (GdaBlob*) gda_value_get_blob (blob_value); +gda_blob_op_read (blob->op, blob, 0, 40); + </programlisting> + +Another example is to write the contents of a blob to a file on disk, using a special + <link linkend="GdaBlobOp">GdaBlobOp</link> object (internal to &LIBGDA; which interfaces + with a file in a filesystem): + <programlisting> +GValue *blob_value; // value to copy from +GValue *tmp_value; +GdaBlob *file_blob; + +GValue *blob_value = ... +tmp_value = gda_value_new_blob_from_file ("MyFile.bin"); +file_blob = (GdaBlob*) gda_value_get_blob (tmp_value); + +if (! gda_blob_op_write_all (file_blob->op, gda_value_get_blob (blob_value))) { + // error +} +else { + gsize size; + size = gda_blob_op_get_length (file_blob->op); + g_print ("Wrote %s, size = %d\n", filename, size); +} +gda_value_free (tmp_value); + </programlisting> + +For further information, see: + <itemizedlist> + <listitem><para>the section about <link linkend="gen_blobs">Binary large objects (BLOBs)</link>'s + abstraction</para></listitem> + <listitem><para><link linkend="libgda-provider-blobop">Virtual methods for Blob operations</link> + section for more information + about how to implement the virtual methods when creating a database provider</para></listitem> + </itemizedlist> + + + The #GdaColumn object represents a #GdaDataModel's column and handle all its properties. + + + The functions in this section allow applications an easy access to libgda's +configuration (the list of data sources and database providers). + +As soon as a <link linkend="GdaConfig">GdaConfig</link> is needed (for example when requesting information +about a data source or about a server provider), a single instance object is created, +and no other will need to be created. A pointer to this object can be obtained with +<link linkend="gda-config-get">gda_config_get()</link>. Of course one can (right after having called +<link linkend="gda-init">gda_init()</link>) force the creation of a GdaConfig object with some +specific properties set, using a simple call like: +<programlisting> +g_object_new (GDA_TYPE_CONFIG, "user-filename", "my_file", NULL); +</programlisting> +Please note that after that call, the caller has a reference to the newly created object, and should technically +call <link linkend="g-object-unref">g_object_unref()</link> when finished using it. It is safe to do this +but also pointless since that object should not be destroyed (as no other will be created) as &LIBGDA; also +keeps a reference for itself. + +Data sources are defined in a per-user configuration file which is by default <filename>${HOME}/.libgda/config</filename> and +in a system wide configuration file which is by default <filename>${prefix}/etc/libgda-4.0/config</filename>. Those +filenames can be modified by setting the <link linkend="GdaConfig--user-file">user-file</link> and +<link linkend="GdaConfig--system-file">system-file</link> properties for the single <link linkend="GdaConfig">GdaConfig</link> +instance. Note that setting either of these properties to <literal>NULL</literal> will disable using the corresponding +configuration file (DSN will exist only in memory and their definition will be lost when the application finishes). + +The #GdaConfig object implements its own locking mechanism so it is thread-safe. + +Note about localization: when the #GdaConfig loads configuration files, it filters the +contents based on the current locale, so for example if your current locale is "de" then +all the loaded strings (for the ones which are translated) will be in the German language. +Changing the locale afterwards will have no effect on the #GdaConfig and the already loaded +configuration. +The consequence is that you should first call setlocale() youself in your code before using +a #GdaConfig object. As a side note you should also call gtk_init() before gdaui_init() because +gtk_init() calls setlocale(). + + + Each connection to a database is represented by a #GdaConnection object. A connection is created +using gda_connection_new_from_dsn() if a data source has been defined, or gda_connection_new_from_string() +otherwise. It is not recommended to create a #GdaConnection object using g_object_new() as the results are +unpredictable (some parts won't correctly be initialized). + +Once the connection has been created, it can be opened using gda_connection_open() or gda_connection_open_async(). +By default these functions will block, unless you speficy a #GMainContext from which events will be processed +while opening the connection using gda_connection_set_main_context(). + +The same gda_connection_set_main_context() allows the program to still handle events while a +potentially blocking operation (such as executing a statement) is being carried out (this is a change compared to the +#GdaConnection object in Libgda versions before 6.x, where asynchronous execution was featured +using a set of specific functions like gda_connection_async_statement_execute()). + +The #GdaConnection object implements its own locking mechanism so it is thread-safe. If a #GMainContext has been +specified using gda_connection_set_main_context(), then the events will continue to be processed while the +lock on the connection is being acquired. + + + Events occurring on a connection are each represented as a #GdaConnectionEvent object. Each #GdaConnection +is responsible for keeping a list of past events; that list can be consulted using the +gda_connection_get_events() function. + + + The #GdaDataAccessWrapper object simply wraps another #GdaDataModel data model object +and allows data to be accessed in a random way while remaining memory efficient as much as possible. + + + The #GdaDataComparator is a simple object which takes two #GdaDataModel objects and compare them. +Actual comparison is performed when the gda_data_comparator_compute_diff() is called; for each +difference found, the <link linkend="GdaDataComparator-diff-computed">diff-computed</link> signal +is emitted (any user installed signal handler which returns FALSE stops the computing process). + +There are some limitations to this object: +<itemizedlist> + <listitem><para>The data models compared must have the same number and type of columns</para></listitem> + <listitem><para>The comparison is done column-for-column: one cannot omit columns in the comparison, nor compare + columns with different positions</para></listitem> +</itemizedlist> + + + Because data types vary a lot from a DBMS to another, the #GdaDataHandler interface helps +managing data in its various representations, and converting from one to another: +<itemizedlist> + <listitem><para>as a #GValue which is a generic value container for the C language</para></listitem> + <listitem><para>as a human readable string (in the user defined locale)</para></listitem> + <listitem><para>as an SQL string (a string which can be used in SQL statements)</para></listitem> +</itemizedlist> + +For each data type, a corresponding #GdaDataHandler object can be requested using the +<link linkend="gda-data-handler-get-default">gda_data_handler_get_default()</link> function. However, when working +with a specific database provider, it's better to use a #GdaDataHandler which may be specific to the +database provider which will correctly handle each database specifics using +<link linkend="gda-server-provider-get-data-handler-g-type">gda_server_provider_get_data_handler_g_type()</link> or +<link linkend="gda-server-provider-get-data-handler-dbms">gda_server_provider_get_data_handler_dbms()</link>. + + + A #GdaDataModel represents an array of values organized in rows and columns. All the data in the same +column have the same type, and all the data in each row have the same semantic meaning. The #GdaDataModel is +actually an interface implemented by other objects to support various kinds of data storage and operations. + +When a SELECT statement is executed using an opened #GdaConnection, the returned value (if no error occurred) +is a #GdaDataSelect object which implements the #GdaDataModel interface. Please see the #GdaDataSelect's +documentation for more information. + +Depending on the real implementation, the contents of data models may be modified by the user using functions +provided by the model. The actual operations a data model permits can be known using the +gda_data_model_get_access_flags() method. + +Again, depending on the real implementation, data retrieving can be done either accessing direct random +values located by their row and column, or using a cursor, or both. Use the gda_data_model_get_access_flags() +method to know how the data model can be accessed. +<itemizedlist> + <listitem><para>Random access to a data model's contents is done using gda_data_model_get_value_at(), or using + one or more #GdaDataModelIter object(s);</para></listitem> + <listitem><para>Cursor access to a data model's contents is done using a #GdaDataModelIter object. If this mode is + the only supported, then only one #GdaDataModelIter object can be created and + it is <emphasis>not possible</emphasis> to use gda_data_model_get_value_at() in this case.</para></listitem> +</itemizedlist> + +Random access data models are easier to use since picking a value is very simple using the gda_data_model_get_value_at(), +but consume more memory since all the accessible values must generally be present in memory even if they are not used. +Thus if a data model must handle large quantities of data, it is generally wiser to use a data model which can be +only accessed using a cursor. + +As a side note there are also data models which wrap other data models such as: +<itemizedlist> + <listitem><para>The #GdaDataProxy data model which stores temporary modifications and shows only some + parts of the wrapped data model</para></listitem> + <listitem><para>The #GdaDataAccessWrapper data model which offers a memory efficient random access on top of a + wrapped cursor based access data model</para></listitem> +</itemizedlist> + +Also see the section about <link linkend="gda-data-model-writing">writing your own GdaDataModel</link> + +Finally, the #GdaDataModel object implements its own locking mechanism and can be used simultaneously from several threads. + + + The #GdaDataModelArray object is a data model which internally uses a #GArray to index all its rows (represented +as #GdaRow objects). In this data model, all the data is stored in memory, which can be a memory limitation if the number +of rows is huge. +This type of data model is easy to use to store some temporary data, and has a random access mode (any value can be accessed +at any time without the need for an iterator). + + + The #GdaDataModelDir object lists files on a filesystem which are located +below a "basedir" directory, one file per row. The data model has the following columns: +<itemizedlist> + <listitem><para>the "dir_name" column (G_TYPE_STRING): contains the dirname part of the file</para></listitem> + <listitem><para>the "file_name" column (G_TYPE_STRING): contains the file name part of the file</para></listitem> + <listitem><para>the "size" column (G_TYPE_UINT): contains the size in bytes of the file</para></listitem> + <listitem><para>the "mime_type" column (G_TYPE_STRING): contains the mime type of the file (if GnomeVFS has been found, and NULL otherwise)</para></listitem> + <listitem><para>the "md5sum" column (G_TYPE_STRING): contains the MD5 hash of each file (if LibGCrypt has been found, and NULL otherwise)</para></listitem> + <listitem><para>the "data" column (GDA_TYPE_BLOB): contains the contents of each file</para></listitem> +</itemizedlist> + +Note that the actual values of the "mime_type", "md5sum" and "data" columns are computed only when they + are requested to help with performances. + + + The #GdaDataModelImport data model imports data from a string or a file. The data can either be +in a CSV (comma separated values) format or in an XML format as described by the libgda-array.dtd DTD (as a side +way it is also possible to import data from an already-build XML tree validated against that DTD). + +The caller must decide, upon construction, if the new #GdaDataModelImport must support random access or simply +a cursor based access. Random access makes it easier to use the resulting data model but consumes more memory as +all the data is copied in memory, and is thus not suitable for large data sets. Note that importing from an +already-build XML tree will always result in a random access data model. + +Various import options can be specified using parameters in a #GdaSet object. The available options +depend on the format of the imported data listed here: +<itemizedlist> + <listitem><para>"SEPARATOR" (string, CVS import only): specifies the separator to consider</para></listitem> + <listitem><para>"ESCAPE_CHAR" (string, CVS import only): specifies the character used to "escape" the strings + contained between two separators</para></listitem> + <listitem><para>"ENCODING" (string, CVS import only): specifies the character set used in the imported data</para></listitem> + <listitem><para>"TITLE_AS_FIRST_LINE" (boolean, CVS import only): TRUE to specify that the first line of the + imported data contains the column names</para></listitem> + <listitem><para>"G_TYPE_&lt;col number&gt;" (GType, CVS import only): specifies the requested GType type for the column + numbered "col number"</para></listitem> +</itemizedlist> + + + A #GdaDataModelIter object is used to iterate through the rows of a #GdaDataModel. If the data model is accessible +in a random access way then any number of #GdaDataModelIter objects can be created on the same data model, and +if the data model only supports a cursor based access then only one #GdaDataModelIter can be created. In any case +creating a #GdaDataModelIter should be done using the gda_data_model_create_iter() method. Note that if +the data model only supports a cursor based access, then calling this method several times will always return +the same #GdaDataModelIter, but with its reference count increased by 1 (so you should call g_object_unref() when +finished with it). + +When a #GdaDataModelIter is valid (that is when it points to an existing row in the data model it iterates through), +the individual values (corresponding to each column of the data model, at the pointer row) can be accessed +using the gda_data_model_iter_get_value_at() or gda_data_model_iter_get_value_for_field() methods +(or in the same way #GdaSet's values are accessed as #GdaDataModelIter inherits the #GdaSet). + +Right after being created, a #GdaDataModelIter is invalid (does not point to any row of its data model). To read the +first row of the data model, use the gda_data_model_iter_move_next() method. Calling this method several times will +move the iterator forward, up to when the data model has no more rows and the #GdaDataModelIter will be declared invalid +(and gda_data_model_iter_move_next() has returned FALSE). Note that at this point, the number of rows in the data +model will be known. + +If the data model supports it, a #GdaDataModelIter can be moved backwards using the gda_data_model_iter_move_prev() +method. However if the iterator is invalid, moving backwards will not be possible (on the contrary to +gda_data_model_iter_move_next() which moves to the first row). + +The gda_data_model_iter_move_to_row() method, if the iterator can be moved both forward and backwards, can move the +iterator to a specific row (sometimes faster than moving it forward or backwards a number of times). + +The following figure illustrates the #GdaDataModelIter usage: +<mediaobject> + <imageobject role="html"> + <imagedata fileref="GdaDataModelIter.png" format="PNG" contentwidth="190mm"/> + </imageobject> + <textobject> + <phrase>GdaDataModelIter's usage</phrase> + </textobject> +</mediaobject> + +Note: the new #GdaDataModelIter does not hold any reference to the data model it iterates through (ie. +if this data model is destroyed at some point, the new iterator will become useless but in +any case it will not prevent the data model from being destroyed). + +Note: when the data model emits the "reset" signal, then: +<itemizedlist> + <listitem><para>the number of columns of the iterator can change to reflect the new data model + being itered on. In this case the iterator's position is reset as if it was + just created</para></listitem> + <listitem><para>some column types which were unknown (i.e. GDA_TYPE_NULL type), can change + to their correct type. In this case there is no other iterator change</para></listitem> + <listitem><para>some column types which were not GDA_TYPE_NULL can change, and in this case + the iterator's position is reset as if it was just created</para></listitem> +</itemizedlist> + + + The #GdaDataPivot data model allows one to do some analysis and summarisation on the contents +of a data model. + + + This object stores modifications to be made to a #GdaDataModel object which is proxied until the modifications are actually + written to the #GdaDataModel, it can also filter the proxied data model to show only a subset (a defined number of continuous + rows or by a filter to apply). + + Specifically, for a proxied data model having <varname>nb_cols</varname> columns and <varname>nb_rows</varname> rows, + the #GdaDataProxy object has the following attributes: + <itemizedlist> + <listitem> + <para><varname>2 * nb_cols</varname> columns: +<itemizedlist> + <listitem><para>the first (&gt;= 0) <varname>nb_cols</varname> columns are the current values stored in the + proxy (which correspond to the values of the proxied data model if the considered row has not been + changed). The associated values are writable.</para></listitem> + <listitem><para>the last <varname>nb_cols</varname> columns are the values stored in the proxied data model, + at column <varname>col - nb_cols</varname></para></listitem> +</itemizedlist> + </para> + </listitem> + <listitem><para>a variable number of rows depending on the following attributes: +<itemizedlist> + <listitem><para>if the proxy is configured to have an empty row as the first row</para></listitem> + <listitem><para>if the proxy only displays parts of the proxied data model</para></listitem> + <listitem><para>if new rows have been added to the proxy</para></listitem> +</itemizedlist> + </para></listitem> + <listitem><para>Any #GdaDataModelIter iterator created will only make appear the colmuns as present in the proxied + data model, not any of the other columns</para></listitem> + </itemizedlist> + This situation is illustrated in the following schema, where there is a direct mapping between the proxy's + rows and the proxied data model's rows: + <mediaobject> + <imageobject role="html"> + <imagedata fileref="data_proxy1.png" format="PNG" contentwidth="170mm"/> + </imageobject> + <textobject> + <phrase>GdaDataProxy's values mapping regarding the proxied data model</phrase> + </textobject> + </mediaobject> + + Note that unless explicitly mentioned, the columns are read-only. + + The following figures illustrate row mappings between the data proxy and the proxied data model in + several situations (which can be combined, but are shown alone for simplicity): + <itemizedlist> + <listitem><para>situation where rows 1 and 5 have been marked as deleted from the data proxy, using +<link linkend="gda-data-proxy-delete">gda_data_proxy_delete()</link> method, the data +proxy has 2 rows less than the proxied data model: +<mediaobject> + <imageobject role="html"> + <imagedata fileref="data_proxy2.png" format="PNG" contentwidth="100mm"/> + </imageobject> + <textobject> + <phrase>GdaDataProxy with 2 rows marked as deleted</phrase> + </textobject> +</mediaobject> + </para></listitem> + <listitem><para>situation where the data proxy only shows a sample of the proxied data model +at any given time, using the +<link linkend="gda-data-proxy-set-sample-size">gda_data_proxy_set_sample_size()</link> method +(the sample here is 4 rows wide, and starts at row 3): +<mediaobject> + <imageobject role="html"> + <imagedata fileref="data_proxy3.png" format="PNG" contentwidth="100mm"/> + </imageobject> + <textobject> + <phrase>GdaDataProxy with a sample size of 4</phrase> + </textobject> +</mediaobject> + </para></listitem> + <listitem><para>situation where the data proxy shows a row of NULL values, using the +<link linkend="GdaDataproxy-prepend-null-entry">"prepend-null-entry"</link> property: +<mediaobject> + <imageobject role="html"> + <imagedata fileref="data_proxy4.png" format="PNG" contentwidth="100mm"/> + </imageobject> + <textobject> + <phrase>GdaDataProxy with an extra row of NULL values</phrase> + </textobject> +</mediaobject> + </para></listitem> + <listitem><para>situation where a row has been added to the data proxy, using for example the +<link linkend="gda-data-model-append-row">gda_data_model_append_row()</link> method: +<mediaobject> + <imageobject role="html"> + <imagedata fileref="data_proxy5.png" format="PNG" contentwidth="100mm"/> + </imageobject> + <textobject> + <phrase>GdaDataProxy where a row has been added</phrase> + </textobject> +</mediaobject> + </para></listitem> + </itemizedlist> + + The #GdaDataProxy objects are thread safe, which means any proxy object can be used from + any thread at the same time as they implement their own locking mechanisms. + + + This data model implements the <link linkend="GdaDataModel">GdaDataModel</link> interface and is the required + base object when database providers implement a data model returned when a SELECT statement has been executed. + As the <link linkend="GdaDataModel">GdaDataModel</link> interface is implemented, consult the API + to access and modify the data held in a <link linkend="GdaDataSelect">GdaDataSelect</link> object. + +Depending on the requested data model usage (as specified by the "model_usage" parameter of the +<link linkend="gda-connection-statement-execute">gda_connection_statement_execute()</link> and similar +methods, the #GdaDataSelect will allow random access, cursor based access or both. + +Also, when later you'll be reading the data contained in a #GdaDataSelect object, depending on the actual +implementation (which adapts to the API providede by the database server), some calls to the database server +may be necessary to actually obtain the data. If this behaviour is not the one intended and if you need to +access the data without having to contact the database server (for example for performances reasons), then +you can use the <link linkend="gda_data_select_prepare_for_offline">gda_data_select_prepare_for_offline()</link> +method or specify the <link linkend="GDA-STATEMENT-MODEL-OFFLINE:CAPS">GDA_STATEMENT_MODEL_OFFLINE</link> +flag when executing the SELECT statement. + + The default behaviour however is to disallow modifications, and this section documents how to parametrize + a <link linkend="GdaDataSelect">GdaDataSelect</link> to allow modifications. Once this is done, any modification + done to the data model will be propagated to the modified table in the database using INSERT, UPDATE or DELETE + statements. + + After any modification, it is still possible to read values from the data model (even values for rows which have + been modified or inserted). The data model might then execute some SELECT statement to fetch some actualized values. + + Note: there is a corner case where a modification made to a row would make the row not selected at first in the data model + (for example is the original SELECT statement included a clause <![CDATA["WHERE id < 100"]]> and the modification sets the + <![CDATA["id"]]> value to 110), then the row will still be in the data model even though it would not be if the SELECT statement + which execution created the data model in the first place was re-run. This is illustrated in the schema below: + <mediaobject> + <imageobject role="html"> + <imagedata fileref="writable_data_model.png" format="PNG" contentwidth="100mm"/> + </imageobject> + <textobject> + <phrase>GdaDataSelect data model's contents after some modifications</phrase> + </textobject> + </mediaobject> + + + This is a basic class for database objects, e.g. #GdaDbTable and #GdaDbView. It is not common to +use it directly. + + + #GdaDbBuildable represents an interface for writing and reading xml nodes. #GdaDbTable and +#GdaDbView implement this interface. + + + This is a main object that represents overall database. The best way to create an instance of +#GdaDbCatalog is to call gda_connection_create_db_catalog(). This object may be also constracted +from an xml file using gda_db_catalog_parse_file() or gda_db_catalog_parse_file_from_path() or +didrectly from the open connection using gda_db_catalog_parse_cnc(). + +The database can be updated or modified using gda_db_catalog_perform_operation() and dumped to +a file using gda_db_catalog_write_to_path() or gda_db_catalog_write_to_file(). + + + This object represents a column of a table or a view. The column can be constracted manually +using API or generated from xml file together with other databse objects. See #GdaDbCatalog. +#GdaDbColumn implements #GdaDbBuildable interface for parsing xml file. This is a typical example +how the #GdaDbColumn API can be used. + +|[<!-- language="C" --> +GdaDbTable *tproject = gda_db_table_new (); +gda_db_base_set_name (GDA_DB_BASE (tproject), "Project"); + +GdaDbColumn *pid = gda_db_column_new (); +gda_db_column_set_name (pid, "id"); +gda_db_column_set_type (pid, G_TYPE_INT); +gda_db_column_set_nnul (pid, TRUE); +gda_db_column_set_autoinc (pid, TRUE); +gda_db_column_set_unique (pid, TRUE); +gda_db_column_set_pkey (pid, TRUE); + +gda_db_table_append_column (tproject, pid); + +g_object_unref (pid); +]| + + + For generating database from xml file or for mapping +database to an xml file #GdaDbFkey holds information about +foregn keys with a convenient set of methods to manipulate them. +#GdaDbFkey implements #GdaDbBuildable interface for parsing xml file. This is an example how +#GdaDbFkey can be used: + +|[<!-- language="C" --> +GdaDbFkey *fkey = gda_db_fkey_new (); +gda_db_fkey_set_ref_table (fkey, "Project"); +gda_db_fkey_set_ondelete (fkey, GDA_DB_FKEY_RESTRICT); +gda_db_fkey_set_onupdate (fkey, GDA_DB_FKEY_RESTRICT); +gda_db_fkey_set_field (fkey, "project_id", "id"); + +gda_db_table_append_fkey (temployee, fkey); +]| + + + The object #GdaDbIndex holds information about index in a table. Just populate the information +using index API, set table as property, execute gda_ddl_modifiable_create() method. This +method executes all needed DB manopulations to add the target index to the DB. This can be +illustarted by the following example: + +|[<!-- language="C" --> +GdaDbTable *table = gda_db_table_new(); +// Populate table as needed. +GdaDbIndex *index = gda_db_index_new (); +GdaDbIndexField *field = gda_db_index_field_new (); +GdaDbColumn *fcol = gda_db_column_new (); +GError *error = NULL; + +gda_db_index_set_unique (index, TRUE); +gda_db_base_set_name (GDA_DB_BASE (index), "MyIndex"); + +gda_db_column_set_name (fcol, "name"); + +gda_db_index_field_set_column (field, fcol); +gda_db_index_field_set_sort_order (field, GDA_DB_INDEX_SORT_ORDER_ASC); +gda_db_index_append_field (index, field); + +g_object_unref (fcol); +g_object_unref (field); + +g_object_set (index, "table", table, NULL); + +res = gda_ddl_modifiable_create (GDA_DDL_MODIFIABLE(index), cnc, NULL, &error); + +if (!res) + g_print("Error during index addition\n"); +]| + + + This object is a container for information needed to create an index for a table. After +population with information, it should be passed to the #GdaDbIndex instance. See #GdaDbIndex +section for the example. + + + This object represents a table of a database. The table view can be constracted manually +using API or generated from xml file together with other databse objects. See #GdaDbCatalog. +#GdaDbTable implements #GdaDbBuildable interface for parsing xml file. + +#GdaDbTable can be used as a container to hold other objects, e.g. #GdaDbColumn, #GdaDbFkey and +as soon as populated with all needed objects the table can be created using +gda_ddl_modifiable_create(), + +To delete the table a method gda_ddl_modifiable_drop() can be called. + +A simple example of how to create a table with 3 columns being the last column of the foreign key. + +|[<!-- language="C" --> + +GdaConnection *cnc; +//Open connection here + +GError *error = NULL; + +GdaDbTable *tproject = gda_db_table_new (); +gda_db_base_set_name (GDA_DB_BASE (tproject), "Project"); + +GdaDbColumn *pid = gda_db_column_new (); +GdaDbColumn *pname = gda_db_column_new (); +GdaDbColumn *pfkey = gda_db_column_new (); +GdaDbFkey *fkey = gda_db_fkey_new (); + +gda_db_column_set_name (pid, "id"); +gda_db_column_set_type (pid, G_TYPE_INT); +gda_db_column_set_nnul (pid, TRUE); +gda_db_column_set_autoinc (pid, TRUE); +gda_db_column_set_unique (pid, TRUE); +gda_db_column_set_pkey (pid, TRUE); + +gda_db_column_set_name (pname, "name"); +gda_db_column_set_type (pname, G_TYPE_STRING); +gda_db_column_set_size (pname, 30); +gda_db_column_set_nnul (pname, TRUE); +gda_db_column_set_unique (pname, TRUE); + +gda_db_column_set_name (pfkey, "fkey"); +gda_db_column_set_type (pfkey, G_TYPE_INT); +gda_db_column_set_nnul (pfkey, TRUE); + +gda_db_fkey_set_ref_table (fkey, "AnotherTable"); +gda_db_fkey_set_ondelete (fkey, GDA_DB_FKEY_RESTRICT); +gda_db_fkey_set_onupdate (fkey, GDA_DB_FKEY_RESTRICT); +gda_db_fkey_set_field (fkey, "fkey", "another_table_id"); + +gda_db_table_append_column (tproject, pid); +g_object_unref (pid); + +gda_db_table_append_column (tproject, pname); +g_object_unref (pname); + +gda_db_table_append_column (tproject, pfkey); +g_object_unref (pfkey); + +gda_db_table_append_fkey (tproject, fkey); +g_object_unref (fkey); + +if (!gda_ddl_modifiable_create (GDA_DDL_MODIFIABLE (tproject), cnc, NULL, &error)) +{ + g_error ("It was not possible to create the table in the database: %s\n", + error && error->message ? error->message : "No detail"); +} + +g_object_unref (tproject); + +]| + + + This object represents a view of a database. The view can be constracted manually +using API or generated from xml file together with other databse objects. See #GdaDbCatalog. +#GdaDbView implements #GdaDbBuildable interface for parsing xml file. This is typical example +how #GdaDbView can be used + +|[<!-- language="C" --> + + GdaDbView *myview = gda_db_view_new (); + gda_db_base_set_name (GDA_DB_BASE (myview), "MyView"); + gda_db_view_set_istemp (myview, FALSE); + gda_db_view_set_defstring (myview, "SELECT name, project_id FROM NewEmployee"); + + res = gda_db_view_create (myview, fixture->cnc, TRUE, &error); + + if (!res) + GDA_PGSQL_ERROR_HANDLE (error); + ]| + + + This interface should be used to perform some DDL opration using objects that implement it. +Calling gda_ddl_modifiable_create() on #GdaDbColumn operation will execute ADD COLUMN +operation. The user should pass a pointer to instance of #GdaDbTable as user_data where +column will be added (cretaed). + +If the underlying object does not implement the operation, then %FALSE is returned and the error +is set. + + + You should normally not need to use this API, refer to the #GdaDataHandler +interface documentation for more information. + + + You should normally not need to use this API, refer to the #GdaDataHandler +interface documentation for more information. + + + You should normally not need to use this API, refer to the #GdaDataHandler +interface documentation for more information. + + + You should normally not need to use this API, refer to the #GdaDataHandler +interface documentation for more information. + + + You should normally not need to use this API, refer to the #GdaDataHandler +interface documentation for more information. + + + You should normally not need to use this API, refer to the #GdaDataHandler +interface documentation for more information. + + + You should normally not need to use this API, refer to the #GdaDataHandler +interface documentation for more information. + + + The #GdaHolder is a container for a single #GValue value. It also specifies various attributes +of the contained value (default value, ...) + +The type of a #GdaHolder has to be set and cannot be modified, except if it's initialized +with a GDA_TYPE_NULL GType (representing NULL values) where it can be changed once to a real GType. + +Each GdaHolder object is thread safe. + + + This interface is implemented by objects which are thread safe (ie. can be used by several threads at +the same time). Before using an object from a thread, one has to call gda_lockable_lock() or +gda_lockable_trylock() and call gda_lockable_unlock() when the object is not used anymore. + + + Logging functions. + + + Previous versions of &LIBGDA; relied on an XML based file to store dictionary information, such as +the database's schema (tables, views, etc) and various other information. The problems were that it was +difficult for an application to integrate its own data into the dictionary and that there were some +performances problems as the XML file needed to be parsed (and converted into its own in-memory structure) +before any data could be read out of it. + +The new dictionary now relies on a database structure to store its data (see the +<link linkend="information_schema">database schema</link> section for a detailed description). The actual database can be a +single file (using an SQLite database), an entirely in memory database (also using an SQLite database), or +a more conventional backend such as a PostgreSQL database for a shared dictionary on a server. + +The #GdaMetaStore object is thread safe. + + + The #GdaMetaStruct object reads data from a #GdaMetaStore object and + creates an easy to use in memory representation for some database objects. For example one can easily + analyze the columns of a table (or its foreign keys) using a #GdaMetaStruct. + + When created, the new #GdaMetaStruct object is empty (it does not have any information about any database object). + Information about database objects is computed upon request using the gda_meta_struct_complement() method. Information + about individual database objects is represented by #GdaMetaDbObject structures, which can be obtained using + gda_meta_struct_get_db_object() or gda_meta_struct_get_all_db_objects(). + + Note that the #GdaMetaDbObject structures may change or may be removed or replaced by others, so it not + advised to keep pointers to these structures: pointers to these structures should be considered valid + as long as gda_meta_struct_complement() and other similar functions have not been called. + + In the following code sample, one prints the columns names and types of a table: + <programlisting> +GdaMetaStruct *mstruct; +GdaMetaDbObject *dbo; +GValue *catalog, *schema, *name; + +// Define name (and optionnally catalog and schema) +[...] + +mstruct = gda_meta_struct_new (); +gda_meta_struct_complement (mstruct, store, GDA_META_DB_TABLE, catalog, schema, name, NULL); +dbo = gda_meta_struct_get_db_object (mstruct, catalog, schema, name); +if (!dbo) + g_print ("Table not found\n"); +else { + GSList *list; + for (list = GDA_META_TABLE (dbo)->columns; list; list = list->next) { + GdaMetaTableColumn *tcol = GDA_META_TABLE_COLUMN (list->data); + g_print ("COLUMN: %s (%s)\n", tcol->column_name, tcol->column_type); + } +} +gda_meta_struct_free (mstruct); + </programlisting> + If now the database object type is not known, one can use the following code: + <programlisting> +GdaMetaStruct *mstruct; +GdaMetaDbObject *dbo; +GValue *catalog, *schema, *name; + +// Define name (and optionnally catalog and schema) +[...] + +mstruct = gda_meta_struct_new (); +gda_meta_struct_complement (mstruct, store, GDA_META_DB_UNKNOWN, catalog, schema, name, NULL); +dbo = gda_meta_struct_get_db_object (mstruct, catalog, schema, name); +if (!dbo) + g_print ("Object not found\n"); +else { + if ((dbo->obj_type == GDA_META_DB_TABLE) || (dbo->obj_type == GDA_META_DB_VIEW)) { + if (dbo->obj_type == GDA_META_DB_TABLE) + g_print ("Is a table\n"); + else if (dbo->obj_type == GDA_META_DB_VIEW) { + g_print ("Is a view, definition is:\n"); + g_print ("%s\n", GDA_META_VIEW (dbo)->view_def); + } + + GSList *list; + for (list = GDA_META_TABLE (dbo)->columns; list; list = list->next) { + GdaMetaTableColumn *tcol = GDA_META_TABLE_COLUMN (list->data); + g_print ("COLUMN: %s (%s)\n", tcol->column_name, tcol->column_type); + } + } + else + g_print ("Not a table or a view\n"); +} +gda_meta_struct_free (mstruct); + </programlisting> + + + The #GdaPStmt represents the association between a #GdaStatement statement and a <emphasis>prepared statement</emphasis> +which is database dependent and is an in-memory representation of a statement. Using prepared statement has the +following advantages: +<itemizedlist> + <listitem><para>the parsing of the SQL has to be done only once, which improves performances if the statement +has to be executed more than once</para></listitem> + <listitem><para>if a statement has been prepared, then it means it is syntactically correct and has been +<emphasis>understood</emphasis> by the database's API</para></listitem> + <listitem><para>it is possible to use variables in prepared statement which eliminates the risk +of SQL code injection</para></listitem> +</itemizedlist> + +The #GdaPStmt is not intended to be instantiated, but subclassed by database provider's implementation. +Once created, the database provider's implementation can decide to associate (for future lookup) to +a #GdaStatement object in a connection using gda_connection_add_prepared_statement(). + +The #GdaPStmt object can keep a reference to the #GdaStatement object (which can be set and get using +the gda_pstmt_set_gda_statement() and gda_pstmt_get_gda_statement()), however that reference +if a weak one (which means it will be lost if the #GdaStatement object is destroyed). + + + This object is used to store KEY=VALUE pairs. It is mainly used internally by Libgda to store connection +parameters. + +Authentification values are kept in a mangled form in memory, and unmangled when +they are requested using gda_quark_list_find(), and when you don't need them anymore, +call gda_quark_list_protect_values() to remove the unmangled version. + + + The #GdaRepetitiveStatement object allows one to specify a statement to be executed +several times using different variables' values sets for each execution. Using the object +has almost no interrest at all if the statement to be executed several times has no parameter. + +Use the gda_connection_repetitive_statement_execute() method to execute the repetitive statement. + + + The #GdaDataModelArray object uses #GdaRow to store each row of data. Each #GdaRow has the same +number of #GValue values (equal to the number of columns of the data model). + +As a side note, the #GdaRow object is also used internally by the implementation of the data models returned +when executing a SELECT statement. + + + This object is basically just a data store: it can store named values, the values being +organized hierarchically by their name which are similar to a Unix file path. For example a value can be read from its path +using the gda_server_operation_get_value_at() method, or set using the gda_server_operation_set_value_at() method. + +Each #GdaServerOperation contains some structure which is usually defined by a database provider to implement +a specific operation. The structure is composed of the following building blocks: +<itemizedlist> + <listitem><para>Named values (internally represented as a #GdaHolder object)</para></listitem> + <listitem><para>Named values in a vector (internally represented as a #GdaSet object)</para></listitem> + <listitem><para>Values in an array (internally represented as a #GdaDataModel object)</para></listitem> + <listitem><para>Sequences of one or more of the previous blocks. A sequence can contain any number of + instances of the template block (there may be lower and upper boundaries to the number of instances)</para></listitem> +</itemizedlist> + +<emphasis>Important note:</emphasis> #GdaServerOperation objects are usually not created +manually using gda_server_operation_new(), but +using a #GdaServerProvider object with gda_server_provider_create_operation(). +See the <link linkend="DDLIntro">global introduction about DDL</link> for more information. +Alternatively one can use the <link linkend="libgda-40-Convenience-functions">Convenience functions</link> +which internally manipulate #GdaServerOperation objects. + + + To each part of a path is associated a node (as a #GdaServerOperationNode structure). For example the +"/TABLE_DEF_P/TABLE_NAME" path has two nodes, one associated to "/TABLE_DEF_P" and one to +"/TABLE_DEF_P/TABLE_NAME". For more information about the path's format, see the +gda_server_operation_set_value_at()'s documentation. + +This API is designed to get information about all the nodes present in a #GdaServerOperation object (refer to the +gda_server_operation_get_root_nodes() function) and about each node of a path, and allows inspection +of its contents. It is mainly reserved for database provider's implementations but can have its purpose +outside of this scope. + + + The #GdaServerOperation object can contain sequences of templates. For example when creating a table, +one can specify several foreign keys where for each foreign key, one must define the column(s) on which the +foreign key applies, the referenced table and the corresponding columns of the referenced table (plus some +additional information). In this case the foreign keys are defined as a sequence of templates (the foreign key +definition): there can be zero or more foreign keys. + + + The #GdaServerProvider class is a virtual class which all the DBMS providers +must inherit, and implement its virtual methods. + +See the <link linkend="libgda-provider-class">Virtual methods for providers</link> section for more information +about how to implement the virtual methods. + + + The #GdaSet object is a container for several values (as #GdaHolder objects). Each #GdaSet object also +maintains some publicly accessible information about the #GdaHolder objects, through the #GdaSetNode, #GdaSetSource and +#GdaSetGroup structures (see gda_set_get_node(), gda_set_get_source() and gda_set_get_group()). + +It is possible to control the values a #GdaHolder can have in the #GdaSet by connecting to the +<link linkend="GdaSet-before-holder-change">"before-holder-change"</link> signal. + + + The #GdaSqlBuilder can be used to build a #GdaStatement from its structural description, +much in the same way a #GdaSqlParser can be used to build a #GdaStatement from an SQL +string. + +The #GdaSqlBuilder internally constructs a #GdaSqlStatement and uses it when requested to produce +a #GdaStatement (see gda_sql_builder_get_statement()), or a #GdaSqlStatement (see +gda_sql_builder_get_sql_statement()). + +During the building process, some pieces of the statement are constructed, and assembled into the +final statement. Each of these pieces can be reused anytime in the same #GdaSqlBuilder object, and each +is identified using a single unsigned integer ID. That ID is dynamically allocated by the object. + +The following example builds the equivalent of the <![CDATA["name='joe' AND age >= ##ageparam::int"]]> expression: +<programlisting><![CDATA[ +GdaSqlBuilder *b=... +guint id_field = gda_sql_builder_add_id (b, "name"); // build the "name" SQL identifier +guint id_value = gda_sql_builder_add_expr (b, NULL, G_TYPE_STRING, "joe"); // 'joe' expression +guint id_cond1 = gda_sql_builder_add_cond (b, GDA_SQL_OPERATOR_TYPE_EQ, id_field, id_value, 0); // "name='joe'" + +guint id_cond2 = gda_sql_builder_add_cond (b, GDA_SQL_OPERATOR_TYPE_GT, + gda_sql_builder_add_id (b, "age"), // build the "age" SQL identifier + gda_sql_builder_add_param (b, "ageparam", G_TYPE_INT, FALSE), // parameter + 0); +guint id_cond_and = gda_sql_builder_add_cond (b, GDA_SQL_OPERATOR_TYPE_AND, id_cond1, id_cond2, 0); // whole expression +]]></programlisting> + +For more examples, see the <link linkend="howto-sqlbuilder">Build statements without using a parser</link> section. + + + The #GdaSqlParser is an object dedicated to creating #GdaStatement and #GdaBatch objects from SQL strings. The actual contents +of the parsed statements is represented as #GdaSqlStatement structures (which can be obtained from any #GdaStatement through the +"structure" property). + +#GdaSqlParser parsers can be created by calling gda_server_provider_create_parser() for a provider adapted SQL parser, or using +gda_sql_parser_new() for a general purpose SQL parser. + +The #GdaSqlParser can either work in "parse" mode where it will try to parse the SQL string, or in "delimiter" mode where it will +only attempt at delimiting SQL statements in a string which may contain several SQL statements (usually separated by a semi column). +If operating in "parser" mode, and the parser can't correctly parse the string, then it will switch to the "delimiter" mode +for the next statement in the string to parse (and create a GDA_SQL_STATEMENT_UNKNOWN statement). + +The #GdaSqlParser object parses and analyzes SQL statements and reports the following statement types: +<itemizedlist> +<listitem><para>SELECT (and COMPOUND select), + INSERT, UPDATE and DELETE SQL statements should be completely parsed. +</para></listitem> +<listitem><para>Transaction related statements (corresponding to the BEGIN, COMMIT, ROLLBACK, +SAVEPOINT, ROLLBACK SAVEPOINT and DELETE SAVEPOINT) are parsed and a minimalist structure is created to +extract some information (that structure is not enough per-se to re-create the complete SQL statement). +</para></listitem> +<listitem><para>Any other type of SQL statement (CREATE TABLE, ...) creates a #GdaStatement of type + GDA_SQL_STATEMENT_UNKNOWN, and it only able to locate place holders (variables) and end of statement + marks.</para></listitem> +</itemizedlist> + +NOTE: Any SQL of a type which should be parsed which but which creates a #GdaStatement of type GDA_SQL_STATEMENT_UNKNOWN +(check with gda_statement_get_statement_type()) should be reported as a bug. + +The #GdaSqlParser object recognizes place holders (variables), which can later be queried and valued using +gda_statement_get_parameters(). The following syntax are recognized (other syntaxes might be +recognized for specific database providers if the #GdaSqlParser is created using gda_server_provider_create_parser() +but for portability reasons it's better to avoid them): +<itemizedlist> +<listitem><para><programlisting>##NAME[::TYPE[::NULL]]]</programlisting>: + for a variable named NAME with the optional type TYPE (which can be a GType + name or a custom database type name), and with the optional "::NULL" to instruct that the variable can + be NULL. +</para></listitem> +<listitem><para> + <programlisting>## /&ast; name:NAME [type:TYPE] [nullok:[TRUE|FALSE]] [descr:DESCR] &ast;/</programlisting> + for a variable named NAME with the optional type TYPE (which can be a GType + name or a custom database type name), with the optional "nullok" attribute and an optional + description DESCR. Note that the NAME, TYPE and DESCR literals here must be quoted (simple or double quotes) if + they include non alphanumeric characters, and that there must always be at least a space between the + <![CDATA[##]]> and the opening and closing comments (C style). +</para></listitem> +</itemizedlist> +Note that the type string must be a type recognized by the +<link linkend="gda-g-type-from-string">gda_g_type_from_string()</link> function (all valid GType names +plus a few synonyms). Examples of correct place holders definitions are: +<programlisting> +## /&ast; name:"+0" type:gchararray &ast;/ +## /&ast; name:'-5' type:string &ast;/ +## /&ast;name:myvar type:gint descr:ToBeDefined nullok:FALSE&ast;/ +## /&ast;name:myvar type:int descr:"A long description"&ast;/ +##+0::gchararray +##-5::timestamp +</programlisting> + +Also note that variables should not be used when an SQL identifier is expected. For example the following +examples <emphasis>should be avoided</emphasis> because they may not work properly (depending on the database being used): +<programlisting> +SELECT * FROM ##tablename::string; +DELETE FROM mytable WHERE ##tcol::string = 5; +ALTER GROUP mygroup ADD USER ##name::gchararray; +</programlisting> + +The #GdaSqlParser object internally uses a LEMON generated parser (the same as the one used by SQLite). + +The #GdaSqlParser object implements its own locking mechanism so it is thread-safe. + + + Use the #GdaSqlBuilder object to build #GdaSqlStatement structures. + +Every SQL statement can be decomposed in a #GdaSqlStatement structure. This is not a #GObject, but rather just a C structure +which can be manipulated directly. The structure is a tree composed of several key structures which are show in the following diagram +(even though it does not show, all structures "inherit" the #GdaSqlAnyPart structure which holds some basic information). +<mediaobject> + <imageobject role="html"> + <imagedata fileref="parts.png" format="PNG"/> + </imageobject> + <caption> + <para> + Main parts of the #GdaSqlStatement structure. + </para> + </caption> +</mediaobject> + +The examples/SqlParserConsole directory of &LIBGDA;'s sources contains a small utility +to display statements' structures as a graph (using the GraphViz language). It has been used to +provide the examples in this section of the documentation. + + + The #GdaStatement represents a single SQL statement (multiple statements can be grouped in a #GdaBatch object). + + A #GdaStatement can either be built by describing its constituing parts using a #GdaSqlBuilder object, + or from an SQL statement using a #GdaSqlParser object. + + A #GdaConnection can use a #GdaStatement to: + <itemizedlist> + <listitem><para>prepare it for a future execution, the preparation step involves converting the #GdaStatement +object into a structure used by the database's own API, see gda_connection_statement_prepare()</para></listitem> + <listitem><para>execute it using gda_connection_statement_execute_select() if it is known that the statement is a +selection statement, gda_connection_statement_execute_non_select() if it is not a selection statement, or +gda_connection_statement_execute() when the type of expected result is unknown.</para></listitem> + </itemizedlist> + Note that it is possible to use the same #GdaStatement object at the same time with several #GdaConnection objects. + + + On any connection (as a #GdaConnection object), if the database provider used by the connection +supports it, transactions may be started, committed or rolledback, or savepoints added, removed or rolledback. +These operations can be performed using Libgda's API (such as gda_connection_begin_transaction()), or directly +using some SQL on the connection (usually a "BEGIN;" command). The #GdaTransactionStatus's aim is to +make it easy to keep track of all the commands which have been issued on a connection regarding transactions. + +One #GdaTransactionStatus object is automatically attached to a #GdaConnection when a transaction is started, and +is destroyed when the transaction is finished. A pointer to this object can be fetched using +gda_connection_get_transaction_status() (beware that it should then not be modified). The end user is not +supposed to instantiate #GdaTransactionStatus objects + +#GdaTransactionStatus's attributes are directly accessible using the public members of the object. + + + The #GdaTree is the top level object representing hierarchically structured data. From this object it +is also possible (depending on the tree managers it uses), to clean (remove all the nodes) the whole tree, +or to request a complete or partial update of the nodes. + +It is also possible to set attributes to the tree itself (as it is possible to do for tree nodes), +or to dump the whole or part of a tree in an indented and easy to read fashion. + + + A #GdaTreeManager object is responsible for creating nodes in the tree(s) for which it +operates. + +When creating nodes, a #GdaTreeManager object can (depending on its implementation), get some +named attributes from the node below which it has to create nodes, using the gda_tree_node_fetch_attribute() +or gda_tree_node_get_node_attribute(). For example the #GdaTreeMgrColumns manager (which creates a node for each column +of a table) needs the table name and the schema in which the table is; both can be specified using an +object's property, or, if not specified that way, are fetched as attributes. + +The #GdaTreeManager itself is an abstract type (which can't be instantiated). Use an existing sub class or subclass +it yourself. + + + The #GdaTreeMgrColumns is a #GdaTreeManager object which creates a node for +each column in a table. + +It uses the #GdaMetaStore associated to a #GdaConnection to get the columns list +for a table designated by its name and the database schema it is in; it's up to the +caller to make sure the data in the #GdaMetaStore is up to date. + +The #GdaConnection to be used needs to be specified when the object is created. The table +name and schema can however be specified when the object is created, and if not, are +fetched from the #GdaTreeNode below which the nodes will be placed (using +gda_tree_node_fetch_attribute()). + + + The #GdaTreeMgrLabel is a #GdaTreeManager object which creates a single node. This tree manager +is useful to create "sections" in a #GdaTree hierarchy. + + + The #GdaTreeMgrSchemas is a #GdaTreeManager object which creates a node for +each schema in a database. + +It uses the #GdaMetaStore associated to a #GdaConnection to get the schemas list; it's up to the +caller to make sure the data in the #GdaMetaStore is up to date. + +The #GdaConnection to be used needs to be specified when the object is created. + + + The #GdaTreeMgrSelect is a #GdaTreeManager object which executes a SELECT statement and +creates a node for each row in the result. + +The #GdaConnection and SELECT #GdaStatement to be used need to be specified when the object is created. +If the SELECT statement to be used needs some parameters, then it is possible to give values to some of them +when constructing the object, but not necessary. + +If the SELECT statement needs some parameters which have not been provided during the construction, then +these parameters will be fetched from the #GdaTreeNode below which the nodes will be placed (using +gda_tree_node_fetch_attribute()). + +For each node created, an attribute is set for each column in the SELECT statement: the attribute name is +the column name and the attribute value is the value if that column. + + + The #GdaTreeMgrTables is a #GdaTreeManager object which creates a node for +each table in a database schema. + +It uses the #GdaMetaStore associated to a #GdaConnection to get the tables list +in database schema; it's up to the +caller to make sure the data in the #GdaMetaStore is up to date. + +The #GdaConnection to be used needs to be specified when the object is created. The +schema can however be specified when the object is created, and if not, is +fetched from the #GdaTreeNode below which the nodes will be placed (using +gda_tree_node_fetch_attribute()). + + + Every node in a #GdaTree tree is represented by a single #GdaTreeNode object. There is no distinction +between nodes which have children and those which don't (leaf nodes). + +The #GdaTreeNode is very basic as it only has a "name" attribute: users are encouraged to subclass it to +add more features if needed (and make use of them by defining a #GdaTreeManagerNodeFunc function and +calling gda_tree_manager_set_node_create_func()). + + + Some useful functions. + + + &LIBGDA; manages each individual value within an opaque #GValue structure. Any GValue type can be used, +and &LIBGDA; adds a few more data types usually found in DBMS such as NUMERIC, TIME, TIMESTAMP, GEOMETRIC POINT, BINARY and BLOB. + +Libgda makes a distinction between binary and blob types +<itemizedlist> + <listitem><para>binary data can be inserted into an SQL statement using a +(DBMS dependent) syntax, such as "X'ABCD'" syntax for SQLite or the binary strings syntax for PostgreSQL. Binary data +is manipulated using a #GdaBinary structure (which is basically a bytes buffer and a length attribute). + </para></listitem> + <listitem><para>blob data are a special feature that some DBMS have which requires some non SQL code to manipulate them. +Usually only a reference is stored in each table containing a blob, and the actual blob data resides somewhere on the disk +(while still being managed transparently by the database). For example PotsgreSQL stores blobs as files on the disk and +references them using object identifiers (Oid). Blob data +is manipulated using a #GdaBlob structure which encapsulates a #GdaBinary structure and adds a reference to a +#GdaBlobOp object used to read and write data from and to the blob. + </para></listitem> +</itemizedlist> +Please note that is distinction between binary data and blobs is Libgda only and does not reflect the DBMS's documentations; +for instance MySQL has several BLOB types but Libgda interprets them as binary types. + +Each provider or connection can be queried about its blob support using the gda_server_provider_supports_feature() or +gda_connection_supports_feature() methods. + +There are two special value types which are: +<itemizedlist> + <listitem><para>the GDA_TYPE_NULL value which never changes and acutally represents an SQL NULL value</para></listitem> + <listitem><para>the GDA_TYPE_DEFAULT value which represents a default value which &LIBGDA; does not interpret (such as when a table column's default value is a function call)</para></listitem> +</itemizedlist> + + + The purpose of the #GdaWorker object is to execute "jobs" (functions with arguments) within a worker thread, using +gda_worker_submit_job(). + +Any code executing in any thread context can submit jobs to @worker and is guaranted not to be blocked (except if using +gda_worker_wait_job() or if the +jobs are submitted within the worker thread itself). Once jobs have been submitted, it's up to the caller to regularly +check if a job has completed using gda_worker_fetch_job_result(). If you don't want to have to check regularly (which is +like some polling operation), then you can use gda_worker_set_callback() which adds a callback when any job has completed. + +gda_worker_wait_job() allows you to execute a job in the worker thread while blocking the calling thread. + +Before fetching a jobs's result, it is also possible to request the cancellation of the job using gda_worker_cancel_job(), or +completely discard the job using gda_worker_forget_job(). + +Jobs can also be submitted using gda_worker_do_job(), which internally runs a #GMainLoop and allows you to execute a job +while at the same time processing events for the specified #GMainContext. + +The #GdaWorker implements its own locking mechanism and can safely be used from multiple +threads at once without needing further locking. + + + The #GdaXaTransaction object acts as a distributed transaction manager: to make sure local transactions on several +connections (to possibly different databases and database types) either all succeed or all fail. For more information, +see the X/Open CAE document Distributed Transaction Processing: The XA Specification. +This document is published by The Open Group and available at +<ulink url="http://www.opengroup.org/public/pubs/catalog/c193.htm">http://www.opengroup.org/public/pubs/catalog/c193.htm</ulink>. + +The two phases commit protocol is implemented during the execution of a distributed transaction: modifications +made on any connection are first <emphasis>prepared</emphasis> (which means that they are store in the database), and +if that phase succeeded for all the involved connections, then the <emphasis>commit</emphasis> phase is executed +(where all the data previously stored during the <emphasis>prepare</emphasis> phase are actually committed). +That second phase may actually fail, but the distributed transaction will still be considered as successfull +as the data stored during the <emphasis>prepare</emphasis> phase can be committed afterwards. + +A distributed transaction involves the following steps: +<orderedlist> + <listitem><para>Create a #GdaXaTransaction object</para></listitem> + <listitem><para>Register the connections which will be part of the distributed transaction with that object +using gda_xa_transaction_register_connection()</para></listitem> + <listitem><para>Beging the distributed transaction using gda_xa_transaction_begin()</para></listitem> + <listitem><para>Work individually on each connection as normally (make modifications)</para></listitem> + <listitem><para>Commit the distributed transaction using gda_xa_transaction_commit()</para></listitem> + <listitem><para>Discard the #GdaXaTransaction object using g_object_unref()</para></listitem> +</orderedlist> + + + Creates a new boolean #GdaHolder object with an ID set to @id, and a value initialized to +@abool. + + + + a string + + + a boolean value + + + + + Creates a new boolean #GdaHolder object with an ID set to @id, and a value initialized to +@anint. + + + + a string + + + an int value + + + + + Creates a new boolean #GdaHolder object with an ID set to @id, and a value initialized to +@str. + + + + a string + + + a string + + + + + Does the same as strcmp(@id1, @id2), but handles the case where id1 and/or id2 are enclosed in double quotes. +can also be used in hash tables as a #GEqualFunc. + + + %TRUE if @id1 and @id2 are equal. + + + + + an identifier string + + + + an identifier string + + + + + + computes a hash string from @id, to be used in hash tables as a #GHashFunc + + + a new hash + + + + + an identifier string + + + + + + Disables GDA logs. + + + + + + + Enables GDA logs. + + + + + + + Logs the given error in the GDA log file. + + + + + + + format string (see the printf(3) documentation). + + + + arguments to insert in the error. + + + + + + + + whether GDA logs are enabled (%TRUE or %FALSE). + + + + + Logs the given message in the GDA log file. + + + + + + + format string (see the printf(3) documentation). + + + + arguments to insert in the message. + + + + + + This function is similar to gda_parse_iso8601_date() (with @first being @G_DATE_YEAR, @second being @G_DATE_MONTH, +@third being @G_DATE_DAY and @sep being '-') but allows one to specify the expected date format. + + + %TRUE if @value has been sucessfuly parsed as a valid date (see g_date_valid()). + + + + + a pointer to a #GDate structure which will be filled + + + + a string to be parsed + + + + a #GDateDMY specifying which of year, month or day appears first (in the first bytes) in @value + + + + a #GDateDMY specifying which of year, month or day appears second (in the first bytes) in @value + + + + a #GDateDMY specifying which of year, month or day appears third (in the first bytes) in @value + + + + spcifies the expected separator character bewteen year, month and day (for example '-') + + + + + + + + a new parsed #GdaTime + + + + + a string + + + + the time separator, usually ':'. If equal to @0, then the expexted format will be HHMMSS... + + + + + + This function is similar to g_date_time_new_from_iso8601() (with @first being @G_DATE_YEAR, @second being @G_DATE_MONTH, +@third being @G_DATE_DAY and @sep being '-') but allows one to specify the expected date format. + + + a new #GDateTime if @value has been successfully parsed as a valid date (see g_date_valid()). + + + + + a string to be parsed + + + + a #GDateDMY specifying which of year, month or day appears first (in the first bytes) in @value + + + + a #GDateDMY specifying which of year, month or day appears second (in the first bytes) in @value + + + + a #GDateDMY specifying which of year, month or day appears third (in the first bytes) in @value + + + + specifies the expected separator character between year, month and day (for example '-') + + + + + + Extracts date parts from @value, and sets @gdate's contents + +Accepted date format is "YYYY-MM-DD" (more or less than 4 digits for years and +less than 2 digits for month and day are accepted). Years must be in the 1-65535 range, +a limitation imposed by #GDate. + + + %TRUE if @value has been sucessfuly parsed as a valid date (see g_date_valid()). + + + + + a pointer to a #GDate structure which will be filled + + + + a string + + + + + + Extracts time parts from @value, and sets @timegda's contents + +Accepted date format is "HH:MM:SS[.ms][TZ]" where TZ is +hour or -hour. +If no time zone is given UTC is used. + + + a new parsed #GdaTime + + + + + a string + + + + + + The methods mentioned in this section are reserved for database providers implementations and should +not bu used by developers outside that scope. + + + + + + + + Modifies @sqlst to take into account any parameter which might be %NULL: if @sqlst contains the +equivalent of "xxx = &lt;parameter definition&gt;" and if that parameter is in @params and +its value is of type GDA_TYPE_NUL, then that part is replaced with "xxx IS NULL". It also +handles the "xxx IS NOT NULL" transformation. + +If @out_modified is not %NULL, then it will be set to %TRUE if @sqlst has been modified +by this function, and to %FALSE otherwise. + +This function is used by provider's implementations to make sure one can use parameters with +NULL values in statements without having to rewrite statements, as database usually don't +consider that "xxx = NULL" is the same as "xxx IS NULL" when using parameters. + + + the modified @sqlst statement, or %NULL if an error occurred + + + + + a #GdaSqlStatement + + + + a #GdaSet to be used as parameters when executing @stmt + + + + a place to store the boolean which tells if @stmt has been modified or not, or %NULL + + + + + + Modifies @stmt to take into account any parameter which might be %NULL: if @stmt contains the +equivalent of "xxx = &lt;parameter definition&gt;" and if that parameter is in @params and +its value is of type GDA_TYPE_NUL, then that part is replaced with "xxx IS NULL". It also +handles the "xxx IS NOT NULL" transformation. + +For example the following SELECT: +<programlisting>SELECT * FROM data WHERE id = ##id::int::null AND name = ##name::string</programlisting> +in case the "id" parameter is set to NULL, is converted to: +<programlisting>SELECT * FROM data WHERE id IS NULL AND name = ##name::string</programlisting> + +if @out_stmt is not %NULL, then it will contain: +<itemizedlist> + <listitem><para>the modified statement if some modifications were required and no error occured (the function returns %TRUE)</para></listitem> + <listitem><para>%NULL if no modification to @stmt were required and no erro occurred (the function returns %FALSE)</para></listitem> + <listitem><para>%NULL if an error occured (the function returns %TRUE)</para></listitem> +</itemizedlist> + +This function is used by provider's implementations to make sure one can use parameters with +NULL values in statements without having to rewrite statements, as database usually don't +consider that "xxx = NULL" is the same as "xxx IS NULL" when using parameters. + + + %TRUE if @stmt needs to be transformed to handle NULL parameters, and %FALSE otherwise + + + + + a #GdaStatement + + + + a #GdaSet to be used as parameters when executing @stmt + + + + a place to store the new #GdaStatement, or %NULL + + + + + + Decodes @string using the RFC 1738 recommendations: the +<constant>&lt;&gt;&quot;#%{}|\^~[]&apos;`;/?:@=&amp;</constant> and space characters are replaced by +<constant>&quot;%%ab&quot;</constant> where +<constant>ab</constant> is the hexadecimal number corresponding to the character. + +@string should respect the RFC 1738 encoding. If this is not the case (for example if there +is a "%2z" because 2z is not an hexadecimal value), then the part with the problem +is not decoded, and the function returns FALSE. + +@string is decoded in place, no new string gets created. + + + %TRUE if no error occurred. + + + + + a string to decode + + + + + + Encodes @string using the RFC 1738 recommendations: the +<constant>&lt;&gt;&quot;#%{}|\^~[]&apos;`;/?:@=&amp;</constant> and space characters are replaced by +<constant>&quot;%%ab&quot;</constant> where +<constant>ab</constant> is the hexadecimal number corresponding to the character. + + + a new string or %NULL + + + + + a string to encode + + + + + + Creates a new #GdaStatement, selecting the same data as @stmt, but which always returns an +empty (no row) data model. This is use dy database providers' implementations. + + + a new #GdaStatement + + + + + a SELECT #GdaStatement + + + + + + + + + + + + + + + + + + + + + + + + + + Add double quotes around the @str identifier. This function is normally used only by database provider's +implementation. Any double quote character is replaced by two double quote characters. + +For other uses, see gda_sql_identifier_quote(). + + + + + + + an SQL identifier + + + + + + Prepares @str to be compared: +<itemizedlist> +<listitem><para>if surrounded by double quotes or single quotes, then just remove the quotes</para></listitem> +<listitem><para>otherwise convert to lower case</para></listitem> +</itemizedlist> + +The quoted string: +<itemizedlist> + <listitem><para>must start and finish with the same single or double quotes character</para></listitem> + <listitem><para>can contain the delimiter character (the single or double quotes) in the string if every instance + of it is preceeded with a backslash character or with the delimiter character itself</para></listitem> +</itemizedlist> + +This function is normally used only by database provider's implementation. + +WARNING: @str must NOT be a composed identifier (&lt;part1&gt;."&lt;part2&gt;" for example) +WARNING: you may have to <code>#include &lt;sql-parser/gda-sql-parser.h&gt;</code> + + + @str + + + + + a quoted string + + + + + + Use this function for any SQL identifier to make sure that: +<itemizedlist> + <listitem> + <para>it is correctly formatted + to be used with @cnc (if @cnc is %NULL, then some default SQL quoting rules will be applied, + similar to PostgreSQL's way) if @for_meta_store is %FALSE; + </para> + </listitem> + <listitem> + <para>it is correctly formatted to be used with the #GdaMetaStore's object associated to @cnc + is @for_meta_store is %TRUE. + </para> + </listitem> +</itemizedlist> + +The @force_quotes allow some control of how to interpret @id: if %FALSE, then @id will be left +unchanged most of the time (except for example if it's a reserved keyword), otherwise +if @force_quotes is %TRUE, then the returned string will most probably have quotes around it +to request that the database keep the case sensitiveness (but again, this may vary depending +on the database being accessed through @cnc). + +For example, the following table gives the result of this function depending on the arguments +when @cnc is %NULL (and @prov is also %NULL): +<table frame="all"> + <tgroup cols="6" colsep="1" rowsep="1" align="justify"> + <thead> + <row> + <entry>id</entry> + <entry>for_meta_store=%FALSE, force_quotes=%FALSE</entry> + <entry>for_meta_store=%TRUE, force_quotes=%FALSE</entry> + <entry>for_meta_store=%FALSE, force_quotes=%TRUE</entry> + <entry>for_meta_store=%TRUE, force_quotes=%TRUE</entry> + <entry>remark</entry> + </row> + </thead> + <tbody> + <row> + <entry>"double word"</entry> + <entry>"double word"</entry> + <entry>"double word"</entry> + <entry>"double word"</entry> + <entry>"double word"</entry> + <entry>non allowed character in SQL identifier</entry> + </row> + <row> + <entry>"CapitalTest"</entry> + <entry>"CapitalTest"</entry> + <entry>"CapitalTest"</entry> + <entry>"CapitalTest"</entry> + <entry>"CapitalTest"</entry> + <entry>Mixed case SQL identifier, already quoted</entry> + </row> + <row> + <entry>CapitalTest</entry> + <entry>CapitalTest</entry> + <entry>capitaltest</entry> + <entry>"CapitalTest"</entry> + <entry>"CapitalTest"</entry> + <entry>Mixed case SQL identifier, non quoted</entry> + </row> + <row> + <entry>"mytable"</entry> + <entry>"mytable"</entry> + <entry>mytable</entry> + <entry>"mytable"</entry> + <entry>mytable</entry> + <entry>All lowser case, quoted</entry> + </row> + <row> + <entry>mytable</entry> + <entry>mytable</entry> + <entry>mytable</entry> + <entry>"mytable"</entry> + <entry>mytable</entry> + <entry>All lowser case</entry> + </row> + <row> + <entry>MYTABLE</entry> + <entry>MYTABLE</entry> + <entry>mytable</entry> + <entry>"MYTABLE"</entry> + <entry>"MYTABLE"</entry> + <entry>All upper case</entry> + </row> + <row> + <entry>"MYTABLE"</entry> + <entry>"MYTABLE"</entry> + <entry>"MYTABLE"</entry> + <entry>"MYTABLE"</entry> + <entry>"MYTABLE"</entry> + <entry>All upper case, quoted</entry> + </row> + <row> + <entry>desc</entry> + <entry>"desc"</entry> + <entry>"desc"</entry> + <entry>"desc"</entry> + <entry>"desc"</entry> + <entry>SQL reserved keyword</entry> + </row> + <row> + <entry>5ive</entry> + <entry>"5ive"</entry> + <entry>"5ive"</entry> + <entry>"5ive"</entry> + <entry>"5ive"</entry> + <entry>SQL identifier starting with a digit</entry> + </row> + </tbody> + </tgroup> +</table> + +Here are a few examples of when and how to use this function: +<itemizedlist> + <listitem> + <para> + When creating a table, the user has entered the table name, this function can be used to + create a valid SQL identifier from the user provided table name: + <programlisting> +gchar *user_sqlid=... +gchar *valid_sqlid = gda_sql_identifier_quote (user_sqlid, cnc, NULL, FALSE, FALSE); +gchar *sql = g_strdup_printf ("CREATE TABLE %s ...", valid_sqlid); +g_free (valid_sqlid); + </programlisting> + Note that this is an illustration and creating a table should be sone using a #GdaServerOperation + object. + </para> + </listitem> + <listitem> + <para> + When updating the meta data associated to a table which has been created with the code + above: + <programlisting> +GValue table_name_value = { 0 }; +gchar* column_names[] = { (gchar*)"table_name" }; +GValue* column_values[] = { &table_name_value }; +GdaMetaContext mcontext = { (gchar*)"_tables", 1, column_names, column_values }; +g_value_init (&amp;table_name_value, G_TYPE_STRING); +g_value_take_string (&amp;table_name_value, gda_sql_identifier_quote (user_sqlid, cnc, NULL, TRUE, FALSE); +gda_connection_update_meta_store (cnc, &amp;mcontext, NULL); +g_value_reset (&amp;table_name_value); + </programlisting> + </para> + </listitem> + <listitem> + <para> + When using a #GdaMetaStruct object to fetch information about a table (which has been created with + the code above): + <programlisting> +GValue table_name_value = { 0 }; +g_value_init (&amp;table_name_value, G_TYPE_STRING); +g_value_take_string (&amp;table_name_value, gda_sql_identifier_quote (user_sqlid, cnc, NULL, TRUE, FALSE); +GdaMetaDbObject *dbo; +dbo = gda_meta_struct_complement (mstruct, GDA_META_DB_TABLE, NULL, NULL, &amp;table_name_value, NULL); +g_value_reset (&amp;table_name_value); + </programlisting> + </para> + </listitem> +</itemizedlist> + + +Note that @id must not be a composed SQL identifier (such as "mytable.mycolumn" which should be +treated as the "mytable" and "mycolumn" SQL identifiers). If unsure, use gda_sql_identifier_split(). + +Also note that if @cnc is %NULL, then it's possible to pass an non %NULL @prov to have a result specific +to @prov. + +For more information, see the <link linkend="gen:sql_identifiers">SQL identifiers and abstraction</link> and +<link linkend="information_schema:sql_identifiers">SQL identifiers in meta data</link> sections. + + + the representation of @id ready to be used in SQL statement, as a new string, + or %NULL if @id is in a wrong format + + + + + an SQL identifier + + + + a #GdaConnection object, or %NULL + + + + a #GdaServerProvider object, or %NULL +@for_meta_store set to %TRUE if the returned string will be used in a #GdaMetaStore + + + + + + + set to %TRUE to force the returned string to be quoted + + + + + + Splits @id into an array of it sub parts. @id's format has to be "&lt;part&gt;[.&lt;part&gt;[...]]" where +each part is either a text surrounded by double quotes which can contain upper and lower cases or +an SQL identifier in lower case. + +For example the <![CDATA["test.\"ATable\""]]> string will result in the array: <![CDATA[{"test", "\"ATable\"", NULL}]]> + + + a new %NULL-terminated array of strings, or NULL (use g_strfreev() to free the returned array) + + + + + + + an SQL identifier + + + + + + Returns #GdaSqlOperatorType that correspond with the string @op. + + + #GdaSqlOperatorType + + + + + a #GdaSqlOperation structure + + + + + + Returns a constant string representing a operator name. You don't need to free +the returned string. + + + a string with the operator's name or NULL in case @op is invalid. + + + + + a #GdaSqlOperation structure + + + + + + Creates a new string representing the join type. + + + a string representing the Join type. + + + + + a #GdaSqlSelectJoinType structure to be copied + + + + + + + + + + + + + + + + + Converts a string to a #GdaSqlStatementType value, see also gda_sql_statement_type_to_string() + + + a #GdaSqlStatementType value + + + + + a string representing a #GdaSqlStatementType type + + + + + + Converts a #GdaSqlStatementType to a string, see also gda_sql_statement_string_to_type() + + + a constant string + + + + + a #GdaSqlStatementType value + + + + + + Simplified version of gda_value_stringify(). + + + a new string + + + + + a #GValue pointer + + + + + + + + + + + + + + + + + Performs the reverse of gda_binary_to_string() (note that for any "\xyz" succession +of 4 characters where "xyz" represents a valid octal value, the resulting read value will +be modulo 256). + +I @str is %NULL, then an empty (i.e. where the @data part is %NULL) #GdaBinary is created and returned. + + + a new #GdaBinary if no error were found in @str, or %NULL otherwise + + + + + a string to convert, or %NULL + + + + + + Performs the reverse of gda_blob_to_string(). + + + a new #gdaBlob if no error were found in @str, or NULL otherwise + + + + + a string to convert + + + + + + The "encoding" consists in replacing non +alphanumeric character with the string "__gdaXX" where XX is the hex. representation +of the non alphanumeric char. + + + a new string + + + + + the text to convert + + + + + + Check the column types of a GdaDataModel. + + + %TRUE if the data model's columns match the provided data types and number + + + + + a #GdaDataModel object + + + + the minimum requested number of columns + + + + @nbcols arguments of type GType or -1 (if any data type is accepted) + + + + + + Check the column types of a GdaDataModel. + + + %TRUE if the data model's columns match the provided data types and number + + + + + a #GdaDataModel object + + + + the minimum requested number of columns. Lenght of @types + + + + array with @nbcols length of type GType or null (if any data type is accepted) + + + + + + + + Dump the data in a #GdaDataModel into a xmlNodePtr (as used in libxml). + +Warning: this function uses a #GdaDataModelIter iterator, and if @model does not offer a random access +(check using gda_data_model_get_access_flags()), the iterator will be the same as normally used +to access data in @model previously to calling this method, and this iterator will be moved (point to +another row). + + + %TRUE if no error occurred + + + + + a #GdaDataModel + + + + the parent XML node + + + + an array containing which columns of @model will be exported, or %NULL for all columns + + + + + + the number of columns in @cols + + + + an array containing which rows of @model will be exported, or %NULL for all rows + + + + + + the number of rows in @rows + + + + set to %TRUE to add column ID information + + + + + + Finds the description of a field into Metadata from a #GdaDataModel. + + + The field's description, or NULL if description is not set + + + + + a #GdaDataSelect data model + + + + field name + + + + + + Note: this method may set the "source" custom string property + + + %TRUE if no error occurred + + + + + a #GdaHolder + + + + an xmlNodePtr with a &lt;parameter&gt; tag + + + + a list of #GdaDataModel + + + + + + + + Compares two values of the same type, with the exception that a value of any type can be +compared to a GDA_TYPE_NULL value, specifically: +<itemizedlist> + <listitem><para>if @value1 and @value2 are both GDA_TYPE_NULL values then the returned value is 0</para></listitem> + <listitem><para>if @value1 is a GDA_TYPE_NULL value and @value2 is of another type then the returned value is -1</para></listitem> + <listitem><para>if @value1 is of another type and @value2 is a GDA_TYPE_NULL value then the returned value is 1</para></listitem> + <listitem><para>in all other cases, @value1 and @value2 must be of the same type and their values are compared</para></listitem> +</itemizedlist> + + + if both values have the same type, returns 0 if both contain +the same value, an integer less than 0 if @value1 is less than @value2 or +an integer greater than 0 if @value1 is greater than @value2. + + + + + a #GValue to compare (not %NULL) + + + + the other #GValue to be compared to @value1 (not %NULL) + + + + + + Creates a new #GValue from an existing one. + + + a newly allocated #GValue with a copy of the data in @value. + +Free-function: gda_value_free + + + + + value to get a copy from. + + + + + + Tells if two values are equal or not, by comparing memory representations. Unlike gda_value_compare(), +the returned value is boolean, and gives no idea about ordering. + +The two values must be of the same type, with the exception that a value of any type can be +compared to a GDA_TYPE_NULL value, specifically: +<itemizedlist> + <listitem><para>if @value1 and @value2 are both GDA_TYPE_NULL values then the returned value is 0</para></listitem> + <listitem><para>if @value1 is a GDA_TYPE_NULL value and @value2 is of another type then the returned value is 1</para></listitem> + <listitem><para>if @value1 is of another type and @value2 is a GDA_TYPE_NULL value then the returned value is 1</para></listitem> + <listitem><para>in all other cases, @value1 and @value2 must be of the same type and their values are compared</para></listitem> +</itemizedlist> + + + a non 0 value if @value1 and @value2 differ, and 0 if they are equal + + + + + a #GValue to compare. + + + + the other #GValue to be compared to @value1. + + + + + + Deallocates all memory associated to a #GValue. + + + + + + + the resource to free (or %NULL) + + + + + + + + the value stored in @value. + + + + + a #GValue whose value we want to get. + + + + + + + + the value stored in @value. + + + + + a #GValue whose value we want to get. + + + + + + + + the value stored in @value. + + + + + a #GValue whose value we want to get. + + + + + + + + a #GdaMetaStoreChange + + + + + a #GValue to get value from + + + + + + + + the value stored in @value. + + + + + a #GValue whose value we want to get. + + + + + + + + the value stored in @value. + + + + + a #GValue whose value we want to get. + + + + + + + + the value stored in @value. + + + + + a #GValue whose value we want to get. + + + + + + + + the value stored in @value. + + + + + a #GValue whose value we want to get. + + + + + + Tests if a given @value is of type #GDA_TYPE_NULL. + + + a boolean that says whether or not @value is of type #GDA_TYPE_NULL. + + + + + value to test. + + + + + + Gets whether the value stored in the given #GValue is of numeric type or not. + + + %TRUE if a number, %FALSE otherwise. + + + + + a #GValue. + + + + + + + + + + + + + + + Creates a new #GValue of type @type, left in the same state as when g_value_init() is called. + + + the newly created #GValue with the specified @type. You need to set the value in the returned GValue. + +Free-function: gda_value_free + + + + + the new value type. + + + + + + Makes a new #GValue of type #GDA_TYPE_BINARY with value @val. + + + the newly created #GValue. + +Free-function: gda_value_free + + + + + value to set for the new #GValue. + + + + the size of the memory pool pointer to by @val. + + + + + + Makes a new #GValue of type #GDA_TYPE_BLOB with the data contained by @val. + + + the newly created #GValue. + +Free-function: gda_value_free + + + + + value to set for the new #GValue. + + + + the size of the memory pool pointer to by @val. + + + + + + Makes a new #GValue of type #GDA_TYPE_BLOB interfacing with the contents of the file +named @filename + + + the newly created #GValue. + +Free-function: gda_value_free + + + + + name of the file to manipulate + + + + + + Makes a new #GValue of type #G_TYPE_DATE_TIME with value @val +(of type time_t). The returned timestamp's value is relative to the current +timezone (i.e. is localtime). + +For example, to get a time stamp representing the current date and time, use: + +<code> +ts = gda_value_new_date_time_from_timet (time (NULL)); +</code> + + + the newly created #GValue, or %NULL in case of error + +Free-function: gda_value_free + + + + + value to set for the new #GValue. + + + + + + Creates a new default value. + + + a new #GValue of the type #GDA_TYPE_DEFAULT + + + + + the default value as a string, or %NULL + + + + + + Makes a new #GValue of type @type from its string representation. + +For more information +about the string format, see the gda_value_set_from_string() function. +This function is typically used when reading configuration files or other non-user input that should be locale +independent. + + + the newly created #GValue or %NULL if the string representation cannot be converted to the specified @type. + +Free-function: gda_value_free + + + + + stringified representation of the value. + + + + the new value type. + + + + + + Creates a GValue from an XML representation of it. That XML +node corresponds to the following string representation: +&lt;value type="gdatype"&gt;value&lt;/value&gt; + +For more information +about the string format, see the gda_value_set_from_string() function. +This function is typically used when reading configuration files or other non-user input that should be locale +independent. + + + the newly created #GValue. + +Free-function: gda_value_free + + + + + an XML node representing the value. + + + + + + Creates a new #GValue initiated to a #GdaNull structure with a #GDA_TYPE_NULL, to +represent a NULL in the database. + + + a new #GValue of the type #GDA_TYPE_NULL + + + + + Makes a new #GValue of type #GDA_TYPE_TIME with value @val +(of type time_t). The returned times's value is relative to the current +timezone (i.e. is localtime). + +For example, to get a time representing the current time, use: + +<code> +ts = gda_value_new_time_from_timet (time (NULL)); +</code> + + + the newly created #GValue, or %NULL in case of error + +Free-function: gda_value_free + + + + + value to set for the new #GValue. + + + + + + Resets the #GValue and set a new type to #GType. + + + + + + + the #GValue to be reseted + + + + the #GType to set to + + + + + + Stores @val into @value. + + + + + + + a #GValue that will store @val. + + + + a #GdaBinary structure with the data and its size to be stored in @value. + + + + + + Stores @val into @value. + + + + + + + a #GValue that will store @val. + + + + a #GdaBlob structure with the data and its size to be stored in @value. + + + + + + Stores the value data from its string representation as @type. + +The accepted formats are: +<itemizedlist> + <listitem><para>G_TYPE_BOOLEAN: a caseless comparison is made with "true" or "false"</para></listitem> + <listitem><para>numerical types: C locale format (dot as a fraction separator)</para></listitem> + <listitem><para>G_TYPE_DATE: see <link linkend="gda-parse-iso8601-date">gda_parse_iso8601_date()</link></para></listitem> + <listitem><para>GDA_TYPE_TIME: see <link linkend="gda-parse-iso8601-time">gda_parse_iso8601_time()</link></para></listitem> + <listitem><para>GDA_TYPE_TIMESTAMP: see <link linkend="g-date-time-new-iso8601">g_date_time_new_from_iso8601()</link></para></listitem> +</itemizedlist> + +This function is typically used when reading configuration files or other non-user input that should be locale +independent. + + + %TRUE if the value has been converted to @type from +its string representation; it not means that the value is converted +successfully, just that the transformation is available. %FALSE otherwise. + + + + + a #GValue that will store @val. + + + + the stringified representation of the value. + + + + the type of the value + + + + + + Sets the value of a #GValue from another #GValue. This +is different from #gda_value_copy, which creates a new #GValue. +#gda_value_set_from_value, on the other hand, copies the contents +of @copy into @value, which must already be allocated. + +If values are incompatible (see @g_value_type_compatible) then @value is set to a +#GDA_TYPE_NULL, and %FALSE is returned. + + + %TRUE if successful, %FALSE otherwise. + + + + + a #GValue. + + + + the value to copy from. + + + + + + Stores @val into @value. + + + + + + + a #GValue that will store @val. + + + + value to be stored in @value. + + + + + + + + + + + + a #GValue to set value to + + + + a #GdaMetaStoreChange to be set + + + + + + Sets the type of @value to #GDA_TYPE_NULL. + + + + + + + a #GValue that will store a value of type #GDA_TYPE_NULL. + + + + + + Stores @val into @value. + + + + + + + a #GValue that will store @val. + + + + value to be stored in @value. + + + + + + Stores @val into @value. + + + + + + + a #GValue that will store @val. + + + + value to be stored in @value. + + + + + + Stores @val into @value. + + + + + + + a #GValue that will store @val. + + + + value to be stored in @value. + + + + + + Stores @val into @value. + + + + + + + a #GValue that will store @val. + + + + value to be stored in @value. + + + + + + Converts a GValue to its string representation which is a human readable value. Note that the +returned string does not take into account the current locale of the user (on the contrary to the +#GdaDataHandler objects). Using this function should be limited to debugging and values serialization +purposes. + +Output is in the "C" locale for numbers, and dates are converted in a YYYY-MM-DD format. + + + a new string, or %NULL if the conversion cannot be done. Free the value with a g_free() when you've finished using it. + + + + + a #GValue. + + + + + + Stores @val into @value, but on the contrary to gda_value_set_binary(), the @binary +argument is not copied, but used as-is and it should be considered owned by @value. + + + + + + + a #GValue that will store @val. + + + + a #GdaBinary structure with the data and its size to be stored in @value. + + + + + + Stores @val into @value, but on the contrary to gda_value_set_blob(), the @blob +argument is not copied, but used as-is and it should be considered owned by @value. + + + + + + + a #GValue that will store @val. + + + + a #GdaBlob structure with the data and its size to be stored in @value. + + + + + + Serializes the given #GValue to an XML node string. + + + the XML node. Once not needed anymore, you should free it. + + + + + a #GValue. + + + + + + This methods creates an XML string representation of a #GValue + + + an string representing a #GValue in XML format + + + + + a #GValue to convert to string + + + + + + + + + + + This function creates a new #GdaWorker, or reuses the one at @location. Specifically: +<orderedlist> + <listitem><para>if *@location is %NULL, then a new #GdaWorker is created. In this case if @allow_destroy is %FALSE, then the returned + #GdaWorker's reference count is 2, thus preventing it form ever being destroyed (unless gda_worker_unref() is called somewhere else)</para></listitem> + <listitem><para>if *@location is not %NULL, the the #GdaWorker it points to is returned, its reference count increased by 1</para></listitem> +</orderedlist> + +When the returned #GdaWorker's reference count reaches 0, then it is destroyed, and *@location is set to %NULL. + +In any case, the returned value is the same as *@location. + + + a #GdaWorker + + + + + a place to store and test for existence, not %NULL + + + + defines if the created @GdaWorker (see case 1 below) will allow its reference to drop to 0 and be destroyed + + + + + + diff --git a/.flatpak-builder/cache/objects/f6/f25497027961e032f26e33601018d09be5a0b7c2b68850de064e6c9f738a7c.file b/.flatpak-builder/cache/objects/f6/f25497027961e032f26e33601018d09be5a0b7c2b68850de064e6c9f738a7c.file new file mode 100644 index 0000000..d0f3be5 --- /dev/null +++ b/.flatpak-builder/cache/objects/f6/f25497027961e032f26e33601018d09be5a0b7c2b68850de064e6c9f738a7c.file @@ -0,0 +1,396 @@ +# values.py +# +# Copyright 2022 James Westman +# +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation; either version 3 of the +# License, or (at your option) any later version. +# +# This file is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program. If not, see . +# +# SPDX-License-Identifier: LGPL-3.0-or-later + +import typing as T + +from .common import * +from .types import TypeName +from .gobject_object import Object +from .contexts import ScopeCtx, ValueTypeCtx + + +class Translated(AstNode): + grammar = AnyOf( + ["_", "(", UseQuoted("string"), ")"], + [ + "C_", + "(", + UseQuoted("context"), + ",", + UseQuoted("string"), + ")", + ], + ) + + @property + def string(self) -> str: + return self.tokens["string"] + + @property + def translate_context(self) -> T.Optional[str]: + return self.tokens["context"] + + @validate() + def validate_for_type(self) -> None: + expected_type = self.context[ValueTypeCtx].value_type + if expected_type is not None and not expected_type.assignable_to(StringType()): + raise CompileError( + f"Cannot convert translated string to {expected_type.full_name}" + ) + + +class TypeLiteral(AstNode): + grammar = [ + "typeof", + AnyOf( + [ + "<", + to_parse_node(TypeName).expected("type name"), + Match(">").expected(), + ], + [ + UseExact("lparen", "("), + to_parse_node(TypeName).expected("type name"), + UseExact("rparen", ")").expected("')'"), + ], + ), + ] + + @property + def type(self): + return gir.TypeType() + + @property + def type_name(self) -> TypeName: + return self.children[TypeName][0] + + @validate() + def validate_for_type(self) -> None: + expected_type = self.context[ValueTypeCtx].value_type + if expected_type is not None and not isinstance(expected_type, gir.TypeType): + raise CompileError(f"Cannot convert GType to {expected_type.full_name}") + + @validate("lparen", "rparen") + def upgrade_to_angle_brackets(self): + if self.tokens["lparen"]: + raise UpgradeWarning( + "Use angle bracket syntax introduced in blueprint 0.8.0", + actions=[ + CodeAction( + "Use <> instead of ()", + f"<{self.children[TypeName][0].as_string}>", + ) + ], + ) + + +class QuotedLiteral(AstNode): + grammar = UseQuoted("value") + + @property + def value(self) -> str: + return self.tokens["value"] + + @property + def type(self): + return gir.StringType() + + @validate() + def validate_for_type(self) -> None: + expected_type = self.context[ValueTypeCtx].value_type + if ( + isinstance(expected_type, gir.IntType) + or isinstance(expected_type, gir.UIntType) + or isinstance(expected_type, gir.FloatType) + ): + raise CompileError(f"Cannot convert string to number") + + elif isinstance(expected_type, gir.StringType): + pass + + elif ( + isinstance(expected_type, gir.Class) + or isinstance(expected_type, gir.Interface) + or isinstance(expected_type, gir.Boxed) + ): + parseable_types = [ + "Gdk.Paintable", + "Gdk.Texture", + "Gdk.Pixbuf", + "Gio.File", + "Gtk.ShortcutTrigger", + "Gtk.ShortcutAction", + "Gdk.RGBA", + "Gdk.ContentFormats", + "Gsk.Transform", + "GLib.Variant", + ] + if expected_type.full_name not in parseable_types: + hints = [] + if isinstance(expected_type, gir.TypeType): + hints.append(f"use the typeof operator: 'typeof({self.value})'") + raise CompileError( + f"Cannot convert string to {expected_type.full_name}", hints=hints + ) + + elif expected_type is not None: + raise CompileError(f"Cannot convert string to {expected_type.full_name}") + + +class NumberLiteral(AstNode): + grammar = [ + Optional(AnyOf(UseExact("sign", "-"), UseExact("sign", "+"))), + UseNumber("value"), + ] + + @property + def type(self) -> gir.GirType: + if isinstance(self.value, int): + return gir.IntType() + else: + return gir.FloatType() + + @property + def value(self) -> T.Union[int, float]: + if self.tokens["sign"] == "-": + return -self.tokens["value"] + else: + return self.tokens["value"] + + @validate() + def validate_for_type(self) -> None: + expected_type = self.context[ValueTypeCtx].value_type + if isinstance(expected_type, gir.IntType): + if not isinstance(self.value, int): + raise CompileError( + f"Cannot convert {self.group.tokens['value']} to integer" + ) + + elif isinstance(expected_type, gir.UIntType): + if self.value < 0: + raise CompileError( + f"Cannot convert -{self.group.tokens['value']} to unsigned integer" + ) + + elif not isinstance(expected_type, gir.FloatType) and expected_type is not None: + raise CompileError(f"Cannot convert number to {expected_type.full_name}") + + +class Flag(AstNode): + grammar = UseIdent("value") + + @property + def name(self) -> str: + return self.tokens["value"] + + @property + def value(self) -> T.Optional[int]: + type = self.context[ValueTypeCtx].value_type + if not isinstance(type, Enumeration): + return None + elif member := type.members.get(self.name): + return member.value + else: + return None + + @docs() + def docs(self): + type = self.context[ValueTypeCtx].value_type + if not isinstance(type, Enumeration): + return + if member := type.members.get(self.tokens["value"]): + return member.doc + + @validate() + def validate_for_type(self): + expected_type = self.context[ValueTypeCtx].value_type + if ( + isinstance(expected_type, gir.Bitfield) + and self.tokens["value"] not in expected_type.members + ): + raise CompileError( + f"{self.tokens['value']} is not a member of {expected_type.full_name}", + did_you_mean=(self.tokens["value"], expected_type.members.keys()), + ) + + @validate() + def unique(self): + self.validate_unique_in_parent( + f"Duplicate flag '{self.name}'", lambda x: x.name == self.name + ) + + +class Flags(AstNode): + grammar = [Flag, "|", Flag, ZeroOrMore(["|", Flag])] + + @property + def flags(self) -> T.List[Flag]: + return self.children + + @validate() + def validate_for_type(self) -> None: + expected_type = self.context[ValueTypeCtx].value_type + if expected_type is not None and not isinstance(expected_type, gir.Bitfield): + raise CompileError(f"{expected_type.full_name} is not a bitfield type") + + +class IdentLiteral(AstNode): + grammar = UseIdent("value") + + @property + def ident(self) -> str: + return self.tokens["value"] + + @property + def type(self) -> T.Optional[gir.GirType]: + # If the expected type is known, then use that. Otherwise, guess. + if expected_type := self.context[ValueTypeCtx].value_type: + return expected_type + elif self.ident in ["true", "false"]: + return gir.BoolType() + elif object := self.context[ScopeCtx].objects.get(self.ident): + return object.gir_class + elif self.root.is_legacy_template(self.ident): + return self.root.template.class_name.gir_type + else: + return None + + @validate() + def validate_for_type(self) -> None: + expected_type = self.context[ValueTypeCtx].value_type + if isinstance(expected_type, gir.BoolType): + if self.ident not in ["true", "false"]: + raise CompileError(f"Expected 'true' or 'false' for boolean value") + + elif isinstance(expected_type, gir.Enumeration): + if self.ident not in expected_type.members: + raise CompileError( + f"{self.ident} is not a member of {expected_type.full_name}", + did_you_mean=(self.ident, list(expected_type.members.keys())), + ) + + elif self.root.is_legacy_template(self.ident): + raise UpgradeWarning( + "Use 'template' instead of the class name (introduced in 0.8.0)", + actions=[CodeAction("Use 'template'", "template")], + ) + + elif expected_type is not None: + object = self.context[ScopeCtx].objects.get(self.ident) + if object is None: + if self.ident == "null": + if not self.context[ValueTypeCtx].allow_null: + raise CompileError("null is not permitted here") + else: + raise CompileError( + f"Could not find object with ID {self.ident}", + did_you_mean=( + self.ident, + self.context[ScopeCtx].objects.keys(), + ), + ) + elif object.gir_class and not object.gir_class.assignable_to(expected_type): + raise CompileError( + f"Cannot assign {object.gir_class.full_name} to {expected_type.full_name}" + ) + + @docs() + def docs(self) -> T.Optional[str]: + type = self.context[ValueTypeCtx].value_type + if isinstance(type, gir.Enumeration): + if member := type.members.get(self.ident): + return member.doc + else: + return type.doc + elif isinstance(type, gir.GirNode): + return type.doc + else: + return None + + def get_semantic_tokens(self) -> T.Iterator[SemanticToken]: + type = self.context[ValueTypeCtx].value_type + if isinstance(type, gir.Enumeration): + token = self.group.tokens["value"] + yield SemanticToken(token.start, token.end, SemanticTokenType.EnumMember) + + +class Literal(AstNode): + grammar = AnyOf( + TypeLiteral, + QuotedLiteral, + NumberLiteral, + IdentLiteral, + ) + + @property + def value( + self, + ) -> T.Union[TypeLiteral, QuotedLiteral, NumberLiteral, IdentLiteral]: + return self.children[0] + + +class ObjectValue(AstNode): + grammar = Object + + @property + def object(self) -> Object: + return self.children[Object][0] + + @validate() + def validate_for_type(self) -> None: + expected_type = self.context[ValueTypeCtx].value_type + if ( + expected_type is not None + and self.object.gir_class is not None + and not self.object.gir_class.assignable_to(expected_type) + ): + raise CompileError( + f"Cannot assign {self.object.gir_class.full_name} to {expected_type.full_name}" + ) + + +class Value(AstNode): + grammar = AnyOf(Translated, Flags, Literal) + + @property + def child( + self, + ) -> T.Union[Translated, Flags, Literal]: + return self.children[0] + + +class StringValue(AstNode): + grammar = AnyOf(Translated, QuotedLiteral) + + @property + def child( + self, + ) -> T.Union[Translated, QuotedLiteral]: + return self.children[0] + + @property + def string(self) -> str: + if isinstance(self.child, Translated): + return self.child.string + else: + return self.child.value + + @context(ValueTypeCtx) + def value_type(self) -> ValueTypeCtx: + return ValueTypeCtx(StringType()) diff --git a/.flatpak-builder/cache/objects/f7/ad71ce53ee1b483651dd291c457062c1ee0996ef22e235ae63ee2d17abc95e.dirtree b/.flatpak-builder/cache/objects/f7/ad71ce53ee1b483651dd291c457062c1ee0996ef22e235ae63ee2d17abc95e.dirtree new file mode 100644 index 0000000..4b04279 Binary files /dev/null and b/.flatpak-builder/cache/objects/f7/ad71ce53ee1b483651dd291c457062c1ee0996ef22e235ae63ee2d17abc95e.dirtree differ diff --git a/.flatpak-builder/cache/objects/f7/b27e5d2c3974583c301f82edffaaadca86d5d6a9fc2ea870e43f1a1bc03a0b.file b/.flatpak-builder/cache/objects/f7/b27e5d2c3974583c301f82edffaaadca86d5d6a9fc2ea870e43f1a1bc03a0b.file new file mode 100644 index 0000000..c8581d8 --- /dev/null +++ b/.flatpak-builder/cache/objects/f7/b27e5d2c3974583c301f82edffaaadca86d5d6a9fc2ea870e43f1a1bc03a0b.file @@ -0,0 +1,3742 @@ +/* Driver template for the LEMON parser generator. +** The author disclaims copyright to this source code. +*/ +/* First off, code is included that follows the "include" declaration +** in the input grammar file. */ +#include +#line 36 "../libgda/sql-parser/parser.y" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef struct { + GValue *fname; + GdaSqlExpr *expr; +} UpdateSet; + +typedef struct { + gboolean distinct; + GdaSqlExpr *expr; +} Distinct; + +typedef struct { + GdaSqlExpr *count; + GdaSqlExpr *offset; +} Limit; + +typedef struct { + GSList *when_list; + GSList *then_list; +} CaseBody; + +static GdaSqlOperatorType +sql_operation_string_to_operator (const gchar *op) +{ + switch (g_ascii_toupper (*op)) { + case 'A': + return GDA_SQL_OPERATOR_TYPE_AND; + case 'O': + return GDA_SQL_OPERATOR_TYPE_OR; + case 'N': + return GDA_SQL_OPERATOR_TYPE_NOT; + case '=': + return GDA_SQL_OPERATOR_TYPE_EQ; + case 'I': + if (op[1] == 'S') + return GDA_SQL_OPERATOR_TYPE_IS; + else if (op[1] == 'N') + return GDA_SQL_OPERATOR_TYPE_IN; + else if (op[1] == 'I') + return GDA_SQL_OPERATOR_TYPE_ILIKE; + break; + case 'L': + return GDA_SQL_OPERATOR_TYPE_LIKE; + case 'B': + return GDA_SQL_OPERATOR_TYPE_BETWEEN; + case '>': + if (op[1] == '=') + return GDA_SQL_OPERATOR_TYPE_GEQ; + else if (op[1] == 0) + return GDA_SQL_OPERATOR_TYPE_GT; + break; + case '<': + if (op[1] == '=') + return GDA_SQL_OPERATOR_TYPE_LEQ; + else if (op[1] == '>') + return GDA_SQL_OPERATOR_TYPE_DIFF; + else if (op[1] == 0) + return GDA_SQL_OPERATOR_TYPE_LT; + break; + case '!': + if (op[1] == '=') + return GDA_SQL_OPERATOR_TYPE_DIFF; + else if (op[1] == '~') { + if (op[2] == 0) + return GDA_SQL_OPERATOR_TYPE_NOT_REGEXP; + else if (op[2] == '*') + return GDA_SQL_OPERATOR_TYPE_NOT_REGEXP_CI; + } + break; + case '~': + if (op[1] == '*') + return GDA_SQL_OPERATOR_TYPE_REGEXP_CI; + else if (op[1] == 0) + return GDA_SQL_OPERATOR_TYPE_REGEXP; + break; + case 'S': + return GDA_SQL_OPERATOR_TYPE_SIMILAR; + case '|': + if (op[1] == '|') + return GDA_SQL_OPERATOR_TYPE_CONCAT; + else + return GDA_SQL_OPERATOR_TYPE_BITOR; + case '+': + return GDA_SQL_OPERATOR_TYPE_PLUS; + case '-': + return GDA_SQL_OPERATOR_TYPE_MINUS; + case '*': + return GDA_SQL_OPERATOR_TYPE_STAR; + case '/': + return GDA_SQL_OPERATOR_TYPE_DIV; + case '%': + return GDA_SQL_OPERATOR_TYPE_REM; + case '&': + return GDA_SQL_OPERATOR_TYPE_BITAND; + } + g_error ("Unhandled operator named '%s'\n", op); + return 0; +} + +static GdaSqlOperatorType +string_to_op_type (GValue *value) +{ + GdaSqlOperatorType op; + op = sql_operation_string_to_operator (g_value_get_string (value)); + g_value_reset (value); + g_free (value); + return op; +} + +static GdaSqlExpr * +compose_multiple_expr (GdaSqlOperatorType op, GdaSqlExpr *left, GdaSqlExpr *right) { + GdaSqlExpr *ret; + if (left->cond && (left->cond->operator_type == op)) { + ret = left; + ret->cond->operands = g_slist_append (ret->cond->operands, right); + } + else { + GdaSqlOperation *cond; + ret = gda_sql_expr_new (NULL); + cond = gda_sql_operation_new (GDA_SQL_ANY_PART (ret)); + ret->cond = cond; + cond->operator_type = op; + cond->operands = g_slist_prepend (NULL, right); + GDA_SQL_ANY_PART (right)->parent = GDA_SQL_ANY_PART (cond); + cond->operands = g_slist_prepend (cond->operands, left); + GDA_SQL_ANY_PART (left)->parent = GDA_SQL_ANY_PART (cond); + } + return ret; +} + +static GdaSqlExpr * +create_two_expr (GdaSqlOperatorType op, GdaSqlExpr *left, GdaSqlExpr *right) { + GdaSqlExpr *ret; + GdaSqlOperation *cond; + ret = gda_sql_expr_new (NULL); + cond = gda_sql_operation_new (GDA_SQL_ANY_PART (ret)); + ret->cond = cond; + cond->operator_type = op; + cond->operands = g_slist_prepend (NULL, right); + GDA_SQL_ANY_PART (right)->parent = GDA_SQL_ANY_PART (cond); + cond->operands = g_slist_prepend (cond->operands, left); + GDA_SQL_ANY_PART (left)->parent = GDA_SQL_ANY_PART (cond); + return ret; +} + +static GdaSqlExpr * +create_uni_expr (GdaSqlOperatorType op, GdaSqlExpr *expr) { + GdaSqlExpr *ret; + GdaSqlOperation *cond; + ret = gda_sql_expr_new (NULL); + cond = gda_sql_operation_new (GDA_SQL_ANY_PART (ret)); + ret->cond = cond; + cond->operator_type = op; + cond->operands = g_slist_prepend (NULL, expr); + GDA_SQL_ANY_PART (expr)->parent = GDA_SQL_ANY_PART (cond); + return ret; +} + +static GdaSqlStatement * +compose_multiple_compounds (GdaSqlStatementCompoundType ctype, GdaSqlStatement *left, GdaSqlStatement *right) { + GdaSqlStatement *ret = NULL; + GdaSqlStatementCompound *lc = (GdaSqlStatementCompound*) left->contents; + if (lc->compound_type == ctype) { + GdaSqlStatementCompound *rc = (GdaSqlStatementCompound*) right->contents; + if (!rc->stmt_list->next || rc->compound_type == ctype) { + GSList *list; + for (list = rc->stmt_list; list; list = list->next) + GDA_SQL_ANY_PART (((GdaSqlStatement*)list->data)->contents)->parent = GDA_SQL_ANY_PART (lc); + + ret = left; + lc->stmt_list = g_slist_concat (lc->stmt_list, rc->stmt_list); + rc->stmt_list = NULL; + gda_sql_statement_free (right); + } + } + else { + ret = gda_sql_statement_new (GDA_SQL_STATEMENT_COMPOUND); + gda_sql_statement_compound_set_type (ret, ctype); + gda_sql_statement_compound_take_stmt (ret, left); + gda_sql_statement_compound_take_stmt (ret, right); + } + return ret; +} + +#line 208 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" +/* Next is all token values, in a form suitable for use by makeheaders. +** This section will be null unless lemon is run with the -m switch. +*/ +/* +** These constants (all generated automatically by the parser generator) +** specify the various kinds of tokens (terminals) that the parser +** understands. +** +** Each symbol here is a terminal symbol in the grammar. +*/ +/* Make sure the INTERFACE macro is defined. +*/ +#ifndef INTERFACE +# define INTERFACE 1 +#endif +/* The next thing included is series of defines which control +** various aspects of the generated parser. +** YYCODETYPE is the data type used for storing terminal +** and nonterminal numbers. "unsigned char" is +** used if there are fewer than 250 terminals +** and nonterminals. "int" is used otherwise. +** YYNOCODE is a number of type YYCODETYPE which corresponds +** to no legal terminal or nonterminal number. This +** number is used to fill in empty slots of the hash +** table. +** YYFALLBACK If defined, this indicates that one or more tokens +** have fall-back values which should be used if the +** original value of the token will not parse. +** YYACTIONTYPE is the data type used for storing terminal +** and nonterminal numbers. "unsigned char" is +** used if there are fewer than 250 rules and +** states combined. "int" is used otherwise. +** priv_gda_sql_parserTOKENTYPE is the data type used for minor tokens given +** directly to the parser from the tokenizer. +** YYMINORTYPE is the data type used for all minor tokens. +** This is typically a union of many types, one of +** which is priv_gda_sql_parserTOKENTYPE. The entry in the union +** for base tokens is called "yy0". +** YYSTACKDEPTH is the maximum depth of the parser's stack. If +** zero the stack is dynamically sized using realloc() +** priv_gda_sql_parserARG_SDECL A static variable declaration for the %extra_argument +** priv_gda_sql_parserARG_PDECL A parameter declaration for the %extra_argument +** priv_gda_sql_parserARG_STORE Code to store %extra_argument into yypParser +** priv_gda_sql_parserARG_FETCH Code to extract %extra_argument from yypParser +** YYNSTATE the combined number of states. +** YYNRULE the number of rules in the grammar +** YYERRORSYMBOL is the code number of the error symbol. If not +** defined, then do no error processing. +*/ +#define YYCODETYPE unsigned char +#define YYNOCODE 211 +#define YYACTIONTYPE unsigned short int +#define priv_gda_sql_parserTOKENTYPE GValue * +typedef union { + int yyinit; + priv_gda_sql_parserTOKENTYPE yy0; + Limit yy44; + CaseBody yy59; + GdaSqlExpr * yy70; + GdaSqlStatement * yy116; + GdaSqlSelectTarget * yy134; + GdaSqlExpr* yy146; + GdaSqlOperatorType yy147; + GdaTransactionIsolation yy169; + GdaSqlSelectFrom * yy191; + gboolean yy276; + Distinct * yy297; + GSList * yy325; + GSList* yy333; + GdaSqlParamSpec * yy339; + GdaSqlSelectJoinType yy371; +} YYMINORTYPE; +#ifndef YYSTACKDEPTH +#define YYSTACKDEPTH 100 +#endif +#define priv_gda_sql_parserARG_SDECL GdaSqlParserIface *pdata; +#define priv_gda_sql_parserARG_PDECL ,GdaSqlParserIface *pdata +#define priv_gda_sql_parserARG_FETCH GdaSqlParserIface *pdata = yypParser->pdata +#define priv_gda_sql_parserARG_STORE yypParser->pdata = pdata +#define YYNSTATE 367 +#define YYNRULE 200 +#define YYFALLBACK 1 +#define YY_NO_ACTION (YYNSTATE+YYNRULE+2) +#define YY_ACCEPT_ACTION (YYNSTATE+YYNRULE+1) +#define YY_ERROR_ACTION (YYNSTATE+YYNRULE) + +/* The yyzerominor constant is used to initialize instances of +** YYMINORTYPE objects to zero. */ +static const YYMINORTYPE yyzerominor = { 0 }; + +/* Define the yytestcase() macro to be a no-op if is not already defined +** otherwise. +** +** Applications can choose to define yytestcase() in the %include section +** to a macro that can assist in verifying code coverage. For production +** code the yytestcase() macro should be turned off. But it is useful +** for testing. +*/ +#ifndef yytestcase +# define yytestcase(X) +#endif + + +/* Next are the tables used to determine what action to take based on the +** current state and lookahead token. These tables are used to implement +** functions that take a state number and lookahead value and return an +** action integer. +** +** Suppose the action integer is N. Then the action is determined as +** follows +** +** 0 <= N < YYNSTATE Shift N. That is, push the lookahead +** token onto the stack and goto state N. +** +** YYNSTATE <= N < YYNSTATE+YYNRULE Reduce by rule N-YYNSTATE. +** +** N == YYNSTATE+YYNRULE A syntax error has occurred. +** +** N == YYNSTATE+YYNRULE+1 The parser accepts its input. +** +** N == YYNSTATE+YYNRULE+2 No such action. Denotes unused +** slots in the yy_action[] table. +** +** The action table is constructed as a single large table named yy_action[]. +** Given state S and lookahead X, the action is computed as +** +** yy_action[ yy_shift_ofst[S] + X ] +** +** If the index value yy_shift_ofst[S]+X is out of range or if the value +** yy_lookahead[yy_shift_ofst[S]+X] is not equal to X or if yy_shift_ofst[S] +** is equal to YY_SHIFT_USE_DFLT, it means that the action is not in the table +** and that yy_default[S] should be used instead. +** +** The formula above is for computing the action when the lookahead is +** a terminal symbol. If the lookahead is a non-terminal (as occurs after +** a reduce action) then the yy_reduce_ofst[] array is used in place of +** the yy_shift_ofst[] array and YY_REDUCE_USE_DFLT is used in place of +** YY_SHIFT_USE_DFLT. +** +** The following are the tables generated in this section: +** +** yy_action[] A single table containing all actions. +** yy_lookahead[] A table containing the lookahead for each entry in +** yy_action. Used to detect hash collisions. +** yy_shift_ofst[] For each state, the offset into yy_action for +** shifting terminals. +** yy_reduce_ofst[] For each state, the offset into yy_action for +** shifting non-terminals after a reduce. +** yy_default[] Default action for each state. +*/ +#define YY_ACTTAB_COUNT (1395) +static const YYACTIONTYPE yy_action[] = { + /* 0 */ 41, 40, 367, 246, 246, 142, 243, 22, 51, 49, + /* 10 */ 49, 44, 103, 368, 36, 43, 43, 43, 43, 37, + /* 20 */ 37, 37, 37, 37, 138, 47, 47, 160, 77, 52, + /* 30 */ 52, 51, 49, 49, 44, 244, 354, 353, 165, 352, + /* 40 */ 351, 350, 349, 45, 46, 203, 13, 39, 38, 238, + /* 50 */ 339, 77, 42, 42, 36, 43, 43, 43, 43, 37, + /* 60 */ 37, 37, 37, 37, 175, 47, 47, 323, 298, 52, + /* 70 */ 52, 51, 49, 49, 44, 84, 322, 318, 228, 227, + /* 80 */ 200, 199, 198, 229, 194, 182, 282, 195, 41, 40, + /* 90 */ 219, 77, 246, 319, 243, 276, 202, 21, 157, 328, + /* 100 */ 104, 278, 363, 43, 43, 43, 43, 37, 37, 37, + /* 110 */ 37, 37, 340, 47, 47, 137, 50, 52, 52, 51, + /* 120 */ 49, 49, 44, 244, 354, 263, 262, 193, 28, 50, + /* 130 */ 26, 45, 46, 203, 13, 39, 38, 238, 339, 77, + /* 140 */ 42, 42, 36, 43, 43, 43, 43, 37, 37, 37, + /* 150 */ 37, 37, 1, 47, 47, 280, 279, 52, 52, 51, + /* 160 */ 49, 49, 44, 41, 40, 82, 37, 128, 47, 47, + /* 170 */ 286, 285, 52, 52, 51, 49, 49, 44, 221, 77, + /* 180 */ 186, 52, 52, 51, 49, 49, 44, 333, 213, 352, + /* 190 */ 351, 350, 349, 127, 77, 147, 358, 363, 173, 172, + /* 200 */ 171, 366, 365, 77, 366, 365, 45, 46, 203, 13, + /* 210 */ 39, 38, 238, 339, 329, 42, 42, 36, 43, 43, + /* 220 */ 43, 43, 37, 37, 37, 37, 37, 48, 47, 47, + /* 230 */ 343, 50, 52, 52, 51, 49, 49, 44, 41, 40, + /* 240 */ 314, 3, 246, 348, 243, 37, 37, 37, 37, 37, + /* 250 */ 63, 47, 47, 312, 77, 52, 52, 51, 49, 49, + /* 260 */ 44, 232, 357, 336, 173, 172, 171, 235, 303, 246, + /* 270 */ 364, 305, 34, 244, 354, 197, 226, 77, 173, 172, + /* 280 */ 171, 45, 46, 203, 13, 39, 38, 238, 339, 225, + /* 290 */ 42, 42, 36, 43, 43, 43, 43, 37, 37, 37, + /* 300 */ 37, 37, 359, 47, 47, 146, 306, 52, 52, 51, + /* 310 */ 49, 49, 44, 183, 338, 41, 40, 184, 2, 335, + /* 320 */ 242, 6, 243, 75, 204, 173, 172, 171, 104, 77, + /* 330 */ 363, 356, 370, 291, 140, 136, 267, 266, 289, 278, + /* 340 */ 370, 370, 370, 287, 265, 264, 337, 334, 288, 327, + /* 350 */ 234, 244, 354, 299, 358, 122, 59, 76, 45, 46, + /* 360 */ 203, 13, 39, 38, 238, 339, 310, 42, 42, 36, + /* 370 */ 43, 43, 43, 43, 37, 37, 37, 37, 37, 196, + /* 380 */ 47, 47, 66, 181, 52, 52, 51, 49, 49, 44, + /* 390 */ 246, 156, 243, 246, 201, 305, 41, 40, 104, 189, + /* 400 */ 363, 242, 224, 243, 174, 246, 77, 243, 246, 65, + /* 410 */ 205, 178, 57, 95, 11, 215, 218, 139, 20, 347, + /* 420 */ 357, 244, 354, 56, 154, 10, 230, 173, 172, 171, + /* 430 */ 151, 296, 244, 354, 131, 124, 244, 354, 27, 45, + /* 440 */ 46, 203, 13, 39, 38, 238, 339, 50, 42, 42, + /* 450 */ 36, 43, 43, 43, 43, 37, 37, 37, 37, 37, + /* 460 */ 359, 47, 47, 58, 134, 52, 52, 51, 49, 49, + /* 470 */ 44, 18, 403, 180, 295, 72, 185, 41, 40, 55, + /* 480 */ 246, 378, 243, 246, 254, 243, 222, 77, 90, 356, + /* 490 */ 363, 90, 317, 363, 68, 378, 378, 57, 284, 271, + /* 500 */ 153, 50, 53, 208, 261, 278, 149, 277, 246, 147, + /* 510 */ 360, 244, 354, 278, 244, 354, 358, 316, 315, 24, + /* 520 */ 45, 46, 203, 13, 39, 38, 238, 339, 358, 42, + /* 530 */ 42, 36, 43, 43, 43, 43, 37, 37, 37, 37, + /* 540 */ 37, 313, 47, 47, 284, 311, 52, 52, 51, 49, + /* 550 */ 49, 44, 289, 273, 41, 40, 246, 287, 243, 278, + /* 560 */ 192, 341, 288, 246, 104, 239, 377, 270, 77, 173, + /* 570 */ 172, 171, 293, 278, 253, 132, 330, 16, 403, 309, + /* 580 */ 377, 377, 357, 284, 173, 172, 171, 244, 354, 363, + /* 590 */ 220, 50, 62, 196, 357, 292, 57, 45, 46, 203, + /* 600 */ 13, 39, 38, 238, 339, 358, 42, 42, 36, 43, + /* 610 */ 43, 43, 43, 37, 37, 37, 37, 37, 188, 47, + /* 620 */ 47, 281, 359, 52, 52, 51, 49, 49, 44, 41, + /* 630 */ 40, 252, 217, 246, 359, 243, 44, 191, 246, 186, + /* 640 */ 243, 104, 190, 362, 216, 77, 104, 269, 75, 74, + /* 650 */ 284, 356, 246, 77, 307, 246, 363, 152, 155, 71, + /* 660 */ 363, 54, 260, 356, 244, 354, 358, 82, 278, 244, + /* 670 */ 354, 357, 45, 35, 203, 13, 39, 38, 238, 339, + /* 680 */ 358, 42, 42, 36, 43, 43, 43, 43, 37, 37, + /* 690 */ 37, 37, 37, 9, 47, 47, 211, 147, 52, 52, + /* 700 */ 51, 49, 49, 44, 41, 40, 246, 246, 243, 150, + /* 710 */ 246, 359, 243, 246, 108, 243, 361, 246, 126, 207, + /* 720 */ 77, 143, 179, 8, 7, 130, 326, 251, 246, 125, + /* 730 */ 206, 70, 357, 363, 173, 172, 171, 244, 354, 363, + /* 740 */ 356, 244, 354, 60, 244, 354, 357, 45, 33, 203, + /* 750 */ 13, 39, 38, 238, 339, 324, 42, 42, 36, 43, + /* 760 */ 43, 43, 43, 37, 37, 37, 37, 37, 342, 47, + /* 770 */ 47, 15, 359, 52, 52, 51, 49, 49, 44, 41, + /* 780 */ 40, 246, 187, 243, 79, 246, 359, 243, 246, 107, + /* 790 */ 243, 14, 297, 144, 141, 77, 89, 342, 321, 363, + /* 800 */ 177, 356, 173, 172, 171, 176, 83, 294, 81, 80, + /* 810 */ 164, 342, 244, 354, 53, 356, 244, 354, 77, 244, + /* 820 */ 354, 145, 25, 46, 203, 13, 39, 38, 238, 339, + /* 830 */ 358, 42, 42, 36, 43, 43, 43, 43, 37, 37, + /* 840 */ 37, 37, 37, 342, 47, 47, 163, 231, 52, 52, + /* 850 */ 51, 49, 49, 44, 41, 40, 246, 162, 243, 246, + /* 860 */ 19, 243, 233, 246, 123, 243, 161, 112, 23, 159, + /* 870 */ 77, 109, 358, 17, 358, 325, 223, 568, 148, 308, + /* 880 */ 129, 240, 283, 220, 275, 272, 214, 244, 354, 73, + /* 890 */ 244, 354, 178, 268, 244, 354, 357, 363, 67, 203, + /* 900 */ 13, 39, 38, 238, 339, 209, 42, 42, 36, 43, + /* 910 */ 43, 43, 43, 37, 37, 37, 37, 37, 78, 47, + /* 920 */ 47, 61, 358, 52, 52, 51, 49, 49, 44, 212, + /* 930 */ 246, 240, 302, 210, 250, 69, 359, 248, 357, 336, + /* 940 */ 357, 85, 30, 158, 358, 77, 358, 358, 237, 304, + /* 950 */ 246, 170, 243, 240, 246, 249, 243, 245, 169, 289, + /* 960 */ 300, 301, 120, 355, 287, 356, 31, 32, 346, 288, + /* 970 */ 345, 135, 290, 133, 274, 29, 4, 247, 359, 320, + /* 980 */ 359, 244, 354, 258, 257, 244, 354, 256, 357, 336, + /* 990 */ 241, 259, 30, 255, 358, 335, 569, 220, 331, 569, + /* 1000 */ 196, 569, 569, 240, 569, 569, 147, 356, 569, 356, + /* 1010 */ 357, 336, 357, 357, 30, 569, 31, 32, 12, 569, + /* 1020 */ 569, 569, 337, 334, 236, 29, 5, 332, 359, 569, + /* 1030 */ 569, 569, 569, 569, 569, 569, 569, 569, 31, 32, + /* 1040 */ 346, 569, 344, 569, 569, 335, 569, 29, 5, 569, + /* 1050 */ 359, 569, 359, 359, 246, 569, 243, 356, 569, 569, + /* 1060 */ 357, 336, 118, 569, 30, 569, 358, 335, 12, 569, + /* 1070 */ 569, 569, 337, 334, 236, 240, 246, 332, 243, 356, + /* 1080 */ 569, 356, 356, 569, 117, 244, 354, 569, 31, 32, + /* 1090 */ 12, 569, 569, 569, 337, 334, 236, 29, 4, 332, + /* 1100 */ 359, 569, 569, 569, 569, 569, 569, 244, 354, 569, + /* 1110 */ 569, 246, 569, 243, 569, 569, 569, 335, 569, 116, + /* 1120 */ 569, 569, 569, 246, 569, 243, 569, 569, 147, 356, + /* 1130 */ 569, 115, 357, 336, 569, 569, 30, 569, 569, 569, + /* 1140 */ 12, 569, 244, 354, 337, 334, 236, 569, 246, 332, + /* 1150 */ 243, 246, 569, 243, 244, 354, 114, 569, 569, 121, + /* 1160 */ 31, 32, 569, 569, 569, 569, 569, 569, 569, 29, + /* 1170 */ 5, 569, 359, 246, 569, 243, 246, 569, 243, 244, + /* 1180 */ 354, 106, 244, 354, 119, 569, 569, 569, 569, 335, + /* 1190 */ 569, 246, 569, 243, 569, 246, 569, 243, 246, 105, + /* 1200 */ 243, 356, 569, 111, 244, 354, 168, 244, 354, 569, + /* 1210 */ 569, 246, 12, 243, 569, 569, 337, 334, 236, 167, + /* 1220 */ 569, 332, 244, 354, 569, 569, 244, 354, 569, 244, + /* 1230 */ 354, 569, 569, 246, 569, 243, 569, 569, 569, 569, + /* 1240 */ 569, 110, 244, 354, 569, 246, 569, 243, 246, 569, + /* 1250 */ 243, 569, 246, 166, 243, 246, 88, 243, 569, 246, + /* 1260 */ 102, 243, 569, 101, 244, 354, 569, 87, 569, 569, + /* 1270 */ 246, 569, 243, 246, 569, 243, 244, 354, 100, 244, + /* 1280 */ 354, 86, 569, 244, 354, 569, 244, 354, 569, 569, + /* 1290 */ 244, 354, 246, 569, 243, 569, 569, 569, 569, 569, + /* 1300 */ 99, 244, 354, 569, 244, 354, 246, 569, 243, 246, + /* 1310 */ 569, 243, 569, 246, 98, 243, 569, 64, 246, 569, + /* 1320 */ 243, 97, 569, 244, 354, 569, 96, 246, 569, 243, + /* 1330 */ 569, 569, 569, 569, 246, 94, 243, 244, 354, 569, + /* 1340 */ 244, 354, 93, 569, 244, 354, 246, 569, 243, 244, + /* 1350 */ 354, 569, 569, 246, 92, 243, 569, 569, 244, 354, + /* 1360 */ 569, 91, 246, 569, 243, 244, 354, 569, 569, 569, + /* 1370 */ 113, 569, 569, 569, 569, 569, 569, 244, 354, 569, + /* 1380 */ 569, 569, 569, 569, 244, 354, 569, 569, 569, 569, + /* 1390 */ 569, 569, 569, 244, 354, +}; +static const YYCODETYPE yy_lookahead[] = { + /* 0 */ 26, 27, 0, 172, 172, 174, 174, 33, 97, 98, + /* 10 */ 99, 100, 180, 0, 80, 81, 82, 83, 84, 85, + /* 20 */ 86, 87, 88, 89, 144, 91, 92, 196, 117, 95, + /* 30 */ 96, 97, 98, 99, 100, 203, 204, 155, 206, 157, + /* 40 */ 158, 159, 160, 69, 70, 71, 72, 73, 74, 75, + /* 50 */ 76, 117, 78, 79, 80, 81, 82, 83, 84, 85, + /* 60 */ 86, 87, 88, 89, 154, 91, 92, 5, 123, 95, + /* 70 */ 96, 97, 98, 99, 100, 130, 14, 107, 108, 109, + /* 80 */ 110, 111, 112, 113, 23, 165, 53, 54, 26, 27, + /* 90 */ 57, 117, 172, 123, 174, 166, 176, 123, 169, 106, + /* 100 */ 180, 172, 182, 81, 82, 83, 84, 85, 86, 87, + /* 110 */ 88, 89, 106, 91, 92, 144, 123, 95, 96, 97, + /* 120 */ 98, 99, 100, 203, 204, 64, 65, 66, 148, 123, + /* 130 */ 150, 69, 70, 71, 72, 73, 74, 75, 76, 117, + /* 140 */ 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, + /* 150 */ 88, 89, 105, 91, 92, 55, 56, 95, 96, 97, + /* 160 */ 98, 99, 100, 26, 27, 105, 89, 144, 91, 92, + /* 170 */ 58, 59, 95, 96, 97, 98, 99, 100, 163, 117, + /* 180 */ 165, 95, 96, 97, 98, 99, 100, 155, 128, 157, + /* 190 */ 158, 159, 160, 144, 117, 135, 1, 182, 114, 115, + /* 200 */ 116, 120, 121, 117, 120, 121, 69, 70, 71, 72, + /* 210 */ 73, 74, 75, 76, 106, 78, 79, 80, 81, 82, + /* 220 */ 83, 84, 85, 86, 87, 88, 89, 105, 91, 92, + /* 230 */ 106, 123, 95, 96, 97, 98, 99, 100, 26, 27, + /* 240 */ 107, 105, 172, 106, 174, 85, 86, 87, 88, 89, + /* 250 */ 180, 91, 92, 107, 117, 95, 96, 97, 98, 99, + /* 260 */ 100, 191, 67, 68, 114, 115, 116, 75, 1, 172, + /* 270 */ 106, 174, 80, 203, 204, 178, 143, 117, 114, 115, + /* 280 */ 116, 69, 70, 71, 72, 73, 74, 75, 76, 143, + /* 290 */ 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, + /* 300 */ 88, 89, 107, 91, 92, 185, 106, 95, 96, 97, + /* 310 */ 98, 99, 100, 165, 17, 26, 27, 106, 105, 124, + /* 320 */ 172, 201, 174, 123, 176, 114, 115, 116, 180, 117, + /* 330 */ 182, 136, 106, 166, 167, 168, 64, 65, 13, 172, + /* 340 */ 114, 115, 116, 18, 64, 65, 151, 152, 23, 106, + /* 350 */ 202, 203, 204, 1, 1, 194, 195, 145, 69, 70, + /* 360 */ 71, 72, 73, 74, 75, 76, 107, 78, 79, 80, + /* 370 */ 81, 82, 83, 84, 85, 86, 87, 88, 89, 54, + /* 380 */ 91, 92, 8, 165, 95, 96, 97, 98, 99, 100, + /* 390 */ 172, 17, 174, 172, 176, 174, 26, 27, 180, 178, + /* 400 */ 182, 172, 143, 174, 154, 172, 117, 174, 172, 180, + /* 410 */ 174, 58, 145, 180, 138, 62, 63, 181, 123, 106, + /* 420 */ 67, 203, 204, 49, 50, 138, 193, 114, 115, 116, + /* 430 */ 106, 202, 203, 204, 60, 61, 203, 204, 149, 69, + /* 440 */ 70, 71, 72, 73, 74, 75, 76, 123, 78, 79, + /* 450 */ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, + /* 460 */ 107, 91, 92, 167, 168, 95, 96, 97, 98, 99, + /* 470 */ 100, 123, 51, 165, 134, 122, 165, 26, 27, 105, + /* 480 */ 172, 106, 174, 172, 106, 174, 146, 117, 180, 136, + /* 490 */ 182, 180, 107, 182, 123, 120, 121, 145, 123, 166, + /* 500 */ 126, 123, 131, 129, 171, 172, 132, 166, 172, 135, + /* 510 */ 174, 203, 204, 172, 203, 204, 1, 107, 107, 149, + /* 520 */ 69, 70, 71, 72, 73, 74, 75, 76, 1, 78, + /* 530 */ 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, + /* 540 */ 89, 107, 91, 92, 123, 107, 95, 96, 97, 98, + /* 550 */ 99, 100, 13, 166, 26, 27, 172, 18, 174, 172, + /* 560 */ 176, 106, 23, 172, 180, 174, 106, 166, 117, 114, + /* 570 */ 115, 116, 165, 172, 106, 60, 106, 142, 51, 107, + /* 580 */ 120, 121, 67, 123, 114, 115, 116, 203, 204, 182, + /* 590 */ 51, 123, 105, 54, 67, 106, 145, 69, 70, 71, + /* 600 */ 72, 73, 74, 75, 76, 1, 78, 79, 80, 81, + /* 610 */ 82, 83, 84, 85, 86, 87, 88, 89, 52, 91, + /* 620 */ 92, 54, 107, 95, 96, 97, 98, 99, 100, 26, + /* 630 */ 27, 106, 68, 172, 107, 174, 100, 176, 172, 165, + /* 640 */ 174, 180, 176, 165, 123, 117, 180, 124, 123, 122, + /* 650 */ 123, 136, 172, 117, 174, 172, 182, 174, 68, 127, + /* 660 */ 182, 122, 166, 136, 203, 204, 1, 105, 172, 203, + /* 670 */ 204, 67, 69, 70, 71, 72, 73, 74, 75, 76, + /* 680 */ 1, 78, 79, 80, 81, 82, 83, 84, 85, 86, + /* 690 */ 87, 88, 89, 105, 91, 92, 123, 135, 95, 96, + /* 700 */ 97, 98, 99, 100, 26, 27, 172, 172, 174, 174, + /* 710 */ 172, 107, 174, 172, 180, 174, 165, 172, 180, 174, + /* 720 */ 117, 180, 165, 105, 105, 60, 106, 1, 172, 125, + /* 730 */ 174, 130, 67, 182, 114, 115, 116, 203, 204, 182, + /* 740 */ 136, 203, 204, 133, 203, 204, 67, 69, 70, 71, + /* 750 */ 72, 73, 74, 75, 76, 192, 78, 79, 80, 81, + /* 760 */ 82, 83, 84, 85, 86, 87, 88, 89, 205, 91, + /* 770 */ 92, 79, 107, 95, 96, 97, 98, 99, 100, 26, + /* 780 */ 27, 172, 165, 174, 105, 172, 107, 174, 172, 180, + /* 790 */ 174, 79, 200, 180, 106, 117, 180, 205, 192, 182, + /* 800 */ 209, 136, 114, 115, 116, 209, 183, 134, 183, 183, + /* 810 */ 179, 205, 203, 204, 131, 136, 203, 204, 117, 203, + /* 820 */ 204, 207, 148, 70, 71, 72, 73, 74, 75, 76, + /* 830 */ 1, 78, 79, 80, 81, 82, 83, 84, 85, 86, + /* 840 */ 87, 88, 89, 205, 91, 92, 187, 140, 95, 96, + /* 850 */ 97, 98, 99, 100, 26, 27, 172, 188, 174, 172, + /* 860 */ 139, 174, 137, 172, 180, 174, 189, 180, 136, 197, + /* 870 */ 117, 180, 1, 142, 1, 190, 141, 162, 163, 198, + /* 880 */ 165, 10, 168, 51, 168, 122, 173, 203, 204, 170, + /* 890 */ 203, 204, 58, 171, 203, 204, 67, 182, 170, 71, + /* 900 */ 72, 73, 74, 75, 76, 69, 78, 79, 80, 81, + /* 910 */ 82, 83, 84, 85, 86, 87, 88, 89, 175, 91, + /* 920 */ 92, 105, 1, 95, 96, 97, 98, 99, 100, 177, + /* 930 */ 172, 10, 174, 123, 179, 173, 107, 164, 67, 68, + /* 940 */ 67, 184, 71, 169, 1, 117, 1, 1, 208, 200, + /* 950 */ 172, 186, 174, 10, 172, 179, 174, 172, 180, 13, + /* 960 */ 200, 203, 180, 172, 18, 136, 95, 96, 97, 23, + /* 970 */ 97, 169, 167, 169, 167, 104, 105, 164, 107, 199, + /* 980 */ 107, 203, 204, 172, 172, 203, 204, 172, 67, 68, + /* 990 */ 172, 172, 71, 172, 1, 124, 210, 51, 77, 210, + /* 1000 */ 54, 210, 210, 10, 210, 210, 135, 136, 210, 136, + /* 1010 */ 67, 68, 67, 67, 71, 210, 95, 96, 147, 210, + /* 1020 */ 210, 210, 151, 152, 153, 104, 105, 156, 107, 210, + /* 1030 */ 210, 210, 210, 210, 210, 210, 210, 210, 95, 96, + /* 1040 */ 97, 210, 97, 210, 210, 124, 210, 104, 105, 210, + /* 1050 */ 107, 210, 107, 107, 172, 210, 174, 136, 210, 210, + /* 1060 */ 67, 68, 180, 210, 71, 210, 1, 124, 147, 210, + /* 1070 */ 210, 210, 151, 152, 153, 10, 172, 156, 174, 136, + /* 1080 */ 210, 136, 136, 210, 180, 203, 204, 210, 95, 96, + /* 1090 */ 147, 210, 210, 210, 151, 152, 153, 104, 105, 156, + /* 1100 */ 107, 210, 210, 210, 210, 210, 210, 203, 204, 210, + /* 1110 */ 210, 172, 210, 174, 210, 210, 210, 124, 210, 180, + /* 1120 */ 210, 210, 210, 172, 210, 174, 210, 210, 135, 136, + /* 1130 */ 210, 180, 67, 68, 210, 210, 71, 210, 210, 210, + /* 1140 */ 147, 210, 203, 204, 151, 152, 153, 210, 172, 156, + /* 1150 */ 174, 172, 210, 174, 203, 204, 180, 210, 210, 180, + /* 1160 */ 95, 96, 210, 210, 210, 210, 210, 210, 210, 104, + /* 1170 */ 105, 210, 107, 172, 210, 174, 172, 210, 174, 203, + /* 1180 */ 204, 180, 203, 204, 180, 210, 210, 210, 210, 124, + /* 1190 */ 210, 172, 210, 174, 210, 172, 210, 174, 172, 180, + /* 1200 */ 174, 136, 210, 180, 203, 204, 180, 203, 204, 210, + /* 1210 */ 210, 172, 147, 174, 210, 210, 151, 152, 153, 180, + /* 1220 */ 210, 156, 203, 204, 210, 210, 203, 204, 210, 203, + /* 1230 */ 204, 210, 210, 172, 210, 174, 210, 210, 210, 210, + /* 1240 */ 210, 180, 203, 204, 210, 172, 210, 174, 172, 210, + /* 1250 */ 174, 210, 172, 180, 174, 172, 180, 174, 210, 172, + /* 1260 */ 180, 174, 210, 180, 203, 204, 210, 180, 210, 210, + /* 1270 */ 172, 210, 174, 172, 210, 174, 203, 204, 180, 203, + /* 1280 */ 204, 180, 210, 203, 204, 210, 203, 204, 210, 210, + /* 1290 */ 203, 204, 172, 210, 174, 210, 210, 210, 210, 210, + /* 1300 */ 180, 203, 204, 210, 203, 204, 172, 210, 174, 172, + /* 1310 */ 210, 174, 210, 172, 180, 174, 210, 180, 172, 210, + /* 1320 */ 174, 180, 210, 203, 204, 210, 180, 172, 210, 174, + /* 1330 */ 210, 210, 210, 210, 172, 180, 174, 203, 204, 210, + /* 1340 */ 203, 204, 180, 210, 203, 204, 172, 210, 174, 203, + /* 1350 */ 204, 210, 210, 172, 180, 174, 210, 210, 203, 204, + /* 1360 */ 210, 180, 172, 210, 174, 203, 204, 210, 210, 210, + /* 1370 */ 180, 210, 210, 210, 210, 210, 210, 203, 204, 210, + /* 1380 */ 210, 210, 210, 210, 203, 204, 210, 210, 210, 210, + /* 1390 */ 210, 210, 210, 203, 204, +}; +#define YY_SHIFT_USE_DFLT (-121) +#define YY_SHIFT_COUNT (248) +#define YY_SHIFT_MIN (-120) +#define YY_SHIFT_MAX (1065) +static const short yy_shift_ofst[] = { + /* 0 */ 374, 871, 993, 993, 993, 993, 943, 1065, 1065, 1065, + /* 10 */ 1065, 1065, 1065, 921, 1065, 1065, 1065, 1065, 1065, 1065, + /* 20 */ 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, + /* 30 */ 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, + /* 40 */ 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, + /* 50 */ 1065, 1065, 1065, 1065, 946, 374, 353, 195, 527, 679, + /* 60 */ 829, 829, 829, 62, 62, 451, 539, 604, 829, 829, + /* 70 */ 829, 829, 829, 829, 829, 829, 829, 829, 60, 562, + /* 80 */ 562, 562, 562, 562, -121, -121, -26, 370, 289, 212, + /* 90 */ 137, 528, 528, 528, 528, 528, 528, 528, 528, 528, + /* 100 */ 528, 528, 528, 528, 528, 678, 603, 528, 528, 753, + /* 110 */ 828, 828, 828, -66, -66, -66, -66, -66, -66, 22, + /* 120 */ 160, 77, -30, 86, 665, 515, -89, 945, 873, 84, + /* 130 */ 829, 829, 829, 325, 460, 325, 375, 829, 829, 371, + /* 140 */ 421, 352, 267, 536, 536, -20, -55, 340, 81, 836, + /* 150 */ 683, 810, 816, 836, 763, 834, 763, 832, 832, 735, + /* 160 */ 731, 732, 725, 721, 707, 674, 701, 701, 701, 701, + /* 170 */ 683, 673, 673, 673, -121, -121, 32, -118, 61, 688, + /* 180 */ 620, 470, 455, 313, 226, 211, 164, 150, 33, 525, + /* 190 */ 468, 378, 324, 280, 272, 100, 112, 200, 259, 146, + /* 200 */ 133, 108, 6, 192, -7, 712, 692, 610, 601, 726, + /* 210 */ 619, 618, 573, 588, 532, 590, 523, 521, 564, 567, + /* 220 */ 566, 489, 435, 487, 472, 438, 434, 411, 410, 385, + /* 230 */ 348, 287, 295, 276, 243, 213, 250, 297, 136, 124, + /* 240 */ 122, 49, 23, 47, -90, -29, -120, 13, 2, +}; +#define YY_REDUCE_USE_DFLT (-170) +#define YY_REDUCE_COUNT (175) +#define YY_REDUCE_MIN (-169) +#define YY_REDUCE_MAX (1190) +static const short yy_reduce_ofst[] = { + /* 0 */ 715, 148, 218, -80, 311, 308, 229, 466, 461, 384, + /* 10 */ 233, 70, -168, 1190, 1181, 1174, 1162, 1155, 1146, 1141, + /* 20 */ 1137, 1134, 1120, 1101, 1098, 1087, 1083, 1080, 1076, 1073, + /* 30 */ 1061, 1039, 1026, 1023, 1019, 1004, 1001, 979, 976, 951, + /* 40 */ 939, 904, 882, 782, 778, 691, 687, 684, 616, 613, + /* 50 */ 609, 541, 538, 534, 167, 15, 333, 758, -71, -169, + /* 60 */ 236, 221, 97, 606, 563, 592, 296, 496, 556, 545, + /* 70 */ 535, 483, 401, 387, 341, 480, 391, 336, 617, 557, + /* 80 */ 551, 478, 474, 407, 161, 120, 638, 638, 638, 638, + /* 90 */ 638, 638, 638, 638, 638, 638, 638, 638, 638, 638, + /* 100 */ 638, 638, 638, 638, 638, 638, 638, 638, 638, 638, + /* 110 */ 638, 638, 638, 638, 638, 638, 638, 638, 638, 638, + /* 120 */ 638, 638, 780, 638, 821, 819, 638, 791, 818, 813, + /* 130 */ 815, 812, 811, 807, 804, 805, 802, 791, 785, 776, + /* 140 */ 774, 760, 749, 638, 638, 740, 765, 757, 773, 762, + /* 150 */ 755, 752, 743, 713, 728, 722, 719, 716, 714, 681, + /* 160 */ 672, 685, 677, 669, 659, 614, 638, 638, 638, 638, + /* 170 */ 631, 626, 625, 623, 596, 591, +}; +static const YYACTIONTYPE yy_default[] = { + /* 0 */ 567, 500, 500, 500, 567, 567, 567, 500, 500, 500, + /* 10 */ 567, 567, 541, 567, 567, 567, 567, 567, 567, 567, + /* 20 */ 567, 567, 567, 567, 567, 567, 567, 567, 567, 567, + /* 30 */ 567, 567, 567, 567, 567, 567, 567, 567, 567, 567, + /* 40 */ 567, 567, 567, 567, 567, 567, 567, 567, 567, 567, + /* 50 */ 567, 567, 567, 567, 409, 567, 409, 567, 409, 567, + /* 60 */ 567, 567, 567, 455, 455, 493, 373, 409, 567, 567, + /* 70 */ 567, 567, 409, 409, 409, 567, 567, 567, 567, 567, + /* 80 */ 567, 567, 567, 567, 465, 485, 446, 567, 567, 567, + /* 90 */ 567, 437, 436, 497, 467, 499, 498, 457, 448, 447, + /* 100 */ 543, 544, 542, 540, 502, 567, 567, 501, 434, 519, + /* 110 */ 530, 529, 518, 533, 526, 525, 524, 523, 522, 528, + /* 120 */ 521, 527, 461, 515, 567, 567, 512, 567, 567, 567, + /* 130 */ 567, 567, 567, 567, 403, 567, 403, 567, 567, 433, + /* 140 */ 379, 493, 493, 513, 514, 545, 460, 494, 567, 424, + /* 150 */ 433, 421, 428, 424, 401, 389, 401, 567, 567, 464, + /* 160 */ 468, 445, 449, 456, 458, 567, 531, 517, 516, 520, + /* 170 */ 433, 442, 442, 442, 555, 555, 567, 567, 567, 567, + /* 180 */ 567, 567, 567, 567, 534, 567, 567, 423, 567, 567, + /* 190 */ 567, 567, 567, 394, 393, 567, 567, 567, 567, 567, + /* 200 */ 567, 567, 567, 567, 567, 567, 567, 567, 567, 567, + /* 210 */ 567, 567, 422, 567, 567, 567, 567, 387, 567, 567, + /* 220 */ 567, 567, 496, 567, 567, 567, 567, 567, 567, 567, + /* 230 */ 459, 567, 450, 567, 567, 567, 567, 567, 567, 567, + /* 240 */ 567, 565, 564, 506, 504, 565, 564, 567, 567, 435, + /* 250 */ 432, 425, 429, 427, 426, 418, 417, 416, 420, 419, + /* 260 */ 392, 391, 396, 395, 400, 399, 398, 397, 390, 388, + /* 270 */ 386, 385, 402, 384, 383, 382, 376, 375, 410, 408, + /* 280 */ 407, 406, 405, 380, 404, 415, 414, 413, 412, 411, + /* 290 */ 381, 374, 369, 439, 443, 495, 487, 486, 484, 483, + /* 300 */ 482, 492, 491, 481, 480, 431, 463, 430, 462, 479, + /* 310 */ 478, 477, 476, 475, 474, 473, 472, 471, 470, 469, + /* 320 */ 466, 452, 454, 453, 451, 444, 534, 509, 507, 537, + /* 330 */ 538, 547, 554, 552, 551, 550, 549, 548, 539, 546, + /* 340 */ 535, 536, 532, 510, 490, 489, 488, 508, 505, 559, + /* 350 */ 558, 557, 556, 553, 503, 566, 563, 562, 561, 560, + /* 360 */ 511, 441, 440, 438, 370, 372, 371, +}; + +/* The next table maps tokens into fallback tokens. If a construct +** like the following: +** +** %fallback ID X Y Z. +** +** appears in the grammar, then ID becomes a fallback token for X, Y, +** and Z. Whenever one of the tokens X, Y, or Z is input to the parser +** but it does not parse, the type of the token is changed to ID and +** the parse is retried before an error is thrown. +*/ +#ifdef YYFALLBACK +static const YYCODETYPE yyFallback[] = { + 0, /* $ => nothing */ + 0, /* ID => nothing */ + 1, /* ABORT => ID */ + 1, /* AFTER => ID */ + 1, /* ANALYZE => ID */ + 1, /* ASC => ID */ + 1, /* ATTACH => ID */ + 1, /* BEFORE => ID */ + 1, /* BEGIN => ID */ + 1, /* CASCADE => ID */ + 1, /* CAST => ID */ + 1, /* CONFLICT => ID */ + 1, /* DATABASE => ID */ + 1, /* DEFERRED => ID */ + 1, /* DESC => ID */ + 1, /* DETACH => ID */ + 1, /* EACH => ID */ + 1, /* END => ID */ + 1, /* EXCLUSIVE => ID */ + 1, /* EXPLAIN => ID */ + 1, /* FAIL => ID */ + 1, /* FOR => ID */ + 1, /* IGNORE => ID */ + 1, /* IMMEDIATE => ID */ + 1, /* INITIALLY => ID */ + 1, /* INSTEAD => ID */ + 1, /* LIKE => ID */ + 1, /* ILIKE => ID */ + 1, /* MATCH => ID */ + 1, /* PLAN => ID */ + 1, /* QUERY => ID */ + 1, /* KEY => ID */ + 1, /* OF => ID */ + 1, /* OFFSET => ID */ + 1, /* PRAGMA => ID */ + 1, /* RAISE => ID */ + 1, /* REPLACE => ID */ + 1, /* RESTRICT => ID */ + 1, /* ROW => ID */ + 1, /* TEMP => ID */ + 1, /* TRIGGER => ID */ + 1, /* VACUUM => ID */ + 1, /* VIEW => ID */ + 1, /* VIRTUAL => ID */ + 1, /* REINDEX => ID */ + 1, /* RENAME => ID */ + 1, /* CTIME_KW => ID */ + 1, /* IF => ID */ + 1, /* DELIMITER => ID */ + 1, /* COMMIT => ID */ + 1, /* ROLLBACK => ID */ + 1, /* ISOLATION => ID */ + 1, /* LEVEL => ID */ + 1, /* SERIALIZABLE => ID */ + 1, /* READ => ID */ + 1, /* COMMITTED => ID */ + 1, /* UNCOMMITTED => ID */ + 1, /* REPEATABLE => ID */ + 1, /* WRITE => ID */ + 1, /* ONLY => ID */ + 1, /* SAVEPOINT => ID */ + 1, /* RELEASE => ID */ + 1, /* COMMENT => ID */ + 1, /* FORCE => ID */ + 1, /* WAIT => ID */ + 1, /* NOWAIT => ID */ + 1, /* BATCH => ID */ + 0, /* TEXTUAL => nothing */ + 67, /* STRING => TEXTUAL */ +}; +#endif /* YYFALLBACK */ + +/* The following structure represents a single element of the +** parser's stack. Information stored includes: +** +** + The state number for the parser at this level of the stack. +** +** + The value of the token stored at this level of the stack. +** (In other words, the "major" token.) +** +** + The semantic value stored at this level of the stack. This is +** the information used by the action routines in the grammar. +** It is sometimes called the "minor" token. +*/ +struct yyStackEntry { + YYACTIONTYPE stateno; /* The state-number */ + YYCODETYPE major; /* The major token value. This is the code + ** number for the token at this stack level */ + YYMINORTYPE minor; /* The user-supplied minor token value. This + ** is the value of the token */ +}; +typedef struct yyStackEntry yyStackEntry; + +/* The state of the parser is completely contained in an instance of +** the following structure */ +struct yyParser { + int yyidx; /* Index of top element in stack */ +#ifdef YYTRACKMAXSTACKDEPTH + int yyidxMax; /* Maximum value of yyidx */ +#endif + int yyerrcnt; /* Shifts left before out of the error */ + priv_gda_sql_parserARG_SDECL /* A place to hold %extra_argument */ +#if YYSTACKDEPTH<=0 + int yystksz; /* Current side of the stack */ + yyStackEntry *yystack; /* The parser's stack */ +#else + yyStackEntry yystack[YYSTACKDEPTH]; /* The parser's stack */ +#endif +}; +typedef struct yyParser yyParser; + +#ifndef NDEBUG +#include +static FILE *yyTraceFILE = 0; +static char *yyTracePrompt = 0; +#endif /* NDEBUG */ + +#ifndef NDEBUG +/* +** Turn parser tracing on by giving a stream to which to write the trace +** and a prompt to preface each trace message. Tracing is turned off +** by making either argument NULL +** +** Inputs: +**
    +**
  • A FILE* to which trace output should be written. +** If NULL, then tracing is turned off. +**
  • A prefix string written at the beginning of every +** line of trace output. If NULL, then tracing is +** turned off. +**
+** +** Outputs: +** None. +*/ +void priv_gda_sql_parserTrace(FILE *TraceFILE, char *zTracePrompt){ + yyTraceFILE = TraceFILE; + yyTracePrompt = zTracePrompt; + if( yyTraceFILE==0 ) yyTracePrompt = 0; + else if( yyTracePrompt==0 ) yyTraceFILE = 0; +} +#endif /* NDEBUG */ + +#ifndef NDEBUG +/* For tracing shifts, the names of all terminals and nonterminals +** are required. The following table supplies these names */ +static const char *const yyTokenName[] = { + "$", "ID", "ABORT", "AFTER", + "ANALYZE", "ASC", "ATTACH", "BEFORE", + "BEGIN", "CASCADE", "CAST", "CONFLICT", + "DATABASE", "DEFERRED", "DESC", "DETACH", + "EACH", "END", "EXCLUSIVE", "EXPLAIN", + "FAIL", "FOR", "IGNORE", "IMMEDIATE", + "INITIALLY", "INSTEAD", "LIKE", "ILIKE", + "MATCH", "PLAN", "QUERY", "KEY", + "OF", "OFFSET", "PRAGMA", "RAISE", + "REPLACE", "RESTRICT", "ROW", "TEMP", + "TRIGGER", "VACUUM", "VIEW", "VIRTUAL", + "REINDEX", "RENAME", "CTIME_KW", "IF", + "DELIMITER", "COMMIT", "ROLLBACK", "ISOLATION", + "LEVEL", "SERIALIZABLE", "READ", "COMMITTED", + "UNCOMMITTED", "REPEATABLE", "WRITE", "ONLY", + "SAVEPOINT", "RELEASE", "COMMENT", "FORCE", + "WAIT", "NOWAIT", "BATCH", "TEXTUAL", + "STRING", "OR", "AND", "NOT", + "IS", "NOTLIKE", "NOTILIKE", "IN", + "ISNULL", "NOTNULL", "DIFF", "EQ", + "BETWEEN", "GT", "LEQ", "LT", + "GEQ", "REGEXP", "REGEXP_CI", "NOT_REGEXP", + "NOT_REGEXP_CI", "SIMILAR", "ESCAPE", "BITAND", + "BITOR", "LSHIFT", "RSHIFT", "PLUS", + "MINUS", "STAR", "SLASH", "REM", + "CONCAT", "COLLATE", "UMINUS", "UPLUS", + "BITNOT", "LP", "RP", "JOIN", + "INNER", "NATURAL", "LEFT", "RIGHT", + "FULL", "CROSS", "UNION", "EXCEPT", + "INTERSECT", "PGCAST", "ILLEGAL", "SQLCOMMENT", + "SEMI", "END_OF_FILE", "TRANSACTION", "COMMA", + "INTEGER", "TO", "INSERT", "INTO", + "VALUES", "DELETE", "FROM", "WHERE", + "UPDATE", "SET", "ALL", "SELECT", + "LIMIT", "ORDER", "BY", "HAVING", + "GROUP", "USING", "ON", "OUTER", + "DOT", "AS", "DISTINCT", "CASE", + "WHEN", "THEN", "ELSE", "NULL", + "FLOAT", "UNSPECVAL", "LSBRACKET", "RSBRACKET", + "SIMPLEPARAM", "PNAME", "PDESCR", "PTYPE", + "PNULLOK", "error", "stmt", "cmd", + "eos", "compound", "nm_opt", "transtype", + "transilev", "opt_comma", "trans_opt_kw", "ora_commit_write", + "nm", "opt_on_conflict", "fullname", "inscollist_opt", + "rexprlist", "ins_extra_values", "inscollist", "where_opt", + "expr", "setlist", "selectcmd", "opt_compound_all", + "distinct", "selcollist", "from", "groupby_opt", + "having_opt", "orderby_opt", "limit_opt", "sortlist", + "sortorder", "rnexprlist", "seltablist", "stl_prefix", + "seltarget", "on_cond", "using_opt", "jointype", + "as", "sclp", "starname", "value", + "pvalue", "uni_op", "case_operand", "case_exprlist", + "case_else", "paramspec", +}; +#endif /* NDEBUG */ + +#ifndef NDEBUG +/* For tracing reduce actions, the names of all rules are required. +*/ +static const char *const yyRuleName[] = { + /* 0 */ "stmt ::= cmd eos", + /* 1 */ "stmt ::= compound eos", + /* 2 */ "cmd ::= LP cmd RP", + /* 3 */ "compound ::= LP compound RP", + /* 4 */ "eos ::= SEMI", + /* 5 */ "eos ::= END_OF_FILE", + /* 6 */ "cmd ::= BEGIN", + /* 7 */ "cmd ::= BEGIN TRANSACTION nm_opt", + /* 8 */ "cmd ::= BEGIN transtype TRANSACTION nm_opt", + /* 9 */ "cmd ::= BEGIN transtype nm_opt", + /* 10 */ "cmd ::= BEGIN transilev", + /* 11 */ "cmd ::= BEGIN TRANSACTION transilev", + /* 12 */ "cmd ::= BEGIN TRANSACTION transtype", + /* 13 */ "cmd ::= BEGIN TRANSACTION transtype opt_comma transilev", + /* 14 */ "cmd ::= BEGIN TRANSACTION transilev opt_comma transtype", + /* 15 */ "cmd ::= BEGIN transtype opt_comma transilev", + /* 16 */ "cmd ::= BEGIN transilev opt_comma transtype", + /* 17 */ "cmd ::= END trans_opt_kw nm_opt", + /* 18 */ "cmd ::= COMMIT nm_opt", + /* 19 */ "cmd ::= COMMIT TRANSACTION nm_opt", + /* 20 */ "cmd ::= COMMIT FORCE STRING", + /* 21 */ "cmd ::= COMMIT FORCE STRING COMMA INTEGER", + /* 22 */ "cmd ::= COMMIT COMMENT STRING", + /* 23 */ "cmd ::= COMMIT COMMENT STRING ora_commit_write", + /* 24 */ "cmd ::= COMMIT ora_commit_write", + /* 25 */ "cmd ::= ROLLBACK trans_opt_kw nm_opt", + /* 26 */ "ora_commit_write ::= WRITE IMMEDIATE", + /* 27 */ "ora_commit_write ::= WRITE BATCH", + /* 28 */ "ora_commit_write ::= WRITE WAIT", + /* 29 */ "ora_commit_write ::= WRITE NOWAIT", + /* 30 */ "ora_commit_write ::= WRITE IMMEDIATE WAIT", + /* 31 */ "ora_commit_write ::= WRITE IMMEDIATE NOWAIT", + /* 32 */ "ora_commit_write ::= WRITE BATCH WAIT", + /* 33 */ "ora_commit_write ::= WRITE BATCH NOWAIT", + /* 34 */ "trans_opt_kw ::=", + /* 35 */ "trans_opt_kw ::= TRANSACTION", + /* 36 */ "opt_comma ::=", + /* 37 */ "opt_comma ::= COMMA", + /* 38 */ "transilev ::= ISOLATION LEVEL SERIALIZABLE", + /* 39 */ "transilev ::= ISOLATION LEVEL REPEATABLE READ", + /* 40 */ "transilev ::= ISOLATION LEVEL READ COMMITTED", + /* 41 */ "transilev ::= ISOLATION LEVEL READ UNCOMMITTED", + /* 42 */ "nm_opt ::=", + /* 43 */ "nm_opt ::= nm", + /* 44 */ "transtype ::= DEFERRED", + /* 45 */ "transtype ::= IMMEDIATE", + /* 46 */ "transtype ::= EXCLUSIVE", + /* 47 */ "transtype ::= READ WRITE", + /* 48 */ "transtype ::= READ ONLY", + /* 49 */ "cmd ::= SAVEPOINT nm", + /* 50 */ "cmd ::= RELEASE SAVEPOINT nm", + /* 51 */ "cmd ::= RELEASE nm", + /* 52 */ "cmd ::= ROLLBACK trans_opt_kw TO nm", + /* 53 */ "cmd ::= ROLLBACK trans_opt_kw TO SAVEPOINT nm", + /* 54 */ "cmd ::= INSERT opt_on_conflict INTO fullname inscollist_opt VALUES LP rexprlist RP", + /* 55 */ "cmd ::= INSERT opt_on_conflict INTO fullname inscollist_opt VALUES LP rexprlist RP ins_extra_values", + /* 56 */ "cmd ::= INSERT opt_on_conflict INTO fullname inscollist_opt compound", + /* 57 */ "opt_on_conflict ::=", + /* 58 */ "opt_on_conflict ::= OR ID", + /* 59 */ "ins_extra_values ::= ins_extra_values COMMA LP rexprlist RP", + /* 60 */ "ins_extra_values ::= COMMA LP rexprlist RP", + /* 61 */ "inscollist_opt ::=", + /* 62 */ "inscollist_opt ::= LP inscollist RP", + /* 63 */ "inscollist ::= inscollist COMMA fullname", + /* 64 */ "inscollist ::= fullname", + /* 65 */ "cmd ::= DELETE FROM fullname where_opt", + /* 66 */ "where_opt ::=", + /* 67 */ "where_opt ::= WHERE expr", + /* 68 */ "cmd ::= UPDATE opt_on_conflict fullname SET setlist where_opt", + /* 69 */ "setlist ::= setlist COMMA fullname EQ expr", + /* 70 */ "setlist ::= fullname EQ expr", + /* 71 */ "compound ::= selectcmd", + /* 72 */ "compound ::= compound UNION opt_compound_all compound", + /* 73 */ "compound ::= compound EXCEPT opt_compound_all compound", + /* 74 */ "compound ::= compound INTERSECT opt_compound_all compound", + /* 75 */ "opt_compound_all ::=", + /* 76 */ "opt_compound_all ::= ALL", + /* 77 */ "selectcmd ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt", + /* 78 */ "limit_opt ::=", + /* 79 */ "limit_opt ::= LIMIT expr", + /* 80 */ "limit_opt ::= LIMIT expr OFFSET expr", + /* 81 */ "limit_opt ::= LIMIT expr COMMA expr", + /* 82 */ "orderby_opt ::=", + /* 83 */ "orderby_opt ::= ORDER BY sortlist", + /* 84 */ "sortlist ::= sortlist COMMA expr sortorder", + /* 85 */ "sortlist ::= expr sortorder", + /* 86 */ "sortorder ::= ASC", + /* 87 */ "sortorder ::= DESC", + /* 88 */ "sortorder ::=", + /* 89 */ "having_opt ::=", + /* 90 */ "having_opt ::= HAVING expr", + /* 91 */ "groupby_opt ::=", + /* 92 */ "groupby_opt ::= GROUP BY rnexprlist", + /* 93 */ "from ::=", + /* 94 */ "from ::= FROM seltablist", + /* 95 */ "seltablist ::= stl_prefix seltarget on_cond using_opt", + /* 96 */ "using_opt ::= USING LP inscollist RP", + /* 97 */ "using_opt ::=", + /* 98 */ "stl_prefix ::=", + /* 99 */ "stl_prefix ::= seltablist jointype", + /* 100 */ "on_cond ::= ON expr", + /* 101 */ "on_cond ::=", + /* 102 */ "jointype ::= COMMA", + /* 103 */ "jointype ::= JOIN", + /* 104 */ "jointype ::= CROSS JOIN", + /* 105 */ "jointype ::= INNER JOIN", + /* 106 */ "jointype ::= NATURAL JOIN", + /* 107 */ "jointype ::= LEFT JOIN", + /* 108 */ "jointype ::= LEFT OUTER JOIN", + /* 109 */ "jointype ::= RIGHT JOIN", + /* 110 */ "jointype ::= RIGHT OUTER JOIN", + /* 111 */ "jointype ::= FULL JOIN", + /* 112 */ "jointype ::= FULL OUTER JOIN", + /* 113 */ "seltarget ::= fullname as", + /* 114 */ "seltarget ::= fullname ID", + /* 115 */ "seltarget ::= LP compound RP as", + /* 116 */ "seltarget ::= LP compound RP ID", + /* 117 */ "sclp ::= selcollist COMMA", + /* 118 */ "sclp ::=", + /* 119 */ "selcollist ::= sclp expr as", + /* 120 */ "selcollist ::= sclp starname", + /* 121 */ "starname ::= STAR", + /* 122 */ "starname ::= nm DOT STAR", + /* 123 */ "starname ::= nm DOT nm DOT STAR", + /* 124 */ "as ::= AS fullname", + /* 125 */ "as ::= AS value", + /* 126 */ "as ::=", + /* 127 */ "distinct ::=", + /* 128 */ "distinct ::= ALL", + /* 129 */ "distinct ::= DISTINCT", + /* 130 */ "distinct ::= DISTINCT ON expr", + /* 131 */ "rnexprlist ::= rnexprlist COMMA expr", + /* 132 */ "rnexprlist ::= expr", + /* 133 */ "rexprlist ::=", + /* 134 */ "rexprlist ::= rexprlist COMMA expr", + /* 135 */ "rexprlist ::= expr", + /* 136 */ "expr ::= pvalue", + /* 137 */ "expr ::= value", + /* 138 */ "expr ::= LP expr RP", + /* 139 */ "expr ::= fullname", + /* 140 */ "expr ::= fullname LP rexprlist RP", + /* 141 */ "expr ::= fullname LP compound RP", + /* 142 */ "expr ::= fullname LP starname RP", + /* 143 */ "expr ::= CAST LP expr AS fullname RP", + /* 144 */ "expr ::= expr PGCAST fullname", + /* 145 */ "expr ::= expr PLUS|MINUS expr", + /* 146 */ "expr ::= expr STAR expr", + /* 147 */ "expr ::= expr SLASH|REM expr", + /* 148 */ "expr ::= expr BITAND|BITOR expr", + /* 149 */ "expr ::= MINUS expr", + /* 150 */ "expr ::= PLUS expr", + /* 151 */ "expr ::= expr AND expr", + /* 152 */ "expr ::= expr OR expr", + /* 153 */ "expr ::= expr CONCAT expr", + /* 154 */ "expr ::= expr GT|LEQ|GEQ|LT expr", + /* 155 */ "expr ::= expr DIFF|EQ expr", + /* 156 */ "expr ::= expr LIKE expr", + /* 157 */ "expr ::= expr ILIKE expr", + /* 158 */ "expr ::= expr NOTLIKE expr", + /* 159 */ "expr ::= expr NOTILIKE expr", + /* 160 */ "expr ::= expr REGEXP|REGEXP_CI|NOT_REGEXP|NOT_REGEXP_CI|SIMILAR expr", + /* 161 */ "expr ::= expr BETWEEN expr AND expr", + /* 162 */ "expr ::= expr NOT BETWEEN expr AND expr", + /* 163 */ "expr ::= NOT expr", + /* 164 */ "expr ::= BITNOT expr", + /* 165 */ "expr ::= expr uni_op", + /* 166 */ "expr ::= expr IS expr", + /* 167 */ "expr ::= LP compound RP", + /* 168 */ "expr ::= expr IN LP rexprlist RP", + /* 169 */ "expr ::= expr IN LP compound RP", + /* 170 */ "expr ::= expr NOT IN LP rexprlist RP", + /* 171 */ "expr ::= expr NOT IN LP compound RP", + /* 172 */ "expr ::= CASE case_operand case_exprlist case_else END", + /* 173 */ "case_operand ::= expr", + /* 174 */ "case_operand ::=", + /* 175 */ "case_exprlist ::= case_exprlist WHEN expr THEN expr", + /* 176 */ "case_exprlist ::= WHEN expr THEN expr", + /* 177 */ "case_else ::= ELSE expr", + /* 178 */ "case_else ::=", + /* 179 */ "uni_op ::= ISNULL", + /* 180 */ "uni_op ::= IS NOTNULL", + /* 181 */ "value ::= NULL", + /* 182 */ "value ::= STRING", + /* 183 */ "value ::= INTEGER", + /* 184 */ "value ::= FLOAT", + /* 185 */ "pvalue ::= UNSPECVAL LSBRACKET paramspec RSBRACKET", + /* 186 */ "pvalue ::= value LSBRACKET paramspec RSBRACKET", + /* 187 */ "pvalue ::= SIMPLEPARAM", + /* 188 */ "paramspec ::=", + /* 189 */ "paramspec ::= paramspec PNAME", + /* 190 */ "paramspec ::= paramspec PDESCR", + /* 191 */ "paramspec ::= paramspec PTYPE", + /* 192 */ "paramspec ::= paramspec PNULLOK", + /* 193 */ "nm ::= JOIN", + /* 194 */ "nm ::= ID", + /* 195 */ "nm ::= TEXTUAL", + /* 196 */ "nm ::= LIMIT", + /* 197 */ "fullname ::= nm", + /* 198 */ "fullname ::= nm DOT nm", + /* 199 */ "fullname ::= nm DOT nm DOT nm", +}; +#endif /* NDEBUG */ + + +#if YYSTACKDEPTH<=0 +/* +** Try to increase the size of the parser stack. +*/ +static void yyGrowStack(yyParser *p){ + int newSize; + yyStackEntry *pNew; + + newSize = p->yystksz*2 + 100; + pNew = realloc(p->yystack, newSize*sizeof(pNew[0])); + if( pNew ){ + p->yystack = pNew; + p->yystksz = newSize; +#ifndef NDEBUG + if( yyTraceFILE ){ + fprintf(yyTraceFILE,"%sStack grows to %d entries!\n", + yyTracePrompt, p->yystksz); + } +#endif + } +} +#endif + +/* +** This function allocates a new parser. +** The only argument is a pointer to a function which works like +** malloc. +** +** Inputs: +** A pointer to the function used to allocate memory. +** +** Outputs: +** A pointer to a parser. This pointer is used in subsequent calls +** to priv_gda_sql_parser and priv_gda_sql_parserFree. +*/ +void *priv_gda_sql_parserAlloc(void *(*mallocProc)(size_t)){ + yyParser *pParser; + pParser = (yyParser*)(*mallocProc)( (size_t)sizeof(yyParser) ); + if( pParser ){ + pParser->yyidx = -1; +#ifdef YYTRACKMAXSTACKDEPTH + pParser->yyidxMax = 0; +#endif +#if YYSTACKDEPTH<=0 + pParser->yystack = NULL; + pParser->yystksz = 0; + yyGrowStack(pParser); +#endif + } + return pParser; +} + +/* The following function deletes the value associated with a +** symbol. The symbol can be either a terminal or nonterminal. +** "yymajor" is the symbol code, and "yypminor" is a pointer to +** the value. +*/ +static void yy_destructor( + yyParser *yypParser, /* The parser */ + YYCODETYPE yymajor, /* Type code for object to destroy */ + YYMINORTYPE *yypminor /* The object to be destroyed */ +){ + priv_gda_sql_parserARG_FETCH; + switch( yymajor ){ + /* Here is inserted the actions which take place when a + ** terminal or non-terminal is destroyed. This can happen + ** when the symbol is popped from the stack during a + ** reduce or during error processing or when a parser is + ** being destroyed before it is finished parsing. + ** + ** Note: during a reduce, the only symbols destroyed are those + ** which appear on the RHS of the rule, but which are not used + ** inside the C code. + */ + /* TERMINAL Destructor */ + case 1: /* ID */ + case 2: /* ABORT */ + case 3: /* AFTER */ + case 4: /* ANALYZE */ + case 5: /* ASC */ + case 6: /* ATTACH */ + case 7: /* BEFORE */ + case 8: /* BEGIN */ + case 9: /* CASCADE */ + case 10: /* CAST */ + case 11: /* CONFLICT */ + case 12: /* DATABASE */ + case 13: /* DEFERRED */ + case 14: /* DESC */ + case 15: /* DETACH */ + case 16: /* EACH */ + case 17: /* END */ + case 18: /* EXCLUSIVE */ + case 19: /* EXPLAIN */ + case 20: /* FAIL */ + case 21: /* FOR */ + case 22: /* IGNORE */ + case 23: /* IMMEDIATE */ + case 24: /* INITIALLY */ + case 25: /* INSTEAD */ + case 26: /* LIKE */ + case 27: /* ILIKE */ + case 28: /* MATCH */ + case 29: /* PLAN */ + case 30: /* QUERY */ + case 31: /* KEY */ + case 32: /* OF */ + case 33: /* OFFSET */ + case 34: /* PRAGMA */ + case 35: /* RAISE */ + case 36: /* REPLACE */ + case 37: /* RESTRICT */ + case 38: /* ROW */ + case 39: /* TEMP */ + case 40: /* TRIGGER */ + case 41: /* VACUUM */ + case 42: /* VIEW */ + case 43: /* VIRTUAL */ + case 44: /* REINDEX */ + case 45: /* RENAME */ + case 46: /* CTIME_KW */ + case 47: /* IF */ + case 48: /* DELIMITER */ + case 49: /* COMMIT */ + case 50: /* ROLLBACK */ + case 51: /* ISOLATION */ + case 52: /* LEVEL */ + case 53: /* SERIALIZABLE */ + case 54: /* READ */ + case 55: /* COMMITTED */ + case 56: /* UNCOMMITTED */ + case 57: /* REPEATABLE */ + case 58: /* WRITE */ + case 59: /* ONLY */ + case 60: /* SAVEPOINT */ + case 61: /* RELEASE */ + case 62: /* COMMENT */ + case 63: /* FORCE */ + case 64: /* WAIT */ + case 65: /* NOWAIT */ + case 66: /* BATCH */ + case 67: /* TEXTUAL */ + case 68: /* STRING */ + case 69: /* OR */ + case 70: /* AND */ + case 71: /* NOT */ + case 72: /* IS */ + case 73: /* NOTLIKE */ + case 74: /* NOTILIKE */ + case 75: /* IN */ + case 76: /* ISNULL */ + case 77: /* NOTNULL */ + case 78: /* DIFF */ + case 79: /* EQ */ + case 80: /* BETWEEN */ + case 81: /* GT */ + case 82: /* LEQ */ + case 83: /* LT */ + case 84: /* GEQ */ + case 85: /* REGEXP */ + case 86: /* REGEXP_CI */ + case 87: /* NOT_REGEXP */ + case 88: /* NOT_REGEXP_CI */ + case 89: /* SIMILAR */ + case 90: /* ESCAPE */ + case 91: /* BITAND */ + case 92: /* BITOR */ + case 93: /* LSHIFT */ + case 94: /* RSHIFT */ + case 95: /* PLUS */ + case 96: /* MINUS */ + case 97: /* STAR */ + case 98: /* SLASH */ + case 99: /* REM */ + case 100: /* CONCAT */ + case 101: /* COLLATE */ + case 102: /* UMINUS */ + case 103: /* UPLUS */ + case 104: /* BITNOT */ + case 105: /* LP */ + case 106: /* RP */ + case 107: /* JOIN */ + case 108: /* INNER */ + case 109: /* NATURAL */ + case 110: /* LEFT */ + case 111: /* RIGHT */ + case 112: /* FULL */ + case 113: /* CROSS */ + case 114: /* UNION */ + case 115: /* EXCEPT */ + case 116: /* INTERSECT */ + case 117: /* PGCAST */ + case 118: /* ILLEGAL */ + case 119: /* SQLCOMMENT */ + case 120: /* SEMI */ + case 121: /* END_OF_FILE */ + case 122: /* TRANSACTION */ + case 123: /* COMMA */ + case 124: /* INTEGER */ + case 125: /* TO */ + case 126: /* INSERT */ + case 127: /* INTO */ + case 128: /* VALUES */ + case 129: /* DELETE */ + case 130: /* FROM */ + case 131: /* WHERE */ + case 132: /* UPDATE */ + case 133: /* SET */ + case 134: /* ALL */ + case 135: /* SELECT */ + case 136: /* LIMIT */ + case 137: /* ORDER */ + case 138: /* BY */ + case 139: /* HAVING */ + case 140: /* GROUP */ + case 141: /* USING */ + case 142: /* ON */ + case 143: /* OUTER */ + case 144: /* DOT */ + case 145: /* AS */ + case 146: /* DISTINCT */ + case 147: /* CASE */ + case 148: /* WHEN */ + case 149: /* THEN */ + case 150: /* ELSE */ + case 151: /* NULL */ + case 152: /* FLOAT */ + case 153: /* UNSPECVAL */ + case 154: /* LSBRACKET */ + case 155: /* RSBRACKET */ + case 156: /* SIMPLEPARAM */ + case 157: /* PNAME */ + case 158: /* PDESCR */ + case 159: /* PTYPE */ + case 160: /* PNULLOK */ +{ +#line 9 "../libgda/sql-parser/parser.y" +if ((yypminor->yy0)) { +#ifdef GDA_DEBUG_NO + gchar *str = gda_sql_value_stringify ((yypminor->yy0)); + g_print ("___ token destructor /%s/\n", str) + g_free (str); +#endif + g_value_unset ((yypminor->yy0)); g_free ((yypminor->yy0));} +#line 1406 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" +} + break; + case 162: /* stmt */ +{ +#line 280 "../libgda/sql-parser/parser.y" +g_print ("Statement destroyed by parser: %p\n", (yypminor->yy116)); gda_sql_statement_free ((yypminor->yy116)); +#line 1413 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" +} + break; + case 163: /* cmd */ + case 165: /* compound */ + case 182: /* selectcmd */ +{ +#line 303 "../libgda/sql-parser/parser.y" +gda_sql_statement_free ((yypminor->yy116)); +#line 1422 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" +} + break; + case 175: /* inscollist_opt */ + case 178: /* inscollist */ + case 198: /* using_opt */ +{ +#line 479 "../libgda/sql-parser/parser.y" +if ((yypminor->yy333)) {g_slist_free_full ((yypminor->yy333), (GDestroyNotify) gda_sql_field_free);} +#line 1431 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" +} + break; + case 176: /* rexprlist */ + case 193: /* rnexprlist */ +{ +#line 768 "../libgda/sql-parser/parser.y" +if ((yypminor->yy325)) {g_slist_free_full ((yypminor->yy325), (GDestroyNotify) gda_sql_expr_free);} +#line 1439 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" +} + break; + case 177: /* ins_extra_values */ +{ +#line 469 "../libgda/sql-parser/parser.y" +GSList *list; + for (list = (yypminor->yy333); list; list = list->next) { + g_slist_free_full ((GSList*) list->data, (GDestroyNotify) gda_sql_field_free); + } + g_slist_free ((yypminor->yy333)); + +#line 1451 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" +} + break; + case 179: /* where_opt */ + case 180: /* expr */ + case 188: /* having_opt */ + case 197: /* on_cond */ + case 204: /* pvalue */ +{ +#line 501 "../libgda/sql-parser/parser.y" +gda_sql_expr_free ((yypminor->yy70)); +#line 1462 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" +} + break; + case 181: /* setlist */ +{ +#line 521 "../libgda/sql-parser/parser.y" +GSList *list; + for (list = (yypminor->yy333); list; list = list->next) { + UpdateSet *set = (UpdateSet*) list->data; + g_value_reset (set->fname); g_free (set->fname); + gda_sql_expr_free (set->expr); + g_free (set); + } + g_slist_free ((yypminor->yy333)); + +#line 1477 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" +} + break; + case 184: /* distinct */ +{ +#line 754 "../libgda/sql-parser/parser.y" +if ((yypminor->yy297)) {if ((yypminor->yy297)->expr) gda_sql_expr_free ((yypminor->yy297)->expr); g_free ((yypminor->yy297));} +#line 1484 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" +} + break; + case 185: /* selcollist */ + case 201: /* sclp */ +{ +#line 711 "../libgda/sql-parser/parser.y" +g_slist_free_full ((yypminor->yy325), (GDestroyNotify) gda_sql_select_field_free); +#line 1492 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" +} + break; + case 186: /* from */ + case 194: /* seltablist */ + case 195: /* stl_prefix */ +{ +#line 634 "../libgda/sql-parser/parser.y" +gda_sql_select_from_free ((yypminor->yy191)); +#line 1501 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" +} + break; + case 187: /* groupby_opt */ +{ +#line 629 "../libgda/sql-parser/parser.y" +if ((yypminor->yy333)) {g_slist_free_full ((yypminor->yy333), (GDestroyNotify) gda_sql_expr_free);} +#line 1508 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" +} + break; + case 189: /* orderby_opt */ + case 191: /* sortlist */ +{ +#line 598 "../libgda/sql-parser/parser.y" +if ((yypminor->yy325)) {g_slist_free_full ((yypminor->yy325), (GDestroyNotify) gda_sql_select_order_free);} +#line 1516 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" +} + break; + case 190: /* limit_opt */ +{ +#line 591 "../libgda/sql-parser/parser.y" +gda_sql_expr_free ((yypminor->yy44).count); gda_sql_expr_free ((yypminor->yy44).offset); +#line 1523 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" +} + break; + case 196: /* seltarget */ +{ +#line 693 "../libgda/sql-parser/parser.y" +gda_sql_select_target_free ((yypminor->yy134)); +#line 1530 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" +} + break; + case 206: /* case_operand */ + case 208: /* case_else */ +{ +#line 935 "../libgda/sql-parser/parser.y" +gda_sql_expr_free ((yypminor->yy146)); +#line 1538 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" +} + break; + case 207: /* case_exprlist */ +{ +#line 940 "../libgda/sql-parser/parser.y" +g_slist_free_full ((yypminor->yy59).when_list, (GDestroyNotify) gda_sql_expr_free); + g_slist_free_full ((yypminor->yy59).then_list, (GDestroyNotify) gda_sql_expr_free); +#line 1546 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" +} + break; + case 209: /* paramspec */ +{ +#line 978 "../libgda/sql-parser/parser.y" +gda_sql_param_spec_free ((yypminor->yy339)); +#line 1553 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" +} + break; + default: break; /* If no destructor action specified: do nothing */ + } +} + +/* +** Pop the parser's stack once. +** +** If there is a destructor routine associated with the token which +** is popped from the stack, then call it. +** +** Return the major token number for the symbol popped. +*/ +static int yy_pop_parser_stack(yyParser *pParser){ + YYCODETYPE yymajor; + yyStackEntry *yytos; + + if( pParser->yyidx<0 ) return 0; + yytos = &pParser->yystack[pParser->yyidx]; +#ifndef NDEBUG + if( yyTraceFILE && pParser->yyidx>=0 ){ + fprintf(yyTraceFILE,"%sPopping %s\n", + yyTracePrompt, + yyTokenName[yytos->major]); + } +#endif + yymajor = yytos->major; + yy_destructor(pParser, yymajor, &yytos->minor); + pParser->yyidx--; + return yymajor; +} + +/* +** Deallocate and destroy a parser. Destructors are all called for +** all stack elements before shutting the parser down. +** +** Inputs: +**
    +**
  • A pointer to the parser. This should be a pointer +** obtained from priv_gda_sql_parserAlloc. +**
  • A pointer to a function used to reclaim memory obtained +** from malloc. +**
+*/ +void priv_gda_sql_parserFree( + void *p, /* The parser to be deleted */ + void (*freeProc)(void*) /* Function used to reclaim memory */ +){ + yyParser *pParser = (yyParser*)p; + if( pParser==0 ) return; + while( pParser->yyidx>=0 ) yy_pop_parser_stack(pParser); +#if YYSTACKDEPTH<=0 + free(pParser->yystack); +#endif + (*freeProc)((void*)pParser); +} + +/* +** Return the peak depth of the stack for a parser. +*/ +#ifdef YYTRACKMAXSTACKDEPTH +int priv_gda_sql_parserStackPeak(void *p){ + yyParser *pParser = (yyParser*)p; + return pParser->yyidxMax; +} +#endif + +/* +** Find the appropriate action for a parser given the terminal +** look-ahead token iLookAhead. +** +** If the look-ahead token is YYNOCODE, then check to see if the action is +** independent of the look-ahead. If it is, return the action, otherwise +** return YY_NO_ACTION. +*/ +static int yy_find_shift_action( + yyParser *pParser, /* The parser */ + YYCODETYPE iLookAhead /* The look-ahead token */ +){ + int i; + int stateno = pParser->yystack[pParser->yyidx].stateno; + + if( stateno>YY_SHIFT_COUNT + || (i = yy_shift_ofst[stateno])==YY_SHIFT_USE_DFLT ){ + return yy_default[stateno]; + } + assert( iLookAhead!=YYNOCODE ); + i += iLookAhead; + if( i<0 || i>=YY_ACTTAB_COUNT || yy_lookahead[i]!=iLookAhead ){ + if( iLookAhead>0 ){ +#ifdef YYFALLBACK + YYCODETYPE iFallback; /* Fallback token */ + if( iLookAhead %s\n", + yyTracePrompt, yyTokenName[iLookAhead], yyTokenName[iFallback]); + } +#endif + return yy_find_shift_action(pParser, iFallback); + } +#endif +#ifdef YYWILDCARD + { + int j = i - iLookAhead + YYWILDCARD; + if( +#if YY_SHIFT_MIN+YYWILDCARD<0 + j>=0 && +#endif +#if YY_SHIFT_MAX+YYWILDCARD>=YY_ACTTAB_COUNT + j %s\n", + yyTracePrompt, yyTokenName[iLookAhead], yyTokenName[YYWILDCARD]); + } +#endif /* NDEBUG */ + return yy_action[j]; + } + } +#endif /* YYWILDCARD */ + } + return yy_default[stateno]; + }else{ + return yy_action[i]; + } +} + +/* +** Find the appropriate action for a parser given the non-terminal +** look-ahead token iLookAhead. +** +** If the look-ahead token is YYNOCODE, then check to see if the action is +** independent of the look-ahead. If it is, return the action, otherwise +** return YY_NO_ACTION. +*/ +static int yy_find_reduce_action( + int stateno, /* Current state number */ + YYCODETYPE iLookAhead /* The look-ahead token */ +){ + int i; +#ifdef YYERRORSYMBOL + if( stateno>YY_REDUCE_COUNT ){ + return yy_default[stateno]; + } +#else + assert( stateno<=YY_REDUCE_COUNT ); +#endif + i = yy_reduce_ofst[stateno]; + assert( i!=YY_REDUCE_USE_DFLT ); + assert( iLookAhead!=YYNOCODE ); + i += iLookAhead; +#ifdef YYERRORSYMBOL + if( i<0 || i>=YY_ACTTAB_COUNT || yy_lookahead[i]!=iLookAhead ){ + return yy_default[stateno]; + } +#else + assert( i>=0 && iyyidx--; +#ifndef NDEBUG + if( yyTraceFILE ){ + fprintf(yyTraceFILE,"%sStack Overflow!\n",yyTracePrompt); + } +#endif + while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser); + /* Here code is inserted which will execute if the parser + ** stack every overflows */ +#line 25 "../libgda/sql-parser/parser.y" + + gda_sql_parser_set_overflow_error (pdata->parser); +#line 1739 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + priv_gda_sql_parserARG_STORE; /* Suppress warning about unused %extra_argument var */ +} + +/* +** Perform a shift action. +*/ +static void yy_shift( + yyParser *yypParser, /* The parser to be shifted */ + int yyNewState, /* The new state to shift in */ + int yyMajor, /* The major token to shift in */ + YYMINORTYPE *yypMinor /* Pointer to the minor token to shift in */ +){ + yyStackEntry *yytos; + yypParser->yyidx++; +#ifdef YYTRACKMAXSTACKDEPTH + if( yypParser->yyidx>yypParser->yyidxMax ){ + yypParser->yyidxMax = yypParser->yyidx; + } +#endif +#if YYSTACKDEPTH>0 + if( yypParser->yyidx>=YYSTACKDEPTH ){ + yyStackOverflow(yypParser, yypMinor); + return; + } +#else + if( yypParser->yyidx>=yypParser->yystksz ){ + yyGrowStack(yypParser); + if( yypParser->yyidx>=yypParser->yystksz ){ + yyStackOverflow(yypParser, yypMinor); + return; + } + } +#endif + yytos = &yypParser->yystack[yypParser->yyidx]; + yytos->stateno = (YYACTIONTYPE)yyNewState; + yytos->major = (YYCODETYPE)yyMajor; + yytos->minor = *yypMinor; +#ifndef NDEBUG + if( yyTraceFILE && yypParser->yyidx>0 ){ + int i; + fprintf(yyTraceFILE,"%sShift %d\n",yyTracePrompt,yyNewState); + fprintf(yyTraceFILE,"%sStack:",yyTracePrompt); + for(i=1; i<=yypParser->yyidx; i++) + fprintf(yyTraceFILE," %s",yyTokenName[yypParser->yystack[i].major]); + fprintf(yyTraceFILE,"\n"); + } +#endif +} + +/* The following table contains information about every rule that +** is used during the reduce. +*/ +static const struct { + YYCODETYPE lhs; /* Symbol on the left-hand side of the rule */ + unsigned char nrhs; /* Number of right-hand side symbols in the rule */ +} yyRuleInfo[] = { + { 162, 2 }, + { 162, 2 }, + { 163, 3 }, + { 165, 3 }, + { 164, 1 }, + { 164, 1 }, + { 163, 1 }, + { 163, 3 }, + { 163, 4 }, + { 163, 3 }, + { 163, 2 }, + { 163, 3 }, + { 163, 3 }, + { 163, 5 }, + { 163, 5 }, + { 163, 4 }, + { 163, 4 }, + { 163, 3 }, + { 163, 2 }, + { 163, 3 }, + { 163, 3 }, + { 163, 5 }, + { 163, 3 }, + { 163, 4 }, + { 163, 2 }, + { 163, 3 }, + { 171, 2 }, + { 171, 2 }, + { 171, 2 }, + { 171, 2 }, + { 171, 3 }, + { 171, 3 }, + { 171, 3 }, + { 171, 3 }, + { 170, 0 }, + { 170, 1 }, + { 169, 0 }, + { 169, 1 }, + { 168, 3 }, + { 168, 4 }, + { 168, 4 }, + { 168, 4 }, + { 166, 0 }, + { 166, 1 }, + { 167, 1 }, + { 167, 1 }, + { 167, 1 }, + { 167, 2 }, + { 167, 2 }, + { 163, 2 }, + { 163, 3 }, + { 163, 2 }, + { 163, 4 }, + { 163, 5 }, + { 163, 9 }, + { 163, 10 }, + { 163, 6 }, + { 173, 0 }, + { 173, 2 }, + { 177, 5 }, + { 177, 4 }, + { 175, 0 }, + { 175, 3 }, + { 178, 3 }, + { 178, 1 }, + { 163, 4 }, + { 179, 0 }, + { 179, 2 }, + { 163, 6 }, + { 181, 5 }, + { 181, 3 }, + { 165, 1 }, + { 165, 4 }, + { 165, 4 }, + { 165, 4 }, + { 183, 0 }, + { 183, 1 }, + { 182, 9 }, + { 190, 0 }, + { 190, 2 }, + { 190, 4 }, + { 190, 4 }, + { 189, 0 }, + { 189, 3 }, + { 191, 4 }, + { 191, 2 }, + { 192, 1 }, + { 192, 1 }, + { 192, 0 }, + { 188, 0 }, + { 188, 2 }, + { 187, 0 }, + { 187, 3 }, + { 186, 0 }, + { 186, 2 }, + { 194, 4 }, + { 198, 4 }, + { 198, 0 }, + { 195, 0 }, + { 195, 2 }, + { 197, 2 }, + { 197, 0 }, + { 199, 1 }, + { 199, 1 }, + { 199, 2 }, + { 199, 2 }, + { 199, 2 }, + { 199, 2 }, + { 199, 3 }, + { 199, 2 }, + { 199, 3 }, + { 199, 2 }, + { 199, 3 }, + { 196, 2 }, + { 196, 2 }, + { 196, 4 }, + { 196, 4 }, + { 201, 2 }, + { 201, 0 }, + { 185, 3 }, + { 185, 2 }, + { 202, 1 }, + { 202, 3 }, + { 202, 5 }, + { 200, 2 }, + { 200, 2 }, + { 200, 0 }, + { 184, 0 }, + { 184, 1 }, + { 184, 1 }, + { 184, 3 }, + { 193, 3 }, + { 193, 1 }, + { 176, 0 }, + { 176, 3 }, + { 176, 1 }, + { 180, 1 }, + { 180, 1 }, + { 180, 3 }, + { 180, 1 }, + { 180, 4 }, + { 180, 4 }, + { 180, 4 }, + { 180, 6 }, + { 180, 3 }, + { 180, 3 }, + { 180, 3 }, + { 180, 3 }, + { 180, 3 }, + { 180, 2 }, + { 180, 2 }, + { 180, 3 }, + { 180, 3 }, + { 180, 3 }, + { 180, 3 }, + { 180, 3 }, + { 180, 3 }, + { 180, 3 }, + { 180, 3 }, + { 180, 3 }, + { 180, 3 }, + { 180, 5 }, + { 180, 6 }, + { 180, 2 }, + { 180, 2 }, + { 180, 2 }, + { 180, 3 }, + { 180, 3 }, + { 180, 5 }, + { 180, 5 }, + { 180, 6 }, + { 180, 6 }, + { 180, 5 }, + { 206, 1 }, + { 206, 0 }, + { 207, 5 }, + { 207, 4 }, + { 208, 2 }, + { 208, 0 }, + { 205, 1 }, + { 205, 2 }, + { 203, 1 }, + { 203, 1 }, + { 203, 1 }, + { 203, 1 }, + { 204, 4 }, + { 204, 4 }, + { 204, 1 }, + { 209, 0 }, + { 209, 2 }, + { 209, 2 }, + { 209, 2 }, + { 209, 2 }, + { 172, 1 }, + { 172, 1 }, + { 172, 1 }, + { 172, 1 }, + { 174, 1 }, + { 174, 3 }, + { 174, 5 }, +}; + +static void yy_accept(yyParser*); /* Forward Declaration */ + +/* +** Perform a reduce action and the shift that must immediately +** follow the reduce. +*/ +static void yy_reduce( + yyParser *yypParser, /* The parser */ + int yyruleno /* Number of the rule by which to reduce */ +){ + int yygoto; /* The next state */ + int yyact; /* The next action */ + YYMINORTYPE yygotominor; /* The LHS of the rule reduced */ + yyStackEntry *yymsp; /* The top of the parser's stack */ + int yysize; /* Amount to pop the stack */ + priv_gda_sql_parserARG_FETCH; + yymsp = &yypParser->yystack[yypParser->yyidx]; +#ifndef NDEBUG + if( yyTraceFILE && yyruleno>=0 + && yyruleno<(int)(sizeof(yyRuleName)/sizeof(yyRuleName[0])) ){ + fprintf(yyTraceFILE, "%sReduce [%s].\n", yyTracePrompt, + yyRuleName[yyruleno]); + } +#endif /* NDEBUG */ + + /* Silence complaints from purify about yygotominor being uninitialized + ** in some cases when it is copied into the stack after the following + ** switch. yygotominor is uninitialized when a rule reduces that does + ** not set the value of its left-hand side nonterminal. Leaving the + ** value of the nonterminal uninitialized is utterly harmless as long + ** as the value is never used. So really the only thing this code + ** accomplishes is to quieten purify. + ** + ** 2007-01-16: The wireshark project (www.wireshark.org) reports that + ** without this code, their parser segfaults. I'm not sure what there + ** parser is doing to make this happen. This is the second bug report + ** from wireshark this week. Clearly they are stressing Lemon in ways + ** that it has not been previously stressed... (SQLite ticket #2172) + */ + /*memset(&yygotominor, 0, sizeof(yygotominor));*/ + yygotominor = yyzerominor; + + + switch( yyruleno ){ + /* Beginning here are the reduction cases. A typical example + ** follows: + ** case 0: + ** #line + ** { ... } // User supplied code + ** #line + ** break; + */ + case 0: /* stmt ::= cmd eos */ +#line 281 "../libgda/sql-parser/parser.y" +{pdata->parsed_statement = yymsp[-1].minor.yy116;} +#line 2053 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 1: /* stmt ::= compound eos */ +#line 282 "../libgda/sql-parser/parser.y" +{ + GdaSqlStatementCompound *scompound = (GdaSqlStatementCompound *) yymsp[-1].minor.yy116->contents; + if (scompound->stmt_list->next) + /* real compound (multiple statements) */ + pdata->parsed_statement = yymsp[-1].minor.yy116; + else { + /* false compound (only 1 select) */ + pdata->parsed_statement = (GdaSqlStatement*) scompound->stmt_list->data; + GDA_SQL_ANY_PART (pdata->parsed_statement->contents)->parent = NULL; + g_slist_free (scompound->stmt_list); + scompound->stmt_list = NULL; + gda_sql_statement_free (yymsp[-1].minor.yy116); + } +} +#line 2071 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 2: /* cmd ::= LP cmd RP */ + case 3: /* compound ::= LP compound RP */ yytestcase(yyruleno==3); +#line 296 "../libgda/sql-parser/parser.y" +{yygotominor.yy116 = yymsp[-1].minor.yy116; yy_destructor(yypParser,105,&yymsp[-2].minor); + yy_destructor(yypParser,106,&yymsp[0].minor); +} +#line 2079 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 4: /* eos ::= SEMI */ +#line 299 "../libgda/sql-parser/parser.y" +{ + yy_destructor(yypParser,120,&yymsp[0].minor); +} +#line 2086 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 5: /* eos ::= END_OF_FILE */ +#line 300 "../libgda/sql-parser/parser.y" +{ + yy_destructor(yypParser,121,&yymsp[0].minor); +} +#line 2093 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 6: /* cmd ::= BEGIN */ +#line 308 "../libgda/sql-parser/parser.y" +{yygotominor.yy116 = gda_sql_statement_new (GDA_SQL_STATEMENT_BEGIN); yy_destructor(yypParser,8,&yymsp[0].minor); +} +#line 2099 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 7: /* cmd ::= BEGIN TRANSACTION nm_opt */ +#line 309 "../libgda/sql-parser/parser.y" +{yygotominor.yy116 = gda_sql_statement_new (GDA_SQL_STATEMENT_BEGIN); + gda_sql_statement_trans_take_name (yygotominor.yy116, yymsp[0].minor.yy0); + yy_destructor(yypParser,8,&yymsp[-2].minor); + yy_destructor(yypParser,122,&yymsp[-1].minor); +} +#line 2108 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 8: /* cmd ::= BEGIN transtype TRANSACTION nm_opt */ +#line 313 "../libgda/sql-parser/parser.y" +{yygotominor.yy116 = gda_sql_statement_new (GDA_SQL_STATEMENT_BEGIN); + gda_sql_statement_trans_take_mode (yygotominor.yy116, yymsp[-2].minor.yy0); + gda_sql_statement_trans_take_name (yygotominor.yy116, yymsp[0].minor.yy0); + yy_destructor(yypParser,8,&yymsp[-3].minor); + yy_destructor(yypParser,122,&yymsp[-1].minor); +} +#line 2118 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 9: /* cmd ::= BEGIN transtype nm_opt */ +#line 318 "../libgda/sql-parser/parser.y" +{yygotominor.yy116 = gda_sql_statement_new (GDA_SQL_STATEMENT_BEGIN); + gda_sql_statement_trans_take_mode (yygotominor.yy116, yymsp[-1].minor.yy0); + gda_sql_statement_trans_take_name (yygotominor.yy116, yymsp[0].minor.yy0); + yy_destructor(yypParser,8,&yymsp[-2].minor); +} +#line 2127 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 10: /* cmd ::= BEGIN transilev */ +#line 323 "../libgda/sql-parser/parser.y" +{yygotominor.yy116 = gda_sql_statement_new (GDA_SQL_STATEMENT_BEGIN); + gda_sql_statement_trans_set_isol_level (yygotominor.yy116, yymsp[0].minor.yy169); + yy_destructor(yypParser,8,&yymsp[-1].minor); +} +#line 2135 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 11: /* cmd ::= BEGIN TRANSACTION transilev */ +#line 327 "../libgda/sql-parser/parser.y" +{yygotominor.yy116 = gda_sql_statement_new (GDA_SQL_STATEMENT_BEGIN); + gda_sql_statement_trans_set_isol_level (yygotominor.yy116, yymsp[0].minor.yy169); + yy_destructor(yypParser,8,&yymsp[-2].minor); + yy_destructor(yypParser,122,&yymsp[-1].minor); +} +#line 2144 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 12: /* cmd ::= BEGIN TRANSACTION transtype */ +#line 331 "../libgda/sql-parser/parser.y" +{yygotominor.yy116 = gda_sql_statement_new (GDA_SQL_STATEMENT_BEGIN); + gda_sql_statement_trans_take_mode (yygotominor.yy116, yymsp[0].minor.yy0); + yy_destructor(yypParser,8,&yymsp[-2].minor); + yy_destructor(yypParser,122,&yymsp[-1].minor); +} +#line 2153 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 13: /* cmd ::= BEGIN TRANSACTION transtype opt_comma transilev */ +#line 335 "../libgda/sql-parser/parser.y" +{yygotominor.yy116 = gda_sql_statement_new (GDA_SQL_STATEMENT_BEGIN); + gda_sql_statement_trans_take_mode (yygotominor.yy116, yymsp[-2].minor.yy0); + gda_sql_statement_trans_set_isol_level (yygotominor.yy116, yymsp[0].minor.yy169); + yy_destructor(yypParser,8,&yymsp[-4].minor); + yy_destructor(yypParser,122,&yymsp[-3].minor); +} +#line 2163 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 14: /* cmd ::= BEGIN TRANSACTION transilev opt_comma transtype */ +#line 340 "../libgda/sql-parser/parser.y" +{yygotominor.yy116 = gda_sql_statement_new (GDA_SQL_STATEMENT_BEGIN); + gda_sql_statement_trans_take_mode (yygotominor.yy116, yymsp[0].minor.yy0); + gda_sql_statement_trans_set_isol_level (yygotominor.yy116, yymsp[-2].minor.yy169); + yy_destructor(yypParser,8,&yymsp[-4].minor); + yy_destructor(yypParser,122,&yymsp[-3].minor); +} +#line 2173 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 15: /* cmd ::= BEGIN transtype opt_comma transilev */ +#line 345 "../libgda/sql-parser/parser.y" +{yygotominor.yy116 = gda_sql_statement_new (GDA_SQL_STATEMENT_BEGIN); + gda_sql_statement_trans_take_mode (yygotominor.yy116, yymsp[-2].minor.yy0); + gda_sql_statement_trans_set_isol_level (yygotominor.yy116, yymsp[0].minor.yy169); + yy_destructor(yypParser,8,&yymsp[-3].minor); +} +#line 2182 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 16: /* cmd ::= BEGIN transilev opt_comma transtype */ +#line 350 "../libgda/sql-parser/parser.y" +{yygotominor.yy116 = gda_sql_statement_new (GDA_SQL_STATEMENT_BEGIN); + gda_sql_statement_trans_take_mode (yygotominor.yy116, yymsp[0].minor.yy0); + gda_sql_statement_trans_set_isol_level (yygotominor.yy116, yymsp[-2].minor.yy169); + yy_destructor(yypParser,8,&yymsp[-3].minor); +} +#line 2191 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 17: /* cmd ::= END trans_opt_kw nm_opt */ +#line 355 "../libgda/sql-parser/parser.y" +{yygotominor.yy116 = gda_sql_statement_new (GDA_SQL_STATEMENT_COMMIT); + gda_sql_statement_trans_take_name (yygotominor.yy116, yymsp[0].minor.yy0); + yy_destructor(yypParser,17,&yymsp[-2].minor); +} +#line 2199 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 18: /* cmd ::= COMMIT nm_opt */ +#line 359 "../libgda/sql-parser/parser.y" +{yygotominor.yy116 = gda_sql_statement_new (GDA_SQL_STATEMENT_COMMIT); + gda_sql_statement_trans_take_name (yygotominor.yy116, yymsp[0].minor.yy0); + yy_destructor(yypParser,49,&yymsp[-1].minor); +} +#line 2207 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 19: /* cmd ::= COMMIT TRANSACTION nm_opt */ +#line 363 "../libgda/sql-parser/parser.y" +{yygotominor.yy116 = gda_sql_statement_new (GDA_SQL_STATEMENT_COMMIT); + gda_sql_statement_trans_take_name (yygotominor.yy116, yymsp[0].minor.yy0); + yy_destructor(yypParser,49,&yymsp[-2].minor); + yy_destructor(yypParser,122,&yymsp[-1].minor); +} +#line 2216 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 20: /* cmd ::= COMMIT FORCE STRING */ +#line 367 "../libgda/sql-parser/parser.y" +{yygotominor.yy116 = gda_sql_statement_new (GDA_SQL_STATEMENT_COMMIT); yy_destructor(yypParser,49,&yymsp[-2].minor); + yy_destructor(yypParser,63,&yymsp[-1].minor); + yy_destructor(yypParser,68,&yymsp[0].minor); +} +#line 2224 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 21: /* cmd ::= COMMIT FORCE STRING COMMA INTEGER */ +#line 368 "../libgda/sql-parser/parser.y" +{yygotominor.yy116 = gda_sql_statement_new (GDA_SQL_STATEMENT_COMMIT); yy_destructor(yypParser,49,&yymsp[-4].minor); + yy_destructor(yypParser,63,&yymsp[-3].minor); + yy_destructor(yypParser,68,&yymsp[-2].minor); + yy_destructor(yypParser,123,&yymsp[-1].minor); + yy_destructor(yypParser,124,&yymsp[0].minor); +} +#line 2234 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 22: /* cmd ::= COMMIT COMMENT STRING */ +#line 369 "../libgda/sql-parser/parser.y" +{yygotominor.yy116 = gda_sql_statement_new (GDA_SQL_STATEMENT_COMMIT); yy_destructor(yypParser,49,&yymsp[-2].minor); + yy_destructor(yypParser,62,&yymsp[-1].minor); + yy_destructor(yypParser,68,&yymsp[0].minor); +} +#line 2242 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 23: /* cmd ::= COMMIT COMMENT STRING ora_commit_write */ +#line 370 "../libgda/sql-parser/parser.y" +{yygotominor.yy116 = gda_sql_statement_new (GDA_SQL_STATEMENT_COMMIT); yy_destructor(yypParser,49,&yymsp[-3].minor); + yy_destructor(yypParser,62,&yymsp[-2].minor); + yy_destructor(yypParser,68,&yymsp[-1].minor); +} +#line 2250 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 24: /* cmd ::= COMMIT ora_commit_write */ +#line 371 "../libgda/sql-parser/parser.y" +{yygotominor.yy116 = gda_sql_statement_new (GDA_SQL_STATEMENT_COMMIT); yy_destructor(yypParser,49,&yymsp[-1].minor); +} +#line 2256 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 25: /* cmd ::= ROLLBACK trans_opt_kw nm_opt */ +#line 373 "../libgda/sql-parser/parser.y" +{yygotominor.yy116 = gda_sql_statement_new (GDA_SQL_STATEMENT_ROLLBACK); + gda_sql_statement_trans_take_name (yygotominor.yy116, yymsp[0].minor.yy0); + yy_destructor(yypParser,50,&yymsp[-2].minor); +} +#line 2264 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 26: /* ora_commit_write ::= WRITE IMMEDIATE */ +#line 377 "../libgda/sql-parser/parser.y" +{ + yy_destructor(yypParser,58,&yymsp[-1].minor); + yy_destructor(yypParser,23,&yymsp[0].minor); +} +#line 2272 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 27: /* ora_commit_write ::= WRITE BATCH */ +#line 378 "../libgda/sql-parser/parser.y" +{ + yy_destructor(yypParser,58,&yymsp[-1].minor); + yy_destructor(yypParser,66,&yymsp[0].minor); +} +#line 2280 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 28: /* ora_commit_write ::= WRITE WAIT */ +#line 379 "../libgda/sql-parser/parser.y" +{ + yy_destructor(yypParser,58,&yymsp[-1].minor); + yy_destructor(yypParser,64,&yymsp[0].minor); +} +#line 2288 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 29: /* ora_commit_write ::= WRITE NOWAIT */ +#line 380 "../libgda/sql-parser/parser.y" +{ + yy_destructor(yypParser,58,&yymsp[-1].minor); + yy_destructor(yypParser,65,&yymsp[0].minor); +} +#line 2296 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 30: /* ora_commit_write ::= WRITE IMMEDIATE WAIT */ +#line 381 "../libgda/sql-parser/parser.y" +{ + yy_destructor(yypParser,58,&yymsp[-2].minor); + yy_destructor(yypParser,23,&yymsp[-1].minor); + yy_destructor(yypParser,64,&yymsp[0].minor); +} +#line 2305 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 31: /* ora_commit_write ::= WRITE IMMEDIATE NOWAIT */ +#line 382 "../libgda/sql-parser/parser.y" +{ + yy_destructor(yypParser,58,&yymsp[-2].minor); + yy_destructor(yypParser,23,&yymsp[-1].minor); + yy_destructor(yypParser,65,&yymsp[0].minor); +} +#line 2314 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 32: /* ora_commit_write ::= WRITE BATCH WAIT */ +#line 383 "../libgda/sql-parser/parser.y" +{ + yy_destructor(yypParser,58,&yymsp[-2].minor); + yy_destructor(yypParser,66,&yymsp[-1].minor); + yy_destructor(yypParser,64,&yymsp[0].minor); +} +#line 2323 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 33: /* ora_commit_write ::= WRITE BATCH NOWAIT */ +#line 384 "../libgda/sql-parser/parser.y" +{ + yy_destructor(yypParser,58,&yymsp[-2].minor); + yy_destructor(yypParser,66,&yymsp[-1].minor); + yy_destructor(yypParser,65,&yymsp[0].minor); +} +#line 2332 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 35: /* trans_opt_kw ::= TRANSACTION */ +#line 387 "../libgda/sql-parser/parser.y" +{ + yy_destructor(yypParser,122,&yymsp[0].minor); +} +#line 2339 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 37: /* opt_comma ::= COMMA */ +#line 390 "../libgda/sql-parser/parser.y" +{ + yy_destructor(yypParser,123,&yymsp[0].minor); +} +#line 2346 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 38: /* transilev ::= ISOLATION LEVEL SERIALIZABLE */ +#line 393 "../libgda/sql-parser/parser.y" +{yygotominor.yy169 = GDA_TRANSACTION_ISOLATION_SERIALIZABLE; yy_destructor(yypParser,51,&yymsp[-2].minor); + yy_destructor(yypParser,52,&yymsp[-1].minor); + yy_destructor(yypParser,53,&yymsp[0].minor); +} +#line 2354 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 39: /* transilev ::= ISOLATION LEVEL REPEATABLE READ */ +#line 394 "../libgda/sql-parser/parser.y" +{yygotominor.yy169 = GDA_TRANSACTION_ISOLATION_REPEATABLE_READ; yy_destructor(yypParser,51,&yymsp[-3].minor); + yy_destructor(yypParser,52,&yymsp[-2].minor); + yy_destructor(yypParser,57,&yymsp[-1].minor); + yy_destructor(yypParser,54,&yymsp[0].minor); +} +#line 2363 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 40: /* transilev ::= ISOLATION LEVEL READ COMMITTED */ +#line 395 "../libgda/sql-parser/parser.y" +{yygotominor.yy169 = GDA_TRANSACTION_ISOLATION_READ_COMMITTED; yy_destructor(yypParser,51,&yymsp[-3].minor); + yy_destructor(yypParser,52,&yymsp[-2].minor); + yy_destructor(yypParser,54,&yymsp[-1].minor); + yy_destructor(yypParser,55,&yymsp[0].minor); +} +#line 2372 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 41: /* transilev ::= ISOLATION LEVEL READ UNCOMMITTED */ +#line 396 "../libgda/sql-parser/parser.y" +{yygotominor.yy169 = GDA_TRANSACTION_ISOLATION_READ_UNCOMMITTED; yy_destructor(yypParser,51,&yymsp[-3].minor); + yy_destructor(yypParser,52,&yymsp[-2].minor); + yy_destructor(yypParser,54,&yymsp[-1].minor); + yy_destructor(yypParser,56,&yymsp[0].minor); +} +#line 2381 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 42: /* nm_opt ::= */ + case 57: /* opt_on_conflict ::= */ yytestcase(yyruleno==57); + case 126: /* as ::= */ yytestcase(yyruleno==126); +#line 398 "../libgda/sql-parser/parser.y" +{yygotominor.yy0 = NULL;} +#line 2388 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 43: /* nm_opt ::= nm */ + case 44: /* transtype ::= DEFERRED */ yytestcase(yyruleno==44); + case 45: /* transtype ::= IMMEDIATE */ yytestcase(yyruleno==45); + case 46: /* transtype ::= EXCLUSIVE */ yytestcase(yyruleno==46); + case 121: /* starname ::= STAR */ yytestcase(yyruleno==121); + case 182: /* value ::= STRING */ yytestcase(yyruleno==182); + case 183: /* value ::= INTEGER */ yytestcase(yyruleno==183); + case 184: /* value ::= FLOAT */ yytestcase(yyruleno==184); + case 193: /* nm ::= JOIN */ yytestcase(yyruleno==193); + case 194: /* nm ::= ID */ yytestcase(yyruleno==194); + case 195: /* nm ::= TEXTUAL */ yytestcase(yyruleno==195); + case 196: /* nm ::= LIMIT */ yytestcase(yyruleno==196); + case 197: /* fullname ::= nm */ yytestcase(yyruleno==197); +#line 399 "../libgda/sql-parser/parser.y" +{yygotominor.yy0 = yymsp[0].minor.yy0;} +#line 2405 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 47: /* transtype ::= READ WRITE */ +#line 404 "../libgda/sql-parser/parser.y" +{yygotominor.yy0 = g_new0 (GValue, 1); + g_value_init (yygotominor.yy0, G_TYPE_STRING); + g_value_set_string (yygotominor.yy0, "READ_WRITE"); + yy_destructor(yypParser,54,&yymsp[-1].minor); + yy_destructor(yypParser,58,&yymsp[0].minor); +} +#line 2415 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 48: /* transtype ::= READ ONLY */ +#line 408 "../libgda/sql-parser/parser.y" +{yygotominor.yy0 = g_new0 (GValue, 1); + g_value_init (yygotominor.yy0, G_TYPE_STRING); + g_value_set_string (yygotominor.yy0, "READ_ONLY"); + yy_destructor(yypParser,54,&yymsp[-1].minor); + yy_destructor(yypParser,59,&yymsp[0].minor); +} +#line 2425 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 49: /* cmd ::= SAVEPOINT nm */ +#line 416 "../libgda/sql-parser/parser.y" +{yygotominor.yy116 = gda_sql_statement_new (GDA_SQL_STATEMENT_SAVEPOINT); + gda_sql_statement_trans_take_name (yygotominor.yy116, yymsp[0].minor.yy0); + yy_destructor(yypParser,60,&yymsp[-1].minor); +} +#line 2433 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 50: /* cmd ::= RELEASE SAVEPOINT nm */ +#line 420 "../libgda/sql-parser/parser.y" +{yygotominor.yy116 = gda_sql_statement_new (GDA_SQL_STATEMENT_DELETE_SAVEPOINT); + gda_sql_statement_trans_take_name (yygotominor.yy116, yymsp[0].minor.yy0); + yy_destructor(yypParser,61,&yymsp[-2].minor); + yy_destructor(yypParser,60,&yymsp[-1].minor); +} +#line 2442 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 51: /* cmd ::= RELEASE nm */ +#line 424 "../libgda/sql-parser/parser.y" +{yygotominor.yy116 = gda_sql_statement_new (GDA_SQL_STATEMENT_DELETE_SAVEPOINT); + gda_sql_statement_trans_take_name (yygotominor.yy116, yymsp[0].minor.yy0); + yy_destructor(yypParser,61,&yymsp[-1].minor); +} +#line 2450 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 52: /* cmd ::= ROLLBACK trans_opt_kw TO nm */ +#line 428 "../libgda/sql-parser/parser.y" +{yygotominor.yy116 = gda_sql_statement_new (GDA_SQL_STATEMENT_ROLLBACK_SAVEPOINT); + gda_sql_statement_trans_take_name (yygotominor.yy116, yymsp[0].minor.yy0); + yy_destructor(yypParser,50,&yymsp[-3].minor); + yy_destructor(yypParser,125,&yymsp[-1].minor); +} +#line 2459 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 53: /* cmd ::= ROLLBACK trans_opt_kw TO SAVEPOINT nm */ +#line 432 "../libgda/sql-parser/parser.y" +{yygotominor.yy116 = gda_sql_statement_new (GDA_SQL_STATEMENT_ROLLBACK_SAVEPOINT); + gda_sql_statement_trans_take_name (yygotominor.yy116, yymsp[0].minor.yy0); + yy_destructor(yypParser,50,&yymsp[-4].minor); + yy_destructor(yypParser,125,&yymsp[-2].minor); + yy_destructor(yypParser,60,&yymsp[-1].minor); +} +#line 2469 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 54: /* cmd ::= INSERT opt_on_conflict INTO fullname inscollist_opt VALUES LP rexprlist RP */ +#line 439 "../libgda/sql-parser/parser.y" +{ + yygotominor.yy116 = gda_sql_statement_new (GDA_SQL_STATEMENT_INSERT); + gda_sql_statement_insert_take_table_name (yygotominor.yy116, yymsp[-5].minor.yy0); + gda_sql_statement_insert_take_fields_list (yygotominor.yy116, yymsp[-4].minor.yy333); + gda_sql_statement_insert_take_1_values_list (yygotominor.yy116, g_slist_reverse (yymsp[-1].minor.yy325)); + gda_sql_statement_insert_take_on_conflict (yygotominor.yy116, yymsp[-7].minor.yy0); + yy_destructor(yypParser,126,&yymsp[-8].minor); + yy_destructor(yypParser,127,&yymsp[-6].minor); + yy_destructor(yypParser,128,&yymsp[-3].minor); + yy_destructor(yypParser,105,&yymsp[-2].minor); + yy_destructor(yypParser,106,&yymsp[0].minor); +} +#line 2485 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 55: /* cmd ::= INSERT opt_on_conflict INTO fullname inscollist_opt VALUES LP rexprlist RP ins_extra_values */ +#line 447 "../libgda/sql-parser/parser.y" +{ + yygotominor.yy116 = gda_sql_statement_new (GDA_SQL_STATEMENT_INSERT); + gda_sql_statement_insert_take_table_name (yygotominor.yy116, yymsp[-6].minor.yy0); + gda_sql_statement_insert_take_fields_list (yygotominor.yy116, yymsp[-5].minor.yy333); + gda_sql_statement_insert_take_1_values_list (yygotominor.yy116, g_slist_reverse (yymsp[-2].minor.yy325)); + gda_sql_statement_insert_take_extra_values_list (yygotominor.yy116, yymsp[0].minor.yy333); + gda_sql_statement_insert_take_on_conflict (yygotominor.yy116, yymsp[-8].minor.yy0); + yy_destructor(yypParser,126,&yymsp[-9].minor); + yy_destructor(yypParser,127,&yymsp[-7].minor); + yy_destructor(yypParser,128,&yymsp[-4].minor); + yy_destructor(yypParser,105,&yymsp[-3].minor); + yy_destructor(yypParser,106,&yymsp[-1].minor); +} +#line 2502 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 56: /* cmd ::= INSERT opt_on_conflict INTO fullname inscollist_opt compound */ +#line 456 "../libgda/sql-parser/parser.y" +{ + yygotominor.yy116 = gda_sql_statement_new (GDA_SQL_STATEMENT_INSERT); + gda_sql_statement_insert_take_table_name (yygotominor.yy116, yymsp[-2].minor.yy0); + gda_sql_statement_insert_take_fields_list (yygotominor.yy116, yymsp[-1].minor.yy333); + gda_sql_statement_insert_take_select (yygotominor.yy116, yymsp[0].minor.yy116); + gda_sql_statement_insert_take_on_conflict (yygotominor.yy116, yymsp[-4].minor.yy0); + yy_destructor(yypParser,126,&yymsp[-5].minor); + yy_destructor(yypParser,127,&yymsp[-3].minor); +} +#line 2515 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 58: /* opt_on_conflict ::= OR ID */ +#line 466 "../libgda/sql-parser/parser.y" +{yygotominor.yy0 = yymsp[0].minor.yy0; yy_destructor(yypParser,69,&yymsp[-1].minor); +} +#line 2521 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 59: /* ins_extra_values ::= ins_extra_values COMMA LP rexprlist RP */ +#line 475 "../libgda/sql-parser/parser.y" +{yygotominor.yy333 = g_slist_append (yymsp[-4].minor.yy333, g_slist_reverse (yymsp[-1].minor.yy325)); yy_destructor(yypParser,123,&yymsp[-3].minor); + yy_destructor(yypParser,105,&yymsp[-2].minor); + yy_destructor(yypParser,106,&yymsp[0].minor); +} +#line 2529 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 60: /* ins_extra_values ::= COMMA LP rexprlist RP */ +#line 476 "../libgda/sql-parser/parser.y" +{yygotominor.yy333 = g_slist_append (NULL, g_slist_reverse (yymsp[-1].minor.yy325)); yy_destructor(yypParser,123,&yymsp[-3].minor); + yy_destructor(yypParser,105,&yymsp[-2].minor); + yy_destructor(yypParser,106,&yymsp[0].minor); +} +#line 2537 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 61: /* inscollist_opt ::= */ + case 97: /* using_opt ::= */ yytestcase(yyruleno==97); +#line 480 "../libgda/sql-parser/parser.y" +{yygotominor.yy333 = NULL;} +#line 2543 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 62: /* inscollist_opt ::= LP inscollist RP */ +#line 481 "../libgda/sql-parser/parser.y" +{yygotominor.yy333 = yymsp[-1].minor.yy333; yy_destructor(yypParser,105,&yymsp[-2].minor); + yy_destructor(yypParser,106,&yymsp[0].minor); +} +#line 2550 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 63: /* inscollist ::= inscollist COMMA fullname */ +#line 485 "../libgda/sql-parser/parser.y" +{GdaSqlField *field; + field = gda_sql_field_new (NULL); + gda_sql_field_take_name (field, yymsp[0].minor.yy0); + yygotominor.yy333 = g_slist_append (yymsp[-2].minor.yy333, field); + yy_destructor(yypParser,123,&yymsp[-1].minor); +} +#line 2560 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 64: /* inscollist ::= fullname */ +#line 490 "../libgda/sql-parser/parser.y" +{GdaSqlField *field = gda_sql_field_new (NULL); + gda_sql_field_take_name (field, yymsp[0].minor.yy0); + yygotominor.yy333 = g_slist_prepend (NULL, field); +} +#line 2568 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 65: /* cmd ::= DELETE FROM fullname where_opt */ +#line 496 "../libgda/sql-parser/parser.y" +{yygotominor.yy116 = gda_sql_statement_new (GDA_SQL_STATEMENT_DELETE); + gda_sql_statement_delete_take_table_name (yygotominor.yy116, yymsp[-1].minor.yy0); + gda_sql_statement_delete_take_condition (yygotominor.yy116, yymsp[0].minor.yy70); yy_destructor(yypParser,129,&yymsp[-3].minor); + yy_destructor(yypParser,130,&yymsp[-2].minor); +} +#line 2577 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 66: /* where_opt ::= */ + case 89: /* having_opt ::= */ yytestcase(yyruleno==89); + case 101: /* on_cond ::= */ yytestcase(yyruleno==101); +#line 502 "../libgda/sql-parser/parser.y" +{yygotominor.yy70 = NULL;} +#line 2584 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 67: /* where_opt ::= WHERE expr */ +#line 503 "../libgda/sql-parser/parser.y" +{yygotominor.yy70 = yymsp[0].minor.yy70; yy_destructor(yypParser,131,&yymsp[-1].minor); +} +#line 2590 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 68: /* cmd ::= UPDATE opt_on_conflict fullname SET setlist where_opt */ +#line 506 "../libgda/sql-parser/parser.y" +{ + GSList *list; + yygotominor.yy116 = gda_sql_statement_new (GDA_SQL_STATEMENT_UPDATE); + gda_sql_statement_update_take_table_name (yygotominor.yy116, yymsp[-3].minor.yy0); + gda_sql_statement_update_take_on_conflict (yygotominor.yy116, yymsp[-4].minor.yy0); + gda_sql_statement_update_take_condition (yygotominor.yy116, yymsp[0].minor.yy70); + for (list = yymsp[-1].minor.yy333; list; list = list->next) { + UpdateSet *set = (UpdateSet*) list->data; + gda_sql_statement_update_take_set_value (yygotominor.yy116, set->fname, set->expr); + g_free (set); + } + g_slist_free (yymsp[-1].minor.yy333); + yy_destructor(yypParser,132,&yymsp[-5].minor); + yy_destructor(yypParser,133,&yymsp[-2].minor); +} +#line 2609 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 69: /* setlist ::= setlist COMMA fullname EQ expr */ +#line 530 "../libgda/sql-parser/parser.y" +{UpdateSet *set; + set = g_new (UpdateSet, 1); + set->fname = yymsp[-2].minor.yy0; + set->expr = yymsp[0].minor.yy70; + yygotominor.yy333 = g_slist_append (yymsp[-4].minor.yy333, set); + yy_destructor(yypParser,123,&yymsp[-3].minor); + yy_destructor(yypParser,79,&yymsp[-1].minor); +} +#line 2621 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 70: /* setlist ::= fullname EQ expr */ +#line 536 "../libgda/sql-parser/parser.y" +{UpdateSet *set; + set = g_new (UpdateSet, 1); + set->fname = yymsp[-2].minor.yy0; + set->expr = yymsp[0].minor.yy70; + yygotominor.yy333 = g_slist_append (NULL, set); + yy_destructor(yypParser,79,&yymsp[-1].minor); +} +#line 2632 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 71: /* compound ::= selectcmd */ +#line 547 "../libgda/sql-parser/parser.y" +{ + yygotominor.yy116 = gda_sql_statement_new (GDA_SQL_STATEMENT_COMPOUND); + gda_sql_statement_compound_take_stmt (yygotominor.yy116, yymsp[0].minor.yy116); +} +#line 2640 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 72: /* compound ::= compound UNION opt_compound_all compound */ +#line 551 "../libgda/sql-parser/parser.y" +{ + yygotominor.yy116 = compose_multiple_compounds (yymsp[-1].minor.yy276 ? GDA_SQL_STATEMENT_COMPOUND_UNION_ALL : GDA_SQL_STATEMENT_COMPOUND_UNION, + yymsp[-3].minor.yy116, yymsp[0].minor.yy116); + yy_destructor(yypParser,114,&yymsp[-2].minor); +} +#line 2649 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 73: /* compound ::= compound EXCEPT opt_compound_all compound */ +#line 556 "../libgda/sql-parser/parser.y" +{ + yygotominor.yy116 = compose_multiple_compounds (yymsp[-1].minor.yy276 ? GDA_SQL_STATEMENT_COMPOUND_EXCEPT_ALL : GDA_SQL_STATEMENT_COMPOUND_EXCEPT, + yymsp[-3].minor.yy116, yymsp[0].minor.yy116); + yy_destructor(yypParser,115,&yymsp[-2].minor); +} +#line 2658 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 74: /* compound ::= compound INTERSECT opt_compound_all compound */ +#line 561 "../libgda/sql-parser/parser.y" +{ + yygotominor.yy116 = compose_multiple_compounds (yymsp[-1].minor.yy276 ? GDA_SQL_STATEMENT_COMPOUND_INTERSECT_ALL : GDA_SQL_STATEMENT_COMPOUND_INTERSECT, + yymsp[-3].minor.yy116, yymsp[0].minor.yy116); + yy_destructor(yypParser,116,&yymsp[-2].minor); +} +#line 2667 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 75: /* opt_compound_all ::= */ +#line 567 "../libgda/sql-parser/parser.y" +{yygotominor.yy276 = FALSE;} +#line 2672 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 76: /* opt_compound_all ::= ALL */ +#line 568 "../libgda/sql-parser/parser.y" +{yygotominor.yy276 = TRUE; yy_destructor(yypParser,134,&yymsp[0].minor); +} +#line 2678 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 77: /* selectcmd ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt */ +#line 575 "../libgda/sql-parser/parser.y" +{ + yygotominor.yy116 = gda_sql_statement_new (GDA_SQL_STATEMENT_SELECT); + if (yymsp[-7].minor.yy297) { + gda_sql_statement_select_take_distinct (yygotominor.yy116, yymsp[-7].minor.yy297->distinct, yymsp[-7].minor.yy297->expr); + g_free (yymsp[-7].minor.yy297); + } + gda_sql_statement_select_take_expr_list (yygotominor.yy116, yymsp[-6].minor.yy325); + gda_sql_statement_select_take_from (yygotominor.yy116, yymsp[-5].minor.yy191); + gda_sql_statement_select_take_where_cond (yygotominor.yy116, yymsp[-4].minor.yy70); + gda_sql_statement_select_take_group_by (yygotominor.yy116, yymsp[-3].minor.yy333); + gda_sql_statement_select_take_having_cond (yygotominor.yy116, yymsp[-2].minor.yy70); + gda_sql_statement_select_take_order_by (yygotominor.yy116, yymsp[-1].minor.yy325); + gda_sql_statement_select_take_limits (yygotominor.yy116, yymsp[0].minor.yy44.count, yymsp[0].minor.yy44.offset); + yy_destructor(yypParser,135,&yymsp[-8].minor); +} +#line 2697 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 78: /* limit_opt ::= */ +#line 592 "../libgda/sql-parser/parser.y" +{yygotominor.yy44.count = NULL; yygotominor.yy44.offset = NULL;} +#line 2702 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 79: /* limit_opt ::= LIMIT expr */ +#line 593 "../libgda/sql-parser/parser.y" +{yygotominor.yy44.count = yymsp[0].minor.yy70; yygotominor.yy44.offset = NULL; yy_destructor(yypParser,136,&yymsp[-1].minor); +} +#line 2708 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 80: /* limit_opt ::= LIMIT expr OFFSET expr */ +#line 594 "../libgda/sql-parser/parser.y" +{yygotominor.yy44.count = yymsp[-2].minor.yy70; yygotominor.yy44.offset = yymsp[0].minor.yy70; yy_destructor(yypParser,136,&yymsp[-3].minor); + yy_destructor(yypParser,33,&yymsp[-1].minor); +} +#line 2715 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 81: /* limit_opt ::= LIMIT expr COMMA expr */ +#line 595 "../libgda/sql-parser/parser.y" +{yygotominor.yy44.count = yymsp[-2].minor.yy70; yygotominor.yy44.offset = yymsp[0].minor.yy70; yy_destructor(yypParser,136,&yymsp[-3].minor); + yy_destructor(yypParser,123,&yymsp[-1].minor); +} +#line 2722 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 82: /* orderby_opt ::= */ +#line 599 "../libgda/sql-parser/parser.y" +{yygotominor.yy325 = 0;} +#line 2727 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 83: /* orderby_opt ::= ORDER BY sortlist */ +#line 600 "../libgda/sql-parser/parser.y" +{yygotominor.yy325 = yymsp[0].minor.yy325; yy_destructor(yypParser,137,&yymsp[-2].minor); + yy_destructor(yypParser,138,&yymsp[-1].minor); +} +#line 2734 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 84: /* sortlist ::= sortlist COMMA expr sortorder */ +#line 604 "../libgda/sql-parser/parser.y" +{GdaSqlSelectOrder *order; + order = gda_sql_select_order_new (NULL); + order->expr = yymsp[-1].minor.yy70; + order->asc = yymsp[0].minor.yy276; + yygotominor.yy325 = g_slist_append (yymsp[-3].minor.yy325, order); + yy_destructor(yypParser,123,&yymsp[-2].minor); +} +#line 2745 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 85: /* sortlist ::= expr sortorder */ +#line 610 "../libgda/sql-parser/parser.y" +{GdaSqlSelectOrder *order; + order = gda_sql_select_order_new (NULL); + order->expr = yymsp[-1].minor.yy70; + order->asc = yymsp[0].minor.yy276; + yygotominor.yy325 = g_slist_prepend (NULL, order); +} +#line 2755 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 86: /* sortorder ::= ASC */ +#line 618 "../libgda/sql-parser/parser.y" +{yygotominor.yy276 = TRUE; yy_destructor(yypParser,5,&yymsp[0].minor); +} +#line 2761 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 87: /* sortorder ::= DESC */ +#line 619 "../libgda/sql-parser/parser.y" +{yygotominor.yy276 = FALSE; yy_destructor(yypParser,14,&yymsp[0].minor); +} +#line 2767 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 88: /* sortorder ::= */ +#line 620 "../libgda/sql-parser/parser.y" +{yygotominor.yy276 = TRUE;} +#line 2772 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 90: /* having_opt ::= HAVING expr */ +#line 626 "../libgda/sql-parser/parser.y" +{yygotominor.yy70 = yymsp[0].minor.yy70; yy_destructor(yypParser,139,&yymsp[-1].minor); +} +#line 2778 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 91: /* groupby_opt ::= */ +#line 630 "../libgda/sql-parser/parser.y" +{yygotominor.yy333 = 0;} +#line 2783 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 92: /* groupby_opt ::= GROUP BY rnexprlist */ +#line 631 "../libgda/sql-parser/parser.y" +{yygotominor.yy333 = g_slist_reverse (yymsp[0].minor.yy325); yy_destructor(yypParser,140,&yymsp[-2].minor); + yy_destructor(yypParser,138,&yymsp[-1].minor); +} +#line 2790 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 93: /* from ::= */ + case 98: /* stl_prefix ::= */ yytestcase(yyruleno==98); +#line 635 "../libgda/sql-parser/parser.y" +{yygotominor.yy191 = NULL;} +#line 2796 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 94: /* from ::= FROM seltablist */ +#line 636 "../libgda/sql-parser/parser.y" +{yygotominor.yy191 = yymsp[0].minor.yy191; yy_destructor(yypParser,130,&yymsp[-1].minor); +} +#line 2802 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 95: /* seltablist ::= stl_prefix seltarget on_cond using_opt */ +#line 643 "../libgda/sql-parser/parser.y" +{ + GSList *last; + if (yymsp[-3].minor.yy191) + yygotominor.yy191 = yymsp[-3].minor.yy191; + else + yygotominor.yy191 = gda_sql_select_from_new (NULL); + gda_sql_select_from_take_new_target (yygotominor.yy191, yymsp[-2].minor.yy134); + last = g_slist_last (yygotominor.yy191->joins); + if (last) { + GdaSqlSelectJoin *join = (GdaSqlSelectJoin *) (last->data); + join->expr = yymsp[-1].minor.yy70; + join->position = g_slist_length (yygotominor.yy191->targets) - 1; + join->use = yymsp[0].minor.yy333; + } +} +#line 2821 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 96: /* using_opt ::= USING LP inscollist RP */ +#line 661 "../libgda/sql-parser/parser.y" +{yygotominor.yy333 = yymsp[-1].minor.yy333; yy_destructor(yypParser,141,&yymsp[-3].minor); + yy_destructor(yypParser,105,&yymsp[-2].minor); + yy_destructor(yypParser,106,&yymsp[0].minor); +} +#line 2829 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 99: /* stl_prefix ::= seltablist jointype */ +#line 665 "../libgda/sql-parser/parser.y" +{GdaSqlSelectJoin *join; + yygotominor.yy191 = yymsp[-1].minor.yy191; + join = gda_sql_select_join_new (GDA_SQL_ANY_PART (yygotominor.yy191)); + join->type = yymsp[0].minor.yy371; + gda_sql_select_from_take_new_join (yygotominor.yy191, join); +} +#line 2839 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 100: /* on_cond ::= ON expr */ +#line 675 "../libgda/sql-parser/parser.y" +{yygotominor.yy70 = yymsp[0].minor.yy70; yy_destructor(yypParser,142,&yymsp[-1].minor); +} +#line 2845 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 102: /* jointype ::= COMMA */ +#line 679 "../libgda/sql-parser/parser.y" +{yygotominor.yy371 = GDA_SQL_SELECT_JOIN_CROSS; yy_destructor(yypParser,123,&yymsp[0].minor); +} +#line 2851 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 103: /* jointype ::= JOIN */ +#line 680 "../libgda/sql-parser/parser.y" +{yygotominor.yy371 = GDA_SQL_SELECT_JOIN_INNER; yy_destructor(yypParser,107,&yymsp[0].minor); +} +#line 2857 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 104: /* jointype ::= CROSS JOIN */ +#line 681 "../libgda/sql-parser/parser.y" +{yygotominor.yy371 = GDA_SQL_SELECT_JOIN_CROSS; yy_destructor(yypParser,113,&yymsp[-1].minor); + yy_destructor(yypParser,107,&yymsp[0].minor); +} +#line 2864 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 105: /* jointype ::= INNER JOIN */ +#line 682 "../libgda/sql-parser/parser.y" +{yygotominor.yy371 = GDA_SQL_SELECT_JOIN_INNER; yy_destructor(yypParser,108,&yymsp[-1].minor); + yy_destructor(yypParser,107,&yymsp[0].minor); +} +#line 2871 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 106: /* jointype ::= NATURAL JOIN */ +#line 683 "../libgda/sql-parser/parser.y" +{yygotominor.yy371 = GDA_SQL_SELECT_JOIN_NATURAL; yy_destructor(yypParser,109,&yymsp[-1].minor); + yy_destructor(yypParser,107,&yymsp[0].minor); +} +#line 2878 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 107: /* jointype ::= LEFT JOIN */ +#line 684 "../libgda/sql-parser/parser.y" +{yygotominor.yy371 = GDA_SQL_SELECT_JOIN_LEFT; yy_destructor(yypParser,110,&yymsp[-1].minor); + yy_destructor(yypParser,107,&yymsp[0].minor); +} +#line 2885 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 108: /* jointype ::= LEFT OUTER JOIN */ +#line 685 "../libgda/sql-parser/parser.y" +{yygotominor.yy371 = GDA_SQL_SELECT_JOIN_LEFT; yy_destructor(yypParser,110,&yymsp[-2].minor); + yy_destructor(yypParser,143,&yymsp[-1].minor); + yy_destructor(yypParser,107,&yymsp[0].minor); +} +#line 2893 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 109: /* jointype ::= RIGHT JOIN */ +#line 686 "../libgda/sql-parser/parser.y" +{yygotominor.yy371 = GDA_SQL_SELECT_JOIN_RIGHT; yy_destructor(yypParser,111,&yymsp[-1].minor); + yy_destructor(yypParser,107,&yymsp[0].minor); +} +#line 2900 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 110: /* jointype ::= RIGHT OUTER JOIN */ +#line 687 "../libgda/sql-parser/parser.y" +{yygotominor.yy371 = GDA_SQL_SELECT_JOIN_RIGHT; yy_destructor(yypParser,111,&yymsp[-2].minor); + yy_destructor(yypParser,143,&yymsp[-1].minor); + yy_destructor(yypParser,107,&yymsp[0].minor); +} +#line 2908 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 111: /* jointype ::= FULL JOIN */ +#line 688 "../libgda/sql-parser/parser.y" +{yygotominor.yy371 = GDA_SQL_SELECT_JOIN_FULL; yy_destructor(yypParser,112,&yymsp[-1].minor); + yy_destructor(yypParser,107,&yymsp[0].minor); +} +#line 2915 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 112: /* jointype ::= FULL OUTER JOIN */ +#line 689 "../libgda/sql-parser/parser.y" +{yygotominor.yy371 = GDA_SQL_SELECT_JOIN_FULL; yy_destructor(yypParser,112,&yymsp[-2].minor); + yy_destructor(yypParser,143,&yymsp[-1].minor); + yy_destructor(yypParser,107,&yymsp[0].minor); +} +#line 2923 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 113: /* seltarget ::= fullname as */ +#line 694 "../libgda/sql-parser/parser.y" +{yygotominor.yy134 = gda_sql_select_target_new (NULL); + gda_sql_select_target_take_alias (yygotominor.yy134, yymsp[0].minor.yy0); + gda_sql_select_target_take_table_name (yygotominor.yy134, yymsp[-1].minor.yy0); +} +#line 2931 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 114: /* seltarget ::= fullname ID */ +#line 698 "../libgda/sql-parser/parser.y" +{yygotominor.yy134 = gda_sql_select_target_new (NULL); + gda_sql_select_target_take_alias (yygotominor.yy134, yymsp[0].minor.yy0); + gda_sql_select_target_take_table_name (yygotominor.yy134, yymsp[-1].minor.yy0); +} +#line 2939 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 115: /* seltarget ::= LP compound RP as */ + case 116: /* seltarget ::= LP compound RP ID */ yytestcase(yyruleno==116); +#line 702 "../libgda/sql-parser/parser.y" +{yygotominor.yy134 = gda_sql_select_target_new (NULL); + gda_sql_select_target_take_alias (yygotominor.yy134, yymsp[0].minor.yy0); + gda_sql_select_target_take_select (yygotominor.yy134, yymsp[-2].minor.yy116); + yy_destructor(yypParser,105,&yymsp[-3].minor); + yy_destructor(yypParser,106,&yymsp[-1].minor); +} +#line 2950 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 117: /* sclp ::= selcollist COMMA */ +#line 715 "../libgda/sql-parser/parser.y" +{yygotominor.yy325 = yymsp[-1].minor.yy325; yy_destructor(yypParser,123,&yymsp[0].minor); +} +#line 2956 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 118: /* sclp ::= */ + case 133: /* rexprlist ::= */ yytestcase(yyruleno==133); +#line 716 "../libgda/sql-parser/parser.y" +{yygotominor.yy325 = NULL;} +#line 2962 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 119: /* selcollist ::= sclp expr as */ +#line 718 "../libgda/sql-parser/parser.y" +{GdaSqlSelectField *field; + field = gda_sql_select_field_new (NULL); + gda_sql_select_field_take_expr (field, yymsp[-1].minor.yy70); + gda_sql_select_field_take_alias (field, yymsp[0].minor.yy0); + yygotominor.yy325 = g_slist_append (yymsp[-2].minor.yy325, field);} +#line 2971 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 120: /* selcollist ::= sclp starname */ +#line 723 "../libgda/sql-parser/parser.y" +{GdaSqlSelectField *field; + field = gda_sql_select_field_new (NULL); + gda_sql_select_field_take_star_value (field, yymsp[0].minor.yy0); + yygotominor.yy325 = g_slist_append (yymsp[-1].minor.yy325, field);} +#line 2979 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 122: /* starname ::= nm DOT STAR */ + case 198: /* fullname ::= nm DOT nm */ yytestcase(yyruleno==198); +#line 729 "../libgda/sql-parser/parser.y" +{gchar *str; + str = g_strdup_printf ("%s.%s", g_value_get_string (yymsp[-2].minor.yy0), g_value_get_string (yymsp[0].minor.yy0)); + yygotominor.yy0 = g_new0 (GValue, 1); + g_value_init (yygotominor.yy0, G_TYPE_STRING); + g_value_take_string (yygotominor.yy0, str); + g_value_reset (yymsp[-2].minor.yy0); g_free (yymsp[-2].minor.yy0); + g_value_reset (yymsp[0].minor.yy0); g_free (yymsp[0].minor.yy0); + yy_destructor(yypParser,144,&yymsp[-1].minor); +} +#line 2993 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 123: /* starname ::= nm DOT nm DOT STAR */ + case 199: /* fullname ::= nm DOT nm DOT nm */ yytestcase(yyruleno==199); +#line 738 "../libgda/sql-parser/parser.y" +{gchar *str; + str = g_strdup_printf ("%s.%s.%s", g_value_get_string (yymsp[-4].minor.yy0), + g_value_get_string (yymsp[-2].minor.yy0), g_value_get_string (yymsp[0].minor.yy0)); + yygotominor.yy0 = g_new0 (GValue, 1); + g_value_init (yygotominor.yy0, G_TYPE_STRING); + g_value_take_string (yygotominor.yy0, str); + g_value_reset (yymsp[-4].minor.yy0); g_free (yymsp[-4].minor.yy0); + g_value_reset (yymsp[-2].minor.yy0); g_free (yymsp[-2].minor.yy0); + g_value_reset (yymsp[0].minor.yy0); g_free (yymsp[0].minor.yy0); + yy_destructor(yypParser,144,&yymsp[-3].minor); + yy_destructor(yypParser,144,&yymsp[-1].minor); +} +#line 3010 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 124: /* as ::= AS fullname */ + case 125: /* as ::= AS value */ yytestcase(yyruleno==125); +#line 749 "../libgda/sql-parser/parser.y" +{yygotominor.yy0 = yymsp[0].minor.yy0; yy_destructor(yypParser,145,&yymsp[-1].minor); +} +#line 3017 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 127: /* distinct ::= */ +#line 755 "../libgda/sql-parser/parser.y" +{yygotominor.yy297 = NULL;} +#line 3022 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 128: /* distinct ::= ALL */ +#line 756 "../libgda/sql-parser/parser.y" +{yygotominor.yy297 = NULL; yy_destructor(yypParser,134,&yymsp[0].minor); +} +#line 3028 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 129: /* distinct ::= DISTINCT */ +#line 757 "../libgda/sql-parser/parser.y" +{yygotominor.yy297 = g_new0 (Distinct, 1); yygotominor.yy297->distinct = TRUE; yy_destructor(yypParser,146,&yymsp[0].minor); +} +#line 3034 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 130: /* distinct ::= DISTINCT ON expr */ +#line 758 "../libgda/sql-parser/parser.y" +{yygotominor.yy297 = g_new0 (Distinct, 1); yygotominor.yy297->distinct = TRUE; yygotominor.yy297->expr = yymsp[0].minor.yy70; yy_destructor(yypParser,146,&yymsp[-2].minor); + yy_destructor(yypParser,142,&yymsp[-1].minor); +} +#line 3041 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 131: /* rnexprlist ::= rnexprlist COMMA expr */ + case 134: /* rexprlist ::= rexprlist COMMA expr */ yytestcase(yyruleno==134); +#line 763 "../libgda/sql-parser/parser.y" +{yygotominor.yy325 = g_slist_prepend (yymsp[-2].minor.yy325, yymsp[0].minor.yy70); yy_destructor(yypParser,123,&yymsp[-1].minor); +} +#line 3048 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 132: /* rnexprlist ::= expr */ + case 135: /* rexprlist ::= expr */ yytestcase(yyruleno==135); +#line 764 "../libgda/sql-parser/parser.y" +{yygotominor.yy325 = g_slist_append (NULL, yymsp[0].minor.yy70);} +#line 3054 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 136: /* expr ::= pvalue */ +#line 776 "../libgda/sql-parser/parser.y" +{yygotominor.yy70 = yymsp[0].minor.yy70;} +#line 3059 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 137: /* expr ::= value */ + case 139: /* expr ::= fullname */ yytestcase(yyruleno==139); +#line 777 "../libgda/sql-parser/parser.y" +{yygotominor.yy70 = gda_sql_expr_new (NULL); yygotominor.yy70->value = yymsp[0].minor.yy0;} +#line 3065 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 138: /* expr ::= LP expr RP */ +#line 778 "../libgda/sql-parser/parser.y" +{yygotominor.yy70 = yymsp[-1].minor.yy70; yy_destructor(yypParser,105,&yymsp[-2].minor); + yy_destructor(yypParser,106,&yymsp[0].minor); +} +#line 3072 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 140: /* expr ::= fullname LP rexprlist RP */ +#line 780 "../libgda/sql-parser/parser.y" +{GdaSqlFunction *func; + yygotominor.yy70 = gda_sql_expr_new (NULL); + func = gda_sql_function_new (GDA_SQL_ANY_PART (yygotominor.yy70)); + gda_sql_function_take_name (func, yymsp[-3].minor.yy0); + gda_sql_function_take_args_list (func, g_slist_reverse (yymsp[-1].minor.yy325)); + yygotominor.yy70->func = func; yy_destructor(yypParser,105,&yymsp[-2].minor); + yy_destructor(yypParser,106,&yymsp[0].minor); +} +#line 3084 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 141: /* expr ::= fullname LP compound RP */ +#line 786 "../libgda/sql-parser/parser.y" +{GdaSqlFunction *func; + GdaSqlExpr *expr; + yygotominor.yy70 = gda_sql_expr_new (NULL); + func = gda_sql_function_new (GDA_SQL_ANY_PART (yygotominor.yy70)); + gda_sql_function_take_name (func, yymsp[-3].minor.yy0); + expr = gda_sql_expr_new (GDA_SQL_ANY_PART (func)); + gda_sql_expr_take_select (expr, yymsp[-1].minor.yy116); + gda_sql_function_take_args_list (func, g_slist_prepend (NULL, expr)); + yygotominor.yy70->func = func; yy_destructor(yypParser,105,&yymsp[-2].minor); + yy_destructor(yypParser,106,&yymsp[0].minor); +} +#line 3099 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 142: /* expr ::= fullname LP starname RP */ +#line 795 "../libgda/sql-parser/parser.y" +{GdaSqlFunction *func; + GdaSqlExpr *expr; + yygotominor.yy70 = gda_sql_expr_new (NULL); + func = gda_sql_function_new (GDA_SQL_ANY_PART (yygotominor.yy70)); + gda_sql_function_take_name (func, yymsp[-3].minor.yy0); + expr = gda_sql_expr_new (GDA_SQL_ANY_PART (func)); + expr->value = yymsp[-1].minor.yy0; + gda_sql_function_take_args_list (func, g_slist_prepend (NULL, expr)); + yygotominor.yy70->func = func; yy_destructor(yypParser,105,&yymsp[-2].minor); + yy_destructor(yypParser,106,&yymsp[0].minor); +} +#line 3114 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 143: /* expr ::= CAST LP expr AS fullname RP */ +#line 804 "../libgda/sql-parser/parser.y" +{yygotominor.yy70 = yymsp[-3].minor.yy70; + yymsp[-3].minor.yy70->cast_as = g_value_dup_string (yymsp[-1].minor.yy0); + g_value_reset (yymsp[-1].minor.yy0); + g_free (yymsp[-1].minor.yy0); yy_destructor(yypParser,10,&yymsp[-5].minor); + yy_destructor(yypParser,105,&yymsp[-4].minor); + yy_destructor(yypParser,145,&yymsp[-2].minor); + yy_destructor(yypParser,106,&yymsp[0].minor); +} +#line 3126 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 144: /* expr ::= expr PGCAST fullname */ +#line 808 "../libgda/sql-parser/parser.y" +{yygotominor.yy70 = yymsp[-2].minor.yy70; + yymsp[-2].minor.yy70->cast_as = g_value_dup_string (yymsp[0].minor.yy0); + g_value_reset (yymsp[0].minor.yy0); + g_free (yymsp[0].minor.yy0); yy_destructor(yypParser,117,&yymsp[-1].minor); +} +#line 3135 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 145: /* expr ::= expr PLUS|MINUS expr */ +#line 813 "../libgda/sql-parser/parser.y" +{yygotominor.yy70 = compose_multiple_expr (string_to_op_type (yymsp[-1].minor.yy0), yymsp[-2].minor.yy70, yymsp[0].minor.yy70);} +#line 3140 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 146: /* expr ::= expr STAR expr */ +#line 814 "../libgda/sql-parser/parser.y" +{yygotominor.yy70 = compose_multiple_expr (GDA_SQL_OPERATOR_TYPE_STAR, yymsp[-2].minor.yy70, yymsp[0].minor.yy70); yy_destructor(yypParser,97,&yymsp[-1].minor); +} +#line 3146 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 147: /* expr ::= expr SLASH|REM expr */ + case 148: /* expr ::= expr BITAND|BITOR expr */ yytestcase(yyruleno==148); + case 154: /* expr ::= expr GT|LEQ|GEQ|LT expr */ yytestcase(yyruleno==154); + case 155: /* expr ::= expr DIFF|EQ expr */ yytestcase(yyruleno==155); + case 160: /* expr ::= expr REGEXP|REGEXP_CI|NOT_REGEXP|NOT_REGEXP_CI|SIMILAR expr */ yytestcase(yyruleno==160); +#line 815 "../libgda/sql-parser/parser.y" +{yygotominor.yy70 = create_two_expr (string_to_op_type (yymsp[-1].minor.yy0), yymsp[-2].minor.yy70, yymsp[0].minor.yy70);} +#line 3155 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 149: /* expr ::= MINUS expr */ +#line 818 "../libgda/sql-parser/parser.y" +{yygotominor.yy70 = create_uni_expr (GDA_SQL_OPERATOR_TYPE_MINUS, yymsp[0].minor.yy70); yy_destructor(yypParser,96,&yymsp[-1].minor); +} +#line 3161 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 150: /* expr ::= PLUS expr */ +#line 819 "../libgda/sql-parser/parser.y" +{yygotominor.yy70 = create_uni_expr (GDA_SQL_OPERATOR_TYPE_PLUS, yymsp[0].minor.yy70); yy_destructor(yypParser,95,&yymsp[-1].minor); +} +#line 3167 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 151: /* expr ::= expr AND expr */ +#line 821 "../libgda/sql-parser/parser.y" +{yygotominor.yy70 = compose_multiple_expr (GDA_SQL_OPERATOR_TYPE_AND, yymsp[-2].minor.yy70, yymsp[0].minor.yy70); yy_destructor(yypParser,70,&yymsp[-1].minor); +} +#line 3173 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 152: /* expr ::= expr OR expr */ +#line 822 "../libgda/sql-parser/parser.y" +{yygotominor.yy70 = compose_multiple_expr (GDA_SQL_OPERATOR_TYPE_OR, yymsp[-2].minor.yy70, yymsp[0].minor.yy70); yy_destructor(yypParser,69,&yymsp[-1].minor); +} +#line 3179 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 153: /* expr ::= expr CONCAT expr */ +#line 823 "../libgda/sql-parser/parser.y" +{yygotominor.yy70 = compose_multiple_expr (GDA_SQL_OPERATOR_TYPE_CONCAT, yymsp[-2].minor.yy70, yymsp[0].minor.yy70); yy_destructor(yypParser,100,&yymsp[-1].minor); +} +#line 3185 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 156: /* expr ::= expr LIKE expr */ +#line 827 "../libgda/sql-parser/parser.y" +{yygotominor.yy70 = create_two_expr (GDA_SQL_OPERATOR_TYPE_LIKE, yymsp[-2].minor.yy70, yymsp[0].minor.yy70); yy_destructor(yypParser,26,&yymsp[-1].minor); +} +#line 3191 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 157: /* expr ::= expr ILIKE expr */ +#line 828 "../libgda/sql-parser/parser.y" +{yygotominor.yy70 = create_two_expr (GDA_SQL_OPERATOR_TYPE_ILIKE, yymsp[-2].minor.yy70, yymsp[0].minor.yy70); yy_destructor(yypParser,27,&yymsp[-1].minor); +} +#line 3197 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 158: /* expr ::= expr NOTLIKE expr */ +#line 829 "../libgda/sql-parser/parser.y" +{yygotominor.yy70 = create_two_expr (GDA_SQL_OPERATOR_TYPE_NOTLIKE, yymsp[-2].minor.yy70, yymsp[0].minor.yy70); yy_destructor(yypParser,73,&yymsp[-1].minor); +} +#line 3203 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 159: /* expr ::= expr NOTILIKE expr */ +#line 830 "../libgda/sql-parser/parser.y" +{yygotominor.yy70 = create_two_expr (GDA_SQL_OPERATOR_TYPE_NOTILIKE, yymsp[-2].minor.yy70, yymsp[0].minor.yy70); yy_destructor(yypParser,74,&yymsp[-1].minor); +} +#line 3209 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 161: /* expr ::= expr BETWEEN expr AND expr */ +#line 832 "../libgda/sql-parser/parser.y" +{GdaSqlOperation *cond; + yygotominor.yy70 = gda_sql_expr_new (NULL); + cond = gda_sql_operation_new (GDA_SQL_ANY_PART (yygotominor.yy70)); + yygotominor.yy70->cond = cond; + cond->operator_type = GDA_SQL_OPERATOR_TYPE_BETWEEN; + cond->operands = g_slist_append (NULL, yymsp[-4].minor.yy70); + GDA_SQL_ANY_PART (yymsp[-4].minor.yy70)->parent = GDA_SQL_ANY_PART (cond); + cond->operands = g_slist_append (cond->operands, yymsp[-2].minor.yy70); + GDA_SQL_ANY_PART (yymsp[-2].minor.yy70)->parent = GDA_SQL_ANY_PART (cond); + cond->operands = g_slist_append (cond->operands, yymsp[0].minor.yy70); + GDA_SQL_ANY_PART (yymsp[0].minor.yy70)->parent = GDA_SQL_ANY_PART (cond); + yy_destructor(yypParser,80,&yymsp[-3].minor); + yy_destructor(yypParser,70,&yymsp[-1].minor); +} +#line 3227 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 162: /* expr ::= expr NOT BETWEEN expr AND expr */ +#line 845 "../libgda/sql-parser/parser.y" +{GdaSqlOperation *cond; + GdaSqlExpr *expr; + expr = gda_sql_expr_new (NULL); + cond = gda_sql_operation_new (GDA_SQL_ANY_PART (expr)); + expr->cond = cond; + cond->operator_type = GDA_SQL_OPERATOR_TYPE_BETWEEN; + cond->operands = g_slist_append (NULL, yymsp[-5].minor.yy70); + GDA_SQL_ANY_PART (yymsp[-5].minor.yy70)->parent = GDA_SQL_ANY_PART (cond); + cond->operands = g_slist_append (cond->operands, yymsp[-2].minor.yy70); + GDA_SQL_ANY_PART (yymsp[-2].minor.yy70)->parent = GDA_SQL_ANY_PART (cond); + cond->operands = g_slist_append (cond->operands, yymsp[0].minor.yy70); + GDA_SQL_ANY_PART (yymsp[0].minor.yy70)->parent = GDA_SQL_ANY_PART (cond); + + yygotominor.yy70 = gda_sql_expr_new (NULL); + cond = gda_sql_operation_new (GDA_SQL_ANY_PART (yygotominor.yy70)); + yygotominor.yy70->cond = cond; + cond->operator_type = GDA_SQL_OPERATOR_TYPE_NOT; + cond->operands = g_slist_prepend (NULL, expr); + GDA_SQL_ANY_PART (expr)->parent = GDA_SQL_ANY_PART (cond); + yy_destructor(yypParser,71,&yymsp[-4].minor); + yy_destructor(yypParser,80,&yymsp[-3].minor); + yy_destructor(yypParser,70,&yymsp[-1].minor); +} +#line 3254 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 163: /* expr ::= NOT expr */ +#line 866 "../libgda/sql-parser/parser.y" +{yygotominor.yy70 = create_uni_expr (GDA_SQL_OPERATOR_TYPE_NOT, yymsp[0].minor.yy70); yy_destructor(yypParser,71,&yymsp[-1].minor); +} +#line 3260 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 164: /* expr ::= BITNOT expr */ +#line 867 "../libgda/sql-parser/parser.y" +{yygotominor.yy70 = create_uni_expr (GDA_SQL_OPERATOR_TYPE_BITNOT, yymsp[0].minor.yy70); yy_destructor(yypParser,104,&yymsp[-1].minor); +} +#line 3266 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 165: /* expr ::= expr uni_op */ +#line 868 "../libgda/sql-parser/parser.y" +{yygotominor.yy70 = create_uni_expr (yymsp[0].minor.yy147, yymsp[-1].minor.yy70);} +#line 3271 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 166: /* expr ::= expr IS expr */ +#line 870 "../libgda/sql-parser/parser.y" +{yygotominor.yy70 = create_two_expr (GDA_SQL_OPERATOR_TYPE_IS, yymsp[-2].minor.yy70, yymsp[0].minor.yy70); yy_destructor(yypParser,72,&yymsp[-1].minor); +} +#line 3277 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 167: /* expr ::= LP compound RP */ +#line 871 "../libgda/sql-parser/parser.y" +{yygotominor.yy70 = gda_sql_expr_new (NULL); gda_sql_expr_take_select (yygotominor.yy70, yymsp[-1].minor.yy116); yy_destructor(yypParser,105,&yymsp[-2].minor); + yy_destructor(yypParser,106,&yymsp[0].minor); +} +#line 3284 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 168: /* expr ::= expr IN LP rexprlist RP */ +#line 872 "../libgda/sql-parser/parser.y" +{GdaSqlOperation *cond; + GSList *list; + yygotominor.yy70 = gda_sql_expr_new (NULL); + cond = gda_sql_operation_new (GDA_SQL_ANY_PART (yygotominor.yy70)); + yygotominor.yy70->cond = cond; + cond->operator_type = GDA_SQL_OPERATOR_TYPE_IN; + cond->operands = g_slist_prepend (g_slist_reverse (yymsp[-1].minor.yy325), yymsp[-4].minor.yy70); + for (list = cond->operands; list; list = list->next) + GDA_SQL_ANY_PART (list->data)->parent = GDA_SQL_ANY_PART (cond); + yy_destructor(yypParser,75,&yymsp[-3].minor); + yy_destructor(yypParser,105,&yymsp[-2].minor); + yy_destructor(yypParser,106,&yymsp[0].minor); +} +#line 3301 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 169: /* expr ::= expr IN LP compound RP */ +#line 882 "../libgda/sql-parser/parser.y" +{GdaSqlOperation *cond; + GdaSqlExpr *expr; + yygotominor.yy70 = gda_sql_expr_new (NULL); + cond = gda_sql_operation_new (GDA_SQL_ANY_PART (yygotominor.yy70)); + yygotominor.yy70->cond = cond; + cond->operator_type = GDA_SQL_OPERATOR_TYPE_IN; + + expr = gda_sql_expr_new (GDA_SQL_ANY_PART (cond)); + gda_sql_expr_take_select (expr, yymsp[-1].minor.yy116); + cond->operands = g_slist_prepend (NULL, expr); + cond->operands = g_slist_prepend (cond->operands, yymsp[-4].minor.yy70); + GDA_SQL_ANY_PART (yymsp[-4].minor.yy70)->parent = GDA_SQL_ANY_PART (cond); + yy_destructor(yypParser,75,&yymsp[-3].minor); + yy_destructor(yypParser,105,&yymsp[-2].minor); + yy_destructor(yypParser,106,&yymsp[0].minor); +} +#line 3321 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 170: /* expr ::= expr NOT IN LP rexprlist RP */ +#line 895 "../libgda/sql-parser/parser.y" +{GdaSqlOperation *cond; + GSList *list; + yygotominor.yy70 = gda_sql_expr_new (NULL); + cond = gda_sql_operation_new (GDA_SQL_ANY_PART (yygotominor.yy70)); + yygotominor.yy70->cond = cond; + cond->operator_type = GDA_SQL_OPERATOR_TYPE_NOTIN; + cond->operands = g_slist_prepend (g_slist_reverse (yymsp[-1].minor.yy325), yymsp[-5].minor.yy70); + for (list = cond->operands; list; list = list->next) + GDA_SQL_ANY_PART (list->data)->parent = GDA_SQL_ANY_PART (cond); + yy_destructor(yypParser,71,&yymsp[-4].minor); + yy_destructor(yypParser,75,&yymsp[-3].minor); + yy_destructor(yypParser,105,&yymsp[-2].minor); + yy_destructor(yypParser,106,&yymsp[0].minor); +} +#line 3339 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 171: /* expr ::= expr NOT IN LP compound RP */ +#line 905 "../libgda/sql-parser/parser.y" +{GdaSqlOperation *cond; + GdaSqlExpr *expr; + yygotominor.yy70 = gda_sql_expr_new (NULL); + cond = gda_sql_operation_new (GDA_SQL_ANY_PART (yygotominor.yy70)); + yygotominor.yy70->cond = cond; + cond->operator_type = GDA_SQL_OPERATOR_TYPE_NOTIN; + + expr = gda_sql_expr_new (GDA_SQL_ANY_PART (cond)); + gda_sql_expr_take_select (expr, yymsp[-1].minor.yy116); + cond->operands = g_slist_prepend (NULL, expr); + cond->operands = g_slist_prepend (cond->operands, yymsp[-5].minor.yy70); + GDA_SQL_ANY_PART (yymsp[-5].minor.yy70)->parent = GDA_SQL_ANY_PART (cond); + yy_destructor(yypParser,71,&yymsp[-4].minor); + yy_destructor(yypParser,75,&yymsp[-3].minor); + yy_destructor(yypParser,105,&yymsp[-2].minor); + yy_destructor(yypParser,106,&yymsp[0].minor); +} +#line 3360 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 172: /* expr ::= CASE case_operand case_exprlist case_else END */ +#line 918 "../libgda/sql-parser/parser.y" +{ + GdaSqlCase *sc; + GSList *list; + yygotominor.yy70 = gda_sql_expr_new (NULL); + sc = gda_sql_case_new (GDA_SQL_ANY_PART (yygotominor.yy70)); + sc->base_expr = yymsp[-3].minor.yy146; + sc->else_expr = yymsp[-1].minor.yy146; + sc->when_expr_list = yymsp[-2].minor.yy59.when_list; + sc->then_expr_list = yymsp[-2].minor.yy59.then_list; + yygotominor.yy70->case_s = sc; + for (list = sc->when_expr_list; list; list = list->next) + GDA_SQL_ANY_PART (list->data)->parent = GDA_SQL_ANY_PART (sc); + for (list = sc->then_expr_list; list; list = list->next) + GDA_SQL_ANY_PART (list->data)->parent = GDA_SQL_ANY_PART (sc); + yy_destructor(yypParser,147,&yymsp[-4].minor); + yy_destructor(yypParser,17,&yymsp[0].minor); +} +#line 3381 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 173: /* case_operand ::= expr */ +#line 936 "../libgda/sql-parser/parser.y" +{yygotominor.yy146 = yymsp[0].minor.yy70;} +#line 3386 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 174: /* case_operand ::= */ + case 178: /* case_else ::= */ yytestcase(yyruleno==178); +#line 937 "../libgda/sql-parser/parser.y" +{yygotominor.yy146 = NULL;} +#line 3392 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 175: /* case_exprlist ::= case_exprlist WHEN expr THEN expr */ +#line 943 "../libgda/sql-parser/parser.y" +{ + yygotominor.yy59.when_list = g_slist_append (yymsp[-4].minor.yy59.when_list, yymsp[-2].minor.yy70); + yygotominor.yy59.then_list = g_slist_append (yymsp[-4].minor.yy59.then_list, yymsp[0].minor.yy70); + yy_destructor(yypParser,148,&yymsp[-3].minor); + yy_destructor(yypParser,149,&yymsp[-1].minor); +} +#line 3402 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 176: /* case_exprlist ::= WHEN expr THEN expr */ +#line 947 "../libgda/sql-parser/parser.y" +{ + yygotominor.yy59.when_list = g_slist_prepend (NULL, yymsp[-2].minor.yy70); + yygotominor.yy59.then_list = g_slist_prepend (NULL, yymsp[0].minor.yy70); + yy_destructor(yypParser,148,&yymsp[-3].minor); + yy_destructor(yypParser,149,&yymsp[-1].minor); +} +#line 3412 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 177: /* case_else ::= ELSE expr */ +#line 954 "../libgda/sql-parser/parser.y" +{yygotominor.yy146 = yymsp[0].minor.yy70; yy_destructor(yypParser,150,&yymsp[-1].minor); +} +#line 3418 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 179: /* uni_op ::= ISNULL */ +#line 958 "../libgda/sql-parser/parser.y" +{yygotominor.yy147 = GDA_SQL_OPERATOR_TYPE_ISNULL; yy_destructor(yypParser,76,&yymsp[0].minor); +} +#line 3424 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 180: /* uni_op ::= IS NOTNULL */ +#line 959 "../libgda/sql-parser/parser.y" +{yygotominor.yy147 = GDA_SQL_OPERATOR_TYPE_ISNOTNULL; yy_destructor(yypParser,72,&yymsp[-1].minor); + yy_destructor(yypParser,77,&yymsp[0].minor); +} +#line 3431 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 181: /* value ::= NULL */ +#line 963 "../libgda/sql-parser/parser.y" +{yygotominor.yy0 = NULL; yy_destructor(yypParser,151,&yymsp[0].minor); +} +#line 3437 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 185: /* pvalue ::= UNSPECVAL LSBRACKET paramspec RSBRACKET */ +#line 972 "../libgda/sql-parser/parser.y" +{yygotominor.yy70 = gda_sql_expr_new (NULL); yygotominor.yy70->param_spec = yymsp[-1].minor.yy339; yy_destructor(yypParser,153,&yymsp[-3].minor); + yy_destructor(yypParser,154,&yymsp[-2].minor); + yy_destructor(yypParser,155,&yymsp[0].minor); +} +#line 3445 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 186: /* pvalue ::= value LSBRACKET paramspec RSBRACKET */ +#line 973 "../libgda/sql-parser/parser.y" +{yygotominor.yy70 = gda_sql_expr_new (NULL); yygotominor.yy70->value = yymsp[-3].minor.yy0; yygotominor.yy70->param_spec = yymsp[-1].minor.yy339; yy_destructor(yypParser,154,&yymsp[-2].minor); + yy_destructor(yypParser,155,&yymsp[0].minor); +} +#line 3452 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 187: /* pvalue ::= SIMPLEPARAM */ +#line 974 "../libgda/sql-parser/parser.y" +{yygotominor.yy70 = gda_sql_expr_new (NULL); yygotominor.yy70->param_spec = gda_sql_param_spec_new (yymsp[0].minor.yy0);} +#line 3457 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 188: /* paramspec ::= */ +#line 979 "../libgda/sql-parser/parser.y" +{yygotominor.yy339 = NULL;} +#line 3462 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 189: /* paramspec ::= paramspec PNAME */ +#line 980 "../libgda/sql-parser/parser.y" +{if (!yymsp[-1].minor.yy339) yygotominor.yy339 = gda_sql_param_spec_new (NULL); else yygotominor.yy339 = yymsp[-1].minor.yy339; + gda_sql_param_spec_take_name (yygotominor.yy339, yymsp[0].minor.yy0);} +#line 3468 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 190: /* paramspec ::= paramspec PDESCR */ +#line 982 "../libgda/sql-parser/parser.y" +{if (!yymsp[-1].minor.yy339) yygotominor.yy339 = gda_sql_param_spec_new (NULL); else yygotominor.yy339 = yymsp[-1].minor.yy339; + gda_sql_param_spec_take_descr (yygotominor.yy339, yymsp[0].minor.yy0);} +#line 3474 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 191: /* paramspec ::= paramspec PTYPE */ +#line 984 "../libgda/sql-parser/parser.y" +{if (!yymsp[-1].minor.yy339) yygotominor.yy339 = gda_sql_param_spec_new (NULL); else yygotominor.yy339 = yymsp[-1].minor.yy339; + gda_sql_param_spec_take_type (yygotominor.yy339, yymsp[0].minor.yy0);} +#line 3480 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + case 192: /* paramspec ::= paramspec PNULLOK */ +#line 986 "../libgda/sql-parser/parser.y" +{if (!yymsp[-1].minor.yy339) yygotominor.yy339 = gda_sql_param_spec_new (NULL); else yygotominor.yy339 = yymsp[-1].minor.yy339; + gda_sql_param_spec_take_nullok (yygotominor.yy339, yymsp[0].minor.yy0);} +#line 3486 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + break; + default: + /* (34) trans_opt_kw ::= */ yytestcase(yyruleno==34); + /* (36) opt_comma ::= */ yytestcase(yyruleno==36); + break; + }; + yygoto = yyRuleInfo[yyruleno].lhs; + yysize = yyRuleInfo[yyruleno].nrhs; + yypParser->yyidx -= yysize; + yyact = yy_find_reduce_action(yymsp[-yysize].stateno,(YYCODETYPE)yygoto); + if( yyact < YYNSTATE ){ +#ifdef NDEBUG + /* If we are not debugging and the reduce action popped at least + ** one element off the stack, then we can push the new element back + ** onto the stack here, and skip the stack overflow test in yy_shift(). + ** That gives a significant speed improvement. */ + if( yysize ){ + yypParser->yyidx++; + yymsp -= yysize-1; + yymsp->stateno = (YYACTIONTYPE)yyact; + yymsp->major = (YYCODETYPE)yygoto; + yymsp->minor = yygotominor; + }else +#endif + { + yy_shift(yypParser,yyact,yygoto,&yygotominor); + } + }else{ + assert( yyact == YYNSTATE + YYNRULE + 1 ); + yy_accept(yypParser); + } +} + +/* +** The following code executes when the parse fails +*/ +#ifndef YYNOERRORRECOVERY +static void yy_parse_failed( + yyParser *yypParser /* The parser */ +){ + priv_gda_sql_parserARG_FETCH; +#ifndef NDEBUG + if( yyTraceFILE ){ + fprintf(yyTraceFILE,"%sFail!\n",yyTracePrompt); + } +#endif + while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser); + /* Here code is inserted which will be executed whenever the + ** parser fails */ + priv_gda_sql_parserARG_STORE; /* Suppress warning about unused %extra_argument variable */ +} +#endif /* YYNOERRORRECOVERY */ + +/* +** The following code executes when a syntax error first occurs. +*/ +static void yy_syntax_error( + yyParser *yypParser, /* The parser */ + int yymajor, /* The major type of the error token */ + YYMINORTYPE yyminor /* The minor type of the error token */ +){ + priv_gda_sql_parserARG_FETCH; +#define TOKEN (yyminor.yy0) +#line 22 "../libgda/sql-parser/parser.y" + + gda_sql_parser_set_syntax_error (pdata->parser); +#line 3553 "/run/build/libgda/_flatpak_build/libgda/sql-parser/parser.c" + priv_gda_sql_parserARG_STORE; /* Suppress warning about unused %extra_argument variable */ +} + +/* +** The following is executed when the parser accepts +*/ +static void yy_accept( + yyParser *yypParser /* The parser */ +){ + priv_gda_sql_parserARG_FETCH; +#ifndef NDEBUG + if( yyTraceFILE ){ + fprintf(yyTraceFILE,"%sAccept!\n",yyTracePrompt); + } +#endif + while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser); + /* Here code is inserted which will be executed whenever the + ** parser accepts */ + priv_gda_sql_parserARG_STORE; /* Suppress warning about unused %extra_argument variable */ +} + +/* The main parser program. +** The first argument is a pointer to a structure obtained from +** "priv_gda_sql_parserAlloc" which describes the current state of the parser. +** The second argument is the major token number. The third is +** the minor token. The fourth optional argument is whatever the +** user wants (and specified in the grammar) and is available for +** use by the action routines. +** +** Inputs: +**
    +**
  • A pointer to the parser (an opaque structure.) +**
  • The major token number. +**
  • The minor token number. +**
  • An option argument of a grammar-specified type. +**
+** +** Outputs: +** None. +*/ +void priv_gda_sql_parser( + void *yyp, /* The parser */ + int yymajor, /* The major token code number */ + priv_gda_sql_parserTOKENTYPE yyminor /* The value for the token */ + priv_gda_sql_parserARG_PDECL /* Optional %extra_argument parameter */ +){ + YYMINORTYPE yyminorunion; + int yyact; /* The parser action. */ + int yyendofinput; /* True if we are at the end of input */ +#ifdef YYERRORSYMBOL + int yyerrorhit = 0; /* True if yymajor has invoked an error */ +#endif + yyParser *yypParser; /* The parser */ + + /* (re)initialize the parser, if necessary */ + yypParser = (yyParser*)yyp; + if( yypParser->yyidx<0 ){ +#if YYSTACKDEPTH<=0 + if( yypParser->yystksz <=0 ){ + /*memset(&yyminorunion, 0, sizeof(yyminorunion));*/ + yyminorunion = yyzerominor; + yyStackOverflow(yypParser, &yyminorunion); + return; + } +#endif + yypParser->yyidx = 0; + yypParser->yyerrcnt = -1; + yypParser->yystack[0].stateno = 0; + yypParser->yystack[0].major = 0; + } + yyminorunion.yy0 = yyminor; + yyendofinput = (yymajor==0); + priv_gda_sql_parserARG_STORE; + +#ifndef NDEBUG + if( yyTraceFILE ){ + fprintf(yyTraceFILE,"%sInput %s\n",yyTracePrompt,yyTokenName[yymajor]); + } +#endif + + do{ + yyact = yy_find_shift_action(yypParser,(YYCODETYPE)yymajor); + if( yyactyyerrcnt--; + yymajor = YYNOCODE; + }else if( yyact < YYNSTATE + YYNRULE ){ + yy_reduce(yypParser,yyact-YYNSTATE); + }else{ + assert( yyact == YY_ERROR_ACTION ); +#ifdef YYERRORSYMBOL + int yymx; +#endif +#ifndef NDEBUG + if( yyTraceFILE ){ + fprintf(yyTraceFILE,"%sSyntax Error!\n",yyTracePrompt); + } +#endif +#ifdef YYERRORSYMBOL + /* A syntax error has occurred. + ** The response to an error depends upon whether or not the + ** grammar defines an error token "ERROR". + ** + ** This is what we do if the grammar does define ERROR: + ** + ** * Call the %syntax_error function. + ** + ** * Begin popping the stack until we enter a state where + ** it is legal to shift the error symbol, then shift + ** the error symbol. + ** + ** * Set the error count to three. + ** + ** * Begin accepting and shifting new tokens. No new error + ** processing will occur until three tokens have been + ** shifted successfully. + ** + */ + if( yypParser->yyerrcnt<0 ){ + yy_syntax_error(yypParser,yymajor,yyminorunion); + } + yymx = yypParser->yystack[yypParser->yyidx].major; + if( yymx==YYERRORSYMBOL || yyerrorhit ){ +#ifndef NDEBUG + if( yyTraceFILE ){ + fprintf(yyTraceFILE,"%sDiscard input token %s\n", + yyTracePrompt,yyTokenName[yymajor]); + } +#endif + yy_destructor(yypParser, (YYCODETYPE)yymajor,&yyminorunion); + yymajor = YYNOCODE; + }else{ + while( + yypParser->yyidx >= 0 && + yymx != YYERRORSYMBOL && + (yyact = yy_find_reduce_action( + yypParser->yystack[yypParser->yyidx].stateno, + YYERRORSYMBOL)) >= YYNSTATE + ){ + yy_pop_parser_stack(yypParser); + } + if( yypParser->yyidx < 0 || yymajor==0 ){ + yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion); + yy_parse_failed(yypParser); + yymajor = YYNOCODE; + }else if( yymx!=YYERRORSYMBOL ){ + YYMINORTYPE u2; + u2.YYERRSYMDT = 0; + yy_shift(yypParser,yyact,YYERRORSYMBOL,&u2); + } + } + yypParser->yyerrcnt = 3; + yyerrorhit = 1; +#elif defined(YYNOERRORRECOVERY) + /* If the YYNOERRORRECOVERY macro is defined, then do not attempt to + ** do any kind of error recovery. Instead, simply invoke the syntax + ** error routine and continue going as if nothing had happened. + ** + ** Applications can set this macro (for example inside %include) if + ** they intend to abandon the parse upon the first syntax error seen. + */ + yy_syntax_error(yypParser,yymajor,yyminorunion); + yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion); + yymajor = YYNOCODE; + +#else /* YYERRORSYMBOL is not defined */ + /* This is what we do if the grammar does not define ERROR: + ** + ** * Report an error message, and throw away the input token. + ** + ** * If the input token is $, then fail the parse. + ** + ** As before, subsequent error messages are suppressed until + ** three input tokens have been successfully shifted. + */ + if( yypParser->yyerrcnt<=0 ){ + yy_syntax_error(yypParser,yymajor,yyminorunion); + } + yypParser->yyerrcnt = 3; + yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion); + if( yyendofinput ){ + yy_parse_failed(yypParser); + } + yymajor = YYNOCODE; +#endif + } + }while( yymajor!=YYNOCODE && yypParser->yyidx>=0 ); + return; +} diff --git a/.flatpak-builder/cache/objects/f8/12aea78c14ed80c7804493f6b4b2fcd40af37c3016d85b75ed120a6c5ceadf.file b/.flatpak-builder/cache/objects/f8/12aea78c14ed80c7804493f6b4b2fcd40af37c3016d85b75ed120a6c5ceadf.file new file mode 100644 index 0000000..e362bab Binary files /dev/null and b/.flatpak-builder/cache/objects/f8/12aea78c14ed80c7804493f6b4b2fcd40af37c3016d85b75ed120a6c5ceadf.file differ diff --git a/.flatpak-builder/cache/objects/f8/ff2db4592fd9c73e731ad3f513cd80aa378991d7ca04009468c78ab0cc302d.commit b/.flatpak-builder/cache/objects/f8/ff2db4592fd9c73e731ad3f513cd80aa378991d7ca04009468c78ab0cc302d.commit new file mode 100644 index 0000000..d55208b Binary files /dev/null and b/.flatpak-builder/cache/objects/f8/ff2db4592fd9c73e731ad3f513cd80aa378991d7ca04009468c78ab0cc302d.commit differ diff --git a/.flatpak-builder/cache/objects/f9/5041b0292a0d4dbd0e8ecb971f9404661731dde2958bd977c369dd96f4e617.dirtree b/.flatpak-builder/cache/objects/f9/5041b0292a0d4dbd0e8ecb971f9404661731dde2958bd977c369dd96f4e617.dirtree new file mode 100644 index 0000000..f68fce0 Binary files /dev/null and b/.flatpak-builder/cache/objects/f9/5041b0292a0d4dbd0e8ecb971f9404661731dde2958bd977c369dd96f4e617.dirtree differ diff --git a/.flatpak-builder/cache/objects/f9/6ae4d771275ac3550c2dcf153a4f85050c5353e99eedc9bf3421ec985aa949.dirtree b/.flatpak-builder/cache/objects/f9/6ae4d771275ac3550c2dcf153a4f85050c5353e99eedc9bf3421ec985aa949.dirtree new file mode 100644 index 0000000..50b07e1 Binary files /dev/null and b/.flatpak-builder/cache/objects/f9/6ae4d771275ac3550c2dcf153a4f85050c5353e99eedc9bf3421ec985aa949.dirtree differ diff --git a/.flatpak-builder/cache/objects/f9/7e3beea58ef5dbba4c6347d8f07c13805f5a350988b1ce59fc5c03f7d082a5.file b/.flatpak-builder/cache/objects/f9/7e3beea58ef5dbba4c6347d8f07c13805f5a350988b1ce59fc5c03f7d082a5.file new file mode 100644 index 0000000..f7b212f --- /dev/null +++ b/.flatpak-builder/cache/objects/f9/7e3beea58ef5dbba4c6347d8f07c13805f5a350988b1ce59fc5c03f7d082a5.file @@ -0,0 +1,1136 @@ +/* gda-db-catalog.c + * + * Copyright (C) 2018-2019 Pavlo Solntsev + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#define G_LOG_DOMAIN "GDA-db-catalog" + +#include "gda-db-catalog.h" +#include "gda-db-table.h" +#include "gda-db-view.h" +#include "gda-db-fkey.h" +#include "gda-db-column-private.h" +#include "gda-db-fkey-private.h" +#include +#include +#include +#include +#include +#include + +#include "gda-server-provider.h" +#include +#include "gda-meta-struct.h" +#include "gda-ddl-modifiable.h" + +G_DEFINE_QUARK (gda_db_catalog_error, gda_db_catalog_error) + +typedef struct +{ + GList *mp_tables; /* List of all tables that should be create, GdaDbTable */ + GList *mp_views; /* List of all views that should be created, GdaDbView */ + gchar *mp_schemaname; + GdaConnection *cnc; +} GdaDbCatalogPrivate; + +/** + * SECTION:gda-db-catalog + * @title: GdaDbCatalog + * @short_description: Object to constract database representation from an xml file or by reading + * the existing datatabase + * @see_also: #GdaDbTable, #GdaDbView + * @stability: Stable + * @include: libgda/libgda.h + * + * This is a main object that represents overall database. The best way to create an instance of + * #GdaDbCatalog is to call gda_connection_create_db_catalog(). This object may be also constracted + * from an xml file using gda_db_catalog_parse_file() or gda_db_catalog_parse_file_from_path() or + * didrectly from the open connection using gda_db_catalog_parse_cnc(). + * + * The database can be updated or modified using gda_db_catalog_perform_operation() and dumped to + * a file using gda_db_catalog_write_to_path() or gda_db_catalog_write_to_file(). + * + */ + +G_DEFINE_TYPE_WITH_PRIVATE (GdaDbCatalog, gda_db_catalog, G_TYPE_OBJECT) + +enum { + PROP_0, + PROP_SCHEMA_NAME, + PROP_CNC, + /**/ + N_PROPS +}; + +static GParamSpec *properties [N_PROPS] = {NULL}; + +/** + * gda_db_catalog_new: + * + * Create new instance of #GdaDbCatalog. + * + * Returns: a new instance of #GdaDbCatalog + * + * Since: 6.0 + */ +GdaDbCatalog* +gda_db_catalog_new (void) +{ + return g_object_new (GDA_TYPE_DB_CATALOG, NULL); +} + +static void +gda_db_catalog_finalize (GObject *object) +{ + GdaDbCatalog *self = GDA_DB_CATALOG(object); + GdaDbCatalogPrivate *priv = gda_db_catalog_get_instance_private (self); + + g_free (priv->mp_schemaname); + + G_OBJECT_CLASS (gda_db_catalog_parent_class)->finalize (object); +} + +static void +gda_db_catalog_dispose (GObject *object) +{ + GdaDbCatalog *self = GDA_DB_CATALOG(object); + GdaDbCatalogPrivate *priv = gda_db_catalog_get_instance_private (self); + + if (priv->mp_tables) + g_list_free_full (priv->mp_tables, (GDestroyNotify) g_object_unref); + + if (priv->mp_views) + g_list_free_full (priv->mp_views, (GDestroyNotify) g_object_unref); + + if (priv->cnc) + g_object_unref (priv->cnc); + + G_OBJECT_CLASS (gda_db_catalog_parent_class)->dispose (object); +} + +static void +gda_db_catalog_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + GdaDbCatalog *self = GDA_DB_CATALOG (object); + GdaDbCatalogPrivate *priv = gda_db_catalog_get_instance_private (self); + + switch (prop_id) + { + case PROP_SCHEMA_NAME: + g_value_set_string (value, priv->mp_schemaname); + break; + case PROP_CNC: + g_value_set_object (value, G_OBJECT(priv->cnc)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +gda_db_catalog_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + GdaDbCatalog *self = GDA_DB_CATALOG (object); + GdaDbCatalogPrivate *priv = gda_db_catalog_get_instance_private (self); + + switch (prop_id) + { + case PROP_SCHEMA_NAME: + g_free(priv->mp_schemaname); + priv->mp_schemaname = g_value_dup_string (value); + break; + case PROP_CNC: + if (priv->cnc) + g_object_unref (priv->cnc); + + priv->cnc = GDA_CONNECTION (g_object_ref (G_OBJECT (g_value_get_object (value)))); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +gda_db_catalog_class_init (GdaDbCatalogClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->finalize = gda_db_catalog_finalize; + object_class->dispose = gda_db_catalog_dispose; + object_class->get_property = gda_db_catalog_get_property; + object_class->set_property = gda_db_catalog_set_property; + + properties[PROP_SCHEMA_NAME] = + g_param_spec_string ("schema_name", + "schema-name", + "Name of the schema", + NULL, + G_PARAM_READWRITE); + + properties[PROP_CNC] = + g_param_spec_object ("connection", + "Connection", + "Connection to use", + GDA_TYPE_CONNECTION, + G_PARAM_READWRITE); + + g_object_class_install_properties (object_class,N_PROPS,properties); +} + +static void +gda_db_catalog_init (GdaDbCatalog *self) +{ + GdaDbCatalogPrivate *priv = gda_db_catalog_get_instance_private (self); + + priv->mp_tables = NULL; + priv->mp_views = NULL; + priv->mp_schemaname = NULL; + priv->cnc = NULL; +} + +xmlDtdPtr +_gda_db_catalog_get_dtd () +{ + xmlDtdPtr _gda_db_catalog_dtd = NULL; + gchar *file; + /* GdaDbCreator DTD */ + file = gda_gbr_get_file_path (GDA_DATA_DIR, LIBGDA_ABI_NAME, "dtd", + "libgda-db-catalog.dtd", NULL); + if (g_file_test (file, G_FILE_TEST_EXISTS)) { + _gda_db_catalog_dtd = xmlParseDTD (NULL, (xmlChar*)file); + } else { + const gchar *gdatopsrcdir = g_getenv ("GDA_TOP_SRC_DIR"); + if (gdatopsrcdir) + { + g_free (file); + file = g_build_filename (gdatopsrcdir, "libgda", + "libgda-db-catalog.dtd", NULL); + _gda_db_catalog_dtd = xmlParseDTD (NULL, (xmlChar*)file); + } + } + + if (_gda_db_catalog_dtd != NULL) { + _gda_db_catalog_dtd->name = xmlStrdup((xmlChar*) "db-catalog"); + } else { + g_message (_("Could not parse '%s': " + "Validation for XML files for GdaDbCreator will not be performed (some weird errors may occur)"), + file); + } + + g_free (file); + return _gda_db_catalog_dtd; +} + +static gboolean +_gda_db_catalog_validate_doc (xmlDocPtr doc, + GError **error) +{ + g_return_val_if_fail (doc, FALSE); + + xmlValidCtxtPtr ctx = NULL; + + ctx = xmlNewValidCtxt (); + + if (!ctx) + { + g_set_error (error, + GDA_DB_CATALOG_ERROR, + GDA_DB_CATALOG_CONTEXT_NULL, + _("Context to validate xml file can't be created.")); + goto on_error; + } + + xmlDtdPtr _gda_db_catalog_dtd = _gda_db_catalog_get_dtd (); + + int valid = 0; + + if (_gda_db_catalog_dtd != NULL) { + valid = xmlValidateDtd (ctx, doc,_gda_db_catalog_dtd); + xmlFreeDtd (_gda_db_catalog_dtd); + } + + if (!valid) + { + g_set_error (error, + GDA_DB_CATALOG_ERROR, + GDA_DB_CATALOG_INVALID_XML, + _("xml file is invalid")); + goto on_error; + } + + xmlFreeValidCtxt (ctx); + return TRUE; + +on_error: + if (ctx) xmlFreeValidCtxt (ctx); + return FALSE; +} + +/** + * _gda_db_catalog_parse_doc: + * @self: a #GdaDbCatalog instance + * @doc: a #xmlDocPtr instance to parse + * @error: error container + * + * Internal method to populate #GdaDbCatalog from @doc instance. + * + * Returns: %TRUE if no errors, %FALSE otherwise. + * + */ +static gboolean +_gda_db_catalog_parse_doc (GdaDbCatalog *self, + xmlDocPtr doc, + GError **error) +{ + g_return_val_if_fail (self, FALSE); + g_return_val_if_fail (doc, FALSE); + + xmlChar *schema_name = NULL; + xmlNodePtr node = NULL; + + node = xmlDocGetRootElement (doc); + + if (!node || g_strcmp0 ((gchar *)node->name, "schema") != 0) + { + g_set_error (error, + GDA_DB_CATALOG_ERROR, + GDA_DB_CATALOG_INVALID_SCHEMA, + _("Root node should be .")); + goto on_error; + } + + GdaDbCatalogPrivate *priv = gda_db_catalog_get_instance_private (self); + + schema_name = xmlGetProp(node,(xmlChar *)"name"); +// g_assert (schema_name); /* If schema_name == NULL we have problem with validation */ + if (schema_name) + g_object_set (self, "schema_name", (char*)schema_name, NULL); + + xmlFree (schema_name); + + /* walk through the xmlDoc */ + for (node = node->children; node; node = node->next) + { + /* tag for table creation */ + if (!g_strcmp0 ((gchar *) node->name, "table")) + { + GdaDbTable *table; + table = gda_db_table_new (); + gda_db_base_set_schema (GDA_DB_BASE(table), priv->mp_schemaname); + + if (!gda_db_buildable_parse_node (GDA_DB_BUILDABLE(table), node, error)) + { + g_object_unref (table); + goto on_error; + } + else + priv->mp_tables = g_list_append (priv->mp_tables,table); + } + else if (!g_strcmp0 ((gchar *) node->name, "view")) + { + GdaDbView *view; + view = gda_db_view_new (); + gda_db_base_set_schema (GDA_DB_BASE(view), priv->mp_schemaname); + + if (!gda_db_buildable_parse_node (GDA_DB_BUILDABLE(view), node, error)) + { + g_object_unref (view); + goto on_error; + } + else + priv->mp_views = g_list_append (priv->mp_views, view); + } /* end of else if */ + } /* End of for loop */ + + xmlFree (node); + return TRUE; + +on_error: + if (node) xmlFree (node); + return FALSE; +} + +/** + * gda_db_catalog_parse_file_from_path: + * @self: an instance of #GdaDbCatalog + * @xmlfile: xml file to parse + * @error: Error container + * + * This method reads information from @xmlfile and populate @self object. + * The @xmlfile should correspond to the following DTD format: + * + * |[ + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * ]| + * + * Up to day description of the xml file schema can be found in DTD file + * [libgda-db-catalog.dtd](https://gitlab.gnome.org/GNOME/libgda/blob/master/libgda/libgda-db-catalog.dtd) + * + * The given @xmlfile will be checked before parsing and %FALSE will be + * returned if fails. The @xmlfile will be validated internally using + * gda_db_catalog_validate_file_from_path(). he same method can be used to validate xmlfile + * before parsing it. + */ +gboolean +gda_db_catalog_parse_file_from_path (GdaDbCatalog *self, + const gchar *xmlfile, + GError **error) +{ + g_return_val_if_fail (self,FALSE); + g_return_val_if_fail (xmlfile,FALSE); + + xmlDocPtr doc = NULL; + + doc = xmlParseFile (xmlfile); + + if (!doc) + { + g_set_error (error, + GDA_DB_CATALOG_ERROR, + GDA_DB_CATALOG_DOC_NULL, + _("xmlDoc object can't be created from xmfile name '%s'"), xmlfile); + goto on_error; + } + + if (!_gda_db_catalog_validate_doc (doc, error)) + { + g_set_error (error, + GDA_DB_CATALOG_ERROR, + GDA_DB_CATALOG_INVALID_XML, + _("xml file '%s' is not valid\n"), xmlfile); + goto on_error; + } + + if (!_gda_db_catalog_parse_doc (self, doc, error)) + goto on_error; + + xmlFreeDoc (doc); + return TRUE; + +on_error: + if (doc) xmlFreeDoc (doc); + + return FALSE; +} + +/** + * gda_db_catalog_validate_file_from_path: + * @xmlfile: xml file to validate + * @error: error container + * + * Convenient method to varify xmlfile before prsing it. + * + * Returns: %TRUE if @xmlfile is valid, %FALSE otherwise + * + * Since: 6.0 + */ +gboolean +gda_db_catalog_validate_file_from_path (const gchar *xmlfile, + GError **error) +{ + g_return_val_if_fail (xmlfile, FALSE); + + xmlDocPtr doc = NULL; + + doc = xmlParseFile(xmlfile); + + if (!doc) + { + g_set_error (error, + GDA_DB_CATALOG_ERROR, + GDA_DB_CATALOG_DOC_NULL, + _("xmlDoc object can't be created from xmfile name '%s'"), xmlfile); + goto on_error; + } + + if (!_gda_db_catalog_validate_doc (doc, error)) + goto on_error; + + xmlFreeDoc (doc); + + return TRUE; + +on_error: + if (doc) xmlFreeDoc (doc); + return FALSE; +} + +/** + * gda_db_catalog_get_tables: + * @self: a #GdaDbCatalog object + * + * Returns: (element-type Gda.DbTable) (transfer none): a list of tables as #GdaDbTable or %NULL. + * + * Since: 6.0 + */ +GList* +gda_db_catalog_get_tables (GdaDbCatalog *self) +{ + g_return_val_if_fail (self, NULL); + + GdaDbCatalogPrivate *priv = gda_db_catalog_get_instance_private (self); + return priv->mp_tables; +} + +/** + * gda_db_catalog_get_views: + * @self: a #GdaDbCatalog object + * + * Returns: (element-type Gda.DbView) (transfer none): a list of views as #GdaDbView or %NULL + * + * Since: 6.0 + */ +GList* +gda_db_catalog_get_views (GdaDbCatalog *self) +{ + g_return_val_if_fail (self, NULL); + + GdaDbCatalogPrivate *priv = gda_db_catalog_get_instance_private (self); + return priv->mp_views; +} + +/** + * gda_db_catalog_get_table: + * @self: a #GdaDbCatalog object + * @name: table name + * + * Convenient function to return a table based on name + * + * Returns: table as #GdaDbTable or %NULL + * + */ +const GdaDbTable* +gda_db_catalog_get_table (GdaDbCatalog *self, + const gchar *catalog, + const gchar *schema, + const gchar *name) +{ + g_return_val_if_fail (self, NULL); + g_return_val_if_fail (name, NULL); + + GdaDbCatalogPrivate *priv = gda_db_catalog_get_instance_private (self); + + GdaDbBase *iobj = gda_db_base_new (); + gda_db_base_set_names (iobj, catalog, schema, name); + + GList *it = NULL; + + for (it = priv->mp_tables; it; it = it->next) + if (!gda_db_base_compare (iobj,GDA_DB_BASE(it->data))) + { + g_object_unref (iobj); + return GDA_DB_TABLE(it->data); + } + + g_object_unref (iobj); + return NULL; +} + +/** + * gda_db_catalog_get_view: + * @self: a #GdaDbCatalog object + * @name: view name + * + * Convenient function to return a view based on name. + * + * Returns: table as #GdaDbView or %NULL if the view is not found. + * + */ +const GdaDbView* +gda_db_catalog_get_view (GdaDbCatalog *self, + const gchar *catalog, + const gchar *schema, + const gchar *name) +{ + GdaDbCatalogPrivate *priv = gda_db_catalog_get_instance_private (self); + + GList *it = NULL; + + GdaDbBase *iobj = gda_db_base_new (); + gda_db_base_set_names (iobj,catalog,schema,name); + + for (it = priv->mp_views; it; it = it->next) + if (!gda_db_base_compare (iobj, GDA_DB_BASE(it))) + { + g_object_unref (iobj); + return GDA_DB_VIEW(it); + } + + g_object_unref (iobj); + return NULL; +} + +/* + * _gda_db_table_new_from_meta: + * @obj: a #GdaMetaDbObject + * + * Create new #GdaDbTable instance from the corresponding #GdaMetaDbObject + * object. If %NULL is passed this function works exactly as + * gda_db_table_new() + * + * This method should not be part of the public API. + * + * Since: 6.0 + */ +static GdaDbTable* +_gda_db_table_new_from_meta (GdaMetaDbObject *obj) +{ + if (!obj) + return gda_db_table_new (); + + GdaMetaTable *metatable = GDA_META_TABLE(obj); + GdaDbTable *table = gda_db_table_new (); + + gda_db_base_set_names(GDA_DB_BASE(table), + obj->obj_catalog, + obj->obj_schema, + obj->obj_name); + + GSList *it = NULL; + for (it = metatable->columns; it; it = it->next) + { + GdaDbColumn *column = gda_db_column_new_from_meta (GDA_META_TABLE_COLUMN(it->data)); + + gda_db_table_append_column (table, column); + g_object_unref (column); + } + + for (it = metatable->fk_list;it;it = it->next) + { + if (!GDA_META_TABLE_FOREIGN_KEY_IS_DECLARED(GDA_META_TABLE_FOREIGN_KEY(it->data))) + continue; + + GdaDbFkey *fkey = gda_db_fkey_new_from_meta (GDA_META_TABLE_FOREIGN_KEY(it->data)); + + gda_db_table_append_fkey (table, fkey); + g_object_unref (fkey); + + } + + return table; +} + +/* + * _gda_db_view_new_from_meta: + * @view: a #GdaMetaView instance + * + * Create new #GdaDbView object from the corresponding #GdaMetaView object + * + * This method should not be part of the public API. + * + * Returns: New instance of #GdaDbView + */ +static GdaDbView* +_gda_db_view_new_from_meta (GdaMetaView *view) +{ + if (!view) + return gda_db_view_new (); + + GdaDbView *dbview = gda_db_view_new (); + + gda_db_view_set_defstring (dbview,view->view_def); + gda_db_view_set_replace (dbview,view->is_updatable); + + return dbview; +} + +/** + * gda_db_catalog_parse_cnc: + * @self: a #GdaDbCatalog instance + * @error: error storage object + * + * Parse internal cnc to populate @self object. This method should be called every time after + * database was modified or @self was just created using gda_connection_create_db_catalog(). The + * method will return %FALSE if no internal #GdaConnection available. + * + * Returns: Returns %TRUE if succeeded, %FALSE otherwise. + * + * Since: 6.0 + */ +gboolean +gda_db_catalog_parse_cnc (GdaDbCatalog *self, + GError **error) +{ + g_return_val_if_fail (self, FALSE); + + GdaDbCatalogPrivate *priv = gda_db_catalog_get_instance_private (self); + + if (!priv->cnc && !gda_connection_is_opened (priv->cnc)) + return FALSE; + + if(!gda_connection_update_meta_store (priv->cnc, NULL, error)) + return FALSE; + + + GdaMetaStore *mstore = NULL; + GdaMetaStruct *mstruct = NULL; + + mstore = gda_connection_get_meta_store (priv->cnc); + mstruct = (GdaMetaStruct*) g_object_new (GDA_TYPE_META_STRUCT, + "meta-store", mstore, + "features", GDA_META_STRUCT_FEATURE_ALL, NULL); + + GSList *dblist = NULL; + + if(!gda_meta_struct_complement_all (mstruct, error)) + goto on_error; + + dblist = gda_meta_struct_get_all_db_objects (mstruct); + + if (!dblist) + goto on_error; + + GSList *it = NULL; + + for (it=dblist; it; it = it->next) + { + if(GDA_META_DB_OBJECT(it->data)->obj_type == GDA_META_DB_TABLE) + { + GdaDbTable *table = _gda_db_table_new_from_meta (it->data); + priv->mp_tables = g_list_append (priv->mp_tables,table); + continue; + } + + if(GDA_META_DB_OBJECT(it->data)->obj_type == GDA_META_DB_VIEW) + { + GdaDbView *view = _gda_db_view_new_from_meta (it->data); + priv->mp_views = g_list_append (priv->mp_views, view); + continue; + } + } + + g_slist_free (dblist); + g_object_unref (mstruct); + return TRUE; + +on_error: + if (dblist) + g_slist_free (dblist); + g_object_unref (mstruct); + return FALSE; +} + +/** + * gda_db_catalog_append_table: + * @self: a #GdaDbCatalog instance + * @table: table to append + * + * This method append @table to the total list of all tables stored in @self. This method increase + * reference count for @table. + * + * Since: 6.0 + */ +void +gda_db_catalog_append_table (GdaDbCatalog *self, + GdaDbTable *table) +{ + g_return_if_fail (self); + + GdaDbCatalogPrivate *priv = gda_db_catalog_get_instance_private (self); + + priv->mp_tables = g_list_append (priv->mp_tables, g_object_ref (table)); +} + +/** + * gda_db_catalog_append_view: + * @self: a #GdaDbCatalog instance + * @view: view to append + * + * This method append @view to the total list of all views stored in @self. This method increase + * reference count for @view. + * + * Since: 6.0 + */ +void +gda_db_catalog_append_view (GdaDbCatalog *self, + GdaDbView *view) +{ + g_return_if_fail (self); + + GdaDbCatalogPrivate *priv = gda_db_catalog_get_instance_private (self); + + priv->mp_views = g_list_append (priv->mp_views, g_object_ref (view)); +} + +/** + * gda_db_catalog_perform_operation: + * @self: a #GdaDbCatalog object + * @error: object to store error + * + * After population @self with all data this method may be + * called to trigger code and modify user database. This is the main + * method to work with database. For retrieving information from database to an + * xml file use gda_db_catalog_parse_cnc() and gda_db_buildable_write_node(). + * + * Connection can be added as a property using g_object_set() call and should be opened to use + * this method. See gda_connection_open() method for reference. + * + * Only table can be created. Views are ignored + * + * Each table from database compared with each table in the #GdaDbCatalog + * instance. If the table doesn't exist in database, it will be created (CREATE_TABLE). + * If table exists in the database and xml file, all columns will be checked. If columns + * are present in xml file but not in the database it will be created (ADD_COLUMN). If + * column exists but has different parameters, e.g. nonnull it will not be + * modified. + * + * Note: Pkeys are not checked. This is a limitation that should be removed. The corresponding + * issue was open on gitlab page. + */ +gboolean +gda_db_catalog_perform_operation (GdaDbCatalog *self, + GError **error) +{ + g_return_val_if_fail (self, FALSE); + gboolean st = TRUE; + + GdaDbCatalogPrivate *priv = gda_db_catalog_get_instance_private (self); + + if (!gda_connection_is_opened (priv->cnc)) + { + g_set_error (error, + GDA_DB_CATALOG_ERROR, + GDA_DB_CATALOG_CONNECTION_CLOSED, + _("Connection is not opened")); + return FALSE; + } + + gda_lockable_lock ((GdaLockable*)priv->cnc); +// We need to get MetaData + if(!gda_connection_update_meta_store (priv->cnc, NULL, error)) + return FALSE; + + GdaMetaStore *mstore = gda_connection_get_meta_store (priv->cnc); + GdaMetaStruct *mstruct = (GdaMetaStruct*) g_object_new (GDA_TYPE_META_STRUCT, + "meta-store", mstore, + "features", GDA_META_STRUCT_FEATURE_ALL, + NULL); + + // We need information about catalog, schema, name for each object we would + // like to check + + GdaMetaDbObject *mobj = NULL; + GValue *catalog = NULL; + GValue *schema = NULL; + GValue *name = NULL; + + catalog = gda_value_new (G_TYPE_STRING); + schema = gda_value_new (G_TYPE_STRING); + name = gda_value_new (G_TYPE_STRING); + + GList *it = NULL; + for (it = priv->mp_tables; it; it = it->next) + { + /* SQLite accepts only one possible value for schema: "main". + * Other databases may also ignore schema and reference objects only by database and + * name, e.g. db_name.table_name + * */ + g_value_set_string (catalog, gda_db_base_get_catalog(it->data)); + g_value_set_string (schema , gda_db_base_get_schema (it->data)); + g_value_set_string (name , gda_db_base_get_name (it->data)); + + mobj = gda_meta_struct_complement (mstruct, GDA_META_DB_TABLE, catalog, schema,name, NULL); + + if (mobj) + { + g_debug("Object %s was found in the database\n", gda_db_base_get_name(GDA_DB_BASE(it->data))); + st = gda_db_table_update (it->data,GDA_META_TABLE(mobj), priv->cnc, error); + + if (!st) + break; + } + else + { + st = gda_ddl_modifiable_create (GDA_DDL_MODIFIABLE (it->data), priv->cnc, NULL, error); + + if (!st) + break; + } + } /* End of for loop */ + + gda_value_free (catalog); + gda_value_free (schema); + gda_value_free (name); + + if (st) { + /*TODO: add update option for views */ + for (it = priv->mp_views; it; it = it->next) { + st = gda_ddl_modifiable_create (GDA_DDL_MODIFIABLE (it->data), priv->cnc, NULL, error); + if (!st) { + break; + } + } /* End of for loop */ + } + + g_object_unref (mstruct); + gda_lockable_unlock ((GdaLockable*) priv->cnc); + + return st; +} + +/** + * gda_db_catalog_write_to_file: + * @self: a #GdaDbCatalog instance + * @file: a #GFile to write database description + * @error: container to hold error + * + * This method writes database description as xml file. + * Similar to gda_db_catalog_write_to_path() + * + * Returns: %TRUE if no error occurred, %FALSE otherwise. + * + * Since: 6.0 + */ +gboolean +gda_db_catalog_write_to_file (GdaDbCatalog *self, + GFile *file, + GError **error) +{ + g_return_val_if_fail (self, FALSE); + g_return_val_if_fail (file, FALSE); + + gchar *filepath = g_file_get_path (file); + gboolean res = gda_db_catalog_write_to_path (self, filepath, error); + g_free (filepath); + return res; +} + +/** + * gda_db_catalog_write_to_path: + * @self: a #GdaDbCatalog instance + * @path: path to xml file to save #GdaDbCatalog + * @error: container to hold an error + * + * Save content of @self to a user friendly xml file. + * + * Returns: %TRUE is no error, %FALSE otherwise. + * + * Since: 6.0 + */ +gboolean +gda_db_catalog_write_to_path (GdaDbCatalog *self, + const gchar *path, + GError **error) +{ + g_return_val_if_fail (self,FALSE); + g_return_val_if_fail (path,FALSE); + + GdaDbCatalogPrivate *priv = gda_db_catalog_get_instance_private (self); + + xmlDocPtr doc = NULL; + xmlNodePtr node_root = NULL; + + doc = xmlNewDoc (BAD_CAST "1.0"); + node_root = xmlNewNode (NULL, BAD_CAST "schema"); + + if (priv->mp_schemaname) + xmlNewProp (node_root, (xmlChar*)"name",(xmlChar*)priv->mp_schemaname); + + xmlDocSetRootElement (doc, node_root); + + GList *it = NULL; + + for (it = priv->mp_tables; it; it=it->next) + if (!gda_db_buildable_write_node (GDA_DB_BUILDABLE(GDA_DB_TABLE(it->data)), + node_root, error)) + goto on_error; + + for (it = priv->mp_views; it; it=it->next) + if (!gda_db_buildable_write_node (GDA_DB_BUILDABLE(GDA_DB_VIEW(it->data)), + node_root,error)) + goto on_error; + + xmlSaveFormatFileEnc (path, doc, "UTF-8", 1); + xmlFreeDoc (doc); + xmlCleanupParser (); + + return TRUE; + +on_error: + xmlFreeDoc (doc); + xmlCleanupParser (); + return FALSE; +} + +/** + * gda_db_catalog_parse_file: + * @self: an instance of #GdaDbCatalog + * @xmlfile: xml file as #GFile instance + * @error: Error container + * + * For detailed description see gda_db_catalog_parse_file_from_path() + * + * Since: 6.0 + */ +gboolean +gda_db_catalog_parse_file (GdaDbCatalog *self, + GFile *xmlfile, + GError **error) +{ + g_return_val_if_fail (self, FALSE); + g_return_val_if_fail (xmlfile, FALSE); + + GFileInputStream *istream = NULL; + xmlDocPtr doc = NULL; + + istream = g_file_read (xmlfile, NULL, error); + + if(!istream) + { + g_set_error (error, + GDA_DB_CATALOG_ERROR, + GDA_DB_CATALOG_FILE_READ, + _("Can't open stream for reading file '%s'"), g_file_get_basename (xmlfile)); + return FALSE; + } + + xmlParserCtxtPtr ctxt = NULL; + int buffer_size = 10; + char buffer[buffer_size]; + int ctxt_res = 0; + gchar *uri; + ctxt = xmlCreatePushParserCtxt (NULL, NULL, buffer, ctxt_res, NULL); + if (!ctxt) + { + uri = g_file_get_uri (xmlfile); + g_set_error (error, + GDA_DB_CATALOG_ERROR, + GDA_DB_CATALOG_FILE_READ, + _("Can't create parse context for '%s'"), uri); + g_free (uri); + goto on_error; + } + + int rescheck; + while ((ctxt_res = g_input_stream_read ((GInputStream*)istream, buffer, buffer_size-1, + NULL, error)) > 0) + { + rescheck = xmlParseChunk (ctxt, buffer, ctxt_res, 0); + + if (rescheck != 0) + { + g_set_error (error, + GDA_DB_CATALOG_ERROR, + GDA_DB_CATALOG_PARSE_CHUNK, + _("Error during parsing with error '%d'"), rescheck); + + goto on_error; + } + } + + xmlParseChunk (ctxt, buffer, 0, 1); + + doc = ctxt->myDoc; + ctxt_res = ctxt->wellFormed; + + if (!ctxt_res) + { + uri = g_file_get_uri (xmlfile); + g_set_error (error, + GDA_DB_CATALOG_ERROR, + GDA_DB_CATALOG_PARSE, + _("Failed to parse file: '%s'"), uri); + g_free (uri); + goto on_error; + } + + if (!doc) + { + uri = g_file_get_uri (xmlfile); + g_set_error (error, + GDA_DB_CATALOG_ERROR, + GDA_DB_CATALOG_DOC_NULL, + _("XML Document can't be created from file: '%s'"), uri); + g_free (uri); + goto on_error; + } + + if (!_gda_db_catalog_validate_doc (doc, error)) + { + g_set_error (error, + GDA_DB_CATALOG_ERROR, + GDA_DB_CATALOG_INVALID_XML, + _("XML file is not valid\n")); + goto on_error; + } + + if (!_gda_db_catalog_parse_doc (self, doc, error)) + goto on_error; + + g_input_stream_close (G_INPUT_STREAM(istream), NULL, error); + xmlFreeParserCtxt (ctxt); + xmlFreeDoc (doc); + g_object_unref (istream); + return TRUE; + +on_error: + g_input_stream_close (G_INPUT_STREAM(istream), NULL, error); + g_object_unref (istream); + if (ctxt) + xmlFreeParserCtxt (ctxt); + if (doc) + xmlFreeDoc (doc); + + return FALSE; +} diff --git a/.flatpak-builder/cache/objects/f9/9239d170575dcff1edc35ab8fb7dc9729fa2d18af5a84b51617d7396faecb2.file b/.flatpak-builder/cache/objects/f9/9239d170575dcff1edc35ab8fb7dc9729fa2d18af5a84b51617d7396faecb2.file new file mode 100644 index 0000000..7d450d1 --- /dev/null +++ b/.flatpak-builder/cache/objects/f9/9239d170575dcff1edc35ab8fb7dc9729fa2d18af5a84b51617d7396faecb2.file @@ -0,0 +1,407 @@ +import typing as T + +from .. import OutputFormat +from ...language import * +from .xml_emitter import XmlEmitter + + +class XmlOutput(OutputFormat): + def emit(self, ui: UI) -> str: + xml = XmlEmitter() + self._emit_ui(ui, xml) + return xml.result + + def _emit_ui(self, ui: UI, xml: XmlEmitter): + xml.start_tag("interface") + + self._emit_gtk_directive(ui.gtk_decl, xml) + + for x in ui.contents: + if isinstance(x, Template): + self._emit_template(x, xml) + elif isinstance(x, Object): + self._emit_object(x, xml) + elif isinstance(x, Menu): + self._emit_menu(x, xml) + else: + raise CompilerBugError() + + xml.end_tag() + + def _emit_gtk_directive(self, gtk: GtkDirective, xml: XmlEmitter): + xml.put_self_closing("requires", lib="gtk", version=gtk.gir_namespace.version) + + def _emit_template(self, template: Template, xml: XmlEmitter): + xml.start_tag( + "template", **{"class": template.gir_class}, parent=template.parent_type + ) + self._emit_object_or_template(template, xml) + xml.end_tag() + + def _emit_object(self, obj: Object, xml: XmlEmitter): + xml.start_tag( + "object", + **{"class": obj.class_name}, + id=obj.id, + ) + self._emit_object_or_template(obj, xml) + xml.end_tag() + + def _emit_object_or_template( + self, obj: T.Union[Object, Template, ExtListItemFactory], xml: XmlEmitter + ): + for child in obj.content.children: + if isinstance(child, Property): + self._emit_property(child, xml) + elif isinstance(child, Signal): + self._emit_signal(child, xml) + elif isinstance(child, Child): + self._emit_child(child, xml) + else: + self._emit_extensions(child, xml) + + # List action widgets + action_widgets = obj.action_widgets + if action_widgets: + xml.start_tag("action-widgets") + for action_widget in action_widgets: + xml.start_tag( + "action-widget", + response=action_widget.response_id, + default=action_widget.is_default or None, + ) + xml.put_text(action_widget.widget_id) + xml.end_tag() + xml.end_tag() + + def _emit_menu(self, menu: Menu, xml: XmlEmitter): + xml.start_tag(menu.tag, id=menu.id) + for child in menu.items: + if isinstance(child, Menu): + self._emit_menu(child, xml) + elif isinstance(child, MenuAttribute): + xml.start_tag( + "attribute", + name=child.name, + **self._translated_string_attrs(child.value.child), + ) + xml.put_text(child.value.string) + xml.end_tag() + else: + raise CompilerBugError() + xml.end_tag() + + def _emit_property(self, property: Property, xml: XmlEmitter): + value = property.value + + props: T.Dict[str, T.Optional[str]] = { + "name": property.name, + } + + if isinstance(value, Value): + child = value.child + + if isinstance(child, Translated): + xml.start_tag( + "property", **props, **self._translated_string_attrs(child) + ) + xml.put_text(child.string) + xml.end_tag() + else: + xml.start_tag("property", **props) + self._emit_value(value, xml) + xml.end_tag() + + elif isinstance(value, Binding): + if simple := value.simple_binding: + props["bind-source"] = self._object_id(value, simple.source) + props["bind-property"] = simple.property_name + props["bind-flags"] = "sync-create" + xml.put_self_closing("property", **props) + else: + xml.start_tag("binding", **props) + self._emit_expression(value.expression, xml) + xml.end_tag() + + elif isinstance(value, PropertyBinding): + bind_flags = [] + if not value.no_sync_create: + bind_flags.append("sync-create") + if value.inverted: + bind_flags.append("invert-boolean") + if value.bidirectional: + bind_flags.append("bidirectional") + + props["bind-source"] = self._object_id(value, value.source) + props["bind-property"] = value.property_name + props["bind-flags"] = "|".join(bind_flags) or None + xml.put_self_closing("property", **props) + + elif isinstance(value, ObjectValue): + xml.start_tag("property", **props) + self._emit_object(value.object, xml) + xml.end_tag() + + else: + raise CompilerBugError() + + def _translated_string_attrs( + self, translated: T.Optional[T.Union[QuotedLiteral, Translated]] + ) -> T.Dict[str, T.Optional[str]]: + if translated is None: + return {} + elif isinstance(translated, QuotedLiteral): + return {} + else: + return {"translatable": "true", "context": translated.translate_context} + + def _emit_signal(self, signal: Signal, xml: XmlEmitter): + name = signal.name + if signal.detail_name: + name += "::" + signal.detail_name + xml.put_self_closing( + "signal", + name=name, + handler=signal.handler, + swapped=signal.is_swapped or None, + object=( + self._object_id(signal, signal.object_id) if signal.object_id else None + ), + ) + + def _emit_child(self, child: Child, xml: XmlEmitter): + child_type = internal_child = None + if child.annotation is not None: + annotation = child.annotation.child + if isinstance(annotation, ChildType): + child_type = annotation.child_type + elif isinstance(annotation, ChildInternal): + internal_child = annotation.internal_child + elif isinstance(annotation, ChildExtension): + child_type = "action" + else: + raise CompilerBugError() + + xml.start_tag("child", type=child_type, internal_child=internal_child) + self._emit_object(child.object, xml) + xml.end_tag() + + def _emit_literal(self, literal: Literal, xml: XmlEmitter): + value = literal.value + if isinstance(value, IdentLiteral): + value_type = value.context[ValueTypeCtx].value_type + if isinstance(value_type, gir.BoolType): + xml.put_text(value.ident) + elif isinstance(value_type, gir.Enumeration): + xml.put_text(str(value_type.members[value.ident].value)) + else: + xml.put_text(self._object_id(value, value.ident)) + elif isinstance(value, TypeLiteral): + xml.put_text(value.type_name.glib_type_name) + else: + xml.put_text(value.value) + + def _emit_value(self, value: Value, xml: XmlEmitter): + if isinstance(value.child, Literal): + self._emit_literal(value.child, xml) + elif isinstance(value.child, Flags): + xml.put_text( + "|".join([str(flag.value or flag.name) for flag in value.child.flags]) + ) + elif isinstance(value.child, Translated): + raise CompilerBugError("translated values must be handled in the parent") + elif isinstance(value.child, TypeLiteral): + xml.put_text(value.child.type_name.glib_type_name) + elif isinstance(value.child, ObjectValue): + self._emit_object(value.child.object, xml) + else: + raise CompilerBugError() + + def _emit_expression(self, expression: Expression, xml: XmlEmitter): + self._emit_expression_part(expression.last, xml) + + def _emit_expression_part(self, expression: ExprBase, xml: XmlEmitter): + if isinstance(expression, LiteralExpr): + self._emit_literal_expr(expression, xml) + elif isinstance(expression, LookupOp): + self._emit_lookup_op(expression, xml) + elif isinstance(expression, Expression): + self._emit_expression(expression, xml) + elif isinstance(expression, CastExpr): + self._emit_cast_expr(expression, xml) + elif isinstance(expression, ClosureExpr): + self._emit_closure_expr(expression, xml) + else: + raise CompilerBugError() + + def _emit_literal_expr(self, expr: LiteralExpr, xml: XmlEmitter): + if expr.is_object: + xml.start_tag("constant") + else: + xml.start_tag("constant", type=expr.type) + self._emit_literal(expr.literal, xml) + xml.end_tag() + + def _emit_lookup_op(self, expr: LookupOp, xml: XmlEmitter): + xml.start_tag("lookup", name=expr.property_name, type=expr.lhs.type) + self._emit_expression_part(expr.lhs, xml) + xml.end_tag() + + def _emit_cast_expr(self, expr: CastExpr, xml: XmlEmitter): + self._emit_expression_part(expr.lhs, xml) + + def _emit_closure_expr(self, expr: ClosureExpr, xml: XmlEmitter): + xml.start_tag("closure", function=expr.closure_name, type=expr.type) + for arg in expr.args: + self._emit_expression_part(arg.expr, xml) + xml.end_tag() + + def _emit_attribute( + self, + tag: str, + attr: str, + name: str, + value: T.Union[Value, StringValue], + xml: XmlEmitter, + ): + attrs = {attr: name} + + if isinstance(value.child, Translated): + xml.start_tag(tag, **attrs, **self._translated_string_attrs(value.child)) + xml.put_text(value.child.string) + xml.end_tag() + elif isinstance(value.child, QuotedLiteral): + xml.start_tag(tag, **attrs) + xml.put_text(value.child.value) + xml.end_tag() + else: + xml.start_tag(tag, **attrs) + self._emit_value(value, xml) + xml.end_tag() + + def _emit_extensions(self, extension, xml: XmlEmitter): + if isinstance(extension, ExtAccessibility): + xml.start_tag("accessibility") + for prop in extension.properties: + self._emit_attribute(prop.tag_name, "name", prop.name, prop.value, xml) + xml.end_tag() + + elif isinstance(extension, AdwBreakpointCondition): + xml.start_tag("condition") + xml.put_text(extension.condition) + xml.end_tag() + + elif isinstance(extension, AdwBreakpointSetters): + for setter in extension.setters: + attrs = {} + + if isinstance(setter.value.child, Translated): + attrs = self._translated_string_attrs(setter.value.child) + + xml.start_tag( + "setter", + object=self._object_id(setter, setter.object_id), + property=setter.property_name, + **attrs, + ) + if isinstance(setter.value.child, Translated): + xml.put_text(setter.value.child.string) + elif ( + isinstance(setter.value.child, Literal) + and isinstance(setter.value.child.value, IdentLiteral) + and setter.value.child.value.ident == "null" + and setter.context[ScopeCtx].objects.get("null") is None + ): + pass + else: + self._emit_value(setter.value, xml) + xml.end_tag() + + elif isinstance(extension, Filters): + xml.start_tag(extension.tokens["tag_name"]) + for prop in extension.children: + xml.start_tag(prop.tokens["tag_name"]) + xml.put_text(prop.tokens["name"]) + xml.end_tag() + xml.end_tag() + + elif isinstance(extension, ExtComboBoxItems): + xml.start_tag("items") + for prop in extension.children: + self._emit_attribute("item", "id", prop.name, prop.value, xml) + xml.end_tag() + + elif isinstance(extension, ExtLayout): + xml.start_tag("layout") + for prop in extension.children: + self._emit_attribute("property", "name", prop.name, prop.value, xml) + xml.end_tag() + + elif isinstance(extension, ExtAdwMessageDialog): + xml.start_tag("responses") + for response in extension.responses: + xml.start_tag( + "response", + id=response.id, + **self._translated_string_attrs(response.value.child), + enabled=None if response.enabled else "false", + appearance=response.appearance, + ) + xml.put_text(response.value.string) + xml.end_tag() + xml.end_tag() + + elif isinstance(extension, ExtScaleMarks): + xml.start_tag("marks") + for mark in extension.children: + xml.start_tag( + "mark", + value=mark.value, + position=mark.position, + **self._translated_string_attrs(mark.label and mark.label.child), + ) + if mark.label is not None: + xml.put_text(mark.label.string) + xml.end_tag() + xml.end_tag() + + elif isinstance(extension, ExtStringListStrings): + xml.start_tag("items") + for string in extension.children: + value = string.child + xml.start_tag("item", **self._translated_string_attrs(value.child)) + xml.put_text(value.string) + xml.end_tag() + xml.end_tag() + + elif isinstance(extension, ExtListItemFactory): + child_xml = XmlEmitter() + child_xml.start_tag("interface") + child_xml.start_tag("template", **{"class": "GtkListItem"}) + self._emit_object_or_template(extension, child_xml) + child_xml.end_tag() + child_xml.end_tag() + xml.start_tag("property", name="bytes") + xml.put_cdata(child_xml.result) + xml.end_tag() + + elif isinstance(extension, ExtStyles): + xml.start_tag("style") + for style in extension.children: + xml.put_self_closing("class", name=style.name) + xml.end_tag() + + elif isinstance(extension, ExtSizeGroupWidgets): + xml.start_tag("widgets") + for prop in extension.children: + xml.put_self_closing("widget", name=prop.name) + xml.end_tag() + + else: + raise CompilerBugError() + + def _object_id(self, node: AstNode, id: str) -> str: + if id == "template" and node.context[ScopeCtx].template is not None: + return node.context[ScopeCtx].template.gir_class.glib_type_name + else: + return id diff --git a/.flatpak-builder/cache/objects/fa/1e08311693c99e9c9fd1c1067dbd35d018954961382864194e7e62532e1758.file b/.flatpak-builder/cache/objects/fa/1e08311693c99e9c9fd1c1067dbd35d018954961382864194e7e62532e1758.file new file mode 100644 index 0000000..fb17ae3 --- /dev/null +++ b/.flatpak-builder/cache/objects/fa/1e08311693c99e9c9fd1c1067dbd35d018954961382864194e7e62532e1758.file @@ -0,0 +1,253 @@ + +/* This file is generated by glib-mkenums, do not modify it. This code is licensed under the same license as the containing project. Note that it links to GLib, so must comply with the LGPL linking clauses. */ + +#include "gda-sql-parser-enum-types.h" +#include "gda-statement-struct-decl.h" +#include "gda-sql-statement.h" +#include "gda-sql-parser.h" +#include "gda-statement-struct.h" +#include "gda-statement-struct-compound.h" +#include "gda-statement-struct-delete.h" +#include "gda-statement-struct-update.h" +#include "gda-statement-struct-insert.h" +#include "gda-statement-struct-parts.h" +#include "gda-statement-struct-pspec.h" +#include "gda-statement-struct-select.h" +#include "gda-statement-struct-trans.h" +#include "gda-statement-struct-unknown.h" +#include "gda-statement-struct-util.h" + +#define C_ENUM(v) ((gint) v) +#define C_FLAGS(v) ((guint) v) + +/* enumerations from "gda-sql-parser.h" */ + +GType +gda_sql_parser_error_get_type (void) +{ +static gsize gtype_id = 0; +static const GEnumValue values[] = { + { C_ENUM(GDA_SQL_PARSER_SYNTAX_ERROR), "GDA_SQL_PARSER_SYNTAX_ERROR", "syntax-error" }, + { C_ENUM(GDA_SQL_PARSER_OVERFLOW_ERROR), "GDA_SQL_PARSER_OVERFLOW_ERROR", "overflow-error" }, + { C_ENUM(GDA_SQL_PARSER_EMPTY_SQL_ERROR), "GDA_SQL_PARSER_EMPTY_SQL_ERROR", "empty-sql-error" }, +{ 0, NULL, NULL } + }; + if (g_once_init_enter (>ype_id)) { + GType new_type = g_enum_register_static (g_intern_static_string ("GdaSqlParserError"), values); + g_once_init_leave (>ype_id, new_type); + } + return (GType) gtype_id; + } + +GType +gda_sql_parser_mode_get_type (void) +{ +static gsize gtype_id = 0; +static const GEnumValue values[] = { + { C_ENUM(GDA_SQL_PARSER_MODE_PARSE), "GDA_SQL_PARSER_MODE_PARSE", "parse" }, + { C_ENUM(GDA_SQL_PARSER_MODE_DELIMIT), "GDA_SQL_PARSER_MODE_DELIMIT", "delimit" }, +{ 0, NULL, NULL } + }; + if (g_once_init_enter (>ype_id)) { + GType new_type = g_enum_register_static (g_intern_static_string ("GdaSqlParserMode"), values); + g_once_init_leave (>ype_id, new_type); + } + return (GType) gtype_id; + } + +GType +gda_sql_parser_flavour_get_type (void) +{ +static gsize gtype_id = 0; +static const GEnumValue values[] = { + { C_ENUM(GDA_SQL_PARSER_FLAVOUR_STANDARD), "GDA_SQL_PARSER_FLAVOUR_STANDARD", "standard" }, + { C_ENUM(GDA_SQL_PARSER_FLAVOUR_SQLITE), "GDA_SQL_PARSER_FLAVOUR_SQLITE", "sqlite" }, + { C_ENUM(GDA_SQL_PARSER_FLAVOUR_MYSQL), "GDA_SQL_PARSER_FLAVOUR_MYSQL", "mysql" }, + { C_ENUM(GDA_SQL_PARSER_FLAVOUR_ORACLE), "GDA_SQL_PARSER_FLAVOUR_ORACLE", "oracle" }, + { C_ENUM(GDA_SQL_PARSER_FLAVOUR_POSTGRESQL), "GDA_SQL_PARSER_FLAVOUR_POSTGRESQL", "postgresql" }, +{ 0, NULL, NULL } + }; + if (g_once_init_enter (>ype_id)) { + GType new_type = g_enum_register_static (g_intern_static_string ("GdaSqlParserFlavour"), values); + g_once_init_leave (>ype_id, new_type); + } + return (GType) gtype_id; + } + +/* enumerations from "gda-statement-struct-compound.h" */ + +GType +gda_sql_statement_compound_type_get_type (void) +{ +static gsize gtype_id = 0; +static const GEnumValue values[] = { + { C_ENUM(GDA_SQL_STATEMENT_COMPOUND_UNION), "GDA_SQL_STATEMENT_COMPOUND_UNION", "union" }, + { C_ENUM(GDA_SQL_STATEMENT_COMPOUND_UNION_ALL), "GDA_SQL_STATEMENT_COMPOUND_UNION_ALL", "union-all" }, + { C_ENUM(GDA_SQL_STATEMENT_COMPOUND_INTERSECT), "GDA_SQL_STATEMENT_COMPOUND_INTERSECT", "intersect" }, + { C_ENUM(GDA_SQL_STATEMENT_COMPOUND_INTERSECT_ALL), "GDA_SQL_STATEMENT_COMPOUND_INTERSECT_ALL", "intersect-all" }, + { C_ENUM(GDA_SQL_STATEMENT_COMPOUND_EXCEPT), "GDA_SQL_STATEMENT_COMPOUND_EXCEPT", "except" }, + { C_ENUM(GDA_SQL_STATEMENT_COMPOUND_EXCEPT_ALL), "GDA_SQL_STATEMENT_COMPOUND_EXCEPT_ALL", "except-all" }, +{ 0, NULL, NULL } + }; + if (g_once_init_enter (>ype_id)) { + GType new_type = g_enum_register_static (g_intern_static_string ("GdaSqlStatementCompoundType"), values); + g_once_init_leave (>ype_id, new_type); + } + return (GType) gtype_id; + } + +/* enumerations from "gda-statement-struct-decl.h" */ + +GType +gda_sql_error_get_type (void) +{ +static gsize gtype_id = 0; +static const GEnumValue values[] = { + { C_ENUM(GDA_SQL_STRUCTURE_CONTENTS_ERROR), "GDA_SQL_STRUCTURE_CONTENTS_ERROR", "structure-contents-error" }, + { C_ENUM(GDA_SQL_MALFORMED_IDENTIFIER_ERROR), "GDA_SQL_MALFORMED_IDENTIFIER_ERROR", "malformed-identifier-error" }, + { C_ENUM(GDA_SQL_MISSING_IDENTIFIER_ERROR), "GDA_SQL_MISSING_IDENTIFIER_ERROR", "missing-identifier-error" }, + { C_ENUM(GDA_SQL_VALIDATION_ERROR), "GDA_SQL_VALIDATION_ERROR", "validation-error" }, +{ 0, NULL, NULL } + }; + if (g_once_init_enter (>ype_id)) { + GType new_type = g_enum_register_static (g_intern_static_string ("GdaSqlError"), values); + g_once_init_leave (>ype_id, new_type); + } + return (GType) gtype_id; + } + +GType +gda_sql_statement_type_get_type (void) +{ +static gsize gtype_id = 0; +static const GEnumValue values[] = { + { C_ENUM(GDA_SQL_STATEMENT_SELECT), "GDA_SQL_STATEMENT_SELECT", "select" }, + { C_ENUM(GDA_SQL_STATEMENT_INSERT), "GDA_SQL_STATEMENT_INSERT", "insert" }, + { C_ENUM(GDA_SQL_STATEMENT_UPDATE), "GDA_SQL_STATEMENT_UPDATE", "update" }, + { C_ENUM(GDA_SQL_STATEMENT_DELETE), "GDA_SQL_STATEMENT_DELETE", "delete" }, + { C_ENUM(GDA_SQL_STATEMENT_COMPOUND), "GDA_SQL_STATEMENT_COMPOUND", "compound" }, + { C_ENUM(GDA_SQL_STATEMENT_BEGIN), "GDA_SQL_STATEMENT_BEGIN", "begin" }, + { C_ENUM(GDA_SQL_STATEMENT_ROLLBACK), "GDA_SQL_STATEMENT_ROLLBACK", "rollback" }, + { C_ENUM(GDA_SQL_STATEMENT_COMMIT), "GDA_SQL_STATEMENT_COMMIT", "commit" }, + { C_ENUM(GDA_SQL_STATEMENT_SAVEPOINT), "GDA_SQL_STATEMENT_SAVEPOINT", "savepoint" }, + { C_ENUM(GDA_SQL_STATEMENT_ROLLBACK_SAVEPOINT), "GDA_SQL_STATEMENT_ROLLBACK_SAVEPOINT", "rollback-savepoint" }, + { C_ENUM(GDA_SQL_STATEMENT_DELETE_SAVEPOINT), "GDA_SQL_STATEMENT_DELETE_SAVEPOINT", "delete-savepoint" }, + { C_ENUM(GDA_SQL_STATEMENT_UNKNOWN), "GDA_SQL_STATEMENT_UNKNOWN", "unknown" }, + { C_ENUM(GDA_SQL_STATEMENT_NONE), "GDA_SQL_STATEMENT_NONE", "none" }, +{ 0, NULL, NULL } + }; + if (g_once_init_enter (>ype_id)) { + GType new_type = g_enum_register_static (g_intern_static_string ("GdaSqlStatementType"), values); + g_once_init_leave (>ype_id, new_type); + } + return (GType) gtype_id; + } + +GType +gda_sql_any_part_type_get_type (void) +{ +static gsize gtype_id = 0; +static const GEnumValue values[] = { + { C_ENUM(GDA_SQL_ANY_STMT_SELECT), "GDA_SQL_ANY_STMT_SELECT", "stmt-select" }, + { C_ENUM(GDA_SQL_ANY_STMT_INSERT), "GDA_SQL_ANY_STMT_INSERT", "stmt-insert" }, + { C_ENUM(GDA_SQL_ANY_STMT_UPDATE), "GDA_SQL_ANY_STMT_UPDATE", "stmt-update" }, + { C_ENUM(GDA_SQL_ANY_STMT_DELETE), "GDA_SQL_ANY_STMT_DELETE", "stmt-delete" }, + { C_ENUM(GDA_SQL_ANY_STMT_COMPOUND), "GDA_SQL_ANY_STMT_COMPOUND", "stmt-compound" }, + { C_ENUM(GDA_SQL_ANY_STMT_BEGIN), "GDA_SQL_ANY_STMT_BEGIN", "stmt-begin" }, + { C_ENUM(GDA_SQL_ANY_STMT_ROLLBACK), "GDA_SQL_ANY_STMT_ROLLBACK", "stmt-rollback" }, + { C_ENUM(GDA_SQL_ANY_STMT_COMMIT), "GDA_SQL_ANY_STMT_COMMIT", "stmt-commit" }, + { C_ENUM(GDA_SQL_ANY_STMT_SAVEPOINT), "GDA_SQL_ANY_STMT_SAVEPOINT", "stmt-savepoint" }, + { C_ENUM(GDA_SQL_ANY_STMT_ROLLBACK_SAVEPOINT), "GDA_SQL_ANY_STMT_ROLLBACK_SAVEPOINT", "stmt-rollback-savepoint" }, + { C_ENUM(GDA_SQL_ANY_STMT_DELETE_SAVEPOINT), "GDA_SQL_ANY_STMT_DELETE_SAVEPOINT", "stmt-delete-savepoint" }, + { C_ENUM(GDA_SQL_ANY_STMT_UNKNOWN), "GDA_SQL_ANY_STMT_UNKNOWN", "stmt-unknown" }, + { C_ENUM(GDA_SQL_ANY_EXPR), "GDA_SQL_ANY_EXPR", "expr" }, + { C_ENUM(GDA_SQL_ANY_SQL_FIELD), "GDA_SQL_ANY_SQL_FIELD", "sql-field" }, + { C_ENUM(GDA_SQL_ANY_SQL_TABLE), "GDA_SQL_ANY_SQL_TABLE", "sql-table" }, + { C_ENUM(GDA_SQL_ANY_SQL_FUNCTION), "GDA_SQL_ANY_SQL_FUNCTION", "sql-function" }, + { C_ENUM(GDA_SQL_ANY_SQL_OPERATION), "GDA_SQL_ANY_SQL_OPERATION", "sql-operation" }, + { C_ENUM(GDA_SQL_ANY_SQL_CASE), "GDA_SQL_ANY_SQL_CASE", "sql-case" }, + { C_ENUM(GDA_SQL_ANY_SQL_SELECT_FIELD), "GDA_SQL_ANY_SQL_SELECT_FIELD", "sql-select-field" }, + { C_ENUM(GDA_SQL_ANY_SQL_SELECT_TARGET), "GDA_SQL_ANY_SQL_SELECT_TARGET", "sql-select-target" }, + { C_ENUM(GDA_SQL_ANY_SQL_SELECT_JOIN), "GDA_SQL_ANY_SQL_SELECT_JOIN", "sql-select-join" }, + { C_ENUM(GDA_SQL_ANY_SQL_SELECT_FROM), "GDA_SQL_ANY_SQL_SELECT_FROM", "sql-select-from" }, + { C_ENUM(GDA_SQL_ANY_SQL_SELECT_ORDER), "GDA_SQL_ANY_SQL_SELECT_ORDER", "sql-select-order" }, +{ 0, NULL, NULL } + }; + if (g_once_init_enter (>ype_id)) { + GType new_type = g_enum_register_static (g_intern_static_string ("GdaSqlAnyPartType"), values); + g_once_init_leave (>ype_id, new_type); + } + return (GType) gtype_id; + } + +/* enumerations from "gda-statement-struct-parts.h" */ + +GType +gda_sql_operator_type_get_type (void) +{ +static gsize gtype_id = 0; +static const GEnumValue values[] = { + { C_ENUM(GDA_SQL_OPERATOR_TYPE_AND), "GDA_SQL_OPERATOR_TYPE_AND", "and" }, + { C_ENUM(GDA_SQL_OPERATOR_TYPE_OR), "GDA_SQL_OPERATOR_TYPE_OR", "or" }, + { C_ENUM(GDA_SQL_OPERATOR_TYPE_EQ), "GDA_SQL_OPERATOR_TYPE_EQ", "eq" }, + { C_ENUM(GDA_SQL_OPERATOR_TYPE_IS), "GDA_SQL_OPERATOR_TYPE_IS", "is" }, + { C_ENUM(GDA_SQL_OPERATOR_TYPE_LIKE), "GDA_SQL_OPERATOR_TYPE_LIKE", "like" }, + { C_ENUM(GDA_SQL_OPERATOR_TYPE_BETWEEN), "GDA_SQL_OPERATOR_TYPE_BETWEEN", "between" }, + { C_ENUM(GDA_SQL_OPERATOR_TYPE_GT), "GDA_SQL_OPERATOR_TYPE_GT", "gt" }, + { C_ENUM(GDA_SQL_OPERATOR_TYPE_LT), "GDA_SQL_OPERATOR_TYPE_LT", "lt" }, + { C_ENUM(GDA_SQL_OPERATOR_TYPE_GEQ), "GDA_SQL_OPERATOR_TYPE_GEQ", "geq" }, + { C_ENUM(GDA_SQL_OPERATOR_TYPE_LEQ), "GDA_SQL_OPERATOR_TYPE_LEQ", "leq" }, + { C_ENUM(GDA_SQL_OPERATOR_TYPE_DIFF), "GDA_SQL_OPERATOR_TYPE_DIFF", "diff" }, + { C_ENUM(GDA_SQL_OPERATOR_TYPE_REGEXP), "GDA_SQL_OPERATOR_TYPE_REGEXP", "regexp" }, + { C_ENUM(GDA_SQL_OPERATOR_TYPE_REGEXP_CI), "GDA_SQL_OPERATOR_TYPE_REGEXP_CI", "regexp-ci" }, + { C_ENUM(GDA_SQL_OPERATOR_TYPE_NOT_REGEXP), "GDA_SQL_OPERATOR_TYPE_NOT_REGEXP", "not-regexp" }, + { C_ENUM(GDA_SQL_OPERATOR_TYPE_NOT_REGEXP_CI), "GDA_SQL_OPERATOR_TYPE_NOT_REGEXP_CI", "not-regexp-ci" }, + { C_ENUM(GDA_SQL_OPERATOR_TYPE_SIMILAR), "GDA_SQL_OPERATOR_TYPE_SIMILAR", "similar" }, + { C_ENUM(GDA_SQL_OPERATOR_TYPE_ISNULL), "GDA_SQL_OPERATOR_TYPE_ISNULL", "isnull" }, + { C_ENUM(GDA_SQL_OPERATOR_TYPE_ISNOTNULL), "GDA_SQL_OPERATOR_TYPE_ISNOTNULL", "isnotnull" }, + { C_ENUM(GDA_SQL_OPERATOR_TYPE_NOT), "GDA_SQL_OPERATOR_TYPE_NOT", "not" }, + { C_ENUM(GDA_SQL_OPERATOR_TYPE_IN), "GDA_SQL_OPERATOR_TYPE_IN", "in" }, + { C_ENUM(GDA_SQL_OPERATOR_TYPE_NOTIN), "GDA_SQL_OPERATOR_TYPE_NOTIN", "notin" }, + { C_ENUM(GDA_SQL_OPERATOR_TYPE_CONCAT), "GDA_SQL_OPERATOR_TYPE_CONCAT", "concat" }, + { C_ENUM(GDA_SQL_OPERATOR_TYPE_PLUS), "GDA_SQL_OPERATOR_TYPE_PLUS", "plus" }, + { C_ENUM(GDA_SQL_OPERATOR_TYPE_MINUS), "GDA_SQL_OPERATOR_TYPE_MINUS", "minus" }, + { C_ENUM(GDA_SQL_OPERATOR_TYPE_STAR), "GDA_SQL_OPERATOR_TYPE_STAR", "star" }, + { C_ENUM(GDA_SQL_OPERATOR_TYPE_DIV), "GDA_SQL_OPERATOR_TYPE_DIV", "div" }, + { C_ENUM(GDA_SQL_OPERATOR_TYPE_REM), "GDA_SQL_OPERATOR_TYPE_REM", "rem" }, + { C_ENUM(GDA_SQL_OPERATOR_TYPE_BITAND), "GDA_SQL_OPERATOR_TYPE_BITAND", "bitand" }, + { C_ENUM(GDA_SQL_OPERATOR_TYPE_BITOR), "GDA_SQL_OPERATOR_TYPE_BITOR", "bitor" }, + { C_ENUM(GDA_SQL_OPERATOR_TYPE_BITNOT), "GDA_SQL_OPERATOR_TYPE_BITNOT", "bitnot" }, + { C_ENUM(GDA_SQL_OPERATOR_TYPE_ILIKE), "GDA_SQL_OPERATOR_TYPE_ILIKE", "ilike" }, + { C_ENUM(GDA_SQL_OPERATOR_TYPE_NOTLIKE), "GDA_SQL_OPERATOR_TYPE_NOTLIKE", "notlike" }, + { C_ENUM(GDA_SQL_OPERATOR_TYPE_NOTILIKE), "GDA_SQL_OPERATOR_TYPE_NOTILIKE", "notilike" }, +{ 0, NULL, NULL } + }; + if (g_once_init_enter (>ype_id)) { + GType new_type = g_enum_register_static (g_intern_static_string ("GdaSqlOperatorType"), values); + g_once_init_leave (>ype_id, new_type); + } + return (GType) gtype_id; + } + +GType +gda_sql_select_join_type_get_type (void) +{ +static gsize gtype_id = 0; +static const GEnumValue values[] = { + { C_ENUM(GDA_SQL_SELECT_JOIN_CROSS), "GDA_SQL_SELECT_JOIN_CROSS", "cross" }, + { C_ENUM(GDA_SQL_SELECT_JOIN_NATURAL), "GDA_SQL_SELECT_JOIN_NATURAL", "natural" }, + { C_ENUM(GDA_SQL_SELECT_JOIN_INNER), "GDA_SQL_SELECT_JOIN_INNER", "inner" }, + { C_ENUM(GDA_SQL_SELECT_JOIN_LEFT), "GDA_SQL_SELECT_JOIN_LEFT", "left" }, + { C_ENUM(GDA_SQL_SELECT_JOIN_RIGHT), "GDA_SQL_SELECT_JOIN_RIGHT", "right" }, + { C_ENUM(GDA_SQL_SELECT_JOIN_FULL), "GDA_SQL_SELECT_JOIN_FULL", "full" }, +{ 0, NULL, NULL } + }; + if (g_once_init_enter (>ype_id)) { + GType new_type = g_enum_register_static (g_intern_static_string ("GdaSqlSelectJoinType"), values); + g_once_init_leave (>ype_id, new_type); + } + return (GType) gtype_id; + } + +/* Generated data ends here */ + diff --git a/.flatpak-builder/cache/objects/fa/3bdbcc9c087d5fbb617d2ae850fe388cb7a04838d17fd051cfbe95663357b3.dirtree b/.flatpak-builder/cache/objects/fa/3bdbcc9c087d5fbb617d2ae850fe388cb7a04838d17fd051cfbe95663357b3.dirtree new file mode 100644 index 0000000..ba50511 Binary files /dev/null and b/.flatpak-builder/cache/objects/fa/3bdbcc9c087d5fbb617d2ae850fe388cb7a04838d17fd051cfbe95663357b3.dirtree differ diff --git a/.flatpak-builder/cache/objects/fa/3e0c00ff97ce955ce10dd2fe314d07fdb3f4e081a167bfc90db836d20f6161.file b/.flatpak-builder/cache/objects/fa/3e0c00ff97ce955ce10dd2fe314d07fdb3f4e081a167bfc90db836d20f6161.file new file mode 120000 index 0000000..e2181d7 --- /dev/null +++ b/.flatpak-builder/cache/objects/fa/3e0c00ff97ce955ce10dd2fe314d07fdb3f4e081a167bfc90db836d20f6161.file @@ -0,0 +1 @@ +../../share/runtime/locale/hu/share/hu \ No newline at end of file diff --git a/.flatpak-builder/cache/objects/fa/5f2399efad9a78228f1b7d5a356d1bed1aec51b311cf47c85b07bb02d95f79.file b/.flatpak-builder/cache/objects/fa/5f2399efad9a78228f1b7d5a356d1bed1aec51b311cf47c85b07bb02d95f79.file new file mode 100644 index 0000000..d1466a0 --- /dev/null +++ b/.flatpak-builder/cache/objects/fa/5f2399efad9a78228f1b7d5a356d1bed1aec51b311cf47c85b07bb02d95f79.file @@ -0,0 +1,5456 @@ +/* + * Copyright (C) 2008 - 2009 Bas Driessen + * Copyright (C) 2008 - 2011 Murray Cumming + * Copyright (C) 2008 - 2015 Vivien Malerba + * Copyright (C) 2010 David King + * Copyright (C) 2010 Jonh Wendell + * Copyright (C) 2011 - 2013, 2018-2019 Daniel Espinosa + * Copyright (C) 2013 Carl-Anton Ingmarsson + * Copyright (C) 2013 Miguel Angel Cabrera Moya + * Copyright (C) 2015 Corentin Noël + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#undef GDA_DISABLE_DEPRECATED + +/* + * Note about schema versions: + * Each time the schema evolves: + * - the schema is backward compatible so it can be used by older versions of Libgda + * - it does not modify any table or view not starting with a '_' + * - the version number is increased by 1: + * version 1 for libgda between 4.0.0 and 4.1.3 + * version 2 for libgda >= 4.1.4: added the "_table_indexes" and "_index_column_usage" tables + * version 3 for libgda >= 4.2.4: added the "__declared_fk" table + * version 4 for libgda >= 5.2.0: added "schema_default" to "_schemata" table + * version 5 for libgda >= 6.0: changed columns types to use TEXT types + */ +#define CURRENT_SCHEMA_VERSION "5" + +#define G_LOG_DOMAIN "GDA-meta-store" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "gda-marshal.h" +#include "gda-custom-marshal.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "gda-data-meta-wrapper.h" +#include + +// This is a copy of the macro located at gda-value.h +#define l_g_value_unset(val) G_STMT_START{ if (G_IS_VALUE (val)) g_value_unset (val); }G_STMT_END + + +/* change general information */ +struct _GdaMetaStoreChange { + GdaMetaStoreChangeType c_type; + gchar *table_name; + GHashTable *keys; /* key = ('+' or '-') and a column position in @table (string) starting at 0, + * value = a GValue pointer */ +}; + +G_DEFINE_BOXED_TYPE (GdaMetaStoreChange, gda_meta_store_change, gda_meta_store_change_copy, gda_meta_store_change_free) + + +/** + * gda_meta_store_change_new: + * + * Creates a new #GdaMetaStoreChange + */ +GdaMetaStoreChange* +gda_meta_store_change_new (void) +{ + GdaMetaStoreChange* change = g_new0 (GdaMetaStoreChange, 1); + change->table_name = NULL; + change->c_type = -1; + change->keys = g_hash_table_new_full (g_str_hash, g_str_equal, + g_free, (GDestroyNotify) gda_value_free); + return change; +} + +void +gda_meta_store_change_set_change_type (GdaMetaStoreChange *change, GdaMetaStoreChangeType ctype) +{ + g_return_if_fail (change != NULL); + change->c_type = ctype; +} + +GdaMetaStoreChangeType +gda_meta_store_change_get_change_type (GdaMetaStoreChange *change) +{ + g_return_val_if_fail (change != NULL, GDA_META_STORE_MODIFY); + return change->c_type; +} +/** + * gda_meta_store_change_set_table_name: + * @change: a #GdaMetaStoreChange + * @table_name: name of the table + * + */ +void +gda_meta_store_change_set_table_name (GdaMetaStoreChange *change, const gchar *table_name) +{ + g_return_if_fail (change != NULL); + change->table_name = g_strdup (table_name); +} +/** + * gda_meta_store_change_get_table_name: + * @change: a #GdaMetaStoreChange + * + * Returns: (transfer full): a string with the table name + */ +gchar* +gda_meta_store_change_get_table_name (GdaMetaStoreChange *change) +{ + g_return_val_if_fail (change != NULL, NULL); + return g_strdup (change->table_name); +} +/** + * gda_meta_store_change_get_keys: + * @change: a #GdaMetaStoreChange + * + * Returns: (element-type utf8 GValue) (transfer none): hash table with string key key = ('+' or '-') and a column position in @table (string) starting at 0 and value as #GValue pointer + */ +GHashTable* +gda_meta_store_change_get_keys (GdaMetaStoreChange *change) +{ + g_return_val_if_fail (change != NULL, NULL); + return change->keys; +} + +/** + * gda_meta_store_change_copy: + * @src: a #GdaMetaStoreChange + * + * Returns: a new #GdaMetaStoreChange + */ +GdaMetaStoreChange* +gda_meta_store_change_copy (GdaMetaStoreChange *src) +{ + GdaMetaStoreChange* copy; + g_return_val_if_fail (src != NULL, NULL); + copy = gda_meta_store_change_new (); + gda_meta_store_change_set_change_type (copy, gda_meta_store_change_get_change_type (src)); + gda_meta_store_change_set_table_name (copy, gda_meta_store_change_get_table_name (src)); + GList *keys = g_hash_table_get_keys (src->keys); + while (keys) { + g_hash_table_insert (copy->keys, keys->data, gda_value_copy (g_hash_table_lookup (src->keys, keys->data))); + keys = keys->next; + } + return copy; +} + +/** + * gda_meta_store_change_free: + * @change: a #GdaMetaStoreChange to be freed + * + */ +void +gda_meta_store_change_free (GdaMetaStoreChange *change) +{ + g_return_if_fail (change != NULL); + if (change->table_name != NULL) + g_free (change->table_name); + g_hash_table_unref (change->keys); +} + +/** + * gda_value_set_meta_store_change: + * @value: a #GValue to set value to + * @change: a #GdaMetaStoreChange to be set + * + */ +void +gda_value_set_meta_store_change (GValue *value, GdaMetaStoreChange *change) +{ + g_return_if_fail (value != NULL); + g_return_if_fail (change != NULL); + + l_g_value_unset (value); + g_value_init (value, GDA_TYPE_META_STORE_CHANGE); + if (change) + g_value_set_boxed (value, change); + else { + g_value_set_boxed (value, gda_meta_store_change_new ()); + } +} + +/** + * gda_value_get_meta_store_change: + * @value: a #GValue to get value from + * + * Returns: (transfer none): a #GdaMetaStoreChange + * + */ +GdaMetaStoreChange* +gda_value_get_meta_store_change (GValue *value) +{ + GdaMetaStoreChange *val; + + g_return_val_if_fail (value, NULL); + g_return_val_if_fail (gda_value_isa (value, GDA_TYPE_META_STORE_CHANGE), NULL); + + val = (GdaMetaStoreChange*) g_value_get_boxed (value); + + return val; +} + +/* + IMPLEMENTATION NOTES: + In this implementation, for 5.2, the new API for GdaMetaContext struct doesn't touch size, column_names and + column_values members, but added a HashTable member in order to make more easy to access to column/value + elements. + + Take care about to use gda_meta_context_free or g_free on this struct if you don't use the new API because + unexpected results. + + Changes include: table string is copied and columns are stored in a GHashTable witch it's reference counting + is incremented. When is freed, table string is freed and hash ref is decremented. +*/ + + +/** + * gda_meta_context_new: + * + * Creates a new #GdaMetaContext struct with a #GHashTable to store column/value pairs. + * + * Return: (transfer full): a new #GdaMetaContext struct with a new created hash to + * store column name/value pairs. + * + * Since: 5.2 + */ +GdaMetaContext* +gda_meta_context_new (void) +{ + GdaMetaContext *ctx = g_new0 (GdaMetaContext, 1); + ctx->table_name = g_strdup (""); + ctx->columns = g_hash_table_new_full (g_str_hash, g_str_equal, (GDestroyNotify) g_free, + (GDestroyNotify) gda_value_free); + return ctx; +} + +/** + * gda_meta_context_copy: + * @ctx: a #GdaMetaContext + * + * Copy constructor. + * + * Returns: a new #GdaMetaContext + * + * Since: 5.2 + */ +GdaMetaContext * +gda_meta_context_copy (GdaMetaContext *ctx) +{ + g_return_val_if_fail (ctx, NULL); + + GdaMetaContext *n; + n = gda_meta_context_new (); + gda_meta_context_set_table (n, gda_meta_context_get_table (ctx)); + gda_meta_context_set_columns (n, ctx->columns, NULL); + + return n; +} + +/** + * gda_meta_context_set_table: + * @ctx: a #GdaMetaContext struct to set table to + * @table: a string with the table's name to use in context + * + * Set table's name to use in the context. The table is one of database + * schema used to store meta information about the database. Use "_tables" to update meta information + * about database's tables. + * + * Since: 5.2 + */ +void +gda_meta_context_set_table (GdaMetaContext *ctx, const gchar *table_name) +{ + g_return_if_fail (ctx && table_name); + ctx->table_name = g_strdup (table_name); +} + +/** + * gda_meta_context_get_table: + * @ctx: a #GdaMetaContext struct to get table's name from + * + * Get table's name to used in the context. + * + * Return: (transfer none): A string with the table's name used in the context. + * + * Since: 5.2 + */ +const gchar* +gda_meta_context_get_table (GdaMetaContext *ctx) +{ + g_return_val_if_fail (ctx, NULL); + return ctx->table_name; +} + +/** + * gda_meta_context_set_column: + * @ctx: a #GdaMetaContext struct to add column/value pais to + * @column: (transfer none): the column's name + * @value: (transfer none): the column's value + * @cnc: (nullable): a #GdaConnection to be used when identifier are normalized, or NULL + * + * Sets a new column/value pair to the given context @ctx. Column, must be a column in the given table's + * name setted by #gda_meta_context_set_table () (a table in the database + * schema). If the given @column already exists it's value is overwrited. + * + * Column's name and value is copied and destroyed when #gda_meta_context_free is called. + * + * Since: 5.2 + */ +void +gda_meta_context_set_column (GdaMetaContext *ctx, const gchar* column, const GValue* value, GdaConnection *cnc) +{ + g_return_if_fail (ctx && column && value); + GValue *v; + if (G_VALUE_HOLDS_STRING((GValue*)value)) { + v = gda_value_new (G_TYPE_STRING); + g_value_take_string (v, gda_sql_identifier_quote (g_value_get_string ((GValue*)value), cnc, NULL, + TRUE, FALSE)); + g_hash_table_insert (ctx->columns, (gpointer) g_strdup (column), (gpointer) v); + } + else + g_hash_table_insert (ctx->columns, (gpointer) g_strdup (column), (gpointer) gda_value_copy (value)); +} + +/** + * gda_meta_context_set_columns: + * @ctx: a #GdaMetaContext struct to set colums to + * @columns: (element-type utf8 GObject.Value): a #GHashTable with the table's columns' name and their values + * to use in context. + * @cnc: (nullable): a #GdaConnection to used to normalize identifiers quoting, or NULL + * + * Set columns to use in the context. The #GHashTable use column's name as key and a #GValue as value, + * to represent its value. + * + * @columns incements its reference counting. Is recommended to use #gda_meta_context_free in order to free them. + * + * Since: 5.2 + */ +void +gda_meta_context_set_columns (GdaMetaContext *ctx, GHashTable *columns, GdaConnection *cnc) +{ + g_return_if_fail (ctx && columns && cnc); + g_return_if_fail (GDA_IS_CONNECTION (cnc)); + g_hash_table_unref (ctx->columns); + ctx->columns = g_hash_table_ref (columns); + // FIXME: Old but necesary initialization + // FIXME: Remove code that use column_names and column_values arrays + if (ctx->column_names) + g_free (ctx->column_names); + if (ctx->column_values) + g_free (ctx->column_values); + ctx->column_names = g_new (gchar*, g_hash_table_size (ctx->columns)); + ctx->column_values = g_new (GValue*, g_hash_table_size (ctx->columns)); + + GHashTableIter iter; + gpointer key, value; + gint i = 0; // FIXME: Code to remove + g_hash_table_iter_init (&iter, ctx->columns); + while (g_hash_table_iter_next (&iter, &key, &value)) { + // Normalize identifier quote + if (G_VALUE_HOLDS_STRING((GValue*)value)) { + GValue *v = gda_value_new (G_TYPE_STRING); + g_value_take_string (v, gda_sql_identifier_quote (g_value_get_string ((GValue*)value), cnc, NULL, + TRUE, FALSE)); + g_hash_table_insert (ctx->columns, key, (gpointer) v); + } + + // FIXME: Code to remove + ctx->column_names[i] = (gchar*) key; + ctx->column_values[i] = (GValue*) value; + i++; + } +} + +/** + * gda_meta_context_free: + * @ctx: (nullable): a #GdaMetaContext struct to free + * + * Frees any resources taken by @ctx struct. If @ctx is %NULL, then nothing happens. + * + * Since: 5.2 + */ +void +gda_meta_context_free (GdaMetaContext *ctx) +{ + if (!ctx) + return; + + g_free (ctx->table_name); + g_hash_table_unref (ctx->columns); + g_free (ctx); + // REMIND: ctx->column_names and ctx->column_values must not be freed +} + +/** + * gda_meta_context_stringify: + * @ctx: a #GdaMetaContext + * + * Creates a string representation of given context. + * + * Returns: (transfer full): a new string with the representation of the context + */ +gchar* +gda_meta_context_stringify (GdaMetaContext *ctx) +{ + g_return_val_if_fail (ctx != NULL, g_strdup ("")); + gint i; + gchar *str; + GString *string = g_string_new ("{"); + g_string_append (string, ctx->table_name); + g_string_append (string, "}=>{{"); + + for (i = 0; i < ctx->size; i++) { + if (i > 0) + g_string_append_c (string, ' '); + str = gda_value_stringify (ctx->column_values[i]); + g_string_append_printf (string, " [%s => %s]", ctx->column_names[i], str); + g_free (str); + } + if (i == 0) + g_string_append (string, "no constraints in context"); + g_string_append (string, "}}"); + str = string->str; + g_string_free (string, FALSE); + return str; +} + +/** + * gda_meta_context_get_n_columns: + * @ctx: a #GdaMetaContext + * + * Returns: the number of columns in the context + */ +gint +gda_meta_context_get_n_columns (GdaMetaContext *ctx) +{ + g_return_val_if_fail (ctx != NULL, 0); + return ctx->size; +} + + +G_DEFINE_BOXED_TYPE(GdaMetaContext, gda_meta_context, gda_meta_context_copy, gda_meta_context_free) + +/* + * Main static functions + */ +static void gda_meta_store_class_init (GdaMetaStoreClass *klass); +static GObject *gda_meta_store_constructor (GType type, + guint n_construct_properties, + GObjectConstructParam *construct_properties); +static void gda_meta_store_init (GdaMetaStore *store); +static void gda_meta_store_dispose (GObject *object); +static void gda_meta_store_finalize (GObject *object); + +static void gda_meta_store_set_property (GObject *object, + guint param_id, + const GValue *value, + GParamSpec *pspec); +static void gda_meta_store_get_property (GObject *object, + guint param_id, + GValue *value, + GParamSpec *pspec); + +static gboolean initialize_cnc_struct (GdaMetaStore *store, GError **error); + +/* simple predefined statements */ +enum { + STMT_GET_VERSION, + STMT_SET_VERSION, + STMT_UPD_VERSION, + STMT_DEL_ATT_VALUE, + STMT_SET_ATT_VALUE, + STMT_ADD_DECLARE_FK, + STMT_DEL_DECLARE_FK, + STMT_LAST +} PreStmtType; + +/* + * Complements the DbObject structure, for tables only + * contains predefined statements for data selection and modifications + */ +typedef struct { + GSList *columns; /* list of TableColumn */ + + /* data access statements */ + GdaStatement *current_all; + GdaStatement *delete_all; + + GdaStatement *insert; + GdaStatement *update; + GdaStatement *delete; + + /* a single #GdaSet for all the statements above */ + GdaSet *params; + + /* PK fields index */ + gint *pk_cols_array; + gint pk_cols_nb; + + /* GType for each column of the SELECT statement */ + GType *type_cols_array; /* terminated with G_TYPE_NONE */ + + /* fk_list */ + GSList *reverse_fk_list; /* list of TableFKey where @depend_on == this DbObject */ + GSList *fk_list; /* list of TableFKey where @table_info == this DbObject */ + + /* columns which contain SQL identifiers */ + gint *ident_cols; + gint ident_cols_size; + + GType gtype_column; /* -1 if no column represents a GType */ +} TableInfo; +static void table_info_free_contents (TableInfo *info); + +/* + * Complements the DbObject structure, for views only + * contains view definition + */ +typedef struct { + gchar *view_def; +} ViewInfo; +static void view_info_free_contents (ViewInfo *info); + +/* + * Struture to hold information about each object + * which can be created in the internal GdaMetaStore's connection. + * It is available for tables, views, triggers, ... + */ +typedef struct { + GdaMetaStore *store; /* if not NULL, the store in which this db object is, + * or %NULL if it's a class db object */ + GdaServerOperationType obj_type; + gchar *obj_name; /* may be %NULL */ + GdaServerOperation *create_op; /* may be %NULL */ + GSList *depend_list; /* list of DbObject pointers on which this object depends */ + + union { + TableInfo table_info; + ViewInfo view_info; + } extra; +} DbObject; +#define DB_OBJECT(x) ((DbObject*)(x)) +#define TABLE_INFO(dbobj) (&((dbobj)->extra.table_info)) +#define VIEW_INFO(dbobj) (&((dbobj)->extra.view_info)) + +typedef struct { + gchar *column_name; + gchar *column_type; + GType gtype; + gboolean pkey; + gboolean nullok; + gboolean autoinc; +} TableColumn; +static void table_column_free (TableColumn *tcol); +#define TABLE_COLUMN(x) ((TableColumn*)(x)) + +typedef struct { + DbObject *table_info; + DbObject *depend_on; + + gint cols_nb; + gint *fk_cols_array; /* FK fields index */ + gchar **fk_names_array; /* FK fields names */ + gint *ref_pk_cols_array; /* Ref PK fields index */ + gchar **ref_pk_names_array; /* Ref PK fields names */ + + gchar *fk_fields_cond; +} TableFKey; +static void table_fkey_free (TableFKey *tfk); + +/* statements defined by the @... arguments of the gda_meta_store_modify() function */ +typedef struct { + /* actual statements */ + GdaStatement *select; + GdaStatement *delete; + + /* a single #GdaSet for all the statements above */ + GdaSet *params; +} TableConditionInfo; + +typedef struct { + gchar *prov; + gchar *path; + gchar *expr; +} ProviderSpecificKey; + +typedef struct { + gchar *repl; +} ProviderSpecificValue; + +static guint ProviderSpecific_hash (gconstpointer key); +static gboolean ProviderSpecific_equal (gconstpointer a, gconstpointer b); +static void provider_specific_key_free (ProviderSpecificKey *key); +static void provider_specific_value_free (ProviderSpecificValue *val); + +typedef struct { + GdaConnection *cnc; + GdaSqlIdentifierStyle ident_style; + GdaSqlReservedKeywordsFunc reserved_keyword_func; + + GError *init_error; + gint version; + gboolean schema_ok; + + gchar *catalog; /* name of the catalog in which all the objects are created, or NULL if none specified */ + gchar *schema; /* name of the schema in which all the objects are created, or NULL if none specified */ + + GSList *p_db_objects; /* list of DbObject structures */ + GHashTable *p_db_objects_hash; /* key = table name, value = a DbObject structure */ + + gboolean override_mode; + + gint max_extract_stmt; /* 0 => don't keep GdaStatement */ + gint current_extract_stmt; + GHashTable *extract_stmt_hash; /* key = a SQL string, value = a #GdaStatement */ + + GRecMutex mutex; + /* Internal */ + GdaSqlParser *parser;; + GdaStatement **prep_stmts; /* Simple prepared statements, of size STMT_LAST, general usage */ + + /* Internal database's schema information */ + GSList *db_objects; /* list of DbObject structures */ + GHashTable *db_objects_hash; /* key = table name, value = a DbObject structure */ + GHashTable *table_cond_info_hash; /* key = string composed of the column names of + * the parameters separated by a period, + * value = a TableConditionInfo structure */ + GHashTable *provider_specifics; /* key = a ProviderSpecificKey , value = a ProviderSpecificValue */ + GdaSet *attributes_set; +} GdaMetaStorePrivate; + + +G_DEFINE_TYPE_WITH_PRIVATE (GdaMetaStore, gda_meta_store, G_TYPE_OBJECT) + +static void db_object_free (DbObject *dbobj); +static void create_db_objects (GdaMetaStorePrivate *priv, GdaMetaStore *store); + + +/* signals */ +enum { + SUGGEST_UPDATE, + META_CHANGED, + META_RESET, + LAST_SIGNAL +}; + +static gint gda_meta_store_signals[LAST_SIGNAL] = { 0, 0, 0 }; + +/* properties */ +enum { + PROP_0, + PROP_CNC_STRING, + PROP_CNC_OBJECT, + PROP_CATALOG, + PROP_SCHEMA +}; + +/* module error */ +GQuark gda_meta_store_error_quark (void) { + static GQuark quark; + if (!quark) + quark = g_quark_from_static_string ("gda_meta_store_error"); + return quark; +} + +static GdaStatement * +compute_prepared_stmt (GdaSqlParser *parser, const gchar *sql) { + GdaStatement *stmt; + stmt = gda_sql_parser_parse_string (parser, sql, NULL, NULL); + if (!stmt) + g_warning ("INTERNAL GdaMetaStore error: could not parse internal statement '%s'", sql); + return stmt; +} + +static guint +ProviderSpecific_hash (gconstpointer key) +{ + ProviderSpecificKey *pkey = (ProviderSpecificKey*) key; + return g_str_hash (pkey->path) + g_str_hash (pkey->prov) + + (pkey->expr ? g_str_hash (pkey->expr) : 0); +} + +static gboolean +ProviderSpecific_equal (gconstpointer a, gconstpointer b) +{ + ProviderSpecificKey *pa, *pb; + pa = (ProviderSpecificKey*) a; + pb = (ProviderSpecificKey*) b; + + if (strcmp (pa->prov, pb->prov) || + (pa->expr && !pb->expr) || + (pb->expr && !pa->expr) || + (pa->expr && pb->expr && strcmp (pa->expr, pb->expr)) || + strcmp (pa->path, pb->path)) + return FALSE; + else + return TRUE; +} + +static void +provider_specific_key_free (ProviderSpecificKey *key) +{ + g_free (key->expr); + g_free (key); +} +static void +provider_specific_value_free (ProviderSpecificValue *val) +{ + g_free (val->repl); + g_free (val); +} + +static gboolean +suggest_update_accumulator (G_GNUC_UNUSED GSignalInvocationHint *ihint, + GValue *return_accu, + const GValue *handler_return, + G_GNUC_UNUSED gpointer data) +{ + GError *error; + + error = g_value_get_boxed (handler_return); + g_value_set_boxed (return_accu, error); + + return error ? FALSE : TRUE; /* stop signal if 'thisvalue' is FALSE */ +} + +static GError * +m_suggest_update (G_GNUC_UNUSED GdaMetaStore *store, G_GNUC_UNUSED GdaMetaContext *suggest) +{ + return NULL; /* defaults allows update suggest */ +} + +static void +gda_meta_store_class_init (GdaMetaStoreClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + /** + * GdaMetaStore::suggest-update: + * @store: the #GdaMetaStore instance that emitted the signal + * @suggest: (type Gda.MetaContext): the suggested update, as a #GdaMetaContext structure + * + * This signal is emitted when the contents of a table should be updated (data to update or insert only; + * deleting data is done automatically). This signal is used for internal purposes by the #GdaConnection + * object. + * + * Returns: a new #GError error structure if there was an error when processing the + * signal, or %NULL if signal propagation should continue + **/ + gda_meta_store_signals[SUGGEST_UPDATE] = + g_signal_new ("suggest-update", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GdaMetaStoreClass, suggest_update), + suggest_update_accumulator, NULL, + _gda_marshal_ERROR__METACONTEXT, G_TYPE_ERROR, + 1, G_TYPE_POINTER); + /** + * GdaMetaStore::meta-changed: + * @store: the #GdaMetaStore instance that emitted the signal + * @changes: (type GLib.SList) (element-type Gda.MetaStoreChange): a list of changes made, as a #GSList of pointers to #GdaMetaStoreChange (which must not be modified) + * + * This signal is emitted when the @store's contents have changed (the changes are in the @changes list) + */ + gda_meta_store_signals[META_CHANGED] = + g_signal_new ("meta-changed", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (GdaMetaStoreClass, meta_changed), + NULL, NULL, + _gda_marshal_VOID__SLIST, G_TYPE_NONE, + 1, G_TYPE_POINTER); + /** + * GdaMetaStore::meta-reset: + * @store: the #GdaMetaStore instance that emitted the signal + * + * This signal is emitted when the @store's contents have been reset completely and when + * no detailed changes are available + */ + gda_meta_store_signals[META_RESET] = + g_signal_new ("meta-reset", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (GdaMetaStoreClass, meta_reset), + NULL, NULL, + _gda_marshal_VOID__VOID, G_TYPE_NONE, 0); + + klass->suggest_update = m_suggest_update; + klass->meta_changed = NULL; + klass->meta_reset = NULL; + + /* Properties */ + object_class->set_property = gda_meta_store_set_property; + object_class->get_property = gda_meta_store_get_property; + g_object_class_install_property (object_class, PROP_CNC_STRING, + g_param_spec_string ("cnc-string", NULL, _ ("Connection string for the internal connection to use"), NULL, + (G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY))); + g_object_class_install_property (object_class, PROP_CNC_OBJECT, + g_param_spec_object ("cnc", NULL, _ ("Connection object internally used"), GDA_TYPE_CONNECTION, + (G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY))); + g_object_class_install_property (object_class, PROP_CATALOG, + g_param_spec_string ("catalog", NULL, _ ("Catalog in which the database objects will be created"), NULL, + (G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY))); + g_object_class_install_property (object_class, PROP_SCHEMA, + g_param_spec_string ("schema", NULL, _ ("Schema in which the database objects will be created"), NULL, + (G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY))); + + object_class->constructor = gda_meta_store_constructor; + object_class->dispose = gda_meta_store_dispose; + object_class->finalize = gda_meta_store_finalize; +} + + +static void +gda_meta_store_init (GdaMetaStore *store) +{ + GdaMetaStorePrivate *priv = gda_meta_store_get_instance_private (store); + priv->cnc = NULL; + priv->ident_style = GDA_SQL_IDENTIFIERS_LOWER_CASE; + priv->reserved_keyword_func = NULL; + priv->schema_ok = FALSE; + + priv->init_error = NULL; + priv->version = 0; + + priv->catalog = NULL; + priv->schema = NULL; + + priv->p_db_objects = NULL; + priv->p_db_objects_hash = g_hash_table_new (g_str_hash, g_str_equal); + + priv->override_mode = FALSE; + + priv->max_extract_stmt = 10; + priv->current_extract_stmt = 0; + priv->extract_stmt_hash = NULL; + + /* Class private data */ + priv->prep_stmts = g_new0 (GdaStatement *, STMT_LAST); + priv->parser = gda_sql_parser_new (); + priv->provider_specifics = g_hash_table_new_full (ProviderSpecific_hash, + ProviderSpecific_equal, + (GDestroyNotify) provider_specific_key_free, + (GDestroyNotify) provider_specific_value_free); + + /* priv->provider_specifics = g_hash_table_new (ProviderSpecific_hash, ProviderSpecific_equal); */ + priv->db_objects_hash = g_hash_table_new (g_str_hash, g_str_equal); + create_db_objects (priv, NULL); + priv->table_cond_info_hash = g_hash_table_new (g_str_hash, g_str_equal); + + priv->prep_stmts[STMT_SET_VERSION] = + compute_prepared_stmt (priv->parser, + "INSERT INTO _attributes (att_name, att_value) VALUES ('_schema_version', ##version::string)"); + priv->prep_stmts[STMT_UPD_VERSION] = + compute_prepared_stmt (priv->parser, + "UPDATE _attributes SET att_value = ##version::string WHERE att_name = '_schema_version'"); + priv->prep_stmts[STMT_GET_VERSION] = + compute_prepared_stmt (priv->parser, + "SELECT att_value FROM _attributes WHERE att_name='_schema_version'"); + priv->prep_stmts[STMT_DEL_ATT_VALUE] = + compute_prepared_stmt (priv->parser, + "DELETE FROM _attributes WHERE att_name = ##name::string"); + priv->prep_stmts[STMT_SET_ATT_VALUE] = + compute_prepared_stmt (priv->parser, + "INSERT INTO _attributes VALUES (##name::string, ##value::string::null)"); + priv->prep_stmts[STMT_ADD_DECLARE_FK] = + compute_prepared_stmt (priv->parser, + "INSERT INTO __declared_fk (constraint_name, table_catalog, table_schema, table_name, column_name, ref_table_catalog, ref_table_schema, ref_table_name, ref_column_name) VALUES (##fkname::string, ##tcal::string, ##tschema::string, ##tname::string, ##colname::string, ##ref_tcal::string, ##ref_tschema::string, ##ref_tname::string, ##ref_colname::string)"); + priv->prep_stmts[STMT_DEL_DECLARE_FK] = + compute_prepared_stmt (priv->parser, + "DELETE FROM __declared_fk WHERE constraint_name = ##fkname::string AND table_catalog = ##tcal::string AND table_schema = ##tschema::string AND table_name = ##tname::string AND ref_table_catalog = ##ref_tcal::string AND ref_table_schema = ##ref_tschema::string AND ref_table_name = ##ref_tname::string"); + priv->attributes_set = NULL; +/*#define GDA_DEBUG_GRAPH*/ +#ifdef GDA_DEBUG_GRAPH +#define INFORMATION_SCHEMA_GRAPH_FILE "information_schema.dot" + GString *string; + GSList *list; + string = g_string_new ("digraph G {\nrankdir = RL;\nnode [shape = box];\n"); + for (list = priv->db_objects; list; list = list->next) { + DbObject *dbo = (DbObject*) list->data; + switch (dbo->obj_type) { + case GDA_SERVER_OPERATION_CREATE_TABLE: + g_string_append_printf (string, "%s;\n", dbo->obj_name); + break; + case GDA_SERVER_OPERATION_CREATE_VIEW: + g_string_append_printf (string, "%s [ shape = ellipse ];\n", dbo->obj_name); + break; + default: + g_string_append_printf (string, "%s [ shape = note ];\n", dbo->obj_name); + break; + } + + GSList *dep_list; + for (dep_list = dbo->depend_list; dep_list; dep_list = dep_list->next) + g_string_append_printf (string, "%s -> %s\n", dbo->obj_name, + ((DbObject*) dep_list->data)->obj_name); + } + g_string_append_c (string, '}'); + GError *lerror = NULL; + if (g_file_set_contents (INFORMATION_SCHEMA_GRAPH_FILE, string->str, -1, &lerror)) + g_print ("Information schema graph written to '%s'\n" + "Use 'dot' (from the GraphViz package) to create a picture, for example:\n" + "\tdot -Tpng -o graph.png %s\n", INFORMATION_SCHEMA_GRAPH_FILE, INFORMATION_SCHEMA_GRAPH_FILE); + else { + g_print ("Information schema graph not written to '%s': %s\n", INFORMATION_SCHEMA_GRAPH_FILE, + lerror && lerror->message ? lerror->message : "No detail"); + if (lerror) + g_error_free (lerror); + } + g_string_free (string, TRUE); +#endif + + g_rec_mutex_init (& (priv->mutex)); +} + +static GObject * +gda_meta_store_constructor (GType type, + guint n_construct_properties, + GObjectConstructParam *construct_properties) +{ + GObject *object; + guint i; + GdaMetaStore *store; + gboolean been_specified = FALSE; + + static GRecMutex init_rmutex; + g_rec_mutex_lock (&init_rmutex); + object = G_OBJECT_CLASS (G_OBJECT_CLASS (gda_meta_store_parent_class))->constructor (type, + n_construct_properties, + construct_properties); + for (i = 0; i< n_construct_properties; i++) { + GObjectConstructParam *prop = &(construct_properties[i]); + if (!strcmp (g_param_spec_get_name (prop->pspec), "cnc-string")) { + if (g_value_get_string (prop->value)) + been_specified = TRUE; + } + else if (!strcmp (g_param_spec_get_name (prop->pspec), "system-filename")) { + if (g_value_get_pointer (prop->value)) + been_specified = TRUE; + } + } + store = (GdaMetaStore *) object; + GdaMetaStorePrivate *priv = gda_meta_store_get_instance_private (store); + + if (!priv->cnc && !been_specified) { + /* in memory DB */ + g_object_set (object, "cnc-string", "SQLite://DB_DIR=.;DB_NAME=__gda_tmp", NULL); + } + + if (priv->cnc) { + gda_lockable_lock (GDA_LOCKABLE (priv->cnc)); + gda_connection_increase_usage (priv->cnc); /* USAGE ++ */ + priv->schema_ok = initialize_cnc_struct (store, &(priv->init_error)); + gda_connection_decrease_usage (priv->cnc); /* USAGE -- */ + gda_lockable_unlock (GDA_LOCKABLE (priv->cnc)); + } + + /* create a local copy of all the DbObject structures defined in klass->cpriv */ + if (priv->catalog && !priv->schema) { + if (! priv->init_error) + g_set_error (&(priv->init_error), GDA_META_STORE_ERROR, + GDA_META_STORE_INCORRECT_SCHEMA_ERROR, + "%s", + _("Catalog specified but no schema specified, store will not be usable")); + priv->schema_ok = FALSE; + } + else { + GdaMetaStoreClass *klass = (GdaMetaStoreClass *) G_OBJECT_GET_CLASS (store); + GSList *list; + if (!priv->schema) { + /* uses all the priv->db_objects AS IS in priv->p_db_objects */ + priv->p_db_objects = g_slist_copy (priv->db_objects); + for (list = priv->p_db_objects; list; list = list->next) + g_hash_table_insert (priv->p_db_objects_hash, DB_OBJECT (list->data)->obj_name, + list->data); + } + else + create_db_objects (priv, store); + } + g_rec_mutex_unlock (&init_rmutex); + return object; +} + +/** + * gda_meta_store_new_with_file: + * @file_name: a file name + * + * Create a new #GdaMetaStore object using @file_name as its internal + * database + * + * Returns: (transfer full): the newly created object, or %NULL if an error occurred + */ +GdaMetaStore * +gda_meta_store_new_with_file (const gchar *file_name) +{ + gchar *string; + gchar *base, *dir; + GdaMetaStore *store; + + g_return_val_if_fail (file_name && *file_name, NULL); + + base = g_path_get_basename (file_name); + dir = g_path_get_dirname (file_name); + if (g_str_has_suffix (base, ".db")) + base [strlen (base) - 3] = 0; + string = g_strdup_printf ("SQLite://DB_DIR=%s;DB_NAME=%s", dir, base); + g_free (base); + g_free (dir); + store = gda_meta_store_new (string); + g_free (string); + return store; +} + +/** + * gda_meta_store_new: + * @cnc_string: (nullable): a connection string, or %NULL for an in-memory internal database + * + * Create a new #GdaMetaStore object. + * + * Returns: (transfer full): the newly created object, or %NULL if an error occurred + */ +GdaMetaStore * +gda_meta_store_new (const gchar *cnc_string) +{ + GObject *obj; + GdaMetaStore *store; +#ifdef GDA_DEBUG_NO + GTimer *timer; + timer = g_timer_new (); +#endif + static GRecMutex init_rmutex; + g_rec_mutex_lock (&init_rmutex); + if (cnc_string) + obj = g_object_new (GDA_TYPE_META_STORE, "cnc-string", cnc_string, NULL); + else + obj = g_object_new (GDA_TYPE_META_STORE, "cnc-string", "SQLite://DB_NAME=__gda_tmp", NULL); + g_rec_mutex_unlock (&init_rmutex); +#ifdef GDA_DEBUG_NO + g_timer_stop (timer); + g_print ("GdaMetaStore took %.03f sec. to create.\n", g_timer_elapsed (timer, NULL)); + g_timer_destroy (timer); +#endif + store = GDA_META_STORE (obj); + GdaMetaStorePrivate *priv = gda_meta_store_get_instance_private (store); + if (!priv->cnc) { + g_object_unref (store); + store = NULL; + } + else { + if (gda_lockable_trylock (GDA_LOCKABLE (priv->cnc))) + gda_lockable_unlock (GDA_LOCKABLE (priv->cnc)); + else { + g_warning (_("Can't obtain connection lock")); + g_object_unref (store); + store = NULL; + } + } + + return store; +} + +static void +gda_meta_store_dispose (GObject *object) +{ + GdaMetaStore *store; + + g_return_if_fail (GDA_IS_META_STORE (object)); + + store = GDA_META_STORE (object); + GdaMetaStorePrivate *priv = gda_meta_store_get_instance_private (store); + GSList *list; + + if (priv->extract_stmt_hash) { + g_hash_table_destroy (priv->extract_stmt_hash); + priv->extract_stmt_hash = NULL; + } + + if (priv->override_mode) + _gda_meta_store_cancel_data_reset (store, NULL); + + g_free (priv->catalog); + g_free (priv->schema); + + /* custom db objects */ + g_hash_table_destroy (priv->p_db_objects_hash); + for (list = priv->p_db_objects; list; list = list->next) { + if (DB_OBJECT (list->data)->store == store) + db_object_free (DB_OBJECT (list->data)); + } + g_slist_free (priv->p_db_objects); + + /* internal connection */ + if (priv->cnc) { + g_object_unref (G_OBJECT (priv->cnc)); + priv->cnc = NULL; + } + if (priv->parser) { + g_object_unref (G_OBJECT (priv->parser)); + priv->parser = NULL; + } + if (priv->db_objects) { + g_slist_free_full (priv->db_objects, (GDestroyNotify) db_object_free); + priv->db_objects = NULL; + } + if (priv->db_objects_hash) { + g_hash_table_unref (priv->db_objects_hash); + priv->db_objects_hash = NULL; + } + if (priv->table_cond_info_hash) { + g_hash_table_unref (priv->table_cond_info_hash); + priv->table_cond_info_hash = NULL; + } + if (priv->provider_specifics) { + g_hash_table_unref (priv->provider_specifics); + priv->provider_specifics = NULL; + } + if (priv->prep_stmts) { + g_object_unref (priv->prep_stmts[STMT_SET_VERSION]); + g_object_unref (priv->prep_stmts[STMT_UPD_VERSION]); + g_object_unref (priv->prep_stmts[STMT_GET_VERSION]); + g_object_unref (priv->prep_stmts[STMT_DEL_ATT_VALUE]); + g_object_unref (priv->prep_stmts[STMT_SET_ATT_VALUE]); + g_object_unref (priv->prep_stmts[STMT_ADD_DECLARE_FK]); + g_object_unref (priv->prep_stmts[STMT_DEL_DECLARE_FK]); + g_free (priv->prep_stmts); + priv->prep_stmts = NULL; + } + if (priv->attributes_set != NULL) { + g_object_unref (priv->attributes_set); + priv->attributes_set = NULL; + } + + g_rec_mutex_clear (& (priv->mutex)); + + /* parent class */ + G_OBJECT_CLASS (gda_meta_store_parent_class)->dispose (object); +} + +static void +gda_meta_store_finalize (GObject *object) +{ + GdaMetaStore *store; + + g_return_if_fail (object != NULL); + g_return_if_fail (GDA_IS_META_STORE (object)); + + store = GDA_META_STORE (object); + GdaMetaStorePrivate *priv = gda_meta_store_get_instance_private (store); + if (priv->init_error) + g_error_free (priv->init_error); + + /* parent class */ + G_OBJECT_CLASS (gda_meta_store_parent_class)->finalize (object); +} + +static void +gda_meta_store_set_property (GObject *object, + guint param_id, + const GValue *value, + GParamSpec *pspec) +{ + GdaMetaStore *store; + const gchar *cnc_string; + + store = GDA_META_STORE (object); + GdaMetaStorePrivate *priv = gda_meta_store_get_instance_private (store); + switch (param_id) { + case PROP_CNC_STRING: + if (!priv->cnc) { + cnc_string = g_value_get_string (value); + if (cnc_string) { + GdaConnection *cnc; + GError *error = NULL; + cnc = gda_connection_new_from_string (NULL, cnc_string, NULL, + GDA_CONNECTION_OPTIONS_NONE, + &error); + if (cnc) { + if (!gda_connection_open (cnc, &error)) { + g_object_unref (cnc); + g_warning (_("Could not open internal GdaMetaStore connection: %s"), + error && error->message ? error->message : _("No detail")); + g_clear_error (&error); + cnc = NULL; + } + } else { + g_warning (_("Could not create internal GdaMetaStore connection: %s"), + error && error->message ? error->message : _("No detail")); + g_clear_error (&error); + if (g_ascii_strcasecmp (cnc_string, "sqlite")) { + /* use _gda_config_sqlite_provider */ + g_clear_error (&error); + cnc = _gda_open_internal_sqlite_connection (cnc_string); + } + } + priv->cnc = cnc; + } + } + break; + case PROP_CNC_OBJECT: + if (!priv->cnc) + priv->cnc = g_value_dup_object (value); + break; + case PROP_CATALOG: + g_free (priv->catalog); + if (g_value_get_string (value) && *g_value_get_string (value)) + priv->catalog = g_strdup (g_value_get_string (value)); + else + priv->catalog = NULL; + break; + case PROP_SCHEMA: + g_free (priv->schema); + if (g_value_get_string (value) && *g_value_get_string (value)) + priv->schema = g_strdup (g_value_get_string (value)); + else + priv->schema = NULL; + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + break; + } +} + +static void +gda_meta_store_get_property (GObject *object, + guint param_id, + GValue *value, + GParamSpec *pspec) +{ + GdaMetaStore *store; + store = GDA_META_STORE (object); + GdaMetaStorePrivate *priv = gda_meta_store_get_instance_private (store); + + switch (param_id) { + case PROP_CNC_STRING: + g_assert_not_reached (); + break; + case PROP_CNC_OBJECT: + g_value_set_object (value, (GObject *) priv->cnc); + break; + case PROP_CATALOG: + g_value_set_string (value, priv->catalog); + break; + case PROP_SCHEMA: + g_value_set_string (value, priv->schema); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + break; + } +} + +/** + * gda_meta_store_set_identifiers_style: + * @store: a #GdaMetaStore object + * @style: a style + * + * Specifies how @store must handle SQL identifiers it has to store. This method is mainly used by + * database providers. + * + * Since: 4.2 + */ +void +gda_meta_store_set_identifiers_style (GdaMetaStore *store, GdaSqlIdentifierStyle style) +{ + g_return_if_fail (GDA_IS_META_STORE (store)); + GdaMetaStorePrivate *priv = gda_meta_store_get_instance_private (store); + priv->ident_style = style; +} + +/** + * gda_meta_store_set_reserved_keywords_func: + * @store: a #GdaMetaStore object + * @func: (nullable) (scope call): a #GdaSqlReservedKeywordsFunc function, or %NULL + * + * Specifies a function which @store will use to determine if a keyword is an SQL reserved + * keyword or not. + * + * This method is mainly used by database providers. + * + * Since: 4.2 + */ +void +gda_meta_store_set_reserved_keywords_func(GdaMetaStore *store, GdaSqlReservedKeywordsFunc func) +{ + g_return_if_fail (GDA_IS_META_STORE (store)); + GdaMetaStorePrivate *priv = gda_meta_store_get_instance_private (store); + priv->reserved_keyword_func = func; +} + +/* + * Checks the structure of @priv->cnc and update it if necessary + */ +static gboolean prepare_server_operations (GdaMetaStore *store, GError **error); +static gboolean handle_schema_version (GdaMetaStore *store, gboolean *schema_present, GError **error); +static gboolean +initialize_cnc_struct (GdaMetaStore *store, GError **error) +{ + gboolean schema_present; + GdaMetaStorePrivate *priv = gda_meta_store_get_instance_private (store); + g_return_val_if_fail (GDA_IS_CONNECTION (priv->cnc), FALSE); + g_return_val_if_fail (gda_connection_is_opened (priv->cnc), FALSE); + + if (handle_schema_version (store, &schema_present, error)) + return TRUE; + if (schema_present) + return FALSE; + + g_clear_error (error); + + /* assume schema not present => create it */ + GSList *list; + gboolean allok = TRUE; + GdaServerProvider *prov; + if (!prepare_server_operations (store, error)) + return FALSE; + + prov = gda_connection_get_provider (priv->cnc); + for (list = priv->db_objects; list; list = list->next) { + DbObject *dbo = DB_OBJECT (list->data); + if (dbo->create_op) { + if (!gda_server_provider_perform_operation (prov, priv->cnc, dbo->create_op, error)) { + gchar *sql = NULL; + GError *lerror = NULL; + sql = gda_server_operation_render (dbo->create_op, &lerror); + if (sql == NULL) { + g_warning (_("Internal error while trying to render operation in MetaStore creation: %s"), + lerror && lerror->message ? lerror->message : _("No error was set")); + g_clear_error (&lerror); + } else { + g_warning ("Interna Error. Operation tried to create MetaStore table '%s': %s", + dbo->obj_name, sql); + } + g_warning (_("Internal Error. Couldn't create MetaStore table '%s': %s"), + dbo->obj_name, + (*error) && (*error)->message ? (*error)->message : _("No error was set")); + allok = FALSE; + break; + } + g_object_unref (dbo->create_op); + dbo->create_op = NULL; + } + } + if (!allok) + return FALSE; + + /* set version info to CURRENT_SCHEMA_VERSION */ + GdaSet *params; + if (! gda_statement_get_parameters (priv->prep_stmts[STMT_SET_VERSION], ¶ms, NULL)) { + g_set_error (error, GDA_META_STORE_ERROR, GDA_META_STORE_INCORRECT_SCHEMA_ERROR, + "%s", _ ("Could not set the internal schema's version. No prepared statement's parameters were found")); + return FALSE; + } + g_assert (gda_set_set_holder_value (params, NULL, "version", CURRENT_SCHEMA_VERSION)); + if (gda_connection_statement_execute_non_select (priv->cnc, + priv->prep_stmts[STMT_SET_VERSION], + params, NULL, NULL) == -1) { + g_object_unref (params); + g_set_error (error, GDA_META_STORE_ERROR, GDA_META_STORE_INCORRECT_SCHEMA_ERROR, + "%s", _ ("Could not set the internal schema's version. Statement execution fails")); + return FALSE; + } + g_object_unref (params); + + return handle_schema_version (store, NULL, error); +} + + +static GdaServerOperation *create_server_operation_for_table (GHashTable *specific_hash, + GdaServerProvider *prov, GdaConnection *cnc, + DbObject *dbobj, GError **error); +static GdaServerOperation *create_server_operation_for_view (GHashTable *specific_hash, + GdaServerProvider *prov, GdaConnection *cnc, + DbObject *dbobj, GError **error); +static gboolean prepare_dbo_server_operation (GdaMetaStorePrivate *priv, GdaMetaStore *store, GdaServerProvider *prov, + DbObject *dbo, GError **error); +static gboolean +prepare_server_operations (GdaMetaStore *store, GError **error) +{ + GSList *objects; + GdaMetaStorePrivate *priv = gda_meta_store_get_instance_private (store); + + for (objects = priv->db_objects; objects; objects = objects->next) { + DbObject *dbo = DB_OBJECT (objects->data); + if (! prepare_dbo_server_operation (priv, store, gda_connection_get_provider (priv->cnc), + dbo, error)) + return FALSE; + } + + return TRUE; +} + +static gboolean +prepare_dbo_server_operation (GdaMetaStorePrivate *priv, GdaMetaStore *store, GdaServerProvider *prov, + DbObject *dbo, GError **error) +{ + if (dbo->create_op) { + g_object_unref (dbo->create_op); + dbo->create_op = NULL; + } + + switch (dbo->obj_type) { + case GDA_SERVER_OPERATION_CREATE_TABLE: + dbo->create_op = create_server_operation_for_table (priv->provider_specifics, + prov, priv->cnc, dbo, error); + if (!dbo->create_op) + return FALSE; + break; + case GDA_SERVER_OPERATION_CREATE_VIEW: + dbo->create_op = create_server_operation_for_view (priv->provider_specifics, + prov, priv->cnc, dbo, error); + if (!dbo->create_op) + return FALSE; + break; + default: + break; + } + return TRUE; +} + +static const gchar * +provider_specific_match (GHashTable *specific_hash, GdaServerProvider *prov, const gchar *expr, const gchar *path) +{ + ProviderSpecificKey spec; + ProviderSpecificValue *val; + + spec.prov = (gchar *) gda_server_provider_get_name (prov); + spec.path = (gchar *) path; + spec.expr = (gchar *) expr; + val = g_hash_table_lookup (specific_hash, &spec); + /*g_print ("RULESEARCH %s, %s, %s => %s\n", spec.prov, spec.path, spec.expr, val ? val->repl : "-no rule found-");*/ + if (val) + return val->repl; + else + return expr; +} + +static GdaServerOperation * +create_server_operation_for_table (GHashTable *specific_hash, + GdaServerProvider *prov, GdaConnection *cnc, DbObject *dbobj, GError **error) +{ + GdaServerOperation *op; + GSList *list; + gint index; + const gchar *repl; + + op = gda_server_provider_create_operation (prov, cnc, dbobj->obj_type, NULL, error); + if (!op) + return NULL; + if (! gda_server_operation_set_value_at (op, dbobj->obj_name, error, "/TABLE_DEF_P/TABLE_NAME")) + goto onerror; + + if (!gda_server_operation_set_value_at (op, + GDA_BOOL_TO_STR (TRUE), + error, + "/TABLE_DEF_P/TABLE_IFNOTEXISTS")) + return FALSE; + + /* columns */ + for (index = 0, list = TABLE_INFO (dbobj)->columns; list; list = list->next, index++) { + TableColumn *tcol = TABLE_COLUMN (list->data); + if (! gda_server_operation_set_value_at (op, tcol->column_name, error, + "/FIELDS_A/@COLUMN_NAME/%d", index)) + goto onerror; + repl = provider_specific_match (specific_hash, prov, tcol->column_type ? tcol->column_type : "string", + "/FIELDS_A/@COLUMN_TYPE"); + if (! gda_server_operation_set_value_at (op, repl ? repl : "string", error, + "/FIELDS_A/@COLUMN_TYPE/%d", index)) + goto onerror; + if (! gda_server_operation_set_value_at (op, NULL, error, + "/FIELDS_A/@COLUMN_SIZE/%d", index)) + goto onerror; + if (! gda_server_operation_set_value_at (op, tcol->nullok ? "FALSE" : "TRUE", error, + "/FIELDS_A/@COLUMN_NNUL/%d", index)) + goto onerror; + if (! gda_server_operation_set_value_at (op, tcol->autoinc ? "TRUE" : "FALSE", error, + "/FIELDS_A/@COLUMN_AUTOINC/%d", index)) + goto onerror; + repl = provider_specific_match (specific_hash, prov, "dummy", "/FIELDS_A/@COLUMN_PKEY"); + if (repl) { + if (! gda_server_operation_set_value_at (op, tcol->pkey ? "TRUE" : "FALSE", error, + "/FIELDS_A/@COLUMN_PKEY/%d", index)) + goto onerror; + } + else { + if (! gda_server_operation_set_value_at (op, "FALSE", error, "/FIELDS_A/@COLUMN_PKEY/%d", index)) + goto onerror; + } + } + + /* foreign keys: just used as an indication by the GdaMetaStore object: they are not enforced because + * the database may not be up to date everywhere at any time and because the references are sometimes + * on views and not on tables, which is not supported by databases */ + + return op; + onerror: + g_object_unref (op); + return NULL; +} + +static GdaServerOperation * +create_server_operation_for_view (G_GNUC_UNUSED GHashTable *specific_hash, + GdaServerProvider *prov, GdaConnection *cnc, DbObject *dbobj, GError **error) +{ + GdaServerOperation *op; + + op = gda_server_provider_create_operation (prov, cnc, dbobj->obj_type, NULL, error); + if (!op) + return NULL; + if (! gda_server_operation_set_value_at (op, dbobj->obj_name, error, "/VIEW_DEF_P/VIEW_NAME")) + goto onerror; + if (! gda_server_operation_set_value_at (op, VIEW_INFO (dbobj)->view_def, error, "/VIEW_DEF_P/VIEW_DEF")) + goto onerror; + + return op; + onerror: + g_object_unref (op); + return NULL; +} + +/* + * Returns: -1 if column not found + */ +static gint +column_name_to_index (TableInfo *tinfo, const gchar *column_name) +{ + GSList *list; + gint i; + for (i = 0, list = tinfo->columns; list; list = list->next, i++) + if (!strcmp (TABLE_COLUMN (list->data)->column_name, column_name)) + return i; + return -1; +} + +static DbObject *create_table_object (GdaMetaStorePrivate *priv, GdaMetaStore *store, xmlNodePtr node, GError **error); +static DbObject *create_view_object (GdaMetaStorePrivate *priv, GdaMetaStore *store, xmlNodePtr node, GError **error); +static GSList *reorder_db_objects (GSList *objects, GHashTable *hash); +static gboolean complement_db_objects (GSList *objects, GHashTable *hash, GError **error); + +/* + * Creates all DbObject structures and place them into priv->db_objects or priv->p_db_objects + * + * If @store is %NULL, then all the DB objects created are attached to priv->db_objects, otherwise + * they are placed in priv->p_db_objects + */ +static void +create_db_objects (GdaMetaStorePrivate *priv, GdaMetaStore *store) +{ + xmlNodePtr node; + GError *lerror = NULL; + GError **error = &lerror; + GOutputStream *ostream; + GInputStream *istream; + GFile *res; + xmlDocPtr doc = NULL; + gssize size; + gchar *schema; + + /* load information schema's structure XML file */ + ostream = g_memory_output_stream_new_resizable (); + res = g_file_new_for_uri ("resource:///libgda/information_schema.xml"); + istream = G_INPUT_STREAM (g_file_read (res, NULL, &lerror)); + if (istream == NULL) { + g_warning (_("Internal error: no information schema was found: %s"), + lerror && lerror->message ? lerror->message : "No error message was set"); + g_clear_error (&lerror); + return; + } + g_clear_error (&lerror); + size = g_output_stream_splice (ostream, istream, G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE, NULL, &lerror); + if (size == -1) { + g_warning (_("Internal error: can't read information schema: %s"), + lerror && lerror->message ? lerror->message : "No error message was set"); + g_clear_error (&lerror); + return; + } + g_clear_error (&lerror); + schema = (gchar*) g_memory_output_stream_get_data (G_MEMORY_OUTPUT_STREAM (ostream)); + doc = xmlReadDoc ((const xmlChar*) schema, "", NULL, XML_PARSE_RECOVER); + g_object_unref (ostream); + g_object_unref (istream); + g_object_unref (res); + + node = xmlDocGetRootElement (doc); + if (!node || strcmp ((gchar *) node->name, "schema")) { + g_warning ("Root node of current information schema should be ."); + return; + } + + /* walk through the xmlDoc */ + if (store) { + priv->p_db_objects = NULL; + } else + priv->db_objects = NULL; + for (node = node->children; node; node = node->next) { + /* tag to allow for provider specific transformations */ + if (!strcmp ((gchar *) node->name, "specifics")) { + xmlNodePtr snode; + for (snode = node->children; snode; snode = snode->next) { + if (strcmp ((gchar *) snode->name, "provider")) + continue; + xmlChar *pname; + pname = xmlGetProp (snode, BAD_CAST "name"); + if (!pname) { + g_warning (" section ignored because no provider name specified"); + continue; /* ignore this section */ + } + + xmlNodePtr rnode; + gboolean pname_used = FALSE; + for (rnode = snode->children; rnode; rnode = rnode->next) { + if (!strcmp ((gchar *) rnode->name, "replace") || + !strcmp ((gchar *) rnode->name, "ignore")) { + xmlChar *context; + context = xmlGetProp (rnode, BAD_CAST "context"); + if (!context) { + g_warning ("<%s> section ignored because no context specified", + snode->name); + continue; + } + ProviderSpecificKey *key = g_new0 (ProviderSpecificKey, 1); + ProviderSpecificValue *val = g_new0 (ProviderSpecificValue, 1); + key->prov = (gchar *) pname; + pname_used = TRUE; + key->path = (gchar *) context; + key->expr = (gchar *) xmlGetProp (rnode, BAD_CAST "expr"); + val->repl = (gchar *) xmlGetProp (rnode, BAD_CAST "replace_with"); + g_hash_table_insert (priv->provider_specifics, key, val); + /*g_print ("RULE: %s, %s, %s => %s\n", key->prov, + key->path, key->expr, val->repl);*/ + } + } + if (!pname_used) + xmlFree (pname); + } + } + + /*
tag for table creation */ + else if (!strcmp ((gchar *) node->name, "table")) { + DbObject *dbo; + dbo = create_table_object (priv, store, node, error); + if (!dbo) + g_error ("Information schema creation error: %s", + lerror && lerror->message ? lerror->message : "No detail"); + } + /* tag for view creation */ + else if (!strcmp ((gchar *) node->name, "view")) { + DbObject *dbo; + dbo = create_view_object (priv, store, node, error); + if (!dbo) + g_error ("Information schema creation error: %s", + lerror && lerror->message ? lerror->message : "No detail"); + } + } + xmlFreeDoc (doc); + + if (store) { + priv->p_db_objects = reorder_db_objects (priv->p_db_objects, priv->p_db_objects_hash); + if (!complement_db_objects (priv->p_db_objects, priv->p_db_objects_hash, error)) + g_error ("Information schema structure error: %s", + lerror && lerror->message ? lerror->message : "No detail"); + } + else { + priv->db_objects = reorder_db_objects (priv->db_objects, priv->db_objects_hash); + if (!complement_db_objects (priv->db_objects, priv->db_objects_hash, error)) + g_error ("Information schema structure error: %s", + lerror && lerror->message ? lerror->message : "No detail"); + } + + /* make sure that for each Table DbObject, every TableFKey in @fk_list references a primary key of the referenced table */ + GSList *list; + for (list = priv->db_objects; list; list = list->next) { + DbObject *dbo; + dbo = DB_OBJECT (list->data); + + if (dbo->obj_type != GDA_SERVER_OPERATION_CREATE_TABLE) + continue; + + TableInfo *tinfo; + GSList *fklist; + tinfo = TABLE_INFO (dbo); + for (fklist = tinfo->fk_list; fklist; fklist = fklist->next) { + TableFKey *tfk; + TableInfo *reftinfo; + gint i; + tfk = (TableFKey*) fklist->data; + if (tfk->table_info != dbo) + g_error ("Information schema structure error for table '%s': " + "Foreign key structure attached to wrong table", dbo->obj_name); + if (!tfk->depend_on || (tfk->depend_on->obj_type != GDA_SERVER_OPERATION_CREATE_TABLE)) + g_error ("Information schema structure error for table '%s': " + "Foreign key references an object '%s' which is not a table", + dbo->obj_name, tfk->depend_on ? tfk->depend_on->obj_name : "nothing referenced"); + reftinfo = TABLE_INFO (tfk->depend_on); + if (tfk->cols_nb <= 0) + g_error ("Information schema structure error for table '%s': " + "Foreign key is not composed of at least one column", dbo->obj_name); + if (!tfk->fk_cols_array || !tfk->fk_names_array || + !tfk->ref_pk_cols_array || !tfk->ref_pk_names_array) + g_error ("Information schema structure error for table '%s': " + "Foreign key is not completely defined", dbo->obj_name); + for (i = 0; i < tfk->cols_nb; i++) { + gint j; + for (j = 0; j < tfk->cols_nb; j++) { + if ((i != j) && (tfk->ref_pk_cols_array [i] == tfk->ref_pk_cols_array [j])) + g_error ("Information schema structure error for table '%s': " + "column is referenced twice, at position %d and %d", dbo->obj_name, + tfk->ref_pk_cols_array [i], tfk->ref_pk_cols_array [j]); + } + } + for (i = 0; i < tfk->cols_nb; i++) { + TableColumn *tcol; + tcol = g_slist_nth_data (reftinfo->columns, tfk->ref_pk_cols_array [i]); + if (!tcol) + g_error ("Information schema structure error for table '%s': " + "cannot identify column at position %d", dbo->obj_name, tfk->ref_pk_cols_array [i]); + if (!tcol->pkey) + g_error ("Information schema structure error for table '%s': " + "referenced column at position %d is not part of a primary key", + dbo->obj_name, tfk->ref_pk_cols_array [i]); + if (column_name_to_index (reftinfo, tfk->ref_pk_names_array [i]) != tfk->ref_pk_cols_array [i]) + g_error ("Information schema structure error for table '%s': " + "referenced column at position %d has wrong associated name '%s'", + dbo->obj_name, tfk->ref_pk_cols_array [i], tfk->ref_pk_names_array [i]); + } + if (tfk->cols_nb != reftinfo->pk_cols_nb) + g_error ("Information schema structure error for table '%s': " + "Foreign key does only reference part of reterenced table's primary key", + dbo->obj_name); + } + } +} + +static void compute_view_dependencies (GdaMetaStorePrivate *priv, GdaMetaStore *store, + DbObject *view_dbobj, GdaSqlStatement *sqlst); +static DbObject * +create_view_object (GdaMetaStorePrivate *priv, GdaMetaStore *store, xmlNodePtr node, GError **error) +{ + DbObject *dbobj = NULL; + xmlChar *view_name; + gchar *complete_obj_name = NULL; + + view_name = xmlGetProp (node, BAD_CAST "name"); + if (!view_name) { + g_set_error (error, GDA_META_STORE_ERROR, GDA_META_STORE_META_CONTEXT_ERROR, + "%s", _("Missing view name from node")); + return NULL; + } + + /* determine object's complete name */ + if (store) { + if (priv->schema) { + complete_obj_name = g_strdup_printf ("%s.%s", priv->schema, (gchar *) view_name); + } + } else + complete_obj_name = g_strdup ((gchar *) view_name); + + /* DbObject structure */ + if (store) { + dbobj = g_hash_table_lookup (priv->p_db_objects_hash, view_name); + } else + dbobj = g_hash_table_lookup (priv->db_objects_hash, view_name); + if (!dbobj) { + dbobj = g_new0 (DbObject, 1); + dbobj->store = store; + dbobj->obj_name = g_strdup ((gchar *) view_name); + if (store) { + priv->p_db_objects = g_slist_prepend (priv->p_db_objects, dbobj); + g_hash_table_insert (priv->p_db_objects_hash, dbobj->obj_name, dbobj); + } + else { + priv->db_objects = g_slist_prepend (priv->db_objects, dbobj); + g_hash_table_insert (priv->db_objects_hash, dbobj->obj_name, dbobj); + } + } + xmlFree (view_name); + dbobj->obj_type = GDA_SERVER_OPERATION_CREATE_VIEW; + + /* walk through the view attributes */ + xmlNodePtr cnode; + for (cnode = node->children; cnode; cnode = cnode->next) { + xmlChar *def; + if (strcmp ((gchar *) cnode->name, "definition")) + continue; + def = xmlNodeGetContent (cnode); + if (!def) { + g_set_error (error, GDA_META_STORE_ERROR, GDA_META_STORE_META_CONTEXT_ERROR, + "%s", _("Missing view definition from node")); + goto onerror; + } + + /* use a parser to analyze the view dependencies */ + GdaStatement *stmt; + const gchar *remain; + stmt = gda_sql_parser_parse_string (priv->parser, (gchar *) def, &remain, error); + if (!stmt) { + xmlFree (def); + goto onerror; + } + if (remain) { + g_set_error (error, GDA_META_STORE_ERROR, GDA_META_STORE_META_CONTEXT_ERROR, + _("View definition contains more than one statement (for view '%s')"), + complete_obj_name); + g_object_unref (stmt); + xmlFree (def); + goto onerror; + } + VIEW_INFO (dbobj)->view_def = g_strdup ((gchar *) def); + xmlFree (def); + + if ((gda_statement_get_statement_type (stmt) == GDA_SQL_STATEMENT_SELECT) || + (gda_statement_get_statement_type (stmt) == GDA_SQL_STATEMENT_COMPOUND)) { + GdaSqlStatement *sqlst; + g_object_get (G_OBJECT (stmt), "structure", &sqlst, NULL); + compute_view_dependencies (priv, store, dbobj, sqlst); + gda_sql_statement_free (sqlst); + g_object_unref (stmt); + +#ifdef GDA_DEBUG_NO + g_print ("View %s depends on: ", complete_obj_name); + GSList *list; + for (list = dbobj->depend_list; list; list = list->next) + g_print ("%s ", DB_OBJECT (list->data)->obj_name); + g_print ("\n"); +#endif + } + else { + g_set_error (error, GDA_META_STORE_ERROR, GDA_META_STORE_META_CONTEXT_ERROR, + _("View definition is not a selection statement (for view '%s')"), + complete_obj_name); + g_object_unref (stmt); + goto onerror; + } + } + g_free (complete_obj_name); + return dbobj; + +onerror: + g_free (complete_obj_name); + db_object_free (dbobj); + return NULL; +} + +static GdaSqlExpr *make_expr_EQUAL (GdaSqlAnyPart *parent, xmlChar *cname, xmlChar *type, GType ptype, gboolean nullok, gint index); +static GdaSqlExpr *make_expr_AND (GdaSqlAnyPart *parent, GdaSqlExpr *current); +static DbObject * +create_table_object (GdaMetaStorePrivate *priv, GdaMetaStore *store, xmlNodePtr node, GError **error) +{ + DbObject *dbobj; + xmlChar *table_name; + gchar *complete_obj_name; + + table_name = xmlGetProp (node, BAD_CAST "name"); + if (!table_name) { + g_set_error (error, GDA_META_STORE_ERROR, GDA_META_STORE_SCHEMA_OBJECT_DESCR_ERROR, + "%s", _("Missing table name from
node")); + return NULL; + } + + /* determine object's complete name */ + if (store) + { + priv = gda_meta_store_get_instance_private (store); + if (priv->schema) + complete_obj_name = g_strdup_printf ("%s.%s", priv->schema, (gchar *) table_name); + else + complete_obj_name = g_strdup ((gchar *) table_name); + } + else + complete_obj_name = g_strdup ((gchar *) table_name); + + /* DbObject structure */ + if (store) { + priv = gda_meta_store_get_instance_private (store); + dbobj = g_hash_table_lookup (priv->p_db_objects_hash, table_name); + } else + dbobj = g_hash_table_lookup (priv->db_objects_hash, table_name); + if (!dbobj) { + dbobj = g_new0 (DbObject, 1); + dbobj->store = store; + dbobj->obj_name = g_strdup ((gchar *) table_name); + if (store) { + priv->p_db_objects = g_slist_prepend (priv->p_db_objects, dbobj); + g_hash_table_insert (priv->p_db_objects_hash, dbobj->obj_name, dbobj); + } + else { + priv->db_objects = g_slist_prepend (priv->db_objects, dbobj); + g_hash_table_insert (priv->db_objects_hash, dbobj->obj_name, dbobj); + } + } + xmlFree (table_name); + dbobj->obj_type = GDA_SERVER_OPERATION_CREATE_TABLE; + TABLE_INFO (dbobj)->gtype_column = -1; + + /* current_all */ + gchar *sql; + sql = g_strdup_printf ("SELECT * FROM %s", complete_obj_name); + TABLE_INFO (dbobj)->current_all = compute_prepared_stmt (priv->parser, sql); + g_free (sql); + if (!TABLE_INFO (dbobj)->current_all) { + g_set_error (error, GDA_META_STORE_ERROR, GDA_META_STORE_INTERNAL_ERROR, + "Internal fatal error: could not create SELECT ALL statement (for table '%s')", + complete_obj_name); + goto onerror; + } + + /* delete all */ + sql = g_strdup_printf ("DELETE FROM %s", complete_obj_name); + TABLE_INFO (dbobj)->delete_all = compute_prepared_stmt (priv->parser, sql); + g_free (sql); + if (!TABLE_INFO (dbobj)->delete_all) { + g_set_error (error, GDA_META_STORE_ERROR, GDA_META_STORE_INTERNAL_ERROR, + "Internal fatal error: could not create DELETE ALL statement (for table '%s')", + complete_obj_name); + goto onerror; + } + + /* INSERT, UPDATE and DELETE statements */ + GdaSqlStatement *sql_ist; + GdaSqlStatementInsert *ist; + GdaSqlStatement *sql_ust; + GdaSqlStatementUpdate *ust; + GdaSqlStatement *sql_dst; + GdaSqlStatementDelete *dst; + + sql_ist = gda_sql_statement_new (GDA_SQL_STATEMENT_INSERT); + ist = (GdaSqlStatementInsert*) sql_ist->contents; + g_assert (GDA_SQL_ANY_PART (ist)->type == GDA_SQL_ANY_STMT_INSERT); + + sql_ust = gda_sql_statement_new (GDA_SQL_STATEMENT_UPDATE); + ust = (GdaSqlStatementUpdate*) sql_ust->contents; + g_assert (GDA_SQL_ANY_PART (ust)->type == GDA_SQL_ANY_STMT_UPDATE); + + sql_dst = gda_sql_statement_new (GDA_SQL_STATEMENT_DELETE); + dst = (GdaSqlStatementDelete*) sql_dst->contents; + g_assert (GDA_SQL_ANY_PART (dst)->type == GDA_SQL_ANY_STMT_DELETE); + + ist->table = gda_sql_table_new (GDA_SQL_ANY_PART (ist)); + ist->table->table_name = g_strdup ((gchar *) complete_obj_name); + + ust->table = gda_sql_table_new (GDA_SQL_ANY_PART (ust)); + ust->table->table_name = g_strdup ((gchar *) complete_obj_name); + + dst->table = gda_sql_table_new (GDA_SQL_ANY_PART (dst)); + dst->table->table_name = g_strdup ((gchar *) complete_obj_name); + + /* walk through the columns and Fkey nodes */ + xmlNodePtr cnode; + gint colindex = 0; + GSList *insert_values_list = NULL; + for (cnode = node->children; cnode; cnode = cnode->next) { + if (!strcmp ((gchar *) cnode->name, "column")) { + xmlChar *cname, *ctype, *xstr; + gboolean pkey = FALSE; + gboolean nullok = FALSE; + gboolean autoinc = FALSE; + + cname = xmlGetProp (cnode, BAD_CAST "name"); + if (!cname) + g_error ("Missing column name (table=%s)", complete_obj_name); + if (g_str_has_suffix ((const gchar*) cname, "gtype")) + TABLE_INFO (dbobj)->gtype_column = colindex; + + xstr = xmlGetProp (cnode, BAD_CAST "pkey"); + if (xstr) { + if ((*xstr == 'T') || (*xstr == 't')) + pkey = TRUE; + xmlFree (xstr); + } + xstr = xmlGetProp (cnode, BAD_CAST "nullok"); + if (xstr) { + if ((*xstr == 'T') || (*xstr == 't')) + nullok = TRUE; + xmlFree (xstr); + } + xstr = xmlGetProp (cnode, BAD_CAST "autoinc"); + if (xstr) { + if ((*xstr == 'T') || (*xstr == 't')) + autoinc = TRUE; + xmlFree (xstr); + } + ctype = xmlGetProp (cnode, BAD_CAST "type"); + + /* a field */ + GdaSqlField *field; + field = gda_sql_field_new (GDA_SQL_ANY_PART (ist)); + field->field_name = g_strdup ((gchar *) cname); + ist->fields_list = g_slist_append (ist->fields_list, field); + + field = gda_sql_field_new (GDA_SQL_ANY_PART (ust)); + field->field_name = g_strdup ((gchar *) cname); + ust->fields_list = g_slist_append (ust->fields_list, field); + + /* SQL identifier ? */ +#define MAX_IDENT_IN_TABLE 11 + xstr = xmlGetProp (cnode, BAD_CAST "ident"); + if (xstr) { + if ((*xstr == 'T') || (*xstr == 't')) { + if (!TABLE_INFO (dbobj)->ident_cols) { + TABLE_INFO (dbobj)->ident_cols = g_new0 (gint, MAX_IDENT_IN_TABLE); + TABLE_INFO (dbobj)->ident_cols_size = 0; + } + g_assert (TABLE_INFO (dbobj)->ident_cols_size < MAX_IDENT_IN_TABLE); + TABLE_INFO (dbobj)->ident_cols [TABLE_INFO (dbobj)->ident_cols_size] = colindex; + TABLE_INFO (dbobj)->ident_cols_size ++; + } + xmlFree (xstr); + } + + /* parameter */ + GType ptype; + GdaSqlParamSpec *pspec = g_new0 (GdaSqlParamSpec, 1); + GdaSqlExpr *expr; + ptype = ctype ? gda_g_type_from_string ((gchar *) ctype) : G_TYPE_STRING; + if (ptype == G_TYPE_INVALID) + ptype = GDA_TYPE_NULL; + pspec->name = g_strdup_printf ("+%d", colindex); + pspec->g_type = ptype; + pspec->nullok = nullok; + expr = gda_sql_expr_new (GDA_SQL_ANY_PART (ist)); + expr->param_spec = pspec; + insert_values_list = g_slist_append (insert_values_list, expr); + + pspec = g_new0 (GdaSqlParamSpec, 1); + pspec->name = g_strdup_printf ("+%d", colindex); + pspec->g_type = ptype; + pspec->nullok = nullok; + expr = gda_sql_expr_new (GDA_SQL_ANY_PART (ust)); + expr->param_spec = pspec; + ust->expr_list = g_slist_append (ust->expr_list, expr); + + /* condition */ + if (pkey) { + /* Key columns */ + TABLE_INFO (dbobj)->pk_cols_nb ++; + if (TABLE_INFO (dbobj)->pk_cols_nb == 1) + TABLE_INFO (dbobj)->pk_cols_array = g_new0 (gint, TABLE_INFO (dbobj)->pk_cols_nb); + else + TABLE_INFO (dbobj)->pk_cols_array = g_renew (gint, TABLE_INFO (dbobj)->pk_cols_array, + TABLE_INFO (dbobj)->pk_cols_nb); + TABLE_INFO (dbobj)->pk_cols_array [TABLE_INFO (dbobj)->pk_cols_nb - 1] = colindex; + + /* WHERE for UPDATE */ + expr = make_expr_EQUAL (GDA_SQL_ANY_PART (ust), cname, ctype, ptype, nullok, colindex); + if (!ust->cond) + ust->cond = expr; + else { + g_assert (ust->cond->cond); + if (ust->cond->cond->operator_type == GDA_SQL_OPERATOR_TYPE_AND) + ust->cond->cond->operands = g_slist_append (ust->cond->cond->operands, + expr); + else { + ust->cond = make_expr_AND (GDA_SQL_ANY_PART (ust), ust->cond); + ust->cond->cond->operands = g_slist_append (ust->cond->cond->operands, + expr); + } + } + /* WHERE for DELETE */ + expr = make_expr_EQUAL (GDA_SQL_ANY_PART (dst), cname, ctype, ptype, nullok, colindex); + if (!dst->cond) + dst->cond = expr; + else { + g_assert (dst->cond->cond); + if (dst->cond->cond->operator_type == GDA_SQL_OPERATOR_TYPE_AND) + dst->cond->cond->operands = g_slist_append (dst->cond->cond->operands, + expr); + else { + dst->cond = make_expr_AND (GDA_SQL_ANY_PART (dst), dst->cond); + dst->cond->cond->operands = g_slist_append (dst->cond->cond->operands, + expr); + } + } + } + /* columns type */ + if (colindex == 0) + TABLE_INFO (dbobj)->type_cols_array = g_new0 (GType, colindex + 2); + else + TABLE_INFO (dbobj)->type_cols_array = g_renew (GType, TABLE_INFO (dbobj)->type_cols_array, + colindex + 2); + TABLE_INFO (dbobj)->type_cols_array [colindex] = ptype; + TABLE_INFO (dbobj)->type_cols_array [colindex+1] = G_TYPE_NONE; + + /* TableColumn */ + TableColumn *tcol = NULL; + GSList *tlist; + for (tlist = TABLE_INFO (dbobj)->columns; tlist; tlist = tlist->next) { + if (((TableColumn*) tlist->data)->column_name && + !strcmp (((TableColumn*) tlist->data)->column_name, (gchar*) cname)) { + tcol = (TableColumn*) tlist->data; + if ((tcol->gtype != ptype) || + (tcol->pkey != pkey) || + (tcol->nullok != nullok) || + (tcol->autoinc != autoinc) || + (! tcol->column_type && ctype) || + (tcol->column_type && !ctype) || + (tcol->column_type && strcmp (tcol->column_type, (gchar *) ctype))) { + g_set_error (error, GDA_META_STORE_ERROR, + GDA_META_STORE_SCHEMA_OBJECT_DESCR_ERROR, + _("Column '%s' already exists and has different characteristics"), + tcol->column_name); + xmlFree (cname); + if (ctype) + xmlFree (ctype); + goto onerror; + } + break; + } + } + if (!tcol) { + tcol = g_new0 (TableColumn, 1); + TABLE_INFO (dbobj)->columns = g_slist_append (TABLE_INFO (dbobj)->columns, tcol); + tcol->column_name = g_strdup ((gchar *) cname); + tcol->column_type = ctype ? g_strdup ((gchar *) ctype) : NULL; + tcol->gtype = ptype; + tcol->pkey = pkey; + tcol->nullok = nullok; + tcol->autoinc = autoinc; + } + + /* free mem */ + xmlFree (cname); + if (ctype) + xmlFree (ctype); + colindex++; + } + else if (!strcmp ((gchar *) cnode->name, "fkey")) { + xmlNodePtr fnode; + xmlChar *ref_table; + + ref_table = xmlGetProp (cnode, BAD_CAST "ref_table"); + if (!ref_table) { + g_set_error (error, GDA_META_STORE_ERROR, + GDA_META_STORE_SCHEMA_OBJECT_DESCR_ERROR, + _("Missing foreign key's referenced table name (for table '%s')"), + complete_obj_name); + goto onerror; + } + + /* referenced DbObject */ + DbObject *ref_obj; + if (store) { + priv = gda_meta_store_get_instance_private (store); + ref_obj = g_hash_table_lookup (priv->p_db_objects_hash, ref_table); + } else + ref_obj = g_hash_table_lookup (priv->db_objects_hash, ref_table); + if (!ref_obj) { + ref_obj = g_new0 (DbObject, 1); + ref_obj->store = store; + ref_obj->obj_name = g_strdup ((gchar *) ref_table); + if (store) { + priv = gda_meta_store_get_instance_private (store); + priv->p_db_objects = g_slist_prepend (priv->p_db_objects, + ref_obj); + g_hash_table_insert (priv->p_db_objects_hash, ref_obj->obj_name, + ref_obj); + } + else { + priv->db_objects = g_slist_prepend (priv->db_objects, ref_obj); + g_hash_table_insert (priv->db_objects_hash, ref_obj->obj_name, ref_obj); + } + } + xmlFree (ref_table); + dbobj->depend_list = g_slist_append (dbobj->depend_list, ref_obj); + + /* TableFKey structure */ + TableFKey *tfk = g_new0 (TableFKey, 1); + + tfk->table_info = dbobj; + tfk->depend_on = ref_obj; + + for (fnode = cnode->children; fnode; fnode = fnode->next) { + if (!strcmp ((gchar *) fnode->name, "part")) + tfk->cols_nb ++; + } + + tfk->fk_cols_array = g_new0 (gint, tfk->cols_nb); + tfk->fk_names_array = g_new0 (gchar *, tfk->cols_nb); + tfk->ref_pk_cols_array = g_new0 (gint, tfk->cols_nb); + tfk->ref_pk_names_array = g_new0 (gchar*, tfk->cols_nb); + + gint fkcolindex = 0; + for (fnode = cnode->children; fnode; fnode = fnode->next) { + xmlChar *col, *ref_col; + if (strcmp ((gchar *) fnode->name, "part")) + continue; + col = xmlGetProp (fnode, BAD_CAST "column"); + if (!col) { + g_set_error (error, GDA_META_STORE_ERROR, + GDA_META_STORE_SCHEMA_OBJECT_DESCR_ERROR, + _("Missing foreign key's column name (for table '%s')"), + complete_obj_name); + table_fkey_free (tfk); + goto onerror; + } + ref_col = xmlGetProp (fnode, BAD_CAST "ref_column"); + tfk->fk_cols_array [fkcolindex] = column_name_to_index (TABLE_INFO (dbobj), + (gchar *) col); + tfk->fk_names_array [fkcolindex] = g_strdup ((gchar *) col); + if (tfk->fk_cols_array [fkcolindex] < 0) { + g_set_error (error, GDA_META_STORE_ERROR, + GDA_META_STORE_SCHEMA_OBJECT_DESCR_ERROR, + _("Column '%s' not found in table '%s'"), (gchar *) col, + complete_obj_name); + table_fkey_free (tfk); + goto onerror; + } + tfk->ref_pk_cols_array [fkcolindex] = -1; + tfk->ref_pk_names_array [fkcolindex] = ref_col ? + g_strdup ((gchar*) ref_col) : g_strdup ((gchar*) col); + + xmlFree (col); + if (ref_col) + xmlFree (ref_col); + fkcolindex ++; + } + + TABLE_INFO (dbobj)->fk_list = g_slist_append (TABLE_INFO (dbobj)->fk_list, tfk); + } + } + + /* finish the statements */ + ist->values_list = g_slist_append (NULL, insert_values_list); + TABLE_INFO (dbobj)->insert = g_object_new (GDA_TYPE_STATEMENT, "structure", sql_ist, NULL); + gda_sql_statement_free (sql_ist); + + TABLE_INFO (dbobj)->update = g_object_new (GDA_TYPE_STATEMENT, "structure", sql_ust, NULL); + gda_sql_statement_free (sql_ust); + + TABLE_INFO (dbobj)->delete = g_object_new (GDA_TYPE_STATEMENT, "structure", sql_dst, NULL); + gda_sql_statement_free (sql_dst); + + if (TABLE_INFO (dbobj)->pk_cols_nb == 0) + g_error ("Missing key fields identification (table=%s)", complete_obj_name); + +#ifdef GDA_DEBUG_NO + /* debug */ + gchar *str; + str = gda_statement_to_sql (TABLE_INFO (dbobj)->insert, NULL, NULL); + g_print ("INSERT: %s\n", str); + g_free (str); + str = gda_statement_to_sql (TABLE_INFO (dbobj)->update, NULL, NULL); + g_print ("UPDATE: %s\n", str); + g_free (str); + str = gda_statement_to_sql (TABLE_INFO (dbobj)->delete, NULL, NULL); + g_print ("DELETE: %s\n", str); + g_free (str); +#endif + + /* determine parameters */ + GdaSet *params; + if (!gda_statement_get_parameters (TABLE_INFO (dbobj)->insert, &(TABLE_INFO (dbobj)->params), NULL)) + g_error ("Internal fatal error: could not get INSERT statement's parameters (table=%s)", + complete_obj_name); + if (!gda_statement_get_parameters (TABLE_INFO (dbobj)->update, ¶ms, NULL)) + g_error ("Internal fatal error: could not get UPDATE statement's parameters (table=%s)", + complete_obj_name); + gda_set_merge_with_set (TABLE_INFO (dbobj)->params, params); + g_object_unref (params); + + if (!gda_statement_get_parameters (TABLE_INFO (dbobj)->delete, ¶ms, NULL)) + g_error ("Internal fatal error: could not get DELETE statement's parameters (table=%s)", + complete_obj_name); + gda_set_merge_with_set (TABLE_INFO (dbobj)->params, params); + g_object_unref (params); + + /* insert DbObject */ + if (store) { + priv = gda_meta_store_get_instance_private (store); + g_hash_table_insert (priv->p_db_objects_hash, dbobj->obj_name, dbobj); + } else + g_hash_table_insert (priv->db_objects_hash, dbobj->obj_name, dbobj); + + g_free (complete_obj_name); + return dbobj; + + onerror: + g_free (complete_obj_name); + db_object_free (dbobj); + return NULL; +} + + +static GdaSqlExpr * +make_expr_AND (GdaSqlAnyPart *parent, GdaSqlExpr *current) +{ + GdaSqlExpr *expr; + expr = gda_sql_expr_new (parent); + expr->cond = gda_sql_operation_new (GDA_SQL_ANY_PART (expr)); + expr->cond->operator_type = GDA_SQL_OPERATOR_TYPE_AND; + + expr->cond->operands = g_slist_append (NULL, current); + GDA_SQL_ANY_PART (current)->parent = GDA_SQL_ANY_PART (expr->cond); + + return expr; +} + +static GdaSqlExpr * +make_expr_EQUAL (GdaSqlAnyPart *parent, xmlChar *cname, G_GNUC_UNUSED xmlChar *type, GType ptype, + gboolean nullok, gint index) +{ + GdaSqlOperation *op; + GdaSqlExpr *retexpr, *expr; + GdaSqlParamSpec *pspec; + + retexpr = gda_sql_expr_new (parent); + + op = gda_sql_operation_new (GDA_SQL_ANY_PART (retexpr)); + op->operator_type = GDA_SQL_OPERATOR_TYPE_EQ; + retexpr->cond = op; + + expr = gda_sql_expr_new (GDA_SQL_ANY_PART (op)); + g_value_set_string ((expr->value = gda_value_new (G_TYPE_STRING)), (gchar *) cname); + op->operands = g_slist_append (op->operands, expr); + + pspec = g_new0 (GdaSqlParamSpec, 1); + pspec->name = g_strdup_printf ("-%d", index); + pspec->g_type = ptype; + pspec->nullok = nullok; + expr = gda_sql_expr_new (GDA_SQL_ANY_PART (op)); + expr->param_spec = pspec; + op->operands = g_slist_append (op->operands, expr); + + return retexpr; +} + + +static void +compute_view_dependencies (GdaMetaStorePrivate *priv, GdaMetaStore *store, + DbObject *view_dbobj, GdaSqlStatement *sqlst) +{ + if (sqlst->stmt_type == GDA_SQL_STATEMENT_SELECT) { + GdaSqlStatementSelect *selst; + selst = (GdaSqlStatementSelect*) (sqlst->contents); + GSList *targets; + for (targets = selst->from->targets; targets; targets = targets->next) { + GdaSqlSelectTarget *t = (GdaSqlSelectTarget *) targets->data; + + if (!t->table_name) + continue; + DbObject *ref_obj = NULL; + if (store) { + priv = gda_meta_store_get_instance_private (store); + ref_obj = g_hash_table_lookup (priv->p_db_objects_hash, t->table_name); + } else + ref_obj = g_hash_table_lookup (priv->db_objects_hash, t->table_name); + + if (!ref_obj) { + ref_obj = g_new0 (DbObject, 1); + ref_obj->store = store; + ref_obj->obj_name = g_strdup (t->table_name); + if (store) { + priv = gda_meta_store_get_instance_private (store); + priv->p_db_objects = g_slist_prepend (priv->p_db_objects, + ref_obj); + g_hash_table_insert (priv->p_db_objects_hash, ref_obj->obj_name, + ref_obj); + } + else { + priv->db_objects = g_slist_prepend (priv->db_objects, ref_obj); + g_hash_table_insert (priv->db_objects_hash, ref_obj->obj_name, ref_obj); + } + } + view_dbobj->depend_list = g_slist_append (view_dbobj->depend_list, ref_obj); + } + } + else if (sqlst->stmt_type == GDA_SQL_STATEMENT_COMPOUND) { + GdaSqlStatementCompound *cst; + GSList *list; + cst = (GdaSqlStatementCompound*) (sqlst->contents); + for (list = cst->stmt_list; list; list = list->next) + compute_view_dependencies (priv, store, view_dbobj, (GdaSqlStatement*) list->data); + } + else + g_assert_not_reached (); +} + +/* + * Makes a list of all the DbObject structures listed in @objects + * which are not present in @ordered_list and for which no dependency is in @ordered_list + */ +static GSList * +build_pass (GSList *objects, GSList *ordered_list) +{ + GSList *retlist = NULL, *list; + + for (list = objects; list; list = list->next) { + gboolean has_dep = FALSE; + GSList *dep_list; + if (g_slist_find (ordered_list, list->data)) + continue; + for (dep_list = DB_OBJECT (list->data)->depend_list; dep_list; dep_list = dep_list->next) { + if (!g_slist_find (ordered_list, dep_list->data)) { + has_dep = TRUE; + break; + } + } + if (has_dep) + continue; + retlist = g_slist_prepend (retlist, list->data); + } + +#ifdef GDA_DEBUG_NO + g_print (">> PASS\n"); + for (list = retlist; list; list = list->next) + g_print ("--> %s\n", DB_OBJECT (list->data)->obj_name); + g_print ("<<\n"); +#endif + + return retlist; +} + +/* + * Returns: a new list containing all the items in @objects but correctly ordered + * in a way that for any given DbObject in the list, all the dependencies are _before_ it in the list + */ +static GSList * +reorder_db_objects (GSList *objects, G_GNUC_UNUSED GHashTable *hash) +{ + GSList *pass_list; + GSList *ordered_list = NULL; + + for (pass_list = build_pass (objects, ordered_list); pass_list; pass_list = build_pass (objects, ordered_list)) + ordered_list = g_slist_concat (ordered_list, pass_list); + +#ifdef GDA_DEBUG_NO + GSList *list; + for (list = ordered_list; list; list = list->next) + g_print ("--> %s\n", ((DbObject*) list->data)->obj_name); +#endif + + return ordered_list; +} + +/* + * Computes TableInfo->reverse_fk_list, TableFKey->ref_pk_cols_array and TableFKey->fk_fields_cond + * + * Returns: TRUE if all information is Ok + */ +static gboolean +complement_db_objects (GSList *objects, G_GNUC_UNUSED GHashTable *hash, GError **error) +{ + GSList *list; + for (list = objects; list; list = list->next) { + if (DB_OBJECT (list->data)->obj_type != GDA_SERVER_OPERATION_CREATE_TABLE) + continue; + + TableInfo *info = TABLE_INFO (DB_OBJECT (list->data)); + GSList *klist; + for (klist = info->fk_list; klist; klist = klist->next) { + TableFKey *tfk = (TableFKey *) klist->data; + gint i; + GString *cond = NULL; + + /* fix TableFKey->ref_pk_cols_array */ + for (i = 0; i < tfk->cols_nb; i++) { + gint col; + col = column_name_to_index (TABLE_INFO (tfk->depend_on), tfk->ref_pk_names_array[i]); + if (col < 0) { + g_set_error (error, GDA_META_STORE_ERROR, + GDA_META_STORE_META_CONTEXT_ERROR, + _("Foreign key column '%s' not found in table '%s'"), + tfk->ref_pk_names_array[i], tfk->depend_on->obj_name); + if (cond) + g_string_free (cond, TRUE); + return FALSE; + } + tfk->ref_pk_cols_array[i] = col; + + TableColumn *tcol; + if (cond) + g_string_append (cond, " AND "); + else + cond = g_string_new (""); + tcol = TABLE_COLUMN (g_slist_nth_data (info->columns, tfk->fk_cols_array[i])); + g_assert (tcol); + g_string_append_printf (cond, "%s = ##%s::%s%s", tcol->column_name, + tfk->fk_names_array[i], + tcol->column_type ? tcol->column_type : g_type_name (tcol->gtype), + tcol->nullok ? "::NULL" : ""); + } + + /* fix TableFKey->fk_fields_cond */ + g_assert (cond); + tfk->fk_fields_cond = cond->str; + g_string_free (cond, FALSE); + + /* fix TableInfo->reverse_fk_list, + * but we don't want the "_tables"-->"_views" reverse dependency */ + if (strcmp (tfk->depend_on->obj_name, "_tables") || + strcmp (tfk->table_info->obj_name, "_views")) + TABLE_INFO (tfk->depend_on)->reverse_fk_list = + g_slist_append (TABLE_INFO (tfk->depend_on)->reverse_fk_list, tfk); + } + } + + return TRUE; +} + +static void +db_object_free (DbObject *dbobj) +{ + if (dbobj) { + g_free (dbobj->obj_name); + if (dbobj->create_op) + g_object_unref (dbobj->create_op); + if (dbobj->depend_list) + g_slist_free (dbobj->depend_list); + switch (dbobj->obj_type) { + case GDA_SERVER_OPERATION_CREATE_TABLE: + table_info_free_contents (TABLE_INFO (dbobj)); + break; + case GDA_SERVER_OPERATION_CREATE_VIEW: + view_info_free_contents (VIEW_INFO (dbobj)); + break; + default: + TO_IMPLEMENT; + break; + } + g_free (dbobj); + } +} + +static void +table_info_free_contents (TableInfo *info) +{ + g_slist_free_full (info->columns, (GDestroyNotify) table_column_free); + if (info->current_all) + g_object_unref (info->current_all); + if (info->delete_all) + g_object_unref (info->delete_all); + if (info->insert) + g_object_unref (info->insert); + if (info->update) + g_object_unref (info->update); + if (info->delete) + g_object_unref (info->delete); + if (info->params) + g_object_unref (info->params); + g_free (info->pk_cols_array); + g_free (info->type_cols_array); + g_slist_free_full (info->fk_list, (GDestroyNotify) table_fkey_free); + g_slist_free (info->reverse_fk_list); + if (info->ident_cols) + g_free (info->ident_cols); +} + +static void +view_info_free_contents (ViewInfo *info) +{ + g_free (info->view_def); +} + +static void +table_column_free (TableColumn *tcol) +{ + g_free (tcol->column_name); + g_free (tcol->column_type); + g_free (tcol); +} + +static void +table_fkey_free (TableFKey *tfk) +{ + gint i; + g_free (tfk->fk_cols_array); + g_free (tfk->ref_pk_cols_array); + for (i = 0; i < tfk->cols_nb; i++) { + g_free (tfk->ref_pk_names_array [i]); + g_free (tfk->fk_names_array [i]); + } + g_free (tfk->ref_pk_names_array); + g_free (tfk->fk_names_array); + g_free (tfk->fk_fields_cond); + g_free (tfk); +} + +static gboolean +update_schema_version (GdaMetaStore *store, G_GNUC_UNUSED const gchar *version, GError **error) +{ + GdaSet *params; + GdaMetaStoreClass *klass; + GdaMetaStorePrivate *priv = gda_meta_store_get_instance_private (store); + + if (! gda_statement_get_parameters (priv->prep_stmts[STMT_UPD_VERSION], ¶ms, NULL)) { + g_set_error (error, GDA_META_STORE_ERROR, GDA_META_STORE_INCORRECT_SCHEMA_ERROR, + "%s", _ ("Could not update the internal schema's version. No prepared statement's parameters were found")); + return FALSE; + } + g_assert (gda_set_set_holder_value (params, NULL, "version", CURRENT_SCHEMA_VERSION)); + if (gda_connection_statement_execute_non_select (priv->cnc, + priv->prep_stmts[STMT_UPD_VERSION], + params, NULL, NULL) == -1) { + g_object_unref (params); + g_set_error (error, GDA_META_STORE_ERROR, GDA_META_STORE_INCORRECT_SCHEMA_ERROR, + "%s", _ ("Could not update the internal schema's version. Statement execution fails")); + return FALSE; + } + g_object_unref (params); + + + /* update version */ + priv->version = atoi (CURRENT_SCHEMA_VERSION); /* Flawfinder: ignore */ + return TRUE; +} + +/* + * If no transaction is started, then start one + * @out_started: a place to store if a transaction was actually started in the function + * + * Returns: TRUE if no error occurred + */ +static gboolean +check_transaction_started (GdaConnection *cnc, gboolean *out_started) +{ + GdaTransactionStatus *trans; + + trans = gda_connection_get_transaction_status (cnc); + if (!trans) { + if (!gda_connection_begin_transaction (cnc, NULL, + GDA_TRANSACTION_ISOLATION_UNKNOWN, NULL)) + return FALSE; + else + *out_started = TRUE; + } + return TRUE; +} + +/* + * Create a database object from its name, + * to be used by functions implementing versions migrations + */ +static gboolean +create_a_dbobj (GdaMetaStore *store, const gchar *obj_name, GError **error) +{ + DbObject *dbobj; + GdaServerProvider *prov; + GdaMetaStorePrivate *priv = gda_meta_store_get_instance_private (store); + + dbobj = g_hash_table_lookup (priv->db_objects_hash, obj_name); + if (!dbobj) { + g_set_error (error, GDA_META_STORE_ERROR, GDA_META_STORE_SCHEMA_OBJECT_NOT_FOUND_ERROR, + _("Schema description does not contain the object '%s', check installation"), + obj_name); + return FALSE; + } + prov = gda_connection_get_provider (priv->cnc); + if (! prepare_dbo_server_operation (priv, store, prov, dbobj, error)) + return FALSE; + g_assert (dbobj->create_op); + + gboolean retval; + retval = gda_server_provider_perform_operation (prov, priv->cnc, dbobj->create_op, error); + g_object_unref (dbobj->create_op); + dbobj->create_op = NULL; + return retval; +} + +/* + * Create a database object from its name, + * to be used by functions implementing versions migrations + */ +static gboolean +add_a_column (GdaMetaStore *store, const gchar *table_name, const gchar *column_name, GError **error) +{ + DbObject *dbobj; + GdaServerProvider *prov; + gboolean retval = FALSE; + GdaMetaStorePrivate *priv = gda_meta_store_get_instance_private (store); + + dbobj = g_hash_table_lookup (priv->db_objects_hash, table_name); + if (!dbobj) { + g_set_error (error, GDA_META_STORE_ERROR, GDA_META_STORE_SCHEMA_OBJECT_NOT_FOUND_ERROR, + _("Schema description does not contain the object '%s', check installation"), + table_name); + return FALSE; + } + prov = gda_connection_get_provider (priv->cnc); + + GdaServerOperation *op; + op = gda_server_provider_create_operation (prov, priv->cnc, GDA_SERVER_OPERATION_ADD_COLUMN, NULL, error); + if (!op) + return FALSE; + + GSList *list; + if (! gda_server_operation_set_value_at (op, table_name, error, "/COLUMN_DEF_P/TABLE_NAME")) + goto out; + + for (list = TABLE_INFO (dbobj)->columns; list; list = list->next) { + TableColumn *tcol = TABLE_COLUMN (list->data); + if (!strcmp (tcol->column_name, column_name)) { + const gchar *repl; + if (! gda_server_operation_set_value_at (op, tcol->column_name, + error, "/COLUMN_DEF_P/COLUMN_NAME")) + goto out; + repl = provider_specific_match (priv->provider_specifics, prov, + tcol->column_type ? tcol->column_type : "string", + "/FIELDS_A/@COLUMN_TYPE"); + if (! gda_server_operation_set_value_at (op, repl ? repl : "string", error, + "/COLUMN_DEF_P/COLUMN_TYPE")) + goto out; + if (! gda_server_operation_set_value_at (op, NULL, error, + "/COLUMN_DEF_P/COLUMN_SIZE")) + goto out; + if (! gda_server_operation_set_value_at (op, tcol->nullok ? "FALSE" : "TRUE", error, + "/COLUMN_DEF_P/COLUMN_NNUL")) + goto out; + break; + } + } + if (!list) { + g_set_error (error, GDA_META_STORE_ERROR, GDA_META_STRUCT_UNKNOWN_OBJECT_ERROR, + _("Could not find description for column named '%s'"), column_name); + goto out; + } + + retval = gda_server_provider_perform_operation (prov, priv->cnc, op, error); + + out: + g_object_unref (op); + return retval; +} + +/* migrate schema from version 1 to 2 */ +static void +migrate_schema_from_v1_to_v2 (GdaMetaStore *store, GError **error) +{ + GdaMetaStorePrivate *priv = gda_meta_store_get_instance_private (store); + g_return_if_fail (GDA_IS_CONNECTION (priv->cnc)); + g_return_if_fail (gda_connection_is_opened (priv->cnc)); + + /* begin a transaction if possible */ + gboolean transaction_started = FALSE; + if (! check_transaction_started (priv->cnc, &transaction_started)) + return; + + /* create tables for this migration */ + if (! create_a_dbobj (store, "_table_indexes", error)) + goto out; + if (! create_a_dbobj (store, "_index_column_usage", error)) + goto out; + + /* set version info to CURRENT_SCHEMA_VERSION */ + update_schema_version (store, "2", error); + + out: + if (transaction_started) { + /* handle transaction started if necessary */ + if (priv->version != 2) + gda_connection_rollback_transaction (priv->cnc, NULL, NULL); + else + gda_connection_commit_transaction (priv->cnc, NULL, NULL); + } +} + +/* migrate schema from version 2 to 3 */ +static void +migrate_schema_from_v2_to_v3 (GdaMetaStore *store, GError **error) +{ + GdaMetaStorePrivate *priv = gda_meta_store_get_instance_private (store); + g_return_if_fail (GDA_IS_CONNECTION (priv->cnc)); + g_return_if_fail (gda_connection_is_opened (priv->cnc)); + + /* begin a transaction if possible */ + gboolean transaction_started = FALSE; + if (! check_transaction_started (priv->cnc, &transaction_started)) + return; + + /* create tables for this migration */ + if (! create_a_dbobj (store, "__declared_fk", error)) + goto out; + + /* set version info to CURRENT_SCHEMA_VERSION */ + update_schema_version (store, "3", error); + + out: + if (transaction_started) { + /* handle transaction started if necessary */ + if (priv->version != 3) + gda_connection_rollback_transaction (priv->cnc, NULL, NULL); + else + gda_connection_commit_transaction (priv->cnc, NULL, NULL); + } +} + +/* migrate schema from version 2 to 3 */ +static void +migrate_schema_from_v3_to_v4 (GdaMetaStore *store, GError **error) +{ + GdaMetaStorePrivate *priv = gda_meta_store_get_instance_private (store); + g_return_if_fail (GDA_IS_CONNECTION (priv->cnc)); + g_return_if_fail (gda_connection_is_opened (priv->cnc)); + + /* begin a transaction if possible */ + gboolean transaction_started = FALSE; + if (! check_transaction_started (priv->cnc, &transaction_started)) + return; + + if (! add_a_column (store, "_schemata", "schema_default", error)) + goto out; + + /* set version info to CURRENT_SCHEMA_VERSION */ + update_schema_version (store, "4", error); + + out: + if (transaction_started) { + /* handle transaction started if necessary */ + if (priv->version != 4) + gda_connection_rollback_transaction (priv->cnc, NULL, NULL); + else + gda_connection_commit_transaction (priv->cnc, NULL, NULL); + } +} + +static gboolean +handle_schema_version (GdaMetaStore *store, gboolean *schema_present, GError **error) +{ + GdaDataModel *model; + GdaMetaStoreClass *klass = (GdaMetaStoreClass *) G_OBJECT_GET_CLASS (store); + GdaMetaStorePrivate *priv = gda_meta_store_get_instance_private (store); + + model = gda_connection_statement_execute_select_fullv (priv->cnc, + priv->prep_stmts[STMT_GET_VERSION], + NULL, GDA_STATEMENT_MODEL_RANDOM_ACCESS, NULL, + 0, G_TYPE_STRING, -1); + if (schema_present) + *schema_present = model ? TRUE : FALSE; + if (model) { + const GValue *version; + if (gda_data_model_get_n_rows (model) != 1) { + g_set_error (error, GDA_META_STORE_ERROR, GDA_META_STORE_INCORRECT_SCHEMA_ERROR, + "%s", _("Could not get the internal schema's version")); + g_object_unref (model); + return FALSE; + } + + version = gda_data_model_get_value_at (model, 0, 0, error); + if (!version) + return FALSE; + + if (gda_value_is_null (version) || !gda_value_isa (version, G_TYPE_STRING)) { + g_set_error (error, GDA_META_STORE_ERROR, GDA_META_STORE_INCORRECT_SCHEMA_ERROR, + "%s", _("Could not get the internal schema's version")); + g_object_unref (model); + return FALSE; + } + priv->version = atoi (g_value_get_string (version)); /* Flawfinder: ignore */ + if (priv->version < 1) + priv->version = 1; + if (priv->version != atoi (CURRENT_SCHEMA_VERSION)) { /* Flawfinder: ignore */ + switch (priv->version) { + case 1: + migrate_schema_from_v1_to_v2 (store, error); + /* fallthrough */ + case 2: + migrate_schema_from_v2_to_v3 (store, error); + /* fallthrough */ + case 3: + migrate_schema_from_v3_to_v4 (store, error); + /* fallthrough */ + case 4: + /* function call for migration from V4 will be here */ + break; + default: + /* no downgrade to do */ + break; + } + + if (priv->version != atoi (CURRENT_SCHEMA_VERSION)) { /* Flawfinder: ignore */ + /* it's an error */ + g_object_unref (model); + return FALSE; + } + } + g_object_unref (model); + return TRUE; + } + else { + g_set_error (error, GDA_META_STORE_ERROR, GDA_META_STORE_INCORRECT_SCHEMA_ERROR, + "%s", _("Could not get the internal schema's version")); + return FALSE; + } +} + +/** + * gda_meta_store_get_version: + * @store: a #GdaMetaStore object + * + * Get @store's internal schema's version + * + * Returns: the version (incremented each time the schema changes, backward compatible) + */ +gint +gda_meta_store_get_version (GdaMetaStore *store) { + g_return_val_if_fail (GDA_IS_META_STORE (store), 0); + GdaMetaStorePrivate *priv = gda_meta_store_get_instance_private (store); + + return priv->version; +} + +/** + * gda_meta_store_get_internal_connection: + * @store: a #GdaMetaStore object + * + * Get a pointer to the #GdaConnection object internally used by @store to store + * its contents. + * + * The returned connection can be used to access some other data than the one managed by @store + * itself. The returned object is not owned by the caller (if you need to keep it, then use g_object_ref()). + * Do not close the connection. + * + * Returns: (transfer none): a #GdaConnection, or %NULL + */ +GdaConnection * +gda_meta_store_get_internal_connection (GdaMetaStore *store) { + g_return_val_if_fail (GDA_IS_META_STORE (store), 0); + GdaMetaStorePrivate *priv = gda_meta_store_get_instance_private (store); + + return priv->cnc; +} + +/** + * gda_meta_store_sql_identifier_quote: + * @id: an SQL identifier + * @cnc: a #GdaConnection + * + * Use this method to get a correctly quoted (if necessary) SQL identifier which can be used + * to retrieve or filter information in a #GdaMetaStore which stores meta data about @cnc. + * + * The returned SQL identifier can be used in conjunction with gda_connection_update_meta_store(), + * gda_connection_get_meta_store_data(), gda_connection_get_meta_store_data_v() and + * gda_meta_store_extract(). + * + * Returns: (transfer full): a new string, to free with g_free() once not needed anymore + * + * Since: 4.0.3 + */ +gchar * +gda_meta_store_sql_identifier_quote (const gchar *id, GdaConnection *cnc) +{ + GdaConnectionOptions cncoptions; + g_return_val_if_fail (!cnc || GDA_IS_CONNECTION (cnc), NULL); + + g_object_get (G_OBJECT (cnc), "options", &cncoptions, NULL); + return gda_sql_identifier_quote (id, cnc, NULL, TRUE, + cncoptions & GDA_CONNECTION_OPTIONS_SQL_IDENTIFIERS_CASE_SENSITIVE); +} + +/** + * gda_meta_store_extract: + * @store: a #GdaMetaStore object + * @select_sql: a SELECT statement + * @error: (nullable): a place to store errors, or %NULL + * @...: a list of (variable name (gchar *), GValue *value) terminated with NULL, representing values for all the + * variables mentioned in @select_sql. If there is no variable then this part can be omitted. + * + * Extracts some data stored in @store using a custom SELECT query. If the @select_sql filter involves + * SQL identifiers (such as table or column names), then the values should have been adapted using + * gda_meta_store_sql_identifier_quote(). + * + * For more information about + * SQL identifiers are represented in @store, see the + * meta data section about SQL identifiers. + * + * Returns: (transfer full): a new #GdaDataModel, or %NULL if an error occurred + */ +GdaDataModel * +gda_meta_store_extract (GdaMetaStore *store, const gchar *select_sql, GError **error, ...) +{ + GdaStatement *stmt = NULL; + GdaDataModel *model; + GdaSet *params = NULL; + + g_return_val_if_fail (GDA_IS_META_STORE (store), NULL); + g_return_val_if_fail (select_sql, NULL); + GdaMetaStorePrivate *priv = gda_meta_store_get_instance_private (store); + + if (priv->init_error) { + g_propagate_error (error, g_error_copy (priv->init_error)); + return NULL; + } + + g_rec_mutex_lock (& (priv->mutex)); + + if ((priv->max_extract_stmt > 0) && !priv->extract_stmt_hash) + priv->extract_stmt_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref); + + /* statement creation */ + if (priv->extract_stmt_hash) + stmt = g_hash_table_lookup (priv->extract_stmt_hash, select_sql); + if (stmt) + g_object_ref (stmt); + else { + const gchar *remain; + + stmt = gda_sql_parser_parse_string (priv->parser, select_sql, &remain, error); + if (!stmt) { + g_rec_mutex_unlock (& (priv->mutex)); + return NULL; + } + if (remain) { + g_set_error (error, GDA_META_STORE_ERROR, GDA_META_STORE_EXTRACT_SQL_ERROR, + "%s", _("More than one SQL statement")); + g_object_unref (stmt); + g_rec_mutex_unlock (& (priv->mutex)); + return NULL; + } + + if (priv->current_extract_stmt < priv->max_extract_stmt) { + g_hash_table_insert (priv->extract_stmt_hash, g_strdup (select_sql), g_object_ref (stmt)); + priv->current_extract_stmt++; + } + } + + /* parameters */ + if (!gda_statement_get_parameters (stmt, ¶ms, error)) { + g_object_unref (stmt); + g_rec_mutex_unlock (& (priv->mutex)); + return NULL; + } + if (params) { + va_list ap; + gchar *pname; + GSList *list, *params_set = NULL; + va_start (ap, error); + for (pname = va_arg (ap, gchar *); pname; pname = va_arg (ap, gchar *)) { + GValue *value; + GdaHolder *h; + value = va_arg (ap, GValue *); + h = gda_set_get_holder (params, pname); + if (!h) + g_warning (_("Parameter '%s' is not present in statement"), pname); + else { + GError *lerror = NULL; + if (!gda_holder_set_value (h, value, &lerror)) { + g_object_unref (stmt); + g_object_unref (params); + va_end (ap); + g_slist_free (params_set); + g_rec_mutex_unlock (& (priv->mutex)); + g_set_error (error, GDA_META_STORE_ERROR, GDA_META_STORE_EXTRACT_SQL_ERROR, + _("While extracting data from Meta Store: %s"), + lerror && lerror->message ? lerror->message : "No error message was set"); + g_clear_error (&lerror); + return NULL; + } + params_set = g_slist_prepend (params_set, h); + } + } + va_end (ap); + + for (list = gda_set_get_holders (params); list; list = list->next) { + if (!g_slist_find (params_set, list->data)) + g_warning (_("No value set for parameter '%s'"), + gda_holder_get_id (GDA_HOLDER (list->data))); + } + g_slist_free (params_set); + } + + /* execution */ + model = gda_connection_statement_execute_select (priv->cnc, stmt, params, error); + g_object_unref (stmt); + if (params) + g_object_unref (params); + + g_rec_mutex_unlock (& (priv->mutex)); + return model; +} + +/** + * gda_meta_store_extract_v: (rename-to gda_meta_store_extract) + * @store: a #GdaMetaStore object + * @select_sql: a SELECT statement + * @vars: (element-type utf8 GObject.Value) (nullable): a hash table with all variables names as keys and GValue* as + * value, representing values for all the variables mentioned in @select_sql. If there is no variable then this part can be + * omitted. + * @error: a place to store errors, or %NULL + * + * Extracts some data stored in @store using a custom SELECT query. If the @select_sql filter involves + * SQL identifiers (such as table or column names), then the values should have been adapted using + * gda_meta_store_sql_identifier_quote(). + * + * For more information about + * SQL identifiers are represented in @store, see the + * meta data section about SQL identifiers. + * + * Returns: (transfer full): a new #GdaDataModel, or %NULL if an error occurred + * + * Since: 4.2.6 + */ +GdaDataModel * +gda_meta_store_extract_v (GdaMetaStore *store, const gchar *select_sql, GHashTable *vars, GError **error) +{ + GdaStatement *stmt = NULL; + GdaDataModel *model; + GdaSet *params = NULL; + + g_return_val_if_fail (GDA_IS_META_STORE (store), NULL); + g_return_val_if_fail (select_sql, NULL); + GdaMetaStorePrivate *priv = gda_meta_store_get_instance_private (store); + + if (priv->init_error) { + g_propagate_error (error, g_error_copy (priv->init_error)); + return NULL; + } + + g_rec_mutex_lock (& (priv->mutex)); + + if ((priv->max_extract_stmt > 0) && !priv->extract_stmt_hash) + priv->extract_stmt_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref); + + /* statement creation */ + if (priv->extract_stmt_hash) + stmt = g_hash_table_lookup (priv->extract_stmt_hash, select_sql); + if (stmt) + g_object_ref (stmt); + else { + const gchar *remain; + + stmt = gda_sql_parser_parse_string (priv->parser, select_sql, &remain, error); + if (!stmt) { + g_rec_mutex_unlock (& (priv->mutex)); + return NULL; + } + if (remain) { + g_set_error (error, GDA_META_STORE_ERROR, GDA_META_STORE_EXTRACT_SQL_ERROR, + "%s", _("More than one SQL statement")); + g_object_unref (stmt); + g_rec_mutex_unlock (& (priv->mutex)); + return NULL; + } + + if (priv->current_extract_stmt < priv->max_extract_stmt) { + g_hash_table_insert (priv->extract_stmt_hash, g_strdup (select_sql), g_object_ref (stmt)); + priv->current_extract_stmt++; + } + } + + /* parameters */ + if (!gda_statement_get_parameters (stmt, ¶ms, error)) { + g_object_unref (stmt); + g_rec_mutex_unlock (& (priv->mutex)); + return NULL; + } + if (params) { + GSList *list, *params_set = NULL; + gchar *pname; + GValue *value; + GHashTableIter iter; + g_hash_table_iter_init (&iter, vars); + while (g_hash_table_iter_next (&iter, (gpointer*)&pname, (gpointer*)&value)) { + GdaHolder *h; + h = gda_set_get_holder (params, pname); + if (!h) + g_message (_("Parameter '%s' is not present in statement"), pname); + else { + GError *lerror = NULL; + if (!gda_holder_set_value (h, value, &lerror)) { + g_object_unref (stmt); + g_object_unref (params); + g_set_error (error, GDA_META_STORE_ERROR, GDA_META_STORE_EXTRACT_SQL_ERROR, + _("While extracting data from store: %s"), + lerror && lerror->message ? lerror->message : "No error message was set"); + g_clear_error (&lerror); + g_rec_mutex_unlock (& (priv->mutex)); + return NULL; + } + params_set = g_slist_prepend (params_set, h); + } + } + + for (list = gda_set_get_holders (params); list; list = list->next) { + if (!g_slist_find (params_set, list->data)) + g_message (_("No value set for parameter '%s'"), + gda_holder_get_id (GDA_HOLDER (list->data))); + } + g_slist_free (params_set); + } + + /* execution */ + model = gda_connection_statement_execute_select (priv->cnc, stmt, params, error); + g_object_unref (stmt); + if (params) + g_object_unref (params); + + g_rec_mutex_unlock (& (priv->mutex)); + return model; +} + +static gboolean prepare_tables_infos (GdaMetaStore *store, TableInfo **out_table_infos, + TableConditionInfo **out_cond_infos, gboolean *out_with_key, + const gchar *table_name, const gchar *condition, GError **error, + gint nvalues, const gchar **value_names, const GValue **values); +static gint find_row_in_model (GdaDataModel *find_in, GdaDataModel *data, gint row, + gint *pk_cols, gint pk_cols_nb, gboolean *out_has_changed, GError **error); +/** + * gda_meta_store_modify: + * @store: a #GdaMetaStore object + * @table_name: the name of the table to modify within @store + * @new_data: (nullable): a #GdaDataModel containing the new data to set in @table_name, or %NULL (treated as a data model + * with no row at all) + * @condition: (nullable): SQL expression (which may contain variables) defining the rows which are being obsoleted by @new_data, or %NULL + * @error: (nullable): a place to store errors, or %NULL + * @...: a list of (variable name (gchar *), GValue *value) terminated with NULL, representing values for all the + * variables mentioned in @condition. + * + * Propagates an update to @store, the update's contents is represented by @new_data, this function is + * primarily reserved to database providers. + * + * For example tell @store to update its list of tables, @new_data should contain the same columns as the "_tables" + * table of @store, and contain one row per table in the store; there should not be any more argument after the @error + * argument. + * + * Now, to update only one table, the @new_data data model should have one row for the table to update (or no row + * at all if the table does not exist anymore), and have values for the primary key of the "_tables" table of + * @store, namely "table_catalog", "table_schema" and "table_name". + * + * Returns: TRUE if no error occurred + */ +gboolean +gda_meta_store_modify (GdaMetaStore *store, const gchar *table_name, + GdaDataModel *new_data, const gchar *condition, GError **error, ...) +{ + va_list ap; + gboolean retval; + gint size = 5, n_values = 0; + const gchar **value_names; + const GValue **values; + gchar *name; + + g_return_val_if_fail (GDA_IS_META_STORE (store), FALSE); + g_return_val_if_fail (table_name, FALSE); + g_return_val_if_fail (!new_data || GDA_IS_DATA_MODEL (new_data), FALSE); + GdaMetaStorePrivate *priv = gda_meta_store_get_instance_private (store); + + if (priv->init_error) { + g_propagate_error (error, g_error_copy (priv->init_error)); + return FALSE; + } + + value_names = g_new (const gchar *, size); + values = g_new (const GValue *, size); + + va_start (ap, error); + for (n_values = 0, name = va_arg (ap, gchar*); name; n_values++, name = va_arg (ap, gchar*)) { + GValue *v; + v = va_arg (ap, GValue *); + if (n_values >= size) { + size += 5; + value_names = g_renew (const gchar *, value_names, size); + values = g_renew (const GValue *, values, size); + } + value_names [n_values] = name; + values [n_values] = v; + } + va_end (ap); + retval = gda_meta_store_modify_v (store, table_name, new_data, condition, + n_values, value_names, values, error); + g_free (value_names); + g_free (values); + return retval; +} + +/** + * gda_meta_store_modify_with_context: + * @store: a #GdaMetaStore object + * @context: (transfer none): a #GdaMetaContext context describing what to modify in @store + * @new_data: (transfer none) (nullable): a #GdaDataModel containing the new data to set in @table_name, or %NULL (treated as a data model + * with no row at all) + * @error: a place to store errors, or %NULL + * + * Propagates an update to @store, the update's contents is represented by @new_data, this function is + * primarily reserved to database providers. + * + * Returns: TRUE if no error occurred + */ +gboolean +gda_meta_store_modify_with_context (GdaMetaStore *store, GdaMetaContext *context, + GdaDataModel *new_data, GError **error) +{ + GString *cond = NULL; + gint i; + gboolean retval; + + g_return_val_if_fail (context, FALSE); + GdaMetaStorePrivate *priv = gda_meta_store_get_instance_private (store); + + for (i = 0; i < context->size; i++) { + if (i == 0) + cond = g_string_new (""); + else + g_string_append (cond, " AND "); + g_string_append_printf (cond, "%s = ##%s::%s", context->column_names [i], + context->column_names [i], + g_type_name (G_VALUE_TYPE (context->column_values [i]))); + } + + if (priv->init_error) { + g_propagate_error (error, g_error_copy (priv->init_error)); + if (cond) + g_string_free (cond, TRUE); + return FALSE; + } + + retval = gda_meta_store_modify_v (store, context->table_name, new_data, cond ? cond->str : NULL, + context->size, + (const gchar **) context->column_names, + (const GValue **)context->column_values, error); + if (cond) + g_string_free (cond, TRUE); + return retval; +} + +/*#define DEBUG_STORE_MODIFY*/ +/** + * gda_meta_store_modify_v: (rename-to gda_meta_store_modify) + * @store: a #GdaMetaStore object + * @table_name: the name of the table to modify within @store + * @new_data: (nullable): a #GdaDataModel containing the new data to set in @table_name, or %NULL (treated as a data model + * with no row at all) + * @condition: (nullable): SQL expression (which may contain variables) defining the rows which are being obsoleted by @new_data, or %NULL + * @nvalues: number of values in @value_names and @values + * @value_names: (array length=nvalues): names of values + * @values: (array length=nvalues): values + * @error: (nullable): a place to store errors, or %NULL + * + * Propagates an update to @store, the update's contents is represented by @new_data, this function is + * primarily reserved to database providers. + * + * Returns: %TRUE if no error occurred + * + * Since: 4.2.6 + */ +gboolean +gda_meta_store_modify_v (GdaMetaStore *store, const gchar *table_name, + GdaDataModel *new_data, const gchar *condition, + gint nvalues, const gchar **value_names, const GValue **values, + GError **error) +{ + TableInfo *schema_set; + TableConditionInfo *custom_set; + gboolean prep, with_cond; + gboolean retval = TRUE; + GSList *all_changes = NULL; + gboolean started_transaction = FALSE; + + g_return_val_if_fail (GDA_IS_META_STORE (store), FALSE); + GdaMetaStorePrivate *priv = gda_meta_store_get_instance_private (store); + g_return_val_if_fail (priv->cnc, FALSE); + g_return_val_if_fail (gda_connection_is_opened (priv->cnc), FALSE); + g_return_val_if_fail (!new_data || GDA_IS_DATA_MODEL (new_data), FALSE); + + g_rec_mutex_lock (& (priv->mutex)); + + /* get the correct TableInfo */ + prep = prepare_tables_infos (store, &schema_set, &custom_set, &with_cond, table_name, + condition, error, nvalues, value_names, values); + if (!prep) { + g_rec_mutex_unlock (& (priv->mutex)); + return FALSE; + } + + GdaDataModel *current = NULL; + gboolean *rows_to_del = NULL; + gint current_n_rows = 0, i; + gint current_n_cols = 0; + + if (! priv->override_mode) { + /* get current data */ + current = gda_connection_statement_execute_select_full (priv->cnc, + with_cond ? custom_set->select : + schema_set->current_all, + with_cond ? custom_set->params : NULL, + GDA_STATEMENT_MODEL_RANDOM_ACCESS, + schema_set->type_cols_array, error); + if (!current) { + g_rec_mutex_unlock (& (priv->mutex)); + return FALSE; + } + current_n_rows = gda_data_model_get_n_rows (current); + current_n_cols = gda_data_model_get_n_columns (current); + rows_to_del = g_new (gboolean, current_n_rows); + memset (rows_to_del, TRUE, sizeof (gboolean) * current_n_rows); +#ifdef DEBUG_STORE_MODIFY + g_print ("CURRENT:\n"); + gda_data_model_dump (current, stdout); +#endif + + /* start a transaction if possible */ + if (! gda_connection_get_transaction_status (priv->cnc)) { + started_transaction = gda_connection_begin_transaction (priv->cnc, NULL, + GDA_TRANSACTION_ISOLATION_UNKNOWN, + NULL); +#ifdef DEBUG_STORE_MODIFY + g_print ("------- BEGIN\n"); +#endif + } + } + else { + /* remove everything from table */ + if (gda_connection_statement_execute_non_select (priv->cnc, + schema_set->delete_all, NULL, + NULL, error) == -1) { + /*g_print ("may be error: %s\n", error && *error && (*error)->message ? (*error)->message : "Nope");*/ + g_rec_mutex_unlock (& (priv->mutex)); + return FALSE; + } + } + + /* treat rows to insert / update */ + if (new_data) { + GdaDataModel *wrapped_data; + gint new_n_rows, new_n_cols; + + if (schema_set->ident_cols) + wrapped_data = _gda_data_meta_wrapper_new (new_data, !priv->override_mode, + schema_set->ident_cols, schema_set->ident_cols_size, + priv->ident_style, + priv->reserved_keyword_func); + else + wrapped_data = g_object_ref (new_data); + + new_n_rows = gda_data_model_get_n_rows (wrapped_data); + new_n_cols = gda_data_model_get_n_columns (wrapped_data); +#ifdef DEBUG_STORE_MODIFY + if (new_data != wrapped_data) { + g_print ("NEW for table %s:\n", table_name); + gda_data_model_dump (new_data, stdout); + + g_print ("wrapped as:\n"); + gda_data_model_dump (wrapped_data, stdout); + } +#endif + + for (i = 0; i < new_n_rows; i++) { + /* find existing row if necessary */ + gint erow = -1; + gboolean has_changed = FALSE; + GdaMetaStoreChange *change = NULL; + + if (!priv->override_mode) { + if (current) { + erow = find_row_in_model (current, wrapped_data, i, + schema_set->pk_cols_array, + schema_set->pk_cols_nb, &has_changed, + error); +#ifdef DEBUG_STORE_MODIFY + g_print ("FIND row %d(/%d) returned row %d (%s)\n", i, new_n_rows - 1, erow, + has_changed ? "CHANGED" : "unchanged"); +#endif + } + if (erow < -1) { + retval = FALSE; + g_object_unref (wrapped_data); + goto out; + } + + /* prepare change information */ + change = gda_meta_store_change_new (); + gda_meta_store_change_set_table_name (change, table_name); + all_changes = g_slist_append (all_changes, change); + } + + /* bind parameters for new values */ + gint j; + for (j = 0; j < new_n_cols; j++) { + gchar *pid = g_strdup_printf ("+%d", j); + GdaHolder *h; + h = gda_set_get_holder (schema_set->params, pid); + if (h) { + const GValue *value; + GError *lerror = NULL; + value = gda_data_model_get_value_at (wrapped_data, j, i, error); + if (!value) { + g_free (pid); + retval = FALSE; + g_object_unref (wrapped_data); + goto out; + } + /* optionaly test reported GType validity */ + if ((G_VALUE_TYPE (value) == schema_set->gtype_column) && + (G_VALUE_TYPE (value) != GDA_TYPE_NULL)) { + GType gtype; + g_assert (g_type_is_a (G_VALUE_TYPE (value), G_TYPE_STRING)); + gtype = gda_g_type_from_string (g_value_get_string (value)); + if (g_type_is_a (gtype, G_TYPE_INVALID) || g_type_is_a (gtype, GDA_TYPE_NULL)) { + g_warning (" Unknown reported type '%s', please report this bug to " + "https://gitlab.gnome.org/GNOME/libgda/issues", g_value_get_string (value)); + } + } + + if (! gda_holder_set_value (h, value, &lerror)) { + g_free (pid); + retval = FALSE; + g_object_unref (wrapped_data); + g_set_error (error, GDA_META_STORE_ERROR, GDA_META_STORE_EXTRACT_SQL_ERROR, + _("Internal error, while updating internal meta store table '%s': Parameter value type error: %s"), + table_name, lerror && lerror->message ? lerror->message : "No error message was set"); + g_clear_error (&lerror); + goto out; + } + if (change) { + /*g_print ("CH %p key=[%s] value=[%s]\n", change, pid, gda_value_stringify (value)); */ + g_hash_table_insert (change->keys, pid, gda_value_copy (value)); + pid = NULL; + } + } + g_free (pid); + } + + /* execute INSERT or UPDATE statements */ + if (erow == -1) { + /* INSERT: bind INSERT parameters */ +#ifdef DEBUG_STORE_MODIFY + g_print ("Insert new row %d into table %s\n", i, table_name); +#endif + if (gda_connection_statement_execute_non_select (priv->cnc, + schema_set->insert, schema_set->params, + NULL, error) == -1) { + retval = FALSE; + g_object_unref (wrapped_data); + goto out; + } + if (change) + change->c_type = GDA_META_STORE_ADD; + } + else if (has_changed) { + /* also bind parameters with existing values */ + for (j = 0; j < current_n_cols; j++) { + gchar *pid = g_strdup_printf ("-%d", j); + GdaHolder *h; + h = gda_set_get_holder (schema_set->params, pid); + if (h) { + const GValue *value; + value = gda_data_model_get_value_at (current, j, erow, error); + if (!value) { + g_free (pid); + retval = FALSE; + g_object_unref (wrapped_data); + goto out; + } + if (!gda_holder_set_value (h, value, error)) { + g_free (pid); + retval = FALSE; + g_object_unref (wrapped_data); + goto out; + } + if (change) { + /* g_print ("CH %p key=[%s] value=[%s]\n", change, pid, gda_value_stringify (value)); */ + g_hash_table_insert (change->keys, pid, gda_value_copy (value)); + pid = NULL; + } + } + g_free (pid); + } + /* UPDATE */ +#ifdef DEBUG_STORE_MODIFY + g_print ("Update for row %d (old row was %d) into table %s\n", i, erow, table_name); +#endif + if (gda_connection_statement_execute_non_select (priv->cnc, + schema_set->update, schema_set->params, + NULL, error) == -1) { + retval = FALSE; + g_object_unref (wrapped_data); + goto out; + } + if (change) + change->c_type = GDA_META_STORE_MODIFY; + rows_to_del [erow] = FALSE; + } + else if (rows_to_del) + /* row has not changed */ + rows_to_del [erow] = FALSE; + + if (!priv->override_mode) { + /* Dependencies update: reverse_fk_list */ + GSList *list; + for (list = schema_set->reverse_fk_list; list; list = list->next) { + TableFKey *tfk = (TableFKey*) list->data; + gint k; + GdaMetaContext context; + + context.table_name = tfk->table_info->obj_name; + context.size = tfk->cols_nb; + context.column_names = tfk->fk_names_array; + context.column_values = g_new (GValue *, context.size); + + for (k = 0; k < tfk->cols_nb; k++) { + context.column_values [k] = (GValue*) gda_data_model_get_value_at (new_data, + tfk->ref_pk_cols_array[k], i, error); + if (!context.column_values [k]) { + g_free (context.column_values); + retval = FALSE; + g_object_unref (wrapped_data); + goto out; + } + } +#ifdef DEBUG_STORE_MODIFY + g_print ("Suggest update data into table '%s':", tfk->table_info->obj_name); + for (k = 0; k < tfk->cols_nb; k++) { + gchar *str; + str = gda_value_stringify (context.column_values [k]); + g_print (" [%s => %s]", context.column_names[k], str); + g_free (str); + } + g_print ("\n"); +#endif + GError *suggest_reports_error = NULL; + g_signal_emit (store, gda_meta_store_signals[SUGGEST_UPDATE], 0, &context, + &suggest_reports_error); + g_free (context.column_values); + if (suggest_reports_error) { + retval = FALSE; + if (error && !(*error)) + g_propagate_error (error, suggest_reports_error); + else + g_error_free (suggest_reports_error); + g_object_unref (wrapped_data); + goto out; + } + } + } + } + g_object_unref (wrapped_data); + } + + if (!priv->override_mode) { + /* treat rows to delete */ + for (i = 0; i < current_n_rows; i++) { + if (rows_to_del [i]) { + /* prepare change information */ + GdaMetaStoreChange *change = NULL; + change = gda_meta_store_change_new (); + gda_meta_store_change_set_change_type (change, GDA_META_STORE_REMOVE); + gda_meta_store_change_set_table_name (change, table_name); + all_changes = g_slist_append (all_changes, change); + + /* DELETE */ + gint j; + for (j = 0; j < current_n_cols; j++) { + gchar *pid = g_strdup_printf ("-%d", j); + GdaHolder *h; + const GValue *value; + value = gda_data_model_get_value_at (current, j, i, error); + if (!value) { + g_free (pid); + retval = FALSE; + goto out; + } + + h = gda_set_get_holder (schema_set->params, pid); + if (h && ! gda_holder_set_value (h, value, error)) { + g_free (pid); + retval = FALSE; + goto out; + } + + /* g_print ("CH %p key=[%s] value=[%s]\n", change, pid, gda_value_stringify (value)); */ + g_hash_table_insert (change->keys, pid, gda_value_copy (value)); + } +#ifdef DEBUG_STORE_MODIFY + g_print ("Delete existing row %d from table %s\n", i, table_name); +#endif + /* reverse_fk_list */ + GSList *list; + for (list = schema_set->reverse_fk_list; list; list = list->next) { + TableFKey *tfk = (TableFKey*) list->data; + const GValue **values; + gint k; + + /*g_print ("Also remove data from table '%s'...\n", tfk->table_info->obj_name);*/ + values = g_new (const GValue *, tfk->cols_nb); + for (k = 0; k < tfk->cols_nb; k++) { + values [k] = gda_data_model_get_value_at (current, tfk->ref_pk_cols_array[k], i, error); + if (!values [k]) { + g_free (values); + retval = FALSE; + goto out; + } + } + if (!gda_meta_store_modify_v (store, tfk->table_info->obj_name, NULL, + tfk->fk_fields_cond, + tfk->cols_nb, (const gchar **) tfk->fk_names_array, values, error)) { + retval = FALSE; + g_free (values); + goto out; + } + g_free (values); + } + + if (gda_connection_statement_execute_non_select (priv->cnc, + schema_set->delete, schema_set->params, + NULL, error) == -1) { + retval = FALSE; + goto out; + } + } + } + + if (retval && started_transaction) { + retval = gda_connection_commit_transaction (priv->cnc, NULL, NULL); +#ifdef DEBUG_STORE_MODIFY + g_print ("------- COMMIT\n"); +#endif + } + if (retval && all_changes) + g_signal_emit (store, gda_meta_store_signals[META_CHANGED], 0, all_changes); + } + +out: + if (all_changes) { + g_slist_free_full (all_changes, (GDestroyNotify) gda_meta_store_change_free); + } + g_free (rows_to_del); + if (current) + g_object_unref (current); + if (!retval && started_transaction) { + gda_connection_rollback_transaction (priv->cnc, NULL, NULL); +#ifdef DEBUG_STORE_MODIFY + g_print ("------- ROLLBACK\n"); +#endif + } + + g_rec_mutex_unlock (& (priv->mutex)); + return retval; +} + + +/* + * Find the row in @find_in from the values of @data at line @row, and columns pointed by + * the values of @pk_cols + * + * Returns: + * -2 on error, + * -1 if not found, + * >=0 if found (if changes need to be made, then @out_has_changed is set to TRUE). + */ +static gint +find_row_in_model (GdaDataModel *find_in, GdaDataModel *data, gint row, gint *pk_cols, gint pk_cols_nb, + gboolean *out_has_changed, GError **error) +{ + gint i, erow; + GSList *values = NULL; + + for (i = 0; i < pk_cols_nb; i++) { + const GValue *cvalue; + cvalue = gda_data_model_get_value_at (data, pk_cols[i], row, error); + if (!cvalue) + return -2; + values = g_slist_append (values, (gpointer) cvalue); + } + erow = gda_data_model_get_row_from_values (find_in, values, pk_cols); + g_slist_free (values); + + if (erow >= 0) { + gint ncols; + ncols = gda_data_model_get_n_columns (find_in); + if (ncols > gda_data_model_get_n_columns (data)) { + g_set_error (error, GDA_META_STORE_ERROR, GDA_META_STORE_MODIFY_CONTENTS_ERROR, + "%s", _("Data models should have the same number of columns")); + erow = -2; + } + else { + gboolean changed = FALSE; + for (i = 0; i < ncols; i++) { + const GValue *v1, *v2; + v1 = gda_data_model_get_value_at (find_in, i, erow, error); + if (!v1) + return -2; + v2 = gda_data_model_get_value_at (data, i, row, error); + if (!v2) + return -2; + if (gda_value_compare (v1, v2)) { + changed = TRUE; + break; + } + } + *out_has_changed = changed; + } + } + + return erow; +} + +static TableConditionInfo *create_custom_set (GdaMetaStore *store, const gchar *table_name, const gchar *condition, GError **error); + +static gboolean +prepare_tables_infos (GdaMetaStore *store, TableInfo **out_table_infos, TableConditionInfo **out_cond_infos, + gboolean *out_with_key, + const gchar *table_name, const gchar *condition, GError **error, + gint nvalues, const gchar **value_names, const GValue **values) +{ + GdaMetaStoreClass *klass = (GdaMetaStoreClass *) G_OBJECT_GET_CLASS (store); + GdaMetaStorePrivate *priv = gda_meta_store_get_instance_private (store); + + g_assert (out_table_infos); + g_assert (out_cond_infos); + g_assert (out_with_key); + *out_with_key = FALSE; + + /* compute *out_cond_infos */ + *out_cond_infos= NULL; + if (condition) { + gchar *key; + key = g_strdup_printf ("%s.%s", table_name, condition); + *out_with_key = TRUE; + *out_cond_infos = g_hash_table_lookup (priv->table_cond_info_hash, key); + if (! *out_cond_infos) { + *out_cond_infos = create_custom_set (store, table_name, condition, error); + if (! *out_cond_infos) { + g_free (key); + return FALSE; + } + g_hash_table_insert (priv->table_cond_info_hash, key, *out_cond_infos); + } + else + g_free (key); + } + + /* fetch or create *out_table_infos */ + DbObject *dbobj = g_hash_table_lookup (priv->db_objects_hash, table_name); + if (!dbobj) { + g_set_error (error, GDA_META_STORE_ERROR, GDA_META_STORE_SCHEMA_OBJECT_NOT_FOUND_ERROR, + _("Unknown database object '%s'"), table_name); + return FALSE; + } + *out_table_infos = TABLE_INFO (dbobj); + + /* bind parameters for *out_cond_infos */ + gint i; + for (i = 0; i < nvalues; i++) { + GdaHolder *h; + GValue *wvalue; + + wvalue = _gda_data_meta_wrapper_compute_value (values [i], priv->ident_style, + priv->reserved_keyword_func); + h = gda_set_get_holder ((*out_cond_infos)->params, value_names [i]); + if (!h || !gda_holder_set_value (h, wvalue ? wvalue : values[i], NULL)) { + g_set_error (error, GDA_META_STORE_ERROR, GDA_META_STORE_INTERNAL_ERROR, + _ ("Could not set value for parameter '%s'"), value_names [i]); + if (wvalue) + gda_value_free (wvalue); + return FALSE; + } + if (wvalue) + gda_value_free (wvalue); + } + + return TRUE; +} + +static TableConditionInfo * +create_custom_set (GdaMetaStore *store, const gchar *table_name, const gchar *condition, GError **error) +{ + gchar *sql; + TableConditionInfo *set; + GdaMetaStorePrivate *priv = gda_meta_store_get_instance_private (store); + + g_assert (condition); + set = g_new0 (TableConditionInfo, 1); + + /* SELECT */ + sql = g_strdup_printf ("SELECT * FROM %s WHERE %s", table_name, condition); + set->select = compute_prepared_stmt (priv->parser, sql); + g_free (sql); + if (!set->select || + (gda_statement_get_statement_type (set->select) != GDA_SQL_STATEMENT_SELECT)) { + g_set_error (error, GDA_META_STORE_ERROR, GDA_META_STORE_MODIFY_CONTENTS_ERROR, + "%s", _("Could not create SELECT statement")); + goto out; + } + + /* parameters (are the same for both statements */ + if (! gda_statement_get_parameters (set->select, &(set->params), error)) + goto out; + + /* DELETE */ + sql = g_strdup_printf ("DELETE FROM %s WHERE %s", table_name, condition); + set->delete = compute_prepared_stmt (priv->parser, sql); + g_free (sql); + if (!set->delete|| + (gda_statement_get_statement_type (set->delete) != GDA_SQL_STATEMENT_DELETE)) { + g_set_error (error, GDA_META_STORE_ERROR, GDA_META_STORE_MODIFY_CONTENTS_ERROR, + "%s", _("Could not create DELETE statement")); + goto out; + } + return set; + +out: + if (set->select) + g_object_unref (set->select); + if (set->delete) + g_object_unref (set->delete); + if (set->params) + g_object_unref (set->params); + g_free (set); + return NULL; +} + +/** + * _gda_meta_store_begin_data_reset: + * @store: a #GdaMetaStore object + * @error: (nullable): a place to store errors, or %NULL + * + * Sets @store in a mode where only the modifications completely overriding a table + * will be allowed, where no detailed modifications report is made and where the "suggest-update" + * signal is not emitted. + * + * Returns: TRUE if no error occurred + */ +gboolean +_gda_meta_store_begin_data_reset (GdaMetaStore *store, GError **error) +{ + g_return_val_if_fail (GDA_IS_META_STORE (store), FALSE); + GdaMetaStorePrivate *priv = gda_meta_store_get_instance_private (store); + + if (priv->init_error) { + g_propagate_error (error, g_error_copy (priv->init_error)); + return FALSE; + } + + if (priv->override_mode) + return TRUE; + + g_rec_mutex_lock (& (priv->mutex)); + if (! gda_connection_get_transaction_status (priv->cnc)) { + if (!gda_connection_begin_transaction (priv->cnc, NULL, + GDA_TRANSACTION_ISOLATION_UNKNOWN, error)) { + g_rec_mutex_unlock (& (priv->mutex)); + return FALSE; + } + } + else { + g_set_error (error, GDA_META_STORE_ERROR, GDA_META_STORE_TRANSACTION_ALREADY_STARTED_ERROR, + "%s", _("A transaction has already been started")); + g_rec_mutex_unlock (& (priv->mutex)); + return FALSE; + + } + priv->override_mode = TRUE; + g_rec_mutex_unlock (& (priv->mutex)); + return TRUE; +} + +/** + * _gda_meta_store_cancel_data_reset: + * @store: a #GdaMetaStore object + * @error: (nullable): a place to store errors, or %NULL + * + * Cancels any modification done since _gda_meta_store_begin_data_reset() was called. + * + * Returns: TRUE if no error occurred + */ +gboolean +_gda_meta_store_cancel_data_reset (GdaMetaStore *store, GError **error) +{ + gboolean retval; + g_return_val_if_fail (GDA_IS_META_STORE (store), FALSE); + GdaMetaStorePrivate *priv = gda_meta_store_get_instance_private (store); + + if (priv->init_error) { + g_propagate_error (error, g_error_copy (priv->init_error)); + return FALSE; + } + + g_rec_mutex_lock (& (priv->mutex)); + if (!priv->override_mode) { + g_rec_mutex_unlock (& (priv->mutex)); + return TRUE; + } + + priv->override_mode = FALSE; + retval = gda_connection_rollback_transaction (priv->cnc, NULL, error); + g_rec_mutex_unlock (& (priv->mutex)); + return retval; +} + +/** + * _gda_meta_store_finish_data_reset: + * @store: a #GdaMetaStore object + * @error: (nullable): a place to store errors, or %NULL + * + * Commits any modification done since _gda_meta_store_begin_data_reset() was called. + * + * Returns: TRUE if no error occurred + */ +gboolean +_gda_meta_store_finish_data_reset (GdaMetaStore *store, GError **error) +{ + g_return_val_if_fail (GDA_IS_META_STORE (store), FALSE); + GdaMetaStorePrivate *priv = gda_meta_store_get_instance_private (store); + + if (priv->init_error) { + g_propagate_error (error, g_error_copy (priv->init_error)); + return FALSE; + } + + g_rec_mutex_lock (& (priv->mutex)); + if (!priv->override_mode) { + g_rec_mutex_unlock (& (priv->mutex)); + return TRUE; + } + + priv->override_mode = FALSE; + if (!gda_connection_commit_transaction (priv->cnc, NULL, error)) { + g_rec_mutex_unlock (& (priv->mutex)); + return FALSE; + } + else { + g_signal_emit (store, gda_meta_store_signals[META_RESET], 0); + g_rec_mutex_unlock (& (priv->mutex)); + return TRUE; + } +} + + + +/** + * gda_meta_store_create_modify_data_model: + * @store: a #GdaMetaStore object + * @table_name: the name of a table present in @store + * + * Creates a new #GdaDataModelArray data model which can be used, after being correctly filled, + * with the gda_meta_store_modify*() methods.* + * + * To be used by provider's implementation + * + * Returns: (transfer full): a new #GdaDataModel + */ +GdaDataModel * +gda_meta_store_create_modify_data_model (GdaMetaStore *store, const gchar *table_name) +{ + DbObject *dbobj; + TableInfo *tinfo; + GdaDataModel *model; + GSList *list; + gint i; + + g_return_val_if_fail (GDA_IS_META_STORE (store), FALSE); + g_return_val_if_fail (table_name && *table_name, FALSE); + GdaMetaStorePrivate *priv = gda_meta_store_get_instance_private (store); + + g_rec_mutex_lock (& (priv->mutex)); + + dbobj = g_hash_table_lookup (priv->p_db_objects_hash, table_name); + if (!dbobj) { + g_warning ("Table '%s' is not known by the GdaMetaStore", table_name); + g_rec_mutex_unlock (& (priv->mutex)); + return NULL; + } + if (dbobj->obj_type != GDA_SERVER_OPERATION_CREATE_TABLE) { + g_warning ("Table '%s' is not a database table in the GdaMetaStore", table_name); + g_rec_mutex_unlock (& (priv->mutex)); + return NULL; + } + + tinfo = TABLE_INFO (dbobj); + model = gda_data_model_array_new (g_slist_length (tinfo->columns)); + for (i = 0, list = tinfo->columns; list; list = list->next, i++) { + GdaColumn *col; + TableColumn *tcol = TABLE_COLUMN (list->data); + + col = gda_data_model_describe_column (model, i); + gda_column_set_g_type (col, tcol->gtype); + gda_column_set_name (col, tcol->column_name); + } + + g_rec_mutex_unlock (& (priv->mutex)); + return model; +} + +/** + * gda_meta_store_schema_get_all_tables: + * @store: a #GdaMetaStore object + * + * Get an ordered list of the tables @store knows about. The tables are ordered in a way that tables dependencies + * are respected: if table B has a foreign key on table A, then table A will be listed before table B in the returned + * list. + * + * Returns: (transfer container) (element-type utf8): a new list of tables names (as gchar*), the list must be freed when no longer needed, but the strings present in the list must not be modified. + */ +GSList * +gda_meta_store_schema_get_all_tables (GdaMetaStore *store) +{ + GSList *list, *ret; + + g_return_val_if_fail (GDA_IS_META_STORE (store), NULL); + GdaMetaStorePrivate *priv = gda_meta_store_get_instance_private (store); + + g_rec_mutex_lock (& (priv->mutex)); + + for (ret = NULL, list = priv->db_objects; list; list = list->next) { + DbObject *dbobj = DB_OBJECT (list->data); + if (dbobj->obj_type == GDA_SERVER_OPERATION_CREATE_TABLE) + ret = g_slist_prepend (ret, dbobj->obj_name); + } + for (ret = NULL, list = priv->p_db_objects; list; list = list->next) { + DbObject *dbobj = DB_OBJECT (list->data); + if (dbobj->obj_type == GDA_SERVER_OPERATION_CREATE_TABLE) + ret = g_slist_prepend (ret, dbobj->obj_name); + } + + g_rec_mutex_unlock (& (priv->mutex)); + + return g_slist_reverse (ret); +} + +/** + * gda_meta_store_schema_get_depend_tables: + * @store: a #GdaMetaStore object + * @table_name: the name of the table for which all the dependencies must be listed + * + * + * Get an ordered list of the tables @store knows about on which the @table_name table depends (recursively). + * The tables are ordered in a way that tables dependencies + * are respected: if table B has a foreign key on table A, then table A will be listed before table B in the returned + * list. + * + * Returns: (transfer container) (element-type utf8): a new list of tables names (as gchar*), the list must be freed when no longer needed, but the strings present in the list must not be modified. + */ +GSList * +gda_meta_store_schema_get_depend_tables (GdaMetaStore *store, const gchar *table_name) +{ + GSList *list, *ret; + DbObject *dbo; + + g_return_val_if_fail (GDA_IS_META_STORE (store), NULL); + g_return_val_if_fail (table_name && *table_name, NULL); + GdaMetaStorePrivate *priv = gda_meta_store_get_instance_private (store); + + g_rec_mutex_lock (& (priv->mutex)); + dbo = g_hash_table_lookup (priv->p_db_objects_hash, table_name); + if (!dbo) { + g_rec_mutex_unlock (& (priv->mutex)); + return NULL; + } + + for (ret = NULL, list = dbo->depend_list; list; list = list->next) { + DbObject *dbobj = DB_OBJECT (list->data); + if (dbobj->obj_type == GDA_SERVER_OPERATION_CREATE_TABLE) + ret = g_slist_prepend (ret, dbobj->obj_name); + } + + g_rec_mutex_unlock (& (priv->mutex)); + + return g_slist_reverse (ret); +} + + +/** + * gda_meta_store_schema_get_structure: + * @store: a #GdaMetaStore object + * @error: (nullable): a place to store errors, or %NULL + * + * Creates a new #GdaMetaStruct object representing @store's internal database structure. + * + * Returns: (transfer full): a new #GdaMetaStruct object, or %NULL if an error occurred + */ +GdaMetaStruct * +gda_meta_store_schema_get_structure (GdaMetaStore *store, GError **error) +{ + GdaMetaStruct *mstruct; + GdaDataModel *model; + gint i, nrows; + GdaMetaStore *real_store; + + g_return_val_if_fail (GDA_IS_META_STORE (store), NULL); + GdaMetaStorePrivate *priv = gda_meta_store_get_instance_private (store); + if (priv->init_error) { + g_propagate_error (error, g_error_copy (priv->init_error)); + return NULL; + } + + g_rec_mutex_lock (& (priv->mutex)); + + /* make sure the private connection's meta store is up to date */ + if (! gda_connection_update_meta_store (priv->cnc, NULL, error)) { + g_rec_mutex_unlock (& (priv->mutex)); + return NULL; + } + + /* create a GdaMetaStruct */ + real_store = gda_connection_get_meta_store (priv->cnc); + GdaMetaStorePrivate *real_priv = gda_meta_store_get_instance_private (real_store); + model = gda_meta_store_extract (real_store, + "SELECT table_catalog, table_schema, table_name FROM _tables", + error, NULL); + if (!model) { + g_rec_mutex_unlock (& (priv->mutex)); + return NULL; + } + + mstruct = (GdaMetaStruct*) g_object_new (GDA_TYPE_META_STRUCT, "meta-store", real_store, "features", GDA_META_STRUCT_FEATURE_ALL, NULL); + nrows = gda_data_model_get_n_rows (model); + for (i = 0; i < nrows; i++) { + /* FIXME: only take into account the database objects which have a corresponding DbObject */ + const GValue *cv0, *cv1, *cv2; + cv0 = gda_data_model_get_value_at (model, 0, i, error); + if (!cv0) { + g_rec_mutex_unlock (& (priv->mutex)); + return NULL; + } + cv1 = gda_data_model_get_value_at (model, 1, i, error); + if (!cv1) { + g_rec_mutex_unlock (& (priv->mutex)); + return NULL; + } + cv2 = gda_data_model_get_value_at (model, 2, i, error); + if (!cv2) { + g_rec_mutex_unlock (& (priv->mutex)); + return NULL; + } + if (!gda_meta_struct_complement (mstruct, GDA_META_DB_UNKNOWN, cv0, cv1, cv2, error)) { + g_object_unref (mstruct); + g_object_unref (model); + g_rec_mutex_unlock (& (priv->mutex)); + return NULL; + } + } + g_object_unref (model); + + /* complement the meta struct with some info about dependencies */ + GSList *list, *all_db_obj_list; + + all_db_obj_list = g_slist_copy (priv->db_objects); + if (real_priv->p_db_objects) + all_db_obj_list = g_slist_concat (all_db_obj_list, + g_slist_copy (real_priv->p_db_objects)); + + for (list = all_db_obj_list; list; list = list->next) { + DbObject *dbobj = DB_OBJECT (list->data); + if (dbobj->obj_type == GDA_SERVER_OPERATION_CREATE_TABLE) { + GdaMetaDbObject *mdbo; + GSList *dep_list; + GValue *value; + + g_value_set_string ((value = gda_value_new (G_TYPE_STRING)), dbobj->obj_name); + mdbo = gda_meta_struct_get_db_object (mstruct, NULL, NULL, value); + gda_value_free (value); + if (!mdbo) + continue; + for (dep_list = dbobj->depend_list; dep_list; dep_list = dep_list->next) { + GdaMetaDbObject *dep_mdbo; + g_value_set_string ((value = gda_value_new (G_TYPE_STRING)), DB_OBJECT (dep_list->data)->obj_name); + dep_mdbo = gda_meta_struct_get_db_object (mstruct, NULL, NULL, value); + gda_value_free (value); + if (dep_mdbo && !g_slist_find (mdbo->depend_list, dep_mdbo)) { + /* FIXME: dependencies are added using the mdbo->depend_list list, and not as + * real foreign key */ + mdbo->depend_list = g_slist_append (mdbo->depend_list, dep_mdbo); + } + } + } + } + g_slist_free (all_db_obj_list); + + g_rec_mutex_unlock (& (priv->mutex)); + + return mstruct; +} + +/** + * gda_meta_store_get_attribute_value: + * @store: a #GdaMetaStore object + * @att_name: name of the attribute to get + * @att_value: (out): the place to store the attribute value + * @error: (nullable): a place to store errors, or %NULL + * + * The #GdaMetaStore object maintains a list of (name,value) attributes (attributes names starting with a '_' + * character are for internal use only and cannot be altered). This method and the gda_meta_store_set_attribute_value() + * method allows the user to add, set or remove attributes specific to their usage. + * + * This method allows to get the value of a attribute stored in @store. The returned attribute value is + * placed at @att_value, the caller is responsible for free that string. + * + * If there is no attribute named @att_name then @att_value is set to %NULL + * and @error will contain the GDA_META_STORE_ATTRIBUTE_NOT_FOUND_ERROR error code, and FALSE is returned. + * + * Returns: TRUE if no error occurred + */ +gboolean +gda_meta_store_get_attribute_value (GdaMetaStore *store, const gchar *att_name, gchar **att_value, GError **error) +{ + GdaDataModel *model; + GValue *value; + gint nrows; + g_return_val_if_fail (GDA_IS_META_STORE (store), FALSE); + g_return_val_if_fail (att_name && *att_name, FALSE); + g_return_val_if_fail (att_value, FALSE); + GdaMetaStorePrivate *priv = gda_meta_store_get_instance_private (store); + + if (priv->init_error) { + g_propagate_error (error, g_error_copy (priv->init_error)); + return FALSE; + } + + g_rec_mutex_lock (& (priv->mutex)); + + *att_value = NULL; + g_value_set_string ((value = gda_value_new (G_TYPE_STRING)), att_name); + model = gda_meta_store_extract (store, "SELECT att_value FROM _attributes WHERE att_name = ##n::string", error, + "n", value, NULL); + gda_value_free (value); + if (!model) { + g_rec_mutex_unlock (& (priv->mutex)); + return FALSE; + } + nrows = gda_data_model_get_n_rows (model); + if (nrows < 1) + g_set_error (error, GDA_META_STORE_ERROR, GDA_META_STORE_ATTRIBUTE_NOT_FOUND_ERROR, + _("Attribute '%s' not found"), att_name); + else if (nrows > 1) + g_set_error (error, GDA_META_STORE_ERROR, GDA_META_STORE_ATTRIBUTE_ERROR, + ngettext ("Attribute '%s' has %d value", "Attribute '%s' has %d values", nrows), + att_name, nrows); + else { + value = (GValue*) gda_data_model_get_value_at (model, 0, 0, error); + if (!value) { + g_rec_mutex_unlock (& (priv->mutex)); + return FALSE; + } + if (G_VALUE_TYPE (value) == G_TYPE_STRING) { + const gchar *val; + val = g_value_get_string (value); + if (val) + *att_value = g_strdup (val); + } + g_rec_mutex_unlock (& (priv->mutex)); + return TRUE; + } + g_rec_mutex_unlock (& (priv->mutex)); + return FALSE; +} + +/** + * gda_meta_store_set_attribute_value: + * @store: a #GdaMetaStore object + * @att_name: name of the attribute to set + * @att_value: (nullable): value of the attribute to set, or %NULL to unset the attribute + * @error: (nullable): a place to store errors, or %NULL + * + * Set the value of the attribute named @att_name to @att_value; see gda_meta_store_get_attribute_value() for + * more information. + * + * Returns: TRUE if no error occurred + */ +gboolean +gda_meta_store_set_attribute_value (GdaMetaStore *store, const gchar *att_name, + const gchar *att_value, GError **error) +{ + gboolean started_transaction = FALSE; + + g_return_val_if_fail (GDA_IS_META_STORE (store), FALSE); + g_return_val_if_fail (att_name && *att_name, FALSE); + GdaMetaStorePrivate *priv = gda_meta_store_get_instance_private (store); + + if (*att_name == '_') { + g_set_error (error, GDA_META_STORE_ERROR, GDA_META_STORE_ATTRIBUTE_ERROR, + "%s", _("Attributes names starting with a '_' are reserved for internal usage")); + return FALSE; + } + + g_rec_mutex_lock (& (priv->mutex)); + + if (!priv->attributes_set) { + if (!gda_statement_get_parameters (priv->prep_stmts [STMT_SET_ATT_VALUE], &priv->attributes_set, error)) { + g_rec_mutex_unlock (& (priv->mutex)); + return FALSE; + } + } + + if (!gda_set_set_holder_value (priv->attributes_set, error, "name", att_name)) { + g_rec_mutex_unlock (& (priv->mutex)); + return FALSE; + } + + /* start a transaction if possible */ + gda_lockable_lock (GDA_LOCKABLE (priv->cnc)); + gda_connection_increase_usage (priv->cnc); /* USAGE ++ */ + if (! gda_connection_get_transaction_status (priv->cnc)) + started_transaction = gda_connection_begin_transaction (priv->cnc, NULL, + GDA_TRANSACTION_ISOLATION_UNKNOWN, + NULL); + else + g_warning (_("Could not start a transaction because one already started, this could lead to GdaMetaStore " + "attributes problems")); + + /* delete existing attribute */ + if (gda_connection_statement_execute_non_select (priv->cnc, + priv->prep_stmts [STMT_DEL_ATT_VALUE], priv->attributes_set, + NULL, error) == -1) + goto onerror; + + if (att_value) { + /* set new attribute */ + if (!gda_set_set_holder_value (priv->attributes_set, error, "value", att_value)) + goto onerror; + + if (gda_connection_statement_execute_non_select (priv->cnc, + priv->prep_stmts [STMT_SET_ATT_VALUE], priv->attributes_set, + NULL, error) == -1) + goto onerror; + } + if (started_transaction) + gda_connection_commit_transaction (priv->cnc, NULL, NULL); + gda_connection_decrease_usage (priv->cnc); /* USAGE -- */ + gda_lockable_unlock (GDA_LOCKABLE (priv->cnc)); + g_rec_mutex_unlock (& (priv->mutex)); + return TRUE; + + onerror: + if (started_transaction) + gda_connection_rollback_transaction (priv->cnc, NULL, NULL); + gda_connection_decrease_usage (priv->cnc); /* USAGE -- */ + gda_lockable_unlock (GDA_LOCKABLE (priv->cnc)); + g_rec_mutex_unlock (& (priv->mutex)); + return FALSE; +} + +/** + * gda_meta_store_schema_add_custom_object: + * @store: a #GdaMetaStore object + * @xml_description: an XML description of the table or view to add to @store + * @error: (nullable): a place to store errors, or %NULL + * + * The internal database used by @store can be 'augmented' with some user-defined database objects + * (such as tables or views). This method allows one to add a new database object. + * + * If the internal database already contains the object, then: + * + * if the object is equal to the provided description then TRUE is returned + * if the object exists but differs from the provided description, then FALSE is returned, + * with the GDA_META_STORE_SCHEMA_OBJECT_CONFLICT_ERROR error code + * + * + * The @xml_description defines the table of view's definition, for example: + * + + +
]]> + * + * The partial DTD for this XML description of the object to add is the following (the top node must be + * a <table> or a <view>): + * + + + + + + + + + + + + + + + + +]]> + * + * Returns: TRUE if the new object has successfully been added + */ +gboolean +gda_meta_store_schema_add_custom_object (GdaMetaStore *store, const gchar *xml_description, GError **error) +{ + xmlDocPtr doc; + xmlNodePtr node; + DbObject *dbo = NULL; + GValue *value; + GdaMetaStore *pstore = NULL; + GdaMetaStruct *mstruct = NULL; + GError *lerror = NULL; + + GSList *pre_p_db_objects = NULL; + + g_return_val_if_fail (GDA_IS_META_STORE (store), FALSE); + g_return_val_if_fail (xml_description && *xml_description, FALSE); + GdaMetaStorePrivate *priv = gda_meta_store_get_instance_private (store); + + if (priv->init_error) { + g_propagate_error (error, g_error_copy (priv->init_error)); + return FALSE; + } + + /* load XML description */ + doc = xmlParseDoc (BAD_CAST xml_description); + if (!doc) { + g_set_error (error, GDA_META_STORE_ERROR, GDA_META_STORE_SCHEMA_OBJECT_DESCR_ERROR, + "%s", _("Could not parse XML description of custom database object to add")); + return FALSE; + } + node = xmlDocGetRootElement (doc); + + g_rec_mutex_lock (& (priv->mutex)); + + + /* check that object name does not start with '_' */ + xmlChar *prop; + prop = xmlGetProp (node, BAD_CAST "name"); + if (!prop) { + g_set_error (error, GDA_META_STORE_ERROR, GDA_META_STORE_SCHEMA_OBJECT_DESCR_ERROR, + "%s", _("Missing custom database object name")); + goto onerror; + } + else if (*prop == '_') { + g_set_error (error, GDA_META_STORE_ERROR, GDA_META_STORE_SCHEMA_OBJECT_DESCR_ERROR, + "%s", _("Custom database object names starting with a '_' are reserved for internal usage")); + goto onerror; + } + + /* keep a list of custom DB objects _before_ adding the new one(s) (more than + * one if there are dependencies) */ + pre_p_db_objects = g_slist_copy (priv->p_db_objects); + + /* create DbObject structure from XML description, stored in @store's custom db objects */ + if (!strcmp ((gchar *) node->name, "table")) + dbo = create_table_object (priv, store, node, error); + else if (!strcmp ((gchar *) node->name, "view")) + dbo = create_view_object (priv, store, node, error); + + if (!dbo) + goto onerror; + xmlFreeDoc (doc); + doc = NULL; + + /* check for an already existing database object with the same name */ + /*g_print ("Obj name: %s\n", dbo->obj_name);*/ + + /* make sure the private connection's meta store is up to date about the requested object */ + switch (dbo->obj_type) { + case GDA_SERVER_OPERATION_CREATE_TABLE: + case GDA_SERVER_OPERATION_CREATE_VIEW: { + GdaMetaContext context; + gboolean upd_ok; + memset (&context, 0, sizeof (GdaMetaContext)); + context.table_name = "_tables"; + context.size = 1; + context.column_names = g_new0 (gchar *, 3); + context.column_values = g_new0 (GValue *, 3); + context.column_names[0] = "table_name"; + g_value_set_string ((context.column_values[0] = gda_value_new (G_TYPE_STRING)), dbo->obj_name); + upd_ok = gda_connection_update_meta_store (priv->cnc, &context, error); + g_free (context.column_names); + gda_value_free (context.column_values[0]); + g_free (context.column_values); + if (!upd_ok) + goto onerror; + break; + } + default: + TO_IMPLEMENT; + } + + /* create a GdaMetaStruct */ + GdaMetaDbObject *eobj; + gboolean needs_creation = TRUE; + pstore = gda_connection_get_meta_store (priv->cnc); + mstruct = (GdaMetaStruct*) g_object_new (GDA_TYPE_META_STRUCT, "meta-store", pstore, "features", GDA_META_STRUCT_FEATURE_ALL, NULL); + g_value_set_string ((value = gda_value_new (G_TYPE_STRING)), dbo->obj_name); + if (!(eobj = gda_meta_struct_complement (mstruct, GDA_META_DB_UNKNOWN, + NULL, NULL, value, &lerror))) { + if (lerror && (lerror->domain == GDA_META_STRUCT_ERROR) && + (lerror->code == GDA_META_STRUCT_UNKNOWN_OBJECT_ERROR)) + g_error_free (lerror); + else { + g_propagate_error (error, lerror); + goto onerror; + } + } + gda_value_free (value); + + if (eobj) { + gboolean conflict = FALSE; + + /*g_print ("Check Existing object's conformance...\n");*/ + switch (eobj->obj_type) { + case GDA_META_DB_TABLE: + if (dbo->obj_type != GDA_SERVER_OPERATION_CREATE_TABLE) + conflict = TRUE; + else { + GdaMetaTable *mt = GDA_META_TABLE (eobj); + TableInfo *ti = TABLE_INFO (dbo); + if (g_slist_length (mt->columns) != g_slist_length (ti->columns)) + conflict = TRUE; + } + break; + case GDA_META_DB_VIEW: + if (dbo->obj_type != GDA_SERVER_OPERATION_CREATE_VIEW) + conflict = TRUE; + else { + GdaMetaView *mv = GDA_META_VIEW (eobj); + ViewInfo *vi = VIEW_INFO (dbo); + if (!mv->view_def || + !vi->view_def || + strcmp (mv->view_def, vi->view_def)) + conflict = TRUE; + } + break; + default: + TO_IMPLEMENT; + } + + if (conflict) { + g_set_error (error, GDA_META_STORE_ERROR, GDA_META_STORE_SCHEMA_OBJECT_CONFLICT_ERROR, + "%s", _("Another object with the same name already exists")); + goto onerror; + } + needs_creation = FALSE; + } + g_object_unref (mstruct); + mstruct = NULL; + + if (needs_creation) { + /* prepare the create operation */ + GdaServerProvider *prov; + prov = gda_connection_get_provider (priv->cnc); + if (! prepare_dbo_server_operation (priv, store, prov, dbo, error)) + goto onerror; + + /* actually create the object in database */ + /*g_print ("Creating object: %s\n", dbo->obj_name);*/ + if (dbo->create_op) { + if (!gda_server_provider_perform_operation (prov, priv->cnc, dbo->create_op, error)) + goto onerror; + g_object_unref (dbo->create_op); + dbo->create_op = NULL; + } + } + + g_rec_mutex_unlock (& (priv->mutex)); + return TRUE; + + onerror: + if (doc) + xmlFreeDoc (doc); + if (dbo) { + GSList *current_objects, *list; + current_objects = g_slist_copy (priv->p_db_objects); + for (list = current_objects; list; list = list->next) { + dbo = DB_OBJECT (list->data); + if (!g_slist_find (pre_p_db_objects, dbo)) { + /* remove the DbObject */ + priv->p_db_objects = g_slist_remove (priv->p_db_objects, dbo); + g_hash_table_remove (priv->p_db_objects_hash, dbo->obj_name); + db_object_free (dbo); + } + } + g_slist_free (current_objects); + } + g_rec_mutex_unlock (& (priv->mutex)); + g_slist_free (pre_p_db_objects); + if (pstore) + g_object_unref (pstore); + if (mstruct) + g_object_unref (mstruct); + + return FALSE; +} + +/** + * gda_meta_store_schema_remove_custom_object: + * @store: a #GdaMetaStore object + * @obj_name: name of the custom object to remove + * @error: (nullable): a place to store errors, or %NULL + * + * Removes the custom database object named @obj_name. + * + * Returns: TRUE if the custom object has successfully been removed + */ +gboolean +gda_meta_store_schema_remove_custom_object (GdaMetaStore *store, const gchar *obj_name, GError **error) +{ + g_return_val_if_fail (GDA_IS_META_STORE (store), FALSE); + g_return_val_if_fail (obj_name && *obj_name, FALSE); + GdaMetaStorePrivate *priv = gda_meta_store_get_instance_private (store); + + if (priv->init_error) { + g_propagate_error (error, g_error_copy (priv->init_error)); + return FALSE; + } + + g_rec_mutex_lock (& (priv->mutex)); + TO_IMPLEMENT; + g_rec_mutex_unlock (& (priv->mutex)); + + return FALSE; +} + +/* + * Makes sure @context is well formed, and call gda_sql_identifier_prepare_for_compare() on SQL + * identifiers's values + * + * Returns: a new #GdaMetaContext + */ +GdaMetaContext * +_gda_meta_store_validate_context (GdaMetaStore *store, GdaMetaContext *context, GError **error) +{ + g_return_val_if_fail (store != NULL, NULL); + g_return_val_if_fail (GDA_IS_META_STORE (store), NULL); + g_return_val_if_fail (context != NULL, NULL); + + gint i; + GdaMetaStorePrivate *priv = gda_meta_store_get_instance_private (store); + + if (priv->init_error) { + g_propagate_error (error, g_error_copy (priv->init_error)); + return FALSE; + } + + if (!context->table_name || !(*context->table_name)) { + g_set_error (error, GDA_META_STORE_ERROR, GDA_META_STORE_META_CONTEXT_ERROR, + "%s", _("Missing table name in meta data context")); + return NULL; + } + + /* handle quoted SQL identifiers */ + DbObject *dbobj = g_hash_table_lookup (priv->db_objects_hash, context->table_name); + if (dbobj && (dbobj->obj_type == GDA_SERVER_OPERATION_CREATE_TABLE)) { + GdaMetaContext *lcontext; + TableInfo *tinfo; + + lcontext = g_new0 (GdaMetaContext, 1); + lcontext->table_name = context->table_name; + lcontext->size = context->size; + if (lcontext->size > 0) { + lcontext->column_names = g_new0 (gchar*, lcontext->size); + lcontext->column_values = g_new0 (GValue*, lcontext->size); + } + + tinfo = TABLE_INFO (dbobj); + for (i = 0; i < lcontext->size; i++) { + GSList *list; + gint colindex; + + if (!context->column_names [i]) { + g_set_error (error, GDA_META_STORE_ERROR, GDA_META_STORE_META_CONTEXT_ERROR, + "%s", _("Missing column name in meta data context")); + goto onerror; + } + lcontext->column_names [i] = g_strdup (context->column_names [i]); + + for (colindex = 0, list = tinfo->columns; + list; + colindex++, list = list->next) { + if (!strcmp (TABLE_COLUMN (list->data)->column_name, lcontext->column_names [i])) { + gint j; + for (j = 0; j < tinfo->ident_cols_size; j++) { + if (tinfo->ident_cols [j] == colindex) { + /* we have an SQL identifier */ + if (! context->column_values [i]) { + g_set_error (error, GDA_META_STORE_ERROR, + GDA_META_STORE_META_CONTEXT_ERROR, + _("Missing condition in meta data context")); + goto onerror; + } + else if (G_VALUE_TYPE (context->column_values [i]) == G_TYPE_STRING) { + gchar *id; + id = g_value_dup_string (context->column_values [i]); + gda_sql_identifier_prepare_for_compare (id); + if (priv->ident_style == GDA_SQL_IDENTIFIERS_UPPER_CASE) { + /* move to upper case */ + gchar *ptr; + for (ptr = id; *ptr; ptr++) { + if ((*ptr >= 'a') && (*ptr <= 'z')) + *ptr += 'A' - 'a'; + } + } + lcontext->column_values [i] = gda_value_new (G_TYPE_STRING); + g_value_take_string (lcontext->column_values [i], id); + + } + else if (G_VALUE_TYPE (context->column_values [i]) == GDA_TYPE_NULL) { + lcontext->column_values [i] = gda_value_new_null (); + } + else { + g_set_error (error, GDA_META_STORE_ERROR, + GDA_META_STORE_META_CONTEXT_ERROR, + _("Malformed condition in meta data context")); + goto onerror; + } + } + } + + if (! lcontext->column_values [i]) { + lcontext->column_values [i] = gda_value_copy (context->column_values [i]); + } + colindex = -1; + break; + } + } + + if (colindex != -1) { + /* column not found => error */ + g_set_error (error, GDA_META_STORE_ERROR, GDA_META_STORE_META_CONTEXT_ERROR, + _("Unknown column name '%s' in meta data context"), + lcontext->column_names [i]); + goto onerror; + } + else + continue; + + onerror: + for (i = 0; i < lcontext->size; i++) { + g_free (lcontext->column_names [i]); + if (lcontext->column_values [i]) + gda_value_free (lcontext->column_values [i]); + } + g_free (lcontext->column_names); + g_free (lcontext->column_values); + g_free (lcontext); + return NULL; + } + return lcontext; + } + else { + g_set_error (error, GDA_META_STORE_ERROR, GDA_META_STORE_META_CONTEXT_ERROR, + "%s", _("Unknown table in meta data context")); + return NULL; + } +} + +/* + * Returns: a list of new #GdaMetaContext structures, one for each dependency context->table_name has, + * or %NULL if there is no downstream context, or if an error occurred (check @error to make the difference). + * + * WARNING: each new GdaMetaContext structure is allocated, but: + * - the @table_name argument is not copied + * - if @size > 0 then @column_names and @column_values are allocated, but their contents is not! + */ +GSList * +_gda_meta_store_schema_get_upstream_contexts (GdaMetaStore *store, GdaMetaContext *context, GError **error) +{ + DbObject *dbo; + GSList *list, *retlist = NULL; + TableInfo *tinfo; + GdaMetaStorePrivate *priv = gda_meta_store_get_instance_private (store); + + if (priv->init_error) { + g_propagate_error (error, g_error_copy (priv->init_error)); + return NULL; + } + + g_rec_mutex_lock (& (priv->mutex)); + + /* find the associated DbObject */ + dbo = g_hash_table_lookup (priv->p_db_objects_hash, context->table_name); + if (!dbo) { + g_set_error (error, GDA_META_STORE_ERROR, GDA_META_STORE_SCHEMA_OBJECT_NOT_FOUND_ERROR, + _("Unknown database object '%s'"), context->table_name); + g_rec_mutex_unlock (& (priv->mutex)); + return NULL; + } + if (dbo->obj_type != GDA_SERVER_OPERATION_CREATE_TABLE) { + g_rec_mutex_unlock (& (priv->mutex)); + return NULL; + } + + tinfo = TABLE_INFO (dbo); + if (!tinfo->fk_list) { + /* this is not an error, just that there are no dependency */ + g_rec_mutex_unlock (& (priv->mutex)); + return NULL; + } + + /* Identify the TableFKey if @context permits it */ + if (context->size > 0) { + for (list = tinfo->fk_list; list; list = list->next) { + TableFKey *tfk = (TableFKey*) list->data; + gint i, j, partial_parts = 0; + gint *cols_array; + + cols_array = g_new (gint, tfk->cols_nb); + for (i = 0; i < tfk->cols_nb; i++) { + cols_array [i] = -1; + for (j = 0; j < context->size; j++) { + if (!strcmp (tfk->fk_names_array[i], context->column_names[j])) { + cols_array [i] = j; + partial_parts++; + break; + } + } + } + if (partial_parts > 0) { + GdaMetaContext *ct; + ct = g_new0 (GdaMetaContext, 1); + ct->table_name = tfk->depend_on->obj_name; + ct->size = partial_parts; + ct->column_names = g_new0 (gchar *, ct->size); + ct->column_values = g_new0 (GValue *, ct->size); + retlist = g_slist_prepend (retlist, ct); + for (j = 0, i = 0; i < tfk->cols_nb; i++) { + if (cols_array [i] >= 0) { + ct->column_names [j] = tfk->ref_pk_names_array [i]; + ct->column_values [j] = context->column_values [cols_array [i]]; + j++; + } + } + g_free (cols_array); + break; + } + else { + GdaMetaContext *ct; + ct = g_new0 (GdaMetaContext, 1); + ct->table_name = tfk->depend_on->obj_name; + ct->size = 0; + retlist = g_slist_prepend (retlist, ct); + } + g_free (cols_array); + } + } + else { + for (list = tinfo->fk_list; list; list = list->next) { + TableFKey *tfk = (TableFKey*) list->data; + GdaMetaContext *ct; + ct = g_new0 (GdaMetaContext, 1); + ct->table_name = tfk->depend_on->obj_name; + ct->size = 0; + retlist = g_slist_prepend (retlist, ct); + } + } + + g_rec_mutex_unlock (& (priv->mutex)); + return g_slist_reverse (retlist); +} + +/* + * Returns: a list of new #GdaMetaContext structures, one for each reverse dependency context->table_name has, + * or %NULL if there is no downstream context, or if an error occurred (check @error to make the difference). + * + * WARNING: each new GdaMetaContext structure is allocated, but: + * - the @table_name argument is not copied + * - if @size > 0 then @column_names and @column_values are allocated, but their contents is not! + */ +GSList * +_gda_meta_store_schema_get_downstream_contexts (GdaMetaStore *store, GdaMetaContext *context, GError **error) +{ + DbObject *dbo; + GSList *list, *retlist = NULL; + TableInfo *tinfo; + GdaMetaStorePrivate *priv = gda_meta_store_get_instance_private (store); + + if (priv->init_error) { + g_propagate_error (error, g_error_copy (priv->init_error)); + return NULL; + } + + g_rec_mutex_lock (& (priv->mutex)); + + /* find the associated DbObject */ + dbo = g_hash_table_lookup (priv->p_db_objects_hash, context->table_name); + if (!dbo) { + g_set_error (error, GDA_META_STORE_ERROR, GDA_META_STORE_SCHEMA_OBJECT_NOT_FOUND_ERROR, + _("Unknown database object '%s'"), context->table_name); + g_rec_mutex_unlock (& (priv->mutex)); + return NULL; + } + if (dbo->obj_type != GDA_SERVER_OPERATION_CREATE_TABLE) { + g_rec_mutex_unlock (& (priv->mutex)); + return NULL; + } + + tinfo = TABLE_INFO (dbo); + if (!tinfo->reverse_fk_list) { + /* this is not an error, just that there are no dependency */ + g_rec_mutex_unlock (& (priv->mutex)); + return NULL; + } + + for (list = tinfo->reverse_fk_list; list; list = list->next) { + TableFKey *tfk = (TableFKey*) list->data; + GdaMetaContext *ct; + + /* REM: there may be duplicates, but we don't really care here (it'd take more resources to get rid of + * them than it takes to put duplicates in a hash table */ + ct = g_new0 (GdaMetaContext, 1); + ct->table_name = tfk->table_info->obj_name; + ct->size = 0; + retlist = g_slist_prepend (retlist, ct); + } + + g_rec_mutex_unlock (& (priv->mutex)); + return g_slist_reverse (retlist); +} + +/* + * arguments_to_name + * + * Returns: a new string + */ +static gchar * +arguments_to_name (const gchar *catalog, const gchar *schema, const gchar *table) +{ + g_assert (table); + gchar *str; + if (catalog) { + if (schema) + str = g_strdup_printf ("%s.%s.%s", catalog, schema, table); + else + str = g_strdup (table); /* should not happen */ + } + else if (schema) + str = g_strdup_printf ("%s.%s", schema, table); + else + str = g_strdup (table); + return str; +} + +/** + * gda_meta_store_declare_foreign_key: + * @store: a #GdaMetaStore + * @mstruct: (nullable): a #GdaMetaStruct, or %NULL + * @fk_name: the name of the foreign key to declare + * @catalog: (nullable): the catalog in which the table (for which the foreign key is for) is, or %NULL + * @schema: (nullable): the schema in which the table (for which the foreign key is for) is, or %NULL + * @table: the name of the table (for which the foreign key is for) + * @ref_catalog: (nullable): the catalog in which the referenced table is, or %NULL + * @ref_schema: (nullable): the schema in which the referenced table is, or %NULL + * @ref_table: the name of the referenced table + * @nb_cols: the number of columns involved (>0) + * @colnames: (array length=nb_cols): an array of column names from the table for which the foreign key is for + * @ref_colnames: (array length=nb_cols): an array of column names from the referenced table + * @error: (nullable): a place to store errors, or %NULL + * + * Defines a new declared foreign key into @store. If another declared foreign key is already defined + * between the two tables and with the same name, then it is first removed. + * + * This method begins a transaction if possible (ie. none is already started), and if it can't, + * then if there is an error, the job may be partially done. + * + * A check is always performed to make sure all the database objects actually + * exist and returns an error if not. The check is performed using @mstruct if it's not %NULL (in + * this case only the tables already represented in @mstruct will be considered, in other words: @mstruct + * will not be modified), and using an internal #GdaMetaStruct is %NULL. + * + * The @catalog, @schema, @table, @ref_catalog, @ref_schema and @ref_table must follow the SQL + * identifiers naming convention, see the SQL identifiers + * section. The same convention needs to be respected for the strings in @conames and @ref_colnames. + * + * If @catalog is not %NULL, then @schema must also be not %NULL (the same restriction applies to + * @ref_catalog and @ref_schema). + * + * Returns: %TRUE if no error occurred + * + * Since: 4.2.4 + */ +gboolean +gda_meta_store_declare_foreign_key (GdaMetaStore *store, GdaMetaStruct *mstruct, + const gchar *fk_name, + const gchar *catalog, const gchar *schema, const gchar *table, + const gchar *ref_catalog, const gchar *ref_schema, const gchar *ref_table, + guint nb_cols, + gchar **colnames, gchar **ref_colnames, + GError **error) +{ + gboolean retval = FALSE; + GdaSet *params = NULL; + GdaMetaTable *mtable = NULL, *ref_mtable = NULL; + GdaMetaDbObject *dbo = NULL, *ref_dbo = NULL; + GdaMetaStruct *u_mstruct = NULL; + + g_return_val_if_fail (GDA_IS_META_STORE (store), FALSE); + g_return_val_if_fail (!mstruct || GDA_IS_META_STRUCT (mstruct), FALSE); + g_return_val_if_fail (fk_name, FALSE); + g_return_val_if_fail (!catalog || (catalog && schema), FALSE); + g_return_val_if_fail (!ref_catalog || (ref_catalog && ref_schema), FALSE); + g_return_val_if_fail (table, FALSE); + g_return_val_if_fail (ref_table, FALSE); + g_return_val_if_fail (nb_cols > 0, FALSE); + g_return_val_if_fail (colnames, FALSE); + g_return_val_if_fail (ref_colnames, FALSE); + + GdaMetaStorePrivate *priv = gda_meta_store_get_instance_private (store); + + if (!mstruct) + u_mstruct = (GdaMetaStruct*) g_object_new (GDA_TYPE_META_STRUCT, "meta-store", store, "features", GDA_META_STRUCT_FEATURE_NONE, NULL); + + /* find database objects */ + GValue *v1 = NULL, *v2 = NULL, *v3; + + if (catalog) + g_value_set_string ((v1 = gda_value_new (G_TYPE_STRING)), catalog); + if (schema) + g_value_set_string ((v2 = gda_value_new (G_TYPE_STRING)), schema); + g_value_set_string ((v3 = gda_value_new (G_TYPE_STRING)), table); + if (mstruct) { + dbo = gda_meta_struct_get_db_object (mstruct, v1, v2, v3); + if (!dbo || (dbo->obj_type != GDA_META_DB_TABLE)) { + gchar *tmp; + tmp = arguments_to_name (catalog, schema, table); + g_set_error (error, GDA_META_STRUCT_ERROR, + GDA_META_STRUCT_UNKNOWN_OBJECT_ERROR, + _("Could not find object named '%s'"), tmp); + g_free (tmp); + dbo = NULL; + } + } + else + dbo = gda_meta_struct_complement (u_mstruct, GDA_META_DB_TABLE, v1, v2, v3, error); + if (v1) + gda_value_free (v1); + if (v2) + gda_value_free (v2); + gda_value_free (v3); + if (! dbo) + goto out; + mtable = GDA_META_TABLE (dbo); + + v1 = NULL; + v2 = NULL; + if (ref_catalog) + g_value_set_string ((v1 = gda_value_new (G_TYPE_STRING)), ref_catalog); + if (ref_schema) + g_value_set_string ((v2 = gda_value_new (G_TYPE_STRING)), ref_schema); + g_value_set_string ((v3 = gda_value_new (G_TYPE_STRING)), ref_table); + if (mstruct) { + ref_dbo = gda_meta_struct_get_db_object (mstruct, v1, v2, v3); + if (!ref_dbo || (ref_dbo->obj_type != GDA_META_DB_TABLE)) { + gchar *tmp; + tmp = arguments_to_name (ref_catalog, ref_schema, ref_table); + g_set_error (error, GDA_META_STRUCT_ERROR, + GDA_META_STRUCT_UNKNOWN_OBJECT_ERROR, + _("Could not find object named '%s'"), tmp); + g_free (tmp); + ref_dbo = NULL; + } + } + else + ref_dbo = gda_meta_struct_complement (u_mstruct, GDA_META_DB_TABLE, v1, v2, v3, error); + if (v1) + gda_value_free (v1); + if (v2) + gda_value_free (v2); + gda_value_free (v3); + if (! ref_dbo) + goto out; + ref_mtable = GDA_META_TABLE (ref_dbo); + + /* set statement's variables */ + if (! gda_statement_get_parameters (priv->prep_stmts[STMT_ADD_DECLARE_FK], + ¶ms, error)) + goto out; + if (! gda_set_set_holder_value (params, error, "tcal", dbo->obj_catalog)) + goto out; + if (! gda_set_set_holder_value (params, error, "tschema", dbo->obj_schema)) + goto out; + if (! gda_set_set_holder_value (params, error, "tname", dbo->obj_name)) + goto out; + if (! gda_set_set_holder_value (params, error, "ref_tcal", ref_dbo->obj_catalog)) + goto out; + if (! gda_set_set_holder_value (params, error, "ref_tschema", ref_dbo->obj_schema)) + goto out; + if (! gda_set_set_holder_value (params, error, "ref_tname", ref_dbo->obj_name)) + goto out; + + if (! gda_set_set_holder_value (params, error, "fkname", fk_name)) + goto out; + + GdaConnection *store_cnc; + gboolean intrans; + store_cnc = gda_meta_store_get_internal_connection (store); + intrans = gda_connection_begin_transaction (store_cnc, NULL, + GDA_TRANSACTION_ISOLATION_UNKNOWN, + NULL); + + /* remove existing declared FK, if any */ + if (gda_connection_statement_execute_non_select (store_cnc, + priv->prep_stmts[STMT_DEL_DECLARE_FK], + params, + NULL, error) == -1) { + if (intrans) + gda_connection_rollback_transaction (store_cnc, NULL, NULL); + goto out; + } + + /* declare FK */ + guint l; + for (l = 0; l < nb_cols; l++) { + /* check that column name exists */ + GSList *list; + for (list = mtable->columns; list; list = list->next) { + if (!strcmp (GDA_META_TABLE_COLUMN (list->data)->column_name, + colnames[l])) + break; + } + if (!list) { + gchar *str; + str = arguments_to_name (catalog, schema, table); + g_set_error (error, GDA_META_STORE_ERROR, + GDA_META_STORE_SCHEMA_OBJECT_NOT_FOUND_ERROR, + _("Could not find column '%s' in table '%s'"), + colnames[l], str); + g_free (str); + goto out; + } + if (! gda_set_set_holder_value (params, error, "colname", colnames[l])) + goto out; + + /* check that column name exists */ + for (list = ref_mtable->columns; list; list = list->next) { + if (!strcmp (GDA_META_TABLE_COLUMN (list->data)->column_name, + ref_colnames[l])) + break; + } + if (!list) { + gchar *str; + str = arguments_to_name (ref_catalog, ref_schema, ref_table); + g_set_error (error, GDA_META_STORE_ERROR, + GDA_META_STORE_SCHEMA_OBJECT_NOT_FOUND_ERROR, + _("Could not find column '%s' in table '%s'"), + ref_colnames[l], str); + g_free (str); + goto out; + } + if (! gda_set_set_holder_value (params, error, "ref_colname", ref_colnames[l])) + goto out; + + if (gda_connection_statement_execute_non_select (store_cnc, + priv->prep_stmts[STMT_ADD_DECLARE_FK], + params, + NULL, error) == -1) { + if (intrans) + gda_connection_rollback_transaction (store_cnc, NULL, + NULL); + goto out; + } + } + + if (intrans) + gda_connection_commit_transaction (store_cnc, NULL, NULL); + retval = TRUE; + + out: + if (u_mstruct) + g_object_unref (u_mstruct); + if (params) + g_object_unref (params); + + return retval; +} + +/** + * gda_meta_store_undeclare_foreign_key: + * @store: a #GdaMetaStore + * @mstruct: (nullable): a #GdaMetaStruct, or %NULL + * @fk_name: the name of the foreign key to declare + * @catalog: (nullable): the catalog in which the table (for which the foreign key is for) is, or %NULL + * @schema: (nullable): the schema in which the table (for which the foreign key is for) is, or %NULL + * @table: the name of the table (for which the foreign key is for) + * @ref_catalog: (nullable): the catalog in which the referenced table is, or %NULL + * @ref_schema: (nullable): the schema in which the referenced table is, or %NULL + * @ref_table: the name of the referenced table + * @error: (nullable): a place to store errors, or %NULL + * + * Removes a declared foreign key from @store. + * + * This method begins a transaction if possible (ie. none is already started), and if it can't, then if there + * is an error, the job may be partially done. + * + * A check is always performed to make sure all the database objects actually + * exist and returns an error if not. The check is performed using @mstruct if it's not %NULL (in + * this case only the tables already represented in @mstruct will be considered, in other words: @mstruct + * will not be modified), and using an internal #GdaMetaStruct is %NULL. + * + * See gda_meta_store_declare_foreign_key() for more information anout the @catalog, @schema, @name, + * @ref_catalog, @ref_schema and @ref_name arguments. + * + * Returns: %TRUE if no error occurred + * + * Since: 4.2.4 + */ +gboolean +gda_meta_store_undeclare_foreign_key (GdaMetaStore *store, GdaMetaStruct *mstruct, + const gchar *fk_name, + const gchar *catalog, const gchar *schema, const gchar *table, + const gchar *ref_catalog, const gchar *ref_schema, const gchar *ref_table, + GError **error) +{ + gboolean retval = FALSE; + GdaSet *params = NULL; + GdaMetaDbObject *dbo = NULL, *ref_dbo = NULL; + GdaMetaStruct *u_mstruct = NULL; + + g_return_val_if_fail (GDA_IS_META_STORE (store), FALSE); + g_return_val_if_fail (!mstruct || GDA_IS_META_STRUCT (mstruct), FALSE); + g_return_val_if_fail (fk_name, FALSE); + g_return_val_if_fail (!catalog || (catalog && schema), FALSE); + g_return_val_if_fail (!ref_catalog || (ref_catalog && ref_schema), FALSE); + g_return_val_if_fail (table, FALSE); + g_return_val_if_fail (ref_table, FALSE); + + GdaMetaStorePrivate *priv = gda_meta_store_get_instance_private (store); + + if (!mstruct) + u_mstruct = (GdaMetaStruct*) g_object_new (GDA_TYPE_META_STRUCT, "meta-store", store, "features", GDA_META_STRUCT_FEATURE_NONE, NULL); + + /* find database objects */ + GValue *v1 = NULL, *v2 = NULL, *v3; + + if (catalog) + g_value_set_string ((v1 = gda_value_new (G_TYPE_STRING)), catalog); + if (schema) + g_value_set_string ((v2 = gda_value_new (G_TYPE_STRING)), schema); + g_value_set_string ((v3 = gda_value_new (G_TYPE_STRING)), table); + if (mstruct) { + dbo = gda_meta_struct_get_db_object (mstruct, v1, v2, v3); + if (!dbo || (dbo->obj_type != GDA_META_DB_TABLE)) { + gchar *tmp; + tmp = arguments_to_name (catalog, schema, table); + g_set_error (error, GDA_META_STRUCT_ERROR, + GDA_META_STRUCT_UNKNOWN_OBJECT_ERROR, + _("Could not find object named '%s'"), tmp); + g_free (tmp); + dbo = NULL; + } + } + else + dbo = gda_meta_struct_complement (u_mstruct, GDA_META_DB_TABLE, v1, v2, v3, error); + if (v1) + gda_value_free (v1); + if (v2) + gda_value_free (v2); + gda_value_free (v3); + if (! dbo) + goto out; + + v1 = NULL; + v2 = NULL; + if (ref_catalog) + g_value_set_string ((v1 = gda_value_new (G_TYPE_STRING)), ref_catalog); + if (ref_schema) + g_value_set_string ((v2 = gda_value_new (G_TYPE_STRING)), ref_schema); + g_value_set_string ((v3 = gda_value_new (G_TYPE_STRING)), ref_table); + if (mstruct) { + ref_dbo = gda_meta_struct_get_db_object (mstruct, v1, v2, v3); + if (!ref_dbo || (ref_dbo->obj_type != GDA_META_DB_TABLE)) { + gchar *tmp; + tmp = arguments_to_name (ref_catalog, ref_schema, ref_table); + g_set_error (error, GDA_META_STRUCT_ERROR, + GDA_META_STRUCT_UNKNOWN_OBJECT_ERROR, + _("Could not find object named '%s'"), tmp); + g_free (tmp); + ref_dbo = NULL; + } + } + else + ref_dbo = gda_meta_struct_complement (u_mstruct, GDA_META_DB_TABLE, v1, v2, v3, error); + if (v1) + gda_value_free (v1); + if (v2) + gda_value_free (v2); + gda_value_free (v3); + if (! ref_dbo) + goto out; + + /* set statement's variables */ + if (! gda_statement_get_parameters (priv->prep_stmts[STMT_DEL_DECLARE_FK], + ¶ms, error)) + goto out; + if (! gda_set_set_holder_value (params, error, "tcal", dbo->obj_catalog)) + goto out; + if (! gda_set_set_holder_value (params, error, "tschema", dbo->obj_schema)) + goto out; + if (! gda_set_set_holder_value (params, error, "tname", dbo->obj_name)) + goto out; + if (! gda_set_set_holder_value (params, error, "ref_tcal", ref_dbo->obj_catalog)) + goto out; + if (! gda_set_set_holder_value (params, error, "ref_tschema", ref_dbo->obj_schema)) + goto out; + if (! gda_set_set_holder_value (params, error, "ref_tname", ref_dbo->obj_name)) + goto out; + + if (! gda_set_set_holder_value (params, error, "fkname", fk_name)) + goto out; + + GdaConnection *store_cnc; + gboolean intrans; + store_cnc = gda_meta_store_get_internal_connection (store); + intrans = gda_connection_begin_transaction (store_cnc, NULL, + GDA_TRANSACTION_ISOLATION_UNKNOWN, + NULL); + + /* remove existing declared FK, if any */ + if (gda_connection_statement_execute_non_select (store_cnc, + priv->prep_stmts[STMT_DEL_DECLARE_FK], + params, + NULL, error) == -1) { + if (intrans) + gda_connection_rollback_transaction (store_cnc, NULL, NULL); + goto out; + } + + if (intrans) + gda_connection_commit_transaction (store_cnc, NULL, NULL); + retval = TRUE; + + out: + if (u_mstruct) + g_object_unref (u_mstruct); + if (params) + g_object_unref (params); + + return retval; +} + +/** + * gda_meta_store_create_struct: + * @store: a #GdaMetaStore + * @features: features of new struct + * + * Returns: (transfer full): a new #GdaMetaStruct using @store + */ +GdaMetaStruct* +gda_meta_store_create_struct (GdaMetaStore *store, GdaMetaStructFeature features) +{ + return (GdaMetaStruct*) g_object_new (GDA_TYPE_META_STRUCT, "meta-store", store, "features", features, NULL); +} + diff --git a/.flatpak-builder/cache/objects/fa/a57cbad99ba0c00eb26557845ee18a000b08d35b62ac18d9c1441046cbdf4d.dirtree b/.flatpak-builder/cache/objects/fa/a57cbad99ba0c00eb26557845ee18a000b08d35b62ac18d9c1441046cbdf4d.dirtree new file mode 100644 index 0000000..ceadc9a Binary files /dev/null and b/.flatpak-builder/cache/objects/fa/a57cbad99ba0c00eb26557845ee18a000b08d35b62ac18d9c1441046cbdf4d.dirtree differ diff --git a/.flatpak-builder/cache/objects/fa/ad4b55d7ec52b5fa31dfe4d281f4f6d0729fb9eba0d70defbd7a20ba7bd2a2.file b/.flatpak-builder/cache/objects/fa/ad4b55d7ec52b5fa31dfe4d281f4f6d0729fb9eba0d70defbd7a20ba7bd2a2.file new file mode 100644 index 0000000..94369d5 --- /dev/null +++ b/.flatpak-builder/cache/objects/fa/ad4b55d7ec52b5fa31dfe4d281f4f6d0729fb9eba0d70defbd7a20ba7bd2a2.file @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2009 - 2011 Vivien Malerba + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GDA_TREE_MGR_SCHEMAS_H__ +#define __GDA_TREE_MGR_SCHEMAS_H__ + +#include +#include "gda-tree-manager.h" + +G_BEGIN_DECLS + +#define GDA_TYPE_TREE_MGR_SCHEMAS (gda_tree_mgr_schemas_get_type()) +G_DECLARE_DERIVABLE_TYPE(GdaTreeMgrSchemas, gda_tree_mgr_schemas, GDA, TREE_MGR_SCHEMAS, GdaTreeManager) +struct _GdaTreeMgrSchemasClass { + GdaTreeManagerClass object_class; +}; + +/** + * SECTION:gda-tree-mgr-schemas + * @short_description: A tree manager which creates a node for each schema in a database + * @title: GdaTreeMgrSchemas + * @stability: Stable + * @see_also: + * + * The #GdaTreeMgrSchemas is a #GdaTreeManager object which creates a node for + * each schema in a database. + * + * It uses the #GdaMetaStore associated to a #GdaConnection to get the schemas list; it's up to the + * caller to make sure the data in the #GdaMetaStore is up to date. + * + * The #GdaConnection to be used needs to be specified when the object is created. + */ + +GdaTreeManager* gda_tree_mgr_schemas_new (GdaConnection *cnc); + +G_END_DECLS + +#endif diff --git a/.flatpak-builder/cache/objects/fa/b3fd2126638c00854a32ede6ad9663105d668164d52cbeb9d4ed2a073b401a.file b/.flatpak-builder/cache/objects/fa/b3fd2126638c00854a32ede6ad9663105d668164d52cbeb9d4ed2a073b401a.file new file mode 100644 index 0000000..46bbfee --- /dev/null +++ b/.flatpak-builder/cache/objects/fa/b3fd2126638c00854a32ede6ad9663105d668164d52cbeb9d4ed2a073b401a.file @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2008 - 2012 Vivien Malerba + * Copyright (C) 2012 - 2013 Daniel Espinosa + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GDA_PSTMT_H__ +#define __GDA_PSTMT_H__ + +#include +#include + +G_BEGIN_DECLS + +#define GDA_TYPE_PSTMT (gda_pstmt_get_type()) + +G_DECLARE_DERIVABLE_TYPE (GdaPStmt, gda_pstmt, GDA, PSTMT, GObject) + +/** + * GdaPStmt: + * @sql: actual SQL code used for this prepared statement, mem freed by GdaPStmt + * @param_ids: (element-type utf8): list of parameters' IDs (as gchar *), mem freed by GdaPStmt + * @ncols: number of types in array + * @types: (array length=ncols) (element-type GLib.Type): array of ncols types + * @tmpl_columns: (element-type Gda.Column): list of #GdaColumn objects which data models created from this prep. statement can copy + * + */ + +struct _GdaPStmtClass { + GObjectClass parent_class; + + /*< private >*/ + /* Padding for future expansion */ + void (*_gda_reserved1) (void); + void (*_gda_reserved2) (void); + void (*_gda_reserved3) (void); + void (*_gda_reserved4) (void); +}; + +/** + * SECTION:gda-pstmt + * @short_description: Base class for prepared statement's + * @title: GdaPstmt + * @stability: Stable + * @see_also: + * + * The #GdaPStmt represents the association between a #GdaStatement statement and a prepared statement + * which is database dependent and is an in-memory representation of a statement. Using prepared statement has the + * following advantages: + * + * the parsing of the SQL has to be done only once, which improves performances if the statement + * has to be executed more than once + * if a statement has been prepared, then it means it is syntactically correct and has been + * understood by the database's API + * it is possible to use variables in prepared statement which eliminates the risk + * of SQL code injection + * + * + * The #GdaPStmt is not intended to be instantiated, but subclassed by database provider's implementation. + * Once created, the database provider's implementation can decide to associate (for future lookup) to + * a #GdaStatement object in a connection using gda_connection_add_prepared_statement(). + * + * The #GdaPStmt object can keep a reference to the #GdaStatement object (which can be set and get using + * the gda_pstmt_set_gda_statement() and gda_pstmt_get_gda_statement()), however that reference + * if a weak one (which means it will be lost if the #GdaStatement object is destroyed). + */ + +void gda_pstmt_set_gda_statement (GdaPStmt *pstmt, GdaStatement *stmt); +void gda_pstmt_copy_contents (GdaPStmt *src, GdaPStmt *dest); +GdaStatement *gda_pstmt_get_gda_statement (GdaPStmt *pstmt); + + +gchar *gda_pstmt_get_sql (GdaPStmt *ps); +void gda_pstmt_set_sql (GdaPStmt *ps, const gchar *sql); +GSList *gda_pstmt_get_param_ids (GdaPStmt *ps); +void gda_pstmt_set_param_ids (GdaPStmt *ps, GSList* params); +gint gda_pstmt_get_ncols (GdaPStmt *ps); +void gda_pstmt_set_cols (GdaPStmt *ps, gint ncols, GType *types); +GSList *gda_pstmt_get_tmpl_columns (GdaPStmt *ps); +void gda_pstmt_set_tmpl_columns (GdaPStmt *ps, GSList* columns); +GType *gda_pstmt_get_types (GdaPStmt *ps); + +G_END_DECLS + +#endif diff --git a/.flatpak-builder/cache/objects/fb/34fdfe86e39ccedea1f2670cc7b975254a56595aa787f7d3c6fc9175c68455.file b/.flatpak-builder/cache/objects/fb/34fdfe86e39ccedea1f2670cc7b975254a56595aa787f7d3c6fc9175c68455.file new file mode 100644 index 0000000..5da6fcf --- /dev/null +++ b/.flatpak-builder/cache/objects/fb/34fdfe86e39ccedea1f2670cc7b975254a56595aa787f7d3c6fc9175c68455.file @@ -0,0 +1,154 @@ +/* + * Copyright (C) 2008 Massimo Cora + * Copyright (C) 2008 - 2012 Vivien Malerba + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + + +#ifndef __GDA_HOLDER_H_ +#define __GDA_HOLDER_H_ + +#include +#include +#include "gda-value.h" + +G_BEGIN_DECLS + +/* error reporting */ +extern GQuark gda_holder_error_quark (void); +#define GDA_HOLDER_ERROR gda_holder_error_quark () + +typedef enum { + GDA_HOLDER_STRING_CONVERSION_ERROR, + GDA_HOLDER_VALUE_TYPE_ERROR, + GDA_HOLDER_VALUE_NULL_ERROR, + GDA_HOLDER_VALUE_CHANGE_ERROR +} GdaHolderError; + +#define GDA_TYPE_HOLDER (gda_holder_get_type()) +G_DECLARE_DERIVABLE_TYPE(GdaHolder, gda_holder, GDA, HOLDER, GObject) + + +/* struct for the object's class */ +struct _GdaHolderClass +{ + GObjectClass parent_class; + void (*changed) (GdaHolder *holder); + void (*source_changed) (GdaHolder *holder); + GError *(*validate_change) (GdaHolder *holder, const GValue *new_value); + void (*to_default) (GdaHolder *holder); + + /*< private >*/ + /* Padding for future expansion */ + void (*_gda_reserved1) (void); + void (*_gda_reserved2) (void); + void (*_gda_reserved3) (void); + void (*_gda_reserved4) (void); +}; + +/** + * SECTION:gda-holder + * @short_description: Container for a single #GValue + * @title: GdaHolder + * @stability: Stable + * @see_also: The #GdaSet object which "groups" several #GdaHolder objects + * + * The #GdaHolder is a container for a single #GValue value. It also specifies various attributes + * of the contained value (default value, ...) + * + * The type of a #GdaHolder has to be set and cannot be modified, except if it's initialized + * with a GDA_TYPE_NULL GType (representing NULL values) where it can be changed once to a real GType. + * + * Each GdaHolder object is thread safe. + */ + +GdaHolder *gda_holder_new (GType type, const gchar *id); +GdaHolder *gda_holder_new_inline (GType type, const gchar *id, ...); +GdaHolder *gda_holder_copy (GdaHolder *orig); + +GType gda_holder_get_g_type (GdaHolder *holder); +const gchar *gda_holder_get_id (GdaHolder *holder); +gchar * gda_holder_get_alphanum_id (GdaHolder *holder); + + +/** + * gda_holder_new_string: + * @id: a string + * @str: a string + * + * Creates a new boolean #GdaHolder object with an ID set to @id, and a value initialized to + * @str. + * + * Returns: a new #GdaHolder + */ +#define gda_holder_new_string(id,str) gda_holder_new_inline (G_TYPE_STRING, (id), (str)) + +/** + * gda_holder_new_boolean: + * @id: a string + * @abool: a boolean value + * + * Creates a new boolean #GdaHolder object with an ID set to @id, and a value initialized to + * @abool. + * + * Returns: a new #GdaHolder + */ +#define gda_holder_new_boolean(id,abool) gda_holder_new_inline (G_TYPE_BOOLEAN, (id), (abool)) + +/** + * gda_holder_new_int: + * @id: a string + * @anint: an int value + * + * Creates a new boolean #GdaHolder object with an ID set to @id, and a value initialized to + * @anint. + * + * Returns: a new #GdaHolder + */ +#define gda_holder_new_int(id,anint) gda_holder_new_inline (G_TYPE_INT, (id), (anint)) + +const GValue *gda_holder_get_value (GdaHolder *holder); +gchar *gda_holder_get_value_str (GdaHolder *holder, GdaDataHandler *dh); +gboolean gda_holder_set_value (GdaHolder *holder, const GValue *value, GError **error); +gboolean gda_holder_take_value (GdaHolder *holder, GValue *value, GError **error); +GValue *gda_holder_take_static_value (GdaHolder *holder, const GValue *value, gboolean *value_changed, GError **error); +gboolean gda_holder_set_value_str (GdaHolder *holder, GdaDataHandler *dh, const gchar *value, GError **error); + +const GValue *gda_holder_get_default_value (GdaHolder *holder); +void gda_holder_set_default_value (GdaHolder *holder, const GValue *value); +gboolean gda_holder_set_value_to_default (GdaHolder *holder); +gboolean gda_holder_value_is_default (GdaHolder *holder); + +void gda_holder_force_invalid (GdaHolder *holder); +void gda_holder_force_invalid_e (GdaHolder *holder, GError *error); +gboolean gda_holder_is_valid (GdaHolder *holder); +gboolean gda_holder_is_valid_e (GdaHolder *holder, GError **error); + + +void gda_holder_set_not_null (GdaHolder *holder, gboolean not_null); +gboolean gda_holder_get_not_null (GdaHolder *holder); + +gboolean gda_holder_set_source_model (GdaHolder *holder, GdaDataModel *model, + gint col, GError **error); +GdaDataModel *gda_holder_get_source_model (GdaHolder *holder, gint *col); + +gboolean gda_holder_set_bind (GdaHolder *holder, GdaHolder *bind_to, GError **error); +GdaHolder *gda_holder_get_bind (GdaHolder *holder); + +G_END_DECLS + +#endif diff --git a/.flatpak-builder/cache/objects/fb/af42066e1e696e3449907ae46517968769b3bec32b76638a99beb0cf0b6c55.file b/.flatpak-builder/cache/objects/fb/af42066e1e696e3449907ae46517968769b3bec32b76638a99beb0cf0b6c55.file new file mode 100644 index 0000000..1ca5ce5 --- /dev/null +++ b/.flatpak-builder/cache/objects/fb/af42066e1e696e3449907ae46517968769b3bec32b76638a99beb0cf0b6c55.file @@ -0,0 +1,2566 @@ +/* + * Copyright (C) 2008 - 2012 Murray Cumming + * Copyright (C) 2008 - 2014 Vivien Malerba + * Copyright (C) 2009 Bas Driessen + * Copyright (C) 2010 David King + * Copyright (C) 2010 Jonh Wendell + * Copyright (C) 2012, 2018 Daniel Espinosa + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +#define G_LOG_DOMAIN "GDA-meta-struct" + +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Main static functions + */ +static void gda_meta_struct_dispose (GObject *object); + +static void gda_meta_struct_set_property (GObject *object, + guint param_id, + const GValue *value, + GParamSpec *pspec); +static void gda_meta_struct_get_property (GObject *object, + guint param_id, + GValue *value, + GParamSpec *pspec); + + +static void meta_store_changed_cb (GdaMetaStore *store, GSList *changes, GdaMetaStruct *mstruct); +static void meta_store_reset_cb (GdaMetaStore *store, GdaMetaStruct *mstruct); + +typedef struct { + GdaMetaStore *store; + GSList *db_objects; /* list of GdaMetaDbObject structures */ + GHashTable *index; /* key = [catalog].[schema].[name], value = a GdaMetaDbObject. Note: catalog, schema and name + * are case sensitive (and don't have any double quote around them) */ + guint features; + gboolean auto_incement; + gchar *desc; + GdaSqlParser *parser; +} GdaMetaStructPrivate; +G_DEFINE_TYPE_WITH_PRIVATE (GdaMetaStruct, gda_meta_struct, G_TYPE_OBJECT) + + +static GdaMetaDbObject *_meta_struct_get_db_object (GdaMetaStruct *mstruct, + const GValue *catalog, const GValue *schema, const GValue *name); + +static void gda_meta_db_object_free (GdaMetaDbObject *dbo); +static void gda_meta_db_object_free_contents (GdaMetaDbObject *dbo); +static void gda_meta_table_free_contents (GdaMetaTable *table); +static void gda_meta_view_free_contents (GdaMetaView *view); +static void gda_meta_table_column_free (GdaMetaTableColumn *tcol); +static void gda_meta_table_foreign_key_free (GdaMetaTableForeignKey *tfk); + +/* properties */ +enum { + PROP_0, + PROP_STORE, + PROP_FEATURES +}; + +/* module error */ +GQuark gda_meta_struct_error_quark (void) { + static GQuark quark; + if (!quark) + quark = g_quark_from_static_string ("gda_meta_struct_error"); + return quark; +} + + +static void +gda_meta_struct_class_init (GdaMetaStructClass *klass) { + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + /* Properties */ + object_class->set_property = gda_meta_struct_set_property; + object_class->get_property = gda_meta_struct_get_property; + g_object_class_install_property (object_class, PROP_STORE, + g_param_spec_object ("meta-store", NULL, + /* To translators: GdaMetaStore is an object holding meta data information + * which will be used as an information source */ + _ ("GdaMetaStore object to fetch information from"), + GDA_TYPE_META_STORE, + (G_PARAM_WRITABLE | G_PARAM_READABLE | + G_PARAM_CONSTRUCT_ONLY))); + g_object_class_install_property (object_class, PROP_FEATURES, + /* To translators: The GdaMetaStruct object computes lists of tables, views, + * and some other information, the "Features to compute" allows one to avoid + * computing some features which won't be used */ + g_param_spec_uint ("features", _ ("Features to compute"), NULL, + GDA_META_STRUCT_FEATURE_NONE, G_MAXINT, + GDA_META_STRUCT_FEATURE_ALL, + (G_PARAM_WRITABLE | G_PARAM_READABLE | + G_PARAM_CONSTRUCT_ONLY))); + + /* virtual methods */ + object_class->dispose = gda_meta_struct_dispose; + +} + + +static void +gda_meta_struct_init (GdaMetaStruct *mstruct) { + GdaMetaStructPrivate *priv = gda_meta_struct_get_instance_private (mstruct); + priv->store = NULL; + priv->db_objects = NULL; + priv->index = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); + priv->auto_incement = FALSE; + priv->desc = NULL; + priv->parser = gda_sql_parser_new (); +} + +static void +gda_meta_struct_dispose (GObject *object) +{ + GdaMetaStruct *mstruct; + + g_assert_nonnull (object); + g_assert_true (GDA_IS_META_STRUCT (object)); + + mstruct = GDA_META_STRUCT (object); + GdaMetaStructPrivate *priv = gda_meta_struct_get_instance_private (mstruct); + if (priv->store) { + g_signal_handlers_disconnect_by_func (G_OBJECT (priv->store), + G_CALLBACK (meta_store_changed_cb), mstruct); + g_signal_handlers_disconnect_by_func (G_OBJECT (priv->store), + G_CALLBACK (meta_store_reset_cb), mstruct); + g_object_unref (priv->store); + priv->store = NULL; + } + if (priv->db_objects) { + g_slist_free_full (priv->db_objects, (GDestroyNotify) gda_meta_db_object_free); + priv->db_objects = NULL; + } + if (priv->index) { + g_hash_table_destroy (priv->index); + priv->index = NULL; + } + + if (priv->parser) + g_clear_object (&priv->parser); + + /* parent class */ + G_OBJECT_CLASS (gda_meta_struct_parent_class)->dispose (object); +} + +static void +gda_meta_struct_set_property (GObject *object, + guint param_id, + const GValue *value, + GParamSpec *pspec) +{ + GdaMetaStruct *mstruct; + + mstruct = GDA_META_STRUCT (object); + GdaMetaStructPrivate *priv = gda_meta_struct_get_instance_private (mstruct); + switch (param_id) { + case PROP_STORE: + priv->store = g_value_get_object (value); + if (priv->store) { + g_object_ref (priv->store); + g_signal_connect (G_OBJECT (priv->store), "meta-changed", + G_CALLBACK (meta_store_changed_cb), mstruct); + g_signal_connect (G_OBJECT (priv->store), "meta-reset", + G_CALLBACK (meta_store_reset_cb), mstruct); + } + break; + case PROP_FEATURES: + priv->features = g_value_get_uint (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + break; + } +} + +static void +gda_meta_struct_get_property (GObject *object, + guint param_id, + GValue *value, + GParamSpec *pspec) +{ + GdaMetaStruct *mstruct; + mstruct = GDA_META_STRUCT (object); + GdaMetaStructPrivate *priv = gda_meta_struct_get_instance_private (mstruct); + + switch (param_id) { + case PROP_STORE: + g_value_set_object (value, priv->store); + break; + case PROP_FEATURES: + g_value_set_uint (value, priv->features); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + break; + } +} + +static void +meta_store_changed_cb (GdaMetaStore *store, G_GNUC_UNUSED GSList *changes, GdaMetaStruct *mstruct) +{ + /* for now we mark ALL the db objects as outdated */ + meta_store_reset_cb (store, mstruct); +} + +static void +meta_store_reset_cb (G_GNUC_UNUSED GdaMetaStore *store, GdaMetaStruct *mstruct) +{ + GdaMetaStructPrivate *priv = gda_meta_struct_get_instance_private (mstruct); + /* mark ALL the db objects as outdated */ + GSList *list; + for (list = priv->db_objects; list; list = list->next) + GDA_META_DB_OBJECT (list->data)->outdated = TRUE; +} + + +static void +compute_view_dependencies (GdaMetaStruct *mstruct, GdaMetaDbObject *view_dbobj, GdaSqlStatement *sqlst) +{ + GdaMetaStructPrivate *priv = gda_meta_struct_get_instance_private (mstruct); + if (sqlst->stmt_type == GDA_SQL_STATEMENT_SELECT) { + GdaSqlStatementSelect *selst; + selst = (GdaSqlStatementSelect*) (sqlst->contents); + GSList *targets = NULL; + if (selst->from) + targets = selst->from->targets; + for (; targets; targets = targets->next) { + GdaSqlSelectTarget *t = (GdaSqlSelectTarget *) targets->data; + GValue *catalog, *schema, *name; + GdaMetaDbObject *ref_obj, *tmp_obj; + GdaMetaStruct *m2; + GValue *vname; + + if (!t->table_name) + continue; + + m2 = (GdaMetaStruct*) g_object_new (GDA_TYPE_META_STRUCT, "meta-store", priv->store, "features", GDA_META_STRUCT_FEATURE_NONE, NULL); + g_value_set_string ((vname = gda_value_new (G_TYPE_STRING)), t->table_name); + if (! (tmp_obj = gda_meta_struct_complement (m2, + GDA_META_DB_TABLE, NULL, NULL, vname, NULL))) + tmp_obj = gda_meta_struct_complement (m2, + GDA_META_DB_VIEW, NULL, NULL, vname, NULL); + gda_value_free (vname); + + if (!tmp_obj) { + /* could not find dependency */ + g_object_unref (m2); + continue; + } + + /* the dependency exists, and is identified by tmp_obj->obj_catalog, tmp_obj->obj_schema + * and tmp_obj->obj_name */ + g_value_set_string ((catalog = gda_value_new (G_TYPE_STRING)), tmp_obj->obj_catalog); + g_value_set_string ((schema = gda_value_new (G_TYPE_STRING)), tmp_obj->obj_schema); + g_value_set_string ((name = gda_value_new (G_TYPE_STRING)), tmp_obj->obj_name); + ref_obj = _meta_struct_get_db_object (mstruct, catalog, schema, name); + if (!ref_obj) { + gchar *str; + ref_obj = g_new0 (GdaMetaDbObject, 1); + ref_obj->obj_type = GDA_META_DB_UNKNOWN; + ref_obj->obj_catalog = g_strdup (tmp_obj->obj_catalog); + ref_obj->obj_schema = g_strdup (tmp_obj->obj_schema); + ref_obj->obj_name = g_strdup (tmp_obj->obj_name); + + priv->db_objects = g_slist_append (priv->db_objects, ref_obj); + str = g_strdup_printf ("%s.%s.%s", tmp_obj->obj_catalog, + tmp_obj->obj_schema, tmp_obj->obj_name); + g_hash_table_insert (priv->index, str, ref_obj); + } + g_object_unref (m2); + g_assert (ref_obj); + gda_value_free (catalog); + gda_value_free (schema); + gda_value_free (name); + + view_dbobj->depend_list = g_slist_append (view_dbobj->depend_list, ref_obj); + } + } + else if (sqlst->stmt_type == GDA_SQL_STATEMENT_COMPOUND) { + GdaSqlStatementCompound *cst; + GSList *list; + cst = (GdaSqlStatementCompound*) (sqlst->contents); + for (list = cst->stmt_list; list; list = list->next) + compute_view_dependencies (mstruct, view_dbobj, (GdaSqlStatement*) list->data); + } + else + g_assert_not_reached (); +} + +static GdaMetaDbObject * _meta_struct_complement (GdaMetaStruct *mstruct, GdaMetaDbObjectType type, + const GValue *icatalog, const GValue *ischema, const GValue *iname, + const GValue *short_name, const GValue *full_name, + const GValue *owner, GError **error); +static gboolean determine_db_object_from_schema_and_name (GdaMetaStruct *mstruct, + GdaMetaDbObjectType *int_out_type, GValue **out_catalog, + GValue **out_short_name, GValue **out_full_name, + GValue **out_owner, const GValue *schema, const GValue *name); +static gboolean determine_db_object_from_short_name (GdaMetaStruct *mstruct, + GdaMetaDbObjectType *int_out_type, GValue **out_catalog, + GValue **out_schema, GValue **out_name, GValue **out_short_name, + GValue **out_full_name, GValue **out_owner, const GValue *name); +static gboolean determine_db_object_from_missing_type (GdaMetaStruct *mstruct, + GdaMetaDbObjectType *out_type, GValue **out_short_name, + GValue **out_full_name, GValue **out_owner, const GValue *catalog, + const GValue *schema, const GValue *name); +static gchar *array_type_to_sql (GdaMetaStore *store, const GValue *specific_name); +static gchar * +get_user_obj_name (const GValue *catalog, const GValue *schema, const GValue *name) +{ + GString *string = NULL; + gchar *ret; + if (catalog && (G_VALUE_TYPE (catalog) != GDA_TYPE_NULL)) + string = g_string_new (g_value_get_string (catalog)); + if (schema && (G_VALUE_TYPE (schema) != GDA_TYPE_NULL)) { + if (string) { + g_string_append_c (string, '.'); + g_string_append (string, g_value_get_string (schema)); + } + else + string = g_string_new (g_value_get_string (schema)); + } + if (name && (G_VALUE_TYPE (name) != GDA_TYPE_NULL)) { + if (string) { + g_string_append_c (string, '.'); + g_string_append (string, g_value_get_string (name)); + } + else + string = g_string_new (g_value_get_string (name)); + } + ret = string->str; + g_string_free (string, FALSE); + return ret; +} + +static gchar * +prepare_sql_identifier_for_compare (gchar *str) +{ + if (!str || (*str == '"')) + return str; + else { + gchar *ptr; + for (ptr = str; *ptr; ptr++) + *ptr = g_ascii_tolower (*ptr); + return str; + } +} + +/** + * gda_meta_struct_complement: + * @mstruct: a #GdaMetaStruct object + * @type: the type of object to add (which can be GDA_META_DB_UNKNOWN) + * @catalog: (nullable): the catalog the object belongs to (as a G_TYPE_STRING GValue), or %NULL + * @schema: (nullable): the schema the object belongs to (as a G_TYPE_STRING GValue), or %NULL + * @name: the object's name (as a G_TYPE_STRING GValue), not %NULL + * @error: (nullable): a place to store errors, or %NULL + * + * Creates a new #GdaMetaDbObject structure in @mstruct to represent the database object (of type @type) + * which can be uniquely identified as @catalog.@schema.@name. + * + * If @catalog is not %NULL, then @schema should not be %NULL. + * + * If both @catalog and @schema are %NULL, then the database object will be the one which is + * "visible" by default (that is which can be accessed only by its short @name name). + * + * If @catalog is %NULL and @schema is not %NULL, then the database object will be the one which + * can be accessed by its @schema.@name name. + * + * Important note: @catalog, @schema and @name will be used using the following convention: + * + * be surrounded by double quotes for a case sensitive search + * otherwise for case insensitive search + * + * + * For more information, see the + * meta data section about SQL identifiers. + * + * Returns: (transfer none) (nullable): the #GdaMetaDbObject corresponding to the database object if no error occurred, or %NULL + */ +GdaMetaDbObject * +gda_meta_struct_complement (GdaMetaStruct *mstruct, GdaMetaDbObjectType type, + const GValue *catalog, const GValue *schema, const GValue *name, + GError **error) +{ + GdaMetaDbObject *dbo = NULL; + GdaMetaDbObjectType real_type = type; + GValue *short_name = NULL, *full_name=NULL, *owner=NULL; + GValue *icatalog = NULL, *ischema = NULL, *iname = NULL; /* GValue with identifiers ready to be compared */ + + g_return_val_if_fail (GDA_IS_META_STRUCT (mstruct), NULL); + + GdaMetaStructPrivate *priv = gda_meta_struct_get_instance_private (mstruct); + + /* checks */ + g_return_val_if_fail (priv->store, NULL); + g_return_val_if_fail (name && (G_VALUE_TYPE (name) == G_TYPE_STRING), NULL); + + if (catalog && (gda_value_is_null (catalog) || !g_value_get_string (catalog))) + catalog = NULL; + if (schema && (gda_value_is_null (schema) || !g_value_get_string (schema))) + schema = NULL; + g_return_val_if_fail (!catalog || (catalog && schema), NULL); + g_return_val_if_fail (!catalog || (G_VALUE_TYPE (catalog) == G_TYPE_STRING), NULL); + g_return_val_if_fail (!schema || (G_VALUE_TYPE (schema) == G_TYPE_STRING), NULL); + + /* create ready to compare strings for catalog, schema and name */ + gchar *schema_s, *name_s; + if (_split_identifier_string (g_value_dup_string (name), &schema_s, &name_s)) { + g_value_take_string ((iname = gda_value_new (G_TYPE_STRING)), prepare_sql_identifier_for_compare (name_s)); + if (schema_s) + g_value_take_string ((ischema = gda_value_new (G_TYPE_STRING)), prepare_sql_identifier_for_compare (schema_s)); + } + else + g_value_take_string ((iname = gda_value_new (G_TYPE_STRING)), + prepare_sql_identifier_for_compare (g_value_dup_string (name))); + if (catalog) + g_value_take_string ((icatalog = gda_value_new (G_TYPE_STRING)), + prepare_sql_identifier_for_compare (g_value_dup_string (catalog))); + if (schema && !ischema) + g_value_take_string ((ischema = gda_value_new (G_TYPE_STRING)), + prepare_sql_identifier_for_compare (g_value_dup_string (schema))); + + if (!icatalog) { + if (ischema) { + g_return_val_if_fail (ischema && (G_VALUE_TYPE (ischema) == G_TYPE_STRING), NULL); + if (! determine_db_object_from_schema_and_name (mstruct, &real_type, &icatalog, + &short_name, &full_name, &owner, + ischema, iname)) { + gchar *tmp; + tmp = get_user_obj_name (catalog, schema, name); + g_set_error (error, GDA_META_STRUCT_ERROR, GDA_META_STRUCT_UNKNOWN_OBJECT_ERROR, + _("Could not find object named '%s'"), tmp); + g_free (tmp); + gda_value_free (ischema); + gda_value_free (iname); + return NULL; + } + } + else { + GValue *real_name = NULL; + if (! determine_db_object_from_short_name (mstruct, &real_type, &icatalog, + &ischema, &real_name, + &short_name, &full_name, &owner, iname)) { + gchar *tmp; + tmp = get_user_obj_name (catalog, schema, name); + g_set_error (error, GDA_META_STRUCT_ERROR, GDA_META_STRUCT_UNKNOWN_OBJECT_ERROR, + _("Could not find object named '%s'"), tmp); + g_free (tmp); + gda_value_free (iname); + return NULL; + } + if (real_name) { + gda_value_free (iname); + iname = real_name; + } + } + } + else if (type == GDA_META_DB_UNKNOWN) { + if (! determine_db_object_from_missing_type (mstruct, &real_type, &short_name, &full_name, &owner, + icatalog, ischema, iname)) { + gchar *tmp; + tmp = get_user_obj_name (catalog, schema, name); + g_set_error (error, GDA_META_STRUCT_ERROR, GDA_META_STRUCT_UNKNOWN_OBJECT_ERROR, + _("Could not find object named '%s'"), tmp); + g_free (tmp); + gda_value_free (icatalog); + gda_value_free (ischema); + gda_value_free (iname); + return NULL; + } + } + type = real_type; + dbo = _meta_struct_complement (mstruct, type, icatalog, ischema, iname, short_name, full_name, owner, error); + + gda_value_free (icatalog); + gda_value_free (ischema); + gda_value_free (iname); + + if (short_name) gda_value_free (short_name); + if (full_name) gda_value_free (full_name); + if (owner) gda_value_free (owner); + return dbo; +} + +static GdaMetaForeignKeyPolicy +policy_string_to_value (const gchar *string) +{ + if (!string) + return GDA_META_FOREIGN_KEY_UNKNOWN; + if (*string == 'C') + return GDA_META_FOREIGN_KEY_CASCADE; + else if (*string == 'R') + return GDA_META_FOREIGN_KEY_RESTRICT; + else if (*string == 'N') { + if (!strcmp (string + 1, "ONE")) + return GDA_META_FOREIGN_KEY_NONE; + else + return GDA_META_FOREIGN_KEY_NO_ACTION; + } + else if (*string == 'S') { + if (!strcmp (string + 1, "ET NULL")) + return GDA_META_FOREIGN_KEY_SET_NULL; + else + return GDA_META_FOREIGN_KEY_SET_DEFAULT; + } + return GDA_META_FOREIGN_KEY_UNKNOWN; +} + +/* + * Find if there is already a declared foreign for @dbo to @ref_dbo using the columns + * listed in @columns + * + * @columns contains 4 columns, with no NULL value, and with nrows>0 + * - @dbo's column name (string) + * - @dbo's column name ordinal position (int) + * - @ref_dbo's column name (string) + * - @ref_dbo's column name ordinal position (int) + */ +static GdaMetaTableForeignKey * +find_real_foreign_key (GdaMetaTable *table, GdaMetaDbObject *ref_dbo, GdaDataModel *columns) +{ + GSList *list; + gint nrows = -1; + for (list = table->fk_list; list; list = list->next) { + GdaMetaTableForeignKey *fk = (GdaMetaTableForeignKey*) list->data; + gint i; + gboolean *mapping; + if (fk->depend_on != ref_dbo) + continue; + + if (nrows == -1) + nrows = gda_data_model_get_n_rows (columns); + + if (nrows != fk->cols_nb) + continue; + + mapping = g_new0 (gboolean, nrows); + for (i = 0; i < nrows; i++) { + const GValue *cvalues[4]; + const gchar *fk_colname, *ref_colname; + gint fk_pos, ref_pos; + gint j; + for (j = 0; j < 4; j++) { + cvalues[j] = gda_data_model_get_value_at (columns, j, i, NULL); + if (!cvalues[j]) { + g_free (mapping); + goto out; + } + } + fk_colname = g_value_get_string (cvalues[0]); + fk_pos = g_value_get_int (cvalues[1]); + ref_colname = g_value_get_string (cvalues[2]); + ref_pos = g_value_get_int (cvalues[3]); + if (!fk_colname || !*fk_colname || + !ref_colname || !*ref_colname) { + g_free (mapping); + goto out; + } + + for (j = 0; j < nrows; j++) { + if (mapping [j]) /* row already mapped? */ + continue; + if ((fk_pos == fk->fk_cols_array[j]) && + (ref_pos == fk->ref_pk_cols_array[j]) && + !strcmp (fk_colname, fk->fk_names_array[j]) && + !strcmp (ref_colname, fk->ref_pk_names_array[j])) { + mapping [j] = TRUE; + break; + } + } + if (j == nrows) + /* i'th row has not been mapped */ + break; + } + g_free (mapping); + if (i == nrows) + /* all the rows have been mapped */ + return fk; + else + continue; + } + out: + return NULL; +} + +static gboolean +add_declared_foreign_keys (GdaMetaStruct *mstruct, GdaMetaTable *mt, GError **error) +{ + const gchar *sql1 = "SELECT DISTINCT constraint_name, ref_table_catalog, ref_table_schema, ref_table_name FROM __declared_fk WHERE table_catalog = ##tc::string AND table_schema = ##ts::string AND table_name = ##tname::string ORDER BY constraint_name, ref_table_catalog, ref_table_schema, ref_table_name"; + const gchar *sql2 = "select de.column_name, c.ordinal_position, de.ref_column_name, rc.ordinal_position FROM __declared_fk de LEFT JOIN _columns c ON (de.table_catalog=c.table_catalog AND de.table_schema=c.table_schema AND de.table_name=c.table_name AND de.column_name=c.column_name) LEFT JOIN _columns rc ON (de.ref_table_catalog=rc.table_catalog AND de.ref_table_schema=rc.table_schema AND de.ref_table_name=rc.table_name AND de.ref_column_name=rc.column_name) WHERE de.constraint_name=##cname::string AND de.table_catalog=##tc::string AND de.table_schema=##ts::string AND de.table_name=##tname::string"; + GdaDataModel *model, *cmodel = NULL; + gint i, nrows; + GValue *v1, *v2, *v3; + GdaMetaDbObject *dbo; + GdaMetaStructPrivate *priv = gda_meta_struct_get_instance_private (mstruct); + + dbo = (GdaMetaDbObject*) mt; + g_value_set_string ((v1 = gda_value_new (G_TYPE_STRING)), dbo->obj_catalog); + g_value_set_string ((v2 = gda_value_new (G_TYPE_STRING)), dbo->obj_schema); + g_value_set_string ((v3 = gda_value_new (G_TYPE_STRING)), dbo->obj_name); + model = gda_meta_store_extract (priv->store, sql1, + error, "tc", v1, "ts", v2, "tname", v3, NULL); + if (!model) + goto onerror; + + nrows = gda_data_model_get_n_rows (model); + for (i = 0; i < nrows; i++) { + GdaMetaDbObject *ref_dbo = NULL; + GdaMetaTableForeignKey *tfk = NULL; + const GValue *fk_catalog, *fk_schema, *fk_tname, *fk_name; + gboolean ignore = FALSE; + + fk_name = gda_data_model_get_value_at (model, 0, i, error); + if (!fk_name) goto onerror; + fk_catalog = gda_data_model_get_value_at (model, 1, i, error); + if (!fk_catalog) goto onerror; + fk_schema = gda_data_model_get_value_at (model, 2, i, error); + if (!fk_schema) goto onerror; + fk_tname = gda_data_model_get_value_at (model, 3, i, error); + if (!fk_tname) goto onerror; + + /* get columns */ + cmodel = gda_meta_store_extract (priv->store, sql2, + error, "tc", v1, "ts", v2, "tname", v3, + "cname", fk_name, NULL); + if (!cmodel) + goto onerror; + + /* create new FK structure */ + tfk = g_new0 (GdaMetaTableForeignKey, 1); + tfk->meta_table = dbo; + tfk->declared = TRUE; + tfk->fk_name = g_value_dup_string (fk_name); + tfk->on_update_policy = GDA_META_FOREIGN_KEY_NONE; + tfk->on_delete_policy = GDA_META_FOREIGN_KEY_NONE; + + /* ignore if some columns are not found in the schema + * (maybe wrong or outdated FK decl) */ + gint j, cnrows; + cnrows = gda_data_model_get_n_rows (cmodel); + if (cnrows == 0) + ignore = TRUE; + else { + tfk->cols_nb = cnrows; + tfk->fk_cols_array = g_new0 (gint, cnrows); + tfk->fk_names_array = g_new0 (gchar *, cnrows); + tfk->ref_pk_cols_array = g_new0 (gint, cnrows); + tfk->ref_pk_names_array = g_new0 (gchar *, cnrows); + } + for (j = 0; j < cnrows; j++) { + const GValue *ov; + ov = gda_data_model_get_value_at (cmodel, 0, j, error); + if (!ov) goto onerror; + if (G_VALUE_TYPE (ov) != G_TYPE_STRING) { + ignore = TRUE; + break; + } + tfk->fk_names_array [j] = g_value_dup_string (ov); + + ov = gda_data_model_get_value_at (cmodel, 1, j, error); + if (!ov) goto onerror; + if (G_VALUE_TYPE (ov) != G_TYPE_INT) { + ignore = TRUE; + break; + } + tfk->fk_cols_array [j] = g_value_get_int (ov); + + ov = gda_data_model_get_value_at (cmodel, 2, j, error); + if (!ov) goto onerror; + if (G_VALUE_TYPE (ov) != G_TYPE_STRING) { + ignore = TRUE; + break; + } + tfk->ref_pk_names_array [j] = g_value_dup_string (ov); + + ov = gda_data_model_get_value_at (cmodel, 3, j, error); + if (!ov) goto onerror; + if (G_VALUE_TYPE (ov) != G_TYPE_INT) { + ignore = TRUE; + break; + } + tfk->ref_pk_cols_array [j] = g_value_get_int (ov); + } + + /* ignore if there is already an implemented FK */ + if (! ignore) { + ref_dbo = _meta_struct_get_db_object (mstruct, fk_catalog, + fk_schema, fk_tname); + if (ref_dbo && find_real_foreign_key (mt, ref_dbo, cmodel)) + ignore = TRUE; + } + if (ignore) { + /* ignore this FK end move on to the next one */ + if (tfk) + gda_meta_table_foreign_key_free (tfk); + continue; + } + + tfk->depend_on = ref_dbo; + if (!tfk->depend_on) { + gchar *str; + tfk->depend_on = g_new0 (GdaMetaDbObject, 1); + tfk->depend_on->obj_type = GDA_META_DB_UNKNOWN; + tfk->depend_on->obj_catalog = g_strdup (g_value_get_string (fk_catalog)); + tfk->depend_on->obj_schema = g_strdup (g_value_get_string (fk_schema)); + tfk->depend_on->obj_name = g_strdup (g_value_get_string (fk_tname)); + priv->db_objects = g_slist_append (priv->db_objects, tfk->depend_on); + str = g_strdup_printf ("%s.%s.%s", g_value_get_string (fk_catalog), + g_value_get_string (fk_schema), + g_value_get_string (fk_tname)); + g_hash_table_insert (priv->index, str, tfk->depend_on); + } + else if (tfk->depend_on->obj_type == GDA_META_DB_TABLE) { + GdaMetaTable *dot = GDA_META_TABLE (tfk->depend_on); + dot->reverse_fk_list = g_slist_prepend (dot->reverse_fk_list, tfk); + } + + dbo->depend_list = g_slist_append (dbo->depend_list, tfk->depend_on); + mt->fk_list = g_slist_prepend (mt->fk_list, tfk); + } + g_object_unref (model); + if (cmodel) + g_object_unref (cmodel); + + gda_value_free (v1); + gda_value_free (v2); + gda_value_free (v3); + + return TRUE; + + onerror: + if (model) + g_object_unref (model); + if (cmodel) + g_object_unref (cmodel); + gda_value_free (v1); + gda_value_free (v2); + gda_value_free (v3); + + return FALSE; +} + +static GdaMetaDbObject * +_meta_struct_complement (GdaMetaStruct *mstruct, GdaMetaDbObjectType type, + const GValue *icatalog, const GValue *ischema, const GValue *iname, + const GValue *short_name, const GValue *full_name, const GValue *owner, GError **error) +{ + /* at this point icatalog, ischema and iname are NOT NULL */ + GdaMetaDbObject *dbo = NULL; + const GValue *cvalue; + GdaMetaStructPrivate *priv = gda_meta_struct_get_instance_private (mstruct); + + /* create new GdaMetaDbObject or get already existing one */ + dbo = _meta_struct_get_db_object (mstruct, icatalog, ischema, iname); + if (!dbo) { + dbo = g_new0 (GdaMetaDbObject, 1); + dbo->obj_catalog = g_strdup (g_value_get_string (icatalog)); + dbo->obj_schema = g_strdup (g_value_get_string (ischema)); + dbo->obj_name = g_strdup (g_value_get_string (iname)); + if (short_name) + dbo->obj_short_name = g_strdup (g_value_get_string (short_name)); + if (full_name) + dbo->obj_full_name = g_strdup (g_value_get_string (full_name)); + if (owner && !gda_value_is_null (owner)) + dbo->obj_owner = g_strdup (g_value_get_string (owner)); + } + else if (dbo->obj_type == type) + return dbo; /* nothing to do */ + else if (dbo->obj_type != GDA_META_DB_UNKNOWN) { + /* DB Object already exists, return an error */ + g_set_error (error, GDA_META_STRUCT_ERROR, GDA_META_STRUCT_DUPLICATE_OBJECT_ERROR, + _("Object %s.%s.%s already exists in GdaMetaStruct and has a different object type"), + g_value_get_string (icatalog), g_value_get_string (ischema), + g_value_get_string (iname)); + dbo = NULL; + goto onerror; + } + dbo->obj_type = type; + + switch (type) { + case GDA_META_DB_VIEW: { + gchar *sql = "SELECT view_definition, is_updatable, table_short_name, table_full_name, table_owner " + "FROM _views NATURAL JOIN _tables " + "WHERE table_catalog = ##tc::string " + "AND table_schema = ##ts::string AND table_name = ##tname::string"; + GdaDataModel *model; + gint nrows; + GdaMetaView *mv; + + model = gda_meta_store_extract (priv->store, sql, + error, "tc", icatalog, "ts", ischema, "tname", iname, NULL); + if (!model) + goto onerror; + nrows = gda_data_model_get_n_rows (model); + if (nrows < 1) { + g_object_unref (model); + g_set_error (error, GDA_META_STRUCT_ERROR, GDA_META_STRUCT_UNKNOWN_OBJECT_ERROR, + _("View %s.%s.%s not found in meta store object"), + g_value_get_string (icatalog), g_value_get_string (ischema), + g_value_get_string (iname)); + goto onerror; + } + + if (!dbo->obj_short_name) { + cvalue = gda_data_model_get_value_at (model, 2, 0, error); + if (!cvalue) goto onerror; + dbo->obj_short_name = g_value_dup_string (cvalue); + } + if (!dbo->obj_full_name) { + cvalue = gda_data_model_get_value_at (model, 3, 0, error); + if (!cvalue) goto onerror; + dbo->obj_full_name = g_value_dup_string (cvalue); + } + if (!dbo->obj_owner) { + cvalue = gda_data_model_get_value_at (model, 4, 0, error); + if (!cvalue) goto onerror; + if (!gda_value_is_null (cvalue)) + dbo->obj_owner = g_value_dup_string (cvalue); + } + + mv = GDA_META_VIEW (dbo); + cvalue = gda_data_model_get_value_at (model, 0, 0, error); + if (!cvalue) goto onerror; + if (G_VALUE_TYPE (cvalue) != GDA_TYPE_NULL) + mv->view_def = g_value_dup_string (cvalue); + else + mv->view_def = g_strdup (""); + + cvalue = gda_data_model_get_value_at (model, 1, 0, error); + if (!cvalue) goto onerror; + if (G_VALUE_TYPE (cvalue) != GDA_TYPE_NULL) + mv->is_updatable = g_value_get_boolean (cvalue); + else + mv->is_updatable = FALSE; + + /* view's dependencies, from its definition */ + if ((priv->features & GDA_META_STRUCT_FEATURE_VIEW_DEPENDENCIES) && + mv->view_def && *mv->view_def) { + GdaStatement *stmt; + const gchar *remain; + stmt = gda_sql_parser_parse_string (priv->parser, mv->view_def, &remain, NULL); + if (stmt && + ((gda_statement_get_statement_type (stmt) == GDA_SQL_STATEMENT_SELECT) || + (gda_statement_get_statement_type (stmt) == GDA_SQL_STATEMENT_COMPOUND))) { + GdaSqlStatement *sqlst; + g_object_get (G_OBJECT (stmt), "structure", &sqlst, NULL); + compute_view_dependencies (mstruct, dbo, sqlst); + gda_sql_statement_free (sqlst); + g_object_unref (stmt); + +#ifdef GDA_DEBUG_NO + g_print ("View %s depends on: ", dbo->obj_name); + GSList *list; + for (list = dbo->depend_list; list; list = list->next) + g_print ("%s ", GDA_META_DB_OBJECT (list->data)->obj_name); + g_print ("\n"); +#endif + } + } + break; + } + case GDA_META_DB_TABLE: { + /* columns */ + gchar *sql = "SELECT c.column_name, c.data_type, c.gtype, c.is_nullable, t.table_short_name, t.table_full_name, c.column_default, t.table_owner, c.array_spec, c.extra, c.column_comments, coalesce (c.character_maximum_length, c.character_octet_length) FROM _tables as t LEFT NATURAL JOIN _columns as c WHERE table_catalog = ##tc::string AND table_schema = ##ts::string AND table_name = ##tname::string ORDER BY ordinal_position"; + GdaMetaTable *mt; + GdaDataModel *model; + gint i, nrows; + + model = gda_meta_store_extract (priv->store, sql, + error, "tc", icatalog, "ts", ischema, "tname", iname, NULL); + if (!model) + goto onerror; + + nrows = gda_data_model_get_n_rows (model); + if (nrows < 1) { + g_object_unref (model); + g_set_error (error, GDA_META_STRUCT_ERROR, GDA_META_STRUCT_UNKNOWN_OBJECT_ERROR, + _("Table %s.%s.%s not found (or missing columns information)"), + g_value_get_string (icatalog), g_value_get_string (ischema), + g_value_get_string (iname)); + goto onerror; + } + if (!dbo->obj_short_name) { + cvalue = gda_data_model_get_value_at (model, 4, 0, error); + if (!cvalue) goto onerror; + dbo->obj_short_name = g_value_dup_string (cvalue); + } + if (!dbo->obj_full_name) { + cvalue = gda_data_model_get_value_at (model, 5, 0, error); + if (!cvalue) goto onerror; + dbo->obj_full_name = g_value_dup_string (cvalue); + } + if (!dbo->obj_owner) { + cvalue = gda_data_model_get_value_at (model, 7, 0, error); + if (!cvalue) goto onerror; + if (!gda_value_is_null (cvalue)) + dbo->obj_owner = g_value_dup_string (cvalue); + } + + cvalue = gda_data_model_get_value_at (model, 0, 0, error); + if (cvalue && (G_VALUE_TYPE (cvalue) == GDA_TYPE_NULL)) { + if (type == GDA_META_DB_VIEW) { + /* we don't have the list of columns for the view. + * This can sometimes happen in SQLite */ + nrows = 0; + } + } + mt = GDA_META_TABLE (dbo); + for (i = 0; i < nrows; i++) { + GdaMetaTableColumn *tcol; + const gchar *cstr = NULL; + gint len = -1; + tcol = g_new0 (GdaMetaTableColumn, 1); /* Note: tcol->pkey is not determined here */ + mt->columns = g_slist_prepend (mt->columns, tcol); + + cvalue = gda_data_model_get_value_at (model, 0, i, error); + if (!cvalue) goto onerror; + tcol->column_name = g_value_dup_string (cvalue); + + cvalue = gda_data_model_get_value_at (model, 1, i, error); + if (!cvalue) goto onerror; + if (!gda_value_is_null (cvalue)) + cstr = g_value_get_string (cvalue); + + cvalue = gda_data_model_get_value_at (model, 11, i, error); + if (!cvalue) goto onerror; + if (!gda_value_is_null (cvalue)) + len = g_value_get_int (cvalue); + + if (cstr && *cstr) { + if (len >= 0) + tcol->column_type = g_strdup_printf ("%s (%d)", cstr, len); + else + tcol->column_type = g_strdup (cstr); + } + else { + cvalue = gda_data_model_get_value_at (model, 8, i, error); + if (!cvalue) goto onerror; + tcol->column_type = array_type_to_sql (priv->store, cvalue); + if (!tcol->column_type) + goto onerror; + } + + cvalue = gda_data_model_get_value_at (model, 2, i, error); + if (!cvalue) goto onerror; + tcol->gtype = gda_g_type_from_string (g_value_get_string (cvalue)); + if (tcol->gtype == G_TYPE_INVALID) + tcol->gtype = GDA_TYPE_NULL; + + cvalue = gda_data_model_get_value_at (model, 3, i, error); + if (!cvalue) goto onerror; + tcol->nullok = g_value_get_boolean (cvalue); + + cvalue = gda_data_model_get_value_at (model, 6, i, error); + if (!cvalue) goto onerror; + if (!gda_value_is_null (cvalue)) + tcol->default_value = g_value_dup_string (cvalue); + + cvalue = gda_data_model_get_value_at (model, 9, i, error); + if (!cvalue) goto onerror; + if (!gda_value_is_null (cvalue)) { + gchar **array, *tmp; + gint ai; + + cstr = g_value_get_string (cvalue); + array = g_strsplit (cstr, ",", 0); + for (ai = 0; array [ai]; ai++) { + tmp = g_strstrip (array [ai]); + if (!g_strcmp0 (tmp, GDA_EXTRA_AUTO_INCREMENT)) { + tcol->auto_incement = TRUE; + } + } + g_strfreev (array); + } + + cvalue = gda_data_model_get_value_at (model, 10, i, error); + if (!cvalue) goto onerror; + if (!gda_value_is_null (cvalue)) { + tcol->desc = g_value_dup_string (cvalue); + } + + } + mt->columns = g_slist_reverse (mt->columns); + g_object_unref (model); + + /* primary key */ + sql = "SELECT constraint_name FROM _table_constraints WHERE constraint_type='PRIMARY KEY' AND table_catalog = ##tc::string AND table_schema = ##ts::string AND table_name = ##tname::string"; + model = gda_meta_store_extract (priv->store, sql, + error, "tc", icatalog, "ts", ischema, "tname", iname, NULL); + if (!model) + goto onerror; + + nrows = gda_data_model_get_n_rows (model); + if (nrows >= 1) { + GdaDataModel *pkmodel; + sql = "SELECT column_name FROM _key_column_usage WHERE table_catalog = ##cc::string AND table_schema = ##cs::string AND table_name = ##tname::string AND constraint_name = ##cname::string ORDER BY ordinal_position"; + cvalue = gda_data_model_get_value_at (model, 0, 0, error); + if (!cvalue) goto onerror; + pkmodel = gda_meta_store_extract (priv->store, sql, error, + "cc", icatalog, + "cs", ischema, + "tname", iname, + "cname", cvalue, NULL); + if (!pkmodel) { + g_object_unref (model); + goto onerror; + } + nrows = gda_data_model_get_n_rows (pkmodel); + mt->pk_cols_nb = nrows; + mt->pk_cols_array = g_new0 (gint, mt->pk_cols_nb); + for (i = 0; i < nrows; i++) { + GdaMetaTableColumn *tcol; + cvalue = gda_data_model_get_value_at (pkmodel, 0, i, error); + if (!cvalue) goto onerror; + tcol = gda_meta_struct_get_table_column (mstruct, mt, cvalue); + if (!tcol) { + mt->pk_cols_array [i] = -1; + g_set_error (error, GDA_META_STRUCT_ERROR, GDA_META_STRUCT_INCOHERENCE_ERROR, + _("Internal GdaMetaStore error: column %s not found"), + g_value_get_string (cvalue)); + goto onerror; + } + else { + mt->pk_cols_array [i] = g_slist_index (mt->columns, tcol); + tcol->pkey = TRUE; + } + } + + g_object_unref (pkmodel); + } + g_object_unref (model); + + /* foreign keys */ + if (priv->features & GDA_META_STRUCT_FEATURE_FOREIGN_KEYS) { + sql = "SELECT ref_table_catalog, ref_table_schema, ref_table_name, constraint_name, ref_constraint_name, update_rule, delete_rule, constraint_name FROM _referential_constraints WHERE table_catalog = ##tc::string AND table_schema = ##ts::string AND table_name = ##tname::string"; + model = gda_meta_store_extract (priv->store, sql, error, + "tc", icatalog, + "ts", ischema, + "tname", iname, NULL); + if (!model) + goto onerror; + + nrows = gda_data_model_get_n_rows (model); + for (i = 0; i < nrows; i++) { + GdaMetaTableForeignKey *tfk = NULL; + const GValue *fk_catalog, *fk_schema, *fk_tname, *fk_name; + const GValue *upd_policy, *del_policy; + + GdaDataModel *fk_cols = NULL; + GdaDataModel *ref_pk_cols = NULL; + + fk_catalog = gda_data_model_get_value_at (model, 0, i, error); + if (!fk_catalog) goto onfkerror; + fk_schema = gda_data_model_get_value_at (model, 1, i, error); + if (!fk_schema) goto onfkerror; + fk_tname = gda_data_model_get_value_at (model, 2, i, error); + if (!fk_tname) goto onfkerror; + upd_policy = gda_data_model_get_value_at (model, 5, i, error); + if (!upd_policy) goto onfkerror; + del_policy = gda_data_model_get_value_at (model, 6, i, error); + if (!del_policy) goto onfkerror; + fk_name = gda_data_model_get_value_at (model, 7, i, error); + if (!fk_name) goto onfkerror; + + tfk = g_new0 (GdaMetaTableForeignKey, 1); + tfk->meta_table = dbo; + tfk->fk_name = g_value_dup_string (fk_name); + tfk->depend_on = _meta_struct_get_db_object (mstruct, fk_catalog, fk_schema, fk_tname); + if (!tfk->depend_on) { + gchar *str; + tfk->depend_on = g_new0 (GdaMetaDbObject, 1); + tfk->depend_on->obj_type = GDA_META_DB_UNKNOWN; + tfk->depend_on->obj_catalog = g_strdup (g_value_get_string (fk_catalog)); + tfk->depend_on->obj_schema = g_strdup (g_value_get_string (fk_schema)); + tfk->depend_on->obj_name = g_strdup (g_value_get_string (fk_tname)); + priv->db_objects = g_slist_append (priv->db_objects, tfk->depend_on); + str = g_strdup_printf ("%s.%s.%s", g_value_get_string (fk_catalog), + g_value_get_string (fk_schema), + g_value_get_string (fk_tname)); + g_hash_table_insert (priv->index, str, tfk->depend_on); + } + else if (tfk->depend_on->obj_type == GDA_META_DB_TABLE) { + GdaMetaTable *dot = GDA_META_TABLE (tfk->depend_on); + dot->reverse_fk_list = g_slist_prepend (dot->reverse_fk_list, tfk); + } + dbo->depend_list = g_slist_append (dbo->depend_list, tfk->depend_on); + + if (G_VALUE_TYPE (upd_policy) == G_TYPE_STRING) + tfk->on_update_policy = policy_string_to_value (g_value_get_string (upd_policy)); + else + tfk->on_update_policy = GDA_META_FOREIGN_KEY_UNKNOWN; + + if (G_VALUE_TYPE (upd_policy) == G_TYPE_STRING) + tfk->on_delete_policy = policy_string_to_value (g_value_get_string (del_policy)); + else + tfk->on_delete_policy = GDA_META_FOREIGN_KEY_UNKNOWN; + + tfk->declared = FALSE; + + /* FIXME: compute @cols_nb, and all the @*_array members (ref_pk_cols_array must be + * initialized with -1 values everywhere */ + sql = "SELECT k.column_name, c.ordinal_position FROM _key_column_usage k INNER JOIN _columns c ON (c.table_catalog = k.table_catalog AND c.table_schema = k.table_schema AND c.table_name=k.table_name AND c.column_name=k.column_name) WHERE k.table_catalog = ##tc::string AND k.table_schema = ##ts::string AND k.table_name = ##tname::string AND k.constraint_name = ##cname::string ORDER BY k.ordinal_position"; + gboolean fkerror = FALSE; + cvalue = gda_data_model_get_value_at (model, 3, i, error); + if (!cvalue) goto onfkerror; + fk_cols = gda_meta_store_extract (priv->store, sql, error, + "tc", icatalog, + "ts", ischema, + "tname", iname, + "cname", cvalue, NULL); + /*g_print ("tname=%s cvalue=%s\n", gda_value_stringify (iname), + gda_value_stringify (cvalue));*/ + + cvalue = gda_data_model_get_value_at (model, 4, i, error); + if (!cvalue) goto onfkerror; + ref_pk_cols = gda_meta_store_extract (priv->store, sql, error, + "tc", fk_catalog, + "ts", fk_schema, + "tname", fk_tname, + "cname", cvalue, NULL); + /*g_print ("tname=%s cvalue=%s\n", gda_value_stringify (fk_tname), + gda_value_stringify (cvalue));*/ + + if (fk_cols && ref_pk_cols) { + gint fk_nrows, ref_pk_nrows; + fk_nrows = gda_data_model_get_n_rows (fk_cols); + ref_pk_nrows = gda_data_model_get_n_rows (ref_pk_cols); + if (fk_nrows != ref_pk_nrows) { + /*gda_data_model_dump (fk_cols, stdout); + gda_data_model_dump (ref_pk_cols, stdout);*/ + if (ref_pk_nrows > 0) + fkerror = TRUE; + else { + /* not an error, only the referenced table is not present + * in the meta store, which is possible if the meta + * store was only partially updated */ + } + } + else { + gint n; + tfk->cols_nb = fk_nrows; + tfk->fk_cols_array = g_new0 (gint, fk_nrows); + tfk->fk_names_array = g_new0 (gchar *, fk_nrows); + tfk->ref_pk_cols_array = g_new0 (gint, fk_nrows); + tfk->ref_pk_names_array = g_new0 (gchar *, fk_nrows); + for (n = 0; n < fk_nrows; n++) { + const GValue *cv; + cv = gda_data_model_get_value_at (fk_cols, 1, n, error); + if (!cv) goto onfkerror; + tfk->fk_cols_array [n] = g_value_get_int (cv); + + cv = gda_data_model_get_value_at (fk_cols, 0, n, error); + if (!cv) goto onfkerror; + tfk->fk_names_array [n] = g_value_dup_string (cv); + + cv = gda_data_model_get_value_at (ref_pk_cols, 1, n, error); + if (!cv) goto onfkerror; + tfk->ref_pk_cols_array [n] = g_value_get_int (cv); + + cv = gda_data_model_get_value_at (ref_pk_cols, 0, n, error); + if (!cv) goto onfkerror; + tfk->ref_pk_names_array [n] = g_value_dup_string (cv); + } + } + } + else + fkerror = TRUE; + + if (fkerror) { + g_set_error (error, GDA_META_STRUCT_ERROR, GDA_META_STRUCT_INCOHERENCE_ERROR, + _("Meta data incoherence in foreign key constraint for table %s.%s.%s " + "referencing table %s.%s.%s"), + g_value_get_string (icatalog), + g_value_get_string (ischema), + g_value_get_string (iname), + g_value_get_string (fk_catalog), + g_value_get_string (fk_schema), + g_value_get_string (fk_tname)); + goto onfkerror; + } + if (fk_cols) + g_object_unref (fk_cols); + if (ref_pk_cols) + g_object_unref (ref_pk_cols); + + mt->fk_list = g_slist_prepend (mt->fk_list, tfk); + continue; + + onfkerror: + if (fk_cols) + g_object_unref (fk_cols); + if (ref_pk_cols) + g_object_unref (ref_pk_cols); + if (tfk) + mt->fk_list = g_slist_prepend (mt->fk_list, tfk); + goto onerror; + } + mt->fk_list = g_slist_reverse (mt->fk_list); + g_object_unref (model); + /* Note: mt->reverse_fk_list is not determined here */ + + add_declared_foreign_keys (mstruct, mt, NULL); + } + + break; + } + default: + TO_IMPLEMENT; + } + + if (dbo && !g_slist_find (priv->db_objects, dbo)) { + gchar *str; + priv->db_objects = g_slist_append (priv->db_objects, dbo); + str = g_strdup_printf ("%s.%s.%s", g_value_get_string (icatalog), + g_value_get_string (ischema), + g_value_get_string (iname)); + g_hash_table_insert (priv->index, str, dbo); + } + if (dbo && (dbo->obj_type == GDA_META_DB_TABLE) && + (priv->features & GDA_META_STRUCT_FEATURE_FOREIGN_KEYS)) { + /* compute GdaMetaTableForeignKey's @ref_pk_cols_array arrays and GdaMetaTable' @reverse_fk_list lists*/ + GSList *list; + for (list = priv->db_objects; list; list = list->next) { + GdaMetaDbObject *tmpdbo; + tmpdbo = GDA_META_DB_OBJECT (list->data); + if (tmpdbo->obj_type != GDA_META_DB_TABLE) + continue; + + GdaMetaTable *mt = GDA_META_TABLE (tmpdbo); + GSList *klist; + for (klist = mt->fk_list; klist; klist = klist->next) { + GdaMetaTableForeignKey *tfk = GDA_META_TABLE_FOREIGN_KEY (klist->data); + GdaMetaTable *ref_mt = GDA_META_TABLE (tfk->depend_on); + gint i; + + if (tfk->depend_on != dbo) + continue; + + for (i = 0; i < tfk->cols_nb; i++) { + gint col; + GdaMetaTableColumn *r_tcol; + GValue *r_val; + + if (tfk->ref_pk_cols_array[i] != -1) /* already correctly set */ + continue; + + if (tfk->depend_on->obj_type != GDA_META_DB_TABLE) + continue; /* can't be set now */ + + g_value_set_string ((r_val = gda_value_new (G_TYPE_STRING)), tfk->ref_pk_names_array[i]); + r_tcol = gda_meta_struct_get_table_column (mstruct, ref_mt, r_val); + gda_value_free (r_val); + col = g_slist_index (ref_mt->columns, r_tcol); + if (!r_tcol || (col < 0)) { + g_set_error (error, GDA_META_STRUCT_ERROR, GDA_META_STRUCT_INCOHERENCE_ERROR, + _("Foreign key column '%s' not found in table '%s'"), + tfk->ref_pk_names_array[i], tfk->depend_on->obj_name); + dbo = NULL; + goto onerror; + } + tfk->ref_pk_cols_array[i] = col; + } + + GDA_META_TABLE (dbo)->reverse_fk_list = g_slist_append (GDA_META_TABLE (dbo)->reverse_fk_list, + tfk); + } + } + } + return dbo; + + onerror: + if (dbo) + dbo->obj_type = GDA_META_DB_UNKNOWN; + + return NULL; +} + +static gchar * +array_type_to_sql (GdaMetaStore *store, const GValue *specific_name) +{ + gchar *str; + GdaDataModel *model; + gint nrows; + const GValue *cvalue; + + if (!specific_name || gda_value_is_null (specific_name)) + return g_strdup ("[]"); + + model = gda_meta_store_extract (store, "SELECT data_type, array_spec FROM _element_types WHERE specific_name = ##name::string", + NULL, "name", specific_name, NULL); + if (!model) + return g_strdup ("[]"); + nrows = gda_data_model_get_n_rows (model); + if (nrows != 1) { + g_object_unref (model); + return g_strdup ("[]"); + } + + cvalue = gda_data_model_get_value_at (model, 0, 0, NULL); + if (!cvalue) + return NULL; + if (gda_value_is_null (cvalue) || !g_value_get_string (cvalue)) { + /* use array_spec */ + gchar *str2; + cvalue = gda_data_model_get_value_at (model, 1, 0, NULL); + if (!cvalue) + return NULL; + str2 = array_type_to_sql (store, cvalue); + str = g_strdup_printf ("%s[]", str2); + g_free (str2); + } + else { + cvalue = gda_data_model_get_value_at (model, 0, 0, NULL); + if (!cvalue) + return NULL; + str = g_strdup_printf ("%s[]", g_value_get_string (cvalue)); + } + g_object_unref (model); + return str; +} + + +/** + * gda_meta_struct_complement_schema: + * @mstruct: a #GdaMetaStruct object + * @catalog: (nullable): name of a catalog, or %NULL + * @schema: (nullable): name of a schema, or %NULL + * @error: (nullable): a place to store errors, or %NULL + * + * This method is similar to gda_meta_struct_complement() but creates #GdaMetaDbObject for all the + * database object which are in the @schema schema (and in the @catalog catalog). + * If @catalog is %NULL, then any catalog will be used, and + * if @schema is %NULL then any schema will be used (if @schema is %NULL then catalog must also be %NULL). + * + * Please refer to gda_meta_struct_complement() form more information. + * + * Returns: TRUE if no error occurred + */ +gboolean +gda_meta_struct_complement_schema (GdaMetaStruct *mstruct, const GValue *catalog, const GValue *schema, + GError **error) +{ + GdaDataModel *tables_model = NULL, *views_model = NULL; + gint i, nrows, k; + const GValue *cvalues[6]; + + /* schema and catalog are known */ + const gchar *sql1 = "SELECT table_name " + "FROM _tables WHERE table_short_name, table_full_name, table_owner, table_catalog = ##cat::string AND table_schema = ##schema::string " + "AND table_type LIKE '%TABLE%' " + "ORDER BY table_schema, table_name"; + const gchar *sql2 = "SELECT table_short_name, table_full_name, table_owner, table_name " + "FROM _tables WHERE table_catalog = ##cat::string AND table_schema = ##schema::string " + "AND table_type LIKE '%VIEW%' " + "ORDER BY table_schema, table_name"; + + /* schema is known, catalog unknown */ + const gchar *sql3 = "SELECT table_short_name, table_full_name, table_owner, table_name, table_catalog, table_schema " + "FROM _tables WHERE table_schema = ##schema::string AND table_type LIKE '%TABLE%' " + "ORDER BY table_schema, table_name"; + const gchar *sql4 = "SELECT table_short_name, table_full_name, table_owner, table_name, table_catalog, table_schema " + "FROM _tables WHERE table_schema = ##schema::string AND table_type LIKE '%VIEW%' " + "ORDER BY table_schema, table_name"; + + /* schema and catalog are unknown */ + const gchar *sql5 = "SELECT table_short_name, table_full_name, table_owner, table_name, table_catalog, table_schema " + "FROM _tables WHERE table_type LIKE '%TABLE%' " + "ORDER BY table_schema, table_name"; + const gchar *sql6 = "SELECT table_short_name, table_full_name, table_owner, table_name, table_catalog, table_schema " + "FROM _tables WHERE table_type LIKE '%VIEW%' " + "ORDER BY table_schema, table_name"; + + g_return_val_if_fail (GDA_IS_META_STRUCT (mstruct), FALSE); + GdaMetaStructPrivate *priv = gda_meta_struct_get_instance_private (mstruct); + g_return_val_if_fail (priv->store, FALSE); + g_return_val_if_fail (!catalog || (catalog && schema), FALSE); + g_return_val_if_fail (!catalog || (G_VALUE_TYPE (catalog) == G_TYPE_STRING), FALSE); + g_return_val_if_fail (!schema || (G_VALUE_TYPE (schema) == G_TYPE_STRING), FALSE); + + if (schema) { + if (catalog) { + tables_model = gda_meta_store_extract (priv->store, sql1, error, + "cat", catalog, "schema", schema, NULL); + if (tables_model) + views_model = gda_meta_store_extract (priv->store, sql2, error, + "cat", catalog, "schema", schema, NULL); + } + else { + tables_model = gda_meta_store_extract (priv->store, sql3, + error, "schema", schema, NULL); + if (tables_model) + views_model = gda_meta_store_extract (priv->store, sql4, + error, "schema", schema, NULL); + } + } + else { + tables_model = gda_meta_store_extract (priv->store, sql5, error, NULL); + if (tables_model) + views_model = gda_meta_store_extract (priv->store, sql6, error, NULL); + } + + if (!tables_model || !views_model) + return FALSE; + + /* tables */ + nrows = gda_data_model_get_n_rows (tables_model); + for (i = 0; i < nrows; i++) { + for (k = 0; k <= 5; k++) { + cvalues [k] = gda_data_model_get_value_at (tables_model, k, i, error); + if (!cvalues [k]) { + g_object_unref (tables_model); + g_object_unref (views_model); + return FALSE; + } + } + if (!_meta_struct_complement (mstruct, GDA_META_DB_TABLE, + catalog ? catalog : cvalues [4], + schema ? schema : cvalues [5], + cvalues [3], + cvalues [0], + cvalues [1], + cvalues [2], error)) { + g_object_unref (tables_model); + g_object_unref (views_model); + return FALSE; + } + } + g_object_unref (tables_model); + + /* views */ + nrows = gda_data_model_get_n_rows (views_model); + for (i = 0; i < nrows; i++) { + for (k = 0; k <= 5; k++) { + cvalues [k] = gda_data_model_get_value_at (views_model, k, i, error); + if (!cvalues [k]) { + g_object_unref (views_model); + return FALSE; + } + } + if (!_meta_struct_complement (mstruct, GDA_META_DB_VIEW, + catalog ? catalog : cvalues [4], + schema ? schema : cvalues [5], + cvalues [3], + cvalues [0], + cvalues [1], + cvalues [2], error)) { + g_object_unref (views_model); + return FALSE; + } + } + g_object_unref (views_model); + + return TRUE; +} + +static gboolean +real_gda_meta_struct_complement_all (GdaMetaStruct *mstruct, gboolean default_only, GError **error) +{ + GdaDataModel *model; + gint i, nrows, k; + const GValue *cvalues[6]; + const gchar *sql1 = "SELECT table_catalog, table_schema, table_name, table_short_name, table_full_name, table_owner " + "FROM _tables WHERE table_short_name = table_name AND table_type LIKE '%TABLE%' " + "ORDER BY table_schema, table_name"; + const gchar *sql2 = "SELECT table_catalog, table_schema, table_name, table_short_name, table_full_name, table_owner " + "FROM _tables WHERE table_short_name = table_name AND table_type='VIEW' " + "ORDER BY table_schema, table_name"; + const gchar *sql3 = "SELECT table_catalog, table_schema, table_name, table_short_name, table_full_name, table_owner " + "FROM _tables WHERE table_type LIKE '%TABLE%' " + "ORDER BY table_schema, table_name"; + const gchar *sql4 = "SELECT table_catalog, table_schema, table_name, table_short_name, table_full_name, table_owner " + "FROM _tables WHERE table_type='VIEW' " + "ORDER BY table_schema, table_name"; + + g_return_val_if_fail (GDA_IS_META_STRUCT (mstruct), FALSE); + GdaMetaStructPrivate *priv = gda_meta_struct_get_instance_private (mstruct); + g_return_val_if_fail (priv->store, FALSE); + + /* tables */ + model = gda_meta_store_extract (priv->store, default_only ? sql1 : sql3, error, NULL); + if (!model) + return FALSE; + nrows = gda_data_model_get_n_rows (model); + for (i = 0; i < nrows; i++) { + for (k = 0; k <= 5; k++) { + cvalues [k] = gda_data_model_get_value_at (model, k, i, error); + if (!cvalues [k]) { + g_object_unref (model); + return FALSE; + } + } + if (!_meta_struct_complement (mstruct, GDA_META_DB_TABLE, + cvalues [0], cvalues [1], + cvalues [2], cvalues [3], + cvalues [4], cvalues [5], error)) { + g_object_unref (model); + return FALSE; + } + } + g_object_unref (model); + + /* views */ + model = gda_meta_store_extract (priv->store, default_only ? sql2 : sql4, error, NULL); + if (!model) + return FALSE; + nrows = gda_data_model_get_n_rows (model); + for (i = 0; i < nrows; i++) { + for (k = 0; k <= 5; k++) { + cvalues [k] = gda_data_model_get_value_at (model, k, i, error); + if (!cvalues [k]) { + g_object_unref (model); + return FALSE; + } + } + if (!_meta_struct_complement (mstruct, GDA_META_DB_VIEW, + cvalues [0], cvalues [1], + cvalues [2], cvalues [3], + cvalues [4], cvalues [5], error)) { + g_object_unref (model); + return FALSE; + } + } + g_object_unref (model); + return TRUE; +} + +/** + * gda_meta_struct_complement_default: + * @mstruct: a #GdaMetaStruct object + * @error: (nullable): a place to store errors, or %NULL + * + * This method is similar to gda_meta_struct_complement() and gda_meta_struct_complement_all() + * but creates #GdaMetaDbObject for all the + * database object which are usable using only their short name (that is which do not need to be prefixed by + * the schema in which they are to be used). + * + * Please refer to gda_meta_struct_complement() form more information. + * + * Returns: TRUE if no error occurred + */ +gboolean +gda_meta_struct_complement_default (GdaMetaStruct *mstruct, GError **error) +{ + return real_gda_meta_struct_complement_all (mstruct, TRUE, error); +} + +/** + * gda_meta_struct_complement_all: + * @mstruct: a #GdaMetaStruct object + * @error: (nullable): a place to store errors, or %NULL + * + * This method is similar to gda_meta_struct_complement() and gda_meta_struct_complement_default() + * but creates #GdaMetaDbObject for all the database object. + * + * Please refer to gda_meta_struct_complement() form more information. + * + * Returns: TRUE if no error occurred + */ +gboolean +gda_meta_struct_complement_all (GdaMetaStruct *mstruct, GError **error) +{ + return real_gda_meta_struct_complement_all (mstruct, FALSE, error); +} + +/** + * gda_meta_struct_complement_depend: + * @mstruct: a #GdaMetaStruct object + * @dbo: a #GdaMetaDbObject part of @mstruct + * @error: (nullable): a place to store errors, or %NULL + * + * This method is similar to gda_meta_struct_complement() but creates #GdaMetaDbObject for all the dependencies + * of @dbo. + * + * Please refer to gda_meta_struct_complement() form more information. + * + * Returns: TRUE if no error occurred + */ +gboolean +gda_meta_struct_complement_depend (GdaMetaStruct *mstruct, GdaMetaDbObject *dbo, + GError **error) +{ + GSList *list; + + g_return_val_if_fail (GDA_IS_META_STRUCT (mstruct), FALSE); + GdaMetaStructPrivate *priv = gda_meta_struct_get_instance_private (mstruct); + g_return_val_if_fail (priv->store, FALSE); + g_return_val_if_fail (dbo, FALSE); + g_return_val_if_fail (g_slist_find (priv->db_objects, dbo), FALSE); + + for (list = dbo->depend_list; list; list = list->next) { + GdaMetaDbObject *dep_dbo = GDA_META_DB_OBJECT (list->data); + if (dep_dbo->obj_type != GDA_META_DB_UNKNOWN) + continue; + + GValue *cat = NULL, *schema = NULL, *name = NULL; + GdaMetaDbObject *tmpobj; + g_return_val_if_fail (dep_dbo->obj_name, FALSE); + if (dep_dbo->obj_catalog) + g_value_take_string ((cat = gda_value_new (G_TYPE_STRING)), + g_strdup_printf ("\"%s\"", dep_dbo->obj_catalog)); + if (dep_dbo->obj_schema) + g_value_take_string ((schema = gda_value_new (G_TYPE_STRING)), + g_strdup_printf ("\"%s\"", dep_dbo->obj_schema)); + g_value_take_string ((name = gda_value_new (G_TYPE_STRING)), + g_strdup_printf ("\"%s\"", dep_dbo->obj_name)); + tmpobj = gda_meta_struct_complement (mstruct, GDA_META_DB_UNKNOWN, cat, schema, name, error); + if (cat) gda_value_free (cat); + if (schema) gda_value_free (schema); + gda_value_free (name); + if (!tmpobj) + return FALSE; + } + return TRUE; +} + + +/* + * Makes a list of all the GdaMetaDbObject structures listed in @objects + * which are not present in @ordered_list and for which no dependency is in @ordered_list + */ +static GSList * +build_pass (GSList *objects, GSList *ordered_list) +{ + GSList *retlist = NULL, *list; + + for (list = objects; list; list = list->next) { + gboolean has_dep = FALSE; + GSList *dep_list; + if (g_slist_find (ordered_list, list->data)) + continue; + for (dep_list = GDA_META_DB_OBJECT (list->data)->depend_list; dep_list; dep_list = dep_list->next) { + if (!g_slist_find (ordered_list, dep_list->data)) { + has_dep = TRUE; + break; + } + } + if (has_dep) + continue; + retlist = g_slist_prepend (retlist, list->data); + } + +#ifdef GDA_DEBUG_NO + g_print (">> PASS\n"); + for (list = retlist; list; list = list->next) + g_print ("--> %s\n", GDA_META_DB_OBJECT (list->data)->obj_name); + g_print ("<<\n"); +#endif + + return retlist; +} + +static gint +db_object_sort_func (GdaMetaDbObject *dbo1, GdaMetaDbObject *dbo2) +{ + gint retval = 0; + if (dbo1->obj_schema && dbo2->obj_schema) { + retval = strcmp (dbo1->obj_schema, dbo2->obj_schema); + if (retval) + return retval; + } + else if (dbo1->obj_schema) + return 1; + else if (dbo2->obj_schema) + return -1; + + if (dbo1->obj_name && dbo2->obj_name) + return strcmp (dbo1->obj_name, dbo2->obj_name); + else if (dbo1->obj_name) + return 1; + else if (dbo2->obj_name) + return -1; + return 0; +} + +/** + * gda_meta_struct_sort_db_objects: + * @mstruct: a #GdaMetaStruct object + * @sort_type: the kind of sorting requested + * @error: (nullable): a place to store errors, or %NULL + * + * Reorders the list of database objects within @mstruct in a way specified by @sort_type. + * + * Returns: TRUE if no error occurred + */ +gboolean +gda_meta_struct_sort_db_objects (GdaMetaStruct *mstruct, GdaMetaSortType sort_type, + G_GNUC_UNUSED GError **error) +{ + GSList *pass_list; + GSList *ordered_list = NULL; + + g_return_val_if_fail (GDA_IS_META_STRUCT (mstruct), FALSE); + GdaMetaStructPrivate *priv = gda_meta_struct_get_instance_private (mstruct); + + switch (sort_type) { + case GDA_META_SORT_ALHAPETICAL: + priv->db_objects = g_slist_sort (priv->db_objects, (GCompareFunc) db_object_sort_func); + ordered_list = priv->db_objects; + break; + case GDA_META_SORT_DEPENDENCIES: + if (mstruct == NULL) { + g_set_error (error, GDA_META_STRUCT_ERROR, GDA_META_STORE_INTERNAL_ERROR, + _("No meta struct was provided for object sorting")); + return FALSE; + } + for (pass_list = build_pass (priv->db_objects, ordered_list); + pass_list; + pass_list = build_pass (priv->db_objects, ordered_list)) + ordered_list = g_slist_concat (ordered_list, pass_list); + g_slist_free (priv->db_objects); + priv->db_objects = ordered_list; + break; + default: + TO_IMPLEMENT; + break; + } + +#ifdef GDA_DEBUG_NO + GSList *list; + for (list = ordered_list; list; list = list->next) + g_print ("--> %s\n", GDA_META_DB_OBJECT (list->data)->obj_name); +#endif + return TRUE; +} + +/* + * Same as gda_meta_struct_get_db_object except that @catalog, @schema and @name are ready to be + * compared (no need to double quote) + */ +static GdaMetaDbObject * +_meta_struct_get_db_object (GdaMetaStruct *mstruct, const GValue *catalog, const GValue *schema, const GValue *name) +{ + gchar *key; + GdaMetaDbObject *dbo; + GdaMetaStructPrivate *priv = gda_meta_struct_get_instance_private (mstruct); + + if (catalog && schema) { + g_return_val_if_fail (G_VALUE_TYPE (catalog) == G_TYPE_STRING, NULL); + g_return_val_if_fail (G_VALUE_TYPE (schema) == G_TYPE_STRING, NULL); + + key = g_strdup_printf ("%s.%s.%s", g_value_get_string (catalog), g_value_get_string (schema), + g_value_get_string (name)); + dbo = g_hash_table_lookup (priv->index, key); + g_free (key); + return dbo; + } + else { + /* walk through all the objects, and pick the ones with a matching name */ + GSList *list; + GSList *matching = NULL; + const gchar *obj_name = g_value_get_string (name); + const gchar *obj_schema = NULL, *obj_catalog = NULL; + if (catalog) { + g_return_val_if_fail (G_VALUE_TYPE (catalog) == G_TYPE_STRING, NULL); + obj_catalog = g_value_get_string (catalog); + } + if (schema) { + g_return_val_if_fail (G_VALUE_TYPE (schema) == G_TYPE_STRING, NULL); + obj_schema = g_value_get_string (schema); + } + + for (list = priv->db_objects; list; list = list->next) { + GdaMetaDbObject *dbo; + dbo = GDA_META_DB_OBJECT (list->data); + if (gda_identifier_equal (dbo->obj_name, obj_name) && + (!obj_schema || gda_identifier_equal (dbo->obj_schema, obj_schema)) && + (!obj_catalog || gda_identifier_equal (dbo->obj_catalog, obj_catalog))) + matching = g_slist_prepend (matching, dbo); + } + + if (matching && !matching->next) { + GdaMetaDbObject *dbo = GDA_META_DB_OBJECT (matching->data); + g_slist_free (matching); + return dbo; + } + else { + /* none or more than one found => return NULL */ + if (matching) + g_slist_free (matching); + return NULL; + } + } +} + +/** + * gda_meta_struct_get_all_db_objects: + * @mstruct: a #GdaMetaStruct object + * + * Get a list of all the #GdaMetaDbObject structures representing database objects in @mstruct. Note that + * no #GdaMetaDbObject structure must not be modified. + * + * Returns: (transfer container) (element-type Gda.MetaDbObject) (nullable): a new #GSList list of pointers to + * #GdaMetaDbObject structures which must be destroyed after usage using g_slist_free(). The individual + * #GdaMetaDbObject must not be modified. + */ +GSList * +gda_meta_struct_get_all_db_objects (GdaMetaStruct *mstruct) +{ + g_return_val_if_fail (GDA_IS_META_STRUCT (mstruct), NULL); + GdaMetaStructPrivate *priv = gda_meta_struct_get_instance_private (mstruct); + if (priv->db_objects) + return g_slist_copy (priv->db_objects); + else + return NULL; +} + +/** + * gda_meta_struct_get_db_object: + * @mstruct: a #GdaMetaStruct object + * @catalog: (nullable): the catalog the object belongs to (as a G_TYPE_STRING GValue), or %NULL + * @schema: (nullable): the schema the object belongs to (as a G_TYPE_STRING GValue), or %NULL + * @name: the object's name (as a G_TYPE_STRING GValue), not %NULL + * + * Tries to locate the #GdaMetaDbObject structure representing the database object named after + * @catalog, @schema and @name. + * + * If one or both of @catalog and @schema are %NULL, and more than one database object matches the name, then + * the return value is also %NULL. + * + * Returns: (transfer none) (nullable): the #GdaMetaDbObject or %NULL if not found + */ +GdaMetaDbObject * +gda_meta_struct_get_db_object (GdaMetaStruct *mstruct, const GValue *catalog, const GValue *schema, const GValue *name) +{ + GdaMetaDbObject *dbo; + GValue *icatalog = NULL, *ischema = NULL, *iname = NULL; /* GValue with identifiers ready to be compared */ + + g_return_val_if_fail (GDA_IS_META_STRUCT (mstruct), NULL); + g_return_val_if_fail (name && (G_VALUE_TYPE (name) == G_TYPE_STRING), NULL); + g_return_val_if_fail (!catalog || (catalog && schema), NULL); + g_return_val_if_fail (!catalog || (G_VALUE_TYPE (catalog) == G_TYPE_STRING), NULL); + g_return_val_if_fail (!schema || (G_VALUE_TYPE (schema) == G_TYPE_STRING), NULL); + + /* prepare identifiers */ + g_value_take_string ((iname = gda_value_new (G_TYPE_STRING)), prepare_sql_identifier_for_compare (g_value_dup_string (name))); + if (catalog) + g_value_take_string ((icatalog = gda_value_new (G_TYPE_STRING)), + prepare_sql_identifier_for_compare (g_value_dup_string (catalog))); + if (schema) + g_value_take_string ((ischema = gda_value_new (G_TYPE_STRING)), + prepare_sql_identifier_for_compare (g_value_dup_string (schema))); + + dbo = _meta_struct_get_db_object (mstruct, icatalog, ischema, iname); + if (icatalog) gda_value_free (icatalog); + if (ischema) gda_value_free (ischema); + gda_value_free (iname); + + return dbo; +} + +/** + * gda_meta_struct_get_table_column: + * @mstruct: a #GdaMetaStruct object + * @table: the #GdaMetaTable structure to find the column for + * @col_name: the name of the column to find (as a G_TYPE_STRING GValue) + * + * Tries to find the #GdaMetaTableColumn representing the column named @col_name in @table. + * + * Returns: (transfer none) (nullable): the #GdaMetaTableColumn or %NULL if not found + */ +GdaMetaTableColumn * +gda_meta_struct_get_table_column (GdaMetaStruct *mstruct, GdaMetaTable *table, const GValue *col_name) +{ + GSList *list; + const gchar *cname; + + g_return_val_if_fail (GDA_IS_META_STRUCT (mstruct), NULL); + g_return_val_if_fail (table, NULL); + g_return_val_if_fail (col_name && (G_VALUE_TYPE (col_name) == G_TYPE_STRING), NULL); + cname = g_value_get_string (col_name); + + for (list = table->columns; list; list = list->next) { + GdaMetaTableColumn *tcol = GDA_META_TABLE_COLUMN (list->data); + if (gda_identifier_equal (tcol->column_name, cname)) + return tcol; + } + return NULL; +} + +/** + * gda_meta_struct_dump_as_graph: + * @mstruct: a #GdaMetaStruct object + * @info: informs what kind of information to show in the resulting graph + * @error: (nullable): a place to store errors, or %NULL + * + * Creates a new graph (in the GraphViz syntax) representation of @mstruct. + * + * Returns: (transfer full) (nullable): a new string, or %NULL if an error occurred. + */ +gchar * +gda_meta_struct_dump_as_graph (GdaMetaStruct *mstruct, GdaMetaGraphInfo info, G_GNUC_UNUSED GError **error) +{ + GString *string; + gchar *result; + + g_return_val_if_fail (GDA_IS_META_STRUCT (mstruct), NULL); + GdaMetaStructPrivate *priv = gda_meta_struct_get_instance_private (mstruct); + + string = g_string_new ("digraph G {\nrankdir = BT;\nnode [shape = plaintext];\n"); + GSList *dbo_list; + for (dbo_list = priv->db_objects; dbo_list; dbo_list = dbo_list->next) { + gchar *objname, *fullname; + GdaMetaDbObject *dbo = GDA_META_DB_OBJECT (dbo_list->data); + GSList *list; + gboolean use_html = (info & GDA_META_GRAPH_COLUMNS) ? TRUE : FALSE; + + /* obj human readable name, and full name */ + fullname = g_strdup_printf ("%s.%s.%s", dbo->obj_catalog, dbo->obj_schema, dbo->obj_name); + if (dbo->obj_short_name) + objname = g_strdup (dbo->obj_short_name); + else if (dbo->obj_schema) + objname = g_strdup_printf ("%s.%s", dbo->obj_schema, dbo->obj_name); + else + objname = g_strdup (dbo->obj_name); + + /* node */ + switch (dbo->obj_type) { + case GDA_META_DB_UNKNOWN: + break; + case GDA_META_DB_TABLE: + if (use_html) { + g_string_append_printf (string, "\"%s\" [label=<", fullname); + g_string_append_printf (string, "", objname); + } + else + g_string_append_printf (string, "\"%s\" [ shape = box label = \"%s\" ]", fullname, objname); + break; + case GDA_META_DB_VIEW: + if (use_html) { + g_string_append_printf (string, "\"%s\" [label=<
%s
", fullname); + g_string_append_printf (string, "", objname); + } + else + g_string_append_printf (string, "\"%s\" [ shape = ellipse, label = \"%s\" ]", fullname, objname); + break; + default: + TO_IMPLEMENT; + g_string_append_printf (string, "\"%s\" [ shape = note label = \"%s\" ]", fullname, objname); + break; + } + + /* columns, only for tables */ + if (dbo->obj_type == GDA_META_DB_TABLE) { + GdaMetaTable *mt = GDA_META_TABLE (dbo); + GSList *depend_dbo_list = NULL; + if (info & GDA_META_GRAPH_COLUMNS) { + for (list = mt->columns; list; list = list->next) { + GdaMetaTableColumn *tcol = GDA_META_TABLE_COLUMN (list->data); + GString *extra = g_string_new (""); + if (tcol->pkey) + g_string_append_printf (extra, "key"); + g_string_append_printf (string, "", + tcol->column_name, extra->str); + g_string_free (extra, TRUE); + } + } + if (use_html) + g_string_append (string, "
%s
%s%s
>];\n"); + /* foreign keys */ + for (list = mt->fk_list; list; list = list->next) { + GdaMetaTableForeignKey *tfk = GDA_META_TABLE_FOREIGN_KEY (list->data); + if (tfk->depend_on->obj_type != GDA_META_DB_UNKNOWN) { + g_string_append_printf (string, "\"%s\" -> \"%s.%s.%s\";\n", fullname, + tfk->depend_on->obj_catalog, tfk->depend_on->obj_schema, + tfk->depend_on->obj_name); + depend_dbo_list = g_slist_prepend (depend_dbo_list, tfk->depend_on); + } + } + + /* dependencies other than foreign keys */ + for (list = dbo->depend_list; list; list = list->next) { + if (!g_slist_find (depend_dbo_list, list->data)) { + GdaMetaDbObject *dep_dbo = GDA_META_DB_OBJECT (list->data); + if (dep_dbo->obj_type != GDA_META_DB_UNKNOWN) + g_string_append_printf (string, "\"%s\" -> \"%s.%s.%s\";\n", + fullname, + dep_dbo->obj_catalog, dep_dbo->obj_schema, + dep_dbo->obj_name); + } + } + + g_slist_free (depend_dbo_list); + } + else if (dbo->obj_type == GDA_META_DB_VIEW) { + GdaMetaTable *mt = GDA_META_TABLE (dbo); + if (info & GDA_META_GRAPH_COLUMNS) { + for (list = mt->columns; list; list = list->next) { + GdaMetaTableColumn *tcol = GDA_META_TABLE_COLUMN (list->data); + g_string_append_printf (string, "%s", tcol->column_name); + } + } + if (use_html) + g_string_append (string, ">];\n"); + /* dependencies */ + for (list = dbo->depend_list; list; list = list->next) { + GdaMetaDbObject *ddbo = GDA_META_DB_OBJECT (list->data); + if (ddbo->obj_type != GDA_META_DB_UNKNOWN) + g_string_append_printf (string, "\"%s\" -> \"%s.%s.%s\";\n", fullname, + ddbo->obj_catalog, ddbo->obj_schema, + ddbo->obj_name); + } + } + + g_free (objname); + g_free (fullname); + } + g_string_append_c (string, '}'); + + result = string->str; + g_string_free (string, FALSE); + return result; +} + +static void +gda_meta_db_object_free_contents (GdaMetaDbObject *dbo) +{ + g_free (dbo->obj_catalog); + g_free (dbo->obj_schema); + g_free (dbo->obj_name); + g_free (dbo->obj_short_name); + g_free (dbo->obj_full_name); + g_free (dbo->obj_owner); + switch (dbo->obj_type) { + case GDA_META_DB_UNKNOWN: + break; + case GDA_META_DB_TABLE: + gda_meta_table_free_contents (GDA_META_TABLE (dbo)); + break; + case GDA_META_DB_VIEW: + gda_meta_view_free_contents (GDA_META_VIEW (dbo)); + break; + default: + TO_IMPLEMENT; + } + g_slist_free (dbo->depend_list); + memset (dbo, 0, sizeof (GdaMetaDbObject)); +} + +static void +gda_meta_db_object_free (GdaMetaDbObject *dbo) +{ + gda_meta_db_object_free_contents (dbo); + g_free (dbo); +} + +static void +gda_meta_table_free_contents (GdaMetaTable *table) +{ + g_slist_free_full (table->columns, (GDestroyNotify) gda_meta_table_column_free); + g_free (table->pk_cols_array); + g_slist_free_full (table->fk_list, (GDestroyNotify) gda_meta_table_foreign_key_free); + g_slist_free (table->reverse_fk_list); +} + +static void +gda_meta_view_free_contents (GdaMetaView *view) +{ + gda_meta_table_free_contents ((GdaMetaTable*) view); + g_free (view->view_def); +} + +static void +gda_meta_table_column_free (GdaMetaTableColumn *tcol) +{ + g_free (tcol->column_name); + g_free (tcol->column_type); + g_free (tcol->default_value); + if (tcol->desc != NULL) { + g_free (tcol->desc); + } + g_free (tcol); +} + +static void +gda_meta_table_foreign_key_free (GdaMetaTableForeignKey *tfk) +{ + gint i; + for (i = 0; i < tfk->cols_nb; i++) { + g_free (tfk->fk_names_array[i]); + g_free (tfk->ref_pk_names_array[i]); + } + g_free (tfk->fk_cols_array); + g_free (tfk->fk_names_array); + g_free (tfk->ref_pk_cols_array); + g_free (tfk->ref_pk_names_array); + g_free (tfk->fk_name); + g_free (tfk); +} + +static gboolean +determine_db_object_from_schema_and_name (GdaMetaStruct *mstruct, + GdaMetaDbObjectType *in_out_type, GValue **out_catalog, + GValue **out_short_name, + GValue **out_full_name, GValue **out_owner, + const GValue *schema, const GValue *name) +{ + const GValue *cvalue; + GdaDataModel *model = NULL; + *out_catalog = NULL; + *out_short_name = NULL; + *out_full_name = NULL; + *out_owner = NULL; + GdaMetaStructPrivate *priv = gda_meta_struct_get_instance_private (mstruct); + + switch (*in_out_type) { + case GDA_META_DB_UNKNOWN: { + GdaMetaDbObjectType type = GDA_META_DB_TABLE; + if (determine_db_object_from_schema_and_name (mstruct, &type, out_catalog, + out_short_name, out_full_name, out_owner, + schema, name)) { + *in_out_type = GDA_META_DB_TABLE; + return TRUE; + } + type = GDA_META_DB_VIEW; + if (determine_db_object_from_schema_and_name (mstruct, &type, out_catalog, + out_short_name, out_full_name, out_owner, + schema, name)) { + *in_out_type = GDA_META_DB_VIEW; + return TRUE; + } + return FALSE; + break; + } + + case GDA_META_DB_TABLE: { + const gchar *sql = "SELECT table_catalog, table_short_name, table_full_name, table_owner FROM _tables as t WHERE table_schema = ##ts::string AND table_name = ##tname::string AND table_name NOT IN (SELECT v.table_name FROM _views as v WHERE v.table_catalog=t.table_catalog AND v.table_schema=t.table_schema)"; + gint nrows; + model = gda_meta_store_extract (priv->store, sql, NULL, "ts", schema, "tname", name, NULL); + if (!model) + return FALSE; + + nrows = gda_data_model_get_n_rows (model); + if (nrows != 1) { + g_object_unref (model); + return FALSE; + } + cvalue = gda_data_model_get_value_at (model, 0, 0, NULL); + if (!cvalue) goto copyerror; + *out_catalog = gda_value_copy (cvalue); + + cvalue = gda_data_model_get_value_at (model, 1, 0, NULL); + if (!cvalue) goto copyerror; + *out_short_name = gda_value_copy (cvalue); + + cvalue = gda_data_model_get_value_at (model, 2, 0, NULL); + if (!cvalue) goto copyerror; + *out_full_name = gda_value_copy (cvalue); + + cvalue = gda_data_model_get_value_at (model, 3, 0, NULL); + if (!cvalue) goto copyerror; + *out_owner = gda_value_copy (cvalue); + + g_object_unref (model); + return TRUE; + } + + case GDA_META_DB_VIEW:{ + const gchar *sql = "SELECT table_catalog, table_short_name, table_full_name, table_owner FROM _tables NATURAL JOIN _views WHERE table_schema = ##ts::string AND table_name = ##tname::string"; + gint nrows; + model = gda_meta_store_extract (priv->store, sql, NULL, "ts", schema, "tname", name, NULL); + if (!model) + return FALSE; + + nrows = gda_data_model_get_n_rows (model); + if (nrows != 1) { + g_object_unref (model); + return FALSE; + } + cvalue = gda_data_model_get_value_at (model, 0, 0, NULL); + if (!cvalue) goto copyerror; + *out_catalog = gda_value_copy (cvalue); + + cvalue = gda_data_model_get_value_at (model, 1, 0, NULL); + if (!cvalue) goto copyerror; + *out_short_name = gda_value_copy (cvalue); + + cvalue = gda_data_model_get_value_at (model, 2, 0, NULL); + if (!cvalue) goto copyerror; + *out_full_name = gda_value_copy (cvalue); + + cvalue = gda_data_model_get_value_at (model, 3, 0, NULL); + if (!cvalue) goto copyerror; + *out_owner = gda_value_copy (cvalue); + + g_object_unref (model); + return TRUE; + } + default: + TO_IMPLEMENT; + } + + copyerror: + if (model) + g_object_unref (model); + if (*out_catalog) { + gda_value_free (*out_catalog); + *out_catalog = NULL; + } + if (*out_short_name) { + gda_value_free (*out_short_name); + *out_short_name = NULL; + } + if (*out_full_name) { + gda_value_free (*out_full_name); + *out_full_name = NULL; + } + if (*out_owner) { + gda_value_free (*out_owner); + *out_owner = NULL; + } + + return FALSE; +} + +static gboolean +determine_db_object_from_short_name (GdaMetaStruct *mstruct, + GdaMetaDbObjectType *in_out_type, GValue **out_catalog, + GValue **out_schema, GValue **out_name, GValue **out_short_name, + GValue **out_full_name, GValue **out_owner, const GValue *name) +{ + const GValue *cvalue; + GdaDataModel *model = NULL; + *out_name = NULL; + *out_schema = NULL; + *out_catalog = NULL; + *out_short_name = NULL; + *out_full_name = NULL; + *out_owner = NULL; + GdaMetaStructPrivate *priv = gda_meta_struct_get_instance_private (mstruct); + + /* general lookup */ + switch (*in_out_type) { + case GDA_META_DB_UNKNOWN: { + GdaMetaDbObjectType type = GDA_META_DB_TABLE; + if (determine_db_object_from_short_name (mstruct, &type, out_catalog, out_schema, out_name, + out_short_name, out_full_name, out_owner, name)) { + *in_out_type = GDA_META_DB_TABLE; + return TRUE; + } + type = GDA_META_DB_VIEW; + if (determine_db_object_from_short_name (mstruct, &type, out_catalog, out_schema, out_name, + out_short_name, out_full_name, out_owner, name)) { + *in_out_type = GDA_META_DB_VIEW; + return TRUE; + } + return FALSE; + break; + } + + case GDA_META_DB_TABLE: { + const gchar *sql = "SELECT table_catalog, table_schema, table_name, table_short_name, table_full_name, table_owner FROM _tables as t WHERE table_short_name = ##tname::string AND table_name NOT IN (SELECT v.table_name FROM _views as v WHERE v.table_catalog=t.table_catalog AND v.table_schema=t.table_schema)"; + gint nrows; + model = gda_meta_store_extract (priv->store, sql, NULL, "tname", name, NULL); + if (!model) + return FALSE; + + nrows = gda_data_model_get_n_rows (model); + if (nrows != 1) { + g_object_unref (model); + goto next; + } + + cvalue = gda_data_model_get_value_at (model, 0, 0, NULL); + if (!cvalue) goto copyerror; + *out_catalog = gda_value_copy (cvalue); + + cvalue = gda_data_model_get_value_at (model, 1, 0, NULL); + if (!cvalue) goto copyerror; + *out_schema = gda_value_copy (cvalue); + + cvalue = gda_data_model_get_value_at (model, 2, 0, NULL); + if (!cvalue) goto copyerror; + *out_name = gda_value_copy (cvalue); + + cvalue = gda_data_model_get_value_at (model, 3, 0, NULL); + if (!cvalue) goto copyerror; + *out_short_name = gda_value_copy (cvalue); + + cvalue = gda_data_model_get_value_at (model, 4, 0, NULL); + if (!cvalue) goto copyerror; + *out_full_name = gda_value_copy (cvalue); + + cvalue = gda_data_model_get_value_at (model, 5, 0, NULL); + if (!cvalue) goto copyerror; + *out_owner = gda_value_copy (cvalue); + + g_object_unref (model); + return TRUE; + } + + case GDA_META_DB_VIEW:{ + const gchar *sql = "SELECT table_catalog, table_schema, table_name, table_short_name, table_full_name, table_owner FROM _tables NATURAL JOIN _views WHERE table_short_name = ##tname::string"; + gint nrows; + model = gda_meta_store_extract (priv->store, sql, NULL, "tname", name, NULL); + if (!model) + return FALSE; + + nrows = gda_data_model_get_n_rows (model); + if (nrows != 1) { + g_object_unref (model); + goto next; + } + + cvalue = gda_data_model_get_value_at (model, 0, 0, NULL); + if (!cvalue) goto copyerror; + *out_catalog = gda_value_copy (cvalue); + + cvalue = gda_data_model_get_value_at (model, 1, 0, NULL); + if (!cvalue) goto copyerror; + *out_schema = gda_value_copy (cvalue); + + cvalue = gda_data_model_get_value_at (model, 2, 0, NULL); + if (!cvalue) goto copyerror; + *out_name = gda_value_copy (cvalue); + + cvalue = gda_data_model_get_value_at (model, 3, 0, NULL); + if (!cvalue) goto copyerror; + *out_short_name = gda_value_copy (cvalue); + + cvalue = gda_data_model_get_value_at (model, 4, 0, NULL); + if (!cvalue) goto copyerror; + *out_full_name = gda_value_copy (cvalue); + + cvalue = gda_data_model_get_value_at (model, 5, 0, NULL); + if (!cvalue) goto copyerror; + *out_owner = gda_value_copy (cvalue); + + g_object_unref (model); + return TRUE; + } + default: + TO_IMPLEMENT; + } + + next: + model = NULL; + { + /* treat the case where name is in fact . */ + gchar *obj_schema; + gchar *obj_name; + if (_split_identifier_string (g_strdup ((gchar *) g_value_get_string (name)), &obj_schema, &obj_name)) { + GValue *sv, *nv; + gboolean retval; + if (!obj_schema) { + g_free (obj_name); + return FALSE; + } + if (!obj_name) { + g_free (obj_schema); + return FALSE; + } + g_value_take_string ((sv = gda_value_new (G_TYPE_STRING)), prepare_sql_identifier_for_compare (obj_schema)); + g_value_take_string ((nv = gda_value_new (G_TYPE_STRING)), prepare_sql_identifier_for_compare (obj_name)); + retval = determine_db_object_from_schema_and_name (mstruct, in_out_type, out_catalog, + out_short_name, out_full_name, out_owner, + sv, nv); + if (retval) { + *out_schema = sv; + *out_name = nv; + } + else { + gda_value_free (sv); + gda_value_free (nv); + } + return retval; + } + } + + copyerror: + if (model) + g_object_unref (model); + if (*out_catalog) { + gda_value_free (*out_catalog); + *out_catalog = NULL; + } + if (*out_schema) { + gda_value_free (*out_schema); + *out_schema = NULL; + } + if (*out_name) { + gda_value_free (*out_name); + *out_name = NULL; + } + if (*out_short_name) { + gda_value_free (*out_short_name); + *out_short_name = NULL; + } + if (*out_full_name) { + gda_value_free (*out_full_name); + *out_full_name = NULL; + } + if (*out_owner) { + gda_value_free (*out_owner); + *out_owner = NULL; + } + + return FALSE; +} + +static gboolean +determine_db_object_from_missing_type (GdaMetaStruct *mstruct, + GdaMetaDbObjectType *out_type, GValue **out_short_name, + GValue **out_full_name, GValue **out_owner, const GValue *catalog, + const GValue *schema, const GValue *name) +{ + /* try as a view first */ + const gchar *sql = "SELECT table_short_name, table_full_name, table_owner FROM _tables NATURAL JOIN _views WHERE table_catalog = ##tc::string AND table_schema = ##ts::string AND table_name = ##tname::string"; + GdaDataModel *model = NULL; + const GValue *cvalue; + GdaMetaStructPrivate *priv = gda_meta_struct_get_instance_private (mstruct); + + *out_type = GDA_META_DB_UNKNOWN; + *out_short_name = NULL; + *out_full_name = NULL; + *out_owner = NULL; + + model = gda_meta_store_extract (priv->store, sql, NULL, "tc", catalog, "ts", schema, "tname", name, NULL); + if (model && (gda_data_model_get_n_rows (model) == 1)) { + *out_type = GDA_META_DB_VIEW; + + cvalue = gda_data_model_get_value_at (model, 0, 0, NULL); + if (!cvalue) goto copyerror; + *out_short_name = gda_value_copy (cvalue); + + cvalue = gda_data_model_get_value_at (model, 1, 0, NULL); + if (!cvalue) goto copyerror; + *out_full_name = gda_value_copy (cvalue); + + cvalue = gda_data_model_get_value_at (model, 2, 0, NULL); + if (!cvalue) goto copyerror; + *out_owner = gda_value_copy (cvalue); + + g_object_unref (model); + return TRUE; + } + if (model) + g_object_unref (model); + + /* try as a table */ + sql = "SELECT table_short_name, table_full_name, table_owner FROM _tables WHERE table_catalog = ##tc::string AND table_schema = ##ts::string AND table_name = ##tname::string"; + model = gda_meta_store_extract (priv->store, sql, NULL, "tc", catalog, "ts", schema, "tname", name, NULL); + if (model && (gda_data_model_get_n_rows (model) == 1)) { + *out_type = GDA_META_DB_TABLE; + + cvalue = gda_data_model_get_value_at (model, 0, 0, NULL); + if (!cvalue) goto copyerror; + *out_short_name = gda_value_copy (cvalue); + + cvalue = gda_data_model_get_value_at (model, 1, 0, NULL); + if (!cvalue) goto copyerror; + *out_full_name = gda_value_copy (cvalue); + + cvalue = gda_data_model_get_value_at (model, 2, 0, NULL); + if (!cvalue) goto copyerror; + *out_owner = gda_value_copy (cvalue); + + g_object_unref (model); + return TRUE; + } + if (model) { + g_object_unref (model); + model = NULL; + } + +copyerror: + if (model) + g_object_unref (model); + + *out_type = GDA_META_DB_UNKNOWN; + if (*out_short_name) { + gda_value_free (*out_short_name); + *out_short_name = NULL; + } + if (*out_full_name) { + gda_value_free (*out_full_name); + *out_full_name = NULL; + } + if (*out_owner) { + gda_value_free (*out_owner); + *out_owner = NULL; + } + return FALSE; +} + +/** + * _gda_meta_struct_add_db_object: + * @mstruct: a #GdaMetaStruct object + * @dbo: a #GdaMetaDbObject structure + * @error: (nullable): a place to store errors, or %NULL + * + * Adds @dbo to the database objects known to @mstruct. In any case (whether an error occured or not) + * @dbo's ownership is then transferred to @smtruct and should + * not be used after calling this function (it may have been destroyed). If you need a pointer to the #GdaMetaDbObject + * for a database object, use gda_meta_struct_get_db_object(). + * + * Returns: (transfer none) (nullable): a pointer to the #GdaMetaDbObject used in @mstruct to represent the added database object (may be @dbo or not) + */ +GdaMetaDbObject * +_gda_meta_struct_add_db_object (GdaMetaStruct *mstruct, GdaMetaDbObject *dbo, GError **error) +{ + GdaMetaDbObject *edbo; + GValue *v1 = NULL, *v2 = NULL, *v3 = NULL; + g_return_val_if_fail (GDA_IS_META_STRUCT (mstruct), NULL); + g_return_val_if_fail (dbo, NULL); + GdaMetaStructPrivate *priv = gda_meta_struct_get_instance_private (mstruct); + + if (!dbo->obj_name) { + g_set_error (error, GDA_META_STRUCT_ERROR, GDA_META_STRUCT_INCOHERENCE_ERROR, + "%s", _("Missing object name in GdaMetaDbObject structure")); + gda_meta_db_object_free (dbo); + return NULL; + } + if (dbo->obj_catalog) + g_value_set_string ((v1 = gda_value_new (G_TYPE_STRING)), dbo->obj_catalog); + if (dbo->obj_schema) + g_value_set_string ((v2 = gda_value_new (G_TYPE_STRING)), dbo->obj_schema); + g_value_set_string ((v3 = gda_value_new (G_TYPE_STRING)), dbo->obj_name); + + edbo = gda_meta_struct_get_db_object (mstruct, v1, v2, v3); + if (v1) gda_value_free (v1); + if (v2) gda_value_free (v2); + gda_value_free (v3); + + if (edbo) { + if (edbo->obj_type == GDA_META_DB_UNKNOWN) { + /* overwrite */ + gda_meta_db_object_free_contents (edbo); + *edbo = *dbo; + g_free (dbo); + return edbo; + } + else { + g_set_error (error, GDA_META_STRUCT_ERROR, GDA_META_STRUCT_DUPLICATE_OBJECT_ERROR, + _("Database object '%s' already exists"), edbo->obj_full_name); + gda_meta_db_object_free (dbo); + return NULL; + } + } + else { + priv->db_objects = g_slist_append (priv->db_objects, dbo); + g_hash_table_insert (priv->index, g_strdup (dbo->obj_full_name), dbo); + return dbo; + } +} + diff --git a/.flatpak-builder/cache/objects/fb/ea4a3cb34ad4863241367ce83fd7250c884b814cce2b931fb92fd4159be71e.file b/.flatpak-builder/cache/objects/fb/ea4a3cb34ad4863241367ce83fd7250c884b814cce2b931fb92fd4159be71e.file new file mode 100644 index 0000000..929a51b --- /dev/null +++ b/.flatpak-builder/cache/objects/fb/ea4a3cb34ad4863241367ce83fd7250c884b814cce2b931fb92fd4159be71e.file @@ -0,0 +1,77 @@ +/* + * gda-db-index-field.h + * Copyright (C) 2019 Pavlo Solntsev + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, see . + * + */ + +#ifndef GDA_DB_INDEX_FIELD_H +#define GDA_DB_INDEX_FIELD_H + +#include +#include +#include "gda-db-base.h" +#include "gda-db-column.h" + +G_BEGIN_DECLS + +#define GDA_TYPE_DB_INDEX_FIELD (gda_db_index_field_get_type()) + +G_DECLARE_DERIVABLE_TYPE (GdaDbIndexField, gda_db_index_field, GDA, DB_INDEX_FIELD, GObject) + +struct _GdaDbIndexFieldClass +{ + GObjectClass parent_class; +}; + +/** + * GdaDbIndexSortOrder: + * @GDA_DB_INDEX_SORT_ORDER_ASC: ascending sorting + * @GDA_DB_INDEX_SORT_ORDER_DESC: descending sorting + * + * Enum values to specify the sorting + */ +typedef enum +{ + GDA_DB_INDEX_SORT_ORDER_ASC = 0, + GDA_DB_INDEX_SORT_ORDER_DESC +} GdaDbIndexSortOrder; + +GdaDbIndexField *gda_db_index_field_new (void); + +void gda_db_index_field_set_column (GdaDbIndexField *self, + GdaDbColumn *column); + +GdaDbColumn *gda_db_index_field_get_column (GdaDbIndexField *self); + +void gda_db_index_field_set_collate (GdaDbIndexField *self, + const gchar *collate); + +const gchar * gda_db_index_field_get_collate (GdaDbIndexField *self); + +void gda_db_index_field_set_sort_order (GdaDbIndexField *self, + GdaDbIndexSortOrder sorder); + +GdaDbIndexSortOrder gda_db_index_field_get_sort_order (GdaDbIndexField *self); + +const gchar * gda_db_index_field_get_sort_order_str (GdaDbIndexField *self); + +G_END_DECLS + +#endif /* end of include guard: GDA-DB-INDEX_H */ + + + + diff --git a/.flatpak-builder/cache/objects/fc/071dcc67602abecac0726c519bddaa8f9aca5ec8ab75c95a8ce8e73505be80.file b/.flatpak-builder/cache/objects/fc/071dcc67602abecac0726c519bddaa8f9aca5ec8ab75c95a8ce8e73505be80.file new file mode 100755 index 0000000..cbbe00a --- /dev/null +++ b/.flatpak-builder/cache/objects/fc/071dcc67602abecac0726c519bddaa8f9aca5ec8ab75c95a8ce8e73505be80.file @@ -0,0 +1,41 @@ +# libcanberra-gstreamer.la - a libtool library file +# Generated by libtool (GNU libtool) 2.4.2 +# +# Please DO NOT delete this file! +# It is necessary for linking the library. + +# The name that we can dlopen(3). +dlname='libcanberra-gstreamer.so' + +# Names of this library. +library_names='libcanberra-gstreamer.so libcanberra-gstreamer.so libcanberra-gstreamer.so' + +# The name of the static archive. +old_library='' + +# Linker flags that can not go in dependency_libs. +inherited_linker_flags=' -pthread' + +# Libraries that this one depends upon. +dependency_libs=' -L/app/lib -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 /app/lib/libcanberra.la -lvorbisfile -lltdl -lm' + +# Names of additional weak libraries provided by this library +weak_library_names='' + +# Version information for libcanberra-gstreamer. +current=0 +age=0 +revision=0 + +# Is this an already installed library? +installed=yes + +# Should we warn about portability when linking against -modules? +shouldnotlink=yes + +# Files to dlopen/dlpreopen +dlopen='' +dlpreopen='' + +# Directory that this library needs to be installed in: +libdir='/app/lib/libcanberra-0.30' diff --git a/.flatpak-builder/cache/objects/fc/e527c5eb75f74f03ad46e2eb546e40385542fc5fc537155c9b8db44631c6df.file b/.flatpak-builder/cache/objects/fc/e527c5eb75f74f03ad46e2eb546e40385542fc5fc537155c9b8db44631c6df.file new file mode 100644 index 0000000..ff080ea --- /dev/null +++ b/.flatpak-builder/cache/objects/fc/e527c5eb75f74f03ad46e2eb546e40385542fc5fc537155c9b8db44631c6df.file @@ -0,0 +1,621 @@ +# parse_tree.py +# +# Copyright 2021 James Westman +# +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation; either version 3 of the +# License, or (at your option) any later version. +# +# This file is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program. If not, see . +# +# SPDX-License-Identifier: LGPL-3.0-or-later + +""" Utilities for parsing an AST from a token stream. """ + +import typing as T + +from collections import defaultdict +from enum import Enum +from .ast_utils import AstNode + +from .errors import ( + assert_true, + CompilerBugError, + CompileError, + CompileWarning, + UnexpectedTokenError, +) +from .tokenizer import Token, TokenType + + +SKIP_TOKENS = [TokenType.COMMENT, TokenType.WHITESPACE] + + +class ParseResult(Enum): + """Represents the result of parsing. The extra EMPTY result is necessary + to avoid freezing the parser: imagine a ZeroOrMore node containing a node + that can match empty. It will repeatedly match empty and never advance + the parser. So, ZeroOrMore stops when a failed *or empty* match is + made.""" + + SUCCESS = 0 + FAILURE = 1 + EMPTY = 2 + + def matched(self): + return self == ParseResult.SUCCESS + + def succeeded(self): + return self != ParseResult.FAILURE + + def failed(self): + return self == ParseResult.FAILURE + + +class ParseGroup: + """A matching group. Match groups have an AST type, children grouped by + type, and key=value pairs. At the end of parsing, the match groups will + be converted to AST nodes by passing the children and key=value pairs to + the AST node constructor.""" + + def __init__(self, ast_type: T.Type[AstNode], start: int): + self.ast_type = ast_type + self.children: T.List[ParseGroup] = [] + self.keys: T.Dict[str, T.Any] = {} + self.tokens: T.Dict[str, T.Optional[Token]] = {} + self.start = start + self.end: T.Optional[int] = None + self.incomplete = False + + def add_child(self, child: "ParseGroup"): + self.children.append(child) + + def set_val(self, key: str, val: T.Any, token: T.Optional[Token]): + assert_true(key not in self.keys) + + self.keys[key] = val + self.tokens[key] = token + + def to_ast(self): + """Creates an AST node from the match group.""" + children = [child.to_ast() for child in self.children] + + try: + return self.ast_type(self, children, self.keys, incomplete=self.incomplete) + except TypeError as e: + raise CompilerBugError( + f"Failed to construct ast.{self.ast_type.__name__} from ParseGroup. See the previous stacktrace." + ) + + def __str__(self): + result = str(self.ast_type.__name__) + result += "".join([f"\n{key}: {val}" for key, val in self.keys.items()]) + "\n" + result += "\n".join( + [str(child) for children in self.children.values() for child in children] + ) + return result.replace("\n", "\n ") + + +class ParseContext: + """Contains the state of the parser.""" + + def __init__(self, tokens: T.List[Token], index=0): + self.tokens = tokens + + self.binding_power = 0 + self.index = index + self.start = index + self.group: T.Optional[ParseGroup] = None + self.group_keys: T.Dict[str, T.Tuple[T.Any, T.Optional[Token]]] = {} + self.group_children: T.List[ParseGroup] = [] + self.last_group: T.Optional[ParseGroup] = None + self.group_incomplete = False + + self.errors: T.List[CompileError] = [] + self.warnings: T.List[CompileWarning] = [] + + def create_child(self) -> "ParseContext": + """Creates a new ParseContext at this context's position. The new + context will be used to parse one node. If parsing is successful, the + new context will be applied to "self". If parsing fails, the new + context will be discarded.""" + ctx = ParseContext(self.tokens, self.index) + ctx.errors = self.errors + ctx.warnings = self.warnings + ctx.binding_power = self.binding_power + return ctx + + def apply_child(self, other: "ParseContext"): + """Applies a child context to this context.""" + + if other.group is not None: + # If the other context had a match group, collect all the matched + # values into it and then add it to our own match group. + for key, (val, token) in other.group_keys.items(): + other.group.set_val(key, val, token) + for child in other.group_children: + other.group.add_child(child) + other.group.end = other.tokens[other.index - 1].end + other.group.incomplete = other.group_incomplete + self.group_children.append(other.group) + else: + # If the other context had no match group of its own, collect all + # its matched values + self.group_keys = {**self.group_keys, **other.group_keys} + self.group_children += other.group_children + self.group_incomplete |= other.group_incomplete + + self.index = other.index + # Propagate the last parsed group down the stack so it can be easily + # retrieved at the end of the process + if other.group: + self.last_group = other.group + elif other.last_group: + self.last_group = other.last_group + + def start_group(self, ast_type: T.Type[AstNode]): + """Sets this context to have its own match group.""" + assert_true(self.group is None) + self.group = ParseGroup(ast_type, self.tokens[self.index].start) + + def set_group_val(self, key: str, value: T.Any, token: T.Optional[Token]): + """Sets a matched key=value pair on the current match group.""" + assert_true(key not in self.group_keys) + self.group_keys[key] = (value, token) + + def set_group_incomplete(self): + """Marks the current match group as incomplete (it could not be fully + parsed, but the parser recovered).""" + self.group_incomplete = True + + def skip(self): + """Skips whitespace and comments.""" + while ( + self.index < len(self.tokens) + and self.tokens[self.index].type in SKIP_TOKENS + ): + self.index += 1 + + def next_token(self) -> Token: + """Advances the token iterator and returns the next token.""" + self.skip() + token = self.tokens[self.index] + self.index += 1 + return token + + def peek_token(self) -> Token: + """Returns the next token without advancing the iterator.""" + self.skip() + token = self.tokens[self.index] + return token + + def skip_unexpected_token(self): + """Skips a token and logs an "unexpected token" error.""" + + self.skip() + start = self.tokens[self.index].start + self.next_token() + self.skip() + end = self.tokens[self.index - 1].end + + if ( + len(self.errors) + and isinstance((err := self.errors[-1]), UnexpectedTokenError) + and err.end == start + ): + err.end = end + else: + self.errors.append(UnexpectedTokenError(start, end)) + + def is_eof(self) -> bool: + return self.index >= len(self.tokens) or self.peek_token().type == TokenType.EOF + + +class ParseNode: + """Base class for the nodes in the parser tree.""" + + def parse(self, ctx: ParseContext) -> ParseResult: + """Attempts to match the ParseNode at the context's current location.""" + start_idx = ctx.index + inner_ctx = ctx.create_child() + + if self._parse(inner_ctx): + ctx.apply_child(inner_ctx) + if ctx.index == start_idx: + return ParseResult.EMPTY + else: + return ParseResult.SUCCESS + else: + return ParseResult.FAILURE + + def _parse(self, ctx: ParseContext) -> bool: + raise NotImplementedError() + + def err(self, message: str) -> "Err": + """Causes this ParseNode to raise an exception if it fails to parse. + This prevents the parser from backtracking, so you should understand + what it does and how the parser works before using it.""" + return Err(self, message) + + def expected(self, expect: str) -> "Err": + """Convenience method for err().""" + return self.err("Expected " + expect) + + def warn(self, message) -> "Warning": + """Causes this ParseNode to emit a warning if it parses successfully.""" + return Warning(self, message) + + +class Err(ParseNode): + """ParseNode that emits a compile error if it fails to parse.""" + + def __init__(self, child, message: str): + self.child = to_parse_node(child) + self.message = message + + def _parse(self, ctx: ParseContext): + if self.child.parse(ctx).failed(): + start_idx = ctx.start + while ctx.tokens[start_idx].type in SKIP_TOKENS: + start_idx += 1 + + start_token = ctx.tokens[start_idx] + end_token = ctx.tokens[ctx.index] + raise CompileError(self.message, start_token.start, end_token.end) + return True + + +class Warning(ParseNode): + """ParseNode that emits a compile warning if it parses successfully.""" + + def __init__(self, child, message: str): + self.child = to_parse_node(child) + self.message = message + + def _parse(self, ctx: ParseContext): + ctx.skip() + start_idx = ctx.index + if self.child.parse(ctx).succeeded(): + start_token = ctx.tokens[start_idx] + end_token = ctx.tokens[ctx.index] + ctx.warnings.append( + CompileWarning(self.message, start_token.start, end_token.end) + ) + return True + else: + return False + + +class Fail(ParseNode): + """ParseNode that emits a compile error if it parses successfully.""" + + def __init__(self, child, message: str): + self.child = to_parse_node(child) + self.message = message + + def _parse(self, ctx: ParseContext): + if self.child.parse(ctx).succeeded(): + start_idx = ctx.start + while ctx.tokens[start_idx].type in SKIP_TOKENS: + start_idx += 1 + + start_token = ctx.tokens[start_idx] + end_token = ctx.tokens[ctx.index] + raise CompileError(self.message, start_token.start, end_token.end) + return True + + +class Group(ParseNode): + """ParseNode that creates a match group.""" + + def __init__(self, ast_type: T.Type[AstNode], child): + self.ast_type = ast_type + self.child = to_parse_node(child) + + def _parse(self, ctx: ParseContext) -> bool: + ctx.skip() + ctx.start_group(self.ast_type) + return self.child.parse(ctx).succeeded() + + +class Sequence(ParseNode): + """ParseNode that attempts to match all of its children in sequence.""" + + def __init__(self, *children): + self.children = [to_parse_node(child) for child in children] + + def _parse(self, ctx) -> bool: + for child in self.children: + if child.parse(ctx).failed(): + return False + return True + + +class Statement(ParseNode): + """ParseNode that attempts to match all of its children in sequence. If any + child raises an error, the error will be logged but parsing will continue.""" + + def __init__(self, *children): + self.children = [to_parse_node(child) for child in children] + + def _parse(self, ctx) -> bool: + for child in self.children: + try: + if child.parse(ctx).failed(): + return False + except CompileError as e: + ctx.errors.append(e) + ctx.set_group_incomplete() + return True + + token = ctx.peek_token() + if str(token) != ";": + ctx.errors.append(CompileError("Expected `;`", token.start, token.end)) + else: + ctx.next_token() + return True + + +class AnyOf(ParseNode): + """ParseNode that attempts to match exactly one of its children. Child + nodes are attempted in order.""" + + def __init__(self, *children): + self.children = children + + @property + def children(self): + return self._children + + @children.setter + def children(self, children): + self._children = [to_parse_node(child) for child in children] + + def _parse(self, ctx): + for child in self.children: + if child.parse(ctx).succeeded(): + return True + return False + + +class Until(ParseNode): + """ParseNode that repeats its child until a delimiting token is found. If + the child does not match, one token is skipped and the match is attempted + again.""" + + def __init__(self, child, delimiter, between_delimiter=None): + self.child = to_parse_node(child) + self.delimiter = to_parse_node(delimiter) + self.between_delimiter = ( + to_parse_node(between_delimiter) if between_delimiter is not None else None + ) + + def _parse(self, ctx: ParseContext): + while not self.delimiter.parse(ctx).succeeded(): + if ctx.is_eof(): + return False + + try: + if not self.child.parse(ctx).matched(): + ctx.skip_unexpected_token() + + if ( + self.between_delimiter is not None + and not self.between_delimiter.parse(ctx).succeeded() + ): + if self.delimiter.parse(ctx).succeeded(): + return True + else: + if ctx.is_eof(): + return False + ctx.skip_unexpected_token() + except CompileError as e: + ctx.errors.append(e) + ctx.next_token() + + return True + + +class ZeroOrMore(ParseNode): + """ParseNode that matches its child any number of times (including zero + times). It cannot fail to parse. If its child raises an exception, one token + will be skipped and parsing will continue.""" + + def __init__(self, child): + self.child = to_parse_node(child) + + def _parse(self, ctx): + while True: + try: + if not self.child.parse(ctx).matched(): + return True + except CompileError as e: + ctx.errors.append(e) + ctx.next_token() + + +class Delimited(ParseNode): + """ParseNode that matches its first child any number of times (including zero + times) with its second child in between and optionally at the end.""" + + def __init__(self, child, delimiter): + self.child = to_parse_node(child) + self.delimiter = to_parse_node(delimiter) + + def _parse(self, ctx): + while self.child.parse(ctx).matched() and self.delimiter.parse(ctx).matched(): + pass + return True + + +class Optional(ParseNode): + """ParseNode that matches its child zero or one times. It cannot fail to + parse.""" + + def __init__(self, child): + self.child = to_parse_node(child) + + def _parse(self, ctx): + self.child.parse(ctx) + return True + + +class Eof(ParseNode): + """ParseNode that matches an EOF token.""" + + def _parse(self, ctx: ParseContext) -> bool: + token = ctx.next_token() + return token.type == TokenType.EOF + + +class Match(ParseNode): + """ParseNode that matches the given literal token.""" + + def __init__(self, op: str): + self.op = op + + def _parse(self, ctx: ParseContext) -> bool: + token = ctx.next_token() + return str(token) == self.op + + def expected(self, expect: T.Optional[str] = None): + """Convenience method for err().""" + if expect is None: + return self.err(f"Expected '{self.op}'") + else: + return self.err("Expected " + expect) + + +class UseIdent(ParseNode): + """ParseNode that matches any identifier and sets it in a key=value pair on + the containing match group.""" + + def __init__(self, key: str): + self.key = key + + def _parse(self, ctx: ParseContext): + token = ctx.next_token() + if token.type != TokenType.IDENT: + return False + + ctx.set_group_val(self.key, str(token), token) + return True + + +class UseNumber(ParseNode): + """ParseNode that matches a number and sets it in a key=value pair on + the containing match group.""" + + def __init__(self, key: str): + self.key = key + + def _parse(self, ctx: ParseContext): + token = ctx.next_token() + if token.type != TokenType.NUMBER: + return False + + number = token.get_number() + if number % 1.0 == 0: + number = int(number) + ctx.set_group_val(self.key, number, token) + return True + + +class UseNumberText(ParseNode): + """ParseNode that matches a number, but sets its *original text* it in a + key=value pair on the containing match group.""" + + def __init__(self, key: str): + self.key = key + + def _parse(self, ctx: ParseContext): + token = ctx.next_token() + if token.type != TokenType.NUMBER: + return False + + ctx.set_group_val(self.key, str(token), token) + return True + + +class UseQuoted(ParseNode): + """ParseNode that matches a quoted string and sets it in a key=value pair + on the containing match group.""" + + def __init__(self, key: str): + self.key = key + + def _parse(self, ctx: ParseContext): + token = ctx.next_token() + if token.type != TokenType.QUOTED: + return False + + string = ( + str(token)[1:-1] + .replace("\\n", "\n") + .replace('\\"', '"') + .replace("\\\\", "\\") + .replace("\\'", "'") + ) + ctx.set_group_val(self.key, string, token) + return True + + +class UseLiteral(ParseNode): + """ParseNode that doesn't match anything, but rather sets a static key=value + pair on the containing group. Useful for, e.g., property and signal flags: + `Sequence(Keyword("swapped"), UseLiteral("swapped", True))`""" + + def __init__(self, key: str, literal: T.Any): + self.key = key + self.literal = literal + + def _parse(self, ctx: ParseContext): + ctx.set_group_val(self.key, self.literal, None) + return True + + +class UseExact(ParseNode): + """Matches the given identifier and sets it as a named token.""" + + def __init__(self, key: str, string: str): + self.key = key + self.string = string + + def _parse(self, ctx: ParseContext): + token = ctx.next_token() + ctx.set_group_val(self.key, self.string, token) + return str(token) == self.string + + +class Keyword(ParseNode): + """Matches the given identifier and sets it as a named token, with the name + being the identifier itself.""" + + def __init__(self, kw: str): + self.kw = kw + self.set_token = True + + def _parse(self, ctx: ParseContext): + token = ctx.next_token() + ctx.set_group_val(self.kw, True, token) + return str(token) == self.kw + + +def to_parse_node(value) -> ParseNode: + if isinstance(value, str): + return Match(value) + elif isinstance(value, list): + return Sequence(*value) + elif isinstance(value, type) and hasattr(value, "grammar"): + return Group(value, getattr(value, "grammar")) + elif isinstance(value, ParseNode): + return value + else: + raise CompilerBugError() diff --git a/.flatpak-builder/cache/objects/fd/588334ee20b49e192beeff12a5b7653e033d5bda12cefe6bc5256837f49f77.dirtree b/.flatpak-builder/cache/objects/fd/588334ee20b49e192beeff12a5b7653e033d5bda12cefe6bc5256837f49f77.dirtree new file mode 100644 index 0000000..ea953aa Binary files /dev/null and b/.flatpak-builder/cache/objects/fd/588334ee20b49e192beeff12a5b7653e033d5bda12cefe6bc5256837f49f77.dirtree differ diff --git a/.flatpak-builder/cache/objects/fd/df64ec165fb32330a1fd2aca6bf098e8a682caf617d9c46637eb651d93fe71.file b/.flatpak-builder/cache/objects/fd/df64ec165fb32330a1fd2aca6bf098e8a682caf617d9c46637eb651d93fe71.file new file mode 100644 index 0000000..9bba1fc --- /dev/null +++ b/.flatpak-builder/cache/objects/fd/df64ec165fb32330a1fd2aca6bf098e8a682caf617d9c46637eb651d93fe71.file @@ -0,0 +1,498 @@ +/* + * Copyright (C) 2008 - 2012 Vivien Malerba + * Copyright (C) 2018 Daniel Espinosa + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GDA_META_STRUCT_H_ +#define __GDA_META_STRUCT_H_ + +#include +#include +#include +#include + +G_BEGIN_DECLS + +#define GDA_TYPE_META_STRUCT (gda_meta_struct_get_type()) +G_DECLARE_DERIVABLE_TYPE(GdaMetaStruct, gda_meta_struct, GDA, META_STRUCT, GObject) + +/* struct for the object's class */ +struct _GdaMetaStructClass +{ + GObjectClass parent_class; + + /*< private >*/ + /* Padding for future expansion */ + void (*_gda_reserved1) (void); + void (*_gda_reserved2) (void); + void (*_gda_reserved3) (void); + void (*_gda_reserved4) (void); +}; + +/* error reporting */ +extern GQuark gda_meta_struct_error_quark (void); +#define GDA_META_STRUCT_ERROR gda_meta_struct_error_quark () + +typedef enum { + GDA_META_STRUCT_UNKNOWN_OBJECT_ERROR, + GDA_META_STRUCT_DUPLICATE_OBJECT_ERROR, + GDA_META_STRUCT_INCOHERENCE_ERROR, + GDA_META_STRUCT_XML_ERROR +} GdaMetaStructError; + +/** + * GdaMetaDbObjectType: + * @GDA_META_DB_UNKNOWN: unknown type + * @GDA_META_DB_TABLE: represents a table + * @GDA_META_DB_VIEW: represents a view + * + * Type of database object which can be handled as a #GdaMetaDbObject + */ +typedef enum { + GDA_META_DB_UNKNOWN, + GDA_META_DB_TABLE, + GDA_META_DB_VIEW +} GdaMetaDbObjectType; + +/* + * Controls which features are computed about database objects + */ +/** + * GdaMetaStructFeature: + * @GDA_META_STRUCT_FEATURE_NONE: database objects only have their own attributes + * @GDA_META_STRUCT_FEATURE_FOREIGN_KEYS: foreign keys are computed for tables + * @GDA_META_STRUCT_FEATURE_VIEW_DEPENDENCIES: for views, the tables they use are also computed + * @GDA_META_STRUCT_FEATURE_ALL: all the features are computed + * + * Controls which features are computed about database objects. + */ +typedef enum { + GDA_META_STRUCT_FEATURE_NONE = 0, + GDA_META_STRUCT_FEATURE_FOREIGN_KEYS = 1 << 0, + GDA_META_STRUCT_FEATURE_VIEW_DEPENDENCIES = 1 << 1, + + GDA_META_STRUCT_FEATURE_ALL = GDA_META_STRUCT_FEATURE_FOREIGN_KEYS | + GDA_META_STRUCT_FEATURE_VIEW_DEPENDENCIES +} GdaMetaStructFeature; + +/** + * GdaMetaSortType: + * @GDA_META_SORT_ALHAPETICAL: sort alphabetically + * @GDA_META_SORT_DEPENDENCIES: sort by dependencies + * + * Types of sorting + */ +typedef enum { + GDA_META_SORT_ALHAPETICAL, + GDA_META_SORT_DEPENDENCIES +} GdaMetaSortType; + +/** + * GdaMetaTable: + * @columns: (element-type Gda.MetaTableColumn): list of #GdaMetaTableColumn structures, one for each column in the table + * @pk_cols_array: index of the columns part of the primary key for the table (WARNING: columns numbering + * here start at 0) + * @pk_cols_nb: size of the @pk_cols_array array + * @reverse_fk_list: (element-type Gda.MetaTableForeignKey): list of #GdaMetaTableForeignKey where the referenced table is this table + * @fk_list: (element-type Gda.MetaTableForeignKey): list of #GdaMetaTableForeignKey for this table + * + * This structure specifies a #GdaMetaDbObject to represent a table's specific attributes, + * its contents must not be modified. + * + * Note that in some cases, the columns cannot be determined for views, and in this case the + * @columns will be %NULL (this can be the case for example with SQLite where a view + * uses a function which is not natively provided by SQLite. + */ +typedef struct { + /*< public >*/ + GSList *columns; + + /* PK fields index */ + gint *pk_cols_array; + gint pk_cols_nb; + + /* Foreign keys */ + GSList *reverse_fk_list; /* list of GdaMetaTableForeignKey where @depend_on == this GdaMetaDbObject */ + GSList *fk_list; /* list of GdaMetaTableForeignKey where @meta_table == this GdaMetaDbObject */ + + /*< private >*/ + /* Padding for future expansion */ + gpointer _gda_reserved1; + gpointer _gda_reserved2; + gpointer _gda_reserved3; + gpointer _gda_reserved4; +} GdaMetaTable; + +/** + * GdaMetaView: + * @table: a view is also a table as it has columns + * @view_def: views' definition + * @is_updatable: tells if the view's contents can be updated + * + * This structure specifies a #GdaMetaDbObject to represent a view's specific attributes, + * its contents must not be modified. + */ +typedef struct { + /*< public >*/ + GdaMetaTable table; + gchar *view_def; + gboolean is_updatable; + + /*< private >*/ + /* Padding for future expansion */ + gpointer _gda_reserved1; + gpointer _gda_reserved2; + gpointer _gda_reserved3; + gpointer _gda_reserved4; +} GdaMetaView; + +/** + * GdaMetaDbObject: + * @extra: union for the actual object's contents, to be able to cast it using GDA_META_TABLE(), GDA_META_VIEW() + * @obj_type: the type of object (table, view) + * @outdated: set to %TRUE if the information in this #GdaMetaDbObject may be outdated because the #GdaMetaStore has been updated + * @obj_catalog: the catalog the object is in + * @obj_schema: the schema the object is in + * @obj_name: the object's name + * @obj_short_name: the shortest way to name the object + * @obj_full_name: the full name of the object (in the <schema>.<nameagt; notation + * @obj_owner: object's owner + * @depend_list: (element-type Gda.MetaDbObject): list of #GdaMetaDbObject pointers on which this object depends (through foreign keys + * or tables used for views) + * + * Struture to hold information about each database object (tables, views, ...), + * its contents must not be modified. + * + * Note: @obj_catalog, @obj_schema, @obj_name, @obj_short_name and @obj_full_name respect the + * SQL identifiers convention used in + * #GdaMetaStore objects. Before using these SQL identifiers, you should check the + * gda_sql_identifier_quote() to know if is it is necessary to surround by double quotes + * before using in an SQL statement. + */ +typedef struct { + /*< public >*/ + union { + GdaMetaTable meta_table; + GdaMetaView meta_view; + } extra; + GdaMetaDbObjectType obj_type; + gboolean outdated; + gchar *obj_catalog; + gchar *obj_schema; + gchar *obj_name; + gchar *obj_short_name; + gchar *obj_full_name; + gchar *obj_owner; + + GSList *depend_list; + + /*< private >*/ + /* Padding for future expansion */ + gpointer _gda_reserved1; + gpointer _gda_reserved2; + gpointer _gda_reserved3; + gpointer _gda_reserved4; +} GdaMetaDbObject; + +/** + * GDA_META_DB_OBJECT: + * @dbo: a pointer + * + * Casts @dbo to a #GdaMetaDbObject, no check is made on the validity of @dbo + * + * Returns: a pointer to a #GdaMetaDbObject + */ +#define GDA_META_DB_OBJECT(dbo) ((GdaMetaDbObject*)(dbo)) + +/** + * GDA_META_TABLE: + * @dbo: a pointer + * + * Casts @dbo to a #GdaMetaTable, no check is made on the validity of @dbo + * + * Returns: a pointer to a #GdaMetaTable + */ +#define GDA_META_TABLE(dbobj) (&((dbobj)->extra.meta_table)) + +/** + * GDA_META_VIEW: + * @dbo: a pointer + * + * Casts @dbo to a #GdaMetaView, no check is made on the validity of @dbo + * + * Returns: a pointer to a #GdaMetaView + */ +#define GDA_META_VIEW(dbobj) (&((dbobj)->extra.meta_view)) + +/** + * GdaMetaTableColumn: + * @column_name: the column's name + * @column_type: the column's DBMS's type + * @gtype: the detected column's #GType + * @pkey: tells if the column is part of a primary key + * @nullok: tells if the column can be %NULL + * @default_value: (nullable): the column's default value, represented as a valid SQL value (surrounded by simple quotes for strings, ...), or %NULL if column has no default value + * + * This structure represents a table of view's column, its contents must not be modified. + */ +typedef struct { + /*< public >*/ + gchar *column_name; + gchar *column_type; + GType gtype; + gboolean pkey; + gboolean nullok; + gchar *default_value; + gboolean auto_incement; + gchar *desc; + + /*< private >*/ + /* Padding for future expansion */ + gpointer _gda_reserved1; + gpointer _gda_reserved2; + gpointer _gda_reserved3; + gpointer _gda_reserved4; +} GdaMetaTableColumn; + +/** + * GDA_META_TABLE_COLUMN: + * @col: a pointer + * + * Casts @col to a #GdaMetaTableColumn, no check is made + * + * Returns: @col, casted to a #GdaMetaTableColumn + */ +#define GDA_META_TABLE_COLUMN(col) ((GdaMetaTableColumn*)(col)) + +/** + * GdaMetaForeignKeyPolicy: + * @GDA_META_FOREIGN_KEY_UNKNOWN: unspecified policy + * @GDA_META_FOREIGN_KEY_NONE: not enforced policy + * @GDA_META_FOREIGN_KEY_NO_ACTION: return an error, no action taken + * @GDA_META_FOREIGN_KEY_RESTRICT: same as @GDA_META_FOREIGN_KEY_NO_ACTION, not deferrable + * @GDA_META_FOREIGN_KEY_CASCADE: policy is to delete any rows referencing the deleted row, or update the value of the referencing column to the new value of the referenced column, respectively + * @GDA_META_FOREIGN_KEY_SET_NULL: policy is to set the referencing column to NULL + * @GDA_META_FOREIGN_KEY_SET_DEFAULT: policy is to set the referencing column to its default value + * + * Defines the filtering policy of a foreign key when invoked on an UPDATE + * or DELETE operation. + */ +typedef enum { + GDA_META_FOREIGN_KEY_UNKNOWN, + GDA_META_FOREIGN_KEY_NONE, + GDA_META_FOREIGN_KEY_NO_ACTION, + GDA_META_FOREIGN_KEY_RESTRICT, + GDA_META_FOREIGN_KEY_CASCADE, + GDA_META_FOREIGN_KEY_SET_NULL, + GDA_META_FOREIGN_KEY_SET_DEFAULT +} GdaMetaForeignKeyPolicy; + +/** + * GdaMetaTableForeignKey: + * @meta_table: the #GdaMetaDbObject for which this structure represents a foreign key + * @depend_on: the #GdaMetaDbObject which is referenced by the foreign key + * @cols_nb: the size of the @fk_cols_array, @fk_names_array, @ref_pk_cols_array and @ref_pk_names_array arrays + * @fk_cols_array: the columns' indexes in @meta_table which participate in the constraint (WARNING: columns numbering + * here start at 1) + * @fk_names_array: the columns' names in @meta_table which participate in the constraint + * @ref_pk_cols_array: the columns' indexes in @depend_on which participate in the constraint (WARNING: columns numbering + * here start at 1) + * @ref_pk_names_array: the columns' names in @depend_on which participate in the constraint + * + * This structure represents a foreign key constraint, its contents must not be modified. + */ +typedef struct { + /*< public >*/ + GdaMetaDbObject *meta_table; + GdaMetaDbObject *depend_on; + + gint cols_nb; + gint *fk_cols_array; /* FK fields index */ + gchar **fk_names_array; /* FK fields names */ + gint *ref_pk_cols_array; /* Ref PK fields index */ + gchar **ref_pk_names_array; /* Ref PK fields names */ + + /*< private >*/ + GdaMetaForeignKeyPolicy on_update_policy; /* pointer containing the GdaMetaForeignKeyPolicy integer + * to keep ABI from 4.0, use GINT_TO_POINTER and + * GPOINTER_TO_INT */ + GdaMetaForeignKeyPolicy on_delete_policy; /* pointer containing the GdaMetaForeignKeyPolicy integer + * to keep ABI from 4.0, use GINT_TO_POINTER and + * GPOINTER_TO_INT */ + gboolean declared; /* pointer to a boolean to keep ABI from 4.0. + * Any non NULL if FK has been declared in meta data */ + + /*< public >*/ + gchar *fk_name; + + /*< private >*/ + /* Padding for future expansion */ + gpointer _gda_reserved1; + gpointer _gda_reserved2; + gpointer _gda_reserved3; + gpointer _gda_reserved4; +} GdaMetaTableForeignKey; +/** + * GDA_META_TABLE_FOREIGN_KEY: + * @fk: a pointer + * + * Casts @fk to a #GdaMetaTableForeignKey (no check is actuelly being done on @fk's validity) + * + * Returns: @col, casted to a #GdaMetaTableForeignKey + */ +#define GDA_META_TABLE_FOREIGN_KEY(fk) ((GdaMetaTableForeignKey*)(fk)) + +/** + * GDA_META_TABLE_FOREIGN_KEY_ON_UPDATE_POLICY: + * @fk: a pointer to a #GdaMetaTableForeignKey + * + * Tells the actual policy implemented by @fk when used in the context of an UPDATE. + * + * Returns: the policy as a #GdaMetaForeignKeyPolicy + */ +#define GDA_META_TABLE_FOREIGN_KEY_ON_UPDATE_POLICY(fk) (((GdaMetaTableForeignKey*)(fk))->on_update_policy) + +/** + * GDA_META_TABLE_FOREIGN_KEY_ON_DELETE_POLICY: + * @fk: a pointer to a #GdaMetaTableForeignKey + * + * Tells the actual policy implemented by @fk when used in the context of a DELETE. + * + * Returns: the policy as a #GdaMetaForeignKeyPolicy + */ +#define GDA_META_TABLE_FOREIGN_KEY_ON_DELETE_POLICY(fk) (((GdaMetaTableForeignKey*)(fk))->on_delete_policy) + +/** + * GDA_META_TABLE_FOREIGN_KEY_IS_DECLARED: + * @fk: a pointer to a #GdaMetaTableForeignKey + * + * Tells if @fk is an actual foreign key defined in the database's schema, or if it is an indication which + * has been added to help Libgda understand the database schema. + * + * Returns: %TRUE if @fk has been declared in the database's meta data and %FALSE if @fk is an actual foreign key defined in the database's schema + */ +#define GDA_META_TABLE_FOREIGN_KEY_IS_DECLARED(fk) (((GdaMetaTableForeignKey*)(fk))->declared) + +/** + * SECTION:gda-meta-struct + * @short_description: In memory representation of some database objects + * @title: GdaMetaStruct + * @stability: Stable + * @see_also: #GdaMetaStore + * + * The #GdaMetaStruct object reads data from a #GdaMetaStore object and + * creates an easy to use in memory representation for some database objects. For example one can easily + * analyze the columns of a table (or its foreign keys) using a #GdaMetaStruct. + * + * When created, the new #GdaMetaStruct object is empty (it does not have any information about any database object). + * Information about database objects is computed upon request using the gda_meta_struct_complement() method. Information + * about individual database objects is represented by #GdaMetaDbObject structures, which can be obtained using + * gda_meta_struct_get_db_object() or gda_meta_struct_get_all_db_objects(). + * + * Note that the #GdaMetaDbObject structures may change or may be removed or replaced by others, so it not + * advised to keep pointers to these structures: pointers to these structures should be considered valid + * as long as gda_meta_struct_complement() and other similar functions have not been called. + * + * In the following code sample, one prints the columns names and types of a table: + * + *GdaMetaStruct *mstruct; + *GdaMetaDbObject *dbo; + *GValue *catalog, *schema, *name; + * + * // Define name (and optionnally catalog and schema) + *[...] + * + *mstruct = gda_meta_struct_new (); + *gda_meta_struct_complement (mstruct, store, GDA_META_DB_TABLE, catalog, schema, name, NULL); + *dbo = gda_meta_struct_get_db_object (mstruct, catalog, schema, name); + *if (!dbo) + * g_print ("Table not found\n"); + *else { + * GSList *list; + * for (list = GDA_META_TABLE (dbo)->columns; list; list = list->next) { + * GdaMetaTableColumn *tcol = GDA_META_TABLE_COLUMN (list->data); + * g_print ("COLUMN: %s (%s)\n", tcol->column_name, tcol->column_type); + * } + *} + *gda_meta_struct_free (mstruct); + * + * If now the database object type is not known, one can use the following code: + * + *GdaMetaStruct *mstruct; + *GdaMetaDbObject *dbo; + *GValue *catalog, *schema, *name; + * + * // Define name (and optionnally catalog and schema) + *[...] + * + *mstruct = gda_meta_struct_new (); + *gda_meta_struct_complement (mstruct, store, GDA_META_DB_UNKNOWN, catalog, schema, name, NULL); + *dbo = gda_meta_struct_get_db_object (mstruct, catalog, schema, name); + *if (!dbo) + * g_print ("Object not found\n"); + *else { + * if ((dbo->obj_type == GDA_META_DB_TABLE) || (dbo->obj_type == GDA_META_DB_VIEW)) { + * if (dbo->obj_type == GDA_META_DB_TABLE) + * g_print ("Is a table\n"); + * else if (dbo->obj_type == GDA_META_DB_VIEW) { + * g_print ("Is a view, definition is:\n"); + * g_print ("%s\n", GDA_META_VIEW (dbo)->view_def); + * } + * + * GSList *list; + * for (list = GDA_META_TABLE (dbo)->columns; list; list = list->next) { + * GdaMetaTableColumn *tcol = GDA_META_TABLE_COLUMN (list->data); + * g_print ("COLUMN: %s (%s)\n", tcol->column_name, tcol->column_type); + * } + * } + * else + * g_print ("Not a table or a view\n"); + *} + *gda_meta_struct_free (mstruct); + * + */ + +gboolean gda_meta_struct_load_from_xml_file (GdaMetaStruct *mstruct, const gchar *catalog, + const gchar *schema, + const gchar *xml_spec_file, GError **error); +GdaMetaDbObject *gda_meta_struct_complement (GdaMetaStruct *mstruct, GdaMetaDbObjectType type, + const GValue *catalog, const GValue *schema, const GValue *name, + GError **error); +gboolean gda_meta_struct_complement_schema (GdaMetaStruct *mstruct, + const GValue *catalog, const GValue *schema, GError **error); +gboolean gda_meta_struct_complement_default (GdaMetaStruct *mstruct, GError **error); +gboolean gda_meta_struct_complement_all (GdaMetaStruct *mstruct, GError **error); +gboolean gda_meta_struct_complement_depend (GdaMetaStruct *mstruct, GdaMetaDbObject *dbo, + GError **error); + +gboolean gda_meta_struct_sort_db_objects (GdaMetaStruct *mstruct, GdaMetaSortType sort_type, GError **error); +GSList *gda_meta_struct_get_all_db_objects (GdaMetaStruct *mstruct); +GdaMetaDbObject *gda_meta_struct_get_db_object (GdaMetaStruct *mstruct, + const GValue *catalog, const GValue *schema, const GValue *name); +GdaMetaTableColumn *gda_meta_struct_get_table_column (GdaMetaStruct *mstruct, GdaMetaTable *table, + const GValue *col_name); + +typedef enum { + GDA_META_GRAPH_COLUMNS = 1 << 0 +} GdaMetaGraphInfo; + +gchar *gda_meta_struct_dump_as_graph (GdaMetaStruct *mstruct, GdaMetaGraphInfo info, GError **error); + +G_END_DECLS + +#endif diff --git a/.flatpak-builder/cache/objects/fe/77fd5760829fc1f018f2171b05abe4a4c664072c84f4d751a550a59a0a5d70.dirtree b/.flatpak-builder/cache/objects/fe/77fd5760829fc1f018f2171b05abe4a4c664072c84f4d751a550a59a0a5d70.dirtree new file mode 100644 index 0000000..4d666c2 Binary files /dev/null and b/.flatpak-builder/cache/objects/fe/77fd5760829fc1f018f2171b05abe4a4c664072c84f4d751a550a59a0a5d70.dirtree differ diff --git a/.flatpak-builder/cache/objects/ff/5c4cd3e48e7d65497035d1779c4714900cd9ab664ac796a0eef055ba9bbb07.dirtree b/.flatpak-builder/cache/objects/ff/5c4cd3e48e7d65497035d1779c4714900cd9ab664ac796a0eef055ba9bbb07.dirtree new file mode 100644 index 0000000..2eb1ecc Binary files /dev/null and b/.flatpak-builder/cache/objects/ff/5c4cd3e48e7d65497035d1779c4714900cd9ab664ac796a0eef055ba9bbb07.dirtree differ diff --git a/.flatpak-builder/cache/objects/ff/74b249e0067f7b1f755479aecdb66a7d63d16b1bca9ae4e28270e64330a7ab.dirtree b/.flatpak-builder/cache/objects/ff/74b249e0067f7b1f755479aecdb66a7d63d16b1bca9ae4e28270e64330a7ab.dirtree new file mode 100644 index 0000000..215685d Binary files /dev/null and b/.flatpak-builder/cache/objects/ff/74b249e0067f7b1f755479aecdb66a7d63d16b1bca9ae4e28270e64330a7ab.dirtree differ diff --git a/.flatpak-builder/cache/objects/ff/9260f0565e9e290c98f84c899338359e6e2d3cb357be4c4429f741cb66aefc.file b/.flatpak-builder/cache/objects/ff/9260f0565e9e290c98f84c899338359e6e2d3cb357be4c4429f741cb66aefc.file new file mode 100644 index 0000000..4c32ce1 Binary files /dev/null and b/.flatpak-builder/cache/objects/ff/9260f0565e9e290c98f84c899338359e6e2d3cb357be4c4429f741cb66aefc.file differ diff --git a/.flatpak-builder/cache/objects/ff/99feba6ef0e72b82e3590d829eabe2f0816332bc844a8e8a875f3b09d66b45.file b/.flatpak-builder/cache/objects/ff/99feba6ef0e72b82e3590d829eabe2f0816332bc844a8e8a875f3b09d66b45.file new file mode 100644 index 0000000..d24f00c --- /dev/null +++ b/.flatpak-builder/cache/objects/ff/99feba6ef0e72b82e3590d829eabe2f0816332bc844a8e8a875f3b09d66b45.file @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2000 Reinhard Müller + * Copyright (C) 2000 - 2004 Rodrigo Moya + * Copyright (C) 2001 Carlos Perelló Marín + * Copyright (C) 2001 - 2014 Vivien Malerba + * Copyright (C) 2002 Andrew Hill + * Copyright (C) 2002 - 2003 Gonzalo Paniagua Javier + * Copyright (C) 2003 - 2006 Murray Cumming + * Copyright (C) 2004 Szalai Ferenc + * Copyright (C) 2005 Bas Driessen + * Copyright (C) 2005 Álvaro Peña + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __LIBGDA_H__ +#define __LIBGDA_H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include + +G_BEGIN_DECLS + +/** + * SECTION:libgda + * @short_description: Library initialization and information + * @title: Library initialization + * @stability: Stable + * @see_also: + */ + +void gda_init (void); +void gda_locale_changed (void); + +G_END_DECLS + +#endif + + + + + diff --git a/.flatpak-builder/cache/objects/ff/dfd5cbb6b61d5ac6211c079decdc50017130779f9c072cfdfdce3cbfe795ac.file b/.flatpak-builder/cache/objects/ff/dfd5cbb6b61d5ac6211c079decdc50017130779f9c072cfdfdce3cbfe795ac.file new file mode 100644 index 0000000..748bf81 --- /dev/null +++ b/.flatpak-builder/cache/objects/ff/dfd5cbb6b61d5ac6211c079decdc50017130779f9c072cfdfdce3cbfe795ac.file @@ -0,0 +1,168 @@ +/* + * Copyright (C) 2006 Rodrigo Moya + * Copyright (C) 2006 - 2013 Vivien Malerba + * Copyright (C) 2007 Murray Cumming + * Copyright (C) 2009 Bas Driessen + * Copyright (C) 2010 David King + * Copyright (C) 2010 Jonh Wendell + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "gda-handler-boolean.h" +#include +#include + +struct _GdaHandlerBoolean +{ + GObject parent_instance; +}; + +static void data_handler_iface_init (GdaDataHandlerInterface *iface); + +G_DEFINE_TYPE_EXTENDED (GdaHandlerBoolean, gda_handler_boolean, G_TYPE_OBJECT, 0, + G_IMPLEMENT_INTERFACE (GDA_TYPE_DATA_HANDLER, data_handler_iface_init)) + +/** + * gda_handler_boolean_new: + * + * Creates a data handler for booleans + * + * Returns: (type GdaHandlerBoolean) (transfer full): the new object + */ +GdaDataHandler * +gda_handler_boolean_new (void) +{ + GObject *obj; + + obj = g_object_new (GDA_TYPE_HANDLER_BOOLEAN, NULL); + + return (GdaDataHandler *) obj; +} + +static gchar * +gda_handler_boolean_get_sql_from_value (G_GNUC_UNUSED GdaDataHandler *iface, const GValue *value) +{ + g_assert (value); + + gchar *retval; + if (g_value_get_boolean (value)) + retval = g_strdup ("TRUE"); + else + retval = g_strdup ("FALSE"); + + return retval; +} + +static gchar * +gda_handler_boolean_get_str_from_value (G_GNUC_UNUSED GdaDataHandler *iface, const GValue *value) +{ + g_assert (value); + return gda_value_stringify ((GValue *) value); +} + +static GValue * +gda_handler_boolean_get_value_from_sql (G_GNUC_UNUSED GdaDataHandler *iface, const gchar *sql, G_GNUC_UNUSED GType type) +{ + g_assert (sql); + + GValue *value; + value = g_value_init (g_new0 (GValue, 1), G_TYPE_BOOLEAN); + if ((*sql == 't') || (*sql == 'T')) + g_value_set_boolean (value, TRUE); + else + g_value_set_boolean (value, FALSE); + + return value; +} + +static GValue * +gda_handler_boolean_get_value_from_str (G_GNUC_UNUSED GdaDataHandler *iface, const gchar *str, G_GNUC_UNUSED GType type) +{ + g_assert (str); + + GValue *value; + gchar *lcstr; + value = g_value_init (g_new0 (GValue, 1), G_TYPE_BOOLEAN); + lcstr = g_utf8_strdown (str, -1); + if (!strcmp (lcstr, "true") || (*lcstr == 't')) + g_value_set_boolean (value, TRUE); + g_free (lcstr); + + return value; +} + + +static GValue * +gda_handler_boolean_get_sane_init_value (G_GNUC_UNUSED GdaDataHandler *iface, G_GNUC_UNUSED GType type) +{ + GValue *value; + + value = g_value_init (g_new0 (GValue, 1), G_TYPE_BOOLEAN); + g_value_set_boolean (value, FALSE); + + return value; +} + +static gboolean +gda_handler_boolean_accepts_g_type (G_GNUC_UNUSED GdaDataHandler *iface, GType type) +{ + g_assert (iface); + return type == G_TYPE_BOOLEAN ? TRUE : FALSE; +} + +static const gchar * +gda_handler_boolean_get_descr (GdaDataHandler *iface) +{ + g_return_val_if_fail (GDA_IS_HANDLER_BOOLEAN (iface), NULL); + return g_object_get_data (G_OBJECT (iface), "descr"); +} + +static void +gda_handler_boolean_init (GdaHandlerBoolean *hdl) +{ + g_object_set_data (G_OBJECT (hdl), "name", "InternalBoolean"); + g_object_set_data (G_OBJECT (hdl), "descr", _("Boolean representation")); +} + +static void +gda_handler_boolean_dispose (GObject *object) +{ + g_return_if_fail (GDA_IS_HANDLER_BOOLEAN (object)); + + /* for the parent class */ + G_OBJECT_CLASS (gda_handler_boolean_parent_class)->dispose (object); +} + +static void +data_handler_iface_init (GdaDataHandlerInterface *iface) +{ + iface->get_sql_from_value = gda_handler_boolean_get_sql_from_value; + iface->get_str_from_value = gda_handler_boolean_get_str_from_value; + iface->get_value_from_sql = gda_handler_boolean_get_value_from_sql; + iface->get_value_from_str = gda_handler_boolean_get_value_from_str; + iface->get_sane_init_value = gda_handler_boolean_get_sane_init_value; + iface->accepts_g_type = gda_handler_boolean_accepts_g_type; + iface->get_descr = gda_handler_boolean_get_descr; +} + +static void +gda_handler_boolean_class_init (GdaHandlerBooleanClass * class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (class); + + object_class->dispose = gda_handler_boolean_dispose; +} diff --git a/.flatpak-builder/cache/objects/ff/f35396b819a568def0db7acc11d3a75e2c5b8221077fa41697ca4f4d5888de.dirtree b/.flatpak-builder/cache/objects/ff/f35396b819a568def0db7acc11d3a75e2c5b8221077fa41697ca4f4d5888de.dirtree new file mode 100644 index 0000000..1859395 Binary files /dev/null and b/.flatpak-builder/cache/objects/ff/f35396b819a568def0db7acc11d3a75e2c5b8221077fa41697ca4f4d5888de.dirtree differ diff --git a/.flatpak-builder/cache/refs/heads/x86_64-io.gitlab.idevecore.Pomodoro.json/build-blueprint b/.flatpak-builder/cache/refs/heads/x86_64-io.gitlab.idevecore.Pomodoro.json/build-blueprint new file mode 100644 index 0000000..815759a --- /dev/null +++ b/.flatpak-builder/cache/refs/heads/x86_64-io.gitlab.idevecore.Pomodoro.json/build-blueprint @@ -0,0 +1 @@ +e87e27305ac87b75f6843bb558d2c2673e1c4e36c2bfa633d0624623f3c6b57d diff --git a/.flatpak-builder/cache/refs/heads/x86_64-io.gitlab.idevecore.Pomodoro.json/build-gsound b/.flatpak-builder/cache/refs/heads/x86_64-io.gitlab.idevecore.Pomodoro.json/build-gsound index f520abc..3e586f4 100644 --- a/.flatpak-builder/cache/refs/heads/x86_64-io.gitlab.idevecore.Pomodoro.json/build-gsound +++ b/.flatpak-builder/cache/refs/heads/x86_64-io.gitlab.idevecore.Pomodoro.json/build-gsound @@ -1 +1,5 @@ +<<<<<<< HEAD 293afffede885b824178c7f81257e39eacfbb9030a4014fc2bc6dc6a20b1a21b +======= +e45c18d345d29ccf740fcde2e689758a1160eff3ad47c1972d935cbf03229275 +>>>>>>> new-pomodoro diff --git a/.flatpak-builder/cache/refs/heads/x86_64-io.gitlab.idevecore.Pomodoro.json/build-intltool b/.flatpak-builder/cache/refs/heads/x86_64-io.gitlab.idevecore.Pomodoro.json/build-intltool index 2d88b08..56ad7a5 100644 --- a/.flatpak-builder/cache/refs/heads/x86_64-io.gitlab.idevecore.Pomodoro.json/build-intltool +++ b/.flatpak-builder/cache/refs/heads/x86_64-io.gitlab.idevecore.Pomodoro.json/build-intltool @@ -1 +1,5 @@ +<<<<<<< HEAD 8dc2ea87da10be2dd41366d9b6aadfb728d7606e5a70c4b4d7f074a72e3af816 +======= +aa52b6198e5f93921739e93780c8389dc326554536d65b0275be8c6ff6664e53 +>>>>>>> new-pomodoro diff --git a/.flatpak-builder/cache/refs/heads/x86_64-io.gitlab.idevecore.Pomodoro.json/build-libcanberra b/.flatpak-builder/cache/refs/heads/x86_64-io.gitlab.idevecore.Pomodoro.json/build-libcanberra index e7a8400..38d5b67 100644 --- a/.flatpak-builder/cache/refs/heads/x86_64-io.gitlab.idevecore.Pomodoro.json/build-libcanberra +++ b/.flatpak-builder/cache/refs/heads/x86_64-io.gitlab.idevecore.Pomodoro.json/build-libcanberra @@ -1 +1,5 @@ +<<<<<<< HEAD 81022337c414dba4bc79b78783f7177655a60870a08c5ff1721369195e698620 +======= +90c7e6d465f437764c0a146b44f7e53a4eb9d4e35445d15cdb8d9cafa63b45e5 +>>>>>>> new-pomodoro diff --git a/.flatpak-builder/cache/refs/heads/x86_64-io.gitlab.idevecore.Pomodoro.json/build-sound-theme-freedesktop b/.flatpak-builder/cache/refs/heads/x86_64-io.gitlab.idevecore.Pomodoro.json/build-sound-theme-freedesktop index d4d92e1..fd30e78 100644 --- a/.flatpak-builder/cache/refs/heads/x86_64-io.gitlab.idevecore.Pomodoro.json/build-sound-theme-freedesktop +++ b/.flatpak-builder/cache/refs/heads/x86_64-io.gitlab.idevecore.Pomodoro.json/build-sound-theme-freedesktop @@ -1 +1,5 @@ +<<<<<<< HEAD 769ca8281dbb9e48b7f15ae3104d7e038fa4fc669ddaa9472a73899848d98e41 +======= +c72bfc81fba4f645e6d39339a685ff991419c1130f5b52fa2d7930d3d79e848a +>>>>>>> new-pomodoro diff --git a/.flatpak-builder/cache/refs/heads/x86_64-io.gitlab.idevecore.Pomodoro.json/init b/.flatpak-builder/cache/refs/heads/x86_64-io.gitlab.idevecore.Pomodoro.json/init index 9230116..7d4db90 100644 --- a/.flatpak-builder/cache/refs/heads/x86_64-io.gitlab.idevecore.Pomodoro.json/init +++ b/.flatpak-builder/cache/refs/heads/x86_64-io.gitlab.idevecore.Pomodoro.json/init @@ -1 +1,5 @@ +<<<<<<< HEAD 9ddb0aed68aa31e9d26078c5c621c7a58ac73e46d31516f8e362e101983ffffe +======= +ce47a8b8df566ef0081f3ab5820de7343f68d35d386e938dfff2a52df12b2cf8 +>>>>>>> new-pomodoro diff --git a/.flatpak-builder/cache/refs/heads/x86_64-io.gitlab.idevecore.PomodoroDevel.json/build-blueprint b/.flatpak-builder/cache/refs/heads/x86_64-io.gitlab.idevecore.PomodoroDevel.json/build-blueprint new file mode 100644 index 0000000..351943e --- /dev/null +++ b/.flatpak-builder/cache/refs/heads/x86_64-io.gitlab.idevecore.PomodoroDevel.json/build-blueprint @@ -0,0 +1 @@ +765359d4da48ccf73c19559e42cfa1e50e0458bfd0c02ef07ff855811ffeb7ed diff --git a/.flatpak-builder/cache/refs/heads/x86_64-io.gitlab.idevecore.PomodoroDevel.json/build-gsound b/.flatpak-builder/cache/refs/heads/x86_64-io.gitlab.idevecore.PomodoroDevel.json/build-gsound new file mode 100644 index 0000000..3201cf7 --- /dev/null +++ b/.flatpak-builder/cache/refs/heads/x86_64-io.gitlab.idevecore.PomodoroDevel.json/build-gsound @@ -0,0 +1 @@ +f0a7fa4cbe2e1b13ba12785c1f6b980e2bfc35afcccd1b9786dc59232db8f23d diff --git a/.flatpak-builder/cache/refs/heads/x86_64-io.gitlab.idevecore.PomodoroDevel.json/build-intltool b/.flatpak-builder/cache/refs/heads/x86_64-io.gitlab.idevecore.PomodoroDevel.json/build-intltool new file mode 100644 index 0000000..9385852 --- /dev/null +++ b/.flatpak-builder/cache/refs/heads/x86_64-io.gitlab.idevecore.PomodoroDevel.json/build-intltool @@ -0,0 +1 @@ +6110c59899e01c7fad15261591a6b95b8fc01ee0c672ddf71455afcff2a9b35d diff --git a/.flatpak-builder/cache/refs/heads/x86_64-io.gitlab.idevecore.PomodoroDevel.json/build-intltool-2 b/.flatpak-builder/cache/refs/heads/x86_64-io.gitlab.idevecore.PomodoroDevel.json/build-intltool-2 new file mode 100644 index 0000000..590fa36 --- /dev/null +++ b/.flatpak-builder/cache/refs/heads/x86_64-io.gitlab.idevecore.PomodoroDevel.json/build-intltool-2 @@ -0,0 +1 @@ +6f8c81d836bf4c5911a16383efc75b3c5a9c291c98a11061e51fa2a91de24f09 diff --git a/.flatpak-builder/cache/refs/heads/x86_64-io.gitlab.idevecore.PomodoroDevel.json/build-libcanberra b/.flatpak-builder/cache/refs/heads/x86_64-io.gitlab.idevecore.PomodoroDevel.json/build-libcanberra new file mode 100644 index 0000000..4e5b8f1 --- /dev/null +++ b/.flatpak-builder/cache/refs/heads/x86_64-io.gitlab.idevecore.PomodoroDevel.json/build-libcanberra @@ -0,0 +1 @@ +a0b45af78d2bca3a416234aa2e962c284e2b50849c352301cc9c0b16834d9b7c diff --git a/.flatpak-builder/cache/refs/heads/x86_64-io.gitlab.idevecore.PomodoroDevel.json/build-libgda b/.flatpak-builder/cache/refs/heads/x86_64-io.gitlab.idevecore.PomodoroDevel.json/build-libgda new file mode 100644 index 0000000..90a451c --- /dev/null +++ b/.flatpak-builder/cache/refs/heads/x86_64-io.gitlab.idevecore.PomodoroDevel.json/build-libgda @@ -0,0 +1 @@ +525ab9bcfaca65f75c7d58dede754178496c2efa026bac44be1c39a62e392c75 diff --git a/.flatpak-builder/cache/refs/heads/x86_64-io.gitlab.idevecore.PomodoroDevel.json/build-sound-theme-freedesktop b/.flatpak-builder/cache/refs/heads/x86_64-io.gitlab.idevecore.PomodoroDevel.json/build-sound-theme-freedesktop new file mode 100644 index 0000000..c4c0134 --- /dev/null +++ b/.flatpak-builder/cache/refs/heads/x86_64-io.gitlab.idevecore.PomodoroDevel.json/build-sound-theme-freedesktop @@ -0,0 +1 @@ +590fcef45719fda14e5aaab578cd89901890aa44a6e11d5f9fd7ab9ed03a2d9e diff --git a/.flatpak-builder/cache/refs/heads/x86_64-io.gitlab.idevecore.PomodoroDevel.json/init b/.flatpak-builder/cache/refs/heads/x86_64-io.gitlab.idevecore.PomodoroDevel.json/init new file mode 100644 index 0000000..4f90c7f --- /dev/null +++ b/.flatpak-builder/cache/refs/heads/x86_64-io.gitlab.idevecore.PomodoroDevel.json/init @@ -0,0 +1 @@ +ef085dd09fc9201b53d2d1fc8b2fabad6c5b4611a904e12b235064d9bc27093c diff --git a/.flatpak-builder/ccache/0/0/46iaphr1s4fvj0gsh2cmncr95dc9k1uR b/.flatpak-builder/ccache/0/0/46iaphr1s4fvj0gsh2cmncr95dc9k1uR new file mode 100644 index 0000000..d485e26 Binary files /dev/null and b/.flatpak-builder/ccache/0/0/46iaphr1s4fvj0gsh2cmncr95dc9k1uR differ diff --git a/.flatpak-builder/ccache/0/0/a8k7a42698467901tfski41m520hjreM b/.flatpak-builder/ccache/0/0/a8k7a42698467901tfski41m520hjreM new file mode 100644 index 0000000..4d67e34 Binary files /dev/null and b/.flatpak-builder/ccache/0/0/a8k7a42698467901tfski41m520hjreM differ diff --git a/.flatpak-builder/ccache/0/0/stats b/.flatpak-builder/ccache/0/0/stats new file mode 100644 index 0000000..43dfd5f --- /dev/null +++ b/.flatpak-builder/ccache/0/0/stats @@ -0,0 +1,82 @@ +0 +0 +0 +0 +0 +0 +0 +0 +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +2 +0 +0 +3 +0 +0 +0 +0 +0 +2 +0 +0 +0 +0 +1 +0 +7 +1 +0 +0 +0 +0 +0 +0 +1 +4 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 diff --git a/.flatpak-builder/ccache/0/1/stats b/.flatpak-builder/ccache/0/1/stats index 94504b0..a9eefc1 100644 --- a/.flatpak-builder/ccache/0/1/stats +++ b/.flatpak-builder/ccache/0/1/stats @@ -2,7 +2,18 @@ 0 0 0 +<<<<<<< HEAD +======= +1 +0 +0 +0 +2 +0 +0 +0 0 +>>>>>>> new-pomodoro 0 0 0 @@ -18,14 +29,32 @@ 0 0 0 +<<<<<<< HEAD +======= +1 +0 +0 +0 +0 +3 +1 +2 +4 +>>>>>>> new-pomodoro +0 0 0 0 0 0 +<<<<<<< HEAD 0 0 0 +======= +4 +2 +>>>>>>> new-pomodoro 1 0 0 @@ -63,6 +92,7 @@ 0 0 0 +<<<<<<< HEAD 0 0 0 @@ -80,3 +110,5 @@ 0 0 0 +======= +>>>>>>> new-pomodoro diff --git a/.flatpak-builder/ccache/0/2/62gdi7nfmqci4lcbj4h43q1mmlvnn42M b/.flatpak-builder/ccache/0/2/62gdi7nfmqci4lcbj4h43q1mmlvnn42M new file mode 100644 index 0000000..7a6d330 Binary files /dev/null and b/.flatpak-builder/ccache/0/2/62gdi7nfmqci4lcbj4h43q1mmlvnn42M differ diff --git a/.flatpak-builder/ccache/0/2/8141kv218mctau7ks4q92brmcku3m82M b/.flatpak-builder/ccache/0/2/8141kv218mctau7ks4q92brmcku3m82M new file mode 100644 index 0000000..df2e60e Binary files /dev/null and b/.flatpak-builder/ccache/0/2/8141kv218mctau7ks4q92brmcku3m82M differ diff --git a/.flatpak-builder/ccache/0/2/stats b/.flatpak-builder/ccache/0/2/stats new file mode 100644 index 0000000..cfee81f --- /dev/null +++ b/.flatpak-builder/ccache/0/2/stats @@ -0,0 +1,82 @@ +0 +0 +0 +0 +1 +0 +0 +0 +0 +0 +1 +0 +0 +0 +0 +0 +0 +0 +0 +2 +0 +0 +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +1 +1 +2 +2 +0 +0 +0 +0 +0 +0 +2 +1 +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 diff --git a/.flatpak-builder/ccache/0/3/54n3loptsosm11o70acfb36ri9u9idkM b/.flatpak-builder/ccache/0/3/54n3loptsosm11o70acfb36ri9u9idkM new file mode 100644 index 0000000..c5d997c Binary files /dev/null and b/.flatpak-builder/ccache/0/3/54n3loptsosm11o70acfb36ri9u9idkM differ diff --git a/.flatpak-builder/ccache/0/3/stats b/.flatpak-builder/ccache/0/3/stats index 68c5368..654c7bd 100644 --- a/.flatpak-builder/ccache/0/3/stats +++ b/.flatpak-builder/ccache/0/3/stats @@ -2,7 +2,17 @@ 0 0 0 +<<<<<<< HEAD 1 +======= +2 +0 +0 +0 +0 +0 +3 +>>>>>>> new-pomodoro 0 0 0 @@ -14,6 +24,7 @@ 0 0 0 +<<<<<<< HEAD 0 0 0 @@ -34,6 +45,8 @@ 1 1 0 +======= +>>>>>>> new-pomodoro 2 0 0 @@ -41,10 +54,31 @@ 0 0 0 +<<<<<<< HEAD 2 0 1 0 +======= +0 +0 +0 +0 +2 +2 +4 +4 +0 +0 +0 +0 +0 +0 +4 +2 +2 +0 +>>>>>>> new-pomodoro 0 0 0 diff --git a/.flatpak-builder/ccache/0/4/stats b/.flatpak-builder/ccache/0/4/stats index 17815a7..564d457 100644 --- a/.flatpak-builder/ccache/0/4/stats +++ b/.flatpak-builder/ccache/0/4/stats @@ -6,6 +6,7 @@ 0 0 0 +<<<<<<< HEAD 0 0 0 @@ -22,6 +23,11 @@ 0 1 0 +======= +1 +0 +3 +>>>>>>> new-pomodoro 0 0 0 @@ -31,10 +37,20 @@ 0 0 0 +<<<<<<< HEAD 1 1 2 2 +======= +0 +0 +3 +0 +0 +0 +0 +>>>>>>> new-pomodoro 0 0 0 @@ -43,6 +59,19 @@ 0 2 1 +<<<<<<< HEAD +======= +7 +3 +0 +0 +0 +0 +0 +0 +3 +4 +>>>>>>> new-pomodoro 1 0 0 diff --git a/.flatpak-builder/ccache/0/5/0db85klsms2bhvmkec935mr3qomcrneM b/.flatpak-builder/ccache/0/5/0db85klsms2bhvmkec935mr3qomcrneM new file mode 100644 index 0000000..ab1a40c Binary files /dev/null and b/.flatpak-builder/ccache/0/5/0db85klsms2bhvmkec935mr3qomcrneM differ diff --git a/.flatpak-builder/ccache/0/5/dba1okouov7pk8smfc44om809bu8dmeM b/.flatpak-builder/ccache/0/5/dba1okouov7pk8smfc44om809bu8dmeM new file mode 100644 index 0000000..19a6eab Binary files /dev/null and b/.flatpak-builder/ccache/0/5/dba1okouov7pk8smfc44om809bu8dmeM differ diff --git a/.flatpak-builder/ccache/0/5/stats b/.flatpak-builder/ccache/0/5/stats index f4f6fb2..e1e72f1 100644 --- a/.flatpak-builder/ccache/0/5/stats +++ b/.flatpak-builder/ccache/0/5/stats @@ -6,15 +6,27 @@ 0 0 0 +<<<<<<< HEAD +======= +1 +0 +0 0 +>>>>>>> new-pomodoro 0 0 0 0 0 +<<<<<<< HEAD +======= +6 +>>>>>>> new-pomodoro 0 0 0 +0 +<<<<<<< HEAD 4 0 0 @@ -43,6 +55,31 @@ 0 2 0 +======= +3 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +2 +1 +7 +3 +0 +0 +0 +0 +0 +0 +3 +4 +>>>>>>> new-pomodoro 1 0 0 diff --git a/.flatpak-builder/ccache/0/6/0bau6mbvqsmab1c50u5rgrbrtt2h9fcM b/.flatpak-builder/ccache/0/6/0bau6mbvqsmab1c50u5rgrbrtt2h9fcM new file mode 100644 index 0000000..0a6f8ee Binary files /dev/null and b/.flatpak-builder/ccache/0/6/0bau6mbvqsmab1c50u5rgrbrtt2h9fcM differ diff --git a/.flatpak-builder/ccache/0/6/2abn45u96esisj74cl0ls762eq7bqt2R b/.flatpak-builder/ccache/0/6/2abn45u96esisj74cl0ls762eq7bqt2R new file mode 100644 index 0000000..180b957 Binary files /dev/null and b/.flatpak-builder/ccache/0/6/2abn45u96esisj74cl0ls762eq7bqt2R differ diff --git a/.flatpak-builder/ccache/0/6/cbtchhbtngeork2hab46l4jl44k91toR b/.flatpak-builder/ccache/0/6/cbtchhbtngeork2hab46l4jl44k91toR new file mode 100644 index 0000000..41367a8 Binary files /dev/null and b/.flatpak-builder/ccache/0/6/cbtchhbtngeork2hab46l4jl44k91toR differ diff --git a/.flatpak-builder/ccache/0/6/stats b/.flatpak-builder/ccache/0/6/stats index ea16044..53ec78c 100644 --- a/.flatpak-builder/ccache/0/6/stats +++ b/.flatpak-builder/ccache/0/6/stats @@ -20,20 +20,32 @@ 1 0 0 +<<<<<<< HEAD 2 +======= +>>>>>>> new-pomodoro 0 0 0 0 0 +<<<<<<< HEAD 5 +======= +0 +7 +>>>>>>> new-pomodoro 0 0 0 0 1 1 +<<<<<<< HEAD 4 +======= +0 +>>>>>>> new-pomodoro 2 0 0 @@ -42,7 +54,11 @@ 0 0 2 +<<<<<<< HEAD 2 +======= +0 +>>>>>>> new-pomodoro 1 0 0 diff --git a/.flatpak-builder/ccache/0/7/a7pdguug5ptntvhldoetht0v2u19ssaM b/.flatpak-builder/ccache/0/7/a7pdguug5ptntvhldoetht0v2u19ssaM new file mode 100644 index 0000000..d64bd87 Binary files /dev/null and b/.flatpak-builder/ccache/0/7/a7pdguug5ptntvhldoetht0v2u19ssaM differ diff --git a/.flatpak-builder/ccache/0/7/c8srhfsn6ovopqvllrucoralm8pc91uM b/.flatpak-builder/ccache/0/7/c8srhfsn6ovopqvllrucoralm8pc91uM new file mode 100644 index 0000000..b2ed73c Binary files /dev/null and b/.flatpak-builder/ccache/0/7/c8srhfsn6ovopqvllrucoralm8pc91uM differ diff --git a/.flatpak-builder/ccache/0/7/stats b/.flatpak-builder/ccache/0/7/stats index 3c139e1..57a2fad 100644 --- a/.flatpak-builder/ccache/0/7/stats +++ b/.flatpak-builder/ccache/0/7/stats @@ -6,6 +6,7 @@ 0 0 0 +<<<<<<< HEAD 0 0 0 @@ -43,6 +44,45 @@ 0 2 2 +======= +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +2 +1 +1 +3 +0 +0 +0 +0 +0 +0 +3 +1 +>>>>>>> new-pomodoro 1 0 0 diff --git a/.flatpak-builder/ccache/0/8/091ngo2s08g6207dh958m81inslvuceM b/.flatpak-builder/ccache/0/8/091ngo2s08g6207dh958m81inslvuceM new file mode 100644 index 0000000..0f41674 Binary files /dev/null and b/.flatpak-builder/ccache/0/8/091ngo2s08g6207dh958m81inslvuceM differ diff --git a/.flatpak-builder/ccache/0/8/26p0r5c59nci47h6f34f7up919qh5ocM b/.flatpak-builder/ccache/0/8/26p0r5c59nci47h6f34f7up919qh5ocM new file mode 100644 index 0000000..2d7e229 Binary files /dev/null and b/.flatpak-builder/ccache/0/8/26p0r5c59nci47h6f34f7up919qh5ocM differ diff --git a/.flatpak-builder/ccache/0/8/a2g136dfio9ubvvke0ebelmgmpkr4vkM b/.flatpak-builder/ccache/0/8/a2g136dfio9ubvvke0ebelmgmpkr4vkM new file mode 100644 index 0000000..fb04c42 Binary files /dev/null and b/.flatpak-builder/ccache/0/8/a2g136dfio9ubvvke0ebelmgmpkr4vkM differ diff --git a/.flatpak-builder/ccache/0/8/stats b/.flatpak-builder/ccache/0/8/stats index 791429c..f65c90d 100644 --- a/.flatpak-builder/ccache/0/8/stats +++ b/.flatpak-builder/ccache/0/8/stats @@ -2,7 +2,15 @@ 0 0 0 +<<<<<<< HEAD 3 +======= +2 +0 +0 +0 +2 +>>>>>>> new-pomodoro 0 0 0 @@ -11,11 +19,15 @@ 0 0 0 +<<<<<<< HEAD 0 0 0 0 4 +======= +6 +>>>>>>> new-pomodoro 0 0 0 @@ -31,6 +43,7 @@ 0 0 0 +<<<<<<< HEAD 3 3 4 @@ -44,6 +57,21 @@ 6 2 3 +======= +4 +2 +6 +6 +0 +0 +0 +0 +0 +0 +6 +4 +2 +>>>>>>> new-pomodoro 0 0 0 diff --git a/.flatpak-builder/ccache/0/9/c074cf094ej75tgmsjj079miikaauo8M b/.flatpak-builder/ccache/0/9/c074cf094ej75tgmsjj079miikaauo8M new file mode 100644 index 0000000..0a32b13 Binary files /dev/null and b/.flatpak-builder/ccache/0/9/c074cf094ej75tgmsjj079miikaauo8M differ diff --git a/.flatpak-builder/ccache/0/9/stats b/.flatpak-builder/ccache/0/9/stats index 96f1a76..5060335 100644 --- a/.flatpak-builder/ccache/0/9/stats +++ b/.flatpak-builder/ccache/0/9/stats @@ -2,7 +2,11 @@ 0 0 0 +<<<<<<< HEAD 0 +======= +1 +>>>>>>> new-pomodoro 0 0 0 @@ -31,6 +35,7 @@ 0 0 0 +<<<<<<< HEAD 0 0 4 @@ -42,6 +47,11 @@ 0 0 0 +======= +1 +1 +4 +>>>>>>> new-pomodoro 2 0 0 @@ -49,6 +59,17 @@ 0 0 0 +<<<<<<< HEAD +======= +2 +2 +1 +0 +0 +0 +0 +0 +>>>>>>> new-pomodoro 0 0 0 diff --git a/.flatpak-builder/ccache/0/CACHEDIR.TAG b/.flatpak-builder/ccache/0/CACHEDIR.TAG new file mode 100644 index 0000000..874477f --- /dev/null +++ b/.flatpak-builder/ccache/0/CACHEDIR.TAG @@ -0,0 +1,4 @@ +Signature: 8a477f597d28d172789f06886806bc55 +# This file is a cache directory tag created by ccache. +# For information about cache directory tags, see: +# http://www.brynosaurus.com/cachedir/ diff --git a/.flatpak-builder/ccache/0/a/49kb57vspg66qvrk8egvd37hsf61vjuM b/.flatpak-builder/ccache/0/a/49kb57vspg66qvrk8egvd37hsf61vjuM new file mode 100644 index 0000000..aa1174a Binary files /dev/null and b/.flatpak-builder/ccache/0/a/49kb57vspg66qvrk8egvd37hsf61vjuM differ diff --git a/.flatpak-builder/ccache/0/a/91ob46q03i2nic5nu5thtudlv5ssbdsM b/.flatpak-builder/ccache/0/a/91ob46q03i2nic5nu5thtudlv5ssbdsM new file mode 100644 index 0000000..53d24f4 Binary files /dev/null and b/.flatpak-builder/ccache/0/a/91ob46q03i2nic5nu5thtudlv5ssbdsM differ diff --git a/.flatpak-builder/ccache/0/a/stats b/.flatpak-builder/ccache/0/a/stats index 6dfdff4..824a181 100644 --- a/.flatpak-builder/ccache/0/a/stats +++ b/.flatpak-builder/ccache/0/a/stats @@ -2,15 +2,20 @@ 0 0 0 +<<<<<<< HEAD +======= +1 0 0 0 0 0 +1 0 0 0 0 +>>>>>>> new-pomodoro 0 0 0 @@ -18,8 +23,27 @@ 0 0 0 +<<<<<<< HEAD +======= +3 +>>>>>>> new-pomodoro 0 0 +0 +0 +0 +0 +0 +0 +0 +0 +<<<<<<< HEAD +0 +======= +1 +1 +6 +>>>>>>> new-pomodoro 2 0 0 @@ -27,6 +51,7 @@ 0 0 0 +<<<<<<< HEAD 0 0 0 @@ -44,6 +69,11 @@ 0 2 0 +======= +2 +3 +1 +>>>>>>> new-pomodoro 0 0 0 diff --git a/.flatpak-builder/ccache/0/b/32mprt1s9ibnp1uhmn3pahclc35iv4mM b/.flatpak-builder/ccache/0/b/32mprt1s9ibnp1uhmn3pahclc35iv4mM new file mode 100644 index 0000000..b38eff6 Binary files /dev/null and b/.flatpak-builder/ccache/0/b/32mprt1s9ibnp1uhmn3pahclc35iv4mM differ diff --git a/.flatpak-builder/ccache/0/b/stats b/.flatpak-builder/ccache/0/b/stats index aee5c07..c06e817 100644 --- a/.flatpak-builder/ccache/0/b/stats +++ b/.flatpak-builder/ccache/0/b/stats @@ -2,6 +2,7 @@ 0 0 0 +<<<<<<< HEAD 0 0 0 @@ -9,6 +10,15 @@ 0 0 4 +======= +1 +0 +0 +0 +0 +0 +6 +>>>>>>> new-pomodoro 0 0 0 @@ -31,6 +41,7 @@ 0 0 0 +<<<<<<< HEAD 0 0 4 @@ -42,6 +53,11 @@ 0 0 0 +======= +1 +1 +4 +>>>>>>> new-pomodoro 2 0 0 @@ -49,6 +65,17 @@ 0 0 0 +<<<<<<< HEAD +======= +2 +2 +1 +0 +0 +0 +0 +0 +>>>>>>> new-pomodoro 0 0 0 diff --git a/.flatpak-builder/ccache/0/c/21bpi7hjm672e5dv7r3mm12joptiua6M b/.flatpak-builder/ccache/0/c/21bpi7hjm672e5dv7r3mm12joptiua6M new file mode 100644 index 0000000..6d81353 Binary files /dev/null and b/.flatpak-builder/ccache/0/c/21bpi7hjm672e5dv7r3mm12joptiua6M differ diff --git a/.flatpak-builder/ccache/0/c/3derqtuh47jmr7t9m6qh5svj11uiegoR b/.flatpak-builder/ccache/0/c/3derqtuh47jmr7t9m6qh5svj11uiegoR new file mode 100644 index 0000000..32e721d Binary files /dev/null and b/.flatpak-builder/ccache/0/c/3derqtuh47jmr7t9m6qh5svj11uiegoR differ diff --git a/.flatpak-builder/ccache/0/c/95gdia8si046sqegmnoakctfb7hstdaR b/.flatpak-builder/ccache/0/c/95gdia8si046sqegmnoakctfb7hstdaR new file mode 100644 index 0000000..92faa5f Binary files /dev/null and b/.flatpak-builder/ccache/0/c/95gdia8si046sqegmnoakctfb7hstdaR differ diff --git a/.flatpak-builder/ccache/0/c/c53sagcv62uq18vir30rmnful1cdh4aR b/.flatpak-builder/ccache/0/c/c53sagcv62uq18vir30rmnful1cdh4aR new file mode 100644 index 0000000..324a8d8 Binary files /dev/null and b/.flatpak-builder/ccache/0/c/c53sagcv62uq18vir30rmnful1cdh4aR differ diff --git a/.flatpak-builder/ccache/0/c/stats b/.flatpak-builder/ccache/0/c/stats index f65b672..a67271d 100644 --- a/.flatpak-builder/ccache/0/c/stats +++ b/.flatpak-builder/ccache/0/c/stats @@ -2,6 +2,7 @@ 0 0 0 +<<<<<<< HEAD 2 0 0 @@ -34,6 +35,8 @@ 2 2 4 +======= +>>>>>>> new-pomodoro 4 0 0 @@ -41,9 +44,47 @@ 0 0 0 +<<<<<<< HEAD 4 2 2 +======= +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +2 +0 +0 +0 +0 +0 +2 +0 +0 +0 +0 +4 +4 +4 +8 +0 +0 +0 +0 +0 +0 +8 +2 +4 +>>>>>>> new-pomodoro 0 0 0 diff --git a/.flatpak-builder/ccache/0/d/111k7em5cdcl29gbiti1pbfpgofl9veR b/.flatpak-builder/ccache/0/d/111k7em5cdcl29gbiti1pbfpgofl9veR new file mode 100644 index 0000000..26381e8 Binary files /dev/null and b/.flatpak-builder/ccache/0/d/111k7em5cdcl29gbiti1pbfpgofl9veR differ diff --git a/.flatpak-builder/ccache/0/d/4a9e3sfrccb7rfjm7ppcsj451b1gd64M b/.flatpak-builder/ccache/0/d/4a9e3sfrccb7rfjm7ppcsj451b1gd64M new file mode 100644 index 0000000..5780c42 Binary files /dev/null and b/.flatpak-builder/ccache/0/d/4a9e3sfrccb7rfjm7ppcsj451b1gd64M differ diff --git a/.flatpak-builder/ccache/0/d/c7io4ph5beqgi3e0k8piu21kpr7vlssM b/.flatpak-builder/ccache/0/d/c7io4ph5beqgi3e0k8piu21kpr7vlssM new file mode 100644 index 0000000..187742f Binary files /dev/null and b/.flatpak-builder/ccache/0/d/c7io4ph5beqgi3e0k8piu21kpr7vlssM differ diff --git a/.flatpak-builder/ccache/0/d/stats b/.flatpak-builder/ccache/0/d/stats index f65b672..74d32ae 100644 --- a/.flatpak-builder/ccache/0/d/stats +++ b/.flatpak-builder/ccache/0/d/stats @@ -6,6 +6,15 @@ 0 0 0 +<<<<<<< HEAD +======= +1 +0 +2 +0 +0 +0 +>>>>>>> new-pomodoro 0 0 0 @@ -25,6 +34,7 @@ 0 0 0 +<<<<<<< HEAD 0 0 0 @@ -35,14 +45,25 @@ 2 4 4 +======= +3 +2 +1 +5 +>>>>>>> new-pomodoro 0 0 0 0 0 0 +<<<<<<< HEAD 4 2 +======= +5 +1 +>>>>>>> new-pomodoro 2 0 0 diff --git a/.flatpak-builder/ccache/0/e/stats b/.flatpak-builder/ccache/0/e/stats index 6dfdff4..36446f6 100644 --- a/.flatpak-builder/ccache/0/e/stats +++ b/.flatpak-builder/ccache/0/e/stats @@ -2,11 +2,19 @@ 0 0 0 +<<<<<<< HEAD 0 0 0 0 0 +======= +1 +0 +0 +0 +1 +>>>>>>> new-pomodoro 0 0 0 @@ -31,6 +39,7 @@ 0 0 0 +<<<<<<< HEAD 0 0 4 @@ -44,6 +53,21 @@ 0 2 0 +======= +2 +1 +5 +3 +0 +0 +0 +0 +0 +0 +3 +3 +1 +>>>>>>> new-pomodoro 0 0 0 diff --git a/.flatpak-builder/ccache/0/f/380q6l92m63c1ujgkvcenb7ok3hooueM b/.flatpak-builder/ccache/0/f/380q6l92m63c1ujgkvcenb7ok3hooueM new file mode 100644 index 0000000..75685c9 Binary files /dev/null and b/.flatpak-builder/ccache/0/f/380q6l92m63c1ujgkvcenb7ok3hooueM differ diff --git a/.flatpak-builder/ccache/0/f/4evrt46i3anr11s85avujctmro0f2ocR b/.flatpak-builder/ccache/0/f/4evrt46i3anr11s85avujctmro0f2ocR new file mode 100644 index 0000000..17ea065 Binary files /dev/null and b/.flatpak-builder/ccache/0/f/4evrt46i3anr11s85avujctmro0f2ocR differ diff --git a/.flatpak-builder/ccache/0/f/aa0cq847mjghsnm34vkmjka4mbf8pliM b/.flatpak-builder/ccache/0/f/aa0cq847mjghsnm34vkmjka4mbf8pliM new file mode 100644 index 0000000..6b75662 Binary files /dev/null and b/.flatpak-builder/ccache/0/f/aa0cq847mjghsnm34vkmjka4mbf8pliM differ diff --git a/.flatpak-builder/ccache/0/f/stats b/.flatpak-builder/ccache/0/f/stats index 1416d92..ad84242 100644 --- a/.flatpak-builder/ccache/0/f/stats +++ b/.flatpak-builder/ccache/0/f/stats @@ -2,6 +2,15 @@ 0 0 0 +<<<<<<< HEAD +======= +2 +0 +0 +0 +0 +0 +>>>>>>> new-pomodoro 1 0 0 @@ -14,12 +23,15 @@ 0 0 0 +<<<<<<< HEAD 0 0 0 0 0 0 +======= +>>>>>>> new-pomodoro 2 0 0 @@ -31,6 +43,7 @@ 0 0 0 +<<<<<<< HEAD 1 1 4 @@ -44,6 +57,21 @@ 2 2 1 +======= +2 +2 +4 +4 +0 +0 +0 +0 +0 +0 +4 +2 +2 +>>>>>>> new-pomodoro 0 0 0 diff --git a/.flatpak-builder/ccache/0/stats b/.flatpak-builder/ccache/0/stats index ba2ed50..498d91c 100644 --- a/.flatpak-builder/ccache/0/stats +++ b/.flatpak-builder/ccache/0/stats @@ -9,12 +9,17 @@ 0 0 0 +<<<<<<< HEAD 18 228 0 0 0 0 +======= +43 +648 +>>>>>>> new-pomodoro 0 0 0 @@ -54,6 +59,7 @@ 2 0 2 +<<<<<<< HEAD 0 1 1 @@ -79,4 +85,35 @@ 12 64 28 +======= +1 +2 +2 +5 +2 +4 +2 +3 +1 +5 +6 +1 +5 +44 +0 +32 +8 +8 +40 +64 +20 +56 +52 +36 +8 +124 +52 +36 +68 +>>>>>>> new-pomodoro 0 diff --git a/.flatpak-builder/ccache/1/0/8cf0hgdgqmdqoukh55bqlqgre8d8s7mR b/.flatpak-builder/ccache/1/0/8cf0hgdgqmdqoukh55bqlqgre8d8s7mR new file mode 100644 index 0000000..67465d3 Binary files /dev/null and b/.flatpak-builder/ccache/1/0/8cf0hgdgqmdqoukh55bqlqgre8d8s7mR differ diff --git a/.flatpak-builder/ccache/1/0/b23nr9spkee52hrvhmhirfod5vihsj2M b/.flatpak-builder/ccache/1/0/b23nr9spkee52hrvhmhirfod5vihsj2M new file mode 100644 index 0000000..2f2e9f8 Binary files /dev/null and b/.flatpak-builder/ccache/1/0/b23nr9spkee52hrvhmhirfod5vihsj2M differ diff --git a/.flatpak-builder/ccache/1/0/stats b/.flatpak-builder/ccache/1/0/stats index 3c139e1..d71d571 100644 --- a/.flatpak-builder/ccache/1/0/stats +++ b/.flatpak-builder/ccache/1/0/stats @@ -2,6 +2,13 @@ 0 0 0 +<<<<<<< HEAD +======= +2 +0 +0 +0 +>>>>>>> new-pomodoro 1 0 0 @@ -13,6 +20,7 @@ 0 0 0 +<<<<<<< HEAD 0 0 0 @@ -43,6 +51,11 @@ 0 2 2 +======= +2 +0 +0 +>>>>>>> new-pomodoro 1 0 0 @@ -54,6 +67,32 @@ 0 0 0 +<<<<<<< HEAD +======= +3 +2 +3 +5 +0 +0 +0 +0 +0 +0 +5 +2 +2 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +>>>>>>> new-pomodoro 0 0 0 diff --git a/.flatpak-builder/ccache/1/1/205cstnojbfjsjhqu21ram4nhp7jmtgR b/.flatpak-builder/ccache/1/1/205cstnojbfjsjhqu21ram4nhp7jmtgR new file mode 100644 index 0000000..1689014 Binary files /dev/null and b/.flatpak-builder/ccache/1/1/205cstnojbfjsjhqu21ram4nhp7jmtgR differ diff --git a/.flatpak-builder/ccache/1/1/23du96i47bjjdqv3hipa42hp9pufqtmR b/.flatpak-builder/ccache/1/1/23du96i47bjjdqv3hipa42hp9pufqtmR new file mode 100644 index 0000000..d210d37 Binary files /dev/null and b/.flatpak-builder/ccache/1/1/23du96i47bjjdqv3hipa42hp9pufqtmR differ diff --git a/.flatpak-builder/ccache/1/1/9fovaj79lv7ie3i9ooj0f22jto00h9cM b/.flatpak-builder/ccache/1/1/9fovaj79lv7ie3i9ooj0f22jto00h9cM new file mode 100644 index 0000000..e07dcdf Binary files /dev/null and b/.flatpak-builder/ccache/1/1/9fovaj79lv7ie3i9ooj0f22jto00h9cM differ diff --git a/.flatpak-builder/ccache/1/1/stats b/.flatpak-builder/ccache/1/1/stats index b3cd973..714f51d 100644 --- a/.flatpak-builder/ccache/1/1/stats +++ b/.flatpak-builder/ccache/1/1/stats @@ -2,11 +2,19 @@ 0 0 0 +<<<<<<< HEAD 0 0 0 0 0 +======= +1 +0 +0 +0 +1 +>>>>>>> new-pomodoro 0 0 0 @@ -31,6 +39,7 @@ 0 0 0 +<<<<<<< HEAD 0 0 4 @@ -44,6 +53,21 @@ 0 2 0 +======= +2 +1 +5 +3 +0 +0 +0 +0 +0 +0 +3 +3 +1 +>>>>>>> new-pomodoro 0 0 0 diff --git a/.flatpak-builder/ccache/1/2/6cs13c6t5pkcgo54fn6qfeftpspfatmM b/.flatpak-builder/ccache/1/2/6cs13c6t5pkcgo54fn6qfeftpspfatmM new file mode 100644 index 0000000..7e53452 Binary files /dev/null and b/.flatpak-builder/ccache/1/2/6cs13c6t5pkcgo54fn6qfeftpspfatmM differ diff --git a/.flatpak-builder/ccache/1/2/stats b/.flatpak-builder/ccache/1/2/stats index 6dfdff4..ec8ffad 100644 --- a/.flatpak-builder/ccache/1/2/stats +++ b/.flatpak-builder/ccache/1/2/stats @@ -2,10 +2,14 @@ 0 0 0 +<<<<<<< HEAD 0 0 0 0 +======= +1 +>>>>>>> new-pomodoro 0 0 0 @@ -23,6 +27,10 @@ 2 0 0 +<<<<<<< HEAD +======= +2 +>>>>>>> new-pomodoro 0 0 0 @@ -33,6 +41,7 @@ 0 0 0 +<<<<<<< HEAD 4 0 0 @@ -42,6 +51,11 @@ 0 0 0 +======= +1 +1 +4 +>>>>>>> new-pomodoro 2 0 0 @@ -49,6 +63,17 @@ 0 0 0 +<<<<<<< HEAD +======= +2 +2 +1 +0 +0 +0 +0 +0 +>>>>>>> new-pomodoro 0 0 0 diff --git a/.flatpak-builder/ccache/1/3/stats b/.flatpak-builder/ccache/1/3/stats index 6dfdff4..0f480f3 100644 --- a/.flatpak-builder/ccache/1/3/stats +++ b/.flatpak-builder/ccache/1/3/stats @@ -2,13 +2,18 @@ 0 0 0 +<<<<<<< HEAD +======= +1 0 0 0 +1 0 0 0 0 +>>>>>>> new-pomodoro 0 0 0 @@ -18,6 +23,17 @@ 0 0 0 +<<<<<<< HEAD +0 +0 +0 +0 +======= +3 +>>>>>>> new-pomodoro +0 +0 +0 0 0 2 @@ -25,12 +41,20 @@ 0 0 0 +<<<<<<< HEAD +======= +2 +1 +7 +3 +>>>>>>> new-pomodoro 0 0 0 0 0 0 +<<<<<<< HEAD 0 0 4 @@ -44,6 +68,11 @@ 0 2 0 +======= +3 +4 +1 +>>>>>>> new-pomodoro 0 0 0 diff --git a/.flatpak-builder/ccache/1/4/stats b/.flatpak-builder/ccache/1/4/stats index b3cd973..435d36d 100644 --- a/.flatpak-builder/ccache/1/4/stats +++ b/.flatpak-builder/ccache/1/4/stats @@ -2,6 +2,7 @@ 0 0 0 +<<<<<<< HEAD 0 0 0 @@ -21,6 +22,9 @@ 0 0 2 +======= +1 +>>>>>>> new-pomodoro 0 0 0 @@ -33,22 +37,50 @@ 0 0 0 +<<<<<<< HEAD 4 +======= +>>>>>>> new-pomodoro +0 +0 +0 +0 +0 +0 +0 +0 +<<<<<<< HEAD +======= +0 0 0 +1 +0 +0 +0 +0 +1 +1 0 +>>>>>>> new-pomodoro +2 0 0 0 0 0 +0 +<<<<<<< HEAD +======= 2 0 +1 0 0 0 0 0 +>>>>>>> new-pomodoro 0 0 0 diff --git a/.flatpak-builder/ccache/1/5/7186dfgfcut4flsn4j2j2uhaqifn8hsM b/.flatpak-builder/ccache/1/5/7186dfgfcut4flsn4j2j2uhaqifn8hsM new file mode 100644 index 0000000..4076dd6 Binary files /dev/null and b/.flatpak-builder/ccache/1/5/7186dfgfcut4flsn4j2j2uhaqifn8hsM differ diff --git a/.flatpak-builder/ccache/1/5/stats b/.flatpak-builder/ccache/1/5/stats new file mode 100644 index 0000000..90eda0b --- /dev/null +++ b/.flatpak-builder/ccache/1/5/stats @@ -0,0 +1,82 @@ +0 +0 +1 +0 +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +2 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +2 +2 +4 +4 +0 +0 +0 +0 +0 +0 +2 +2 +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 diff --git a/.flatpak-builder/ccache/1/6/a1am8mjiohc0evi5rakmfss71kit7a2M b/.flatpak-builder/ccache/1/6/a1am8mjiohc0evi5rakmfss71kit7a2M new file mode 100644 index 0000000..eed82fb Binary files /dev/null and b/.flatpak-builder/ccache/1/6/a1am8mjiohc0evi5rakmfss71kit7a2M differ diff --git a/.flatpak-builder/ccache/1/6/b4vvahdkfbvt87bdqkjbuf41vv7576kM b/.flatpak-builder/ccache/1/6/b4vvahdkfbvt87bdqkjbuf41vv7576kM new file mode 100644 index 0000000..3aa8663 Binary files /dev/null and b/.flatpak-builder/ccache/1/6/b4vvahdkfbvt87bdqkjbuf41vv7576kM differ diff --git a/.flatpak-builder/ccache/1/6/stats b/.flatpak-builder/ccache/1/6/stats index 8b3bd56..0f043dd 100644 --- a/.flatpak-builder/ccache/1/6/stats +++ b/.flatpak-builder/ccache/1/6/stats @@ -6,7 +6,11 @@ 0 0 0 +<<<<<<< HEAD 0 +======= +2 +>>>>>>> new-pomodoro 0 0 0 @@ -20,14 +24,32 @@ 0 0 0 +<<<<<<< HEAD +======= +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 2 0 +2 +>>>>>>> new-pomodoro +2 0 0 0 0 0 0 +<<<<<<< HEAD +0 0 0 0 @@ -42,6 +64,9 @@ 0 0 0 +======= +2 +>>>>>>> new-pomodoro 2 0 0 diff --git a/.flatpak-builder/ccache/1/7/53d1op3e7e1ufclskqmg81d0760jthiM b/.flatpak-builder/ccache/1/7/53d1op3e7e1ufclskqmg81d0760jthiM new file mode 100644 index 0000000..9f44103 Binary files /dev/null and b/.flatpak-builder/ccache/1/7/53d1op3e7e1ufclskqmg81d0760jthiM differ diff --git a/.flatpak-builder/ccache/1/7/stats b/.flatpak-builder/ccache/1/7/stats index b9a8757..7043eee 100644 --- a/.flatpak-builder/ccache/1/7/stats +++ b/.flatpak-builder/ccache/1/7/stats @@ -2,13 +2,46 @@ 0 0 0 +<<<<<<< HEAD +======= +2 +0 +0 +0 +0 +0 +4 +0 +0 +0 +0 +0 +0 +3 +0 +>>>>>>> new-pomodoro 1 0 0 0 0 0 +<<<<<<< HEAD 1 +======= +0 +0 +0 +0 +0 +0 +0 +0 +2 +2 +0 +4 +>>>>>>> new-pomodoro 0 0 0 @@ -17,9 +50,12 @@ 0 4 0 +<<<<<<< HEAD 1 0 0 +======= +>>>>>>> new-pomodoro 2 0 0 @@ -31,6 +67,7 @@ 0 0 0 +<<<<<<< HEAD 1 1 4 @@ -54,6 +91,8 @@ 0 0 0 +======= +>>>>>>> new-pomodoro 0 0 0 diff --git a/.flatpak-builder/ccache/1/8/78pslours15kl6s31d8bbvevpicpeuaR b/.flatpak-builder/ccache/1/8/78pslours15kl6s31d8bbvevpicpeuaR new file mode 100644 index 0000000..dd83431 Binary files /dev/null and b/.flatpak-builder/ccache/1/8/78pslours15kl6s31d8bbvevpicpeuaR differ diff --git a/.flatpak-builder/ccache/1/8/stats b/.flatpak-builder/ccache/1/8/stats index d631ee3..c93e94c 100644 --- a/.flatpak-builder/ccache/1/8/stats +++ b/.flatpak-builder/ccache/1/8/stats @@ -2,10 +2,14 @@ 0 0 0 +<<<<<<< HEAD +======= +1 0 0 0 0 +>>>>>>> new-pomodoro 0 0 0 @@ -20,6 +24,11 @@ 0 0 0 +0 +0 +0 +0 +<<<<<<< HEAD 2 0 0 @@ -37,18 +46,38 @@ 0 0 0 +======= +0 +3 +>>>>>>> new-pomodoro +0 +0 +0 +0 +<<<<<<< HEAD +======= +1 +1 +>>>>>>> new-pomodoro +0 +2 +0 0 0 0 0 0 +<<<<<<< HEAD +======= 2 0 +1 0 0 0 0 0 +>>>>>>> new-pomodoro 0 0 0 diff --git a/.flatpak-builder/ccache/1/9/57n3ugcc4s6h6fr4351dj6v7mft14b0M b/.flatpak-builder/ccache/1/9/57n3ugcc4s6h6fr4351dj6v7mft14b0M new file mode 100644 index 0000000..205d52b Binary files /dev/null and b/.flatpak-builder/ccache/1/9/57n3ugcc4s6h6fr4351dj6v7mft14b0M differ diff --git a/.flatpak-builder/ccache/1/9/7act92108l0jftj69ag5ftufhhbnfd6R b/.flatpak-builder/ccache/1/9/7act92108l0jftj69ag5ftufhhbnfd6R new file mode 100644 index 0000000..4034fba Binary files /dev/null and b/.flatpak-builder/ccache/1/9/7act92108l0jftj69ag5ftufhhbnfd6R differ diff --git a/.flatpak-builder/ccache/1/9/e03sgfd74rghpd9l4g0vk51sl9g2tvcM b/.flatpak-builder/ccache/1/9/e03sgfd74rghpd9l4g0vk51sl9g2tvcM new file mode 100644 index 0000000..9480e44 Binary files /dev/null and b/.flatpak-builder/ccache/1/9/e03sgfd74rghpd9l4g0vk51sl9g2tvcM differ diff --git a/.flatpak-builder/ccache/1/9/stats b/.flatpak-builder/ccache/1/9/stats index 9ea0144..d93c1e1 100644 --- a/.flatpak-builder/ccache/1/9/stats +++ b/.flatpak-builder/ccache/1/9/stats @@ -2,13 +2,21 @@ 0 0 0 +<<<<<<< HEAD 3 0 +======= +1 +>>>>>>> new-pomodoro 0 0 0 1 1 +<<<<<<< HEAD +======= +1 +>>>>>>> new-pomodoro 0 0 0 @@ -20,11 +28,21 @@ 1 0 0 +<<<<<<< HEAD +======= +0 +0 +0 +0 +0 +0 +>>>>>>> new-pomodoro 2 0 0 0 0 +<<<<<<< HEAD 0 0 0 @@ -43,13 +61,30 @@ 0 6 2 +======= +2 +1 +1 +>>>>>>> new-pomodoro +3 +0 +0 +0 +0 +0 +0 +<<<<<<< HEAD +======= 3 +1 +1 0 0 0 0 0 0 +>>>>>>> new-pomodoro 0 0 0 diff --git a/.flatpak-builder/ccache/1/CACHEDIR.TAG b/.flatpak-builder/ccache/1/CACHEDIR.TAG new file mode 100644 index 0000000..874477f --- /dev/null +++ b/.flatpak-builder/ccache/1/CACHEDIR.TAG @@ -0,0 +1,4 @@ +Signature: 8a477f597d28d172789f06886806bc55 +# This file is a cache directory tag created by ccache. +# For information about cache directory tags, see: +# http://www.brynosaurus.com/cachedir/ diff --git a/.flatpak-builder/ccache/1/a/3avmqa4tsbobetk92ptr8fchhnmbu10M b/.flatpak-builder/ccache/1/a/3avmqa4tsbobetk92ptr8fchhnmbu10M new file mode 100644 index 0000000..cbf3eaa Binary files /dev/null and b/.flatpak-builder/ccache/1/a/3avmqa4tsbobetk92ptr8fchhnmbu10M differ diff --git a/.flatpak-builder/ccache/1/a/dfrg5ntgjl01c65vo7gh5m1ckjto91eR b/.flatpak-builder/ccache/1/a/dfrg5ntgjl01c65vo7gh5m1ckjto91eR new file mode 100644 index 0000000..64fa757 Binary files /dev/null and b/.flatpak-builder/ccache/1/a/dfrg5ntgjl01c65vo7gh5m1ckjto91eR differ diff --git a/.flatpak-builder/ccache/1/a/stats b/.flatpak-builder/ccache/1/a/stats index 14d4363..6729ee5 100644 --- a/.flatpak-builder/ccache/1/a/stats +++ b/.flatpak-builder/ccache/1/a/stats @@ -15,12 +15,22 @@ 0 0 0 +<<<<<<< HEAD 4 +======= +3 0 0 0 +>>>>>>> new-pomodoro 0 +0 +0 +0 +<<<<<<< HEAD 2 +======= +>>>>>>> new-pomodoro 0 0 0 @@ -33,7 +43,10 @@ 0 0 0 +<<<<<<< HEAD 4 +======= +>>>>>>> new-pomodoro 0 0 0 @@ -42,7 +55,10 @@ 0 0 0 +<<<<<<< HEAD 2 +======= +>>>>>>> new-pomodoro 0 0 0 diff --git a/.flatpak-builder/ccache/1/b/32skgcbcejooc0tssi7qgi1rmv86n4mM b/.flatpak-builder/ccache/1/b/32skgcbcejooc0tssi7qgi1rmv86n4mM new file mode 100644 index 0000000..a4af535 Binary files /dev/null and b/.flatpak-builder/ccache/1/b/32skgcbcejooc0tssi7qgi1rmv86n4mM differ diff --git a/.flatpak-builder/ccache/1/b/stats b/.flatpak-builder/ccache/1/b/stats new file mode 100644 index 0000000..3a9791f --- /dev/null +++ b/.flatpak-builder/ccache/1/b/stats @@ -0,0 +1,82 @@ +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +3 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 diff --git a/.flatpak-builder/ccache/1/c/d7dmcda8pa0ghgj6er0lr7l3ouhgiegM b/.flatpak-builder/ccache/1/c/d7dmcda8pa0ghgj6er0lr7l3ouhgiegM new file mode 100644 index 0000000..e1710bf Binary files /dev/null and b/.flatpak-builder/ccache/1/c/d7dmcda8pa0ghgj6er0lr7l3ouhgiegM differ diff --git a/.flatpak-builder/ccache/1/c/f4fecm7cfhr108n4fgmitdd3dksts4aM b/.flatpak-builder/ccache/1/c/f4fecm7cfhr108n4fgmitdd3dksts4aM new file mode 100644 index 0000000..44f1262 Binary files /dev/null and b/.flatpak-builder/ccache/1/c/f4fecm7cfhr108n4fgmitdd3dksts4aM differ diff --git a/.flatpak-builder/ccache/1/c/stats b/.flatpak-builder/ccache/1/c/stats index 3c139e1..24d1901 100644 --- a/.flatpak-builder/ccache/1/c/stats +++ b/.flatpak-builder/ccache/1/c/stats @@ -2,6 +2,7 @@ 0 0 0 +<<<<<<< HEAD 1 0 0 @@ -34,6 +35,49 @@ 1 1 4 +======= +2 +2 +0 +0 +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +4 +0 +0 +0 +0 +0 +3 +0 +0 +0 +0 +5 +2 +9 +7 +0 +0 +0 +0 +0 +0 +5 +5 +>>>>>>> new-pomodoro 2 0 0 @@ -41,6 +85,7 @@ 0 0 0 +<<<<<<< HEAD 2 2 1 @@ -50,6 +95,8 @@ 0 0 0 +======= +>>>>>>> new-pomodoro 0 0 0 diff --git a/.flatpak-builder/ccache/1/d/4fuj1k6kmo8q7lg5qsbfacr89colsasM b/.flatpak-builder/ccache/1/d/4fuj1k6kmo8q7lg5qsbfacr89colsasM new file mode 100644 index 0000000..8999398 Binary files /dev/null and b/.flatpak-builder/ccache/1/d/4fuj1k6kmo8q7lg5qsbfacr89colsasM differ diff --git a/.flatpak-builder/ccache/1/d/7cn2n33jr2jf4ndt6kgr8gk40pada7mM b/.flatpak-builder/ccache/1/d/7cn2n33jr2jf4ndt6kgr8gk40pada7mM new file mode 100644 index 0000000..68ea556 Binary files /dev/null and b/.flatpak-builder/ccache/1/d/7cn2n33jr2jf4ndt6kgr8gk40pada7mM differ diff --git a/.flatpak-builder/ccache/1/d/a6k5rm5q1i51r8e7vj3mif54q5pvbcqR b/.flatpak-builder/ccache/1/d/a6k5rm5q1i51r8e7vj3mif54q5pvbcqR new file mode 100644 index 0000000..c7a17b8 Binary files /dev/null and b/.flatpak-builder/ccache/1/d/a6k5rm5q1i51r8e7vj3mif54q5pvbcqR differ diff --git a/.flatpak-builder/ccache/1/d/ab2emgo09kvdiraj0j8km6uf5j54djoR b/.flatpak-builder/ccache/1/d/ab2emgo09kvdiraj0j8km6uf5j54djoR new file mode 100644 index 0000000..045acda Binary files /dev/null and b/.flatpak-builder/ccache/1/d/ab2emgo09kvdiraj0j8km6uf5j54djoR differ diff --git a/.flatpak-builder/ccache/1/d/stats b/.flatpak-builder/ccache/1/d/stats index 9779324..120cb31 100644 --- a/.flatpak-builder/ccache/1/d/stats +++ b/.flatpak-builder/ccache/1/d/stats @@ -8,8 +8,12 @@ 0 0 0 +<<<<<<< HEAD 4 +======= +3 0 +>>>>>>> new-pomodoro 0 0 0 @@ -20,7 +24,11 @@ 0 0 0 +0 +<<<<<<< HEAD 2 +======= +>>>>>>> new-pomodoro 0 0 0 @@ -33,7 +41,11 @@ 0 1 1 +<<<<<<< HEAD 4 +======= +0 +>>>>>>> new-pomodoro 2 0 0 @@ -42,7 +54,11 @@ 0 0 2 +<<<<<<< HEAD 2 +======= +0 +>>>>>>> new-pomodoro 1 0 0 diff --git a/.flatpak-builder/ccache/1/e/4a3s1imp8vn5ttkra7143v8vc3b62oqR b/.flatpak-builder/ccache/1/e/4a3s1imp8vn5ttkra7143v8vc3b62oqR new file mode 100644 index 0000000..d195685 Binary files /dev/null and b/.flatpak-builder/ccache/1/e/4a3s1imp8vn5ttkra7143v8vc3b62oqR differ diff --git a/.flatpak-builder/ccache/1/e/6ccpl08d22oeqvr7hv1asti2isvdpd2M b/.flatpak-builder/ccache/1/e/6ccpl08d22oeqvr7hv1asti2isvdpd2M new file mode 100644 index 0000000..e8666bc Binary files /dev/null and b/.flatpak-builder/ccache/1/e/6ccpl08d22oeqvr7hv1asti2isvdpd2M differ diff --git a/.flatpak-builder/ccache/1/e/e0474uqqdvlr49gtsij9vhmq0kmiq5kM b/.flatpak-builder/ccache/1/e/e0474uqqdvlr49gtsij9vhmq0kmiq5kM new file mode 100644 index 0000000..b37ea2e Binary files /dev/null and b/.flatpak-builder/ccache/1/e/e0474uqqdvlr49gtsij9vhmq0kmiq5kM differ diff --git a/.flatpak-builder/ccache/1/e/efdfidfsnn5bn4m07g9otle68btuguoM b/.flatpak-builder/ccache/1/e/efdfidfsnn5bn4m07g9otle68btuguoM new file mode 100644 index 0000000..17c582d Binary files /dev/null and b/.flatpak-builder/ccache/1/e/efdfidfsnn5bn4m07g9otle68btuguoM differ diff --git a/.flatpak-builder/ccache/1/e/stats b/.flatpak-builder/ccache/1/e/stats index 9aaa00c..59e3d3a 100644 --- a/.flatpak-builder/ccache/1/e/stats +++ b/.flatpak-builder/ccache/1/e/stats @@ -2,12 +2,54 @@ 0 0 0 +<<<<<<< HEAD 1 +======= +2 +>>>>>>> new-pomodoro +0 +0 +0 +0 +0 +<<<<<<< HEAD +======= +0 +0 +0 +0 +0 +0 +0 +3 +0 +4 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +2 +2 +0 +4 +0 +0 0 0 0 0 +4 0 +>>>>>>> new-pomodoro 2 0 0 @@ -31,6 +73,7 @@ 0 0 0 +<<<<<<< HEAD 1 1 0 @@ -66,6 +109,8 @@ 0 0 0 +======= +>>>>>>> new-pomodoro 0 0 0 diff --git a/.flatpak-builder/ccache/1/f/0dmprd52p4h5lspv7e1ab9rqaffbg4oM b/.flatpak-builder/ccache/1/f/0dmprd52p4h5lspv7e1ab9rqaffbg4oM new file mode 100644 index 0000000..66e6c56 Binary files /dev/null and b/.flatpak-builder/ccache/1/f/0dmprd52p4h5lspv7e1ab9rqaffbg4oM differ diff --git a/.flatpak-builder/ccache/1/f/34nehod38e9ms1dgu4avduk5aefjuuuR b/.flatpak-builder/ccache/1/f/34nehod38e9ms1dgu4avduk5aefjuuuR new file mode 100644 index 0000000..344b35f Binary files /dev/null and b/.flatpak-builder/ccache/1/f/34nehod38e9ms1dgu4avduk5aefjuuuR differ diff --git a/.flatpak-builder/ccache/1/f/stats b/.flatpak-builder/ccache/1/f/stats index 68c5368..2a847fc 100644 --- a/.flatpak-builder/ccache/1/f/stats +++ b/.flatpak-builder/ccache/1/f/stats @@ -2,8 +2,16 @@ 0 0 0 +<<<<<<< HEAD +======= +3 +0 +0 +0 1 0 +>>>>>>> new-pomodoro +1 0 0 0 @@ -26,6 +34,8 @@ 0 0 0 +<<<<<<< HEAD +0 0 0 0 @@ -44,6 +54,21 @@ 2 0 1 +======= +4 +3 +1 +7 +0 +0 +0 +0 +0 +0 +7 +1 +3 +>>>>>>> new-pomodoro 0 0 0 diff --git a/.flatpak-builder/ccache/1/stats b/.flatpak-builder/ccache/1/stats index a4fb520..5765892 100644 --- a/.flatpak-builder/ccache/1/stats +++ b/.flatpak-builder/ccache/1/stats @@ -9,8 +9,13 @@ 0 0 0 +<<<<<<< HEAD 11 68 +======= +39 +636 +>>>>>>> new-pomodoro 0 0 0 @@ -47,6 +52,7 @@ 0 0 0 +<<<<<<< HEAD 1 1 1 @@ -79,4 +85,38 @@ 0 0 0 +======= +3 +4 +2 +2 +2 +1 +2 +1 +2 +3 +4 +1 +2 +4 +4 +2 +48 +72 +24 +12 +8 +20 +16 +20 +48 +60 +52 +20 +40 +72 +72 +52 +>>>>>>> new-pomodoro 0 diff --git a/.flatpak-builder/ccache/2/0/c42lj22c0s76q7cj1nkug95se8ts1f4M b/.flatpak-builder/ccache/2/0/c42lj22c0s76q7cj1nkug95se8ts1f4M new file mode 100644 index 0000000..d1eb5fa Binary files /dev/null and b/.flatpak-builder/ccache/2/0/c42lj22c0s76q7cj1nkug95se8ts1f4M differ diff --git a/.flatpak-builder/ccache/2/0/stats b/.flatpak-builder/ccache/2/0/stats index 68c5368..141bcfd 100644 --- a/.flatpak-builder/ccache/2/0/stats +++ b/.flatpak-builder/ccache/2/0/stats @@ -26,7 +26,11 @@ 0 0 0 +<<<<<<< HEAD 0 +======= +4 +>>>>>>> new-pomodoro 0 0 0 diff --git a/.flatpak-builder/ccache/2/1/09kf78k05qrv8ejdg3ntfvah4decid0M b/.flatpak-builder/ccache/2/1/09kf78k05qrv8ejdg3ntfvah4decid0M new file mode 100644 index 0000000..e977574 Binary files /dev/null and b/.flatpak-builder/ccache/2/1/09kf78k05qrv8ejdg3ntfvah4decid0M differ diff --git a/.flatpak-builder/ccache/2/1/5bngsv0bi5986pvkq0tq05emd3arsmoM b/.flatpak-builder/ccache/2/1/5bngsv0bi5986pvkq0tq05emd3arsmoM new file mode 100644 index 0000000..1d147af Binary files /dev/null and b/.flatpak-builder/ccache/2/1/5bngsv0bi5986pvkq0tq05emd3arsmoM differ diff --git a/.flatpak-builder/ccache/2/1/6138tknnt2g6nhbebn205b27qjnu2jsM b/.flatpak-builder/ccache/2/1/6138tknnt2g6nhbebn205b27qjnu2jsM new file mode 100644 index 0000000..9a75cab Binary files /dev/null and b/.flatpak-builder/ccache/2/1/6138tknnt2g6nhbebn205b27qjnu2jsM differ diff --git a/.flatpak-builder/ccache/2/1/62lk7kluujc7ofi4vo0ta928iio346mM b/.flatpak-builder/ccache/2/1/62lk7kluujc7ofi4vo0ta928iio346mM new file mode 100644 index 0000000..04dd0d5 Binary files /dev/null and b/.flatpak-builder/ccache/2/1/62lk7kluujc7ofi4vo0ta928iio346mM differ diff --git a/.flatpak-builder/ccache/2/1/bf4ppulbjt5ai8ltmakrec5jomtggicM b/.flatpak-builder/ccache/2/1/bf4ppulbjt5ai8ltmakrec5jomtggicM new file mode 100644 index 0000000..9ab7b67 Binary files /dev/null and b/.flatpak-builder/ccache/2/1/bf4ppulbjt5ai8ltmakrec5jomtggicM differ diff --git a/.flatpak-builder/ccache/2/1/fb4k132j69pvdi8r8b8hamidk3232uiM b/.flatpak-builder/ccache/2/1/fb4k132j69pvdi8r8b8hamidk3232uiM new file mode 100644 index 0000000..9972164 Binary files /dev/null and b/.flatpak-builder/ccache/2/1/fb4k132j69pvdi8r8b8hamidk3232uiM differ diff --git a/.flatpak-builder/ccache/2/1/stats b/.flatpak-builder/ccache/2/1/stats index 159047e..c7fe530 100644 --- a/.flatpak-builder/ccache/2/1/stats +++ b/.flatpak-builder/ccache/2/1/stats @@ -8,7 +8,11 @@ 0 0 0 +<<<<<<< HEAD 0 +======= +4 +>>>>>>> new-pomodoro 0 0 0 diff --git a/.flatpak-builder/ccache/2/2/stats b/.flatpak-builder/ccache/2/2/stats index fbe4d7f..e548246 100644 --- a/.flatpak-builder/ccache/2/2/stats +++ b/.flatpak-builder/ccache/2/2/stats @@ -2,6 +2,7 @@ 0 0 0 +<<<<<<< HEAD 3 0 0 @@ -10,10 +11,15 @@ 0 0 0 +======= +2 0 0 0 +1 0 +1 +>>>>>>> new-pomodoro 0 0 0 @@ -25,6 +31,14 @@ 0 0 0 +<<<<<<< HEAD +======= +2 +>>>>>>> new-pomodoro +0 +0 +0 +0 0 0 0 @@ -32,6 +46,7 @@ 0 0 3 +<<<<<<< HEAD 3 0 6 @@ -44,6 +59,20 @@ 6 0 3 +======= +2 +5 +5 +0 +0 +0 +0 +0 +0 +5 +3 +2 +>>>>>>> new-pomodoro 0 0 0 diff --git a/.flatpak-builder/ccache/2/3/9ajhfpu4qckkqlfacrtlttvovs78tc4R b/.flatpak-builder/ccache/2/3/9ajhfpu4qckkqlfacrtlttvovs78tc4R new file mode 100644 index 0000000..1a99174 Binary files /dev/null and b/.flatpak-builder/ccache/2/3/9ajhfpu4qckkqlfacrtlttvovs78tc4R differ diff --git a/.flatpak-builder/ccache/2/3/fcrslunvvbarsl6gekq3tojld2308h8R b/.flatpak-builder/ccache/2/3/fcrslunvvbarsl6gekq3tojld2308h8R new file mode 100644 index 0000000..5426dde Binary files /dev/null and b/.flatpak-builder/ccache/2/3/fcrslunvvbarsl6gekq3tojld2308h8R differ diff --git a/.flatpak-builder/ccache/2/4/743hoisl23sfej61ktmov6ekck110ioR b/.flatpak-builder/ccache/2/4/743hoisl23sfej61ktmov6ekck110ioR new file mode 100644 index 0000000..22cbbe7 Binary files /dev/null and b/.flatpak-builder/ccache/2/4/743hoisl23sfej61ktmov6ekck110ioR differ diff --git a/.flatpak-builder/ccache/2/4/stats b/.flatpak-builder/ccache/2/4/stats index 5e796ec..a622877 100644 --- a/.flatpak-builder/ccache/2/4/stats +++ b/.flatpak-builder/ccache/2/4/stats @@ -20,6 +20,7 @@ 1 0 0 +<<<<<<< HEAD 0 0 0 @@ -34,6 +35,8 @@ 1 1 0 +======= +>>>>>>> new-pomodoro 2 0 0 @@ -41,8 +44,27 @@ 0 0 0 +<<<<<<< HEAD 2 0 +======= +0 +0 +0 +0 +1 +1 +4 +2 +0 +0 +0 +0 +0 +0 +2 +2 +>>>>>>> new-pomodoro 1 0 0 diff --git a/.flatpak-builder/ccache/2/5/c3tnmalva7rt2miqj3ur1buee8jav82M b/.flatpak-builder/ccache/2/5/c3tnmalva7rt2miqj3ur1buee8jav82M new file mode 100644 index 0000000..da98bb9 Binary files /dev/null and b/.flatpak-builder/ccache/2/5/c3tnmalva7rt2miqj3ur1buee8jav82M differ diff --git a/.flatpak-builder/ccache/2/5/stats b/.flatpak-builder/ccache/2/5/stats new file mode 100644 index 0000000..baf883c --- /dev/null +++ b/.flatpak-builder/ccache/2/5/stats @@ -0,0 +1,82 @@ +0 +0 +0 +0 +0 +0 +0 +0 +4 +0 +0 +0 +0 +0 +0 +0 +0 +2 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +4 +0 +4 +4 +0 +0 +0 +0 +0 +0 +2 +4 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 diff --git a/.flatpak-builder/ccache/2/6/103424kubea4osqu4f9k94lupkn23dsM b/.flatpak-builder/ccache/2/6/103424kubea4osqu4f9k94lupkn23dsM new file mode 100644 index 0000000..8553f15 Binary files /dev/null and b/.flatpak-builder/ccache/2/6/103424kubea4osqu4f9k94lupkn23dsM differ diff --git a/.flatpak-builder/ccache/2/6/396h4vj2i7p5303sj0hq13s0vhmk5aaM b/.flatpak-builder/ccache/2/6/396h4vj2i7p5303sj0hq13s0vhmk5aaM new file mode 100644 index 0000000..499825e Binary files /dev/null and b/.flatpak-builder/ccache/2/6/396h4vj2i7p5303sj0hq13s0vhmk5aaM differ diff --git a/.flatpak-builder/ccache/2/6/a2a5jqpve5j9b2m2h82fqp8koq1k0q2M b/.flatpak-builder/ccache/2/6/a2a5jqpve5j9b2m2h82fqp8koq1k0q2M new file mode 100644 index 0000000..9c0f0bc Binary files /dev/null and b/.flatpak-builder/ccache/2/6/a2a5jqpve5j9b2m2h82fqp8koq1k0q2M differ diff --git a/.flatpak-builder/ccache/2/6/f9ph1ivkaciroebam4qrhovv65g7mdiM b/.flatpak-builder/ccache/2/6/f9ph1ivkaciroebam4qrhovv65g7mdiM new file mode 100644 index 0000000..4b18d6d Binary files /dev/null and b/.flatpak-builder/ccache/2/6/f9ph1ivkaciroebam4qrhovv65g7mdiM differ diff --git a/.flatpak-builder/ccache/2/6/stats b/.flatpak-builder/ccache/2/6/stats index 9aaa00c..c511f72 100644 --- a/.flatpak-builder/ccache/2/6/stats +++ b/.flatpak-builder/ccache/2/6/stats @@ -2,12 +2,54 @@ 0 0 0 +<<<<<<< HEAD 1 +======= +2 +>>>>>>> new-pomodoro +0 +0 +0 +0 +0 +<<<<<<< HEAD +======= +0 +0 +0 0 0 0 0 0 +0 +0 +0 +0 +2 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +2 +2 +4 +4 +0 +0 +0 +0 +0 +0 +4 +2 +>>>>>>> new-pomodoro 2 0 0 @@ -31,6 +73,7 @@ 0 0 0 +<<<<<<< HEAD 1 1 0 @@ -66,6 +109,8 @@ 0 0 0 +======= +>>>>>>> new-pomodoro 0 0 0 diff --git a/.flatpak-builder/ccache/2/7/19h2b3f7bghqfdcf43ggeepkb6a0or4M b/.flatpak-builder/ccache/2/7/19h2b3f7bghqfdcf43ggeepkb6a0or4M new file mode 100644 index 0000000..c7bbfaa Binary files /dev/null and b/.flatpak-builder/ccache/2/7/19h2b3f7bghqfdcf43ggeepkb6a0or4M differ diff --git a/.flatpak-builder/ccache/2/7/stats b/.flatpak-builder/ccache/2/7/stats index a46b94b..59451d6 100644 --- a/.flatpak-builder/ccache/2/7/stats +++ b/.flatpak-builder/ccache/2/7/stats @@ -8,22 +8,40 @@ 0 0 0 +<<<<<<< HEAD +======= +1 +0 +0 0 0 0 +>>>>>>> new-pomodoro 0 0 0 0 0 0 +<<<<<<< HEAD +======= +2 +>>>>>>> new-pomodoro +0 +0 0 0 0 +<<<<<<< HEAD +======= +3 +>>>>>>> new-pomodoro 0 0 0 0 +<<<<<<< HEAD +0 0 0 4 @@ -34,6 +52,11 @@ 1 1 0 +======= +1 +1 +4 +>>>>>>> new-pomodoro 2 0 0 @@ -42,7 +65,11 @@ 0 0 2 +<<<<<<< HEAD 0 +======= +2 +>>>>>>> new-pomodoro 1 0 0 diff --git a/.flatpak-builder/ccache/2/8/93qegjkjo9lh74e3g24ph3v30uhk2csR b/.flatpak-builder/ccache/2/8/93qegjkjo9lh74e3g24ph3v30uhk2csR new file mode 100644 index 0000000..14ff3ae Binary files /dev/null and b/.flatpak-builder/ccache/2/8/93qegjkjo9lh74e3g24ph3v30uhk2csR differ diff --git a/.flatpak-builder/ccache/2/8/stats b/.flatpak-builder/ccache/2/8/stats new file mode 100644 index 0000000..2f41575 --- /dev/null +++ b/.flatpak-builder/ccache/2/8/stats @@ -0,0 +1,82 @@ +0 +0 +0 +0 +2 +0 +0 +0 +0 +0 +2 +0 +0 +0 +0 +0 +0 +2 +0 +0 +0 +0 +2 +0 +0 +0 +0 +0 +2 +0 +0 +0 +0 +2 +2 +4 +4 +0 +0 +0 +0 +0 +0 +4 +2 +2 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 diff --git a/.flatpak-builder/ccache/2/9/0be391983gf5ttofi0skrkf9m7rq00gR b/.flatpak-builder/ccache/2/9/0be391983gf5ttofi0skrkf9m7rq00gR new file mode 100644 index 0000000..72d37aa Binary files /dev/null and b/.flatpak-builder/ccache/2/9/0be391983gf5ttofi0skrkf9m7rq00gR differ diff --git a/.flatpak-builder/ccache/2/9/24m37l9hjvr9brhrr6a8qfp37ht70coR b/.flatpak-builder/ccache/2/9/24m37l9hjvr9brhrr6a8qfp37ht70coR new file mode 100644 index 0000000..a97a66d Binary files /dev/null and b/.flatpak-builder/ccache/2/9/24m37l9hjvr9brhrr6a8qfp37ht70coR differ diff --git a/.flatpak-builder/ccache/2/9/64pambk528uve8bj6qs9rv2e2fgrt8aM b/.flatpak-builder/ccache/2/9/64pambk528uve8bj6qs9rv2e2fgrt8aM new file mode 100644 index 0000000..6836774 Binary files /dev/null and b/.flatpak-builder/ccache/2/9/64pambk528uve8bj6qs9rv2e2fgrt8aM differ diff --git a/.flatpak-builder/ccache/2/9/774v3u31q1ck67e79gsd127loafe062M b/.flatpak-builder/ccache/2/9/774v3u31q1ck67e79gsd127loafe062M new file mode 100644 index 0000000..e8504ec Binary files /dev/null and b/.flatpak-builder/ccache/2/9/774v3u31q1ck67e79gsd127loafe062M differ diff --git a/.flatpak-builder/ccache/2/9/stats b/.flatpak-builder/ccache/2/9/stats index 68c5368..123bbda 100644 --- a/.flatpak-builder/ccache/2/9/stats +++ b/.flatpak-builder/ccache/2/9/stats @@ -2,6 +2,13 @@ 0 0 0 +<<<<<<< HEAD +======= +3 +0 +0 +0 +>>>>>>> new-pomodoro 1 0 0 @@ -27,6 +34,7 @@ 0 0 0 +<<<<<<< HEAD 0 0 0 @@ -44,6 +52,21 @@ 2 0 1 +======= +4 +3 +1 +7 +0 +0 +0 +0 +0 +0 +7 +1 +3 +>>>>>>> new-pomodoro 0 0 0 diff --git a/.flatpak-builder/ccache/2/CACHEDIR.TAG b/.flatpak-builder/ccache/2/CACHEDIR.TAG new file mode 100644 index 0000000..874477f --- /dev/null +++ b/.flatpak-builder/ccache/2/CACHEDIR.TAG @@ -0,0 +1,4 @@ +Signature: 8a477f597d28d172789f06886806bc55 +# This file is a cache directory tag created by ccache. +# For information about cache directory tags, see: +# http://www.brynosaurus.com/cachedir/ diff --git a/.flatpak-builder/ccache/2/a/7dcdfqa8fgop9cbmmh84jhk6gui277aR b/.flatpak-builder/ccache/2/a/7dcdfqa8fgop9cbmmh84jhk6gui277aR new file mode 100644 index 0000000..82511b1 Binary files /dev/null and b/.flatpak-builder/ccache/2/a/7dcdfqa8fgop9cbmmh84jhk6gui277aR differ diff --git a/.flatpak-builder/ccache/2/a/stats b/.flatpak-builder/ccache/2/a/stats index d073591..2ad5de1 100644 --- a/.flatpak-builder/ccache/2/a/stats +++ b/.flatpak-builder/ccache/2/a/stats @@ -2,7 +2,11 @@ 0 0 0 +<<<<<<< HEAD 2 +======= +3 +>>>>>>> new-pomodoro 0 0 0 @@ -31,6 +35,7 @@ 0 0 0 +<<<<<<< HEAD 2 2 0 @@ -44,6 +49,21 @@ 3 0 2 +======= +3 +3 +0 +6 +0 +0 +0 +0 +0 +0 +5 +0 +3 +>>>>>>> new-pomodoro 0 0 0 diff --git a/.flatpak-builder/ccache/2/b/700nedjp0t7m0e8di194l6dlrafum8qM b/.flatpak-builder/ccache/2/b/700nedjp0t7m0e8di194l6dlrafum8qM new file mode 100644 index 0000000..4564d66 Binary files /dev/null and b/.flatpak-builder/ccache/2/b/700nedjp0t7m0e8di194l6dlrafum8qM differ diff --git a/.flatpak-builder/ccache/2/b/d5ft4qpfaaom72su6g9vq6s33nbdv4uM b/.flatpak-builder/ccache/2/b/d5ft4qpfaaom72su6g9vq6s33nbdv4uM new file mode 100644 index 0000000..5d2317b Binary files /dev/null and b/.flatpak-builder/ccache/2/b/d5ft4qpfaaom72su6g9vq6s33nbdv4uM differ diff --git a/.flatpak-builder/ccache/2/b/stats b/.flatpak-builder/ccache/2/b/stats index 159047e..1a6bcec 100644 --- a/.flatpak-builder/ccache/2/b/stats +++ b/.flatpak-builder/ccache/2/b/stats @@ -6,6 +6,7 @@ 0 0 0 +<<<<<<< HEAD 0 0 0 @@ -17,6 +18,8 @@ 0 0 0 +======= +>>>>>>> new-pomodoro 1 0 0 @@ -26,6 +29,7 @@ 0 0 0 +<<<<<<< HEAD 0 0 0 @@ -43,6 +47,36 @@ 0 0 0 +======= +2 +0 +1 +0 +0 +2 +0 +0 +0 +0 +0 +2 +0 +0 +0 +0 +1 +0 +5 +1 +0 +0 +0 +0 +0 +0 +1 +3 +>>>>>>> new-pomodoro 0 0 0 diff --git a/.flatpak-builder/ccache/2/c/27miljs9l6of9f9jgcobjdr4bim5as4R b/.flatpak-builder/ccache/2/c/27miljs9l6of9f9jgcobjdr4bim5as4R new file mode 100644 index 0000000..2bcb14f Binary files /dev/null and b/.flatpak-builder/ccache/2/c/27miljs9l6of9f9jgcobjdr4bim5as4R differ diff --git a/.flatpak-builder/ccache/2/c/a959srf7ilmverbi5d0mfk8jgjmdgbmM b/.flatpak-builder/ccache/2/c/a959srf7ilmverbi5d0mfk8jgjmdgbmM new file mode 100644 index 0000000..493243a Binary files /dev/null and b/.flatpak-builder/ccache/2/c/a959srf7ilmverbi5d0mfk8jgjmdgbmM differ diff --git a/.flatpak-builder/ccache/2/c/e4futd840b1bvqhf4qpikmfga30itqcR b/.flatpak-builder/ccache/2/c/e4futd840b1bvqhf4qpikmfga30itqcR new file mode 100644 index 0000000..2decd69 Binary files /dev/null and b/.flatpak-builder/ccache/2/c/e4futd840b1bvqhf4qpikmfga30itqcR differ diff --git a/.flatpak-builder/ccache/2/c/stats b/.flatpak-builder/ccache/2/c/stats index cd47901..e351c64 100644 --- a/.flatpak-builder/ccache/2/c/stats +++ b/.flatpak-builder/ccache/2/c/stats @@ -2,6 +2,7 @@ 0 0 0 +<<<<<<< HEAD 1 0 0 @@ -34,6 +35,8 @@ 1 1 0 +======= +>>>>>>> new-pomodoro 2 0 0 @@ -41,13 +44,52 @@ 0 0 0 +<<<<<<< HEAD 2 +======= +0 +0 +0 +0 +0 +0 +0 +0 +3 +0 +0 +0 +0 +0 +0 +0 +>>>>>>> new-pomodoro 0 1 0 0 0 0 +<<<<<<< HEAD +======= +2 +2 +0 +4 +0 +0 +0 +0 +0 +0 +4 +0 +2 +0 +0 +0 +0 +>>>>>>> new-pomodoro 0 0 0 diff --git a/.flatpak-builder/ccache/2/d/0dvl367q35fordh7tm388ahl402aeosM b/.flatpak-builder/ccache/2/d/0dvl367q35fordh7tm388ahl402aeosM new file mode 100644 index 0000000..e1dbd13 Binary files /dev/null and b/.flatpak-builder/ccache/2/d/0dvl367q35fordh7tm388ahl402aeosM differ diff --git a/.flatpak-builder/ccache/2/d/dbqoeq146nof1lqcm64m8eb700oet4gM b/.flatpak-builder/ccache/2/d/dbqoeq146nof1lqcm64m8eb700oet4gM new file mode 100644 index 0000000..b0a9ab4 Binary files /dev/null and b/.flatpak-builder/ccache/2/d/dbqoeq146nof1lqcm64m8eb700oet4gM differ diff --git a/.flatpak-builder/ccache/2/d/stats b/.flatpak-builder/ccache/2/d/stats index 3db7527..03145d3 100644 --- a/.flatpak-builder/ccache/2/d/stats +++ b/.flatpak-builder/ccache/2/d/stats @@ -2,6 +2,11 @@ 0 1 0 +<<<<<<< HEAD +======= +1 +0 +>>>>>>> new-pomodoro 0 0 0 @@ -29,6 +34,7 @@ 0 0 0 +<<<<<<< HEAD 0 0 1 @@ -44,6 +50,21 @@ 0 0 0 +======= +2 +2 +0 +4 +0 +0 +0 +0 +0 +0 +2 +0 +1 +>>>>>>> new-pomodoro 0 0 0 diff --git a/.flatpak-builder/ccache/2/e/e0lue4obeibsj8q0ac0julf3d0oksbaM b/.flatpak-builder/ccache/2/e/e0lue4obeibsj8q0ac0julf3d0oksbaM new file mode 100644 index 0000000..68ea556 Binary files /dev/null and b/.flatpak-builder/ccache/2/e/e0lue4obeibsj8q0ac0julf3d0oksbaM differ diff --git a/.flatpak-builder/ccache/2/e/stats b/.flatpak-builder/ccache/2/e/stats new file mode 100644 index 0000000..5896cf1 --- /dev/null +++ b/.flatpak-builder/ccache/2/e/stats @@ -0,0 +1,82 @@ +0 +0 +0 +0 +1 +0 +0 +0 +1 +0 +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +3 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +2 +1 +7 +3 +0 +0 +0 +0 +0 +0 +3 +4 +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 diff --git a/.flatpak-builder/ccache/2/stats b/.flatpak-builder/ccache/2/stats index dd514a2..8bcb25a 100644 --- a/.flatpak-builder/ccache/2/stats +++ b/.flatpak-builder/ccache/2/stats @@ -9,6 +9,7 @@ 0 0 0 +<<<<<<< HEAD 15 112 0 @@ -78,5 +79,76 @@ 0 8 0 +======= +44 +960 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +1 +6 +2 +4 +2 +1 +4 +2 +1 +6 +2 +4 +3 +4 +1 +1 +20 +108 +8 +100 +100 +20 +72 +12 +24 +88 +156 +40 +148 +48 +12 +>>>>>>> new-pomodoro 4 0 diff --git a/.flatpak-builder/ccache/3/0/7d5l260vbp41d5mbo87vdmrbob00ah0M b/.flatpak-builder/ccache/3/0/7d5l260vbp41d5mbo87vdmrbob00ah0M new file mode 100644 index 0000000..65a15f9 Binary files /dev/null and b/.flatpak-builder/ccache/3/0/7d5l260vbp41d5mbo87vdmrbob00ah0M differ diff --git a/.flatpak-builder/ccache/3/0/stats b/.flatpak-builder/ccache/3/0/stats index 5203da7..790d4c8 100644 --- a/.flatpak-builder/ccache/3/0/stats +++ b/.flatpak-builder/ccache/3/0/stats @@ -2,12 +2,20 @@ 0 0 0 +<<<<<<< HEAD +======= +2 +>>>>>>> new-pomodoro 0 0 0 0 +<<<<<<< HEAD 0 0 +======= +2 +>>>>>>> new-pomodoro 1 0 0 @@ -31,6 +39,7 @@ 0 0 0 +<<<<<<< HEAD 0 0 0 @@ -44,6 +53,21 @@ 0 0 0 +======= +2 +2 +0 +4 +0 +0 +0 +0 +0 +0 +4 +0 +2 +>>>>>>> new-pomodoro 0 0 0 diff --git a/.flatpak-builder/ccache/3/1/2260ohlievp0dgm22f52b2rhbkngtv8M b/.flatpak-builder/ccache/3/1/2260ohlievp0dgm22f52b2rhbkngtv8M new file mode 100644 index 0000000..a124877 Binary files /dev/null and b/.flatpak-builder/ccache/3/1/2260ohlievp0dgm22f52b2rhbkngtv8M differ diff --git a/.flatpak-builder/ccache/3/1/482ah26eiq0iogck4hbt4icekssk2fkR b/.flatpak-builder/ccache/3/1/482ah26eiq0iogck4hbt4icekssk2fkR new file mode 100644 index 0000000..9ad273d Binary files /dev/null and b/.flatpak-builder/ccache/3/1/482ah26eiq0iogck4hbt4icekssk2fkR differ diff --git a/.flatpak-builder/ccache/3/1/d1iouu2u86qbn70fvmidd0eehtjbctoM b/.flatpak-builder/ccache/3/1/d1iouu2u86qbn70fvmidd0eehtjbctoM new file mode 100644 index 0000000..d2eff17 Binary files /dev/null and b/.flatpak-builder/ccache/3/1/d1iouu2u86qbn70fvmidd0eehtjbctoM differ diff --git a/.flatpak-builder/ccache/3/1/stats b/.flatpak-builder/ccache/3/1/stats index 68c5368..778a4c4 100644 --- a/.flatpak-builder/ccache/3/1/stats +++ b/.flatpak-builder/ccache/3/1/stats @@ -2,6 +2,15 @@ 0 0 0 +<<<<<<< HEAD +======= +2 +0 +0 +0 +1 +0 +>>>>>>> new-pomodoro 1 0 0 @@ -25,6 +34,7 @@ 0 0 0 +<<<<<<< HEAD 0 0 0 @@ -34,6 +44,20 @@ 1 1 0 +======= +3 +2 +1 +5 +0 +0 +0 +0 +0 +0 +5 +1 +>>>>>>> new-pomodoro 2 0 0 @@ -41,6 +65,7 @@ 0 0 0 +<<<<<<< HEAD 2 0 1 @@ -50,6 +75,8 @@ 0 0 0 +======= +>>>>>>> new-pomodoro 0 0 0 diff --git a/.flatpak-builder/ccache/3/2/60nqftnl2e6j9hq772vfi8g6ih5p0gmR b/.flatpak-builder/ccache/3/2/60nqftnl2e6j9hq772vfi8g6ih5p0gmR new file mode 100644 index 0000000..f58ed71 Binary files /dev/null and b/.flatpak-builder/ccache/3/2/60nqftnl2e6j9hq772vfi8g6ih5p0gmR differ diff --git a/.flatpak-builder/ccache/3/2/7f7tc988iijb9bld4splbf75ked497cM b/.flatpak-builder/ccache/3/2/7f7tc988iijb9bld4splbf75ked497cM new file mode 100644 index 0000000..6ceef12 Binary files /dev/null and b/.flatpak-builder/ccache/3/2/7f7tc988iijb9bld4splbf75ked497cM differ diff --git a/.flatpak-builder/ccache/3/2/stats b/.flatpak-builder/ccache/3/2/stats index 94504b0..2db1455 100644 --- a/.flatpak-builder/ccache/3/2/stats +++ b/.flatpak-builder/ccache/3/2/stats @@ -20,21 +20,33 @@ 0 0 0 +<<<<<<< HEAD +======= +4 +>>>>>>> new-pomodoro 0 0 0 0 0 +<<<<<<< HEAD 0 1 0 0 +======= +4 +>>>>>>> new-pomodoro 0 0 0 0 0 0 +<<<<<<< HEAD +======= +8 +>>>>>>> new-pomodoro 0 0 0 @@ -43,6 +55,10 @@ 0 0 0 +<<<<<<< HEAD +======= +4 +>>>>>>> new-pomodoro 0 0 0 diff --git a/.flatpak-builder/ccache/3/3/aapd6sqbm8jftdjiq2sv6qqqvga0r6aR b/.flatpak-builder/ccache/3/3/aapd6sqbm8jftdjiq2sv6qqqvga0r6aR new file mode 100644 index 0000000..0c3062e Binary files /dev/null and b/.flatpak-builder/ccache/3/3/aapd6sqbm8jftdjiq2sv6qqqvga0r6aR differ diff --git a/.flatpak-builder/ccache/3/3/stats b/.flatpak-builder/ccache/3/3/stats index 68c5368..2396ccd 100644 --- a/.flatpak-builder/ccache/3/3/stats +++ b/.flatpak-builder/ccache/3/3/stats @@ -2,6 +2,7 @@ 0 0 0 +<<<<<<< HEAD 1 0 0 @@ -34,6 +35,8 @@ 1 1 0 +======= +>>>>>>> new-pomodoro 2 0 0 @@ -41,9 +44,47 @@ 0 0 0 +<<<<<<< HEAD 2 0 1 +======= +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +2 +2 +0 +4 +0 +0 +0 +0 +0 +0 +4 +0 +2 +>>>>>>> new-pomodoro 0 0 0 diff --git a/.flatpak-builder/ccache/3/4/95sn2ktaqd2hpq281e75puvppcm98ciM b/.flatpak-builder/ccache/3/4/95sn2ktaqd2hpq281e75puvppcm98ciM new file mode 100644 index 0000000..da7f2c8 Binary files /dev/null and b/.flatpak-builder/ccache/3/4/95sn2ktaqd2hpq281e75puvppcm98ciM differ diff --git a/.flatpak-builder/ccache/3/4/stats b/.flatpak-builder/ccache/3/4/stats index ff7d4de..94397d7 100644 --- a/.flatpak-builder/ccache/3/4/stats +++ b/.flatpak-builder/ccache/3/4/stats @@ -2,6 +2,13 @@ 0 0 0 +<<<<<<< HEAD +======= +1 +0 +0 +0 +>>>>>>> new-pomodoro 2 0 0 @@ -13,10 +20,13 @@ 0 0 0 +<<<<<<< HEAD 0 0 0 0 +======= +>>>>>>> new-pomodoro 1 0 0 @@ -31,9 +41,15 @@ 0 0 0 +<<<<<<< HEAD 2 2 0 +======= +3 +1 +2 +>>>>>>> new-pomodoro 4 0 0 @@ -42,8 +58,13 @@ 0 0 4 +<<<<<<< HEAD 0 2 +======= +2 +1 +>>>>>>> new-pomodoro 0 0 0 diff --git a/.flatpak-builder/ccache/3/5/67qph483ep2ltceat57er62hvqufa3sR b/.flatpak-builder/ccache/3/5/67qph483ep2ltceat57er62hvqufa3sR new file mode 100644 index 0000000..285eddc Binary files /dev/null and b/.flatpak-builder/ccache/3/5/67qph483ep2ltceat57er62hvqufa3sR differ diff --git a/.flatpak-builder/ccache/3/5/abbmf5clsdudun44fc5jlcjd6sfsaquM b/.flatpak-builder/ccache/3/5/abbmf5clsdudun44fc5jlcjd6sfsaquM new file mode 100644 index 0000000..f423ef6 Binary files /dev/null and b/.flatpak-builder/ccache/3/5/abbmf5clsdudun44fc5jlcjd6sfsaquM differ diff --git a/.flatpak-builder/ccache/3/5/ban152aradgjm28jhsucogrs26va8lsM b/.flatpak-builder/ccache/3/5/ban152aradgjm28jhsucogrs26va8lsM new file mode 100644 index 0000000..133d890 Binary files /dev/null and b/.flatpak-builder/ccache/3/5/ban152aradgjm28jhsucogrs26va8lsM differ diff --git a/.flatpak-builder/ccache/3/5/f3pbol95krrsr2lvjt6pbrbbrkcd3gkM b/.flatpak-builder/ccache/3/5/f3pbol95krrsr2lvjt6pbrbbrkcd3gkM new file mode 100644 index 0000000..f86cfd2 Binary files /dev/null and b/.flatpak-builder/ccache/3/5/f3pbol95krrsr2lvjt6pbrbbrkcd3gkM differ diff --git a/.flatpak-builder/ccache/3/5/stats b/.flatpak-builder/ccache/3/5/stats new file mode 100644 index 0000000..1e9aaf3 --- /dev/null +++ b/.flatpak-builder/ccache/3/5/stats @@ -0,0 +1,82 @@ +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +4 +0 +2 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 diff --git a/.flatpak-builder/ccache/3/6/4ed0gh1rdmh4amk7c1060d4omsm6moaM b/.flatpak-builder/ccache/3/6/4ed0gh1rdmh4amk7c1060d4omsm6moaM new file mode 100644 index 0000000..15e1874 Binary files /dev/null and b/.flatpak-builder/ccache/3/6/4ed0gh1rdmh4amk7c1060d4omsm6moaM differ diff --git a/.flatpak-builder/ccache/3/6/stats b/.flatpak-builder/ccache/3/6/stats index eccac08..c63e375 100644 --- a/.flatpak-builder/ccache/3/6/stats +++ b/.flatpak-builder/ccache/3/6/stats @@ -8,6 +8,7 @@ 0 0 0 +<<<<<<< HEAD 0 0 0 @@ -34,6 +35,8 @@ 1 1 0 +======= +>>>>>>> new-pomodoro 2 0 0 @@ -41,8 +44,39 @@ 0 0 0 +<<<<<<< HEAD 2 0 +======= +0 +0 +1 +0 +0 +1 +0 +0 +0 +0 +0 +2 +0 +0 +0 +0 +1 +1 +2 +2 +0 +0 +0 +0 +0 +0 +2 +1 +>>>>>>> new-pomodoro 1 0 0 diff --git a/.flatpak-builder/ccache/3/7/a5sa03mqb3f5v1airg9pgv6nj0gspeaM b/.flatpak-builder/ccache/3/7/a5sa03mqb3f5v1airg9pgv6nj0gspeaM new file mode 100644 index 0000000..b4028b8 Binary files /dev/null and b/.flatpak-builder/ccache/3/7/a5sa03mqb3f5v1airg9pgv6nj0gspeaM differ diff --git a/.flatpak-builder/ccache/3/7/caaq7iek01igu3sp7mrfdaic7mjo350M b/.flatpak-builder/ccache/3/7/caaq7iek01igu3sp7mrfdaic7mjo350M new file mode 100644 index 0000000..44cc778 Binary files /dev/null and b/.flatpak-builder/ccache/3/7/caaq7iek01igu3sp7mrfdaic7mjo350M differ diff --git a/.flatpak-builder/ccache/3/7/stats b/.flatpak-builder/ccache/3/7/stats index eccac08..55ccf80 100644 --- a/.flatpak-builder/ccache/3/7/stats +++ b/.flatpak-builder/ccache/3/7/stats @@ -2,11 +2,14 @@ 0 0 0 +<<<<<<< HEAD 1 0 0 0 0 +======= +>>>>>>> new-pomodoro 0 0 0 @@ -17,12 +20,16 @@ 0 0 0 +<<<<<<< HEAD 1 +======= +>>>>>>> new-pomodoro 0 0 0 0 0 +<<<<<<< HEAD 0 0 0 @@ -43,6 +50,8 @@ 0 2 0 +======= +>>>>>>> new-pomodoro 1 0 0 @@ -80,3 +89,32 @@ 0 0 0 +<<<<<<< HEAD +======= +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +>>>>>>> new-pomodoro diff --git a/.flatpak-builder/ccache/3/8/012arqsm0gotjkn16nrfinr5jt8mc8kR b/.flatpak-builder/ccache/3/8/012arqsm0gotjkn16nrfinr5jt8mc8kR new file mode 100644 index 0000000..c56a736 Binary files /dev/null and b/.flatpak-builder/ccache/3/8/012arqsm0gotjkn16nrfinr5jt8mc8kR differ diff --git a/.flatpak-builder/ccache/3/8/stats b/.flatpak-builder/ccache/3/8/stats index fdb1454..e4440aa 100644 --- a/.flatpak-builder/ccache/3/8/stats +++ b/.flatpak-builder/ccache/3/8/stats @@ -2,6 +2,22 @@ 0 0 0 +<<<<<<< HEAD +======= +3 +0 +0 +0 +0 +0 +1 +0 +0 +0 +0 +0 +0 +>>>>>>> new-pomodoro 2 0 0 @@ -18,12 +34,20 @@ 0 0 0 +<<<<<<< HEAD +======= +3 +3 +0 +6 +>>>>>>> new-pomodoro 0 0 0 0 0 0 +<<<<<<< HEAD 0 0 0 @@ -44,6 +68,11 @@ 4 0 2 +======= +6 +0 +3 +>>>>>>> new-pomodoro 0 0 0 diff --git a/.flatpak-builder/ccache/3/9/f8jabq09vo0cl5013gpg2fvb5omh2naM b/.flatpak-builder/ccache/3/9/f8jabq09vo0cl5013gpg2fvb5omh2naM new file mode 100644 index 0000000..5a8e2b2 Binary files /dev/null and b/.flatpak-builder/ccache/3/9/f8jabq09vo0cl5013gpg2fvb5omh2naM differ diff --git a/.flatpak-builder/ccache/3/9/stats b/.flatpak-builder/ccache/3/9/stats new file mode 100644 index 0000000..4ef9394 --- /dev/null +++ b/.flatpak-builder/ccache/3/9/stats @@ -0,0 +1,82 @@ +0 +0 +0 +0 +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +4 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +1 +1 +8 +2 +0 +0 +0 +0 +0 +0 +2 +4 +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 diff --git a/.flatpak-builder/ccache/3/CACHEDIR.TAG b/.flatpak-builder/ccache/3/CACHEDIR.TAG new file mode 100644 index 0000000..874477f --- /dev/null +++ b/.flatpak-builder/ccache/3/CACHEDIR.TAG @@ -0,0 +1,4 @@ +Signature: 8a477f597d28d172789f06886806bc55 +# This file is a cache directory tag created by ccache. +# For information about cache directory tags, see: +# http://www.brynosaurus.com/cachedir/ diff --git a/.flatpak-builder/ccache/3/a/2d7l2jjcvgod2goc5umt82cgknprug4R b/.flatpak-builder/ccache/3/a/2d7l2jjcvgod2goc5umt82cgknprug4R new file mode 100644 index 0000000..dff67e1 Binary files /dev/null and b/.flatpak-builder/ccache/3/a/2d7l2jjcvgod2goc5umt82cgknprug4R differ diff --git a/.flatpak-builder/ccache/3/a/48749h3m4oldutmo4jao2t53m1qk2vaR b/.flatpak-builder/ccache/3/a/48749h3m4oldutmo4jao2t53m1qk2vaR new file mode 100644 index 0000000..33be597 Binary files /dev/null and b/.flatpak-builder/ccache/3/a/48749h3m4oldutmo4jao2t53m1qk2vaR differ diff --git a/.flatpak-builder/ccache/3/a/53r4q0doks63g1g8dc93bk9dk26ilmaR b/.flatpak-builder/ccache/3/a/53r4q0doks63g1g8dc93bk9dk26ilmaR new file mode 100644 index 0000000..77ff6f2 Binary files /dev/null and b/.flatpak-builder/ccache/3/a/53r4q0doks63g1g8dc93bk9dk26ilmaR differ diff --git a/.flatpak-builder/ccache/3/a/7643vqggnf2cje23m160oglemr40ufkM b/.flatpak-builder/ccache/3/a/7643vqggnf2cje23m160oglemr40ufkM new file mode 100644 index 0000000..14646ba Binary files /dev/null and b/.flatpak-builder/ccache/3/a/7643vqggnf2cje23m160oglemr40ufkM differ diff --git a/.flatpak-builder/ccache/3/a/8018ud31j7g07vucv1olgv8oaqdsp48R b/.flatpak-builder/ccache/3/a/8018ud31j7g07vucv1olgv8oaqdsp48R new file mode 100644 index 0000000..10aed3a Binary files /dev/null and b/.flatpak-builder/ccache/3/a/8018ud31j7g07vucv1olgv8oaqdsp48R differ diff --git a/.flatpak-builder/ccache/3/a/e5ue6mpcbhc9esa8unltd5i26c6gdt4R b/.flatpak-builder/ccache/3/a/e5ue6mpcbhc9esa8unltd5i26c6gdt4R new file mode 100644 index 0000000..48ab096 Binary files /dev/null and b/.flatpak-builder/ccache/3/a/e5ue6mpcbhc9esa8unltd5i26c6gdt4R differ diff --git a/.flatpak-builder/ccache/3/a/stats b/.flatpak-builder/ccache/3/a/stats index fdb1454..2047b23 100644 --- a/.flatpak-builder/ccache/3/a/stats +++ b/.flatpak-builder/ccache/3/a/stats @@ -6,6 +6,7 @@ 0 0 0 +<<<<<<< HEAD 0 0 0 @@ -23,6 +24,11 @@ 0 0 0 +======= +1 +0 +1 +>>>>>>> new-pomodoro 0 0 0 @@ -32,17 +38,42 @@ 0 0 2 +<<<<<<< HEAD 2 0 4 +======= +0 +0 +1 +0 0 0 0 0 0 0 +0 +0 +0 +3 +2 +3 +5 +>>>>>>> new-pomodoro +0 +0 +0 +0 +0 +0 +<<<<<<< HEAD 4 0 +======= +5 +2 +>>>>>>> new-pomodoro 2 0 0 diff --git a/.flatpak-builder/ccache/3/b/71h88c9imse2olk6j67k9miip8mpghiR b/.flatpak-builder/ccache/3/b/71h88c9imse2olk6j67k9miip8mpghiR new file mode 100644 index 0000000..32f5db8 Binary files /dev/null and b/.flatpak-builder/ccache/3/b/71h88c9imse2olk6j67k9miip8mpghiR differ diff --git a/.flatpak-builder/ccache/3/b/stats b/.flatpak-builder/ccache/3/b/stats index 68c5368..3371c18 100644 --- a/.flatpak-builder/ccache/3/b/stats +++ b/.flatpak-builder/ccache/3/b/stats @@ -8,12 +8,22 @@ 0 0 0 +<<<<<<< HEAD +======= +1 +0 +0 +0 +0 +0 +>>>>>>> new-pomodoro 0 0 0 0 0 0 +<<<<<<< HEAD 0 0 0 @@ -34,6 +44,8 @@ 1 1 0 +======= +>>>>>>> new-pomodoro 2 0 0 @@ -41,8 +53,27 @@ 0 0 0 +<<<<<<< HEAD 2 0 +======= +0 +0 +0 +0 +1 +1 +4 +2 +0 +0 +0 +0 +0 +0 +2 +2 +>>>>>>> new-pomodoro 1 0 0 diff --git a/.flatpak-builder/ccache/3/c/24ji0n7al21bb9j0kbvlui4q3l0rl3mM b/.flatpak-builder/ccache/3/c/24ji0n7al21bb9j0kbvlui4q3l0rl3mM new file mode 100644 index 0000000..dd78c44 Binary files /dev/null and b/.flatpak-builder/ccache/3/c/24ji0n7al21bb9j0kbvlui4q3l0rl3mM differ diff --git a/.flatpak-builder/ccache/3/c/stats b/.flatpak-builder/ccache/3/c/stats index fdb1454..c548269 100644 --- a/.flatpak-builder/ccache/3/c/stats +++ b/.flatpak-builder/ccache/3/c/stats @@ -2,7 +2,11 @@ 0 0 0 +<<<<<<< HEAD 2 +======= +3 +>>>>>>> new-pomodoro 0 0 0 @@ -20,6 +24,10 @@ 0 0 0 +<<<<<<< HEAD +======= +5 +>>>>>>> new-pomodoro 0 0 0 @@ -30,20 +38,35 @@ 0 0 0 +<<<<<<< HEAD 0 2 2 0 4 +======= +3 +3 +10 +6 0 0 +>>>>>>> new-pomodoro 0 0 0 0 +<<<<<<< HEAD +0 +0 4 0 2 +======= +6 +5 +3 +>>>>>>> new-pomodoro 0 0 0 diff --git a/.flatpak-builder/ccache/3/d/f1f4p3lfrvns73loh5g6krno0h0b9msR b/.flatpak-builder/ccache/3/d/f1f4p3lfrvns73loh5g6krno0h0b9msR new file mode 100644 index 0000000..2393e3a Binary files /dev/null and b/.flatpak-builder/ccache/3/d/f1f4p3lfrvns73loh5g6krno0h0b9msR differ diff --git a/.flatpak-builder/ccache/3/d/stats b/.flatpak-builder/ccache/3/d/stats index 5203da7..8192081 100644 --- a/.flatpak-builder/ccache/3/d/stats +++ b/.flatpak-builder/ccache/3/d/stats @@ -2,10 +2,15 @@ 0 0 0 +<<<<<<< HEAD +======= +2 +>>>>>>> new-pomodoro 0 0 0 0 +<<<<<<< HEAD 0 0 1 @@ -17,6 +22,10 @@ 0 0 0 +======= +2 +3 +>>>>>>> new-pomodoro 0 0 0 @@ -28,6 +37,10 @@ 0 0 0 +<<<<<<< HEAD +======= +5 +>>>>>>> new-pomodoro 0 0 0 @@ -38,12 +51,25 @@ 0 0 0 +<<<<<<< HEAD +======= +2 +2 +10 +4 +>>>>>>> new-pomodoro 0 0 0 0 0 0 +<<<<<<< HEAD +======= +4 +5 +2 +>>>>>>> new-pomodoro 0 0 0 diff --git a/.flatpak-builder/ccache/3/e/a6t00uqgm36ajfkpjp3i7qje2a7v2okM b/.flatpak-builder/ccache/3/e/a6t00uqgm36ajfkpjp3i7qje2a7v2okM new file mode 100644 index 0000000..5c55153 Binary files /dev/null and b/.flatpak-builder/ccache/3/e/a6t00uqgm36ajfkpjp3i7qje2a7v2okM differ diff --git a/.flatpak-builder/ccache/3/e/stats b/.flatpak-builder/ccache/3/e/stats index 68c5368..123bbda 100644 --- a/.flatpak-builder/ccache/3/e/stats +++ b/.flatpak-builder/ccache/3/e/stats @@ -2,6 +2,13 @@ 0 0 0 +<<<<<<< HEAD +======= +3 +0 +0 +0 +>>>>>>> new-pomodoro 1 0 0 @@ -27,6 +34,7 @@ 0 0 0 +<<<<<<< HEAD 0 0 0 @@ -44,6 +52,21 @@ 2 0 1 +======= +4 +3 +1 +7 +0 +0 +0 +0 +0 +0 +7 +1 +3 +>>>>>>> new-pomodoro 0 0 0 diff --git a/.flatpak-builder/ccache/3/f/85bgovnc721p56ad62d67pk40bkaggcR b/.flatpak-builder/ccache/3/f/85bgovnc721p56ad62d67pk40bkaggcR new file mode 100644 index 0000000..19ec424 Binary files /dev/null and b/.flatpak-builder/ccache/3/f/85bgovnc721p56ad62d67pk40bkaggcR differ diff --git a/.flatpak-builder/ccache/3/f/f5serminroa8cft2tkpi1maccrofga0M b/.flatpak-builder/ccache/3/f/f5serminroa8cft2tkpi1maccrofga0M new file mode 100644 index 0000000..6062488 Binary files /dev/null and b/.flatpak-builder/ccache/3/f/f5serminroa8cft2tkpi1maccrofga0M differ diff --git a/.flatpak-builder/ccache/3/f/stats b/.flatpak-builder/ccache/3/f/stats new file mode 100644 index 0000000..2873c3b --- /dev/null +++ b/.flatpak-builder/ccache/3/f/stats @@ -0,0 +1,82 @@ +0 +0 +0 +0 +2 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +2 +0 +0 +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +2 +2 +2 +4 +0 +0 +0 +0 +0 +0 +4 +1 +2 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 diff --git a/.flatpak-builder/ccache/3/stats b/.flatpak-builder/ccache/3/stats index da1e1db..d5fad06 100644 --- a/.flatpak-builder/ccache/3/stats +++ b/.flatpak-builder/ccache/3/stats @@ -9,8 +9,13 @@ 0 0 0 +<<<<<<< HEAD 18 116 +======= +45 +976 +>>>>>>> new-pomodoro 0 0 0 @@ -47,6 +52,7 @@ 0 0 0 +<<<<<<< HEAD 2 0 0 @@ -79,4 +85,38 @@ 8 4 8 +======= +3 +3 +2 +2 +3 +7 +1 +2 +1 +2 +6 +3 +1 +3 +2 +4 +28 +48 +40 +40 +20 +84 +20 +28 +36 +24 +320 +188 +20 +16 +24 +40 +>>>>>>> new-pomodoro 0 diff --git a/.flatpak-builder/ccache/4/0/stats b/.flatpak-builder/ccache/4/0/stats index 68c5368..a135599 100644 --- a/.flatpak-builder/ccache/4/0/stats +++ b/.flatpak-builder/ccache/4/0/stats @@ -2,6 +2,13 @@ 0 0 0 +<<<<<<< HEAD +======= +2 +0 +0 +0 +>>>>>>> new-pomodoro 1 0 0 @@ -27,6 +34,7 @@ 0 0 0 +<<<<<<< HEAD 0 0 0 @@ -34,6 +42,20 @@ 1 1 0 +======= +3 +2 +1 +5 +0 +0 +0 +0 +0 +0 +5 +1 +>>>>>>> new-pomodoro 2 0 0 @@ -41,6 +63,7 @@ 0 0 0 +<<<<<<< HEAD 2 0 1 @@ -50,6 +73,8 @@ 0 0 0 +======= +>>>>>>> new-pomodoro 0 0 0 diff --git a/.flatpak-builder/ccache/4/1/67e05hfl6bbcr421sv4v4n6h7ggg7niM b/.flatpak-builder/ccache/4/1/67e05hfl6bbcr421sv4v4n6h7ggg7niM new file mode 100644 index 0000000..6272622 Binary files /dev/null and b/.flatpak-builder/ccache/4/1/67e05hfl6bbcr421sv4v4n6h7ggg7niM differ diff --git a/.flatpak-builder/ccache/4/1/82d0qs4qdsuvokg8oakajl1jld0h4uuM b/.flatpak-builder/ccache/4/1/82d0qs4qdsuvokg8oakajl1jld0h4uuM new file mode 100644 index 0000000..aa2fac1 Binary files /dev/null and b/.flatpak-builder/ccache/4/1/82d0qs4qdsuvokg8oakajl1jld0h4uuM differ diff --git a/.flatpak-builder/ccache/4/1/d43r1299hl2au8qcp64dr0fgrvod556M b/.flatpak-builder/ccache/4/1/d43r1299hl2au8qcp64dr0fgrvod556M new file mode 100644 index 0000000..ab181c9 Binary files /dev/null and b/.flatpak-builder/ccache/4/1/d43r1299hl2au8qcp64dr0fgrvod556M differ diff --git a/.flatpak-builder/ccache/4/2/5b6m0nd44dr6beksh2jm3i6c8h3f6kgM b/.flatpak-builder/ccache/4/2/5b6m0nd44dr6beksh2jm3i6c8h3f6kgM new file mode 100644 index 0000000..ba35de3 Binary files /dev/null and b/.flatpak-builder/ccache/4/2/5b6m0nd44dr6beksh2jm3i6c8h3f6kgM differ diff --git a/.flatpak-builder/ccache/4/2/6f121vgn9ib7ddnnqe49ucdgscbplhiM b/.flatpak-builder/ccache/4/2/6f121vgn9ib7ddnnqe49ucdgscbplhiM new file mode 100644 index 0000000..91f5cbe Binary files /dev/null and b/.flatpak-builder/ccache/4/2/6f121vgn9ib7ddnnqe49ucdgscbplhiM differ diff --git a/.flatpak-builder/ccache/4/2/bfi7ki47dpithm8rqba6d69sql1jkekM b/.flatpak-builder/ccache/4/2/bfi7ki47dpithm8rqba6d69sql1jkekM new file mode 100644 index 0000000..5c3c3f7 Binary files /dev/null and b/.flatpak-builder/ccache/4/2/bfi7ki47dpithm8rqba6d69sql1jkekM differ diff --git a/.flatpak-builder/ccache/4/2/e66tdb3gp9571dcjvcvdkiep2ffgp22M b/.flatpak-builder/ccache/4/2/e66tdb3gp9571dcjvcvdkiep2ffgp22M new file mode 100644 index 0000000..e9eb378 Binary files /dev/null and b/.flatpak-builder/ccache/4/2/e66tdb3gp9571dcjvcvdkiep2ffgp22M differ diff --git a/.flatpak-builder/ccache/4/2/stats b/.flatpak-builder/ccache/4/2/stats index ff7d4de..4f0eaf7 100644 --- a/.flatpak-builder/ccache/4/2/stats +++ b/.flatpak-builder/ccache/4/2/stats @@ -1,6 +1,10 @@ 0 0 +<<<<<<< HEAD 0 +======= +2 +>>>>>>> new-pomodoro 0 2 0 @@ -15,7 +19,11 @@ 0 0 0 +<<<<<<< HEAD 0 +======= +2 +>>>>>>> new-pomodoro 0 1 0 @@ -31,10 +39,17 @@ 0 0 0 +<<<<<<< HEAD 2 2 0 4 +======= +4 +4 +0 +8 +>>>>>>> new-pomodoro 0 0 0 diff --git a/.flatpak-builder/ccache/4/3/7esgaj5ta4ft99hs2354gpn226fhc70M b/.flatpak-builder/ccache/4/3/7esgaj5ta4ft99hs2354gpn226fhc70M new file mode 100644 index 0000000..16a0b0c Binary files /dev/null and b/.flatpak-builder/ccache/4/3/7esgaj5ta4ft99hs2354gpn226fhc70M differ diff --git a/.flatpak-builder/ccache/4/3/b980na2u3qbutq21ea12cub56eh2322M b/.flatpak-builder/ccache/4/3/b980na2u3qbutq21ea12cub56eh2322M new file mode 100644 index 0000000..a0d616b Binary files /dev/null and b/.flatpak-builder/ccache/4/3/b980na2u3qbutq21ea12cub56eh2322M differ diff --git a/.flatpak-builder/ccache/4/3/c1hn305inkhhqc15f7g38emuqkkm3rkM b/.flatpak-builder/ccache/4/3/c1hn305inkhhqc15f7g38emuqkkm3rkM new file mode 100644 index 0000000..b9db68d Binary files /dev/null and b/.flatpak-builder/ccache/4/3/c1hn305inkhhqc15f7g38emuqkkm3rkM differ diff --git a/.flatpak-builder/ccache/4/3/c28bb3jr5busgkfqmguhdp136i99p3sR b/.flatpak-builder/ccache/4/3/c28bb3jr5busgkfqmguhdp136i99p3sR new file mode 100644 index 0000000..e0fd3b6 Binary files /dev/null and b/.flatpak-builder/ccache/4/3/c28bb3jr5busgkfqmguhdp136i99p3sR differ diff --git a/.flatpak-builder/ccache/4/3/stats b/.flatpak-builder/ccache/4/3/stats new file mode 100644 index 0000000..621acad --- /dev/null +++ b/.flatpak-builder/ccache/4/3/stats @@ -0,0 +1,82 @@ +0 +0 +0 +0 +1 +0 +0 +0 +0 +0 +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +1 +1 +0 +2 +0 +0 +0 +0 +0 +0 +2 +0 +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 diff --git a/.flatpak-builder/ccache/4/4/28vmgg9e4ql14dvho5nv8blci3jtctgM b/.flatpak-builder/ccache/4/4/28vmgg9e4ql14dvho5nv8blci3jtctgM new file mode 100644 index 0000000..5db7fc4 Binary files /dev/null and b/.flatpak-builder/ccache/4/4/28vmgg9e4ql14dvho5nv8blci3jtctgM differ diff --git a/.flatpak-builder/ccache/4/4/e5rjr6s2eepj98qoomnm2497q0kpv4uM b/.flatpak-builder/ccache/4/4/e5rjr6s2eepj98qoomnm2497q0kpv4uM new file mode 100644 index 0000000..797cd9d Binary files /dev/null and b/.flatpak-builder/ccache/4/4/e5rjr6s2eepj98qoomnm2497q0kpv4uM differ diff --git a/.flatpak-builder/ccache/4/4/efhqkfprrhh8f46sjqsipqqbkr4v66gM b/.flatpak-builder/ccache/4/4/efhqkfprrhh8f46sjqsipqqbkr4v66gM new file mode 100644 index 0000000..63988ab Binary files /dev/null and b/.flatpak-builder/ccache/4/4/efhqkfprrhh8f46sjqsipqqbkr4v66gM differ diff --git a/.flatpak-builder/ccache/4/4/stats b/.flatpak-builder/ccache/4/4/stats index 68c5368..a135599 100644 --- a/.flatpak-builder/ccache/4/4/stats +++ b/.flatpak-builder/ccache/4/4/stats @@ -2,6 +2,13 @@ 0 0 0 +<<<<<<< HEAD +======= +2 +0 +0 +0 +>>>>>>> new-pomodoro 1 0 0 @@ -27,6 +34,7 @@ 0 0 0 +<<<<<<< HEAD 0 0 0 @@ -34,6 +42,20 @@ 1 1 0 +======= +3 +2 +1 +5 +0 +0 +0 +0 +0 +0 +5 +1 +>>>>>>> new-pomodoro 2 0 0 @@ -41,6 +63,7 @@ 0 0 0 +<<<<<<< HEAD 2 0 1 @@ -50,6 +73,8 @@ 0 0 0 +======= +>>>>>>> new-pomodoro 0 0 0 diff --git a/.flatpak-builder/ccache/4/5/68c90lu29u87pnp5ncf5eocalph4mhgR b/.flatpak-builder/ccache/4/5/68c90lu29u87pnp5ncf5eocalph4mhgR new file mode 100644 index 0000000..182a578 Binary files /dev/null and b/.flatpak-builder/ccache/4/5/68c90lu29u87pnp5ncf5eocalph4mhgR differ diff --git a/.flatpak-builder/ccache/4/5/7e2sh6nc543oulofk0fp0f1cul7m950M b/.flatpak-builder/ccache/4/5/7e2sh6nc543oulofk0fp0f1cul7m950M new file mode 100644 index 0000000..5167ae8 Binary files /dev/null and b/.flatpak-builder/ccache/4/5/7e2sh6nc543oulofk0fp0f1cul7m950M differ diff --git a/.flatpak-builder/ccache/4/5/8b1q2m583somatoij54vgss30neph7aR b/.flatpak-builder/ccache/4/5/8b1q2m583somatoij54vgss30neph7aR new file mode 100644 index 0000000..c7b8c97 Binary files /dev/null and b/.flatpak-builder/ccache/4/5/8b1q2m583somatoij54vgss30neph7aR differ diff --git a/.flatpak-builder/ccache/4/5/ae1nbf9l70cdde3o24qj7s0tksgtfkeR b/.flatpak-builder/ccache/4/5/ae1nbf9l70cdde3o24qj7s0tksgtfkeR new file mode 100644 index 0000000..3999871 Binary files /dev/null and b/.flatpak-builder/ccache/4/5/ae1nbf9l70cdde3o24qj7s0tksgtfkeR differ diff --git a/.flatpak-builder/ccache/4/5/stats b/.flatpak-builder/ccache/4/5/stats index 3db7527..758abac 100644 --- a/.flatpak-builder/ccache/4/5/stats +++ b/.flatpak-builder/ccache/4/5/stats @@ -2,6 +2,17 @@ 0 1 0 +<<<<<<< HEAD +======= +1 +0 +0 +0 +0 +0 +1 +0 +>>>>>>> new-pomodoro 0 0 0 @@ -12,6 +23,7 @@ 0 0 0 +<<<<<<< HEAD 0 0 0 @@ -34,6 +46,8 @@ 1 1 0 +======= +>>>>>>> new-pomodoro 2 0 0 @@ -45,6 +59,23 @@ 0 0 0 +<<<<<<< HEAD +======= +2 +2 +4 +4 +0 +0 +0 +0 +0 +0 +2 +2 +1 +0 +>>>>>>> new-pomodoro 0 0 0 diff --git a/.flatpak-builder/ccache/4/6/0f9rlngggu56p4gleoj04ctogrj1mvoM b/.flatpak-builder/ccache/4/6/0f9rlngggu56p4gleoj04ctogrj1mvoM new file mode 100644 index 0000000..fbc38aa Binary files /dev/null and b/.flatpak-builder/ccache/4/6/0f9rlngggu56p4gleoj04ctogrj1mvoM differ diff --git a/.flatpak-builder/ccache/4/6/15ik556hoco47s0tink7oljvg7atajoM b/.flatpak-builder/ccache/4/6/15ik556hoco47s0tink7oljvg7atajoM new file mode 100644 index 0000000..1ad179c Binary files /dev/null and b/.flatpak-builder/ccache/4/6/15ik556hoco47s0tink7oljvg7atajoM differ diff --git a/.flatpak-builder/ccache/4/6/c2u4t95g34cvoga2f41lkdq84asob3gR b/.flatpak-builder/ccache/4/6/c2u4t95g34cvoga2f41lkdq84asob3gR new file mode 100644 index 0000000..2bc9d84 Binary files /dev/null and b/.flatpak-builder/ccache/4/6/c2u4t95g34cvoga2f41lkdq84asob3gR differ diff --git a/.flatpak-builder/ccache/4/6/stats b/.flatpak-builder/ccache/4/6/stats index d7cfc2e..567e0a6 100644 --- a/.flatpak-builder/ccache/4/6/stats +++ b/.flatpak-builder/ccache/4/6/stats @@ -6,6 +6,7 @@ 0 0 0 +<<<<<<< HEAD 0 0 0 @@ -15,6 +16,8 @@ 0 0 0 +======= +>>>>>>> new-pomodoro 1 0 1 @@ -24,6 +27,7 @@ 0 0 0 +<<<<<<< HEAD 0 0 0 @@ -33,6 +37,12 @@ 0 1 1 +======= +1 +0 +1 +0 +>>>>>>> new-pomodoro 0 2 0 @@ -41,8 +51,27 @@ 0 0 0 +<<<<<<< HEAD +2 +0 +======= +0 +0 +0 +0 2 +1 +5 +3 +0 +0 +0 +0 +0 0 +3 +3 +>>>>>>> new-pomodoro 1 0 0 diff --git a/.flatpak-builder/ccache/4/7/3c1mgvfsqr3oeonk8gjtbljphd2bv9eM b/.flatpak-builder/ccache/4/7/3c1mgvfsqr3oeonk8gjtbljphd2bv9eM new file mode 100644 index 0000000..a122d7b Binary files /dev/null and b/.flatpak-builder/ccache/4/7/3c1mgvfsqr3oeonk8gjtbljphd2bv9eM differ diff --git a/.flatpak-builder/ccache/4/7/697uc5go1m97ntsj7vnei0ro332oi62M b/.flatpak-builder/ccache/4/7/697uc5go1m97ntsj7vnei0ro332oi62M new file mode 100644 index 0000000..229fbb9 Binary files /dev/null and b/.flatpak-builder/ccache/4/7/697uc5go1m97ntsj7vnei0ro332oi62M differ diff --git a/.flatpak-builder/ccache/4/7/abnbe7uruocj982b8vfptnum07pf3fgM b/.flatpak-builder/ccache/4/7/abnbe7uruocj982b8vfptnum07pf3fgM new file mode 100644 index 0000000..4e28526 Binary files /dev/null and b/.flatpak-builder/ccache/4/7/abnbe7uruocj982b8vfptnum07pf3fgM differ diff --git a/.flatpak-builder/ccache/4/7/d5gkkej9trl9bijf8k7figdus19thm2M b/.flatpak-builder/ccache/4/7/d5gkkej9trl9bijf8k7figdus19thm2M new file mode 100644 index 0000000..e2b98e8 Binary files /dev/null and b/.flatpak-builder/ccache/4/7/d5gkkej9trl9bijf8k7figdus19thm2M differ diff --git a/.flatpak-builder/ccache/4/7/stats b/.flatpak-builder/ccache/4/7/stats index 621acad..5f0c55e 100644 --- a/.flatpak-builder/ccache/4/7/stats +++ b/.flatpak-builder/ccache/4/7/stats @@ -2,6 +2,7 @@ 0 0 0 +<<<<<<< HEAD 1 0 0 @@ -9,7 +10,15 @@ 0 0 1 +======= +2 +0 +0 +0 +1 0 +3 +>>>>>>> new-pomodoro 0 0 0 @@ -21,6 +30,8 @@ 0 0 0 +<<<<<<< HEAD +0 0 0 0 @@ -34,6 +45,8 @@ 1 1 0 +======= +>>>>>>> new-pomodoro 2 0 0 @@ -41,10 +54,31 @@ 0 0 0 +<<<<<<< HEAD 2 0 1 0 +======= +0 +0 +0 +0 +3 +2 +5 +5 +0 +0 +0 +0 +0 +0 +5 +3 +2 +0 +>>>>>>> new-pomodoro 0 0 0 diff --git a/.flatpak-builder/ccache/4/8/e5uogdpoir107fgh1jflp6kpd2de484M b/.flatpak-builder/ccache/4/8/e5uogdpoir107fgh1jflp6kpd2de484M new file mode 100644 index 0000000..927b496 Binary files /dev/null and b/.flatpak-builder/ccache/4/8/e5uogdpoir107fgh1jflp6kpd2de484M differ diff --git a/.flatpak-builder/ccache/4/9/8fjgsbd3u612hl2hde4a96641afs25aM b/.flatpak-builder/ccache/4/9/8fjgsbd3u612hl2hde4a96641afs25aM new file mode 100644 index 0000000..cbf05ba Binary files /dev/null and b/.flatpak-builder/ccache/4/9/8fjgsbd3u612hl2hde4a96641afs25aM differ diff --git a/.flatpak-builder/ccache/4/9/stats b/.flatpak-builder/ccache/4/9/stats index a2f99a7..f5b2e1e 100644 --- a/.flatpak-builder/ccache/4/9/stats +++ b/.flatpak-builder/ccache/4/9/stats @@ -2,6 +2,7 @@ 0 0 0 +<<<<<<< HEAD 1 0 0 @@ -9,6 +10,8 @@ 0 0 0 +======= +>>>>>>> new-pomodoro 0 0 0 @@ -22,6 +25,7 @@ 0 0 0 +<<<<<<< HEAD 0 0 0 @@ -43,11 +47,44 @@ 0 2 0 +======= +>>>>>>> new-pomodoro 1 0 0 0 0 +<<<<<<< HEAD +======= +4 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +8 +0 +0 +0 +0 +0 +0 +0 +0 +4 +0 +0 +0 +0 +0 +>>>>>>> new-pomodoro 0 0 0 diff --git a/.flatpak-builder/ccache/4/CACHEDIR.TAG b/.flatpak-builder/ccache/4/CACHEDIR.TAG new file mode 100644 index 0000000..874477f --- /dev/null +++ b/.flatpak-builder/ccache/4/CACHEDIR.TAG @@ -0,0 +1,4 @@ +Signature: 8a477f597d28d172789f06886806bc55 +# This file is a cache directory tag created by ccache. +# For information about cache directory tags, see: +# http://www.brynosaurus.com/cachedir/ diff --git a/.flatpak-builder/ccache/4/a/c4lro4skjqa6cu8v75vplohd3ve37ccM b/.flatpak-builder/ccache/4/a/c4lro4skjqa6cu8v75vplohd3ve37ccM new file mode 100644 index 0000000..9759379 Binary files /dev/null and b/.flatpak-builder/ccache/4/a/c4lro4skjqa6cu8v75vplohd3ve37ccM differ diff --git a/.flatpak-builder/ccache/4/a/f1e3cp5rlfaltmcuokp104aigar6k7aR b/.flatpak-builder/ccache/4/a/f1e3cp5rlfaltmcuokp104aigar6k7aR new file mode 100644 index 0000000..d664353 Binary files /dev/null and b/.flatpak-builder/ccache/4/a/f1e3cp5rlfaltmcuokp104aigar6k7aR differ diff --git a/.flatpak-builder/ccache/4/a/stats b/.flatpak-builder/ccache/4/a/stats new file mode 100644 index 0000000..f65b672 --- /dev/null +++ b/.flatpak-builder/ccache/4/a/stats @@ -0,0 +1,82 @@ +0 +0 +0 +0 +2 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +2 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +2 +2 +4 +4 +0 +0 +0 +0 +0 +0 +4 +2 +2 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 diff --git a/.flatpak-builder/ccache/4/b/32scn062qm467qblph7ns5hp8tl463sM b/.flatpak-builder/ccache/4/b/32scn062qm467qblph7ns5hp8tl463sM new file mode 100644 index 0000000..89a219a Binary files /dev/null and b/.flatpak-builder/ccache/4/b/32scn062qm467qblph7ns5hp8tl463sM differ diff --git a/.flatpak-builder/ccache/4/b/512essl5m9k39v45ed441p51405e7ccR b/.flatpak-builder/ccache/4/b/512essl5m9k39v45ed441p51405e7ccR new file mode 100644 index 0000000..73f5c9f Binary files /dev/null and b/.flatpak-builder/ccache/4/b/512essl5m9k39v45ed441p51405e7ccR differ diff --git a/.flatpak-builder/ccache/4/b/d583tgvlmkbp6c1qj6vlgt1t0ec1rd8M b/.flatpak-builder/ccache/4/b/d583tgvlmkbp6c1qj6vlgt1t0ec1rd8M new file mode 100644 index 0000000..276bff3 Binary files /dev/null and b/.flatpak-builder/ccache/4/b/d583tgvlmkbp6c1qj6vlgt1t0ec1rd8M differ diff --git a/.flatpak-builder/ccache/4/b/stats b/.flatpak-builder/ccache/4/b/stats new file mode 100644 index 0000000..68c5368 --- /dev/null +++ b/.flatpak-builder/ccache/4/b/stats @@ -0,0 +1,82 @@ +0 +0 +0 +0 +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +1 +1 +0 +2 +0 +0 +0 +0 +0 +0 +2 +0 +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 diff --git a/.flatpak-builder/ccache/4/c/15dpp8u2vog5tumrsnlk756lnirov10R b/.flatpak-builder/ccache/4/c/15dpp8u2vog5tumrsnlk756lnirov10R new file mode 100644 index 0000000..7ecdae5 Binary files /dev/null and b/.flatpak-builder/ccache/4/c/15dpp8u2vog5tumrsnlk756lnirov10R differ diff --git a/.flatpak-builder/ccache/4/c/60ju37bqsajg2ogakk5755igf38fa9uM b/.flatpak-builder/ccache/4/c/60ju37bqsajg2ogakk5755igf38fa9uM new file mode 100644 index 0000000..a8f1e53 Binary files /dev/null and b/.flatpak-builder/ccache/4/c/60ju37bqsajg2ogakk5755igf38fa9uM differ diff --git a/.flatpak-builder/ccache/4/c/b4of1bo7ftj5u1un6buspadqqjl9ib8M b/.flatpak-builder/ccache/4/c/b4of1bo7ftj5u1un6buspadqqjl9ib8M new file mode 100644 index 0000000..d3d0573 Binary files /dev/null and b/.flatpak-builder/ccache/4/c/b4of1bo7ftj5u1un6buspadqqjl9ib8M differ diff --git a/.flatpak-builder/ccache/4/c/stats b/.flatpak-builder/ccache/4/c/stats index 68c5368..f35da92 100644 --- a/.flatpak-builder/ccache/4/c/stats +++ b/.flatpak-builder/ccache/4/c/stats @@ -6,6 +6,13 @@ 0 0 0 +<<<<<<< HEAD +======= +1 +0 +0 +0 +>>>>>>> new-pomodoro 0 0 0 @@ -16,6 +23,7 @@ 0 0 0 +<<<<<<< HEAD 0 0 0 @@ -34,6 +42,8 @@ 1 1 0 +======= +>>>>>>> new-pomodoro 2 0 0 @@ -41,8 +51,27 @@ 0 0 0 +<<<<<<< HEAD +2 +0 +======= +0 +0 +0 +0 2 +1 +5 +3 +0 +0 +0 +0 +0 0 +3 +3 +>>>>>>> new-pomodoro 1 0 0 diff --git a/.flatpak-builder/ccache/4/d/34vl9d5ev1eq5s0t6j5e07j11shn0ggM b/.flatpak-builder/ccache/4/d/34vl9d5ev1eq5s0t6j5e07j11shn0ggM new file mode 100644 index 0000000..2bc7382 Binary files /dev/null and b/.flatpak-builder/ccache/4/d/34vl9d5ev1eq5s0t6j5e07j11shn0ggM differ diff --git a/.flatpak-builder/ccache/4/d/7b6gr4sv7lrtpki0b7l26a797k5etd6M b/.flatpak-builder/ccache/4/d/7b6gr4sv7lrtpki0b7l26a797k5etd6M new file mode 100644 index 0000000..37f5edc Binary files /dev/null and b/.flatpak-builder/ccache/4/d/7b6gr4sv7lrtpki0b7l26a797k5etd6M differ diff --git a/.flatpak-builder/ccache/4/d/c1m5il49e20a2veoh6rp9d4e9m039c0M b/.flatpak-builder/ccache/4/d/c1m5il49e20a2veoh6rp9d4e9m039c0M new file mode 100644 index 0000000..821b6ce Binary files /dev/null and b/.flatpak-builder/ccache/4/d/c1m5il49e20a2veoh6rp9d4e9m039c0M differ diff --git a/.flatpak-builder/ccache/4/d/stats b/.flatpak-builder/ccache/4/d/stats new file mode 100644 index 0000000..91903e7 --- /dev/null +++ b/.flatpak-builder/ccache/4/d/stats @@ -0,0 +1,82 @@ +0 +0 +0 +0 +0 +0 +0 +0 +1 +0 +0 +0 +0 +0 +0 +0 +0 +2 +0 +2 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +1 +0 +1 +1 +0 +0 +0 +0 +0 +0 +1 +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 diff --git a/.flatpak-builder/ccache/4/e/stats b/.flatpak-builder/ccache/4/e/stats index 7367a33..c9e3d55 100644 --- a/.flatpak-builder/ccache/4/e/stats +++ b/.flatpak-builder/ccache/4/e/stats @@ -2,6 +2,7 @@ 0 0 0 +<<<<<<< HEAD 1 0 0 @@ -28,12 +29,52 @@ 0 0 0 +======= +2 +>>>>>>> new-pomodoro 0 0 0 1 1 0 +<<<<<<< HEAD +======= +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +6 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +3 +2 +13 +5 +0 +0 +0 +0 +0 +0 +5 +7 +>>>>>>> new-pomodoro 2 0 0 @@ -41,6 +82,7 @@ 0 0 0 +<<<<<<< HEAD 2 0 1 @@ -50,6 +92,8 @@ 0 0 0 +======= +>>>>>>> new-pomodoro 0 0 0 diff --git a/.flatpak-builder/ccache/4/f/stats b/.flatpak-builder/ccache/4/f/stats new file mode 100644 index 0000000..894a8d9 --- /dev/null +++ b/.flatpak-builder/ccache/4/f/stats @@ -0,0 +1,82 @@ +0 +0 +0 +0 +0 +0 +0 +0 +1 +0 +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +1 +0 +1 +1 +0 +0 +0 +0 +0 +0 +1 +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 diff --git a/.flatpak-builder/ccache/4/stats b/.flatpak-builder/ccache/4/stats index 06777f0..5931475 100644 --- a/.flatpak-builder/ccache/4/stats +++ b/.flatpak-builder/ccache/4/stats @@ -9,8 +9,13 @@ 0 0 0 +<<<<<<< HEAD 24 200 +======= +59 +1024 +>>>>>>> new-pomodoro 0 0 0 @@ -48,6 +53,7 @@ 0 0 1 +<<<<<<< HEAD 1 1 2 @@ -77,6 +83,37 @@ 32 16 0 +======= +4 +5 +6 +5 +5 +4 +6 +3 +2 +3 +7 +4 +3 +0 +1 +24 +48 +68 +136 +60 +136 +68 +84 +20 +12 +100 +156 +60 +48 +>>>>>>> new-pomodoro 0 4 0 diff --git a/.flatpak-builder/ccache/5/0/stats b/.flatpak-builder/ccache/5/0/stats index 68c5368..b25ba1a 100644 --- a/.flatpak-builder/ccache/5/0/stats +++ b/.flatpak-builder/ccache/5/0/stats @@ -2,11 +2,14 @@ 0 0 0 +<<<<<<< HEAD 1 0 0 0 0 +======= +>>>>>>> new-pomodoro 0 0 0 @@ -25,6 +28,7 @@ 0 0 0 +<<<<<<< HEAD 0 0 0 @@ -44,6 +48,32 @@ 2 0 1 +======= +2 +0 +0 +0 +0 +0 +2 +0 +0 +0 +0 +0 +0 +4 +0 +0 +0 +0 +0 +0 +0 +0 +2 +0 +>>>>>>> new-pomodoro 0 0 0 diff --git a/.flatpak-builder/ccache/5/1/7f79nqnpflih50o3kleikd3550h5cf2M b/.flatpak-builder/ccache/5/1/7f79nqnpflih50o3kleikd3550h5cf2M new file mode 100644 index 0000000..d5e68ce Binary files /dev/null and b/.flatpak-builder/ccache/5/1/7f79nqnpflih50o3kleikd3550h5cf2M differ diff --git a/.flatpak-builder/ccache/5/1/b8gnfkr7rom94r9ef26avebmi7dom46M b/.flatpak-builder/ccache/5/1/b8gnfkr7rom94r9ef26avebmi7dom46M new file mode 100644 index 0000000..292a016 Binary files /dev/null and b/.flatpak-builder/ccache/5/1/b8gnfkr7rom94r9ef26avebmi7dom46M differ diff --git a/.flatpak-builder/ccache/5/1/stats b/.flatpak-builder/ccache/5/1/stats new file mode 100644 index 0000000..621acad --- /dev/null +++ b/.flatpak-builder/ccache/5/1/stats @@ -0,0 +1,82 @@ +0 +0 +0 +0 +1 +0 +0 +0 +0 +0 +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +1 +1 +0 +2 +0 +0 +0 +0 +0 +0 +2 +0 +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 diff --git a/.flatpak-builder/ccache/5/2/3f4qtuishd231jd68ssfdna2sqgujikR b/.flatpak-builder/ccache/5/2/3f4qtuishd231jd68ssfdna2sqgujikR new file mode 100644 index 0000000..ddd6445 Binary files /dev/null and b/.flatpak-builder/ccache/5/2/3f4qtuishd231jd68ssfdna2sqgujikR differ diff --git a/.flatpak-builder/ccache/5/2/5bvtvs6bo1hv7mnahsha1qls79gsnsgM b/.flatpak-builder/ccache/5/2/5bvtvs6bo1hv7mnahsha1qls79gsnsgM new file mode 100644 index 0000000..a038487 Binary files /dev/null and b/.flatpak-builder/ccache/5/2/5bvtvs6bo1hv7mnahsha1qls79gsnsgM differ diff --git a/.flatpak-builder/ccache/5/2/stats b/.flatpak-builder/ccache/5/2/stats index fdb1454..de6825e 100644 --- a/.flatpak-builder/ccache/5/2/stats +++ b/.flatpak-builder/ccache/5/2/stats @@ -6,6 +6,9 @@ 0 0 0 +<<<<<<< HEAD +======= +1 0 0 0 @@ -19,6 +22,25 @@ 0 0 0 +2 +0 +0 +0 +>>>>>>> new-pomodoro +0 +0 +0 +0 +0 +0 +0 +<<<<<<< HEAD +0 +0 +0 +0 +0 +0 0 0 0 @@ -35,14 +57,25 @@ 2 0 4 +======= +3 +2 +5 +5 +>>>>>>> new-pomodoro 0 0 0 0 0 0 +<<<<<<< HEAD 4 0 +======= +5 +3 +>>>>>>> new-pomodoro 2 0 0 diff --git a/.flatpak-builder/ccache/5/3/stats b/.flatpak-builder/ccache/5/3/stats index 7be146c..589e5e1 100644 --- a/.flatpak-builder/ccache/5/3/stats +++ b/.flatpak-builder/ccache/5/3/stats @@ -2,6 +2,15 @@ 0 0 0 +<<<<<<< HEAD +======= +1 +0 +0 +0 +0 +>>>>>>> new-pomodoro +0 0 0 0 @@ -9,12 +18,40 @@ 0 0 0 +<<<<<<< HEAD +======= +1 +0 +0 +0 +0 +2 +>>>>>>> new-pomodoro +0 +0 +0 +0 +0 +<<<<<<< HEAD +======= +0 +0 +0 +0 +0 +1 +1 +4 +2 0 0 0 0 0 0 +2 +2 +>>>>>>> new-pomodoro 1 0 0 @@ -52,6 +89,7 @@ 0 0 0 +<<<<<<< HEAD 0 0 0 @@ -80,3 +118,5 @@ 0 0 0 +======= +>>>>>>> new-pomodoro diff --git a/.flatpak-builder/ccache/5/4/stats b/.flatpak-builder/ccache/5/4/stats new file mode 100644 index 0000000..68b1cf6 --- /dev/null +++ b/.flatpak-builder/ccache/5/4/stats @@ -0,0 +1,82 @@ +0 +0 +2 +0 +1 +0 +0 +0 +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +4 +3 +1 +7 +0 +0 +0 +0 +0 +0 +3 +1 +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 diff --git a/.flatpak-builder/ccache/5/5/78l5a0nhht1jpkd1ternajrq9keijc6R b/.flatpak-builder/ccache/5/5/78l5a0nhht1jpkd1ternajrq9keijc6R new file mode 100644 index 0000000..8f5fed3 Binary files /dev/null and b/.flatpak-builder/ccache/5/5/78l5a0nhht1jpkd1ternajrq9keijc6R differ diff --git a/.flatpak-builder/ccache/5/5/b60jp4udjn8luq6kngnasf2i2k9v76kR b/.flatpak-builder/ccache/5/5/b60jp4udjn8luq6kngnasf2i2k9v76kR new file mode 100644 index 0000000..c963ab1 Binary files /dev/null and b/.flatpak-builder/ccache/5/5/b60jp4udjn8luq6kngnasf2i2k9v76kR differ diff --git a/.flatpak-builder/ccache/5/5/stats b/.flatpak-builder/ccache/5/5/stats index ff7d4de..c5139c4 100644 --- a/.flatpak-builder/ccache/5/5/stats +++ b/.flatpak-builder/ccache/5/5/stats @@ -2,13 +2,21 @@ 0 0 0 +<<<<<<< HEAD 2 0 +======= +3 +>>>>>>> new-pomodoro 0 0 0 0 0 +<<<<<<< HEAD +======= +3 +>>>>>>> new-pomodoro 0 0 0 @@ -26,6 +34,7 @@ 0 0 0 +<<<<<<< HEAD 0 0 0 @@ -34,16 +43,34 @@ 2 2 0 +======= +>>>>>>> new-pomodoro 4 0 0 0 0 +<<<<<<< HEAD 0 0 4 0 2 +======= +3 +3 +0 +6 +0 +0 +0 +0 +0 +0 +6 +0 +3 +>>>>>>> new-pomodoro 0 0 0 diff --git a/.flatpak-builder/ccache/5/6/cbrjc6oq7q9i66p922k2tjauqtjuhrgR b/.flatpak-builder/ccache/5/6/cbrjc6oq7q9i66p922k2tjauqtjuhrgR new file mode 100644 index 0000000..7dfdadb Binary files /dev/null and b/.flatpak-builder/ccache/5/6/cbrjc6oq7q9i66p922k2tjauqtjuhrgR differ diff --git a/.flatpak-builder/ccache/5/6/stats b/.flatpak-builder/ccache/5/6/stats index 7367a33..15360f5 100644 --- a/.flatpak-builder/ccache/5/6/stats +++ b/.flatpak-builder/ccache/5/6/stats @@ -2,12 +2,23 @@ 0 0 0 +<<<<<<< HEAD +======= +2 +0 +0 +0 +0 +>>>>>>> new-pomodoro 1 0 0 0 0 +<<<<<<< HEAD 1 +======= +>>>>>>> new-pomodoro 0 0 0 @@ -27,12 +38,25 @@ 0 0 0 +<<<<<<< HEAD +======= +2 +2 +0 +4 +>>>>>>> new-pomodoro 0 0 0 0 +<<<<<<< HEAD 1 1 +======= +0 +0 +4 +>>>>>>> new-pomodoro 0 2 0 @@ -41,6 +65,7 @@ 0 0 0 +<<<<<<< HEAD 2 0 1 @@ -50,6 +75,8 @@ 0 0 0 +======= +>>>>>>> new-pomodoro 0 0 0 diff --git a/.flatpak-builder/ccache/5/7/stats b/.flatpak-builder/ccache/5/7/stats new file mode 100644 index 0000000..2145faa --- /dev/null +++ b/.flatpak-builder/ccache/5/7/stats @@ -0,0 +1,82 @@ +0 +0 +0 +0 +1 +0 +0 +0 +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +2 +1 +1 +3 +0 +0 +0 +0 +0 +0 +3 +1 +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 diff --git a/.flatpak-builder/ccache/5/8/stats b/.flatpak-builder/ccache/5/8/stats new file mode 100644 index 0000000..12da393 --- /dev/null +++ b/.flatpak-builder/ccache/5/8/stats @@ -0,0 +1,82 @@ +0 +0 +0 +0 +0 +0 +0 +0 +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +4 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +1 +0 +9 +1 +0 +0 +0 +0 +0 +0 +1 +5 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 diff --git a/.flatpak-builder/ccache/5/9/6e7qmoal4vv6l7oehv0k5duk15v5ifiM b/.flatpak-builder/ccache/5/9/6e7qmoal4vv6l7oehv0k5duk15v5ifiM new file mode 100644 index 0000000..c898ba4 Binary files /dev/null and b/.flatpak-builder/ccache/5/9/6e7qmoal4vv6l7oehv0k5duk15v5ifiM differ diff --git a/.flatpak-builder/ccache/5/9/98a0rbe5vor0ilgmkbr77djvtushhuiR b/.flatpak-builder/ccache/5/9/98a0rbe5vor0ilgmkbr77djvtushhuiR new file mode 100644 index 0000000..6796a0d Binary files /dev/null and b/.flatpak-builder/ccache/5/9/98a0rbe5vor0ilgmkbr77djvtushhuiR differ diff --git a/.flatpak-builder/ccache/5/9/stats b/.flatpak-builder/ccache/5/9/stats index 68c5368..123bbda 100644 --- a/.flatpak-builder/ccache/5/9/stats +++ b/.flatpak-builder/ccache/5/9/stats @@ -2,6 +2,13 @@ 0 0 0 +<<<<<<< HEAD +======= +3 +0 +0 +0 +>>>>>>> new-pomodoro 1 0 0 @@ -27,6 +34,7 @@ 0 0 0 +<<<<<<< HEAD 0 0 0 @@ -44,6 +52,21 @@ 2 0 1 +======= +4 +3 +1 +7 +0 +0 +0 +0 +0 +0 +7 +1 +3 +>>>>>>> new-pomodoro 0 0 0 diff --git a/.flatpak-builder/ccache/5/CACHEDIR.TAG b/.flatpak-builder/ccache/5/CACHEDIR.TAG new file mode 100644 index 0000000..874477f --- /dev/null +++ b/.flatpak-builder/ccache/5/CACHEDIR.TAG @@ -0,0 +1,4 @@ +Signature: 8a477f597d28d172789f06886806bc55 +# This file is a cache directory tag created by ccache. +# For information about cache directory tags, see: +# http://www.brynosaurus.com/cachedir/ diff --git a/.flatpak-builder/ccache/5/a/4e9absb0bm00jf64mmu8e62q8r72c8aM b/.flatpak-builder/ccache/5/a/4e9absb0bm00jf64mmu8e62q8r72c8aM new file mode 100644 index 0000000..56fa221 Binary files /dev/null and b/.flatpak-builder/ccache/5/a/4e9absb0bm00jf64mmu8e62q8r72c8aM differ diff --git a/.flatpak-builder/ccache/5/a/53rncg7a8gttkie5dc00fo1upcvs1amM b/.flatpak-builder/ccache/5/a/53rncg7a8gttkie5dc00fo1upcvs1amM new file mode 100644 index 0000000..60a35f9 Binary files /dev/null and b/.flatpak-builder/ccache/5/a/53rncg7a8gttkie5dc00fo1upcvs1amM differ diff --git a/.flatpak-builder/ccache/5/a/8esmj6m9b32lmjdsac9dhn1c06fqv20M b/.flatpak-builder/ccache/5/a/8esmj6m9b32lmjdsac9dhn1c06fqv20M new file mode 100644 index 0000000..7fd919b Binary files /dev/null and b/.flatpak-builder/ccache/5/a/8esmj6m9b32lmjdsac9dhn1c06fqv20M differ diff --git a/.flatpak-builder/ccache/5/a/a5nv0gadsc5rbilnih9tjhbfds88ipaR b/.flatpak-builder/ccache/5/a/a5nv0gadsc5rbilnih9tjhbfds88ipaR new file mode 100644 index 0000000..cfd45a9 Binary files /dev/null and b/.flatpak-builder/ccache/5/a/a5nv0gadsc5rbilnih9tjhbfds88ipaR differ diff --git a/.flatpak-builder/ccache/5/a/aebe4s553jaj8ctphujd8u467r29vqqM b/.flatpak-builder/ccache/5/a/aebe4s553jaj8ctphujd8u467r29vqqM new file mode 100644 index 0000000..f667b63 Binary files /dev/null and b/.flatpak-builder/ccache/5/a/aebe4s553jaj8ctphujd8u467r29vqqM differ diff --git a/.flatpak-builder/ccache/5/a/ddjf819ub8e0dqpl3oh8tj7ksm08qigR b/.flatpak-builder/ccache/5/a/ddjf819ub8e0dqpl3oh8tj7ksm08qigR new file mode 100644 index 0000000..1dc8e7f Binary files /dev/null and b/.flatpak-builder/ccache/5/a/ddjf819ub8e0dqpl3oh8tj7ksm08qigR differ diff --git a/.flatpak-builder/ccache/5/a/stats b/.flatpak-builder/ccache/5/a/stats index aef4995..5c6fd10 100644 --- a/.flatpak-builder/ccache/5/a/stats +++ b/.flatpak-builder/ccache/5/a/stats @@ -6,6 +6,22 @@ 0 0 0 +<<<<<<< HEAD +======= +1 +1 +1 +0 +0 +0 +0 +0 +0 +3 +0 +0 +0 +>>>>>>> new-pomodoro 0 1 0 @@ -13,6 +29,7 @@ 0 0 0 +<<<<<<< HEAD 0 0 0 @@ -43,6 +60,25 @@ 0 4 1 +======= +2 +0 +0 +0 +0 +3 +2 +3 +5 +0 +0 +0 +0 +0 +0 +5 +2 +>>>>>>> new-pomodoro 2 0 0 diff --git a/.flatpak-builder/ccache/5/b/17fmu6ad3u3plkr5isqta3t3e3ql3reR b/.flatpak-builder/ccache/5/b/17fmu6ad3u3plkr5isqta3t3e3ql3reR new file mode 100644 index 0000000..eed5a29 Binary files /dev/null and b/.flatpak-builder/ccache/5/b/17fmu6ad3u3plkr5isqta3t3e3ql3reR differ diff --git a/.flatpak-builder/ccache/5/c/b2ef1lou9su4nrrq8dk0rrcqtcl9g0uR b/.flatpak-builder/ccache/5/c/b2ef1lou9su4nrrq8dk0rrcqtcl9g0uR new file mode 100644 index 0000000..ac9d195 Binary files /dev/null and b/.flatpak-builder/ccache/5/c/b2ef1lou9su4nrrq8dk0rrcqtcl9g0uR differ diff --git a/.flatpak-builder/ccache/5/c/d7qqes4i33u002hgdfm10cbm5pc5t0cM b/.flatpak-builder/ccache/5/c/d7qqes4i33u002hgdfm10cbm5pc5t0cM new file mode 100644 index 0000000..7c96a8d Binary files /dev/null and b/.flatpak-builder/ccache/5/c/d7qqes4i33u002hgdfm10cbm5pc5t0cM differ diff --git a/.flatpak-builder/ccache/5/c/stats b/.flatpak-builder/ccache/5/c/stats new file mode 100644 index 0000000..68c5368 --- /dev/null +++ b/.flatpak-builder/ccache/5/c/stats @@ -0,0 +1,82 @@ +0 +0 +0 +0 +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +1 +1 +0 +2 +0 +0 +0 +0 +0 +0 +2 +0 +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 diff --git a/.flatpak-builder/ccache/5/d/1dsa3b2gepbtt9ede59258ntm9102jcM b/.flatpak-builder/ccache/5/d/1dsa3b2gepbtt9ede59258ntm9102jcM new file mode 100644 index 0000000..0b77ae6 Binary files /dev/null and b/.flatpak-builder/ccache/5/d/1dsa3b2gepbtt9ede59258ntm9102jcM differ diff --git a/.flatpak-builder/ccache/5/d/33ipgvmhissokheurcdev3v0ffpit3mM b/.flatpak-builder/ccache/5/d/33ipgvmhissokheurcdev3v0ffpit3mM new file mode 100644 index 0000000..9971d21 Binary files /dev/null and b/.flatpak-builder/ccache/5/d/33ipgvmhissokheurcdev3v0ffpit3mM differ diff --git a/.flatpak-builder/ccache/5/d/stats b/.flatpak-builder/ccache/5/d/stats new file mode 100644 index 0000000..621acad --- /dev/null +++ b/.flatpak-builder/ccache/5/d/stats @@ -0,0 +1,82 @@ +0 +0 +0 +0 +1 +0 +0 +0 +0 +0 +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +1 +1 +0 +2 +0 +0 +0 +0 +0 +0 +2 +0 +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 diff --git a/.flatpak-builder/ccache/5/e/stats b/.flatpak-builder/ccache/5/e/stats index aaf3740..9b80d88 100644 --- a/.flatpak-builder/ccache/5/e/stats +++ b/.flatpak-builder/ccache/5/e/stats @@ -2,7 +2,11 @@ 0 1 0 +<<<<<<< HEAD 1 +======= +2 +>>>>>>> new-pomodoro 0 0 0 @@ -20,18 +24,23 @@ 0 0 0 +<<<<<<< HEAD 1 0 0 0 0 0 +======= +3 +>>>>>>> new-pomodoro 0 0 0 0 0 2 +<<<<<<< HEAD 2 2 4 @@ -44,6 +53,25 @@ 2 1 1 +======= +0 +0 +0 +0 +3 +3 +6 +6 +0 +0 +0 +0 +0 +0 +4 +3 +2 +>>>>>>> new-pomodoro 0 0 0 diff --git a/.flatpak-builder/ccache/5/stats b/.flatpak-builder/ccache/5/stats index 16d9a58..3f8e9ac 100644 --- a/.flatpak-builder/ccache/5/stats +++ b/.flatpak-builder/ccache/5/stats @@ -9,8 +9,13 @@ 0 0 0 +<<<<<<< HEAD 20 200 +======= +33 +588 +>>>>>>> new-pomodoro 0 0 0 @@ -48,6 +53,7 @@ 0 0 0 +<<<<<<< HEAD 1 0 2 @@ -78,5 +84,37 @@ 16 0 40 +======= +2 +2 +1 +1 +2 +3 +2 +1 +3 +6 +2 +2 +2 +3 +1 +0 +40 +44 +4 +4 +40 +32 +8 +4 +72 +216 +20 +48 +40 +12 +>>>>>>> new-pomodoro 4 0 diff --git a/.flatpak-builder/ccache/6/0/35913s7aeb7irfbit1avoj9et98t83aR b/.flatpak-builder/ccache/6/0/35913s7aeb7irfbit1avoj9et98t83aR new file mode 100644 index 0000000..a0d0b3d Binary files /dev/null and b/.flatpak-builder/ccache/6/0/35913s7aeb7irfbit1avoj9et98t83aR differ diff --git a/.flatpak-builder/ccache/6/0/42fd71h18rrl45c4k9n9pugvqiqlgcsM b/.flatpak-builder/ccache/6/0/42fd71h18rrl45c4k9n9pugvqiqlgcsM new file mode 100644 index 0000000..4e89bf0 Binary files /dev/null and b/.flatpak-builder/ccache/6/0/42fd71h18rrl45c4k9n9pugvqiqlgcsM differ diff --git a/.flatpak-builder/ccache/6/0/stats b/.flatpak-builder/ccache/6/0/stats index e2c92a1..9e4d239 100644 --- a/.flatpak-builder/ccache/6/0/stats +++ b/.flatpak-builder/ccache/6/0/stats @@ -2,6 +2,24 @@ 0 0 0 +<<<<<<< HEAD +======= +4 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +>>>>>>> new-pomodoro 3 0 0 @@ -16,15 +34,23 @@ 0 0 0 +<<<<<<< HEAD 0 1 +======= +4 +4 0 +8 +>>>>>>> new-pomodoro 0 0 0 0 0 0 +<<<<<<< HEAD +0 0 0 0 @@ -44,6 +70,11 @@ 6 0 3 +======= +8 +0 +4 +>>>>>>> new-pomodoro 0 0 0 diff --git a/.flatpak-builder/ccache/6/1/05ocmq7sq618f4vq30lti7cp5406d2cR b/.flatpak-builder/ccache/6/1/05ocmq7sq618f4vq30lti7cp5406d2cR new file mode 100644 index 0000000..ebe380e Binary files /dev/null and b/.flatpak-builder/ccache/6/1/05ocmq7sq618f4vq30lti7cp5406d2cR differ diff --git a/.flatpak-builder/ccache/6/1/2cjvg8glcm9t9l6qlavmolh9rt2gtfuM b/.flatpak-builder/ccache/6/1/2cjvg8glcm9t9l6qlavmolh9rt2gtfuM new file mode 100644 index 0000000..b2aedb4 Binary files /dev/null and b/.flatpak-builder/ccache/6/1/2cjvg8glcm9t9l6qlavmolh9rt2gtfuM differ diff --git a/.flatpak-builder/ccache/6/1/5edda5d71rri0cap6g01t3f74qe192oM b/.flatpak-builder/ccache/6/1/5edda5d71rri0cap6g01t3f74qe192oM new file mode 100644 index 0000000..2c10f7d Binary files /dev/null and b/.flatpak-builder/ccache/6/1/5edda5d71rri0cap6g01t3f74qe192oM differ diff --git a/.flatpak-builder/ccache/6/1/6295u8frgbekn0ldromi8a38slq7auqM b/.flatpak-builder/ccache/6/1/6295u8frgbekn0ldromi8a38slq7auqM new file mode 100644 index 0000000..1d1a15a Binary files /dev/null and b/.flatpak-builder/ccache/6/1/6295u8frgbekn0ldromi8a38slq7auqM differ diff --git a/.flatpak-builder/ccache/6/1/d994p64bohkhd6fbv2ifkdhukds63fcM b/.flatpak-builder/ccache/6/1/d994p64bohkhd6fbv2ifkdhukds63fcM new file mode 100644 index 0000000..c52fe74 Binary files /dev/null and b/.flatpak-builder/ccache/6/1/d994p64bohkhd6fbv2ifkdhukds63fcM differ diff --git a/.flatpak-builder/ccache/6/1/stats b/.flatpak-builder/ccache/6/1/stats index 68c5368..abd3e7e 100644 --- a/.flatpak-builder/ccache/6/1/stats +++ b/.flatpak-builder/ccache/6/1/stats @@ -2,6 +2,27 @@ 0 0 0 +<<<<<<< HEAD +======= +3 +0 +0 +0 +1 +0 +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +>>>>>>> new-pomodoro 1 0 0 @@ -13,12 +34,20 @@ 0 0 0 +<<<<<<< HEAD +======= +4 +3 +3 +7 +>>>>>>> new-pomodoro 0 0 0 0 0 0 +<<<<<<< HEAD 0 0 0 @@ -44,6 +73,11 @@ 2 0 1 +======= +7 +2 +3 +>>>>>>> new-pomodoro 0 0 0 diff --git a/.flatpak-builder/ccache/6/3/19ufu55v09pnbbfahcttbq0hcr9t4nqM b/.flatpak-builder/ccache/6/3/19ufu55v09pnbbfahcttbq0hcr9t4nqM new file mode 100644 index 0000000..2f32c0d Binary files /dev/null and b/.flatpak-builder/ccache/6/3/19ufu55v09pnbbfahcttbq0hcr9t4nqM differ diff --git a/.flatpak-builder/ccache/6/3/stats b/.flatpak-builder/ccache/6/3/stats new file mode 100644 index 0000000..bd882a9 --- /dev/null +++ b/.flatpak-builder/ccache/6/3/stats @@ -0,0 +1,82 @@ +0 +0 +0 +0 +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +4 +0 +0 +0 +0 +0 +4 +0 +0 +0 +0 +1 +1 +8 +2 +0 +0 +0 +0 +0 +0 +2 +4 +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 diff --git a/.flatpak-builder/ccache/6/4/stats b/.flatpak-builder/ccache/6/4/stats new file mode 100644 index 0000000..5748fbd --- /dev/null +++ b/.flatpak-builder/ccache/6/4/stats @@ -0,0 +1,82 @@ +0 +0 +0 +0 +1 +0 +0 +0 +2 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +3 +1 +2 +4 +0 +0 +0 +0 +0 +0 +4 +2 +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 diff --git a/.flatpak-builder/ccache/6/5/6d1c14jvhqufo4ie9lcg4hj1msamsakR b/.flatpak-builder/ccache/6/5/6d1c14jvhqufo4ie9lcg4hj1msamsakR new file mode 100644 index 0000000..baf228f Binary files /dev/null and b/.flatpak-builder/ccache/6/5/6d1c14jvhqufo4ie9lcg4hj1msamsakR differ diff --git a/.flatpak-builder/ccache/6/5/stats b/.flatpak-builder/ccache/6/5/stats new file mode 100644 index 0000000..68c5368 --- /dev/null +++ b/.flatpak-builder/ccache/6/5/stats @@ -0,0 +1,82 @@ +0 +0 +0 +0 +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +1 +1 +0 +2 +0 +0 +0 +0 +0 +0 +2 +0 +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 diff --git a/.flatpak-builder/ccache/6/6/2fk86sflsvo81lua3tg5chj193c2rbuR b/.flatpak-builder/ccache/6/6/2fk86sflsvo81lua3tg5chj193c2rbuR new file mode 100644 index 0000000..ca1c7e7 Binary files /dev/null and b/.flatpak-builder/ccache/6/6/2fk86sflsvo81lua3tg5chj193c2rbuR differ diff --git a/.flatpak-builder/ccache/6/6/bdghl678c3ndgd6l57l7gmfo2c1890mR b/.flatpak-builder/ccache/6/6/bdghl678c3ndgd6l57l7gmfo2c1890mR new file mode 100644 index 0000000..7b48db0 Binary files /dev/null and b/.flatpak-builder/ccache/6/6/bdghl678c3ndgd6l57l7gmfo2c1890mR differ diff --git a/.flatpak-builder/ccache/6/6/stats b/.flatpak-builder/ccache/6/6/stats index 7be146c..85e6353 100644 --- a/.flatpak-builder/ccache/6/6/stats +++ b/.flatpak-builder/ccache/6/6/stats @@ -2,7 +2,11 @@ 0 0 0 +<<<<<<< HEAD 0 +======= +2 +>>>>>>> new-pomodoro 0 0 0 @@ -20,6 +24,7 @@ 0 0 0 +<<<<<<< HEAD 0 0 0 @@ -44,6 +49,32 @@ 0 0 0 +======= +3 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +2 +2 +6 +4 +0 +0 +0 +0 +0 +0 +4 +3 +2 +>>>>>>> new-pomodoro 0 0 0 diff --git a/.flatpak-builder/ccache/6/7/3b2mf1lp81nic64ajs43nh5q25spaqsR b/.flatpak-builder/ccache/6/7/3b2mf1lp81nic64ajs43nh5q25spaqsR new file mode 100644 index 0000000..7e8c76d Binary files /dev/null and b/.flatpak-builder/ccache/6/7/3b2mf1lp81nic64ajs43nh5q25spaqsR differ diff --git a/.flatpak-builder/ccache/6/7/b829m5pf550u1m1j63kaei978o62cm2R b/.flatpak-builder/ccache/6/7/b829m5pf550u1m1j63kaei978o62cm2R new file mode 100644 index 0000000..1965621 Binary files /dev/null and b/.flatpak-builder/ccache/6/7/b829m5pf550u1m1j63kaei978o62cm2R differ diff --git a/.flatpak-builder/ccache/6/7/bd2gslpbv3u61sbg3334366ns0rgq9gM b/.flatpak-builder/ccache/6/7/bd2gslpbv3u61sbg3334366ns0rgq9gM new file mode 100644 index 0000000..896ab60 Binary files /dev/null and b/.flatpak-builder/ccache/6/7/bd2gslpbv3u61sbg3334366ns0rgq9gM differ diff --git a/.flatpak-builder/ccache/6/7/stats b/.flatpak-builder/ccache/6/7/stats index 68c5368..9c7f8d2 100644 --- a/.flatpak-builder/ccache/6/7/stats +++ b/.flatpak-builder/ccache/6/7/stats @@ -1,5 +1,6 @@ 0 0 +<<<<<<< HEAD 0 0 1 @@ -41,12 +42,58 @@ 0 0 0 +======= +>>>>>>> new-pomodoro 2 0 1 0 0 0 +<<<<<<< HEAD +======= +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +2 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +4 +3 +5 +7 +0 +0 +0 +0 +0 +0 +3 +3 +1 +0 +0 +0 +>>>>>>> new-pomodoro 0 0 0 diff --git a/.flatpak-builder/ccache/6/8/1els94m471otrb86ud3mbaog5em4hdeR b/.flatpak-builder/ccache/6/8/1els94m471otrb86ud3mbaog5em4hdeR new file mode 100644 index 0000000..88ced51 Binary files /dev/null and b/.flatpak-builder/ccache/6/8/1els94m471otrb86ud3mbaog5em4hdeR differ diff --git a/.flatpak-builder/ccache/6/8/453tnutu9h21bvced1nkmkhnjufaq4sM b/.flatpak-builder/ccache/6/8/453tnutu9h21bvced1nkmkhnjufaq4sM new file mode 100644 index 0000000..ba99c87 Binary files /dev/null and b/.flatpak-builder/ccache/6/8/453tnutu9h21bvced1nkmkhnjufaq4sM differ diff --git a/.flatpak-builder/ccache/6/8/stats b/.flatpak-builder/ccache/6/8/stats index ff7d4de..7f52c80 100644 --- a/.flatpak-builder/ccache/6/8/stats +++ b/.flatpak-builder/ccache/6/8/stats @@ -2,13 +2,21 @@ 0 0 0 +<<<<<<< HEAD 2 0 +======= +3 +>>>>>>> new-pomodoro 0 0 0 0 0 +<<<<<<< HEAD +======= +3 +>>>>>>> new-pomodoro 0 0 0 @@ -20,30 +28,51 @@ 1 0 0 +<<<<<<< HEAD 0 0 0 0 0 0 +======= +2 +>>>>>>> new-pomodoro 0 0 0 0 0 2 +<<<<<<< HEAD 2 0 4 +======= +0 0 0 0 +3 +3 +4 +6 +>>>>>>> new-pomodoro +0 0 0 0 +0 +0 +<<<<<<< HEAD 4 0 2 +======= +6 +2 +3 +>>>>>>> new-pomodoro 0 0 0 diff --git a/.flatpak-builder/ccache/6/9/5b84nsoipq3sov6rfhmr6p91c6c2bsmM b/.flatpak-builder/ccache/6/9/5b84nsoipq3sov6rfhmr6p91c6c2bsmM new file mode 100644 index 0000000..cbf05ba Binary files /dev/null and b/.flatpak-builder/ccache/6/9/5b84nsoipq3sov6rfhmr6p91c6c2bsmM differ diff --git a/.flatpak-builder/ccache/6/9/93nr9fe3dsnftf25nbo16g86ncm747sR b/.flatpak-builder/ccache/6/9/93nr9fe3dsnftf25nbo16g86ncm747sR new file mode 100644 index 0000000..1cfb3a2 Binary files /dev/null and b/.flatpak-builder/ccache/6/9/93nr9fe3dsnftf25nbo16g86ncm747sR differ diff --git a/.flatpak-builder/ccache/6/9/b9eajg06e0q2ruve891j9am5kpo11bmR b/.flatpak-builder/ccache/6/9/b9eajg06e0q2ruve891j9am5kpo11bmR new file mode 100644 index 0000000..2c3bf5d Binary files /dev/null and b/.flatpak-builder/ccache/6/9/b9eajg06e0q2ruve891j9am5kpo11bmR differ diff --git a/.flatpak-builder/ccache/6/9/stats b/.flatpak-builder/ccache/6/9/stats new file mode 100644 index 0000000..c782842 --- /dev/null +++ b/.flatpak-builder/ccache/6/9/stats @@ -0,0 +1,82 @@ +0 +0 +0 +0 +0 +0 +0 +0 +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +2 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +1 +0 +5 +1 +0 +0 +0 +0 +0 +0 +1 +3 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 diff --git a/.flatpak-builder/ccache/6/CACHEDIR.TAG b/.flatpak-builder/ccache/6/CACHEDIR.TAG new file mode 100644 index 0000000..874477f --- /dev/null +++ b/.flatpak-builder/ccache/6/CACHEDIR.TAG @@ -0,0 +1,4 @@ +Signature: 8a477f597d28d172789f06886806bc55 +# This file is a cache directory tag created by ccache. +# For information about cache directory tags, see: +# http://www.brynosaurus.com/cachedir/ diff --git a/.flatpak-builder/ccache/6/a/stats b/.flatpak-builder/ccache/6/a/stats index 68c5368..ebed48e 100644 --- a/.flatpak-builder/ccache/6/a/stats +++ b/.flatpak-builder/ccache/6/a/stats @@ -2,7 +2,11 @@ 0 0 0 +<<<<<<< HEAD 1 +======= +3 +>>>>>>> new-pomodoro 0 0 0 @@ -31,19 +35,32 @@ 0 0 0 +<<<<<<< HEAD 1 1 0 2 +======= +3 +3 0 +6 +>>>>>>> new-pomodoro 0 0 0 0 0 +0 +<<<<<<< HEAD 2 0 1 +======= +6 +0 +3 +>>>>>>> new-pomodoro 0 0 0 diff --git a/.flatpak-builder/ccache/6/b/79c6pkhevs65dskvc2kta6tb0g621mqR b/.flatpak-builder/ccache/6/b/79c6pkhevs65dskvc2kta6tb0g621mqR new file mode 100644 index 0000000..952dd8f Binary files /dev/null and b/.flatpak-builder/ccache/6/b/79c6pkhevs65dskvc2kta6tb0g621mqR differ diff --git a/.flatpak-builder/ccache/6/b/stats b/.flatpak-builder/ccache/6/b/stats new file mode 100644 index 0000000..3c139e1 --- /dev/null +++ b/.flatpak-builder/ccache/6/b/stats @@ -0,0 +1,82 @@ +0 +0 +0 +0 +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +2 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +1 +1 +4 +2 +0 +0 +0 +0 +0 +0 +2 +2 +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 diff --git a/.flatpak-builder/ccache/6/c/b31sjrt4vaqsft1p2ajohia0ff0sld2M b/.flatpak-builder/ccache/6/c/b31sjrt4vaqsft1p2ajohia0ff0sld2M new file mode 100644 index 0000000..e4d8d26 Binary files /dev/null and b/.flatpak-builder/ccache/6/c/b31sjrt4vaqsft1p2ajohia0ff0sld2M differ diff --git a/.flatpak-builder/ccache/6/c/c30t1t9hbc19jpigk6mbsvhp781d1umM b/.flatpak-builder/ccache/6/c/c30t1t9hbc19jpigk6mbsvhp781d1umM new file mode 100644 index 0000000..9ef8526 Binary files /dev/null and b/.flatpak-builder/ccache/6/c/c30t1t9hbc19jpigk6mbsvhp781d1umM differ diff --git a/.flatpak-builder/ccache/6/c/f8298chvf41m2v7i5439sgcenibcsruM b/.flatpak-builder/ccache/6/c/f8298chvf41m2v7i5439sgcenibcsruM new file mode 100644 index 0000000..fd33bfd Binary files /dev/null and b/.flatpak-builder/ccache/6/c/f8298chvf41m2v7i5439sgcenibcsruM differ diff --git a/.flatpak-builder/ccache/6/c/stats b/.flatpak-builder/ccache/6/c/stats index fdb1454..7047371 100644 --- a/.flatpak-builder/ccache/6/c/stats +++ b/.flatpak-builder/ccache/6/c/stats @@ -2,6 +2,7 @@ 0 0 0 +<<<<<<< HEAD 2 0 0 @@ -34,14 +35,30 @@ 2 2 0 +======= +>>>>>>> new-pomodoro 4 0 0 0 0 0 +<<<<<<< HEAD 0 4 +======= +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +>>>>>>> new-pomodoro 0 2 0 @@ -54,6 +71,32 @@ 0 0 0 +<<<<<<< HEAD +======= +4 +4 +4 +8 +0 +0 +0 +0 +0 +0 +8 +2 +4 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +>>>>>>> new-pomodoro 0 0 0 diff --git a/.flatpak-builder/ccache/6/d/17lt8gd2eu8uq7v2n23bjgah7nujr0oR b/.flatpak-builder/ccache/6/d/17lt8gd2eu8uq7v2n23bjgah7nujr0oR new file mode 100644 index 0000000..a791464 Binary files /dev/null and b/.flatpak-builder/ccache/6/d/17lt8gd2eu8uq7v2n23bjgah7nujr0oR differ diff --git a/.flatpak-builder/ccache/6/d/92mjmue1lpmnikhob0k38ul0vsqpejgR b/.flatpak-builder/ccache/6/d/92mjmue1lpmnikhob0k38ul0vsqpejgR new file mode 100644 index 0000000..f20bdc1 Binary files /dev/null and b/.flatpak-builder/ccache/6/d/92mjmue1lpmnikhob0k38ul0vsqpejgR differ diff --git a/.flatpak-builder/ccache/6/d/stats b/.flatpak-builder/ccache/6/d/stats index 3f6c445..95019f2 100644 --- a/.flatpak-builder/ccache/6/d/stats +++ b/.flatpak-builder/ccache/6/d/stats @@ -6,6 +6,7 @@ 0 0 0 +<<<<<<< HEAD 0 0 0 @@ -15,6 +16,8 @@ 0 0 0 +======= +>>>>>>> new-pomodoro 1 0 1 @@ -24,6 +27,12 @@ 0 0 0 +<<<<<<< HEAD +======= +1 +0 +1 +>>>>>>> new-pomodoro 0 0 1 @@ -31,18 +40,37 @@ 0 0 0 +<<<<<<< HEAD 1 1 0 2 0 0 +======= +0 +1 +>>>>>>> new-pomodoro 0 0 0 0 2 +<<<<<<< HEAD +0 +======= +1 +3 +3 0 +0 +0 +0 +0 +0 +3 +2 +>>>>>>> new-pomodoro 1 0 0 diff --git a/.flatpak-builder/ccache/6/e/2do597cdls3p58o569nl76io0pb8algR b/.flatpak-builder/ccache/6/e/2do597cdls3p58o569nl76io0pb8algR new file mode 100644 index 0000000..4a9a5e6 Binary files /dev/null and b/.flatpak-builder/ccache/6/e/2do597cdls3p58o569nl76io0pb8algR differ diff --git a/.flatpak-builder/ccache/6/e/5dqnv9als0ss9avujpie2vqhgq4o2f4R b/.flatpak-builder/ccache/6/e/5dqnv9als0ss9avujpie2vqhgq4o2f4R new file mode 100644 index 0000000..c83e4bd Binary files /dev/null and b/.flatpak-builder/ccache/6/e/5dqnv9als0ss9avujpie2vqhgq4o2f4R differ diff --git a/.flatpak-builder/ccache/6/e/stats b/.flatpak-builder/ccache/6/e/stats new file mode 100644 index 0000000..442be51 --- /dev/null +++ b/.flatpak-builder/ccache/6/e/stats @@ -0,0 +1,82 @@ +0 +0 +0 +0 +1 +0 +0 +0 +0 +0 +3 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +1 +1 +2 +2 +0 +0 +0 +0 +0 +0 +2 +1 +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 diff --git a/.flatpak-builder/ccache/6/f/fa4jsimd56rv9859fbccd0muopvh2noR b/.flatpak-builder/ccache/6/f/fa4jsimd56rv9859fbccd0muopvh2noR new file mode 100644 index 0000000..6e2fafa Binary files /dev/null and b/.flatpak-builder/ccache/6/f/fa4jsimd56rv9859fbccd0muopvh2noR differ diff --git a/.flatpak-builder/ccache/6/f/stats b/.flatpak-builder/ccache/6/f/stats index 85e812b..2c07089 100644 --- a/.flatpak-builder/ccache/6/f/stats +++ b/.flatpak-builder/ccache/6/f/stats @@ -2,6 +2,7 @@ 0 0 0 +<<<<<<< HEAD 0 0 0 @@ -20,6 +21,8 @@ 0 0 0 +======= +>>>>>>> new-pomodoro 1 0 0 @@ -33,6 +36,28 @@ 0 0 0 +<<<<<<< HEAD +======= +0 +0 +0 +0 +0 +3 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +1 +1 +6 +>>>>>>> new-pomodoro 2 0 0 @@ -40,8 +65,13 @@ 0 0 0 +<<<<<<< HEAD 0 0 +======= +2 +3 +>>>>>>> new-pomodoro 1 0 0 @@ -79,4 +109,7 @@ 0 0 0 +<<<<<<< HEAD 0 +======= +>>>>>>> new-pomodoro diff --git a/.flatpak-builder/ccache/6/stats b/.flatpak-builder/ccache/6/stats index 8e07e64..f71b998 100644 --- a/.flatpak-builder/ccache/6/stats +++ b/.flatpak-builder/ccache/6/stats @@ -9,8 +9,13 @@ 0 0 0 +<<<<<<< HEAD 19 168 +======= +43 +852 +>>>>>>> new-pomodoro 0 0 0 @@ -47,6 +52,7 @@ 0 0 0 +<<<<<<< HEAD 2 2 1 @@ -80,3 +86,38 @@ 4 0 0 +======= +4 +5 +1 +2 +2 +2 +2 +3 +2 +4 +0 +5 +5 +2 +3 +1 +32 +96 +8 +12 +12 +20 +28 +76 +36 +100 +0 +56 +76 +220 +48 +32 +0 +>>>>>>> new-pomodoro diff --git a/.flatpak-builder/ccache/7/0/26jqi82ds22alo8l79fr9ge8q7ldcnoM b/.flatpak-builder/ccache/7/0/26jqi82ds22alo8l79fr9ge8q7ldcnoM new file mode 100644 index 0000000..5068c82 Binary files /dev/null and b/.flatpak-builder/ccache/7/0/26jqi82ds22alo8l79fr9ge8q7ldcnoM differ diff --git a/.flatpak-builder/ccache/7/0/stats b/.flatpak-builder/ccache/7/0/stats index 68c5368..207bd30 100644 --- a/.flatpak-builder/ccache/7/0/stats +++ b/.flatpak-builder/ccache/7/0/stats @@ -2,6 +2,15 @@ 0 0 0 +<<<<<<< HEAD +======= +2 +0 +0 +0 +0 +0 +>>>>>>> new-pomodoro 1 0 0 @@ -25,14 +34,25 @@ 0 0 0 +<<<<<<< HEAD +======= +2 +2 +0 +4 +>>>>>>> new-pomodoro 0 0 0 0 0 0 +<<<<<<< HEAD 1 1 +======= +4 +>>>>>>> new-pomodoro 0 2 0 @@ -41,6 +61,7 @@ 0 0 0 +<<<<<<< HEAD 2 0 1 @@ -50,6 +71,8 @@ 0 0 0 +======= +>>>>>>> new-pomodoro 0 0 0 diff --git a/.flatpak-builder/ccache/7/1/00riqurr24pul82c78d0fodpr2pfmpkM b/.flatpak-builder/ccache/7/1/00riqurr24pul82c78d0fodpr2pfmpkM new file mode 100644 index 0000000..4037e3a Binary files /dev/null and b/.flatpak-builder/ccache/7/1/00riqurr24pul82c78d0fodpr2pfmpkM differ diff --git a/.flatpak-builder/ccache/7/1/ba6tu6l8v20jdftu4fpujvm548j15f0R b/.flatpak-builder/ccache/7/1/ba6tu6l8v20jdftu4fpujvm548j15f0R new file mode 100644 index 0000000..8b45941 Binary files /dev/null and b/.flatpak-builder/ccache/7/1/ba6tu6l8v20jdftu4fpujvm548j15f0R differ diff --git a/.flatpak-builder/ccache/7/1/f9civc6bjaetvl2s2i0aie4plltivnqM b/.flatpak-builder/ccache/7/1/f9civc6bjaetvl2s2i0aie4plltivnqM new file mode 100644 index 0000000..d71ba87 Binary files /dev/null and b/.flatpak-builder/ccache/7/1/f9civc6bjaetvl2s2i0aie4plltivnqM differ diff --git a/.flatpak-builder/ccache/7/1/stats b/.flatpak-builder/ccache/7/1/stats index 68c5368..2f24a7c 100644 --- a/.flatpak-builder/ccache/7/1/stats +++ b/.flatpak-builder/ccache/7/1/stats @@ -2,6 +2,7 @@ 0 0 0 +<<<<<<< HEAD 1 0 0 @@ -34,6 +35,8 @@ 1 1 0 +======= +>>>>>>> new-pomodoro 2 0 0 @@ -41,9 +44,47 @@ 0 0 0 +<<<<<<< HEAD 2 0 1 +======= +0 +0 +0 +0 +0 +0 +0 +0 +2 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +2 +2 +0 +4 +0 +0 +0 +0 +0 +0 +4 +0 +2 +>>>>>>> new-pomodoro 0 0 0 diff --git a/.flatpak-builder/ccache/7/2/38lr9lg9k96cfd0urq2upjj04tmd3bsM b/.flatpak-builder/ccache/7/2/38lr9lg9k96cfd0urq2upjj04tmd3bsM new file mode 100644 index 0000000..558a152 Binary files /dev/null and b/.flatpak-builder/ccache/7/2/38lr9lg9k96cfd0urq2upjj04tmd3bsM differ diff --git a/.flatpak-builder/ccache/7/2/5cs5osn91c1f35qb5ouq2555kp8849oM b/.flatpak-builder/ccache/7/2/5cs5osn91c1f35qb5ouq2555kp8849oM new file mode 100644 index 0000000..d7e57a0 Binary files /dev/null and b/.flatpak-builder/ccache/7/2/5cs5osn91c1f35qb5ouq2555kp8849oM differ diff --git a/.flatpak-builder/ccache/7/2/664v0onm4keb8h1sg8uf318l2qj991cM b/.flatpak-builder/ccache/7/2/664v0onm4keb8h1sg8uf318l2qj991cM new file mode 100644 index 0000000..073f71e Binary files /dev/null and b/.flatpak-builder/ccache/7/2/664v0onm4keb8h1sg8uf318l2qj991cM differ diff --git a/.flatpak-builder/ccache/7/2/stats b/.flatpak-builder/ccache/7/2/stats new file mode 100644 index 0000000..68c5368 --- /dev/null +++ b/.flatpak-builder/ccache/7/2/stats @@ -0,0 +1,82 @@ +0 +0 +0 +0 +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +1 +1 +0 +2 +0 +0 +0 +0 +0 +0 +2 +0 +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 diff --git a/.flatpak-builder/ccache/7/3/c6uvgcg58shc5g8rqg259bom4fm3hvuM b/.flatpak-builder/ccache/7/3/c6uvgcg58shc5g8rqg259bom4fm3hvuM new file mode 100644 index 0000000..da5791f Binary files /dev/null and b/.flatpak-builder/ccache/7/3/c6uvgcg58shc5g8rqg259bom4fm3hvuM differ diff --git a/.flatpak-builder/ccache/7/3/stats b/.flatpak-builder/ccache/7/3/stats index 5e796ec..cba578e 100644 --- a/.flatpak-builder/ccache/7/3/stats +++ b/.flatpak-builder/ccache/7/3/stats @@ -2,9 +2,13 @@ 0 0 0 +<<<<<<< HEAD 1 0 0 +======= +2 +>>>>>>> new-pomodoro 0 0 0 @@ -17,6 +21,11 @@ 0 0 0 +<<<<<<< HEAD +======= +3 +0 +>>>>>>> new-pomodoro 1 0 0 @@ -31,9 +40,24 @@ 0 0 0 +<<<<<<< HEAD +1 1 +0 +======= +3 +2 1 +5 +0 0 +0 +0 +0 +0 +5 +1 +>>>>>>> new-pomodoro 2 0 0 @@ -41,6 +65,7 @@ 0 0 0 +<<<<<<< HEAD 2 0 1 @@ -50,6 +75,8 @@ 0 0 0 +======= +>>>>>>> new-pomodoro 0 0 0 diff --git a/.flatpak-builder/ccache/7/4/7139bfnejt6ac2hoejo5qkuc4gnhtkuR b/.flatpak-builder/ccache/7/4/7139bfnejt6ac2hoejo5qkuc4gnhtkuR new file mode 100644 index 0000000..5f2e842 Binary files /dev/null and b/.flatpak-builder/ccache/7/4/7139bfnejt6ac2hoejo5qkuc4gnhtkuR differ diff --git a/.flatpak-builder/ccache/7/4/f98haktdl9l2qkqe74c2vgiposele1oR b/.flatpak-builder/ccache/7/4/f98haktdl9l2qkqe74c2vgiposele1oR new file mode 100644 index 0000000..f0c1314 Binary files /dev/null and b/.flatpak-builder/ccache/7/4/f98haktdl9l2qkqe74c2vgiposele1oR differ diff --git a/.flatpak-builder/ccache/7/4/stats b/.flatpak-builder/ccache/7/4/stats index 7be146c..bdb088e 100644 --- a/.flatpak-builder/ccache/7/4/stats +++ b/.flatpak-builder/ccache/7/4/stats @@ -20,6 +20,7 @@ 0 0 0 +<<<<<<< HEAD 0 0 0 @@ -43,6 +44,31 @@ 0 0 0 +======= +2 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +4 +0 +0 +0 +0 +0 +0 +0 +0 +2 +>>>>>>> new-pomodoro 0 0 0 diff --git a/.flatpak-builder/ccache/7/5/50k8uhelemm0mbtusgo742d49qid0pkM b/.flatpak-builder/ccache/7/5/50k8uhelemm0mbtusgo742d49qid0pkM new file mode 100644 index 0000000..a772c67 Binary files /dev/null and b/.flatpak-builder/ccache/7/5/50k8uhelemm0mbtusgo742d49qid0pkM differ diff --git a/.flatpak-builder/ccache/7/5/fesiclevuahns8ao8262gm95nupn7ncR b/.flatpak-builder/ccache/7/5/fesiclevuahns8ao8262gm95nupn7ncR new file mode 100644 index 0000000..0fa6530 Binary files /dev/null and b/.flatpak-builder/ccache/7/5/fesiclevuahns8ao8262gm95nupn7ncR differ diff --git a/.flatpak-builder/ccache/7/5/stats b/.flatpak-builder/ccache/7/5/stats new file mode 100644 index 0000000..68c5368 --- /dev/null +++ b/.flatpak-builder/ccache/7/5/stats @@ -0,0 +1,82 @@ +0 +0 +0 +0 +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +1 +1 +0 +2 +0 +0 +0 +0 +0 +0 +2 +0 +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 diff --git a/.flatpak-builder/ccache/7/6/19j5qb5tnfqsp24d31mi2bqj24r0e0aM b/.flatpak-builder/ccache/7/6/19j5qb5tnfqsp24d31mi2bqj24r0e0aM new file mode 100644 index 0000000..9b7603c Binary files /dev/null and b/.flatpak-builder/ccache/7/6/19j5qb5tnfqsp24d31mi2bqj24r0e0aM differ diff --git a/.flatpak-builder/ccache/7/6/65iftikuf59bh8v0ol0r1bef2i4tv70M b/.flatpak-builder/ccache/7/6/65iftikuf59bh8v0ol0r1bef2i4tv70M new file mode 100644 index 0000000..83e9e12 Binary files /dev/null and b/.flatpak-builder/ccache/7/6/65iftikuf59bh8v0ol0r1bef2i4tv70M differ diff --git a/.flatpak-builder/ccache/7/6/d194ucoic57m7vq457u6aguh7jcr8deM b/.flatpak-builder/ccache/7/6/d194ucoic57m7vq457u6aguh7jcr8deM new file mode 100644 index 0000000..622b04e Binary files /dev/null and b/.flatpak-builder/ccache/7/6/d194ucoic57m7vq457u6aguh7jcr8deM differ diff --git a/.flatpak-builder/ccache/7/6/stats b/.flatpak-builder/ccache/7/6/stats index 68c5368..773a110 100644 --- a/.flatpak-builder/ccache/7/6/stats +++ b/.flatpak-builder/ccache/7/6/stats @@ -2,11 +2,14 @@ 0 0 0 +<<<<<<< HEAD 1 0 0 0 0 +======= +>>>>>>> new-pomodoro 0 0 0 @@ -22,6 +25,7 @@ 0 0 0 +<<<<<<< HEAD 0 0 0 @@ -44,6 +48,35 @@ 2 0 1 +======= +2 +0 +0 +2 +0 +0 +0 +0 +0 +2 +0 +0 +0 +0 +0 +0 +4 +0 +0 +0 +0 +0 +0 +0 +0 +2 +0 +>>>>>>> new-pomodoro 0 0 0 diff --git a/.flatpak-builder/ccache/7/7/stats b/.flatpak-builder/ccache/7/7/stats index eba65b8..3ed81b5 100644 --- a/.flatpak-builder/ccache/7/7/stats +++ b/.flatpak-builder/ccache/7/7/stats @@ -8,7 +8,11 @@ 0 0 0 +<<<<<<< HEAD 1 +======= +3 +>>>>>>> new-pomodoro 0 0 0 diff --git a/.flatpak-builder/ccache/7/8/01bnmk7827ht0f539jsi58nbqceoai4R b/.flatpak-builder/ccache/7/8/01bnmk7827ht0f539jsi58nbqceoai4R new file mode 100644 index 0000000..e1e4719 Binary files /dev/null and b/.flatpak-builder/ccache/7/8/01bnmk7827ht0f539jsi58nbqceoai4R differ diff --git a/.flatpak-builder/ccache/7/8/stats b/.flatpak-builder/ccache/7/8/stats index 68c5368..43e8801 100644 --- a/.flatpak-builder/ccache/7/8/stats +++ b/.flatpak-builder/ccache/7/8/stats @@ -2,6 +2,7 @@ 0 0 0 +<<<<<<< HEAD 1 0 0 @@ -34,6 +35,8 @@ 1 1 0 +======= +>>>>>>> new-pomodoro 2 0 0 @@ -41,9 +44,47 @@ 0 0 0 +<<<<<<< HEAD 2 0 1 +======= +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +2 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +2 +2 +4 +4 +0 +0 +0 +0 +0 +0 +4 +2 +2 +>>>>>>> new-pomodoro 0 0 0 diff --git a/.flatpak-builder/ccache/7/9/c91edc392aurk5fpdhqe82142r0c98oM b/.flatpak-builder/ccache/7/9/c91edc392aurk5fpdhqe82142r0c98oM new file mode 100644 index 0000000..eb498ed Binary files /dev/null and b/.flatpak-builder/ccache/7/9/c91edc392aurk5fpdhqe82142r0c98oM differ diff --git a/.flatpak-builder/ccache/7/9/stats b/.flatpak-builder/ccache/7/9/stats index 85e812b..1edd9d1 100644 --- a/.flatpak-builder/ccache/7/9/stats +++ b/.flatpak-builder/ccache/7/9/stats @@ -6,9 +6,15 @@ 0 0 0 +<<<<<<< HEAD 0 0 0 +======= +1 +0 +1 +>>>>>>> new-pomodoro 0 0 0 @@ -31,8 +37,22 @@ 0 0 0 +<<<<<<< HEAD +0 0 +======= +1 +0 +3 +1 0 +0 +0 +0 +0 +0 +1 +>>>>>>> new-pomodoro 2 0 0 @@ -42,6 +62,7 @@ 0 0 0 +<<<<<<< HEAD 1 0 0 @@ -51,6 +72,8 @@ 0 0 0 +======= +>>>>>>> new-pomodoro 0 0 0 diff --git a/.flatpak-builder/ccache/7/CACHEDIR.TAG b/.flatpak-builder/ccache/7/CACHEDIR.TAG new file mode 100644 index 0000000..874477f --- /dev/null +++ b/.flatpak-builder/ccache/7/CACHEDIR.TAG @@ -0,0 +1,4 @@ +Signature: 8a477f597d28d172789f06886806bc55 +# This file is a cache directory tag created by ccache. +# For information about cache directory tags, see: +# http://www.brynosaurus.com/cachedir/ diff --git a/.flatpak-builder/ccache/7/a/3au23nva0kqhm3ms8nlk3khnc3vpiq0M b/.flatpak-builder/ccache/7/a/3au23nva0kqhm3ms8nlk3khnc3vpiq0M new file mode 100644 index 0000000..f56eb88 Binary files /dev/null and b/.flatpak-builder/ccache/7/a/3au23nva0kqhm3ms8nlk3khnc3vpiq0M differ diff --git a/.flatpak-builder/ccache/7/a/acluaqb7rol0l499oos5rblrcks7d3aM b/.flatpak-builder/ccache/7/a/acluaqb7rol0l499oos5rblrcks7d3aM new file mode 100644 index 0000000..20b61b0 Binary files /dev/null and b/.flatpak-builder/ccache/7/a/acluaqb7rol0l499oos5rblrcks7d3aM differ diff --git a/.flatpak-builder/ccache/7/a/stats b/.flatpak-builder/ccache/7/a/stats index 5203da7..c2f85ef 100644 --- a/.flatpak-builder/ccache/7/a/stats +++ b/.flatpak-builder/ccache/7/a/stats @@ -1,13 +1,20 @@ 0 0 +<<<<<<< HEAD 0 +======= +2 0 +5 +>>>>>>> new-pomodoro 0 0 0 0 0 0 +0 +<<<<<<< HEAD 1 0 0 @@ -15,6 +22,10 @@ 0 0 0 +======= +>>>>>>> new-pomodoro +0 +0 0 0 0 @@ -34,16 +45,27 @@ 0 0 0 +<<<<<<< HEAD 0 +======= +7 +7 0 +14 +>>>>>>> new-pomodoro 0 0 0 0 0 0 +<<<<<<< HEAD 0 +======= +10 0 +5 +>>>>>>> new-pomodoro 0 0 0 diff --git a/.flatpak-builder/ccache/7/b/2cj6s7lfqsp7uf9djierdit0ks340haM b/.flatpak-builder/ccache/7/b/2cj6s7lfqsp7uf9djierdit0ks340haM new file mode 100644 index 0000000..b58b22c Binary files /dev/null and b/.flatpak-builder/ccache/7/b/2cj6s7lfqsp7uf9djierdit0ks340haM differ diff --git a/.flatpak-builder/ccache/7/b/51pmbarhr62de8hs2ofl33irlepvisgM b/.flatpak-builder/ccache/7/b/51pmbarhr62de8hs2ofl33irlepvisgM new file mode 100644 index 0000000..f666240 Binary files /dev/null and b/.flatpak-builder/ccache/7/b/51pmbarhr62de8hs2ofl33irlepvisgM differ diff --git a/.flatpak-builder/ccache/7/b/5ajekkejam46vhcqvq4srrmusjnqf62M b/.flatpak-builder/ccache/7/b/5ajekkejam46vhcqvq4srrmusjnqf62M new file mode 100644 index 0000000..0679c62 Binary files /dev/null and b/.flatpak-builder/ccache/7/b/5ajekkejam46vhcqvq4srrmusjnqf62M differ diff --git a/.flatpak-builder/ccache/7/b/b8jge44hmol28pm9p6g952up51bqdb6M b/.flatpak-builder/ccache/7/b/b8jge44hmol28pm9p6g952up51bqdb6M new file mode 100644 index 0000000..37b4be1 Binary files /dev/null and b/.flatpak-builder/ccache/7/b/b8jge44hmol28pm9p6g952up51bqdb6M differ diff --git a/.flatpak-builder/ccache/7/b/stats b/.flatpak-builder/ccache/7/b/stats index 82d956f..f12847e 100644 --- a/.flatpak-builder/ccache/7/b/stats +++ b/.flatpak-builder/ccache/7/b/stats @@ -6,7 +6,11 @@ 1 0 0 +<<<<<<< HEAD 0 +======= +1 +>>>>>>> new-pomodoro 0 0 0 @@ -31,19 +35,32 @@ 0 0 0 +<<<<<<< HEAD 2 1 2 3 +======= +3 +1 +3 +4 +>>>>>>> new-pomodoro 0 0 0 0 0 0 +<<<<<<< HEAD 2 1 1 +======= +3 +2 +1 +>>>>>>> new-pomodoro 0 0 0 diff --git a/.flatpak-builder/ccache/7/c/1d054q9bto9pcn2mp5j05lt2ns2e9eaR b/.flatpak-builder/ccache/7/c/1d054q9bto9pcn2mp5j05lt2ns2e9eaR new file mode 100644 index 0000000..67eac64 Binary files /dev/null and b/.flatpak-builder/ccache/7/c/1d054q9bto9pcn2mp5j05lt2ns2e9eaR differ diff --git a/.flatpak-builder/ccache/7/c/stats b/.flatpak-builder/ccache/7/c/stats index fdb1454..e0577d3 100644 --- a/.flatpak-builder/ccache/7/c/stats +++ b/.flatpak-builder/ccache/7/c/stats @@ -2,6 +2,13 @@ 0 0 0 +<<<<<<< HEAD +======= +1 +0 +0 +0 +>>>>>>> new-pomodoro 2 0 0 @@ -11,10 +18,15 @@ 0 0 0 +<<<<<<< HEAD +======= +2 +>>>>>>> new-pomodoro 0 0 0 0 +<<<<<<< HEAD 0 0 0 @@ -26,14 +38,27 @@ 0 0 0 +======= +2 +>>>>>>> new-pomodoro 0 0 0 0 0 2 +<<<<<<< HEAD 2 0 +======= +0 +0 +0 +0 +3 +1 +6 +>>>>>>> new-pomodoro 4 0 0 @@ -42,8 +67,13 @@ 0 0 4 +<<<<<<< HEAD 0 2 +======= +4 +1 +>>>>>>> new-pomodoro 0 0 0 diff --git a/.flatpak-builder/ccache/7/d/4erqdmi8t28f3rpgircvtg3augl960eR b/.flatpak-builder/ccache/7/d/4erqdmi8t28f3rpgircvtg3augl960eR new file mode 100644 index 0000000..8543e33 Binary files /dev/null and b/.flatpak-builder/ccache/7/d/4erqdmi8t28f3rpgircvtg3augl960eR differ diff --git a/.flatpak-builder/ccache/7/d/63l9heg8m1buqr5islfgebg9osfr900M b/.flatpak-builder/ccache/7/d/63l9heg8m1buqr5islfgebg9osfr900M new file mode 100644 index 0000000..94a9f04 Binary files /dev/null and b/.flatpak-builder/ccache/7/d/63l9heg8m1buqr5islfgebg9osfr900M differ diff --git a/.flatpak-builder/ccache/7/d/d8utrvatn9i6el57errd6jvuq5c4p90M b/.flatpak-builder/ccache/7/d/d8utrvatn9i6el57errd6jvuq5c4p90M new file mode 100644 index 0000000..c3b206e Binary files /dev/null and b/.flatpak-builder/ccache/7/d/d8utrvatn9i6el57errd6jvuq5c4p90M differ diff --git a/.flatpak-builder/ccache/7/d/stats b/.flatpak-builder/ccache/7/d/stats new file mode 100644 index 0000000..68c5368 --- /dev/null +++ b/.flatpak-builder/ccache/7/d/stats @@ -0,0 +1,82 @@ +0 +0 +0 +0 +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +1 +1 +0 +2 +0 +0 +0 +0 +0 +0 +2 +0 +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 diff --git a/.flatpak-builder/ccache/7/e/stats b/.flatpak-builder/ccache/7/e/stats new file mode 100644 index 0000000..6de5542 --- /dev/null +++ b/.flatpak-builder/ccache/7/e/stats @@ -0,0 +1,82 @@ +0 +0 +0 +0 +2 +0 +0 +0 +0 +0 +2 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +2 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +2 +2 +4 +4 +0 +0 +0 +0 +0 +0 +4 +2 +2 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 diff --git a/.flatpak-builder/ccache/7/f/21d3v38sm52den8hg1ut6no9vmiglbcR b/.flatpak-builder/ccache/7/f/21d3v38sm52den8hg1ut6no9vmiglbcR new file mode 100644 index 0000000..d23e10e Binary files /dev/null and b/.flatpak-builder/ccache/7/f/21d3v38sm52den8hg1ut6no9vmiglbcR differ diff --git a/.flatpak-builder/ccache/7/f/stats b/.flatpak-builder/ccache/7/f/stats new file mode 100644 index 0000000..68c5368 --- /dev/null +++ b/.flatpak-builder/ccache/7/f/stats @@ -0,0 +1,82 @@ +0 +0 +0 +0 +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +1 +1 +0 +2 +0 +0 +0 +0 +0 +0 +2 +0 +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 diff --git a/.flatpak-builder/ccache/7/stats b/.flatpak-builder/ccache/7/stats index e7d9ed6..7b23a8c 100644 --- a/.flatpak-builder/ccache/7/stats +++ b/.flatpak-builder/ccache/7/stats @@ -9,6 +9,7 @@ 0 0 0 +<<<<<<< HEAD 20 156 0 @@ -79,4 +80,76 @@ 4 12 8 +======= +45 +776 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +1 +3 +3 +1 +4 +3 +3 +2 +2 +1 +4 +6 +3 +4 +3 +2 +20 +40 +52 +16 +176 +156 +40 +8 +24 +20 +40 +88 +20 +48 +12 +16 +>>>>>>> new-pomodoro 0 diff --git a/.flatpak-builder/ccache/8/0/dfdn9agqo4av8sghm2tb5r7ahrj5deqM b/.flatpak-builder/ccache/8/0/dfdn9agqo4av8sghm2tb5r7ahrj5deqM new file mode 100644 index 0000000..11126ee Binary files /dev/null and b/.flatpak-builder/ccache/8/0/dfdn9agqo4av8sghm2tb5r7ahrj5deqM differ diff --git a/.flatpak-builder/ccache/8/0/e7ua7ut2epvju0aq01aq74j4otsm5osM b/.flatpak-builder/ccache/8/0/e7ua7ut2epvju0aq01aq74j4otsm5osM new file mode 100644 index 0000000..7f83e90 Binary files /dev/null and b/.flatpak-builder/ccache/8/0/e7ua7ut2epvju0aq01aq74j4otsm5osM differ diff --git a/.flatpak-builder/ccache/8/0/stats b/.flatpak-builder/ccache/8/0/stats index eccac08..c96e8f9 100644 --- a/.flatpak-builder/ccache/8/0/stats +++ b/.flatpak-builder/ccache/8/0/stats @@ -2,6 +2,7 @@ 0 0 0 +<<<<<<< HEAD 1 0 0 @@ -34,6 +35,8 @@ 1 1 0 +======= +>>>>>>> new-pomodoro 2 0 0 @@ -41,11 +44,50 @@ 0 0 0 +<<<<<<< HEAD 2 +======= +0 +0 +0 +0 +0 +0 +0 +>>>>>>> new-pomodoro 0 1 0 0 +<<<<<<< HEAD +======= +2 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +2 +2 +4 +4 +0 +0 +0 +0 +0 +0 +4 +2 +2 +0 +0 +>>>>>>> new-pomodoro 0 0 0 diff --git a/.flatpak-builder/ccache/8/1/5ben103arki6t7rlavcp0udursue7i4R b/.flatpak-builder/ccache/8/1/5ben103arki6t7rlavcp0udursue7i4R new file mode 100644 index 0000000..2423b7b Binary files /dev/null and b/.flatpak-builder/ccache/8/1/5ben103arki6t7rlavcp0udursue7i4R differ diff --git a/.flatpak-builder/ccache/8/1/62rs7ugobpb9t89mlg32m967bhfnoeuR b/.flatpak-builder/ccache/8/1/62rs7ugobpb9t89mlg32m967bhfnoeuR new file mode 100644 index 0000000..1d13fab Binary files /dev/null and b/.flatpak-builder/ccache/8/1/62rs7ugobpb9t89mlg32m967bhfnoeuR differ diff --git a/.flatpak-builder/ccache/8/1/7068if32l7baj31qkt123194ph7lrmsM b/.flatpak-builder/ccache/8/1/7068if32l7baj31qkt123194ph7lrmsM new file mode 100644 index 0000000..4706243 Binary files /dev/null and b/.flatpak-builder/ccache/8/1/7068if32l7baj31qkt123194ph7lrmsM differ diff --git a/.flatpak-builder/ccache/8/1/83sss255va8r5fo13o8dshilvgcrpioR b/.flatpak-builder/ccache/8/1/83sss255va8r5fo13o8dshilvgcrpioR new file mode 100644 index 0000000..07a38af Binary files /dev/null and b/.flatpak-builder/ccache/8/1/83sss255va8r5fo13o8dshilvgcrpioR differ diff --git a/.flatpak-builder/ccache/8/1/stats b/.flatpak-builder/ccache/8/1/stats new file mode 100644 index 0000000..147cecf --- /dev/null +++ b/.flatpak-builder/ccache/8/1/stats @@ -0,0 +1,82 @@ +0 +0 +0 +0 +2 +0 +0 +0 +0 +0 +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +2 +2 +0 +4 +0 +0 +0 +0 +0 +0 +4 +0 +2 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 diff --git a/.flatpak-builder/ccache/8/2/0dhrdnmuffsufeepthm9nh7hf3rtam8R b/.flatpak-builder/ccache/8/2/0dhrdnmuffsufeepthm9nh7hf3rtam8R new file mode 100644 index 0000000..b78cab1 Binary files /dev/null and b/.flatpak-builder/ccache/8/2/0dhrdnmuffsufeepthm9nh7hf3rtam8R differ diff --git a/.flatpak-builder/ccache/8/2/4443sdh6rqij2fnelio76aogqtcssmcM b/.flatpak-builder/ccache/8/2/4443sdh6rqij2fnelio76aogqtcssmcM new file mode 100644 index 0000000..0c06329 Binary files /dev/null and b/.flatpak-builder/ccache/8/2/4443sdh6rqij2fnelio76aogqtcssmcM differ diff --git a/.flatpak-builder/ccache/8/2/d5pei922aarif6p5rbe1urfbkip242eR b/.flatpak-builder/ccache/8/2/d5pei922aarif6p5rbe1urfbkip242eR new file mode 100644 index 0000000..0c2d96c Binary files /dev/null and b/.flatpak-builder/ccache/8/2/d5pei922aarif6p5rbe1urfbkip242eR differ diff --git a/.flatpak-builder/ccache/8/2/stats b/.flatpak-builder/ccache/8/2/stats index 861cdb0..c8b86c3 100644 --- a/.flatpak-builder/ccache/8/2/stats +++ b/.flatpak-builder/ccache/8/2/stats @@ -6,7 +6,12 @@ 0 0 0 +<<<<<<< HEAD +======= +3 0 +3 +>>>>>>> new-pomodoro 0 0 0 @@ -18,10 +23,15 @@ 0 0 0 +<<<<<<< HEAD 0 0 0 0 +======= +4 +>>>>>>> new-pomodoro +0 0 0 0 @@ -31,18 +41,30 @@ 0 0 0 +<<<<<<< HEAD 2 2 0 4 +======= +5 +2 +11 +7 +>>>>>>> new-pomodoro 0 0 0 0 0 0 +<<<<<<< HEAD 4 0 +======= +7 +7 +>>>>>>> new-pomodoro 2 0 0 diff --git a/.flatpak-builder/ccache/8/3/00v3f5i2d96ulhov6s515rjjs1h60caM b/.flatpak-builder/ccache/8/3/00v3f5i2d96ulhov6s515rjjs1h60caM new file mode 100644 index 0000000..ac67e66 Binary files /dev/null and b/.flatpak-builder/ccache/8/3/00v3f5i2d96ulhov6s515rjjs1h60caM differ diff --git a/.flatpak-builder/ccache/8/3/a2imb1qb2c1r1bt0em2errlu1op11k4M b/.flatpak-builder/ccache/8/3/a2imb1qb2c1r1bt0em2errlu1op11k4M new file mode 100644 index 0000000..12b83dd Binary files /dev/null and b/.flatpak-builder/ccache/8/3/a2imb1qb2c1r1bt0em2errlu1op11k4M differ diff --git a/.flatpak-builder/ccache/8/3/abnskmievn6pi1am1lqaq7spbku22niM b/.flatpak-builder/ccache/8/3/abnskmievn6pi1am1lqaq7spbku22niM new file mode 100644 index 0000000..9dc9eab Binary files /dev/null and b/.flatpak-builder/ccache/8/3/abnskmievn6pi1am1lqaq7spbku22niM differ diff --git a/.flatpak-builder/ccache/8/3/stats b/.flatpak-builder/ccache/8/3/stats new file mode 100644 index 0000000..68c5368 --- /dev/null +++ b/.flatpak-builder/ccache/8/3/stats @@ -0,0 +1,82 @@ +0 +0 +0 +0 +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +1 +1 +0 +2 +0 +0 +0 +0 +0 +0 +2 +0 +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 diff --git a/.flatpak-builder/ccache/8/4/e5jmrsjoiomcto1n36387g9ohubpdo0R b/.flatpak-builder/ccache/8/4/e5jmrsjoiomcto1n36387g9ohubpdo0R new file mode 100644 index 0000000..c99949a Binary files /dev/null and b/.flatpak-builder/ccache/8/4/e5jmrsjoiomcto1n36387g9ohubpdo0R differ diff --git a/.flatpak-builder/ccache/8/4/stats b/.flatpak-builder/ccache/8/4/stats index 7be146c..e05a09b 100644 --- a/.flatpak-builder/ccache/8/4/stats +++ b/.flatpak-builder/ccache/8/4/stats @@ -15,7 +15,11 @@ 0 0 0 +<<<<<<< HEAD 1 +======= +3 +>>>>>>> new-pomodoro 0 0 0 diff --git a/.flatpak-builder/ccache/8/5/11nt8tg7avghfohiu60skqn626sqvhsM b/.flatpak-builder/ccache/8/5/11nt8tg7avghfohiu60skqn626sqvhsM new file mode 100644 index 0000000..f5d6210 Binary files /dev/null and b/.flatpak-builder/ccache/8/5/11nt8tg7avghfohiu60skqn626sqvhsM differ diff --git a/.flatpak-builder/ccache/8/5/aab1jvbpb2a24upaa6mf2o3rn54lf7qM b/.flatpak-builder/ccache/8/5/aab1jvbpb2a24upaa6mf2o3rn54lf7qM new file mode 100644 index 0000000..7cac486 Binary files /dev/null and b/.flatpak-builder/ccache/8/5/aab1jvbpb2a24upaa6mf2o3rn54lf7qM differ diff --git a/.flatpak-builder/ccache/8/5/d965gtpi59d2a4l9j72erdjviu238d2M b/.flatpak-builder/ccache/8/5/d965gtpi59d2a4l9j72erdjviu238d2M new file mode 100644 index 0000000..f0a603e Binary files /dev/null and b/.flatpak-builder/ccache/8/5/d965gtpi59d2a4l9j72erdjviu238d2M differ diff --git a/.flatpak-builder/ccache/8/5/stats b/.flatpak-builder/ccache/8/5/stats new file mode 100644 index 0000000..70e6c98 --- /dev/null +++ b/.flatpak-builder/ccache/8/5/stats @@ -0,0 +1,82 @@ +0 +0 +0 +0 +0 +0 +0 +0 +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +1 +0 +1 +1 +0 +0 +0 +0 +0 +0 +1 +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 diff --git a/.flatpak-builder/ccache/8/6/0erht71ucufq3laiih8enkthirl5n82R b/.flatpak-builder/ccache/8/6/0erht71ucufq3laiih8enkthirl5n82R new file mode 100644 index 0000000..01eedc2 Binary files /dev/null and b/.flatpak-builder/ccache/8/6/0erht71ucufq3laiih8enkthirl5n82R differ diff --git a/.flatpak-builder/ccache/8/6/3f426sd9s17fnvq2t0978qqjm1dmmg2M b/.flatpak-builder/ccache/8/6/3f426sd9s17fnvq2t0978qqjm1dmmg2M new file mode 100644 index 0000000..9662805 Binary files /dev/null and b/.flatpak-builder/ccache/8/6/3f426sd9s17fnvq2t0978qqjm1dmmg2M differ diff --git a/.flatpak-builder/ccache/8/6/stats b/.flatpak-builder/ccache/8/6/stats new file mode 100644 index 0000000..68c5368 --- /dev/null +++ b/.flatpak-builder/ccache/8/6/stats @@ -0,0 +1,82 @@ +0 +0 +0 +0 +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +1 +1 +0 +2 +0 +0 +0 +0 +0 +0 +2 +0 +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 diff --git a/.flatpak-builder/ccache/8/7/2dqhjdqbt0o6ihmkkqi6lslco5v4l1uM b/.flatpak-builder/ccache/8/7/2dqhjdqbt0o6ihmkkqi6lslco5v4l1uM new file mode 100644 index 0000000..52c3812 Binary files /dev/null and b/.flatpak-builder/ccache/8/7/2dqhjdqbt0o6ihmkkqi6lslco5v4l1uM differ diff --git a/.flatpak-builder/ccache/8/7/c4poa4gtaeoihqj1o2e5be9dit3cjbsM b/.flatpak-builder/ccache/8/7/c4poa4gtaeoihqj1o2e5be9dit3cjbsM new file mode 100644 index 0000000..fe1fad3 Binary files /dev/null and b/.flatpak-builder/ccache/8/7/c4poa4gtaeoihqj1o2e5be9dit3cjbsM differ diff --git a/.flatpak-builder/ccache/8/7/stats b/.flatpak-builder/ccache/8/7/stats index 6ec2a17..9f88ae9 100644 --- a/.flatpak-builder/ccache/8/7/stats +++ b/.flatpak-builder/ccache/8/7/stats @@ -2,9 +2,11 @@ 0 0 0 +<<<<<<< HEAD 1 0 0 +======= 0 0 0 @@ -15,9 +17,39 @@ 0 0 0 +0 +0 +0 +3 +0 +1 +0 +0 +2 +0 +0 +0 +0 +0 +4 +>>>>>>> new-pomodoro +0 +0 +0 +0 +0 +0 +<<<<<<< HEAD +0 +0 +0 +0 1 0 1 +======= +4 +>>>>>>> new-pomodoro 0 0 0 @@ -31,6 +63,7 @@ 0 0 0 +<<<<<<< HEAD 1 1 0 @@ -47,6 +80,8 @@ 0 0 0 +======= +>>>>>>> new-pomodoro 0 0 0 diff --git a/.flatpak-builder/ccache/8/8/54oes7mh5mr86ikr79l4uduvmsvjdauR b/.flatpak-builder/ccache/8/8/54oes7mh5mr86ikr79l4uduvmsvjdauR new file mode 100644 index 0000000..e6713b1 Binary files /dev/null and b/.flatpak-builder/ccache/8/8/54oes7mh5mr86ikr79l4uduvmsvjdauR differ diff --git a/.flatpak-builder/ccache/8/8/5atltea0v3t509mo10f9si2micc0nnaM b/.flatpak-builder/ccache/8/8/5atltea0v3t509mo10f9si2micc0nnaM new file mode 100644 index 0000000..e4b1c24 Binary files /dev/null and b/.flatpak-builder/ccache/8/8/5atltea0v3t509mo10f9si2micc0nnaM differ diff --git a/.flatpak-builder/ccache/8/8/cbionpa9b3aiiona2ee0tp9litfgvcaM b/.flatpak-builder/ccache/8/8/cbionpa9b3aiiona2ee0tp9litfgvcaM new file mode 100644 index 0000000..5ccaaf6 Binary files /dev/null and b/.flatpak-builder/ccache/8/8/cbionpa9b3aiiona2ee0tp9litfgvcaM differ diff --git a/.flatpak-builder/ccache/8/8/stats b/.flatpak-builder/ccache/8/8/stats index 68c5368..b8a6695 100644 --- a/.flatpak-builder/ccache/8/8/stats +++ b/.flatpak-builder/ccache/8/8/stats @@ -6,8 +6,15 @@ 0 0 0 +<<<<<<< HEAD +======= +1 +0 +1 +0 0 0 +>>>>>>> new-pomodoro 0 0 0 @@ -27,6 +34,9 @@ 0 0 0 +<<<<<<< HEAD +0 +0 0 0 0 @@ -43,6 +53,20 @@ 0 2 0 +======= +2 +1 +1 +3 +0 +0 +0 +0 +0 +0 +3 +1 +>>>>>>> new-pomodoro 1 0 0 diff --git a/.flatpak-builder/ccache/8/9/stats b/.flatpak-builder/ccache/8/9/stats index 159047e..929de48 100644 --- a/.flatpak-builder/ccache/8/9/stats +++ b/.flatpak-builder/ccache/8/9/stats @@ -2,21 +2,56 @@ 0 0 0 +<<<<<<< HEAD +======= +1 +0 +0 +0 +0 +>>>>>>> new-pomodoro +0 +0 +0 +0 +0 0 0 0 0 0 +<<<<<<< HEAD +======= +3 0 0 +2 +>>>>>>> new-pomodoro 0 0 0 0 0 +<<<<<<< HEAD +======= +0 +0 +0 +0 +0 +1 +1 +4 +2 +0 +0 +0 0 0 0 +2 +2 +>>>>>>> new-pomodoro 1 0 0 @@ -54,6 +89,7 @@ 0 0 0 +<<<<<<< HEAD 0 0 0 @@ -80,3 +116,5 @@ 0 0 0 +======= +>>>>>>> new-pomodoro diff --git a/.flatpak-builder/ccache/8/CACHEDIR.TAG b/.flatpak-builder/ccache/8/CACHEDIR.TAG new file mode 100644 index 0000000..874477f --- /dev/null +++ b/.flatpak-builder/ccache/8/CACHEDIR.TAG @@ -0,0 +1,4 @@ +Signature: 8a477f597d28d172789f06886806bc55 +# This file is a cache directory tag created by ccache. +# For information about cache directory tags, see: +# http://www.brynosaurus.com/cachedir/ diff --git a/.flatpak-builder/ccache/8/a/26d0ee9fpfud1nualcv4u1i51pdissmR b/.flatpak-builder/ccache/8/a/26d0ee9fpfud1nualcv4u1i51pdissmR new file mode 100644 index 0000000..922a387 Binary files /dev/null and b/.flatpak-builder/ccache/8/a/26d0ee9fpfud1nualcv4u1i51pdissmR differ diff --git a/.flatpak-builder/ccache/8/a/stats b/.flatpak-builder/ccache/8/a/stats index 68c5368..a135599 100644 --- a/.flatpak-builder/ccache/8/a/stats +++ b/.flatpak-builder/ccache/8/a/stats @@ -2,6 +2,13 @@ 0 0 0 +<<<<<<< HEAD +======= +2 +0 +0 +0 +>>>>>>> new-pomodoro 1 0 0 @@ -27,6 +34,7 @@ 0 0 0 +<<<<<<< HEAD 0 0 0 @@ -34,6 +42,20 @@ 1 1 0 +======= +3 +2 +1 +5 +0 +0 +0 +0 +0 +0 +5 +1 +>>>>>>> new-pomodoro 2 0 0 @@ -41,6 +63,7 @@ 0 0 0 +<<<<<<< HEAD 2 0 1 @@ -50,6 +73,8 @@ 0 0 0 +======= +>>>>>>> new-pomodoro 0 0 0 diff --git a/.flatpak-builder/ccache/8/b/stats b/.flatpak-builder/ccache/8/b/stats new file mode 100644 index 0000000..621acad --- /dev/null +++ b/.flatpak-builder/ccache/8/b/stats @@ -0,0 +1,82 @@ +0 +0 +0 +0 +1 +0 +0 +0 +0 +0 +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +1 +1 +0 +2 +0 +0 +0 +0 +0 +0 +2 +0 +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 diff --git a/.flatpak-builder/ccache/8/c/0fr0nojd5rdoskshcdgp5eanvlvmrh4M b/.flatpak-builder/ccache/8/c/0fr0nojd5rdoskshcdgp5eanvlvmrh4M new file mode 100644 index 0000000..11db745 Binary files /dev/null and b/.flatpak-builder/ccache/8/c/0fr0nojd5rdoskshcdgp5eanvlvmrh4M differ diff --git a/.flatpak-builder/ccache/8/c/13vc03s3aauu6tf67n4l1pp8d16b80oM b/.flatpak-builder/ccache/8/c/13vc03s3aauu6tf67n4l1pp8d16b80oM new file mode 100644 index 0000000..4b18d6d Binary files /dev/null and b/.flatpak-builder/ccache/8/c/13vc03s3aauu6tf67n4l1pp8d16b80oM differ diff --git a/.flatpak-builder/ccache/8/c/adk0ak8gtqj633ps77350se36ev2d60M b/.flatpak-builder/ccache/8/c/adk0ak8gtqj633ps77350se36ev2d60M new file mode 100644 index 0000000..d406f54 Binary files /dev/null and b/.flatpak-builder/ccache/8/c/adk0ak8gtqj633ps77350se36ev2d60M differ diff --git a/.flatpak-builder/ccache/8/c/stats b/.flatpak-builder/ccache/8/c/stats index 7534b59..8d9db2b 100644 --- a/.flatpak-builder/ccache/8/c/stats +++ b/.flatpak-builder/ccache/8/c/stats @@ -2,11 +2,53 @@ 0 0 0 +<<<<<<< HEAD +======= +1 +0 +0 +0 +0 +3 +0 +0 +0 +0 +>>>>>>> new-pomodoro +0 +0 +0 +0 +0 +<<<<<<< HEAD +======= +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +1 +1 +0 +2 +0 +0 0 0 0 0 +2 0 +>>>>>>> new-pomodoro 1 0 0 @@ -44,6 +86,7 @@ 0 0 0 +<<<<<<< HEAD 0 0 0 @@ -80,3 +123,5 @@ 0 0 0 +======= +>>>>>>> new-pomodoro diff --git a/.flatpak-builder/ccache/8/d/8bf1vjot9o49u04f9tedkajcgd2frjcR b/.flatpak-builder/ccache/8/d/8bf1vjot9o49u04f9tedkajcgd2frjcR new file mode 100644 index 0000000..35c6f2b Binary files /dev/null and b/.flatpak-builder/ccache/8/d/8bf1vjot9o49u04f9tedkajcgd2frjcR differ diff --git a/.flatpak-builder/ccache/8/d/stats b/.flatpak-builder/ccache/8/d/stats new file mode 100644 index 0000000..e1364cc --- /dev/null +++ b/.flatpak-builder/ccache/8/d/stats @@ -0,0 +1,82 @@ +0 +0 +2 +0 +3 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +2 +0 +0 +0 +0 +0 +2 +0 +0 +0 +0 +5 +5 +4 +10 +0 +0 +0 +0 +0 +0 +6 +2 +3 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 diff --git a/.flatpak-builder/ccache/8/e/194hu3bjour9g5vd1mqoam8gp16dr9aM b/.flatpak-builder/ccache/8/e/194hu3bjour9g5vd1mqoam8gp16dr9aM new file mode 100644 index 0000000..6c9680f Binary files /dev/null and b/.flatpak-builder/ccache/8/e/194hu3bjour9g5vd1mqoam8gp16dr9aM differ diff --git a/.flatpak-builder/ccache/8/e/343a2d0aoh79mqg1r00s02pnbnrbr3kM b/.flatpak-builder/ccache/8/e/343a2d0aoh79mqg1r00s02pnbnrbr3kM new file mode 100644 index 0000000..64e56c9 Binary files /dev/null and b/.flatpak-builder/ccache/8/e/343a2d0aoh79mqg1r00s02pnbnrbr3kM differ diff --git a/.flatpak-builder/ccache/8/e/b626vps2qeio7mbup4oetcjmtvl3unkM b/.flatpak-builder/ccache/8/e/b626vps2qeio7mbup4oetcjmtvl3unkM new file mode 100644 index 0000000..d6535e1 Binary files /dev/null and b/.flatpak-builder/ccache/8/e/b626vps2qeio7mbup4oetcjmtvl3unkM differ diff --git a/.flatpak-builder/ccache/8/e/c9vdocc92tigivi2nobe1o00lvhf828M b/.flatpak-builder/ccache/8/e/c9vdocc92tigivi2nobe1o00lvhf828M new file mode 100644 index 0000000..7064e99 Binary files /dev/null and b/.flatpak-builder/ccache/8/e/c9vdocc92tigivi2nobe1o00lvhf828M differ diff --git a/.flatpak-builder/ccache/8/e/stats b/.flatpak-builder/ccache/8/e/stats index eba65b8..92438b6 100644 --- a/.flatpak-builder/ccache/8/e/stats +++ b/.flatpak-builder/ccache/8/e/stats @@ -2,9 +2,13 @@ 0 0 0 +<<<<<<< HEAD 0 0 0 +======= +2 +>>>>>>> new-pomodoro 0 0 0 @@ -17,6 +21,11 @@ 0 0 0 +<<<<<<< HEAD +======= +0 +0 +>>>>>>> new-pomodoro 1 0 0 @@ -31,6 +40,10 @@ 0 0 0 +<<<<<<< HEAD +0 +0 +0 0 0 0 @@ -41,10 +54,22 @@ 0 0 0 +======= +3 +2 +1 +5 +0 +0 0 0 0 0 +5 +1 +2 +>>>>>>> new-pomodoro +0 0 0 0 diff --git a/.flatpak-builder/ccache/8/f/df3skmtd74b7cs1i2eskmv3cecmh2iaM b/.flatpak-builder/ccache/8/f/df3skmtd74b7cs1i2eskmv3cecmh2iaM new file mode 100644 index 0000000..aa8dee8 Binary files /dev/null and b/.flatpak-builder/ccache/8/f/df3skmtd74b7cs1i2eskmv3cecmh2iaM differ diff --git a/.flatpak-builder/ccache/8/stats b/.flatpak-builder/ccache/8/stats index 14afe43..e3f0e15 100644 --- a/.flatpak-builder/ccache/8/stats +++ b/.flatpak-builder/ccache/8/stats @@ -9,8 +9,13 @@ 0 0 0 +<<<<<<< HEAD 22 208 +======= +48 +820 +>>>>>>> new-pomodoro 0 0 0 @@ -47,6 +52,7 @@ 0 0 0 +<<<<<<< HEAD 2 0 3 @@ -79,4 +85,38 @@ 8 8 0 +======= +4 +4 +5 +5 +1 +3 +2 +2 +3 +1 +3 +3 +3 +2 +6 +1 +32 +92 +100 +60 +4 +52 +60 +28 +60 +4 +140 +12 +44 +56 +56 +20 +>>>>>>> new-pomodoro 0 diff --git a/.flatpak-builder/ccache/9/0/caue3sotvev0rp5d33scmmg589ijlogM b/.flatpak-builder/ccache/9/0/caue3sotvev0rp5d33scmmg589ijlogM new file mode 100644 index 0000000..1dca99c Binary files /dev/null and b/.flatpak-builder/ccache/9/0/caue3sotvev0rp5d33scmmg589ijlogM differ diff --git a/.flatpak-builder/ccache/9/0/e3h4t8bhe60egmeicocqbt5e1qbs044M b/.flatpak-builder/ccache/9/0/e3h4t8bhe60egmeicocqbt5e1qbs044M new file mode 100644 index 0000000..ac462a7 Binary files /dev/null and b/.flatpak-builder/ccache/9/0/e3h4t8bhe60egmeicocqbt5e1qbs044M differ diff --git a/.flatpak-builder/ccache/9/0/stats b/.flatpak-builder/ccache/9/0/stats index 94504b0..49f97d1 100644 --- a/.flatpak-builder/ccache/9/0/stats +++ b/.flatpak-builder/ccache/9/0/stats @@ -2,6 +2,18 @@ 0 0 0 +<<<<<<< HEAD +======= +1 +0 +0 +0 +0 +>>>>>>> new-pomodoro +0 +0 +0 +0 0 0 0 @@ -11,21 +23,40 @@ 0 0 0 +<<<<<<< HEAD +======= +4 0 0 0 0 0 +1 +0 +0 +0 +0 +1 +1 +8 +2 +>>>>>>> new-pomodoro +0 0 0 0 0 0 +<<<<<<< HEAD 0 0 0 0 0 +======= +2 +4 +>>>>>>> new-pomodoro 1 0 0 @@ -63,6 +94,7 @@ 0 0 0 +<<<<<<< HEAD 0 0 0 @@ -80,3 +112,5 @@ 0 0 0 +======= +>>>>>>> new-pomodoro diff --git a/.flatpak-builder/ccache/9/1/110rrpht9cb106imi34v8lhhbsnufpuR b/.flatpak-builder/ccache/9/1/110rrpht9cb106imi34v8lhhbsnufpuR new file mode 100644 index 0000000..96fd64d Binary files /dev/null and b/.flatpak-builder/ccache/9/1/110rrpht9cb106imi34v8lhhbsnufpuR differ diff --git a/.flatpak-builder/ccache/9/1/52k115311730le3gu2222cb3bipekoaM b/.flatpak-builder/ccache/9/1/52k115311730le3gu2222cb3bipekoaM new file mode 100644 index 0000000..5d57ec7 Binary files /dev/null and b/.flatpak-builder/ccache/9/1/52k115311730le3gu2222cb3bipekoaM differ diff --git a/.flatpak-builder/ccache/9/1/90gp2n72rjiahoj1rtfuaepjm9dnl2kR b/.flatpak-builder/ccache/9/1/90gp2n72rjiahoj1rtfuaepjm9dnl2kR new file mode 100644 index 0000000..ae2179a Binary files /dev/null and b/.flatpak-builder/ccache/9/1/90gp2n72rjiahoj1rtfuaepjm9dnl2kR differ diff --git a/.flatpak-builder/ccache/9/1/stats b/.flatpak-builder/ccache/9/1/stats index 112bd13..01aa1b3 100644 --- a/.flatpak-builder/ccache/9/1/stats +++ b/.flatpak-builder/ccache/9/1/stats @@ -2,6 +2,7 @@ 0 0 0 +<<<<<<< HEAD 1 0 0 @@ -34,6 +35,12 @@ 1 1 0 +======= +3 +0 +0 +0 +>>>>>>> new-pomodoro 2 0 0 @@ -41,9 +48,43 @@ 0 0 0 +<<<<<<< HEAD 2 0 1 +======= +0 +0 +3 +0 +0 +0 +0 +2 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +5 +3 +6 +8 +0 +0 +0 +0 +0 +0 +8 +4 +3 +>>>>>>> new-pomodoro 0 0 0 diff --git a/.flatpak-builder/ccache/9/2/07cgvahc3uv1vvaol0519s2dsic3ftgR b/.flatpak-builder/ccache/9/2/07cgvahc3uv1vvaol0519s2dsic3ftgR new file mode 100644 index 0000000..743bbd4 Binary files /dev/null and b/.flatpak-builder/ccache/9/2/07cgvahc3uv1vvaol0519s2dsic3ftgR differ diff --git a/.flatpak-builder/ccache/9/2/26lndhl995u1a5hvpigol4klo66p2jsR b/.flatpak-builder/ccache/9/2/26lndhl995u1a5hvpigol4klo66p2jsR new file mode 100644 index 0000000..b54f49a Binary files /dev/null and b/.flatpak-builder/ccache/9/2/26lndhl995u1a5hvpigol4klo66p2jsR differ diff --git a/.flatpak-builder/ccache/9/2/3av2n7ba5eaeg3l8nlnkrrckve1ougeR b/.flatpak-builder/ccache/9/2/3av2n7ba5eaeg3l8nlnkrrckve1ougeR new file mode 100644 index 0000000..f6e7b72 Binary files /dev/null and b/.flatpak-builder/ccache/9/2/3av2n7ba5eaeg3l8nlnkrrckve1ougeR differ diff --git a/.flatpak-builder/ccache/9/2/867sgh4jsq33lol68nbq7koa5r6lfggR b/.flatpak-builder/ccache/9/2/867sgh4jsq33lol68nbq7koa5r6lfggR new file mode 100644 index 0000000..2db353c Binary files /dev/null and b/.flatpak-builder/ccache/9/2/867sgh4jsq33lol68nbq7koa5r6lfggR differ diff --git a/.flatpak-builder/ccache/9/2/8bskiis75ijijf2t77g9ftl1bj0a6qoM b/.flatpak-builder/ccache/9/2/8bskiis75ijijf2t77g9ftl1bj0a6qoM new file mode 100644 index 0000000..6c8fa8f Binary files /dev/null and b/.flatpak-builder/ccache/9/2/8bskiis75ijijf2t77g9ftl1bj0a6qoM differ diff --git a/.flatpak-builder/ccache/9/2/95uk0u2t486t72n2eido1ltjmfcjgleR b/.flatpak-builder/ccache/9/2/95uk0u2t486t72n2eido1ltjmfcjgleR new file mode 100644 index 0000000..67b15be Binary files /dev/null and b/.flatpak-builder/ccache/9/2/95uk0u2t486t72n2eido1ltjmfcjgleR differ diff --git a/.flatpak-builder/ccache/9/2/97pmsd3qvair9obfiotmedv1k4q7tloM b/.flatpak-builder/ccache/9/2/97pmsd3qvair9obfiotmedv1k4q7tloM new file mode 100644 index 0000000..62255ba Binary files /dev/null and b/.flatpak-builder/ccache/9/2/97pmsd3qvair9obfiotmedv1k4q7tloM differ diff --git a/.flatpak-builder/ccache/9/2/d9bgn0f76405tupkjpuvvitalcv64dcM b/.flatpak-builder/ccache/9/2/d9bgn0f76405tupkjpuvvitalcv64dcM new file mode 100644 index 0000000..a72739d Binary files /dev/null and b/.flatpak-builder/ccache/9/2/d9bgn0f76405tupkjpuvvitalcv64dcM differ diff --git a/.flatpak-builder/ccache/9/2/e2ii9gh8qju8kdss1uv2m89oqq4jmeeM b/.flatpak-builder/ccache/9/2/e2ii9gh8qju8kdss1uv2m89oqq4jmeeM new file mode 100644 index 0000000..3818bb9 Binary files /dev/null and b/.flatpak-builder/ccache/9/2/e2ii9gh8qju8kdss1uv2m89oqq4jmeeM differ diff --git a/.flatpak-builder/ccache/9/2/stats b/.flatpak-builder/ccache/9/2/stats index 68c5368..2f24a7c 100644 --- a/.flatpak-builder/ccache/9/2/stats +++ b/.flatpak-builder/ccache/9/2/stats @@ -2,6 +2,7 @@ 0 0 0 +<<<<<<< HEAD 1 0 0 @@ -34,6 +35,8 @@ 1 1 0 +======= +>>>>>>> new-pomodoro 2 0 0 @@ -41,9 +44,47 @@ 0 0 0 +<<<<<<< HEAD 2 0 1 +======= +0 +0 +0 +0 +0 +0 +0 +0 +2 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +2 +2 +0 +4 +0 +0 +0 +0 +0 +0 +4 +0 +2 +>>>>>>> new-pomodoro 0 0 0 diff --git a/.flatpak-builder/ccache/9/3/69q6dmsjmau9s1l93dnn8tli0k6gejaM b/.flatpak-builder/ccache/9/3/69q6dmsjmau9s1l93dnn8tli0k6gejaM new file mode 100644 index 0000000..88eca41 Binary files /dev/null and b/.flatpak-builder/ccache/9/3/69q6dmsjmau9s1l93dnn8tli0k6gejaM differ diff --git a/.flatpak-builder/ccache/9/3/71mpg2q0i3qdustplgdbl9gss49bu1qR b/.flatpak-builder/ccache/9/3/71mpg2q0i3qdustplgdbl9gss49bu1qR new file mode 100644 index 0000000..651a570 Binary files /dev/null and b/.flatpak-builder/ccache/9/3/71mpg2q0i3qdustplgdbl9gss49bu1qR differ diff --git a/.flatpak-builder/ccache/9/3/96cpsufdq4ktqfgve66co7ri75gv8nsR b/.flatpak-builder/ccache/9/3/96cpsufdq4ktqfgve66co7ri75gv8nsR new file mode 100644 index 0000000..d76d121 Binary files /dev/null and b/.flatpak-builder/ccache/9/3/96cpsufdq4ktqfgve66co7ri75gv8nsR differ diff --git a/.flatpak-builder/ccache/9/3/stats b/.flatpak-builder/ccache/9/3/stats index fdb1454..847df31 100644 --- a/.flatpak-builder/ccache/9/3/stats +++ b/.flatpak-builder/ccache/9/3/stats @@ -20,7 +20,11 @@ 0 0 0 +<<<<<<< HEAD 0 +======= +3 +>>>>>>> new-pomodoro 0 0 0 @@ -33,7 +37,11 @@ 0 2 2 +<<<<<<< HEAD 0 +======= +6 +>>>>>>> new-pomodoro 4 0 0 @@ -42,7 +50,11 @@ 0 0 4 +<<<<<<< HEAD 0 +======= +3 +>>>>>>> new-pomodoro 2 0 0 diff --git a/.flatpak-builder/ccache/9/4/b16vncqr7a33ccb6d6gaioi32qthauaR b/.flatpak-builder/ccache/9/4/b16vncqr7a33ccb6d6gaioi32qthauaR new file mode 100644 index 0000000..497f344 Binary files /dev/null and b/.flatpak-builder/ccache/9/4/b16vncqr7a33ccb6d6gaioi32qthauaR differ diff --git a/.flatpak-builder/ccache/9/4/stats b/.flatpak-builder/ccache/9/4/stats index 159047e..595e629 100644 --- a/.flatpak-builder/ccache/9/4/stats +++ b/.flatpak-builder/ccache/9/4/stats @@ -2,9 +2,30 @@ 0 0 0 +<<<<<<< HEAD +======= +1 +0 +0 +0 +0 +0 +1 +0 +0 +0 +0 +0 0 0 0 +1 +0 +0 +0 +0 +>>>>>>> new-pomodoro +0 0 0 0 @@ -13,10 +34,24 @@ 0 0 0 +<<<<<<< HEAD +======= +1 +1 +0 +2 +>>>>>>> new-pomodoro +0 +0 +0 0 0 0 +<<<<<<< HEAD +======= +2 0 +>>>>>>> new-pomodoro 1 0 0 @@ -54,6 +89,7 @@ 0 0 0 +<<<<<<< HEAD 0 0 0 @@ -80,3 +116,5 @@ 0 0 0 +======= +>>>>>>> new-pomodoro diff --git a/.flatpak-builder/ccache/9/5/44v2q3u8t7rqe7hqjl1eoq4n2120s0iM b/.flatpak-builder/ccache/9/5/44v2q3u8t7rqe7hqjl1eoq4n2120s0iM new file mode 100644 index 0000000..c0af691 Binary files /dev/null and b/.flatpak-builder/ccache/9/5/44v2q3u8t7rqe7hqjl1eoq4n2120s0iM differ diff --git a/.flatpak-builder/ccache/9/5/stats b/.flatpak-builder/ccache/9/5/stats index cd47901..fa15d3a 100644 --- a/.flatpak-builder/ccache/9/5/stats +++ b/.flatpak-builder/ccache/9/5/stats @@ -2,6 +2,7 @@ 0 0 0 +<<<<<<< HEAD 1 0 0 @@ -34,15 +35,20 @@ 1 1 0 +======= +>>>>>>> new-pomodoro 2 0 0 0 0 0 +<<<<<<< HEAD 0 2 0 +======= +>>>>>>> new-pomodoro 1 0 0 @@ -52,6 +58,44 @@ 0 0 0 +<<<<<<< HEAD +======= +1 +0 +0 +2 +0 +0 +0 +0 +0 +1 +0 +0 +0 +0 +2 +2 +4 +4 +0 +0 +0 +0 +0 +0 +4 +2 +2 +0 +0 +0 +0 +0 +0 +0 +0 +>>>>>>> new-pomodoro 0 0 0 diff --git a/.flatpak-builder/ccache/9/6/05reqblmoek51sudgon43i2ail4ktaeR b/.flatpak-builder/ccache/9/6/05reqblmoek51sudgon43i2ail4ktaeR new file mode 100644 index 0000000..20ceb5c Binary files /dev/null and b/.flatpak-builder/ccache/9/6/05reqblmoek51sudgon43i2ail4ktaeR differ diff --git a/.flatpak-builder/ccache/9/6/c33lk0bv6isaqaqji1kbmvk1fofikg8M b/.flatpak-builder/ccache/9/6/c33lk0bv6isaqaqji1kbmvk1fofikg8M new file mode 100644 index 0000000..8a7fbb0 Binary files /dev/null and b/.flatpak-builder/ccache/9/6/c33lk0bv6isaqaqji1kbmvk1fofikg8M differ diff --git a/.flatpak-builder/ccache/9/6/stats b/.flatpak-builder/ccache/9/6/stats new file mode 100644 index 0000000..621acad --- /dev/null +++ b/.flatpak-builder/ccache/9/6/stats @@ -0,0 +1,82 @@ +0 +0 +0 +0 +1 +0 +0 +0 +0 +0 +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +1 +1 +0 +2 +0 +0 +0 +0 +0 +0 +2 +0 +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 diff --git a/.flatpak-builder/ccache/9/7/52tc1m6akffv6vndq7cfjpqol46u02aR b/.flatpak-builder/ccache/9/7/52tc1m6akffv6vndq7cfjpqol46u02aR new file mode 100644 index 0000000..d09fc2f Binary files /dev/null and b/.flatpak-builder/ccache/9/7/52tc1m6akffv6vndq7cfjpqol46u02aR differ diff --git a/.flatpak-builder/ccache/9/7/stats b/.flatpak-builder/ccache/9/7/stats new file mode 100644 index 0000000..4c84f8f --- /dev/null +++ b/.flatpak-builder/ccache/9/7/stats @@ -0,0 +1,82 @@ +0 +0 +0 +0 +0 +0 +0 +0 +1 +0 +2 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +1 +0 +3 +1 +0 +0 +0 +0 +0 +0 +1 +2 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 diff --git a/.flatpak-builder/ccache/9/8/stats b/.flatpak-builder/ccache/9/8/stats new file mode 100644 index 0000000..68c5368 --- /dev/null +++ b/.flatpak-builder/ccache/9/8/stats @@ -0,0 +1,82 @@ +0 +0 +0 +0 +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +1 +1 +0 +2 +0 +0 +0 +0 +0 +0 +2 +0 +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 diff --git a/.flatpak-builder/ccache/9/9/stats b/.flatpak-builder/ccache/9/9/stats index 860ae45..5a458e9 100644 --- a/.flatpak-builder/ccache/9/9/stats +++ b/.flatpak-builder/ccache/9/9/stats @@ -8,7 +8,11 @@ 0 0 0 +<<<<<<< HEAD 1 +======= +0 +>>>>>>> new-pomodoro 0 0 0 diff --git a/.flatpak-builder/ccache/9/CACHEDIR.TAG b/.flatpak-builder/ccache/9/CACHEDIR.TAG new file mode 100644 index 0000000..874477f --- /dev/null +++ b/.flatpak-builder/ccache/9/CACHEDIR.TAG @@ -0,0 +1,4 @@ +Signature: 8a477f597d28d172789f06886806bc55 +# This file is a cache directory tag created by ccache. +# For information about cache directory tags, see: +# http://www.brynosaurus.com/cachedir/ diff --git a/.flatpak-builder/ccache/9/a/016llmp7qghg4dfdd93he02s3emhb18M b/.flatpak-builder/ccache/9/a/016llmp7qghg4dfdd93he02s3emhb18M new file mode 100644 index 0000000..e4869c3 Binary files /dev/null and b/.flatpak-builder/ccache/9/a/016llmp7qghg4dfdd93he02s3emhb18M differ diff --git a/.flatpak-builder/ccache/9/a/63mn9brevcq32km6jkfqesu55tspn74M b/.flatpak-builder/ccache/9/a/63mn9brevcq32km6jkfqesu55tspn74M new file mode 100644 index 0000000..2f9e432 Binary files /dev/null and b/.flatpak-builder/ccache/9/a/63mn9brevcq32km6jkfqesu55tspn74M differ diff --git a/.flatpak-builder/ccache/9/a/96ftk0svtaiicersetjbbhf9u5jtprkM b/.flatpak-builder/ccache/9/a/96ftk0svtaiicersetjbbhf9u5jtprkM new file mode 100644 index 0000000..bd9086c Binary files /dev/null and b/.flatpak-builder/ccache/9/a/96ftk0svtaiicersetjbbhf9u5jtprkM differ diff --git a/.flatpak-builder/ccache/9/a/b6rii7349ccnn5tit1p25e86mq7aqbkM b/.flatpak-builder/ccache/9/a/b6rii7349ccnn5tit1p25e86mq7aqbkM new file mode 100644 index 0000000..7a3d8ac Binary files /dev/null and b/.flatpak-builder/ccache/9/a/b6rii7349ccnn5tit1p25e86mq7aqbkM differ diff --git a/.flatpak-builder/ccache/9/a/eb8f3qo3gct48h44fjrib40fdltjpdmR b/.flatpak-builder/ccache/9/a/eb8f3qo3gct48h44fjrib40fdltjpdmR new file mode 100644 index 0000000..d73398c Binary files /dev/null and b/.flatpak-builder/ccache/9/a/eb8f3qo3gct48h44fjrib40fdltjpdmR differ diff --git a/.flatpak-builder/ccache/9/a/stats b/.flatpak-builder/ccache/9/a/stats new file mode 100644 index 0000000..5f43e14 --- /dev/null +++ b/.flatpak-builder/ccache/9/a/stats @@ -0,0 +1,82 @@ +0 +0 +0 +0 +1 +0 +0 +0 +1 +0 +1 +0 +0 +0 +0 +0 +0 +2 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +2 +1 +1 +3 +0 +0 +0 +0 +0 +0 +3 +1 +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 diff --git a/.flatpak-builder/ccache/9/b/06d90ua7b4j13006botk56p49ibpnm4M b/.flatpak-builder/ccache/9/b/06d90ua7b4j13006botk56p49ibpnm4M new file mode 100644 index 0000000..0c53aba Binary files /dev/null and b/.flatpak-builder/ccache/9/b/06d90ua7b4j13006botk56p49ibpnm4M differ diff --git a/.flatpak-builder/ccache/9/b/stats b/.flatpak-builder/ccache/9/b/stats index 159047e..29cca45 100644 --- a/.flatpak-builder/ccache/9/b/stats +++ b/.flatpak-builder/ccache/9/b/stats @@ -17,7 +17,11 @@ 0 0 0 +<<<<<<< HEAD 1 +======= +3 +>>>>>>> new-pomodoro 0 0 0 diff --git a/.flatpak-builder/ccache/9/c/0fskp9g9jdku0hg34bi4k7a6cvtt5ssR b/.flatpak-builder/ccache/9/c/0fskp9g9jdku0hg34bi4k7a6cvtt5ssR new file mode 100644 index 0000000..7920124 Binary files /dev/null and b/.flatpak-builder/ccache/9/c/0fskp9g9jdku0hg34bi4k7a6cvtt5ssR differ diff --git a/.flatpak-builder/ccache/9/c/12c5f7h0ufi6fgah1st2hmejkmehgnaR b/.flatpak-builder/ccache/9/c/12c5f7h0ufi6fgah1st2hmejkmehgnaR new file mode 100644 index 0000000..b332534 Binary files /dev/null and b/.flatpak-builder/ccache/9/c/12c5f7h0ufi6fgah1st2hmejkmehgnaR differ diff --git a/.flatpak-builder/ccache/9/c/200l1vqa75gj1e9cdlvkga2clnlk8caM b/.flatpak-builder/ccache/9/c/200l1vqa75gj1e9cdlvkga2clnlk8caM new file mode 100644 index 0000000..8e906ab Binary files /dev/null and b/.flatpak-builder/ccache/9/c/200l1vqa75gj1e9cdlvkga2clnlk8caM differ diff --git a/.flatpak-builder/ccache/9/c/feof9fl9buln1n3gvvla37ok2piiag0M b/.flatpak-builder/ccache/9/c/feof9fl9buln1n3gvvla37ok2piiag0M new file mode 100644 index 0000000..81da43e Binary files /dev/null and b/.flatpak-builder/ccache/9/c/feof9fl9buln1n3gvvla37ok2piiag0M differ diff --git a/.flatpak-builder/ccache/9/c/stats b/.flatpak-builder/ccache/9/c/stats index 8eb5989..cd0e9a5 100644 --- a/.flatpak-builder/ccache/9/c/stats +++ b/.flatpak-builder/ccache/9/c/stats @@ -8,6 +8,7 @@ 0 0 0 +<<<<<<< HEAD 0 0 0 @@ -15,6 +16,8 @@ 0 0 0 +======= +>>>>>>> new-pomodoro 1 0 0 @@ -22,6 +25,16 @@ 0 0 0 +<<<<<<< HEAD +======= +1 +0 +2 +0 +0 +2 +0 +>>>>>>> new-pomodoro 0 0 0 @@ -33,7 +46,11 @@ 0 2 2 +<<<<<<< HEAD 0 +======= +4 +>>>>>>> new-pomodoro 4 0 0 @@ -42,7 +59,11 @@ 0 0 4 +<<<<<<< HEAD 0 +======= +2 +>>>>>>> new-pomodoro 2 0 0 diff --git a/.flatpak-builder/ccache/9/d/2djcun7u1tibasdgjspldgcrecs8h7gM b/.flatpak-builder/ccache/9/d/2djcun7u1tibasdgjspldgcrecs8h7gM new file mode 100644 index 0000000..11173cc Binary files /dev/null and b/.flatpak-builder/ccache/9/d/2djcun7u1tibasdgjspldgcrecs8h7gM differ diff --git a/.flatpak-builder/ccache/9/d/stats b/.flatpak-builder/ccache/9/d/stats index 159047e..37e5dbb 100644 --- a/.flatpak-builder/ccache/9/d/stats +++ b/.flatpak-builder/ccache/9/d/stats @@ -2,21 +2,59 @@ 0 0 0 +<<<<<<< HEAD +======= +1 +0 +0 +0 +1 +2 +1 +0 +0 +0 +0 +0 +0 +0 +0 +1 +0 +0 +3 0 0 0 0 +>>>>>>> new-pomodoro 0 0 0 0 0 0 +<<<<<<< HEAD +======= +2 +1 +7 +3 +>>>>>>> new-pomodoro +0 +0 +0 +0 0 0 +<<<<<<< HEAD 0 0 0 +======= +3 +4 +>>>>>>> new-pomodoro 1 0 0 @@ -54,6 +92,7 @@ 0 0 0 +<<<<<<< HEAD 0 0 0 @@ -80,3 +119,5 @@ 0 0 0 +======= +>>>>>>> new-pomodoro diff --git a/.flatpak-builder/ccache/9/e/stats b/.flatpak-builder/ccache/9/e/stats new file mode 100644 index 0000000..24ebfa2 --- /dev/null +++ b/.flatpak-builder/ccache/9/e/stats @@ -0,0 +1,82 @@ +0 +0 +0 +0 +1 +0 +0 +0 +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +3 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +2 +1 +7 +3 +0 +0 +0 +0 +0 +0 +3 +4 +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 diff --git a/.flatpak-builder/ccache/9/f/31vktneeups9juuu6thf601ceijlc9aR b/.flatpak-builder/ccache/9/f/31vktneeups9juuu6thf601ceijlc9aR new file mode 100644 index 0000000..d5f96d5 Binary files /dev/null and b/.flatpak-builder/ccache/9/f/31vktneeups9juuu6thf601ceijlc9aR differ diff --git a/.flatpak-builder/ccache/9/f/b1rhlp7f544441nkck0qv3bs0cdhfrcM b/.flatpak-builder/ccache/9/f/b1rhlp7f544441nkck0qv3bs0cdhfrcM new file mode 100644 index 0000000..77d829d Binary files /dev/null and b/.flatpak-builder/ccache/9/f/b1rhlp7f544441nkck0qv3bs0cdhfrcM differ diff --git a/.flatpak-builder/ccache/9/f/stats b/.flatpak-builder/ccache/9/f/stats index 159047e..74464d5 100644 --- a/.flatpak-builder/ccache/9/f/stats +++ b/.flatpak-builder/ccache/9/f/stats @@ -2,6 +2,15 @@ 0 0 0 +<<<<<<< HEAD +======= +1 +0 +0 +0 +0 +>>>>>>> new-pomodoro +0 0 0 0 @@ -11,12 +20,38 @@ 0 0 0 +<<<<<<< HEAD +======= +1 +0 +0 +2 +>>>>>>> new-pomodoro +0 +0 +0 +0 +0 +<<<<<<< HEAD +======= +0 +0 +0 +0 +0 +1 +1 +4 +2 0 0 0 0 0 0 +2 +2 +>>>>>>> new-pomodoro 1 0 0 @@ -54,6 +89,7 @@ 0 0 0 +<<<<<<< HEAD 0 0 0 @@ -80,3 +116,5 @@ 0 0 0 +======= +>>>>>>> new-pomodoro diff --git a/.flatpak-builder/ccache/9/stats b/.flatpak-builder/ccache/9/stats index 987cd23..a8d7f9d 100644 --- a/.flatpak-builder/ccache/9/stats +++ b/.flatpak-builder/ccache/9/stats @@ -9,6 +9,7 @@ 0 0 0 +<<<<<<< HEAD 20 168 0 @@ -79,4 +80,76 @@ 0 60 0 +======= +53 +800 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +3 +3 +9 +4 +5 +2 +3 +1 +1 +3 +7 +1 +4 +1 +4 +2 +24 +48 +136 +112 +76 +24 +28 +12 +4 +24 +144 +20 +36 +12 +60 +40 +>>>>>>> new-pomodoro 0 diff --git a/.flatpak-builder/ccache/a/0/2e94l8o4sjul7179gi2hn01k43iue3gR b/.flatpak-builder/ccache/a/0/2e94l8o4sjul7179gi2hn01k43iue3gR new file mode 100644 index 0000000..86038cf Binary files /dev/null and b/.flatpak-builder/ccache/a/0/2e94l8o4sjul7179gi2hn01k43iue3gR differ diff --git a/.flatpak-builder/ccache/a/0/stats b/.flatpak-builder/ccache/a/0/stats index 68c5368..0d6a887 100644 --- a/.flatpak-builder/ccache/a/0/stats +++ b/.flatpak-builder/ccache/a/0/stats @@ -6,6 +6,13 @@ 0 0 0 +<<<<<<< HEAD +======= +1 +0 +0 +0 +>>>>>>> new-pomodoro 0 0 0 @@ -27,6 +34,7 @@ 0 0 0 +<<<<<<< HEAD 0 0 0 @@ -43,6 +51,20 @@ 0 2 0 +======= +2 +1 +1 +3 +0 +0 +0 +0 +0 +0 +3 +1 +>>>>>>> new-pomodoro 1 0 0 diff --git a/.flatpak-builder/ccache/a/1/cf2k2bbvgac24ukjjd86q1aoh3jm66eR b/.flatpak-builder/ccache/a/1/cf2k2bbvgac24ukjjd86q1aoh3jm66eR new file mode 100644 index 0000000..3470e8e Binary files /dev/null and b/.flatpak-builder/ccache/a/1/cf2k2bbvgac24ukjjd86q1aoh3jm66eR differ diff --git a/.flatpak-builder/ccache/a/1/stats b/.flatpak-builder/ccache/a/1/stats index 7534b59..aa6d9bf 100644 --- a/.flatpak-builder/ccache/a/1/stats +++ b/.flatpak-builder/ccache/a/1/stats @@ -1,12 +1,22 @@ 0 0 +<<<<<<< HEAD +======= +2 0 0 +>>>>>>> new-pomodoro 0 0 0 0 +<<<<<<< HEAD 0 +0 +0 +======= +1 +>>>>>>> new-pomodoro 1 0 0 @@ -16,6 +26,26 @@ 0 0 0 +<<<<<<< HEAD +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 0 0 0 @@ -24,8 +54,11 @@ 0 0 0 +======= +2 0 0 +2 0 0 0 @@ -36,6 +69,10 @@ 0 0 0 +2 +2 +4 +4 0 0 0 @@ -43,6 +80,8 @@ 0 0 0 +2 +>>>>>>> new-pomodoro 0 0 0 diff --git a/.flatpak-builder/ccache/a/2/5du743a2u2cj6a0ok685sb6k39b5kokM b/.flatpak-builder/ccache/a/2/5du743a2u2cj6a0ok685sb6k39b5kokM new file mode 100644 index 0000000..09c8464 Binary files /dev/null and b/.flatpak-builder/ccache/a/2/5du743a2u2cj6a0ok685sb6k39b5kokM differ diff --git a/.flatpak-builder/ccache/a/2/stats b/.flatpak-builder/ccache/a/2/stats index 7b36bb9..dea4e69 100644 --- a/.flatpak-builder/ccache/a/2/stats +++ b/.flatpak-builder/ccache/a/2/stats @@ -2,10 +2,14 @@ 0 0 0 +<<<<<<< HEAD +======= +1 0 0 0 0 +>>>>>>> new-pomodoro 0 0 0 @@ -16,7 +20,29 @@ 0 0 0 +<<<<<<< HEAD +======= +4 0 +0 +4 +>>>>>>> new-pomodoro +0 +0 +0 +0 +0 +<<<<<<< HEAD +======= +0 +0 +0 +0 +0 +1 +1 +8 +>>>>>>> new-pomodoro 2 0 0 @@ -24,6 +50,7 @@ 0 0 0 +<<<<<<< HEAD 0 0 0 @@ -44,6 +71,11 @@ 0 0 0 +======= +2 +4 +1 +>>>>>>> new-pomodoro 0 0 0 diff --git a/.flatpak-builder/ccache/a/3/30t2s5pjd9sqfaislvdklc7qbnord68R b/.flatpak-builder/ccache/a/3/30t2s5pjd9sqfaislvdklc7qbnord68R new file mode 100644 index 0000000..8b568cd Binary files /dev/null and b/.flatpak-builder/ccache/a/3/30t2s5pjd9sqfaislvdklc7qbnord68R differ diff --git a/.flatpak-builder/ccache/a/3/3amofs2o0n0e3aosq3r94ms0v0vqpvoR b/.flatpak-builder/ccache/a/3/3amofs2o0n0e3aosq3r94ms0v0vqpvoR new file mode 100644 index 0000000..e307d32 Binary files /dev/null and b/.flatpak-builder/ccache/a/3/3amofs2o0n0e3aosq3r94ms0v0vqpvoR differ diff --git a/.flatpak-builder/ccache/a/3/stats b/.flatpak-builder/ccache/a/3/stats index f7fab00..8631fc7 100644 --- a/.flatpak-builder/ccache/a/3/stats +++ b/.flatpak-builder/ccache/a/3/stats @@ -2,14 +2,30 @@ 0 0 0 +<<<<<<< HEAD +======= +1 +0 +0 +0 +1 +0 +0 0 0 +>>>>>>> new-pomodoro 0 0 0 0 0 0 +<<<<<<< HEAD +0 +======= +3 +>>>>>>> new-pomodoro +0 0 0 0 @@ -22,10 +38,24 @@ 0 0 0 +<<<<<<< HEAD +======= +2 +1 +1 +3 +>>>>>>> new-pomodoro 0 0 0 0 +<<<<<<< HEAD +======= +0 +0 +3 +1 +>>>>>>> new-pomodoro 1 0 0 @@ -63,6 +93,7 @@ 0 0 0 +<<<<<<< HEAD 0 0 0 @@ -80,3 +111,5 @@ 0 0 0 +======= +>>>>>>> new-pomodoro diff --git a/.flatpak-builder/ccache/a/4/6d9c7hr3jmslk591ui5po2b48k8nmioM b/.flatpak-builder/ccache/a/4/6d9c7hr3jmslk591ui5po2b48k8nmioM new file mode 100644 index 0000000..b994313 Binary files /dev/null and b/.flatpak-builder/ccache/a/4/6d9c7hr3jmslk591ui5po2b48k8nmioM differ diff --git a/.flatpak-builder/ccache/a/4/stats b/.flatpak-builder/ccache/a/4/stats index 68c5368..a135599 100644 --- a/.flatpak-builder/ccache/a/4/stats +++ b/.flatpak-builder/ccache/a/4/stats @@ -2,6 +2,13 @@ 0 0 0 +<<<<<<< HEAD +======= +2 +0 +0 +0 +>>>>>>> new-pomodoro 1 0 0 @@ -27,6 +34,7 @@ 0 0 0 +<<<<<<< HEAD 0 0 0 @@ -34,6 +42,20 @@ 1 1 0 +======= +3 +2 +1 +5 +0 +0 +0 +0 +0 +0 +5 +1 +>>>>>>> new-pomodoro 2 0 0 @@ -41,6 +63,7 @@ 0 0 0 +<<<<<<< HEAD 2 0 1 @@ -50,6 +73,8 @@ 0 0 0 +======= +>>>>>>> new-pomodoro 0 0 0 diff --git a/.flatpak-builder/ccache/a/5/14v4s905s995n2tvaminsm730738ackR b/.flatpak-builder/ccache/a/5/14v4s905s995n2tvaminsm730738ackR new file mode 100644 index 0000000..d08fbe6 Binary files /dev/null and b/.flatpak-builder/ccache/a/5/14v4s905s995n2tvaminsm730738ackR differ diff --git a/.flatpak-builder/ccache/a/5/83fgulnkt0ct98higd0dpt36fhpmfogM b/.flatpak-builder/ccache/a/5/83fgulnkt0ct98higd0dpt36fhpmfogM new file mode 100644 index 0000000..d294483 Binary files /dev/null and b/.flatpak-builder/ccache/a/5/83fgulnkt0ct98higd0dpt36fhpmfogM differ diff --git a/.flatpak-builder/ccache/a/5/e4qcv7nbni8ffhb6nutijp3rrhdbq52R b/.flatpak-builder/ccache/a/5/e4qcv7nbni8ffhb6nutijp3rrhdbq52R new file mode 100644 index 0000000..ee181fd Binary files /dev/null and b/.flatpak-builder/ccache/a/5/e4qcv7nbni8ffhb6nutijp3rrhdbq52R differ diff --git a/.flatpak-builder/ccache/a/6/380kh4ebhu120v0u6on7bf2hq8d32poR b/.flatpak-builder/ccache/a/6/380kh4ebhu120v0u6on7bf2hq8d32poR new file mode 100644 index 0000000..5115b85 Binary files /dev/null and b/.flatpak-builder/ccache/a/6/380kh4ebhu120v0u6on7bf2hq8d32poR differ diff --git a/.flatpak-builder/ccache/a/6/56pr8nacc0vuubeq4hsumoevob5j8j6M b/.flatpak-builder/ccache/a/6/56pr8nacc0vuubeq4hsumoevob5j8j6M new file mode 100644 index 0000000..adcc909 Binary files /dev/null and b/.flatpak-builder/ccache/a/6/56pr8nacc0vuubeq4hsumoevob5j8j6M differ diff --git a/.flatpak-builder/ccache/a/6/stats b/.flatpak-builder/ccache/a/6/stats index a2f99a7..1d8e12c 100644 --- a/.flatpak-builder/ccache/a/6/stats +++ b/.flatpak-builder/ccache/a/6/stats @@ -2,6 +2,7 @@ 0 0 0 +<<<<<<< HEAD 1 0 0 @@ -34,6 +35,12 @@ 1 1 0 +======= +3 +0 +0 +0 +>>>>>>> new-pomodoro 2 0 0 @@ -41,13 +48,48 @@ 0 0 0 +<<<<<<< HEAD 2 +======= +0 +>>>>>>> new-pomodoro 0 1 0 0 0 0 +<<<<<<< HEAD +======= +2 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +5 +3 +6 +8 +0 +0 +0 +0 +0 +0 +8 +4 +3 +0 +0 +0 +0 +>>>>>>> new-pomodoro 0 0 0 diff --git a/.flatpak-builder/ccache/a/7/3c3slfim53klshk9p4572bc0l5l2aroM b/.flatpak-builder/ccache/a/7/3c3slfim53klshk9p4572bc0l5l2aroM new file mode 100644 index 0000000..1ca1736 Binary files /dev/null and b/.flatpak-builder/ccache/a/7/3c3slfim53klshk9p4572bc0l5l2aroM differ diff --git a/.flatpak-builder/ccache/a/7/a76e80mea6f42bvcsbftc1l9g728uf0M b/.flatpak-builder/ccache/a/7/a76e80mea6f42bvcsbftc1l9g728uf0M new file mode 100644 index 0000000..e977574 Binary files /dev/null and b/.flatpak-builder/ccache/a/7/a76e80mea6f42bvcsbftc1l9g728uf0M differ diff --git a/.flatpak-builder/ccache/a/7/e51cq5qa09mv3gnh7dei07ijior1bh0M b/.flatpak-builder/ccache/a/7/e51cq5qa09mv3gnh7dei07ijior1bh0M new file mode 100644 index 0000000..b01d63c Binary files /dev/null and b/.flatpak-builder/ccache/a/7/e51cq5qa09mv3gnh7dei07ijior1bh0M differ diff --git a/.flatpak-builder/ccache/a/7/stats b/.flatpak-builder/ccache/a/7/stats new file mode 100644 index 0000000..2145faa --- /dev/null +++ b/.flatpak-builder/ccache/a/7/stats @@ -0,0 +1,82 @@ +0 +0 +0 +0 +1 +0 +0 +0 +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +2 +1 +1 +3 +0 +0 +0 +0 +0 +0 +3 +1 +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 diff --git a/.flatpak-builder/ccache/a/8/44ak22me0d9knf4b9ouk9k8qg4b6pf6M b/.flatpak-builder/ccache/a/8/44ak22me0d9knf4b9ouk9k8qg4b6pf6M new file mode 100644 index 0000000..6460a96 Binary files /dev/null and b/.flatpak-builder/ccache/a/8/44ak22me0d9knf4b9ouk9k8qg4b6pf6M differ diff --git a/.flatpak-builder/ccache/a/8/bcdrbqvdf6bnaeopoarcfq834817r8kR b/.flatpak-builder/ccache/a/8/bcdrbqvdf6bnaeopoarcfq834817r8kR new file mode 100644 index 0000000..7f745aa Binary files /dev/null and b/.flatpak-builder/ccache/a/8/bcdrbqvdf6bnaeopoarcfq834817r8kR differ diff --git a/.flatpak-builder/ccache/a/8/c1rg2fdifgt6ua2u3k3kmgf42jcrgioR b/.flatpak-builder/ccache/a/8/c1rg2fdifgt6ua2u3k3kmgf42jcrgioR new file mode 100644 index 0000000..36cc3af Binary files /dev/null and b/.flatpak-builder/ccache/a/8/c1rg2fdifgt6ua2u3k3kmgf42jcrgioR differ diff --git a/.flatpak-builder/ccache/a/8/stats b/.flatpak-builder/ccache/a/8/stats new file mode 100644 index 0000000..a796506 --- /dev/null +++ b/.flatpak-builder/ccache/a/8/stats @@ -0,0 +1,82 @@ +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +4 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +8 +0 +0 +0 +0 +0 +0 +0 +0 +4 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 diff --git a/.flatpak-builder/ccache/a/9/77duflor27qm61mrk9l3kqddsea3nn6M b/.flatpak-builder/ccache/a/9/77duflor27qm61mrk9l3kqddsea3nn6M new file mode 100644 index 0000000..7f83e90 Binary files /dev/null and b/.flatpak-builder/ccache/a/9/77duflor27qm61mrk9l3kqddsea3nn6M differ diff --git a/.flatpak-builder/ccache/a/9/7ddmv99o65lmcbv0onstksl1tke59j4M b/.flatpak-builder/ccache/a/9/7ddmv99o65lmcbv0onstksl1tke59j4M new file mode 100644 index 0000000..ad4614c Binary files /dev/null and b/.flatpak-builder/ccache/a/9/7ddmv99o65lmcbv0onstksl1tke59j4M differ diff --git a/.flatpak-builder/ccache/a/9/c26mca5d9iu09kp74m2mrmdr3ec4kqcR b/.flatpak-builder/ccache/a/9/c26mca5d9iu09kp74m2mrmdr3ec4kqcR new file mode 100644 index 0000000..f10d4aa Binary files /dev/null and b/.flatpak-builder/ccache/a/9/c26mca5d9iu09kp74m2mrmdr3ec4kqcR differ diff --git a/.flatpak-builder/ccache/a/9/stats b/.flatpak-builder/ccache/a/9/stats index 94504b0..30fc3ac 100644 --- a/.flatpak-builder/ccache/a/9/stats +++ b/.flatpak-builder/ccache/a/9/stats @@ -2,6 +2,7 @@ 0 0 0 +<<<<<<< HEAD 0 0 0 @@ -9,6 +10,15 @@ 0 0 0 +======= +2 +0 +0 +0 +1 +0 +1 +>>>>>>> new-pomodoro 0 0 0 @@ -31,6 +41,8 @@ 0 0 0 +<<<<<<< HEAD +0 0 0 0 @@ -43,9 +55,23 @@ 0 0 0 +======= +3 +2 +1 +5 +0 +0 +0 0 0 0 +5 +1 +2 +>>>>>>> new-pomodoro +0 +0 0 0 0 diff --git a/.flatpak-builder/ccache/a/CACHEDIR.TAG b/.flatpak-builder/ccache/a/CACHEDIR.TAG new file mode 100644 index 0000000..874477f --- /dev/null +++ b/.flatpak-builder/ccache/a/CACHEDIR.TAG @@ -0,0 +1,4 @@ +Signature: 8a477f597d28d172789f06886806bc55 +# This file is a cache directory tag created by ccache. +# For information about cache directory tags, see: +# http://www.brynosaurus.com/cachedir/ diff --git a/.flatpak-builder/ccache/a/a/3cvnmln4rodi1m2nletl1rtjen531rkR b/.flatpak-builder/ccache/a/a/3cvnmln4rodi1m2nletl1rtjen531rkR new file mode 100644 index 0000000..36e4f0d Binary files /dev/null and b/.flatpak-builder/ccache/a/a/3cvnmln4rodi1m2nletl1rtjen531rkR differ diff --git a/.flatpak-builder/ccache/a/a/aem8kcms09vvj62b9ma1mv1t88dtjg8M b/.flatpak-builder/ccache/a/a/aem8kcms09vvj62b9ma1mv1t88dtjg8M new file mode 100644 index 0000000..472a15a Binary files /dev/null and b/.flatpak-builder/ccache/a/a/aem8kcms09vvj62b9ma1mv1t88dtjg8M differ diff --git a/.flatpak-builder/ccache/a/a/stats b/.flatpak-builder/ccache/a/a/stats new file mode 100644 index 0000000..c782842 --- /dev/null +++ b/.flatpak-builder/ccache/a/a/stats @@ -0,0 +1,82 @@ +0 +0 +0 +0 +0 +0 +0 +0 +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +2 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +1 +0 +5 +1 +0 +0 +0 +0 +0 +0 +1 +3 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 diff --git a/.flatpak-builder/ccache/a/b/813tmbtnbhrma5bv2aj84v8huth1i3qR b/.flatpak-builder/ccache/a/b/813tmbtnbhrma5bv2aj84v8huth1i3qR new file mode 100644 index 0000000..9926434 Binary files /dev/null and b/.flatpak-builder/ccache/a/b/813tmbtnbhrma5bv2aj84v8huth1i3qR differ diff --git a/.flatpak-builder/ccache/a/b/dauddn2mh0m2ubgqd9nkhvae0anvdmaM b/.flatpak-builder/ccache/a/b/dauddn2mh0m2ubgqd9nkhvae0anvdmaM new file mode 100644 index 0000000..0799864 Binary files /dev/null and b/.flatpak-builder/ccache/a/b/dauddn2mh0m2ubgqd9nkhvae0anvdmaM differ diff --git a/.flatpak-builder/ccache/a/b/stats b/.flatpak-builder/ccache/a/b/stats index 159047e..fe5a423 100644 --- a/.flatpak-builder/ccache/a/b/stats +++ b/.flatpak-builder/ccache/a/b/stats @@ -8,6 +8,7 @@ 0 0 0 +<<<<<<< HEAD 0 0 0 @@ -17,6 +18,8 @@ 0 0 0 +======= +>>>>>>> new-pomodoro 1 0 0 @@ -26,6 +29,18 @@ 0 0 0 +<<<<<<< HEAD +======= +3 +0 +0 +0 +0 +0 +0 +0 +0 +>>>>>>> new-pomodoro 0 0 0 diff --git a/.flatpak-builder/ccache/a/c/03ddfonrmvsfumh6m8cs82g1sv71cjuR b/.flatpak-builder/ccache/a/c/03ddfonrmvsfumh6m8cs82g1sv71cjuR new file mode 100644 index 0000000..66ea32f Binary files /dev/null and b/.flatpak-builder/ccache/a/c/03ddfonrmvsfumh6m8cs82g1sv71cjuR differ diff --git a/.flatpak-builder/ccache/a/c/90cfh5eo25p31v2mocdijin6h8cgseoR b/.flatpak-builder/ccache/a/c/90cfh5eo25p31v2mocdijin6h8cgseoR new file mode 100644 index 0000000..b8ad7e0 Binary files /dev/null and b/.flatpak-builder/ccache/a/c/90cfh5eo25p31v2mocdijin6h8cgseoR differ diff --git a/.flatpak-builder/ccache/a/c/stats b/.flatpak-builder/ccache/a/c/stats index ff7d4de..1ec4716 100644 --- a/.flatpak-builder/ccache/a/c/stats +++ b/.flatpak-builder/ccache/a/c/stats @@ -2,11 +2,19 @@ 0 0 0 +<<<<<<< HEAD 2 0 0 0 0 +======= +3 +0 +0 +0 +1 +>>>>>>> new-pomodoro 0 0 0 @@ -26,6 +34,7 @@ 0 0 0 +<<<<<<< HEAD 0 0 0 @@ -37,13 +46,31 @@ 4 0 0 +======= +2 +>>>>>>> new-pomodoro 0 0 0 0 4 +<<<<<<< HEAD 0 2 +======= +3 +1 +7 +0 +0 +0 +0 +0 +0 +7 +1 +3 +>>>>>>> new-pomodoro 0 0 0 diff --git a/.flatpak-builder/ccache/a/d/08n73dpnkms35o9pgovoql3o5esr9qsM b/.flatpak-builder/ccache/a/d/08n73dpnkms35o9pgovoql3o5esr9qsM new file mode 100644 index 0000000..e97fbd9 Binary files /dev/null and b/.flatpak-builder/ccache/a/d/08n73dpnkms35o9pgovoql3o5esr9qsM differ diff --git a/.flatpak-builder/ccache/a/d/51f3nanebj2pjqjgtq91pjv914ko310R b/.flatpak-builder/ccache/a/d/51f3nanebj2pjqjgtq91pjv914ko310R new file mode 100644 index 0000000..b7d9910 Binary files /dev/null and b/.flatpak-builder/ccache/a/d/51f3nanebj2pjqjgtq91pjv914ko310R differ diff --git a/.flatpak-builder/ccache/a/d/736a4n1ho8blehsnumq9fh7ilu8jk4aR b/.flatpak-builder/ccache/a/d/736a4n1ho8blehsnumq9fh7ilu8jk4aR new file mode 100644 index 0000000..052229c Binary files /dev/null and b/.flatpak-builder/ccache/a/d/736a4n1ho8blehsnumq9fh7ilu8jk4aR differ diff --git a/.flatpak-builder/ccache/a/d/stats b/.flatpak-builder/ccache/a/d/stats index eccac08..a5da129 100644 --- a/.flatpak-builder/ccache/a/d/stats +++ b/.flatpak-builder/ccache/a/d/stats @@ -2,12 +2,17 @@ 0 0 0 +<<<<<<< HEAD 1 +======= +3 +>>>>>>> new-pomodoro 0 0 0 0 0 +<<<<<<< HEAD 0 0 0 @@ -34,6 +39,8 @@ 1 1 0 +======= +>>>>>>> new-pomodoro 2 0 0 @@ -41,11 +48,44 @@ 0 0 0 +<<<<<<< HEAD 2 +======= +0 +>>>>>>> new-pomodoro 0 1 0 0 +<<<<<<< HEAD +======= +2 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +3 +3 +4 +6 +0 +0 +0 +0 +0 +0 +6 +2 +3 +0 +0 +>>>>>>> new-pomodoro 0 0 0 diff --git a/.flatpak-builder/ccache/a/e/94efboqet544iatf7568fssvgoe4kpgM b/.flatpak-builder/ccache/a/e/94efboqet544iatf7568fssvgoe4kpgM new file mode 100644 index 0000000..c289095 Binary files /dev/null and b/.flatpak-builder/ccache/a/e/94efboqet544iatf7568fssvgoe4kpgM differ diff --git a/.flatpak-builder/ccache/a/e/f2iu14tk6es94c8kcmoantk3inrvociR b/.flatpak-builder/ccache/a/e/f2iu14tk6es94c8kcmoantk3inrvociR new file mode 100644 index 0000000..1142c6a Binary files /dev/null and b/.flatpak-builder/ccache/a/e/f2iu14tk6es94c8kcmoantk3inrvociR differ diff --git a/.flatpak-builder/ccache/a/e/stats b/.flatpak-builder/ccache/a/e/stats new file mode 100644 index 0000000..5203da7 --- /dev/null +++ b/.flatpak-builder/ccache/a/e/stats @@ -0,0 +1,82 @@ +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 diff --git a/.flatpak-builder/ccache/a/f/638obfhcegutt2j97ou9imhneufgfakR b/.flatpak-builder/ccache/a/f/638obfhcegutt2j97ou9imhneufgfakR new file mode 100644 index 0000000..877b18f Binary files /dev/null and b/.flatpak-builder/ccache/a/f/638obfhcegutt2j97ou9imhneufgfakR differ diff --git a/.flatpak-builder/ccache/a/f/stats b/.flatpak-builder/ccache/a/f/stats index 68c5368..85ee3f5 100644 --- a/.flatpak-builder/ccache/a/f/stats +++ b/.flatpak-builder/ccache/a/f/stats @@ -6,11 +6,21 @@ 0 0 0 +<<<<<<< HEAD +======= +1 +0 +1 +0 +0 +0 +>>>>>>> new-pomodoro 0 0 0 0 0 +<<<<<<< HEAD 0 0 0 @@ -34,6 +44,8 @@ 1 1 0 +======= +>>>>>>> new-pomodoro 2 0 0 @@ -41,8 +53,30 @@ 0 0 0 +<<<<<<< HEAD 2 0 +======= +0 +0 +0 +0 +0 +0 +0 +2 +1 +1 +3 +0 +0 +0 +0 +0 +0 +3 +1 +>>>>>>> new-pomodoro 1 0 0 diff --git a/.flatpak-builder/ccache/a/stats b/.flatpak-builder/ccache/a/stats index edec14b..2d05b8f 100644 --- a/.flatpak-builder/ccache/a/stats +++ b/.flatpak-builder/ccache/a/stats @@ -9,8 +9,13 @@ 0 0 0 +<<<<<<< HEAD 23 340 +======= +51 +848 +>>>>>>> new-pomodoro 0 0 0 @@ -48,6 +53,7 @@ 0 0 3 +<<<<<<< HEAD 1 0 3 @@ -79,4 +85,37 @@ 16 0 56 +======= +2 +1 +5 +2 +3 +4 +3 +6 +3 +3 +3 +4 +4 +2 +3 +32 +32 +12 +56 +16 +76 +52 +32 +160 +44 +24 +40 +120 +84 +32 +36 +>>>>>>> new-pomodoro 0 diff --git a/.flatpak-builder/ccache/b/0/20jsn8strqd82fmd9hm8v4camonm91mR b/.flatpak-builder/ccache/b/0/20jsn8strqd82fmd9hm8v4camonm91mR new file mode 100644 index 0000000..d4beb79 Binary files /dev/null and b/.flatpak-builder/ccache/b/0/20jsn8strqd82fmd9hm8v4camonm91mR differ diff --git a/.flatpak-builder/ccache/b/0/7321m7udfpl13vqqmfi60rim62p0u4sM b/.flatpak-builder/ccache/b/0/7321m7udfpl13vqqmfi60rim62p0u4sM new file mode 100644 index 0000000..a512778 Binary files /dev/null and b/.flatpak-builder/ccache/b/0/7321m7udfpl13vqqmfi60rim62p0u4sM differ diff --git a/.flatpak-builder/ccache/b/0/cad03sb5tng9kmu8l1hh2mom702d3tcM b/.flatpak-builder/ccache/b/0/cad03sb5tng9kmu8l1hh2mom702d3tcM new file mode 100644 index 0000000..fbcd3fd Binary files /dev/null and b/.flatpak-builder/ccache/b/0/cad03sb5tng9kmu8l1hh2mom702d3tcM differ diff --git a/.flatpak-builder/ccache/b/0/stats b/.flatpak-builder/ccache/b/0/stats new file mode 100644 index 0000000..20308c9 --- /dev/null +++ b/.flatpak-builder/ccache/b/0/stats @@ -0,0 +1,82 @@ +0 +0 +0 +0 +0 +0 +0 +0 +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +2 +0 +0 +0 +0 +0 +2 +0 +0 +0 +0 +1 +0 +5 +1 +0 +0 +0 +0 +0 +0 +1 +3 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 diff --git a/.flatpak-builder/ccache/b/1/b2llthvk402t44jalnvcgabhikjspa6R b/.flatpak-builder/ccache/b/1/b2llthvk402t44jalnvcgabhikjspa6R new file mode 100644 index 0000000..ae90e45 Binary files /dev/null and b/.flatpak-builder/ccache/b/1/b2llthvk402t44jalnvcgabhikjspa6R differ diff --git a/.flatpak-builder/ccache/b/1/stats b/.flatpak-builder/ccache/b/1/stats new file mode 100644 index 0000000..ab20bf4 --- /dev/null +++ b/.flatpak-builder/ccache/b/1/stats @@ -0,0 +1,82 @@ +0 +0 +0 +0 +2 +0 +0 +0 +0 +0 +2 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +2 +2 +0 +4 +0 +0 +0 +0 +0 +0 +4 +0 +2 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 diff --git a/.flatpak-builder/ccache/b/2/1de2fril0g8mk78i2t1jsgrsgcm7a3aM b/.flatpak-builder/ccache/b/2/1de2fril0g8mk78i2t1jsgrsgcm7a3aM new file mode 100644 index 0000000..a72739d Binary files /dev/null and b/.flatpak-builder/ccache/b/2/1de2fril0g8mk78i2t1jsgrsgcm7a3aM differ diff --git a/.flatpak-builder/ccache/b/2/86jfterm5d22u5uvo6su3on85niecdgR b/.flatpak-builder/ccache/b/2/86jfterm5d22u5uvo6su3on85niecdgR new file mode 100644 index 0000000..81202d3 Binary files /dev/null and b/.flatpak-builder/ccache/b/2/86jfterm5d22u5uvo6su3on85niecdgR differ diff --git a/.flatpak-builder/ccache/b/2/b3c83k0spi6ds5kb0v454idslu39pp2M b/.flatpak-builder/ccache/b/2/b3c83k0spi6ds5kb0v454idslu39pp2M new file mode 100644 index 0000000..e9ca97b Binary files /dev/null and b/.flatpak-builder/ccache/b/2/b3c83k0spi6ds5kb0v454idslu39pp2M differ diff --git a/.flatpak-builder/ccache/b/2/dcnui2tp0a2i9a5nsribr5n8osik7pqM b/.flatpak-builder/ccache/b/2/dcnui2tp0a2i9a5nsribr5n8osik7pqM new file mode 100644 index 0000000..a01b740 Binary files /dev/null and b/.flatpak-builder/ccache/b/2/dcnui2tp0a2i9a5nsribr5n8osik7pqM differ diff --git a/.flatpak-builder/ccache/b/2/e24ou03beve6liqal7kls730jvlrdviM b/.flatpak-builder/ccache/b/2/e24ou03beve6liqal7kls730jvlrdviM new file mode 100644 index 0000000..670fc75 Binary files /dev/null and b/.flatpak-builder/ccache/b/2/e24ou03beve6liqal7kls730jvlrdviM differ diff --git a/.flatpak-builder/ccache/b/2/stats b/.flatpak-builder/ccache/b/2/stats index 68c5368..a135599 100644 --- a/.flatpak-builder/ccache/b/2/stats +++ b/.flatpak-builder/ccache/b/2/stats @@ -2,6 +2,13 @@ 0 0 0 +<<<<<<< HEAD +======= +2 +0 +0 +0 +>>>>>>> new-pomodoro 1 0 0 @@ -27,6 +34,7 @@ 0 0 0 +<<<<<<< HEAD 0 0 0 @@ -34,6 +42,20 @@ 1 1 0 +======= +3 +2 +1 +5 +0 +0 +0 +0 +0 +0 +5 +1 +>>>>>>> new-pomodoro 2 0 0 @@ -41,6 +63,7 @@ 0 0 0 +<<<<<<< HEAD 2 0 1 @@ -50,6 +73,8 @@ 0 0 0 +======= +>>>>>>> new-pomodoro 0 0 0 diff --git a/.flatpak-builder/ccache/b/3/07609smjoogm4u4p3edbb71djq6kehiM b/.flatpak-builder/ccache/b/3/07609smjoogm4u4p3edbb71djq6kehiM new file mode 100644 index 0000000..d18d17c Binary files /dev/null and b/.flatpak-builder/ccache/b/3/07609smjoogm4u4p3edbb71djq6kehiM differ diff --git a/.flatpak-builder/ccache/b/3/25ie1mt23q7gc489oqog6r8b1i3e01eM b/.flatpak-builder/ccache/b/3/25ie1mt23q7gc489oqog6r8b1i3e01eM new file mode 100644 index 0000000..df30ffe Binary files /dev/null and b/.flatpak-builder/ccache/b/3/25ie1mt23q7gc489oqog6r8b1i3e01eM differ diff --git a/.flatpak-builder/ccache/b/3/4dftues71dtjcc6omth7bu74069h7buM b/.flatpak-builder/ccache/b/3/4dftues71dtjcc6omth7bu74069h7buM new file mode 100644 index 0000000..5d36858 Binary files /dev/null and b/.flatpak-builder/ccache/b/3/4dftues71dtjcc6omth7bu74069h7buM differ diff --git a/.flatpak-builder/ccache/b/3/5a4jefvi8dd0lemvcbshpuk3tb9jlfsM b/.flatpak-builder/ccache/b/3/5a4jefvi8dd0lemvcbshpuk3tb9jlfsM new file mode 100644 index 0000000..b7b5c07 Binary files /dev/null and b/.flatpak-builder/ccache/b/3/5a4jefvi8dd0lemvcbshpuk3tb9jlfsM differ diff --git a/.flatpak-builder/ccache/b/3/f56tbhd75amm8h9vv2soeoqtv4lfkd0R b/.flatpak-builder/ccache/b/3/f56tbhd75amm8h9vv2soeoqtv4lfkd0R new file mode 100644 index 0000000..deff009 Binary files /dev/null and b/.flatpak-builder/ccache/b/3/f56tbhd75amm8h9vv2soeoqtv4lfkd0R differ diff --git a/.flatpak-builder/ccache/b/3/stats b/.flatpak-builder/ccache/b/3/stats index 159047e..3939860 100644 --- a/.flatpak-builder/ccache/b/3/stats +++ b/.flatpak-builder/ccache/b/3/stats @@ -6,6 +6,21 @@ 0 0 0 +<<<<<<< HEAD +======= +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +3 +0 0 0 0 @@ -13,11 +28,30 @@ 0 0 0 +>>>>>>> new-pomodoro 0 0 0 0 +0 +<<<<<<< HEAD +======= +1 +0 +1 +1 +>>>>>>> new-pomodoro +0 +0 +0 +0 +0 +0 +1 +<<<<<<< HEAD +======= 1 +>>>>>>> new-pomodoro 0 0 0 @@ -55,6 +89,7 @@ 0 0 0 +<<<<<<< HEAD 0 0 0 @@ -80,3 +115,5 @@ 0 0 0 +======= +>>>>>>> new-pomodoro diff --git a/.flatpak-builder/ccache/b/4/94jvjdtqkccuetkgqvp4n3edlgb5s5gM b/.flatpak-builder/ccache/b/4/94jvjdtqkccuetkgqvp4n3edlgb5s5gM new file mode 100644 index 0000000..836b12f Binary files /dev/null and b/.flatpak-builder/ccache/b/4/94jvjdtqkccuetkgqvp4n3edlgb5s5gM differ diff --git a/.flatpak-builder/ccache/b/4/aacapvvi8sqe13md08tbu6oqa4a37pgM b/.flatpak-builder/ccache/b/4/aacapvvi8sqe13md08tbu6oqa4a37pgM new file mode 100644 index 0000000..81d701d Binary files /dev/null and b/.flatpak-builder/ccache/b/4/aacapvvi8sqe13md08tbu6oqa4a37pgM differ diff --git a/.flatpak-builder/ccache/b/4/stats b/.flatpak-builder/ccache/b/4/stats new file mode 100644 index 0000000..621acad --- /dev/null +++ b/.flatpak-builder/ccache/b/4/stats @@ -0,0 +1,82 @@ +0 +0 +0 +0 +1 +0 +0 +0 +0 +0 +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +1 +1 +0 +2 +0 +0 +0 +0 +0 +0 +2 +0 +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 diff --git a/.flatpak-builder/ccache/b/5/3d4guckm49bqp3t9j1egjspillovhk0R b/.flatpak-builder/ccache/b/5/3d4guckm49bqp3t9j1egjspillovhk0R new file mode 100644 index 0000000..337d003 Binary files /dev/null and b/.flatpak-builder/ccache/b/5/3d4guckm49bqp3t9j1egjspillovhk0R differ diff --git a/.flatpak-builder/ccache/b/5/stats b/.flatpak-builder/ccache/b/5/stats index 94504b0..13fe033 100644 --- a/.flatpak-builder/ccache/b/5/stats +++ b/.flatpak-builder/ccache/b/5/stats @@ -2,7 +2,11 @@ 0 0 0 +<<<<<<< HEAD 0 +======= +2 +>>>>>>> new-pomodoro 0 0 0 @@ -31,6 +35,7 @@ 0 0 0 +<<<<<<< HEAD 0 0 0 @@ -44,6 +49,21 @@ 0 0 0 +======= +2 +2 +0 +4 +0 +0 +0 +0 +0 +0 +4 +0 +2 +>>>>>>> new-pomodoro 0 0 0 diff --git a/.flatpak-builder/ccache/b/6/stats b/.flatpak-builder/ccache/b/6/stats index ff7d4de..f016268 100644 --- a/.flatpak-builder/ccache/b/6/stats +++ b/.flatpak-builder/ccache/b/6/stats @@ -2,6 +2,27 @@ 0 0 0 +<<<<<<< HEAD +======= +3 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +3 +0 +0 +>>>>>>> new-pomodoro 2 0 0 @@ -13,6 +34,7 @@ 0 0 0 +<<<<<<< HEAD 0 0 0 @@ -35,15 +57,27 @@ 2 0 4 +======= +3 +3 +4 +6 +>>>>>>> new-pomodoro 0 0 0 0 0 0 +<<<<<<< HEAD 4 0 2 +======= +6 +2 +3 +>>>>>>> new-pomodoro 0 0 0 diff --git a/.flatpak-builder/ccache/b/7/dcg5tpk228hvli6pptgn8brnqtkg8g6M b/.flatpak-builder/ccache/b/7/dcg5tpk228hvli6pptgn8brnqtkg8g6M new file mode 100644 index 0000000..e2fd401 Binary files /dev/null and b/.flatpak-builder/ccache/b/7/dcg5tpk228hvli6pptgn8brnqtkg8g6M differ diff --git a/.flatpak-builder/ccache/b/7/e1i2luiu4i1n4vko3i61velm7mska20M b/.flatpak-builder/ccache/b/7/e1i2luiu4i1n4vko3i61velm7mska20M new file mode 100644 index 0000000..cebdc1d Binary files /dev/null and b/.flatpak-builder/ccache/b/7/e1i2luiu4i1n4vko3i61velm7mska20M differ diff --git a/.flatpak-builder/ccache/b/7/stats b/.flatpak-builder/ccache/b/7/stats index fdb1454..4caedd8 100644 --- a/.flatpak-builder/ccache/b/7/stats +++ b/.flatpak-builder/ccache/b/7/stats @@ -8,6 +8,9 @@ 0 0 0 +<<<<<<< HEAD +======= +1 0 0 0 @@ -19,6 +22,25 @@ 0 0 0 +2 +0 +0 +0 +0 +0 +>>>>>>> new-pomodoro +0 +0 +0 +0 +0 +<<<<<<< HEAD +0 +0 +0 +0 +0 +0 0 0 0 @@ -34,6 +56,11 @@ 2 2 0 +======= +2 +2 +4 +>>>>>>> new-pomodoro 4 0 0 @@ -42,7 +69,11 @@ 0 0 4 +<<<<<<< HEAD 0 +======= +2 +>>>>>>> new-pomodoro 2 0 0 diff --git a/.flatpak-builder/ccache/b/8/3bbo1f7rl44f6f6i9lna9sav5lcu5omR b/.flatpak-builder/ccache/b/8/3bbo1f7rl44f6f6i9lna9sav5lcu5omR new file mode 100644 index 0000000..86c75db Binary files /dev/null and b/.flatpak-builder/ccache/b/8/3bbo1f7rl44f6f6i9lna9sav5lcu5omR differ diff --git a/.flatpak-builder/ccache/b/8/4c8prpc6jni7htjamqko8g3930a62l8M b/.flatpak-builder/ccache/b/8/4c8prpc6jni7htjamqko8g3930a62l8M new file mode 100644 index 0000000..9d8f2c3 Binary files /dev/null and b/.flatpak-builder/ccache/b/8/4c8prpc6jni7htjamqko8g3930a62l8M differ diff --git a/.flatpak-builder/ccache/b/8/stats b/.flatpak-builder/ccache/b/8/stats new file mode 100644 index 0000000..2145faa --- /dev/null +++ b/.flatpak-builder/ccache/b/8/stats @@ -0,0 +1,82 @@ +0 +0 +0 +0 +1 +0 +0 +0 +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +2 +1 +1 +3 +0 +0 +0 +0 +0 +0 +3 +1 +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 diff --git a/.flatpak-builder/ccache/b/9/bb68d0qi1n68c16qgaapdt7o2kvsvdeR b/.flatpak-builder/ccache/b/9/bb68d0qi1n68c16qgaapdt7o2kvsvdeR new file mode 100644 index 0000000..be19e98 Binary files /dev/null and b/.flatpak-builder/ccache/b/9/bb68d0qi1n68c16qgaapdt7o2kvsvdeR differ diff --git a/.flatpak-builder/ccache/b/9/bc5o19478non2r38e9nrmluldpkeuuoR b/.flatpak-builder/ccache/b/9/bc5o19478non2r38e9nrmluldpkeuuoR new file mode 100644 index 0000000..4c0fe68 Binary files /dev/null and b/.flatpak-builder/ccache/b/9/bc5o19478non2r38e9nrmluldpkeuuoR differ diff --git a/.flatpak-builder/ccache/b/9/ce9lf52n19jsulcua9rlr07r2mg04riR b/.flatpak-builder/ccache/b/9/ce9lf52n19jsulcua9rlr07r2mg04riR new file mode 100644 index 0000000..f917a81 Binary files /dev/null and b/.flatpak-builder/ccache/b/9/ce9lf52n19jsulcua9rlr07r2mg04riR differ diff --git a/.flatpak-builder/ccache/b/9/stats b/.flatpak-builder/ccache/b/9/stats index 50e268c..3bcc117 100644 --- a/.flatpak-builder/ccache/b/9/stats +++ b/.flatpak-builder/ccache/b/9/stats @@ -2,6 +2,7 @@ 0 0 0 +<<<<<<< HEAD 1 0 0 @@ -34,13 +35,18 @@ 1 1 0 +======= +>>>>>>> new-pomodoro 2 0 0 0 +<<<<<<< HEAD 0 0 0 +======= +>>>>>>> new-pomodoro 2 0 1 @@ -61,6 +67,44 @@ 0 0 0 +<<<<<<< HEAD +======= +1 +0 +0 +0 +0 +4 +2 +2 +6 +0 +0 +0 +0 +0 +0 +6 +2 +2 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +>>>>>>> new-pomodoro 0 0 0 diff --git a/.flatpak-builder/ccache/b/CACHEDIR.TAG b/.flatpak-builder/ccache/b/CACHEDIR.TAG new file mode 100644 index 0000000..874477f --- /dev/null +++ b/.flatpak-builder/ccache/b/CACHEDIR.TAG @@ -0,0 +1,4 @@ +Signature: 8a477f597d28d172789f06886806bc55 +# This file is a cache directory tag created by ccache. +# For information about cache directory tags, see: +# http://www.brynosaurus.com/cachedir/ diff --git a/.flatpak-builder/ccache/b/a/45an9fmfji7l9tdel5hdfs19nhlfahmM b/.flatpak-builder/ccache/b/a/45an9fmfji7l9tdel5hdfs19nhlfahmM new file mode 100644 index 0000000..f8284c3 Binary files /dev/null and b/.flatpak-builder/ccache/b/a/45an9fmfji7l9tdel5hdfs19nhlfahmM differ diff --git a/.flatpak-builder/ccache/b/a/stats b/.flatpak-builder/ccache/b/a/stats index 68c5368..3371c18 100644 --- a/.flatpak-builder/ccache/b/a/stats +++ b/.flatpak-builder/ccache/b/a/stats @@ -8,12 +8,22 @@ 0 0 0 +<<<<<<< HEAD +======= +1 +0 +0 +0 +0 +0 +>>>>>>> new-pomodoro 0 0 0 0 0 0 +<<<<<<< HEAD 0 0 0 @@ -34,6 +44,8 @@ 1 1 0 +======= +>>>>>>> new-pomodoro 2 0 0 @@ -41,8 +53,27 @@ 0 0 0 +<<<<<<< HEAD 2 0 +======= +0 +0 +0 +0 +1 +1 +4 +2 +0 +0 +0 +0 +0 +0 +2 +2 +>>>>>>> new-pomodoro 1 0 0 diff --git a/.flatpak-builder/ccache/b/b/39pu0kt5h1uiomionid6ap81397dm72M b/.flatpak-builder/ccache/b/b/39pu0kt5h1uiomionid6ap81397dm72M new file mode 100644 index 0000000..5fbec4d Binary files /dev/null and b/.flatpak-builder/ccache/b/b/39pu0kt5h1uiomionid6ap81397dm72M differ diff --git a/.flatpak-builder/ccache/b/b/c81bhv4d8bq4b05443qme11eo57kg4oM b/.flatpak-builder/ccache/b/b/c81bhv4d8bq4b05443qme11eo57kg4oM new file mode 100644 index 0000000..1dde13c Binary files /dev/null and b/.flatpak-builder/ccache/b/b/c81bhv4d8bq4b05443qme11eo57kg4oM differ diff --git a/.flatpak-builder/ccache/b/b/stats b/.flatpak-builder/ccache/b/b/stats index 159047e..63533cf 100644 --- a/.flatpak-builder/ccache/b/b/stats +++ b/.flatpak-builder/ccache/b/b/stats @@ -8,6 +8,7 @@ 0 0 0 +<<<<<<< HEAD 0 0 0 @@ -17,6 +18,8 @@ 0 0 0 +======= +>>>>>>> new-pomodoro 1 0 0 @@ -26,6 +29,7 @@ 0 0 0 +<<<<<<< HEAD 0 0 0 @@ -43,6 +47,34 @@ 0 0 0 +======= +1 +0 +0 +2 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +4 +0 +0 +0 +0 +0 +0 +0 +0 +2 +>>>>>>> new-pomodoro 0 0 0 diff --git a/.flatpak-builder/ccache/b/c/d6o7cs56jok341j0jhp4ret0ceqvdv8M b/.flatpak-builder/ccache/b/c/d6o7cs56jok341j0jhp4ret0ceqvdv8M new file mode 100644 index 0000000..4edf9b1 Binary files /dev/null and b/.flatpak-builder/ccache/b/c/d6o7cs56jok341j0jhp4ret0ceqvdv8M differ diff --git a/.flatpak-builder/ccache/b/c/stats b/.flatpak-builder/ccache/b/c/stats index 68c5368..0153eec 100644 --- a/.flatpak-builder/ccache/b/c/stats +++ b/.flatpak-builder/ccache/b/c/stats @@ -2,6 +2,13 @@ 0 0 0 +<<<<<<< HEAD +======= +2 +0 +0 +0 +>>>>>>> new-pomodoro 1 0 0 @@ -16,6 +23,7 @@ 0 0 0 +<<<<<<< HEAD 0 0 0 @@ -34,6 +42,8 @@ 1 1 0 +======= +>>>>>>> new-pomodoro 2 0 0 @@ -41,10 +51,31 @@ 0 0 0 +<<<<<<< HEAD 2 0 1 0 +======= +0 +0 +0 +0 +3 +2 +5 +5 +0 +0 +0 +0 +0 +0 +5 +3 +2 +0 +>>>>>>> new-pomodoro 0 0 0 diff --git a/.flatpak-builder/ccache/b/d/stats b/.flatpak-builder/ccache/b/d/stats new file mode 100644 index 0000000..958def3 --- /dev/null +++ b/.flatpak-builder/ccache/b/d/stats @@ -0,0 +1,82 @@ +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +1 +0 +0 +0 +0 +0 +0 +0 +0 +2 +0 +0 +4 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +8 +0 +0 +0 +0 +0 +0 +0 +0 +4 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 diff --git a/.flatpak-builder/ccache/b/e/fa3oetoajb3e901jblg1dpagugphkamM b/.flatpak-builder/ccache/b/e/fa3oetoajb3e901jblg1dpagugphkamM new file mode 100644 index 0000000..55e8893 Binary files /dev/null and b/.flatpak-builder/ccache/b/e/fa3oetoajb3e901jblg1dpagugphkamM differ diff --git a/.flatpak-builder/ccache/b/e/fdtfqnoe0glsebn2d95lelh5dlaffl6M b/.flatpak-builder/ccache/b/e/fdtfqnoe0glsebn2d95lelh5dlaffl6M new file mode 100644 index 0000000..88d2db0 Binary files /dev/null and b/.flatpak-builder/ccache/b/e/fdtfqnoe0glsebn2d95lelh5dlaffl6M differ diff --git a/.flatpak-builder/ccache/b/e/stats b/.flatpak-builder/ccache/b/e/stats index 68c5368..3bfbd51 100644 --- a/.flatpak-builder/ccache/b/e/stats +++ b/.flatpak-builder/ccache/b/e/stats @@ -8,6 +8,7 @@ 0 0 0 +<<<<<<< HEAD 0 0 0 @@ -34,6 +35,8 @@ 1 1 0 +======= +>>>>>>> new-pomodoro 2 0 0 @@ -41,8 +44,39 @@ 0 0 0 +<<<<<<< HEAD 2 0 +======= +0 +0 +0 +0 +0 +2 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +1 +1 +4 +2 +0 +0 +0 +0 +0 +0 +2 +2 +>>>>>>> new-pomodoro 1 0 0 diff --git a/.flatpak-builder/ccache/b/f/81k4r3meeo6rjp1kj1a2q87lbra0ebgR b/.flatpak-builder/ccache/b/f/81k4r3meeo6rjp1kj1a2q87lbra0ebgR new file mode 100644 index 0000000..b65f96d Binary files /dev/null and b/.flatpak-builder/ccache/b/f/81k4r3meeo6rjp1kj1a2q87lbra0ebgR differ diff --git a/.flatpak-builder/ccache/b/f/fev6279vve05us6vpn3gd6pktur4rl2M b/.flatpak-builder/ccache/b/f/fev6279vve05us6vpn3gd6pktur4rl2M new file mode 100644 index 0000000..3fdf55d Binary files /dev/null and b/.flatpak-builder/ccache/b/f/fev6279vve05us6vpn3gd6pktur4rl2M differ diff --git a/.flatpak-builder/ccache/b/f/stats b/.flatpak-builder/ccache/b/f/stats index 94504b0..3f9ec58 100644 --- a/.flatpak-builder/ccache/b/f/stats +++ b/.flatpak-builder/ccache/b/f/stats @@ -2,6 +2,7 @@ 0 0 0 +<<<<<<< HEAD 0 0 0 @@ -23,6 +24,9 @@ 0 0 0 +======= +2 +>>>>>>> new-pomodoro 0 0 0 @@ -40,10 +44,37 @@ 0 0 0 +<<<<<<< HEAD 0 0 0 0 +======= +2 +0 +0 +0 +0 +0 +1 +0 +0 +0 +0 +3 +2 +5 +5 +0 +0 +0 +0 +0 +0 +5 +3 +2 +>>>>>>> new-pomodoro 0 0 0 diff --git a/.flatpak-builder/ccache/b/stats b/.flatpak-builder/ccache/b/stats index d511c18..caedcc5 100644 --- a/.flatpak-builder/ccache/b/stats +++ b/.flatpak-builder/ccache/b/stats @@ -9,8 +9,13 @@ 0 0 0 +<<<<<<< HEAD 19 128 +======= +49 +640 +>>>>>>> new-pomodoro 0 0 0 @@ -47,6 +52,7 @@ 0 0 0 +<<<<<<< HEAD 0 1 2 @@ -79,4 +85,38 @@ 20 0 8 +======= +3 +2 +6 +6 +2 +2 +1 +2 +4 +4 +2 +3 +2 +4 +2 +4 +40 +24 +116 +104 +40 +16 +4 +32 +56 +32 +24 +44 +24 +20 +20 +44 +>>>>>>> new-pomodoro 0 diff --git a/.flatpak-builder/ccache/bin/c++ b/.flatpak-builder/ccache/bin/c++ new file mode 120000 index 0000000..2329eb0 --- /dev/null +++ b/.flatpak-builder/ccache/bin/c++ @@ -0,0 +1 @@ +/usr/bin/ccache \ No newline at end of file diff --git a/.flatpak-builder/ccache/bin/cc b/.flatpak-builder/ccache/bin/cc new file mode 120000 index 0000000..2329eb0 --- /dev/null +++ b/.flatpak-builder/ccache/bin/cc @@ -0,0 +1 @@ +/usr/bin/ccache \ No newline at end of file diff --git a/.flatpak-builder/ccache/bin/g++ b/.flatpak-builder/ccache/bin/g++ new file mode 120000 index 0000000..2329eb0 --- /dev/null +++ b/.flatpak-builder/ccache/bin/g++ @@ -0,0 +1 @@ +/usr/bin/ccache \ No newline at end of file diff --git a/.flatpak-builder/ccache/bin/gcc b/.flatpak-builder/ccache/bin/gcc new file mode 120000 index 0000000..2329eb0 --- /dev/null +++ b/.flatpak-builder/ccache/bin/gcc @@ -0,0 +1 @@ +/usr/bin/ccache \ No newline at end of file diff --git a/.flatpak-builder/ccache/c/0/d91iccvmmrtv9h6ov28eh825e6fqkdcM b/.flatpak-builder/ccache/c/0/d91iccvmmrtv9h6ov28eh825e6fqkdcM new file mode 100644 index 0000000..fd35ce0 Binary files /dev/null and b/.flatpak-builder/ccache/c/0/d91iccvmmrtv9h6ov28eh825e6fqkdcM differ diff --git a/.flatpak-builder/ccache/c/0/ecvi3dkmhb570014pk3h3oon7rgfqaiM b/.flatpak-builder/ccache/c/0/ecvi3dkmhb570014pk3h3oon7rgfqaiM new file mode 100644 index 0000000..3100982 Binary files /dev/null and b/.flatpak-builder/ccache/c/0/ecvi3dkmhb570014pk3h3oon7rgfqaiM differ diff --git a/.flatpak-builder/ccache/c/1/17d8vpjm9sq3jbq1efi5stn44g84oruM b/.flatpak-builder/ccache/c/1/17d8vpjm9sq3jbq1efi5stn44g84oruM new file mode 100644 index 0000000..e01b847 Binary files /dev/null and b/.flatpak-builder/ccache/c/1/17d8vpjm9sq3jbq1efi5stn44g84oruM differ diff --git a/.flatpak-builder/ccache/c/1/34bkegujejdmg70dd3hg7jfahkhvntkM b/.flatpak-builder/ccache/c/1/34bkegujejdmg70dd3hg7jfahkhvntkM new file mode 100644 index 0000000..9a3b358 Binary files /dev/null and b/.flatpak-builder/ccache/c/1/34bkegujejdmg70dd3hg7jfahkhvntkM differ diff --git a/.flatpak-builder/ccache/c/1/7583k6tt3uj0icjldus5on0vp2lrk28R b/.flatpak-builder/ccache/c/1/7583k6tt3uj0icjldus5on0vp2lrk28R new file mode 100644 index 0000000..92b795d Binary files /dev/null and b/.flatpak-builder/ccache/c/1/7583k6tt3uj0icjldus5on0vp2lrk28R differ diff --git a/.flatpak-builder/ccache/c/1/stats b/.flatpak-builder/ccache/c/1/stats index 68c5368..d83df89 100644 --- a/.flatpak-builder/ccache/c/1/stats +++ b/.flatpak-builder/ccache/c/1/stats @@ -2,6 +2,7 @@ 0 0 0 +<<<<<<< HEAD 1 0 0 @@ -34,6 +35,8 @@ 1 1 0 +======= +>>>>>>> new-pomodoro 2 0 0 @@ -41,9 +44,47 @@ 0 0 0 +<<<<<<< HEAD 2 0 1 +======= +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +2 +0 +0 +0 +0 +0 +2 +0 +0 +0 +0 +2 +2 +4 +4 +0 +0 +0 +0 +0 +0 +4 +2 +2 +>>>>>>> new-pomodoro 0 0 0 diff --git a/.flatpak-builder/ccache/c/2/10tji5ck7lfsmg0be7p0nt17vcso6k4M b/.flatpak-builder/ccache/c/2/10tji5ck7lfsmg0be7p0nt17vcso6k4M new file mode 100644 index 0000000..afe3f86 Binary files /dev/null and b/.flatpak-builder/ccache/c/2/10tji5ck7lfsmg0be7p0nt17vcso6k4M differ diff --git a/.flatpak-builder/ccache/c/2/284h3hbs648e12n19to8enrrerakbpuR b/.flatpak-builder/ccache/c/2/284h3hbs648e12n19to8enrrerakbpuR new file mode 100644 index 0000000..eb832d6 Binary files /dev/null and b/.flatpak-builder/ccache/c/2/284h3hbs648e12n19to8enrrerakbpuR differ diff --git a/.flatpak-builder/ccache/c/2/4b23pj0jppk4nv8911ufm2b3na6a8deR b/.flatpak-builder/ccache/c/2/4b23pj0jppk4nv8911ufm2b3na6a8deR new file mode 100644 index 0000000..5f197a2 Binary files /dev/null and b/.flatpak-builder/ccache/c/2/4b23pj0jppk4nv8911ufm2b3na6a8deR differ diff --git a/.flatpak-builder/ccache/c/2/6b9ap4g3u0v8le9dgg0hcpqr1m66rdaR b/.flatpak-builder/ccache/c/2/6b9ap4g3u0v8le9dgg0hcpqr1m66rdaR new file mode 100644 index 0000000..48b11fe Binary files /dev/null and b/.flatpak-builder/ccache/c/2/6b9ap4g3u0v8le9dgg0hcpqr1m66rdaR differ diff --git a/.flatpak-builder/ccache/c/2/stats b/.flatpak-builder/ccache/c/2/stats new file mode 100644 index 0000000..ed6b583 --- /dev/null +++ b/.flatpak-builder/ccache/c/2/stats @@ -0,0 +1,82 @@ +0 +0 +0 +0 +2 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +2 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +2 +2 +0 +4 +0 +0 +0 +0 +0 +0 +4 +0 +2 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 diff --git a/.flatpak-builder/ccache/c/3/stats b/.flatpak-builder/ccache/c/3/stats new file mode 100644 index 0000000..7bc5178 --- /dev/null +++ b/.flatpak-builder/ccache/c/3/stats @@ -0,0 +1,82 @@ +0 +0 +0 +0 +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +2 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +1 +1 +0 +2 +0 +0 +0 +0 +0 +0 +2 +0 +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 diff --git a/.flatpak-builder/ccache/c/4/45mb1v8lossiblld5q6brqsb3a2a5n2M b/.flatpak-builder/ccache/c/4/45mb1v8lossiblld5q6brqsb3a2a5n2M new file mode 100644 index 0000000..12eda7a Binary files /dev/null and b/.flatpak-builder/ccache/c/4/45mb1v8lossiblld5q6brqsb3a2a5n2M differ diff --git a/.flatpak-builder/ccache/c/4/stats b/.flatpak-builder/ccache/c/4/stats index d7cfc2e..7e1e3cc 100644 --- a/.flatpak-builder/ccache/c/4/stats +++ b/.flatpak-builder/ccache/c/4/stats @@ -6,7 +6,11 @@ 0 0 0 +<<<<<<< HEAD 0 +======= +1 +>>>>>>> new-pomodoro 0 0 0 @@ -31,6 +35,7 @@ 0 0 0 +<<<<<<< HEAD 1 1 0 @@ -43,6 +48,20 @@ 0 2 0 +======= +2 +1 +1 +3 +0 +0 +0 +0 +0 +0 +3 +1 +>>>>>>> new-pomodoro 1 0 0 diff --git a/.flatpak-builder/ccache/c/5/024kp0r05b15m4pks9itn95hei37fmuM b/.flatpak-builder/ccache/c/5/024kp0r05b15m4pks9itn95hei37fmuM new file mode 100644 index 0000000..5ecbbcb Binary files /dev/null and b/.flatpak-builder/ccache/c/5/024kp0r05b15m4pks9itn95hei37fmuM differ diff --git a/.flatpak-builder/ccache/c/5/16lep0i2f1b97i2jjbq31ajl0k224kcM b/.flatpak-builder/ccache/c/5/16lep0i2f1b97i2jjbq31ajl0k224kcM new file mode 100644 index 0000000..f21180e Binary files /dev/null and b/.flatpak-builder/ccache/c/5/16lep0i2f1b97i2jjbq31ajl0k224kcM differ diff --git a/.flatpak-builder/ccache/c/5/3531a7724d19l910j7du5nj82uleqtkR b/.flatpak-builder/ccache/c/5/3531a7724d19l910j7du5nj82uleqtkR new file mode 100644 index 0000000..52424a5 Binary files /dev/null and b/.flatpak-builder/ccache/c/5/3531a7724d19l910j7du5nj82uleqtkR differ diff --git a/.flatpak-builder/ccache/c/5/stats b/.flatpak-builder/ccache/c/5/stats index f7fab00..755aef1 100644 --- a/.flatpak-builder/ccache/c/5/stats +++ b/.flatpak-builder/ccache/c/5/stats @@ -2,11 +2,19 @@ 0 0 0 +<<<<<<< HEAD 0 0 0 0 0 +======= +1 +0 +0 +0 +1 +>>>>>>> new-pomodoro 0 0 0 @@ -20,12 +28,35 @@ 1 0 0 +<<<<<<< HEAD +======= +1 +0 +0 +0 +0 +0 +1 +0 +0 +0 +0 +2 +1 +3 +3 +>>>>>>> new-pomodoro 0 0 0 0 0 0 +<<<<<<< HEAD +======= +3 +2 +>>>>>>> new-pomodoro 1 0 0 @@ -63,6 +94,7 @@ 0 0 0 +<<<<<<< HEAD 0 0 0 @@ -80,3 +112,5 @@ 0 0 0 +======= +>>>>>>> new-pomodoro diff --git a/.flatpak-builder/ccache/c/6/f3fsd89vdc3ik1b0cdn9lm83du4t632M b/.flatpak-builder/ccache/c/6/f3fsd89vdc3ik1b0cdn9lm83du4t632M new file mode 100644 index 0000000..abcbe8a Binary files /dev/null and b/.flatpak-builder/ccache/c/6/f3fsd89vdc3ik1b0cdn9lm83du4t632M differ diff --git a/.flatpak-builder/ccache/c/6/stats b/.flatpak-builder/ccache/c/6/stats index fbe4d7f..64a73d0 100644 --- a/.flatpak-builder/ccache/c/6/stats +++ b/.flatpak-builder/ccache/c/6/stats @@ -6,7 +6,12 @@ 0 0 0 +<<<<<<< HEAD +======= +1 0 +1 +>>>>>>> new-pomodoro 0 0 0 @@ -18,6 +23,10 @@ 0 0 0 +<<<<<<< HEAD +======= +2 +>>>>>>> new-pomodoro 0 0 0 @@ -28,9 +37,18 @@ 0 0 0 +<<<<<<< HEAD +======= +4 +3 +5 +7 +>>>>>>> new-pomodoro +0 0 0 0 +<<<<<<< HEAD 3 3 0 @@ -45,6 +63,14 @@ 0 3 0 +======= +0 +0 +7 +3 +3 +0 +>>>>>>> new-pomodoro 0 0 0 diff --git a/.flatpak-builder/ccache/c/7/28e23mnjup4ap76011rmkd8iuba4c8gR b/.flatpak-builder/ccache/c/7/28e23mnjup4ap76011rmkd8iuba4c8gR new file mode 100644 index 0000000..75200a4 Binary files /dev/null and b/.flatpak-builder/ccache/c/7/28e23mnjup4ap76011rmkd8iuba4c8gR differ diff --git a/.flatpak-builder/ccache/c/7/60r7vna0e73a9n5ttncetqs633c1s68M b/.flatpak-builder/ccache/c/7/60r7vna0e73a9n5ttncetqs633c1s68M new file mode 100644 index 0000000..a258d35 Binary files /dev/null and b/.flatpak-builder/ccache/c/7/60r7vna0e73a9n5ttncetqs633c1s68M differ diff --git a/.flatpak-builder/ccache/c/7/d0dd679v6d4diqe0bcbt2hbgop8iavmR b/.flatpak-builder/ccache/c/7/d0dd679v6d4diqe0bcbt2hbgop8iavmR new file mode 100644 index 0000000..305e47b Binary files /dev/null and b/.flatpak-builder/ccache/c/7/d0dd679v6d4diqe0bcbt2hbgop8iavmR differ diff --git a/.flatpak-builder/ccache/c/7/f01ce4ik43k3s9too06abchi700ohhcM b/.flatpak-builder/ccache/c/7/f01ce4ik43k3s9too06abchi700ohhcM new file mode 100644 index 0000000..e4b7a6a Binary files /dev/null and b/.flatpak-builder/ccache/c/7/f01ce4ik43k3s9too06abchi700ohhcM differ diff --git a/.flatpak-builder/ccache/c/7/stats b/.flatpak-builder/ccache/c/7/stats index 94504b0..df9e245 100644 --- a/.flatpak-builder/ccache/c/7/stats +++ b/.flatpak-builder/ccache/c/7/stats @@ -2,18 +2,52 @@ 0 0 0 +<<<<<<< HEAD +======= +1 +0 +0 +0 +1 +0 0 0 0 +>>>>>>> new-pomodoro 0 0 0 0 0 0 +<<<<<<< HEAD +======= +2 +0 +0 +1 +0 +0 +0 +0 +0 +1 +0 +0 +0 +0 +2 +1 +3 +3 +>>>>>>> new-pomodoro +0 +0 +0 0 0 0 +<<<<<<< HEAD 0 0 0 @@ -26,6 +60,10 @@ 0 0 0 +======= +3 +2 +>>>>>>> new-pomodoro 1 0 0 @@ -63,6 +101,7 @@ 0 0 0 +<<<<<<< HEAD 0 0 0 @@ -80,3 +119,5 @@ 0 0 0 +======= +>>>>>>> new-pomodoro diff --git a/.flatpak-builder/ccache/c/8/816pf7ailji3higeplnshbt6k0q4r6cM b/.flatpak-builder/ccache/c/8/816pf7ailji3higeplnshbt6k0q4r6cM new file mode 100644 index 0000000..2a25da7 Binary files /dev/null and b/.flatpak-builder/ccache/c/8/816pf7ailji3higeplnshbt6k0q4r6cM differ diff --git a/.flatpak-builder/ccache/c/8/8eebbqcjlljv18lcbf7iliip477c3d0M b/.flatpak-builder/ccache/c/8/8eebbqcjlljv18lcbf7iliip477c3d0M new file mode 100644 index 0000000..7f3b54f Binary files /dev/null and b/.flatpak-builder/ccache/c/8/8eebbqcjlljv18lcbf7iliip477c3d0M differ diff --git a/.flatpak-builder/ccache/c/8/stats b/.flatpak-builder/ccache/c/8/stats index 7be146c..e1d8571 100644 --- a/.flatpak-builder/ccache/c/8/stats +++ b/.flatpak-builder/ccache/c/8/stats @@ -8,6 +8,7 @@ 0 0 0 +<<<<<<< HEAD 0 0 0 @@ -15,6 +16,8 @@ 0 0 0 +======= +>>>>>>> new-pomodoro 1 0 0 @@ -22,6 +25,16 @@ 0 0 0 +<<<<<<< HEAD +======= +3 +0 +2 +0 +0 +0 +0 +>>>>>>> new-pomodoro 0 0 0 diff --git a/.flatpak-builder/ccache/c/9/04lhsk8lsqrjk8buh764p4rpllktg6sM b/.flatpak-builder/ccache/c/9/04lhsk8lsqrjk8buh764p4rpllktg6sM new file mode 100644 index 0000000..8e6f02e Binary files /dev/null and b/.flatpak-builder/ccache/c/9/04lhsk8lsqrjk8buh764p4rpllktg6sM differ diff --git a/.flatpak-builder/ccache/c/9/0a233tmd6l9215c3gurnv3i868ogtg0R b/.flatpak-builder/ccache/c/9/0a233tmd6l9215c3gurnv3i868ogtg0R new file mode 100644 index 0000000..62f5d97 Binary files /dev/null and b/.flatpak-builder/ccache/c/9/0a233tmd6l9215c3gurnv3i868ogtg0R differ diff --git a/.flatpak-builder/ccache/c/9/4c4babkrsrh3kr57vvlcdmjvr6bg8riR b/.flatpak-builder/ccache/c/9/4c4babkrsrh3kr57vvlcdmjvr6bg8riR new file mode 100644 index 0000000..1901e8f Binary files /dev/null and b/.flatpak-builder/ccache/c/9/4c4babkrsrh3kr57vvlcdmjvr6bg8riR differ diff --git a/.flatpak-builder/ccache/c/9/87t20f4tk94rarmcqefn7d20gpv5uruR b/.flatpak-builder/ccache/c/9/87t20f4tk94rarmcqefn7d20gpv5uruR new file mode 100644 index 0000000..d32d92f Binary files /dev/null and b/.flatpak-builder/ccache/c/9/87t20f4tk94rarmcqefn7d20gpv5uruR differ diff --git a/.flatpak-builder/ccache/c/9/89080aacvcv7f9h1jbo83pamukag70kR b/.flatpak-builder/ccache/c/9/89080aacvcv7f9h1jbo83pamukag70kR new file mode 100644 index 0000000..80bc918 Binary files /dev/null and b/.flatpak-builder/ccache/c/9/89080aacvcv7f9h1jbo83pamukag70kR differ diff --git a/.flatpak-builder/ccache/c/9/d1tr7guid57sd8aahlhgtsf3cgubvu8R b/.flatpak-builder/ccache/c/9/d1tr7guid57sd8aahlhgtsf3cgubvu8R new file mode 100644 index 0000000..af3daf1 Binary files /dev/null and b/.flatpak-builder/ccache/c/9/d1tr7guid57sd8aahlhgtsf3cgubvu8R differ diff --git a/.flatpak-builder/ccache/c/9/stats b/.flatpak-builder/ccache/c/9/stats new file mode 100644 index 0000000..5203da7 --- /dev/null +++ b/.flatpak-builder/ccache/c/9/stats @@ -0,0 +1,82 @@ +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 diff --git a/.flatpak-builder/ccache/c/CACHEDIR.TAG b/.flatpak-builder/ccache/c/CACHEDIR.TAG new file mode 100644 index 0000000..874477f --- /dev/null +++ b/.flatpak-builder/ccache/c/CACHEDIR.TAG @@ -0,0 +1,4 @@ +Signature: 8a477f597d28d172789f06886806bc55 +# This file is a cache directory tag created by ccache. +# For information about cache directory tags, see: +# http://www.brynosaurus.com/cachedir/ diff --git a/.flatpak-builder/ccache/c/a/0embu3vr9norbf2krmldk15md1n700iM b/.flatpak-builder/ccache/c/a/0embu3vr9norbf2krmldk15md1n700iM new file mode 100644 index 0000000..ff59ab9 Binary files /dev/null and b/.flatpak-builder/ccache/c/a/0embu3vr9norbf2krmldk15md1n700iM differ diff --git a/.flatpak-builder/ccache/c/a/stats b/.flatpak-builder/ccache/c/a/stats new file mode 100644 index 0000000..70e6c98 --- /dev/null +++ b/.flatpak-builder/ccache/c/a/stats @@ -0,0 +1,82 @@ +0 +0 +0 +0 +0 +0 +0 +0 +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +1 +0 +1 +1 +0 +0 +0 +0 +0 +0 +1 +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 diff --git a/.flatpak-builder/ccache/c/b/10hel8v2rllu51f6if9naakgsog1nnkR b/.flatpak-builder/ccache/c/b/10hel8v2rllu51f6if9naakgsog1nnkR new file mode 100644 index 0000000..8e61e0f Binary files /dev/null and b/.flatpak-builder/ccache/c/b/10hel8v2rllu51f6if9naakgsog1nnkR differ diff --git a/.flatpak-builder/ccache/c/b/stats b/.flatpak-builder/ccache/c/b/stats index a2f99a7..ef211fb 100644 --- a/.flatpak-builder/ccache/c/b/stats +++ b/.flatpak-builder/ccache/c/b/stats @@ -8,6 +8,7 @@ 0 0 0 +<<<<<<< HEAD 0 0 0 @@ -16,6 +17,16 @@ 0 0 1 +======= +1 +0 +0 +0 +0 +0 +0 +3 +>>>>>>> new-pomodoro 0 0 0 diff --git a/.flatpak-builder/ccache/c/c/408mjvss66u0hq7gr02s2errmkqj328M b/.flatpak-builder/ccache/c/c/408mjvss66u0hq7gr02s2errmkqj328M new file mode 100644 index 0000000..d58c13a Binary files /dev/null and b/.flatpak-builder/ccache/c/c/408mjvss66u0hq7gr02s2errmkqj328M differ diff --git a/.flatpak-builder/ccache/c/c/a08gc6k8jhp4mrm28mr2arras92c4b2M b/.flatpak-builder/ccache/c/c/a08gc6k8jhp4mrm28mr2arras92c4b2M new file mode 100644 index 0000000..a3dbe54 Binary files /dev/null and b/.flatpak-builder/ccache/c/c/a08gc6k8jhp4mrm28mr2arras92c4b2M differ diff --git a/.flatpak-builder/ccache/c/c/baogahi5ge8ajmbtb0uf39g6tr7sp2qR b/.flatpak-builder/ccache/c/c/baogahi5ge8ajmbtb0uf39g6tr7sp2qR new file mode 100644 index 0000000..80048b4 Binary files /dev/null and b/.flatpak-builder/ccache/c/c/baogahi5ge8ajmbtb0uf39g6tr7sp2qR differ diff --git a/.flatpak-builder/ccache/c/c/cdfo72kg9o2amdtt2l26qkrdd2k1jjaM b/.flatpak-builder/ccache/c/c/cdfo72kg9o2amdtt2l26qkrdd2k1jjaM new file mode 100644 index 0000000..229845e Binary files /dev/null and b/.flatpak-builder/ccache/c/c/cdfo72kg9o2amdtt2l26qkrdd2k1jjaM differ diff --git a/.flatpak-builder/ccache/c/c/stats b/.flatpak-builder/ccache/c/c/stats index 4356b40..9c062f8 100644 --- a/.flatpak-builder/ccache/c/c/stats +++ b/.flatpak-builder/ccache/c/c/stats @@ -2,6 +2,7 @@ 0 0 0 +<<<<<<< HEAD 3 0 0 @@ -10,6 +11,15 @@ 0 0 0 +======= +2 +0 +0 +0 +1 +0 +2 +>>>>>>> new-pomodoro 0 0 0 @@ -21,6 +31,10 @@ 0 0 0 +<<<<<<< HEAD +======= +4 +>>>>>>> new-pomodoro 0 0 0 @@ -32,18 +46,30 @@ 0 0 3 +<<<<<<< HEAD 3 0 6 +======= +2 +9 +5 +>>>>>>> new-pomodoro 0 0 0 0 0 0 +<<<<<<< HEAD 6 0 3 +======= +5 +5 +2 +>>>>>>> new-pomodoro 0 0 0 diff --git a/.flatpak-builder/ccache/c/d/0eduaf8qcsbgqbhjo4ocuku9tci753kM b/.flatpak-builder/ccache/c/d/0eduaf8qcsbgqbhjo4ocuku9tci753kM new file mode 100644 index 0000000..ca08fab Binary files /dev/null and b/.flatpak-builder/ccache/c/d/0eduaf8qcsbgqbhjo4ocuku9tci753kM differ diff --git a/.flatpak-builder/ccache/c/d/1en8j93ihajgi3l2lhe86n5avsiqckkR b/.flatpak-builder/ccache/c/d/1en8j93ihajgi3l2lhe86n5avsiqckkR new file mode 100644 index 0000000..2071a8f Binary files /dev/null and b/.flatpak-builder/ccache/c/d/1en8j93ihajgi3l2lhe86n5avsiqckkR differ diff --git a/.flatpak-builder/ccache/c/d/861ost6f8qitql40pmju3g9jkgenu7qR b/.flatpak-builder/ccache/c/d/861ost6f8qitql40pmju3g9jkgenu7qR new file mode 100644 index 0000000..c3af799 Binary files /dev/null and b/.flatpak-builder/ccache/c/d/861ost6f8qitql40pmju3g9jkgenu7qR differ diff --git a/.flatpak-builder/ccache/c/d/stats b/.flatpak-builder/ccache/c/d/stats new file mode 100644 index 0000000..621acad --- /dev/null +++ b/.flatpak-builder/ccache/c/d/stats @@ -0,0 +1,82 @@ +0 +0 +0 +0 +1 +0 +0 +0 +0 +0 +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +1 +1 +0 +2 +0 +0 +0 +0 +0 +0 +2 +0 +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 diff --git a/.flatpak-builder/ccache/c/e/f4tpcjak6k6747mv8dlgqubjhantpq6M b/.flatpak-builder/ccache/c/e/f4tpcjak6k6747mv8dlgqubjhantpq6M new file mode 100644 index 0000000..37cd137 Binary files /dev/null and b/.flatpak-builder/ccache/c/e/f4tpcjak6k6747mv8dlgqubjhantpq6M differ diff --git a/.flatpak-builder/ccache/c/e/stats b/.flatpak-builder/ccache/c/e/stats index 159047e..e4c79b5 100644 --- a/.flatpak-builder/ccache/c/e/stats +++ b/.flatpak-builder/ccache/c/e/stats @@ -2,14 +2,29 @@ 0 0 0 +<<<<<<< HEAD +======= +1 +0 +0 +0 +1 +0 +1 +0 +0 0 0 0 0 0 0 +1 +0 +0 0 0 +>>>>>>> new-pomodoro 0 0 0 @@ -17,6 +32,26 @@ 0 0 0 +0 +0 +<<<<<<< HEAD +======= +2 +1 +1 +3 +>>>>>>> new-pomodoro +0 +0 +0 +0 +0 +0 +<<<<<<< HEAD +======= +3 +1 +>>>>>>> new-pomodoro 1 0 0 @@ -54,6 +89,7 @@ 0 0 0 +<<<<<<< HEAD 0 0 0 @@ -80,3 +116,5 @@ 0 0 0 +======= +>>>>>>> new-pomodoro diff --git a/.flatpak-builder/ccache/c/f/65aqlur714kir99krr0egt9cqaknm1aR b/.flatpak-builder/ccache/c/f/65aqlur714kir99krr0egt9cqaknm1aR new file mode 100644 index 0000000..3bb3845 Binary files /dev/null and b/.flatpak-builder/ccache/c/f/65aqlur714kir99krr0egt9cqaknm1aR differ diff --git a/.flatpak-builder/ccache/c/f/68guikgmq4hqu67uvganr99jm85j50iM b/.flatpak-builder/ccache/c/f/68guikgmq4hqu67uvganr99jm85j50iM new file mode 100644 index 0000000..2cd290e Binary files /dev/null and b/.flatpak-builder/ccache/c/f/68guikgmq4hqu67uvganr99jm85j50iM differ diff --git a/.flatpak-builder/ccache/c/f/a6qtgvd6av2f0jsib90q9a1ktp6spgaR b/.flatpak-builder/ccache/c/f/a6qtgvd6av2f0jsib90q9a1ktp6spgaR new file mode 100644 index 0000000..0d5bbc0 Binary files /dev/null and b/.flatpak-builder/ccache/c/f/a6qtgvd6av2f0jsib90q9a1ktp6spgaR differ diff --git a/.flatpak-builder/ccache/c/f/d60qqusc2mbfqo7mfk9bf195crr5d4gM b/.flatpak-builder/ccache/c/f/d60qqusc2mbfqo7mfk9bf195crr5d4gM new file mode 100644 index 0000000..af022a0 Binary files /dev/null and b/.flatpak-builder/ccache/c/f/d60qqusc2mbfqo7mfk9bf195crr5d4gM differ diff --git a/.flatpak-builder/ccache/c/f/stats b/.flatpak-builder/ccache/c/f/stats index 94504b0..1861d9c 100644 --- a/.flatpak-builder/ccache/c/f/stats +++ b/.flatpak-builder/ccache/c/f/stats @@ -8,7 +8,11 @@ 0 0 0 +<<<<<<< HEAD 0 +======= +3 +>>>>>>> new-pomodoro 0 0 0 diff --git a/.flatpak-builder/ccache/c/stats b/.flatpak-builder/ccache/c/stats index 5061c45..c249556 100644 --- a/.flatpak-builder/ccache/c/stats +++ b/.flatpak-builder/ccache/c/stats @@ -9,8 +9,13 @@ 0 0 0 +<<<<<<< HEAD 14 116 +======= +51 +848 +>>>>>>> new-pomodoro 0 0 0 @@ -47,6 +52,7 @@ 0 0 0 +<<<<<<< HEAD 2 0 1 @@ -79,4 +85,38 @@ 0 20 0 +======= +3 +3 +5 +2 +1 +3 +2 +6 +2 +7 +1 +2 +5 +3 +2 +4 +36 +56 +80 +8 +20 +48 +24 +80 +20 +112 +12 +28 +60 +40 +32 +192 +>>>>>>> new-pomodoro 0 diff --git a/.flatpak-builder/ccache/d/0/353fse7s5cupu3t66qikkl52pi28ohuR b/.flatpak-builder/ccache/d/0/353fse7s5cupu3t66qikkl52pi28ohuR new file mode 100644 index 0000000..a375a03 Binary files /dev/null and b/.flatpak-builder/ccache/d/0/353fse7s5cupu3t66qikkl52pi28ohuR differ diff --git a/.flatpak-builder/ccache/d/0/4bsjv0jkkltvdtu9mk2532jhdgtq3tcR b/.flatpak-builder/ccache/d/0/4bsjv0jkkltvdtu9mk2532jhdgtq3tcR new file mode 100644 index 0000000..02503a2 Binary files /dev/null and b/.flatpak-builder/ccache/d/0/4bsjv0jkkltvdtu9mk2532jhdgtq3tcR differ diff --git a/.flatpak-builder/ccache/d/0/74jq2p54phcf588v3no5ra0r19cfbv0M b/.flatpak-builder/ccache/d/0/74jq2p54phcf588v3no5ra0r19cfbv0M new file mode 100644 index 0000000..9661481 Binary files /dev/null and b/.flatpak-builder/ccache/d/0/74jq2p54phcf588v3no5ra0r19cfbv0M differ diff --git a/.flatpak-builder/ccache/d/0/c47kjvp4ba6fris6lae7niueo1p61pgR b/.flatpak-builder/ccache/d/0/c47kjvp4ba6fris6lae7niueo1p61pgR new file mode 100644 index 0000000..430b2cc Binary files /dev/null and b/.flatpak-builder/ccache/d/0/c47kjvp4ba6fris6lae7niueo1p61pgR differ diff --git a/.flatpak-builder/ccache/d/0/stats b/.flatpak-builder/ccache/d/0/stats index 7367a33..78f2927 100644 --- a/.flatpak-builder/ccache/d/0/stats +++ b/.flatpak-builder/ccache/d/0/stats @@ -2,12 +2,21 @@ 0 0 0 +<<<<<<< HEAD 1 0 0 0 0 1 +======= +2 +0 +0 +0 +1 +3 +>>>>>>> new-pomodoro 0 0 0 @@ -20,6 +29,10 @@ 0 0 0 +<<<<<<< HEAD +======= +5 +>>>>>>> new-pomodoro 0 0 0 @@ -30,10 +43,25 @@ 0 0 0 +<<<<<<< HEAD 0 1 1 0 +======= +3 +2 +11 +5 +0 +0 +0 +0 +0 +0 +5 +6 +>>>>>>> new-pomodoro 2 0 0 @@ -41,6 +69,7 @@ 0 0 0 +<<<<<<< HEAD 2 0 1 @@ -50,6 +79,8 @@ 0 0 0 +======= +>>>>>>> new-pomodoro 0 0 0 diff --git a/.flatpak-builder/ccache/d/1/02ng5pt95j688rqn7aupc28nm23bh7sM b/.flatpak-builder/ccache/d/1/02ng5pt95j688rqn7aupc28nm23bh7sM new file mode 100644 index 0000000..d09cfb3 Binary files /dev/null and b/.flatpak-builder/ccache/d/1/02ng5pt95j688rqn7aupc28nm23bh7sM differ diff --git a/.flatpak-builder/ccache/d/1/11pdbuudpijbflcs8v2g7cop7t9dtmqR b/.flatpak-builder/ccache/d/1/11pdbuudpijbflcs8v2g7cop7t9dtmqR new file mode 100644 index 0000000..ee07c95 Binary files /dev/null and b/.flatpak-builder/ccache/d/1/11pdbuudpijbflcs8v2g7cop7t9dtmqR differ diff --git a/.flatpak-builder/ccache/d/1/24thkvh0pcjjkn4fnhs8b4hisuo1j7aM b/.flatpak-builder/ccache/d/1/24thkvh0pcjjkn4fnhs8b4hisuo1j7aM new file mode 100644 index 0000000..f874c19 Binary files /dev/null and b/.flatpak-builder/ccache/d/1/24thkvh0pcjjkn4fnhs8b4hisuo1j7aM differ diff --git a/.flatpak-builder/ccache/d/1/4eei6pbk7f6k2j1v13ro3vgh8nanbmcM b/.flatpak-builder/ccache/d/1/4eei6pbk7f6k2j1v13ro3vgh8nanbmcM new file mode 100644 index 0000000..136aa39 Binary files /dev/null and b/.flatpak-builder/ccache/d/1/4eei6pbk7f6k2j1v13ro3vgh8nanbmcM differ diff --git a/.flatpak-builder/ccache/d/1/7anpk2ici504pln2e5n6pi8hilreplcM b/.flatpak-builder/ccache/d/1/7anpk2ici504pln2e5n6pi8hilreplcM new file mode 100644 index 0000000..0bca107 Binary files /dev/null and b/.flatpak-builder/ccache/d/1/7anpk2ici504pln2e5n6pi8hilreplcM differ diff --git a/.flatpak-builder/ccache/d/1/ad8ep0u551ttgjf2d62dpqiibcp9lp0R b/.flatpak-builder/ccache/d/1/ad8ep0u551ttgjf2d62dpqiibcp9lp0R new file mode 100644 index 0000000..0046acd Binary files /dev/null and b/.flatpak-builder/ccache/d/1/ad8ep0u551ttgjf2d62dpqiibcp9lp0R differ diff --git a/.flatpak-builder/ccache/d/1/stats b/.flatpak-builder/ccache/d/1/stats new file mode 100644 index 0000000..7bde4b8 --- /dev/null +++ b/.flatpak-builder/ccache/d/1/stats @@ -0,0 +1,82 @@ +0 +0 +0 +0 +1 +0 +0 +0 +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +4 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +2 +1 +1 +3 +0 +0 +0 +0 +0 +0 +3 +1 +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 diff --git a/.flatpak-builder/ccache/d/2/6c2rukp9jhpgen18v4q0mjo5oqpmvpeR b/.flatpak-builder/ccache/d/2/6c2rukp9jhpgen18v4q0mjo5oqpmvpeR new file mode 100644 index 0000000..0d3b03e Binary files /dev/null and b/.flatpak-builder/ccache/d/2/6c2rukp9jhpgen18v4q0mjo5oqpmvpeR differ diff --git a/.flatpak-builder/ccache/d/2/stats b/.flatpak-builder/ccache/d/2/stats new file mode 100644 index 0000000..2bec0ce --- /dev/null +++ b/.flatpak-builder/ccache/d/2/stats @@ -0,0 +1,82 @@ +0 +0 +0 +0 +1 +0 +0 +0 +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +2 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +2 +1 +5 +3 +0 +0 +0 +0 +0 +0 +3 +3 +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 diff --git a/.flatpak-builder/ccache/d/3/111195ka4j1gl85a4742eqirsagm61kM b/.flatpak-builder/ccache/d/3/111195ka4j1gl85a4742eqirsagm61kM new file mode 100644 index 0000000..d94d572 Binary files /dev/null and b/.flatpak-builder/ccache/d/3/111195ka4j1gl85a4742eqirsagm61kM differ diff --git a/.flatpak-builder/ccache/d/3/85n2vgas81vpdgqv3pnk4s34sdo4rc0M b/.flatpak-builder/ccache/d/3/85n2vgas81vpdgqv3pnk4s34sdo4rc0M new file mode 100644 index 0000000..2d00330 Binary files /dev/null and b/.flatpak-builder/ccache/d/3/85n2vgas81vpdgqv3pnk4s34sdo4rc0M differ diff --git a/.flatpak-builder/ccache/d/3/stats b/.flatpak-builder/ccache/d/3/stats index 5203da7..269ad89 100644 --- a/.flatpak-builder/ccache/d/3/stats +++ b/.flatpak-builder/ccache/d/3/stats @@ -6,8 +6,47 @@ 0 0 0 +<<<<<<< HEAD 0 0 +======= +1 +0 +4 +0 +0 +0 +0 +0 +0 +0 +0 +2 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +1 +0 +1 +1 +0 +0 +0 +0 +0 +0 +1 +>>>>>>> new-pomodoro 1 0 0 @@ -46,6 +85,7 @@ 0 0 0 +<<<<<<< HEAD 0 0 0 @@ -80,3 +120,5 @@ 0 0 0 +======= +>>>>>>> new-pomodoro diff --git a/.flatpak-builder/ccache/d/4/48v32ileih08pa0oarkqdh14l4hrb18M b/.flatpak-builder/ccache/d/4/48v32ileih08pa0oarkqdh14l4hrb18M new file mode 100644 index 0000000..b0bc974 Binary files /dev/null and b/.flatpak-builder/ccache/d/4/48v32ileih08pa0oarkqdh14l4hrb18M differ diff --git a/.flatpak-builder/ccache/d/4/76t8j5nibf3bup2via5vatlsptenf32M b/.flatpak-builder/ccache/d/4/76t8j5nibf3bup2via5vatlsptenf32M new file mode 100644 index 0000000..0095fd6 Binary files /dev/null and b/.flatpak-builder/ccache/d/4/76t8j5nibf3bup2via5vatlsptenf32M differ diff --git a/.flatpak-builder/ccache/d/4/8aia7ph3kpklrp6a666n4pgatckb6o6M b/.flatpak-builder/ccache/d/4/8aia7ph3kpklrp6a666n4pgatckb6o6M new file mode 100644 index 0000000..74ac28c Binary files /dev/null and b/.flatpak-builder/ccache/d/4/8aia7ph3kpklrp6a666n4pgatckb6o6M differ diff --git a/.flatpak-builder/ccache/d/4/stats b/.flatpak-builder/ccache/d/4/stats index fdb1454..c307851 100644 --- a/.flatpak-builder/ccache/d/4/stats +++ b/.flatpak-builder/ccache/d/4/stats @@ -2,11 +2,17 @@ 0 0 0 +<<<<<<< HEAD 2 +======= +5 0 0 0 +1 0 +1 +>>>>>>> new-pomodoro 0 0 0 @@ -18,6 +24,10 @@ 0 0 0 +<<<<<<< HEAD +======= +3 +>>>>>>> new-pomodoro 0 0 0 @@ -28,9 +38,21 @@ 0 0 0 +<<<<<<< HEAD +======= +6 +5 +7 +11 +>>>>>>> new-pomodoro 0 0 0 +0 +0 +0 +<<<<<<< HEAD +0 2 2 0 @@ -44,6 +66,11 @@ 4 0 2 +======= +11 +4 +5 +>>>>>>> new-pomodoro 0 0 0 diff --git a/.flatpak-builder/ccache/d/5/54vq39upftk3ao68gru7nsmj6jokojiR b/.flatpak-builder/ccache/d/5/54vq39upftk3ao68gru7nsmj6jokojiR new file mode 100644 index 0000000..63bb9cc Binary files /dev/null and b/.flatpak-builder/ccache/d/5/54vq39upftk3ao68gru7nsmj6jokojiR differ diff --git a/.flatpak-builder/ccache/d/5/stats b/.flatpak-builder/ccache/d/5/stats index 6947074..3956bdb 100644 --- a/.flatpak-builder/ccache/d/5/stats +++ b/.flatpak-builder/ccache/d/5/stats @@ -6,6 +6,7 @@ 0 0 0 +<<<<<<< HEAD 0 0 0 @@ -16,6 +17,18 @@ 0 0 1 +======= +1 +2 +0 +0 +0 +0 +0 +0 +0 +3 +>>>>>>> new-pomodoro 0 0 0 @@ -31,18 +44,30 @@ 0 0 0 +<<<<<<< HEAD 1 1 0 2 +======= +2 +1 +1 +3 +>>>>>>> new-pomodoro 0 0 0 0 0 0 +<<<<<<< HEAD 2 0 +======= +3 +1 +>>>>>>> new-pomodoro 1 0 0 diff --git a/.flatpak-builder/ccache/d/6/a99io5egbt28j3u4uvqsgtgjtpar8v0M b/.flatpak-builder/ccache/d/6/a99io5egbt28j3u4uvqsgtgjtpar8v0M new file mode 100644 index 0000000..acb4422 Binary files /dev/null and b/.flatpak-builder/ccache/d/6/a99io5egbt28j3u4uvqsgtgjtpar8v0M differ diff --git a/.flatpak-builder/ccache/d/6/stats b/.flatpak-builder/ccache/d/6/stats new file mode 100644 index 0000000..68c5368 --- /dev/null +++ b/.flatpak-builder/ccache/d/6/stats @@ -0,0 +1,82 @@ +0 +0 +0 +0 +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +1 +1 +0 +2 +0 +0 +0 +0 +0 +0 +2 +0 +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 diff --git a/.flatpak-builder/ccache/d/7/stats b/.flatpak-builder/ccache/d/7/stats new file mode 100644 index 0000000..147cecf --- /dev/null +++ b/.flatpak-builder/ccache/d/7/stats @@ -0,0 +1,82 @@ +0 +0 +0 +0 +2 +0 +0 +0 +0 +0 +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +2 +2 +0 +4 +0 +0 +0 +0 +0 +0 +4 +0 +2 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 diff --git a/.flatpak-builder/ccache/d/8/111eiaehhtbfo3oqbba98300ev3rgr4M b/.flatpak-builder/ccache/d/8/111eiaehhtbfo3oqbba98300ev3rgr4M new file mode 100644 index 0000000..eb7a183 Binary files /dev/null and b/.flatpak-builder/ccache/d/8/111eiaehhtbfo3oqbba98300ev3rgr4M differ diff --git a/.flatpak-builder/ccache/d/8/d7ourv6acir2g1td9utp1nqe00etv5qM b/.flatpak-builder/ccache/d/8/d7ourv6acir2g1td9utp1nqe00etv5qM new file mode 100644 index 0000000..3f7eefe Binary files /dev/null and b/.flatpak-builder/ccache/d/8/d7ourv6acir2g1td9utp1nqe00etv5qM differ diff --git a/.flatpak-builder/ccache/d/8/stats b/.flatpak-builder/ccache/d/8/stats index fdb1454..c3f7cfb 100644 --- a/.flatpak-builder/ccache/d/8/stats +++ b/.flatpak-builder/ccache/d/8/stats @@ -2,7 +2,11 @@ 0 0 0 +<<<<<<< HEAD 2 +======= +3 +>>>>>>> new-pomodoro 0 0 0 @@ -31,19 +35,32 @@ 0 0 0 +<<<<<<< HEAD 2 2 0 4 +======= +3 +3 0 +6 +>>>>>>> new-pomodoro 0 0 0 0 0 +0 +<<<<<<< HEAD 4 0 2 +======= +6 +0 +3 +>>>>>>> new-pomodoro 0 0 0 diff --git a/.flatpak-builder/ccache/d/9/stats b/.flatpak-builder/ccache/d/9/stats new file mode 100644 index 0000000..2145faa --- /dev/null +++ b/.flatpak-builder/ccache/d/9/stats @@ -0,0 +1,82 @@ +0 +0 +0 +0 +1 +0 +0 +0 +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +2 +1 +1 +3 +0 +0 +0 +0 +0 +0 +3 +1 +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 diff --git a/.flatpak-builder/ccache/d/CACHEDIR.TAG b/.flatpak-builder/ccache/d/CACHEDIR.TAG new file mode 100644 index 0000000..874477f --- /dev/null +++ b/.flatpak-builder/ccache/d/CACHEDIR.TAG @@ -0,0 +1,4 @@ +Signature: 8a477f597d28d172789f06886806bc55 +# This file is a cache directory tag created by ccache. +# For information about cache directory tags, see: +# http://www.brynosaurus.com/cachedir/ diff --git a/.flatpak-builder/ccache/d/a/3f5iji1qqeebcj3dpm2fu1pde5sffokM b/.flatpak-builder/ccache/d/a/3f5iji1qqeebcj3dpm2fu1pde5sffokM new file mode 100644 index 0000000..b7bf477 Binary files /dev/null and b/.flatpak-builder/ccache/d/a/3f5iji1qqeebcj3dpm2fu1pde5sffokM differ diff --git a/.flatpak-builder/ccache/d/a/5f4o43sratojn92dndu3mn6f0p29g6sM b/.flatpak-builder/ccache/d/a/5f4o43sratojn92dndu3mn6f0p29g6sM new file mode 100644 index 0000000..f3c0210 Binary files /dev/null and b/.flatpak-builder/ccache/d/a/5f4o43sratojn92dndu3mn6f0p29g6sM differ diff --git a/.flatpak-builder/ccache/d/a/b500gkicp4vp3sqdcn8eonisome44muR b/.flatpak-builder/ccache/d/a/b500gkicp4vp3sqdcn8eonisome44muR new file mode 100644 index 0000000..a95e60b Binary files /dev/null and b/.flatpak-builder/ccache/d/a/b500gkicp4vp3sqdcn8eonisome44muR differ diff --git a/.flatpak-builder/ccache/d/a/stats b/.flatpak-builder/ccache/d/a/stats index 94504b0..3f9ec58 100644 --- a/.flatpak-builder/ccache/d/a/stats +++ b/.flatpak-builder/ccache/d/a/stats @@ -2,6 +2,7 @@ 0 0 0 +<<<<<<< HEAD 0 0 0 @@ -23,6 +24,9 @@ 0 0 0 +======= +2 +>>>>>>> new-pomodoro 0 0 0 @@ -40,10 +44,37 @@ 0 0 0 +<<<<<<< HEAD 0 0 0 0 +======= +2 +0 +0 +0 +0 +0 +1 +0 +0 +0 +0 +3 +2 +5 +5 +0 +0 +0 +0 +0 +0 +5 +3 +2 +>>>>>>> new-pomodoro 0 0 0 diff --git a/.flatpak-builder/ccache/d/b/530nea87h9us45r3g27f951ifeqnm7iM b/.flatpak-builder/ccache/d/b/530nea87h9us45r3g27f951ifeqnm7iM new file mode 100644 index 0000000..8d57afe Binary files /dev/null and b/.flatpak-builder/ccache/d/b/530nea87h9us45r3g27f951ifeqnm7iM differ diff --git a/.flatpak-builder/ccache/d/b/667im01fptchj8p487u9tisqdkvh8aaR b/.flatpak-builder/ccache/d/b/667im01fptchj8p487u9tisqdkvh8aaR new file mode 100644 index 0000000..c057745 Binary files /dev/null and b/.flatpak-builder/ccache/d/b/667im01fptchj8p487u9tisqdkvh8aaR differ diff --git a/.flatpak-builder/ccache/d/b/723oib4ne8h7vjl7otvf7o7itbg86dkM b/.flatpak-builder/ccache/d/b/723oib4ne8h7vjl7otvf7o7itbg86dkM new file mode 100644 index 0000000..f2bed2a Binary files /dev/null and b/.flatpak-builder/ccache/d/b/723oib4ne8h7vjl7otvf7o7itbg86dkM differ diff --git a/.flatpak-builder/ccache/d/b/79d0tkt7gc6nhi6uastqhv4g9e8funmM b/.flatpak-builder/ccache/d/b/79d0tkt7gc6nhi6uastqhv4g9e8funmM new file mode 100644 index 0000000..17370d6 Binary files /dev/null and b/.flatpak-builder/ccache/d/b/79d0tkt7gc6nhi6uastqhv4g9e8funmM differ diff --git a/.flatpak-builder/ccache/d/b/faaje0lnu822epgo15njsous9i5ket0M b/.flatpak-builder/ccache/d/b/faaje0lnu822epgo15njsous9i5ket0M new file mode 100644 index 0000000..d399057 Binary files /dev/null and b/.flatpak-builder/ccache/d/b/faaje0lnu822epgo15njsous9i5ket0M differ diff --git a/.flatpak-builder/ccache/d/b/stats b/.flatpak-builder/ccache/d/b/stats new file mode 100644 index 0000000..75f40ae --- /dev/null +++ b/.flatpak-builder/ccache/d/b/stats @@ -0,0 +1,82 @@ +0 +0 +0 +0 +0 +0 +0 +0 +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +2 +0 +0 +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +1 +0 +3 +1 +0 +0 +0 +0 +0 +0 +1 +2 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 diff --git a/.flatpak-builder/ccache/d/c/0bs7moc9rqplanbdle7isho70a74onkR b/.flatpak-builder/ccache/d/c/0bs7moc9rqplanbdle7isho70a74onkR new file mode 100644 index 0000000..0088bb3 Binary files /dev/null and b/.flatpak-builder/ccache/d/c/0bs7moc9rqplanbdle7isho70a74onkR differ diff --git a/.flatpak-builder/ccache/d/c/7275issap6m0v2q82u38il4628sdn86M b/.flatpak-builder/ccache/d/c/7275issap6m0v2q82u38il4628sdn86M new file mode 100644 index 0000000..4a872bb Binary files /dev/null and b/.flatpak-builder/ccache/d/c/7275issap6m0v2q82u38il4628sdn86M differ diff --git a/.flatpak-builder/ccache/d/c/d4hlgc0ilp9gho1e9smf913dijkn480M b/.flatpak-builder/ccache/d/c/d4hlgc0ilp9gho1e9smf913dijkn480M new file mode 100644 index 0000000..afbc680 Binary files /dev/null and b/.flatpak-builder/ccache/d/c/d4hlgc0ilp9gho1e9smf913dijkn480M differ diff --git a/.flatpak-builder/ccache/d/c/stats b/.flatpak-builder/ccache/d/c/stats index 147cecf..c1ef9a4 100644 --- a/.flatpak-builder/ccache/d/c/stats +++ b/.flatpak-builder/ccache/d/c/stats @@ -8,7 +8,11 @@ 0 0 0 +<<<<<<< HEAD 1 +======= +2 +>>>>>>> new-pomodoro 0 0 0 diff --git a/.flatpak-builder/ccache/d/d/0bngqqcg338f21s6ikg42139ko28vfiM b/.flatpak-builder/ccache/d/d/0bngqqcg338f21s6ikg42139ko28vfiM new file mode 100644 index 0000000..1023e22 Binary files /dev/null and b/.flatpak-builder/ccache/d/d/0bngqqcg338f21s6ikg42139ko28vfiM differ diff --git a/.flatpak-builder/ccache/d/d/9csb22kiq6s6t1v8v3kplu75ijnr522M b/.flatpak-builder/ccache/d/d/9csb22kiq6s6t1v8v3kplu75ijnr522M new file mode 100644 index 0000000..1704c8b Binary files /dev/null and b/.flatpak-builder/ccache/d/d/9csb22kiq6s6t1v8v3kplu75ijnr522M differ diff --git a/.flatpak-builder/ccache/d/d/d9faab58bplc2ors7m7ebgj0ief8kasM b/.flatpak-builder/ccache/d/d/d9faab58bplc2ors7m7ebgj0ief8kasM new file mode 100644 index 0000000..901e7b2 Binary files /dev/null and b/.flatpak-builder/ccache/d/d/d9faab58bplc2ors7m7ebgj0ief8kasM differ diff --git a/.flatpak-builder/ccache/d/d/stats b/.flatpak-builder/ccache/d/d/stats new file mode 100644 index 0000000..4a3e57d --- /dev/null +++ b/.flatpak-builder/ccache/d/d/stats @@ -0,0 +1,82 @@ +0 +0 +0 +0 +1 +0 +0 +0 +1 +0 +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +2 +1 +1 +3 +0 +0 +0 +0 +0 +0 +3 +1 +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 diff --git a/.flatpak-builder/ccache/d/e/stats b/.flatpak-builder/ccache/d/e/stats index 68c5368..a135599 100644 --- a/.flatpak-builder/ccache/d/e/stats +++ b/.flatpak-builder/ccache/d/e/stats @@ -2,6 +2,13 @@ 0 0 0 +<<<<<<< HEAD +======= +2 +0 +0 +0 +>>>>>>> new-pomodoro 1 0 0 @@ -27,6 +34,7 @@ 0 0 0 +<<<<<<< HEAD 0 0 0 @@ -34,6 +42,20 @@ 1 1 0 +======= +3 +2 +1 +5 +0 +0 +0 +0 +0 +0 +5 +1 +>>>>>>> new-pomodoro 2 0 0 @@ -41,6 +63,7 @@ 0 0 0 +<<<<<<< HEAD 2 0 1 @@ -50,6 +73,8 @@ 0 0 0 +======= +>>>>>>> new-pomodoro 0 0 0 diff --git a/.flatpak-builder/ccache/d/f/b4ps03kf5o1tnc7rf8roddhmlrs3c34R b/.flatpak-builder/ccache/d/f/b4ps03kf5o1tnc7rf8roddhmlrs3c34R new file mode 100644 index 0000000..6f17ec9 Binary files /dev/null and b/.flatpak-builder/ccache/d/f/b4ps03kf5o1tnc7rf8roddhmlrs3c34R differ diff --git a/.flatpak-builder/ccache/d/f/stats b/.flatpak-builder/ccache/d/f/stats index eccac08..9e7349f 100644 --- a/.flatpak-builder/ccache/d/f/stats +++ b/.flatpak-builder/ccache/d/f/stats @@ -6,6 +6,13 @@ 0 0 0 +<<<<<<< HEAD +======= +1 +0 +0 +0 +>>>>>>> new-pomodoro 0 0 0 @@ -13,10 +20,18 @@ 0 0 0 +<<<<<<< HEAD +======= +3 0 0 +3 +>>>>>>> new-pomodoro 0 0 +0 +0 +<<<<<<< HEAD 1 0 0 @@ -35,6 +50,8 @@ 1 0 2 +======= +>>>>>>> new-pomodoro 0 0 0 @@ -42,7 +59,21 @@ 0 0 2 +<<<<<<< HEAD +0 +======= +1 +7 +3 +0 +0 +0 +0 +0 0 +3 +4 +>>>>>>> new-pomodoro 1 0 0 diff --git a/.flatpak-builder/ccache/d/stats b/.flatpak-builder/ccache/d/stats index 3f54804..4ac54c2 100644 --- a/.flatpak-builder/ccache/d/stats +++ b/.flatpak-builder/ccache/d/stats @@ -9,8 +9,13 @@ 0 0 0 +<<<<<<< HEAD 21 120 +======= +55 +884 +>>>>>>> new-pomodoro 0 0 0 @@ -47,6 +52,7 @@ 0 0 0 +<<<<<<< HEAD 0 1 2 @@ -79,4 +85,38 @@ 4 12 0 +======= +4 +7 +2 +4 +4 +1 +3 +1 +2 +2 +7 +6 +4 +4 +3 +1 +84 +108 +28 +40 +44 +28 +32 +4 +24 +24 +248 +72 +44 +36 +12 +56 +>>>>>>> new-pomodoro 0 diff --git a/.flatpak-builder/ccache/e/0/stats b/.flatpak-builder/ccache/e/0/stats index 68c5368..2f24a7c 100644 --- a/.flatpak-builder/ccache/e/0/stats +++ b/.flatpak-builder/ccache/e/0/stats @@ -2,6 +2,7 @@ 0 0 0 +<<<<<<< HEAD 1 0 0 @@ -34,6 +35,8 @@ 1 1 0 +======= +>>>>>>> new-pomodoro 2 0 0 @@ -41,9 +44,47 @@ 0 0 0 +<<<<<<< HEAD 2 0 1 +======= +0 +0 +0 +0 +0 +0 +0 +0 +2 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +2 +2 +0 +4 +0 +0 +0 +0 +0 +0 +4 +0 +2 +>>>>>>> new-pomodoro 0 0 0 diff --git a/.flatpak-builder/ccache/e/1/521rui92kr9hlv7np8u11sc42hn4bfoR b/.flatpak-builder/ccache/e/1/521rui92kr9hlv7np8u11sc42hn4bfoR new file mode 100644 index 0000000..310183a Binary files /dev/null and b/.flatpak-builder/ccache/e/1/521rui92kr9hlv7np8u11sc42hn4bfoR differ diff --git a/.flatpak-builder/ccache/e/1/6afc7mqru9cj8176ldro0kcv7lv2474M b/.flatpak-builder/ccache/e/1/6afc7mqru9cj8176ldro0kcv7lv2474M new file mode 100644 index 0000000..ea352fa Binary files /dev/null and b/.flatpak-builder/ccache/e/1/6afc7mqru9cj8176ldro0kcv7lv2474M differ diff --git a/.flatpak-builder/ccache/e/1/eb3nc076l59d5i9o0iab82jrlqk8dgkR b/.flatpak-builder/ccache/e/1/eb3nc076l59d5i9o0iab82jrlqk8dgkR new file mode 100644 index 0000000..d0b1a34 Binary files /dev/null and b/.flatpak-builder/ccache/e/1/eb3nc076l59d5i9o0iab82jrlqk8dgkR differ diff --git a/.flatpak-builder/ccache/e/1/stats b/.flatpak-builder/ccache/e/1/stats index 68c5368..9906765 100644 --- a/.flatpak-builder/ccache/e/1/stats +++ b/.flatpak-builder/ccache/e/1/stats @@ -2,6 +2,13 @@ 0 0 0 +<<<<<<< HEAD +======= +0 +0 +0 +0 +>>>>>>> new-pomodoro 1 0 0 @@ -13,6 +20,7 @@ 0 0 0 +<<<<<<< HEAD 0 0 0 @@ -43,13 +51,44 @@ 0 2 0 +======= +2 +0 +0 +3 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 1 0 +7 +>>>>>>> new-pomodoro +1 +0 +0 +0 +0 +0 +0 +<<<<<<< HEAD +======= +1 +4 +0 +0 0 0 0 0 0 +>>>>>>> new-pomodoro 0 0 0 diff --git a/.flatpak-builder/ccache/e/2/b7hjmo4cjnr7kpuibbp8ib4f5f4qgp6M b/.flatpak-builder/ccache/e/2/b7hjmo4cjnr7kpuibbp8ib4f5f4qgp6M new file mode 100644 index 0000000..9017aa5 Binary files /dev/null and b/.flatpak-builder/ccache/e/2/b7hjmo4cjnr7kpuibbp8ib4f5f4qgp6M differ diff --git a/.flatpak-builder/ccache/e/2/f813h79e592sh2lasu01itnk2vh2p06R b/.flatpak-builder/ccache/e/2/f813h79e592sh2lasu01itnk2vh2p06R new file mode 100644 index 0000000..f0e1f2f Binary files /dev/null and b/.flatpak-builder/ccache/e/2/f813h79e592sh2lasu01itnk2vh2p06R differ diff --git a/.flatpak-builder/ccache/e/2/stats b/.flatpak-builder/ccache/e/2/stats new file mode 100644 index 0000000..fdb1454 --- /dev/null +++ b/.flatpak-builder/ccache/e/2/stats @@ -0,0 +1,82 @@ +0 +0 +0 +0 +2 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +2 +2 +0 +4 +0 +0 +0 +0 +0 +0 +4 +0 +2 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 diff --git a/.flatpak-builder/ccache/e/3/24uo8f31k4bpdd020i7cikoctgltsq0M b/.flatpak-builder/ccache/e/3/24uo8f31k4bpdd020i7cikoctgltsq0M new file mode 100644 index 0000000..7be5d84 Binary files /dev/null and b/.flatpak-builder/ccache/e/3/24uo8f31k4bpdd020i7cikoctgltsq0M differ diff --git a/.flatpak-builder/ccache/e/3/3bri8s575pkrnart27hl0hfocb6d0aqR b/.flatpak-builder/ccache/e/3/3bri8s575pkrnart27hl0hfocb6d0aqR new file mode 100644 index 0000000..88a8e21 Binary files /dev/null and b/.flatpak-builder/ccache/e/3/3bri8s575pkrnart27hl0hfocb6d0aqR differ diff --git a/.flatpak-builder/ccache/e/3/stats b/.flatpak-builder/ccache/e/3/stats index 68c5368..bd2139f 100644 --- a/.flatpak-builder/ccache/e/3/stats +++ b/.flatpak-builder/ccache/e/3/stats @@ -2,7 +2,16 @@ 0 0 0 +<<<<<<< HEAD 1 +======= +2 +0 +0 +0 +1 +2 +>>>>>>> new-pomodoro 0 0 0 @@ -12,6 +21,7 @@ 0 0 0 +<<<<<<< HEAD 0 0 0 @@ -34,17 +44,43 @@ 1 1 0 +======= +>>>>>>> new-pomodoro +2 +0 +0 +0 +0 +0 +0 +<<<<<<< HEAD 2 0 +1 +0 +======= 0 0 0 0 0 +0 +0 +3 2 +1 +5 0 +0 +0 +0 +0 +0 +5 1 +2 0 +>>>>>>> new-pomodoro 0 0 0 diff --git a/.flatpak-builder/ccache/e/4/04nrehnnrkusdsci8ete18i68ug4d3cR b/.flatpak-builder/ccache/e/4/04nrehnnrkusdsci8ete18i68ug4d3cR new file mode 100644 index 0000000..26c6bf7 Binary files /dev/null and b/.flatpak-builder/ccache/e/4/04nrehnnrkusdsci8ete18i68ug4d3cR differ diff --git a/.flatpak-builder/ccache/e/4/8baumee9inugdec36tcmsf43ug83m66M b/.flatpak-builder/ccache/e/4/8baumee9inugdec36tcmsf43ug83m66M new file mode 100644 index 0000000..bb08451 Binary files /dev/null and b/.flatpak-builder/ccache/e/4/8baumee9inugdec36tcmsf43ug83m66M differ diff --git a/.flatpak-builder/ccache/e/4/stats b/.flatpak-builder/ccache/e/4/stats new file mode 100644 index 0000000..666b48d --- /dev/null +++ b/.flatpak-builder/ccache/e/4/stats @@ -0,0 +1,82 @@ +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +2 +0 +0 +0 +0 +0 +0 +0 +0 +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 diff --git a/.flatpak-builder/ccache/e/5/02on8d4n2auusnr8tec69p5tm2n1uigM b/.flatpak-builder/ccache/e/5/02on8d4n2auusnr8tec69p5tm2n1uigM new file mode 100644 index 0000000..5bf444c Binary files /dev/null and b/.flatpak-builder/ccache/e/5/02on8d4n2auusnr8tec69p5tm2n1uigM differ diff --git a/.flatpak-builder/ccache/e/5/81o0gil43p1s8aurp6g728452rlsuduR b/.flatpak-builder/ccache/e/5/81o0gil43p1s8aurp6g728452rlsuduR new file mode 100644 index 0000000..9e2863a Binary files /dev/null and b/.flatpak-builder/ccache/e/5/81o0gil43p1s8aurp6g728452rlsuduR differ diff --git a/.flatpak-builder/ccache/e/5/stats b/.flatpak-builder/ccache/e/5/stats index 68c5368..43e8801 100644 --- a/.flatpak-builder/ccache/e/5/stats +++ b/.flatpak-builder/ccache/e/5/stats @@ -2,6 +2,7 @@ 0 0 0 +<<<<<<< HEAD 1 0 0 @@ -34,6 +35,8 @@ 1 1 0 +======= +>>>>>>> new-pomodoro 2 0 0 @@ -41,9 +44,47 @@ 0 0 0 +<<<<<<< HEAD 2 0 1 +======= +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +2 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +2 +2 +4 +4 +0 +0 +0 +0 +0 +0 +4 +2 +2 +>>>>>>> new-pomodoro 0 0 0 diff --git a/.flatpak-builder/ccache/e/6/45gq1n1act7tj50vi5qnh1qdti2akv8M b/.flatpak-builder/ccache/e/6/45gq1n1act7tj50vi5qnh1qdti2akv8M new file mode 100644 index 0000000..2cf262a Binary files /dev/null and b/.flatpak-builder/ccache/e/6/45gq1n1act7tj50vi5qnh1qdti2akv8M differ diff --git a/.flatpak-builder/ccache/e/6/76adqht63t7f6dj02u8coc2mjhbru3oR b/.flatpak-builder/ccache/e/6/76adqht63t7f6dj02u8coc2mjhbru3oR new file mode 100644 index 0000000..4cda686 Binary files /dev/null and b/.flatpak-builder/ccache/e/6/76adqht63t7f6dj02u8coc2mjhbru3oR differ diff --git a/.flatpak-builder/ccache/e/6/stats b/.flatpak-builder/ccache/e/6/stats index beb7642..f9d62b8 100644 --- a/.flatpak-builder/ccache/e/6/stats +++ b/.flatpak-builder/ccache/e/6/stats @@ -2,6 +2,11 @@ 0 1 0 +<<<<<<< HEAD +======= +1 +0 +>>>>>>> new-pomodoro 0 0 0 @@ -15,9 +20,13 @@ 0 0 0 +<<<<<<< HEAD 0 0 1 +======= +5 +>>>>>>> new-pomodoro 0 0 0 @@ -31,6 +40,7 @@ 0 0 0 +<<<<<<< HEAD 1 1 0 @@ -44,6 +54,21 @@ 0 0 0 +======= +2 +2 +0 +4 +0 +0 +0 +0 +0 +0 +2 +0 +1 +>>>>>>> new-pomodoro 0 0 0 diff --git a/.flatpak-builder/ccache/e/7/788jhi5oc3ntied3girgjbbmgtsdrl2M b/.flatpak-builder/ccache/e/7/788jhi5oc3ntied3girgjbbmgtsdrl2M new file mode 100644 index 0000000..1ce51c8 Binary files /dev/null and b/.flatpak-builder/ccache/e/7/788jhi5oc3ntied3girgjbbmgtsdrl2M differ diff --git a/.flatpak-builder/ccache/e/7/stats b/.flatpak-builder/ccache/e/7/stats index 0db3a15..2832864 100644 --- a/.flatpak-builder/ccache/e/7/stats +++ b/.flatpak-builder/ccache/e/7/stats @@ -6,8 +6,11 @@ 0 0 0 +<<<<<<< HEAD 0 0 +======= +>>>>>>> new-pomodoro 1 0 0 @@ -19,6 +22,7 @@ 0 0 0 +<<<<<<< HEAD 0 0 0 @@ -43,6 +47,34 @@ 0 2 0 +======= +2 +0 +0 +4 +0 +0 +0 +0 +0 +1 +0 +0 +0 +0 +2 +1 +9 +3 +0 +0 +0 +0 +0 +0 +3 +5 +>>>>>>> new-pomodoro 1 0 0 diff --git a/.flatpak-builder/ccache/e/8/00qu8s8vd20vnctcd275qcujjui0nuqR b/.flatpak-builder/ccache/e/8/00qu8s8vd20vnctcd275qcujjui0nuqR new file mode 100644 index 0000000..36b11fe Binary files /dev/null and b/.flatpak-builder/ccache/e/8/00qu8s8vd20vnctcd275qcujjui0nuqR differ diff --git a/.flatpak-builder/ccache/e/8/84hh1rmgqbs9pmqtj2m53d8odojv7j0M b/.flatpak-builder/ccache/e/8/84hh1rmgqbs9pmqtj2m53d8odojv7j0M new file mode 100644 index 0000000..55e472b Binary files /dev/null and b/.flatpak-builder/ccache/e/8/84hh1rmgqbs9pmqtj2m53d8odojv7j0M differ diff --git a/.flatpak-builder/ccache/e/8/stats b/.flatpak-builder/ccache/e/8/stats new file mode 100644 index 0000000..2bec0ce --- /dev/null +++ b/.flatpak-builder/ccache/e/8/stats @@ -0,0 +1,82 @@ +0 +0 +0 +0 +1 +0 +0 +0 +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +2 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +2 +1 +5 +3 +0 +0 +0 +0 +0 +0 +3 +3 +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 diff --git a/.flatpak-builder/ccache/e/9/c17gtlurltbs67aeup32f8iebi17fkgR b/.flatpak-builder/ccache/e/9/c17gtlurltbs67aeup32f8iebi17fkgR new file mode 100644 index 0000000..e32e232 Binary files /dev/null and b/.flatpak-builder/ccache/e/9/c17gtlurltbs67aeup32f8iebi17fkgR differ diff --git a/.flatpak-builder/ccache/e/9/deaccsehp6g4ru9o8l46jmilis6op1cM b/.flatpak-builder/ccache/e/9/deaccsehp6g4ru9o8l46jmilis6op1cM new file mode 100644 index 0000000..af698f9 Binary files /dev/null and b/.flatpak-builder/ccache/e/9/deaccsehp6g4ru9o8l46jmilis6op1cM differ diff --git a/.flatpak-builder/ccache/e/9/stats b/.flatpak-builder/ccache/e/9/stats new file mode 100644 index 0000000..35912d9 --- /dev/null +++ b/.flatpak-builder/ccache/e/9/stats @@ -0,0 +1,82 @@ +0 +0 +0 +0 +3 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +2 +0 +0 +2 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +3 +3 +4 +6 +0 +0 +0 +0 +0 +0 +6 +2 +3 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 diff --git a/.flatpak-builder/ccache/e/CACHEDIR.TAG b/.flatpak-builder/ccache/e/CACHEDIR.TAG new file mode 100644 index 0000000..874477f --- /dev/null +++ b/.flatpak-builder/ccache/e/CACHEDIR.TAG @@ -0,0 +1,4 @@ +Signature: 8a477f597d28d172789f06886806bc55 +# This file is a cache directory tag created by ccache. +# For information about cache directory tags, see: +# http://www.brynosaurus.com/cachedir/ diff --git a/.flatpak-builder/ccache/e/a/05f0206brbcuc3mem7u27hf4ddqbrpgM b/.flatpak-builder/ccache/e/a/05f0206brbcuc3mem7u27hf4ddqbrpgM new file mode 100644 index 0000000..588d8ac Binary files /dev/null and b/.flatpak-builder/ccache/e/a/05f0206brbcuc3mem7u27hf4ddqbrpgM differ diff --git a/.flatpak-builder/ccache/e/a/282oei3saph4qh522h30pmblabpo1c6M b/.flatpak-builder/ccache/e/a/282oei3saph4qh522h30pmblabpo1c6M new file mode 100644 index 0000000..f79bbb7 Binary files /dev/null and b/.flatpak-builder/ccache/e/a/282oei3saph4qh522h30pmblabpo1c6M differ diff --git a/.flatpak-builder/ccache/e/a/40s4po4m21mf1dui4ptgruec2q40mueM b/.flatpak-builder/ccache/e/a/40s4po4m21mf1dui4ptgruec2q40mueM new file mode 100644 index 0000000..02e0dd9 Binary files /dev/null and b/.flatpak-builder/ccache/e/a/40s4po4m21mf1dui4ptgruec2q40mueM differ diff --git a/.flatpak-builder/ccache/e/a/4ch57heleqd9d4ljq9bcmg6jkbojb7gM b/.flatpak-builder/ccache/e/a/4ch57heleqd9d4ljq9bcmg6jkbojb7gM new file mode 100644 index 0000000..621a2c3 Binary files /dev/null and b/.flatpak-builder/ccache/e/a/4ch57heleqd9d4ljq9bcmg6jkbojb7gM differ diff --git a/.flatpak-builder/ccache/e/a/88tnlcd0c7mpp832f3shc8e55jf5eeoR b/.flatpak-builder/ccache/e/a/88tnlcd0c7mpp832f3shc8e55jf5eeoR new file mode 100644 index 0000000..62c1277 Binary files /dev/null and b/.flatpak-builder/ccache/e/a/88tnlcd0c7mpp832f3shc8e55jf5eeoR differ diff --git a/.flatpak-builder/ccache/e/a/stats b/.flatpak-builder/ccache/e/a/stats index 621acad..c1bf9cb 100644 --- a/.flatpak-builder/ccache/e/a/stats +++ b/.flatpak-builder/ccache/e/a/stats @@ -6,8 +6,11 @@ 0 0 0 +<<<<<<< HEAD 0 0 +======= +>>>>>>> new-pomodoro 1 0 0 @@ -31,6 +34,7 @@ 0 0 0 +<<<<<<< HEAD 1 1 0 @@ -43,6 +47,22 @@ 0 2 0 +======= +0 +0 +2 +1 +1 +3 +0 +0 +0 +0 +0 +0 +3 +1 +>>>>>>> new-pomodoro 1 0 0 diff --git a/.flatpak-builder/ccache/e/b/57g2rebqmoqks4qs70kgol891m8pq92M b/.flatpak-builder/ccache/e/b/57g2rebqmoqks4qs70kgol891m8pq92M new file mode 100644 index 0000000..8a5e9c1 Binary files /dev/null and b/.flatpak-builder/ccache/e/b/57g2rebqmoqks4qs70kgol891m8pq92M differ diff --git a/.flatpak-builder/ccache/e/b/stats b/.flatpak-builder/ccache/e/b/stats new file mode 100644 index 0000000..4a3e57d --- /dev/null +++ b/.flatpak-builder/ccache/e/b/stats @@ -0,0 +1,82 @@ +0 +0 +0 +0 +1 +0 +0 +0 +1 +0 +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +2 +1 +1 +3 +0 +0 +0 +0 +0 +0 +3 +1 +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 diff --git a/.flatpak-builder/ccache/e/c/39h9l0i5b0tbmddbh66k2jum3c5n9t6M b/.flatpak-builder/ccache/e/c/39h9l0i5b0tbmddbh66k2jum3c5n9t6M new file mode 100644 index 0000000..9d61a90 Binary files /dev/null and b/.flatpak-builder/ccache/e/c/39h9l0i5b0tbmddbh66k2jum3c5n9t6M differ diff --git a/.flatpak-builder/ccache/e/c/68vr0df2gah2ii4lo8l3b7puigad2msR b/.flatpak-builder/ccache/e/c/68vr0df2gah2ii4lo8l3b7puigad2msR new file mode 100644 index 0000000..5d41c90 Binary files /dev/null and b/.flatpak-builder/ccache/e/c/68vr0df2gah2ii4lo8l3b7puigad2msR differ diff --git a/.flatpak-builder/ccache/e/c/stats b/.flatpak-builder/ccache/e/c/stats new file mode 100644 index 0000000..fdb1454 --- /dev/null +++ b/.flatpak-builder/ccache/e/c/stats @@ -0,0 +1,82 @@ +0 +0 +0 +0 +2 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +2 +2 +0 +4 +0 +0 +0 +0 +0 +0 +4 +0 +2 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 diff --git a/.flatpak-builder/ccache/e/d/2b9fdr5kqnof1hueu0iokalajfgso56M b/.flatpak-builder/ccache/e/d/2b9fdr5kqnof1hueu0iokalajfgso56M new file mode 100644 index 0000000..692d021 Binary files /dev/null and b/.flatpak-builder/ccache/e/d/2b9fdr5kqnof1hueu0iokalajfgso56M differ diff --git a/.flatpak-builder/ccache/e/d/4ao94vkg0ba3os1lul7e56l5s68k9qiR b/.flatpak-builder/ccache/e/d/4ao94vkg0ba3os1lul7e56l5s68k9qiR new file mode 100644 index 0000000..4ba9d0e Binary files /dev/null and b/.flatpak-builder/ccache/e/d/4ao94vkg0ba3os1lul7e56l5s68k9qiR differ diff --git a/.flatpak-builder/ccache/e/d/8bdki58diu8se7330goqdcvivnchkt2M b/.flatpak-builder/ccache/e/d/8bdki58diu8se7330goqdcvivnchkt2M new file mode 100644 index 0000000..55f79cd Binary files /dev/null and b/.flatpak-builder/ccache/e/d/8bdki58diu8se7330goqdcvivnchkt2M differ diff --git a/.flatpak-builder/ccache/e/d/stats b/.flatpak-builder/ccache/e/d/stats index 159047e..54604d9 100644 --- a/.flatpak-builder/ccache/e/d/stats +++ b/.flatpak-builder/ccache/e/d/stats @@ -2,6 +2,15 @@ 0 0 0 +<<<<<<< HEAD +======= +1 +0 +0 +0 +0 +>>>>>>> new-pomodoro +0 0 0 0 @@ -11,12 +20,38 @@ 0 0 0 +<<<<<<< HEAD +======= +1 +>>>>>>> new-pomodoro +0 +0 +0 +0 +0 +<<<<<<< HEAD +======= +0 +0 +0 +2 +0 +0 +0 +0 +1 +1 +0 +2 +0 0 0 0 0 0 +2 0 +>>>>>>> new-pomodoro 1 0 0 @@ -54,6 +89,7 @@ 0 0 0 +<<<<<<< HEAD 0 0 0 @@ -80,3 +116,5 @@ 0 0 0 +======= +>>>>>>> new-pomodoro diff --git a/.flatpak-builder/ccache/e/e/172suaekan8lrr0hibd6q8oqriu6i8gM b/.flatpak-builder/ccache/e/e/172suaekan8lrr0hibd6q8oqriu6i8gM new file mode 100644 index 0000000..58ceac3 Binary files /dev/null and b/.flatpak-builder/ccache/e/e/172suaekan8lrr0hibd6q8oqriu6i8gM differ diff --git a/.flatpak-builder/ccache/e/e/222hjhg98jgsvqpmh3so9607lan6legR b/.flatpak-builder/ccache/e/e/222hjhg98jgsvqpmh3so9607lan6legR new file mode 100644 index 0000000..daac360 Binary files /dev/null and b/.flatpak-builder/ccache/e/e/222hjhg98jgsvqpmh3so9607lan6legR differ diff --git a/.flatpak-builder/ccache/e/e/e22mrr19cm877ra1m00fd54b48mn8n8M b/.flatpak-builder/ccache/e/e/e22mrr19cm877ra1m00fd54b48mn8n8M new file mode 100644 index 0000000..3420510 Binary files /dev/null and b/.flatpak-builder/ccache/e/e/e22mrr19cm877ra1m00fd54b48mn8n8M differ diff --git a/.flatpak-builder/ccache/e/e/f6atbq46124ppc1brqai2gi98301arcM b/.flatpak-builder/ccache/e/e/f6atbq46124ppc1brqai2gi98301arcM new file mode 100644 index 0000000..45ab618 Binary files /dev/null and b/.flatpak-builder/ccache/e/e/f6atbq46124ppc1brqai2gi98301arcM differ diff --git a/.flatpak-builder/ccache/e/e/stats b/.flatpak-builder/ccache/e/e/stats index fdb1454..c845ddc 100644 --- a/.flatpak-builder/ccache/e/e/stats +++ b/.flatpak-builder/ccache/e/e/stats @@ -8,7 +8,11 @@ 0 0 0 +<<<<<<< HEAD 0 +======= +1 +>>>>>>> new-pomodoro 0 0 0 diff --git a/.flatpak-builder/ccache/e/f/285tknb3kbpm8lgunho0kee703rvmdaR b/.flatpak-builder/ccache/e/f/285tknb3kbpm8lgunho0kee703rvmdaR new file mode 100644 index 0000000..64c7e2a Binary files /dev/null and b/.flatpak-builder/ccache/e/f/285tknb3kbpm8lgunho0kee703rvmdaR differ diff --git a/.flatpak-builder/ccache/e/f/2fm0cdh9u66aaarrh0u6i40a7ocsfl0M b/.flatpak-builder/ccache/e/f/2fm0cdh9u66aaarrh0u6i40a7ocsfl0M new file mode 100644 index 0000000..26213d1 Binary files /dev/null and b/.flatpak-builder/ccache/e/f/2fm0cdh9u66aaarrh0u6i40a7ocsfl0M differ diff --git a/.flatpak-builder/ccache/e/f/stats b/.flatpak-builder/ccache/e/f/stats index 159047e..79cfb38 100644 --- a/.flatpak-builder/ccache/e/f/stats +++ b/.flatpak-builder/ccache/e/f/stats @@ -15,9 +15,15 @@ 0 0 0 +<<<<<<< HEAD 0 0 1 +======= +2 +0 +5 +>>>>>>> new-pomodoro 0 0 0 diff --git a/.flatpak-builder/ccache/e/stats b/.flatpak-builder/ccache/e/stats index 6c36f6b..97516be 100644 --- a/.flatpak-builder/ccache/e/stats +++ b/.flatpak-builder/ccache/e/stats @@ -9,8 +9,13 @@ 0 0 0 +<<<<<<< HEAD 16 100 +======= +50 +776 +>>>>>>> new-pomodoro 0 0 0 @@ -48,6 +53,7 @@ 0 0 0 +<<<<<<< HEAD 0 1 1 @@ -79,4 +85,37 @@ 4 12 0 +======= +3 +3 +3 +3 +2 +4 +3 +3 +3 +5 +2 +3 +4 +7 +2 +0 +112 +44 +36 +60 +32 +52 +28 +76 +28 +92 +16 +36 +48 +72 +44 +>>>>>>> new-pomodoro 0 diff --git a/.flatpak-builder/ccache/f/0/4b0crvon5bi8v8ms55or04vao9k7icoM b/.flatpak-builder/ccache/f/0/4b0crvon5bi8v8ms55or04vao9k7icoM new file mode 100644 index 0000000..948ff1b Binary files /dev/null and b/.flatpak-builder/ccache/f/0/4b0crvon5bi8v8ms55or04vao9k7icoM differ diff --git a/.flatpak-builder/ccache/f/0/afq4ct27q0f3a6bsgpqd59k56vfootoR b/.flatpak-builder/ccache/f/0/afq4ct27q0f3a6bsgpqd59k56vfootoR new file mode 100644 index 0000000..3941eea Binary files /dev/null and b/.flatpak-builder/ccache/f/0/afq4ct27q0f3a6bsgpqd59k56vfootoR differ diff --git a/.flatpak-builder/ccache/f/0/c1325j749e2o9bk48rpn1h8ockuurb2R b/.flatpak-builder/ccache/f/0/c1325j749e2o9bk48rpn1h8ockuurb2R new file mode 100644 index 0000000..15b9b0f Binary files /dev/null and b/.flatpak-builder/ccache/f/0/c1325j749e2o9bk48rpn1h8ockuurb2R differ diff --git a/.flatpak-builder/ccache/f/0/c8v8ujvsrpeg4gl878g3nnigqa3cj2uM b/.flatpak-builder/ccache/f/0/c8v8ujvsrpeg4gl878g3nnigqa3cj2uM new file mode 100644 index 0000000..6da8fc0 Binary files /dev/null and b/.flatpak-builder/ccache/f/0/c8v8ujvsrpeg4gl878g3nnigqa3cj2uM differ diff --git a/.flatpak-builder/ccache/f/0/ddq0arvdfm3as86odmlu6hgmr29s818R b/.flatpak-builder/ccache/f/0/ddq0arvdfm3as86odmlu6hgmr29s818R new file mode 100644 index 0000000..53273ae Binary files /dev/null and b/.flatpak-builder/ccache/f/0/ddq0arvdfm3as86odmlu6hgmr29s818R differ diff --git a/.flatpak-builder/ccache/f/0/stats b/.flatpak-builder/ccache/f/0/stats new file mode 100644 index 0000000..70e6c98 --- /dev/null +++ b/.flatpak-builder/ccache/f/0/stats @@ -0,0 +1,82 @@ +0 +0 +0 +0 +0 +0 +0 +0 +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +1 +0 +1 +1 +0 +0 +0 +0 +0 +0 +1 +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 diff --git a/.flatpak-builder/ccache/f/1/c2n7q2vjpu6ciegdnnn8u93cqhn7jekM b/.flatpak-builder/ccache/f/1/c2n7q2vjpu6ciegdnnn8u93cqhn7jekM new file mode 100644 index 0000000..fc18a0d Binary files /dev/null and b/.flatpak-builder/ccache/f/1/c2n7q2vjpu6ciegdnnn8u93cqhn7jekM differ diff --git a/.flatpak-builder/ccache/f/1/stats b/.flatpak-builder/ccache/f/1/stats new file mode 100644 index 0000000..70e6c98 --- /dev/null +++ b/.flatpak-builder/ccache/f/1/stats @@ -0,0 +1,82 @@ +0 +0 +0 +0 +0 +0 +0 +0 +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +1 +0 +1 +1 +0 +0 +0 +0 +0 +0 +1 +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 diff --git a/.flatpak-builder/ccache/f/2/7dljubpmnh9l43rfupis7hmobs4jb7sM b/.flatpak-builder/ccache/f/2/7dljubpmnh9l43rfupis7hmobs4jb7sM new file mode 100644 index 0000000..58e2bec Binary files /dev/null and b/.flatpak-builder/ccache/f/2/7dljubpmnh9l43rfupis7hmobs4jb7sM differ diff --git a/.flatpak-builder/ccache/f/2/stats b/.flatpak-builder/ccache/f/2/stats index fdb1454..2694cb6 100644 --- a/.flatpak-builder/ccache/f/2/stats +++ b/.flatpak-builder/ccache/f/2/stats @@ -2,6 +2,7 @@ 0 0 0 +<<<<<<< HEAD 2 0 0 @@ -9,11 +10,18 @@ 0 0 0 +======= +3 +>>>>>>> new-pomodoro 0 0 0 0 0 +<<<<<<< HEAD +======= +1 +>>>>>>> new-pomodoro 0 0 0 @@ -32,18 +40,35 @@ 0 0 2 +<<<<<<< HEAD 2 0 4 +======= 0 0 0 0 +3 +3 0 +6 +>>>>>>> new-pomodoro 0 +0 +0 +0 +0 +0 +<<<<<<< HEAD 4 0 2 +======= +6 +0 +3 +>>>>>>> new-pomodoro 0 0 0 diff --git a/.flatpak-builder/ccache/f/3/37lquqtc91g0se2calrkbrpvl29r08aM b/.flatpak-builder/ccache/f/3/37lquqtc91g0se2calrkbrpvl29r08aM new file mode 100644 index 0000000..dbf6944 Binary files /dev/null and b/.flatpak-builder/ccache/f/3/37lquqtc91g0se2calrkbrpvl29r08aM differ diff --git a/.flatpak-builder/ccache/f/3/4appstu0e0a7gg7mq67l4b6qa9tvflgR b/.flatpak-builder/ccache/f/3/4appstu0e0a7gg7mq67l4b6qa9tvflgR new file mode 100644 index 0000000..f21ca0e Binary files /dev/null and b/.flatpak-builder/ccache/f/3/4appstu0e0a7gg7mq67l4b6qa9tvflgR differ diff --git a/.flatpak-builder/ccache/f/3/72023c431cu9dnur6bmseuoar2b8pj8M b/.flatpak-builder/ccache/f/3/72023c431cu9dnur6bmseuoar2b8pj8M new file mode 100644 index 0000000..6666eef Binary files /dev/null and b/.flatpak-builder/ccache/f/3/72023c431cu9dnur6bmseuoar2b8pj8M differ diff --git a/.flatpak-builder/ccache/f/3/stats b/.flatpak-builder/ccache/f/3/stats index 68c5368..0d6a887 100644 --- a/.flatpak-builder/ccache/f/3/stats +++ b/.flatpak-builder/ccache/f/3/stats @@ -6,6 +6,13 @@ 0 0 0 +<<<<<<< HEAD +======= +1 +0 +0 +0 +>>>>>>> new-pomodoro 0 0 0 @@ -27,6 +34,7 @@ 0 0 0 +<<<<<<< HEAD 0 0 0 @@ -43,6 +51,20 @@ 0 2 0 +======= +2 +1 +1 +3 +0 +0 +0 +0 +0 +0 +3 +1 +>>>>>>> new-pomodoro 1 0 0 diff --git a/.flatpak-builder/ccache/f/4/bf7hb304taargc4b9cldvg2j1be0mkmM b/.flatpak-builder/ccache/f/4/bf7hb304taargc4b9cldvg2j1be0mkmM new file mode 100644 index 0000000..12396bf Binary files /dev/null and b/.flatpak-builder/ccache/f/4/bf7hb304taargc4b9cldvg2j1be0mkmM differ diff --git a/.flatpak-builder/ccache/f/4/cc8kqhhnbn7q4km9tbjas50kr3ukud6M b/.flatpak-builder/ccache/f/4/cc8kqhhnbn7q4km9tbjas50kr3ukud6M new file mode 100644 index 0000000..a1b2742 Binary files /dev/null and b/.flatpak-builder/ccache/f/4/cc8kqhhnbn7q4km9tbjas50kr3ukud6M differ diff --git a/.flatpak-builder/ccache/f/4/stats b/.flatpak-builder/ccache/f/4/stats index 68c5368..99b3a7d 100644 --- a/.flatpak-builder/ccache/f/4/stats +++ b/.flatpak-builder/ccache/f/4/stats @@ -2,6 +2,7 @@ 0 0 0 +<<<<<<< HEAD 1 0 0 @@ -34,6 +35,8 @@ 1 1 0 +======= +>>>>>>> new-pomodoro 2 0 0 @@ -41,7 +44,20 @@ 0 0 0 +<<<<<<< HEAD 2 +======= +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +>>>>>>> new-pomodoro 0 1 0 @@ -54,6 +70,32 @@ 0 0 0 +<<<<<<< HEAD +======= +2 +2 +2 +4 +0 +0 +0 +0 +0 +0 +4 +1 +2 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +>>>>>>> new-pomodoro 0 0 0 diff --git a/.flatpak-builder/ccache/f/5/8b1s2t4p31ufi1hb0mv2itnjsqdt328M b/.flatpak-builder/ccache/f/5/8b1s2t4p31ufi1hb0mv2itnjsqdt328M new file mode 100644 index 0000000..a1ef0a8 Binary files /dev/null and b/.flatpak-builder/ccache/f/5/8b1s2t4p31ufi1hb0mv2itnjsqdt328M differ diff --git a/.flatpak-builder/ccache/f/5/stats b/.flatpak-builder/ccache/f/5/stats new file mode 100644 index 0000000..f2a3552 --- /dev/null +++ b/.flatpak-builder/ccache/f/5/stats @@ -0,0 +1,82 @@ +0 +0 +0 +0 +1 +0 +0 +0 +0 +0 +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +4 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +1 +1 +8 +2 +0 +0 +0 +0 +0 +0 +2 +4 +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 diff --git a/.flatpak-builder/ccache/f/6/037nd2d939ps9cc8uscsbldrvjih1noR b/.flatpak-builder/ccache/f/6/037nd2d939ps9cc8uscsbldrvjih1noR new file mode 100644 index 0000000..cbc9a03 Binary files /dev/null and b/.flatpak-builder/ccache/f/6/037nd2d939ps9cc8uscsbldrvjih1noR differ diff --git a/.flatpak-builder/ccache/f/6/2fs057rnnfq4onrlkrp8j14sajj9rb8M b/.flatpak-builder/ccache/f/6/2fs057rnnfq4onrlkrp8j14sajj9rb8M new file mode 100644 index 0000000..5d22fb2 Binary files /dev/null and b/.flatpak-builder/ccache/f/6/2fs057rnnfq4onrlkrp8j14sajj9rb8M differ diff --git a/.flatpak-builder/ccache/f/6/390bjjdqa0jpqhsl17v3h24o3ifcufoM b/.flatpak-builder/ccache/f/6/390bjjdqa0jpqhsl17v3h24o3ifcufoM new file mode 100644 index 0000000..164882d Binary files /dev/null and b/.flatpak-builder/ccache/f/6/390bjjdqa0jpqhsl17v3h24o3ifcufoM differ diff --git a/.flatpak-builder/ccache/f/6/56sv098l2mtlet2e9jn92f3tqgofv3cM b/.flatpak-builder/ccache/f/6/56sv098l2mtlet2e9jn92f3tqgofv3cM new file mode 100644 index 0000000..f65c29e Binary files /dev/null and b/.flatpak-builder/ccache/f/6/56sv098l2mtlet2e9jn92f3tqgofv3cM differ diff --git a/.flatpak-builder/ccache/f/6/stats b/.flatpak-builder/ccache/f/6/stats index 68c5368..c5111a7 100644 --- a/.flatpak-builder/ccache/f/6/stats +++ b/.flatpak-builder/ccache/f/6/stats @@ -2,6 +2,7 @@ 0 0 0 +<<<<<<< HEAD 1 0 0 @@ -34,6 +35,8 @@ 1 1 0 +======= +>>>>>>> new-pomodoro 2 0 0 @@ -41,9 +44,47 @@ 0 0 0 +<<<<<<< HEAD 2 0 1 +======= +0 +0 +0 +0 +0 +0 +2 +0 +4 +0 +0 +4 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +2 +2 +8 +4 +0 +0 +0 +0 +0 +0 +4 +4 +2 +>>>>>>> new-pomodoro 0 0 0 diff --git a/.flatpak-builder/ccache/f/7/cbj4evuicgfcn246fdpp9h5ns32seaoR b/.flatpak-builder/ccache/f/7/cbj4evuicgfcn246fdpp9h5ns32seaoR new file mode 100644 index 0000000..6d9234f Binary files /dev/null and b/.flatpak-builder/ccache/f/7/cbj4evuicgfcn246fdpp9h5ns32seaoR differ diff --git a/.flatpak-builder/ccache/f/7/stats b/.flatpak-builder/ccache/f/7/stats new file mode 100644 index 0000000..cd47901 --- /dev/null +++ b/.flatpak-builder/ccache/f/7/stats @@ -0,0 +1,82 @@ +0 +0 +0 +0 +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +1 +0 +0 +0 +0 +0 +0 +0 +0 +1 +0 +0 +0 +0 +1 +1 +0 +2 +0 +0 +0 +0 +0 +0 +2 +0 +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 diff --git a/.flatpak-builder/ccache/f/8/b178g1b8v0pgp8nhq8v176f4dkksdl0M b/.flatpak-builder/ccache/f/8/b178g1b8v0pgp8nhq8v176f4dkksdl0M new file mode 100644 index 0000000..d64bd87 Binary files /dev/null and b/.flatpak-builder/ccache/f/8/b178g1b8v0pgp8nhq8v176f4dkksdl0M differ diff --git a/.flatpak-builder/ccache/f/8/stats b/.flatpak-builder/ccache/f/8/stats index 7be146c..31c92ad 100644 --- a/.flatpak-builder/ccache/f/8/stats +++ b/.flatpak-builder/ccache/f/8/stats @@ -6,9 +6,15 @@ 0 0 0 +<<<<<<< HEAD 0 0 0 +======= +2 +0 +1 +>>>>>>> new-pomodoro 0 0 0 @@ -31,18 +37,33 @@ 0 0 0 +<<<<<<< HEAD +0 +0 +0 +0 +0 +0 +0 0 0 0 0 0 +======= +2 0 +2 +2 0 0 0 0 0 0 +2 +2 +>>>>>>> new-pomodoro 0 0 0 diff --git a/.flatpak-builder/ccache/f/9/03c2pf31s5aajop5rdlq9g3ngmhfbukM b/.flatpak-builder/ccache/f/9/03c2pf31s5aajop5rdlq9g3ngmhfbukM new file mode 100644 index 0000000..879f046 Binary files /dev/null and b/.flatpak-builder/ccache/f/9/03c2pf31s5aajop5rdlq9g3ngmhfbukM differ diff --git a/.flatpak-builder/ccache/f/9/41fuv5s257iks30f20di88osnrh2166R b/.flatpak-builder/ccache/f/9/41fuv5s257iks30f20di88osnrh2166R new file mode 100644 index 0000000..cd45973 Binary files /dev/null and b/.flatpak-builder/ccache/f/9/41fuv5s257iks30f20di88osnrh2166R differ diff --git a/.flatpak-builder/ccache/f/9/54anbus0863qc86g5m86st25fr6t184M b/.flatpak-builder/ccache/f/9/54anbus0863qc86g5m86st25fr6t184M new file mode 100644 index 0000000..4aa703c Binary files /dev/null and b/.flatpak-builder/ccache/f/9/54anbus0863qc86g5m86st25fr6t184M differ diff --git a/.flatpak-builder/ccache/f/9/5c7rg7to4vh7tusqm1prj4mt0n044ueR b/.flatpak-builder/ccache/f/9/5c7rg7to4vh7tusqm1prj4mt0n044ueR new file mode 100644 index 0000000..5ee4ec4 Binary files /dev/null and b/.flatpak-builder/ccache/f/9/5c7rg7to4vh7tusqm1prj4mt0n044ueR differ diff --git a/.flatpak-builder/ccache/f/9/9affe55v1v7rjqiktof4kcfsnnr0956R b/.flatpak-builder/ccache/f/9/9affe55v1v7rjqiktof4kcfsnnr0956R new file mode 100644 index 0000000..533830a Binary files /dev/null and b/.flatpak-builder/ccache/f/9/9affe55v1v7rjqiktof4kcfsnnr0956R differ diff --git a/.flatpak-builder/ccache/f/9/afo5f0lht3pq652bf5g3l7m8rd2m4hqM b/.flatpak-builder/ccache/f/9/afo5f0lht3pq652bf5g3l7m8rd2m4hqM new file mode 100644 index 0000000..dee2599 Binary files /dev/null and b/.flatpak-builder/ccache/f/9/afo5f0lht3pq652bf5g3l7m8rd2m4hqM differ diff --git a/.flatpak-builder/ccache/f/9/e0gku1a1o85r8nhvhe68ca1knaoniikR b/.flatpak-builder/ccache/f/9/e0gku1a1o85r8nhvhe68ca1knaoniikR new file mode 100644 index 0000000..00efda8 Binary files /dev/null and b/.flatpak-builder/ccache/f/9/e0gku1a1o85r8nhvhe68ca1knaoniikR differ diff --git a/.flatpak-builder/ccache/f/9/stats b/.flatpak-builder/ccache/f/9/stats new file mode 100644 index 0000000..7b36bb9 --- /dev/null +++ b/.flatpak-builder/ccache/f/9/stats @@ -0,0 +1,82 @@ +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +2 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 diff --git a/.flatpak-builder/ccache/f/CACHEDIR.TAG b/.flatpak-builder/ccache/f/CACHEDIR.TAG new file mode 100644 index 0000000..874477f --- /dev/null +++ b/.flatpak-builder/ccache/f/CACHEDIR.TAG @@ -0,0 +1,4 @@ +Signature: 8a477f597d28d172789f06886806bc55 +# This file is a cache directory tag created by ccache. +# For information about cache directory tags, see: +# http://www.brynosaurus.com/cachedir/ diff --git a/.flatpak-builder/ccache/f/a/767kovrq0aplva3a49ktant02cb4nf0R b/.flatpak-builder/ccache/f/a/767kovrq0aplva3a49ktant02cb4nf0R new file mode 100644 index 0000000..219887f Binary files /dev/null and b/.flatpak-builder/ccache/f/a/767kovrq0aplva3a49ktant02cb4nf0R differ diff --git a/.flatpak-builder/ccache/f/a/stats b/.flatpak-builder/ccache/f/a/stats index fdb1454..3f6b574 100644 --- a/.flatpak-builder/ccache/f/a/stats +++ b/.flatpak-builder/ccache/f/a/stats @@ -2,7 +2,11 @@ 0 0 0 +<<<<<<< HEAD 2 +======= +3 +>>>>>>> new-pomodoro 0 0 0 @@ -20,6 +24,7 @@ 0 0 0 +<<<<<<< HEAD 0 0 0 @@ -34,6 +39,8 @@ 2 2 0 +======= +>>>>>>> new-pomodoro 4 0 0 @@ -41,9 +48,29 @@ 0 0 0 +<<<<<<< HEAD 4 0 2 +======= +0 +0 +0 +0 +3 +3 +8 +6 +0 +0 +0 +0 +0 +0 +6 +4 +3 +>>>>>>> new-pomodoro 0 0 0 diff --git a/.flatpak-builder/ccache/f/b/520b3dbhe7vg99ackrcvrad5j8m23seR b/.flatpak-builder/ccache/f/b/520b3dbhe7vg99ackrcvrad5j8m23seR new file mode 100644 index 0000000..d702e93 Binary files /dev/null and b/.flatpak-builder/ccache/f/b/520b3dbhe7vg99ackrcvrad5j8m23seR differ diff --git a/.flatpak-builder/ccache/f/b/stats b/.flatpak-builder/ccache/f/b/stats new file mode 100644 index 0000000..6d993c7 --- /dev/null +++ b/.flatpak-builder/ccache/f/b/stats @@ -0,0 +1,82 @@ +0 +0 +0 +0 +0 +0 +0 +0 +1 +0 +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +2 +0 +0 +0 +0 +1 +0 +1 +1 +0 +0 +0 +0 +0 +0 +1 +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 diff --git a/.flatpak-builder/ccache/f/c/6cc2cesg0ba0de0gemnl86n815rbpnsR b/.flatpak-builder/ccache/f/c/6cc2cesg0ba0de0gemnl86n815rbpnsR new file mode 100644 index 0000000..4b8c104 Binary files /dev/null and b/.flatpak-builder/ccache/f/c/6cc2cesg0ba0de0gemnl86n815rbpnsR differ diff --git a/.flatpak-builder/ccache/f/c/bdq3anhd52e0jfj3bt5b67g09k4sovkR b/.flatpak-builder/ccache/f/c/bdq3anhd52e0jfj3bt5b67g09k4sovkR new file mode 100644 index 0000000..a03e97f Binary files /dev/null and b/.flatpak-builder/ccache/f/c/bdq3anhd52e0jfj3bt5b67g09k4sovkR differ diff --git a/.flatpak-builder/ccache/f/c/stats b/.flatpak-builder/ccache/f/c/stats new file mode 100644 index 0000000..a508c75 --- /dev/null +++ b/.flatpak-builder/ccache/f/c/stats @@ -0,0 +1,82 @@ +0 +0 +0 +0 +1 +0 +0 +0 +0 +0 +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +2 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +1 +1 +4 +2 +0 +0 +0 +0 +0 +0 +2 +2 +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 diff --git a/.flatpak-builder/ccache/f/d/9ekjniplc796r4obhs661pst94p7f8uR b/.flatpak-builder/ccache/f/d/9ekjniplc796r4obhs661pst94p7f8uR new file mode 100644 index 0000000..ce15801 Binary files /dev/null and b/.flatpak-builder/ccache/f/d/9ekjniplc796r4obhs661pst94p7f8uR differ diff --git a/.flatpak-builder/ccache/f/d/bf95b70qhidmn6l0puccibjq754ssn8M b/.flatpak-builder/ccache/f/d/bf95b70qhidmn6l0puccibjq754ssn8M new file mode 100644 index 0000000..f3c0210 Binary files /dev/null and b/.flatpak-builder/ccache/f/d/bf95b70qhidmn6l0puccibjq754ssn8M differ diff --git a/.flatpak-builder/ccache/f/d/stats b/.flatpak-builder/ccache/f/d/stats index 585a67d..38662e3 100644 --- a/.flatpak-builder/ccache/f/d/stats +++ b/.flatpak-builder/ccache/f/d/stats @@ -2,6 +2,27 @@ 0 1 0 +<<<<<<< HEAD +======= +2 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +>>>>>>> new-pomodoro 1 0 0 @@ -13,6 +34,7 @@ 0 0 0 +<<<<<<< HEAD 0 0 0 @@ -45,6 +67,22 @@ 0 1 0 +======= +3 +3 +2 +6 +0 +0 +0 +0 +0 +0 +4 +1 +2 +0 +>>>>>>> new-pomodoro 0 0 0 diff --git a/.flatpak-builder/ccache/f/e/b7qt2oc48tm3rd86q4dd1cp02rbcfb0M b/.flatpak-builder/ccache/f/e/b7qt2oc48tm3rd86q4dd1cp02rbcfb0M new file mode 100644 index 0000000..e36ceb9 Binary files /dev/null and b/.flatpak-builder/ccache/f/e/b7qt2oc48tm3rd86q4dd1cp02rbcfb0M differ diff --git a/.flatpak-builder/ccache/f/e/f9od7hckr9dgl5s705sad9riq5u9j78M b/.flatpak-builder/ccache/f/e/f9od7hckr9dgl5s705sad9riq5u9j78M new file mode 100644 index 0000000..bd0eb97 Binary files /dev/null and b/.flatpak-builder/ccache/f/e/f9od7hckr9dgl5s705sad9riq5u9j78M differ diff --git a/.flatpak-builder/ccache/f/e/stats b/.flatpak-builder/ccache/f/e/stats index 159047e..7110411 100644 --- a/.flatpak-builder/ccache/f/e/stats +++ b/.flatpak-builder/ccache/f/e/stats @@ -2,11 +2,19 @@ 0 0 0 +<<<<<<< HEAD 0 0 0 0 0 +======= +2 +0 +0 +0 +2 +>>>>>>> new-pomodoro 0 0 0 @@ -20,6 +28,23 @@ 1 0 0 +<<<<<<< HEAD +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 0 0 0 @@ -28,6 +53,8 @@ 0 0 0 +======= +2 0 0 0 @@ -38,12 +65,20 @@ 0 0 0 +4 +2 +6 +6 0 0 0 0 0 0 +6 +4 +2 +>>>>>>> new-pomodoro 0 0 0 diff --git a/.flatpak-builder/ccache/f/f/46uug8tsf2f7p0housl5visg0to36iiM b/.flatpak-builder/ccache/f/f/46uug8tsf2f7p0housl5visg0to36iiM new file mode 100644 index 0000000..820a18b Binary files /dev/null and b/.flatpak-builder/ccache/f/f/46uug8tsf2f7p0housl5visg0to36iiM differ diff --git a/.flatpak-builder/ccache/f/f/stats b/.flatpak-builder/ccache/f/f/stats new file mode 100644 index 0000000..5203da7 --- /dev/null +++ b/.flatpak-builder/ccache/f/f/stats @@ -0,0 +1,82 @@ +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 diff --git a/.flatpak-builder/ccache/f/stats b/.flatpak-builder/ccache/f/stats index fc8ed96..6c5c017 100644 --- a/.flatpak-builder/ccache/f/stats +++ b/.flatpak-builder/ccache/f/stats @@ -9,6 +9,7 @@ 0 0 0 +<<<<<<< HEAD 25 156 0 @@ -80,3 +81,76 @@ 8 0 0 +======= +59 +964 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +8 +3 +3 +6 +2 +2 +4 +2 +2 +10 +3 +3 +3 +3 +4 +1 +156 +28 +56 +128 +40 +16 +116 +40 +16 +152 +24 +48 +36 +56 +32 +20 +0 +>>>>>>> new-pomodoro diff --git a/.flatpak-builder/checksums/x86_64-io.gitlab.idevecore.Pomodoro.json b/.flatpak-builder/checksums/x86_64-io.gitlab.idevecore.Pomodoro.json index 2b3cc5b..a53e3fb 100644 --- a/.flatpak-builder/checksums/x86_64-io.gitlab.idevecore.Pomodoro.json +++ b/.flatpak-builder/checksums/x86_64-io.gitlab.idevecore.Pomodoro.json @@ -1 +1,5 @@ -bf4996536a574fa8336319e4f18f6204bb50d576ba9be56f2faaead9c8ff61ff \ No newline at end of file +<<<<<<< HEAD +bf4996536a574fa8336319e4f18f6204bb50d576ba9be56f2faaead9c8ff61ff +======= +adc280bda4a9482148b47e7355599666ac0d68f5ba5a85870f65d95df5e50d2b +>>>>>>> new-pomodoro diff --git a/.flatpak-builder/checksums/x86_64-io.gitlab.idevecore.PomodoroDevel.json b/.flatpak-builder/checksums/x86_64-io.gitlab.idevecore.PomodoroDevel.json new file mode 100644 index 0000000..de78ec8 --- /dev/null +++ b/.flatpak-builder/checksums/x86_64-io.gitlab.idevecore.PomodoroDevel.json @@ -0,0 +1 @@ +ed4761e07ef72c5d9ebe303e72160cbeeac201b96ea43e161422db32bb345eaa \ No newline at end of file diff --git a/.flatpak-builder/downloads/67c74d94196b153b774ab9f89b2fa6c6ba79352407037c8c14d5aeb334e959cd/intltool-0.51.0.tar.gz b/.flatpak-builder/downloads/67c74d94196b153b774ab9f89b2fa6c6ba79352407037c8c14d5aeb334e959cd/intltool-0.51.0.tar.gz new file mode 100644 index 0000000..8886050 Binary files /dev/null and b/.flatpak-builder/downloads/67c74d94196b153b774ab9f89b2fa6c6ba79352407037c8c14d5aeb334e959cd/intltool-0.51.0.tar.gz differ diff --git a/.flatpak-builder/downloads/c2b671e67e0c288a69fc33dc1b6f1b534d07882c2aceed37004bf48c601afa72/.goutputstream-OQHF81 b/.flatpak-builder/downloads/c2b671e67e0c288a69fc33dc1b6f1b534d07882c2aceed37004bf48c601afa72/.goutputstream-OQHF81 new file mode 100644 index 0000000..7244f8c Binary files /dev/null and b/.flatpak-builder/downloads/c2b671e67e0c288a69fc33dc1b6f1b534d07882c2aceed37004bf48c601afa72/.goutputstream-OQHF81 differ diff --git a/.flatpak-builder/downloads/c2b671e67e0c288a69fc33dc1b6f1b534d07882c2aceed37004bf48c601afa72/.libcanberra-0.30.tar.xz0VHF81 b/.flatpak-builder/downloads/c2b671e67e0c288a69fc33dc1b6f1b534d07882c2aceed37004bf48c601afa72/.libcanberra-0.30.tar.xz0VHF81 new file mode 100644 index 0000000..e69de29 diff --git a/.flatpak-builder/downloads/c2b671e67e0c288a69fc33dc1b6f1b534d07882c2aceed37004bf48c601afa72/libcanberra-0.30.tar.xz b/.flatpak-builder/downloads/c2b671e67e0c288a69fc33dc1b6f1b534d07882c2aceed37004bf48c601afa72/libcanberra-0.30.tar.xz new file mode 100644 index 0000000..b9d5d0d Binary files /dev/null and b/.flatpak-builder/downloads/c2b671e67e0c288a69fc33dc1b6f1b534d07882c2aceed37004bf48c601afa72/libcanberra-0.30.tar.xz differ diff --git a/.flatpak-builder/downloads/cb518b20eef05ec2e82dda1fa89a292c1760dc023aba91b8aa69bafac85e8a14/sound-theme-freedesktop-0.8.tar.bz2 b/.flatpak-builder/downloads/cb518b20eef05ec2e82dda1fa89a292c1760dc023aba91b8aa69bafac85e8a14/sound-theme-freedesktop-0.8.tar.bz2 new file mode 100644 index 0000000..313e466 Binary files /dev/null and b/.flatpak-builder/downloads/cb518b20eef05ec2e82dda1fa89a292c1760dc023aba91b8aa69bafac85e8a14/sound-theme-freedesktop-0.8.tar.bz2 differ diff --git a/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_gsound.git/FETCH_HEAD b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_gsound.git/FETCH_HEAD new file mode 100644 index 0000000..18bd8bf --- /dev/null +++ b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_gsound.git/FETCH_HEAD @@ -0,0 +1,2 @@ +95d36d60cf53e0e7c5d5325e0f1f4fc765a611ae branch 'master' of https://gitlab.gnome.org/GNOME/gsound +258de1316d7aad9dfc3ec1369d607852d3e0b2b7 not-for-merge tag '1.0.3' of https://gitlab.gnome.org/GNOME/gsound diff --git a/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_gsound.git/HEAD b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_gsound.git/HEAD new file mode 100644 index 0000000..cb089cd --- /dev/null +++ b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_gsound.git/HEAD @@ -0,0 +1 @@ +ref: refs/heads/master diff --git a/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_gsound.git/config b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_gsound.git/config new file mode 100644 index 0000000..ee8801d --- /dev/null +++ b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_gsound.git/config @@ -0,0 +1,9 @@ +[core] + repositoryformatversion = 0 + filemode = true + bare = true +[remote "origin"] + url = https://gitlab.gnome.org/GNOME/gsound.git + fetch = +refs/*:refs/* +[transfer] + fsckObjects = 1 diff --git a/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_gsound.git/description b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_gsound.git/description new file mode 100644 index 0000000..498b267 --- /dev/null +++ b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_gsound.git/description @@ -0,0 +1 @@ +Unnamed repository; edit this file 'description' to name the repository. diff --git a/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_gsound.git/hooks/applypatch-msg.sample b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_gsound.git/hooks/applypatch-msg.sample new file mode 100755 index 0000000..a5d7b84 --- /dev/null +++ b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_gsound.git/hooks/applypatch-msg.sample @@ -0,0 +1,15 @@ +#!/bin/sh +# +# An example hook script to check the commit log message taken by +# applypatch from an e-mail message. +# +# The hook should exit with non-zero status after issuing an +# appropriate message if it wants to stop the commit. The hook is +# allowed to edit the commit message file. +# +# To enable this hook, rename this file to "applypatch-msg". + +. git-sh-setup +commitmsg="$(git rev-parse --git-path hooks/commit-msg)" +test -x "$commitmsg" && exec "$commitmsg" ${1+"$@"} +: diff --git a/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_gsound.git/hooks/commit-msg.sample b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_gsound.git/hooks/commit-msg.sample new file mode 100755 index 0000000..b58d118 --- /dev/null +++ b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_gsound.git/hooks/commit-msg.sample @@ -0,0 +1,24 @@ +#!/bin/sh +# +# An example hook script to check the commit log message. +# Called by "git commit" with one argument, the name of the file +# that has the commit message. The hook should exit with non-zero +# status after issuing an appropriate message if it wants to stop the +# commit. The hook is allowed to edit the commit message file. +# +# To enable this hook, rename this file to "commit-msg". + +# Uncomment the below to add a Signed-off-by line to the message. +# Doing this in a hook is a bad idea in general, but the prepare-commit-msg +# hook is more suited to it. +# +# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p') +# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1" + +# This example catches duplicate Signed-off-by lines. + +test "" = "$(grep '^Signed-off-by: ' "$1" | + sort | uniq -c | sed -e '/^[ ]*1[ ]/d')" || { + echo >&2 Duplicate Signed-off-by lines. + exit 1 +} diff --git a/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_gsound.git/hooks/fsmonitor-watchman.sample b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_gsound.git/hooks/fsmonitor-watchman.sample new file mode 100755 index 0000000..23e856f --- /dev/null +++ b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_gsound.git/hooks/fsmonitor-watchman.sample @@ -0,0 +1,174 @@ +#!/usr/bin/perl + +use strict; +use warnings; +use IPC::Open2; + +# An example hook script to integrate Watchman +# (https://facebook.github.io/watchman/) with git to speed up detecting +# new and modified files. +# +# The hook is passed a version (currently 2) and last update token +# formatted as a string and outputs to stdout a new update token and +# all files that have been modified since the update token. Paths must +# be relative to the root of the working tree and separated by a single NUL. +# +# To enable this hook, rename this file to "query-watchman" and set +# 'git config core.fsmonitor .git/hooks/query-watchman' +# +my ($version, $last_update_token) = @ARGV; + +# Uncomment for debugging +# print STDERR "$0 $version $last_update_token\n"; + +# Check the hook interface version +if ($version ne 2) { + die "Unsupported query-fsmonitor hook version '$version'.\n" . + "Falling back to scanning...\n"; +} + +my $git_work_tree = get_working_dir(); + +my $retry = 1; + +my $json_pkg; +eval { + require JSON::XS; + $json_pkg = "JSON::XS"; + 1; +} or do { + require JSON::PP; + $json_pkg = "JSON::PP"; +}; + +launch_watchman(); + +sub launch_watchman { + my $o = watchman_query(); + if (is_work_tree_watched($o)) { + output_result($o->{clock}, @{$o->{files}}); + } +} + +sub output_result { + my ($clockid, @files) = @_; + + # Uncomment for debugging watchman output + # open (my $fh, ">", ".git/watchman-output.out"); + # binmode $fh, ":utf8"; + # print $fh "$clockid\n@files\n"; + # close $fh; + + binmode STDOUT, ":utf8"; + print $clockid; + print "\0"; + local $, = "\0"; + print @files; +} + +sub watchman_clock { + my $response = qx/watchman clock "$git_work_tree"/; + die "Failed to get clock id on '$git_work_tree'.\n" . + "Falling back to scanning...\n" if $? != 0; + + return $json_pkg->new->utf8->decode($response); +} + +sub watchman_query { + my $pid = open2(\*CHLD_OUT, \*CHLD_IN, 'watchman -j --no-pretty') + or die "open2() failed: $!\n" . + "Falling back to scanning...\n"; + + # In the query expression below we're asking for names of files that + # changed since $last_update_token but not from the .git folder. + # + # To accomplish this, we're using the "since" generator to use the + # recency index to select candidate nodes and "fields" to limit the + # output to file names only. Then we're using the "expression" term to + # further constrain the results. + my $last_update_line = ""; + if (substr($last_update_token, 0, 1) eq "c") { + $last_update_token = "\"$last_update_token\""; + $last_update_line = qq[\n"since": $last_update_token,]; + } + my $query = <<" END"; + ["query", "$git_work_tree", {$last_update_line + "fields": ["name"], + "expression": ["not", ["dirname", ".git"]] + }] + END + + # Uncomment for debugging the watchman query + # open (my $fh, ">", ".git/watchman-query.json"); + # print $fh $query; + # close $fh; + + print CHLD_IN $query; + close CHLD_IN; + my $response = do {local $/; }; + + # Uncomment for debugging the watch response + # open ($fh, ">", ".git/watchman-response.json"); + # print $fh $response; + # close $fh; + + die "Watchman: command returned no output.\n" . + "Falling back to scanning...\n" if $response eq ""; + die "Watchman: command returned invalid output: $response\n" . + "Falling back to scanning...\n" unless $response =~ /^\{/; + + return $json_pkg->new->utf8->decode($response); +} + +sub is_work_tree_watched { + my ($output) = @_; + my $error = $output->{error}; + if ($retry > 0 and $error and $error =~ m/unable to resolve root .* directory (.*) is not watched/) { + $retry--; + my $response = qx/watchman watch "$git_work_tree"/; + die "Failed to make watchman watch '$git_work_tree'.\n" . + "Falling back to scanning...\n" if $? != 0; + $output = $json_pkg->new->utf8->decode($response); + $error = $output->{error}; + die "Watchman: $error.\n" . + "Falling back to scanning...\n" if $error; + + # Uncomment for debugging watchman output + # open (my $fh, ">", ".git/watchman-output.out"); + # close $fh; + + # Watchman will always return all files on the first query so + # return the fast "everything is dirty" flag to git and do the + # Watchman query just to get it over with now so we won't pay + # the cost in git to look up each individual file. + my $o = watchman_clock(); + $error = $output->{error}; + + die "Watchman: $error.\n" . + "Falling back to scanning...\n" if $error; + + output_result($o->{clock}, ("/")); + $last_update_token = $o->{clock}; + + eval { launch_watchman() }; + return 0; + } + + die "Watchman: $error.\n" . + "Falling back to scanning...\n" if $error; + + return 1; +} + +sub get_working_dir { + my $working_dir; + if ($^O =~ 'msys' || $^O =~ 'cygwin') { + $working_dir = Win32::GetCwd(); + $working_dir =~ tr/\\/\//; + } else { + require Cwd; + $working_dir = Cwd::cwd(); + } + + return $working_dir; +} diff --git a/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_gsound.git/hooks/post-update.sample b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_gsound.git/hooks/post-update.sample new file mode 100755 index 0000000..ec17ec1 --- /dev/null +++ b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_gsound.git/hooks/post-update.sample @@ -0,0 +1,8 @@ +#!/bin/sh +# +# An example hook script to prepare a packed repository for use over +# dumb transports. +# +# To enable this hook, rename this file to "post-update". + +exec git update-server-info diff --git a/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_gsound.git/hooks/pre-applypatch.sample b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_gsound.git/hooks/pre-applypatch.sample new file mode 100755 index 0000000..4142082 --- /dev/null +++ b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_gsound.git/hooks/pre-applypatch.sample @@ -0,0 +1,14 @@ +#!/bin/sh +# +# An example hook script to verify what is about to be committed +# by applypatch from an e-mail message. +# +# The hook should exit with non-zero status after issuing an +# appropriate message if it wants to stop the commit. +# +# To enable this hook, rename this file to "pre-applypatch". + +. git-sh-setup +precommit="$(git rev-parse --git-path hooks/pre-commit)" +test -x "$precommit" && exec "$precommit" ${1+"$@"} +: diff --git a/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_gsound.git/hooks/pre-commit.sample b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_gsound.git/hooks/pre-commit.sample new file mode 100755 index 0000000..e144712 --- /dev/null +++ b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_gsound.git/hooks/pre-commit.sample @@ -0,0 +1,49 @@ +#!/bin/sh +# +# An example hook script to verify what is about to be committed. +# Called by "git commit" with no arguments. The hook should +# exit with non-zero status after issuing an appropriate message if +# it wants to stop the commit. +# +# To enable this hook, rename this file to "pre-commit". + +if git rev-parse --verify HEAD >/dev/null 2>&1 +then + against=HEAD +else + # Initial commit: diff against an empty tree object + against=$(git hash-object -t tree /dev/null) +fi + +# If you want to allow non-ASCII filenames set this variable to true. +allownonascii=$(git config --type=bool hooks.allownonascii) + +# Redirect output to stderr. +exec 1>&2 + +# Cross platform projects tend to avoid non-ASCII filenames; prevent +# them from being added to the repository. We exploit the fact that the +# printable range starts at the space character and ends with tilde. +if [ "$allownonascii" != "true" ] && + # Note that the use of brackets around a tr range is ok here, (it's + # even required, for portability to Solaris 10's /usr/bin/tr), since + # the square bracket bytes happen to fall in the designated range. + test $(git diff --cached --name-only --diff-filter=A -z $against | + LC_ALL=C tr -d '[ -~]\0' | wc -c) != 0 +then + cat <<\EOF +Error: Attempt to add a non-ASCII file name. + +This can cause problems if you want to work with people on other platforms. + +To be portable it is advisable to rename the file. + +If you know what you are doing you can disable this check using: + + git config hooks.allownonascii true +EOF + exit 1 +fi + +# If there are whitespace errors, print the offending file names and fail. +exec git diff-index --check --cached $against -- diff --git a/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_gsound.git/hooks/pre-merge-commit.sample b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_gsound.git/hooks/pre-merge-commit.sample new file mode 100755 index 0000000..399eab1 --- /dev/null +++ b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_gsound.git/hooks/pre-merge-commit.sample @@ -0,0 +1,13 @@ +#!/bin/sh +# +# An example hook script to verify what is about to be committed. +# Called by "git merge" with no arguments. The hook should +# exit with non-zero status after issuing an appropriate message to +# stderr if it wants to stop the merge commit. +# +# To enable this hook, rename this file to "pre-merge-commit". + +. git-sh-setup +test -x "$GIT_DIR/hooks/pre-commit" && + exec "$GIT_DIR/hooks/pre-commit" +: diff --git a/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_gsound.git/hooks/pre-push.sample b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_gsound.git/hooks/pre-push.sample new file mode 100755 index 0000000..4ce688d --- /dev/null +++ b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_gsound.git/hooks/pre-push.sample @@ -0,0 +1,53 @@ +#!/bin/sh + +# An example hook script to verify what is about to be pushed. Called by "git +# push" after it has checked the remote status, but before anything has been +# pushed. If this script exits with a non-zero status nothing will be pushed. +# +# This hook is called with the following parameters: +# +# $1 -- Name of the remote to which the push is being done +# $2 -- URL to which the push is being done +# +# If pushing without using a named remote those arguments will be equal. +# +# Information about the commits which are being pushed is supplied as lines to +# the standard input in the form: +# +# +# +# This sample shows how to prevent push of commits where the log message starts +# with "WIP" (work in progress). + +remote="$1" +url="$2" + +zero=$(git hash-object --stdin &2 "Found WIP commit in $local_ref, not pushing" + exit 1 + fi + fi +done + +exit 0 diff --git a/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_gsound.git/hooks/pre-rebase.sample b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_gsound.git/hooks/pre-rebase.sample new file mode 100755 index 0000000..6cbef5c --- /dev/null +++ b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_gsound.git/hooks/pre-rebase.sample @@ -0,0 +1,169 @@ +#!/bin/sh +# +# Copyright (c) 2006, 2008 Junio C Hamano +# +# The "pre-rebase" hook is run just before "git rebase" starts doing +# its job, and can prevent the command from running by exiting with +# non-zero status. +# +# The hook is called with the following parameters: +# +# $1 -- the upstream the series was forked from. +# $2 -- the branch being rebased (or empty when rebasing the current branch). +# +# This sample shows how to prevent topic branches that are already +# merged to 'next' branch from getting rebased, because allowing it +# would result in rebasing already published history. + +publish=next +basebranch="$1" +if test "$#" = 2 +then + topic="refs/heads/$2" +else + topic=`git symbolic-ref HEAD` || + exit 0 ;# we do not interrupt rebasing detached HEAD +fi + +case "$topic" in +refs/heads/??/*) + ;; +*) + exit 0 ;# we do not interrupt others. + ;; +esac + +# Now we are dealing with a topic branch being rebased +# on top of master. Is it OK to rebase it? + +# Does the topic really exist? +git show-ref -q "$topic" || { + echo >&2 "No such branch $topic" + exit 1 +} + +# Is topic fully merged to master? +not_in_master=`git rev-list --pretty=oneline ^master "$topic"` +if test -z "$not_in_master" +then + echo >&2 "$topic is fully merged to master; better remove it." + exit 1 ;# we could allow it, but there is no point. +fi + +# Is topic ever merged to next? If so you should not be rebasing it. +only_next_1=`git rev-list ^master "^$topic" ${publish} | sort` +only_next_2=`git rev-list ^master ${publish} | sort` +if test "$only_next_1" = "$only_next_2" +then + not_in_topic=`git rev-list "^$topic" master` + if test -z "$not_in_topic" + then + echo >&2 "$topic is already up to date with master" + exit 1 ;# we could allow it, but there is no point. + else + exit 0 + fi +else + not_in_next=`git rev-list --pretty=oneline ^${publish} "$topic"` + /usr/bin/perl -e ' + my $topic = $ARGV[0]; + my $msg = "* $topic has commits already merged to public branch:\n"; + my (%not_in_next) = map { + /^([0-9a-f]+) /; + ($1 => 1); + } split(/\n/, $ARGV[1]); + for my $elem (map { + /^([0-9a-f]+) (.*)$/; + [$1 => $2]; + } split(/\n/, $ARGV[2])) { + if (!exists $not_in_next{$elem->[0]}) { + if ($msg) { + print STDERR $msg; + undef $msg; + } + print STDERR " $elem->[1]\n"; + } + } + ' "$topic" "$not_in_next" "$not_in_master" + exit 1 +fi + +<<\DOC_END + +This sample hook safeguards topic branches that have been +published from being rewound. + +The workflow assumed here is: + + * Once a topic branch forks from "master", "master" is never + merged into it again (either directly or indirectly). + + * Once a topic branch is fully cooked and merged into "master", + it is deleted. If you need to build on top of it to correct + earlier mistakes, a new topic branch is created by forking at + the tip of the "master". This is not strictly necessary, but + it makes it easier to keep your history simple. + + * Whenever you need to test or publish your changes to topic + branches, merge them into "next" branch. + +The script, being an example, hardcodes the publish branch name +to be "next", but it is trivial to make it configurable via +$GIT_DIR/config mechanism. + +With this workflow, you would want to know: + +(1) ... if a topic branch has ever been merged to "next". Young + topic branches can have stupid mistakes you would rather + clean up before publishing, and things that have not been + merged into other branches can be easily rebased without + affecting other people. But once it is published, you would + not want to rewind it. + +(2) ... if a topic branch has been fully merged to "master". + Then you can delete it. More importantly, you should not + build on top of it -- other people may already want to + change things related to the topic as patches against your + "master", so if you need further changes, it is better to + fork the topic (perhaps with the same name) afresh from the + tip of "master". + +Let's look at this example: + + o---o---o---o---o---o---o---o---o---o "next" + / / / / + / a---a---b A / / + / / / / + / / c---c---c---c B / + / / / \ / + / / / b---b C \ / + / / / / \ / + ---o---o---o---o---o---o---o---o---o---o---o "master" + + +A, B and C are topic branches. + + * A has one fix since it was merged up to "next". + + * B has finished. It has been fully merged up to "master" and "next", + and is ready to be deleted. + + * C has not merged to "next" at all. + +We would want to allow C to be rebased, refuse A, and encourage +B to be deleted. + +To compute (1): + + git rev-list ^master ^topic next + git rev-list ^master next + + if these match, topic has not merged in next at all. + +To compute (2): + + git rev-list master..topic + + if this is empty, it is fully merged to "master". + +DOC_END diff --git a/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_gsound.git/hooks/pre-receive.sample b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_gsound.git/hooks/pre-receive.sample new file mode 100755 index 0000000..a1fd29e --- /dev/null +++ b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_gsound.git/hooks/pre-receive.sample @@ -0,0 +1,24 @@ +#!/bin/sh +# +# An example hook script to make use of push options. +# The example simply echoes all push options that start with 'echoback=' +# and rejects all pushes when the "reject" push option is used. +# +# To enable this hook, rename this file to "pre-receive". + +if test -n "$GIT_PUSH_OPTION_COUNT" +then + i=0 + while test "$i" -lt "$GIT_PUSH_OPTION_COUNT" + do + eval "value=\$GIT_PUSH_OPTION_$i" + case "$value" in + echoback=*) + echo "echo from the pre-receive-hook: ${value#*=}" >&2 + ;; + reject) + exit 1 + esac + i=$((i + 1)) + done +fi diff --git a/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_gsound.git/hooks/prepare-commit-msg.sample b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_gsound.git/hooks/prepare-commit-msg.sample new file mode 100755 index 0000000..10fa14c --- /dev/null +++ b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_gsound.git/hooks/prepare-commit-msg.sample @@ -0,0 +1,42 @@ +#!/bin/sh +# +# An example hook script to prepare the commit log message. +# Called by "git commit" with the name of the file that has the +# commit message, followed by the description of the commit +# message's source. The hook's purpose is to edit the commit +# message file. If the hook fails with a non-zero status, +# the commit is aborted. +# +# To enable this hook, rename this file to "prepare-commit-msg". + +# This hook includes three examples. The first one removes the +# "# Please enter the commit message..." help message. +# +# The second includes the output of "git diff --name-status -r" +# into the message, just before the "git status" output. It is +# commented because it doesn't cope with --amend or with squashed +# commits. +# +# The third example adds a Signed-off-by line to the message, that can +# still be edited. This is rarely a good idea. + +COMMIT_MSG_FILE=$1 +COMMIT_SOURCE=$2 +SHA1=$3 + +/usr/bin/perl -i.bak -ne 'print unless(m/^. Please enter the commit message/..m/^#$/)' "$COMMIT_MSG_FILE" + +# case "$COMMIT_SOURCE,$SHA1" in +# ,|template,) +# /usr/bin/perl -i.bak -pe ' +# print "\n" . `git diff --cached --name-status -r` +# if /^#/ && $first++ == 0' "$COMMIT_MSG_FILE" ;; +# *) ;; +# esac + +# SOB=$(git var GIT_COMMITTER_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p') +# git interpret-trailers --in-place --trailer "$SOB" "$COMMIT_MSG_FILE" +# if test -z "$COMMIT_SOURCE" +# then +# /usr/bin/perl -i.bak -pe 'print "\n" if !$first_line++' "$COMMIT_MSG_FILE" +# fi diff --git a/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_gsound.git/hooks/push-to-checkout.sample b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_gsound.git/hooks/push-to-checkout.sample new file mode 100755 index 0000000..af5a0c0 --- /dev/null +++ b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_gsound.git/hooks/push-to-checkout.sample @@ -0,0 +1,78 @@ +#!/bin/sh + +# An example hook script to update a checked-out tree on a git push. +# +# This hook is invoked by git-receive-pack(1) when it reacts to git +# push and updates reference(s) in its repository, and when the push +# tries to update the branch that is currently checked out and the +# receive.denyCurrentBranch configuration variable is set to +# updateInstead. +# +# By default, such a push is refused if the working tree and the index +# of the remote repository has any difference from the currently +# checked out commit; when both the working tree and the index match +# the current commit, they are updated to match the newly pushed tip +# of the branch. This hook is to be used to override the default +# behaviour; however the code below reimplements the default behaviour +# as a starting point for convenient modification. +# +# The hook receives the commit with which the tip of the current +# branch is going to be updated: +commit=$1 + +# It can exit with a non-zero status to refuse the push (when it does +# so, it must not modify the index or the working tree). +die () { + echo >&2 "$*" + exit 1 +} + +# Or it can make any necessary changes to the working tree and to the +# index to bring them to the desired state when the tip of the current +# branch is updated to the new commit, and exit with a zero status. +# +# For example, the hook can simply run git read-tree -u -m HEAD "$1" +# in order to emulate git fetch that is run in the reverse direction +# with git push, as the two-tree form of git read-tree -u -m is +# essentially the same as git switch or git checkout that switches +# branches while keeping the local changes in the working tree that do +# not interfere with the difference between the branches. + +# The below is a more-or-less exact translation to shell of the C code +# for the default behaviour for git's push-to-checkout hook defined in +# the push_to_deploy() function in builtin/receive-pack.c. +# +# Note that the hook will be executed from the repository directory, +# not from the working tree, so if you want to perform operations on +# the working tree, you will have to adapt your code accordingly, e.g. +# by adding "cd .." or using relative paths. + +if ! git update-index -q --ignore-submodules --refresh +then + die "Up-to-date check failed" +fi + +if ! git diff-files --quiet --ignore-submodules -- +then + die "Working directory has unstaged changes" +fi + +# This is a rough translation of: +# +# head_has_history() ? "HEAD" : EMPTY_TREE_SHA1_HEX +if git cat-file -e HEAD 2>/dev/null +then + head=HEAD +else + head=$(git hash-object -t tree --stdin &2 + exit 1 +} + +unset GIT_DIR GIT_WORK_TREE +cd "$worktree" && + +if grep -q "^diff --git " "$1" +then + validate_patch "$1" +else + validate_cover_letter "$1" +fi && + +if test "$GIT_SENDEMAIL_FILE_COUNTER" = "$GIT_SENDEMAIL_FILE_TOTAL" +then + git config --unset-all sendemail.validateWorktree && + trap 'git worktree remove -ff "$worktree"' EXIT && + validate_series +fi diff --git a/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_gsound.git/hooks/update.sample b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_gsound.git/hooks/update.sample new file mode 100755 index 0000000..c4d426b --- /dev/null +++ b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_gsound.git/hooks/update.sample @@ -0,0 +1,128 @@ +#!/bin/sh +# +# An example hook script to block unannotated tags from entering. +# Called by "git receive-pack" with arguments: refname sha1-old sha1-new +# +# To enable this hook, rename this file to "update". +# +# Config +# ------ +# hooks.allowunannotated +# This boolean sets whether unannotated tags will be allowed into the +# repository. By default they won't be. +# hooks.allowdeletetag +# This boolean sets whether deleting tags will be allowed in the +# repository. By default they won't be. +# hooks.allowmodifytag +# This boolean sets whether a tag may be modified after creation. By default +# it won't be. +# hooks.allowdeletebranch +# This boolean sets whether deleting branches will be allowed in the +# repository. By default they won't be. +# hooks.denycreatebranch +# This boolean sets whether remotely creating branches will be denied +# in the repository. By default this is allowed. +# + +# --- Command line +refname="$1" +oldrev="$2" +newrev="$3" + +# --- Safety check +if [ -z "$GIT_DIR" ]; then + echo "Don't run this script from the command line." >&2 + echo " (if you want, you could supply GIT_DIR then run" >&2 + echo " $0 )" >&2 + exit 1 +fi + +if [ -z "$refname" -o -z "$oldrev" -o -z "$newrev" ]; then + echo "usage: $0 " >&2 + exit 1 +fi + +# --- Config +allowunannotated=$(git config --type=bool hooks.allowunannotated) +allowdeletebranch=$(git config --type=bool hooks.allowdeletebranch) +denycreatebranch=$(git config --type=bool hooks.denycreatebranch) +allowdeletetag=$(git config --type=bool hooks.allowdeletetag) +allowmodifytag=$(git config --type=bool hooks.allowmodifytag) + +# check for no description +projectdesc=$(sed -e '1q' "$GIT_DIR/description") +case "$projectdesc" in +"Unnamed repository"* | "") + echo "*** Project description file hasn't been set" >&2 + exit 1 + ;; +esac + +# --- Check types +# if $newrev is 0000...0000, it's a commit to delete a ref. +zero=$(git hash-object --stdin &2 + echo "*** Use 'git tag [ -a | -s ]' for tags you want to propagate." >&2 + exit 1 + fi + ;; + refs/tags/*,delete) + # delete tag + if [ "$allowdeletetag" != "true" ]; then + echo "*** Deleting a tag is not allowed in this repository" >&2 + exit 1 + fi + ;; + refs/tags/*,tag) + # annotated tag + if [ "$allowmodifytag" != "true" ] && git rev-parse $refname > /dev/null 2>&1 + then + echo "*** Tag '$refname' already exists." >&2 + echo "*** Modifying a tag is not allowed in this repository." >&2 + exit 1 + fi + ;; + refs/heads/*,commit) + # branch + if [ "$oldrev" = "$zero" -a "$denycreatebranch" = "true" ]; then + echo "*** Creating a branch is not allowed in this repository" >&2 + exit 1 + fi + ;; + refs/heads/*,delete) + # delete branch + if [ "$allowdeletebranch" != "true" ]; then + echo "*** Deleting a branch is not allowed in this repository" >&2 + exit 1 + fi + ;; + refs/remotes/*,commit) + # tracking branch + ;; + refs/remotes/*,delete) + # delete tracking branch + if [ "$allowdeletebranch" != "true" ]; then + echo "*** Deleting a tracking branch is not allowed in this repository" >&2 + exit 1 + fi + ;; + *) + # Anything else (is there anything else?) + echo "*** Update hook: unknown type of update to ref $refname of type $newrev_type" >&2 + exit 1 + ;; +esac + +# --- Finished +exit 0 diff --git a/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_gsound.git/info/exclude b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_gsound.git/info/exclude new file mode 100644 index 0000000..a5196d1 --- /dev/null +++ b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_gsound.git/info/exclude @@ -0,0 +1,6 @@ +# git ls-files --others --exclude-from=.git/info/exclude +# Lines that start with '#' are comments. +# For a project mostly in C, the following would be a good set of +# exclude patterns (uncomment them if you want to use them): +# *.[oa] +# *~ diff --git a/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_gsound.git/objects/pack/pack-054351548b4d7e5f9035547ca12049f427439aa5.idx b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_gsound.git/objects/pack/pack-054351548b4d7e5f9035547ca12049f427439aa5.idx new file mode 100644 index 0000000..a19b37a Binary files /dev/null and b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_gsound.git/objects/pack/pack-054351548b4d7e5f9035547ca12049f427439aa5.idx differ diff --git a/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_gsound.git/objects/pack/pack-054351548b4d7e5f9035547ca12049f427439aa5.pack b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_gsound.git/objects/pack/pack-054351548b4d7e5f9035547ca12049f427439aa5.pack new file mode 100644 index 0000000..b2ec2cc Binary files /dev/null and b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_gsound.git/objects/pack/pack-054351548b4d7e5f9035547ca12049f427439aa5.pack differ diff --git a/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_gsound.git/objects/pack/pack-054351548b4d7e5f9035547ca12049f427439aa5.rev b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_gsound.git/objects/pack/pack-054351548b4d7e5f9035547ca12049f427439aa5.rev new file mode 100644 index 0000000..23cade0 Binary files /dev/null and b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_gsound.git/objects/pack/pack-054351548b4d7e5f9035547ca12049f427439aa5.rev differ diff --git a/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_gsound.git/refs/heads/master b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_gsound.git/refs/heads/master new file mode 100644 index 0000000..4a4bb76 --- /dev/null +++ b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_gsound.git/refs/heads/master @@ -0,0 +1 @@ +95d36d60cf53e0e7c5d5325e0f1f4fc765a611ae diff --git a/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_gsound.git/refs/tags/1.0.3 b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_gsound.git/refs/tags/1.0.3 new file mode 100644 index 0000000..42c3bab --- /dev/null +++ b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_gsound.git/refs/tags/1.0.3 @@ -0,0 +1 @@ +258de1316d7aad9dfc3ec1369d607852d3e0b2b7 diff --git a/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_gsound.git/shallow b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_gsound.git/shallow new file mode 100644 index 0000000..4a4bb76 --- /dev/null +++ b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_gsound.git/shallow @@ -0,0 +1 @@ +95d36d60cf53e0e7c5d5325e0f1f4fc765a611ae diff --git a/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libgda/FETCH_HEAD b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libgda/FETCH_HEAD new file mode 100644 index 0000000..0d31d50 --- /dev/null +++ b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libgda/FETCH_HEAD @@ -0,0 +1 @@ +dfd61d86d65d3522538b614bb856815da3f67ebe tag 'LIBGDA_6_0_0' of https://gitlab.gnome.org/GNOME/libgda diff --git a/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libgda/HEAD b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libgda/HEAD new file mode 100644 index 0000000..cb089cd --- /dev/null +++ b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libgda/HEAD @@ -0,0 +1 @@ +ref: refs/heads/master diff --git a/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libgda/config b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libgda/config new file mode 100644 index 0000000..e24bff7 --- /dev/null +++ b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libgda/config @@ -0,0 +1,9 @@ +[core] + repositoryformatversion = 0 + filemode = true + bare = true +[remote "origin"] + url = https://gitlab.gnome.org/GNOME/libgda + fetch = +refs/*:refs/* +[transfer] + fsckObjects = 1 diff --git a/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libgda/description b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libgda/description new file mode 100644 index 0000000..498b267 --- /dev/null +++ b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libgda/description @@ -0,0 +1 @@ +Unnamed repository; edit this file 'description' to name the repository. diff --git a/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libgda/hooks/applypatch-msg.sample b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libgda/hooks/applypatch-msg.sample new file mode 100755 index 0000000..a5d7b84 --- /dev/null +++ b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libgda/hooks/applypatch-msg.sample @@ -0,0 +1,15 @@ +#!/bin/sh +# +# An example hook script to check the commit log message taken by +# applypatch from an e-mail message. +# +# The hook should exit with non-zero status after issuing an +# appropriate message if it wants to stop the commit. The hook is +# allowed to edit the commit message file. +# +# To enable this hook, rename this file to "applypatch-msg". + +. git-sh-setup +commitmsg="$(git rev-parse --git-path hooks/commit-msg)" +test -x "$commitmsg" && exec "$commitmsg" ${1+"$@"} +: diff --git a/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libgda/hooks/commit-msg.sample b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libgda/hooks/commit-msg.sample new file mode 100755 index 0000000..b58d118 --- /dev/null +++ b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libgda/hooks/commit-msg.sample @@ -0,0 +1,24 @@ +#!/bin/sh +# +# An example hook script to check the commit log message. +# Called by "git commit" with one argument, the name of the file +# that has the commit message. The hook should exit with non-zero +# status after issuing an appropriate message if it wants to stop the +# commit. The hook is allowed to edit the commit message file. +# +# To enable this hook, rename this file to "commit-msg". + +# Uncomment the below to add a Signed-off-by line to the message. +# Doing this in a hook is a bad idea in general, but the prepare-commit-msg +# hook is more suited to it. +# +# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p') +# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1" + +# This example catches duplicate Signed-off-by lines. + +test "" = "$(grep '^Signed-off-by: ' "$1" | + sort | uniq -c | sed -e '/^[ ]*1[ ]/d')" || { + echo >&2 Duplicate Signed-off-by lines. + exit 1 +} diff --git a/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libgda/hooks/fsmonitor-watchman.sample b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libgda/hooks/fsmonitor-watchman.sample new file mode 100755 index 0000000..23e856f --- /dev/null +++ b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libgda/hooks/fsmonitor-watchman.sample @@ -0,0 +1,174 @@ +#!/usr/bin/perl + +use strict; +use warnings; +use IPC::Open2; + +# An example hook script to integrate Watchman +# (https://facebook.github.io/watchman/) with git to speed up detecting +# new and modified files. +# +# The hook is passed a version (currently 2) and last update token +# formatted as a string and outputs to stdout a new update token and +# all files that have been modified since the update token. Paths must +# be relative to the root of the working tree and separated by a single NUL. +# +# To enable this hook, rename this file to "query-watchman" and set +# 'git config core.fsmonitor .git/hooks/query-watchman' +# +my ($version, $last_update_token) = @ARGV; + +# Uncomment for debugging +# print STDERR "$0 $version $last_update_token\n"; + +# Check the hook interface version +if ($version ne 2) { + die "Unsupported query-fsmonitor hook version '$version'.\n" . + "Falling back to scanning...\n"; +} + +my $git_work_tree = get_working_dir(); + +my $retry = 1; + +my $json_pkg; +eval { + require JSON::XS; + $json_pkg = "JSON::XS"; + 1; +} or do { + require JSON::PP; + $json_pkg = "JSON::PP"; +}; + +launch_watchman(); + +sub launch_watchman { + my $o = watchman_query(); + if (is_work_tree_watched($o)) { + output_result($o->{clock}, @{$o->{files}}); + } +} + +sub output_result { + my ($clockid, @files) = @_; + + # Uncomment for debugging watchman output + # open (my $fh, ">", ".git/watchman-output.out"); + # binmode $fh, ":utf8"; + # print $fh "$clockid\n@files\n"; + # close $fh; + + binmode STDOUT, ":utf8"; + print $clockid; + print "\0"; + local $, = "\0"; + print @files; +} + +sub watchman_clock { + my $response = qx/watchman clock "$git_work_tree"/; + die "Failed to get clock id on '$git_work_tree'.\n" . + "Falling back to scanning...\n" if $? != 0; + + return $json_pkg->new->utf8->decode($response); +} + +sub watchman_query { + my $pid = open2(\*CHLD_OUT, \*CHLD_IN, 'watchman -j --no-pretty') + or die "open2() failed: $!\n" . + "Falling back to scanning...\n"; + + # In the query expression below we're asking for names of files that + # changed since $last_update_token but not from the .git folder. + # + # To accomplish this, we're using the "since" generator to use the + # recency index to select candidate nodes and "fields" to limit the + # output to file names only. Then we're using the "expression" term to + # further constrain the results. + my $last_update_line = ""; + if (substr($last_update_token, 0, 1) eq "c") { + $last_update_token = "\"$last_update_token\""; + $last_update_line = qq[\n"since": $last_update_token,]; + } + my $query = <<" END"; + ["query", "$git_work_tree", {$last_update_line + "fields": ["name"], + "expression": ["not", ["dirname", ".git"]] + }] + END + + # Uncomment for debugging the watchman query + # open (my $fh, ">", ".git/watchman-query.json"); + # print $fh $query; + # close $fh; + + print CHLD_IN $query; + close CHLD_IN; + my $response = do {local $/; }; + + # Uncomment for debugging the watch response + # open ($fh, ">", ".git/watchman-response.json"); + # print $fh $response; + # close $fh; + + die "Watchman: command returned no output.\n" . + "Falling back to scanning...\n" if $response eq ""; + die "Watchman: command returned invalid output: $response\n" . + "Falling back to scanning...\n" unless $response =~ /^\{/; + + return $json_pkg->new->utf8->decode($response); +} + +sub is_work_tree_watched { + my ($output) = @_; + my $error = $output->{error}; + if ($retry > 0 and $error and $error =~ m/unable to resolve root .* directory (.*) is not watched/) { + $retry--; + my $response = qx/watchman watch "$git_work_tree"/; + die "Failed to make watchman watch '$git_work_tree'.\n" . + "Falling back to scanning...\n" if $? != 0; + $output = $json_pkg->new->utf8->decode($response); + $error = $output->{error}; + die "Watchman: $error.\n" . + "Falling back to scanning...\n" if $error; + + # Uncomment for debugging watchman output + # open (my $fh, ">", ".git/watchman-output.out"); + # close $fh; + + # Watchman will always return all files on the first query so + # return the fast "everything is dirty" flag to git and do the + # Watchman query just to get it over with now so we won't pay + # the cost in git to look up each individual file. + my $o = watchman_clock(); + $error = $output->{error}; + + die "Watchman: $error.\n" . + "Falling back to scanning...\n" if $error; + + output_result($o->{clock}, ("/")); + $last_update_token = $o->{clock}; + + eval { launch_watchman() }; + return 0; + } + + die "Watchman: $error.\n" . + "Falling back to scanning...\n" if $error; + + return 1; +} + +sub get_working_dir { + my $working_dir; + if ($^O =~ 'msys' || $^O =~ 'cygwin') { + $working_dir = Win32::GetCwd(); + $working_dir =~ tr/\\/\//; + } else { + require Cwd; + $working_dir = Cwd::cwd(); + } + + return $working_dir; +} diff --git a/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libgda/hooks/post-update.sample b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libgda/hooks/post-update.sample new file mode 100755 index 0000000..ec17ec1 --- /dev/null +++ b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libgda/hooks/post-update.sample @@ -0,0 +1,8 @@ +#!/bin/sh +# +# An example hook script to prepare a packed repository for use over +# dumb transports. +# +# To enable this hook, rename this file to "post-update". + +exec git update-server-info diff --git a/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libgda/hooks/pre-applypatch.sample b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libgda/hooks/pre-applypatch.sample new file mode 100755 index 0000000..4142082 --- /dev/null +++ b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libgda/hooks/pre-applypatch.sample @@ -0,0 +1,14 @@ +#!/bin/sh +# +# An example hook script to verify what is about to be committed +# by applypatch from an e-mail message. +# +# The hook should exit with non-zero status after issuing an +# appropriate message if it wants to stop the commit. +# +# To enable this hook, rename this file to "pre-applypatch". + +. git-sh-setup +precommit="$(git rev-parse --git-path hooks/pre-commit)" +test -x "$precommit" && exec "$precommit" ${1+"$@"} +: diff --git a/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libgda/hooks/pre-commit.sample b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libgda/hooks/pre-commit.sample new file mode 100755 index 0000000..e144712 --- /dev/null +++ b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libgda/hooks/pre-commit.sample @@ -0,0 +1,49 @@ +#!/bin/sh +# +# An example hook script to verify what is about to be committed. +# Called by "git commit" with no arguments. The hook should +# exit with non-zero status after issuing an appropriate message if +# it wants to stop the commit. +# +# To enable this hook, rename this file to "pre-commit". + +if git rev-parse --verify HEAD >/dev/null 2>&1 +then + against=HEAD +else + # Initial commit: diff against an empty tree object + against=$(git hash-object -t tree /dev/null) +fi + +# If you want to allow non-ASCII filenames set this variable to true. +allownonascii=$(git config --type=bool hooks.allownonascii) + +# Redirect output to stderr. +exec 1>&2 + +# Cross platform projects tend to avoid non-ASCII filenames; prevent +# them from being added to the repository. We exploit the fact that the +# printable range starts at the space character and ends with tilde. +if [ "$allownonascii" != "true" ] && + # Note that the use of brackets around a tr range is ok here, (it's + # even required, for portability to Solaris 10's /usr/bin/tr), since + # the square bracket bytes happen to fall in the designated range. + test $(git diff --cached --name-only --diff-filter=A -z $against | + LC_ALL=C tr -d '[ -~]\0' | wc -c) != 0 +then + cat <<\EOF +Error: Attempt to add a non-ASCII file name. + +This can cause problems if you want to work with people on other platforms. + +To be portable it is advisable to rename the file. + +If you know what you are doing you can disable this check using: + + git config hooks.allownonascii true +EOF + exit 1 +fi + +# If there are whitespace errors, print the offending file names and fail. +exec git diff-index --check --cached $against -- diff --git a/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libgda/hooks/pre-merge-commit.sample b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libgda/hooks/pre-merge-commit.sample new file mode 100755 index 0000000..399eab1 --- /dev/null +++ b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libgda/hooks/pre-merge-commit.sample @@ -0,0 +1,13 @@ +#!/bin/sh +# +# An example hook script to verify what is about to be committed. +# Called by "git merge" with no arguments. The hook should +# exit with non-zero status after issuing an appropriate message to +# stderr if it wants to stop the merge commit. +# +# To enable this hook, rename this file to "pre-merge-commit". + +. git-sh-setup +test -x "$GIT_DIR/hooks/pre-commit" && + exec "$GIT_DIR/hooks/pre-commit" +: diff --git a/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libgda/hooks/pre-push.sample b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libgda/hooks/pre-push.sample new file mode 100755 index 0000000..4ce688d --- /dev/null +++ b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libgda/hooks/pre-push.sample @@ -0,0 +1,53 @@ +#!/bin/sh + +# An example hook script to verify what is about to be pushed. Called by "git +# push" after it has checked the remote status, but before anything has been +# pushed. If this script exits with a non-zero status nothing will be pushed. +# +# This hook is called with the following parameters: +# +# $1 -- Name of the remote to which the push is being done +# $2 -- URL to which the push is being done +# +# If pushing without using a named remote those arguments will be equal. +# +# Information about the commits which are being pushed is supplied as lines to +# the standard input in the form: +# +# +# +# This sample shows how to prevent push of commits where the log message starts +# with "WIP" (work in progress). + +remote="$1" +url="$2" + +zero=$(git hash-object --stdin &2 "Found WIP commit in $local_ref, not pushing" + exit 1 + fi + fi +done + +exit 0 diff --git a/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libgda/hooks/pre-rebase.sample b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libgda/hooks/pre-rebase.sample new file mode 100755 index 0000000..6cbef5c --- /dev/null +++ b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libgda/hooks/pre-rebase.sample @@ -0,0 +1,169 @@ +#!/bin/sh +# +# Copyright (c) 2006, 2008 Junio C Hamano +# +# The "pre-rebase" hook is run just before "git rebase" starts doing +# its job, and can prevent the command from running by exiting with +# non-zero status. +# +# The hook is called with the following parameters: +# +# $1 -- the upstream the series was forked from. +# $2 -- the branch being rebased (or empty when rebasing the current branch). +# +# This sample shows how to prevent topic branches that are already +# merged to 'next' branch from getting rebased, because allowing it +# would result in rebasing already published history. + +publish=next +basebranch="$1" +if test "$#" = 2 +then + topic="refs/heads/$2" +else + topic=`git symbolic-ref HEAD` || + exit 0 ;# we do not interrupt rebasing detached HEAD +fi + +case "$topic" in +refs/heads/??/*) + ;; +*) + exit 0 ;# we do not interrupt others. + ;; +esac + +# Now we are dealing with a topic branch being rebased +# on top of master. Is it OK to rebase it? + +# Does the topic really exist? +git show-ref -q "$topic" || { + echo >&2 "No such branch $topic" + exit 1 +} + +# Is topic fully merged to master? +not_in_master=`git rev-list --pretty=oneline ^master "$topic"` +if test -z "$not_in_master" +then + echo >&2 "$topic is fully merged to master; better remove it." + exit 1 ;# we could allow it, but there is no point. +fi + +# Is topic ever merged to next? If so you should not be rebasing it. +only_next_1=`git rev-list ^master "^$topic" ${publish} | sort` +only_next_2=`git rev-list ^master ${publish} | sort` +if test "$only_next_1" = "$only_next_2" +then + not_in_topic=`git rev-list "^$topic" master` + if test -z "$not_in_topic" + then + echo >&2 "$topic is already up to date with master" + exit 1 ;# we could allow it, but there is no point. + else + exit 0 + fi +else + not_in_next=`git rev-list --pretty=oneline ^${publish} "$topic"` + /usr/bin/perl -e ' + my $topic = $ARGV[0]; + my $msg = "* $topic has commits already merged to public branch:\n"; + my (%not_in_next) = map { + /^([0-9a-f]+) /; + ($1 => 1); + } split(/\n/, $ARGV[1]); + for my $elem (map { + /^([0-9a-f]+) (.*)$/; + [$1 => $2]; + } split(/\n/, $ARGV[2])) { + if (!exists $not_in_next{$elem->[0]}) { + if ($msg) { + print STDERR $msg; + undef $msg; + } + print STDERR " $elem->[1]\n"; + } + } + ' "$topic" "$not_in_next" "$not_in_master" + exit 1 +fi + +<<\DOC_END + +This sample hook safeguards topic branches that have been +published from being rewound. + +The workflow assumed here is: + + * Once a topic branch forks from "master", "master" is never + merged into it again (either directly or indirectly). + + * Once a topic branch is fully cooked and merged into "master", + it is deleted. If you need to build on top of it to correct + earlier mistakes, a new topic branch is created by forking at + the tip of the "master". This is not strictly necessary, but + it makes it easier to keep your history simple. + + * Whenever you need to test or publish your changes to topic + branches, merge them into "next" branch. + +The script, being an example, hardcodes the publish branch name +to be "next", but it is trivial to make it configurable via +$GIT_DIR/config mechanism. + +With this workflow, you would want to know: + +(1) ... if a topic branch has ever been merged to "next". Young + topic branches can have stupid mistakes you would rather + clean up before publishing, and things that have not been + merged into other branches can be easily rebased without + affecting other people. But once it is published, you would + not want to rewind it. + +(2) ... if a topic branch has been fully merged to "master". + Then you can delete it. More importantly, you should not + build on top of it -- other people may already want to + change things related to the topic as patches against your + "master", so if you need further changes, it is better to + fork the topic (perhaps with the same name) afresh from the + tip of "master". + +Let's look at this example: + + o---o---o---o---o---o---o---o---o---o "next" + / / / / + / a---a---b A / / + / / / / + / / c---c---c---c B / + / / / \ / + / / / b---b C \ / + / / / / \ / + ---o---o---o---o---o---o---o---o---o---o---o "master" + + +A, B and C are topic branches. + + * A has one fix since it was merged up to "next". + + * B has finished. It has been fully merged up to "master" and "next", + and is ready to be deleted. + + * C has not merged to "next" at all. + +We would want to allow C to be rebased, refuse A, and encourage +B to be deleted. + +To compute (1): + + git rev-list ^master ^topic next + git rev-list ^master next + + if these match, topic has not merged in next at all. + +To compute (2): + + git rev-list master..topic + + if this is empty, it is fully merged to "master". + +DOC_END diff --git a/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libgda/hooks/pre-receive.sample b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libgda/hooks/pre-receive.sample new file mode 100755 index 0000000..a1fd29e --- /dev/null +++ b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libgda/hooks/pre-receive.sample @@ -0,0 +1,24 @@ +#!/bin/sh +# +# An example hook script to make use of push options. +# The example simply echoes all push options that start with 'echoback=' +# and rejects all pushes when the "reject" push option is used. +# +# To enable this hook, rename this file to "pre-receive". + +if test -n "$GIT_PUSH_OPTION_COUNT" +then + i=0 + while test "$i" -lt "$GIT_PUSH_OPTION_COUNT" + do + eval "value=\$GIT_PUSH_OPTION_$i" + case "$value" in + echoback=*) + echo "echo from the pre-receive-hook: ${value#*=}" >&2 + ;; + reject) + exit 1 + esac + i=$((i + 1)) + done +fi diff --git a/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libgda/hooks/prepare-commit-msg.sample b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libgda/hooks/prepare-commit-msg.sample new file mode 100755 index 0000000..10fa14c --- /dev/null +++ b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libgda/hooks/prepare-commit-msg.sample @@ -0,0 +1,42 @@ +#!/bin/sh +# +# An example hook script to prepare the commit log message. +# Called by "git commit" with the name of the file that has the +# commit message, followed by the description of the commit +# message's source. The hook's purpose is to edit the commit +# message file. If the hook fails with a non-zero status, +# the commit is aborted. +# +# To enable this hook, rename this file to "prepare-commit-msg". + +# This hook includes three examples. The first one removes the +# "# Please enter the commit message..." help message. +# +# The second includes the output of "git diff --name-status -r" +# into the message, just before the "git status" output. It is +# commented because it doesn't cope with --amend or with squashed +# commits. +# +# The third example adds a Signed-off-by line to the message, that can +# still be edited. This is rarely a good idea. + +COMMIT_MSG_FILE=$1 +COMMIT_SOURCE=$2 +SHA1=$3 + +/usr/bin/perl -i.bak -ne 'print unless(m/^. Please enter the commit message/..m/^#$/)' "$COMMIT_MSG_FILE" + +# case "$COMMIT_SOURCE,$SHA1" in +# ,|template,) +# /usr/bin/perl -i.bak -pe ' +# print "\n" . `git diff --cached --name-status -r` +# if /^#/ && $first++ == 0' "$COMMIT_MSG_FILE" ;; +# *) ;; +# esac + +# SOB=$(git var GIT_COMMITTER_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p') +# git interpret-trailers --in-place --trailer "$SOB" "$COMMIT_MSG_FILE" +# if test -z "$COMMIT_SOURCE" +# then +# /usr/bin/perl -i.bak -pe 'print "\n" if !$first_line++' "$COMMIT_MSG_FILE" +# fi diff --git a/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libgda/hooks/push-to-checkout.sample b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libgda/hooks/push-to-checkout.sample new file mode 100755 index 0000000..af5a0c0 --- /dev/null +++ b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libgda/hooks/push-to-checkout.sample @@ -0,0 +1,78 @@ +#!/bin/sh + +# An example hook script to update a checked-out tree on a git push. +# +# This hook is invoked by git-receive-pack(1) when it reacts to git +# push and updates reference(s) in its repository, and when the push +# tries to update the branch that is currently checked out and the +# receive.denyCurrentBranch configuration variable is set to +# updateInstead. +# +# By default, such a push is refused if the working tree and the index +# of the remote repository has any difference from the currently +# checked out commit; when both the working tree and the index match +# the current commit, they are updated to match the newly pushed tip +# of the branch. This hook is to be used to override the default +# behaviour; however the code below reimplements the default behaviour +# as a starting point for convenient modification. +# +# The hook receives the commit with which the tip of the current +# branch is going to be updated: +commit=$1 + +# It can exit with a non-zero status to refuse the push (when it does +# so, it must not modify the index or the working tree). +die () { + echo >&2 "$*" + exit 1 +} + +# Or it can make any necessary changes to the working tree and to the +# index to bring them to the desired state when the tip of the current +# branch is updated to the new commit, and exit with a zero status. +# +# For example, the hook can simply run git read-tree -u -m HEAD "$1" +# in order to emulate git fetch that is run in the reverse direction +# with git push, as the two-tree form of git read-tree -u -m is +# essentially the same as git switch or git checkout that switches +# branches while keeping the local changes in the working tree that do +# not interfere with the difference between the branches. + +# The below is a more-or-less exact translation to shell of the C code +# for the default behaviour for git's push-to-checkout hook defined in +# the push_to_deploy() function in builtin/receive-pack.c. +# +# Note that the hook will be executed from the repository directory, +# not from the working tree, so if you want to perform operations on +# the working tree, you will have to adapt your code accordingly, e.g. +# by adding "cd .." or using relative paths. + +if ! git update-index -q --ignore-submodules --refresh +then + die "Up-to-date check failed" +fi + +if ! git diff-files --quiet --ignore-submodules -- +then + die "Working directory has unstaged changes" +fi + +# This is a rough translation of: +# +# head_has_history() ? "HEAD" : EMPTY_TREE_SHA1_HEX +if git cat-file -e HEAD 2>/dev/null +then + head=HEAD +else + head=$(git hash-object -t tree --stdin &2 + exit 1 +} + +unset GIT_DIR GIT_WORK_TREE +cd "$worktree" && + +if grep -q "^diff --git " "$1" +then + validate_patch "$1" +else + validate_cover_letter "$1" +fi && + +if test "$GIT_SENDEMAIL_FILE_COUNTER" = "$GIT_SENDEMAIL_FILE_TOTAL" +then + git config --unset-all sendemail.validateWorktree && + trap 'git worktree remove -ff "$worktree"' EXIT && + validate_series +fi diff --git a/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libgda/hooks/update.sample b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libgda/hooks/update.sample new file mode 100755 index 0000000..c4d426b --- /dev/null +++ b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libgda/hooks/update.sample @@ -0,0 +1,128 @@ +#!/bin/sh +# +# An example hook script to block unannotated tags from entering. +# Called by "git receive-pack" with arguments: refname sha1-old sha1-new +# +# To enable this hook, rename this file to "update". +# +# Config +# ------ +# hooks.allowunannotated +# This boolean sets whether unannotated tags will be allowed into the +# repository. By default they won't be. +# hooks.allowdeletetag +# This boolean sets whether deleting tags will be allowed in the +# repository. By default they won't be. +# hooks.allowmodifytag +# This boolean sets whether a tag may be modified after creation. By default +# it won't be. +# hooks.allowdeletebranch +# This boolean sets whether deleting branches will be allowed in the +# repository. By default they won't be. +# hooks.denycreatebranch +# This boolean sets whether remotely creating branches will be denied +# in the repository. By default this is allowed. +# + +# --- Command line +refname="$1" +oldrev="$2" +newrev="$3" + +# --- Safety check +if [ -z "$GIT_DIR" ]; then + echo "Don't run this script from the command line." >&2 + echo " (if you want, you could supply GIT_DIR then run" >&2 + echo " $0 )" >&2 + exit 1 +fi + +if [ -z "$refname" -o -z "$oldrev" -o -z "$newrev" ]; then + echo "usage: $0 " >&2 + exit 1 +fi + +# --- Config +allowunannotated=$(git config --type=bool hooks.allowunannotated) +allowdeletebranch=$(git config --type=bool hooks.allowdeletebranch) +denycreatebranch=$(git config --type=bool hooks.denycreatebranch) +allowdeletetag=$(git config --type=bool hooks.allowdeletetag) +allowmodifytag=$(git config --type=bool hooks.allowmodifytag) + +# check for no description +projectdesc=$(sed -e '1q' "$GIT_DIR/description") +case "$projectdesc" in +"Unnamed repository"* | "") + echo "*** Project description file hasn't been set" >&2 + exit 1 + ;; +esac + +# --- Check types +# if $newrev is 0000...0000, it's a commit to delete a ref. +zero=$(git hash-object --stdin &2 + echo "*** Use 'git tag [ -a | -s ]' for tags you want to propagate." >&2 + exit 1 + fi + ;; + refs/tags/*,delete) + # delete tag + if [ "$allowdeletetag" != "true" ]; then + echo "*** Deleting a tag is not allowed in this repository" >&2 + exit 1 + fi + ;; + refs/tags/*,tag) + # annotated tag + if [ "$allowmodifytag" != "true" ] && git rev-parse $refname > /dev/null 2>&1 + then + echo "*** Tag '$refname' already exists." >&2 + echo "*** Modifying a tag is not allowed in this repository." >&2 + exit 1 + fi + ;; + refs/heads/*,commit) + # branch + if [ "$oldrev" = "$zero" -a "$denycreatebranch" = "true" ]; then + echo "*** Creating a branch is not allowed in this repository" >&2 + exit 1 + fi + ;; + refs/heads/*,delete) + # delete branch + if [ "$allowdeletebranch" != "true" ]; then + echo "*** Deleting a branch is not allowed in this repository" >&2 + exit 1 + fi + ;; + refs/remotes/*,commit) + # tracking branch + ;; + refs/remotes/*,delete) + # delete tracking branch + if [ "$allowdeletebranch" != "true" ]; then + echo "*** Deleting a tracking branch is not allowed in this repository" >&2 + exit 1 + fi + ;; + *) + # Anything else (is there anything else?) + echo "*** Update hook: unknown type of update to ref $refname of type $newrev_type" >&2 + exit 1 + ;; +esac + +# --- Finished +exit 0 diff --git a/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libgda/info/exclude b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libgda/info/exclude new file mode 100644 index 0000000..a5196d1 --- /dev/null +++ b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libgda/info/exclude @@ -0,0 +1,6 @@ +# git ls-files --others --exclude-from=.git/info/exclude +# Lines that start with '#' are comments. +# For a project mostly in C, the following would be a good set of +# exclude patterns (uncomment them if you want to use them): +# *.[oa] +# *~ diff --git a/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libgda/objects/pack/pack-9cd5e31c161765c7b298586882ce097688e3fcb1.idx b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libgda/objects/pack/pack-9cd5e31c161765c7b298586882ce097688e3fcb1.idx new file mode 100644 index 0000000..20fba66 Binary files /dev/null and b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libgda/objects/pack/pack-9cd5e31c161765c7b298586882ce097688e3fcb1.idx differ diff --git a/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libgda/objects/pack/pack-9cd5e31c161765c7b298586882ce097688e3fcb1.pack b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libgda/objects/pack/pack-9cd5e31c161765c7b298586882ce097688e3fcb1.pack new file mode 100644 index 0000000..de1e756 Binary files /dev/null and b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libgda/objects/pack/pack-9cd5e31c161765c7b298586882ce097688e3fcb1.pack differ diff --git a/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libgda/objects/pack/pack-9cd5e31c161765c7b298586882ce097688e3fcb1.rev b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libgda/objects/pack/pack-9cd5e31c161765c7b298586882ce097688e3fcb1.rev new file mode 100644 index 0000000..f2dda25 Binary files /dev/null and b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libgda/objects/pack/pack-9cd5e31c161765c7b298586882ce097688e3fcb1.rev differ diff --git a/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libgda/refs/tags/LIBGDA_6_0_0 b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libgda/refs/tags/LIBGDA_6_0_0 new file mode 100644 index 0000000..f655b83 --- /dev/null +++ b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libgda/refs/tags/LIBGDA_6_0_0 @@ -0,0 +1 @@ +dfd61d86d65d3522538b614bb856815da3f67ebe diff --git a/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libgda/shallow b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libgda/shallow new file mode 100644 index 0000000..acce71b --- /dev/null +++ b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libgda/shallow @@ -0,0 +1 @@ +5d23892e1c8abd931ad2a7bd24cd543b93ccb04c diff --git a/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libxml2/FETCH_HEAD b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libxml2/FETCH_HEAD new file mode 100644 index 0000000..3e3cb54 --- /dev/null +++ b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libxml2/FETCH_HEAD @@ -0,0 +1 @@ +be5448432faaf7b108665fb2f4336c407dcecee9 tag 'v2.11.4' of https://gitlab.gnome.org/GNOME/libxml2 diff --git a/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libxml2/HEAD b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libxml2/HEAD new file mode 100644 index 0000000..cb089cd --- /dev/null +++ b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libxml2/HEAD @@ -0,0 +1 @@ +ref: refs/heads/master diff --git a/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libxml2/config b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libxml2/config new file mode 100644 index 0000000..2d509e5 --- /dev/null +++ b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libxml2/config @@ -0,0 +1,9 @@ +[core] + repositoryformatversion = 0 + filemode = true + bare = true +[remote "origin"] + url = https://gitlab.gnome.org/GNOME/libxml2 + fetch = +refs/*:refs/* +[transfer] + fsckObjects = 1 diff --git a/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libxml2/description b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libxml2/description new file mode 100644 index 0000000..498b267 --- /dev/null +++ b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libxml2/description @@ -0,0 +1 @@ +Unnamed repository; edit this file 'description' to name the repository. diff --git a/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libxml2/hooks/applypatch-msg.sample b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libxml2/hooks/applypatch-msg.sample new file mode 100755 index 0000000..a5d7b84 --- /dev/null +++ b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libxml2/hooks/applypatch-msg.sample @@ -0,0 +1,15 @@ +#!/bin/sh +# +# An example hook script to check the commit log message taken by +# applypatch from an e-mail message. +# +# The hook should exit with non-zero status after issuing an +# appropriate message if it wants to stop the commit. The hook is +# allowed to edit the commit message file. +# +# To enable this hook, rename this file to "applypatch-msg". + +. git-sh-setup +commitmsg="$(git rev-parse --git-path hooks/commit-msg)" +test -x "$commitmsg" && exec "$commitmsg" ${1+"$@"} +: diff --git a/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libxml2/hooks/commit-msg.sample b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libxml2/hooks/commit-msg.sample new file mode 100755 index 0000000..b58d118 --- /dev/null +++ b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libxml2/hooks/commit-msg.sample @@ -0,0 +1,24 @@ +#!/bin/sh +# +# An example hook script to check the commit log message. +# Called by "git commit" with one argument, the name of the file +# that has the commit message. The hook should exit with non-zero +# status after issuing an appropriate message if it wants to stop the +# commit. The hook is allowed to edit the commit message file. +# +# To enable this hook, rename this file to "commit-msg". + +# Uncomment the below to add a Signed-off-by line to the message. +# Doing this in a hook is a bad idea in general, but the prepare-commit-msg +# hook is more suited to it. +# +# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p') +# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1" + +# This example catches duplicate Signed-off-by lines. + +test "" = "$(grep '^Signed-off-by: ' "$1" | + sort | uniq -c | sed -e '/^[ ]*1[ ]/d')" || { + echo >&2 Duplicate Signed-off-by lines. + exit 1 +} diff --git a/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libxml2/hooks/fsmonitor-watchman.sample b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libxml2/hooks/fsmonitor-watchman.sample new file mode 100755 index 0000000..23e856f --- /dev/null +++ b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libxml2/hooks/fsmonitor-watchman.sample @@ -0,0 +1,174 @@ +#!/usr/bin/perl + +use strict; +use warnings; +use IPC::Open2; + +# An example hook script to integrate Watchman +# (https://facebook.github.io/watchman/) with git to speed up detecting +# new and modified files. +# +# The hook is passed a version (currently 2) and last update token +# formatted as a string and outputs to stdout a new update token and +# all files that have been modified since the update token. Paths must +# be relative to the root of the working tree and separated by a single NUL. +# +# To enable this hook, rename this file to "query-watchman" and set +# 'git config core.fsmonitor .git/hooks/query-watchman' +# +my ($version, $last_update_token) = @ARGV; + +# Uncomment for debugging +# print STDERR "$0 $version $last_update_token\n"; + +# Check the hook interface version +if ($version ne 2) { + die "Unsupported query-fsmonitor hook version '$version'.\n" . + "Falling back to scanning...\n"; +} + +my $git_work_tree = get_working_dir(); + +my $retry = 1; + +my $json_pkg; +eval { + require JSON::XS; + $json_pkg = "JSON::XS"; + 1; +} or do { + require JSON::PP; + $json_pkg = "JSON::PP"; +}; + +launch_watchman(); + +sub launch_watchman { + my $o = watchman_query(); + if (is_work_tree_watched($o)) { + output_result($o->{clock}, @{$o->{files}}); + } +} + +sub output_result { + my ($clockid, @files) = @_; + + # Uncomment for debugging watchman output + # open (my $fh, ">", ".git/watchman-output.out"); + # binmode $fh, ":utf8"; + # print $fh "$clockid\n@files\n"; + # close $fh; + + binmode STDOUT, ":utf8"; + print $clockid; + print "\0"; + local $, = "\0"; + print @files; +} + +sub watchman_clock { + my $response = qx/watchman clock "$git_work_tree"/; + die "Failed to get clock id on '$git_work_tree'.\n" . + "Falling back to scanning...\n" if $? != 0; + + return $json_pkg->new->utf8->decode($response); +} + +sub watchman_query { + my $pid = open2(\*CHLD_OUT, \*CHLD_IN, 'watchman -j --no-pretty') + or die "open2() failed: $!\n" . + "Falling back to scanning...\n"; + + # In the query expression below we're asking for names of files that + # changed since $last_update_token but not from the .git folder. + # + # To accomplish this, we're using the "since" generator to use the + # recency index to select candidate nodes and "fields" to limit the + # output to file names only. Then we're using the "expression" term to + # further constrain the results. + my $last_update_line = ""; + if (substr($last_update_token, 0, 1) eq "c") { + $last_update_token = "\"$last_update_token\""; + $last_update_line = qq[\n"since": $last_update_token,]; + } + my $query = <<" END"; + ["query", "$git_work_tree", {$last_update_line + "fields": ["name"], + "expression": ["not", ["dirname", ".git"]] + }] + END + + # Uncomment for debugging the watchman query + # open (my $fh, ">", ".git/watchman-query.json"); + # print $fh $query; + # close $fh; + + print CHLD_IN $query; + close CHLD_IN; + my $response = do {local $/; }; + + # Uncomment for debugging the watch response + # open ($fh, ">", ".git/watchman-response.json"); + # print $fh $response; + # close $fh; + + die "Watchman: command returned no output.\n" . + "Falling back to scanning...\n" if $response eq ""; + die "Watchman: command returned invalid output: $response\n" . + "Falling back to scanning...\n" unless $response =~ /^\{/; + + return $json_pkg->new->utf8->decode($response); +} + +sub is_work_tree_watched { + my ($output) = @_; + my $error = $output->{error}; + if ($retry > 0 and $error and $error =~ m/unable to resolve root .* directory (.*) is not watched/) { + $retry--; + my $response = qx/watchman watch "$git_work_tree"/; + die "Failed to make watchman watch '$git_work_tree'.\n" . + "Falling back to scanning...\n" if $? != 0; + $output = $json_pkg->new->utf8->decode($response); + $error = $output->{error}; + die "Watchman: $error.\n" . + "Falling back to scanning...\n" if $error; + + # Uncomment for debugging watchman output + # open (my $fh, ">", ".git/watchman-output.out"); + # close $fh; + + # Watchman will always return all files on the first query so + # return the fast "everything is dirty" flag to git and do the + # Watchman query just to get it over with now so we won't pay + # the cost in git to look up each individual file. + my $o = watchman_clock(); + $error = $output->{error}; + + die "Watchman: $error.\n" . + "Falling back to scanning...\n" if $error; + + output_result($o->{clock}, ("/")); + $last_update_token = $o->{clock}; + + eval { launch_watchman() }; + return 0; + } + + die "Watchman: $error.\n" . + "Falling back to scanning...\n" if $error; + + return 1; +} + +sub get_working_dir { + my $working_dir; + if ($^O =~ 'msys' || $^O =~ 'cygwin') { + $working_dir = Win32::GetCwd(); + $working_dir =~ tr/\\/\//; + } else { + require Cwd; + $working_dir = Cwd::cwd(); + } + + return $working_dir; +} diff --git a/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libxml2/hooks/post-update.sample b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libxml2/hooks/post-update.sample new file mode 100755 index 0000000..ec17ec1 --- /dev/null +++ b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libxml2/hooks/post-update.sample @@ -0,0 +1,8 @@ +#!/bin/sh +# +# An example hook script to prepare a packed repository for use over +# dumb transports. +# +# To enable this hook, rename this file to "post-update". + +exec git update-server-info diff --git a/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libxml2/hooks/pre-applypatch.sample b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libxml2/hooks/pre-applypatch.sample new file mode 100755 index 0000000..4142082 --- /dev/null +++ b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libxml2/hooks/pre-applypatch.sample @@ -0,0 +1,14 @@ +#!/bin/sh +# +# An example hook script to verify what is about to be committed +# by applypatch from an e-mail message. +# +# The hook should exit with non-zero status after issuing an +# appropriate message if it wants to stop the commit. +# +# To enable this hook, rename this file to "pre-applypatch". + +. git-sh-setup +precommit="$(git rev-parse --git-path hooks/pre-commit)" +test -x "$precommit" && exec "$precommit" ${1+"$@"} +: diff --git a/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libxml2/hooks/pre-commit.sample b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libxml2/hooks/pre-commit.sample new file mode 100755 index 0000000..e144712 --- /dev/null +++ b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libxml2/hooks/pre-commit.sample @@ -0,0 +1,49 @@ +#!/bin/sh +# +# An example hook script to verify what is about to be committed. +# Called by "git commit" with no arguments. The hook should +# exit with non-zero status after issuing an appropriate message if +# it wants to stop the commit. +# +# To enable this hook, rename this file to "pre-commit". + +if git rev-parse --verify HEAD >/dev/null 2>&1 +then + against=HEAD +else + # Initial commit: diff against an empty tree object + against=$(git hash-object -t tree /dev/null) +fi + +# If you want to allow non-ASCII filenames set this variable to true. +allownonascii=$(git config --type=bool hooks.allownonascii) + +# Redirect output to stderr. +exec 1>&2 + +# Cross platform projects tend to avoid non-ASCII filenames; prevent +# them from being added to the repository. We exploit the fact that the +# printable range starts at the space character and ends with tilde. +if [ "$allownonascii" != "true" ] && + # Note that the use of brackets around a tr range is ok here, (it's + # even required, for portability to Solaris 10's /usr/bin/tr), since + # the square bracket bytes happen to fall in the designated range. + test $(git diff --cached --name-only --diff-filter=A -z $against | + LC_ALL=C tr -d '[ -~]\0' | wc -c) != 0 +then + cat <<\EOF +Error: Attempt to add a non-ASCII file name. + +This can cause problems if you want to work with people on other platforms. + +To be portable it is advisable to rename the file. + +If you know what you are doing you can disable this check using: + + git config hooks.allownonascii true +EOF + exit 1 +fi + +# If there are whitespace errors, print the offending file names and fail. +exec git diff-index --check --cached $against -- diff --git a/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libxml2/hooks/pre-merge-commit.sample b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libxml2/hooks/pre-merge-commit.sample new file mode 100755 index 0000000..399eab1 --- /dev/null +++ b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libxml2/hooks/pre-merge-commit.sample @@ -0,0 +1,13 @@ +#!/bin/sh +# +# An example hook script to verify what is about to be committed. +# Called by "git merge" with no arguments. The hook should +# exit with non-zero status after issuing an appropriate message to +# stderr if it wants to stop the merge commit. +# +# To enable this hook, rename this file to "pre-merge-commit". + +. git-sh-setup +test -x "$GIT_DIR/hooks/pre-commit" && + exec "$GIT_DIR/hooks/pre-commit" +: diff --git a/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libxml2/hooks/pre-push.sample b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libxml2/hooks/pre-push.sample new file mode 100755 index 0000000..4ce688d --- /dev/null +++ b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libxml2/hooks/pre-push.sample @@ -0,0 +1,53 @@ +#!/bin/sh + +# An example hook script to verify what is about to be pushed. Called by "git +# push" after it has checked the remote status, but before anything has been +# pushed. If this script exits with a non-zero status nothing will be pushed. +# +# This hook is called with the following parameters: +# +# $1 -- Name of the remote to which the push is being done +# $2 -- URL to which the push is being done +# +# If pushing without using a named remote those arguments will be equal. +# +# Information about the commits which are being pushed is supplied as lines to +# the standard input in the form: +# +# +# +# This sample shows how to prevent push of commits where the log message starts +# with "WIP" (work in progress). + +remote="$1" +url="$2" + +zero=$(git hash-object --stdin &2 "Found WIP commit in $local_ref, not pushing" + exit 1 + fi + fi +done + +exit 0 diff --git a/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libxml2/hooks/pre-rebase.sample b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libxml2/hooks/pre-rebase.sample new file mode 100755 index 0000000..6cbef5c --- /dev/null +++ b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libxml2/hooks/pre-rebase.sample @@ -0,0 +1,169 @@ +#!/bin/sh +# +# Copyright (c) 2006, 2008 Junio C Hamano +# +# The "pre-rebase" hook is run just before "git rebase" starts doing +# its job, and can prevent the command from running by exiting with +# non-zero status. +# +# The hook is called with the following parameters: +# +# $1 -- the upstream the series was forked from. +# $2 -- the branch being rebased (or empty when rebasing the current branch). +# +# This sample shows how to prevent topic branches that are already +# merged to 'next' branch from getting rebased, because allowing it +# would result in rebasing already published history. + +publish=next +basebranch="$1" +if test "$#" = 2 +then + topic="refs/heads/$2" +else + topic=`git symbolic-ref HEAD` || + exit 0 ;# we do not interrupt rebasing detached HEAD +fi + +case "$topic" in +refs/heads/??/*) + ;; +*) + exit 0 ;# we do not interrupt others. + ;; +esac + +# Now we are dealing with a topic branch being rebased +# on top of master. Is it OK to rebase it? + +# Does the topic really exist? +git show-ref -q "$topic" || { + echo >&2 "No such branch $topic" + exit 1 +} + +# Is topic fully merged to master? +not_in_master=`git rev-list --pretty=oneline ^master "$topic"` +if test -z "$not_in_master" +then + echo >&2 "$topic is fully merged to master; better remove it." + exit 1 ;# we could allow it, but there is no point. +fi + +# Is topic ever merged to next? If so you should not be rebasing it. +only_next_1=`git rev-list ^master "^$topic" ${publish} | sort` +only_next_2=`git rev-list ^master ${publish} | sort` +if test "$only_next_1" = "$only_next_2" +then + not_in_topic=`git rev-list "^$topic" master` + if test -z "$not_in_topic" + then + echo >&2 "$topic is already up to date with master" + exit 1 ;# we could allow it, but there is no point. + else + exit 0 + fi +else + not_in_next=`git rev-list --pretty=oneline ^${publish} "$topic"` + /usr/bin/perl -e ' + my $topic = $ARGV[0]; + my $msg = "* $topic has commits already merged to public branch:\n"; + my (%not_in_next) = map { + /^([0-9a-f]+) /; + ($1 => 1); + } split(/\n/, $ARGV[1]); + for my $elem (map { + /^([0-9a-f]+) (.*)$/; + [$1 => $2]; + } split(/\n/, $ARGV[2])) { + if (!exists $not_in_next{$elem->[0]}) { + if ($msg) { + print STDERR $msg; + undef $msg; + } + print STDERR " $elem->[1]\n"; + } + } + ' "$topic" "$not_in_next" "$not_in_master" + exit 1 +fi + +<<\DOC_END + +This sample hook safeguards topic branches that have been +published from being rewound. + +The workflow assumed here is: + + * Once a topic branch forks from "master", "master" is never + merged into it again (either directly or indirectly). + + * Once a topic branch is fully cooked and merged into "master", + it is deleted. If you need to build on top of it to correct + earlier mistakes, a new topic branch is created by forking at + the tip of the "master". This is not strictly necessary, but + it makes it easier to keep your history simple. + + * Whenever you need to test or publish your changes to topic + branches, merge them into "next" branch. + +The script, being an example, hardcodes the publish branch name +to be "next", but it is trivial to make it configurable via +$GIT_DIR/config mechanism. + +With this workflow, you would want to know: + +(1) ... if a topic branch has ever been merged to "next". Young + topic branches can have stupid mistakes you would rather + clean up before publishing, and things that have not been + merged into other branches can be easily rebased without + affecting other people. But once it is published, you would + not want to rewind it. + +(2) ... if a topic branch has been fully merged to "master". + Then you can delete it. More importantly, you should not + build on top of it -- other people may already want to + change things related to the topic as patches against your + "master", so if you need further changes, it is better to + fork the topic (perhaps with the same name) afresh from the + tip of "master". + +Let's look at this example: + + o---o---o---o---o---o---o---o---o---o "next" + / / / / + / a---a---b A / / + / / / / + / / c---c---c---c B / + / / / \ / + / / / b---b C \ / + / / / / \ / + ---o---o---o---o---o---o---o---o---o---o---o "master" + + +A, B and C are topic branches. + + * A has one fix since it was merged up to "next". + + * B has finished. It has been fully merged up to "master" and "next", + and is ready to be deleted. + + * C has not merged to "next" at all. + +We would want to allow C to be rebased, refuse A, and encourage +B to be deleted. + +To compute (1): + + git rev-list ^master ^topic next + git rev-list ^master next + + if these match, topic has not merged in next at all. + +To compute (2): + + git rev-list master..topic + + if this is empty, it is fully merged to "master". + +DOC_END diff --git a/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libxml2/hooks/pre-receive.sample b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libxml2/hooks/pre-receive.sample new file mode 100755 index 0000000..a1fd29e --- /dev/null +++ b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libxml2/hooks/pre-receive.sample @@ -0,0 +1,24 @@ +#!/bin/sh +# +# An example hook script to make use of push options. +# The example simply echoes all push options that start with 'echoback=' +# and rejects all pushes when the "reject" push option is used. +# +# To enable this hook, rename this file to "pre-receive". + +if test -n "$GIT_PUSH_OPTION_COUNT" +then + i=0 + while test "$i" -lt "$GIT_PUSH_OPTION_COUNT" + do + eval "value=\$GIT_PUSH_OPTION_$i" + case "$value" in + echoback=*) + echo "echo from the pre-receive-hook: ${value#*=}" >&2 + ;; + reject) + exit 1 + esac + i=$((i + 1)) + done +fi diff --git a/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libxml2/hooks/prepare-commit-msg.sample b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libxml2/hooks/prepare-commit-msg.sample new file mode 100755 index 0000000..10fa14c --- /dev/null +++ b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libxml2/hooks/prepare-commit-msg.sample @@ -0,0 +1,42 @@ +#!/bin/sh +# +# An example hook script to prepare the commit log message. +# Called by "git commit" with the name of the file that has the +# commit message, followed by the description of the commit +# message's source. The hook's purpose is to edit the commit +# message file. If the hook fails with a non-zero status, +# the commit is aborted. +# +# To enable this hook, rename this file to "prepare-commit-msg". + +# This hook includes three examples. The first one removes the +# "# Please enter the commit message..." help message. +# +# The second includes the output of "git diff --name-status -r" +# into the message, just before the "git status" output. It is +# commented because it doesn't cope with --amend or with squashed +# commits. +# +# The third example adds a Signed-off-by line to the message, that can +# still be edited. This is rarely a good idea. + +COMMIT_MSG_FILE=$1 +COMMIT_SOURCE=$2 +SHA1=$3 + +/usr/bin/perl -i.bak -ne 'print unless(m/^. Please enter the commit message/..m/^#$/)' "$COMMIT_MSG_FILE" + +# case "$COMMIT_SOURCE,$SHA1" in +# ,|template,) +# /usr/bin/perl -i.bak -pe ' +# print "\n" . `git diff --cached --name-status -r` +# if /^#/ && $first++ == 0' "$COMMIT_MSG_FILE" ;; +# *) ;; +# esac + +# SOB=$(git var GIT_COMMITTER_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p') +# git interpret-trailers --in-place --trailer "$SOB" "$COMMIT_MSG_FILE" +# if test -z "$COMMIT_SOURCE" +# then +# /usr/bin/perl -i.bak -pe 'print "\n" if !$first_line++' "$COMMIT_MSG_FILE" +# fi diff --git a/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libxml2/hooks/push-to-checkout.sample b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libxml2/hooks/push-to-checkout.sample new file mode 100755 index 0000000..af5a0c0 --- /dev/null +++ b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libxml2/hooks/push-to-checkout.sample @@ -0,0 +1,78 @@ +#!/bin/sh + +# An example hook script to update a checked-out tree on a git push. +# +# This hook is invoked by git-receive-pack(1) when it reacts to git +# push and updates reference(s) in its repository, and when the push +# tries to update the branch that is currently checked out and the +# receive.denyCurrentBranch configuration variable is set to +# updateInstead. +# +# By default, such a push is refused if the working tree and the index +# of the remote repository has any difference from the currently +# checked out commit; when both the working tree and the index match +# the current commit, they are updated to match the newly pushed tip +# of the branch. This hook is to be used to override the default +# behaviour; however the code below reimplements the default behaviour +# as a starting point for convenient modification. +# +# The hook receives the commit with which the tip of the current +# branch is going to be updated: +commit=$1 + +# It can exit with a non-zero status to refuse the push (when it does +# so, it must not modify the index or the working tree). +die () { + echo >&2 "$*" + exit 1 +} + +# Or it can make any necessary changes to the working tree and to the +# index to bring them to the desired state when the tip of the current +# branch is updated to the new commit, and exit with a zero status. +# +# For example, the hook can simply run git read-tree -u -m HEAD "$1" +# in order to emulate git fetch that is run in the reverse direction +# with git push, as the two-tree form of git read-tree -u -m is +# essentially the same as git switch or git checkout that switches +# branches while keeping the local changes in the working tree that do +# not interfere with the difference between the branches. + +# The below is a more-or-less exact translation to shell of the C code +# for the default behaviour for git's push-to-checkout hook defined in +# the push_to_deploy() function in builtin/receive-pack.c. +# +# Note that the hook will be executed from the repository directory, +# not from the working tree, so if you want to perform operations on +# the working tree, you will have to adapt your code accordingly, e.g. +# by adding "cd .." or using relative paths. + +if ! git update-index -q --ignore-submodules --refresh +then + die "Up-to-date check failed" +fi + +if ! git diff-files --quiet --ignore-submodules -- +then + die "Working directory has unstaged changes" +fi + +# This is a rough translation of: +# +# head_has_history() ? "HEAD" : EMPTY_TREE_SHA1_HEX +if git cat-file -e HEAD 2>/dev/null +then + head=HEAD +else + head=$(git hash-object -t tree --stdin &2 + exit 1 +} + +unset GIT_DIR GIT_WORK_TREE +cd "$worktree" && + +if grep -q "^diff --git " "$1" +then + validate_patch "$1" +else + validate_cover_letter "$1" +fi && + +if test "$GIT_SENDEMAIL_FILE_COUNTER" = "$GIT_SENDEMAIL_FILE_TOTAL" +then + git config --unset-all sendemail.validateWorktree && + trap 'git worktree remove -ff "$worktree"' EXIT && + validate_series +fi diff --git a/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libxml2/hooks/update.sample b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libxml2/hooks/update.sample new file mode 100755 index 0000000..c4d426b --- /dev/null +++ b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libxml2/hooks/update.sample @@ -0,0 +1,128 @@ +#!/bin/sh +# +# An example hook script to block unannotated tags from entering. +# Called by "git receive-pack" with arguments: refname sha1-old sha1-new +# +# To enable this hook, rename this file to "update". +# +# Config +# ------ +# hooks.allowunannotated +# This boolean sets whether unannotated tags will be allowed into the +# repository. By default they won't be. +# hooks.allowdeletetag +# This boolean sets whether deleting tags will be allowed in the +# repository. By default they won't be. +# hooks.allowmodifytag +# This boolean sets whether a tag may be modified after creation. By default +# it won't be. +# hooks.allowdeletebranch +# This boolean sets whether deleting branches will be allowed in the +# repository. By default they won't be. +# hooks.denycreatebranch +# This boolean sets whether remotely creating branches will be denied +# in the repository. By default this is allowed. +# + +# --- Command line +refname="$1" +oldrev="$2" +newrev="$3" + +# --- Safety check +if [ -z "$GIT_DIR" ]; then + echo "Don't run this script from the command line." >&2 + echo " (if you want, you could supply GIT_DIR then run" >&2 + echo " $0 )" >&2 + exit 1 +fi + +if [ -z "$refname" -o -z "$oldrev" -o -z "$newrev" ]; then + echo "usage: $0 " >&2 + exit 1 +fi + +# --- Config +allowunannotated=$(git config --type=bool hooks.allowunannotated) +allowdeletebranch=$(git config --type=bool hooks.allowdeletebranch) +denycreatebranch=$(git config --type=bool hooks.denycreatebranch) +allowdeletetag=$(git config --type=bool hooks.allowdeletetag) +allowmodifytag=$(git config --type=bool hooks.allowmodifytag) + +# check for no description +projectdesc=$(sed -e '1q' "$GIT_DIR/description") +case "$projectdesc" in +"Unnamed repository"* | "") + echo "*** Project description file hasn't been set" >&2 + exit 1 + ;; +esac + +# --- Check types +# if $newrev is 0000...0000, it's a commit to delete a ref. +zero=$(git hash-object --stdin &2 + echo "*** Use 'git tag [ -a | -s ]' for tags you want to propagate." >&2 + exit 1 + fi + ;; + refs/tags/*,delete) + # delete tag + if [ "$allowdeletetag" != "true" ]; then + echo "*** Deleting a tag is not allowed in this repository" >&2 + exit 1 + fi + ;; + refs/tags/*,tag) + # annotated tag + if [ "$allowmodifytag" != "true" ] && git rev-parse $refname > /dev/null 2>&1 + then + echo "*** Tag '$refname' already exists." >&2 + echo "*** Modifying a tag is not allowed in this repository." >&2 + exit 1 + fi + ;; + refs/heads/*,commit) + # branch + if [ "$oldrev" = "$zero" -a "$denycreatebranch" = "true" ]; then + echo "*** Creating a branch is not allowed in this repository" >&2 + exit 1 + fi + ;; + refs/heads/*,delete) + # delete branch + if [ "$allowdeletebranch" != "true" ]; then + echo "*** Deleting a branch is not allowed in this repository" >&2 + exit 1 + fi + ;; + refs/remotes/*,commit) + # tracking branch + ;; + refs/remotes/*,delete) + # delete tracking branch + if [ "$allowdeletebranch" != "true" ]; then + echo "*** Deleting a tracking branch is not allowed in this repository" >&2 + exit 1 + fi + ;; + *) + # Anything else (is there anything else?) + echo "*** Update hook: unknown type of update to ref $refname of type $newrev_type" >&2 + exit 1 + ;; +esac + +# --- Finished +exit 0 diff --git a/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libxml2/info/exclude b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libxml2/info/exclude new file mode 100644 index 0000000..a5196d1 --- /dev/null +++ b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libxml2/info/exclude @@ -0,0 +1,6 @@ +# git ls-files --others --exclude-from=.git/info/exclude +# Lines that start with '#' are comments. +# For a project mostly in C, the following would be a good set of +# exclude patterns (uncomment them if you want to use them): +# *.[oa] +# *~ diff --git a/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libxml2/objects/pack/pack-189babe75084b93e91d94f4064faa67076fb8a51.idx b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libxml2/objects/pack/pack-189babe75084b93e91d94f4064faa67076fb8a51.idx new file mode 100644 index 0000000..aeae7f4 Binary files /dev/null and b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libxml2/objects/pack/pack-189babe75084b93e91d94f4064faa67076fb8a51.idx differ diff --git a/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libxml2/objects/pack/pack-189babe75084b93e91d94f4064faa67076fb8a51.pack b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libxml2/objects/pack/pack-189babe75084b93e91d94f4064faa67076fb8a51.pack new file mode 100644 index 0000000..d5b48ef Binary files /dev/null and b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libxml2/objects/pack/pack-189babe75084b93e91d94f4064faa67076fb8a51.pack differ diff --git a/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libxml2/objects/pack/pack-189babe75084b93e91d94f4064faa67076fb8a51.rev b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libxml2/objects/pack/pack-189babe75084b93e91d94f4064faa67076fb8a51.rev new file mode 100644 index 0000000..b29360f Binary files /dev/null and b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libxml2/objects/pack/pack-189babe75084b93e91d94f4064faa67076fb8a51.rev differ diff --git a/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libxml2/refs/tags/v2.11.4 b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libxml2/refs/tags/v2.11.4 new file mode 100644 index 0000000..4fd6b60 --- /dev/null +++ b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libxml2/refs/tags/v2.11.4 @@ -0,0 +1 @@ +be5448432faaf7b108665fb2f4336c407dcecee9 diff --git a/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libxml2/shallow b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libxml2/shallow new file mode 100644 index 0000000..414a3ae --- /dev/null +++ b/.flatpak-builder/git/https_gitlab.gnome.org_GNOME_libxml2/shallow @@ -0,0 +1 @@ +2e9f7860a9cb8be29eca90b7409ef0278d30ef10 diff --git a/.flatpak-builder/git/https_gitlab.gnome.org_jwestman_blueprint-compiler/FETCH_HEAD b/.flatpak-builder/git/https_gitlab.gnome.org_jwestman_blueprint-compiler/FETCH_HEAD new file mode 100644 index 0000000..630ab00 --- /dev/null +++ b/.flatpak-builder/git/https_gitlab.gnome.org_jwestman_blueprint-compiler/FETCH_HEAD @@ -0,0 +1 @@ +7be787596e98a5dfd75175fb6b83eca09453b7f5 tag 'v0.8.1' of https://gitlab.gnome.org/jwestman/blueprint-compiler diff --git a/.flatpak-builder/git/https_gitlab.gnome.org_jwestman_blueprint-compiler/HEAD b/.flatpak-builder/git/https_gitlab.gnome.org_jwestman_blueprint-compiler/HEAD new file mode 100644 index 0000000..cb089cd --- /dev/null +++ b/.flatpak-builder/git/https_gitlab.gnome.org_jwestman_blueprint-compiler/HEAD @@ -0,0 +1 @@ +ref: refs/heads/master diff --git a/.flatpak-builder/git/https_gitlab.gnome.org_jwestman_blueprint-compiler/config b/.flatpak-builder/git/https_gitlab.gnome.org_jwestman_blueprint-compiler/config new file mode 100644 index 0000000..b182a79 --- /dev/null +++ b/.flatpak-builder/git/https_gitlab.gnome.org_jwestman_blueprint-compiler/config @@ -0,0 +1,9 @@ +[core] + repositoryformatversion = 0 + filemode = true + bare = true +[remote "origin"] + url = https://gitlab.gnome.org/jwestman/blueprint-compiler + fetch = +refs/*:refs/* +[transfer] + fsckObjects = 1 diff --git a/.flatpak-builder/git/https_gitlab.gnome.org_jwestman_blueprint-compiler/description b/.flatpak-builder/git/https_gitlab.gnome.org_jwestman_blueprint-compiler/description new file mode 100644 index 0000000..498b267 --- /dev/null +++ b/.flatpak-builder/git/https_gitlab.gnome.org_jwestman_blueprint-compiler/description @@ -0,0 +1 @@ +Unnamed repository; edit this file 'description' to name the repository. diff --git a/.flatpak-builder/git/https_gitlab.gnome.org_jwestman_blueprint-compiler/hooks/applypatch-msg.sample b/.flatpak-builder/git/https_gitlab.gnome.org_jwestman_blueprint-compiler/hooks/applypatch-msg.sample new file mode 100755 index 0000000..a5d7b84 --- /dev/null +++ b/.flatpak-builder/git/https_gitlab.gnome.org_jwestman_blueprint-compiler/hooks/applypatch-msg.sample @@ -0,0 +1,15 @@ +#!/bin/sh +# +# An example hook script to check the commit log message taken by +# applypatch from an e-mail message. +# +# The hook should exit with non-zero status after issuing an +# appropriate message if it wants to stop the commit. The hook is +# allowed to edit the commit message file. +# +# To enable this hook, rename this file to "applypatch-msg". + +. git-sh-setup +commitmsg="$(git rev-parse --git-path hooks/commit-msg)" +test -x "$commitmsg" && exec "$commitmsg" ${1+"$@"} +: diff --git a/.flatpak-builder/git/https_gitlab.gnome.org_jwestman_blueprint-compiler/hooks/commit-msg.sample b/.flatpak-builder/git/https_gitlab.gnome.org_jwestman_blueprint-compiler/hooks/commit-msg.sample new file mode 100755 index 0000000..b58d118 --- /dev/null +++ b/.flatpak-builder/git/https_gitlab.gnome.org_jwestman_blueprint-compiler/hooks/commit-msg.sample @@ -0,0 +1,24 @@ +#!/bin/sh +# +# An example hook script to check the commit log message. +# Called by "git commit" with one argument, the name of the file +# that has the commit message. The hook should exit with non-zero +# status after issuing an appropriate message if it wants to stop the +# commit. The hook is allowed to edit the commit message file. +# +# To enable this hook, rename this file to "commit-msg". + +# Uncomment the below to add a Signed-off-by line to the message. +# Doing this in a hook is a bad idea in general, but the prepare-commit-msg +# hook is more suited to it. +# +# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p') +# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1" + +# This example catches duplicate Signed-off-by lines. + +test "" = "$(grep '^Signed-off-by: ' "$1" | + sort | uniq -c | sed -e '/^[ ]*1[ ]/d')" || { + echo >&2 Duplicate Signed-off-by lines. + exit 1 +} diff --git a/.flatpak-builder/git/https_gitlab.gnome.org_jwestman_blueprint-compiler/hooks/fsmonitor-watchman.sample b/.flatpak-builder/git/https_gitlab.gnome.org_jwestman_blueprint-compiler/hooks/fsmonitor-watchman.sample new file mode 100755 index 0000000..23e856f --- /dev/null +++ b/.flatpak-builder/git/https_gitlab.gnome.org_jwestman_blueprint-compiler/hooks/fsmonitor-watchman.sample @@ -0,0 +1,174 @@ +#!/usr/bin/perl + +use strict; +use warnings; +use IPC::Open2; + +# An example hook script to integrate Watchman +# (https://facebook.github.io/watchman/) with git to speed up detecting +# new and modified files. +# +# The hook is passed a version (currently 2) and last update token +# formatted as a string and outputs to stdout a new update token and +# all files that have been modified since the update token. Paths must +# be relative to the root of the working tree and separated by a single NUL. +# +# To enable this hook, rename this file to "query-watchman" and set +# 'git config core.fsmonitor .git/hooks/query-watchman' +# +my ($version, $last_update_token) = @ARGV; + +# Uncomment for debugging +# print STDERR "$0 $version $last_update_token\n"; + +# Check the hook interface version +if ($version ne 2) { + die "Unsupported query-fsmonitor hook version '$version'.\n" . + "Falling back to scanning...\n"; +} + +my $git_work_tree = get_working_dir(); + +my $retry = 1; + +my $json_pkg; +eval { + require JSON::XS; + $json_pkg = "JSON::XS"; + 1; +} or do { + require JSON::PP; + $json_pkg = "JSON::PP"; +}; + +launch_watchman(); + +sub launch_watchman { + my $o = watchman_query(); + if (is_work_tree_watched($o)) { + output_result($o->{clock}, @{$o->{files}}); + } +} + +sub output_result { + my ($clockid, @files) = @_; + + # Uncomment for debugging watchman output + # open (my $fh, ">", ".git/watchman-output.out"); + # binmode $fh, ":utf8"; + # print $fh "$clockid\n@files\n"; + # close $fh; + + binmode STDOUT, ":utf8"; + print $clockid; + print "\0"; + local $, = "\0"; + print @files; +} + +sub watchman_clock { + my $response = qx/watchman clock "$git_work_tree"/; + die "Failed to get clock id on '$git_work_tree'.\n" . + "Falling back to scanning...\n" if $? != 0; + + return $json_pkg->new->utf8->decode($response); +} + +sub watchman_query { + my $pid = open2(\*CHLD_OUT, \*CHLD_IN, 'watchman -j --no-pretty') + or die "open2() failed: $!\n" . + "Falling back to scanning...\n"; + + # In the query expression below we're asking for names of files that + # changed since $last_update_token but not from the .git folder. + # + # To accomplish this, we're using the "since" generator to use the + # recency index to select candidate nodes and "fields" to limit the + # output to file names only. Then we're using the "expression" term to + # further constrain the results. + my $last_update_line = ""; + if (substr($last_update_token, 0, 1) eq "c") { + $last_update_token = "\"$last_update_token\""; + $last_update_line = qq[\n"since": $last_update_token,]; + } + my $query = <<" END"; + ["query", "$git_work_tree", {$last_update_line + "fields": ["name"], + "expression": ["not", ["dirname", ".git"]] + }] + END + + # Uncomment for debugging the watchman query + # open (my $fh, ">", ".git/watchman-query.json"); + # print $fh $query; + # close $fh; + + print CHLD_IN $query; + close CHLD_IN; + my $response = do {local $/; }; + + # Uncomment for debugging the watch response + # open ($fh, ">", ".git/watchman-response.json"); + # print $fh $response; + # close $fh; + + die "Watchman: command returned no output.\n" . + "Falling back to scanning...\n" if $response eq ""; + die "Watchman: command returned invalid output: $response\n" . + "Falling back to scanning...\n" unless $response =~ /^\{/; + + return $json_pkg->new->utf8->decode($response); +} + +sub is_work_tree_watched { + my ($output) = @_; + my $error = $output->{error}; + if ($retry > 0 and $error and $error =~ m/unable to resolve root .* directory (.*) is not watched/) { + $retry--; + my $response = qx/watchman watch "$git_work_tree"/; + die "Failed to make watchman watch '$git_work_tree'.\n" . + "Falling back to scanning...\n" if $? != 0; + $output = $json_pkg->new->utf8->decode($response); + $error = $output->{error}; + die "Watchman: $error.\n" . + "Falling back to scanning...\n" if $error; + + # Uncomment for debugging watchman output + # open (my $fh, ">", ".git/watchman-output.out"); + # close $fh; + + # Watchman will always return all files on the first query so + # return the fast "everything is dirty" flag to git and do the + # Watchman query just to get it over with now so we won't pay + # the cost in git to look up each individual file. + my $o = watchman_clock(); + $error = $output->{error}; + + die "Watchman: $error.\n" . + "Falling back to scanning...\n" if $error; + + output_result($o->{clock}, ("/")); + $last_update_token = $o->{clock}; + + eval { launch_watchman() }; + return 0; + } + + die "Watchman: $error.\n" . + "Falling back to scanning...\n" if $error; + + return 1; +} + +sub get_working_dir { + my $working_dir; + if ($^O =~ 'msys' || $^O =~ 'cygwin') { + $working_dir = Win32::GetCwd(); + $working_dir =~ tr/\\/\//; + } else { + require Cwd; + $working_dir = Cwd::cwd(); + } + + return $working_dir; +} diff --git a/.flatpak-builder/git/https_gitlab.gnome.org_jwestman_blueprint-compiler/hooks/post-update.sample b/.flatpak-builder/git/https_gitlab.gnome.org_jwestman_blueprint-compiler/hooks/post-update.sample new file mode 100755 index 0000000..ec17ec1 --- /dev/null +++ b/.flatpak-builder/git/https_gitlab.gnome.org_jwestman_blueprint-compiler/hooks/post-update.sample @@ -0,0 +1,8 @@ +#!/bin/sh +# +# An example hook script to prepare a packed repository for use over +# dumb transports. +# +# To enable this hook, rename this file to "post-update". + +exec git update-server-info diff --git a/.flatpak-builder/git/https_gitlab.gnome.org_jwestman_blueprint-compiler/hooks/pre-applypatch.sample b/.flatpak-builder/git/https_gitlab.gnome.org_jwestman_blueprint-compiler/hooks/pre-applypatch.sample new file mode 100755 index 0000000..4142082 --- /dev/null +++ b/.flatpak-builder/git/https_gitlab.gnome.org_jwestman_blueprint-compiler/hooks/pre-applypatch.sample @@ -0,0 +1,14 @@ +#!/bin/sh +# +# An example hook script to verify what is about to be committed +# by applypatch from an e-mail message. +# +# The hook should exit with non-zero status after issuing an +# appropriate message if it wants to stop the commit. +# +# To enable this hook, rename this file to "pre-applypatch". + +. git-sh-setup +precommit="$(git rev-parse --git-path hooks/pre-commit)" +test -x "$precommit" && exec "$precommit" ${1+"$@"} +: diff --git a/.flatpak-builder/git/https_gitlab.gnome.org_jwestman_blueprint-compiler/hooks/pre-commit.sample b/.flatpak-builder/git/https_gitlab.gnome.org_jwestman_blueprint-compiler/hooks/pre-commit.sample new file mode 100755 index 0000000..e144712 --- /dev/null +++ b/.flatpak-builder/git/https_gitlab.gnome.org_jwestman_blueprint-compiler/hooks/pre-commit.sample @@ -0,0 +1,49 @@ +#!/bin/sh +# +# An example hook script to verify what is about to be committed. +# Called by "git commit" with no arguments. The hook should +# exit with non-zero status after issuing an appropriate message if +# it wants to stop the commit. +# +# To enable this hook, rename this file to "pre-commit". + +if git rev-parse --verify HEAD >/dev/null 2>&1 +then + against=HEAD +else + # Initial commit: diff against an empty tree object + against=$(git hash-object -t tree /dev/null) +fi + +# If you want to allow non-ASCII filenames set this variable to true. +allownonascii=$(git config --type=bool hooks.allownonascii) + +# Redirect output to stderr. +exec 1>&2 + +# Cross platform projects tend to avoid non-ASCII filenames; prevent +# them from being added to the repository. We exploit the fact that the +# printable range starts at the space character and ends with tilde. +if [ "$allownonascii" != "true" ] && + # Note that the use of brackets around a tr range is ok here, (it's + # even required, for portability to Solaris 10's /usr/bin/tr), since + # the square bracket bytes happen to fall in the designated range. + test $(git diff --cached --name-only --diff-filter=A -z $against | + LC_ALL=C tr -d '[ -~]\0' | wc -c) != 0 +then + cat <<\EOF +Error: Attempt to add a non-ASCII file name. + +This can cause problems if you want to work with people on other platforms. + +To be portable it is advisable to rename the file. + +If you know what you are doing you can disable this check using: + + git config hooks.allownonascii true +EOF + exit 1 +fi + +# If there are whitespace errors, print the offending file names and fail. +exec git diff-index --check --cached $against -- diff --git a/.flatpak-builder/git/https_gitlab.gnome.org_jwestman_blueprint-compiler/hooks/pre-merge-commit.sample b/.flatpak-builder/git/https_gitlab.gnome.org_jwestman_blueprint-compiler/hooks/pre-merge-commit.sample new file mode 100755 index 0000000..399eab1 --- /dev/null +++ b/.flatpak-builder/git/https_gitlab.gnome.org_jwestman_blueprint-compiler/hooks/pre-merge-commit.sample @@ -0,0 +1,13 @@ +#!/bin/sh +# +# An example hook script to verify what is about to be committed. +# Called by "git merge" with no arguments. The hook should +# exit with non-zero status after issuing an appropriate message to +# stderr if it wants to stop the merge commit. +# +# To enable this hook, rename this file to "pre-merge-commit". + +. git-sh-setup +test -x "$GIT_DIR/hooks/pre-commit" && + exec "$GIT_DIR/hooks/pre-commit" +: diff --git a/.flatpak-builder/git/https_gitlab.gnome.org_jwestman_blueprint-compiler/hooks/pre-push.sample b/.flatpak-builder/git/https_gitlab.gnome.org_jwestman_blueprint-compiler/hooks/pre-push.sample new file mode 100755 index 0000000..4ce688d --- /dev/null +++ b/.flatpak-builder/git/https_gitlab.gnome.org_jwestman_blueprint-compiler/hooks/pre-push.sample @@ -0,0 +1,53 @@ +#!/bin/sh + +# An example hook script to verify what is about to be pushed. Called by "git +# push" after it has checked the remote status, but before anything has been +# pushed. If this script exits with a non-zero status nothing will be pushed. +# +# This hook is called with the following parameters: +# +# $1 -- Name of the remote to which the push is being done +# $2 -- URL to which the push is being done +# +# If pushing without using a named remote those arguments will be equal. +# +# Information about the commits which are being pushed is supplied as lines to +# the standard input in the form: +# +# +# +# This sample shows how to prevent push of commits where the log message starts +# with "WIP" (work in progress). + +remote="$1" +url="$2" + +zero=$(git hash-object --stdin &2 "Found WIP commit in $local_ref, not pushing" + exit 1 + fi + fi +done + +exit 0 diff --git a/.flatpak-builder/git/https_gitlab.gnome.org_jwestman_blueprint-compiler/hooks/pre-rebase.sample b/.flatpak-builder/git/https_gitlab.gnome.org_jwestman_blueprint-compiler/hooks/pre-rebase.sample new file mode 100755 index 0000000..6cbef5c --- /dev/null +++ b/.flatpak-builder/git/https_gitlab.gnome.org_jwestman_blueprint-compiler/hooks/pre-rebase.sample @@ -0,0 +1,169 @@ +#!/bin/sh +# +# Copyright (c) 2006, 2008 Junio C Hamano +# +# The "pre-rebase" hook is run just before "git rebase" starts doing +# its job, and can prevent the command from running by exiting with +# non-zero status. +# +# The hook is called with the following parameters: +# +# $1 -- the upstream the series was forked from. +# $2 -- the branch being rebased (or empty when rebasing the current branch). +# +# This sample shows how to prevent topic branches that are already +# merged to 'next' branch from getting rebased, because allowing it +# would result in rebasing already published history. + +publish=next +basebranch="$1" +if test "$#" = 2 +then + topic="refs/heads/$2" +else + topic=`git symbolic-ref HEAD` || + exit 0 ;# we do not interrupt rebasing detached HEAD +fi + +case "$topic" in +refs/heads/??/*) + ;; +*) + exit 0 ;# we do not interrupt others. + ;; +esac + +# Now we are dealing with a topic branch being rebased +# on top of master. Is it OK to rebase it? + +# Does the topic really exist? +git show-ref -q "$topic" || { + echo >&2 "No such branch $topic" + exit 1 +} + +# Is topic fully merged to master? +not_in_master=`git rev-list --pretty=oneline ^master "$topic"` +if test -z "$not_in_master" +then + echo >&2 "$topic is fully merged to master; better remove it." + exit 1 ;# we could allow it, but there is no point. +fi + +# Is topic ever merged to next? If so you should not be rebasing it. +only_next_1=`git rev-list ^master "^$topic" ${publish} | sort` +only_next_2=`git rev-list ^master ${publish} | sort` +if test "$only_next_1" = "$only_next_2" +then + not_in_topic=`git rev-list "^$topic" master` + if test -z "$not_in_topic" + then + echo >&2 "$topic is already up to date with master" + exit 1 ;# we could allow it, but there is no point. + else + exit 0 + fi +else + not_in_next=`git rev-list --pretty=oneline ^${publish} "$topic"` + /usr/bin/perl -e ' + my $topic = $ARGV[0]; + my $msg = "* $topic has commits already merged to public branch:\n"; + my (%not_in_next) = map { + /^([0-9a-f]+) /; + ($1 => 1); + } split(/\n/, $ARGV[1]); + for my $elem (map { + /^([0-9a-f]+) (.*)$/; + [$1 => $2]; + } split(/\n/, $ARGV[2])) { + if (!exists $not_in_next{$elem->[0]}) { + if ($msg) { + print STDERR $msg; + undef $msg; + } + print STDERR " $elem->[1]\n"; + } + } + ' "$topic" "$not_in_next" "$not_in_master" + exit 1 +fi + +<<\DOC_END + +This sample hook safeguards topic branches that have been +published from being rewound. + +The workflow assumed here is: + + * Once a topic branch forks from "master", "master" is never + merged into it again (either directly or indirectly). + + * Once a topic branch is fully cooked and merged into "master", + it is deleted. If you need to build on top of it to correct + earlier mistakes, a new topic branch is created by forking at + the tip of the "master". This is not strictly necessary, but + it makes it easier to keep your history simple. + + * Whenever you need to test or publish your changes to topic + branches, merge them into "next" branch. + +The script, being an example, hardcodes the publish branch name +to be "next", but it is trivial to make it configurable via +$GIT_DIR/config mechanism. + +With this workflow, you would want to know: + +(1) ... if a topic branch has ever been merged to "next". Young + topic branches can have stupid mistakes you would rather + clean up before publishing, and things that have not been + merged into other branches can be easily rebased without + affecting other people. But once it is published, you would + not want to rewind it. + +(2) ... if a topic branch has been fully merged to "master". + Then you can delete it. More importantly, you should not + build on top of it -- other people may already want to + change things related to the topic as patches against your + "master", so if you need further changes, it is better to + fork the topic (perhaps with the same name) afresh from the + tip of "master". + +Let's look at this example: + + o---o---o---o---o---o---o---o---o---o "next" + / / / / + / a---a---b A / / + / / / / + / / c---c---c---c B / + / / / \ / + / / / b---b C \ / + / / / / \ / + ---o---o---o---o---o---o---o---o---o---o---o "master" + + +A, B and C are topic branches. + + * A has one fix since it was merged up to "next". + + * B has finished. It has been fully merged up to "master" and "next", + and is ready to be deleted. + + * C has not merged to "next" at all. + +We would want to allow C to be rebased, refuse A, and encourage +B to be deleted. + +To compute (1): + + git rev-list ^master ^topic next + git rev-list ^master next + + if these match, topic has not merged in next at all. + +To compute (2): + + git rev-list master..topic + + if this is empty, it is fully merged to "master". + +DOC_END diff --git a/.flatpak-builder/git/https_gitlab.gnome.org_jwestman_blueprint-compiler/hooks/pre-receive.sample b/.flatpak-builder/git/https_gitlab.gnome.org_jwestman_blueprint-compiler/hooks/pre-receive.sample new file mode 100755 index 0000000..a1fd29e --- /dev/null +++ b/.flatpak-builder/git/https_gitlab.gnome.org_jwestman_blueprint-compiler/hooks/pre-receive.sample @@ -0,0 +1,24 @@ +#!/bin/sh +# +# An example hook script to make use of push options. +# The example simply echoes all push options that start with 'echoback=' +# and rejects all pushes when the "reject" push option is used. +# +# To enable this hook, rename this file to "pre-receive". + +if test -n "$GIT_PUSH_OPTION_COUNT" +then + i=0 + while test "$i" -lt "$GIT_PUSH_OPTION_COUNT" + do + eval "value=\$GIT_PUSH_OPTION_$i" + case "$value" in + echoback=*) + echo "echo from the pre-receive-hook: ${value#*=}" >&2 + ;; + reject) + exit 1 + esac + i=$((i + 1)) + done +fi diff --git a/.flatpak-builder/git/https_gitlab.gnome.org_jwestman_blueprint-compiler/hooks/prepare-commit-msg.sample b/.flatpak-builder/git/https_gitlab.gnome.org_jwestman_blueprint-compiler/hooks/prepare-commit-msg.sample new file mode 100755 index 0000000..10fa14c --- /dev/null +++ b/.flatpak-builder/git/https_gitlab.gnome.org_jwestman_blueprint-compiler/hooks/prepare-commit-msg.sample @@ -0,0 +1,42 @@ +#!/bin/sh +# +# An example hook script to prepare the commit log message. +# Called by "git commit" with the name of the file that has the +# commit message, followed by the description of the commit +# message's source. The hook's purpose is to edit the commit +# message file. If the hook fails with a non-zero status, +# the commit is aborted. +# +# To enable this hook, rename this file to "prepare-commit-msg". + +# This hook includes three examples. The first one removes the +# "# Please enter the commit message..." help message. +# +# The second includes the output of "git diff --name-status -r" +# into the message, just before the "git status" output. It is +# commented because it doesn't cope with --amend or with squashed +# commits. +# +# The third example adds a Signed-off-by line to the message, that can +# still be edited. This is rarely a good idea. + +COMMIT_MSG_FILE=$1 +COMMIT_SOURCE=$2 +SHA1=$3 + +/usr/bin/perl -i.bak -ne 'print unless(m/^. Please enter the commit message/..m/^#$/)' "$COMMIT_MSG_FILE" + +# case "$COMMIT_SOURCE,$SHA1" in +# ,|template,) +# /usr/bin/perl -i.bak -pe ' +# print "\n" . `git diff --cached --name-status -r` +# if /^#/ && $first++ == 0' "$COMMIT_MSG_FILE" ;; +# *) ;; +# esac + +# SOB=$(git var GIT_COMMITTER_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p') +# git interpret-trailers --in-place --trailer "$SOB" "$COMMIT_MSG_FILE" +# if test -z "$COMMIT_SOURCE" +# then +# /usr/bin/perl -i.bak -pe 'print "\n" if !$first_line++' "$COMMIT_MSG_FILE" +# fi diff --git a/.flatpak-builder/git/https_gitlab.gnome.org_jwestman_blueprint-compiler/hooks/push-to-checkout.sample b/.flatpak-builder/git/https_gitlab.gnome.org_jwestman_blueprint-compiler/hooks/push-to-checkout.sample new file mode 100755 index 0000000..af5a0c0 --- /dev/null +++ b/.flatpak-builder/git/https_gitlab.gnome.org_jwestman_blueprint-compiler/hooks/push-to-checkout.sample @@ -0,0 +1,78 @@ +#!/bin/sh + +# An example hook script to update a checked-out tree on a git push. +# +# This hook is invoked by git-receive-pack(1) when it reacts to git +# push and updates reference(s) in its repository, and when the push +# tries to update the branch that is currently checked out and the +# receive.denyCurrentBranch configuration variable is set to +# updateInstead. +# +# By default, such a push is refused if the working tree and the index +# of the remote repository has any difference from the currently +# checked out commit; when both the working tree and the index match +# the current commit, they are updated to match the newly pushed tip +# of the branch. This hook is to be used to override the default +# behaviour; however the code below reimplements the default behaviour +# as a starting point for convenient modification. +# +# The hook receives the commit with which the tip of the current +# branch is going to be updated: +commit=$1 + +# It can exit with a non-zero status to refuse the push (when it does +# so, it must not modify the index or the working tree). +die () { + echo >&2 "$*" + exit 1 +} + +# Or it can make any necessary changes to the working tree and to the +# index to bring them to the desired state when the tip of the current +# branch is updated to the new commit, and exit with a zero status. +# +# For example, the hook can simply run git read-tree -u -m HEAD "$1" +# in order to emulate git fetch that is run in the reverse direction +# with git push, as the two-tree form of git read-tree -u -m is +# essentially the same as git switch or git checkout that switches +# branches while keeping the local changes in the working tree that do +# not interfere with the difference between the branches. + +# The below is a more-or-less exact translation to shell of the C code +# for the default behaviour for git's push-to-checkout hook defined in +# the push_to_deploy() function in builtin/receive-pack.c. +# +# Note that the hook will be executed from the repository directory, +# not from the working tree, so if you want to perform operations on +# the working tree, you will have to adapt your code accordingly, e.g. +# by adding "cd .." or using relative paths. + +if ! git update-index -q --ignore-submodules --refresh +then + die "Up-to-date check failed" +fi + +if ! git diff-files --quiet --ignore-submodules -- +then + die "Working directory has unstaged changes" +fi + +# This is a rough translation of: +# +# head_has_history() ? "HEAD" : EMPTY_TREE_SHA1_HEX +if git cat-file -e HEAD 2>/dev/null +then + head=HEAD +else + head=$(git hash-object -t tree --stdin &2 + exit 1 +} + +unset GIT_DIR GIT_WORK_TREE +cd "$worktree" && + +if grep -q "^diff --git " "$1" +then + validate_patch "$1" +else + validate_cover_letter "$1" +fi && + +if test "$GIT_SENDEMAIL_FILE_COUNTER" = "$GIT_SENDEMAIL_FILE_TOTAL" +then + git config --unset-all sendemail.validateWorktree && + trap 'git worktree remove -ff "$worktree"' EXIT && + validate_series +fi diff --git a/.flatpak-builder/git/https_gitlab.gnome.org_jwestman_blueprint-compiler/hooks/update.sample b/.flatpak-builder/git/https_gitlab.gnome.org_jwestman_blueprint-compiler/hooks/update.sample new file mode 100755 index 0000000..c4d426b --- /dev/null +++ b/.flatpak-builder/git/https_gitlab.gnome.org_jwestman_blueprint-compiler/hooks/update.sample @@ -0,0 +1,128 @@ +#!/bin/sh +# +# An example hook script to block unannotated tags from entering. +# Called by "git receive-pack" with arguments: refname sha1-old sha1-new +# +# To enable this hook, rename this file to "update". +# +# Config +# ------ +# hooks.allowunannotated +# This boolean sets whether unannotated tags will be allowed into the +# repository. By default they won't be. +# hooks.allowdeletetag +# This boolean sets whether deleting tags will be allowed in the +# repository. By default they won't be. +# hooks.allowmodifytag +# This boolean sets whether a tag may be modified after creation. By default +# it won't be. +# hooks.allowdeletebranch +# This boolean sets whether deleting branches will be allowed in the +# repository. By default they won't be. +# hooks.denycreatebranch +# This boolean sets whether remotely creating branches will be denied +# in the repository. By default this is allowed. +# + +# --- Command line +refname="$1" +oldrev="$2" +newrev="$3" + +# --- Safety check +if [ -z "$GIT_DIR" ]; then + echo "Don't run this script from the command line." >&2 + echo " (if you want, you could supply GIT_DIR then run" >&2 + echo " $0 )" >&2 + exit 1 +fi + +if [ -z "$refname" -o -z "$oldrev" -o -z "$newrev" ]; then + echo "usage: $0 " >&2 + exit 1 +fi + +# --- Config +allowunannotated=$(git config --type=bool hooks.allowunannotated) +allowdeletebranch=$(git config --type=bool hooks.allowdeletebranch) +denycreatebranch=$(git config --type=bool hooks.denycreatebranch) +allowdeletetag=$(git config --type=bool hooks.allowdeletetag) +allowmodifytag=$(git config --type=bool hooks.allowmodifytag) + +# check for no description +projectdesc=$(sed -e '1q' "$GIT_DIR/description") +case "$projectdesc" in +"Unnamed repository"* | "") + echo "*** Project description file hasn't been set" >&2 + exit 1 + ;; +esac + +# --- Check types +# if $newrev is 0000...0000, it's a commit to delete a ref. +zero=$(git hash-object --stdin &2 + echo "*** Use 'git tag [ -a | -s ]' for tags you want to propagate." >&2 + exit 1 + fi + ;; + refs/tags/*,delete) + # delete tag + if [ "$allowdeletetag" != "true" ]; then + echo "*** Deleting a tag is not allowed in this repository" >&2 + exit 1 + fi + ;; + refs/tags/*,tag) + # annotated tag + if [ "$allowmodifytag" != "true" ] && git rev-parse $refname > /dev/null 2>&1 + then + echo "*** Tag '$refname' already exists." >&2 + echo "*** Modifying a tag is not allowed in this repository." >&2 + exit 1 + fi + ;; + refs/heads/*,commit) + # branch + if [ "$oldrev" = "$zero" -a "$denycreatebranch" = "true" ]; then + echo "*** Creating a branch is not allowed in this repository" >&2 + exit 1 + fi + ;; + refs/heads/*,delete) + # delete branch + if [ "$allowdeletebranch" != "true" ]; then + echo "*** Deleting a branch is not allowed in this repository" >&2 + exit 1 + fi + ;; + refs/remotes/*,commit) + # tracking branch + ;; + refs/remotes/*,delete) + # delete tracking branch + if [ "$allowdeletebranch" != "true" ]; then + echo "*** Deleting a tracking branch is not allowed in this repository" >&2 + exit 1 + fi + ;; + *) + # Anything else (is there anything else?) + echo "*** Update hook: unknown type of update to ref $refname of type $newrev_type" >&2 + exit 1 + ;; +esac + +# --- Finished +exit 0 diff --git a/.flatpak-builder/git/https_gitlab.gnome.org_jwestman_blueprint-compiler/info/exclude b/.flatpak-builder/git/https_gitlab.gnome.org_jwestman_blueprint-compiler/info/exclude new file mode 100644 index 0000000..a5196d1 --- /dev/null +++ b/.flatpak-builder/git/https_gitlab.gnome.org_jwestman_blueprint-compiler/info/exclude @@ -0,0 +1,6 @@ +# git ls-files --others --exclude-from=.git/info/exclude +# Lines that start with '#' are comments. +# For a project mostly in C, the following would be a good set of +# exclude patterns (uncomment them if you want to use them): +# *.[oa] +# *~ diff --git a/.flatpak-builder/git/https_gitlab.gnome.org_jwestman_blueprint-compiler/objects/pack/pack-5ea22841f13a34bf57fb3264329adb2cf4ffdf8c.idx b/.flatpak-builder/git/https_gitlab.gnome.org_jwestman_blueprint-compiler/objects/pack/pack-5ea22841f13a34bf57fb3264329adb2cf4ffdf8c.idx new file mode 100644 index 0000000..7aa2e55 Binary files /dev/null and b/.flatpak-builder/git/https_gitlab.gnome.org_jwestman_blueprint-compiler/objects/pack/pack-5ea22841f13a34bf57fb3264329adb2cf4ffdf8c.idx differ diff --git a/.flatpak-builder/git/https_gitlab.gnome.org_jwestman_blueprint-compiler/objects/pack/pack-5ea22841f13a34bf57fb3264329adb2cf4ffdf8c.pack b/.flatpak-builder/git/https_gitlab.gnome.org_jwestman_blueprint-compiler/objects/pack/pack-5ea22841f13a34bf57fb3264329adb2cf4ffdf8c.pack new file mode 100644 index 0000000..d13b04e Binary files /dev/null and b/.flatpak-builder/git/https_gitlab.gnome.org_jwestman_blueprint-compiler/objects/pack/pack-5ea22841f13a34bf57fb3264329adb2cf4ffdf8c.pack differ diff --git a/.flatpak-builder/git/https_gitlab.gnome.org_jwestman_blueprint-compiler/objects/pack/pack-5ea22841f13a34bf57fb3264329adb2cf4ffdf8c.rev b/.flatpak-builder/git/https_gitlab.gnome.org_jwestman_blueprint-compiler/objects/pack/pack-5ea22841f13a34bf57fb3264329adb2cf4ffdf8c.rev new file mode 100644 index 0000000..2434e1a Binary files /dev/null and b/.flatpak-builder/git/https_gitlab.gnome.org_jwestman_blueprint-compiler/objects/pack/pack-5ea22841f13a34bf57fb3264329adb2cf4ffdf8c.rev differ diff --git a/.flatpak-builder/git/https_gitlab.gnome.org_jwestman_blueprint-compiler/refs/tags/v0.8.1 b/.flatpak-builder/git/https_gitlab.gnome.org_jwestman_blueprint-compiler/refs/tags/v0.8.1 new file mode 100644 index 0000000..821465b --- /dev/null +++ b/.flatpak-builder/git/https_gitlab.gnome.org_jwestman_blueprint-compiler/refs/tags/v0.8.1 @@ -0,0 +1 @@ +7be787596e98a5dfd75175fb6b83eca09453b7f5 diff --git a/.flatpak-builder/git/https_gitlab.gnome.org_jwestman_blueprint-compiler/shallow b/.flatpak-builder/git/https_gitlab.gnome.org_jwestman_blueprint-compiler/shallow new file mode 100644 index 0000000..af1dd50 --- /dev/null +++ b/.flatpak-builder/git/https_gitlab.gnome.org_jwestman_blueprint-compiler/shallow @@ -0,0 +1 @@ +aa7679618e864748f4f4d8f15283906e712752fe diff --git a/1q b/1q new file mode 100644 index 0000000..10926e8 --- /dev/null +++ b/1q @@ -0,0 +1,675 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. + diff --git a/2 b/2 index 142bf99..3753aea 100644 --- a/2 +++ b/2 @@ -1,6 +1,12 @@ +<<<<<<< HEAD /* window.js * * Copyright 2023 Francisco Jeferson dos Santos Freires +======= +/* preferences.js + * + * Copyright 2023 francisco +>>>>>>> new-pomodoro * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,6 +25,7 @@ */ import GObject from 'gi://GObject'; +<<<<<<< HEAD import Adw from 'gi://Adw'; import Gio from 'gi://Gio'; import GLib from 'gi://GLib'; @@ -66,3 +73,66 @@ export const PomodoroWindow = GObject.registerClass({ } }); +======= +import Gtk from 'gi://Gtk'; +import Adw from 'gi://Adw'; +import Template from './ui/preferences.blp' assert { type: 'uri' }; + +export default class Preferences extends Adw.PreferencesWindow { + static { + GObject.registerClass({ + Template, + InternalChildren: [ + 'select_theme', + 'switch_run_in_background', + 'switch_play_sounds', + 'set_break_time_after_4_pomodoris', + 'set_break_time', + 'set_work_time', + ], + }, this); + } + constructor(application) { + super(); + this.Application = application; + this.transient_for = this.Application.active_window; + this.Application.settings.get_string('theme') === 'default' ? + this._select_theme.set_selected(2) : + this.Application.settings.get_string('theme') === 'dark' ? + this._select_theme.set_selected(1) : this._select_theme.set_selected(0); + this._switch_run_in_background.set_active(this.Application.settings.get_boolean('run-in-background')); + this._switch_play_sounds.set_active(this.Application.settings.get_boolean('play-sounds')); + + this.Application.settings.set_int('work-time', 10); + this.Application.settings.set_int('break-time', 10); + this.work_time = this.Application.settings.get_int('work-time'); + this.break_time = this.Application.settings.get_int('break-time'); + this.break_after_4_pomodoris = this.Application.settings.get_int('end-time-interval'); + this._set_work_time.set_value(Math.floor(this.work_time / 60) % 60); + this._set_break_time.set_value(Math.floor(this.break_time / 60) % 60); + this._set_break_time_after_4_pomodoris.set_value(Math.floor(this.break_after_4_pomodoris / 60) % 60); + + } + _change_theme(_item) { + const index = _item.get_selected(); + if (index === 0 || index === 1) { + this.Application.settings.set_string('theme', index === 0 ? 'light' : 'dark'); + } else { + this.Application.settings.set_string('theme', 'default'); + } + } + _on_boolean_state_set(widget, state) { + const setting = widget.get_name() + this.Application.settings.set_boolean(setting, state) + } + _on_work_time_changed(_spin_button) { + this.Application.settings.set_int('work-time', _spin_button.get_value() * 60) + } + _on_break_time_changed(_spin_button) { + this.Application.settings.set_int('break-time', _spin_button.get_value() * 60) + } + _on_break_time_after_4_pomodoris_changed(_spin_button) { + this.Application.settings.set_int('end-time-interval', _spin_button.get_value() * 60) + } +} +>>>>>>> new-pomodoro diff --git a/4 b/4 new file mode 100644 index 0000000..1914fe9 --- /dev/null +++ b/4 @@ -0,0 +1,238 @@ +/* timer.js + * + * Copyright 2023 francisco + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +import GObject from 'gi://GObject'; +import Gtk from 'gi://Gtk'; +import Adw from 'gi://Adw'; +import Gdk from 'gi://Gdk'; +import GLib from 'gi://GLib'; +import Template from './timer.blp' assert { type: 'uri' }; + +export default class Timer extends Adw.Bin { + static { + GObject.registerClass({ + Template, + InternalChildren: [ + "tag_label", + "tag_area", + "pomodoro_counts", + 'title_entry', + 'description_entry', + 'timer_label', + 'stack_timer_controls', + ] + }, this); + } + constructor() { + super(); + var sizeGroup = new Gtk.SizeGroup(Gtk.SizeGroupMode.Horizontal); + sizeGroup.add_widget(this._tag_area); + sizeGroup.add_widget(this._tag_label); + this._tag_area.set_draw_func(this._DrawTag); + + this.application = Gtk.Application.get_default(); + this.timer_running = false; + this.work_time = this.application.settings.get_int('work-time'); + this.break_time = this.application.settings.get_int('break-time'); + this.long_break = this.application.settings.get_int('long-break'); + this.sessions_long_break = this.application.settings.get_int('sessions-long-break'); + this.current_work_time = this.work_time; + this.current_break_time = this.break_time; + this.is_break_timer = false; + this.timer_state = null; + this._timer_label.set_text(this._format_timer()) + } + _get_date() { + const current_date = GLib.DateTime.new_now_local(); + const day_of_week = current_date.format('%A'); + const day_of_month = current_date.get_day_of_month(); + const month_of_year = current_date.format('%B'); + const year = current_date.get_year(); + return `${day_of_week}, ${day_of_month} ${_("of")} ${month_of_year} ${_("of")} ${year}` + } + _get_schedule() { + const hour = new GLib.DateTime().get_hour(); + const minute = new GLib.DateTime().get_minute(); + const second = new GLib.DateTime().get_second(); + return `${hour > 9 ? hour : '0' + hour}:${minute > 9 ? minute : '0' + minute}:${second > 9 ? second : '0' + second}` + } + _format_timer() { + let hours = Math.floor(Math.abs(this.current_work_time < 0 ? this.current_work_time + this.current_break_time : this.current_work_time) / 60 / 60) + let minutes = Math.floor(Math.abs(this.current_work_time < 0 ? this.current_work_time + this.current_break_time : this.current_work_time) / 60) % 60; + let seconds = Math.abs(this.current_work_time < 0 ? this.current_work_time + this.current_break_time : this.current_work_time) % 60; + + if (hours.toString().split('').length < 2) { + hours = `0${hours}` + } + if (minutes.toString().split('').length < 2) { + minutes = `0${minutes}` + } + if (seconds.toString().split('').length < 2) { + seconds = `0${seconds}` + } + return `${hours}:${minutes}:${seconds}` + } + _on_handler_timer() { + const title = this._title_entry.get_text(); + const description = this._description_entry.get_text(); + + this.application.timer_state === 'stopped' || this.application.timer_state === 'paused' ? + this.application.timer_state = 'running' : this.application.timer_state = 'paused'; + this._title_entry.editable = false; + this._description_entry.editable = false; + if (this.application.timer_state === 'running') { + if (!this.timer_running) { + const current_date = GLib.DateTime.new_now_local() + this.data = { + title: title ? title : `${_('Started at')} ${this._get_schedule()}`, + description, + work_time: 0, + break_time: 0, + date: { + day: current_date.get_day_of_year(), + week: current_date.get_week_of_year(), + month: current_date.get_month(), + display_date: this._get_date(), + }, + id: GLib.uuid_string_random(), + counts: 0, + } + this.timer_running = true; + GLib.timeout_add_seconds(GLib.PRIORITY_DEFAULT, 1, () => { + if (this.application.timer_state === 'stopped') { + if (!this.data) + return + const array = this.application.data; + array.push(this.data); + this.application.data = array; + this.application.save_data(); + this.data = null; + return GLib.SOURCE_REMOVE + } + if (this.application.timer_state === 'paused') { + if (!this.application.active_window.visible) + this.application.set_background_status(`Paused timer`) + return GLib.SOURCE_CONTINUE + } + + this.current_work_time-- + + if (this.current_work_time === this.work_time - 1) { + this._timer_label.get_style_context().remove_class('error'); + this.application.notify({ title: `${_("Pomodoro started")} - ${this.data.title}`, body: `${_("Description")}: ${this.data.description}\n${_("Created date")}: ${this.data.date.display_date}` }) + } else if (this.current_work_time === 0) { + this._timer_label.get_style_context().add_class('error'); + this.application.notify({ title: `${_("Pomodoro break time")} - ${this.data.title}`, body: `${_("Description")}: ${this.data.description}\n${_("Created date")}: ${this.data.date.display_date}` }) + this.application.sound({ name: 'complete', cancellable: null }) + } + + if (this.current_work_time > 0) { + this.data.work_time = this.data.work_time + 1 + if (!this.application.active_window.visible) + this.application.set_background_status(`Work time: ${this._format_timer()}`) + } else { + this.data.break_time = this.data.break_time + 1 + if (!this.application.active_window.visible) + this.application.set_background_status(`Break time: ${this._format_timer()}`) + } + + this._timer_label.set_text(this._format_timer()) + + if (this.current_work_time > (this.current_break_time * -1)) { + return GLib.SOURCE_CONTINUE + } + + this.application.timer_state = 'paused'; + this._stack_timer_controls.visible_child_name = 'paused_timer'; + this.current_work_time = this.work_time; + this.data.counts = this.data.counts + 1; + if (this.data.counts > 0) { + this._tag_label.set_label(`${this.data.counts}`); + this._pomodoro_counts.set_visible(true); + } + console.log(this.sessions_long_break, this.data.counts) + if (this.data.counts === this.sessions_long_break) { + this.current_break_time = this.long_break; + } + this.application.notify({ title: `${_("Pomodoro finished")} - ${this.data.title}`, body: `${_("Description")}: ${this.data.description}\n${_("Created date")}: ${this.data.date.display_date}` }) + this._timer_label.get_style_context().remove_class('error'); + this.application.sound({ name: 'alarm-clock-elapsed', cancellable: null }) + this._timer_label.set_text(this._format_timer()); + return GLib.SOURCE_CONTINUE + }) + } + this._stack_timer_controls.visible_child_name = 'running_timer'; + } else { + this._stack_timer_controls.visible_child_name = 'paused_timer'; + } + } + _on_reset_timer() { + this.work_time = this.application.settings.get_int('work-time'); + this.break_time = this.application.settings.get_int('break-time'); + this.long_break = this.application.settings.get_int('long-break'); + this.sessions_long_break = this.application.settings.get_int('sessions-long-break'); + this._pomodoro_counts.set_visible(false); + this.timer_running = false; + this.current_work_time = this.work_time; + this.current_break_time = this.break_time; + this._title_entry.editable = true; + this._description_entry.editable = true; + this._stack_timer_controls.visible_child_name = 'init_timer'; + this.data = null; + this._timer_label.get_style_context().remove_class('error'); + this._timer_label.set_text(this._format_timer()); + this.application.timer_state = 'stopped' + } + _on_stop_timer() { + this.work_time = this.application.settings.get_int('work-time'); + this.break_time = this.application.settings.get_int('break-time'); + this.long_break = this.application.settings.get_int('long-break'); + this.sessions_long_break = this.application.settings.get_int('sessions-long-break'); + this._pomodoro_counts.set_visible(false); + this.timer_running = false; + this._title_entry.set_text(''); + this._description_entry.set_text(''); + this.current_work_time = this.work_time; + this.current_break_time = this.break_time; + this._title_entry.editable = true; + this._description_entry.editable = true; + this._stack_timer_controls.visible_child_name = 'init_timer'; + this._timer_label.get_style_context().remove_class('error'); + this._timer_label.set_text(this._format_timer()); + if (this.data) { + const array = this.application.data; + array.push(this.data); + this.application.data = array; + this.application.save_data(); + } + this.data = null; + this.application.timer_state = 'stopped'; + } + _DrawTag(area, cr, width, height) { + const color = new Gdk.RGBA(); + color.parse('rgba(220 ,20 ,60 , 1)'); + Gdk.cairo_set_source_rgba(cr, color); + cr.arc(height / 2, height / 2, height / 2, 0.5 * Math.PI, 1.5 * Math.PI); + cr.arc(width - height / 2, height / 2, height / 2, -0.5 * Math.PI, 0.5 * Math.PI); + cr.closePath(); + cr.fill(); + } +} + diff --git a/README.md b/README.md index b1dbb7b..3f1472b 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,4 @@ +<<<<<<< HEAD Pomodoro ======= @@ -35,3 +36,8 @@ Copyright 2023 Ideve Core ===== Pomodoro is released under the terms of the GNU General Public License, either version 3.0 or, at your option, any later version. +======= +# pomodoro + +A description of this project. +>>>>>>> new-pomodoro diff --git a/data/icons/hicolor/scalable/apps/io.gitlab.idevecore.PomodoroDevel.svg b/data/icons/hicolor/scalable/apps/io.gitlab.idevecore.PomodoroDevel.svg new file mode 100644 index 0000000..17a5030 --- /dev/null +++ b/data/icons/hicolor/scalable/apps/io.gitlab.idevecore.PomodoroDevel.svg @@ -0,0 +1,122 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/data/icons/meson.build b/data/icons/meson.build index 02a194a..b6a6229 100644 --- a/data/icons/meson.build +++ b/data/icons/meson.build @@ -1,5 +1,8 @@ +<<<<<<< HEAD application_id = 'io.gitlab.idevecore.Pomodoro' +======= +>>>>>>> new-pomodoro scalable_dir = join_paths('hicolor', 'scalable', 'apps') install_data( join_paths(scalable_dir, ('@0@.svg').format(application_id)), @@ -8,6 +11,10 @@ install_data( symbolic_dir = join_paths('hicolor', 'symbolic', 'apps') install_data( +<<<<<<< HEAD join_paths(symbolic_dir, ('@0@-symbolic.svg').format(application_id)), +======= + join_paths(symbolic_dir, ('@0@-symbolic.svg').format('io.gitlab.idevecore.Pomodoro')), +>>>>>>> new-pomodoro install_dir: join_paths(get_option('datadir'), 'icons', symbolic_dir) ) diff --git a/data/io.gitlab.idevecore.Pomodoro.appdata.xml.in.in b/data/io.gitlab.idevecore.Pomodoro.appdata.xml.in.in new file mode 100644 index 0000000..55d5f08 --- /dev/null +++ b/data/io.gitlab.idevecore.Pomodoro.appdata.xml.in.in @@ -0,0 +1,87 @@ + + + @app_id@ + @app_id@.desktop + @app_id@ + CC0-1.0 + GPL-3.0-or-later + Pomodoro + Pomodoro is a productivity-focused timer + +

Pomodoro is a timer utility with rules, ideal for better productivity.

+
+ https://gitlab.com/idevecore/pomodoro + https://gitlab.com/idevecore/pomodoro/-/issues + https://ko-fi.com/idevecore + + + + +

In this version, some tweaks and functions were added, as well as bug removal, visibility and performance improvements.

+
    +
  • Pomodoro now works in the background.
  • +
  • Added preferences section.
  • +
  • Added theme choice and permission to run in background in preferences section.
  • +
  • The app's alarms and feedback sounds now use the system default.
  • +
+
+
+ + +

Pomodoro 1.0.0: Application launch

+
+
+
+ + 400 + + + keyboard + pointing + touch + + + + https://gitlab.com/idevecore/pomodoro/-/raw/main/data/screenshots/01.png + + + https://gitlab.com/idevecore/pomodoro/-/raw/main/data/screenshots/02.png + + + https://gitlab.com/idevecore/pomodoro/-/raw/main/data/screenshots/03.png + + + https://gitlab.com/idevecore/pomodoro/-/raw/main/data/screenshots/04.png + + + https://gitlab.com/idevecore/pomodoro/-/raw/main/data/screenshots/05.png + + + + none + none + none + none + none + none + none + none + none + none + none + none + none + none + none + none + none + none + none + none + none + none + + Ideve Core +
+ + diff --git a/data/io.gitlab.idevecore.Pomodoro.desktop.in.in b/data/io.gitlab.idevecore.Pomodoro.desktop.in.in new file mode 100644 index 0000000..50d008e --- /dev/null +++ b/data/io.gitlab.idevecore.Pomodoro.desktop.in.in @@ -0,0 +1,14 @@ +[Desktop Entry] +Name=Pomodoro +GenericName=Timer +TryExec=pomodoro +Exec=pomodoro +Icon=@app_id@ +Terminal=false +Type=Application +Categories=GNOME;GTK;Timer;Clock;StopWatch; +Keywords=timer;clocks;stopwatch; +StartupNotify=true +X-SingleMainWindow=true +X-Purism-FormFactor=Workstation;Mobile; + diff --git a/data/io.gitlab.idevecore.Pomodoro.gschema.xml b/data/io.gitlab.idevecore.Pomodoro.gschema.xml index ee0f03f..8d348dd 100644 --- a/data/io.gitlab.idevecore.Pomodoro.gschema.xml +++ b/data/io.gitlab.idevecore.Pomodoro.gschema.xml @@ -1,9 +1,19 @@ +<<<<<<< HEAD true +======= + + + true + + + true + +>>>>>>> new-pomodoro "default" @@ -13,5 +23,23 @@ "ascending" +<<<<<<< HEAD + + +======= + + 1500 + + + 300 + + + 1800 + + + 4 +
+ +>>>>>>> new-pomodoro diff --git a/data/meson.build b/data/meson.build index e0c127a..1b0ceea 100644 --- a/data/meson.build +++ b/data/meson.build @@ -1,9 +1,24 @@ +<<<<<<< HEAD desktop_file = i18n.merge_file( input: 'io.gitlab.idevecore.Pomodoro.desktop.in', output: 'io.gitlab.idevecore.Pomodoro.desktop', type: 'desktop', po_dir: '../po', install: true, +======= +desktop_conf = configuration_data() +desktop_conf.set('app_id', application_id) +desktop_file = i18n.merge_file( + input: configure_file( + input: files('io.gitlab.idevecore.Pomodoro.desktop.in.in'), + output: 'io.gitlab.idevecore.Pomodoro.desktop.in', + configuration: desktop_conf + ), + output: '@0@.desktop'.format(application_id), + po_dir: join_paths(meson.project_source_root(), 'po'), + type: 'desktop', po_dir: '../po', + install: true, +>>>>>>> new-pomodoro install_dir: join_paths(get_option('datadir'), 'applications') ) @@ -12,12 +27,27 @@ if desktop_utils.found() test('Validate desktop file', desktop_utils, args: [desktop_file]) endif +<<<<<<< HEAD appstream_file = i18n.merge_file( input: 'io.gitlab.idevecore.Pomodoro.appdata.xml.in', output: 'io.gitlab.idevecore.Pomodoro.appdata.xml', po_dir: '../po', install: true, install_dir: join_paths(get_option('datadir'), 'appdata') +======= +appstream_conf = configuration_data() +appstream_conf.set('app_id', application_id) +appstream_file = i18n.merge_file( + input: configure_file( + input: 'io.gitlab.idevecore.Pomodoro.appdata.xml.in.in', + output: 'io.gitlab.idevecore.Pomodoro.appdata.xml.in', + configuration: appstream_conf + ), + output: '@0@.metainfo.xml'.format(application_id), + po_dir: '../po', + install: true, + install_dir: datadir / 'metainfo' +>>>>>>> new-pomodoro ) appstream_util = find_program('appstream-util', required: false) @@ -25,8 +55,19 @@ if appstream_util.found() test('Validate appstream file', appstream_util, args: ['validate', appstream_file]) endif +<<<<<<< HEAD install_data('io.gitlab.idevecore.Pomodoro.gschema.xml', install_dir: join_paths(get_option('datadir'), 'glib-2.0/schemas') +======= +gschema_conf = configuration_data() +gschema_conf.set('app_id', application_id) +configure_file( + input: 'io.gitlab.idevecore.Pomodoro.gschema.xml', + output: '@0@.gschema.xml'.format(application_id), + configuration: gschema_conf, + install: true, + install_dir: datadir / 'glib-2.0/schemas' +>>>>>>> new-pomodoro ) compile_schemas = find_program('glib-compile-schemas', required: false) diff --git a/io.gitlab.idevecore.Pomodoro.json b/io.gitlab.idevecore.Pomodoro.json index 1568127..ff69de3 100644 --- a/io.gitlab.idevecore.Pomodoro.json +++ b/io.gitlab.idevecore.Pomodoro.json @@ -3,14 +3,22 @@ "runtime": "org.gnome.Platform", "runtime-version": "44", "sdk": "org.gnome.Sdk", +<<<<<<< HEAD "command": "io.gitlab.idevecore.Pomodoro", +======= + "command": "pomodoro", +>>>>>>> new-pomodoro "finish-args": [ "--share=network", "--share=ipc", "--socket=fallback-x11", "--device=dri", +<<<<<<< HEAD "--socket=wayland", "--socket=pulseaudio" +======= + "--socket=wayland" +>>>>>>> new-pomodoro ], "cleanup": [ "/include", @@ -25,6 +33,24 @@ ], "modules": [ { +<<<<<<< HEAD +======= + "name": "blueprint", + "buildsystem": "meson", + "cleanup": [ + "*" + ], + "sources": [ + { + "type": "git", + "url": "https://gitlab.gnome.org/jwestman/blueprint-compiler", + "tag": "v0.8.1", + "commit": "aa7679618e864748f4f4d8f15283906e712752fe" + } + ] + }, + { +>>>>>>> new-pomodoro "name": "gsound", "buildsystem": "meson", "sources": [ diff --git a/io.gitlab.idevecore.PomodoroDevel.json b/io.gitlab.idevecore.PomodoroDevel.json new file mode 100644 index 0000000..80d66b3 --- /dev/null +++ b/io.gitlab.idevecore.PomodoroDevel.json @@ -0,0 +1,139 @@ +{ + "app-id": "io.gitlab.idevecore.PomodoroDevel", + "runtime": "org.gnome.Platform", + "runtime-version": "44", + "sdk": "org.gnome.Sdk", + "command": "pomodoro", + "finish-args": [ + "--share=network", + "--share=ipc", + "--socket=fallback-x11", + "--device=dri", + "--socket=wayland", + "--socket=pulseaudio" + ], + "cleanup": [ + "/include", + "/lib/pkgconfig", + "/man", + "/share/doc", + "/share/gtk-doc", + "/share/man", + "/share/pkgconfig", + "*.la", + "*.a" + ], + "modules": [ + { + "name": "libgda", + "buildsystem": "meson", + "cleanup": [ + "*" + ], + "sources": [ + { + "type": "git", + "url": "https://gitlab.gnome.org/GNOME/libgda", + "tag": "LIBGDA_6_0_0", + "commit": "5d23892e1c8abd931ad2a7bd24cd543b93ccb04c" + } + ], + "modules": [ + { + "name": "intltool", + "cleanup": [ + "*" + ], + "sources": [ + { + "type": "archive", + "url": "https://launchpad.net/intltool/trunk/0.51.0/+download/intltool-0.51.0.tar.gz", + "sha256": "67c74d94196b153b774ab9f89b2fa6c6ba79352407037c8c14d5aeb334e959cd" + } + ] + } + ] + }, + { + "name": "blueprint", + "buildsystem": "meson", + "cleanup": [ + "*" + ], + "sources": [ + { + "type": "git", + "url": "https://gitlab.gnome.org/jwestman/blueprint-compiler", + "tag": "v0.8.1", + "commit": "aa7679618e864748f4f4d8f15283906e712752fe" + } + ] + }, + { + "name": "gsound", + "buildsystem": "meson", + "sources": [ + { + "type": "git", + "url": "https://gitlab.gnome.org/GNOME/gsound.git" + } + ], + "modules": [ + { + "name": "libcanberra", + "sources": [ + { + "type": "archive", + "url": "http://0pointer.de/lennart/projects/libcanberra/libcanberra-0.30.tar.xz", + "sha256": "c2b671e67e0c288a69fc33dc1b6f1b534d07882c2aceed37004bf48c601afa72" + } + ], + "config-opts": [ + "--disable-alsa", + "--disable-null", + "--disable-oss" + ] + } + ] + }, + { + "name": "sound-theme-freedesktop", + "sources": [ + { + "type": "archive", + "url": "http://people.freedesktop.org/~mccann/dist/sound-theme-freedesktop-0.8.tar.bz2", + "sha256": "cb518b20eef05ec2e82dda1fa89a292c1760dc023aba91b8aa69bafac85e8a14" + } + ], + "modules": [ + { + "name": "intltool", + "cleanup": [ + "*" + ], + "sources": [ + { + "type": "archive", + "url": "https://launchpad.net/intltool/trunk/0.51.0/+download/intltool-0.51.0.tar.gz", + "sha256": "67c74d94196b153b774ab9f89b2fa6c6ba79352407037c8c14d5aeb334e959cd" + } + ] + } + ] + }, + { + "name": "pomodoro", + "builddir": true, + "buildsystem": "meson", + "config-opts": [ + "-Dprofile=development" + ], + "sources": [ + { + "type": "git", + "url": "file:///home/francisco/Projetos" + } + ] + } + ] +} diff --git a/meson.build b/meson.build index 5ff2fa9..a3b6989 100644 --- a/meson.build +++ b/meson.build @@ -1,18 +1,60 @@ project('pomodoro', +<<<<<<< HEAD version: '1.1.0', meson_version: '>= 0.63.0', +======= + version: '1.2.0', + meson_version: '>= 0.63.0', +>>>>>>> new-pomodoro default_options: [ 'warning_level=2', 'werror=false', ], ) i18n = import('i18n') gnome = import('gnome') +<<<<<<< HEAD +======= +if get_option('profile') == 'development' + profile = 'Devel' + vcs_tag = run_command('git', 'rev-parse', '--short', 'HEAD', check: true).stdout().strip() + if vcs_tag == '' + version_suffix = '-devel' + else + version_suffix = '-@0@'.format (vcs_tag) + endif +else + profile = '' + version_suffix = '' +endif + +application_id = 'io.gitlab.idevecore.Pomodoro@0@'.format(profile) +version = meson.project_version() + version_suffix +prefix = get_option('prefix') +bindir = prefix / get_option('bindir') +libdir = prefix / get_option('libdir') +datadir = prefix / get_option('datadir') +pkgdatadir = datadir / application_id + +>>>>>>> new-pomodoro subdir('data') subdir('src') subdir('po') +<<<<<<< HEAD gnome.post_install( glib_compile_schemas: true, gtk_update_icon_cache: true, +======= + +install_symlink( + meson.project_name(), + pointing_to: pkgdatadir / application_id, + install_dir: bindir +) + +gnome.post_install( + glib_compile_schemas: true, + gtk_update_icon_cache: true, +>>>>>>> new-pomodoro update_desktop_database: true, ) diff --git a/meson_options.txt b/meson_options.txt new file mode 100644 index 0000000..a9e396d --- /dev/null +++ b/meson_options.txt @@ -0,0 +1,9 @@ +option( + 'profile', + type: 'combo', + choices: [ + 'default', + 'development' + ], + value: 'default' +) diff --git a/po/POTFILES b/po/POTFILES index 2c4b37d..3f930dd 100644 --- a/po/POTFILES +++ b/po/POTFILES @@ -4,3 +4,31 @@ data/io.gitlab.idevecore.Pomodoro.gschema.xml src/main.js src/window.js src/window.ui +<<<<<<< HEAD +======= + +src/ui/window.blp +src/application.js +src/ui/preferences.blp +src/preferences.js +src/ui/shortcuts.blp +src/shortcuts.js +src/ui/timer.blp +src/timer.js +src/utils.js +src/pages/preferences/preferences.blp +src/pages/preferences/preferences.js +src/window.blp +src/pages/shortcuts/shortcuts.blp +src/pages/shortcuts/shortcuts.js +src/pages/timer/timer.blp +src/pages/timer/timer.js +src/pages/statistics/statistics.js +src/pages/statistics/statistics.blp +src/pages/history/history.blp +src/pages/history/history.js +src/components/history-row/history-row.blp +src/components/history-row/history-row.js +src/bd.js +src/db.js +>>>>>>> new-pomodoro diff --git a/src/application.js b/src/application.js new file mode 100644 index 0000000..b283f4c --- /dev/null +++ b/src/application.js @@ -0,0 +1,235 @@ +/* application.js + * + * Copyright 2023 Ideve Core + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +import Adw from 'gi://Adw'; +import Gio from 'gi://Gio'; +import GLib from 'gi://GLib'; +import GObject from 'gi://GObject'; +import Gtk from 'gi://Gtk'; +import { gettext as _ } from 'gettext'; +import Window from './window.js'; +import Preferences from './pages/preferences/preferences.js'; +import Shortcuts from './pages/shortcuts/shortcuts.js'; +import Timer from './pages/timer/timer.js'; +import Statictics from './pages/statistics/statistics.js'; +import History from './pages/history/history.js'; +import Database from './db.js'; +import './style.css'; + +const database = new Database(); +database.setup(); + +console.log(database.save({ + title: 'hello', + description: 'hello', + workTime: 1231234, + breakTime: 346237, +})) + +export default class Application extends Adw.Application { + static { + GObject.registerClass(this); + } + constructor() { + super({ application_id: pkg.name, flags: Gio.ApplicationFlags.DEFAULT_FLAGS }); + + const quit_action = new Gio.SimpleAction({ name: 'quit' }); + const preferences_action = new Gio.SimpleAction({ name: 'preferences' }); + const shortcuts_action = new Gio.SimpleAction({ name: 'shortcuts' }); + const show_about_action = new Gio.SimpleAction({ name: 'about' }); + const active_action = new Gio.SimpleAction({ name: 'open' }); + this.settings = new Gio.Settings({ + schema_id: pkg.name, + path: '/io/gitlab/idevecore/Pomodoro/', + }); + this.timer_state = 'stopped'; + this.data = []; + + quit_action.connect('activate', () => { + if (this.active_window.visible) { + this.request_quit() + } else { + this.close_request() + } + }); + preferences_action.connect('activate', () => { + new Preferences(this).present(); + }); + shortcuts_action.connect('activate', () => { + new Shortcuts(this).present(); + }) + show_about_action.connect('activate', () => { + let aboutParams = { + transient_for: this.active_window, + application_name: 'Pomodoro', + application_icon: pkg.name, + developer_name: 'Ideve Core', + version: pkg.version, + developers: [ + 'Ideve Core' + ], + copyright: '© 2023 Ideve Core', + }; + const aboutWindow = new Adw.AboutWindow(aboutParams); + aboutWindow.present(); + }); + active_action.connect("activate", () => { + this.active_window.show(); + }) + + this.add_action(quit_action); + this.add_action(preferences_action); + this.add_action(shortcuts_action); + this.set_accels_for_action('app.quit', ['q']); + this.add_action(show_about_action); + this.add_action(active_action); + this.set_theme(); + this.settings.connect("changed::theme", this.set_theme.bind(this)); + this.load_data(); + } + request_quit() { + this.run_in_background = this.settings.get_boolean('run-in-background'); + if (!this.run_in_background) { + this.close_request() + return + } + if (this.timer_state === 'stopped') { + this.quit(); + return + } + this.active_window.hide() + if (!this.active_window) + return + } + close_request() { + let dialog = new Adw.MessageDialog(); + dialog.set_heading(_('Stop timer?')); + dialog.set_transient_for(this.active_window); + dialog.set_body(_('There is a running timer, wants to stop and exit the application?')); + dialog.add_response('continue', _('Continue')); + dialog.add_response('exit', _('Exit')); + dialog.set_response_appearance('exit', Adw.ResponseAppearance.DESTRUCTIVE); + + dialog.connect('response', (dialog, id) => { + if (id === 'exit') { + this.timer_state = 'stopped'; + setTimeout(() => { + this.quit() + }, 1000) + } + }) + if (this.timer_state === 'running' || this.timer_state == 'paused') { + return dialog.present() + } + this.quit() + } + set_theme() { + const style_manager = Adw.StyleManager.get_default() + if (this.settings.get_string('theme') === 'default') { + style_manager.set_color_scheme(Adw.ColorScheme.DEFAULT) + } else if (this.settings.get_string('theme') === 'dark') { + style_manager.set_color_scheme(Adw.ColorScheme.FORCE_DARK) + } else { + style_manager.set_color_scheme(Adw.ColorScheme.FORCE_LIGHT) + } + } + notify({ title, body }) { + const notification = new Gio.Notification(); + notification.set_title(title); + notification.set_body(body); + notification.set_priority('presence'); + notification.set_default_action("app.open"); + this.send_notification("lunch-is-ready", notification); + } + sound({ name, cancellable }) { + if (!this.settings.get_boolean('play-sounds')) return + return new Promise((resolve, reject) => { + this.gsound.play_full( + { 'event.id': name }, + cancellable, + (source, res) => { + try { + resolve(source.play_full_finish(res)); + } catch (e) { + reject(e); + } + } + ); + }); + } + set_background_status(message) { + const connection = Gio.DBus.session; + const messageVariant = new GLib.Variant('(a{sv})', [{ + 'message': new GLib.Variant('s', message) + }]); + connection.call( + 'org.freedesktop.portal.Desktop', + '/org/freedesktop/portal/desktop', + 'org.freedesktop.portal.Background', + 'SetStatus', + messageVariant, + null, + Gio.DBusCallFlags.NONE, + -1, + null, + (connection, res) => { + try { + connection.call_finish(res); + } catch (e) { + if (e instanceof Gio.DBusError) + Gio.DBusError.strip_remote_error(e); + + logError(e); + } + } + ); + } + save_data() { + const data_dir = GLib.get_user_config_dir(); + const destination = GLib.build_filenamev([data_dir, 'data.json']) + const destination_file = Gio.File.new_for_path(destination) + + destination_file.replace_contents(JSON.stringify(this.data), null, false, Gio.FileCreateFlags.REPLACE_DESTINATION, null); + } + load_data() { + const data_dir = GLib.get_user_config_dir(); + const destination = GLib.build_filenamev([data_dir, 'data.json']) + const destination_file = Gio.File.new_for_path(destination) + + try { + const [, contents] = destination_file.load_contents(null); + const decoder = new TextDecoder('utf-8'); + this.data = JSON.parse(decoder.decode(contents)); + } catch (error) { + destination_file.create(Gio.FileCreateFlags.NONE, null); + destination_file.replace_contents(JSON.stringify([]), null, false, Gio.FileCreateFlags.REPLACE_DESTINATION, null); + const [, contents] = destination_file.load_contents(null); + const decoder = new TextDecoder('utf-8'); + this.data = JSON.parse(decoder.decode(contents)); + } + } + vfunc_activate() { + let { active_window } = this; + if (!active_window) { + active_window = new Window(this); + } + active_window.present(); + } +}; diff --git a/src/components/history-row/history-row.blp b/src/components/history-row/history-row.blp new file mode 100644 index 0000000..4446332 --- /dev/null +++ b/src/components/history-row/history-row.blp @@ -0,0 +1,47 @@ +using Gtk 4.0; +using Adw 1; + +template $Gjs_HistoryRow : Adw.ExpanderRow { + [action] + Gtk.CheckButton selection { + styles ["selection-mode"] + visible: false; + } + + Adw.ActionRow { + title: _("Work time"); + title-lines: 1; + Gtk.Label work_time { + styles ["accent", "dim-label"] + ellipsize: end; + label: "00:00:00"; + } + } + Adw.ActionRow { + title: _("Break time"); + title-lines: 1; + Gtk.Label break_time { + styles ["error", "dim-label"] + ellipsize: end; + label: "00:00:00"; + } + } + Adw.ActionRow description { + styles ["property"] + title: _("Description"); + subtitle-selectable: true; + } + Adw.ActionRow { + styles ["dim-label"] + title: _("Quantities of pomodoros"); + title-lines: 1; + Gtk.Label counts { + ellipsize: end; + } + } + Gtk.Button { + styles ["destructive-action"] + label: _("Remove"); + clicked => $_on_remove_item(); + } +} diff --git a/src/components/history-row/history-row.js b/src/components/history-row/history-row.js new file mode 100644 index 0000000..e6c181f --- /dev/null +++ b/src/components/history-row/history-row.js @@ -0,0 +1,82 @@ +/* history-row.js + * + * Copyright 2023 Ideve Core + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +import GObject from 'gi://GObject'; +import Gtk from 'gi://Gtk'; +import Adw from 'gi://Adw'; +import Template from './history-row.blp' assert { type: 'uri' }; + +export default class HistoryRow extends Adw.ExpanderRow { + static { + GObject.registerClass({ + Template, + InternalChildren: [ + 'work_time', + 'break_time', + 'description', + 'counts', + 'selection', + ], + }, this); + } + constructor(history, item, index) { + super(); + this.application = Gtk.Application.get_default(); + this.item = item; + this.index = index; + this.set_title(this.item.title.toString()); + this.set_subtitle(this.item.date.display_date.toString()); + this._work_time.set_text(this._format_time(this.item.work_time).toString()); + this._break_time.set_text(this._format_time(this.item.break_time).toString()); + this._description.set_subtitle(this.item.description.toString()); + this._counts.set_text(this.item.counts.toString()); + this.history = history; + this.selected = false; + this._selection.connect('toggled', (action, value) => { + this.selected = this._selection.active; + this.history._on_selected(); + }) + } + + _format_time(timer) { + let hours = Math.floor(timer / 60 / 60) + let minutes = Math.floor(timer / 60) % 60; + let seconds = timer % 60; + + if (hours.toString().split('').length < 2) { + hours = `0${hours}` + } + if (minutes.toString().split('').length < 2) { + minutes = `0${minutes}` + } + if (seconds.toString().split('').length < 2) { + seconds = `0${seconds}` + } + return `${hours}:${minutes}:${seconds}` + } + _on_remove_item() { + this.application.data = this.application.data.filter((item) => item !== this.item); + this.application.save_data(); + this.history.load_list(); + } + _toggle_active_selection() { + this._selection.set_visible(this.history.activated_selection) + } +} diff --git a/src/db.js b/src/db.js new file mode 100644 index 0000000..2095694 --- /dev/null +++ b/src/db.js @@ -0,0 +1,108 @@ +import GLib from 'gi://GLib'; +import Gda from 'gi://Gda'; +import Gio from 'gi://Gio'; + +// const data_dir = GLib.get_user_config_dir(); +// const connection = new Gda.Connection({ +// provider: Gda.Config.get_provider('SQLite'), +// cnc_string: `DB_DIR=${data_dir};DB_NAME=pomodoro`, +// }); + +// connection.open(); + +// console.log(connection); + + +export default class Database { + constructor() { + this.database_dir = GLib.get_user_config_dir(); + this.connection = null; + } + init() { + this.connection = new Gda.Connection({ + provider: Gda.Config.get_provider('SQLite'), + cnc_string: `DB_DIR=${this.database_dir};DB_NAME=pomodoro`, + }) + this.connection.open(); + } + setup() { + this.init(); + if (!this.connection || !this.connection.is_opened()) { + debug('connection is not opened'); + return; + } + + this.connection.execute_non_select_command(` + create table if not exists history + ( + id integer not null constraint clipboard_pk primary key autoincrement, + title text not null, + description text not null, + workTime integer not null, + breakTime integer not null + ); + `); + + this.connection.execute_non_select_command(` + create unique index if not exists clipboard_id_uindex on clipboard (id); + `); + } + save(dbItem) { + if (!this.connection || !this.connection.is_opened()) { + console.log('connection is not opened'); + return null; + } + + const builder = new Gda.SqlBuilder({ + stmt_type: Gda.SqlStatementType.INSERT, + }); + + builder.set_table('history'); + builder.add_field_value_as_gvalue('title', dbItem.title); + builder.add_field_value_as_gvalue('description', dbItem.description); + builder.add_field_value_as_gvalue('workTime', dbItem.workTime); + builder.add_field_value_as_gvalue('breakTime', +dbItem.breakTime); + const [_, row] = this.connection.statement_execute_non_select(builder.get_statement(), null); + const id = row.get_nth_holder(0).get_value(); + if (!id) { + return null; + } + return { + id, + title: dbItem.title, + description: dbItem.description, + workTime: dbItem.workTime, + breakTime: dbItem.breakTime, + }; + } + query(clipboardQuery) { + if (!this.connection || !this.connection.is_opened()) { + return []; + } + + const dm = this.connection.statement_execute_select(clipboardQuery.statement, null); + + const iter = dm.create_iter(); + const itemList = []; + + while (iter.move_next()) { + const id = iter.get_value_for_field('id'); + const itemType = iter.get_value_for_field('title'); + const content = iter.get_value_for_field('description'); + const copyDate = iter.get_value_for_field('workTime'); + const isFavorite = iter.get_value_for_field('breakTime'); + + itemList.push({ + id, + itemType, + content, + copyDate: new Date(copyDate), + isFavorite: !!isFavorite, + }); + } + + return itemList; + } +} + + diff --git a/src/icons/check-round-outline-whole-symbolic.svg b/src/icons/check-round-outline-whole-symbolic.svg new file mode 100644 index 0000000..baad4bd --- /dev/null +++ b/src/icons/check-round-outline-whole-symbolic.svg @@ -0,0 +1,2 @@ + + diff --git a/src/icons/hourglass-symbolic.svg b/src/icons/hourglass-symbolic.svg new file mode 100644 index 0000000..025ae1c --- /dev/null +++ b/src/icons/hourglass-symbolic.svg @@ -0,0 +1,2 @@ + + diff --git a/src/icons/meson.build b/src/icons/meson.build new file mode 100644 index 0000000..fdbf04f --- /dev/null +++ b/src/icons/meson.build @@ -0,0 +1,14 @@ +install_data( + [ + 'background-app-ghost-symbolic.svg', + 'dark-mode-symbolic.svg', + 'history-undo-symbolic.svg', + 'hourglass-symbolic.svg', + 'profit-symbolic.svg', + 'sound-wave-symbolic.svg', + 'user-trash-symbolic.svg', + 'user-trash-full-symbolic.svg', + 'check-round-outline-whole-symbolic.svg', + ], + install_dir: datadir / 'icons/hicolor/scalable/status', +) diff --git a/src/icons/sound-wave-symbolic.svg b/src/icons/sound-wave-symbolic.svg new file mode 100644 index 0000000..cc4ddbe --- /dev/null +++ b/src/icons/sound-wave-symbolic.svg @@ -0,0 +1,2 @@ + + diff --git a/src/icons/user-trash-full-symbolic.svg b/src/icons/user-trash-full-symbolic.svg index 3f2ef2d..f647197 100644 --- a/src/icons/user-trash-full-symbolic.svg +++ b/src/icons/user-trash-full-symbolic.svg @@ -1,3 +1,7 @@ +<<<<<<< HEAD +======= + +>>>>>>> new-pomodoro diff --git a/src/icons/user-trash-symbolic.svg b/src/icons/user-trash-symbolic.svg index 352bc33..78950df 100644 --- a/src/icons/user-trash-symbolic.svg +++ b/src/icons/user-trash-symbolic.svg @@ -1,3 +1,7 @@ +<<<<<<< HEAD +======= + +>>>>>>> new-pomodoro diff --git a/src/io.gitlab.idevecore.Pomodoro b/src/io.gitlab.idevecore.Pomodoro new file mode 100755 index 0000000..db5a85d --- /dev/null +++ b/src/io.gitlab.idevecore.Pomodoro @@ -0,0 +1,25 @@ +#!@GJS@ -m +import { exit, programArgs, programInvocationName } from "system"; +import { setConsoleLogDomain } from "console"; +import Gio from "gi://Gio"; +import GLib from "gi://GLib"; + +imports.package.init({ + name: "@app_id@", + version: "@version@", + prefix: "@prefix@", + libdir: "@libdir@", + datadir: "@datadir@", +}); + +setConsoleLogDomain(pkg.name); + +const resource = Gio.resource_load( + "@datadir@/@app_id@/io.gitlab.idevecore.Pomodoro@profile@.src.gresource", +); + +Gio.resources_register(resource); + +const { main } = await import("resource://io/gitlab/idevecore/Pomodoro@profile@/main.js"); +const exit_code = await main([programInvocationName, ...programArgs]); +exit(exit_code); diff --git a/src/main.js b/src/main.js index a389e2f..a1e0d1e 100644 --- a/src/main.js +++ b/src/main.js @@ -18,6 +18,7 @@ * SPDX-License-Identifier: GPL-3.0-or-later */ +<<<<<<< HEAD import GObject from 'gi://GObject'; import Gio from 'gi://Gio'; import Adw from 'gi://Adw?version=1'; @@ -101,8 +102,23 @@ export const PomodoroApplication = GObject.registerClass( export function main(argv) { const application = new PomodoroApplication(); +======= +import GLib from 'gi://GLib?version=2.0' +import Application from "./application.js"; +import GSound from 'gi://GSound'; + +pkg.initGettext(); +GLib.set_application_name('Pomodoro'); + +export function main(argv) { + const application = new Application(); +>>>>>>> new-pomodoro const gsound = new GSound.Context(); gsound.init(null); application.gsound = gsound; return application.runAsync(argv); } +<<<<<<< HEAD +======= + +>>>>>>> new-pomodoro diff --git a/src/meson.build b/src/meson.build index cc1dcf5..2ddf612 100644 --- a/src/meson.build +++ b/src/meson.build @@ -1,3 +1,4 @@ +<<<<<<< HEAD pkgdatadir = join_paths(get_option('datadir'), meson.project_name()) gnome = import('gnome') @@ -13,10 +14,32 @@ data_res = gnome.compile_resources('io.gitlab.idevecore.Pomodoro.data', gresource_bundle: true, install: true, install_dir: pkgdatadir, +======= +blueprint_compiler = find_program('blueprint-compiler') +gjspack = find_program('../troll/gjspack/bin/gjspack') +gresource = custom_target('gjspack', + input: ['main.js', '../po/POTFILES'], + output: application_id + '.src.gresource', + command: [ + gjspack, + '--appid=' + application_id, + '--project-root', meson.source_root(), + '--resource-root', meson.project_source_root() / 'src', + '--blueprint-compiler', blueprint_compiler, + '--no-executable', + '@INPUT0@', + '--potfiles', '@INPUT1@', + '@OUTDIR@', + ], + install: true, + install_dir: pkgdatadir, + build_always_stale: true, +>>>>>>> new-pomodoro ) bin_conf = configuration_data() bin_conf.set('GJS', find_program('gjs').full_path()) +<<<<<<< HEAD bin_conf.set('PACKAGE_VERSION', meson.project_version()) bin_conf.set('PACKAGE_NAME', meson.project_name()) bin_conf.set('prefix', get_option('prefix')) @@ -31,3 +54,21 @@ configure_file( install: true, install_dir: get_option('bindir') ) +======= +bin_conf.set('version', version) +bin_conf.set('profile', profile) +bin_conf.set('app_id', application_id) +bin_conf.set('prefix', prefix) +bin_conf.set('libdir', libdir) +bin_conf.set('datadir', datadir) + +configure_file( + input: 'io.gitlab.idevecore.Pomodoro', + output: application_id, + configuration: bin_conf, + install: true, + install_dir: pkgdatadir +) + +subdir('icons') +>>>>>>> new-pomodoro diff --git a/src/mydb.db b/src/mydb.db new file mode 100644 index 0000000..e69de29 diff --git a/src/pages/history/history.blp b/src/pages/history/history.blp new file mode 100644 index 0000000..ed6588b --- /dev/null +++ b/src/pages/history/history.blp @@ -0,0 +1,125 @@ +using Gtk 4.0; +using Adw 1; + +template $Gjs_History : Adw.Bin { + Gtk.Box { + orientation: vertical; + Adw.Clamp { + halign: center; + Gtk.Box { + orientation: vertical; + Gtk.Box { + margin-start: 12; + margin-end: 12; + Gtk.Box { + orientation: vertical; + halign: start; + Gtk.Label total_work_time { + styles ["title-4", "accent"] + } + Gtk.Label total_break_time { + styles ["title-5", "error"] + } + } + Gtk.Box { + hexpand: true; + halign: end; + margin-start: 10; + Gtk.Button delete_button { + styles ["error"] + valign: center; + icon-name: "user-trash-symbolic"; + sensitive: false; + visible: false; + margin-end: 10; + clicked => $_on_delete(); + } + Gtk.Button { + valign: center; + icon-name: "check-round-outline-whole-symbolic"; + margin-end: 10; + clicked => $_on_active_selection(); + } + Gtk.MenuButton { + menu-model: sorting_menu; + always-show-arrow: true; + valign: center; + child: + Adw.ButtonContent sorting_button_content { + icon-name: "view-sort-descending-symbolic"; + label: _("Date"); + }; + } + } + } + } + } + Gtk.Separator { + margin-bottom: 2; + } + Gtk.Stack stack { + transition-type: crossfade; + vexpand: true; + Gtk.StackPage { + name: "no_history"; + child: + Adw.StatusPage { + icon-name: "history-undo-symbolic"; + Gtk.Button { + styles ["suggested-action", "pill"] + label: _("Add new pomodoro"); + use-underline: true; + halign: center; + clicked => $_on_navigate(); + } + }; + } + Gtk.StackPage { + name: "history"; + child: + Gtk.ScrolledWindow { + Adw.Clamp { + valign: start; + halign: center; + Gtk.ListBox list_box { + styles ["boxed-list"] + valign: start; + margin-bottom: 12; + margin-start: 12; + margin-end: 12; + selection-mode: none; + } + } + }; + } + } + } +} + +menu sorting_menu { + section { + item { + label: _("Name"); + action: "sort.sort"; + target: "name"; + } + item { + label: _("Date"); + action: "sort.sort"; + target: "date"; + } + } + section { + item { + label: _("Ascending"); + action: "sort.order"; + target: "ascending"; + } + item { + label: _("Descending"); + action: "sort.order"; + target: "descending"; + } + } +} + diff --git a/src/pages/history/history.js b/src/pages/history/history.js new file mode 100644 index 0000000..f6010ea --- /dev/null +++ b/src/pages/history/history.js @@ -0,0 +1,197 @@ +/* history.js + * + * Copyright 2023 Ideve Core + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +import GObject from 'gi://GObject'; +import Gtk from 'gi://Gtk'; +import Adw from 'gi://Adw'; +import GLib from 'gi://GLib'; +import Gio from 'gi://Gio'; +import HistoryRow from '../../components/history-row/history-row.js'; +import Template from './history.blp' assert { type: 'uri' }; +import { format_time } from '../../utils.js'; + +export default class History extends Adw.Bin { + static { + GObject.registerClass({ + Template, + InternalChildren: [ + 'stack', + 'list_box', + 'total_work_time', + 'total_break_time', + 'delete_button', + 'sorting_button_content', + ] + }, this); + } + constructor() { + super(); + this.application = Gtk.Application.get_default(); + this._list = []; + this.sort_by = this.application.settings.get_string('sort-by'); + this.order_by = this.application.settings.get_string('order-by'); + const load = new Gio.SimpleAction({ name: 'load' }); + const action_group = new Gio.SimpleActionGroup(); + action_group.insert(load); + this.activated_selection = false; + const sort_action_group = new Gio.SimpleActionGroup(); + this.insert_action_group('sort', sort_action_group); + const sort_action = new Gio.SimpleAction({ name: 'sort', parameter_type: new GLib.VariantType('s') }); + const order_action = new Gio.SimpleAction({ name: 'order', parameter_type: new GLib.VariantType('s') }); + sort_action_group.add_action(sort_action); + sort_action_group.add_action(order_action); + + const load_sorting_button_content = () => { + this._sorting_button_content.set_label(_(this.capitalize(this.sort_by))); + this._sorting_button_content.set_icon_name(this.order_by === 'ascending' ? 'view-sort-ascending-symbolic' : 'view-sort-descending-symbolic'); + } + + load_sorting_button_content() + + sort_action.connect('activate', (action, parameter) => { + let items = [] + this.application.data.forEach((item, index) => { + items.push(this._list_box.get_row_at_index(index)) + }) + items.forEach((item) => { + this._list_box.remove(item) + }) + let sort_by = parameter.deep_unpack(); + this.application.settings.set_string('sort-by', sort_by); + this.sort_by = this.application.settings.get_string('sort-by'); + load_sorting_button_content() + this._list = [] + this.load_list() + }); + + order_action.connect('activate', (action, parameter) => { + let items = [] + this.application.data.forEach((item, index) => { + items.push(this._list_box.get_row_at_index(index)) + }) + items.forEach((item) => { + this._list_box.remove(item) + }) + let sort_by = parameter.deep_unpack(); + this.application.settings.set_string('order-by', sort_by); + this.order_by = this.application.settings.get_string('order-by'); + load_sorting_button_content() + this._list = [] + this.load_list() + }) + this.load_list(); + } + load_list() { + if (this.sort_by === 'name') { + this.application.dat = this.application.data.sort((a, b) => a.title.localeCompare(b.title)) + } else if (this.sort_by === 'date') { + this.application.data = this.application.data.sort((a, b) => a.date.day - b.date.day); + } + + if (this.order_by === 'descending') { + this.application.data = this.application.data.slice(0).reverse() + } + + this.load_time(this.application.data); + if (this.application.data.length === 0) + return this._stack.visible_child_name = "no_history"; + + this._stack.visible_child_name = "history"; + if (this._list.length === 0) { + this.application.data.forEach((item, index) => { + const row = new HistoryRow(this, item, index); + this._list_box.append(row); + this._list.push({ + title: item.title, + row: row, + }) + }); + return + } + const remove_items = this._list.filter(element => this.application.data.findIndex(array_item => array_item.id === element.row.item.id) < 0); + this.application.data.forEach((item, index) => { + const finded = this._list.find(array_item => array_item.row.item.id === item.id); + if (finded) + return + const row = new HistoryRow(this, item, index); + this._list_box.append(row); + this._list.push({ + title: item.title, + row: row, + }) + }) + if (remove_items.length > 0) { + remove_items.forEach((item) => { + this._list_box.remove(item.row) + this._list = this._list.filter((array_item) => array_item !== item) + }) + } + } + load_time(time) { + const total_work_timer = time.reduce((accumulator, current_value) => accumulator + current_value.work_time, 0); + const total_break_timer = time.reduce((accumulator, current_value) => accumulator + current_value.break_time, 0); + this._total_work_time.set_text(`${_("Total work")}: ${format_time(total_work_timer)}`) + this._total_break_time.set_text(`${_("Total break")}: ${format_time(total_break_timer)}`) + } + capitalize(str, lower = false) { + return (lower ? str.toLowerCase() : str).replace(/(?:^|\s|["'([{])+\S/g, match => match.toUpperCase()); + } + _on_delete() { + const selecteds = this._list.filter((item) => item.row.selected === true); + const new_data = this.application.data.filter((item) => !(selecteds.find((selected_item) => selected_item.row.item === item) ? true : false)); + this.application.data = new_data; + this.application.save_data(); + this.load_list(); + this._delete_button.set_sensitive(false) + this._delete_button.set_icon_name('user-trash-symbolic'); + this._on_active_selection(); + } + _on_selected() { + const selecteds = this._list.filter((item) => item.row.selected === true); + let value = []; + selecteds.forEach((item) => { + value.push(item.row.item); + }) + this.load_time(value); + if (value.length > 0) { + this._delete_button.set_icon_name('user-trash-full-symbolic'); + this._delete_button.set_sensitive(true); + } else { + this._delete_button.set_icon_name('user-trash-symbolic'); + this._delete_button.set_sensitive(false); + } + } + _on_active_selection() { + this.activated_selection = !this.activated_selection; + this._list.forEach((item) => { + item.row._toggle_active_selection() + }); + if (!this.activated_selection) { + this.load_time(this.application.data); + this._delete_button.set_visible(false) + } else { + this.load_time([]) + this._delete_button.set_visible(true) + } + } + _on_navigate() { + this.application.active_window.navigate('timer') + } +} diff --git a/src/pages/preferences/preferences.blp b/src/pages/preferences/preferences.blp new file mode 100644 index 0000000..90f8cf7 --- /dev/null +++ b/src/pages/preferences/preferences.blp @@ -0,0 +1,113 @@ +using Gtk 4.0; +using Adw 1; + +template $Gjs_Preferences : Adw.PreferencesWindow { + modal: true; + default-height: 450; + default-width: 400; + Adw.PreferencesPage { + title: _("Preferences"); + Adw.PreferencesGroup { + title: _("User interface"); + Adw.ComboRow select_theme { + notify::selected-item => $_change_theme(); + title: _("Theme"); + icon-name: 'dark-mode-symbolic'; + model: StringList list { + strings [_("Ligth"), _("Dark"), _("System")] + }; + } + Adw.ActionRow { + title: _("Allow execution in the background"); + subtitle: _("Hides the window instead of leaving if there is pomodoro running"); + icon-name: "background-app-ghost-symbolic"; + activatable-widget: switch_run_in_background; + [suffix] + Switch switch_run_in_background { + state-set => $_on_boolean_state_set(); + name: "run-in-background"; + valign: center; + } + } + Adw.ActionRow { + title: _("Allow play sounds"); + subtitle: _("Plays the feedback sounds"); + icon-name: "sound-wave-symbolic"; + activatable-widget: switch_play_sounds; + [suffix] + Switch switch_play_sounds { + state-set => $_on_boolean_state_set(); + name: "play-sounds"; + valign: center; + } + } + } + Adw.PreferencesGroup { + title: _("Customize pomodoro"); + Adw.ActionRow { + title: _("Work time - (minutes)"); + subtitle: "The ideal is to follow the rules of the Pomodoro"; + SpinButton set_work_time { + value-changed => $_on_work_time_changed(); + valign: center; + numeric: true; + adjustment: + Adjustment { + lower: 5; + upper: 300; + page-increment: 1; + step-increment: 1; + }; + } + } + Adw.ActionRow { + title: _("Break time - (minutes)"); + subtitle: "The ideal is to follow the rules of the Pomodoro"; + SpinButton set_break_time { + value-changed => $_on_break_time_changed(); + valign: center; + numeric: true; + adjustment: + Adjustment { + lower: 2; + upper: 30; + page-increment: 1; + step-increment: 1; + }; + } + } + Adw.ActionRow { + title: _("End time interval - (minutes)"); + subtitle: "The ideal is to follow the rules of the Pomodoro"; + SpinButton set_long_break { + value-changed => $_on_long_break_changed(); + valign: center; + numeric: true; + adjustment: + Adjustment { + lower: 15; + upper: 60; + page-increment: 1; + step-increment: 1; + }; + } + } + Adw.ActionRow { + title: _("Sessions until the long break - (minutes)"); + subtitle: "The ideal is to follow the rules of the Pomodoro"; + SpinButton set_sessions_long_break { + value-changed => $_on_sessions_long_break_changed(); + valign: center; + numeric: true; + adjustment: + Adjustment { + lower: 1; + upper: 10; + page-increment: 1; + step-increment: 1; + }; + } + } + } + } +} diff --git a/src/pages/preferences/preferences.js b/src/pages/preferences/preferences.js new file mode 100644 index 0000000..c71d83f --- /dev/null +++ b/src/pages/preferences/preferences.js @@ -0,0 +1,88 @@ +/* preferences.js + * + * Copyright 2023 Ideve Core + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +import GObject from 'gi://GObject'; +import Gtk from 'gi://Gtk'; +import Adw from 'gi://Adw'; +import Template from './preferences.blp' assert { type: 'uri' }; + +export default class Preferences extends Adw.PreferencesWindow { + static { + GObject.registerClass({ + Template, + InternalChildren: [ + 'select_theme', + 'switch_run_in_background', + 'switch_play_sounds', + 'set_long_break', + 'set_break_time', + 'set_work_time', + 'set_sessions_long_break', + ], + }, this); + } + constructor(application) { + super(); + this.Application = application; + this.transient_for = this.Application.active_window; + this.Application.settings.get_string('theme') === 'default' ? + this._select_theme.set_selected(2) : + this.Application.settings.get_string('theme') === 'dark' ? + this._select_theme.set_selected(1) : this._select_theme.set_selected(0); + this._switch_run_in_background.set_active(this.Application.settings.get_boolean('run-in-background')); + this._switch_play_sounds.set_active(this.Application.settings.get_boolean('play-sounds')); + + this.Application.settings.set_int('work-time', 10); + this.Application.settings.set_int('break-time', 10); + this.work_time = this.Application.settings.get_int('work-time'); + this.break_time = this.Application.settings.get_int('break-time'); + this.long_break = this.Application.settings.get_int('long-break'); + this.sessions_long_break = this.Application.settings.get_int('sessions-long-break'); + this._set_work_time.set_value(Math.floor(this.work_time / 60) % 60); + this._set_break_time.set_value(Math.floor(this.break_time / 60) % 60); + this._set_long_break.set_value(Math.floor(this.long_break / 60) % 60); + this._set_sessions_long_break.set_value(this.sessions_long_break); + + } + _change_theme(_item) { + const index = _item.get_selected(); + if (index === 0 || index === 1) { + this.Application.settings.set_string('theme', index === 0 ? 'light' : 'dark'); + } else { + this.Application.settings.set_string('theme', 'default'); + } + } + _on_boolean_state_set(widget, state) { + const setting = widget.get_name() + this.Application.settings.set_boolean(setting, state) + } + _on_work_time_changed(_spin_button) { + this.Application.settings.set_int('work-time', _spin_button.get_value() * 60) + } + _on_break_time_changed(_spin_button) { + this.Application.settings.set_int('break-time', _spin_button.get_value() * 60) + } + _on_long_break_changed(_spin_button) { + this.Application.settings.set_int('long-break', _spin_button.get_value() * 60) + } + _on_sessions_long_break_changed(_spin_button) { + this.Application.settings.set_int('sessions-long-break', _spin_button.get_value()) + } +} diff --git a/src/pages/shortcuts/shortcuts.blp b/src/pages/shortcuts/shortcuts.blp new file mode 100644 index 0000000..869ca30 --- /dev/null +++ b/src/pages/shortcuts/shortcuts.blp @@ -0,0 +1,22 @@ +using Gtk 4.0; +using Adw 1; + +template $Gjs_Shortcuts : ShortcutsWindow { + modal: true; + + ShortcutsSection { + section-name: "shortcuts"; + max-height: 10; + ShortcutsGroup { + title: C_("shortcut window", "General"); + ShortcutsShortcut { + accelerator: "question"; + title: _("Keyboard Shortcuts"); + } + ShortcutsShortcut { + accelerator: "Q"; + title: _("Quit"); + } + } + } +} diff --git a/src/pages/shortcuts/shortcuts.js b/src/pages/shortcuts/shortcuts.js new file mode 100644 index 0000000..a286005 --- /dev/null +++ b/src/pages/shortcuts/shortcuts.js @@ -0,0 +1,39 @@ +/* shortcuts.js + * + * Copyright 2023 Ideve Core + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +import GObject from 'gi://GObject'; +import Gtk from 'gi://Gtk'; +import Adw from 'gi://Adw'; +import Template from './shortcuts.blp' assert { type: 'uri' }; + +export default class Shortcuts extends Gtk.ShortcutsWindow { + static { + GObject.registerClass({ + Template, + InternalChildren: [], + }, this); + } + constructor(application) { + super(); + this.Application = application; + this.transient_for = this.Application.active_window; + } +} + diff --git a/src/pages/statistics/statistics.blp b/src/pages/statistics/statistics.blp new file mode 100644 index 0000000..9724f02 --- /dev/null +++ b/src/pages/statistics/statistics.blp @@ -0,0 +1,104 @@ +using Gtk 4.0; +using Adw 1; + +template $Gjs_Statistics : Adw.Bin { + Gtk.ScrolledWindow { + Adw.Clamp { + valign: center; + halign: center; + Gtk.ListBox { + styles ["boxed-list"] + activate-on-single-click: false; + selection-mode: none; + margin-start: 12; + margin-end: 12; + margin-top: 12; + margin-bottom: 12; + Gtk.ListBoxRow { + activatable: false; + hexpand: true; + Gtk.Box { + styles ["vertical"] + hexpand: true; + valign: start; + spacing: 12; + margin-start: 10; + margin-end: 10; + margin-top: 10; + margin-bottom: 10; + orientation: vertical; + Gtk.Label { + styles ["accent", "fs-2"] + label: _("Today"); + vexpand: true; + } + Adw.ActionRow work_time_today { + title: _("Work time"); + Gtk.Label work_time_today_label { + styles ["accent", "dim-label", "fs-3"] + ellipsize: end; + label: "00:00:00"; + } + } + Adw.ActionRow break_time_today { + title: _("Break time"); + Gtk.Label break_time_today_label { + styles ["error", "dim-label", "fs-3"] + ellipsize: end; + label: "00:00:00"; + } + } + } + } + Adw.ExpanderRow work_time_week { + title: _("This week"); + [action] + Gtk.Label { + styles ["dim-label"] + xalign: 1.0; + } + Adw.ActionRow { + title: _("Work time"); + Gtk.Label work_time_week_label { + styles ["accent", "dim-label", "fs-3"] + ellipsize: end; + label: "00:00:00"; + } + } + Adw.ActionRow { + title: _("Break time"); + Gtk.Label break_time_week_label { + styles ["error", "dim-label", "fs-3"] + ellipsize: end; + label: "00:00:00"; + } + } + } + Adw.ExpanderRow work_time_month { + title: _("This month"); + [action] + Gtk.Label { + styles ["dim-label"] + xalign: 1.0; + } + Adw.ActionRow { + title: _("Work time"); + Gtk.Label work_time_month_label { + styles ["accent", "dim-label", "fs-3"] + ellipsize: end; + label: "00:00:00"; + } + } + Adw.ActionRow { + title: _("Break time"); + Gtk.Label break_time_month_label { + styles ["error", "dim-label", "fs-3"] + ellipsize: end; + label: "00:00:00"; + } + } + } + } + } + } +} diff --git a/src/pages/statistics/statistics.js b/src/pages/statistics/statistics.js new file mode 100644 index 0000000..ec9e537 --- /dev/null +++ b/src/pages/statistics/statistics.js @@ -0,0 +1,126 @@ +/* statistics.js + * + * Copyright 2023 Ideve Core + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +import GObject from 'gi://GObject'; +import Gtk from 'gi://Gtk'; +import Adw from 'gi://Adw'; +import GLib from 'gi://GLib'; +import Template from './statistics.blp' assert { type: 'uri' }; +import { format_time } from '../../utils.js'; + +export default class Statistics extends Adw.Bin { + static { + GObject.registerClass({ + Template, + InternalChildren: [ + 'work_time_today', + 'work_time_today_label', + 'work_time_week', + 'work_time_week_label', + 'work_time_month', + 'work_time_month_label', + 'break_time_today_label', + 'break_time_week_label', + 'break_time_month_label', + ] + }, this); + } + constructor() { + super(); + this.application = Gtk.Application.get_default(); + this._current_date = GLib.DateTime.new_now_local(); + this.load_data(); + } + load_data() { + this.load_work_timer() + this.load_break_timer() + } + get_day() { + return this._current_date.get_day_of_year(); + } + get_week() { + return this._current_date.get_week_of_year(); + } + get_month() { + return this._current_date.get_month(); + } + load_work_timer() { + const today = this.application.data.filter((item) => item.date.day === this.get_day()) + const yesterday = this.application.data.filter((item) => item.date.day === this.get_day() - 1); + const week = this.application.data.filter((item) => item.date.week === this.get_week()); + const last_week = this.application.data.filter((item) => item.date.week === this.get_week() - 1); + const month = this.application.data.filter((item) => item.date.month === this.get_month()); + const last_month = this.application.data.filter((item) => item.date.month === this.get_month() - 1); + const work_time_today = today.reduce((accumulator, current_value) => accumulator + current_value.work_time, 0); + const work_timer_yesterday = yesterday.reduce((accumulator, current_value) => accumulator + current_value.work_time, 0); + const work_time_week = week.reduce((accumulator, current_value) => accumulator + current_value.work_time, 0); + const work_timer_last_week = last_week.reduce((accumulator, current_value) => accumulator + current_value.work_time, 0); + const work_time_month = month.reduce((accumulator, current_value) => accumulator + current_value.work_time, 0); + const work_timer_last_month = last_month.reduce((accumulator, current_value) => accumulator + current_value.work_time, 0); + + const percentage_work_time_today_yesterday = () => { + let value = ((work_time_today - work_timer_yesterday) / work_timer_yesterday) * 100; + value = value ? value : 0 + value = value === Infinity ? 100 : value; + let adjective = _('more'); + if (value < 0) + adjective = _('less'); + return `${Math.abs(value).toFixed(0)}% ${adjective} ${_("than yesterday")}` + } + const percentage_work_time_week_last_week = () => { + let value = ((work_time_week - work_timer_last_week) / work_timer_last_week) * 100; + value = value ? value : 0 + value = value === Infinity ? 100 : value; + + let adjective = _('more'); + if (value < 0) + adjective = _('less'); + return `${Math.abs(value).toFixed(0)}% ${adjective} ${_("than last week")}` + } + const percentage_work_time_month_last_month = () => { + let value = ((work_time_month - work_timer_last_month) / work_timer_last_month) * 100; + value = value ? value : 0 + value = value === Infinity ? 100 : value; + let adjective = _('more'); + if (value < 0) + adjective = _('less'); + return `${Math.abs(value).toFixed(0)}% ${adjective} ${_("than last month")}` + } + this._work_time_today_label.set_text(format_time(work_time_today)) + this._work_time_today.set_subtitle(percentage_work_time_today_yesterday()) + this._work_time_week_label.set_text(format_time(work_time_week)) + this._work_time_week.set_subtitle(percentage_work_time_week_last_week()) + this._work_time_month_label.set_text(format_time(work_time_month)); + this._work_time_month.set_subtitle(percentage_work_time_month_last_month()) + } + load_break_timer() { + const today = this.application.data.filter((item) => item.date.day === this.get_day()) + const week = this.application.data.filter((item) => item.date.week === this.get_week()); + const month = this.application.data.filter((item) => item.date.month === this.get_month()); + + const break_time_today = today.reduce((accumulator, current_value) => accumulator + current_value.break_time, 0); + const break_time_week = week.reduce((accumulator, current_value) => accumulator + current_value.break_time, 0); + const break_time_month = month.reduce((accumulator, current_value) => accumulator + current_value.break_time, 0); + + this._break_time_today_label.set_text(format_time(break_time_today)) + this._break_time_week_label.set_text(format_time(break_time_week)) + this._break_time_month_label.set_text(format_time(break_time_month)) + } +} diff --git a/src/pages/timer/timer.blp b/src/pages/timer/timer.blp new file mode 100644 index 0000000..95fc191 --- /dev/null +++ b/src/pages/timer/timer.blp @@ -0,0 +1,127 @@ +using Gtk 4.0; +using Adw 1; + +template $Gjs_Timer : Adw.Bin { + Adw.Clamp { + valign: center; + halign: center; + ListBox { + styles ["boxed-list"] + activate-on-single-click: false; + selection-mode: none; + margin-start: 20; + margin-end: 20; + margin-top: 20; + margin-bottom: 20; + ListBoxRow { + activatable: false; + hexpand: true; + Box { + styles ["vertical"] + hexpand: true; + valign: start; + spacing: 12; + margin-start: 20; + margin-end: 20; + margin-top: 20; + margin-bottom: 20; + orientation: vertical; + Box { + hexpand: true; + halign: center; + Label timer_label { + styles ["accent", "fs-1"] + label: "00:25:00"; + } + [suffix] + Gtk.Overlay pomodoro_counts { + valign: start; + visible: false; + child: Gtk.DrawingArea tag_area { + height-request: 25; + width-request: 25; + tooltip-text: _("Pomodoros counts"); + }; + + [overlay] + Gtk.Label tag_label { + use-markup: true; + tooltip-text: _("Pomodoros counts"); + } + } + } + ListBox list_box { + styles ["boxed-list"] + selection-mode: none; + Adw.EntryRow title_entry { + title: _("Title"); + } + Adw.EntryRow description_entry { + title: _("Description"); + } + } + Stack stack_timer_controls { + transition-type: crossfade; + StackPage { + name: "init_timer"; + child: + Button { + styles ["suggested-action", "circular", "large-button"] + halign: center; + valign: center; + icon-name: "media-playback-start-symbolic"; + tooltip-text: _("Init timer"); + clicked => $_on_handler_timer(); + }; + } + StackPage { + name: "running_timer"; + child: + Button { + styles ["circular", "large-button"] + halign: center; + valign: center; + icon-name: "media-playback-pause-symbolic"; + tooltip-text: _("Pause timer"); + clicked => $_on_handler_timer(); + }; + } + StackPage { + name: "paused_timer"; + child: + Grid { + halign: center; + column-spacing: 18; + column-homogeneous: true; + Button { + styles ["circular", "large-button"] + halign: center; + valign: center; + icon-name: "view-refresh-symbolic"; + tooltip-text: _("Reset timer"); + clicked => $_on_reset_timer(); + } + Button { + styles ["suggested-action", "circular", "large-button"] + halign: center; + valign: center; + icon-name: "media-playback-start-symbolic"; + tooltip-text: _("Init timer"); + clicked => $_on_handler_timer(); + } + Button { + styles ["circular", "large-button"] + halign: center; + valign: center; + icon-name: "media-playback-stop-symbolic"; + tooltip-text: _("Stop timer"); + clicked => $_on_stop_timer(); + } + }; + } + } + } + } + } + } +} diff --git a/src/pages/timer/timer.js b/src/pages/timer/timer.js new file mode 100644 index 0000000..bce81cc --- /dev/null +++ b/src/pages/timer/timer.js @@ -0,0 +1,238 @@ +/* timer.js + * + * Copyright 2023 Ideve Core + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +import GObject from 'gi://GObject'; +import Gtk from 'gi://Gtk'; +import Adw from 'gi://Adw'; +import Gdk from 'gi://Gdk'; +import GLib from 'gi://GLib'; +import Template from './timer.blp' assert { type: 'uri' }; + +export default class Timer extends Adw.Bin { + static { + GObject.registerClass({ + Template, + InternalChildren: [ + "tag_label", + "tag_area", + "pomodoro_counts", + 'title_entry', + 'description_entry', + 'timer_label', + 'stack_timer_controls', + ] + }, this); + } + constructor() { + super(); + var sizeGroup = new Gtk.SizeGroup(Gtk.SizeGroupMode.Horizontal); + sizeGroup.add_widget(this._tag_area); + sizeGroup.add_widget(this._tag_label); + this._tag_area.set_draw_func(this._DrawTag); + + this.application = Gtk.Application.get_default(); + this.timer_running = false; + this.work_time = this.application.settings.get_int('work-time'); + this.break_time = this.application.settings.get_int('break-time'); + this.long_break = this.application.settings.get_int('long-break'); + this.sessions_long_break = this.application.settings.get_int('sessions-long-break'); + this.current_work_time = this.work_time; + this.current_break_time = this.break_time; + this.is_break_timer = false; + this.timer_state = null; + this._timer_label.set_text(this._format_timer()) + } + _get_date() { + const current_date = GLib.DateTime.new_now_local(); + const day_of_week = current_date.format('%A'); + const day_of_month = current_date.get_day_of_month(); + const month_of_year = current_date.format('%B'); + const year = current_date.get_year(); + return `${day_of_week}, ${day_of_month} ${_("of")} ${month_of_year} ${_("of")} ${year}` + } + _get_schedule() { + const hour = new GLib.DateTime().get_hour(); + const minute = new GLib.DateTime().get_minute(); + const second = new GLib.DateTime().get_second(); + return `${hour > 9 ? hour : '0' + hour}:${minute > 9 ? minute : '0' + minute}:${second > 9 ? second : '0' + second}` + } + _format_timer() { + let hours = Math.floor(Math.abs(this.current_work_time < 0 ? this.current_work_time + this.current_break_time : this.current_work_time) / 60 / 60) + let minutes = Math.floor(Math.abs(this.current_work_time < 0 ? this.current_work_time + this.current_break_time : this.current_work_time) / 60) % 60; + let seconds = Math.abs(this.current_work_time < 0 ? this.current_work_time + this.current_break_time : this.current_work_time) % 60; + + if (hours.toString().split('').length < 2) { + hours = `0${hours}` + } + if (minutes.toString().split('').length < 2) { + minutes = `0${minutes}` + } + if (seconds.toString().split('').length < 2) { + seconds = `0${seconds}` + } + return `${hours}:${minutes}:${seconds}` + } + _on_handler_timer() { + const title = this._title_entry.get_text(); + const description = this._description_entry.get_text(); + + this.application.timer_state === 'stopped' || this.application.timer_state === 'paused' ? + this.application.timer_state = 'running' : this.application.timer_state = 'paused'; + this._title_entry.editable = false; + this._description_entry.editable = false; + if (this.application.timer_state === 'running') { + if (!this.timer_running) { + const current_date = GLib.DateTime.new_now_local() + this.data = { + title: title ? title : `${_('Started at')} ${this._get_schedule()}`, + description, + work_time: 0, + break_time: 0, + date: { + day: current_date.get_day_of_year(), + week: current_date.get_week_of_year(), + month: current_date.get_month(), + display_date: this._get_date(), + }, + id: GLib.uuid_string_random(), + counts: 0, + } + this.timer_running = true; + GLib.timeout_add_seconds(GLib.PRIORITY_DEFAULT, 1, () => { + if (this.application.timer_state === 'stopped') { + if (!this.data) + return + const array = this.application.data; + array.push(this.data); + this.application.data = array; + this.application.save_data(); + this.data = null; + return GLib.SOURCE_REMOVE + } + if (this.application.timer_state === 'paused') { + if (!this.application.active_window.visible) + this.application.set_background_status(`Paused timer`) + return GLib.SOURCE_CONTINUE + } + + this.current_work_time-- + + if (this.current_work_time === this.work_time - 1) { + this._timer_label.get_style_context().remove_class('error'); + this.application.notify({ title: `${_("Pomodoro started")} - ${this.data.title}`, body: `${_("Description")}: ${this.data.description}\n${_("Created date")}: ${this.data.date.display_date}` }) + } else if (this.current_work_time === 0) { + this._timer_label.get_style_context().add_class('error'); + this.application.notify({ title: `${_("Pomodoro break time")} - ${this.data.title}`, body: `${_("Description")}: ${this.data.description}\n${_("Created date")}: ${this.data.date.display_date}` }) + this.application.sound({ name: 'complete', cancellable: null }) + } + + if (this.current_work_time > 0) { + this.data.work_time = this.data.work_time + 1 + if (!this.application.active_window.visible) + this.application.set_background_status(`Work time: ${this._format_timer()}`) + } else { + this.data.break_time = this.data.break_time + 1 + if (!this.application.active_window.visible) + this.application.set_background_status(`Break time: ${this._format_timer()}`) + } + + this._timer_label.set_text(this._format_timer()) + + if (this.current_work_time > (this.current_break_time * -1)) { + return GLib.SOURCE_CONTINUE + } + + this.application.timer_state = 'paused'; + this._stack_timer_controls.visible_child_name = 'paused_timer'; + this.current_work_time = this.work_time; + this.data.counts = this.data.counts + 1; + if (this.data.counts > 0) { + this._tag_label.set_label(`${this.data.counts}`); + this._pomodoro_counts.set_visible(true); + } + console.log(this.sessions_long_break, this.data.counts) + if (this.data.counts === this.sessions_long_break) { + this.current_break_time = this.long_break; + } + this.application.notify({ title: `${_("Pomodoro finished")} - ${this.data.title}`, body: `${_("Description")}: ${this.data.description}\n${_("Created date")}: ${this.data.date.display_date}` }) + this._timer_label.get_style_context().remove_class('error'); + this.application.sound({ name: 'alarm-clock-elapsed', cancellable: null }) + this._timer_label.set_text(this._format_timer()); + return GLib.SOURCE_CONTINUE + }) + } + this._stack_timer_controls.visible_child_name = 'running_timer'; + } else { + this._stack_timer_controls.visible_child_name = 'paused_timer'; + } + } + _on_reset_timer() { + this.work_time = this.application.settings.get_int('work-time'); + this.break_time = this.application.settings.get_int('break-time'); + this.long_break = this.application.settings.get_int('long-break'); + this.sessions_long_break = this.application.settings.get_int('sessions-long-break'); + this._pomodoro_counts.set_visible(false); + this.timer_running = false; + this.current_work_time = this.work_time; + this.current_break_time = this.break_time; + this._title_entry.editable = true; + this._description_entry.editable = true; + this._stack_timer_controls.visible_child_name = 'init_timer'; + this.data = null; + this._timer_label.get_style_context().remove_class('error'); + this._timer_label.set_text(this._format_timer()); + this.application.timer_state = 'stopped' + } + _on_stop_timer() { + this.work_time = this.application.settings.get_int('work-time'); + this.break_time = this.application.settings.get_int('break-time'); + this.long_break = this.application.settings.get_int('long-break'); + this.sessions_long_break = this.application.settings.get_int('sessions-long-break'); + this._pomodoro_counts.set_visible(false); + this.timer_running = false; + this._title_entry.set_text(''); + this._description_entry.set_text(''); + this.current_work_time = this.work_time; + this.current_break_time = this.break_time; + this._title_entry.editable = true; + this._description_entry.editable = true; + this._stack_timer_controls.visible_child_name = 'init_timer'; + this._timer_label.get_style_context().remove_class('error'); + this._timer_label.set_text(this._format_timer()); + if (this.data) { + const array = this.application.data; + array.push(this.data); + this.application.data = array; + this.application.save_data(); + } + this.data = null; + this.application.timer_state = 'stopped'; + } + _DrawTag(area, cr, width, height) { + const color = new Gdk.RGBA(); + color.parse('rgba(220 ,20 ,60 , 1)'); + Gdk.cairo_set_source_rgba(cr, color); + cr.arc(height / 2, height / 2, height / 2, 0.5 * Math.PI, 1.5 * Math.PI); + cr.arc(width - height / 2, height / 2, height / 2, -0.5 * Math.PI, 0.5 * Math.PI); + cr.closePath(); + cr.fill(); + } +} + diff --git a/src/utils.js b/src/utils.js index 6f95b76..2ec0b0e 100644 --- a/src/utils.js +++ b/src/utils.js @@ -18,6 +18,7 @@ * SPDX-License-Identifier: GPL-3.0-or-later */ +<<<<<<< HEAD import GLib from 'gi://GLib'; import Gio from 'gi://Gio'; import Adw from 'gi://Adw'; @@ -169,6 +170,11 @@ export const set_theme = () => { } export const format_timer = (timer) => { +======= + + +export const format_time = (timer) => { +>>>>>>> new-pomodoro let hours = Math.floor(timer / 60 / 60) let minutes = Math.floor(timer / 60) % 60; let seconds = timer % 60; diff --git a/src/window.blp b/src/window.blp new file mode 100644 index 0000000..dec9079 --- /dev/null +++ b/src/window.blp @@ -0,0 +1,90 @@ +using Gtk 4.0; +using Adw 1; + +template $Gjs_Window : Adw.ApplicationWindow { + default-width: 450; + default-height: 600; + hide-on-close: true; + title: _("Pomodoro"); + + Adw.Leaflet { + orientation: vertical; + visible-child: world_leaflet; + transition-type: under; + can-unfold: false; + Adw.Leaflet world_leaflet { + can-navigate-back: true; + Box { + orientation: vertical; + + Adw.HeaderBar { + styles ['flat'] + centering-policy: strict; + [title] + Adw.ViewSwitcherTitle view_switcher_title { + stack: stack; + title: bind-property template.title; + } + [end] + MenuButton { + menu-model: primary_menu; + icon-name: "open-menu-symbolic"; + tooltip-text: _("Main menu"); + } + } + Adw.ViewStack stack { + hexpand: true; + vexpand: true; + Adw.ViewStackPage { + name: "timer"; + title: _("_Timer"); + use-underline: true; + icon-name: "hourglass-symbolic"; + child: + $Gjs_Timer {}; + } + Adw.ViewStackPage { + name: "statistics"; + title: _("_Statistics"); + use-underline: true; + icon-name: "profit-symbolic"; + child: + $Gjs_Statistics {}; + } + Adw.ViewStackPage { + name: "history"; + title: _("_History"); + use-underline: true; + icon-name: "history-undo-symbolic"; + child: + $Gjs_History {}; + } + } + Adw.ViewSwitcherBar { + stack: stack; + reveal: bind-property view_switcher_title.title-visible; + } + } + } + } +} + +menu primary_menu { + section { + item { + label: _("_Preferences"); + action: "app.preferences"; + } + + item { + label: _("_Keyboard Shortcuts"); + action: "app.shortcuts"; + } + + item { + label: _("_About Pomodoro"); + action: "app.about"; + } + } +} + diff --git a/src/window.js b/src/window.js index 193c651..a1c649c 100644 --- a/src/window.js +++ b/src/window.js @@ -19,6 +19,7 @@ */ import GObject from 'gi://GObject'; +<<<<<<< HEAD import Adw from 'gi://Adw'; export const PomodoroWindow = GObject.registerClass({ @@ -26,6 +27,21 @@ export const PomodoroWindow = GObject.registerClass({ Template: 'resource:///io/gitlab/idevecore/Pomodoro/window.ui', InternalChildren: ['stack'], }, class PomodoroWindow extends Adw.ApplicationWindow { +======= +import Gtk from 'gi://Gtk'; +import Adw from 'gi://Adw'; +import Template from './window.blp' assert { type: 'uri' }; + +export default class Window extends Adw.ApplicationWindow { + static { + GObject.registerClass({ + Template, + InternalChildren: [ + 'stack', + ], + }, this); + } +>>>>>>> new-pomodoro constructor(application) { super({ application }); @@ -42,8 +58,16 @@ export const PomodoroWindow = GObject.registerClass({ } }); } +<<<<<<< HEAD navigate(navigate) { this._stack.visible_child_name = navigate; } }); +======= + + navigate(navigate) { + this._stack.visible_child_name = navigate; + } +} +>>>>>>> new-pomodoro diff --git a/troll b/troll new file mode 160000 index 0000000..e7933a0 --- /dev/null +++ b/troll @@ -0,0 +1 @@ +Subproject commit e7933a083681d23fce0078b0246fcff244af5ac3