diff --git a/.gitignore b/.gitignore index d7d5746..954b826 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,5 @@ build/ .*.swp .DS_Store data/ +.env/ +env/ diff --git a/CMakeLists.txt b/CMakeLists.txt index a1fd3e7..9674f4c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,47 +14,61 @@ if(WIN32) endif() # Avoid building tooling we won't need for release -set(BUILD_BENCHMARKS OFF CACHE BOOL "" FORCE) -set(BUILD_FILTERS OFF CACHE BOOL "" FORCE) -set(BUILD_GENERATORS OFF CACHE BOOL "" FORCE) -set(BUILD_TESTING OFF CACHE BOOL "" FORCE) -set(BUILD_FUZZERS OFF CACHE BOOL "" FORCE) -set(ENABLE_DOCS OFF CACHE BOOL "" FORCE) -set(ENABLE_TESTING OFF CACHE BOOL "" FORCE) -set(ENABLE_LINTING OFF CACHE BOOL "" FORCE) +set(BUILD_BENCHMARKS + OFF + CACHE BOOL "" FORCE) +set(BUILD_FILTERS + OFF + CACHE BOOL "" FORCE) +set(BUILD_GENERATORS + OFF + CACHE BOOL "" FORCE) +set(BUILD_TESTING + OFF + CACHE BOOL "" FORCE) +set(BUILD_FUZZERS + OFF + CACHE BOOL "" FORCE) +set(ENABLE_DOCS + OFF + CACHE BOOL "" FORCE) +set(ENABLE_TESTING + OFF + CACHE BOOL "" FORCE) +set(ENABLE_LINTING + OFF + CACHE BOOL "" FORCE) +set(ENABLE_FORMAT + OFF + CACHE BOOL "" FORCE) -# Build the core library as static -# TODO: Is this needed? Consider restoring correctly +# Build the core library as static TODO: Is this needed? Consider restoring +# correctly set(BUILD_SHARED_LIBS OFF) add_subdirectory(h3) # Build the rest (other than the core library dependency) as shared set(BUILD_SHARED_LIBS ON) - set(EXTENSION_SOURCES - src/h3ext_extension.cpp - src/h3_common.cpp - src/h3_indexing.cpp - src/h3_inspection.cpp - src/h3_hierarchy.cpp - src/h3_traversal.cpp - src/h3_vertex.cpp - src/h3_directededge.cpp - src/h3_misc.cpp - src/h3_regions.cpp -) -set(LIB_HEADER_FILES - src/include/h3_common.hpp - src/include/h3_functions.hpp - src/include/h3ext_extension.hpp -) + src/h3ext_extension.cpp + src/h3_common.cpp + src/h3_indexing.cpp + src/h3_inspection.cpp + src/h3_hierarchy.cpp + src/h3_traversal.cpp + src/h3_vertex.cpp + src/h3_directededge.cpp + src/h3_misc.cpp + src/h3_regions.cpp) +set(LIB_HEADER_FILES src/include/h3_common.hpp src/include/h3_functions.hpp + src/include/h3ext_extension.hpp) set(ALL_SOURCE_FILES ${EXTENSION_SOURCES} ${LIB_HEADER_FILES}) add_library(${EXTENSION_NAME} STATIC ${EXTENSION_SOURCES}) -# Note this must be the INSTALL target name. -# See https://stackoverflow.com/a/71080574 +# Note this must be the INSTALL target name. See +# https://stackoverflow.com/a/71080574 target_link_libraries(${EXTENSION_NAME} h3) include_directories(src/include) @@ -68,25 +82,3 @@ install( EXPORT "${DUCKDB_EXPORT_SET}" LIBRARY DESTINATION "${INSTALL_LIB_DIR}" ARCHIVE DESTINATION "${INSTALL_LIB_DIR}") - - -# Automatic code formatting -# Give preference to clang-format-9 -find_program(CLANG_FORMAT_PATH NAMES clang-format-9 clang-format) -option(ENABLE_FORMAT "Enable running clang-format before compiling" OFF) -if(ENABLE_FORMAT) - # Format - add_custom_target(format-ext - COMMAND ${CLANG_FORMAT_PATH} - -style=file:${CMAKE_CURRENT_SOURCE_DIR}/duckdb/.clang-format - -i - ${ALL_SOURCE_FILES} - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} - COMMENT "Formatting sources" - ) - # Always do formatting - add_dependencies(${EXTENSION_NAME} format-ext) -elseif(NOT CLANG_FORMAT_PATH) - message(WARNING "clang-format was not detected, " - "so automatic source code reformatting is disabled") -endif() diff --git a/src/h3_common.cpp b/src/h3_common.cpp index 4ae7bc2..6cbc830 100644 --- a/src/h3_common.cpp +++ b/src/h3_common.cpp @@ -3,9 +3,9 @@ namespace duckdb { void ThrowH3Error(H3Error err) { - if (err) { - throw InvalidInputException(StringUtil::Format("H3 error: '%d'", err)); - } + if (err) { + throw InvalidInputException(StringUtil::Format("H3 error: '%d'", err)); + } } } // namespace duckdb diff --git a/src/h3_directededge.cpp b/src/h3_directededge.cpp index dd8df7f..d9d1003 100644 --- a/src/h3_directededge.cpp +++ b/src/h3_directededge.cpp @@ -3,225 +3,261 @@ namespace duckdb { -static void DirectedEdgeToCellsFunction(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); - - uint64_t edge = args.GetValue(0, i).DefaultCastAs(LogicalType::UBIGINT).GetValue(); - std::vector out(2); - H3Error err = directedEdgeToCells(edge, out.data()); - if (err) { - result.SetValue(i, Value(LogicalType::SQLNULL)); - } else { - ListVector::PushBack(result, Value::UBIGINT(out[0])); - ListVector::PushBack(result, Value::UBIGINT(out[1])); - - result_data[i].length = 2; - } - } - result.Verify(args.size()); -} - -static void OriginToDirectedEdgesFunction(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); - - uint64_t origin = args.GetValue(0, i).DefaultCastAs(LogicalType::UBIGINT).GetValue(); - int64_t actual = 0; - std::vector out(6); - H3Error err = originToDirectedEdges(origin, out.data()); - if (err) { - result.SetValue(i, Value(LogicalType::SQLNULL)); - } else { - for (auto val : out) { - if (val != H3_NULL) { - ListVector::PushBack(result, Value::UBIGINT(val)); - actual++; - } - } - - result_data[i].length = actual; - } - } - result.Verify(args.size()); -} - -static void GetDirectedEdgeOriginFunction(DataChunk &args, ExpressionState &state, Vector &result) { - auto &inputs = args.data[0]; - UnaryExecutor::ExecuteWithNulls(inputs, result, args.size(), - [&](uint64_t input, ValidityMask &mask, idx_t idx) { - H3Index out; - H3Error err = getDirectedEdgeOrigin(input, &out); - if (err) { - mask.SetInvalid(idx); - return H3Index(H3_NULL); - } else { - return out; - } - }); -} - -static void GetDirectedEdgeDestinationFunction(DataChunk &args, ExpressionState &state, Vector &result) { - auto &inputs = args.data[0]; - UnaryExecutor::ExecuteWithNulls(inputs, result, args.size(), - [&](uint64_t input, ValidityMask &mask, idx_t idx) { - H3Index out; - H3Error err = getDirectedEdgeDestination(input, &out); - if (err) { - mask.SetInvalid(idx); - return H3Index(H3_NULL); - } else { - return out; - } - }); -} - -static void CellsToDirectedEdgeFunction(DataChunk &args, ExpressionState &state, Vector &result) { - auto &inputs = args.data[0]; - auto &inputs2 = args.data[1]; - BinaryExecutor::ExecuteWithNulls( - inputs, inputs2, result, args.size(), [&](uint64_t input, uint64_t input2, ValidityMask &mask, idx_t idx) { - H3Index out; - H3Error err = cellsToDirectedEdge(input, input2, &out); - if (err) { - mask.SetInvalid(idx); - return H3Index(H3_NULL); - } else { - return out; - } - }); -} - -static void AreNeighborCellsFunction(DataChunk &args, ExpressionState &state, Vector &result) { - auto &inputs = args.data[0]; - auto &inputs2 = args.data[1]; - BinaryExecutor::ExecuteWithNulls( - inputs, inputs2, result, args.size(), [&](uint64_t input, uint64_t input2, ValidityMask &mask, idx_t idx) { - int out; - H3Error err = areNeighborCells(input, input2, &out); - if (err) { - mask.SetInvalid(idx); - return bool(false); - } else { - return bool(out); - } - }); -} - -static void IsValidDirectedEdgeVarcharFunction(DataChunk &args, ExpressionState &state, Vector &result) { - auto &inputs = args.data[0]; - UnaryExecutor::Execute(inputs, result, args.size(), [&](string_t input) { - H3Index h; - H3Error err = stringToH3(input.GetString().c_str(), &h); - if (err) { - return false; - } - return bool(isValidDirectedEdge(h)); - }); -} - -static void IsValidDirectedEdgeFunction(DataChunk &args, ExpressionState &state, Vector &result) { - auto &inputs = args.data[0]; - UnaryExecutor::Execute(inputs, result, args.size(), - [&](H3Index input) { return bool(isValidDirectedEdge(input)); }); +static void DirectedEdgeToCellsFunction(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); + + uint64_t edge = args.GetValue(0, i) + .DefaultCastAs(LogicalType::UBIGINT) + .GetValue(); + std::vector out(2); + H3Error err = directedEdgeToCells(edge, out.data()); + if (err) { + result.SetValue(i, Value(LogicalType::SQLNULL)); + } else { + ListVector::PushBack(result, Value::UBIGINT(out[0])); + ListVector::PushBack(result, Value::UBIGINT(out[1])); + + result_data[i].length = 2; + } + } + result.Verify(args.size()); +} + +static void OriginToDirectedEdgesFunction(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); + + uint64_t origin = args.GetValue(0, i) + .DefaultCastAs(LogicalType::UBIGINT) + .GetValue(); + int64_t actual = 0; + std::vector out(6); + H3Error err = originToDirectedEdges(origin, out.data()); + if (err) { + result.SetValue(i, Value(LogicalType::SQLNULL)); + } else { + for (auto val : out) { + if (val != H3_NULL) { + ListVector::PushBack(result, Value::UBIGINT(val)); + actual++; + } + } + + result_data[i].length = actual; + } + } + result.Verify(args.size()); +} + +static void GetDirectedEdgeOriginFunction(DataChunk &args, + ExpressionState &state, + Vector &result) { + auto &inputs = args.data[0]; + UnaryExecutor::ExecuteWithNulls( + inputs, result, args.size(), + [&](uint64_t input, ValidityMask &mask, idx_t idx) { + H3Index out; + H3Error err = getDirectedEdgeOrigin(input, &out); + if (err) { + mask.SetInvalid(idx); + return H3Index(H3_NULL); + } else { + return out; + } + }); +} + +static void GetDirectedEdgeDestinationFunction(DataChunk &args, + ExpressionState &state, + Vector &result) { + auto &inputs = args.data[0]; + UnaryExecutor::ExecuteWithNulls( + inputs, result, args.size(), + [&](uint64_t input, ValidityMask &mask, idx_t idx) { + H3Index out; + H3Error err = getDirectedEdgeDestination(input, &out); + if (err) { + mask.SetInvalid(idx); + return H3Index(H3_NULL); + } else { + return out; + } + }); +} + +static void CellsToDirectedEdgeFunction(DataChunk &args, ExpressionState &state, + Vector &result) { + auto &inputs = args.data[0]; + auto &inputs2 = args.data[1]; + BinaryExecutor::ExecuteWithNulls( + inputs, inputs2, result, args.size(), + [&](uint64_t input, uint64_t input2, ValidityMask &mask, idx_t idx) { + H3Index out; + H3Error err = cellsToDirectedEdge(input, input2, &out); + if (err) { + mask.SetInvalid(idx); + return H3Index(H3_NULL); + } else { + return out; + } + }); +} + +static void AreNeighborCellsFunction(DataChunk &args, ExpressionState &state, + Vector &result) { + auto &inputs = args.data[0]; + auto &inputs2 = args.data[1]; + BinaryExecutor::ExecuteWithNulls( + inputs, inputs2, result, args.size(), + [&](uint64_t input, uint64_t input2, ValidityMask &mask, idx_t idx) { + int out; + H3Error err = areNeighborCells(input, input2, &out); + if (err) { + mask.SetInvalid(idx); + return bool(false); + } else { + return bool(out); + } + }); +} + +static void IsValidDirectedEdgeVarcharFunction(DataChunk &args, + ExpressionState &state, + Vector &result) { + auto &inputs = args.data[0]; + UnaryExecutor::Execute( + inputs, result, args.size(), [&](string_t input) { + H3Index h; + H3Error err = stringToH3(input.GetString().c_str(), &h); + if (err) { + return false; + } + return bool(isValidDirectedEdge(h)); + }); +} + +static void IsValidDirectedEdgeFunction(DataChunk &args, ExpressionState &state, + Vector &result) { + auto &inputs = args.data[0]; + UnaryExecutor::Execute( + inputs, result, args.size(), + [&](H3Index input) { return bool(isValidDirectedEdge(input)); }); } struct DirectedEdgeToBoundaryOperator { - template - static RESULT_TYPE Operation(INPUT_TYPE input, Vector &result) { - CellBoundary boundary; - H3Error err = directedEdgeToBoundary(input, &boundary); - - if (err) { - // TODO: Is it possible to return null here instead? - return StringVector::EmptyString(result, 0); - } else { - std::string str = "POLYGON (("; - for (int i = 0; i <= boundary.numVerts; i++) { - std::string sep = (i == 0) ? "" : ", "; - int vertIndex = (i == boundary.numVerts) ? 0 : i; - str += StringUtil::Format("%s%f %f", sep, radsToDegs(boundary.verts[vertIndex].lng), - radsToDegs(boundary.verts[vertIndex].lat)); - } - str += "))"; - - string_t strAsStr = string_t(strdup(str.c_str()), str.size()); - return StringVector::AddString(result, strAsStr); - } - } + template + static RESULT_TYPE Operation(INPUT_TYPE input, Vector &result) { + CellBoundary boundary; + H3Error err = directedEdgeToBoundary(input, &boundary); + + if (err) { + // TODO: Is it possible to return null here instead? + return StringVector::EmptyString(result, 0); + } else { + std::string str = "POLYGON (("; + for (int i = 0; i <= boundary.numVerts; i++) { + std::string sep = (i == 0) ? "" : ", "; + int vertIndex = (i == boundary.numVerts) ? 0 : i; + str += StringUtil::Format("%s%f %f", sep, + radsToDegs(boundary.verts[vertIndex].lng), + radsToDegs(boundary.verts[vertIndex].lat)); + } + str += "))"; + + string_t strAsStr = string_t(strdup(str.c_str()), str.size()); + return StringVector::AddString(result, strAsStr); + } + } }; -static void DirectedEdgeToBoundaryWktFunction(DataChunk &args, ExpressionState &state, Vector &result) { - UnaryExecutor::ExecuteString(args.data[0], result, args.size()); +static void DirectedEdgeToBoundaryWktFunction(DataChunk &args, + ExpressionState &state, + Vector &result) { + UnaryExecutor::ExecuteString( + args.data[0], result, args.size()); } struct DirectedEdgeToBoundaryVarcharOperator { - template - static RESULT_TYPE Operation(INPUT_TYPE input, Vector &result) { - H3Index h; - H3Error err = stringToH3(input.GetString().c_str(), &h); - if (err) { - return StringVector::EmptyString(result, 0); - } else { - return DirectedEdgeToBoundaryOperator().Operation(h, result); - } - } + template + static RESULT_TYPE Operation(INPUT_TYPE input, Vector &result) { + H3Index h; + H3Error err = stringToH3(input.GetString().c_str(), &h); + if (err) { + return StringVector::EmptyString(result, 0); + } else { + return DirectedEdgeToBoundaryOperator().Operation( + h, result); + } + } }; -static void DirectedEdgeToBoundaryWktVarcharFunction(DataChunk &args, ExpressionState &state, Vector &result) { - UnaryExecutor::ExecuteString(args.data[0], result, - args.size()); +static void DirectedEdgeToBoundaryWktVarcharFunction(DataChunk &args, + ExpressionState &state, + Vector &result) { + UnaryExecutor::ExecuteString( + args.data[0], result, args.size()); } CreateScalarFunctionInfo H3Functions::GetDirectedEdgeToCellsFunction() { - return CreateScalarFunctionInfo(ScalarFunction("h3_directed_edge_to_cells", {LogicalType::UBIGINT}, - LogicalType::LIST(LogicalType::UBIGINT), - DirectedEdgeToCellsFunction)); + return CreateScalarFunctionInfo(ScalarFunction( + "h3_directed_edge_to_cells", {LogicalType::UBIGINT}, + LogicalType::LIST(LogicalType::UBIGINT), DirectedEdgeToCellsFunction)); } CreateScalarFunctionInfo H3Functions::GetOriginToDirectedEdgesFunction() { - return CreateScalarFunctionInfo(ScalarFunction("h3_origin_to_directed_edges", {LogicalType::UBIGINT}, - LogicalType::LIST(LogicalType::UBIGINT), - OriginToDirectedEdgesFunction)); + return CreateScalarFunctionInfo(ScalarFunction( + "h3_origin_to_directed_edges", {LogicalType::UBIGINT}, + LogicalType::LIST(LogicalType::UBIGINT), OriginToDirectedEdgesFunction)); } CreateScalarFunctionInfo H3Functions::GetGetDirectedEdgeOriginFunction() { - return CreateScalarFunctionInfo(ScalarFunction("h3_get_directed_edge_origin", {LogicalType::UBIGINT}, - LogicalType::UBIGINT, GetDirectedEdgeOriginFunction)); + return CreateScalarFunctionInfo( + ScalarFunction("h3_get_directed_edge_origin", {LogicalType::UBIGINT}, + LogicalType::UBIGINT, GetDirectedEdgeOriginFunction)); } CreateScalarFunctionInfo H3Functions::GetGetDirectedEdgeDestinationFunction() { - return CreateScalarFunctionInfo(ScalarFunction("h3_get_directed_edge_destination", {LogicalType::UBIGINT}, - LogicalType::UBIGINT, GetDirectedEdgeDestinationFunction)); + return CreateScalarFunctionInfo( + ScalarFunction("h3_get_directed_edge_destination", {LogicalType::UBIGINT}, + LogicalType::UBIGINT, GetDirectedEdgeDestinationFunction)); } CreateScalarFunctionInfo H3Functions::GetCellsToDirectedEdgeFunction() { - return CreateScalarFunctionInfo(ScalarFunction("h3_cells_to_directed_edge", - {LogicalType::UBIGINT, LogicalType::UBIGINT}, LogicalType::UBIGINT, - CellsToDirectedEdgeFunction)); + return CreateScalarFunctionInfo(ScalarFunction( + "h3_cells_to_directed_edge", {LogicalType::UBIGINT, LogicalType::UBIGINT}, + LogicalType::UBIGINT, CellsToDirectedEdgeFunction)); } CreateScalarFunctionInfo H3Functions::GetAreNeighborCellsFunction() { - return CreateScalarFunctionInfo(ScalarFunction("h3_are_neighbor_cells", - {LogicalType::UBIGINT, LogicalType::UBIGINT}, LogicalType::BOOLEAN, - AreNeighborCellsFunction)); + return CreateScalarFunctionInfo(ScalarFunction( + "h3_are_neighbor_cells", {LogicalType::UBIGINT, LogicalType::UBIGINT}, + LogicalType::BOOLEAN, AreNeighborCellsFunction)); } CreateScalarFunctionInfo H3Functions::GetIsValidDirectedEdgeFunctions() { - ScalarFunctionSet funcs("h3_is_valid_directed_edge"); - funcs.AddFunction(ScalarFunction({LogicalType::VARCHAR}, LogicalType::BOOLEAN, IsValidDirectedEdgeVarcharFunction)); - funcs.AddFunction(ScalarFunction({LogicalType::UBIGINT}, LogicalType::BOOLEAN, IsValidDirectedEdgeFunction)); - return CreateScalarFunctionInfo(funcs); + ScalarFunctionSet funcs("h3_is_valid_directed_edge"); + funcs.AddFunction(ScalarFunction({LogicalType::VARCHAR}, LogicalType::BOOLEAN, + IsValidDirectedEdgeVarcharFunction)); + funcs.AddFunction(ScalarFunction({LogicalType::UBIGINT}, LogicalType::BOOLEAN, + IsValidDirectedEdgeFunction)); + return CreateScalarFunctionInfo(funcs); } CreateScalarFunctionInfo H3Functions::GetDirectedEdgeToBoundaryWktFunction() { - ScalarFunctionSet funcs("h3_directed_edge_to_boundary_wkt"); - funcs.AddFunction( - ScalarFunction({LogicalType::VARCHAR}, LogicalType::VARCHAR, DirectedEdgeToBoundaryWktVarcharFunction)); - funcs.AddFunction(ScalarFunction({LogicalType::UBIGINT}, LogicalType::VARCHAR, DirectedEdgeToBoundaryWktFunction)); - return CreateScalarFunctionInfo(funcs); + ScalarFunctionSet funcs("h3_directed_edge_to_boundary_wkt"); + funcs.AddFunction(ScalarFunction({LogicalType::VARCHAR}, LogicalType::VARCHAR, + DirectedEdgeToBoundaryWktVarcharFunction)); + funcs.AddFunction(ScalarFunction({LogicalType::UBIGINT}, LogicalType::VARCHAR, + DirectedEdgeToBoundaryWktFunction)); + return CreateScalarFunctionInfo(funcs); } } // namespace duckdb diff --git a/src/h3_hierarchy.cpp b/src/h3_hierarchy.cpp index 889bfb3..81dadbb 100644 --- a/src/h3_hierarchy.cpp +++ b/src/h3_hierarchy.cpp @@ -3,289 +3,318 @@ namespace duckdb { -static void CellToParentFunction(DataChunk &args, ExpressionState &state, Vector &result) { - auto &inputs = args.data[0]; - auto &inputs2 = args.data[1]; - BinaryExecutor::ExecuteWithNulls( - inputs, inputs2, result, args.size(), [&](uint64_t input, int res, ValidityMask &mask, idx_t idx) { - H3Index parent; - H3Error err = cellToParent(input, res, &parent); - if (err) { - mask.SetInvalid(idx); - return H3Index(H3_NULL); - } else { - return parent; - } - }); +static void CellToParentFunction(DataChunk &args, ExpressionState &state, + Vector &result) { + auto &inputs = args.data[0]; + auto &inputs2 = args.data[1]; + BinaryExecutor::ExecuteWithNulls( + inputs, inputs2, result, args.size(), + [&](uint64_t input, int res, ValidityMask &mask, idx_t idx) { + H3Index parent; + H3Error err = cellToParent(input, res, &parent); + if (err) { + mask.SetInvalid(idx); + return H3Index(H3_NULL); + } else { + return parent; + } + }); } -static void CellToChildrenFunction(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); - - uint64_t parent = args.GetValue(0, i).DefaultCastAs(LogicalType::UBIGINT).GetValue(); - int32_t res = args.GetValue(1, i).DefaultCastAs(LogicalType::INTEGER).GetValue(); - int64_t sz; - H3Error err1 = cellToChildrenSize(parent, res, &sz); - if (err1) { - result.SetValue(i, Value(LogicalType::SQLNULL)); - } else { - - std::vector out(sz); - H3Error err2 = cellToChildren(parent, res, out.data()); - if (err2) { - result.SetValue(i, Value(LogicalType::SQLNULL)); - } else { - int64_t actual = 0; - for (auto val : out) { - if (val != H3_NULL) { - ListVector::PushBack(result, Value::UBIGINT(val)); - actual++; - } - } - - result_data[i].length = actual; - } - } - } - result.Verify(args.size()); +static void CellToChildrenFunction(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); + + uint64_t parent = args.GetValue(0, i) + .DefaultCastAs(LogicalType::UBIGINT) + .GetValue(); + int32_t res = args.GetValue(1, i) + .DefaultCastAs(LogicalType::INTEGER) + .GetValue(); + int64_t sz; + H3Error err1 = cellToChildrenSize(parent, res, &sz); + if (err1) { + result.SetValue(i, Value(LogicalType::SQLNULL)); + } else { + + std::vector out(sz); + H3Error err2 = cellToChildren(parent, res, out.data()); + if (err2) { + result.SetValue(i, Value(LogicalType::SQLNULL)); + } else { + int64_t actual = 0; + for (auto val : out) { + if (val != H3_NULL) { + ListVector::PushBack(result, Value::UBIGINT(val)); + actual++; + } + } + + result_data[i].length = actual; + } + } + } + result.Verify(args.size()); } -static void CellToCenterChildFunction(DataChunk &args, ExpressionState &state, Vector &result) { - auto &inputs = args.data[0]; - auto &inputs2 = args.data[1]; - BinaryExecutor::ExecuteWithNulls( - inputs, inputs2, result, args.size(), [&](uint64_t input, int res, ValidityMask &mask, idx_t idx) { - H3Index child; - H3Error err = cellToCenterChild(input, res, &child); - if (err) { - mask.SetInvalid(idx); - return H3Index(H3_NULL); - } else { - return child; - } - }); +static void CellToCenterChildFunction(DataChunk &args, ExpressionState &state, + Vector &result) { + auto &inputs = args.data[0]; + auto &inputs2 = args.data[1]; + BinaryExecutor::ExecuteWithNulls( + inputs, inputs2, result, args.size(), + [&](uint64_t input, int res, ValidityMask &mask, idx_t idx) { + H3Index child; + H3Error err = cellToCenterChild(input, res, &child); + if (err) { + mask.SetInvalid(idx); + return H3Index(H3_NULL); + } else { + return child; + } + }); } -static void CellToChildPosFunction(DataChunk &args, ExpressionState &state, Vector &result) { - auto &inputs = args.data[0]; - auto &inputs2 = args.data[1]; - BinaryExecutor::ExecuteWithNulls(inputs, inputs2, result, args.size(), - [&](H3Index input, int res, ValidityMask &mask, idx_t idx) { - int64_t child; - H3Error err = cellToChildPos(input, res, &child); - if (err) { - mask.SetInvalid(idx); - return int64_t(0); - } else { - return child; - } - }); +static void CellToChildPosFunction(DataChunk &args, ExpressionState &state, + Vector &result) { + auto &inputs = args.data[0]; + auto &inputs2 = args.data[1]; + BinaryExecutor::ExecuteWithNulls( + inputs, inputs2, result, args.size(), + [&](H3Index input, int res, ValidityMask &mask, idx_t idx) { + int64_t child; + H3Error err = cellToChildPos(input, res, &child); + if (err) { + mask.SetInvalid(idx); + return int64_t(0); + } else { + return child; + } + }); } -static void ChildPosToCellFunction(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(), - [&](int64_t pos, H3Index input, int res, ValidityMask &mask, idx_t idx) { - H3Index child; - H3Error err = childPosToCell(pos, input, res, &child); - if (err) { - mask.SetInvalid(idx); - return H3Index(H3_NULL); - } else { - return child; - } - }); +static void ChildPosToCellFunction(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(), + [&](int64_t pos, H3Index input, int res, ValidityMask &mask, idx_t idx) { + H3Index child; + H3Error err = childPosToCell(pos, input, res, &child); + if (err) { + mask.SetInvalid(idx); + return H3Index(H3_NULL); + } else { + return child; + } + }); } -static void CompactCellsFunction(DataChunk &args, ExpressionState &state, Vector &result) { - D_ASSERT(args.ColumnCount() == 1); - auto count = args.size(); - - Vector &lhs = args.data[0]; - if (lhs.GetType().id() == LogicalTypeId::SQLNULL) { - result.Reference(lhs); - return; - } - - UnifiedVectorFormat lhs_data; - lhs.ToUnifiedFormat(count, lhs_data); - - auto list_entries = (list_entry_t *)lhs_data.data; - - result.SetVectorType(VectorType::FLAT_VECTOR); - auto result_entries = FlatVector::GetData(result); - auto &result_validity = FlatVector::Validity(result); - - idx_t offset = 0; - for (idx_t i = 0; i < count; i++) { - result_entries[i].offset = offset; - result_entries[i].length = 0; - auto list_index = lhs_data.sel->get_index(i); - - if (!lhs_data.validity.RowIsValid(list_index)) { - result_validity.SetInvalid(i); - continue; - } - - const auto &list_entry = list_entries[list_index]; - - const auto lvalue = lhs.GetValue(list_entry.offset).DefaultCastAs(LogicalType::LIST(LogicalType::UBIGINT)); - - auto &list_children = ListValue::GetChildren(lvalue); - - auto input_set = new H3Index[list_children.size()]; - for (size_t i = 0; i < list_children.size(); i++) { - input_set[i] = list_children[i].GetValue(); - } - auto compacted = new H3Index[list_children.size()](); - H3Error err = compactCells(input_set, compacted, list_children.size()); - - if (err) { - result_validity.SetInvalid(i); - } else { - int64_t actual = 0; - for (size_t i = 0; i < list_children.size(); i++) { - auto child_val = compacted[i]; - if (child_val != H3_NULL) { - ListVector::PushBack(result, Value::UBIGINT(child_val)); - actual++; - } - } - - result_entries[i].length = actual; - offset += actual; - } - } - - result.Verify(args.size()); - - if (lhs.GetVectorType() == VectorType::CONSTANT_VECTOR) { - result.SetVectorType(VectorType::CONSTANT_VECTOR); - } +static void CompactCellsFunction(DataChunk &args, ExpressionState &state, + Vector &result) { + D_ASSERT(args.ColumnCount() == 1); + auto count = args.size(); + + Vector &lhs = args.data[0]; + if (lhs.GetType().id() == LogicalTypeId::SQLNULL) { + result.Reference(lhs); + return; + } + + UnifiedVectorFormat lhs_data; + lhs.ToUnifiedFormat(count, lhs_data); + + auto list_entries = (list_entry_t *)lhs_data.data; + + result.SetVectorType(VectorType::FLAT_VECTOR); + auto result_entries = FlatVector::GetData(result); + auto &result_validity = FlatVector::Validity(result); + + idx_t offset = 0; + for (idx_t i = 0; i < count; i++) { + result_entries[i].offset = offset; + result_entries[i].length = 0; + auto list_index = lhs_data.sel->get_index(i); + + if (!lhs_data.validity.RowIsValid(list_index)) { + result_validity.SetInvalid(i); + continue; + } + + const auto &list_entry = list_entries[list_index]; + + const auto lvalue = + lhs.GetValue(list_entry.offset) + .DefaultCastAs(LogicalType::LIST(LogicalType::UBIGINT)); + + auto &list_children = ListValue::GetChildren(lvalue); + + auto input_set = new H3Index[list_children.size()]; + for (size_t i = 0; i < list_children.size(); i++) { + input_set[i] = list_children[i].GetValue(); + } + auto compacted = new H3Index[list_children.size()](); + H3Error err = compactCells(input_set, compacted, list_children.size()); + + if (err) { + result_validity.SetInvalid(i); + } else { + int64_t actual = 0; + for (size_t i = 0; i < list_children.size(); i++) { + auto child_val = compacted[i]; + if (child_val != H3_NULL) { + ListVector::PushBack(result, Value::UBIGINT(child_val)); + actual++; + } + } + + result_entries[i].length = actual; + offset += actual; + } + } + + result.Verify(args.size()); + + if (lhs.GetVectorType() == VectorType::CONSTANT_VECTOR) { + result.SetVectorType(VectorType::CONSTANT_VECTOR); + } } -static void UncompactCellsFunction(DataChunk &args, ExpressionState &state, Vector &result) { - D_ASSERT(args.ColumnCount() == 2); - auto count = args.size(); - - Vector &lhs = args.data[0]; - if (lhs.GetType().id() == LogicalTypeId::SQLNULL) { - result.Reference(lhs); - return; - } - Vector res_vec = args.data[1]; - if (res_vec.GetType().id() == LogicalTypeId::SQLNULL) { - result.Reference(res_vec); - return; - } - - UnifiedVectorFormat lhs_data; - lhs.ToUnifiedFormat(count, lhs_data); - UnifiedVectorFormat res_data; - res_vec.ToUnifiedFormat(count, res_data); - - auto list_entries = (list_entry_t *)lhs_data.data; - - result.SetVectorType(VectorType::FLAT_VECTOR); - auto result_entries = FlatVector::GetData(result); - auto &result_validity = FlatVector::Validity(result); - - idx_t offset = 0; - for (idx_t i = 0; i < count; i++) { - result_entries[i].offset = offset; - result_entries[i].length = 0; - auto list_index = lhs_data.sel->get_index(i); - - if (!lhs_data.validity.RowIsValid(list_index) || !res_data.validity.RowIsValid(list_index)) { - result_validity.SetInvalid(i); - continue; - } - - const auto &list_entry = list_entries[list_index]; - - const auto lvalue = lhs.GetValue(list_entry.offset).DefaultCastAs(LogicalType::LIST(LogicalType::UBIGINT)); - const auto res = res_vec.GetValue(i).DefaultCastAs(LogicalType::INTEGER).GetValue(); - - auto &list_children = ListValue::GetChildren(lvalue); - - auto input_set = new H3Index[list_children.size()]; - for (size_t i = 0; i < list_children.size(); i++) { - input_set[i] = list_children[i].GetValue(); - } - int64_t uncompacted_sz; - H3Error sz_err = uncompactCellsSize(input_set, list_children.size(), res, &uncompacted_sz); - if (sz_err) { - result_validity.SetInvalid(i); - continue; - } - auto uncompacted = new H3Index[uncompacted_sz](); - H3Error err = uncompactCells(input_set, list_children.size(), uncompacted, uncompacted_sz, res); - - if (err) { - result_validity.SetInvalid(i); - } else { - int64_t actual = 0; - for (size_t i = 0; i < uncompacted_sz; i++) { - auto child_val = uncompacted[i]; - if (child_val != H3_NULL) { - ListVector::PushBack(result, Value::UBIGINT(child_val)); - actual++; - } - } - - result_entries[i].length = actual; - offset += actual; - } - } - - result.Verify(args.size()); - - if (lhs.GetVectorType() == VectorType::CONSTANT_VECTOR) { - result.SetVectorType(VectorType::CONSTANT_VECTOR); - } +static void UncompactCellsFunction(DataChunk &args, ExpressionState &state, + Vector &result) { + D_ASSERT(args.ColumnCount() == 2); + auto count = args.size(); + + Vector &lhs = args.data[0]; + if (lhs.GetType().id() == LogicalTypeId::SQLNULL) { + result.Reference(lhs); + return; + } + Vector res_vec = args.data[1]; + if (res_vec.GetType().id() == LogicalTypeId::SQLNULL) { + result.Reference(res_vec); + return; + } + + UnifiedVectorFormat lhs_data; + lhs.ToUnifiedFormat(count, lhs_data); + UnifiedVectorFormat res_data; + res_vec.ToUnifiedFormat(count, res_data); + + auto list_entries = (list_entry_t *)lhs_data.data; + + result.SetVectorType(VectorType::FLAT_VECTOR); + auto result_entries = FlatVector::GetData(result); + auto &result_validity = FlatVector::Validity(result); + + idx_t offset = 0; + for (idx_t i = 0; i < count; i++) { + result_entries[i].offset = offset; + result_entries[i].length = 0; + auto list_index = lhs_data.sel->get_index(i); + + if (!lhs_data.validity.RowIsValid(list_index) || + !res_data.validity.RowIsValid(list_index)) { + result_validity.SetInvalid(i); + continue; + } + + const auto &list_entry = list_entries[list_index]; + + const auto lvalue = + lhs.GetValue(list_entry.offset) + .DefaultCastAs(LogicalType::LIST(LogicalType::UBIGINT)); + const auto res = res_vec.GetValue(i) + .DefaultCastAs(LogicalType::INTEGER) + .GetValue(); + + auto &list_children = ListValue::GetChildren(lvalue); + + auto input_set = new H3Index[list_children.size()]; + for (size_t i = 0; i < list_children.size(); i++) { + input_set[i] = list_children[i].GetValue(); + } + int64_t uncompacted_sz; + H3Error sz_err = uncompactCellsSize(input_set, list_children.size(), res, + &uncompacted_sz); + if (sz_err) { + result_validity.SetInvalid(i); + continue; + } + auto uncompacted = new H3Index[uncompacted_sz](); + H3Error err = uncompactCells(input_set, list_children.size(), uncompacted, + uncompacted_sz, res); + + if (err) { + result_validity.SetInvalid(i); + } else { + int64_t actual = 0; + for (size_t i = 0; i < uncompacted_sz; i++) { + auto child_val = uncompacted[i]; + if (child_val != H3_NULL) { + ListVector::PushBack(result, Value::UBIGINT(child_val)); + actual++; + } + } + + result_entries[i].length = actual; + offset += actual; + } + } + + result.Verify(args.size()); + + if (lhs.GetVectorType() == VectorType::CONSTANT_VECTOR) { + result.SetVectorType(VectorType::CONSTANT_VECTOR); + } } CreateScalarFunctionInfo H3Functions::GetCellToParentFunction() { - return CreateScalarFunctionInfo(ScalarFunction("h3_cell_to_parent", {LogicalType::UBIGINT, LogicalType::INTEGER}, - LogicalType::UBIGINT, CellToParentFunction)); + return CreateScalarFunctionInfo(ScalarFunction( + "h3_cell_to_parent", {LogicalType::UBIGINT, LogicalType::INTEGER}, + LogicalType::UBIGINT, CellToParentFunction)); } CreateScalarFunctionInfo H3Functions::GetCellToChildrenFunction() { - return CreateScalarFunctionInfo(ScalarFunction("h3_cell_to_children", {LogicalType::UBIGINT, LogicalType::INTEGER}, - LogicalType::LIST(LogicalType::UBIGINT), CellToChildrenFunction)); + return CreateScalarFunctionInfo(ScalarFunction( + "h3_cell_to_children", {LogicalType::UBIGINT, LogicalType::INTEGER}, + LogicalType::LIST(LogicalType::UBIGINT), CellToChildrenFunction)); } CreateScalarFunctionInfo H3Functions::GetCellToCenterChildFunction() { - return CreateScalarFunctionInfo(ScalarFunction("h3_cell_to_center_child", - {LogicalType::UBIGINT, LogicalType::INTEGER}, LogicalType::UBIGINT, - CellToCenterChildFunction)); + return CreateScalarFunctionInfo(ScalarFunction( + "h3_cell_to_center_child", {LogicalType::UBIGINT, LogicalType::INTEGER}, + LogicalType::UBIGINT, CellToCenterChildFunction)); } CreateScalarFunctionInfo H3Functions::GetCellToChildPosFunction() { - return CreateScalarFunctionInfo(ScalarFunction("h3_cell_to_child_pos", {LogicalType::UBIGINT, LogicalType::INTEGER}, - LogicalType::BIGINT, CellToChildPosFunction)); + return CreateScalarFunctionInfo(ScalarFunction( + "h3_cell_to_child_pos", {LogicalType::UBIGINT, LogicalType::INTEGER}, + LogicalType::BIGINT, CellToChildPosFunction)); } CreateScalarFunctionInfo H3Functions::GetChildPosToCellFunction() { - return CreateScalarFunctionInfo(ScalarFunction("h3_child_pos_to_cell", - {LogicalType::BIGINT, LogicalType::UBIGINT, LogicalType::INTEGER}, - LogicalType::UBIGINT, ChildPosToCellFunction)); + return CreateScalarFunctionInfo(ScalarFunction( + "h3_child_pos_to_cell", + {LogicalType::BIGINT, LogicalType::UBIGINT, LogicalType::INTEGER}, + LogicalType::UBIGINT, ChildPosToCellFunction)); } CreateScalarFunctionInfo H3Functions::GetCompactCellsFunction() { - return CreateScalarFunctionInfo(ScalarFunction("h3_compact_cells", {LogicalType::LIST(LogicalType::UBIGINT)}, - LogicalType::LIST(LogicalType::UBIGINT), CompactCellsFunction)); + return CreateScalarFunctionInfo(ScalarFunction( + "h3_compact_cells", {LogicalType::LIST(LogicalType::UBIGINT)}, + LogicalType::LIST(LogicalType::UBIGINT), CompactCellsFunction)); } CreateScalarFunctionInfo H3Functions::GetUncompactCellsFunction() { - return CreateScalarFunctionInfo(ScalarFunction("h3_uncompact_cells", - {LogicalType::LIST(LogicalType::UBIGINT), LogicalType::INTEGER}, - LogicalType::LIST(LogicalType::UBIGINT), UncompactCellsFunction)); + return CreateScalarFunctionInfo(ScalarFunction( + "h3_uncompact_cells", + {LogicalType::LIST(LogicalType::UBIGINT), LogicalType::INTEGER}, + LogicalType::LIST(LogicalType::UBIGINT), UncompactCellsFunction)); } } // namespace duckdb diff --git a/src/h3_indexing.cpp b/src/h3_indexing.cpp index 9eff8a3..b26d163 100644 --- a/src/h3_indexing.cpp +++ b/src/h3_indexing.cpp @@ -3,229 +3,259 @@ namespace duckdb { -static void LatLngToCellFunction(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(), - [&](double lat, double lng, int res, ValidityMask &mask, idx_t idx) { - H3Index cell; - LatLng latLng = {.lat = degsToRads(lat), .lng = degsToRads(lng)}; - H3Error err = latLngToCell(&latLng, res, &cell); - if (err) { - mask.SetInvalid(idx); - return H3Index(H3_NULL); - } else { - return cell; - } - }); +static void LatLngToCellFunction(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(), + [&](double lat, double lng, int res, ValidityMask &mask, idx_t idx) { + H3Index cell; + LatLng latLng = {.lat = degsToRads(lat), .lng = degsToRads(lng)}; + H3Error err = latLngToCell(&latLng, res, &cell); + if (err) { + mask.SetInvalid(idx); + return H3Index(H3_NULL); + } else { + return cell; + } + }); } -static void CellToLatFunction(DataChunk &args, ExpressionState &state, Vector &result) { - auto &inputs = args.data[0]; - UnaryExecutor::ExecuteWithNulls(inputs, result, args.size(), - [&](H3Index cell, ValidityMask &mask, idx_t idx) { - LatLng latLng = {.lat = 0, .lng = 0}; - H3Error err = cellToLatLng(cell, &latLng); - if (err) { - mask.SetInvalid(idx); - return .0; - } else { - return radsToDegs(latLng.lat); - } - }); +static void CellToLatFunction(DataChunk &args, ExpressionState &state, + Vector &result) { + auto &inputs = args.data[0]; + UnaryExecutor::ExecuteWithNulls( + inputs, result, args.size(), + [&](H3Index cell, ValidityMask &mask, idx_t idx) { + LatLng latLng = {.lat = 0, .lng = 0}; + H3Error err = cellToLatLng(cell, &latLng); + if (err) { + mask.SetInvalid(idx); + return .0; + } else { + return radsToDegs(latLng.lat); + } + }); } -static void CellToLatVarcharFunction(DataChunk &args, ExpressionState &state, Vector &result) { - auto &inputs = args.data[0]; - UnaryExecutor::ExecuteWithNulls( - inputs, result, args.size(), [&](string_t cellAddress, ValidityMask &mask, idx_t idx) { - H3Index cell; - H3Error err0 = stringToH3(cellAddress.GetString().c_str(), &cell); - if (err0) { - mask.SetInvalid(idx); - return .0; - } else { - LatLng latLng = {.lat = 0, .lng = 0}; - H3Error err = cellToLatLng(cell, &latLng); - if (err) { - mask.SetInvalid(idx); - return .0; - } else { - return radsToDegs(latLng.lat); - } - } - }); +static void CellToLatVarcharFunction(DataChunk &args, ExpressionState &state, + Vector &result) { + auto &inputs = args.data[0]; + UnaryExecutor::ExecuteWithNulls( + inputs, result, args.size(), + [&](string_t cellAddress, ValidityMask &mask, idx_t idx) { + H3Index cell; + H3Error err0 = stringToH3(cellAddress.GetString().c_str(), &cell); + if (err0) { + mask.SetInvalid(idx); + return .0; + } else { + LatLng latLng = {.lat = 0, .lng = 0}; + H3Error err = cellToLatLng(cell, &latLng); + if (err) { + mask.SetInvalid(idx); + return .0; + } else { + return radsToDegs(latLng.lat); + } + } + }); } -static void CellToLngFunction(DataChunk &args, ExpressionState &state, Vector &result) { - auto &inputs = args.data[0]; - UnaryExecutor::ExecuteWithNulls(inputs, result, args.size(), - [&](H3Index cell, ValidityMask &mask, idx_t idx) { - LatLng latLng = {.lat = 0, .lng = 0}; - H3Error err = cellToLatLng(cell, &latLng); - if (err) { - mask.SetInvalid(idx); - return .0; - } else { - return radsToDegs(latLng.lng); - } - }); +static void CellToLngFunction(DataChunk &args, ExpressionState &state, + Vector &result) { + auto &inputs = args.data[0]; + UnaryExecutor::ExecuteWithNulls( + inputs, result, args.size(), + [&](H3Index cell, ValidityMask &mask, idx_t idx) { + LatLng latLng = {.lat = 0, .lng = 0}; + H3Error err = cellToLatLng(cell, &latLng); + if (err) { + mask.SetInvalid(idx); + return .0; + } else { + return radsToDegs(latLng.lng); + } + }); } -static void CellToLngVarcharFunction(DataChunk &args, ExpressionState &state, Vector &result) { - auto &inputs = args.data[0]; - UnaryExecutor::ExecuteWithNulls( - inputs, result, args.size(), [&](string_t cellAddress, ValidityMask &mask, idx_t idx) { - H3Index cell; - H3Error err0 = stringToH3(cellAddress.GetString().c_str(), &cell); - if (err0) { - mask.SetInvalid(idx); - return .0; - } else { - LatLng latLng = {.lat = 0, .lng = 0}; - H3Error err = cellToLatLng(cell, &latLng); - if (err) { - mask.SetInvalid(idx); - return .0; - } else { - return radsToDegs(latLng.lng); - } - } - }); +static void CellToLngVarcharFunction(DataChunk &args, ExpressionState &state, + Vector &result) { + auto &inputs = args.data[0]; + UnaryExecutor::ExecuteWithNulls( + inputs, result, args.size(), + [&](string_t cellAddress, ValidityMask &mask, idx_t idx) { + H3Index cell; + H3Error err0 = stringToH3(cellAddress.GetString().c_str(), &cell); + if (err0) { + mask.SetInvalid(idx); + return .0; + } else { + LatLng latLng = {.lat = 0, .lng = 0}; + H3Error err = cellToLatLng(cell, &latLng); + if (err) { + mask.SetInvalid(idx); + return .0; + } else { + return radsToDegs(latLng.lng); + } + } + }); } -static void CellToLatLngFunction(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); - - uint64_t cell = args.GetValue(0, i).DefaultCastAs(LogicalType::UBIGINT).GetValue(); - LatLng latLng; - H3Error err = cellToLatLng(cell, &latLng); - if (err) { - 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 CellToLatLngFunction(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); + + uint64_t cell = args.GetValue(0, i) + .DefaultCastAs(LogicalType::UBIGINT) + .GetValue(); + LatLng latLng; + H3Error err = cellToLatLng(cell, &latLng); + if (err) { + 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 CellToLatLngVarcharFunction(DataChunk &args, ExpressionState &state, Vector &result) { - UnifiedVectorFormat vdata; - args.data[0].ToUnifiedFormat(args.size(), vdata); - - auto ldata = UnifiedVectorFormat::GetData(vdata); - - result.SetVectorType(VectorType::FLAT_VECTOR); - auto result_data = FlatVector::GetData(result); - for (idx_t i = 0; i < args.size(); i++) { - result_data[i].offset = ListVector::GetListSize(result); - - string_t cellAddress = ldata[i]; - H3Index cell; - H3Error err0 = stringToH3(cellAddress.GetString().c_str(), &cell); - if (err0) { - result.SetValue(i, Value(LogicalType::SQLNULL)); - } else { - LatLng latLng; - H3Error err = cellToLatLng(cell, &latLng); - if (err) { - 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 CellToLatLngVarcharFunction(DataChunk &args, ExpressionState &state, + Vector &result) { + UnifiedVectorFormat vdata; + args.data[0].ToUnifiedFormat(args.size(), vdata); + + auto ldata = UnifiedVectorFormat::GetData(vdata); + + result.SetVectorType(VectorType::FLAT_VECTOR); + auto result_data = FlatVector::GetData(result); + for (idx_t i = 0; i < args.size(); i++) { + result_data[i].offset = ListVector::GetListSize(result); + + string_t cellAddress = ldata[i]; + H3Index cell; + H3Error err0 = stringToH3(cellAddress.GetString().c_str(), &cell); + if (err0) { + result.SetValue(i, Value(LogicalType::SQLNULL)); + } else { + LatLng latLng; + H3Error err = cellToLatLng(cell, &latLng); + if (err) { + 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()); } struct CellToBoundaryOperator { - template - static RESULT_TYPE Operation(INPUT_TYPE input, Vector &result) { - CellBoundary boundary; - H3Error err = cellToBoundary(input, &boundary); - - if (err) { - // TODO: Is it possible to return null here instead? - return StringVector::EmptyString(result, 0); - } else { - std::string str = "POLYGON (("; - for (int i = 0; i <= boundary.numVerts; i++) { - std::string sep = (i == 0) ? "" : ", "; - int vertIndex = (i == boundary.numVerts) ? 0 : i; - str += StringUtil::Format("%s%f %f", sep, radsToDegs(boundary.verts[vertIndex].lng), - radsToDegs(boundary.verts[vertIndex].lat)); - } - str += "))"; - - string_t strAsStr = string_t(strdup(str.c_str()), str.size()); - return StringVector::AddString(result, strAsStr); - } - } + template + static RESULT_TYPE Operation(INPUT_TYPE input, Vector &result) { + CellBoundary boundary; + H3Error err = cellToBoundary(input, &boundary); + + if (err) { + // TODO: Is it possible to return null here instead? + return StringVector::EmptyString(result, 0); + } else { + std::string str = "POLYGON (("; + for (int i = 0; i <= boundary.numVerts; i++) { + std::string sep = (i == 0) ? "" : ", "; + int vertIndex = (i == boundary.numVerts) ? 0 : i; + str += StringUtil::Format("%s%f %f", sep, + radsToDegs(boundary.verts[vertIndex].lng), + radsToDegs(boundary.verts[vertIndex].lat)); + } + str += "))"; + + string_t strAsStr = string_t(strdup(str.c_str()), str.size()); + return StringVector::AddString(result, strAsStr); + } + } }; -static void CellToBoundaryWktFunction(DataChunk &args, ExpressionState &state, Vector &result) { - UnaryExecutor::ExecuteString(args.data[0], result, args.size()); +static void CellToBoundaryWktFunction(DataChunk &args, ExpressionState &state, + Vector &result) { + UnaryExecutor::ExecuteString( + args.data[0], result, args.size()); } struct CellToBoundaryVarcharOperator { - template - static RESULT_TYPE Operation(INPUT_TYPE input, Vector &result) { - H3Index h; - H3Error err = stringToH3(input.GetString().c_str(), &h); - if (err) { - return StringVector::EmptyString(result, 0); - } else { - return CellToBoundaryOperator().Operation(h, result); - } - } + template + static RESULT_TYPE Operation(INPUT_TYPE input, Vector &result) { + H3Index h; + H3Error err = stringToH3(input.GetString().c_str(), &h); + if (err) { + return StringVector::EmptyString(result, 0); + } else { + return CellToBoundaryOperator().Operation(h, + result); + } + } }; -static void CellToBoundaryWktVarcharFunction(DataChunk &args, ExpressionState &state, Vector &result) { - UnaryExecutor::ExecuteString(args.data[0], result, args.size()); +static void CellToBoundaryWktVarcharFunction(DataChunk &args, + ExpressionState &state, + Vector &result) { + UnaryExecutor::ExecuteString( + args.data[0], result, args.size()); } CreateScalarFunctionInfo H3Functions::GetLatLngToCellFunction() { - return CreateScalarFunctionInfo(ScalarFunction("h3_latlng_to_cell", - {LogicalType::DOUBLE, LogicalType::DOUBLE, LogicalType::INTEGER}, - LogicalType::UBIGINT, LatLngToCellFunction)); + return CreateScalarFunctionInfo(ScalarFunction( + "h3_latlng_to_cell", + {LogicalType::DOUBLE, LogicalType::DOUBLE, LogicalType::INTEGER}, + LogicalType::UBIGINT, LatLngToCellFunction)); } CreateScalarFunctionInfo H3Functions::GetCellToLatFunction() { - ScalarFunctionSet funcs("h3_cell_to_lat"); - funcs.AddFunction(ScalarFunction({LogicalType::VARCHAR}, LogicalType::DOUBLE, CellToLatVarcharFunction)); - funcs.AddFunction(ScalarFunction({LogicalType::UBIGINT}, LogicalType::DOUBLE, CellToLatFunction)); - return CreateScalarFunctionInfo(funcs); + ScalarFunctionSet funcs("h3_cell_to_lat"); + funcs.AddFunction(ScalarFunction({LogicalType::VARCHAR}, LogicalType::DOUBLE, + CellToLatVarcharFunction)); + funcs.AddFunction(ScalarFunction({LogicalType::UBIGINT}, LogicalType::DOUBLE, + CellToLatFunction)); + return CreateScalarFunctionInfo(funcs); } CreateScalarFunctionInfo H3Functions::GetCellToLngFunction() { - ScalarFunctionSet funcs("h3_cell_to_lng"); - funcs.AddFunction(ScalarFunction({LogicalType::VARCHAR}, LogicalType::DOUBLE, CellToLngVarcharFunction)); - funcs.AddFunction(ScalarFunction({LogicalType::UBIGINT}, LogicalType::DOUBLE, CellToLngFunction)); - return CreateScalarFunctionInfo(funcs); + ScalarFunctionSet funcs("h3_cell_to_lng"); + funcs.AddFunction(ScalarFunction({LogicalType::VARCHAR}, LogicalType::DOUBLE, + CellToLngVarcharFunction)); + funcs.AddFunction(ScalarFunction({LogicalType::UBIGINT}, LogicalType::DOUBLE, + CellToLngFunction)); + return CreateScalarFunctionInfo(funcs); } CreateScalarFunctionInfo H3Functions::GetCellToLatLngFunction() { - ScalarFunctionSet funcs("h3_cell_to_latlng"); - funcs.AddFunction( - ScalarFunction({LogicalType::VARCHAR}, LogicalType::LIST(LogicalType::DOUBLE), CellToLatLngVarcharFunction)); - funcs.AddFunction( - ScalarFunction({LogicalType::UBIGINT}, LogicalType::LIST(LogicalType::DOUBLE), CellToLatLngFunction)); - return CreateScalarFunctionInfo(funcs); + ScalarFunctionSet funcs("h3_cell_to_latlng"); + funcs.AddFunction(ScalarFunction({LogicalType::VARCHAR}, + LogicalType::LIST(LogicalType::DOUBLE), + CellToLatLngVarcharFunction)); + funcs.AddFunction(ScalarFunction({LogicalType::UBIGINT}, + LogicalType::LIST(LogicalType::DOUBLE), + CellToLatLngFunction)); + return CreateScalarFunctionInfo(funcs); } CreateScalarFunctionInfo H3Functions::GetCellToBoundaryWktFunction() { - ScalarFunctionSet funcs("h3_cell_to_boundary_wkt"); - funcs.AddFunction(ScalarFunction({LogicalType::VARCHAR}, LogicalType::VARCHAR, CellToBoundaryWktVarcharFunction)); - funcs.AddFunction(ScalarFunction({LogicalType::UBIGINT}, LogicalType::VARCHAR, CellToBoundaryWktFunction)); - return CreateScalarFunctionInfo(funcs); + ScalarFunctionSet funcs("h3_cell_to_boundary_wkt"); + funcs.AddFunction(ScalarFunction({LogicalType::VARCHAR}, LogicalType::VARCHAR, + CellToBoundaryWktVarcharFunction)); + funcs.AddFunction(ScalarFunction({LogicalType::UBIGINT}, LogicalType::VARCHAR, + CellToBoundaryWktFunction)); + return CreateScalarFunctionInfo(funcs); } } // namespace duckdb diff --git a/src/h3_inspection.cpp b/src/h3_inspection.cpp index 067efe3..d19a0b0 100644 --- a/src/h3_inspection.cpp +++ b/src/h3_inspection.cpp @@ -3,148 +3,175 @@ namespace duckdb { -static void GetResolutionFunction(DataChunk &args, ExpressionState &state, Vector &result) { - auto &inputs = args.data[0]; - UnaryExecutor::Execute(inputs, result, args.size(), - [&](H3Index cell) { return getResolution(cell); }); -} - -static void GetBaseCellNumberFunction(DataChunk &args, ExpressionState &state, Vector &result) { - auto &inputs = args.data[0]; - UnaryExecutor::Execute(inputs, result, args.size(), - [&](H3Index cell) { return getBaseCellNumber(cell); }); -} - -static void StringToH3Function(DataChunk &args, ExpressionState &state, Vector &result) { - auto &inputs = args.data[0]; - UnaryExecutor::ExecuteWithNulls(inputs, result, args.size(), - [&](string_t input, ValidityMask &mask, idx_t idx) { - H3Index h; - H3Error err = stringToH3(input.GetString().c_str(), &h); - if (err) { - mask.SetInvalid(idx); - return H3Index(H3_NULL); - } else { - return h; - } - }); +static void GetResolutionFunction(DataChunk &args, ExpressionState &state, + Vector &result) { + auto &inputs = args.data[0]; + UnaryExecutor::Execute( + inputs, result, args.size(), + [&](H3Index cell) { return getResolution(cell); }); +} + +static void GetBaseCellNumberFunction(DataChunk &args, ExpressionState &state, + Vector &result) { + auto &inputs = args.data[0]; + UnaryExecutor::Execute( + inputs, result, args.size(), + [&](H3Index cell) { return getBaseCellNumber(cell); }); +} + +static void StringToH3Function(DataChunk &args, ExpressionState &state, + Vector &result) { + auto &inputs = args.data[0]; + UnaryExecutor::ExecuteWithNulls( + inputs, result, args.size(), + [&](string_t input, ValidityMask &mask, idx_t idx) { + H3Index h; + H3Error err = stringToH3(input.GetString().c_str(), &h); + if (err) { + mask.SetInvalid(idx); + return H3Index(H3_NULL); + } else { + return h; + } + }); } struct H3ToStringOperator { - template - static RESULT_TYPE Operation(INPUT_TYPE input, Vector &result) { - auto str = StringUtil::Format("%llx", input); - string_t strAsStr = string_t(strdup(str.c_str()), str.size()); - return StringVector::AddString(result, strAsStr); - } + template + static RESULT_TYPE Operation(INPUT_TYPE input, Vector &result) { + auto str = StringUtil::Format("%llx", input); + string_t strAsStr = string_t(strdup(str.c_str()), str.size()); + return StringVector::AddString(result, strAsStr); + } }; -static void H3ToStringFunction(DataChunk &args, ExpressionState &state, Vector &result) { - UnaryExecutor::ExecuteString(args.data[0], result, args.size()); -} - -static void IsValidCellVarcharFunction(DataChunk &args, ExpressionState &state, Vector &result) { - auto &inputs = args.data[0]; - UnaryExecutor::Execute(inputs, result, args.size(), [&](string_t input) { - H3Index h; - H3Error err = stringToH3(input.GetString().c_str(), &h); - if (err) { - return false; - } - return bool(isValidCell(h)); - }); -} - -static void IsValidCellFunction(DataChunk &args, ExpressionState &state, Vector &result) { - auto &inputs = args.data[0]; - UnaryExecutor::Execute(inputs, result, args.size(), - [&](H3Index input) { return bool(isValidCell(input)); }); -} - -static void IsResClassIIIFunction(DataChunk &args, ExpressionState &state, Vector &result) { - auto &inputs = args.data[0]; - UnaryExecutor::Execute(inputs, result, args.size(), - [&](uint64_t cell) { return bool(isResClassIII(cell)); }); -} - -static void IsPentagonFunction(DataChunk &args, ExpressionState &state, Vector &result) { - auto &inputs = args.data[0]; - UnaryExecutor::Execute(inputs, result, args.size(), - [&](uint64_t cell) { return bool(isPentagon(cell)); }); -} - -static void GetIcosahedronFacesFunction(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); - - uint64_t cell = args.GetValue(0, i).DefaultCastAs(LogicalType::UBIGINT).GetValue(); - int faceCount; - int64_t actual = 0; - H3Error err1 = maxFaceCount(cell, &faceCount); - if (err1) { - result.SetValue(i, Value(LogicalType::SQLNULL)); - } else { - std::vector out(faceCount); - H3Error err2 = getIcosahedronFaces(cell, out.data()); - if (err2) { - result.SetValue(i, Value(LogicalType::SQLNULL)); - } else { - for (auto val : out) { - if (val != -1) { - ListVector::PushBack(result, Value::INTEGER(val)); - actual++; - } - } - } - } - - result_data[i].length = actual; - } - result.Verify(args.size()); +static void H3ToStringFunction(DataChunk &args, ExpressionState &state, + Vector &result) { + UnaryExecutor::ExecuteString( + args.data[0], result, args.size()); +} + +static void IsValidCellVarcharFunction(DataChunk &args, ExpressionState &state, + Vector &result) { + auto &inputs = args.data[0]; + UnaryExecutor::Execute( + inputs, result, args.size(), [&](string_t input) { + H3Index h; + H3Error err = stringToH3(input.GetString().c_str(), &h); + if (err) { + return false; + } + return bool(isValidCell(h)); + }); +} + +static void IsValidCellFunction(DataChunk &args, ExpressionState &state, + Vector &result) { + auto &inputs = args.data[0]; + UnaryExecutor::Execute( + inputs, result, args.size(), + [&](H3Index input) { return bool(isValidCell(input)); }); +} + +static void IsResClassIIIFunction(DataChunk &args, ExpressionState &state, + Vector &result) { + auto &inputs = args.data[0]; + UnaryExecutor::Execute( + inputs, result, args.size(), + [&](uint64_t cell) { return bool(isResClassIII(cell)); }); +} + +static void IsPentagonFunction(DataChunk &args, ExpressionState &state, + Vector &result) { + auto &inputs = args.data[0]; + UnaryExecutor::Execute( + inputs, result, args.size(), + [&](uint64_t cell) { return bool(isPentagon(cell)); }); +} + +static void GetIcosahedronFacesFunction(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); + + uint64_t cell = args.GetValue(0, i) + .DefaultCastAs(LogicalType::UBIGINT) + .GetValue(); + int faceCount; + int64_t actual = 0; + H3Error err1 = maxFaceCount(cell, &faceCount); + if (err1) { + result.SetValue(i, Value(LogicalType::SQLNULL)); + } else { + std::vector out(faceCount); + H3Error err2 = getIcosahedronFaces(cell, out.data()); + if (err2) { + result.SetValue(i, Value(LogicalType::SQLNULL)); + } else { + for (auto val : out) { + if (val != -1) { + ListVector::PushBack(result, Value::INTEGER(val)); + actual++; + } + } + } + } + + result_data[i].length = actual; + } + result.Verify(args.size()); } CreateScalarFunctionInfo H3Functions::GetGetResolutionFunction() { - return CreateScalarFunctionInfo( - ScalarFunction("h3_get_resolution", {LogicalType::UBIGINT}, LogicalType::INTEGER, GetResolutionFunction)); + return CreateScalarFunctionInfo( + ScalarFunction("h3_get_resolution", {LogicalType::UBIGINT}, + LogicalType::INTEGER, GetResolutionFunction)); } CreateScalarFunctionInfo H3Functions::GetGetBaseCellNumberFunction() { - return CreateScalarFunctionInfo(ScalarFunction("h3_get_base_cell_number", {LogicalType::UBIGINT}, - LogicalType::INTEGER, GetBaseCellNumberFunction)); + return CreateScalarFunctionInfo( + ScalarFunction("h3_get_base_cell_number", {LogicalType::UBIGINT}, + LogicalType::INTEGER, GetBaseCellNumberFunction)); } CreateScalarFunctionInfo H3Functions::GetStringToH3Function() { - return CreateScalarFunctionInfo( - ScalarFunction("h3_string_to_h3", {LogicalType::VARCHAR}, LogicalType::UBIGINT, StringToH3Function)); + return CreateScalarFunctionInfo( + ScalarFunction("h3_string_to_h3", {LogicalType::VARCHAR}, + LogicalType::UBIGINT, StringToH3Function)); } CreateScalarFunctionInfo H3Functions::GetH3ToStringFunction() { - return CreateScalarFunctionInfo( - ScalarFunction("h3_h3_to_string", {LogicalType::UBIGINT}, LogicalType::VARCHAR, H3ToStringFunction)); + return CreateScalarFunctionInfo( + ScalarFunction("h3_h3_to_string", {LogicalType::UBIGINT}, + LogicalType::VARCHAR, H3ToStringFunction)); } CreateScalarFunctionInfo H3Functions::GetIsValidCellFunctions() { - ScalarFunctionSet funcs("h3_is_valid_cell"); - funcs.AddFunction(ScalarFunction({LogicalType::VARCHAR}, LogicalType::BOOLEAN, IsValidCellVarcharFunction)); - funcs.AddFunction(ScalarFunction({LogicalType::UBIGINT}, LogicalType::BOOLEAN, IsValidCellFunction)); - return CreateScalarFunctionInfo(funcs); + ScalarFunctionSet funcs("h3_is_valid_cell"); + funcs.AddFunction(ScalarFunction({LogicalType::VARCHAR}, LogicalType::BOOLEAN, + IsValidCellVarcharFunction)); + funcs.AddFunction(ScalarFunction({LogicalType::UBIGINT}, LogicalType::BOOLEAN, + IsValidCellFunction)); + return CreateScalarFunctionInfo(funcs); } CreateScalarFunctionInfo H3Functions::GetIsResClassIIIFunction() { - return CreateScalarFunctionInfo( - ScalarFunction("h3_is_res_class_iii", {LogicalType::UBIGINT}, LogicalType::BOOLEAN, IsResClassIIIFunction)); + return CreateScalarFunctionInfo( + ScalarFunction("h3_is_res_class_iii", {LogicalType::UBIGINT}, + LogicalType::BOOLEAN, IsResClassIIIFunction)); } CreateScalarFunctionInfo H3Functions::GetIsPentagonFunction() { - return CreateScalarFunctionInfo( - ScalarFunction("h3_is_pentagon", {LogicalType::UBIGINT}, LogicalType::BOOLEAN, IsPentagonFunction)); + return CreateScalarFunctionInfo( + ScalarFunction("h3_is_pentagon", {LogicalType::UBIGINT}, + LogicalType::BOOLEAN, IsPentagonFunction)); } CreateScalarFunctionInfo H3Functions::GetGetIcosahedronFacesFunction() { - return CreateScalarFunctionInfo(ScalarFunction("h3_get_icosahedron_faces", {LogicalType::UBIGINT}, - LogicalType::LIST(LogicalType::INTEGER), - GetIcosahedronFacesFunction)); + return CreateScalarFunctionInfo(ScalarFunction( + "h3_get_icosahedron_faces", {LogicalType::UBIGINT}, + LogicalType::LIST(LogicalType::INTEGER), GetIcosahedronFacesFunction)); } } // namespace duckdb diff --git a/src/h3_misc.cpp b/src/h3_misc.cpp index c1dcb5e..84ff5d8 100644 --- a/src/h3_misc.cpp +++ b/src/h3_misc.cpp @@ -3,296 +3,331 @@ namespace duckdb { -// TODO: Consider using enums for (km, m, rads) here, instead of VARCHAR (string) - -static void GetHexagonAreaAvgFunction(DataChunk &args, ExpressionState &state, Vector &result) { - auto &inputs = args.data[0]; - auto &inputs2 = args.data[1]; - BinaryExecutor::ExecuteWithNulls(inputs, inputs2, result, args.size(), - [&](int res, string_t unit, ValidityMask &mask, idx_t idx) { - double out; - H3Error err = E_OPTION_INVALID; - if (unit == "km^2") { - err = getHexagonAreaAvgKm2(res, &out); - } else if (unit == "m^2") { - err = getHexagonAreaAvgM2(res, &out); - } - if (err) { - mask.SetInvalid(idx); - return 0.0; - } else { - return out; - } - }); +// TODO: Consider using enums for (km, m, rads) here, instead of VARCHAR +// (string) + +static void GetHexagonAreaAvgFunction(DataChunk &args, ExpressionState &state, + Vector &result) { + auto &inputs = args.data[0]; + auto &inputs2 = args.data[1]; + BinaryExecutor::ExecuteWithNulls( + inputs, inputs2, result, args.size(), + [&](int res, string_t unit, ValidityMask &mask, idx_t idx) { + double out; + H3Error err = E_OPTION_INVALID; + if (unit == "km^2") { + err = getHexagonAreaAvgKm2(res, &out); + } else if (unit == "m^2") { + err = getHexagonAreaAvgM2(res, &out); + } + if (err) { + mask.SetInvalid(idx); + return 0.0; + } else { + return out; + } + }); } -static double CellAreaFunctionInternal(H3Index cell, string_t unit, ValidityMask &mask, idx_t idx) { - double out; - H3Error err = E_OPTION_INVALID; - if (unit == "rads^2") { - err = cellAreaRads2(cell, &out); - } else if (unit == "km^2") { - err = cellAreaKm2(cell, &out); - } else if (unit == "m^2") { - err = cellAreaM2(cell, &out); - } - if (err) { - mask.SetInvalid(idx); - return 0.0; - } else { - return out; - } +static double CellAreaFunctionInternal(H3Index cell, string_t unit, + ValidityMask &mask, idx_t idx) { + double out; + H3Error err = E_OPTION_INVALID; + if (unit == "rads^2") { + err = cellAreaRads2(cell, &out); + } else if (unit == "km^2") { + err = cellAreaKm2(cell, &out); + } else if (unit == "m^2") { + err = cellAreaM2(cell, &out); + } + if (err) { + mask.SetInvalid(idx); + return 0.0; + } else { + return out; + } } -static void CellAreaVarcharFunction(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 cell, string_t unit, ValidityMask &mask, idx_t idx) { - H3Index h; - H3Error err = stringToH3(cell.GetString().c_str(), &h); - if (err) { - mask.SetInvalid(idx); - return 0.0; - } - return CellAreaFunctionInternal(h, unit, mask, idx); - }); +static void CellAreaVarcharFunction(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 cell, string_t unit, ValidityMask &mask, idx_t idx) { + H3Index h; + H3Error err = stringToH3(cell.GetString().c_str(), &h); + if (err) { + mask.SetInvalid(idx); + return 0.0; + } + return CellAreaFunctionInternal(h, unit, mask, idx); + }); } -static void CellAreaFunction(DataChunk &args, ExpressionState &state, Vector &result) { - auto &inputs = args.data[0]; - auto &inputs2 = args.data[1]; - BinaryExecutor::ExecuteWithNulls(inputs, inputs2, result, args.size(), - CellAreaFunctionInternal); +static void CellAreaFunction(DataChunk &args, ExpressionState &state, + Vector &result) { + auto &inputs = args.data[0]; + auto &inputs2 = args.data[1]; + BinaryExecutor::ExecuteWithNulls( + inputs, inputs2, result, args.size(), CellAreaFunctionInternal); } -static void GetHexagonEdgeLengthAvgFunction(DataChunk &args, ExpressionState &state, Vector &result) { - auto &inputs = args.data[0]; - auto &inputs2 = args.data[1]; - BinaryExecutor::ExecuteWithNulls(inputs, inputs2, result, args.size(), - [&](int res, string_t unit, ValidityMask &mask, idx_t idx) { - double out; - H3Error err = E_OPTION_INVALID; - if (unit == "km") { - err = getHexagonEdgeLengthAvgKm(res, &out); - } else if (unit == "m") { - err = getHexagonEdgeLengthAvgM(res, &out); - } - if (err) { - mask.SetInvalid(idx); - return 0.0; - } else { - return out; - } - }); +static void GetHexagonEdgeLengthAvgFunction(DataChunk &args, + ExpressionState &state, + Vector &result) { + auto &inputs = args.data[0]; + auto &inputs2 = args.data[1]; + BinaryExecutor::ExecuteWithNulls( + inputs, inputs2, result, args.size(), + [&](int res, string_t unit, ValidityMask &mask, idx_t idx) { + double out; + H3Error err = E_OPTION_INVALID; + if (unit == "km") { + err = getHexagonEdgeLengthAvgKm(res, &out); + } else if (unit == "m") { + err = getHexagonEdgeLengthAvgM(res, &out); + } + if (err) { + mask.SetInvalid(idx); + return 0.0; + } else { + return out; + } + }); } -static double EdgeLengthFunctionInternal(H3Index edge, string_t unit, ValidityMask &mask, idx_t idx) { - double out; - H3Error err = E_OPTION_INVALID; - if (unit == "rads") { - err = edgeLengthRads(edge, &out); - } else if (unit == "km") { - err = edgeLengthKm(edge, &out); - } else if (unit == "m") { - err = edgeLengthM(edge, &out); - } - if (err) { - mask.SetInvalid(idx); - return 0.0; - } else { - return out; - } +static double EdgeLengthFunctionInternal(H3Index edge, string_t unit, + ValidityMask &mask, idx_t idx) { + double out; + H3Error err = E_OPTION_INVALID; + if (unit == "rads") { + err = edgeLengthRads(edge, &out); + } else if (unit == "km") { + err = edgeLengthKm(edge, &out); + } else if (unit == "m") { + err = edgeLengthM(edge, &out); + } + if (err) { + mask.SetInvalid(idx); + return 0.0; + } else { + return out; + } } -static void EdgeLengthVarcharFunction(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 edge, string_t unit, ValidityMask &mask, idx_t idx) { - H3Index h; - H3Error err = stringToH3(edge.GetString().c_str(), &h); - if (err) { - mask.SetInvalid(idx); - return 0.0; - } - return EdgeLengthFunctionInternal(h, unit, mask, idx); - }); +static void EdgeLengthVarcharFunction(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 edge, string_t unit, ValidityMask &mask, idx_t idx) { + H3Index h; + H3Error err = stringToH3(edge.GetString().c_str(), &h); + if (err) { + mask.SetInvalid(idx); + return 0.0; + } + return EdgeLengthFunctionInternal(h, unit, mask, idx); + }); } -static void EdgeLengthFunction(DataChunk &args, ExpressionState &state, Vector &result) { - auto &inputs = args.data[0]; - auto &inputs2 = args.data[1]; - BinaryExecutor::ExecuteWithNulls(inputs, inputs2, result, args.size(), - EdgeLengthFunctionInternal); +static void EdgeLengthFunction(DataChunk &args, ExpressionState &state, + Vector &result) { + auto &inputs = args.data[0]; + auto &inputs2 = args.data[1]; + BinaryExecutor::ExecuteWithNulls( + inputs, inputs2, result, args.size(), EdgeLengthFunctionInternal); } -static void GetNumCellsFunction(DataChunk &args, ExpressionState &state, Vector &result) { - auto &inputs = args.data[0]; - UnaryExecutor::ExecuteWithNulls(inputs, result, args.size(), - [&](int res, ValidityMask &mask, idx_t idx) { - int64_t out; - H3Error err = getNumCells(res, &out); - if (err) { - mask.SetInvalid(idx); - return int64_t(0); - } - return out; - }); +static void GetNumCellsFunction(DataChunk &args, ExpressionState &state, + Vector &result) { + auto &inputs = args.data[0]; + UnaryExecutor::ExecuteWithNulls( + inputs, result, args.size(), [&](int res, ValidityMask &mask, idx_t idx) { + int64_t out; + H3Error err = getNumCells(res, &out); + if (err) { + mask.SetInvalid(idx); + return int64_t(0); + } + return out; + }); } -static void GetRes0CellsFunction(DataChunk &args, ExpressionState &state, Vector &result) { - auto result_data = FlatVector::GetData(result); - - int sz = res0CellCount(); - - for (idx_t i = 0; i < args.size(); i++) { - result_data[i].offset = ListVector::GetListSize(result); - - std::vector out(sz); - H3Error err1 = getRes0Cells(out.data()); - if (err1) { - // This should be unreachable - result.SetValue(i, Value(LogicalType::SQLNULL)); - } else { - int64_t actual = 0; - for (auto val : out) { - if (val != H3_NULL) { - ListVector::PushBack(result, Value::UBIGINT(val)); - actual++; - } - } - // actual should always be 122 - - result_data[i].length = actual; - } - } - result.Verify(args.size()); - result.SetVectorType(VectorType::CONSTANT_VECTOR); +static void GetRes0CellsFunction(DataChunk &args, ExpressionState &state, + Vector &result) { + auto result_data = FlatVector::GetData(result); + + int sz = res0CellCount(); + + for (idx_t i = 0; i < args.size(); i++) { + result_data[i].offset = ListVector::GetListSize(result); + + std::vector out(sz); + H3Error err1 = getRes0Cells(out.data()); + if (err1) { + // This should be unreachable + result.SetValue(i, Value(LogicalType::SQLNULL)); + } else { + int64_t actual = 0; + for (auto val : out) { + if (val != H3_NULL) { + ListVector::PushBack(result, Value::UBIGINT(val)); + actual++; + } + } + // actual should always be 122 + + result_data[i].length = actual; + } + } + result.Verify(args.size()); + result.SetVectorType(VectorType::CONSTANT_VECTOR); } -static void GetPentagonsFunction(DataChunk &args, ExpressionState &state, Vector &result) { - auto result_data = FlatVector::GetData(result); - - int sz = pentagonCount(); - - for (idx_t i = 0; i < args.size(); i++) { - result_data[i].offset = ListVector::GetListSize(result); - - int32_t res = args.GetValue(0, i).DefaultCastAs(LogicalType::INTEGER).GetValue(); - - std::vector out(sz); - H3Error err1 = getPentagons(res, out.data()); - if (err1) { - result.SetValue(i, Value(LogicalType::SQLNULL)); - } else { - int64_t actual = 0; - for (auto val : out) { - if (val != H3_NULL) { - ListVector::PushBack(result, Value::UBIGINT(val)); - actual++; - } - } - // actual should always be 12 - - result_data[i].length = actual; - } - } - result.Verify(args.size()); +static void GetPentagonsFunction(DataChunk &args, ExpressionState &state, + Vector &result) { + auto result_data = FlatVector::GetData(result); + + int sz = pentagonCount(); + + for (idx_t i = 0; i < args.size(); i++) { + result_data[i].offset = ListVector::GetListSize(result); + + int32_t res = args.GetValue(0, i) + .DefaultCastAs(LogicalType::INTEGER) + .GetValue(); + + std::vector out(sz); + H3Error err1 = getPentagons(res, out.data()); + if (err1) { + result.SetValue(i, Value(LogicalType::SQLNULL)); + } else { + int64_t actual = 0; + for (auto val : out) { + if (val != H3_NULL) { + ListVector::PushBack(result, Value::UBIGINT(val)); + actual++; + } + } + // actual should always be 12 + + result_data[i].length = actual; + } + } + result.Verify(args.size()); } -static void GreatCircleDistanceFunction(DataChunk &args, ExpressionState &state, Vector &result) { - auto result_data = FlatVector::GetData(result); - - UnifiedVectorFormat unitData; - - args.data[4].ToUnifiedFormat(args.size(), unitData); - - for (idx_t i = 0; i < args.size(); i++) { - double dist = 0.0; - bool isValid = true; - - if (unitData.validity.RowIsValid(i)) { - double lat0 = args.GetValue(0, i).DefaultCastAs(LogicalType::DOUBLE).GetValue(); - double lng0 = args.GetValue(1, i).DefaultCastAs(LogicalType::DOUBLE).GetValue(); - double lat1 = args.GetValue(2, i).DefaultCastAs(LogicalType::DOUBLE).GetValue(); - double lng1 = args.GetValue(3, i).DefaultCastAs(LogicalType::DOUBLE).GetValue(); - string_t unit = args.GetValue(4, i).ToString(); - - LatLng latLng0 = {.lat = lat0, .lng = lng0}; - LatLng latLng1 = {.lat = lat1, .lng = lng1}; - - if (unit == "rads") { - dist = greatCircleDistanceRads(&latLng0, &latLng1); - } else if (unit == "km") { - dist = greatCircleDistanceKm(&latLng0, &latLng1); - } else if (unit == "m") { - dist = greatCircleDistanceM(&latLng0, &latLng1); - } else { - isValid = false; - } - } else { - isValid = false; - } - - if (isValid) { - result.SetValue(i, Value(dist)); - } else { - result.SetValue(i, Value(LogicalType::SQLNULL)); - } - } +static void GreatCircleDistanceFunction(DataChunk &args, ExpressionState &state, + Vector &result) { + auto result_data = FlatVector::GetData(result); + + UnifiedVectorFormat unitData; + + args.data[4].ToUnifiedFormat(args.size(), unitData); + + for (idx_t i = 0; i < args.size(); i++) { + double dist = 0.0; + bool isValid = true; + + if (unitData.validity.RowIsValid(i)) { + double lat0 = args.GetValue(0, i) + .DefaultCastAs(LogicalType::DOUBLE) + .GetValue(); + double lng0 = args.GetValue(1, i) + .DefaultCastAs(LogicalType::DOUBLE) + .GetValue(); + double lat1 = args.GetValue(2, i) + .DefaultCastAs(LogicalType::DOUBLE) + .GetValue(); + double lng1 = args.GetValue(3, i) + .DefaultCastAs(LogicalType::DOUBLE) + .GetValue(); + string_t unit = args.GetValue(4, i).ToString(); + + LatLng latLng0 = {.lat = lat0, .lng = lng0}; + LatLng latLng1 = {.lat = lat1, .lng = lng1}; + + if (unit == "rads") { + dist = greatCircleDistanceRads(&latLng0, &latLng1); + } else if (unit == "km") { + dist = greatCircleDistanceKm(&latLng0, &latLng1); + } else if (unit == "m") { + dist = greatCircleDistanceM(&latLng0, &latLng1); + } else { + isValid = false; + } + } else { + isValid = false; + } + + if (isValid) { + result.SetValue(i, Value(dist)); + } else { + result.SetValue(i, Value(LogicalType::SQLNULL)); + } + } } CreateScalarFunctionInfo H3Functions::GetGetHexagonAreaAvgFunction() { - return CreateScalarFunctionInfo(ScalarFunction("h3_get_hexagon_area_avg", - {LogicalType::INTEGER, LogicalType::VARCHAR}, LogicalType::DOUBLE, - GetHexagonAreaAvgFunction)); + return CreateScalarFunctionInfo(ScalarFunction( + "h3_get_hexagon_area_avg", {LogicalType::INTEGER, LogicalType::VARCHAR}, + LogicalType::DOUBLE, GetHexagonAreaAvgFunction)); } CreateScalarFunctionInfo H3Functions::GetCellAreaFunction() { - ScalarFunctionSet funcs("h3_cell_area"); - funcs.AddFunction( - ScalarFunction({LogicalType::VARCHAR, LogicalType::VARCHAR}, LogicalType::DOUBLE, CellAreaVarcharFunction)); - funcs.AddFunction( - ScalarFunction({LogicalType::UBIGINT, LogicalType::VARCHAR}, LogicalType::DOUBLE, CellAreaFunction)); - return CreateScalarFunctionInfo(funcs); + ScalarFunctionSet funcs("h3_cell_area"); + funcs.AddFunction(ScalarFunction({LogicalType::VARCHAR, LogicalType::VARCHAR}, + LogicalType::DOUBLE, + CellAreaVarcharFunction)); + funcs.AddFunction(ScalarFunction({LogicalType::UBIGINT, LogicalType::VARCHAR}, + LogicalType::DOUBLE, CellAreaFunction)); + return CreateScalarFunctionInfo(funcs); } CreateScalarFunctionInfo H3Functions::GetGetHexagonEdgeLengthAvgFunction() { - return CreateScalarFunctionInfo(ScalarFunction("h3_get_hexagon_edge_length_avg", - {LogicalType::INTEGER, LogicalType::VARCHAR}, LogicalType::DOUBLE, - GetHexagonEdgeLengthAvgFunction)); + return CreateScalarFunctionInfo( + ScalarFunction("h3_get_hexagon_edge_length_avg", + {LogicalType::INTEGER, LogicalType::VARCHAR}, + LogicalType::DOUBLE, GetHexagonEdgeLengthAvgFunction)); } CreateScalarFunctionInfo H3Functions::GetEdgeLengthFunction() { - ScalarFunctionSet funcs("h3_edge_length"); - funcs.AddFunction( - ScalarFunction({LogicalType::VARCHAR, LogicalType::VARCHAR}, LogicalType::DOUBLE, EdgeLengthVarcharFunction)); - funcs.AddFunction( - ScalarFunction({LogicalType::UBIGINT, LogicalType::VARCHAR}, LogicalType::DOUBLE, EdgeLengthFunction)); - return CreateScalarFunctionInfo(funcs); + ScalarFunctionSet funcs("h3_edge_length"); + funcs.AddFunction(ScalarFunction({LogicalType::VARCHAR, LogicalType::VARCHAR}, + LogicalType::DOUBLE, + EdgeLengthVarcharFunction)); + funcs.AddFunction(ScalarFunction({LogicalType::UBIGINT, LogicalType::VARCHAR}, + LogicalType::DOUBLE, EdgeLengthFunction)); + return CreateScalarFunctionInfo(funcs); } CreateScalarFunctionInfo H3Functions::GetGetNumCellsFunction() { - return CreateScalarFunctionInfo( - ScalarFunction("h3_get_num_cells", {LogicalType::INTEGER}, LogicalType::BIGINT, GetNumCellsFunction)); + return CreateScalarFunctionInfo( + ScalarFunction("h3_get_num_cells", {LogicalType::INTEGER}, + LogicalType::BIGINT, GetNumCellsFunction)); } CreateScalarFunctionInfo H3Functions::GetGetRes0CellsFunction() { - return CreateScalarFunctionInfo( - ScalarFunction("h3_get_res0_cells", {}, LogicalType::LIST(LogicalType::UBIGINT), GetRes0CellsFunction)); + return CreateScalarFunctionInfo(ScalarFunction( + "h3_get_res0_cells", {}, LogicalType::LIST(LogicalType::UBIGINT), + GetRes0CellsFunction)); } CreateScalarFunctionInfo H3Functions::GetGetPentagonsFunction() { - return CreateScalarFunctionInfo(ScalarFunction("h3_get_pentagons", {LogicalType::INTEGER}, - LogicalType::LIST(LogicalType::UBIGINT), GetPentagonsFunction)); + return CreateScalarFunctionInfo(ScalarFunction( + "h3_get_pentagons", {LogicalType::INTEGER}, + LogicalType::LIST(LogicalType::UBIGINT), GetPentagonsFunction)); } CreateScalarFunctionInfo H3Functions::GetGreatCircleDistanceFunction() { - return CreateScalarFunctionInfo(ScalarFunction( - "h3_great_circle_distance", - {LogicalType::DOUBLE, LogicalType::DOUBLE, LogicalType::DOUBLE, LogicalType::DOUBLE, LogicalType::VARCHAR}, - LogicalType::DOUBLE, GreatCircleDistanceFunction)); + return CreateScalarFunctionInfo(ScalarFunction( + "h3_great_circle_distance", + {LogicalType::DOUBLE, LogicalType::DOUBLE, LogicalType::DOUBLE, + LogicalType::DOUBLE, LogicalType::VARCHAR}, + LogicalType::DOUBLE, GreatCircleDistanceFunction)); } } // namespace duckdb diff --git a/src/h3_regions.cpp b/src/h3_regions.cpp index 746c491..62f195f 100644 --- a/src/h3_regions.cpp +++ b/src/h3_regions.cpp @@ -6,276 +6,293 @@ namespace duckdb { static const std::string POLYGON = "POLYGON"; static const std::string EMPTY = "EMPTY"; -// TODO: For convenience, 0 is returned instead of throwing. However, this may actually be interpreted by -// cellsToMultiPolygon as the index referring to base cell 0. +// TODO: For convenience, 0 is returned instead of throwing. However, this may +// actually be interpreted by cellsToMultiPolygon as the index referring to base +// cell 0. struct CellsToMultiPolygonWktInputOperator { - static H3Index Get(const Value &value) { - if (value.IsNull()) { - return 0; - } else { - return value.GetValue(); - } - } + static H3Index Get(const Value &value) { + if (value.IsNull()) { + return 0; + } else { + return value.GetValue(); + } + } }; struct CellsToMultiPolygonWktVarcharInputOperator { - static H3Index Get(const Value &value) { - string str = value.GetValue(); - H3Index cell; - H3Error err = stringToH3(str.c_str(), &cell); - if (err) { - return 0; - } else { - return cell; - } - } + static H3Index Get(const Value &value) { + string str = value.GetValue(); + H3Index cell; + H3Error err = stringToH3(str.c_str(), &cell); + if (err) { + return 0; + } else { + return cell; + } + } }; template -static void CellsToMultiPolygonWktFunction(DataChunk &args, ExpressionState &state, Vector &result) { - D_ASSERT(args.ColumnCount() == 1); - auto count = args.size(); - - Vector &lhs = args.data[0]; - if (lhs.GetType().id() == LogicalTypeId::SQLNULL) { - result.Reference(lhs); - return; - } - - UnifiedVectorFormat lhs_data; - lhs.ToUnifiedFormat(count, lhs_data); - - auto list_entries = UnifiedVectorFormat::GetData(lhs_data); - - result.SetVectorType(VectorType::FLAT_VECTOR); - auto result_entries = FlatVector::GetData(result); - auto &result_validity = FlatVector::Validity(result); - - idx_t offset = 0; - for (idx_t i = 0; i < count; i++) { - result_entries[i].offset = offset; - result_entries[i].length = 0; - auto list_index = lhs_data.sel->get_index(i); - - if (!lhs_data.validity.RowIsValid(list_index)) { - result_validity.SetInvalid(i); - continue; - } - - const auto &list_entry = list_entries[list_index]; - - const auto lvalue = lhs.GetValue(list_entry.offset).DefaultCastAs(LogicalType::LIST(InputType)); - - auto &list_children = ListValue::GetChildren(lvalue); - - size_t ii = 0; - auto input_set = new H3Index[list_children.size()]; - for (const auto &child : list_children) { - input_set[ii] = InputOperator::Get(child); - ii++; - } - LinkedGeoPolygon first_lgp; - H3Error err = cellsToLinkedMultiPolygon(input_set, list_children.size(), &first_lgp); - - if (err) { - result_validity.SetInvalid(i); - } else { - std::string str = "MULTIPOLYGON "; - - if (first_lgp.first) { - str += "("; - std::string lgp_sep = ""; - LinkedGeoPolygon *lgp = &first_lgp; - while (lgp) { - LinkedGeoLoop *loop = lgp->first; - std::string loop_sep = ""; - str += lgp_sep + "("; - while (loop) { - LinkedLatLng *lat_lng = loop->first; - std::string lat_lng_sep = ""; - str += loop_sep + "("; - while (lat_lng) { - str += StringUtil::Format("%s%f %f", lat_lng_sep, radsToDegs(lat_lng->vertex.lng), - radsToDegs(lat_lng->vertex.lat)); - - lat_lng_sep = ", "; - lat_lng = lat_lng->next; - } - str += ")"; - loop_sep = ", "; - loop = loop->next; - } - str += ")"; - lgp_sep = ", "; - lgp = lgp->next; - } - str += ")"; - } else { - str += "EMPTY"; - } - - string_t strAsStr = string_t(strdup(str.c_str()), str.size()); - result.SetValue(i, StringVector::AddString(result, strAsStr)); - - destroyLinkedMultiPolygon(&first_lgp); - } - } - - result.Verify(args.size()); - - if (lhs.GetVectorType() == VectorType::CONSTANT_VECTOR) { - result.SetVectorType(VectorType::CONSTANT_VECTOR); - } +static void CellsToMultiPolygonWktFunction(DataChunk &args, + ExpressionState &state, + Vector &result) { + D_ASSERT(args.ColumnCount() == 1); + auto count = args.size(); + + Vector &lhs = args.data[0]; + if (lhs.GetType().id() == LogicalTypeId::SQLNULL) { + result.Reference(lhs); + return; + } + + UnifiedVectorFormat lhs_data; + lhs.ToUnifiedFormat(count, lhs_data); + + auto list_entries = UnifiedVectorFormat::GetData(lhs_data); + + result.SetVectorType(VectorType::FLAT_VECTOR); + auto result_entries = FlatVector::GetData(result); + auto &result_validity = FlatVector::Validity(result); + + idx_t offset = 0; + for (idx_t i = 0; i < count; i++) { + result_entries[i].offset = offset; + result_entries[i].length = 0; + auto list_index = lhs_data.sel->get_index(i); + + if (!lhs_data.validity.RowIsValid(list_index)) { + result_validity.SetInvalid(i); + continue; + } + + const auto &list_entry = list_entries[list_index]; + + const auto lvalue = lhs.GetValue(list_entry.offset) + .DefaultCastAs(LogicalType::LIST(InputType)); + + auto &list_children = ListValue::GetChildren(lvalue); + + size_t ii = 0; + auto input_set = new H3Index[list_children.size()]; + for (const auto &child : list_children) { + input_set[ii] = InputOperator::Get(child); + ii++; + } + LinkedGeoPolygon first_lgp; + H3Error err = + cellsToLinkedMultiPolygon(input_set, list_children.size(), &first_lgp); + + if (err) { + result_validity.SetInvalid(i); + } else { + std::string str = "MULTIPOLYGON "; + + if (first_lgp.first) { + str += "("; + std::string lgp_sep = ""; + LinkedGeoPolygon *lgp = &first_lgp; + while (lgp) { + LinkedGeoLoop *loop = lgp->first; + std::string loop_sep = ""; + str += lgp_sep + "("; + while (loop) { + LinkedLatLng *lat_lng = loop->first; + std::string lat_lng_sep = ""; + str += loop_sep + "("; + while (lat_lng) { + str += StringUtil::Format("%s%f %f", lat_lng_sep, + radsToDegs(lat_lng->vertex.lng), + radsToDegs(lat_lng->vertex.lat)); + + lat_lng_sep = ", "; + lat_lng = lat_lng->next; + } + str += ")"; + loop_sep = ", "; + loop = loop->next; + } + str += ")"; + lgp_sep = ", "; + lgp = lgp->next; + } + str += ")"; + } else { + str += "EMPTY"; + } + + string_t strAsStr = string_t(strdup(str.c_str()), str.size()); + result.SetValue(i, StringVector::AddString(result, strAsStr)); + + destroyLinkedMultiPolygon(&first_lgp); + } + } + + result.Verify(args.size()); + + if (lhs.GetVectorType() == VectorType::CONSTANT_VECTOR) { + result.SetVectorType(VectorType::CONSTANT_VECTOR); + } } static size_t whitespace(const std::string &str, size_t offset) { - while (str[offset] == ' ') { - offset++; - } - return offset; + while (str[offset] == ' ') { + offset++; + } + return offset; } static size_t readNumber(const std::string &str, size_t offset, double &num) { - size_t start = offset; - while (str[offset] != ' ' && str[offset] != ')' && str[offset] != ',') { - offset++; - } - std::string part = str.substr(start, offset - start); - - try { - num = std::stod(part); - return offset; - } catch (std::invalid_argument const &ex) { - throw InvalidInputException(StringUtil::Format("Invalid number around %lu, %lu", start, offset)); - } + size_t start = offset; + while (str[offset] != ' ' && str[offset] != ')' && str[offset] != ',') { + offset++; + } + std::string part = str.substr(start, offset - start); + + try { + num = std::stod(part); + return offset; + } catch (std::invalid_argument const &ex) { + throw InvalidInputException( + StringUtil::Format("Invalid number around %lu, %lu", start, offset)); + } } -static size_t readGeoLoop(const std::string &str, size_t offset, duckdb::shared_ptr> verts, +static size_t readGeoLoop(const std::string &str, size_t offset, + duckdb::shared_ptr> verts, GeoLoop &loop) { - if (str[offset] != '(') { - throw InvalidInputException(StringUtil::Format("Expected ( at pos %lu", offset)); - } - - offset++; - offset = whitespace(str, offset); - - while (str[offset] != ')') { - double x, y; - offset = readNumber(str, offset, x); - offset = whitespace(str, offset); - offset = readNumber(str, offset, y); - offset = whitespace(str, offset); - verts->push_back({.lat = degsToRads(y), .lng = degsToRads(x)}); - - if (str[offset] == ',') { - offset++; - offset = whitespace(str, offset); - } - } - // Consume the ) - offset++; - - loop.numVerts = verts->size(); - loop.verts = verts->data(); - - offset = whitespace(str, offset); - return offset; + if (str[offset] != '(') { + throw InvalidInputException( + StringUtil::Format("Expected ( at pos %lu", offset)); + } + + offset++; + offset = whitespace(str, offset); + + while (str[offset] != ')') { + double x, y; + offset = readNumber(str, offset, x); + offset = whitespace(str, offset); + offset = readNumber(str, offset, y); + offset = whitespace(str, offset); + verts->push_back({.lat = degsToRads(y), .lng = degsToRads(x)}); + + if (str[offset] == ',') { + offset++; + offset = whitespace(str, offset); + } + } + // Consume the ) + offset++; + + loop.numVerts = verts->size(); + loop.verts = verts->data(); + + offset = whitespace(str, offset); + return offset; } -static void PolygonWktToCellsFunction(DataChunk &args, ExpressionState &state, Vector &result) { - // TODO: Note this function is not fully noexcept -- some invalid WKT strings will throw, others - // will return empty lists. - BinaryExecutor::Execute( - args.data[0], args.data[1], result, args.size(), [&](string_t input, int res) { - GeoPolygon polygon; - int32_t flags = 0; - - std::string str = input.GetString(); - - uint64_t offset = ListVector::GetListSize(result); - if (str.rfind(POLYGON, 0) != 0) { - return list_entry_t(offset, 0); - } - - size_t strIndex = POLYGON.length(); - strIndex = whitespace(str, strIndex); - - if (str.rfind(EMPTY, strIndex) == strIndex) { - return list_entry_t(offset, 0); - } - - if (str[strIndex] == '(') { - strIndex++; - strIndex = whitespace(str, strIndex); - - duckdb::shared_ptr> outerVerts = duckdb::make_shared>(); - strIndex = readGeoLoop(str, strIndex, outerVerts, polygon.geoloop); - - std::vector holes; - std::vector>> holesVerts; - while (strIndex < str.length() && str[strIndex] == ',') { - strIndex++; - strIndex = whitespace(str, strIndex); - if (str[strIndex] == '(') { - GeoLoop hole; - duckdb::shared_ptr> verts = duckdb::make_shared>(); - strIndex = readGeoLoop(str, strIndex, verts, hole); - holes.push_back(hole); - holesVerts.push_back(verts); - } else { - throw InvalidInputException( - StringUtil::Format("Invalid WKT: expected a hole loop '(' after ',' at pos %lu", strIndex)); - } - } - if (str[strIndex] != ')') { - throw InvalidInputException( - StringUtil::Format("Invalid WKT: expected a hole loop ',' or final ')' at pos %lu", strIndex)); - } - - polygon.numHoles = holes.size(); - polygon.holes = holes.data(); - - int64_t numCells = 0; - H3Error err = maxPolygonToCellsSize(&polygon, res, flags, &numCells); - if (err) { - return list_entry_t(offset, 0); - } else { - std::vector out(numCells); - H3Error err2 = polygonToCells(&polygon, res, flags, out.data()); - if (err2) { - return list_entry_t(offset, 0); - } else { - uint64_t actual = 0; - for (H3Index outCell : out) { - if (outCell != H3_NULL) { - ListVector::PushBack(result, Value::UBIGINT(outCell)); - actual++; - } - } - return list_entry_t(offset, actual); - } - } - } - return list_entry_t(offset, 0); - }); +static void PolygonWktToCellsFunction(DataChunk &args, ExpressionState &state, + Vector &result) { + // TODO: Note this function is not fully noexcept -- some invalid WKT strings + // will throw, others will return empty lists. + BinaryExecutor::Execute( + args.data[0], args.data[1], result, args.size(), + [&](string_t input, int res) { + GeoPolygon polygon; + int32_t flags = 0; + + std::string str = input.GetString(); + + uint64_t offset = ListVector::GetListSize(result); + if (str.rfind(POLYGON, 0) != 0) { + return list_entry_t(offset, 0); + } + + size_t strIndex = POLYGON.length(); + strIndex = whitespace(str, strIndex); + + if (str.rfind(EMPTY, strIndex) == strIndex) { + return list_entry_t(offset, 0); + } + + if (str[strIndex] == '(') { + strIndex++; + strIndex = whitespace(str, strIndex); + + duckdb::shared_ptr> outerVerts = + duckdb::make_shared>(); + strIndex = readGeoLoop(str, strIndex, outerVerts, polygon.geoloop); + + std::vector holes; + std::vector>> holesVerts; + while (strIndex < str.length() && str[strIndex] == ',') { + strIndex++; + strIndex = whitespace(str, strIndex); + if (str[strIndex] == '(') { + GeoLoop hole; + duckdb::shared_ptr> verts = + duckdb::make_shared>(); + strIndex = readGeoLoop(str, strIndex, verts, hole); + holes.push_back(hole); + holesVerts.push_back(verts); + } else { + throw InvalidInputException(StringUtil::Format( + "Invalid WKT: expected a hole loop '(' after ',' at pos %lu", + strIndex)); + } + } + if (str[strIndex] != ')') { + throw InvalidInputException(StringUtil::Format( + "Invalid WKT: expected a hole loop ',' or final ')' at pos %lu", + strIndex)); + } + + polygon.numHoles = holes.size(); + polygon.holes = holes.data(); + + int64_t numCells = 0; + H3Error err = maxPolygonToCellsSize(&polygon, res, flags, &numCells); + if (err) { + return list_entry_t(offset, 0); + } else { + std::vector out(numCells); + H3Error err2 = polygonToCells(&polygon, res, flags, out.data()); + if (err2) { + return list_entry_t(offset, 0); + } else { + uint64_t actual = 0; + for (H3Index outCell : out) { + if (outCell != H3_NULL) { + ListVector::PushBack(result, Value::UBIGINT(outCell)); + actual++; + } + } + return list_entry_t(offset, actual); + } + } + } + return list_entry_t(offset, 0); + }); } CreateScalarFunctionInfo H3Functions::GetCellsToMultiPolygonWktFunction() { - ScalarFunctionSet funcs("h3_cells_to_multi_polygon_wkt"); - funcs.AddFunction(ScalarFunction( - {LogicalType::LIST(LogicalType::VARCHAR)}, LogicalType::VARCHAR, - CellsToMultiPolygonWktFunction)); - funcs.AddFunction( - ScalarFunction({LogicalType::LIST(LogicalType::UBIGINT)}, LogicalType::VARCHAR, - CellsToMultiPolygonWktFunction)); - return CreateScalarFunctionInfo(funcs); + ScalarFunctionSet funcs("h3_cells_to_multi_polygon_wkt"); + funcs.AddFunction(ScalarFunction( + {LogicalType::LIST(LogicalType::VARCHAR)}, LogicalType::VARCHAR, + CellsToMultiPolygonWktFunction< + LogicalType::VARCHAR, CellsToMultiPolygonWktVarcharInputOperator>)); + funcs.AddFunction(ScalarFunction( + {LogicalType::LIST(LogicalType::UBIGINT)}, LogicalType::VARCHAR, + CellsToMultiPolygonWktFunction)); + return CreateScalarFunctionInfo(funcs); } CreateScalarFunctionInfo H3Functions::GetPolygonWktToCellsFunction() { - // TODO: Expose flags - return CreateScalarFunctionInfo(ScalarFunction("h3_polygon_wkt_to_cells", - {LogicalType::VARCHAR, LogicalType::INTEGER}, - LogicalType::LIST(LogicalType::UBIGINT), PolygonWktToCellsFunction)); + // TODO: Expose flags + return CreateScalarFunctionInfo(ScalarFunction( + "h3_polygon_wkt_to_cells", {LogicalType::VARCHAR, LogicalType::INTEGER}, + LogicalType::LIST(LogicalType::UBIGINT), PolygonWktToCellsFunction)); } } // namespace duckdb diff --git a/src/h3_traversal.cpp b/src/h3_traversal.cpp index fe91e28..b5b0d84 100644 --- a/src/h3_traversal.cpp +++ b/src/h3_traversal.cpp @@ -4,288 +4,329 @@ namespace duckdb { struct GridDiskOperator { - static H3Error fn(H3Index origin, int32_t k, H3Index *out) { - return gridDisk(origin, k, out); - } + static H3Error fn(H3Index origin, int32_t k, H3Index *out) { + return gridDisk(origin, k, out); + } }; struct GridDiskUnsafeOperator { - static H3Error fn(H3Index origin, int32_t k, H3Index *out) { - return gridDiskUnsafe(origin, k, out); - } + static H3Error fn(H3Index origin, int32_t k, H3Index *out) { + return gridDiskUnsafe(origin, k, out); + } }; template -static void GridDiskTmplFunction(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); - - uint64_t origin = args.GetValue(0, i).DefaultCastAs(LogicalType::UBIGINT).GetValue(); - int32_t k = args.GetValue(1, i).DefaultCastAs(LogicalType::INTEGER).GetValue(); - 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) { - ListVector::PushBack(result, Value::UBIGINT(val)); - actual++; - } - } - - result_data[i].length = actual; - } - } - } - result.Verify(args.size()); +static void GridDiskTmplFunction(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); + + uint64_t origin = args.GetValue(0, i) + .DefaultCastAs(LogicalType::UBIGINT) + .GetValue(); + int32_t k = args.GetValue(1, i) + .DefaultCastAs(LogicalType::INTEGER) + .GetValue(); + 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) { + ListVector::PushBack(result, Value::UBIGINT(val)); + 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) { - return gridDiskDistances(origin, k, out, distancesOut); - } + static H3Error fn(H3Index origin, int32_t k, H3Index *out, + int32_t *distancesOut) { + return gridDiskDistances(origin, k, out, distancesOut); + } }; struct GridDiskDistancesSafeOperator { - static H3Error fn(H3Index origin, int32_t k, H3Index *out, int32_t *distancesOut) { - return gridDiskDistancesSafe(origin, k, out, distancesOut); - } + static H3Error fn(H3Index origin, int32_t k, H3Index *out, + int32_t *distancesOut) { + return gridDiskDistancesSafe(origin, k, out, distancesOut); + } }; struct GridDiskDistancesUnsafeOperator { - static H3Error fn(H3Index origin, int32_t k, H3Index *out, int32_t *distancesOut) { - return gridDiskDistancesUnsafe(origin, k, out, distancesOut); - } + static H3Error fn(H3Index origin, int32_t k, H3Index *out, + int32_t *distancesOut) { + return gridDiskDistancesUnsafe(origin, k, out, distancesOut); + } }; template -static void GridDiskDistancesTmplFunction(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); - - uint64_t origin = args.GetValue(0, i).DefaultCastAs(LogicalType::UBIGINT).GetValue(); - int32_t k = args.GetValue(1, i).DefaultCastAs(LogicalType::INTEGER).GetValue(); - 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) { - results[distancesOut[j]].push_back(Value::UBIGINT(out[j])); - } - } - - int64_t actual = 0; - for (auto val : results) { - ListVector::PushBack(result, Value::LIST(LogicalType::UBIGINT, val)); - actual++; - } - - result_data[i].length = actual; - } - } - } - result.Verify(args.size()); +static void GridDiskDistancesTmplFunction(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); + + uint64_t origin = args.GetValue(0, i) + .DefaultCastAs(LogicalType::UBIGINT) + .GetValue(); + int32_t k = args.GetValue(1, i) + .DefaultCastAs(LogicalType::INTEGER) + .GetValue(); + 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) { + results[distancesOut[j]].push_back(Value::UBIGINT(out[j])); + } + } + + int64_t actual = 0; + for (auto val : results) { + ListVector::PushBack(result, Value::LIST(LogicalType::UBIGINT, 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); - for (idx_t i = 0; i < args.size(); i++) { - result_data[i].offset = ListVector::GetListSize(result); - - uint64_t origin = args.GetValue(0, i).DefaultCastAs(LogicalType::UBIGINT).GetValue(); - int32_t k = args.GetValue(1, i).DefaultCastAs(LogicalType::INTEGER).GetValue(); - int64_t sz = k == 0 ? 1 : 6 * k; - std::vector out(sz); - H3Error err = gridRingUnsafe(origin, k, out.data()); - if (err) { - result.SetValue(i, Value(LogicalType::SQLNULL)); - } else { - int64_t actual = 0; - for (auto val : out) { - if (val != H3_NULL) { - ListVector::PushBack(result, Value::UBIGINT(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); + for (idx_t i = 0; i < args.size(); i++) { + result_data[i].offset = ListVector::GetListSize(result); + + uint64_t origin = args.GetValue(0, i) + .DefaultCastAs(LogicalType::UBIGINT) + .GetValue(); + int32_t k = args.GetValue(1, i) + .DefaultCastAs(LogicalType::INTEGER) + .GetValue(); + int64_t sz = k == 0 ? 1 : 6 * k; + std::vector out(sz); + H3Error err = gridRingUnsafe(origin, k, out.data()); + if (err) { + result.SetValue(i, Value(LogicalType::SQLNULL)); + } else { + int64_t actual = 0; + for (auto val : out) { + if (val != H3_NULL) { + ListVector::PushBack(result, Value::UBIGINT(val)); + 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); - for (idx_t i = 0; i < args.size(); i++) { - result_data[i].offset = ListVector::GetListSize(result); - - uint64_t origin = args.GetValue(0, i).DefaultCastAs(LogicalType::UBIGINT).GetValue(); - uint64_t destination = args.GetValue(1, i).DefaultCastAs(LogicalType::UBIGINT).GetValue(); - - int64_t sz; - H3Error err1 = gridPathCellsSize(origin, destination, &sz); - if (err1) { - result.SetValue(i, Value(LogicalType::SQLNULL)); - } else { - std::vector out(sz); - H3Error err2 = gridPathCells(origin, destination, out.data()); - if (err2) { - result.SetValue(i, Value(LogicalType::SQLNULL)); - } else { - int64_t actual = 0; - for (auto val : out) { - if (val != H3_NULL) { - ListVector::PushBack(result, Value::UBIGINT(val)); - 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); + for (idx_t i = 0; i < args.size(); i++) { + result_data[i].offset = ListVector::GetListSize(result); + + uint64_t origin = args.GetValue(0, i) + .DefaultCastAs(LogicalType::UBIGINT) + .GetValue(); + uint64_t destination = args.GetValue(1, i) + .DefaultCastAs(LogicalType::UBIGINT) + .GetValue(); + + int64_t sz; + H3Error err1 = gridPathCellsSize(origin, destination, &sz); + if (err1) { + result.SetValue(i, Value(LogicalType::SQLNULL)); + } else { + std::vector out(sz); + H3Error err2 = gridPathCells(origin, destination, out.data()); + if (err2) { + result.SetValue(i, Value(LogicalType::SQLNULL)); + } else { + int64_t actual = 0; + for (auto val : out) { + if (val != H3_NULL) { + ListVector::PushBack(result, Value::UBIGINT(val)); + actual++; + } + } + + result_data[i].length = actual; + } + } + } + result.Verify(args.size()); } -static void GridDistanceFunction(DataChunk &args, ExpressionState &state, Vector &result) { - auto &inputs = args.data[0]; - auto &inputs2 = args.data[1]; - BinaryExecutor::ExecuteWithNulls( - inputs, inputs2, result, args.size(), - [&](uint64_t origin, uint64_t destination, ValidityMask &mask, idx_t idx) { - int64_t distance; - H3Error err = gridDistance(origin, destination, &distance); - if (err) { - mask.SetInvalid(idx); - return int64_t(0); - } else { - return distance; - } - }); +static void GridDistanceFunction(DataChunk &args, ExpressionState &state, + Vector &result) { + auto &inputs = args.data[0]; + auto &inputs2 = args.data[1]; + BinaryExecutor::ExecuteWithNulls( + inputs, inputs2, result, args.size(), + [&](uint64_t origin, uint64_t destination, ValidityMask &mask, + idx_t idx) { + 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); - for (idx_t i = 0; i < args.size(); i++) { - result_data[i].offset = ListVector::GetListSize(result); - - uint64_t origin = args.GetValue(0, i).DefaultCastAs(LogicalType::UBIGINT).GetValue(); - uint64_t cell = args.GetValue(1, i).DefaultCastAs(LogicalType::UBIGINT).GetValue(); - uint32_t mode = 0; // TODO: Expose mode to the user when applicable - - CoordIJ out; - H3Error err = cellToLocalIj(origin, cell, mode, &out); - if (err) { - 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 CellToLocalIjFunction(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); + + uint64_t origin = args.GetValue(0, i) + .DefaultCastAs(LogicalType::UBIGINT) + .GetValue(); + uint64_t cell = args.GetValue(1, i) + .DefaultCastAs(LogicalType::UBIGINT) + .GetValue(); + uint32_t mode = 0; // TODO: Expose mode to the user when applicable + + CoordIJ out; + H3Error err = cellToLocalIj(origin, cell, mode, &out); + if (err) { + 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]; - auto &inputs2 = args.data[1]; - auto &inputs3 = args.data[2]; - TernaryExecutor::ExecuteWithNulls( - inputs, inputs2, inputs3, result, args.size(), - [&](H3Index origin, int32_t i, int32_t j, ValidityMask &mask, idx_t idx) { - uint32_t mode = 0; // TODO: Expose mode to the user when applicable - - CoordIJ coordIJ {.i = i, .j = j}; - H3Index out; - H3Error err = localIjToCell(origin, &coordIJ, mode, &out); - if (err) { - mask.SetInvalid(idx); - return H3Index(H3_NULL); - } else { - return out; - } - }); +static void LocalIjToCellFunction(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(), + [&](H3Index origin, int32_t i, int32_t j, ValidityMask &mask, idx_t idx) { + uint32_t mode = 0; // TODO: Expose mode to the user when applicable + + CoordIJ coordIJ{.i = i, .j = j}; + H3Index out; + H3Error err = localIjToCell(origin, &coordIJ, mode, &out); + if (err) { + mask.SetInvalid(idx); + return H3Index(H3_NULL); + } else { + return out; + } + }); } // TODO: gridDisksUnsafe? CreateScalarFunctionInfo H3Functions::GetGridDiskFunction() { - return CreateScalarFunctionInfo(ScalarFunction("h3_grid_disk", {LogicalType::UBIGINT, LogicalType::INTEGER}, - LogicalType::LIST(LogicalType::UBIGINT), - GridDiskTmplFunction)); + return CreateScalarFunctionInfo(ScalarFunction( + "h3_grid_disk", {LogicalType::UBIGINT, LogicalType::INTEGER}, + LogicalType::LIST(LogicalType::UBIGINT), + GridDiskTmplFunction)); } CreateScalarFunctionInfo H3Functions::GetGridDiskDistancesFunction() { - return CreateScalarFunctionInfo(ScalarFunction("h3_grid_disk_distances", - {LogicalType::UBIGINT, LogicalType::INTEGER}, - LogicalType::LIST(LogicalType::LIST(LogicalType::UBIGINT)), - GridDiskDistancesTmplFunction)); + return CreateScalarFunctionInfo(ScalarFunction( + "h3_grid_disk_distances", {LogicalType::UBIGINT, LogicalType::INTEGER}, + LogicalType::LIST(LogicalType::LIST(LogicalType::UBIGINT)), + GridDiskDistancesTmplFunction)); } CreateScalarFunctionInfo H3Functions::GetGridDiskUnsafeFunction() { - return CreateScalarFunctionInfo(ScalarFunction("h3_grid_disk_unsafe", {LogicalType::UBIGINT, LogicalType::INTEGER}, - LogicalType::LIST(LogicalType::UBIGINT), - GridDiskTmplFunction)); + return CreateScalarFunctionInfo(ScalarFunction( + "h3_grid_disk_unsafe", {LogicalType::UBIGINT, LogicalType::INTEGER}, + LogicalType::LIST(LogicalType::UBIGINT), + GridDiskTmplFunction)); } CreateScalarFunctionInfo H3Functions::GetGridDiskDistancesUnsafeFunction() { - return CreateScalarFunctionInfo(ScalarFunction("h3_grid_disk_distances_unsafe", - {LogicalType::UBIGINT, LogicalType::INTEGER}, - LogicalType::LIST(LogicalType::LIST(LogicalType::UBIGINT)), - GridDiskDistancesTmplFunction)); + return CreateScalarFunctionInfo(ScalarFunction( + "h3_grid_disk_distances_unsafe", + {LogicalType::UBIGINT, LogicalType::INTEGER}, + LogicalType::LIST(LogicalType::LIST(LogicalType::UBIGINT)), + GridDiskDistancesTmplFunction)); } CreateScalarFunctionInfo H3Functions::GetGridDiskDistancesSafeFunction() { - return CreateScalarFunctionInfo(ScalarFunction("h3_grid_disk_distances_safe", - {LogicalType::UBIGINT, LogicalType::INTEGER}, - LogicalType::LIST(LogicalType::LIST(LogicalType::UBIGINT)), - GridDiskDistancesTmplFunction)); + return CreateScalarFunctionInfo(ScalarFunction( + "h3_grid_disk_distances_safe", + {LogicalType::UBIGINT, LogicalType::INTEGER}, + LogicalType::LIST(LogicalType::LIST(LogicalType::UBIGINT)), + GridDiskDistancesTmplFunction)); } CreateScalarFunctionInfo H3Functions::GetGridRingUnsafeFunction() { - return CreateScalarFunctionInfo(ScalarFunction("h3_grid_ring_unsafe", {LogicalType::UBIGINT, LogicalType::INTEGER}, - LogicalType::LIST(LogicalType::UBIGINT), GridRingUnsafeFunction)); + return CreateScalarFunctionInfo(ScalarFunction( + "h3_grid_ring_unsafe", {LogicalType::UBIGINT, LogicalType::INTEGER}, + LogicalType::LIST(LogicalType::UBIGINT), GridRingUnsafeFunction)); } CreateScalarFunctionInfo H3Functions::GetGridPathCellsFunction() { - return CreateScalarFunctionInfo(ScalarFunction("h3_grid_path_cells", {LogicalType::UBIGINT, LogicalType::UBIGINT}, - LogicalType::LIST(LogicalType::UBIGINT), GridPathCellsFunction)); + return CreateScalarFunctionInfo(ScalarFunction( + "h3_grid_path_cells", {LogicalType::UBIGINT, LogicalType::UBIGINT}, + LogicalType::LIST(LogicalType::UBIGINT), GridPathCellsFunction)); } CreateScalarFunctionInfo H3Functions::GetGridDistanceFunction() { - return CreateScalarFunctionInfo(ScalarFunction("h3_grid_distance", {LogicalType::UBIGINT, LogicalType::UBIGINT}, - LogicalType::BIGINT, GridDistanceFunction)); + return CreateScalarFunctionInfo(ScalarFunction( + "h3_grid_distance", {LogicalType::UBIGINT, LogicalType::UBIGINT}, + LogicalType::BIGINT, GridDistanceFunction)); } CreateScalarFunctionInfo H3Functions::GetCellToLocalIjFunction() { - return CreateScalarFunctionInfo(ScalarFunction("h3_cell_to_local_ij", {LogicalType::UBIGINT, LogicalType::UBIGINT}, - LogicalType::LIST(LogicalType::INTEGER), CellToLocalIjFunction)); + return CreateScalarFunctionInfo(ScalarFunction( + "h3_cell_to_local_ij", {LogicalType::UBIGINT, LogicalType::UBIGINT}, + LogicalType::LIST(LogicalType::INTEGER), CellToLocalIjFunction)); } CreateScalarFunctionInfo H3Functions::GetLocalIjToCellFunction() { - return CreateScalarFunctionInfo(ScalarFunction("h3_local_ij_to_cell", - {LogicalType::UBIGINT, LogicalType::INTEGER, LogicalType::INTEGER}, - LogicalType::UBIGINT, LocalIjToCellFunction)); + return CreateScalarFunctionInfo(ScalarFunction( + "h3_local_ij_to_cell", + {LogicalType::UBIGINT, LogicalType::INTEGER, LogicalType::INTEGER}, + LogicalType::UBIGINT, LocalIjToCellFunction)); } } // namespace duckdb diff --git a/src/h3_vertex.cpp b/src/h3_vertex.cpp index 63919d6..67a7e9f 100644 --- a/src/h3_vertex.cpp +++ b/src/h3_vertex.cpp @@ -3,153 +3,177 @@ namespace duckdb { -static void CellToVertexFunction(DataChunk &args, ExpressionState &state, Vector &result) { - auto &inputs = args.data[0]; - auto &inputs2 = args.data[1]; - BinaryExecutor::ExecuteWithNulls( - inputs, inputs2, result, args.size(), [&](H3Index cell, int32_t vertexNum, ValidityMask &mask, idx_t idx) { - H3Index vertex; - H3Error err = cellToVertex(cell, vertexNum, &vertex); - if (err) { - mask.SetInvalid(idx); - return H3Index(H3_NULL); - } else { - return vertex; - } - }); +static void CellToVertexFunction(DataChunk &args, ExpressionState &state, + Vector &result) { + auto &inputs = args.data[0]; + auto &inputs2 = args.data[1]; + BinaryExecutor::ExecuteWithNulls( + inputs, inputs2, result, args.size(), + [&](H3Index cell, int32_t vertexNum, ValidityMask &mask, idx_t idx) { + H3Index vertex; + H3Error err = cellToVertex(cell, vertexNum, &vertex); + if (err) { + mask.SetInvalid(idx); + return H3Index(H3_NULL); + } else { + return vertex; + } + }); } -static void CellToVertexesFunction(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; - - uint64_t cell = args.GetValue(0, i).DefaultCastAs(LogicalType::UBIGINT).GetValue(); - - 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 result_val = Value::UBIGINT(val); - ListVector::PushBack(result, result_val); - actual++; - } - } - - result_data[i].length = actual; - } - offset += actual; - } - result.Verify(args.size()); - - if (args.AllConstant()) { - result.SetVectorType(VectorType::CONSTANT_VECTOR); - } +static void CellToVertexesFunction(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; + + uint64_t cell = args.GetValue(0, i) + .DefaultCastAs(LogicalType::UBIGINT) + .GetValue(); + + 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 result_val = Value::UBIGINT(val); + ListVector::PushBack(result, result_val); + 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]; - UnaryExecutor::ExecuteWithNulls(inputs, result, args.size(), - [&](H3Index vertex, ValidityMask &mask, idx_t idx) { - LatLng latLng = {.lat = 0, .lng = 0}; - H3Error err = vertexToLatLng(vertex, &latLng); - if (err) { - mask.SetInvalid(idx); - return .0; - } else { - return radsToDegs(latLng.lat); - } - }); +static void VertexToLatFunction(DataChunk &args, ExpressionState &state, + Vector &result) { + auto &inputs = args.data[0]; + UnaryExecutor::ExecuteWithNulls( + inputs, result, args.size(), + [&](H3Index vertex, ValidityMask &mask, idx_t idx) { + LatLng latLng = {.lat = 0, .lng = 0}; + H3Error err = vertexToLatLng(vertex, &latLng); + if (err) { + mask.SetInvalid(idx); + return .0; + } else { + return radsToDegs(latLng.lat); + } + }); } -static void VertexToLngFunction(DataChunk &args, ExpressionState &state, Vector &result) { - auto &inputs = args.data[0]; - UnaryExecutor::ExecuteWithNulls(inputs, result, args.size(), - [&](H3Index vertex, ValidityMask &mask, idx_t idx) { - LatLng latLng = {.lat = 0, .lng = 0}; - H3Error err = vertexToLatLng(vertex, &latLng); - if (err) { - mask.SetInvalid(idx); - return .0; - } else { - return radsToDegs(latLng.lng); - } - }); +static void VertexToLngFunction(DataChunk &args, ExpressionState &state, + Vector &result) { + auto &inputs = args.data[0]; + UnaryExecutor::ExecuteWithNulls( + inputs, result, args.size(), + [&](H3Index vertex, ValidityMask &mask, idx_t idx) { + LatLng latLng = {.lat = 0, .lng = 0}; + H3Error err = vertexToLatLng(vertex, &latLng); + if (err) { + 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); - for (idx_t i = 0; i < args.size(); i++) { - result_data[i].offset = ListVector::GetListSize(result); - - uint64_t vertex = args.GetValue(0, i).DefaultCastAs(LogicalType::UBIGINT).GetValue(); - LatLng latLng; - H3Error err = vertexToLatLng(vertex, &latLng); - ThrowH3Error(err); - - ListVector::PushBack(result, radsToDegs(latLng.lat)); - ListVector::PushBack(result, radsToDegs(latLng.lng)); - result_data[i].length = 2; - } - result.Verify(args.size()); +static void VertexToLatLngFunction(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); + + uint64_t vertex = args.GetValue(0, i) + .DefaultCastAs(LogicalType::UBIGINT) + .GetValue(); + LatLng latLng; + H3Error err = vertexToLatLng(vertex, &latLng); + ThrowH3Error(err); + + 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) { - auto &inputs = args.data[0]; - UnaryExecutor::Execute(inputs, result, args.size(), [&](string_t input) { - H3Index h; - H3Error err = stringToH3(input.GetString().c_str(), &h); - if (err) { - return false; - } - return bool(isValidVertex(h)); - }); +static void IsValidVertexVarcharFunction(DataChunk &args, + ExpressionState &state, + Vector &result) { + auto &inputs = args.data[0]; + UnaryExecutor::Execute( + inputs, result, args.size(), [&](string_t input) { + H3Index h; + H3Error err = stringToH3(input.GetString().c_str(), &h); + if (err) { + return false; + } + return bool(isValidVertex(h)); + }); } -static void IsValidVertexFunction(DataChunk &args, ExpressionState &state, Vector &result) { - auto &inputs = args.data[0]; - UnaryExecutor::Execute(inputs, result, args.size(), - [&](H3Index input) { return bool(isValidVertex(input)); }); +static void IsValidVertexFunction(DataChunk &args, ExpressionState &state, + Vector &result) { + auto &inputs = args.data[0]; + UnaryExecutor::Execute( + inputs, result, args.size(), + [&](H3Index input) { return bool(isValidVertex(input)); }); } CreateScalarFunctionInfo H3Functions::GetCellToVertexFunction() { - return CreateScalarFunctionInfo(ScalarFunction("h3_cell_to_vertex", {LogicalType::UBIGINT, LogicalType::INTEGER}, - LogicalType::UBIGINT, CellToVertexFunction)); + return CreateScalarFunctionInfo(ScalarFunction( + "h3_cell_to_vertex", {LogicalType::UBIGINT, LogicalType::INTEGER}, + LogicalType::UBIGINT, CellToVertexFunction)); } CreateScalarFunctionInfo H3Functions::GetCellToVertexesFunction() { - return CreateScalarFunctionInfo(ScalarFunction("h3_cell_to_vertexes", {LogicalType::UBIGINT}, - LogicalType::LIST(LogicalType::UBIGINT), CellToVertexesFunction)); + return CreateScalarFunctionInfo(ScalarFunction( + "h3_cell_to_vertexes", {LogicalType::UBIGINT}, + LogicalType::LIST(LogicalType::UBIGINT), CellToVertexesFunction)); } CreateScalarFunctionInfo H3Functions::GetVertexToLatFunction() { - return CreateScalarFunctionInfo( - ScalarFunction("h3_vertex_to_lat", {LogicalType::UBIGINT}, LogicalType::DOUBLE, VertexToLatFunction)); + return CreateScalarFunctionInfo( + ScalarFunction("h3_vertex_to_lat", {LogicalType::UBIGINT}, + LogicalType::DOUBLE, VertexToLatFunction)); } CreateScalarFunctionInfo H3Functions::GetVertexToLngFunction() { - return CreateScalarFunctionInfo( - ScalarFunction("h3_vertex_to_lng", {LogicalType::UBIGINT}, LogicalType::DOUBLE, VertexToLngFunction)); + return CreateScalarFunctionInfo( + ScalarFunction("h3_vertex_to_lng", {LogicalType::UBIGINT}, + LogicalType::DOUBLE, VertexToLngFunction)); } CreateScalarFunctionInfo H3Functions::GetVertexToLatLngFunction() { - return CreateScalarFunctionInfo(ScalarFunction("h3_vertex_to_latlng", {LogicalType::UBIGINT}, - LogicalType::LIST(LogicalType::DOUBLE), VertexToLatLngFunction)); + return CreateScalarFunctionInfo(ScalarFunction( + "h3_vertex_to_latlng", {LogicalType::UBIGINT}, + LogicalType::LIST(LogicalType::DOUBLE), VertexToLatLngFunction)); } CreateScalarFunctionInfo H3Functions::GetIsValidVertexFunctions() { - ScalarFunctionSet funcs("h3_is_valid_vertex"); - funcs.AddFunction(ScalarFunction({LogicalType::VARCHAR}, LogicalType::BOOLEAN, IsValidVertexVarcharFunction)); - funcs.AddFunction(ScalarFunction({LogicalType::UBIGINT}, LogicalType::BOOLEAN, IsValidVertexFunction)); - return CreateScalarFunctionInfo(funcs); + ScalarFunctionSet funcs("h3_is_valid_vertex"); + funcs.AddFunction(ScalarFunction({LogicalType::VARCHAR}, LogicalType::BOOLEAN, + IsValidVertexVarcharFunction)); + funcs.AddFunction(ScalarFunction({LogicalType::UBIGINT}, LogicalType::BOOLEAN, + IsValidVertexFunction)); + return CreateScalarFunctionInfo(funcs); } } // namespace duckdb diff --git a/src/h3ext_extension.cpp b/src/h3ext_extension.cpp index c24b4a7..5c74dca 100644 --- a/src/h3ext_extension.cpp +++ b/src/h3ext_extension.cpp @@ -12,32 +12,30 @@ namespace duckdb { void H3extExtension::Load(DuckDB &db) { - Connection con(db); - con.BeginTransaction(); + Connection con(db); + con.BeginTransaction(); - auto &catalog = Catalog::GetSystemCatalog(*con.context); - for (auto &fun : H3Functions::GetFunctions()) { - catalog.CreateFunction(*con.context, fun); - } + auto &catalog = Catalog::GetSystemCatalog(*con.context); + for (auto &fun : H3Functions::GetFunctions()) { + catalog.CreateFunction(*con.context, fun); + } - con.Commit(); + con.Commit(); } -std::string H3extExtension::Name() { - return "h3ext"; -} +std::string H3extExtension::Name() { return "h3ext"; } } // namespace duckdb extern "C" { DUCKDB_EXTENSION_API void h3ext_init(duckdb::DatabaseInstance &db) { - duckdb::DuckDB db_wrapper(db); - db_wrapper.LoadExtension(); + duckdb::DuckDB db_wrapper(db); + db_wrapper.LoadExtension(); } DUCKDB_EXTENSION_API const char *h3ext_version() { - return duckdb::DuckDB::LibraryVersion(); + return duckdb::DuckDB::LibraryVersion(); } } diff --git a/src/include/h3_functions.hpp b/src/include/h3_functions.hpp index 8959516..e441a6f 100644 --- a/src/include/h3_functions.hpp +++ b/src/include/h3_functions.hpp @@ -14,160 +14,160 @@ namespace duckdb { class H3Functions { public: - static vector GetFunctions() { - vector functions; - - // Indexing - functions.push_back(GetLatLngToCellFunction()); - functions.push_back(GetCellToLatFunction()); - functions.push_back(GetCellToLngFunction()); - functions.push_back(GetCellToLatLngFunction()); - functions.push_back(GetCellToBoundaryWktFunction()); - - // Inspection - functions.push_back(GetGetResolutionFunction()); - functions.push_back(GetGetBaseCellNumberFunction()); - functions.push_back(GetStringToH3Function()); - functions.push_back(GetH3ToStringFunction()); - functions.push_back(GetIsValidCellFunctions()); - functions.push_back(GetIsResClassIIIFunction()); - functions.push_back(GetIsPentagonFunction()); - functions.push_back(GetGetIcosahedronFacesFunction()); - - // Hierarchy - functions.push_back(GetCellToParentFunction()); - functions.push_back(GetCellToChildrenFunction()); - functions.push_back(GetCellToCenterChildFunction()); - functions.push_back(GetCellToChildPosFunction()); - functions.push_back(GetChildPosToCellFunction()); - functions.push_back(GetCompactCellsFunction()); - functions.push_back(GetUncompactCellsFunction()); - - // Traversal - functions.push_back(GetGridDiskFunction()); - functions.push_back(GetGridDiskDistancesFunction()); - functions.push_back(GetGridDiskUnsafeFunction()); - functions.push_back(GetGridDiskDistancesUnsafeFunction()); - functions.push_back(GetGridDiskDistancesSafeFunction()); - functions.push_back(GetGridRingUnsafeFunction()); - functions.push_back(GetGridPathCellsFunction()); - functions.push_back(GetGridDistanceFunction()); - functions.push_back(GetCellToLocalIjFunction()); - functions.push_back(GetLocalIjToCellFunction()); - - // Directed edge - functions.push_back(GetAreNeighborCellsFunction()); - functions.push_back(GetCellsToDirectedEdgeFunction()); - functions.push_back(GetIsValidDirectedEdgeFunctions()); - functions.push_back(GetGetDirectedEdgeOriginFunction()); - functions.push_back(GetGetDirectedEdgeDestinationFunction()); - functions.push_back(GetDirectedEdgeToCellsFunction()); - functions.push_back(GetOriginToDirectedEdgesFunction()); - functions.push_back(GetDirectedEdgeToBoundaryWktFunction()); - - // Vertex - functions.push_back(GetCellToVertexFunction()); - functions.push_back(GetCellToVertexesFunction()); - functions.push_back(GetVertexToLatFunction()); - functions.push_back(GetVertexToLngFunction()); - functions.push_back(GetVertexToLatLngFunction()); - functions.push_back(GetIsValidVertexFunctions()); - - // Misc - functions.push_back(GetGetHexagonAreaAvgFunction()); - functions.push_back(GetCellAreaFunction()); - functions.push_back(GetGetHexagonEdgeLengthAvgFunction()); - functions.push_back(GetEdgeLengthFunction()); - functions.push_back(GetGetNumCellsFunction()); - functions.push_back(GetGetRes0CellsFunction()); - functions.push_back(GetGetPentagonsFunction()); - functions.push_back(GetGreatCircleDistanceFunction()); - - // Regions - functions.push_back(GetCellsToMultiPolygonWktFunction()); - functions.push_back(GetPolygonWktToCellsFunction()); - - return functions; - } + static vector GetFunctions() { + vector functions; + + // Indexing + functions.push_back(GetLatLngToCellFunction()); + functions.push_back(GetCellToLatFunction()); + functions.push_back(GetCellToLngFunction()); + functions.push_back(GetCellToLatLngFunction()); + functions.push_back(GetCellToBoundaryWktFunction()); + + // Inspection + functions.push_back(GetGetResolutionFunction()); + functions.push_back(GetGetBaseCellNumberFunction()); + functions.push_back(GetStringToH3Function()); + functions.push_back(GetH3ToStringFunction()); + functions.push_back(GetIsValidCellFunctions()); + functions.push_back(GetIsResClassIIIFunction()); + functions.push_back(GetIsPentagonFunction()); + functions.push_back(GetGetIcosahedronFacesFunction()); + + // Hierarchy + functions.push_back(GetCellToParentFunction()); + functions.push_back(GetCellToChildrenFunction()); + functions.push_back(GetCellToCenterChildFunction()); + functions.push_back(GetCellToChildPosFunction()); + functions.push_back(GetChildPosToCellFunction()); + functions.push_back(GetCompactCellsFunction()); + functions.push_back(GetUncompactCellsFunction()); + + // Traversal + functions.push_back(GetGridDiskFunction()); + functions.push_back(GetGridDiskDistancesFunction()); + functions.push_back(GetGridDiskUnsafeFunction()); + functions.push_back(GetGridDiskDistancesUnsafeFunction()); + functions.push_back(GetGridDiskDistancesSafeFunction()); + functions.push_back(GetGridRingUnsafeFunction()); + functions.push_back(GetGridPathCellsFunction()); + functions.push_back(GetGridDistanceFunction()); + functions.push_back(GetCellToLocalIjFunction()); + functions.push_back(GetLocalIjToCellFunction()); + + // Directed edge + functions.push_back(GetAreNeighborCellsFunction()); + functions.push_back(GetCellsToDirectedEdgeFunction()); + functions.push_back(GetIsValidDirectedEdgeFunctions()); + functions.push_back(GetGetDirectedEdgeOriginFunction()); + functions.push_back(GetGetDirectedEdgeDestinationFunction()); + functions.push_back(GetDirectedEdgeToCellsFunction()); + functions.push_back(GetOriginToDirectedEdgesFunction()); + functions.push_back(GetDirectedEdgeToBoundaryWktFunction()); + + // Vertex + functions.push_back(GetCellToVertexFunction()); + functions.push_back(GetCellToVertexesFunction()); + functions.push_back(GetVertexToLatFunction()); + functions.push_back(GetVertexToLngFunction()); + functions.push_back(GetVertexToLatLngFunction()); + functions.push_back(GetIsValidVertexFunctions()); + + // Misc + functions.push_back(GetGetHexagonAreaAvgFunction()); + functions.push_back(GetCellAreaFunction()); + functions.push_back(GetGetHexagonEdgeLengthAvgFunction()); + functions.push_back(GetEdgeLengthFunction()); + functions.push_back(GetGetNumCellsFunction()); + functions.push_back(GetGetRes0CellsFunction()); + functions.push_back(GetGetPentagonsFunction()); + functions.push_back(GetGreatCircleDistanceFunction()); + + // Regions + functions.push_back(GetCellsToMultiPolygonWktFunction()); + functions.push_back(GetPolygonWktToCellsFunction()); + + return functions; + } private: - // Indexing - static CreateScalarFunctionInfo GetLatLngToCellFunction(); - static CreateScalarFunctionInfo GetCellToLatFunction(); - static CreateScalarFunctionInfo GetCellToLngFunction(); - static CreateScalarFunctionInfo GetCellToLatLngFunction(); - static CreateScalarFunctionInfo GetCellToBoundaryWktFunction(); - - // Inspection - static CreateScalarFunctionInfo GetGetResolutionFunction(); - static CreateScalarFunctionInfo GetGetBaseCellNumberFunction(); - static CreateScalarFunctionInfo GetStringToH3Function(); - static CreateScalarFunctionInfo GetH3ToStringFunction(); - static CreateScalarFunctionInfo GetIsValidCellFunctions(); - static CreateScalarFunctionInfo GetIsResClassIIIFunction(); - static CreateScalarFunctionInfo GetIsPentagonFunction(); - static CreateScalarFunctionInfo GetGetIcosahedronFacesFunction(); - - // Hierarchy - static CreateScalarFunctionInfo GetCellToParentFunction(); - static CreateScalarFunctionInfo GetCellToChildrenFunction(); - static CreateScalarFunctionInfo GetCellToCenterChildFunction(); - static CreateScalarFunctionInfo GetCellToChildPosFunction(); - static CreateScalarFunctionInfo GetChildPosToCellFunction(); - static CreateScalarFunctionInfo GetCompactCellsFunction(); - static CreateScalarFunctionInfo GetUncompactCellsFunction(); - - // Traversal - static CreateScalarFunctionInfo GetGridDiskFunction(); - static CreateScalarFunctionInfo GetGridDiskDistancesFunction(); - static CreateScalarFunctionInfo GetGridDiskUnsafeFunction(); - static CreateScalarFunctionInfo GetGridDiskDistancesUnsafeFunction(); - static CreateScalarFunctionInfo GetGridDiskDistancesSafeFunction(); - static CreateScalarFunctionInfo GetGridRingUnsafeFunction(); - static CreateScalarFunctionInfo GetGridPathCellsFunction(); - static CreateScalarFunctionInfo GetGridDistanceFunction(); - static CreateScalarFunctionInfo GetCellToLocalIjFunction(); - static CreateScalarFunctionInfo GetLocalIjToCellFunction(); - - // Directed edge - static CreateScalarFunctionInfo GetAreNeighborCellsFunction(); - static CreateScalarFunctionInfo GetCellsToDirectedEdgeFunction(); - static CreateScalarFunctionInfo GetIsValidDirectedEdgeFunctions(); - static CreateScalarFunctionInfo GetGetDirectedEdgeOriginFunction(); - static CreateScalarFunctionInfo GetGetDirectedEdgeDestinationFunction(); - static CreateScalarFunctionInfo GetDirectedEdgeToCellsFunction(); - static CreateScalarFunctionInfo GetOriginToDirectedEdgesFunction(); - static CreateScalarFunctionInfo GetDirectedEdgeToBoundaryWktFunction(); - - // Vertex - static CreateScalarFunctionInfo GetCellToVertexFunction(); - static CreateScalarFunctionInfo GetCellToVertexesFunction(); - static CreateScalarFunctionInfo GetVertexToLatFunction(); - static CreateScalarFunctionInfo GetVertexToLngFunction(); - static CreateScalarFunctionInfo GetVertexToLatLngFunction(); - static CreateScalarFunctionInfo GetIsValidVertexFunctions(); - - // Misc - static CreateScalarFunctionInfo GetGetHexagonAreaAvgFunction(); - static CreateScalarFunctionInfo GetCellAreaFunction(); - static CreateScalarFunctionInfo GetGetHexagonEdgeLengthAvgFunction(); - static CreateScalarFunctionInfo GetEdgeLengthFunction(); - static CreateScalarFunctionInfo GetGetNumCellsFunction(); - static CreateScalarFunctionInfo GetGetRes0CellsFunction(); - static CreateScalarFunctionInfo GetGetPentagonsFunction(); - static CreateScalarFunctionInfo GetGreatCircleDistanceFunction(); - - // Regions - static CreateScalarFunctionInfo GetCellsToMultiPolygonWktFunction(); - static CreateScalarFunctionInfo GetPolygonWktToCellsFunction(); - - static void AddAliases(vector names, CreateScalarFunctionInfo fun, - vector &functions) { - for (auto &name : names) { - fun.name = name; - functions.push_back(fun); - } - } + // Indexing + static CreateScalarFunctionInfo GetLatLngToCellFunction(); + static CreateScalarFunctionInfo GetCellToLatFunction(); + static CreateScalarFunctionInfo GetCellToLngFunction(); + static CreateScalarFunctionInfo GetCellToLatLngFunction(); + static CreateScalarFunctionInfo GetCellToBoundaryWktFunction(); + + // Inspection + static CreateScalarFunctionInfo GetGetResolutionFunction(); + static CreateScalarFunctionInfo GetGetBaseCellNumberFunction(); + static CreateScalarFunctionInfo GetStringToH3Function(); + static CreateScalarFunctionInfo GetH3ToStringFunction(); + static CreateScalarFunctionInfo GetIsValidCellFunctions(); + static CreateScalarFunctionInfo GetIsResClassIIIFunction(); + static CreateScalarFunctionInfo GetIsPentagonFunction(); + static CreateScalarFunctionInfo GetGetIcosahedronFacesFunction(); + + // Hierarchy + static CreateScalarFunctionInfo GetCellToParentFunction(); + static CreateScalarFunctionInfo GetCellToChildrenFunction(); + static CreateScalarFunctionInfo GetCellToCenterChildFunction(); + static CreateScalarFunctionInfo GetCellToChildPosFunction(); + static CreateScalarFunctionInfo GetChildPosToCellFunction(); + static CreateScalarFunctionInfo GetCompactCellsFunction(); + static CreateScalarFunctionInfo GetUncompactCellsFunction(); + + // Traversal + static CreateScalarFunctionInfo GetGridDiskFunction(); + static CreateScalarFunctionInfo GetGridDiskDistancesFunction(); + static CreateScalarFunctionInfo GetGridDiskUnsafeFunction(); + static CreateScalarFunctionInfo GetGridDiskDistancesUnsafeFunction(); + static CreateScalarFunctionInfo GetGridDiskDistancesSafeFunction(); + static CreateScalarFunctionInfo GetGridRingUnsafeFunction(); + static CreateScalarFunctionInfo GetGridPathCellsFunction(); + static CreateScalarFunctionInfo GetGridDistanceFunction(); + static CreateScalarFunctionInfo GetCellToLocalIjFunction(); + static CreateScalarFunctionInfo GetLocalIjToCellFunction(); + + // Directed edge + static CreateScalarFunctionInfo GetAreNeighborCellsFunction(); + static CreateScalarFunctionInfo GetCellsToDirectedEdgeFunction(); + static CreateScalarFunctionInfo GetIsValidDirectedEdgeFunctions(); + static CreateScalarFunctionInfo GetGetDirectedEdgeOriginFunction(); + static CreateScalarFunctionInfo GetGetDirectedEdgeDestinationFunction(); + static CreateScalarFunctionInfo GetDirectedEdgeToCellsFunction(); + static CreateScalarFunctionInfo GetOriginToDirectedEdgesFunction(); + static CreateScalarFunctionInfo GetDirectedEdgeToBoundaryWktFunction(); + + // Vertex + static CreateScalarFunctionInfo GetCellToVertexFunction(); + static CreateScalarFunctionInfo GetCellToVertexesFunction(); + static CreateScalarFunctionInfo GetVertexToLatFunction(); + static CreateScalarFunctionInfo GetVertexToLngFunction(); + static CreateScalarFunctionInfo GetVertexToLatLngFunction(); + static CreateScalarFunctionInfo GetIsValidVertexFunctions(); + + // Misc + static CreateScalarFunctionInfo GetGetHexagonAreaAvgFunction(); + static CreateScalarFunctionInfo GetCellAreaFunction(); + static CreateScalarFunctionInfo GetGetHexagonEdgeLengthAvgFunction(); + static CreateScalarFunctionInfo GetEdgeLengthFunction(); + static CreateScalarFunctionInfo GetGetNumCellsFunction(); + static CreateScalarFunctionInfo GetGetRes0CellsFunction(); + static CreateScalarFunctionInfo GetGetPentagonsFunction(); + static CreateScalarFunctionInfo GetGreatCircleDistanceFunction(); + + // Regions + static CreateScalarFunctionInfo GetCellsToMultiPolygonWktFunction(); + static CreateScalarFunctionInfo GetPolygonWktToCellsFunction(); + + static void AddAliases(vector names, CreateScalarFunctionInfo fun, + vector &functions) { + for (auto &name : names) { + fun.name = name; + functions.push_back(fun); + } + } }; } // namespace duckdb diff --git a/src/include/h3ext_extension.hpp b/src/include/h3ext_extension.hpp index 3d95396..d649952 100644 --- a/src/include/h3ext_extension.hpp +++ b/src/include/h3ext_extension.hpp @@ -14,8 +14,8 @@ namespace duckdb { class H3extExtension : public Extension { public: - void Load(DuckDB &db) override; - std::string Name() override; + void Load(DuckDB &db) override; + std::string Name() override; }; } // namespace duckdb