diff --git a/README.md b/README.md index cf3fa20..9c7ad80 100644 --- a/README.md +++ b/README.md @@ -415,7 +415,7 @@ There are also two important restrictions: Example of using window functions with VOPS: - select unnest(t.*) from (select mcount(*) over w,mcount(x) over w,msum(x) over w,mavg(x) over w,mmin(x) over w,mmax(x) over w,x - lag(x) over w + select vops_unnest(t.*) from (select mcount(*) over w,mcount(x) over w,msum(x) over w,mavg(x) over w,mmin(x) over w,mmax(x) over w,x - lag(x) over w from v window w as (rows between unbounded preceding and current row)) t; ### Using indexes @@ -571,16 +571,16 @@ It accepts name of target VOPS table, path to CSV file, optional separator (default is ',') and number of lines in CSV header (no header by default). The function returns number of imported rows. -### Back to normal tuples +### Back to normal tuples A query from VOPS projection returns set of tiles. Output function of tile type is able to print content of the tile. But in some cases it is preferable to transfer result to normal (horizontal) format where each -tuple represents one record. It can be done using `unnest` +tuple represents one record. It can be done using `vops_unnest` function: - postgres=# select unnest(l.*) from vops_lineitem l where filter(l_shipdate <= '1998-12-01'::date) limit 3; - unnest + postgres=# select vops_unnest(l.*) from vops_lineitem l where filter(l_shipdate <= '1998-12-01'::date) limit 3; + vops_unnest --------------------------------------- (1996-03-13,17,33078.9,0.04,0.02,N,O) (1996-04-12,36,38306.2,0.09,0.06,N,O) @@ -589,18 +589,18 @@ tuple represents one record. It can be done using `unnest` ### Back to normal tables -As it was mentioned in previous section, `unnest` function can scatter -records with VOPS types into normal records with scalar types. So it is -possible to use this records in arbitrary SQL queries. But there are two -problems with unnest function: +As it was mentioned in previous section, `vops_unnest` function can +scatter records with VOPS types into normal records with scalar types. +So it is possible to use this records in arbitrary SQL queries. But +there are two problems with vops_unnest function: 1. It is not convenient to use. This function has no static knowledge about the format of output record and this is why programmer has to specify it manually, if here wants to decompose this record. 2. PostgreSQL optimizer has completely no knowledge on result of - transformation performed by unnest() function. This is why it is not - able to choose optimal query execution plan for data retrieved from - VOPS table. + transformation performed by vops_unnest() function. This is why it + is not able to choose optimal query execution plan for data + retrieved from VOPS table. Fortunately Postgres provides solution for both of this problem: foreign data wrappers (FDW). In our case data is not really "foreign": it is diff --git a/expected/test.out b/expected/test.out index 7823dd3..9f93a47 100644 --- a/expected/test.out +++ b/expected/test.out @@ -9,9 +9,9 @@ select populate(destination:='v'::regclass, source:='s'::regclass); 6 (1 row) -select unnest(v.*) from v where x > 1; - unnest --------- +select vops_unnest(v.*) from v where x > 1; + vops_unnest +------------- (2) (3) (4) @@ -71,8 +71,8 @@ select count(*) from v where coalesce(x, 0.0::float8::vops_float4) >= 0; 6 (1 row) -select unnest(t.*) from (select mcount(*) over w,mcount(x) over w,msum(x) over w,mavg(x) over w,mmin(x) over w,mmax(x) over w,x - lag(x) over w from v window w as (rows between unbounded preceding and current row)) t; - unnest +select vops_unnest(t.*) from (select mcount(*) over w,mcount(x) over w,msum(x) over w,mavg(x) over w,mmin(x) over w,mmax(x) over w,x - lag(x) over w from v window w as (rows between unbounded preceding and current row)) t; + vops_unnest ------------------- (1,1,1,1,1,1,) (2,2,3,1.5,1,2,1) @@ -92,9 +92,9 @@ select populate(destination:='v2'::regclass, source:='s2'::regclass,sort:='id'); 100 (1 row) -select unnest(t.*) from (select msum(x,10) over (order by first(id)) from v2) t; - unnest --------- +select vops_unnest(t.*) from (select msum(x,10) over (order by first(id)) from v2) t; + vops_unnest +------------- (1) (3) (6) diff --git a/sql/test.sql b/sql/test.sql index 3a6cd3b..2e044c4 100644 --- a/sql/test.sql +++ b/sql/test.sql @@ -4,7 +4,7 @@ create table s(x real); create table v(x vops_float4); insert into s values(1.0),(2.0),(null),(3.0),(null),(4.0); select populate(destination:='v'::regclass, source:='s'::regclass); -select unnest(v.*) from v where x > 1; +select vops_unnest(v.*) from v where x > 1; select countall(*) from v where x is not null; select count(*) from v where x is null; select count(*) from v where x is not null; @@ -14,14 +14,14 @@ select count(*),count(x),sum(x),avg(x),min(x),max(x),variance(x),var_pop(x),var_ select count(*),count(x),sum(x),avg(x),min(x),max(x),variance(x),var_pop(x),var_samp(x),stddev(x),stddev_pop(x),stddev_samp(x) from s where x > 1.0; select count(*) from v where ifnull(x, 0) >= 0; select count(*) from v where coalesce(x, 0.0::float8::vops_float4) >= 0; -select unnest(t.*) from (select mcount(*) over w,mcount(x) over w,msum(x) over w,mavg(x) over w,mmin(x) over w,mmax(x) over w,x - lag(x) over w from v window w as (rows between unbounded preceding and current row)) t; +select vops_unnest(t.*) from (select mcount(*) over w,mcount(x) over w,msum(x) over w,mavg(x) over w,mmin(x) over w,mmax(x) over w,x - lag(x) over w from v window w as (rows between unbounded preceding and current row)) t; create table s2(x float8, id serial); insert into s2(select generate_series(1,100)); create table v2(x vops_float8, id vops_int4); select populate(destination:='v2'::regclass, source:='s2'::regclass,sort:='id'); -select unnest(t.*) from (select msum(x,10) over (order by first(id)) from v2) t; +select vops_unnest(t.*) from (select msum(x,10) over (order by first(id)) from v2) t; select sum(x) over (order by id rows between 9 preceding and current row) from s2; set vops.auto_substitute_projections=on; diff --git a/tpch2.sql b/tpch2.sql index c0d54a8..862dedf 100644 --- a/tpch2.sql +++ b/tpch2.sql @@ -118,17 +118,17 @@ select count(*), sum(l_extendedprice * (1-l_discount)) as revenue from - (select c.* from vcustomer vc, unnest(vc.*) c(c_custkey int4,c_nationkey int4,c_acctbal real)) c1 + (select c.* from vcustomer vc, vops_unnest(vc.*) c(c_custkey int4,c_nationkey int4,c_acctbal real)) c1 join - (select o.* from vorders vo,unnest(vo.*) o(o_orderkey int4,o_custkey int4,o_orderstatus "char", + (select o.* from vorders vo,vops_unnest(vo.*) o(o_orderkey int4,o_custkey int4,o_orderstatus "char", o_totalprice real,o_orderdate date,o_shippriority int4) where vo.o_orderdate >= '1996-01-01'::date and vo.o_orderdate < '1997-01-01'::date) o1 on c_custkey = o_custkey join - (select l.* from vlineitem vl, unnest(vl.*) l(l_suppkey int4,l_orderkey int4,l_partkey int4,l_shipdate date,l_quantity float4, + (select l.* from vlineitem vl, vops_unnest(vl.*) l(l_suppkey int4,l_orderkey int4,l_partkey int4,l_shipdate date,l_quantity float4, l_extendedprice float4,l_discount float4,l_tax float4,l_returnflag "char",l_linestatus "char")) l1 on l_orderkey = o_orderkey join - (select s.* from vsupplier vs,unnest(vs.*) s(s_suppkey int4,s_nationkey int4,s_acctbal real)) s1 on l_suppkey = s_suppkey + (select s.* from vsupplier vs,vops_unnest(vs.*) s(s_suppkey int4,s_nationkey int4,s_acctbal real)) s1 on l_suppkey = s_suppkey join nation on c_nationkey = n_nationkey join region on n_regionkey = r_regionkey where diff --git a/vops--1.0.sql b/vops--1.0.sql index 31515d9..893da0c 100644 --- a/vops--1.0.sql +++ b/vops--1.0.sql @@ -1,4 +1,4 @@ -/* contrib/vops/vops.sql */ +/* contrib/vops/vops--1.0.sql */ -- complain if script is sourced in psql, rather than via CREATE EXTENSION \echo Use "create extension vops" to load this file. \quit @@ -3453,7 +3453,7 @@ create function import(destination regclass, csv_path cstring, separator cstring create type vops_aggregates as(group_by int8, count int8, aggs float8[]); create function reduce(bigint) returns setof vops_aggregates as 'MODULE_PATHNAME','vops_reduce' language C parallel safe strict immutable; -create function unnest(anyelement) returns setof record as 'MODULE_PATHNAME','vops_unnest' language C parallel safe strict immutable; +create function vops_unnest(anyelement) returns setof record as 'MODULE_PATHNAME','vops_unnest' language C parallel safe strict immutable; create cast (vops_bool as bool) with function filter(vops_bool) AS IMPLICIT; diff --git a/vops.html b/vops.html index 1a7d949..daf0fd3 100644 --- a/vops.html +++ b/vops.html @@ -15,7 +15,7 @@

Vectorized Operations (VOPS)

  • Vector window functions
  • Using indexes
  • Preparing data for VOPS
  • -
  • Back to normal tuples
  • +
  • Back to normal tuples
  • Back to normal tables
  • Standard SQL query transformation
  • @@ -389,7 +389,7 @@

    Vector window functions

    Example of using window functions with VOPS:

    -select unnest(t.*) from (select mcount(*) over w,mcount(x) over w,msum(x) over w,mavg(x) over w,mmin(x) over w,mmax(x) over w,x - lag(x) over w 
    +select vops_unnest(t.*) from (select mcount(*) over w,mcount(x) over w,msum(x) over w,mavg(x) over w,mmin(x) over w,mmax(x) over w,x - lag(x) over w 
     from v window w as (rows between unbounded preceding and current row)) t;
     
    @@ -562,15 +562,15 @@

    Preparing data for VOPS

    (no header by default). The function returns number of imported rows.

    -

    Back to normal tuples

    +

    Back to normal tuples

    A query from VOPS projection returns set of tiles. Output function of tile type is able to print content of the tile. But in some cases it is preferable to transfer result to normal (horizontal) format where each tuple represents one record. -It can be done using unnest function: +It can be done using vops_unnest function:

    -postgres=# select unnest(l.*) from vops_lineitem l where filter(l_shipdate <= '1998-12-01'::date) limit 3;
    -                unnest                 
    +postgres=# select vops_unnest(l.*) from vops_lineitem l where filter(l_shipdate <= '1998-12-01'::date) limit 3;
    +              vops_unnest                 
     ---------------------------------------
      (1996-03-13,17,33078.9,0.04,0.02,N,O)
      (1996-04-12,36,38306.2,0.09,0.06,N,O)
    @@ -581,14 +581,14 @@ 

    Back to normal tuples

    Back to normal tables

    -As it was mentioned in previous section, unnest function can scatter records with VOPS types into normal records with scalar types. +As it was mentioned in previous section, vops_unnest function can scatter records with VOPS types into normal records with scalar types. So it is possible to use this records in arbitrary SQL queries. -But there are two problems with unnest function: +But there are two problems with vops_unnest function:

    1. It is not convenient to use. This function has no static knowledge about the format of output record and this is why programmer has to specify it manually, if here wants to decompose this record.
    2. -
    3. PostgreSQL optimizer has completely no knowledge on result of transformation performed by unnest() function. +
    4. PostgreSQL optimizer has completely no knowledge on result of transformation performed by vops_unnest() function. This is why it is not able to choose optimal query execution plan for data retrieved from VOPS table.

    diff --git a/vops_fdw.c b/vops_fdw.c index b37d26a..ea12f23 100644 --- a/vops_fdw.c +++ b/vops_fdw.c @@ -1509,7 +1509,7 @@ postgresAcquireSampleRowsFunc(Relation relation, int elevel, } appendStringInfoString(&sql, " FROM "); vopsDeparseRelation(&sql, relation); - appendStringInfo(&sql, " t,unnest(t) r(%s)", record.data); + appendStringInfo(&sql, " t,vops_unnest(t) r(%s)", record.data); portal = SPI_cursor_open_with_args(NULL, sql.data, 0, NULL, NULL, NULL, true, 0);