diff --git a/.github/workflows/ubuntu_24.04/expected_gdalinfo_formats.txt b/.github/workflows/ubuntu_24.04/expected_gdalinfo_formats.txt index 1d008a25fe48..cc6aaf4a837a 100644 --- a/.github/workflows/ubuntu_24.04/expected_gdalinfo_formats.txt +++ b/.github/workflows/ubuntu_24.04/expected_gdalinfo_formats.txt @@ -153,6 +153,6 @@ Supported Formats: (ro:read-only, rw:read-write, +:write from scratch, u:update, ENVI -raster- (rw+uv): ENVI .hdr Labelled EHdr -raster- (rw+uv): ESRI .hdr Labelled (*.bil) ISCE -raster- (rw+v): ISCE raster - Zarr -raster,multidimensional raster- (rw+uvs): Zarr + Zarr -raster,multidimensional raster- (rw+uvs): Zarr (*.zarr) RCM -raster- (rovs): Radarsat Constellation Mission XML Product HTTP -raster,vector- (ro): HTTP Fetching Wrapper diff --git a/.github/workflows/windows_conda_expected_gdalinfo_formats.txt b/.github/workflows/windows_conda_expected_gdalinfo_formats.txt index 8511ee4bfddc..6b3d18b03b88 100644 --- a/.github/workflows/windows_conda_expected_gdalinfo_formats.txt +++ b/.github/workflows/windows_conda_expected_gdalinfo_formats.txt @@ -152,6 +152,6 @@ Supported Formats: (ro:read-only, rw:read-write, +:write from scratch, u:update, ENVI -raster- (rw+uv): ENVI .hdr Labelled EHdr -raster- (rw+uv): ESRI .hdr Labelled (*.bil) ISCE -raster- (rw+v): ISCE raster - Zarr -raster,multidimensional raster- (rw+uvs): Zarr + Zarr -raster,multidimensional raster- (rw+uvs): Zarr (*.zarr) RCM -raster- (rovs): Radarsat Constellation Mission XML Product HTTP -raster,vector- (ro): HTTP Fetching Wrapper diff --git a/NEWS.md b/NEWS.md index a0427eecb781..a976003c5cb1 100644 --- a/NEWS.md +++ b/NEWS.md @@ -360,7 +360,7 @@ XODR driver: * Fix typo in handling of Translate widthPct, heightPct * add relatedFieldNameMatch parameter to gdal.VectorTranslate() -# GDAL/OGR 3.10.2 Release Notes +# GDAL/OGR 3.10.2 "Gulf of Mexico" Release Notes GDAL 3.10.2 is a bugfix release. diff --git a/alg/gdal_alg.h b/alg/gdal_alg.h index 8bccbb4429d4..e92cd6625313 100644 --- a/alg/gdal_alg.h +++ b/alg/gdal_alg.h @@ -76,22 +76,6 @@ CPLErr CPL_DLL CPL_STDCALL GDALSieveFilter( * Warp Related. */ -/** - * Callback to transforms points. - * - * @param pTransformerArg return value from a GDALCreateXXXXTransformer() function - * @param bDstToSrc TRUE if transformation is from the destination - * (georeferenced) coordinates to pixel/line or FALSE when transforming - * from pixel/line to georeferenced coordinates. - * @param nPointCount the number of values in the x, y and z arrays. - * @param[in,out] x array containing the X values to be transformed. Must not be NULL. - * @param[in,out] y array containing the Y values to be transformed. Must not be NULL. - * @param[in,out] z array containing the Z values to be transformed. Must not be NULL. - * @param[out] panSuccess array in which a flag indicating success (TRUE) or - * failure (FALSE) of the transformation are placed. Must not be NULL. - * - * @return TRUE if all points have been successfully transformed. - */ typedef int (*GDALTransformerFunc)(void *pTransformerArg, int bDstToSrc, int nPointCount, double *x, double *y, double *z, int *panSuccess); diff --git a/alg/gdaltransformer.cpp b/alg/gdaltransformer.cpp index cb180d8ba464..1859037437c5 100644 --- a/alg/gdaltransformer.cpp +++ b/alg/gdaltransformer.cpp @@ -113,17 +113,17 @@ will be from the source coordinate system to the destination coordinate system. @param nPointCount number of points in the x, y and z arrays. -@param x input X coordinates. Results returned in same array. +@param[in,out] x input X coordinates. Results returned in same array. -@param y input Y coordinates. Results returned in same array. +@param[in,out] y input Y coordinates. Results returned in same array. -@param z input Z coordinates. Results returned in same array. +@param[in,out] z input Z coordinates. Results returned in same array. -@param panSuccess array of ints in which success (TRUE) or failure (FALSE) -flags are returned for the translation of each point. +@param[out] panSuccess array of ints in which success (TRUE) or failure (FALSE) +flags are returned for the translation of each point. Must not be NULL. -@return TRUE if the overall transformation succeeds (though some individual -points may have failed) or FALSE if the overall transformation fails. +@return TRUE if all points have been successfully transformed (changed in 3.11, +previously was TRUE if some points have been successfully transformed) */ diff --git a/autotest/ogr/data/csv/unbalanced_double_quotes.csv b/autotest/ogr/data/csv/unbalanced_double_quotes.csv new file mode 100644 index 000000000000..dc36a60ed855 --- /dev/null +++ b/autotest/ogr/data/csv/unbalanced_double_quotes.csv @@ -0,0 +1,3 @@ +id,txt +1,"foo"" +2,bar diff --git a/autotest/ogr/ogr_csv.py b/autotest/ogr/ogr_csv.py index b7f2c87a588c..d1e6be1c8b3e 100755 --- a/autotest/ogr/ogr_csv.py +++ b/autotest/ogr/ogr_csv.py @@ -3482,6 +3482,22 @@ def test_ogr_schema_override_wkt(tmp_vsimem): assert f.GetGeometryRef().ExportToWkt() == "POINT (1 2)" +############################################################################### +# Test reading CSV with unbalanced double-quotes + + +@gdaltest.enable_exceptions() +def test_ogr_csv_unbalanced_double_quotes(): + + with ogr.Open("data/csv/unbalanced_double_quotes.csv") as ds: + lyr = ds.GetLayer(0) + with pytest.raises( + Exception, + match="CSV file has unbalanced number of double-quotes. Corrupted data will likely be returned", + ): + lyr.GetNextFeature() + + ############################################################################### diff --git a/autotest/ogr/ogr_hana.py b/autotest/ogr/ogr_hana.py index 4ef318c6e2ab..599bad6d834d 100644 --- a/autotest/ogr/ogr_hana.py +++ b/autotest/ogr/ogr_hana.py @@ -11,6 +11,7 @@ # # SPDX-License-Identifier: MIT ############################################################################### +from datetime import datetime, timedelta from os import environ import gdaltest @@ -48,8 +49,11 @@ def setup_driver(): conn, "SELECT REPLACE(CURRENT_UTCDATE, '-', '') || '_' || BINTOHEX(SYSUUID) FROM DUMMY;", ) - gdaltest.hana_schema_name = "{}_{}".format("gdal_test", uid) + schema_prefix = "gdal_test" + drop_old_test_schemas(conn, schema_prefix) + + gdaltest.hana_schema_name = f"{schema_prefix}_{uid}" execute_sql(conn, f'CREATE SCHEMA "{gdaltest.hana_schema_name}"') ds = open_datasource(1) @@ -1375,6 +1379,24 @@ def execute_sql_scalar(conn, sql): return res +def drop_old_test_schemas(conn, schema_prefix): + try: + assert conn + cursor = conn.cursor() + assert cursor + sql = f"""SELECT SCHEMA_NAME FROM SYS.SCHEMAS WHERE SCHEMA_NAME + LIKE '{schema_prefix.replace('_', '__')}__%' ESCAPE '_' AND + LOCALTOUTC(CREATE_TIME) < ?""" + cursor.execute(sql, datetime.now() - timedelta(days=1)) + rows = cursor.fetchall() + cursor.close() + for row in rows: + execute_sql(conn, f'DROP SCHEMA "{row["SCHEMA_NAME"]}" CASCADE') + except Exception as ex: + print(f"Unable to drop old test schemas. Error: {ex}") + pass + + def open_datasource(update=0, open_opts=None): conn_str = "HANA:" + get_connection_str() + ";SCHEMA=" + gdaltest.hana_schema_name if open_opts is None: diff --git a/doc/source/_extensions/driverproperties.py b/doc/source/_extensions/driverproperties.py index 947d5d0d1cfe..f75611662a56 100644 --- a/doc/source/_extensions/driverproperties.py +++ b/doc/source/_extensions/driverproperties.py @@ -22,73 +22,73 @@ def setup(app): app.add_node( shortname, - html=(visit_shortname_node, depart_node), - latex=(visit_admonition, depart_node), - text=(visit_admonition, depart_node), + html=(visit_shortname_node_html, depart_node_html), + latex=(visit_admonition_generic, depart_node_generic), + text=(visit_admonition_generic, depart_node_generic), ) app.add_directive("shortname", ShortName) app.add_node( built_in_by_default, - html=(visit_built_in_by_default_node, depart_node), - latex=(visit_admonition, depart_node), - text=(visit_admonition, depart_node), + html=(visit_built_in_by_default_node_html, depart_node_html), + latex=(visit_admonition_generic, depart_node_generic), + text=(visit_admonition_generic, depart_node_generic), ) app.add_directive("built_in_by_default", BuiltInByDefault) app.add_node( build_dependencies, - html=(visit_build_dependencies_node, depart_node), - latex=(visit_admonition, depart_node), - text=(visit_admonition, depart_node), + html=(visit_build_dependencies_node_html, depart_node_html), + latex=(visit_admonition_generic, depart_node_generic), + text=(visit_admonition_generic, depart_node_generic), ) app.add_directive("build_dependencies", BuildDependencies) app.add_node( supports_create, - html=(visit_supports_create_node, depart_node), - latex=(visit_admonition, depart_node), - text=(visit_admonition, depart_node), + html=(visit_supports_create_node_html, depart_node_html), + latex=(visit_admonition_generic, depart_node_generic), + text=(visit_admonition_generic, depart_node_generic), ) app.add_directive("supports_create", CreateDirective) app.add_node( supports_createcopy, - html=(visit_supports_createcopy_node, depart_node), - latex=(visit_admonition, depart_node), - text=(visit_admonition, depart_node), + html=(visit_supports_createcopy_node_html, depart_node_html), + latex=(visit_admonition_generic, depart_node_generic), + text=(visit_admonition_generic, depart_node_generic), ) app.add_directive("supports_createcopy", CreateCopyDirective) app.add_node( supports_georeferencing, - html=(visit_supports_georeferencing_node, depart_node), - latex=(visit_admonition, depart_node), - text=(visit_admonition, depart_node), + html=(visit_supports_georeferencing_node_html, depart_node_html), + latex=(visit_admonition_generic, depart_node_generic), + text=(visit_admonition_generic, depart_node_generic), ) app.add_directive("supports_georeferencing", GeoreferencingDirective) app.add_node( supports_virtualio, - html=(visit_supports_virtualio_node, depart_node), - latex=(visit_admonition, depart_node), - text=(visit_admonition, depart_node), + html=(visit_supports_virtualio_node_html, depart_node_html), + latex=(visit_admonition_generic, depart_node_generic), + text=(visit_admonition_generic, depart_node_generic), ) app.add_directive("supports_virtualio", VirtualIODirective) app.add_node( supports_multidimensional, - html=(visit_supports_multidimensional_node, depart_node), - latex=(visit_admonition, depart_node), - text=(visit_admonition, depart_node), + html=(visit_supports_multidimensional_node_html, depart_node_html), + latex=(visit_admonition_generic, depart_node_generic), + text=(visit_admonition_generic, depart_node_generic), ) app.add_directive("supports_multidimensional", MultiDimensionalDirective) app.add_node( deprecated_driver, - html=(visit_deprecated_driver_node, depart_node), - latex=(visit_admonition, depart_node), - text=(visit_admonition, depart_node), + html=(visit_deprecated_driver_node_html, depart_node_html), + latex=(visit_admonition_generic, depart_node_generic), + text=(visit_admonition_generic, depart_node_generic), ) app.add_directive("deprecated_driver", DeprecatedDriverDirective) @@ -100,19 +100,27 @@ def setup(app): from docutils import nodes -def visit_admonition(self, node): +def visit_admonition_generic(self, node): self.visit_admonition(node) -def depart_node(self, node): +def depart_node_generic(self, node): self.depart_admonition(node) +def visit_admonition_html(self, node, name: str = ""): + self.body.append(self.starttag(node, "div", CLASS=("admonition " + name))) + + +def depart_node_html(self, node): + self.body.append("\n") + + class shortname(nodes.Admonition, nodes.Element): pass -def visit_shortname_node(self, node): +def visit_shortname_node_html(self, node): self.body.append(self.starttag(node, "div", CLASS=("admonition shortname"))) @@ -120,7 +128,7 @@ class built_in_by_default(nodes.Admonition, nodes.Element): pass -def visit_built_in_by_default_node(self, node): +def visit_built_in_by_default_node_html(self, node): self.body.append( self.starttag(node, "div", CLASS=("admonition built_in_by_default")) ) @@ -130,7 +138,7 @@ class build_dependencies(nodes.Admonition, nodes.Element): pass -def visit_build_dependencies_node(self, node): +def visit_build_dependencies_node_html(self, node): self.body.append( self.starttag(node, "div", CLASS=("admonition build_dependencies")) ) @@ -140,7 +148,7 @@ class supports_create(nodes.Admonition, nodes.Element): pass -def visit_supports_create_node(self, node): +def visit_supports_create_node_html(self, node): self.body.append(self.starttag(node, "div", CLASS=("admonition supports_create"))) @@ -148,7 +156,7 @@ class supports_createcopy(nodes.Admonition, nodes.Element): pass -def visit_supports_createcopy_node(self, node): +def visit_supports_createcopy_node_html(self, node): self.body.append( self.starttag(node, "div", CLASS=("admonition supports_createcopy")) ) @@ -158,7 +166,7 @@ class supports_georeferencing(nodes.Admonition, nodes.Element): pass -def visit_supports_georeferencing_node(self, node): +def visit_supports_georeferencing_node_html(self, node): self.body.append( self.starttag(node, "div", CLASS=("admonition supports_georeferencing")) ) @@ -168,7 +176,7 @@ class supports_virtualio(nodes.Admonition, nodes.Element): pass -def visit_supports_virtualio_node(self, node): +def visit_supports_virtualio_node_html(self, node): self.body.append( self.starttag(node, "div", CLASS=("admonition supports_virtualio")) ) @@ -178,7 +186,7 @@ class supports_multidimensional(nodes.Admonition, nodes.Element): pass -def visit_supports_multidimensional_node(self, node): +def visit_supports_multidimensional_node_html(self, node): self.body.append( self.starttag(node, "div", CLASS=("admonition supports_multidimensional")) ) @@ -188,7 +196,7 @@ class deprecated_driver(nodes.Admonition, nodes.Element): pass -def visit_deprecated_driver_node(self, node): +def visit_deprecated_driver_node_html(self, node): self.body.append(self.starttag(node, "div", CLASS=("danger deprecated_driver"))) diff --git a/doc/source/about_no_title.rst b/doc/source/about_no_title.rst index 0c967d4b28ad..ccb02739c95e 100644 --- a/doc/source/about_no_title.rst +++ b/doc/source/about_no_title.rst @@ -1,4 +1,4 @@ -GDAL is a translator library for raster and vector geospatial data formats that is released under an MIT style Open Source :ref:`license` by the `Open Source Geospatial Foundation`_. As a library, it presents a single raster abstract data model and single vector abstract data model to the calling application for all supported formats. It also comes with a variety of useful command line utilities for data translation and processing. The `NEWS`_ page describes the February 2025 GDAL/OGR 3.10.2 release. +GDAL is a translator library for raster and vector geospatial data formats that is released under an MIT style Open Source :ref:`license` by the `Open Source Geospatial Foundation`_. As a library, it presents a single raster abstract data model and single vector abstract data model to the calling application for all supported formats. It also comes with a variety of useful command line utilities for data translation and processing. The `NEWS`_ page describes the February 2025 GDAL/OGR 3.10.2 "Gulf Of Mexico" release. .. only:: html diff --git a/doc/source/download.rst b/doc/source/download.rst index d11a13e7645a..f39f7091c056 100644 --- a/doc/source/download.rst +++ b/doc/source/download.rst @@ -18,9 +18,9 @@ Source Code Current Release ............... -* **2025-02-14** `gdal-3.10.2.tar.gz`_ `3.10.2 Release Notes`_ (`3.10.2 md5`_) +* **2025-02-14** `gdal-3.10.2.tar.gz`_ `3.10.2 "Gulf of Mexico" Release Notes`_ (`3.10.2 md5`_) -.. _`3.10.2 Release Notes`: https://github.com/OSGeo/gdal/blob/v3.10.2/NEWS.md +.. _`3.10.2 "Gulf of Mexico" Release Notes`: https://github.com/OSGeo/gdal/blob/v3.10.2/NEWS.md .. _`gdal-3.10.2.tar.gz`: https://github.com/OSGeo/gdal/releases/download/v3.10.2/gdal-3.10.2.tar.gz .. _`3.10.2 md5`: https://github.com/OSGeo/gdal/releases/download/v3.10.2/gdal-3.10.2.tar.gz.md5 diff --git a/frmts/zarr/zarrdrivercore.cpp b/frmts/zarr/zarrdrivercore.cpp index 17f6ff4e01e5..4b68bca8c865 100644 --- a/frmts/zarr/zarrdrivercore.cpp +++ b/frmts/zarr/zarrdrivercore.cpp @@ -68,6 +68,7 @@ void ZARRDriverSetCommonMetadata(GDALDriver *poDriver) poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES"); poDriver->SetMetadataItem(GDAL_DCAP_MULTIDIM_RASTER, "YES"); poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "Zarr"); + poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "zarr"); poDriver->SetMetadataItem( GDAL_DMD_CREATIONDATATYPES, "Int8 Byte Int16 UInt16 Int32 UInt32 Int64 UInt64 " diff --git a/port/cpl_csv.cpp b/port/cpl_csv.cpp index 36e0216f39ff..332074647fdb 100644 --- a/port/cpl_csv.cpp +++ b/port/cpl_csv.cpp @@ -706,6 +706,14 @@ CSVReadParseLineGeneric(void *fp, const char *(*pfnReadLine)(void *, size_t), { CPLError(CE_Failure, CPLE_OutOfMemory, "%s", e.what()); } + + if (bInString) + { + CPLError(CE_Failure, CPLE_AppDefined, + "CSV file has unbalanced number of double-quotes. Corrupted " + "data will likely be returned"); + } + return nullptr; }