Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use DuckDB's filesystem for GDAL by default, Handle GDAL errors, Add ST_Union_Agg(), ST_Intersection_Agg(). #126

Merged
merged 2 commits into from
Sep 12, 2023
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
update duckdb, add geos aggregates
  • Loading branch information
Maxxen committed Sep 12, 2023
commit d90eadcaf5885147472a97f481b3261bc3bf0815
2 changes: 1 addition & 1 deletion duckdb
Submodule duckdb updated 1371 files
4 changes: 3 additions & 1 deletion spatial/include/spatial/core/functions/aggregate.hpp
Original file line number Diff line number Diff line change
@@ -6,7 +6,9 @@ namespace spatial {
namespace core {

struct CoreAggregateFunctions {
static void Register(ClientContext &context);
public:
static void Register(ClientContext &context) {
}
};

} // namespace core
3 changes: 3 additions & 0 deletions spatial/include/spatial/geos/geos_wrappers.hpp
Original file line number Diff line number Diff line change
@@ -206,6 +206,9 @@ struct GeosContextWrapper {
string_t Serialize(Vector &result, const unique_ptr<GEOSGeometry, GeosDeleter<GEOSGeometry>> &geom);
};

GEOSGeometry *DeserializeGEOSGeometry(const string_t &blob, GEOSContextHandle_t ctx);
string_t SerializeGEOSGeometry(Vector &result, const GEOSGeometry *geom, GEOSContextHandle_t ctx);

} // namespace geos

} // namespace spatial
2 changes: 1 addition & 1 deletion spatial/src/spatial/core/module.cpp
Original file line number Diff line number Diff line change
@@ -18,7 +18,7 @@ void CoreModule::Register(ClientContext &context) {
CoreScalarFunctions::Register(context);
CoreCastFunctions::Register(context);
CoreTableFunctions::Register(context);
// CoreAggregateFunctions::Register(context);
CoreAggregateFunctions::Register(context);
}

} // namespace core
185 changes: 185 additions & 0 deletions spatial/src/spatial/geos/functions/aggregate.cpp
Original file line number Diff line number Diff line change
@@ -1,12 +1,197 @@
#include "duckdb/parser/parsed_data/create_scalar_function_info.hpp"
#include "duckdb/parser/parsed_data/create_aggregate_function_info.hpp"

#include "spatial/common.hpp"
#include "spatial/geos/functions/aggregate.hpp"
#include "spatial/geos/geos_wrappers.hpp"

#include "geos_c.h"

namespace spatial {

namespace geos {

struct GEOSAggState {
GEOSGeometry *geom = nullptr;
GEOSContextHandle_t context = nullptr;

~GEOSAggState() {
if (geom) {
GEOSGeom_destroy_r(context, geom);
geom = nullptr;
}
if (context) {
GEOS_finish_r(context);
context = nullptr;
}
}
};

//------------------------------------------------------------------------
// INTERSECTION
//------------------------------------------------------------------------
struct IntersectionAggFunction {
template <class STATE>
static void Initialize(STATE &state) {
state.geom = nullptr;
state.context = GEOS_init_r();
}

template <class STATE, class OP>
static void Combine(const STATE &source, STATE &target, AggregateInputData &data) {
if (!source.geom) {
return;
}
if (!target.geom) {
target.geom = GEOSGeom_clone_r(target.context, source.geom);
return;
}
auto curr = target.geom;
target.geom = GEOSIntersection_r(target.context, curr, source.geom);
GEOSGeom_destroy_r(target.context, curr);
}

template <class INPUT_TYPE, class STATE, class OP>
static void Operation(STATE &state, const INPUT_TYPE &input, AggregateUnaryInput &) {
if (!state.geom) {
state.geom = DeserializeGEOSGeometry(input, state.context);
} else {
auto next = DeserializeGEOSGeometry(input, state.context);
auto curr = state.geom;
state.geom = GEOSIntersection_r(state.context, curr, next);
GEOSGeom_destroy_r(state.context, next);
GEOSGeom_destroy_r(state.context, curr);
}
}

template <class INPUT_TYPE, class STATE, class OP>
static void ConstantOperation(STATE &state, const INPUT_TYPE &input, AggregateUnaryInput &, idx_t count) {
// There is no point in doing anything else, intersection is idempotent
if (!state.geom) {
state.geom = DeserializeGEOSGeometry(input, state.context);
}
}

template <class T, class STATE>
static void Finalize(STATE &state, T &target, AggregateFinalizeData &finalize_data) {
if (!state.geom) {
finalize_data.ReturnNull();
} else {
target = SerializeGEOSGeometry(finalize_data.result, state.geom, state.context);
}
}

template <class STATE>
static void Destroy(STATE &state, AggregateInputData &) {
if (state.geom) {
GEOSGeom_destroy_r(state.context, state.geom);
state.geom = nullptr;
}
if (state.context) {
GEOS_finish_r(state.context);
state.context = nullptr;
}
}

static bool IgnoreNull() {
return true;
}
};

//------------------------------------------------------------------------
// UNION
//------------------------------------------------------------------------

struct UnionAggFunction {
template <class STATE>
static void Initialize(STATE &state) {
state.geom = nullptr;
state.context = GEOS_init_r();
}

template <class STATE, class OP>
static void Combine(const STATE &source, STATE &target, AggregateInputData &data) {
if (!source.geom) {
return;
}
if (!target.geom) {
target.geom = GEOSGeom_clone_r(target.context, source.geom);
return;
}
auto curr = target.geom;
target.geom = GEOSUnion_r(target.context, curr, source.geom);
GEOSGeom_destroy_r(target.context, curr);
}

template <class INPUT_TYPE, class STATE, class OP>
static void Operation(STATE &state, const INPUT_TYPE &input, AggregateUnaryInput &) {
if (!state.geom) {
state.geom = DeserializeGEOSGeometry(input, state.context);
} else {
auto next = DeserializeGEOSGeometry(input, state.context);
auto curr = state.geom;
state.geom = GEOSUnion_r(state.context, curr, next);
GEOSGeom_destroy_r(state.context, next);
GEOSGeom_destroy_r(state.context, curr);
}
}

template <class INPUT_TYPE, class STATE, class OP>
static void ConstantOperation(STATE &state, const INPUT_TYPE &input, AggregateUnaryInput &, idx_t count) {
// There is no point in doing anything else, union is idempotent
if (!state.geom) {
state.geom = DeserializeGEOSGeometry(input, state.context);
}
}

template <class T, class STATE>
static void Finalize(STATE &state, T &target, AggregateFinalizeData &finalize_data) {
if (!state.geom) {
finalize_data.ReturnNull();
} else {
target = SerializeGEOSGeometry(finalize_data.result, state.geom, state.context);
}
}

template <class STATE>
static void Destroy(STATE &state, AggregateInputData &) {
if (state.geom) {
GEOSGeom_destroy_r(state.context, state.geom);
state.geom = nullptr;
}
if (state.context) {
GEOS_finish_r(state.context);
state.context = nullptr;
}
}

static bool IgnoreNull() {
return true;
}
};

//------------------------------------------------------------------------
// Register
//------------------------------------------------------------------------
void GeosAggregateFunctions::Register(ClientContext &context) {

auto &catalog = Catalog::GetSystemCatalog(context);

AggregateFunctionSet st_intersection_agg("st_intersection_agg");
st_intersection_agg.AddFunction(
AggregateFunction::UnaryAggregateDestructor<GEOSAggState, string_t, string_t, IntersectionAggFunction>(
core::GeoTypes::GEOMETRY(), core::GeoTypes::GEOMETRY()));
CreateAggregateFunctionInfo intersection_info(std::move(st_intersection_agg));
intersection_info.on_conflict = OnCreateConflict::ALTER_ON_CONFLICT;
catalog.CreateFunction(context, intersection_info);

AggregateFunctionSet st_union_agg("st_union_agg");
st_union_agg.AddFunction(
AggregateFunction::UnaryAggregateDestructor<GEOSAggState, string_t, string_t, UnionAggFunction>(
core::GeoTypes::GEOMETRY(), core::GeoTypes::GEOMETRY()));
CreateAggregateFunctionInfo union_info(std::move(st_union_agg));
union_info.on_conflict = OnCreateConflict::ALTER_ON_CONFLICT;
catalog.CreateFunction(context, union_info);
}

} // namespace geos
22 changes: 15 additions & 7 deletions spatial/src/spatial/geos/geos_wrappers.cpp
Original file line number Diff line number Diff line change
@@ -143,7 +143,7 @@ static GEOSGeometry *DeserializeGeometryCollection(Cursor &reader, GEOSContextHa
}
}

static GEOSGeometry *DeserializeGeometry(Cursor &reader, GEOSContextHandle_t ctx) {
GEOSGeometry *DeserializeGeometry(Cursor &reader, GEOSContextHandle_t ctx) {
auto type = reader.Peek<GeometryType>();
switch (type) {
case GeometryType::POINT: {
@@ -174,11 +174,15 @@ static GEOSGeometry *DeserializeGeometry(Cursor &reader, GEOSContextHandle_t ctx
}
}

GeometryPtr GeosContextWrapper::Deserialize(const string_t &blob) {
GEOSGeometry *DeserializeGEOSGeometry(const string_t &blob, GEOSContextHandle_t ctx) {
Cursor reader(blob);
reader.Skip(4); // Skip type, flags and hash
reader.Skip(4); // Skip padding
return GeometryPtr(DeserializeGeometry(reader, ctx));
return DeserializeGeometry(reader, ctx);
}

GeometryPtr GeosContextWrapper::Deserialize(const string_t &blob) {
return GeometryPtr(DeserializeGEOSGeometry(blob, ctx));
}

//-------------------------------------------------------------------
@@ -451,8 +455,8 @@ static void SerializeGeometry(Cursor &writer, const GEOSGeometry *geom, const GE
}
}

string_t GeosContextWrapper::Serialize(Vector &result, const GeometryPtr &geom) {
auto size = GetSerializedSize(geom.get(), ctx);
string_t SerializeGEOSGeometry(Vector &result, const GEOSGeometry *geom, GEOSContextHandle_t ctx) {
auto size = GetSerializedSize(geom, ctx);
size += sizeof(GeometryHeader); // Header
size += sizeof(uint32_t); // Padding

@@ -465,7 +469,7 @@ string_t GeosContextWrapper::Serialize(Vector &result, const GeometryPtr &geom)
}

GeometryType type;
auto geos_type = GEOSGeomTypeId_r(ctx, geom.get());
auto geos_type = GEOSGeomTypeId_r(ctx, geom);
switch (geos_type) {
case GEOS_POINT:
type = GeometryType::POINT;
@@ -501,11 +505,15 @@ string_t GeosContextWrapper::Serialize(Vector &result, const GeometryPtr &geom)
writer.Write<GeometryHeader>(header); // Header
writer.Write<uint32_t>(0); // Padding

SerializeGeometry(writer, geom.get(), ctx);
SerializeGeometry(writer, geom, ctx);

return blob;
}

string_t GeosContextWrapper::Serialize(Vector &result, const GeometryPtr &geom) {
return SerializeGEOSGeometry(result, geom.get(), ctx);
}

} // namespace geos

} // namespace spatial