CREATE FUNCTION rdf_fdw_settings()
RETURNS text AS 'MODULE_PATHNAME', 'rdf_fdw_settings'
LANGUAGE C IMMUTABLE STRICT;

COMMENT ON FUNCTION rdf_fdw_settings() IS 'Returns detailed dependency information including optional components';

CREATE VIEW rdf_fdw_settings AS
    WITH version_string AS (
        SELECT rdf_fdw_settings() AS v
    )
    SELECT component, version
    FROM version_string,
    LATERAL (VALUES
        ('rdf_fdw',    substring(v from 'rdf_fdw\s+([^\s,]+)')),
        ('PostgreSQL', substring(v from 'PostgreSQL\s+([^,]+)')),
        ('libxml',     substring(v from 'libxml\s+([^,]+)')),
        ('librdf',     substring(v from 'librdf\s+([^,]+)')),
        ('libcurl',    substring(v from 'libcurl\s+([^,]+)')),
        ('ssl',        substring(v from ',ssl\s+([^,]+)')),
        ('zlib',       substring(v from ',zlib\s+([^,]+)')),
        ('libSSH',     substring(v from ',libSSH\s+([^,]+)')),
        ('nghttp2',    substring(v from ',nghttp2\s+([^,]+)')),
        ('compiler',   substring(v from 'compiled by\s+([^,]+)')),
        ('built',      substring(v from 'built on\s+([^,]+)'))
    ) AS components(component, version)
    WHERE version IS NOT NULL;

COMMENT ON VIEW rdf_fdw_settings IS 'Parse detailed dependency information into component versions';

-- SUM aggregate for rdfnode
CREATE FUNCTION sparql.sum_rdfnode_sfunc(internal, rdfnode)
RETURNS internal AS 'MODULE_PATHNAME', 'rdf_fdw_sum_sfunc'
LANGUAGE C IMMUTABLE;

CREATE FUNCTION sparql.sum_rdfnode_finalfunc(internal)
RETURNS rdfnode AS 'MODULE_PATHNAME', 'rdf_fdw_sum_finalfunc'
LANGUAGE C IMMUTABLE;

CREATE AGGREGATE sparql.sum(rdfnode) (
    SFUNC = sparql.sum_rdfnode_sfunc,
    STYPE = internal,
    FINALFUNC = sparql.sum_rdfnode_finalfunc
);

COMMENT ON AGGREGATE sparql.sum(rdfnode) IS 'Computes the sum of numeric rdfnode values with XSD type promotion (integer < decimal < float < double)';

-- AVG aggregate for rdfnode
CREATE FUNCTION sparql.avg_rdfnode_sfunc(internal, rdfnode)
RETURNS internal AS 'MODULE_PATHNAME', 'rdf_fdw_avg_sfunc'
LANGUAGE C IMMUTABLE;

CREATE FUNCTION sparql.avg_rdfnode_finalfunc(internal)
RETURNS rdfnode AS 'MODULE_PATHNAME', 'rdf_fdw_avg_finalfunc'
LANGUAGE C IMMUTABLE;

CREATE AGGREGATE sparql.avg(rdfnode) (
    SFUNC = sparql.avg_rdfnode_sfunc,
    STYPE = internal,
    FINALFUNC = sparql.avg_rdfnode_finalfunc
);

COMMENT ON AGGREGATE sparql.avg(rdfnode) IS 'Computes the average of numeric rdfnode values with XSD type promotion (integer < decimal < float < double)';

-- MIN aggregate for rdfnode
CREATE FUNCTION sparql.min_rdfnode_sfunc(internal, rdfnode)
RETURNS internal AS 'MODULE_PATHNAME', 'rdf_fdw_min_sfunc'
LANGUAGE C IMMUTABLE;

CREATE FUNCTION sparql.min_rdfnode_finalfunc(internal)
RETURNS rdfnode AS 'MODULE_PATHNAME', 'rdf_fdw_min_finalfunc'
LANGUAGE C IMMUTABLE;

CREATE AGGREGATE sparql.min(rdfnode) (
    SFUNC = sparql.min_rdfnode_sfunc,
    STYPE = internal,
    FINALFUNC = sparql.min_rdfnode_finalfunc
);

COMMENT ON AGGREGATE sparql.min(rdfnode) IS 'Returns the minimum numeric rdfnode value';

-- MAX aggregate for rdfnode
CREATE FUNCTION sparql.max_rdfnode_sfunc(internal, rdfnode)
RETURNS internal AS 'MODULE_PATHNAME', 'rdf_fdw_max_sfunc'
LANGUAGE C IMMUTABLE;

CREATE FUNCTION sparql.max_rdfnode_finalfunc(internal)
RETURNS rdfnode AS 'MODULE_PATHNAME', 'rdf_fdw_max_finalfunc'
LANGUAGE C IMMUTABLE;

CREATE AGGREGATE sparql.max(rdfnode) (
    SFUNC = sparql.max_rdfnode_sfunc,
    STYPE = internal,
    FINALFUNC = sparql.max_rdfnode_finalfunc
);

COMMENT ON AGGREGATE sparql.max(rdfnode) IS 'Returns the maximum numeric rdfnode value';

-- GROUP_CONCAT aggregate for rdfnode
CREATE FUNCTION sparql.group_concat_rdfnode_sfunc(internal, rdfnode, text)
RETURNS internal AS 'MODULE_PATHNAME', 'rdf_fdw_group_concat_sfunc'
LANGUAGE C IMMUTABLE;

CREATE FUNCTION sparql.group_concat_rdfnode_finalfunc(internal)
RETURNS rdfnode AS 'MODULE_PATHNAME', 'rdf_fdw_group_concat_finalfunc'
LANGUAGE C IMMUTABLE;

CREATE AGGREGATE sparql.group_concat(rdfnode, text) (
    SFUNC = sparql.group_concat_rdfnode_sfunc,
    STYPE = internal,
    FINALFUNC = sparql.group_concat_rdfnode_finalfunc
);

COMMENT ON AGGREGATE sparql.group_concat(rdfnode, text) IS 
'SPARQL 1.1 GROUP_CONCAT aggregate: concatenates string representations of RDF terms with specified separator';

-- SAMPLE aggregate for rdfnode
CREATE FUNCTION sparql.sample_rdfnode_sfunc(internal, rdfnode)
RETURNS internal AS 'MODULE_PATHNAME', 'rdf_fdw_sample_sfunc'
LANGUAGE C IMMUTABLE;

CREATE FUNCTION sparql.sample_rdfnode_finalfunc(internal)
RETURNS rdfnode AS 'MODULE_PATHNAME', 'rdf_fdw_sample_finalfunc'
LANGUAGE C IMMUTABLE;

CREATE AGGREGATE sparql.sample(rdfnode) (
    SFUNC = sparql.sample_rdfnode_sfunc,
    STYPE = internal,
    FINALFUNC = sparql.sample_rdfnode_finalfunc
);

COMMENT ON AGGREGATE sparql.sample(rdfnode) IS 'Returns an arbitrary (first non-NULL) value from the aggregate group per SPARQL 1.1 Section 18.5.1.8';
