13.7. N:1 follower queries (RLIB compatibility limits) #

13.7.1. Data
13.7.2. C program code
13.7.3. PHP program code
13.7.4. RLIB compatible PHP program code
13.7.5. Report description
13.7.6. Report PDF result

This example below exercises two N:1 (N-to-one) follower queries along with the main query. For more information, see Follower queries.

13.7.1. Data #

The same data is used as in the previous example.

The query that the RLIB compatible method for N:1 followers in this report simulates is:

ocrpttest=> select * from data
ocrpttest-> left outer join lateral (select * from more_data
ocrpttest->      where data.id = more_data.boss_id
ocrpttest->      order by more_data.id limit 1) x on (true)
ocrpttest-> left outer join lateral (select * from moar_data
ocrpttest->      where x.id = moar_data.sk_id
ocrpttest->      order by moar_data.sk_id limit 1) y on (true);
 id |          name          | id | boss_id |      name       | sk_id |      name       
----+------------------------+----+---------+-----------------+-------+-----------------
  1 | Snow White             |  1 |       1 | Doc             |       | 
  2 | Batman                 |  8 |       2 | Robin           |       | 
  3 | Cinderella             |  9 |       3 | Fairy Godmother |     9 | Prince Charming
  4 | Hansel                 | 12 |       4 | Gretel          |       | 
  5 | Little Red Riding Hood |    |         |                 |       | 
  6 | Robin Hood             | 13 |       6 | Little John     |    13 | Will Scarlet
(6 rows)

Note the amount of hoops the SQL query has to jump through to implement the LIMIT 1 clause on both lateral derived queries that results in limiting the number of rows to the main query's number of rows.

13.7.2. C program code #

The program code is identical to the previous example, except that it uses a different report XML description.

#include <stdio.h>
#include <opencreport.h>

int main(int argc, char **argv) {
    opencreport *o = ocrpt_init();
    struct ocrpt_input_connect_parameter conn_params[] = {
        { .param_name = "dbname", .param_value = "ocrpttest" },
        { .param_name = "user", .param_value = "ocrpt" },
        { NULL }
    };
    ocrpt_datasource *ds = ocrpt_datasource_add(o, "pgsql", "postgresql", conn_params);
    ocrpt_query *q1 = ocrpt_query_add_sql(ds, "q1", "select * from data order by id;");
    ocrpt_query *q2 = ocrpt_query_add_sql(ds, "q2", "select * from more_data order by id;");
    ocrpt_query *q3 = ocrpt_query_add_sql(ds, "q3", "select * from moar_data order by sk_id;");

    ocrpt_expr *match = ocrpt_expr_parse(o, "q1.id = q2.boss_id", NULL);
    ocrpt_query_add_follower_n_to_1(q1, q2, match);

    ocrpt_expr *match2 = ocrpt_expr_parse(o, "q2.id = q3.sk_id", NULL);
    ocrpt_query_add_follower_n_to_1(q2, q3, match2);

    if (!ocrpt_parse_xml(o, "example7.xml")) {
        printf("XML parse error\n");
        ocrpt_free(o);
        return 0;
    }

    ocrpt_set_output_format(o, OCRPT_OUTPUT_PDF);
    ocrpt_execute(o);
    ocrpt_spool(o);
    ocrpt_free(o);

    return 0;
}}

13.7.3. PHP program code #

Here's the equivalent program code in PHP.

<?php
$o = new OpenCReport();
$conn_params = [
        "dbname" => "ocrpttest",
        "user" => "ocrpt"
];
$ds = $o->datasource_add("pgsql", "postgresql", $conn_params);
$q1 = $ds->query_add("q1", "select * from data order by id;");
$q2 = $ds->query_add("q2", "select * from more_data order by id;");
$q3 = $ds->query_add("q3", "select * from moar_data order by sk_id;");

$match1 = $o->expr_parse("q1.id = q2.boss_id");
$q1->add_follower_n_to_1($q2, $match1);

$match2 = $o->expr_parse("q2.id = q3.sk_id");
$q2->add_follower_n_to_1($q3, $match2);

if (!$o->parse_xml("example7.xml")) {
    echo "XML parse error" . PHP_EOL;
    exit(0);
}

$o->execute();
$o->spool();

13.7.4. RLIB compatible PHP program code #

Here's the equivalent program code in PHP, using the RLIB compatibility functions. Note that the RLIB compatible API is more limited as it expects a single field name matching.

<?php
$r = rlib_init();

rlib_add_datasource_postgres($r, "pgsql", "dbname=ocrpttest user=ocrpt");
rlib_add_query_as($r, "pgsql", "select * from data order by id;", "q1");
rlib_add_query_as($r, "pgsql", "select * from more_data order by id;", "q2");
rlib_add_query_as($r, "pgsql", "select * from moar_data order by sk_id;", "q3");

rlib_add_resultset_follower_n_to_1($r, "q1", "id", "q2", "boss_id");
rlib_add_resultset_follower_n_to_1($r, "q2", "id", "q3", "sk_id");

if (!rlib_add_report($r, "example7.xml")) {
    echo "XML parse error" . PHP_EOL;
    exit(0);
}

rlib_execute($r);
rlib_spool($r);

13.7.5. Report description #

The program code uses this file contents from example7.xml. It is different in one detail from the previous example: the toplevel XML node is <Report> instead of <OpenCReport>. This results in the RLIB compatibility flag to be enabled automatically. See the Follower match single attribute or the equivalent calls in the C and PHP API documentation.

<?xml version="1.0"?>
<!DOCTYPE report >
<Report orientation="landscape">
    <Detail>
        <FieldHeaders>
            <Output>
                <Line>
                    <literal width="30">Boss name</literal>
                    <literal width="1"/>
                    <literal width="30">Sidekick name</literal>
                    <literal width="1"/>
                    <literal width="30">Sidekick's sidekick name</literal>
                </Line>
            </Output>
        </FieldHeaders>
        <FieldDetails>
            <Output>
                <Line>
                    <field value="q1.name" width="30" align="left" />
                    <literal width="1"/>
                    <field value="q2.name" width="30" align="left" />
                    <literal width="1"/>
                    <field value="q3.name" width="30" align="left" />
                </Line>
            </Output>
        </FieldDetails>
    </Detail>
</Report>

13.7.6. Report PDF result #

Note that compared to RLIB, OpenCReports likely do not produce the same output. This is due to the incomplete and faulty implementation of follower queries in RLIB. OpenCReports faithfully implements LEFT OUTER JOIN with limiting the number of dependent matching rows to 1 that approximates the RLIB behaviour.