From 9742ca1db78119d2921fcfaa2b9f798523509e98 Mon Sep 17 00:00:00 2001 From: Nishant Bansal Date: Fri, 25 Oct 2024 13:37:22 +0530 Subject: [PATCH 1/6] v.info: add json output for columns Signed-off-by: Nishant Bansal --- vector/v.info/local_proto.h | 3 +- vector/v.info/main.c | 2 +- vector/v.info/print.c | 55 ++++++++++++++++++++++++--- vector/v.info/testsuite/test_vinfo.py | 21 ++++++++++ 4 files changed, 74 insertions(+), 7 deletions(-) diff --git a/vector/v.info/local_proto.h b/vector/v.info/local_proto.h index 1ed32468562..b1a7d5795cb 100644 --- a/vector/v.info/local_proto.h +++ b/vector/v.info/local_proto.h @@ -19,7 +19,8 @@ void parse_args(int, char **, char **, char **, int *, int *, int *, void format_double(double, char *); void print_region(struct Map_info *, enum OutputFormat, JSON_Object *); void print_topo(struct Map_info *, enum OutputFormat, JSON_Object *); -void print_columns(struct Map_info *, const char *, const char *); +void print_columns(struct Map_info *, const char *, const char *, + enum OutputFormat); void print_info(struct Map_info *); void print_shell(struct Map_info *, const char *, enum OutputFormat, JSON_Object *); diff --git a/vector/v.info/main.c b/vector/v.info/main.c index 6f4aa9a8fcf..b197cb176e8 100644 --- a/vector/v.info/main.c +++ b/vector/v.info/main.c @@ -85,7 +85,7 @@ int main(int argc, char *argv[]) } } else if (col_flag) { - print_columns(&Map, input_opt, field_opt); + print_columns(&Map, input_opt, field_opt, format); } Vect_close(&Map); diff --git a/vector/v.info/print.c b/vector/v.info/print.c index 6c36d6391f6..3d0fe42e9fa 100644 --- a/vector/v.info/print.c +++ b/vector/v.info/print.c @@ -176,7 +176,7 @@ void print_topo(struct Map_info *Map, enum OutputFormat format, } void print_columns(struct Map_info *Map, const char *input_opt, - const char *field_opt) + const char *field_opt, enum OutputFormat format) { int num_dblinks, col, ncols; @@ -215,13 +215,58 @@ void print_columns(struct Map_info *Map, const char *input_opt, if (db_describe_table(driver, &table_name, &table) != DB_OK) G_fatal_error(_("Unable to describe table <%s>"), fi->table); + JSON_Value *root_value = json_value_init_object(); + JSON_Object *root_object = json_object(root_value); + + JSON_Value *columns_value = json_value_init_array(); + JSON_Array *columns_array = json_array(columns_value); + + if (format == JSON) { + json_object_set_value(root_object, "columns", columns_value); + } + ncols = db_get_table_number_of_columns(table); - for (col = 0; col < ncols; col++) - fprintf(stdout, "%s|%s\n", - db_sqltype_name( - db_get_column_sqltype(db_get_table_column(table, col))), + for (col = 0; col < ncols; col++) { + if (format == JSON) { + + JSON_Value *column_value = json_value_init_object(); + JSON_Object *column_object = json_object(column_value); + + json_object_set_string( + column_object, "name", db_get_column_name(db_get_table_column(table, col))); + int sql_type = + db_get_column_sqltype(db_get_table_column(table, col)); + json_object_set_string(column_object, "sql_type", + db_sqltype_name(sql_type)); + + int c_type = db_sqltype_to_Ctype(sql_type); + json_object_set_boolean( + column_object, "is_number", + (c_type == DB_C_TYPE_INT || c_type == DB_C_TYPE_DOUBLE)); + + json_array_append_value(columns_array, column_value); + } + else { + fprintf(stdout, "%s|%s\n", + db_sqltype_name( + db_get_column_sqltype(db_get_table_column(table, col))), + db_get_column_name(db_get_table_column(table, col))); + } + } + + if (format == JSON) { + char *serialized_string = NULL; + serialized_string = json_serialize_to_string_pretty(root_value); + if (serialized_string == NULL) { + G_fatal_error(_("Failed to initialize pretty JSON string.")); + } + puts(serialized_string); + json_free_serialized_string(serialized_string); + json_value_free(root_value); + } + db_close_database(driver); db_shutdown_driver(driver); } diff --git a/vector/v.info/testsuite/test_vinfo.py b/vector/v.info/testsuite/test_vinfo.py index c8183f76412..366859aebae 100644 --- a/vector/v.info/testsuite/test_vinfo.py +++ b/vector/v.info/testsuite/test_vinfo.py @@ -250,6 +250,27 @@ def test_json(self): result.pop(field) self.assertDictEqual(expected, result) + def test_json_column(self): + module = SimpleModule( + "v.info", map=self.test_vinfo_with_db_3d, format="json", flags="c" + ) + self.runModule(module) + + expected_json = { + "columns": [ + {"is_number": True, "name": "cat", "sql_type": "INTEGER"}, + { + "is_number": True, + "name": "elevation", + "sql_type": "DOUBLE PRECISION", + }, + ] + } + + result = json.loads(module.outputs.stdout) + + self.assertDictEqual(expected_json, result) + def test_database_table(self): """Test the database table column and type of the two vector maps with attribute data""" self.assertModuleKeyValue( From cfc23bfc4445f635ab73eec2b113dc1f8b174430 Mon Sep 17 00:00:00 2001 From: Nishant Bansal Date: Fri, 25 Oct 2024 22:58:18 +0530 Subject: [PATCH 2/6] Improve Resource Cleanup on Fatal Errors Signed-off-by: Nishant Bansal --- vector/v.info/print.c | 36 +++++++++++++++++++++++++++--------- 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/vector/v.info/print.c b/vector/v.info/print.c index 3d0fe42e9fa..5d00f2d1203 100644 --- a/vector/v.info/print.c +++ b/vector/v.info/print.c @@ -189,6 +189,7 @@ void print_columns(struct Map_info *Map, const char *input_opt, num_dblinks = Vect_get_num_dblinks(Map); if (num_dblinks <= 0) { + Vect_close(&Map); G_fatal_error( _("Database connection for map <%s> is not defined in DB file"), input_opt); @@ -198,30 +199,43 @@ void print_columns(struct Map_info *Map, const char *input_opt, "layer <%s>:"), field_opt); - if ((fi = Vect_get_field2(Map, field_opt)) == NULL) + if ((fi = Vect_get_field2(Map, field_opt)) == NULL) { + Vect_close(&Map); G_fatal_error( _("Database connection not defined for layer <%s> of <%s>"), field_opt, input_opt); + } driver = db_start_driver(fi->driver); - if (driver == NULL) + if (driver == NULL) { + Vect_close(&Map); G_fatal_error(_("Unable to open driver <%s>"), fi->driver); + } db_init_handle(&handle); db_set_handle(&handle, fi->database, NULL); - if (db_open_database(driver, &handle) != DB_OK) + if (db_open_database(driver, &handle) != DB_OK) { + db_shutdown_driver(driver); + Vect_close(&Map); G_fatal_error(_("Unable to open database <%s> by driver <%s>"), fi->database, fi->driver); + } db_init_string(&table_name); db_set_string(&table_name, fi->table); - if (db_describe_table(driver, &table_name, &table) != DB_OK) + if (db_describe_table(driver, &table_name, &table) != DB_OK) { + db_close_database(driver); + db_shutdown_driver(driver); + Vect_close(&Map); G_fatal_error(_("Unable to describe table <%s>"), fi->table); + } - JSON_Value *root_value = json_value_init_object(); - JSON_Object *root_object = json_object(root_value); - - JSON_Value *columns_value = json_value_init_array(); - JSON_Array *columns_array = json_array(columns_value); + JSON_Value *root_value = NULL, *columns_value = NULL; + JSON_Object *root_object = NULL; + JSON_Array *columns_array = NULL; if (format == JSON) { + root_value = json_value_init_object(); + root_object = json_object(root_value); + columns_value = json_value_init_array(); + columns_array = json_array(columns_value); json_object_set_value(root_object, "columns", columns_value); } @@ -260,6 +274,10 @@ void print_columns(struct Map_info *Map, const char *input_opt, char *serialized_string = NULL; serialized_string = json_serialize_to_string_pretty(root_value); if (serialized_string == NULL) { + json_value_free(root_value); + db_close_database(driver); + db_shutdown_driver(driver); + Vect_close(&Map); G_fatal_error(_("Failed to initialize pretty JSON string.")); } puts(serialized_string); From 926abad28592e57a6c8904a222c8efaf0a525dc8 Mon Sep 17 00:00:00 2001 From: Nishant Bansal Date: Fri, 25 Oct 2024 23:14:11 +0530 Subject: [PATCH 3/6] fixes map pointer issue Signed-off-by: Nishant Bansal --- vector/v.info/print.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/vector/v.info/print.c b/vector/v.info/print.c index 5d00f2d1203..65fe2e2b0f6 100644 --- a/vector/v.info/print.c +++ b/vector/v.info/print.c @@ -189,7 +189,7 @@ void print_columns(struct Map_info *Map, const char *input_opt, num_dblinks = Vect_get_num_dblinks(Map); if (num_dblinks <= 0) { - Vect_close(&Map); + Vect_close(Map); G_fatal_error( _("Database connection for map <%s> is not defined in DB file"), input_opt); @@ -200,21 +200,21 @@ void print_columns(struct Map_info *Map, const char *input_opt, field_opt); if ((fi = Vect_get_field2(Map, field_opt)) == NULL) { - Vect_close(&Map); + Vect_close(Map); G_fatal_error( _("Database connection not defined for layer <%s> of <%s>"), field_opt, input_opt); } driver = db_start_driver(fi->driver); if (driver == NULL) { - Vect_close(&Map); + Vect_close(Map); G_fatal_error(_("Unable to open driver <%s>"), fi->driver); } db_init_handle(&handle); db_set_handle(&handle, fi->database, NULL); if (db_open_database(driver, &handle) != DB_OK) { db_shutdown_driver(driver); - Vect_close(&Map); + Vect_close(Map); G_fatal_error(_("Unable to open database <%s> by driver <%s>"), fi->database, fi->driver); } @@ -223,7 +223,7 @@ void print_columns(struct Map_info *Map, const char *input_opt, if (db_describe_table(driver, &table_name, &table) != DB_OK) { db_close_database(driver); db_shutdown_driver(driver); - Vect_close(&Map); + Vect_close(Map); G_fatal_error(_("Unable to describe table <%s>"), fi->table); } @@ -277,7 +277,7 @@ void print_columns(struct Map_info *Map, const char *input_opt, json_value_free(root_value); db_close_database(driver); db_shutdown_driver(driver); - Vect_close(&Map); + Vect_close(Map); G_fatal_error(_("Failed to initialize pretty JSON string.")); } puts(serialized_string); From d04f8a3b16a5c93d005ca7ce3e3d3ba43863e6f2 Mon Sep 17 00:00:00 2001 From: Nishant Bansal Date: Sat, 26 Oct 2024 11:43:55 +0530 Subject: [PATCH 4/6] added changes based on review Signed-off-by: Nishant Bansal --- vector/v.info/print.c | 43 +++++++++++++++++++++++++++---------------- 1 file changed, 27 insertions(+), 16 deletions(-) diff --git a/vector/v.info/print.c b/vector/v.info/print.c index 65fe2e2b0f6..302f3a5f66b 100644 --- a/vector/v.info/print.c +++ b/vector/v.info/print.c @@ -208,27 +208,33 @@ void print_columns(struct Map_info *Map, const char *input_opt, driver = db_start_driver(fi->driver); if (driver == NULL) { Vect_close(Map); - G_fatal_error(_("Unable to open driver <%s>"), fi->driver); + const char *driver_name = fi->driver; + Vect_destroy_field_info(fi); + G_fatal_error(_("Unable to open driver <%s>"), driver_name); } db_init_handle(&handle); db_set_handle(&handle, fi->database, NULL); if (db_open_database(driver, &handle) != DB_OK) { + const char *database_name = fi->database; + const char *driver_name = fi->driver; + Vect_destroy_field_info(fi); db_shutdown_driver(driver); Vect_close(Map); G_fatal_error(_("Unable to open database <%s> by driver <%s>"), - fi->database, fi->driver); + database_name, driver_name); } db_init_string(&table_name); db_set_string(&table_name, fi->table); if (db_describe_table(driver, &table_name, &table) != DB_OK) { - db_close_database(driver); - db_shutdown_driver(driver); + const char *table_name = fi->table; + Vect_destroy_field_info(fi); + db_close_database_shutdown_driver(driver); Vect_close(Map); - G_fatal_error(_("Unable to describe table <%s>"), fi->table); + G_fatal_error(_("Unable to describe table <%s>"), table_name); } - JSON_Value *root_value = NULL, *columns_value = NULL; - JSON_Object *root_object = NULL; + JSON_Value *root_value = NULL, *columns_value = NULL, *column_value = NULL; + JSON_Object *root_object = NULL, *column_object = NULL; JSON_Array *columns_array = NULL; if (format == JSON) { @@ -241,10 +247,13 @@ void print_columns(struct Map_info *Map, const char *input_opt, ncols = db_get_table_number_of_columns(table); for (col = 0; col < ncols; col++) { - if (format == JSON) { + switch (format) { + case SHELL: + break; - JSON_Value *column_value = json_value_init_object(); - JSON_Object *column_object = json_object(column_value); + case JSON: + column_value = json_value_init_object(); + column_object = json_object(column_value); json_object_set_string( column_object, "name", @@ -261,12 +270,14 @@ void print_columns(struct Map_info *Map, const char *input_opt, (c_type == DB_C_TYPE_INT || c_type == DB_C_TYPE_DOUBLE)); json_array_append_value(columns_array, column_value); - } - else { + break; + + case PLAIN: fprintf(stdout, "%s|%s\n", db_sqltype_name( db_get_column_sqltype(db_get_table_column(table, col))), db_get_column_name(db_get_table_column(table, col))); + break; } } @@ -275,8 +286,8 @@ void print_columns(struct Map_info *Map, const char *input_opt, serialized_string = json_serialize_to_string_pretty(root_value); if (serialized_string == NULL) { json_value_free(root_value); - db_close_database(driver); - db_shutdown_driver(driver); + Vect_destroy_field_info(fi); + db_close_database_shutdown_driver(driver); Vect_close(Map); G_fatal_error(_("Failed to initialize pretty JSON string.")); } @@ -285,8 +296,8 @@ void print_columns(struct Map_info *Map, const char *input_opt, json_value_free(root_value); } - db_close_database(driver); - db_shutdown_driver(driver); + Vect_destroy_field_info(fi); + db_close_database_shutdown_driver(driver); } void print_shell(struct Map_info *Map, const char *field_opt, From fee4eb1f1c0416105b701d5560ea8c7c15997d48 Mon Sep 17 00:00:00 2001 From: Nishant Bansal Date: Sun, 27 Oct 2024 11:38:40 +0530 Subject: [PATCH 5/6] fixes resource handling issues Signed-off-by: Nishant Bansal --- vector/v.info/print.c | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/vector/v.info/print.c b/vector/v.info/print.c index 302f3a5f66b..ae913bf2e3d 100644 --- a/vector/v.info/print.c +++ b/vector/v.info/print.c @@ -208,29 +208,22 @@ void print_columns(struct Map_info *Map, const char *input_opt, driver = db_start_driver(fi->driver); if (driver == NULL) { Vect_close(Map); - const char *driver_name = fi->driver; - Vect_destroy_field_info(fi); - G_fatal_error(_("Unable to open driver <%s>"), driver_name); + G_fatal_error(_("Unable to open driver <%s>"), fi->driver); } db_init_handle(&handle); db_set_handle(&handle, fi->database, NULL); if (db_open_database(driver, &handle) != DB_OK) { - const char *database_name = fi->database; - const char *driver_name = fi->driver; - Vect_destroy_field_info(fi); db_shutdown_driver(driver); Vect_close(Map); G_fatal_error(_("Unable to open database <%s> by driver <%s>"), - database_name, driver_name); + fi->database, fi->driver); } db_init_string(&table_name); db_set_string(&table_name, fi->table); if (db_describe_table(driver, &table_name, &table) != DB_OK) { - const char *table_name = fi->table; - Vect_destroy_field_info(fi); db_close_database_shutdown_driver(driver); Vect_close(Map); - G_fatal_error(_("Unable to describe table <%s>"), table_name); + G_fatal_error(_("Unable to describe table <%s>"), fi->table); } JSON_Value *root_value = NULL, *columns_value = NULL, *column_value = NULL; @@ -286,7 +279,6 @@ void print_columns(struct Map_info *Map, const char *input_opt, serialized_string = json_serialize_to_string_pretty(root_value); if (serialized_string == NULL) { json_value_free(root_value); - Vect_destroy_field_info(fi); db_close_database_shutdown_driver(driver); Vect_close(Map); G_fatal_error(_("Failed to initialize pretty JSON string.")); From 821488d39ec863a3b6c57df4f8867706ec0ab685 Mon Sep 17 00:00:00 2001 From: Nishant Bansal Date: Mon, 28 Oct 2024 21:23:30 +0530 Subject: [PATCH 6/6] additional changes based on review Signed-off-by: Nishant Bansal --- vector/v.info/main.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/vector/v.info/main.c b/vector/v.info/main.c index b197cb176e8..ef1f5c44d06 100644 --- a/vector/v.info/main.c +++ b/vector/v.info/main.c @@ -54,11 +54,6 @@ int main(int argc, char *argv[]) parse_args(argc, argv, &input_opt, &field_opt, &hist_flag, &col_flag, &shell_flag, &format); - if (format == JSON) { - root_value = json_value_init_object(); - root_object = json_value_get_object(root_value); - } - /* try to open head-only on level 2 */ if (Vect_open_old_head2(&Map, input_opt, "", field_opt) < 2) { /* force level 1, open fully @@ -92,6 +87,11 @@ int main(int argc, char *argv[]) return (EXIT_SUCCESS); } + if (format == JSON) { + root_value = json_value_init_object(); + root_object = json_value_get_object(root_value); + } + if ((shell_flag & SHELL_BASIC) || format == JSON) { print_shell(&Map, field_opt, format, root_object); }