diff --git a/NEXT_CHANGELOG.md b/NEXT_CHANGELOG.md index 97388dbdc4..64e0ba4735 100644 --- a/NEXT_CHANGELOG.md +++ b/NEXT_CHANGELOG.md @@ -3,9 +3,9 @@ ## [Unreleased] ### Added +- Added support for geospatial data types. * Added support for telemetry log levels, which can be controlled via the connection parameter `TelemetryLogLevel`. This allows users to configure the verbosity of telemetry logging from OFF to TRACE. - ### Updated ### Fixed diff --git a/NOTICE b/NOTICE index 2025efe26c..6fd09f3c5a 100644 --- a/NOTICE +++ b/NOTICE @@ -80,6 +80,12 @@ jakartaee/common-annotations-api - https://github.com/jakartaee/common-annotatio Copyright common-annotations-api authors Notice - https://github.com/jakartaee/common-annotations-api/blob/master/NOTICE.md +locationtech/jts - https://github.com/locationtech/jts +Copyright (c) 2007, Eclipse Foundation, Inc. and its licensors +Copyright LocationTech JTS contributors +License: Eclipse Public License v2.0 (EPL-2.0) and Eclipse Distribution License v1.0 (EDL-1.0) +License URLs: https://github.com/locationtech/jts/blob/master/LICENSE_EPLv2.txt, https://github.com/locationtech/jts/blob/master/LICENSE_EDLv1.txt + ________________ This Software contains code from the following open source projects, licensed under the GNU Lesser General Public License (https://www.gnu.org/licenses/lgpl-3.0.html): diff --git a/pom.xml b/pom.xml index 3d63dd67b0..72c7162e7b 100644 --- a/pom.xml +++ b/pom.xml @@ -287,6 +287,11 @@ resilience4j-core ${resilience4j.version} + + org.locationtech.jts + jts-core + 1.20.0 + @@ -539,6 +544,10 @@ org.json com.databricks.internal.json + + org.locationtech.jts + com.databricks.internal.jts + org.osgi com.databricks.internal.osgi diff --git a/src/main/java/com/databricks/jdbc/api/IDatabricksGeospatial.java b/src/main/java/com/databricks/jdbc/api/IDatabricksGeospatial.java new file mode 100644 index 0000000000..d58f8d9f2b --- /dev/null +++ b/src/main/java/com/databricks/jdbc/api/IDatabricksGeospatial.java @@ -0,0 +1,60 @@ +package com.databricks.jdbc.api; + +import com.databricks.jdbc.exception.DatabricksValidationException; + +/** + * Interface for geospatial data types in Databricks JDBC driver. + * + *

This interface provides common functionality for both GEOMETRY and GEOGRAPHY types, allowing + * access to Well-Known Text (WKT), Well-Known Binary (WKB) representation and Spatial Reference + * System Identifier (SRID). + * + *

Following the established patterns of DatabricksStruct, DatabricksArray, and DatabricksMap, + * this interface enables consistent handling of geospatial data across the JDBC driver. + */ +public interface IDatabricksGeospatial { + + /** + * Returns the Well-Known Binary (WKB) representation of the geospatial object. + * + *

WKB is a binary format for representing geometry data that is compact and suitable for + * storage and transmission. This method converts the internal representation to WKB format on + * demand. + * + * @return the WKB representation as a byte array + * @throws DatabricksValidationException if WKT to WKB conversion fails + */ + byte[] getWKB() throws DatabricksValidationException; + + /** + * Returns the Spatial Reference System Identifier (SRID) of the geospatial object. + * + *

SRID identifies the coordinate system used by the geometry. Common values include: + * + *

+ * + * @return the SRID value + */ + int getSRID(); + + /** + * Returns the Well-Known Text (WKT) representation of the geospatial object. + * + *

WKT is a human-readable text format for representing geometry data. This provides a + * complement to the binary WKB format, allowing easy inspection and debugging of geospatial data. + * + * @return the WKT string representation + */ + String getWKT(); + + /** + * Returns the data type of the geospatial object. + * + * @return the type as a string, either "GEOMETRY" or "GEOGRAPHY" + */ + String getType(); +} diff --git a/src/main/java/com/databricks/jdbc/api/IGeography.java b/src/main/java/com/databricks/jdbc/api/IGeography.java new file mode 100644 index 0000000000..bae749bc52 --- /dev/null +++ b/src/main/java/com/databricks/jdbc/api/IGeography.java @@ -0,0 +1,4 @@ +package com.databricks.jdbc.api; + +/** Interface for GEOGRAPHY data types in Databricks JDBC driver. */ +public interface IGeography extends IDatabricksGeospatial {} diff --git a/src/main/java/com/databricks/jdbc/api/IGeometry.java b/src/main/java/com/databricks/jdbc/api/IGeometry.java new file mode 100644 index 0000000000..850eb3af55 --- /dev/null +++ b/src/main/java/com/databricks/jdbc/api/IGeometry.java @@ -0,0 +1,4 @@ +package com.databricks.jdbc.api; + +/** Interface for GEOMETRY data types in Databricks JDBC driver. */ +public interface IGeometry extends IDatabricksGeospatial {} diff --git a/src/main/java/com/databricks/jdbc/api/impl/AbstractDatabricksGeospatial.java b/src/main/java/com/databricks/jdbc/api/impl/AbstractDatabricksGeospatial.java new file mode 100644 index 0000000000..eba7bc4fd4 --- /dev/null +++ b/src/main/java/com/databricks/jdbc/api/impl/AbstractDatabricksGeospatial.java @@ -0,0 +1,119 @@ +package com.databricks.jdbc.api.impl; + +import com.databricks.jdbc.api.IDatabricksGeospatial; +import com.databricks.jdbc.api.impl.converters.WKTConverter; +import com.databricks.jdbc.exception.DatabricksValidationException; +import com.databricks.jdbc.log.JdbcLogger; +import com.databricks.jdbc.log.JdbcLoggerFactory; +import java.util.Objects; + +/** + * Abstract base class for geospatial data types in Databricks JDBC driver. + * + *

This class provides common functionality for both GEOMETRY and GEOGRAPHY types, including + * storage of WKT (Well-Known Text) format data and access to both WKT and WKB representations. + */ +public abstract class AbstractDatabricksGeospatial implements IDatabricksGeospatial { + + private static final JdbcLogger LOGGER = + JdbcLoggerFactory.getLogger(AbstractDatabricksGeospatial.class); + + private final String wkt; + private final int srid; // Spatial Reference System Identifier + + /** + * Constructs an AbstractDatabricksGeospatial with the specified WKT and SRID. + * + * @param wkt the Well-Known Text representation of the geospatial object + * @param srid the Spatial Reference System Identifier + * @throws DatabricksValidationException if the WKT is invalid + */ + protected AbstractDatabricksGeospatial(String wkt, int srid) + throws DatabricksValidationException { + if (wkt == null || wkt.trim().isEmpty()) { + LOGGER.error("WKT string cannot be null or empty"); + throw new DatabricksValidationException("WKT string cannot be null or empty"); + } + + this.wkt = wkt.trim(); + this.srid = srid; + } + + /** + * Returns the Well-Known Binary (WKB) representation of the geospatial object. + * + * @return the WKB representation as a byte array + * @throws DatabricksValidationException if WKT to WKB conversion fails + */ + @Override + public byte[] getWKB() throws DatabricksValidationException { + return WKTConverter.toWKB(wkt); + } + + /** + * Returns the Spatial Reference System Identifier (SRID) of the geospatial object. + * + * @return the SRID value + */ + @Override + public int getSRID() { + return srid; + } + + /** + * Returns the Well-Known Text (WKT) representation of the geospatial object. + * + * @return the WKT string + */ + @Override + public String getWKT() { + return wkt; + } + + /** + * Returns a string representation of the geospatial object in EWKT format. + * + * @return the EWKT string representation + */ + @Override + public String toString() { + return String.format("SRID=%d;%s", srid, wkt); + } + + /** + * Checks if this geospatial object is equal to another object. + * + * @param obj the object to compare + * @return true if the objects are equal, false otherwise + */ + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null || getClass() != obj.getClass()) { + return false; + } + + AbstractDatabricksGeospatial that = (AbstractDatabricksGeospatial) obj; + return srid == that.srid && wkt.equals(that.wkt); + } + + /** + * Returns the hash code for this geospatial object. + * + * @return the hash code + */ + @Override + public int hashCode() { + return Objects.hash(wkt, srid); + } + + /** + * Returns the data type of the geospatial object. + * + * @return the type as a string, either "GEOMETRY" or "GEOGRAPHY" + */ + @Override + public abstract String getType(); +} diff --git a/src/main/java/com/databricks/jdbc/api/impl/DatabricksGeography.java b/src/main/java/com/databricks/jdbc/api/impl/DatabricksGeography.java new file mode 100644 index 0000000000..20f148c563 --- /dev/null +++ b/src/main/java/com/databricks/jdbc/api/impl/DatabricksGeography.java @@ -0,0 +1,25 @@ +package com.databricks.jdbc.api.impl; + +import static com.databricks.jdbc.common.util.DatabricksTypeUtil.GEOGRAPHY; + +import com.databricks.jdbc.api.IGeography; +import com.databricks.jdbc.exception.DatabricksValidationException; + +public class DatabricksGeography extends AbstractDatabricksGeospatial implements IGeography { + + /** + * Constructs a DatabricksGeography with the specified WKT and SRID. + * + * @param wkt the Well-Known Text representation of the geography + * @param srid the Spatial Reference System Identifier + * @throws DatabricksValidationException if the WKT is invalid + */ + public DatabricksGeography(String wkt, int srid) throws DatabricksValidationException { + super(wkt, srid); + } + + @Override + public String getType() { + return GEOGRAPHY; + } +} diff --git a/src/main/java/com/databricks/jdbc/api/impl/DatabricksGeometry.java b/src/main/java/com/databricks/jdbc/api/impl/DatabricksGeometry.java new file mode 100644 index 0000000000..b267e7dd84 --- /dev/null +++ b/src/main/java/com/databricks/jdbc/api/impl/DatabricksGeometry.java @@ -0,0 +1,25 @@ +package com.databricks.jdbc.api.impl; + +import static com.databricks.jdbc.common.util.DatabricksTypeUtil.GEOMETRY; + +import com.databricks.jdbc.api.IGeometry; +import com.databricks.jdbc.exception.DatabricksValidationException; + +public class DatabricksGeometry extends AbstractDatabricksGeospatial implements IGeometry { + + /** + * Constructs a DatabricksGeometry with the specified WKT and SRID. + * + * @param wkt the Well-Known Text representation of the geometry + * @param srid the Spatial Reference System Identifier + * @throws DatabricksValidationException if the WKT is invalid + */ + public DatabricksGeometry(String wkt, int srid) throws DatabricksValidationException { + super(wkt, srid); + } + + @Override + public String getType() { + return GEOMETRY; + } +} diff --git a/src/main/java/com/databricks/jdbc/api/impl/DatabricksResultSet.java b/src/main/java/com/databricks/jdbc/api/impl/DatabricksResultSet.java index e45329af48..9a9da2566e 100644 --- a/src/main/java/com/databricks/jdbc/api/impl/DatabricksResultSet.java +++ b/src/main/java/com/databricks/jdbc/api/impl/DatabricksResultSet.java @@ -1,10 +1,7 @@ package com.databricks.jdbc.api.impl; import static com.databricks.jdbc.common.DatabricksJdbcConstants.EMPTY_STRING; -import static com.databricks.jdbc.common.util.DatabricksTypeUtil.ARRAY; -import static com.databricks.jdbc.common.util.DatabricksTypeUtil.MAP; -import static com.databricks.jdbc.common.util.DatabricksTypeUtil.STRUCT; -import static com.databricks.jdbc.common.util.DatabricksTypeUtil.VARIANT; +import static com.databricks.jdbc.common.util.DatabricksTypeUtil.*; import com.databricks.jdbc.api.IDatabricksResultSet; import com.databricks.jdbc.api.IExecutionStatus; @@ -480,13 +477,19 @@ public ResultSetMetaData getMetaData() throws SQLException { } /** - * Checks if the given type name represents a complex type (ARRAY, MAP, or STRUCT). + * Checks if the given type name represents a complex type (ARRAY, MAP, STRUCT, GEOMETRY, or + * GEOGRAPHY). * * @param typeName The type name to check - * @return true if the type name starts with ARRAY, MAP, or STRUCT, false otherwise + * @return true if the type name starts with ARRAY, MAP, STRUCT, GEOMETRY, or GEOGRAPHY, false + * otherwise */ private static boolean isComplexType(String typeName) { - return typeName.startsWith(ARRAY) || typeName.startsWith(MAP) || typeName.startsWith(STRUCT); + return typeName.startsWith(ARRAY) + || typeName.startsWith(MAP) + || typeName.startsWith(STRUCT) + || typeName.startsWith(GEOMETRY) + || typeName.startsWith(GEOGRAPHY); } @Override @@ -531,6 +534,10 @@ private Object handleComplexDataTypesForSEAInline(Object obj, String columnName) return parser.parseJsonStringToDbMap(obj.toString(), columnName).toString(); } else if (columnName.startsWith(STRUCT)) { return parser.parseJsonStringToDbStruct(obj.toString(), columnName).toString(); + } else if (columnName.startsWith(GEOMETRY)) { + return obj; + } else if (columnName.startsWith(GEOGRAPHY)) { + return obj; } throw new DatabricksParsingException( "Unexpected metadata format. Type is not a COMPLEX: " + columnName, @@ -1969,7 +1976,11 @@ private T getConvertedObject( return defaultValue.get(); } int columnType = resultSetMetaData.getColumnType(columnIndex); - ObjectConverter converter = ConverterHelper.getConverterForSqlType(columnType); + String columnTypeName = resultSetMetaData.getColumnTypeName(columnIndex); + + // Use metadata-aware converter selection for proper handling of databricks-specific types + ObjectConverter converter = + ConverterHelper.getConverterForColumnType(columnType, columnTypeName); return convertMethod.apply(converter, obj); } diff --git a/src/main/java/com/databricks/jdbc/api/impl/DatabricksResultSetMetaData.java b/src/main/java/com/databricks/jdbc/api/impl/DatabricksResultSetMetaData.java index 3afc6e383f..6836257872 100644 --- a/src/main/java/com/databricks/jdbc/api/impl/DatabricksResultSetMetaData.java +++ b/src/main/java/com/databricks/jdbc/api/impl/DatabricksResultSetMetaData.java @@ -5,10 +5,7 @@ import static com.databricks.jdbc.common.MetadataResultConstants.LARGE_DISPLAY_COLUMNS; import static com.databricks.jdbc.common.MetadataResultConstants.REMARKS_COLUMN; import static com.databricks.jdbc.common.util.DatabricksThriftUtil.*; -import static com.databricks.jdbc.common.util.DatabricksTypeUtil.TIMESTAMP; -import static com.databricks.jdbc.common.util.DatabricksTypeUtil.TIMESTAMP_NTZ; -import static com.databricks.jdbc.common.util.DatabricksTypeUtil.VARIANT; -import static com.databricks.jdbc.common.util.DatabricksTypeUtil.getBasePrecisionAndScale; +import static com.databricks.jdbc.common.util.DatabricksTypeUtil.*; import com.databricks.jdbc.api.internal.IDatabricksConnectionContext; import com.databricks.jdbc.common.AccessType; @@ -178,6 +175,7 @@ public DatabricksResultSetMetaData( columnIndex < resultManifest.getSchema().getColumnsSize(); columnIndex++) { TColumnDesc columnDesc = resultManifest.getSchema().getColumns().get(columnIndex); + ColumnInfo columnInfo = getColumnInfoFromTColumnDesc(columnDesc); int[] precisionAndScale = getPrecisionAndScale(columnInfo); int precision = precisionAndScale[0]; @@ -205,6 +203,16 @@ public DatabricksResultSetMetaData( .columnTypeClassName("java.lang.String") .columnType(Types.OTHER) .columnTypeText(VARIANT); + } else if (isGeometryColumn(arrowMetadata, columnIndex)) { + columnBuilder + .columnTypeClassName(GEOMETRY_CLASS_NAME) + .columnType(Types.OTHER) + .columnTypeText(GEOMETRY); + } else if (isGeographyColumn(arrowMetadata, columnIndex)) { + columnBuilder + .columnTypeClassName(GEOGRAPHY_CLASS_NAME) + .columnType(Types.OTHER) + .columnTypeText(GEOGRAPHY); } columnsBuilder.add(columnBuilder.build()); columnNameToIndexMap.putIfAbsent(columnInfo.getName(), ++currIndex); @@ -642,6 +650,20 @@ private boolean isVariantColumn(List arrowMetadata, int i) { && arrowMetadata.get(i).equalsIgnoreCase(VARIANT); } + private boolean isGeometryColumn(List arrowMetadata, int index) { + return arrowMetadata != null + && arrowMetadata.size() > index + && arrowMetadata.get(index) != null + && arrowMetadata.get(index).contains(GEOMETRY); + } + + private boolean isGeographyColumn(List arrowMetadata, int index) { + return arrowMetadata != null + && arrowMetadata.size() > index + && arrowMetadata.get(index) != null + && arrowMetadata.get(index).contains(GEOGRAPHY); + } + private ImmutableDatabricksColumn.Builder getColumnBuilder() { return ImmutableDatabricksColumn.builder() .isAutoIncrement(false) diff --git a/src/main/java/com/databricks/jdbc/api/impl/arrow/ArrowStreamResult.java b/src/main/java/com/databricks/jdbc/api/impl/arrow/ArrowStreamResult.java index 29a88fd6ba..c8252b800f 100644 --- a/src/main/java/com/databricks/jdbc/api/impl/arrow/ArrowStreamResult.java +++ b/src/main/java/com/databricks/jdbc/api/impl/arrow/ArrowStreamResult.java @@ -160,7 +160,7 @@ public Object getObject(int columnIndex) throws DatabricksSQLException { } /** - * Checks if the given type is a complex type (ARRAY, MAP, or STRUCT). + * Checks if the given type is a complex type (ARRAY, MAP, STRUCT, GEOMETRY, or GEOGRAPHY). * * @param type The type to check * @return true if the type is a complex type, false otherwise @@ -169,7 +169,9 @@ public Object getObject(int columnIndex) throws DatabricksSQLException { public static boolean isComplexType(ColumnInfoTypeName type) { return type == ColumnInfoTypeName.ARRAY || type == ColumnInfoTypeName.MAP - || type == ColumnInfoTypeName.STRUCT; + || type == ColumnInfoTypeName.STRUCT + || type == ColumnInfoTypeName.GEOMETRY + || type == ColumnInfoTypeName.GEOGRAPHY; } /** {@inheritDoc} */ diff --git a/src/main/java/com/databricks/jdbc/api/impl/converters/ArrowToJavaObjectConverter.java b/src/main/java/com/databricks/jdbc/api/impl/converters/ArrowToJavaObjectConverter.java index 42be51d2c3..d39a4511af 100644 --- a/src/main/java/com/databricks/jdbc/api/impl/converters/ArrowToJavaObjectConverter.java +++ b/src/main/java/com/databricks/jdbc/api/impl/converters/ArrowToJavaObjectConverter.java @@ -1,10 +1,6 @@ package com.databricks.jdbc.api.impl.converters; -import static com.databricks.jdbc.common.util.DatabricksTypeUtil.ARRAY; -import static com.databricks.jdbc.common.util.DatabricksTypeUtil.MAP; -import static com.databricks.jdbc.common.util.DatabricksTypeUtil.STRUCT; -import static com.databricks.jdbc.common.util.DatabricksTypeUtil.TIMESTAMP; -import static com.databricks.jdbc.common.util.DatabricksTypeUtil.VARIANT; +import static com.databricks.jdbc.common.util.DatabricksTypeUtil.*; import com.databricks.jdbc.api.impl.*; import com.databricks.jdbc.exception.DatabricksParsingException; @@ -14,6 +10,7 @@ import com.databricks.jdbc.log.JdbcLoggerFactory; import com.databricks.jdbc.model.core.ColumnInfo; import com.databricks.jdbc.model.core.ColumnInfoTypeName; +import com.databricks.jdbc.model.telemetry.enums.DatabricksDriverErrorCode; import java.math.BigDecimal; import java.math.RoundingMode; import java.sql.Date; @@ -25,6 +22,8 @@ import java.util.List; import java.util.Optional; import java.util.function.Function; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import org.apache.arrow.vector.TimeStampMicroTZVector; import org.apache.arrow.vector.ValueVector; import org.apache.arrow.vector.util.Text; @@ -32,6 +31,11 @@ public class ArrowToJavaObjectConverter { private static final JdbcLogger LOGGER = JdbcLoggerFactory.getLogger(ArrowToJavaObjectConverter.class); + + // Pre-compiled patterns for SRID extraction from metadata + private static final Pattern GEOMETRY_SRID_PATTERN = Pattern.compile("GEOMETRY\\((\\d+)\\)"); + private static final Pattern GEOGRAPHY_SRID_PATTERN = Pattern.compile("GEOGRAPHY\\((\\d+)\\)"); + private static final List DATE_FORMATTERS = Arrays.asList( DateTimeFormatter.ofPattern("yyyy-MM-dd"), @@ -86,6 +90,12 @@ public static Object convert( if (arrowMetadata.startsWith(TIMESTAMP)) { // for timestamp_ntz column requiredType = ColumnInfoTypeName.TIMESTAMP; } + if (arrowMetadata.startsWith(GEOMETRY)) { + requiredType = ColumnInfoTypeName.GEOMETRY; + } + if (arrowMetadata.startsWith(GEOGRAPHY)) { + requiredType = ColumnInfoTypeName.GEOGRAPHY; + } } if (object == null) { return null; @@ -136,6 +146,9 @@ public static Object convert( } IntervalConverter ic = new IntervalConverter(arrowMetadata); return ic.toLiteral(object); + case GEOMETRY: + case GEOGRAPHY: + return convertToGeospatial(object, arrowMetadata, requiredType); case NULL: return null; default: @@ -163,6 +176,26 @@ private static Object convertToStruct(Object object, String arrowMetadata) return parser.parseJsonStringToDbStruct(object.toString(), arrowMetadata); } + private static AbstractDatabricksGeospatial convertToGeospatial( + Object object, String arrowMetadata, ColumnInfoTypeName type) throws DatabricksSQLException { + String ewkt = convertToString(object); + + // Parse EWKT to extract SRID from data if present + int dataSrid = WKTConverter.extractSRIDFromEWKT(ewkt); + String cleanWkt = WKTConverter.removeSRIDFromEWKT(ewkt); + + // Extract SRID from metadata if not present in data + int finalSrid = dataSrid; + if (dataSrid == 0) { + String typeName = type == ColumnInfoTypeName.GEOMETRY ? GEOMETRY : GEOGRAPHY; + finalSrid = extractSRIDFromMetadata(arrowMetadata, typeName); + } + + return type == ColumnInfoTypeName.GEOMETRY + ? new DatabricksGeometry(cleanWkt, finalSrid) + : new DatabricksGeography(cleanWkt, finalSrid); + } + private static Object convertToTimestamp(Object object, Optional timeZoneOpt) throws DatabricksSQLException { if (object instanceof Text) { @@ -294,4 +327,43 @@ private static T convertToNumber( LOGGER.error(errorMessage); throw new DatabricksValidationException(errorMessage); } + + /** + * Extracts SRID from Arrow metadata string. + * + * @param metadata Arrow metadata like "GEOMETRY(32633)" or "GEOGRAPHY(4326)" + * @param typePrefix The prefix to look for ("GEOMETRY" or "GEOGRAPHY") + * @return SRID value, or 0 if not found + * @throws DatabricksParsingException if metadata format is invalid + */ + private static int extractSRIDFromMetadata(String metadata, String typePrefix) + throws DatabricksParsingException { + if (metadata == null) { + LOGGER.debug("Metadata is null, returning default SRID 0 for {}", typePrefix); + return 0; + } + + try { + // Look for pattern like "GEOMETRY(32633)" or "GEOGRAPHY(4326)" + Pattern pattern = + typePrefix.equals(GEOMETRY) ? GEOMETRY_SRID_PATTERN : GEOGRAPHY_SRID_PATTERN; + Matcher m = pattern.matcher(metadata); + + if (m.find()) { + return Integer.parseInt(m.group(1)); + } + } catch (Exception e) { + String errorMessage = + String.format("Failed to parse SRID from %s metadata: %s", typePrefix, metadata); + LOGGER.error(errorMessage, e); + throw new DatabricksParsingException( + errorMessage, e, DatabricksDriverErrorCode.RESULT_SET_ERROR); + } + + LOGGER.debug( + "No SRID found in metadata for {}, returning default SRID 0. Metadata: {}", + typePrefix, + metadata); + return 0; + } } diff --git a/src/main/java/com/databricks/jdbc/api/impl/converters/ConverterHelper.java b/src/main/java/com/databricks/jdbc/api/impl/converters/ConverterHelper.java index 6815e609f3..dcefd5330a 100644 --- a/src/main/java/com/databricks/jdbc/api/impl/converters/ConverterHelper.java +++ b/src/main/java/com/databricks/jdbc/api/impl/converters/ConverterHelper.java @@ -1,5 +1,10 @@ package com.databricks.jdbc.api.impl.converters; +import static com.databricks.jdbc.common.util.DatabricksTypeUtil.GEOGRAPHY; +import static com.databricks.jdbc.common.util.DatabricksTypeUtil.GEOMETRY; + +import com.databricks.jdbc.api.impl.DatabricksGeography; +import com.databricks.jdbc.api.impl.DatabricksGeometry; import com.databricks.jdbc.exception.DatabricksSQLException; import java.math.BigDecimal; import java.math.BigInteger; @@ -12,6 +17,7 @@ public class ConverterHelper { private static final Map CONVERTER_CACHE = new HashMap<>(); private static final Map> SUPPORTED_CONVERSIONS = new HashMap<>(); + private static final GeospatialConverter GEOSPATIAL_CONVERTER = new GeospatialConverter(); static { // Numeric Types @@ -506,6 +512,10 @@ public static Object convertSqlTypeToSpecificJavaType( return converter.toDatabricksArray(obj); } else if (javaType == Struct.class) { return converter.toDatabricksStruct(obj); + } else if (javaType == DatabricksGeometry.class) { + return converter.toDatabricksGeometry(obj); + } else if (javaType == DatabricksGeography.class) { + return converter.toDatabricksGeography(obj); } return converter.toString(obj); // By default, convert to string } @@ -516,10 +526,30 @@ public static Object convertSqlTypeToSpecificJavaType( * @param columnSqlType The SQL type of the column, as defined in java.sql.Types * @return An ObjectConverter suitable for the specified SQL type */ + // TODO: replace all usages of this method with getConverterForColumnType public static ObjectConverter getConverterForSqlType(int columnSqlType) { return CONVERTER_CACHE.getOrDefault(columnSqlType, CONVERTER_CACHE.get(Types.VARCHAR)); } + /** + * Retrieves the appropriate ObjectConverter for a given SQL type and column type name. This + * method provides metadata-aware converter selection, checking the actual column type name first + * for database-specific types before falling back to SQL type-based selection. + * + * @param columnSqlType The SQL type of the column, as defined in java.sql.Types + * @param columnTypeName The actual column type name from metadata (e.g., "GEOMETRY", "GEOGRAPHY") + * @return An ObjectConverter suitable for the specified column type + */ + public static ObjectConverter getConverterForColumnType( + int columnSqlType, String columnTypeName) { + if (columnTypeName != null) { + if (columnTypeName.equals(GEOMETRY) || columnTypeName.equals(GEOGRAPHY)) { + return GEOSPATIAL_CONVERTER; + } + } + return getConverterForSqlType(columnSqlType); + } + public static boolean isConversionSupported(int fromType, int toType) { return SUPPORTED_CONVERSIONS.containsKey(fromType) && SUPPORTED_CONVERSIONS.get(fromType).contains(toType); diff --git a/src/main/java/com/databricks/jdbc/api/impl/converters/GeospatialConverter.java b/src/main/java/com/databricks/jdbc/api/impl/converters/GeospatialConverter.java new file mode 100644 index 0000000000..69d99e63bf --- /dev/null +++ b/src/main/java/com/databricks/jdbc/api/impl/converters/GeospatialConverter.java @@ -0,0 +1,81 @@ +package com.databricks.jdbc.api.impl.converters; + +import static com.databricks.jdbc.common.util.DatabricksTypeUtil.GEOGRAPHY; +import static com.databricks.jdbc.common.util.DatabricksTypeUtil.GEOMETRY; + +import com.databricks.jdbc.api.IDatabricksGeospatial; +import com.databricks.jdbc.api.impl.DatabricksGeography; +import com.databricks.jdbc.api.impl.DatabricksGeometry; +import com.databricks.jdbc.exception.DatabricksSQLException; +import com.databricks.jdbc.log.JdbcLogger; +import com.databricks.jdbc.log.JdbcLoggerFactory; +import com.databricks.jdbc.model.telemetry.enums.DatabricksDriverErrorCode; +import org.apache.arrow.vector.util.Text; + +public class GeospatialConverter implements ObjectConverter { + + private static final JdbcLogger LOGGER = JdbcLoggerFactory.getLogger(GeospatialConverter.class); + + @Override + public DatabricksGeometry toDatabricksGeometry(Object object) throws DatabricksSQLException { + if (object instanceof DatabricksGeometry) { + return (DatabricksGeometry) object; + } + return convertToGeospatial(object, GEOMETRY, DatabricksGeometry::new); + } + + @Override + public DatabricksGeography toDatabricksGeography(Object object) throws DatabricksSQLException { + if (object instanceof DatabricksGeography) { + return (DatabricksGeography) object; + } + return convertToGeospatial(object, GEOGRAPHY, DatabricksGeography::new); + } + + private T convertToGeospatial( + Object object, String typeName, GeospatialFactory factory) throws DatabricksSQLException { + if (object instanceof String || object instanceof Text) { + String ewktString = object.toString(); + try { + int srid = WKTConverter.extractSRIDFromEWKT(ewktString); + String cleanWKT = WKTConverter.removeSRIDFromEWKT(ewktString); + return factory.create(cleanWKT, srid); + } catch (Exception e) { + String errorMessage = + String.format("Failed to convert EWKT to %s: %s", typeName, ewktString); + LOGGER.warn(errorMessage, e); + throw new DatabricksSQLException(errorMessage, e, DatabricksDriverErrorCode.INVALID_STATE); + } + } + + throw new DatabricksSQLException( + String.format( + "Unsupported %s conversion from type: %s", + typeName.substring(0, 1).toUpperCase() + typeName.substring(1), object.getClass()), + DatabricksDriverErrorCode.UNSUPPORTED_OPERATION); + } + + @FunctionalInterface + private interface GeospatialFactory { + T create(String wkt, int srid) throws Exception; + } + + @Override + public String toString(Object object) throws DatabricksSQLException { + if (object != null) { + return object.toString(); + } + throw new DatabricksSQLException( + "Cannot convert null to String", DatabricksDriverErrorCode.UNSUPPORTED_OPERATION); + } + + @Override + public byte[] toByteArray(Object object) throws DatabricksSQLException { + if (object instanceof IDatabricksGeospatial) { + return ((IDatabricksGeospatial) object).getWKB(); + } + throw new DatabricksSQLException( + "Unsupported byte array conversion operation for geospatial types", + DatabricksDriverErrorCode.UNSUPPORTED_OPERATION); + } +} diff --git a/src/main/java/com/databricks/jdbc/api/impl/converters/ObjectConverter.java b/src/main/java/com/databricks/jdbc/api/impl/converters/ObjectConverter.java index c1df874bed..ecf8fdc9b6 100644 --- a/src/main/java/com/databricks/jdbc/api/impl/converters/ObjectConverter.java +++ b/src/main/java/com/databricks/jdbc/api/impl/converters/ObjectConverter.java @@ -1,6 +1,8 @@ package com.databricks.jdbc.api.impl.converters; import com.databricks.jdbc.api.impl.DatabricksArray; +import com.databricks.jdbc.api.impl.DatabricksGeography; +import com.databricks.jdbc.api.impl.DatabricksGeometry; import com.databricks.jdbc.api.impl.DatabricksMap; import com.databricks.jdbc.api.impl.DatabricksStruct; import com.databricks.jdbc.exception.DatabricksSQLException; @@ -141,6 +143,24 @@ default DatabricksStruct toDatabricksStruct(Object object) throws DatabricksSQLE "Unsupported Struct conversion operation", DatabricksDriverErrorCode.UNSUPPORTED_OPERATION); } + default DatabricksGeometry toDatabricksGeometry(Object object) throws DatabricksSQLException { + if (object instanceof DatabricksGeometry) { + return (DatabricksGeometry) object; + } + throw new DatabricksSQLException( + "Unsupported Geometry conversion operation", + DatabricksDriverErrorCode.UNSUPPORTED_OPERATION); + } + + default DatabricksGeography toDatabricksGeography(Object object) throws DatabricksSQLException { + if (object instanceof DatabricksGeography) { + return (DatabricksGeography) object; + } + throw new DatabricksSQLException( + "Unsupported Geography conversion operation", + DatabricksDriverErrorCode.UNSUPPORTED_OPERATION); + } + default InputStream toBinaryStream(Object object) throws DatabricksSQLException { try (ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream)) { diff --git a/src/main/java/com/databricks/jdbc/api/impl/converters/WKTConverter.java b/src/main/java/com/databricks/jdbc/api/impl/converters/WKTConverter.java new file mode 100644 index 0000000000..52ccae52d5 --- /dev/null +++ b/src/main/java/com/databricks/jdbc/api/impl/converters/WKTConverter.java @@ -0,0 +1,132 @@ +package com.databricks.jdbc.api.impl.converters; + +import com.databricks.jdbc.exception.DatabricksValidationException; +import com.databricks.jdbc.log.JdbcLogger; +import com.databricks.jdbc.log.JdbcLoggerFactory; +import org.locationtech.jts.geom.Geometry; +import org.locationtech.jts.io.ParseException; +import org.locationtech.jts.io.WKBReader; +import org.locationtech.jts.io.WKBWriter; +import org.locationtech.jts.io.WKTReader; +import org.locationtech.jts.io.WKTWriter; + +/** + * Utility class for converting between WKT (Well-Known Text) and WKB (Well-Known Binary) formats. + * + *

This class uses the JTS (Java Topology Suite) library to provide robust WKT/WKB conversion + * functionality for geospatial data. JTS is a widely-used, well-tested library that implements the + * OpenGIS Consortium's Simple Features Specification for SQL. + */ +public class WKTConverter { + + private static final JdbcLogger LOGGER = JdbcLoggerFactory.getLogger(WKTConverter.class); + + private static final ThreadLocal WKT_READER = ThreadLocal.withInitial(WKTReader::new); + private static final ThreadLocal WKT_WRITER = ThreadLocal.withInitial(WKTWriter::new); + private static final ThreadLocal WKB_READER = ThreadLocal.withInitial(WKBReader::new); + private static final ThreadLocal WKB_WRITER = ThreadLocal.withInitial(WKBWriter::new); + + /** + * Converts WKT (Well-Known Text) to WKB (Well-Known Binary) format. + * + *

This implementation uses the JTS library to parse the WKT string into a Geometry object and + * then converts it to WKB format. This provides robust, standards-compliant conversion. + * + * @param wkt the WKT string to convert + * @return the WKB representation as a byte array + * @throws DatabricksValidationException if the WKT is invalid + */ + public static byte[] toWKB(String wkt) throws DatabricksValidationException { + if (wkt == null || wkt.trim().isEmpty()) { + throw new DatabricksValidationException("WKT string cannot be null or empty"); + } + + try { + Geometry geometry = WKT_READER.get().read(wkt); + return WKB_WRITER.get().write(geometry); + } catch (ParseException e) { + String errorMessage = String.format("Invalid WKT format: %s", wkt); + LOGGER.error(errorMessage, e); + throw new DatabricksValidationException(errorMessage, e); + } + } + + /** + * Converts WKB (Well-Known Binary) to WKT (Well-Known Text) format. + * + *

This implementation uses the JTS library to parse the WKB bytes into a Geometry object and + * then converts it to WKT format. + * + * @param wkb the WKB bytes to convert + * @return the WKT representation as a string + * @throws DatabricksValidationException if the WKB is invalid + */ + public static String toWKT(byte[] wkb) throws DatabricksValidationException { + if (wkb == null || wkb.length == 0) { + throw new DatabricksValidationException("WKB bytes cannot be null or empty"); + } + + try { + Geometry geometry = WKB_READER.get().read(wkb); + return WKT_WRITER.get().write(geometry); + } catch (Exception e) { + String errorMessage = String.format("Invalid WKB format: %d bytes", wkb.length); + LOGGER.error(errorMessage, e); + throw new DatabricksValidationException(errorMessage, e); + } + } + + /** + * Extracts the SRID from an EWKT (Extended Well-Known Text) string. + * + *

EWKT format includes SRID prefix: "SRID=4326;POINT(1 2)" + * + * @param ewkt the EWKT string + * @return the SRID value, or 0 if no SRID is specified + */ + public static int extractSRIDFromEWKT(String ewkt) { + if (ewkt == null || ewkt.trim().isEmpty()) { + return 0; + } + + String trimmed = ewkt.trim(); + if (trimmed.startsWith("SRID=")) { + int semicolonIndex = trimmed.indexOf(';'); + if (semicolonIndex > 0) { + try { + String sridStr = trimmed.substring(5, semicolonIndex); + return Integer.parseInt(sridStr); + } catch (NumberFormatException e) { + LOGGER.warn("Invalid SRID format in EWKT: {}", ewkt); + return 0; + } + } + } + + return 0; // Default SRID if not specified + } + + /** + * Removes the SRID prefix from an EWKT string to get clean WKT. + * + *

Converts "SRID=4326;POINT(1 2)" to "POINT(1 2)" + * + * @param ewkt the EWKT string + * @return the clean WKT string without SRID prefix + */ + public static String removeSRIDFromEWKT(String ewkt) { + if (ewkt == null || ewkt.trim().isEmpty()) { + return ewkt; + } + + String trimmed = ewkt.trim(); + if (trimmed.startsWith("SRID=")) { + int semicolonIndex = trimmed.indexOf(';'); + if (semicolonIndex > 0) { + return trimmed.substring(semicolonIndex + 1); + } + } + + return trimmed; // Return as-is if no SRID prefix + } +} diff --git a/src/main/java/com/databricks/jdbc/common/util/DatabricksTypeUtil.java b/src/main/java/com/databricks/jdbc/common/util/DatabricksTypeUtil.java index d402a4ee0f..0610776a31 100644 --- a/src/main/java/com/databricks/jdbc/common/util/DatabricksTypeUtil.java +++ b/src/main/java/com/databricks/jdbc/common/util/DatabricksTypeUtil.java @@ -55,6 +55,10 @@ public class DatabricksTypeUtil { public static final String VARIANT = "VARIANT"; public static final String CHAR = "CHAR"; public static final String INTERVAL = "INTERVAL"; + public static final String GEOMETRY = "GEOMETRY"; + public static final String GEOGRAPHY = "GEOGRAPHY"; + public static final String GEOMETRY_CLASS_NAME = "com.databricks.jdbc.api.IGeometry"; + public static final String GEOGRAPHY_CLASS_NAME = "com.databricks.jdbc.api.IGeography"; public static final String MEASURE = "measure"; private static final ArrayList SIGNED_TYPES = new ArrayList<>( @@ -147,6 +151,8 @@ public static int getColumnType(ColumnInfoTypeName typeName) { return Types.STRUCT; case ARRAY: return Types.ARRAY; + case GEOMETRY: + case GEOGRAPHY: case USER_DEFINED_TYPE: return Types.OTHER; default: @@ -190,6 +196,10 @@ public static String getColumnTypeClassName(ColumnInfoTypeName typeName) { return "java.sql.Struct"; case ARRAY: return "java.sql.Array"; + case GEOMETRY: + return GEOMETRY_CLASS_NAME; + case GEOGRAPHY: + return GEOGRAPHY_CLASS_NAME; case NULL: return "null"; case MAP: @@ -252,6 +262,8 @@ public static int getDisplaySize(ColumnInfoTypeName typeName, int precision, int return 4; // Length of `NULL` case ARRAY: case STRUCT: + case GEOMETRY: + case GEOGRAPHY: default: return 255; } diff --git a/src/test/java/com/databricks/jdbc/api/impl/DatabricksGeographyTest.java b/src/test/java/com/databricks/jdbc/api/impl/DatabricksGeographyTest.java new file mode 100644 index 0000000000..fc62f2b052 --- /dev/null +++ b/src/test/java/com/databricks/jdbc/api/impl/DatabricksGeographyTest.java @@ -0,0 +1,165 @@ +package com.databricks.jdbc.api.impl; + +import static org.junit.jupiter.api.Assertions.*; + +import com.databricks.jdbc.exception.DatabricksValidationException; +import org.junit.jupiter.api.Test; + +/** Test class for DatabricksGeography. Reference: DatabricksGeometryTest.java */ +public class DatabricksGeographyTest { + + // =================================================================================== + // Constructor tests + // =================================================================================== + + @Test + public void testConstructor_WithValidPoint() throws DatabricksValidationException { + DatabricksGeography geography = new DatabricksGeography("POINT(-122.4194 37.7749)", 0); + assertNotNull(geography); + assertEquals("POINT(-122.4194 37.7749)", geography.getWKT()); + assertEquals(0, geography.getSRID()); + } + + @Test + public void testConstructor_WithValidPointAndSRID() throws DatabricksValidationException { + DatabricksGeography geography = new DatabricksGeography("POINT(-122.4194 37.7749)", 4326); + assertNotNull(geography); + assertEquals("POINT(-122.4194 37.7749)", geography.getWKT()); + assertEquals(4326, geography.getSRID()); + } + + @Test + public void testConstructor_WithLineString() throws DatabricksValidationException { + DatabricksGeography geography = + new DatabricksGeography("LINESTRING(-122.4 37.7, -122.5 37.8, -122.6 37.9)", 4326); + assertNotNull(geography); + assertTrue(geography.getWKT().startsWith("LINESTRING")); + } + + @Test + public void testConstructor_WithPolygon() throws DatabricksValidationException { + DatabricksGeography geography = + new DatabricksGeography( + "POLYGON((-122.4 37.7, -122.5 37.7, -122.5 37.8, -122.4 37.8, -122.4 37.7))", 4326); + assertNotNull(geography); + assertTrue(geography.getWKT().startsWith("POLYGON")); + } + + @Test + public void testConstructor_WithNullWKT_ThrowsException() { + assertThrows(DatabricksValidationException.class, () -> new DatabricksGeography(null, 0)); + } + + @Test + public void testConstructor_WithEmptyWKT_ThrowsException() { + assertThrows(DatabricksValidationException.class, () -> new DatabricksGeography("", 0)); + } + + @Test + public void testConstructor_WithWhitespaceWKT_ThrowsException() { + assertThrows(DatabricksValidationException.class, () -> new DatabricksGeography(" ", 0)); + } + + // =================================================================================== + // Accessor tests + // =================================================================================== + + @Test + public void testGetWkt() throws DatabricksValidationException { + DatabricksGeography geography = new DatabricksGeography("POINT(-122.4194 37.7749)", 4326); + assertEquals("POINT(-122.4194 37.7749)", geography.getWKT()); + } + + @Test + public void testGetSrid_WithZero() throws DatabricksValidationException { + DatabricksGeography geography = new DatabricksGeography("POINT(-122.4194 37.7749)", 0); + assertEquals(0, geography.getSRID()); + } + + @Test + public void testGetSrid_With3857() throws DatabricksValidationException { + DatabricksGeography geography = new DatabricksGeography("POINT(-122.4194 37.7749)", 3857); + assertEquals(3857, geography.getSRID()); + } + + @Test + public void testGetWkb_ReturnsValidBytes() throws DatabricksValidationException { + DatabricksGeography geography = new DatabricksGeography("POINT(-122.4194 37.7749)", 4326); + byte[] wkb = geography.getWKB(); + assertNotNull(wkb); + assertTrue(wkb.length > 0); + } + + // =================================================================================== + // toString tests + // =================================================================================== + + @Test + public void testToString_WithZeroSRID() throws DatabricksValidationException { + DatabricksGeography geography = new DatabricksGeography("POINT(-122.4194 37.7749)", 0); + assertEquals("SRID=0;POINT(-122.4194 37.7749)", geography.toString()); + } + + @Test + public void testToString_With4326() throws DatabricksValidationException { + DatabricksGeography geography = new DatabricksGeography("POINT(-122.4194 37.7749)", 4326); + assertEquals("SRID=4326;POINT(-122.4194 37.7749)", geography.toString()); + } + + // =================================================================================== + // equals and hashCode tests + // =================================================================================== + + @Test + public void testEquals_SameWKTAndSRID() throws DatabricksValidationException { + DatabricksGeography geo1 = new DatabricksGeography("POINT(-122.4194 37.7749)", 4326); + DatabricksGeography geo2 = new DatabricksGeography("POINT(-122.4194 37.7749)", 4326); + assertEquals(geo1, geo2); + } + + @Test + public void testEquals_DifferentWKT() throws DatabricksValidationException { + DatabricksGeography geo1 = new DatabricksGeography("POINT(-122.4194 37.7749)", 4326); + DatabricksGeography geo2 = new DatabricksGeography("POINT(-118.2437 34.0522)", 4326); + assertNotEquals(geo1, geo2); + } + + @Test + public void testEquals_DifferentSRID() throws DatabricksValidationException { + DatabricksGeography geo1 = new DatabricksGeography("POINT(-122.4194 37.7749)", 4326); + DatabricksGeography geo2 = new DatabricksGeography("POINT(-122.4194 37.7749)", 3857); + assertNotEquals(geo1, geo2); + } + + @Test + public void testEquals_SameInstance() throws DatabricksValidationException { + DatabricksGeography geography = new DatabricksGeography("POINT(-122.4194 37.7749)", 4326); + assertEquals(geography, geography); + } + + @Test + public void testEquals_WithNull() throws DatabricksValidationException { + DatabricksGeography geography = new DatabricksGeography("POINT(-122.4194 37.7749)", 4326); + assertNotEquals(geography, null); + } + + @Test + public void testEquals_WithDifferentClass() throws DatabricksValidationException { + DatabricksGeography geography = new DatabricksGeography("POINT(-122.4194 37.7749)", 4326); + assertNotEquals(geography, "POINT(-122.4194 37.7749)"); + } + + @Test + public void testHashCode_EqualObjects() throws DatabricksValidationException { + DatabricksGeography geo1 = new DatabricksGeography("POINT(-122.4194 37.7749)", 4326); + DatabricksGeography geo2 = new DatabricksGeography("POINT(-122.4194 37.7749)", 4326); + assertEquals(geo1.hashCode(), geo2.hashCode()); + } + + @Test + public void testHashCode_DifferentObjects() throws DatabricksValidationException { + DatabricksGeography geo1 = new DatabricksGeography("POINT(-122.4194 37.7749)", 4326); + DatabricksGeography geo2 = new DatabricksGeography("POINT(-118.2437 34.0522)", 4326); + assertNotEquals(geo1.hashCode(), geo2.hashCode()); + } +} diff --git a/src/test/java/com/databricks/jdbc/api/impl/DatabricksGeometryTest.java b/src/test/java/com/databricks/jdbc/api/impl/DatabricksGeometryTest.java new file mode 100644 index 0000000000..fedfbbd877 --- /dev/null +++ b/src/test/java/com/databricks/jdbc/api/impl/DatabricksGeometryTest.java @@ -0,0 +1,169 @@ +package com.databricks.jdbc.api.impl; + +import static org.junit.jupiter.api.Assertions.*; + +import com.databricks.jdbc.exception.DatabricksValidationException; +import org.junit.jupiter.api.Test; + +/** Test class for DatabricksGeometry. Reference: DatabricksArrayTest.java */ +public class DatabricksGeometryTest { + + // =================================================================================== + // Constructor tests + // =================================================================================== + + @Test + public void testConstructor_WithValidPoint() throws DatabricksValidationException { + DatabricksGeometry geometry = new DatabricksGeometry("POINT(1 2)", 0); + assertNotNull(geometry); + assertEquals("POINT(1 2)", geometry.getWKT()); + assertEquals(0, geometry.getSRID()); + } + + @Test + public void testConstructor_WithValidPointAndSRID() throws DatabricksValidationException { + DatabricksGeometry geometry = new DatabricksGeometry("POINT(1 2)", 4326); + assertNotNull(geometry); + assertEquals("POINT(1 2)", geometry.getWKT()); + assertEquals(4326, geometry.getSRID()); + } + + @Test + public void testConstructor_WithLineString() throws DatabricksValidationException { + DatabricksGeometry geometry = new DatabricksGeometry("LINESTRING(0 0, 10 10, 20 20)", 0); + assertNotNull(geometry); + assertTrue(geometry.getWKT().startsWith("LINESTRING")); + } + + @Test + public void testConstructor_WithPolygon() throws DatabricksValidationException { + DatabricksGeometry geometry = + new DatabricksGeometry("POLYGON((0 0, 10 0, 10 10, 0 10, 0 0))", 0); + assertNotNull(geometry); + assertTrue(geometry.getWKT().startsWith("POLYGON")); + } + + @Test + public void testConstructor_WithNullWKT_ThrowsException() { + assertThrows(DatabricksValidationException.class, () -> new DatabricksGeometry(null, 0)); + } + + @Test + public void testConstructor_WithEmptyWKT_ThrowsException() { + assertThrows(DatabricksValidationException.class, () -> new DatabricksGeometry("", 0)); + } + + @Test + public void testConstructor_WithWhitespaceWKT_ThrowsException() { + assertThrows(DatabricksValidationException.class, () -> new DatabricksGeometry(" ", 0)); + } + + // =================================================================================== + // Accessor tests + // =================================================================================== + + @Test + public void testGetWkt() throws DatabricksValidationException { + DatabricksGeometry geometry = new DatabricksGeometry("POINT(5 10)", 4326); + assertEquals("POINT(5 10)", geometry.getWKT()); + } + + @Test + public void testGetSrid_WithZero() throws DatabricksValidationException { + DatabricksGeometry geometry = new DatabricksGeometry("POINT(1 2)", 0); + assertEquals(0, geometry.getSRID()); + } + + @Test + public void testGetSrid_With4326() throws DatabricksValidationException { + DatabricksGeometry geometry = new DatabricksGeometry("POINT(1 2)", 4326); + assertEquals(4326, geometry.getSRID()); + } + + @Test + public void testGetSrid_With3857() throws DatabricksValidationException { + DatabricksGeometry geometry = new DatabricksGeometry("POINT(1 2)", 3857); + assertEquals(3857, geometry.getSRID()); + } + + @Test + public void testGetWkb_ReturnsValidBytes() throws DatabricksValidationException { + DatabricksGeometry geometry = new DatabricksGeometry("POINT(1 2)", 4326); + byte[] wkb = geometry.getWKB(); + assertNotNull(wkb); + assertTrue(wkb.length > 0); + } + + // =================================================================================== + // toString tests + // =================================================================================== + + @Test + public void testToString_WithZeroSRID() throws DatabricksValidationException { + DatabricksGeometry geometry = new DatabricksGeometry("POINT(1 2)", 0); + assertEquals("SRID=0;POINT(1 2)", geometry.toString()); + } + + @Test + public void testToString_With4326() throws DatabricksValidationException { + DatabricksGeometry geometry = new DatabricksGeometry("POINT(1 2)", 4326); + assertEquals("SRID=4326;POINT(1 2)", geometry.toString()); + } + + // =================================================================================== + // equals and hashCode tests + // =================================================================================== + + @Test + public void testEquals_SameWKTAndSRID() throws DatabricksValidationException { + DatabricksGeometry geo1 = new DatabricksGeometry("POINT(1 2)", 4326); + DatabricksGeometry geo2 = new DatabricksGeometry("POINT(1 2)", 4326); + assertEquals(geo1, geo2); + } + + @Test + public void testEquals_DifferentWKT() throws DatabricksValidationException { + DatabricksGeometry geo1 = new DatabricksGeometry("POINT(1 2)", 4326); + DatabricksGeometry geo2 = new DatabricksGeometry("POINT(3 4)", 4326); + assertNotEquals(geo1, geo2); + } + + @Test + public void testEquals_DifferentSRID() throws DatabricksValidationException { + DatabricksGeometry geo1 = new DatabricksGeometry("POINT(1 2)", 4326); + DatabricksGeometry geo2 = new DatabricksGeometry("POINT(1 2)", 3857); + assertNotEquals(geo1, geo2); + } + + @Test + public void testEquals_SameInstance() throws DatabricksValidationException { + DatabricksGeometry geometry = new DatabricksGeometry("POINT(1 2)", 4326); + assertEquals(geometry, geometry); + } + + @Test + public void testEquals_WithNull() throws DatabricksValidationException { + DatabricksGeometry geometry = new DatabricksGeometry("POINT(1 2)", 4326); + assertNotEquals(geometry, null); + } + + @Test + public void testEquals_WithDifferentClass() throws DatabricksValidationException { + DatabricksGeometry geometry = new DatabricksGeometry("POINT(1 2)", 4326); + assertNotEquals(geometry, "POINT(1 2)"); + } + + @Test + public void testHashCode_EqualObjects() throws DatabricksValidationException { + DatabricksGeometry geo1 = new DatabricksGeometry("POINT(1 2)", 4326); + DatabricksGeometry geo2 = new DatabricksGeometry("POINT(1 2)", 4326); + assertEquals(geo1.hashCode(), geo2.hashCode()); + } + + @Test + public void testHashCode_DifferentObjects() throws DatabricksValidationException { + DatabricksGeometry geo1 = new DatabricksGeometry("POINT(1 2)", 4326); + DatabricksGeometry geo2 = new DatabricksGeometry("POINT(3 4)", 4326); + assertNotEquals(geo1.hashCode(), geo2.hashCode()); + } +} diff --git a/src/test/java/com/databricks/jdbc/api/impl/converters/ArrowToJavaObjectConverterTest.java b/src/test/java/com/databricks/jdbc/api/impl/converters/ArrowToJavaObjectConverterTest.java index 4afe72d98d..258c38f487 100644 --- a/src/test/java/com/databricks/jdbc/api/impl/converters/ArrowToJavaObjectConverterTest.java +++ b/src/test/java/com/databricks/jdbc/api/impl/converters/ArrowToJavaObjectConverterTest.java @@ -2,10 +2,12 @@ import static com.databricks.jdbc.api.impl.converters.ArrowToJavaObjectConverter.convert; import static com.databricks.jdbc.api.impl.converters.ArrowToJavaObjectConverter.getZoneIdFromTimeZoneOpt; -import static com.databricks.jdbc.common.util.DatabricksTypeUtil.VARIANT; +import static com.databricks.jdbc.common.util.DatabricksTypeUtil.*; import static org.junit.jupiter.api.Assertions.*; import com.databricks.jdbc.api.impl.DatabricksArray; +import com.databricks.jdbc.api.impl.DatabricksGeography; +import com.databricks.jdbc.api.impl.DatabricksGeometry; import com.databricks.jdbc.api.impl.DatabricksStruct; import com.databricks.jdbc.api.internal.IDatabricksConnectionContext; import com.databricks.jdbc.exception.DatabricksValidationException; @@ -541,4 +543,80 @@ public void testGetZoneIdFromTimeZoneOpt_InvalidTimeZones() { DateTimeException.class, () -> getZoneIdFromTimeZoneOpt(Optional.of("5:30"))); // Missing sign } + + @Test + public void testGeometryConversion() throws SQLException { + VarCharVector varCharVector = new VarCharVector("varCharVector", this.bufferAllocator); + varCharVector.allocateNew(); + varCharVector.set(0, new Text("POINT(1 2)")); + varCharVector.setValueCount(1); + + Object result = + convert(varCharVector, 0, ColumnInfoTypeName.GEOMETRY, GEOMETRY, new ColumnInfo()); + + assertNotNull(result); + assertInstanceOf(DatabricksGeometry.class, result); + DatabricksGeometry geometry = (DatabricksGeometry) result; + assertEquals("SRID=0;POINT(1 2)", geometry.toString()); + assertEquals(0, geometry.getSRID()); // Default SRID + + varCharVector.close(); + } + + @Test + public void testGeographyConversion() throws SQLException { + VarCharVector varCharVector = new VarCharVector("varCharVector", this.bufferAllocator); + varCharVector.allocateNew(); + varCharVector.set(0, new Text("POINT(1 2)")); + varCharVector.setValueCount(1); + + Object result = + convert(varCharVector, 0, ColumnInfoTypeName.GEOGRAPHY, GEOGRAPHY, new ColumnInfo()); + + assertNotNull(result); + assertInstanceOf(DatabricksGeography.class, result); + DatabricksGeography geography = (DatabricksGeography) result; + assertEquals("SRID=0;POINT(1 2)", geography.toString()); + assertEquals(0, geography.getSRID()); // Default SRID + + varCharVector.close(); + } + + @Test + public void testGeometryWithSRIDConversion() throws SQLException { + VarCharVector varCharVector = new VarCharVector("varCharVector", this.bufferAllocator); + varCharVector.allocateNew(); + varCharVector.set(0, new Text("SRID=4326;POINT(1 2)")); + varCharVector.setValueCount(1); + + Object result = + convert(varCharVector, 0, ColumnInfoTypeName.GEOMETRY, "GEOMETRY", new ColumnInfo()); + + assertNotNull(result); + assertInstanceOf(DatabricksGeometry.class, result); + DatabricksGeometry geometry = (DatabricksGeometry) result; + assertEquals("SRID=4326;POINT(1 2)", geometry.toString()); + assertEquals(4326, geometry.getSRID()); + + varCharVector.close(); + } + + @Test + public void testGeographyWithSRIDConversion() throws SQLException { + VarCharVector varCharVector = new VarCharVector("varCharVector", this.bufferAllocator); + varCharVector.allocateNew(); + varCharVector.set(0, new Text("SRID=4326;POINT(1 2)")); + varCharVector.setValueCount(1); + + Object result = + convert(varCharVector, 0, ColumnInfoTypeName.GEOGRAPHY, "GEOGRAPHY", new ColumnInfo()); + + assertNotNull(result); + assertInstanceOf(DatabricksGeography.class, result); + DatabricksGeography geography = (DatabricksGeography) result; + assertEquals("SRID=4326;POINT(1 2)", geography.toString()); + assertEquals(4326, geography.getSRID()); + + varCharVector.close(); + } } diff --git a/src/test/java/com/databricks/jdbc/api/impl/converters/GeospatialConverterTest.java b/src/test/java/com/databricks/jdbc/api/impl/converters/GeospatialConverterTest.java new file mode 100644 index 0000000000..22c8844cad --- /dev/null +++ b/src/test/java/com/databricks/jdbc/api/impl/converters/GeospatialConverterTest.java @@ -0,0 +1,118 @@ +package com.databricks.jdbc.api.impl.converters; + +import static org.junit.jupiter.api.Assertions.*; + +import com.databricks.jdbc.api.impl.DatabricksGeography; +import com.databricks.jdbc.api.impl.DatabricksGeometry; +import com.databricks.jdbc.exception.DatabricksSQLException; +import org.apache.arrow.vector.util.Text; +import org.junit.jupiter.api.Test; + +/** Test class for GeospatialConverter. */ +public class GeospatialConverterTest { + + private final GeospatialConverter converter = new GeospatialConverter(); + + // =================================================================================== + // toDatabricksGeometry() tests + // =================================================================================== + + @Test + public void testToDatabricksGeometry_WithValidWKT() throws DatabricksSQLException { + DatabricksGeometry result = converter.toDatabricksGeometry("POINT(1 2)"); + assertNotNull(result); + assertEquals("POINT(1 2)", result.getWKT()); + assertEquals(0, result.getSRID()); + } + + @Test + public void testToDatabricksGeometry_WithEWKT() throws DatabricksSQLException { + DatabricksGeometry result = converter.toDatabricksGeometry("SRID=4326;POINT(1 2)"); + assertNotNull(result); + assertEquals("POINT(1 2)", result.getWKT()); + assertEquals(4326, result.getSRID()); + } + + @Test + public void testToDatabricksGeometry_WithTextInput() throws DatabricksSQLException { + Text textInput = new Text("POINT(1 2)"); + DatabricksGeometry result = converter.toDatabricksGeometry(textInput); + assertNotNull(result); + assertEquals("POINT(1 2)", result.getWKT()); + } + + @Test + public void testToDatabricksGeometry_WithGeometryInstance_ReturnsItself() + throws DatabricksSQLException { + DatabricksGeometry input = new DatabricksGeometry("POINT(1 2)", 4326); + DatabricksGeometry result = converter.toDatabricksGeometry(input); + assertSame(input, result); + } + + @Test + public void testToDatabricksGeometry_WithUnsupportedType_ThrowsException() { + assertThrows(DatabricksSQLException.class, () -> converter.toDatabricksGeometry(123)); + } + + // =================================================================================== + // toDatabricksGeography() tests + // =================================================================================== + + @Test + public void testToDatabricksGeography_WithValidWKT() throws DatabricksSQLException { + DatabricksGeography result = converter.toDatabricksGeography("POINT(-122.4194 37.7749)"); + assertNotNull(result); + assertEquals("POINT(-122.4194 37.7749)", result.getWKT()); + assertEquals(0, result.getSRID()); + } + + @Test + public void testToDatabricksGeography_WithEWKT() throws DatabricksSQLException { + DatabricksGeography result = + converter.toDatabricksGeography("SRID=4326;POINT(-122.4194 37.7749)"); + assertNotNull(result); + assertEquals("POINT(-122.4194 37.7749)", result.getWKT()); + assertEquals(4326, result.getSRID()); + } + + @Test + public void testToDatabricksGeography_WithGeographyInstance_ReturnsItself() + throws DatabricksSQLException { + DatabricksGeography input = new DatabricksGeography("POINT(1 2)", 4326); + DatabricksGeography result = converter.toDatabricksGeography(input); + assertSame(input, result); + } + + // =================================================================================== + // toString() tests + // =================================================================================== + + @Test + public void testToString_WithGeometryObject() throws DatabricksSQLException { + DatabricksGeometry geometry = new DatabricksGeometry("POINT(1 2)", 4326); + String result = converter.toString(geometry); + assertEquals("SRID=4326;POINT(1 2)", result); + } + + @Test + public void testToString_WithNull_ThrowsException() { + assertThrows(DatabricksSQLException.class, () -> converter.toString(null)); + } + + // =================================================================================== + // toByteArray() tests + // =================================================================================== + + @Test + public void testToByteArray_WithGeometryObject() throws DatabricksSQLException { + DatabricksGeometry geometry = new DatabricksGeometry("POINT(1 2)", 4326); + byte[] result = converter.toByteArray(geometry); + assertNotNull(result); + assertTrue(result.length > 0); + } + + @Test + public void testToByteArray_WithNonGeospatialType_ThrowsException() { + assertThrows(DatabricksSQLException.class, () -> converter.toByteArray("not geospatial")); + } +} diff --git a/src/test/java/com/databricks/jdbc/api/impl/converters/WKTConverterTest.java b/src/test/java/com/databricks/jdbc/api/impl/converters/WKTConverterTest.java new file mode 100644 index 0000000000..af2e45e6a9 --- /dev/null +++ b/src/test/java/com/databricks/jdbc/api/impl/converters/WKTConverterTest.java @@ -0,0 +1,206 @@ +package com.databricks.jdbc.api.impl.converters; + +import static org.junit.jupiter.api.Assertions.*; + +import com.databricks.jdbc.exception.DatabricksValidationException; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; +import org.junit.jupiter.api.Test; + +/** Test class for WKTConverter utility. */ +public class WKTConverterTest { + + @Test + public void testToWKB_ValidWKT() throws DatabricksValidationException { + String wkt = "POINT(1 2)"; + byte[] wkb = WKTConverter.toWKB(wkt); + + assertNotNull(wkb); + assertTrue(wkb.length > 0); + // WKB is binary data, not UTF-8 bytes of WKT + // We can verify it's valid WKB by converting it back to WKT + String convertedBack = WKTConverter.toWKT(wkb); + // JTS outputs "POINT (1 2)" with a space after POINT, which is valid WKT + assertEquals("POINT (1 2)", convertedBack); + } + + @Test + public void testToWKB_NullWKT() { + assertThrows(DatabricksValidationException.class, () -> WKTConverter.toWKB(null)); + } + + @Test + public void testToWKB_EmptyWKT() { + assertThrows(DatabricksValidationException.class, () -> WKTConverter.toWKB("")); + } + + @Test + public void testToWKB_WhitespaceWKT() { + assertThrows(DatabricksValidationException.class, () -> WKTConverter.toWKB(" ")); + } + + @Test + public void testExtractSRIDFromEWKT_WithSRID() { + String ewkt = "SRID=4326;POINT(1 2)"; + int srid = WKTConverter.extractSRIDFromEWKT(ewkt); + assertEquals(4326, srid); + } + + @Test + public void testExtractSRIDFromEWKT_WithoutSRID() { + String wkt = "POINT(1 2)"; + int srid = WKTConverter.extractSRIDFromEWKT(wkt); + assertEquals(0, srid); + } + + @Test + public void testExtractSRIDFromEWKT_Null() { + int srid = WKTConverter.extractSRIDFromEWKT(null); + assertEquals(0, srid); + } + + @Test + public void testExtractSRIDFromEWKT_Empty() { + int srid = WKTConverter.extractSRIDFromEWKT(""); + assertEquals(0, srid); + } + + @Test + public void testExtractSRIDFromEWKT_InvalidSRID() { + String ewkt = "SRID=invalid;POINT(1 2)"; + int srid = WKTConverter.extractSRIDFromEWKT(ewkt); + assertEquals(0, srid); // Should return 0 for invalid SRID + } + + @Test + public void testExtractSRIDFromEWKT_NoSemicolon() { + String ewkt = "SRID=4326POINT(1 2)"; + int srid = WKTConverter.extractSRIDFromEWKT(ewkt); + assertEquals(0, srid); // Should return 0 if no semicolon + } + + @Test + public void testRemoveSRIDFromEWKT_WithSRID() { + String ewkt = "SRID=4326;POINT(1 2)"; + String wkt = WKTConverter.removeSRIDFromEWKT(ewkt); + assertEquals("POINT(1 2)", wkt); + } + + @Test + public void testRemoveSRIDFromEWKT_WithoutSRID() { + String wkt = "POINT(1 2)"; + String result = WKTConverter.removeSRIDFromEWKT(wkt); + assertEquals("POINT(1 2)", result); + } + + @Test + public void testRemoveSRIDFromEWKT_Null() { + String result = WKTConverter.removeSRIDFromEWKT(null); + assertNull(result); + } + + @Test + public void testRemoveSRIDFromEWKT_Empty() { + String result = WKTConverter.removeSRIDFromEWKT(""); + assertEquals("", result); + } + + @Test + public void testRemoveSRIDFromEWKT_NoSemicolon() { + String ewkt = "SRID=4326POINT(1 2)"; + String result = WKTConverter.removeSRIDFromEWKT(ewkt); + assertEquals("SRID=4326POINT(1 2)", result); // Should return as-is if no semicolon + } + + @Test + public void testRemoveSRIDFromEWKT_OnlySRID() { + String ewkt = "SRID=4326;"; + String result = WKTConverter.removeSRIDFromEWKT(ewkt); + assertEquals("", result); + } + + @Test + public void testToWKB_InvalidWKTFormat_LogsError() { + String invalidWkt = "POINT(1 2 3 4 5)"; // Too many coordinates for a POINT + + DatabricksValidationException exception = + assertThrows(DatabricksValidationException.class, () -> WKTConverter.toWKB(invalidWkt)); + + assertTrue(exception.getMessage().contains("Invalid WKT format")); + } + + @Test + public void testToWKT_ValidWKB() throws DatabricksValidationException { + // First create valid WKB from WKT + byte[] wkb = WKTConverter.toWKB("POINT (1 2)"); + String wkt = WKTConverter.toWKT(wkb); + + assertEquals("POINT (1 2)", wkt); + } + + @Test + public void testToWKT_NullWKB() { + assertThrows(DatabricksValidationException.class, () -> WKTConverter.toWKT(null)); + } + + @Test + public void testToWKT_EmptyWKB() { + assertThrows(DatabricksValidationException.class, () -> WKTConverter.toWKT(new byte[0])); + } + + @Test + public void testToWKT_InvalidWKB_LogsError() { + byte[] invalidWkb = new byte[] {1, 2, 3, 4, 5}; // Random invalid bytes + + DatabricksValidationException exception = + assertThrows(DatabricksValidationException.class, () -> WKTConverter.toWKT(invalidWkb)); + + assertTrue(exception.getMessage().contains("Invalid WKB format")); + } + + @Test + public void testConcurrency() throws Exception { + int numThreads = 50; + ExecutorService executor = Executors.newFixedThreadPool(numThreads); + CountDownLatch latch = new CountDownLatch(numThreads); + List> futures = new ArrayList<>(); + + for (int threadNum = 0; threadNum < numThreads; threadNum++) { + final int threadId = threadNum; + Future future = + executor.submit( + () -> { + try { + int x = threadId; + int y = threadId * 2; + String wkt = String.format("POINT (%d %d)", x, y); + + byte[] wkb = WKTConverter.toWKB(wkt); + assertNotNull(wkb, "Thread " + threadId + ": WKB should not be null"); + + String convertedWkt = WKTConverter.toWKT(wkb); + assertEquals(wkt, convertedWkt, "Thread " + threadId + ": WKT mismatch"); + + } catch (Exception e) { + fail("Thread " + threadId + " failed: " + e.getMessage()); + } finally { + latch.countDown(); + } + }); + futures.add(future); + } + + assertTrue(latch.await(10, TimeUnit.SECONDS), "Not all threads completed in time"); + executor.shutdown(); + + // Verify all threads completed successfully + for (Future future : futures) { + future.get(); + } + } +} diff --git a/src/test/java/com/databricks/jdbc/integration/fakeservice/tests/DataTypesIntegrationTests.java b/src/test/java/com/databricks/jdbc/integration/fakeservice/tests/DataTypesIntegrationTests.java index 684a478a5a..7809278eac 100644 --- a/src/test/java/com/databricks/jdbc/integration/fakeservice/tests/DataTypesIntegrationTests.java +++ b/src/test/java/com/databricks/jdbc/integration/fakeservice/tests/DataTypesIntegrationTests.java @@ -11,6 +11,7 @@ import java.util.Properties; import java.util.stream.Stream; import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assumptions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; @@ -338,6 +339,65 @@ private void validateIntervalResults(ResultSet resultSet) throws SQLException { assertFalse(resultSet.next()); } + @Test + void testGeospatialTypes() throws SQLException { + + // Skip for THRIFT_SERVER as the test environment version doesn't support geospatial types + // TODO: Update stubs and remove this skip once THRIFT_SERVER environment is upgraded to support + // geospatial types + Assumptions.assumeTrue( + isSqlExecSdkClient(), "Geospatial types are not supported on THRIFT_SERVER yet"); + + String query = + "SELECT * FROM (VALUES " + + "(1, ST_GeomFromText('POINT (1 2)'), ST_GeogFromText('POINT (3 4)')), " + + "(2, ST_GeomFromText('LINESTRING (0 0, 1 1, 2 2)'), ST_GeogFromText('LINESTRING (5 5, 6 6)')), " + + "(3, NULL, NULL)" + + ") AS geospatial_data(id, geom, geog) " + + "ORDER BY id"; + + ResultSet rs = executeQuery(connection, query); + assertNotNull( + rs, "ResultSet should not be null - GEOMETRY/GEOGRAPHY types may not be supported"); + ResultSetMetaData rsmd = rs.getMetaData(); + + // Validate metadata + assertEquals("GEOMETRY", rsmd.getColumnTypeName(2)); + assertEquals("GEOGRAPHY", rsmd.getColumnTypeName(3)); + + // Validate data + int rowCount = 0; + while (rs.next()) { + rowCount++; + int id = rs.getInt("id"); + Object geom = rs.getObject("geom"); + Object geog = rs.getObject("geog"); + + switch (id) { + case 1: + assertNotNull(geom); + assertNotNull(geog); + assertTrue(geom.toString().contains("POINT")); + assertTrue(geog.toString().contains("POINT")); + break; + case 2: + assertNotNull(geom); + assertNotNull(geog); + assertTrue(geom.toString().contains("LINESTRING")); + assertTrue(geog.toString().contains("LINESTRING")); + break; + case 3: + assertNull(geom); + assertNull(geog); + break; + default: + fail("Unexpected row id: " + id); + } + } + assertEquals(3, rowCount); + rs.close(); + } + private void closeConnection(Connection connection) throws SQLException { if (connection != null) { if (((DatabricksConnection) connection).getConnectionContext().getClientType() diff --git a/src/test/resources/cloudfetchapi/datatypesintegrationtests/testgeospatialtypes/mappings/oregon-staging_6051921418418893.jobs_sql_2025-10-10_09_results_2025-10-10t093531z_dfb38243-a074-4425-a7fe-772f480f384a-05a66b02-c06d-4941-9b01-e820827c2f85.json b/src/test/resources/cloudfetchapi/datatypesintegrationtests/testgeospatialtypes/mappings/oregon-staging_6051921418418893.jobs_sql_2025-10-10_09_results_2025-10-10t093531z_dfb38243-a074-4425-a7fe-772f480f384a-05a66b02-c06d-4941-9b01-e820827c2f85.json new file mode 100644 index 0000000000..d53c45f6da --- /dev/null +++ b/src/test/resources/cloudfetchapi/datatypesintegrationtests/testgeospatialtypes/mappings/oregon-staging_6051921418418893.jobs_sql_2025-10-10_09_results_2025-10-10t093531z_dfb38243-a074-4425-a7fe-772f480f384a-05a66b02-c06d-4941-9b01-e820827c2f85.json @@ -0,0 +1,25 @@ +{ + "id" : "05a66b02-c06d-4941-9b01-e820827c2f85", + "name" : "oregon-staging_6051921418418893.jobs_sql_2025-10-10_09_results_2025-10-10t093531z_dfb38243-a074-4425-a7fe-772f480f384a", + "request" : { + "url" : "/oregon-staging/6051921418418893.jobs/sql/2025-10-10/09/results_2025-10-10T09%3A35%3A31Z_dfb38243-a074-4425-a7fe-772f480f384a?[REDACTED]X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=20251010T093531Z&X-Amz-SignedHeaders=host&X-Amz-Expires=899&[REDACTED]X-Amz-Signature=6a356f310ac3c56bbfccb7b5f5f31b34eb1010a04c8250659118a9db52f83e5f", + "method" : "GET" + }, + "response" : { + "status" : 200, + "base64Body" : "BCJNGHRwjroAAACg/////wgBAAAQAAEAsAoADgAGAA0ACAAKDwAiAAQYAKEBCgAMAAAACAAEGAARCAwAASEAoQADAAAAkAAAAEguAKQAANL///8UAAAABABCAAAFAVwAAgIAQMD///8oAPUAZ2VvZwAAEgAYABQAEwASYAAXEjwAERgzACAFAUwABAIAEQQCAAAIAAFEABRtRAA/AAATRAACEhw5ACICIAgAAQIAdAgADAAIAAfEABABHACAAgAAAGlkAABLcvQ0AAAAAGc6z14EIk0YdHCOHAEAAKL/////CAEAABQAAQDyAgwAFgAOABUAEAAEAAwAAACoFwBgAAAABAAQCADSAwoAGAAMAAgABAAKADgAUJgAAAADHAADAgATCAgAAAIAEAEFAAcUAABUAAACABAYBQAHIAARIA4AEgBkAEEAAAAwBgAwAAAhBQBBAAAAWAYABjAAEGANAAcwABFwDgAwAAAxBQADAgAAlAAABAAIAgAEEAAEmAAMEAATBy0AACAAFwLYAAQoAAACAAD4AACYAAAEAPASUE9JTlQoMSAyKUxJTkVTVFJJTkcoMCAwLDEgMSwyIDIpMQAHSAAAAgAAbAEAqAAABACiU1JJRD00MzI2O0oARjMgNCkUAAdUAPAANSA1LDYgNikAAAAAAAAA84O3awAAAACLf1BBBCJNGHRwjggAAID/////AAAAAIaGkggAAAAAhoaSCA==", + "headers" : { + "Accept-Ranges" : "bytes", + "Server" : "AmazonS3", + "ETag" : "\"c0447953da35669e9a3629504add95a8\"", + "Last-Modified" : "Fri, 10 Oct 2025 09:35:32 GMT", + "x-amz-request-id" : "66976VQD1VAX75SS", + "x-amz-server-side-encryption" : "AES256", + "x-amz-id-2" : "JCHXeBYwC7iGlinUE87DghMNEWmGe+GT3g2+gqGelAu6GSSpZRuBjBgl5zvhXnQ1qGnQAKanlRQ=", + "Date" : "Fri, 10 Oct 2025 09:35:33 GMT", + "Content-Type" : "binary/octet-stream" + } + }, + "uuid" : "05a66b02-c06d-4941-9b01-e820827c2f85", + "insertionIndex" : 1 +} \ No newline at end of file diff --git a/src/test/resources/sqlexecapi/datatypesintegrationtests/testgeospatialtypes/mappings/api_2.0_sql_sessions-26c29504-a4b8-440b-bbd1-d7b1d3576eb7.json b/src/test/resources/sqlexecapi/datatypesintegrationtests/testgeospatialtypes/mappings/api_2.0_sql_sessions-26c29504-a4b8-440b-bbd1-d7b1d3576eb7.json new file mode 100644 index 0000000000..d2fbd84c5e --- /dev/null +++ b/src/test/resources/sqlexecapi/datatypesintegrationtests/testgeospatialtypes/mappings/api_2.0_sql_sessions-26c29504-a4b8-440b-bbd1-d7b1d3576eb7.json @@ -0,0 +1,38 @@ +{ + "id" : "26c29504-a4b8-440b-bbd1-d7b1d3576eb7", + "name" : "api_2.0_sql_sessions", + "request" : { + "url" : "/api/2.0/sql/sessions/", + "method" : "POST", + "bodyPatterns" : [ { + "equalToJson" : "{\"warehouse_id\":\"dd43ee29fedd958d\",\"schema\":\"default\",\"catalog\":\"SPARK\"}", + "ignoreArrayOrder" : true, + "ignoreExtraElements" : true + } ] + }, + "response" : { + "status" : 200, + "body" : "{\"session_id\":\"01f0a5bc-7472-14b8-bc16-71f68ce36d0c\"}", + "headers" : { + "x-request-id" : "b03130c4-9753-4a1d-93f1-b8d4fe7d021f", + "date" : "Fri, 10 Oct 2025 09:35:27 GMT", + "server" : "databricks", + "x-databricks-popp-response-code-details" : "via_upstream", + "x-databricks-shard-debug" : "oregon-staging", + "vary" : "Accept-Encoding", + "x-databricks-org-id" : "6051921418418893", + "strict-transport-security" : "max-age=31536000; includeSubDomains; preload", + "x-content-type-options" : "nosniff", + "x-databricks-popp-routing-reason" : "deployment-name", + "content-type" : "application/json", + "server-timing" : "request_id;dur=0;desc=\"b03130c4-9753-4a1d-93f1-b8d4fe7d021f\", client_protocol;dur=0;desc=\"HTTP/1.1\"", + "alt-svc" : "h3=\":5443\"; ma=86400, h3-29=\":5443\"; ma=86400", + "x-databricks-apiproxy-response-code-details" : "via_upstream" + } + }, + "uuid" : "26c29504-a4b8-440b-bbd1-d7b1d3576eb7", + "scenarioName" : "scenario-1-api-2.0-sql-sessions", + "requiredScenarioState" : "Started", + "newScenarioState" : "scenario-1-api-2.0-sql-sessions-2", + "insertionIndex" : 7 +} \ No newline at end of file diff --git a/src/test/resources/sqlexecapi/datatypesintegrationtests/testgeospatialtypes/mappings/api_2.0_sql_sessions-53ba8b00-9e82-4ffe-a90a-aa18dfea3f89.json b/src/test/resources/sqlexecapi/datatypesintegrationtests/testgeospatialtypes/mappings/api_2.0_sql_sessions-53ba8b00-9e82-4ffe-a90a-aa18dfea3f89.json new file mode 100644 index 0000000000..85e8fb750b --- /dev/null +++ b/src/test/resources/sqlexecapi/datatypesintegrationtests/testgeospatialtypes/mappings/api_2.0_sql_sessions-53ba8b00-9e82-4ffe-a90a-aa18dfea3f89.json @@ -0,0 +1,37 @@ +{ + "id" : "53ba8b00-9e82-4ffe-a90a-aa18dfea3f89", + "name" : "api_2.0_sql_sessions", + "request" : { + "url" : "/api/2.0/sql/sessions/", + "method" : "POST", + "bodyPatterns" : [ { + "equalToJson" : "{\"warehouse_id\":\"dd43ee29fedd958d\",\"schema\":\"default\",\"catalog\":\"SPARK\"}", + "ignoreArrayOrder" : true, + "ignoreExtraElements" : true + } ] + }, + "response" : { + "status" : 200, + "body" : "{\"session_id\":\"01f0a5bc-75de-14b1-aba0-dd791b1a50e3\"}", + "headers" : { + "x-request-id" : "b7cfeca3-2f54-4a9b-84b4-d99dedd08fe3", + "date" : "Fri, 10 Oct 2025 09:35:29 GMT", + "server" : "databricks", + "x-databricks-popp-response-code-details" : "via_upstream", + "x-databricks-shard-debug" : "oregon-staging", + "vary" : "Accept-Encoding", + "x-databricks-org-id" : "6051921418418893", + "strict-transport-security" : "max-age=31536000; includeSubDomains; preload", + "x-content-type-options" : "nosniff", + "x-databricks-popp-routing-reason" : "deployment-name", + "content-type" : "application/json", + "server-timing" : "request_id;dur=0;desc=\"b7cfeca3-2f54-4a9b-84b4-d99dedd08fe3\", client_protocol;dur=0;desc=\"HTTP/1.1\"", + "alt-svc" : "h3=\":5443\"; ma=86400, h3-29=\":5443\"; ma=86400", + "x-databricks-apiproxy-response-code-details" : "via_upstream" + } + }, + "uuid" : "53ba8b00-9e82-4ffe-a90a-aa18dfea3f89", + "scenarioName" : "scenario-1-api-2.0-sql-sessions", + "requiredScenarioState" : "scenario-1-api-2.0-sql-sessions-2", + "insertionIndex" : 5 +} \ No newline at end of file diff --git a/src/test/resources/sqlexecapi/datatypesintegrationtests/testgeospatialtypes/mappings/api_2.0_sql_sessions_01f0a5bc-7472-14b8-bc16-71f68ce36d0c-423765cb-ebcc-4198-8b3e-2c1997822b1c.json b/src/test/resources/sqlexecapi/datatypesintegrationtests/testgeospatialtypes/mappings/api_2.0_sql_sessions_01f0a5bc-7472-14b8-bc16-71f68ce36d0c-423765cb-ebcc-4198-8b3e-2c1997822b1c.json new file mode 100644 index 0000000000..b25b01ec9e --- /dev/null +++ b/src/test/resources/sqlexecapi/datatypesintegrationtests/testgeospatialtypes/mappings/api_2.0_sql_sessions_01f0a5bc-7472-14b8-bc16-71f68ce36d0c-423765cb-ebcc-4198-8b3e-2c1997822b1c.json @@ -0,0 +1,29 @@ +{ + "id" : "423765cb-ebcc-4198-8b3e-2c1997822b1c", + "name" : "api_2.0_sql_sessions_01f0a5bc-7472-14b8-bc16-71f68ce36d0c", + "request" : { + "url" : "/api/2.0/sql/sessions/01f0a5bc-7472-14b8-bc16-71f68ce36d0c?warehouse_id=dd43ee29fedd958d", + "method" : "DELETE" + }, + "response" : { + "status" : 200, + "body" : "{}", + "headers" : { + "x-request-id" : "ed1c1402-4910-4360-b08a-9040377de512", + "date" : "Fri, 10 Oct 2025 09:35:35 GMT", + "server" : "databricks", + "x-databricks-popp-response-code-details" : "via_upstream", + "x-databricks-shard-debug" : "oregon-staging", + "x-databricks-org-id" : "6051921418418893", + "strict-transport-security" : "max-age=31536000; includeSubDomains; preload", + "x-content-type-options" : "nosniff", + "x-databricks-popp-routing-reason" : "deployment-name", + "content-type" : "application/json", + "server-timing" : "request_id;dur=0;desc=\"ed1c1402-4910-4360-b08a-9040377de512\", client_protocol;dur=0;desc=\"HTTP/1.1\"", + "alt-svc" : "h3=\":5443\"; ma=86400, h3-29=\":5443\"; ma=86400", + "x-databricks-apiproxy-response-code-details" : "via_upstream" + } + }, + "uuid" : "423765cb-ebcc-4198-8b3e-2c1997822b1c", + "insertionIndex" : 2 +} \ No newline at end of file diff --git a/src/test/resources/sqlexecapi/datatypesintegrationtests/testgeospatialtypes/mappings/api_2.0_sql_sessions_01f0a5bc-75de-14b1-aba0-dd791b1a50e3-838649f2-ff8b-416a-b28f-e9bef5a36f7e.json b/src/test/resources/sqlexecapi/datatypesintegrationtests/testgeospatialtypes/mappings/api_2.0_sql_sessions_01f0a5bc-75de-14b1-aba0-dd791b1a50e3-838649f2-ff8b-416a-b28f-e9bef5a36f7e.json new file mode 100644 index 0000000000..b7006d771d --- /dev/null +++ b/src/test/resources/sqlexecapi/datatypesintegrationtests/testgeospatialtypes/mappings/api_2.0_sql_sessions_01f0a5bc-75de-14b1-aba0-dd791b1a50e3-838649f2-ff8b-416a-b28f-e9bef5a36f7e.json @@ -0,0 +1,29 @@ +{ + "id" : "838649f2-ff8b-416a-b28f-e9bef5a36f7e", + "name" : "api_2.0_sql_sessions_01f0a5bc-75de-14b1-aba0-dd791b1a50e3", + "request" : { + "url" : "/api/2.0/sql/sessions/01f0a5bc-75de-14b1-aba0-dd791b1a50e3?warehouse_id=dd43ee29fedd958d", + "method" : "DELETE" + }, + "response" : { + "status" : 200, + "body" : "{}", + "headers" : { + "x-request-id" : "020075a5-a0e8-4c1f-8885-e395d89fc45e", + "date" : "Fri, 10 Oct 2025 09:35:36 GMT", + "server" : "databricks", + "x-databricks-popp-response-code-details" : "via_upstream", + "x-databricks-shard-debug" : "oregon-staging", + "x-databricks-org-id" : "6051921418418893", + "strict-transport-security" : "max-age=31536000; includeSubDomains; preload", + "x-content-type-options" : "nosniff", + "x-databricks-popp-routing-reason" : "deployment-name", + "content-type" : "application/json", + "server-timing" : "request_id;dur=0;desc=\"020075a5-a0e8-4c1f-8885-e395d89fc45e\", client_protocol;dur=0;desc=\"HTTP/1.1\"", + "alt-svc" : "h3=\":5443\"; ma=86400, h3-29=\":5443\"; ma=86400", + "x-databricks-apiproxy-response-code-details" : "via_upstream" + } + }, + "uuid" : "838649f2-ff8b-416a-b28f-e9bef5a36f7e", + "insertionIndex" : 1 +} \ No newline at end of file diff --git a/src/test/resources/sqlexecapi/datatypesintegrationtests/testgeospatialtypes/mappings/api_2.0_sql_statements-1bc97f2a-5ba2-48a6-a701-819fd4d1fd53.json b/src/test/resources/sqlexecapi/datatypesintegrationtests/testgeospatialtypes/mappings/api_2.0_sql_statements-1bc97f2a-5ba2-48a6-a701-819fd4d1fd53.json new file mode 100644 index 0000000000..ca8e90737f --- /dev/null +++ b/src/test/resources/sqlexecapi/datatypesintegrationtests/testgeospatialtypes/mappings/api_2.0_sql_statements-1bc97f2a-5ba2-48a6-a701-819fd4d1fd53.json @@ -0,0 +1,35 @@ +{ + "id" : "1bc97f2a-5ba2-48a6-a701-819fd4d1fd53", + "name" : "api_2.0_sql_statements", + "request" : { + "url" : "/api/2.0/sql/statements/", + "method" : "POST", + "bodyPatterns" : [ { + "equalToJson" : "{\"statement\":\"SELECT * FROM (VALUES (1, ST_GeomFromText('POINT (1 2)'), ST_GeogFromText('POINT (3 4)')), (2, ST_GeomFromText('LINESTRING (0 0, 1 1, 2 2)'), ST_GeogFromText('LINESTRING (5 5, 6 6)')), (3, NULL, NULL)) AS geospatial_data(id, geom, geog) ORDER BY id\",\"warehouse_id\":\"dd43ee29fedd958d\",\"session_id\":\"01f0a5bc-7472-14b8-bc16-71f68ce36d0c\",\"disposition\":\"EXTERNAL_LINKS\",\"format\":\"ARROW_STREAM\",\"on_wait_timeout\":\"CONTINUE\",\"parameters\":[],\"result_compression\":\"LZ4_FRAME\"}", + "ignoreArrayOrder" : true, + "ignoreExtraElements" : true + } ] + }, + "response" : { + "status" : 200, + "body" : "{\"statement_id\":\"01f0a5bc-7691-1333-a867-e256984f11cf\",\"status\":{\"state\":\"SUCCEEDED\"},\"manifest\":{\"format\":\"ARROW_STREAM\",\"schema\":{\"column_count\":3,\"columns\":[{\"name\":\"id\",\"type_text\":\"INT\",\"type_name\":\"INT\",\"position\":0},{\"name\":\"geom\",\"type_text\":\"GEOMETRY(0)\",\"type_name\":\"GEOMETRY\",\"position\":1},{\"name\":\"geog\",\"type_text\":\"GEOGRAPHY(4326)\",\"type_name\":\"GEOGRAPHY\",\"position\":2}]},\"total_chunk_count\":1,\"chunks\":[{\"chunk_index\":0,\"row_offset\":0,\"row_count\":3,\"byte_count\":720}],\"total_row_count\":3,\"total_byte_count\":720,\"truncated\":false,\"result_compression\":\"LZ4_FRAME\"},\"result\":{\"external_links\":[{\"chunk_index\":0,\"row_offset\":0,\"row_count\":3,\"byte_count\":547,\"external_link\":\"https://e2-dogfood-core.s3.us-west-2.amazonaws.com/oregon-staging/6051921418418893.jobs/sql/2025-10-10/09/results_2025-10-10T09%3A35%3A31Z_dfb38243-a074-4425-a7fe-772f480f384a?[REDACTED]X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=20251010T093531Z&X-Amz-SignedHeaders=host&X-Amz-Expires=899&[REDACTED]X-Amz-Signature=6a356f310ac3c56bbfccb7b5f5f31b34eb1010a04c8250659118a9db52f83e5f\",\"expiration\":\"2025-10-10T09:50:31.512Z\"}]}}", + "headers" : { + "x-request-id" : "c41ca866-9974-4e14-83c2-a6c072d9a33c", + "date" : "Fri, 10 Oct 2025 09:35:31 GMT", + "server" : "databricks", + "x-databricks-popp-response-code-details" : "via_upstream", + "x-databricks-shard-debug" : "oregon-staging", + "vary" : "Accept-Encoding", + "x-databricks-org-id" : "6051921418418893", + "strict-transport-security" : "max-age=31536000; includeSubDomains; preload", + "x-content-type-options" : "nosniff", + "x-databricks-popp-routing-reason" : "deployment-name", + "content-type" : "application/json", + "server-timing" : "request_id;dur=0;desc=\"c41ca866-9974-4e14-83c2-a6c072d9a33c\", client_protocol;dur=0;desc=\"HTTP/1.1\"", + "alt-svc" : "h3=\":5443\"; ma=86400, h3-29=\":5443\"; ma=86400", + "x-databricks-apiproxy-response-code-details" : "via_upstream" + } + }, + "uuid" : "1bc97f2a-5ba2-48a6-a701-819fd4d1fd53", + "insertionIndex" : 4 +} \ No newline at end of file diff --git a/src/test/resources/sqlexecapi/datatypesintegrationtests/testgeospatialtypes/mappings/api_2.0_sql_statements_01f0a5bc-7691-1333-a867-e256984f11cf-03a6959b-2f46-41af-9cc0-dfd458a4d0ac.json b/src/test/resources/sqlexecapi/datatypesintegrationtests/testgeospatialtypes/mappings/api_2.0_sql_statements_01f0a5bc-7691-1333-a867-e256984f11cf-03a6959b-2f46-41af-9cc0-dfd458a4d0ac.json new file mode 100644 index 0000000000..a51a78f2c7 --- /dev/null +++ b/src/test/resources/sqlexecapi/datatypesintegrationtests/testgeospatialtypes/mappings/api_2.0_sql_statements_01f0a5bc-7691-1333-a867-e256984f11cf-03a6959b-2f46-41af-9cc0-dfd458a4d0ac.json @@ -0,0 +1,29 @@ +{ + "id" : "03a6959b-2f46-41af-9cc0-dfd458a4d0ac", + "name" : "api_2.0_sql_statements_01f0a5bc-7691-1333-a867-e256984f11cf", + "request" : { + "url" : "/api/2.0/sql/statements/01f0a5bc-7691-1333-a867-e256984f11cf", + "method" : "DELETE" + }, + "response" : { + "status" : 200, + "body" : "{}", + "headers" : { + "x-request-id" : "b59b889c-e6b6-4c88-af81-ace62198e27f", + "date" : "Fri, 10 Oct 2025 09:35:34 GMT", + "server" : "databricks", + "x-databricks-popp-response-code-details" : "via_upstream", + "x-databricks-shard-debug" : "oregon-staging", + "x-databricks-org-id" : "6051921418418893", + "strict-transport-security" : "max-age=31536000; includeSubDomains; preload", + "x-content-type-options" : "nosniff", + "x-databricks-popp-routing-reason" : "deployment-name", + "content-type" : "application/json", + "server-timing" : "request_id;dur=0;desc=\"b59b889c-e6b6-4c88-af81-ace62198e27f\", client_protocol;dur=0;desc=\"HTTP/1.1\"", + "alt-svc" : "h3=\":5443\"; ma=86400, h3-29=\":5443\"; ma=86400", + "x-databricks-apiproxy-response-code-details" : "via_upstream" + } + }, + "uuid" : "03a6959b-2f46-41af-9cc0-dfd458a4d0ac", + "insertionIndex" : 3 +} \ No newline at end of file diff --git a/src/test/resources/sqlexecapi/datatypesintegrationtests/testgeospatialtypes/mappings/oidc_.well-known_oauth-authorization-server-75d1e2b1-4917-4fc3-bc23-63e9201f71c2.json b/src/test/resources/sqlexecapi/datatypesintegrationtests/testgeospatialtypes/mappings/oidc_.well-known_oauth-authorization-server-75d1e2b1-4917-4fc3-bc23-63e9201f71c2.json new file mode 100644 index 0000000000..1d8f93b433 --- /dev/null +++ b/src/test/resources/sqlexecapi/datatypesintegrationtests/testgeospatialtypes/mappings/oidc_.well-known_oauth-authorization-server-75d1e2b1-4917-4fc3-bc23-63e9201f71c2.json @@ -0,0 +1,36 @@ +{ + "id" : "75d1e2b1-4917-4fc3-bc23-63e9201f71c2", + "name" : "oidc_.well-known_oauth-authorization-server", + "request" : { + "url" : "/oidc/.well-known/oauth-authorization-server", + "method" : "GET" + }, + "response" : { + "status" : 200, + "body" : "{\"authorization_endpoint\":\"https:\\/\\/e2-dogfood.staging.cloud.databricks.com\\/oidc\\/v1\\/authorize\",\"token_endpoint\":\"https:\\/\\/e2-dogfood.staging.cloud.databricks.com\\/oidc\\/v1\\/token\",\"issuer\":\"https:\\/\\/e2-dogfood.staging.cloud.databricks.com\\/oidc\",\"jwks_uri\":\"https:\\/\\/oregon.staging.cloud.databricks.com\\/oidc\\/jwks.json\",\"scopes_supported\":[\"all-apis\",\"apps.apps\",\"catalog.artifact-allowlists\",\"catalog.catalogs\",\"catalog.connections\",\"catalog.credentials\",\"catalog.entity-tag-assignments\",\"catalog.external-lineage\",\"catalog.external-locations\",\"catalog.external-metadata\",\"catalog.functions\",\"catalog.grants\",\"catalog.metastores\",\"catalog.model-versions\",\"catalog.online-tables\",\"catalog.policies\",\"catalog.quality-monitors\",\"catalog.registered-models\",\"catalog.resource-quotas\",\"catalog.rfa\",\"catalog.schemas\",\"catalog.storage-credentials\",\"catalog.system-schemas\",\"catalog.table-constraints\",\"catalog.tables\",\"catalog.temporary-path-credentials\",\"catalog.temporary-table-credentials\",\"catalog.volumes\",\"catalog.workspace-bindings\",\"cleanrooms.clean-room-asset-revisions\",\"cleanrooms.clean-room-assets\",\"cleanrooms.clean-room-auto-approval-rules\",\"cleanrooms.clean-room-task-runs\",\"cleanrooms.clean-rooms\",\"compute.cluster-policies\",\"compute.clusters\",\"compute.command-execution\",\"compute.global-init-scripts\",\"compute.instance-pools\",\"compute.instance-profiles\",\"compute.libraries\",\"compute.policy-compliance-for-clusters\",\"compute.policy-families\",\"dashboards.genie\",\"dashboards.lakeview\",\"dashboards.lakeview-embedded\",\"database.database\",\"email\",\"files.dbfs\",\"files.files\",\"iam.account-access-control-proxy\",\"iam.current-user\",\"iam.groups\",\"iam.permissions\",\"iam.service-principals\",\"iam.users\",\"iamv2.iam\",\"jobs.jobs\",\"jobs.policy-compliance-for-jobs\",\"marketplace.consumer-fulfillments\",\"marketplace.consumer-installations\",\"marketplace.consumer-listings\",\"marketplace.consumer-personalization-requests\",\"marketplace.consumer-providers\",\"marketplace.provider-exchange-filters\",\"marketplace.provider-exchanges\",\"marketplace.provider-files\",\"marketplace.provider-listings\",\"marketplace.provider-personalization-requests\",\"marketplace.provider-provider-analytics-dashboards\",\"marketplace.provider-providers\",\"mcp.external\",\"mcp.functions\",\"mcp.genie\",\"mcp.sql\",\"mcp.vectorsearch\",\"ml.experiments\",\"ml.model-registry\",\"oauth2.service-principal-secrets-proxy\",\"offline_access\",\"openid\",\"pipelines.pipelines\",\"profile\",\"qualitymonitorv2.quality-monitor\",\"serving.serving-endpoints\",\"settings.aibi-dashboard-embedding-access-policy\",\"settings.aibi-dashboard-embedding-approved-domains\",\"settings.automatic-cluster-update\",\"settings.compliance-security-profile\",\"settings.dashboard-email-subscriptions\",\"settings.default-namespace\",\"settings.disable-legacy-access\",\"settings.disable-legacy-dbfs\",\"settings.enable-export-notebook\",\"settings.enable-notebook-table-clipboard\",\"settings.enable-results-downloading\",\"settings.enhanced-security-monitoring\",\"settings.ip-access-lists\",\"settings.notification-destinations\",\"settings.restrict-workspace-admins\",\"settings.sql-results-download\",\"settings.token-management\",\"settings.tokens\",\"settings.workspace-conf\",\"settingsv2.settings\",\"sharing.providers\",\"sharing.recipient-activation\",\"sharing.recipients\",\"sharing.shares\",\"sql\",\"sql.alerts\",\"sql.alerts-legacy\",\"sql.alerts-v2\",\"sql.dashboards\",\"sql.data-sources\",\"sql.dbsql-permissions\",\"sql.driver\",\"sql.queries\",\"sql.queries-legacy\",\"sql.query-history\",\"sql.statement-execution\",\"sql.warehouses\",\"tags.tag-policies\",\"vectorsearch.vector-search-endpoints\",\"vectorsearch.vector-search-indexes\",\"workspace.git-credentials\",\"workspace.repos\",\"workspace.secrets\",\"workspace.workspace\"],\"response_types_supported\":[\"code\",\"id_token\"],\"response_modes_supported\":[\"query\",\"fragment\",\"form_post\"],\"grant_types_supported\":[\"client_credentials\",\"authorization_code\",\"refresh_token\"],\"code_challenge_methods_supported\":[\"S256\"],\"token_endpoint_auth_methods_supported\":[\"client_secret_basic\",\"client_secret_post\",\"none\"],\"subject_types_supported\":[\"public\"],\"id_token_signing_alg_values_supported\":[\"RS256\"],\"claims_supported\":[\"iss\",\"sub\",\"aud\",\"iat\",\"exp\",\"jti\",\"name\",\"family_name\",\"given_name\",\"preferred_username\"],\"request_uri_parameter_supported\":false}", + "headers" : { + "x-request-id" : "8b5b037b-ab96-4532-9ee6-a983e18118fd", + "date" : "Fri, 10 Oct 2025 09:35:26 GMT", + "server" : "databricks", + "x-databricks-popp-response-code-details" : "via_upstream", + "x-databricks-shard-debug" : "oregon-staging", + "vary" : "Accept-Encoding", + "access-control-allow-headers" : "Content-Type", + "x-databricks-org-id" : "6051921418418893", + "strict-transport-security" : "max-age=31536000; includeSubDomains; preload", + "access-control-allow-methods" : "GET", + "access-control-allow-origin" : "*", + "x-content-type-options" : "nosniff", + "x-databricks-popp-routing-reason" : "deployment-name", + "content-type" : "application/json; charset=UTF-8", + "server-timing" : "request_id;dur=0;desc=\"8b5b037b-ab96-4532-9ee6-a983e18118fd\", client_protocol;dur=0;desc=\"HTTP/1.1\"", + "alt-svc" : "h3=\":5443\"; ma=86400, h3-29=\":5443\"; ma=86400", + "x-databricks-apiproxy-response-code-details" : "via_upstream" + } + }, + "uuid" : "75d1e2b1-4917-4fc3-bc23-63e9201f71c2", + "scenarioName" : "scenario-2-oidc-.well-known-oauth-authorization-server", + "requiredScenarioState" : "Started", + "newScenarioState" : "scenario-2-oidc-.well-known-oauth-authorization-server-2", + "insertionIndex" : 8 +} \ No newline at end of file diff --git a/src/test/resources/sqlexecapi/datatypesintegrationtests/testgeospatialtypes/mappings/oidc_.well-known_oauth-authorization-server-872f82e0-1642-4fc5-a033-23dc902aed10.json b/src/test/resources/sqlexecapi/datatypesintegrationtests/testgeospatialtypes/mappings/oidc_.well-known_oauth-authorization-server-872f82e0-1642-4fc5-a033-23dc902aed10.json new file mode 100644 index 0000000000..16a3edb92c --- /dev/null +++ b/src/test/resources/sqlexecapi/datatypesintegrationtests/testgeospatialtypes/mappings/oidc_.well-known_oauth-authorization-server-872f82e0-1642-4fc5-a033-23dc902aed10.json @@ -0,0 +1,35 @@ +{ + "id" : "872f82e0-1642-4fc5-a033-23dc902aed10", + "name" : "oidc_.well-known_oauth-authorization-server", + "request" : { + "url" : "/oidc/.well-known/oauth-authorization-server", + "method" : "GET" + }, + "response" : { + "status" : 200, + "body" : "{\"authorization_endpoint\":\"https:\\/\\/e2-dogfood.staging.cloud.databricks.com\\/oidc\\/v1\\/authorize\",\"token_endpoint\":\"https:\\/\\/e2-dogfood.staging.cloud.databricks.com\\/oidc\\/v1\\/token\",\"issuer\":\"https:\\/\\/e2-dogfood.staging.cloud.databricks.com\\/oidc\",\"jwks_uri\":\"https:\\/\\/oregon.staging.cloud.databricks.com\\/oidc\\/jwks.json\",\"scopes_supported\":[\"all-apis\",\"apps.apps\",\"catalog.artifact-allowlists\",\"catalog.catalogs\",\"catalog.connections\",\"catalog.credentials\",\"catalog.entity-tag-assignments\",\"catalog.external-lineage\",\"catalog.external-locations\",\"catalog.external-metadata\",\"catalog.functions\",\"catalog.grants\",\"catalog.metastores\",\"catalog.model-versions\",\"catalog.online-tables\",\"catalog.policies\",\"catalog.quality-monitors\",\"catalog.registered-models\",\"catalog.resource-quotas\",\"catalog.rfa\",\"catalog.schemas\",\"catalog.storage-credentials\",\"catalog.system-schemas\",\"catalog.table-constraints\",\"catalog.tables\",\"catalog.temporary-path-credentials\",\"catalog.temporary-table-credentials\",\"catalog.volumes\",\"catalog.workspace-bindings\",\"cleanrooms.clean-room-asset-revisions\",\"cleanrooms.clean-room-assets\",\"cleanrooms.clean-room-auto-approval-rules\",\"cleanrooms.clean-room-task-runs\",\"cleanrooms.clean-rooms\",\"compute.cluster-policies\",\"compute.clusters\",\"compute.command-execution\",\"compute.global-init-scripts\",\"compute.instance-pools\",\"compute.instance-profiles\",\"compute.libraries\",\"compute.policy-compliance-for-clusters\",\"compute.policy-families\",\"dashboards.genie\",\"dashboards.lakeview\",\"dashboards.lakeview-embedded\",\"database.database\",\"email\",\"files.dbfs\",\"files.files\",\"iam.account-access-control-proxy\",\"iam.current-user\",\"iam.groups\",\"iam.permissions\",\"iam.service-principals\",\"iam.users\",\"iamv2.iam\",\"jobs.jobs\",\"jobs.policy-compliance-for-jobs\",\"marketplace.consumer-fulfillments\",\"marketplace.consumer-installations\",\"marketplace.consumer-listings\",\"marketplace.consumer-personalization-requests\",\"marketplace.consumer-providers\",\"marketplace.provider-exchange-filters\",\"marketplace.provider-exchanges\",\"marketplace.provider-files\",\"marketplace.provider-listings\",\"marketplace.provider-personalization-requests\",\"marketplace.provider-provider-analytics-dashboards\",\"marketplace.provider-providers\",\"mcp.external\",\"mcp.functions\",\"mcp.genie\",\"mcp.sql\",\"mcp.vectorsearch\",\"ml.experiments\",\"ml.model-registry\",\"oauth2.service-principal-secrets-proxy\",\"offline_access\",\"openid\",\"pipelines.pipelines\",\"profile\",\"qualitymonitorv2.quality-monitor\",\"serving.serving-endpoints\",\"settings.aibi-dashboard-embedding-access-policy\",\"settings.aibi-dashboard-embedding-approved-domains\",\"settings.automatic-cluster-update\",\"settings.compliance-security-profile\",\"settings.dashboard-email-subscriptions\",\"settings.default-namespace\",\"settings.disable-legacy-access\",\"settings.disable-legacy-dbfs\",\"settings.enable-export-notebook\",\"settings.enable-notebook-table-clipboard\",\"settings.enable-results-downloading\",\"settings.enhanced-security-monitoring\",\"settings.ip-access-lists\",\"settings.notification-destinations\",\"settings.restrict-workspace-admins\",\"settings.sql-results-download\",\"settings.token-management\",\"settings.tokens\",\"settings.workspace-conf\",\"settingsv2.settings\",\"sharing.providers\",\"sharing.recipient-activation\",\"sharing.recipients\",\"sharing.shares\",\"sql\",\"sql.alerts\",\"sql.alerts-legacy\",\"sql.alerts-v2\",\"sql.dashboards\",\"sql.data-sources\",\"sql.dbsql-permissions\",\"sql.driver\",\"sql.queries\",\"sql.queries-legacy\",\"sql.query-history\",\"sql.statement-execution\",\"sql.warehouses\",\"tags.tag-policies\",\"vectorsearch.vector-search-endpoints\",\"vectorsearch.vector-search-indexes\",\"workspace.git-credentials\",\"workspace.repos\",\"workspace.secrets\",\"workspace.workspace\"],\"response_types_supported\":[\"code\",\"id_token\"],\"response_modes_supported\":[\"query\",\"fragment\",\"form_post\"],\"grant_types_supported\":[\"client_credentials\",\"authorization_code\",\"refresh_token\"],\"code_challenge_methods_supported\":[\"S256\"],\"token_endpoint_auth_methods_supported\":[\"client_secret_basic\",\"client_secret_post\",\"none\"],\"subject_types_supported\":[\"public\"],\"id_token_signing_alg_values_supported\":[\"RS256\"],\"claims_supported\":[\"iss\",\"sub\",\"aud\",\"iat\",\"exp\",\"jti\",\"name\",\"family_name\",\"given_name\",\"preferred_username\"],\"request_uri_parameter_supported\":false}", + "headers" : { + "x-request-id" : "dfe1201f-10ce-430a-81ba-0404d9248468", + "date" : "Fri, 10 Oct 2025 09:35:28 GMT", + "server" : "databricks", + "x-databricks-popp-response-code-details" : "via_upstream", + "x-databricks-shard-debug" : "oregon-staging", + "vary" : "Accept-Encoding", + "access-control-allow-headers" : "Content-Type", + "x-databricks-org-id" : "6051921418418893", + "strict-transport-security" : "max-age=31536000; includeSubDomains; preload", + "access-control-allow-methods" : "GET", + "access-control-allow-origin" : "*", + "x-content-type-options" : "nosniff", + "x-databricks-popp-routing-reason" : "deployment-name", + "content-type" : "application/json; charset=UTF-8", + "server-timing" : "request_id;dur=0;desc=\"dfe1201f-10ce-430a-81ba-0404d9248468\", client_protocol;dur=0;desc=\"HTTP/1.1\"", + "alt-svc" : "h3=\":5443\"; ma=86400, h3-29=\":5443\"; ma=86400", + "x-databricks-apiproxy-response-code-details" : "via_upstream" + } + }, + "uuid" : "872f82e0-1642-4fc5-a033-23dc902aed10", + "scenarioName" : "scenario-2-oidc-.well-known-oauth-authorization-server", + "requiredScenarioState" : "scenario-2-oidc-.well-known-oauth-authorization-server-2", + "insertionIndex" : 6 +} \ No newline at end of file diff --git a/src/test/resources/thriftserverapi/datatypesintegrationtests/testgeospatialtypes/mappings/oidc_.well-known_oauth-authorization-server-27a67ec3-b459-49cd-9d6f-f2cdf5ecd35a.json b/src/test/resources/thriftserverapi/datatypesintegrationtests/testgeospatialtypes/mappings/oidc_.well-known_oauth-authorization-server-27a67ec3-b459-49cd-9d6f-f2cdf5ecd35a.json new file mode 100644 index 0000000000..da6984e000 --- /dev/null +++ b/src/test/resources/thriftserverapi/datatypesintegrationtests/testgeospatialtypes/mappings/oidc_.well-known_oauth-authorization-server-27a67ec3-b459-49cd-9d6f-f2cdf5ecd35a.json @@ -0,0 +1,33 @@ +{ + "id" : "27a67ec3-b459-49cd-9d6f-f2cdf5ecd35a", + "name" : "oidc_.well-known_oauth-authorization-server", + "request" : { + "url" : "/oidc/.well-known/oauth-authorization-server", + "method" : "GET" + }, + "response" : { + "status" : 200, + "body" : "{\"authorization_endpoint\":\"https:\\/\\/e2-dogfood.staging.cloud.databricks.com\\/oidc\\/v1\\/authorize\",\"token_endpoint\":\"https:\\/\\/e2-dogfood.staging.cloud.databricks.com\\/oidc\\/v1\\/token\",\"issuer\":\"https:\\/\\/e2-dogfood.staging.cloud.databricks.com\\/oidc\",\"jwks_uri\":\"https:\\/\\/oregon.staging.cloud.databricks.com\\/oidc\\/jwks.json\",\"scopes_supported\":[\"all-apis\",\"apps.apps\",\"catalog.artifact-allowlists\",\"catalog.catalogs\",\"catalog.connections\",\"catalog.credentials\",\"catalog.entity-tag-assignments\",\"catalog.external-lineage\",\"catalog.external-locations\",\"catalog.external-metadata\",\"catalog.functions\",\"catalog.grants\",\"catalog.metastores\",\"catalog.model-versions\",\"catalog.online-tables\",\"catalog.policies\",\"catalog.quality-monitors\",\"catalog.registered-models\",\"catalog.resource-quotas\",\"catalog.rfa\",\"catalog.schemas\",\"catalog.storage-credentials\",\"catalog.system-schemas\",\"catalog.table-constraints\",\"catalog.tables\",\"catalog.temporary-path-credentials\",\"catalog.temporary-table-credentials\",\"catalog.volumes\",\"catalog.workspace-bindings\",\"cleanrooms.clean-room-asset-revisions\",\"cleanrooms.clean-room-assets\",\"cleanrooms.clean-room-auto-approval-rules\",\"cleanrooms.clean-room-task-runs\",\"cleanrooms.clean-rooms\",\"compute.cluster-policies\",\"compute.clusters\",\"compute.command-execution\",\"compute.global-init-scripts\",\"compute.instance-pools\",\"compute.instance-profiles\",\"compute.libraries\",\"compute.policy-compliance-for-clusters\",\"compute.policy-families\",\"dashboards.genie\",\"dashboards.lakeview\",\"dashboards.lakeview-embedded\",\"database.database\",\"dataquality.data-quality\",\"email\",\"files.dbfs\",\"files.files\",\"iam.account-access-control-proxy\",\"iam.current-user\",\"iam.groups\",\"iam.permissions\",\"iam.service-principals\",\"iam.users\",\"iamv2.iam\",\"jobs.jobs\",\"jobs.policy-compliance-for-jobs\",\"marketplace.consumer-fulfillments\",\"marketplace.consumer-installations\",\"marketplace.consumer-listings\",\"marketplace.consumer-personalization-requests\",\"marketplace.consumer-providers\",\"marketplace.provider-exchange-filters\",\"marketplace.provider-exchanges\",\"marketplace.provider-files\",\"marketplace.provider-listings\",\"marketplace.provider-personalization-requests\",\"marketplace.provider-provider-analytics-dashboards\",\"marketplace.provider-providers\",\"mcp.external\",\"mcp.functions\",\"mcp.genie\",\"mcp.sql\",\"mcp.vectorsearch\",\"ml.experiments\",\"ml.model-registry\",\"oauth2.service-principal-secrets-proxy\",\"offline_access\",\"openid\",\"pipelines.pipelines\",\"profile\",\"qualitymonitorv2.quality-monitor\",\"serving.serving-endpoints\",\"settings.aibi-dashboard-embedding-access-policy\",\"settings.aibi-dashboard-embedding-approved-domains\",\"settings.automatic-cluster-update\",\"settings.compliance-security-profile\",\"settings.dashboard-email-subscriptions\",\"settings.default-namespace\",\"settings.disable-legacy-access\",\"settings.disable-legacy-dbfs\",\"settings.enable-export-notebook\",\"settings.enable-notebook-table-clipboard\",\"settings.enable-results-downloading\",\"settings.enhanced-security-monitoring\",\"settings.ip-access-lists\",\"settings.notification-destinations\",\"settings.restrict-workspace-admins\",\"settings.sql-results-download\",\"settings.token-management\",\"settings.tokens\",\"settings.workspace-conf\",\"settingsv2.settings\",\"sharing.providers\",\"sharing.recipient-activation\",\"sharing.recipient-federation-policies\",\"sharing.recipients\",\"sharing.shares\",\"sql\",\"sql.alerts\",\"sql.alerts-legacy\",\"sql.alerts-v2\",\"sql.dashboards\",\"sql.data-sources\",\"sql.dbsql-permissions\",\"sql.driver\",\"sql.queries\",\"sql.queries-legacy\",\"sql.query-history\",\"sql.statement-execution\",\"sql.warehouses\",\"tags.tag-policies\",\"vectorsearch.vector-search-endpoints\",\"vectorsearch.vector-search-indexes\",\"workspace.git-credentials\",\"workspace.repos\",\"workspace.secrets\",\"workspace.workspace\"],\"response_types_supported\":[\"code\",\"id_token\"],\"response_modes_supported\":[\"query\",\"fragment\",\"form_post\"],\"grant_types_supported\":[\"client_credentials\",\"authorization_code\",\"refresh_token\"],\"code_challenge_methods_supported\":[\"S256\"],\"token_endpoint_auth_methods_supported\":[\"client_secret_basic\",\"client_secret_post\",\"none\"],\"subject_types_supported\":[\"public\"],\"id_token_signing_alg_values_supported\":[\"RS256\"],\"claims_supported\":[\"iss\",\"sub\",\"aud\",\"iat\",\"exp\",\"jti\",\"name\",\"family_name\",\"given_name\",\"preferred_username\"],\"request_uri_parameter_supported\":false}", + "headers" : { + "x-request-id" : "6398af77-8a27-4154-b641-264b2a96e878", + "date" : "Fri, 24 Oct 2025 09:13:20 GMT", + "server" : "databricks", + "x-databricks-popp-response-code-details" : "via_upstream", + "x-databricks-shard-debug" : "oregon-staging", + "vary" : "Accept-Encoding", + "x-databricks-org-id" : "6051921418418893", + "strict-transport-security" : "max-age=31536000; includeSubDomains; preload", + "x-content-type-options" : "nosniff", + "x-databricks-popp-routing-reason" : "deployment-name", + "content-type" : "application/json; charset=UTF-8", + "server-timing" : "request_id;dur=0;desc=\"6398af77-8a27-4154-b641-264b2a96e878\", client_protocol;dur=0;desc=\"HTTP/1.1\"", + "alt-svc" : "h3=\":5443\"; ma=86400, h3-29=\":5443\"; ma=86400", + "x-databricks-apiproxy-response-code-details" : "via_upstream" + } + }, + "uuid" : "27a67ec3-b459-49cd-9d6f-f2cdf5ecd35a", + "scenarioName" : "scenario-2-oidc-.well-known-oauth-authorization-server", + "requiredScenarioState" : "Started", + "newScenarioState" : "scenario-2-oidc-.well-known-oauth-authorization-server-2", + "insertionIndex" : 6 +} \ No newline at end of file diff --git a/src/test/resources/thriftserverapi/datatypesintegrationtests/testgeospatialtypes/mappings/oidc_.well-known_oauth-authorization-server-a917e9cc-d745-4586-97f4-d6d4701804fd.json b/src/test/resources/thriftserverapi/datatypesintegrationtests/testgeospatialtypes/mappings/oidc_.well-known_oauth-authorization-server-a917e9cc-d745-4586-97f4-d6d4701804fd.json new file mode 100644 index 0000000000..3c97117b70 --- /dev/null +++ b/src/test/resources/thriftserverapi/datatypesintegrationtests/testgeospatialtypes/mappings/oidc_.well-known_oauth-authorization-server-a917e9cc-d745-4586-97f4-d6d4701804fd.json @@ -0,0 +1,32 @@ +{ + "id" : "a917e9cc-d745-4586-97f4-d6d4701804fd", + "name" : "oidc_.well-known_oauth-authorization-server", + "request" : { + "url" : "/oidc/.well-known/oauth-authorization-server", + "method" : "GET" + }, + "response" : { + "status" : 200, + "body" : "{\"authorization_endpoint\":\"https:\\/\\/e2-dogfood.staging.cloud.databricks.com\\/oidc\\/v1\\/authorize\",\"token_endpoint\":\"https:\\/\\/e2-dogfood.staging.cloud.databricks.com\\/oidc\\/v1\\/token\",\"issuer\":\"https:\\/\\/e2-dogfood.staging.cloud.databricks.com\\/oidc\",\"jwks_uri\":\"https:\\/\\/oregon.staging.cloud.databricks.com\\/oidc\\/jwks.json\",\"scopes_supported\":[\"all-apis\",\"apps.apps\",\"catalog.artifact-allowlists\",\"catalog.catalogs\",\"catalog.connections\",\"catalog.credentials\",\"catalog.entity-tag-assignments\",\"catalog.external-lineage\",\"catalog.external-locations\",\"catalog.external-metadata\",\"catalog.functions\",\"catalog.grants\",\"catalog.metastores\",\"catalog.model-versions\",\"catalog.online-tables\",\"catalog.policies\",\"catalog.quality-monitors\",\"catalog.registered-models\",\"catalog.resource-quotas\",\"catalog.rfa\",\"catalog.schemas\",\"catalog.storage-credentials\",\"catalog.system-schemas\",\"catalog.table-constraints\",\"catalog.tables\",\"catalog.temporary-path-credentials\",\"catalog.temporary-table-credentials\",\"catalog.volumes\",\"catalog.workspace-bindings\",\"cleanrooms.clean-room-asset-revisions\",\"cleanrooms.clean-room-assets\",\"cleanrooms.clean-room-auto-approval-rules\",\"cleanrooms.clean-room-task-runs\",\"cleanrooms.clean-rooms\",\"compute.cluster-policies\",\"compute.clusters\",\"compute.command-execution\",\"compute.global-init-scripts\",\"compute.instance-pools\",\"compute.instance-profiles\",\"compute.libraries\",\"compute.policy-compliance-for-clusters\",\"compute.policy-families\",\"dashboards.genie\",\"dashboards.lakeview\",\"dashboards.lakeview-embedded\",\"database.database\",\"dataquality.data-quality\",\"email\",\"files.dbfs\",\"files.files\",\"iam.account-access-control-proxy\",\"iam.current-user\",\"iam.groups\",\"iam.permissions\",\"iam.service-principals\",\"iam.users\",\"iamv2.iam\",\"jobs.jobs\",\"jobs.policy-compliance-for-jobs\",\"marketplace.consumer-fulfillments\",\"marketplace.consumer-installations\",\"marketplace.consumer-listings\",\"marketplace.consumer-personalization-requests\",\"marketplace.consumer-providers\",\"marketplace.provider-exchange-filters\",\"marketplace.provider-exchanges\",\"marketplace.provider-files\",\"marketplace.provider-listings\",\"marketplace.provider-personalization-requests\",\"marketplace.provider-provider-analytics-dashboards\",\"marketplace.provider-providers\",\"mcp.external\",\"mcp.functions\",\"mcp.genie\",\"mcp.sql\",\"mcp.vectorsearch\",\"ml.experiments\",\"ml.model-registry\",\"oauth2.service-principal-secrets-proxy\",\"offline_access\",\"openid\",\"pipelines.pipelines\",\"profile\",\"qualitymonitorv2.quality-monitor\",\"serving.serving-endpoints\",\"settings.aibi-dashboard-embedding-access-policy\",\"settings.aibi-dashboard-embedding-approved-domains\",\"settings.automatic-cluster-update\",\"settings.compliance-security-profile\",\"settings.dashboard-email-subscriptions\",\"settings.default-namespace\",\"settings.disable-legacy-access\",\"settings.disable-legacy-dbfs\",\"settings.enable-export-notebook\",\"settings.enable-notebook-table-clipboard\",\"settings.enable-results-downloading\",\"settings.enhanced-security-monitoring\",\"settings.ip-access-lists\",\"settings.notification-destinations\",\"settings.restrict-workspace-admins\",\"settings.sql-results-download\",\"settings.token-management\",\"settings.tokens\",\"settings.workspace-conf\",\"settingsv2.settings\",\"sharing.providers\",\"sharing.recipient-activation\",\"sharing.recipient-federation-policies\",\"sharing.recipients\",\"sharing.shares\",\"sql\",\"sql.alerts\",\"sql.alerts-legacy\",\"sql.alerts-v2\",\"sql.dashboards\",\"sql.data-sources\",\"sql.dbsql-permissions\",\"sql.driver\",\"sql.queries\",\"sql.queries-legacy\",\"sql.query-history\",\"sql.statement-execution\",\"sql.warehouses\",\"tags.tag-policies\",\"vectorsearch.vector-search-endpoints\",\"vectorsearch.vector-search-indexes\",\"workspace.git-credentials\",\"workspace.repos\",\"workspace.secrets\",\"workspace.workspace\"],\"response_types_supported\":[\"code\",\"id_token\"],\"response_modes_supported\":[\"query\",\"fragment\",\"form_post\"],\"grant_types_supported\":[\"client_credentials\",\"authorization_code\",\"refresh_token\"],\"code_challenge_methods_supported\":[\"S256\"],\"token_endpoint_auth_methods_supported\":[\"client_secret_basic\",\"client_secret_post\",\"none\"],\"subject_types_supported\":[\"public\"],\"id_token_signing_alg_values_supported\":[\"RS256\"],\"claims_supported\":[\"iss\",\"sub\",\"aud\",\"iat\",\"exp\",\"jti\",\"name\",\"family_name\",\"given_name\",\"preferred_username\"],\"request_uri_parameter_supported\":false}", + "headers" : { + "x-request-id" : "2ea66a34-ef7a-4d2e-80ca-0e188dd6cfe0", + "date" : "Fri, 24 Oct 2025 09:13:22 GMT", + "server" : "databricks", + "x-databricks-popp-response-code-details" : "via_upstream", + "x-databricks-shard-debug" : "oregon-staging", + "vary" : "Accept-Encoding", + "x-databricks-org-id" : "6051921418418893", + "strict-transport-security" : "max-age=31536000; includeSubDomains; preload", + "x-content-type-options" : "nosniff", + "x-databricks-popp-routing-reason" : "deployment-name", + "content-type" : "application/json; charset=UTF-8", + "server-timing" : "request_id;dur=0;desc=\"2ea66a34-ef7a-4d2e-80ca-0e188dd6cfe0\", client_protocol;dur=0;desc=\"HTTP/1.1\"", + "alt-svc" : "h3=\":5443\"; ma=86400, h3-29=\":5443\"; ma=86400", + "x-databricks-apiproxy-response-code-details" : "via_upstream" + } + }, + "uuid" : "a917e9cc-d745-4586-97f4-d6d4701804fd", + "scenarioName" : "scenario-2-oidc-.well-known-oauth-authorization-server", + "requiredScenarioState" : "scenario-2-oidc-.well-known-oauth-authorization-server-2", + "insertionIndex" : 4 +} \ No newline at end of file diff --git a/src/test/resources/thriftserverapi/datatypesintegrationtests/testgeospatialtypes/mappings/sql_protocolv1_o_6051921418418893_0819-204509-hill72-2633ce3d-b2d7-44ce-b0c1-fc3ba4fc18ec.json b/src/test/resources/thriftserverapi/datatypesintegrationtests/testgeospatialtypes/mappings/sql_protocolv1_o_6051921418418893_0819-204509-hill72-2633ce3d-b2d7-44ce-b0c1-fc3ba4fc18ec.json new file mode 100644 index 0000000000..0e610868a9 --- /dev/null +++ b/src/test/resources/thriftserverapi/datatypesintegrationtests/testgeospatialtypes/mappings/sql_protocolv1_o_6051921418418893_0819-204509-hill72-2633ce3d-b2d7-44ce-b0c1-fc3ba4fc18ec.json @@ -0,0 +1,34 @@ +{ + "id" : "2633ce3d-b2d7-44ce-b0c1-fc3ba4fc18ec", + "name" : "sql_protocolv1_o_6051921418418893_0819-204509-hill72", + "request" : { + "url" : "/sql/protocolv1/o/6051921418418893/0819-204509-hill72", + "method" : "POST", + "bodyPatterns" : [ { + "binaryEqualTo" : "gAEAAQAAAAxDbG9zZVNlc3Npb24AAAACDAABDAABDAABCwABAAAAEAnNQTevcEGqkAQucLP7Kb0LAAIAAAAQ4AypzuZjTMObzvkAoICHTgAAAAA=" + } ] + }, + "response" : { + "status" : 200, + "base64Body" : "gAEAAgAAAAxDbG9zZVNlc3Npb24AAAACDAAADAABCAABAAAAAAAAAA==", + "headers" : { + "x-request-id" : "e00003a5-f35d-4333-aa14-22a30eede082", + "date" : "Fri, 24 Oct 2025 09:13:25 GMT,Fri, 24 Oct 2025 09:13:25 GMT", + "server" : "databricks", + "x-databricks-popp-response-code-details" : "via_upstream", + "x-databricks-shard-debug" : "oregon-staging", + "x-frame-options" : "SAMEORIGIN", + "x-databricks-org-id" : "6051921418418893", + "strict-transport-security" : "max-age=31536000; includeSubDomains; preload", + "x-content-type-options" : "nosniff", + "x-xss-protection" : "1; mode=block", + "x-databricks-popp-routing-reason" : "deployment-name", + "content-type" : "application/x-thrift", + "server-timing" : "request_id;dur=0;desc=\"e00003a5-f35d-4333-aa14-22a30eede082\", client_protocol;dur=0;desc=\"HTTP/1.1\"", + "alt-svc" : "h3=\":5443\"; ma=86400, h3-29=\":5443\"; ma=86400", + "x-databricks-apiproxy-response-code-details" : "via_upstream" + } + }, + "uuid" : "2633ce3d-b2d7-44ce-b0c1-fc3ba4fc18ec", + "insertionIndex" : 1 +} \ No newline at end of file diff --git a/src/test/resources/thriftserverapi/datatypesintegrationtests/testgeospatialtypes/mappings/sql_protocolv1_o_6051921418418893_0819-204509-hill72-293a9649-9cf5-48ed-820e-e9177e852c1a.json b/src/test/resources/thriftserverapi/datatypesintegrationtests/testgeospatialtypes/mappings/sql_protocolv1_o_6051921418418893_0819-204509-hill72-293a9649-9cf5-48ed-820e-e9177e852c1a.json new file mode 100644 index 0000000000..ff712dbe7b --- /dev/null +++ b/src/test/resources/thriftserverapi/datatypesintegrationtests/testgeospatialtypes/mappings/sql_protocolv1_o_6051921418418893_0819-204509-hill72-293a9649-9cf5-48ed-820e-e9177e852c1a.json @@ -0,0 +1,36 @@ +{ + "id" : "293a9649-9cf5-48ed-820e-e9177e852c1a", + "name" : "sql_protocolv1_o_6051921418418893_0819-204509-hill72", + "request" : { + "url" : "/sql/protocolv1/o/6051921418418893/0819-204509-hill72", + "method" : "POST", + "bodyPatterns" : [ { + "binaryEqualTo" : "gAEAAQAAAAtPcGVuU2Vzc2lvbgAAAAEMAAEIAAH////5DQAECwsAAAAACgUCAAAAAAAApQkMBQQLAAEAAAAFU1BBUksLAAIAAAAHZGVmYXVsdAACBQUBAAA=" + } ] + }, + "response" : { + "status" : 200, + "base64Body" : "gAEAAgAAAAtPcGVuU2Vzc2lvbgAAAAEMAAAMAAEIAAEAAAAAAAgAAgAApQgMAAMMAAELAAEAAAAQCc1BN69wQaqQBC5ws/spvQsAAgAAABDgDKnO5mNMw5vO+QCggIdOBg0BAAAACA0BAAClCAANAAQLCwAAAAAMBQQLAAEAAAAFc3BhcmsLAAIAAAAHZGVmYXVsdAACBQUBAAA=", + "headers" : { + "x-request-id" : "c30cf2c5-0788-4f11-959d-0cbf52033345", + "date" : "Fri, 24 Oct 2025 09:13:23 GMT,Fri, 24 Oct 2025 09:13:23 GMT", + "server" : "databricks", + "x-databricks-popp-response-code-details" : "via_upstream", + "x-databricks-shard-debug" : "oregon-staging", + "x-frame-options" : "SAMEORIGIN", + "x-databricks-org-id" : "6051921418418893", + "strict-transport-security" : "max-age=31536000; includeSubDomains; preload", + "x-content-type-options" : "nosniff", + "x-xss-protection" : "1; mode=block", + "x-databricks-popp-routing-reason" : "deployment-name", + "content-type" : "application/x-thrift", + "server-timing" : "request_id;dur=0;desc=\"c30cf2c5-0788-4f11-959d-0cbf52033345\", client_protocol;dur=0;desc=\"HTTP/1.1\"", + "alt-svc" : "h3=\":5443\"; ma=86400, h3-29=\":5443\"; ma=86400", + "x-databricks-apiproxy-response-code-details" : "via_upstream" + } + }, + "uuid" : "293a9649-9cf5-48ed-820e-e9177e852c1a", + "scenarioName" : "scenario-1-sql-protocolv1-o-6051921418418893-0819-204509-hill72", + "requiredScenarioState" : "scenario-1-sql-protocolv1-o-6051921418418893-0819-204509-hill72-2", + "insertionIndex" : 3 +} \ No newline at end of file diff --git a/src/test/resources/thriftserverapi/datatypesintegrationtests/testgeospatialtypes/mappings/sql_protocolv1_o_6051921418418893_0819-204509-hill72-33b87d3b-3ae5-4f26-aefd-f74b47230318.json b/src/test/resources/thriftserverapi/datatypesintegrationtests/testgeospatialtypes/mappings/sql_protocolv1_o_6051921418418893_0819-204509-hill72-33b87d3b-3ae5-4f26-aefd-f74b47230318.json new file mode 100644 index 0000000000..0f5bcbc188 --- /dev/null +++ b/src/test/resources/thriftserverapi/datatypesintegrationtests/testgeospatialtypes/mappings/sql_protocolv1_o_6051921418418893_0819-204509-hill72-33b87d3b-3ae5-4f26-aefd-f74b47230318.json @@ -0,0 +1,34 @@ +{ + "id" : "33b87d3b-3ae5-4f26-aefd-f74b47230318", + "name" : "sql_protocolv1_o_6051921418418893_0819-204509-hill72", + "request" : { + "url" : "/sql/protocolv1/o/6051921418418893/0819-204509-hill72", + "method" : "POST", + "bodyPatterns" : [ { + "binaryEqualTo" : "gAEAAQAAAAxDbG9zZVNlc3Npb24AAAACDAABDAABDAABCwABAAAAEHT3AdS4M0fbvr9VNZLKF4QLAAIAAAAQuhmVKxnqTW+o2AcGqJWHnQAAAAA=" + } ] + }, + "response" : { + "status" : 200, + "base64Body" : "gAEAAgAAAAxDbG9zZVNlc3Npb24AAAACDAAADAABCAABAAAAAAAAAA==", + "headers" : { + "x-request-id" : "7c4d98c5-9310-444a-8d60-71b75871ebbc", + "date" : "Fri, 24 Oct 2025 09:13:24 GMT,Fri, 24 Oct 2025 09:13:24 GMT", + "server" : "databricks", + "x-databricks-popp-response-code-details" : "via_upstream", + "x-databricks-shard-debug" : "oregon-staging", + "x-frame-options" : "SAMEORIGIN", + "x-databricks-org-id" : "6051921418418893", + "strict-transport-security" : "max-age=31536000; includeSubDomains; preload", + "x-content-type-options" : "nosniff", + "x-xss-protection" : "1; mode=block", + "x-databricks-popp-routing-reason" : "deployment-name", + "content-type" : "application/x-thrift", + "server-timing" : "request_id;dur=0;desc=\"7c4d98c5-9310-444a-8d60-71b75871ebbc\", client_protocol;dur=0;desc=\"HTTP/1.1\"", + "alt-svc" : "h3=\":5443\"; ma=86400, h3-29=\":5443\"; ma=86400", + "x-databricks-apiproxy-response-code-details" : "via_upstream" + } + }, + "uuid" : "33b87d3b-3ae5-4f26-aefd-f74b47230318", + "insertionIndex" : 2 +} \ No newline at end of file diff --git a/src/test/resources/thriftserverapi/datatypesintegrationtests/testgeospatialtypes/mappings/sql_protocolv1_o_6051921418418893_0819-204509-hill72-535e7132-d129-4dae-9556-fb04bf7e09ac.json b/src/test/resources/thriftserverapi/datatypesintegrationtests/testgeospatialtypes/mappings/sql_protocolv1_o_6051921418418893_0819-204509-hill72-535e7132-d129-4dae-9556-fb04bf7e09ac.json new file mode 100644 index 0000000000..4b452253d5 --- /dev/null +++ b/src/test/resources/thriftserverapi/datatypesintegrationtests/testgeospatialtypes/mappings/sql_protocolv1_o_6051921418418893_0819-204509-hill72-535e7132-d129-4dae-9556-fb04bf7e09ac.json @@ -0,0 +1,37 @@ +{ + "id" : "535e7132-d129-4dae-9556-fb04bf7e09ac", + "name" : "sql_protocolv1_o_6051921418418893_0819-204509-hill72", + "request" : { + "url" : "/sql/protocolv1/o/6051921418418893/0819-204509-hill72", + "method" : "POST", + "bodyPatterns" : [ { + "binaryEqualTo" : "gAEAAQAAAAtPcGVuU2Vzc2lvbgAAAAEMAAEIAAH////5DQAECwsAAAAACgUCAAAAAAAApQkMBQQLAAEAAAAFU1BBUksLAAIAAAAHZGVmYXVsdAACBQUBAAA=" + } ] + }, + "response" : { + "status" : 200, + "base64Body" : "gAEAAgAAAAtPcGVuU2Vzc2lvbgAAAAEMAAAMAAEIAAEAAAAAAAgAAgAApQgMAAMMAAELAAEAAAAQdPcB1LgzR9u+v1U1ksoXhAsAAgAAABC6GZUrGepNb6jYBwaolYedBg0BAAAACA0BAAClCAANAAQLCwAAAAAMBQQLAAEAAAAFc3BhcmsLAAIAAAAHZGVmYXVsdAACBQUBAAA=", + "headers" : { + "x-request-id" : "434b02f0-1e52-4dbd-afc4-8abc17cdd547", + "date" : "Fri, 24 Oct 2025 09:13:21 GMT,Fri, 24 Oct 2025 09:13:21 GMT", + "server" : "databricks", + "x-databricks-popp-response-code-details" : "via_upstream", + "x-databricks-shard-debug" : "oregon-staging", + "x-frame-options" : "SAMEORIGIN", + "x-databricks-org-id" : "6051921418418893", + "strict-transport-security" : "max-age=31536000; includeSubDomains; preload", + "x-content-type-options" : "nosniff", + "x-xss-protection" : "1; mode=block", + "x-databricks-popp-routing-reason" : "deployment-name", + "content-type" : "application/x-thrift", + "server-timing" : "request_id;dur=0;desc=\"434b02f0-1e52-4dbd-afc4-8abc17cdd547\", client_protocol;dur=0;desc=\"HTTP/1.1\"", + "alt-svc" : "h3=\":5443\"; ma=86400, h3-29=\":5443\"; ma=86400", + "x-databricks-apiproxy-response-code-details" : "via_upstream" + } + }, + "uuid" : "535e7132-d129-4dae-9556-fb04bf7e09ac", + "scenarioName" : "scenario-1-sql-protocolv1-o-6051921418418893-0819-204509-hill72", + "requiredScenarioState" : "Started", + "newScenarioState" : "scenario-1-sql-protocolv1-o-6051921418418893-0819-204509-hill72-2", + "insertionIndex" : 5 +} \ No newline at end of file