diff --git a/README.md b/README.md index deff072..fc65382 100644 --- a/README.md +++ b/README.md @@ -29,70 +29,69 @@ This extension implements the entire [H3 API](https://h3geo.org/docs/api/indexin All functions support H3 indexes specified as `UBIGINT` (`uint64`) or `BIGINT` (`int64`), but the unsigned one is preferred and is returned when the extension can't detect which -one to use. The unsigned and signed APIs are identical. Many functions also support -`VARCHAR` H3 index input and output. +one to use. The unsigned and signed APIs are identical. Most functions also support +`VARCHAR` H3 index input and output, except as noted below. ### Full list of functions | Function | Notes | Description | --: | --- | --- | `h3_latlng_to_cell` | [u](#fu) | Convert latitude/longitude coordinate to cell ID -| `h3_cell_to_lat` | [v](#fv) | Convert cell ID to latitude -| `h3_cell_to_lng` | [v](#fv) | Convert cell ID to longitude -| `h3_cell_to_latlng` | [v](#fv) | Convert cell ID to latitude/longitude -| `h3_cell_to_boundary_wkt` | [v](#fv) | Convert cell ID to cell boundary -| `h3_get_resolution` | [v](#fv) | Get resolution number of cell ID -| `h3_get_base_cell_number` | [v](#fv) | Get base cell number of cell ID +| `h3_cell_to_lat` | | Convert cell ID to latitude +| `h3_cell_to_lng` | | Convert cell ID to longitude +| `h3_cell_to_latlng` | | Convert cell ID to latitude/longitude +| `h3_cell_to_boundary_wkt` | | Convert cell ID to cell boundary +| `h3_get_resolution` | | Get resolution number of cell ID +| `h3_get_base_cell_number` | | Get base cell number of cell ID | `h3_string_to_h3` | [u](#fu) | Convert VARCHAR cell ID to UBIGINT -| `h3_h3_to_string` | [i](#fi) | Convert BIGINT or UBIGINT cell ID to VARCHAR -| `h3_is_valid_cell` | [v](#fv) | True if this is a valid cell ID -| `h3_is_res_class_iii` | [v](#fv) | True if the cell's resolution is class III -| `h3_is_pentagon` | [v](#fv) | True if the cell is a pentagon -| `h3_get_icosahedron_faces` | [v](#fv) | List of icosahedron face IDs the cell is on -| `h3_cell_to_parent` | [v](#fv) | Get coarser cell for a cell -| `h3_cell_to_children` | [v](#fv) | Get finer cells for a cell -| `h3_cell_to_center_child` | [v](#fv) | Get the center finer cell for a cell -| `h3_cell_to_child_pos` | [v](#fv) | Get a sub-indexing number for a cell inside a parent -| `h3_child_pos_to_cell` | [v](#fv) | Convert parent and sub-indexing number to a cell ID +| `h3_h3_to_string` | | Convert BIGINT or UBIGINT cell ID to VARCHAR +| `h3_is_valid_cell` | | True if this is a valid cell ID +| `h3_is_res_class_iii` | | True if the cell's resolution is class III +| `h3_is_pentagon` | | True if the cell is a pentagon +| `h3_get_icosahedron_faces` | | List of icosahedron face IDs the cell is on +| `h3_cell_to_parent` | | Get coarser cell for a cell +| `h3_cell_to_children` | | Get finer cells for a cell +| `h3_cell_to_center_child` | | Get the center finer cell for a cell +| `h3_cell_to_child_pos` | | Get a sub-indexing number for a cell inside a parent +| `h3_child_pos_to_cell` | | Convert parent and sub-indexing number to a cell ID | `h3_compact_cells` | [i](#fi) | Convert a set of single-resolution cells to the minimal mixed-resolution set | `h3_uncompact_cells` | [i](#fi) | Convert a mixed-resolution set to a single-resolution set of cells -| `h3_grid_disk` | [i](#fi) | Find cells within a grid distance -| `h3_grid_disk_distances` | [i](#fi) | Find cells within a grid distance, sorted by distance -| `h3_grid_disk_unsafe` | [i](#fi) | Find cells within a grid distance, with no pentagon distortion -| `h3_grid_disk_distances_unsafe` | [i](#fi) | Find cells within a grid distance, sorted by distance, with no pentagon distortion -| `h3_grid_ring_unsafe` | [i](#fi) | Find cells exactly a grid distance away, with no pentagon distortion -| `h3_grid_path_cells` | [i](#fi) | Find a grid path to connect two cells -| `h3_grid_distance` | [i](#fi) | Find the grid distance between two cells -| `h3_cell_to_local_ij` | [i](#fi) | Convert a cell ID to a local I,J coordinate space -| `h3_local_ij_to_cell` | [i](#fi) | Convert a local I,J coordinate to a cell ID -| `h3_cell_to_vertex` | [i](#fi) | Get the vertex ID for a cell ID and vertex number -| `h3_cell_to_vertexes` | [i](#fi) | Get all vertex IDs for a cell ID -| `h3_vertex_to_lat` | [i](#fi) | Convert a vertex ID to latitude -| `h3_vertex_to_lng` | [i](#fi) | Convert a vertex ID to longitude -| `h3_vertex_to_latlng` | [i](#fi) | Convert a vertex ID to latitude/longitude coordinate -| `h3_is_valid_vertex` | [v](#fv) | True if passed a valid vertex ID -| `h3_is_valid_directed_edge` | [v](#fv) | True if passed a valid directed edge ID -| `h3_origin_to_directed_edges` | [i](#fi) | Get all directed edge IDs for a cell ID -| `h3_directed_edge_to_cells` | [i](#fi) | Convert a directed edge ID to origin/destination cell IDs -| `h3_get_directed_edge_origin` | [i](#fi) | Convert a directed edge ID to origin cell ID -| `h3_get_directed_edge_destination` | [i](#fi) | Convert a directed edge ID to destination cell ID -| `h3_cells_to_directed_edge` | [i](#fi) | Convert an origin/destination pair to directed edge ID -| `h3_are_neighbor_cells` | [i](#fi) | True if the two cell IDs are directly adjacent -| `h3_directed_edge_to_boundary_wkt` | [v](#fv) | Convert directed edge ID to linestring WKT +| `h3_grid_disk` | | Find cells within a grid distance +| `h3_grid_disk_distances` | | Find cells within a grid distance, sorted by distance +| `h3_grid_disk_unsafe` | | Find cells within a grid distance, with no pentagon distortion +| `h3_grid_disk_distances_unsafe` | | Find cells within a grid distance, sorted by distance, with no pentagon distortion +| `h3_grid_ring_unsafe` | | Find cells exactly a grid distance away, with no pentagon distortion +| `h3_grid_path_cells` | | Find a grid path to connect two cells +| `h3_grid_distance` | | Find the grid distance between two cells +| `h3_cell_to_local_ij` | | Convert a cell ID to a local I,J coordinate space +| `h3_local_ij_to_cell` | | Convert a local I,J coordinate to a cell ID +| `h3_cell_to_vertex` | | Get the vertex ID for a cell ID and vertex number +| `h3_cell_to_vertexes` | | Get all vertex IDs for a cell ID +| `h3_vertex_to_lat` | | Convert a vertex ID to latitude +| `h3_vertex_to_lng` | | Convert a vertex ID to longitude +| `h3_vertex_to_latlng` | | Convert a vertex ID to latitude/longitude coordinate +| `h3_is_valid_vertex` | | True if passed a valid vertex ID +| `h3_is_valid_directed_edge` | | True if passed a valid directed edge ID +| `h3_origin_to_directed_edges` | | Get all directed edge IDs for a cell ID +| `h3_directed_edge_to_cells` | | Convert a directed edge ID to origin/destination cell IDs +| `h3_get_directed_edge_origin` | | Convert a directed edge ID to origin cell ID +| `h3_get_directed_edge_destination` | | Convert a directed edge ID to destination cell ID +| `h3_cells_to_directed_edge` | | Convert an origin/destination pair to directed edge ID +| `h3_are_neighbor_cells` | | True if the two cell IDs are directly adjacent +| `h3_directed_edge_to_boundary_wkt` | | Convert directed edge ID to linestring WKT | `h3_get_hexagon_area_avg` | | Get average area of a hexagon cell at resolution -| `h3_cell_area` | [v](#fv) | Get the area of a cell ID -| `h3_edge_length` | [v](#fv) | Get the length of a directed edge ID +| `h3_cell_area` | | Get the area of a cell ID +| `h3_edge_length` | | Get the length of a directed edge ID | `h3_get_num_cells` | | Get the number of cells at a resolution | `h3_get_res0_cells` | [u](#fu) | Get all resolution 0 cells | `h3_get_pentagons` | [u](#fu) | Get all pentagons at a resolution | `h3_great_circle_distance` | | Compute the great circle distance between two points (haversine) -| `h3_cells_to_multi_polygon_wkt` | [v](#fv) | Convert a set of cells to multipolygon WKT +| `h3_cells_to_multi_polygon_wkt` | | Convert a set of cells to multipolygon WKT | `h3_polygon_wkt_to_cells` | [u](#fu) | Convert polygon WKT to a set of cells ### Notes -* v: Supports VARCHAR, UBIGINT, and BIGINT input and output. -* i: Supports UBIGINT and BIGINT input and output. (TODO for these to support VARCHAR too.) +* i: Supports UBIGINT and BIGINT input and output only, not VARCHAR. (TODO) * u: Supports UBIGINT output only. # Alternative download / install diff --git a/src/h3_directededge.cpp b/src/h3_directededge.cpp index f1bdad4..b7ab39d 100644 --- a/src/h3_directededge.cpp +++ b/src/h3_directededge.cpp @@ -26,6 +26,41 @@ static void DirectedEdgeToCellsFunction(DataChunk &args, ExpressionState &state, result.Verify(args.size()); } +static void DirectedEdgeToCellsVarcharFunction(DataChunk &args, + ExpressionState &state, + Vector &result) { + auto result_data = FlatVector::GetData(result); + for (idx_t i = 0; i < args.size(); i++) { + result_data[i].offset = ListVector::GetListSize(result); + + string edgeInput = args.GetValue(0, i) + .DefaultCastAs(LogicalType::VARCHAR) + .GetValue(); + + H3Index edge; + H3Error err0 = stringToH3(edgeInput.c_str(), &edge); + if (err0) { + result.SetValue(i, Value(LogicalType::SQLNULL)); + } else { + std::vector out(2); + H3Error err1 = directedEdgeToCells(edge, out.data()); + if (err1) { + result.SetValue(i, Value(LogicalType::SQLNULL)); + } else { + auto str0 = StringUtil::Format("%llx", out[0]); + string_t strAsStr0 = string_t(strdup(str0.c_str()), str0.size()); + ListVector::PushBack(result, strAsStr0); + auto str1 = StringUtil::Format("%llx", out[1]); + string_t strAsStr1 = string_t(strdup(str1.c_str()), str1.size()); + ListVector::PushBack(result, strAsStr1); + + result_data[i].length = 2; + } + } + } + result.Verify(args.size()); +} + static void OriginToDirectedEdgesFunction(DataChunk &args, ExpressionState &state, Vector &result) { @@ -57,6 +92,46 @@ static void OriginToDirectedEdgesFunction(DataChunk &args, result.Verify(args.size()); } +static void OriginToDirectedEdgesVarcharFunction(DataChunk &args, + ExpressionState &state, + Vector &result) { + D_ASSERT(result.GetType().id() == LogicalTypeId::LIST); + + auto result_data = FlatVector::GetData(result); + for (idx_t i = 0; i < args.size(); i++) { + result_data[i].offset = ListVector::GetListSize(result); + + string originStr = args.GetValue(0, i) + .DefaultCastAs(LogicalType::VARCHAR) + .GetValue(); + + H3Index origin; + H3Error err0 = stringToH3(originStr.c_str(), &origin); + if (err0) { + result.SetValue(i, Value(LogicalType::SQLNULL)); + } else { + int64_t actual = 0; + std::vector out(6); + H3Error err1 = originToDirectedEdges(origin, out.data()); + if (err1) { + result.SetValue(i, Value(LogicalType::SQLNULL)); + } else { + for (auto val : out) { + if (val != H3_NULL) { + auto str = StringUtil::Format("%llx", val); + string_t strAsStr = string_t(strdup(str.c_str()), str.size()); + ListVector::PushBack(result, strAsStr); + actual++; + } + } + + result_data[i].length = actual; + } + } + } + result.Verify(args.size()); +} + static void GetDirectedEdgeOriginFunction(DataChunk &args, ExpressionState &state, Vector &result) { @@ -75,6 +150,33 @@ static void GetDirectedEdgeOriginFunction(DataChunk &args, }); } +static void GetDirectedEdgeOriginVarcharFunction(DataChunk &args, + ExpressionState &state, + Vector &result) { + auto &inputs = args.data[0]; + UnaryExecutor::ExecuteWithNulls( + inputs, result, args.size(), + [&](string_t inputStr, ValidityMask &mask, idx_t idx) { + H3Index input; + H3Error err0 = stringToH3(inputStr.GetString().c_str(), &input); + if (err0) { + mask.SetInvalid(idx); + return StringVector::EmptyString(result, 0); + } else { + H3Index out; + H3Error err1 = getDirectedEdgeOrigin(input, &out); + if (err1) { + mask.SetInvalid(idx); + return StringVector::EmptyString(result, 0); + } else { + auto str = StringUtil::Format("%llx", out); + string_t strAsStr = string_t(strdup(str.c_str()), str.size()); + return StringVector::AddString(result, strAsStr); + } + } + }); +} + static void GetDirectedEdgeDestinationFunction(DataChunk &args, ExpressionState &state, Vector &result) { @@ -93,6 +195,33 @@ static void GetDirectedEdgeDestinationFunction(DataChunk &args, }); } +static void GetDirectedEdgeDestinationVarcharFunction(DataChunk &args, + ExpressionState &state, + Vector &result) { + auto &inputs = args.data[0]; + UnaryExecutor::ExecuteWithNulls( + inputs, result, args.size(), + [&](string_t inputStr, ValidityMask &mask, idx_t idx) { + H3Index input; + H3Error err0 = stringToH3(inputStr.GetString().c_str(), &input); + if (err0) { + mask.SetInvalid(idx); + return StringVector::EmptyString(result, 0); + } else { + H3Index out; + H3Error err1 = getDirectedEdgeDestination(input, &out); + if (err1) { + mask.SetInvalid(idx); + return StringVector::EmptyString(result, 0); + } else { + auto str = StringUtil::Format("%llx", out); + string_t strAsStr = string_t(strdup(str.c_str()), str.size()); + return StringVector::AddString(result, strAsStr); + } + } + }); +} + static void CellsToDirectedEdgeFunction(DataChunk &args, ExpressionState &state, Vector &result) { auto &inputs = args.data[0]; @@ -111,6 +240,36 @@ static void CellsToDirectedEdgeFunction(DataChunk &args, ExpressionState &state, }); } +static void CellsToDirectedEdgeVarcharFunction(DataChunk &args, + ExpressionState &state, + Vector &result) { + auto &inputs = args.data[0]; + auto &inputs2 = args.data[1]; + BinaryExecutor::ExecuteWithNulls( + inputs, inputs2, result, args.size(), + [&](string_t inputStr, string_t inputStr2, ValidityMask &mask, + idx_t idx) { + H3Index input, input2; + H3Error err0 = stringToH3(inputStr.GetString().c_str(), &input); + H3Error err1 = stringToH3(inputStr2.GetString().c_str(), &input2); + if (err0 || err1) { + mask.SetInvalid(idx); + return StringVector::EmptyString(result, 0); + } else { + H3Index out; + H3Error err = cellsToDirectedEdge(input, input2, &out); + if (err) { + mask.SetInvalid(idx); + return StringVector::EmptyString(result, 0); + } else { + auto str = StringUtil::Format("%llx", out); + string_t strAsStr = string_t(strdup(str.c_str()), str.size()); + return StringVector::AddString(result, strAsStr); + } + } + }); +} + static void AreNeighborCellsFunction(DataChunk &args, ExpressionState &state, Vector &result) { auto &inputs = args.data[0]; @@ -129,6 +288,34 @@ static void AreNeighborCellsFunction(DataChunk &args, ExpressionState &state, }); } +static void AreNeighborCellsVarcharFunction(DataChunk &args, + ExpressionState &state, + Vector &result) { + auto &inputs = args.data[0]; + auto &inputs2 = args.data[1]; + BinaryExecutor::ExecuteWithNulls( + inputs, inputs2, result, args.size(), + [&](string_t inputStr, string_t inputStr2, ValidityMask &mask, + idx_t idx) { + H3Index input, input2; + H3Error err0 = stringToH3(inputStr.GetString().c_str(), &input); + H3Error err1 = stringToH3(inputStr2.GetString().c_str(), &input2); + if (err0 || err1) { + mask.SetInvalid(idx); + return bool(false); + } else { + int out; + H3Error err2 = areNeighborCells(input, input2, &out); + if (err2) { + mask.SetInvalid(idx); + return bool(false); + } else { + return bool(out); + } + } + }); +} + static void IsValidDirectedEdgeVarcharFunction(DataChunk &args, ExpressionState &state, Vector &result) { @@ -210,69 +397,79 @@ static void DirectedEdgeToBoundaryWktVarcharFunction(DataChunk &args, CreateScalarFunctionInfo H3Functions::GetDirectedEdgeToCellsFunction() { ScalarFunctionSet funcs("h3_directed_edge_to_cells"); - // TODO: VARCHAR variant of this function funcs.AddFunction(ScalarFunction({LogicalType::UBIGINT}, LogicalType::LIST(LogicalType::UBIGINT), DirectedEdgeToCellsFunction)); funcs.AddFunction(ScalarFunction({LogicalType::BIGINT}, LogicalType::LIST(LogicalType::UBIGINT), DirectedEdgeToCellsFunction)); + funcs.AddFunction(ScalarFunction({LogicalType::VARCHAR}, + LogicalType::LIST(LogicalType::VARCHAR), + DirectedEdgeToCellsVarcharFunction)); return CreateScalarFunctionInfo(funcs); } CreateScalarFunctionInfo H3Functions::GetOriginToDirectedEdgesFunction() { ScalarFunctionSet funcs("h3_origin_to_directed_edges"); - // TODO: VARCHAR variant of this function funcs.AddFunction(ScalarFunction({LogicalType::UBIGINT}, LogicalType::LIST(LogicalType::UBIGINT), OriginToDirectedEdgesFunction)); funcs.AddFunction(ScalarFunction({LogicalType::BIGINT}, LogicalType::LIST(LogicalType::UBIGINT), OriginToDirectedEdgesFunction)); + funcs.AddFunction(ScalarFunction({LogicalType::VARCHAR}, + LogicalType::LIST(LogicalType::VARCHAR), + OriginToDirectedEdgesVarcharFunction)); return CreateScalarFunctionInfo(funcs); } CreateScalarFunctionInfo H3Functions::GetGetDirectedEdgeOriginFunction() { ScalarFunctionSet funcs("h3_get_directed_edge_origin"); - // TODO: VARCHAR variant of this function funcs.AddFunction(ScalarFunction({LogicalType::UBIGINT}, LogicalType::UBIGINT, GetDirectedEdgeOriginFunction)); funcs.AddFunction(ScalarFunction({LogicalType::BIGINT}, LogicalType::BIGINT, GetDirectedEdgeOriginFunction)); + funcs.AddFunction(ScalarFunction({LogicalType::VARCHAR}, LogicalType::VARCHAR, + GetDirectedEdgeOriginVarcharFunction)); return CreateScalarFunctionInfo(funcs); } CreateScalarFunctionInfo H3Functions::GetGetDirectedEdgeDestinationFunction() { ScalarFunctionSet funcs("h3_get_directed_edge_destination"); - // TODO: VARCHAR variant of this function funcs.AddFunction(ScalarFunction({LogicalType::UBIGINT}, LogicalType::UBIGINT, GetDirectedEdgeDestinationFunction)); funcs.AddFunction(ScalarFunction({LogicalType::BIGINT}, LogicalType::BIGINT, GetDirectedEdgeDestinationFunction)); + funcs.AddFunction(ScalarFunction({LogicalType::VARCHAR}, LogicalType::VARCHAR, + GetDirectedEdgeDestinationVarcharFunction)); return CreateScalarFunctionInfo(funcs); } CreateScalarFunctionInfo H3Functions::GetCellsToDirectedEdgeFunction() { ScalarFunctionSet funcs("h3_cells_to_directed_edge"); - // TODO: VARCHAR variant of this function funcs.AddFunction(ScalarFunction({LogicalType::UBIGINT, LogicalType::UBIGINT}, LogicalType::UBIGINT, CellsToDirectedEdgeFunction)); funcs.AddFunction(ScalarFunction({LogicalType::BIGINT, LogicalType::BIGINT}, LogicalType::BIGINT, CellsToDirectedEdgeFunction)); + funcs.AddFunction(ScalarFunction({LogicalType::VARCHAR, LogicalType::VARCHAR}, + LogicalType::VARCHAR, + CellsToDirectedEdgeVarcharFunction)); return CreateScalarFunctionInfo(funcs); } CreateScalarFunctionInfo H3Functions::GetAreNeighborCellsFunction() { ScalarFunctionSet funcs("h3_are_neighbor_cells"); - // TODO: VARCHAR variant of this function funcs.AddFunction(ScalarFunction({LogicalType::UBIGINT, LogicalType::UBIGINT}, LogicalType::BOOLEAN, AreNeighborCellsFunction)); funcs.AddFunction(ScalarFunction({LogicalType::BIGINT, LogicalType::BIGINT}, LogicalType::BOOLEAN, AreNeighborCellsFunction)); + funcs.AddFunction(ScalarFunction({LogicalType::VARCHAR, LogicalType::VARCHAR}, + LogicalType::BOOLEAN, + AreNeighborCellsVarcharFunction)); return CreateScalarFunctionInfo(funcs); } diff --git a/src/h3_traversal.cpp b/src/h3_traversal.cpp index 22c88dd..43bfec3 100644 --- a/src/h3_traversal.cpp +++ b/src/h3_traversal.cpp @@ -53,6 +53,53 @@ static void GridDiskTmplFunction(DataChunk &args, ExpressionState &state, result.Verify(args.size()); } +template +static void GridDiskTmplVarcharFunction(DataChunk &args, ExpressionState &state, + Vector &result) { + auto result_data = FlatVector::GetData(result); + for (idx_t i = 0; i < args.size(); i++) { + result_data[i].offset = ListVector::GetListSize(result); + + string originInput = args.GetValue(0, i) + .DefaultCastAs(LogicalType::VARCHAR) + .GetValue(); + int32_t k = args.GetValue(1, i) + .DefaultCastAs(LogicalType::INTEGER) + .GetValue(); + + uint64_t origin; + H3Error err0 = stringToH3(originInput.c_str(), &origin); + if (err0) { + result.SetValue(i, Value(LogicalType::SQLNULL)); + } else { + int64_t sz; + H3Error err1 = maxGridDiskSize(k, &sz); + if (err1) { + result.SetValue(i, Value(LogicalType::SQLNULL)); + } else { + std::vector out(sz); + H3Error err2 = Fn::fn(origin, k, out.data()); + if (err2) { + result.SetValue(i, Value(LogicalType::SQLNULL)); + } else { + int64_t actual = 0; + for (auto val : out) { + if (val != H3_NULL) { + auto str = StringUtil::Format("%llx", val); + string_t strAsStr = string_t(strdup(str.c_str()), str.size()); + ListVector::PushBack(result, strAsStr); + actual++; + } + } + + result_data[i].length = actual; + } + } + } + } + result.Verify(args.size()); +} + struct GridDiskDistancesOperator { static H3Error fn(H3Index origin, int32_t k, H3Index *out, int32_t *distancesOut) { @@ -121,6 +168,63 @@ static void GridDiskDistancesTmplFunction(DataChunk &args, result.Verify(args.size()); } +template +static void GridDiskDistancesTmplVarcharFunction(DataChunk &args, + ExpressionState &state, + Vector &result) { + auto result_data = FlatVector::GetData(result); + for (idx_t i = 0; i < args.size(); i++) { + result_data[i].offset = ListVector::GetListSize(result); + + string originInput = args.GetValue(0, i) + .DefaultCastAs(LogicalType::VARCHAR) + .GetValue(); + int32_t k = args.GetValue(1, i) + .DefaultCastAs(LogicalType::INTEGER) + .GetValue(); + + H3Index origin; + H3Error err0 = stringToH3(originInput.c_str(), &origin); + if (err0) { + result.SetValue(i, Value(LogicalType::SQLNULL)); + } else { + int64_t sz; + H3Error err1 = maxGridDiskSize(k, &sz); + if (err1) { + result.SetValue(i, Value(LogicalType::SQLNULL)); + } else { + std::vector out(sz); + std::vector distancesOut(sz); + H3Error err2 = Fn::fn(origin, k, out.data(), distancesOut.data()); + if (err2) { + result.SetValue(i, Value(LogicalType::SQLNULL)); + } else { + // Reorganize the results similar to H3-Java sorted list of list of + // indexes std vector of duckdb vector + std::vector> results(k + 1); + for (idx_t j = 0; j < out.size(); j++) { + if (out[j] != H3_NULL) { + auto str = StringUtil::Format("%llx", out[j]); + string_t strAsStr = string_t(strdup(str.c_str()), str.size()); + results[distancesOut[j]].push_back(strAsStr); + } + } + + int64_t actual = 0; + for (auto val : results) { + ListVector::PushBack(result, + Value::LIST(LogicalType::VARCHAR, val)); + actual++; + } + + result_data[i].length = actual; + } + } + } + } + result.Verify(args.size()); +} + static void GridRingUnsafeFunction(DataChunk &args, ExpressionState &state, Vector &result) { auto result_data = FlatVector::GetData(result); @@ -153,6 +257,47 @@ static void GridRingUnsafeFunction(DataChunk &args, ExpressionState &state, result.Verify(args.size()); } +static void GridRingUnsafeVarcharFunction(DataChunk &args, + ExpressionState &state, + Vector &result) { + auto result_data = FlatVector::GetData(result); + for (idx_t i = 0; i < args.size(); i++) { + result_data[i].offset = ListVector::GetListSize(result); + + string originInput = args.GetValue(0, i) + .DefaultCastAs(LogicalType::VARCHAR) + .GetValue(); + int32_t k = args.GetValue(1, i) + .DefaultCastAs(LogicalType::INTEGER) + .GetValue(); + H3Index origin; + H3Error err0 = stringToH3(originInput.c_str(), &origin); + if (err0) { + result.SetValue(i, Value(LogicalType::SQLNULL)); + } else { + int64_t sz = k == 0 ? 1 : 6 * k; + std::vector out(sz); + H3Error err1 = gridRingUnsafe(origin, k, out.data()); + if (err1) { + result.SetValue(i, Value(LogicalType::SQLNULL)); + } else { + int64_t actual = 0; + for (auto val : out) { + if (val != H3_NULL) { + auto str = StringUtil::Format("%llx", val); + string_t strAsStr = string_t(strdup(str.c_str()), str.size()); + ListVector::PushBack(result, strAsStr); + actual++; + } + } + + result_data[i].length = actual; + } + } + } + result.Verify(args.size()); +} + static void GridPathCellsFunction(DataChunk &args, ExpressionState &state, Vector &result) { auto result_data = FlatVector::GetData(result); @@ -191,6 +336,54 @@ static void GridPathCellsFunction(DataChunk &args, ExpressionState &state, result.Verify(args.size()); } +static void GridPathCellsVarcharFunction(DataChunk &args, + ExpressionState &state, + Vector &result) { + auto result_data = FlatVector::GetData(result); + for (idx_t i = 0; i < args.size(); i++) { + result_data[i].offset = ListVector::GetListSize(result); + + string originInput = args.GetValue(0, i) + .DefaultCastAs(LogicalType::VARCHAR) + .GetValue(); + string destinationInput = args.GetValue(1, i) + .DefaultCastAs(LogicalType::VARCHAR) + .GetValue(); + + H3Index origin, destination; + H3Error err0 = stringToH3(originInput.c_str(), &origin); + H3Error err1 = stringToH3(destinationInput.c_str(), &destination); + if (err0 || err1) { + result.SetValue(i, Value(LogicalType::SQLNULL)); + } else { + int64_t sz; + H3Error err2 = gridPathCellsSize(origin, destination, &sz); + if (err2) { + result.SetValue(i, Value(LogicalType::SQLNULL)); + } else { + std::vector out(sz); + H3Error err3 = gridPathCells(origin, destination, out.data()); + if (err3) { + result.SetValue(i, Value(LogicalType::SQLNULL)); + } else { + int64_t actual = 0; + for (auto val : out) { + if (val != H3_NULL) { + auto str = StringUtil::Format("%llx", val); + string_t strAsStr = string_t(strdup(str.c_str()), str.size()); + ListVector::PushBack(result, strAsStr); + actual++; + } + } + + result_data[i].length = actual; + } + } + } + } + result.Verify(args.size()); +} + static void GridDistanceFunction(DataChunk &args, ExpressionState &state, Vector &result) { auto &inputs = args.data[0]; @@ -210,6 +403,34 @@ static void GridDistanceFunction(DataChunk &args, ExpressionState &state, }); } +static void GridDistanceVarcharFunction(DataChunk &args, ExpressionState &state, + Vector &result) { + auto &inputs = args.data[0]; + auto &inputs2 = args.data[1]; + BinaryExecutor::ExecuteWithNulls( + inputs, inputs2, result, args.size(), + [&](string_t originInput, string_t destinationInput, ValidityMask &mask, + idx_t idx) { + H3Index origin, destination; + H3Error err0 = stringToH3(originInput.GetString().c_str(), &origin); + H3Error err1 = + stringToH3(destinationInput.GetString().c_str(), &destination); + if (err0 || err1) { + mask.SetInvalid(idx); + return int64_t(0); + } else { + int64_t distance; + H3Error err = gridDistance(origin, destination, &distance); + if (err) { + mask.SetInvalid(idx); + return int64_t(0); + } else { + return distance; + } + } + }); +} + static void CellToLocalIjFunction(DataChunk &args, ExpressionState &state, Vector &result) { auto result_data = FlatVector::GetData(result); @@ -237,6 +458,41 @@ static void CellToLocalIjFunction(DataChunk &args, ExpressionState &state, result.Verify(args.size()); } +static void CellToLocalIjVarcharFunction(DataChunk &args, + ExpressionState &state, + Vector &result) { + auto result_data = FlatVector::GetData(result); + for (idx_t i = 0; i < args.size(); i++) { + result_data[i].offset = ListVector::GetListSize(result); + + string originInput = args.GetValue(0, i) + .DefaultCastAs(LogicalType::VARCHAR) + .GetValue(); + string cellInput = args.GetValue(1, i) + .DefaultCastAs(LogicalType::VARCHAR) + .GetValue(); + uint32_t mode = 0; // TODO: Expose mode to the user when applicable + + H3Index origin, cell; + H3Error err0 = stringToH3(originInput.c_str(), &origin); + H3Error err1 = stringToH3(cellInput.c_str(), &cell); + if (err0 || err1) { + result.SetValue(i, Value(LogicalType::SQLNULL)); + } else { + CoordIJ out; + H3Error err2 = cellToLocalIj(origin, cell, mode, &out); + if (err2) { + result.SetValue(i, Value(LogicalType::SQLNULL)); + } else { + ListVector::PushBack(result, Value::INTEGER(out.i)); + ListVector::PushBack(result, Value::INTEGER(out.j)); + result_data[i].length = 2; + } + } + } + result.Verify(args.size()); +} + static void LocalIjToCellFunction(DataChunk &args, ExpressionState &state, Vector &result) { auto &inputs = args.data[0]; @@ -259,21 +515,55 @@ static void LocalIjToCellFunction(DataChunk &args, ExpressionState &state, }); } +static void LocalIjToCellVarcharFunction(DataChunk &args, + ExpressionState &state, + Vector &result) { + auto &inputs = args.data[0]; + auto &inputs2 = args.data[1]; + auto &inputs3 = args.data[2]; + TernaryExecutor::ExecuteWithNulls( + inputs, inputs2, inputs3, result, args.size(), + [&](string_t input, int32_t i, int32_t j, ValidityMask &mask, idx_t idx) { + H3Index origin; + H3Error err0 = stringToH3(input.GetString().c_str(), &origin); + if (err0) { + mask.SetInvalid(idx); + return StringVector::EmptyString(result, 0); + } else { + uint32_t mode = 0; // TODO: Expose mode to the user when applicable + + CoordIJ coordIJ{.i = i, .j = j}; + H3Index out; + H3Error err1 = localIjToCell(origin, &coordIJ, mode, &out); + if (err1) { + mask.SetInvalid(idx); + return StringVector::EmptyString(result, 0); + } else { + auto str = StringUtil::Format("%llx", out); + string_t strAsStr = string_t(strdup(str.c_str()), str.size()); + return StringVector::AddString(result, strAsStr); + } + } + }); +} + CreateScalarFunctionInfo H3Functions::GetGridDiskFunction() { ScalarFunctionSet funcs("h3_grid_disk"); - // TODO: VARCHAR variant of this function funcs.AddFunction(ScalarFunction({LogicalType::UBIGINT, LogicalType::INTEGER}, LogicalType::LIST(LogicalType::UBIGINT), GridDiskTmplFunction)); funcs.AddFunction(ScalarFunction({LogicalType::BIGINT, LogicalType::INTEGER}, LogicalType::LIST(LogicalType::BIGINT), GridDiskTmplFunction)); + funcs.AddFunction( + ScalarFunction({LogicalType::VARCHAR, LogicalType::INTEGER}, + LogicalType::LIST(LogicalType::VARCHAR), + GridDiskTmplVarcharFunction)); return CreateScalarFunctionInfo(funcs); } CreateScalarFunctionInfo H3Functions::GetGridDiskDistancesFunction() { ScalarFunctionSet funcs("h3_grid_disk_distances"); - // TODO: VARCHAR variant of this function funcs.AddFunction( ScalarFunction({LogicalType::UBIGINT, LogicalType::INTEGER}, LogicalType::LIST(LogicalType::LIST(LogicalType::UBIGINT)), @@ -282,12 +572,15 @@ CreateScalarFunctionInfo H3Functions::GetGridDiskDistancesFunction() { ScalarFunction({LogicalType::BIGINT, LogicalType::INTEGER}, LogicalType::LIST(LogicalType::LIST(LogicalType::BIGINT)), GridDiskDistancesTmplFunction)); + funcs.AddFunction(ScalarFunction( + {LogicalType::VARCHAR, LogicalType::INTEGER}, + LogicalType::LIST(LogicalType::LIST(LogicalType::VARCHAR)), + GridDiskDistancesTmplVarcharFunction)); return CreateScalarFunctionInfo(funcs); } CreateScalarFunctionInfo H3Functions::GetGridDiskUnsafeFunction() { ScalarFunctionSet funcs("h3_grid_disk_unsafe"); - // TODO: VARCHAR variant of this function funcs.AddFunction( ScalarFunction({LogicalType::UBIGINT, LogicalType::INTEGER}, LogicalType::LIST(LogicalType::UBIGINT), @@ -296,12 +589,15 @@ CreateScalarFunctionInfo H3Functions::GetGridDiskUnsafeFunction() { ScalarFunction({LogicalType::BIGINT, LogicalType::INTEGER}, LogicalType::LIST(LogicalType::BIGINT), GridDiskTmplFunction)); + funcs.AddFunction( + ScalarFunction({LogicalType::VARCHAR, LogicalType::INTEGER}, + LogicalType::LIST(LogicalType::VARCHAR), + GridDiskTmplVarcharFunction)); return CreateScalarFunctionInfo(funcs); } CreateScalarFunctionInfo H3Functions::GetGridDiskDistancesUnsafeFunction() { ScalarFunctionSet funcs("h3_grid_disk_distances_unsafe"); - // TODO: VARCHAR variant of this function funcs.AddFunction(ScalarFunction( {LogicalType::UBIGINT, LogicalType::INTEGER}, LogicalType::LIST(LogicalType::LIST(LogicalType::UBIGINT)), @@ -310,12 +606,15 @@ CreateScalarFunctionInfo H3Functions::GetGridDiskDistancesUnsafeFunction() { {LogicalType::BIGINT, LogicalType::INTEGER}, LogicalType::LIST(LogicalType::LIST(LogicalType::BIGINT)), GridDiskDistancesTmplFunction)); + funcs.AddFunction(ScalarFunction( + {LogicalType::VARCHAR, LogicalType::INTEGER}, + LogicalType::LIST(LogicalType::LIST(LogicalType::VARCHAR)), + GridDiskDistancesTmplVarcharFunction)); return CreateScalarFunctionInfo(funcs); } CreateScalarFunctionInfo H3Functions::GetGridDiskDistancesSafeFunction() { ScalarFunctionSet funcs("h3_grid_disk_distances_safe"); - // TODO: VARCHAR variant of this function funcs.AddFunction(ScalarFunction( {LogicalType::UBIGINT, LogicalType::INTEGER}, LogicalType::LIST(LogicalType::LIST(LogicalType::UBIGINT)), @@ -324,64 +623,78 @@ CreateScalarFunctionInfo H3Functions::GetGridDiskDistancesSafeFunction() { {LogicalType::BIGINT, LogicalType::INTEGER}, LogicalType::LIST(LogicalType::LIST(LogicalType::BIGINT)), GridDiskDistancesTmplFunction)); + funcs.AddFunction(ScalarFunction( + {LogicalType::VARCHAR, LogicalType::INTEGER}, + LogicalType::LIST(LogicalType::LIST(LogicalType::VARCHAR)), + GridDiskDistancesTmplVarcharFunction)); return CreateScalarFunctionInfo(funcs); } CreateScalarFunctionInfo H3Functions::GetGridRingUnsafeFunction() { ScalarFunctionSet funcs("h3_grid_ring_unsafe"); - // TODO: VARCHAR variant of this function funcs.AddFunction(ScalarFunction({LogicalType::UBIGINT, LogicalType::INTEGER}, LogicalType::LIST(LogicalType::UBIGINT), GridRingUnsafeFunction)); funcs.AddFunction(ScalarFunction({LogicalType::BIGINT, LogicalType::INTEGER}, LogicalType::LIST(LogicalType::BIGINT), GridRingUnsafeFunction)); + funcs.AddFunction(ScalarFunction({LogicalType::VARCHAR, LogicalType::INTEGER}, + LogicalType::LIST(LogicalType::VARCHAR), + GridRingUnsafeVarcharFunction)); return CreateScalarFunctionInfo(funcs); } CreateScalarFunctionInfo H3Functions::GetGridPathCellsFunction() { ScalarFunctionSet funcs("h3_grid_path_cells"); - // TODO: VARCHAR variant of this function funcs.AddFunction(ScalarFunction({LogicalType::UBIGINT, LogicalType::UBIGINT}, LogicalType::LIST(LogicalType::UBIGINT), GridPathCellsFunction)); funcs.AddFunction(ScalarFunction({LogicalType::BIGINT, LogicalType::BIGINT}, LogicalType::LIST(LogicalType::BIGINT), GridPathCellsFunction)); + funcs.AddFunction(ScalarFunction({LogicalType::VARCHAR, LogicalType::VARCHAR}, + LogicalType::LIST(LogicalType::VARCHAR), + GridPathCellsVarcharFunction)); return CreateScalarFunctionInfo(funcs); } CreateScalarFunctionInfo H3Functions::GetGridDistanceFunction() { ScalarFunctionSet funcs("h3_grid_distance"); - // TODO: VARCHAR variant of this function funcs.AddFunction(ScalarFunction({LogicalType::UBIGINT, LogicalType::UBIGINT}, LogicalType::BIGINT, GridDistanceFunction)); funcs.AddFunction(ScalarFunction({LogicalType::BIGINT, LogicalType::BIGINT}, LogicalType::BIGINT, GridDistanceFunction)); + funcs.AddFunction(ScalarFunction({LogicalType::VARCHAR, LogicalType::VARCHAR}, + LogicalType::BIGINT, + GridDistanceVarcharFunction)); return CreateScalarFunctionInfo(funcs); } CreateScalarFunctionInfo H3Functions::GetCellToLocalIjFunction() { ScalarFunctionSet funcs("h3_cell_to_local_ij"); - // TODO: VARCHAR variant of this function funcs.AddFunction(ScalarFunction({LogicalType::UBIGINT, LogicalType::UBIGINT}, LogicalType::LIST(LogicalType::INTEGER), CellToLocalIjFunction)); funcs.AddFunction(ScalarFunction({LogicalType::BIGINT, LogicalType::BIGINT}, LogicalType::LIST(LogicalType::INTEGER), CellToLocalIjFunction)); + funcs.AddFunction(ScalarFunction({LogicalType::VARCHAR, LogicalType::VARCHAR}, + LogicalType::LIST(LogicalType::VARCHAR), + CellToLocalIjVarcharFunction)); return CreateScalarFunctionInfo(funcs); } CreateScalarFunctionInfo H3Functions::GetLocalIjToCellFunction() { ScalarFunctionSet funcs("h3_local_ij_to_cell"); - // TODO: VARCHAR variant of this function funcs.AddFunction(ScalarFunction( {LogicalType::UBIGINT, LogicalType::INTEGER, LogicalType::INTEGER}, LogicalType::UBIGINT, LocalIjToCellFunction)); funcs.AddFunction(ScalarFunction( {LogicalType::BIGINT, LogicalType::INTEGER, LogicalType::INTEGER}, LogicalType::BIGINT, LocalIjToCellFunction)); + funcs.AddFunction(ScalarFunction( + {LogicalType::VARCHAR, LogicalType::INTEGER, LogicalType::INTEGER}, + LogicalType::VARCHAR, LocalIjToCellVarcharFunction)); return CreateScalarFunctionInfo(funcs); } diff --git a/src/h3_vertex.cpp b/src/h3_vertex.cpp index a8b662e..213ece3 100644 --- a/src/h3_vertex.cpp +++ b/src/h3_vertex.cpp @@ -21,6 +21,34 @@ static void CellToVertexFunction(DataChunk &args, ExpressionState &state, }); } +static void CellToVertexVarcharFunction(DataChunk &args, ExpressionState &state, + Vector &result) { + auto &inputs = args.data[0]; + auto &inputs2 = args.data[1]; + BinaryExecutor::ExecuteWithNulls( + inputs, inputs2, result, args.size(), + [&](string_t cellInput, int32_t vertexNum, ValidityMask &mask, + idx_t idx) { + H3Index cell; + H3Error err0 = stringToH3(cellInput.GetString().c_str(), &cell); + if (err0) { + mask.SetInvalid(idx); + return StringVector::EmptyString(result, 0); + } else { + H3Index vertex; + H3Error err1 = cellToVertex(cell, vertexNum, &vertex); + if (err1) { + mask.SetInvalid(idx); + return StringVector::EmptyString(result, 0); + } else { + auto str = StringUtil::Format("%llx", vertex); + string_t strAsStr = string_t(strdup(str.c_str()), str.size()); + return StringVector::AddString(result, strAsStr); + } + } + }); +} + static void CellToVertexesFunction(DataChunk &args, ExpressionState &state, Vector &result) { result.SetVectorType(VectorType::FLAT_VECTOR); @@ -60,6 +88,54 @@ static void CellToVertexesFunction(DataChunk &args, ExpressionState &state, } } +static void CellToVertexesVarcharFunction(DataChunk &args, + ExpressionState &state, + Vector &result) { + result.SetVectorType(VectorType::FLAT_VECTOR); + auto &result_validity = FlatVector::Validity(result); + auto result_data = FlatVector::GetData(result); + idx_t offset = 0; + for (idx_t i = 0; i < args.size(); i++) { + result_data[i].offset = offset; + + string cellInput = args.GetValue(0, i) + .DefaultCastAs(LogicalType::VARCHAR) + .GetValue(); + + H3Index cell; + H3Error err0 = stringToH3(cellInput.c_str(), &cell); + if (err0) { + result_validity.SetInvalid(i); + result_data[i].length = 0; + } else { + int64_t actual = 0; + std::vector out(6); + H3Error err = cellToVertexes(cell, out.data()); + if (err) { + result_validity.SetInvalid(i); + result_data[i].length = 0; + } else { + for (auto val : out) { + if (val != H3_NULL) { + auto str = StringUtil::Format("%llx", val); + string_t strAsStr = string_t(strdup(str.c_str()), str.size()); + ListVector::PushBack(result, strAsStr); + actual++; + } + } + + result_data[i].length = actual; + } + offset += actual; + } + } + result.Verify(args.size()); + + if (args.AllConstant()) { + result.SetVectorType(VectorType::CONSTANT_VECTOR); + } +} + static void VertexToLatFunction(DataChunk &args, ExpressionState &state, Vector &result) { auto &inputs = args.data[0]; @@ -77,6 +153,30 @@ static void VertexToLatFunction(DataChunk &args, ExpressionState &state, }); } +static void VertexToLatVarcharFunction(DataChunk &args, ExpressionState &state, + Vector &result) { + auto &inputs = args.data[0]; + UnaryExecutor::ExecuteWithNulls( + inputs, result, args.size(), + [&](string_t vertexInput, ValidityMask &mask, idx_t idx) { + H3Index vertex; + H3Error err0 = stringToH3(vertexInput.GetString().c_str(), &vertex); + if (err0) { + mask.SetInvalid(idx); + return .0; + } else { + LatLng latLng = {.lat = 0, .lng = 0}; + H3Error err1 = vertexToLatLng(vertex, &latLng); + if (err1) { + mask.SetInvalid(idx); + return .0; + } else { + return radsToDegs(latLng.lat); + } + } + }); +} + static void VertexToLngFunction(DataChunk &args, ExpressionState &state, Vector &result) { auto &inputs = args.data[0]; @@ -94,6 +194,30 @@ static void VertexToLngFunction(DataChunk &args, ExpressionState &state, }); } +static void VertexToLngVarcharFunction(DataChunk &args, ExpressionState &state, + Vector &result) { + auto &inputs = args.data[0]; + UnaryExecutor::ExecuteWithNulls( + inputs, result, args.size(), + [&](string_t vertexInput, ValidityMask &mask, idx_t idx) { + H3Index vertex; + H3Error err0 = stringToH3(vertexInput.GetString().c_str(), &vertex); + if (err0) { + mask.SetInvalid(idx); + return .0; + } else { + LatLng latLng = {.lat = 0, .lng = 0}; + H3Error err1 = vertexToLatLng(vertex, &latLng); + if (err1) { + mask.SetInvalid(idx); + return .0; + } else { + return radsToDegs(latLng.lng); + } + } + }); +} + static void VertexToLatLngFunction(DataChunk &args, ExpressionState &state, Vector &result) { auto result_data = FlatVector::GetData(result); @@ -114,6 +238,35 @@ static void VertexToLatLngFunction(DataChunk &args, ExpressionState &state, result.Verify(args.size()); } +static void VertexToLatLngVarcharFunction(DataChunk &args, + ExpressionState &state, + Vector &result) { + auto result_data = FlatVector::GetData(result); + for (idx_t i = 0; i < args.size(); i++) { + result_data[i].offset = ListVector::GetListSize(result); + + string vertexInput = args.GetValue(0, i) + .DefaultCastAs(LogicalType::VARCHAR) + .GetValue(); + H3Index vertex; + H3Error err0 = stringToH3(vertexInput.c_str(), &vertex); + if (err0) { + result.SetValue(i, Value(LogicalType::SQLNULL)); + } else { + LatLng latLng; + H3Error err1 = vertexToLatLng(vertex, &latLng); + if (err1) { + result.SetValue(i, Value(LogicalType::SQLNULL)); + } else { + ListVector::PushBack(result, radsToDegs(latLng.lat)); + ListVector::PushBack(result, radsToDegs(latLng.lng)); + result_data[i].length = 2; + } + } + } + result.Verify(args.size()); +} + static void IsValidVertexVarcharFunction(DataChunk &args, ExpressionState &state, Vector &result) { @@ -139,55 +292,63 @@ static void IsValidVertexFunction(DataChunk &args, ExpressionState &state, CreateScalarFunctionInfo H3Functions::GetCellToVertexFunction() { ScalarFunctionSet funcs("h3_cell_to_vertex"); - // TODO: VARCHAR variant of this function funcs.AddFunction(ScalarFunction({LogicalType::UBIGINT, LogicalType::INTEGER}, LogicalType::UBIGINT, CellToVertexFunction)); funcs.AddFunction(ScalarFunction({LogicalType::BIGINT, LogicalType::INTEGER}, LogicalType::BIGINT, CellToVertexFunction)); + funcs.AddFunction(ScalarFunction({LogicalType::VARCHAR, LogicalType::INTEGER}, + LogicalType::VARCHAR, + CellToVertexVarcharFunction)); return CreateScalarFunctionInfo(funcs); } CreateScalarFunctionInfo H3Functions::GetCellToVertexesFunction() { ScalarFunctionSet funcs("h3_cell_to_vertexes"); - // TODO: VARCHAR variant of this function funcs.AddFunction(ScalarFunction({LogicalType::UBIGINT}, LogicalType::LIST(LogicalType::UBIGINT), CellToVertexesFunction)); funcs.AddFunction(ScalarFunction({LogicalType::BIGINT}, LogicalType::LIST(LogicalType::BIGINT), CellToVertexesFunction)); + funcs.AddFunction(ScalarFunction({LogicalType::VARCHAR}, + LogicalType::LIST(LogicalType::VARCHAR), + CellToVertexesVarcharFunction)); return CreateScalarFunctionInfo(funcs); } CreateScalarFunctionInfo H3Functions::GetVertexToLatFunction() { ScalarFunctionSet funcs("h3_vertex_to_lat"); - // TODO: VARCHAR variant of this function funcs.AddFunction(ScalarFunction({LogicalType::UBIGINT}, LogicalType::DOUBLE, VertexToLatFunction)); funcs.AddFunction(ScalarFunction({LogicalType::BIGINT}, LogicalType::DOUBLE, VertexToLatFunction)); + funcs.AddFunction(ScalarFunction({LogicalType::VARCHAR}, LogicalType::DOUBLE, + VertexToLatVarcharFunction)); return CreateScalarFunctionInfo(funcs); } CreateScalarFunctionInfo H3Functions::GetVertexToLngFunction() { ScalarFunctionSet funcs("h3_vertex_to_lng"); - // TODO: VARCHAR variant of this function funcs.AddFunction(ScalarFunction({LogicalType::UBIGINT}, LogicalType::DOUBLE, VertexToLngFunction)); funcs.AddFunction(ScalarFunction({LogicalType::BIGINT}, LogicalType::DOUBLE, VertexToLngFunction)); + funcs.AddFunction(ScalarFunction({LogicalType::VARCHAR}, LogicalType::DOUBLE, + VertexToLngVarcharFunction)); return CreateScalarFunctionInfo(funcs); } CreateScalarFunctionInfo H3Functions::GetVertexToLatLngFunction() { ScalarFunctionSet funcs("h3_vertex_to_latlng"); - // TODO: VARCHAR variant of this function funcs.AddFunction(ScalarFunction({LogicalType::UBIGINT}, LogicalType::LIST(LogicalType::DOUBLE), VertexToLatLngFunction)); funcs.AddFunction(ScalarFunction({LogicalType::BIGINT}, LogicalType::LIST(LogicalType::DOUBLE), VertexToLatLngFunction)); + funcs.AddFunction(ScalarFunction({LogicalType::VARCHAR}, + LogicalType::LIST(LogicalType::DOUBLE), + VertexToLatLngVarcharFunction)); return CreateScalarFunctionInfo(funcs); } diff --git a/test/sql/h3/h3_functions_directededge.test b/test/sql/h3/h3_functions_directededge.test index 8888ec7..3d9685a 100644 --- a/test/sql/h3/h3_functions_directededge.test +++ b/test/sql/h3/h3_functions_directededge.test @@ -129,3 +129,43 @@ query I SELECT h3_directed_edge_to_boundary_wkt('115283473fffffff') ---- POLYGON ((-122.037735 37.420129, -122.090429 37.337556, -122.037735 37.420129)) + +query I +SELECT h3_origin_to_directed_edges('85283473fffffff') +---- +[115283473fffffff, 125283473fffffff, 135283473fffffff, 145283473fffffff, 155283473fffffff, 165283473fffffff] + +query I +SELECT h3_directed_edge_to_cells('165283473fffffff') +---- +[85283473fffffff, 85283447fffffff] + +query I +SELECT h3_directed_edge_to_cells('0') +---- +NULL + +query I +SELECT h3_get_directed_edge_origin('165283473fffffff') +---- +85283473fffffff + +query I +SELECT h3_get_directed_edge_destination('165283473fffffff') +---- +85283447fffffff + +query I +SELECT h3_cells_to_directed_edge('85283473fffffff', '85283447fffffff') +---- +165283473fffffff + +query I +SELECT h3_are_neighbor_cells('85283473fffffff', '85283447fffffff') +---- +true + +query I +SELECT h3_are_neighbor_cells('85283473fffffff', '85283443fffffff') +---- +false diff --git a/test/sql/h3/h3_functions_traversal.test b/test/sql/h3/h3_functions_traversal.test index 42fc84f..51ef12d 100644 --- a/test/sql/h3/h3_functions_traversal.test +++ b/test/sql/h3/h3_functions_traversal.test @@ -120,6 +120,66 @@ select h3_grid_ring_unsafe(586265647244115967::bigint, 1); ---- [586267846267371519, 586260699441790975, 586244756523188223, 586245306279002111, 586266196999929855, 586264547732488191] +query I +select h3_grid_disk('822d57fffffffff', 1); +---- +[822d57fffffffff, 822d0ffffffffff, 822c27fffffffff, 822c2ffffffffff, 822d5ffffffffff, 822d47fffffffff, 822d77fffffffff] + +query I +select h3_grid_disk_distances('822d57fffffffff', 1); +---- +[[822d57fffffffff], [822d0ffffffffff, 822c27fffffffff, 822c2ffffffffff, 822d5ffffffffff, 822d47fffffffff, 822d77fffffffff]] + +query I +select h3_grid_disk('8408001ffffffff', 1); +---- +[840800bffffffff, 840800dffffffff, 8408001ffffffff, 8408005ffffffff, 8408007ffffffff, 8408009ffffffff] + +query I +select h3_grid_disk('8408001ffffffff', -1); +---- +NULL + +query I +select h3_grid_disk_distances('8408001ffffffff', 1); +---- +[[8408001ffffffff], [840800bffffffff, 840800dffffffff, 8408005ffffffff, 8408007ffffffff, 8408009ffffffff]] + +query I +select h3_grid_disk_unsafe('822d57fffffffff', 1); +---- +[822d57fffffffff, 822d0ffffffffff, 822c27fffffffff, 822c2ffffffffff, 822d5ffffffffff, 822d47fffffffff, 822d77fffffffff] + +query I +select h3_grid_disk_distances_unsafe('822d57fffffffff', 1); +---- +[[822d57fffffffff], [822d0ffffffffff, 822c27fffffffff, 822c2ffffffffff, 822d5ffffffffff, 822d47fffffffff, 822d77fffffffff]] + +query I +select h3_grid_disk_unsafe('8408001ffffffff', 1); +---- +NULL + +query I +select h3_grid_disk_distances_unsafe('8408001ffffffff', 2); +---- +NULL + +query I +select h3_grid_disk_distances_safe('8408001ffffffff', 2); +---- +[[8408001ffffffff], [8408007ffffffff, 840800bffffffff, 8408005ffffffff, 8408009ffffffff, 840800dffffffff], [8408063ffffffff, 840803dffffffff, 8408047ffffffff, 8408057ffffffff, 840802bffffffff, 840806bffffffff, 8408055ffffffff, 8408029ffffffff, 8408039ffffffff, 8408043ffffffff]] + +query I +select h3_grid_ring_unsafe('8408001ffffffff', 1); +---- +NULL + +query I +select h3_grid_ring_unsafe('822d57fffffffff', 1); +---- +[822d77fffffffff, 822d0ffffffffff, 822c27fffffffff, 822c2ffffffffff, 822d5ffffffffff, 822d47fffffffff] + query I select h3_grid_path_cells(605035864166236159::ubigint, 605034941150920703::ubigint); ---- @@ -140,6 +200,21 @@ select h3_grid_path_cells(605035864166236159::bigint, 0::bigint); ---- NULL +query I +select h3_grid_path_cells('86584e9afffffff', '8658412c7ffffff'); +---- +[86584e9afffffff, 86584e91fffffff, 86584e907ffffff, 86584e92fffffff, 8658412d7ffffff, 8658412c7ffffff] + +query I +select h3_grid_path_cells('86584e9afffffff', '0'); +---- +NULL + +query I +select h3_grid_path_cells('0', '86584e9afffffff'); +---- +NULL + query I select h3_grid_distance(605035864166236159::ubigint, 605034941150920703::ubigint); ---- @@ -160,6 +235,21 @@ select h3_grid_distance(605035864166236159::bigint, 0::bigint); ---- NULL +query I +select h3_grid_distance('86584e9afffffff', '8658412c7ffffff'); +---- +5 + +query I +select h3_grid_distance('86584e9afffffff', '0'); +---- +NULL + +query I +select h3_grid_distance('0', '86584e9afffffff'); +---- +NULL + query I select h3_cell_to_local_ij(605034941285138431::ubigint, 605034941285138431::ubigint); ---- @@ -199,3 +289,28 @@ query I select h3_local_ij_to_cell(605034941285138431::bigint, -1230000, -177); ---- NULL + +query I +select h3_cell_to_local_ij('8658412cfffffff', '8658412cfffffff'); +---- +[-123, -177] + +query I +select h3_cell_to_local_ij('8658412cfffffff', '0'); +---- +NULL + +query I +select h3_cell_to_local_ij('8658412cfffffff', 'abc'); +---- +NULL + +query I +select h3_local_ij_to_cell('8658412cfffffff', -123, -177); +---- +8658412cfffffff + +query I +select h3_local_ij_to_cell('8658412cfffffff', -1230000, -177); +---- +NULL diff --git a/test/sql/h3/h3_functions_vertex.test b/test/sql/h3/h3_functions_vertex.test index 187f707..1d26ee6 100644 --- a/test/sql/h3/h3_functions_vertex.test +++ b/test/sql/h3/h3_functions_vertex.test @@ -99,3 +99,38 @@ query I SELECT h3_vertex_to_lng(cast(h3_string_to_h3('2222597fffffffff') as bigint)); ---- 88.57496213785487 + +query I +SELECT h3_cell_to_vertexes('823d6ffffffffff'); +---- +[2222597fffffffff, 2523d47fffffffff, 2423d47fffffffff, 21224b7fffffffff, 20224b7fffffffff, 2322597fffffffff] + +query I +SELECT h3_cell_to_vertexes('fffffffffffffff'); +---- +NULL + +query I +SELECT h3_cell_to_vertex('823d6ffffffffff', 0); +---- +2222597fffffffff + +query I +SELECT h3_cell_to_vertex('823d6ffffffffff', -1); +---- +NULL + +query I +SELECT h3_vertex_to_latlng('2222597fffffffff'); +---- +[39.38084284181813, 88.57496213785487] + +query I +SELECT h3_vertex_to_lat('2222597fffffffff'); +---- +39.38084284181813 + +query I +SELECT h3_vertex_to_lng('2222597fffffffff'); +---- +88.57496213785487