2001-05-23 15:26:42 +02:00
|
|
|
/*
|
|
|
|
* PROGRAM: JRD Command Oriented Query Language
|
2003-09-15 14:30:28 +02:00
|
|
|
* MODULE: report.cpp
|
2001-05-23 15:26:42 +02:00
|
|
|
* DESCRIPTION: Report writer runtime control
|
|
|
|
*
|
|
|
|
* The contents of this file are subject to the Interbase Public
|
|
|
|
* License Version 1.0 (the "License"); you may not use this file
|
|
|
|
* except in compliance with the License. You may obtain a copy
|
|
|
|
* of the License at http://www.Inprise.com/IPL.html
|
|
|
|
*
|
|
|
|
* Software distributed under the License is distributed on an
|
|
|
|
* "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express
|
|
|
|
* or implied. See the License for the specific language governing
|
|
|
|
* rights and limitations under the License.
|
|
|
|
*
|
|
|
|
* The Original Code was created by Inprise Corporation
|
|
|
|
* and its predecessors. Portions created by Inprise Corporation are
|
|
|
|
* Copyright (C) Inprise Corporation.
|
|
|
|
*
|
|
|
|
* All Rights Reserved.
|
|
|
|
* Contributor(s): ______________________________________.
|
|
|
|
*/
|
|
|
|
|
2001-07-30 01:43:24 +02:00
|
|
|
#include "firebird.h"
|
2001-05-23 15:26:42 +02:00
|
|
|
#include "../jrd/ib_stdio.h"
|
|
|
|
#include "../qli/dtr.h"
|
|
|
|
#include "../qli/exe.h"
|
|
|
|
#include "../qli/compile.h"
|
|
|
|
#include "../qli/report.h"
|
|
|
|
#include "../qli/all_proto.h"
|
|
|
|
#include "../qli/eval_proto.h"
|
|
|
|
#include "../qli/exe_proto.h"
|
|
|
|
#include "../qli/forma_proto.h"
|
|
|
|
#include "../qli/mov_proto.h"
|
|
|
|
#include "../qli/repor_proto.h"
|
|
|
|
|
2004-02-02 12:02:12 +01:00
|
|
|
static void bottom_break(qli_brk*, qli_prt*);
|
|
|
|
static void increment_break(qli_brk*);
|
|
|
|
static void initialize_break(qli_brk*);
|
|
|
|
static bool test_break(qli_brk*, qli_rpt*, qli_msg*);
|
|
|
|
static void top_break(qli_brk*, qli_prt*);
|
|
|
|
static void top_of_page(qli_prt*, bool);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-09-15 14:30:28 +02:00
|
|
|
//#define SWAP(a,b) {temp = a; a = b; b = temp;}
|
|
|
|
inline void swap_uchar(UCHAR*& a, UCHAR*& b)
|
|
|
|
{
|
|
|
|
UCHAR* temp = a;
|
|
|
|
a = b;
|
|
|
|
b = temp;
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
|
2004-02-02 12:02:12 +01:00
|
|
|
void RPT_report( qli_nod* loop)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* R P T _ r e p o r t
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Execute a FOR loop. This may require that a request get
|
|
|
|
* started, a message sent, and a message received for each
|
|
|
|
* record. At the other end of the spectrum, there may be
|
|
|
|
* absolutely nothing to do.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
|
2003-09-25 13:49:12 +02:00
|
|
|
// Get to actual report node
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-02-02 12:02:12 +01:00
|
|
|
qli_nod* node = loop->nod_arg[e_for_statement];
|
|
|
|
qli_rpt* report = (qli_rpt*) node->nod_arg[e_prt_list];
|
|
|
|
qli_prt* print = (qli_prt*) node->nod_arg[e_prt_output];
|
2003-10-16 10:51:06 +02:00
|
|
|
print->prt_new_page = top_of_page;
|
2001-05-23 15:26:42 +02:00
|
|
|
print->prt_page_number = 0;
|
|
|
|
|
2003-09-25 13:49:12 +02:00
|
|
|
// Get to actual report node
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
/* If there is a request associated with the loop, start it and possibly
|
|
|
|
send a message slong with it. */
|
|
|
|
|
2004-02-02 12:02:12 +01:00
|
|
|
qli_msg* message;
|
|
|
|
qli_req* request = (qli_req*) loop->nod_arg[e_for_request];
|
2003-10-16 10:51:06 +02:00
|
|
|
if (request)
|
2004-02-02 12:02:12 +01:00
|
|
|
EXEC_start_request(request, (qli_msg*) loop->nod_arg[e_for_send]);
|
|
|
|
else if (message = (qli_msg*) loop->nod_arg[e_for_send])
|
2001-05-23 15:26:42 +02:00
|
|
|
EXEC_send(message);
|
|
|
|
|
|
|
|
/* Receive messages in a loop until the end of file field comes up
|
|
|
|
true. */
|
|
|
|
|
2004-02-02 12:02:12 +01:00
|
|
|
message = (qli_msg*) loop->nod_arg[e_for_receive];
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
/* Get the first record of the record. If there isn't anything,
|
|
|
|
don't worry about anything. */
|
|
|
|
|
2004-02-02 12:02:12 +01:00
|
|
|
const dsc* desc = EXEC_receive(message, (qli_par*) loop->nod_arg[e_for_eof]);
|
2003-10-16 10:51:06 +02:00
|
|
|
if (*(USHORT*) desc->dsc_address)
|
2001-05-23 15:26:42 +02:00
|
|
|
return;
|
|
|
|
|
|
|
|
if (!report->rpt_buffer) {
|
2004-02-02 12:02:12 +01:00
|
|
|
qli_str* string = (qli_str*) ALLOCDV(type_str, message->msg_length);
|
2001-05-23 15:26:42 +02:00
|
|
|
report->rpt_buffer = (UCHAR *) string->str_data;
|
|
|
|
}
|
|
|
|
|
2001-07-12 07:46:06 +02:00
|
|
|
MOVQ_fast((SCHAR*) message->msg_buffer, (SCHAR*) report->rpt_buffer,
|
2001-05-23 15:26:42 +02:00
|
|
|
(SLONG) message->msg_length);
|
|
|
|
|
2004-02-02 12:02:12 +01:00
|
|
|
qli_brk* control;
|
2001-05-23 15:26:42 +02:00
|
|
|
if (control = report->rpt_top_rpt)
|
2004-02-02 12:02:12 +01:00
|
|
|
FMT_print((qli_nod*) control->brk_line, print);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-09-10 19:52:12 +02:00
|
|
|
top_of_page(print, true);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
initialize_break(report->rpt_bottom_breaks);
|
|
|
|
initialize_break(report->rpt_bottom_page);
|
|
|
|
initialize_break(report->rpt_bottom_rpt);
|
|
|
|
|
2003-09-25 13:49:12 +02:00
|
|
|
// Force TOP breaks for all fields
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
for (control = report->rpt_top_breaks; control;
|
2004-02-02 12:02:12 +01:00
|
|
|
control = control->brk_next) FMT_print((qli_nod*) control->brk_line, print);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
for (;;) {
|
2003-09-25 13:49:12 +02:00
|
|
|
// Check for bottom breaks. If we find one, force all lower breaks.
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
for (control = report->rpt_bottom_breaks; control;
|
|
|
|
control = control->brk_next)
|
2003-09-10 19:52:12 +02:00
|
|
|
{
|
|
|
|
if (test_break(control, report, message)) {
|
2003-09-15 14:30:28 +02:00
|
|
|
swap_uchar(message->msg_buffer, report->rpt_buffer);
|
2001-05-23 15:26:42 +02:00
|
|
|
bottom_break(control, print);
|
2003-09-15 14:30:28 +02:00
|
|
|
swap_uchar(message->msg_buffer, report->rpt_buffer);
|
2001-05-23 15:26:42 +02:00
|
|
|
initialize_break(control);
|
|
|
|
break;
|
|
|
|
}
|
2003-09-10 19:52:12 +02:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (print->prt_lines_remaining <= 0)
|
2003-09-10 19:52:12 +02:00
|
|
|
top_of_page(print, false);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-09-25 13:49:12 +02:00
|
|
|
// Now check for top breaks.
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
for (control = report->rpt_top_breaks; control;
|
|
|
|
control = control->brk_next)
|
2003-09-10 19:52:12 +02:00
|
|
|
{
|
|
|
|
if (test_break(control, report, message)) {
|
2001-05-23 15:26:42 +02:00
|
|
|
top_break(control, print);
|
|
|
|
break;
|
|
|
|
}
|
2003-09-10 19:52:12 +02:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-09-25 13:49:12 +02:00
|
|
|
// Increment statisticals and print detail line, if any
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
increment_break(report->rpt_bottom_breaks);
|
|
|
|
increment_break(report->rpt_bottom_page);
|
|
|
|
increment_break(report->rpt_bottom_rpt);
|
|
|
|
|
|
|
|
if (node = report->rpt_detail_line)
|
|
|
|
FMT_print(node, print);
|
|
|
|
|
2003-09-25 13:49:12 +02:00
|
|
|
// Get the next record. If we're at end, we're almost done.
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-09-15 14:30:28 +02:00
|
|
|
swap_uchar(message->msg_buffer, report->rpt_buffer);
|
2004-02-02 12:02:12 +01:00
|
|
|
desc = EXEC_receive(message, (qli_par*) loop->nod_arg[e_for_eof]);
|
2001-05-23 15:26:42 +02:00
|
|
|
if (*(USHORT *) desc->dsc_address)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2003-09-25 13:49:12 +02:00
|
|
|
// Force BOTTOM breaks for all fields
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-09-15 14:30:28 +02:00
|
|
|
swap_uchar(message->msg_buffer, report->rpt_buffer);
|
2001-05-23 15:26:42 +02:00
|
|
|
bottom_break(report->rpt_bottom_breaks, print);
|
|
|
|
bottom_break(report->rpt_bottom_rpt, print);
|
|
|
|
|
|
|
|
if (control = report->rpt_bottom_page)
|
2004-02-02 12:02:12 +01:00
|
|
|
FMT_print((qli_nod*) control->brk_line, print);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-02-02 12:02:12 +01:00
|
|
|
static void bottom_break( qli_brk* control, qli_prt* print)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* b o t t o m _ b r e a k
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Force all lower breaks then take break.
|
|
|
|
*
|
|
|
|
**************************************/
|
2004-02-02 12:02:12 +01:00
|
|
|
qli_lls* stack;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (!control)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (control->brk_next)
|
|
|
|
bottom_break(control->brk_next, print);
|
|
|
|
|
|
|
|
for (stack = control->brk_statisticals; stack; stack = stack->lls_next)
|
2004-02-02 12:02:12 +01:00
|
|
|
EVAL_break_compute((qli_nod*) stack->lls_object);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-02-02 12:02:12 +01:00
|
|
|
FMT_print((qli_nod*) control->brk_line, print);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-02-02 12:02:12 +01:00
|
|
|
static void increment_break( qli_brk* control)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* i n c r e m e n t _ b r e a k
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Toss another record into running computations.
|
|
|
|
*
|
|
|
|
**************************************/
|
2004-02-02 12:02:12 +01:00
|
|
|
qli_lls* stack;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
for (; control; control = control->brk_next)
|
|
|
|
for (stack = control->brk_statisticals; stack;
|
2004-02-02 12:02:12 +01:00
|
|
|
stack = stack->lls_next) EVAL_break_increment((qli_nod*) stack->lls_object);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-02-02 12:02:12 +01:00
|
|
|
static void initialize_break( qli_brk* control)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* i n i t i a l i z e _ b r e a k
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Execute a control break.
|
|
|
|
*
|
|
|
|
**************************************/
|
2004-02-02 12:02:12 +01:00
|
|
|
qli_lls* stack;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
for (; control; control = control->brk_next)
|
|
|
|
for (stack = control->brk_statisticals; stack;
|
2004-02-02 12:02:12 +01:00
|
|
|
stack = stack->lls_next) EVAL_break_init((qli_nod*) stack->lls_object);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-02-02 12:02:12 +01:00
|
|
|
static bool test_break(qli_brk* control,
|
|
|
|
qli_rpt* report,
|
|
|
|
qli_msg* message)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* t e s t _ b r e a k
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Check to see if there has been a control break for an expression.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
DSC desc1, desc2, *ptr1, *ptr2;
|
2003-09-15 14:30:28 +02:00
|
|
|
UCHAR *p2;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-09-25 13:49:12 +02:00
|
|
|
// Evaluate the two versions of the expression
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-02-02 12:02:12 +01:00
|
|
|
if (ptr1 = EVAL_value((qli_nod*) control->brk_field))
|
2001-05-23 15:26:42 +02:00
|
|
|
desc1 = *ptr1;
|
|
|
|
|
2003-09-15 14:30:28 +02:00
|
|
|
UCHAR* p1 = message->msg_buffer;
|
2001-05-23 15:26:42 +02:00
|
|
|
message->msg_buffer = report->rpt_buffer;
|
|
|
|
|
2004-02-02 12:02:12 +01:00
|
|
|
if (ptr2 = EVAL_value((qli_nod*) control->brk_field))
|
2001-05-23 15:26:42 +02:00
|
|
|
desc2 = *ptr2;
|
|
|
|
|
|
|
|
message->msg_buffer = p1;
|
|
|
|
|
2003-09-25 13:49:12 +02:00
|
|
|
// Check for consistently missing
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (!ptr1 || !ptr2)
|
|
|
|
return (ptr1 != ptr2);
|
|
|
|
|
|
|
|
/* Both fields are present. Check values. Luckily, there's no need
|
|
|
|
to worry about datatypes. */
|
|
|
|
|
|
|
|
p1 = desc1.dsc_address;
|
|
|
|
p2 = desc2.dsc_address;
|
2003-09-15 14:30:28 +02:00
|
|
|
USHORT l = desc1.dsc_length;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (desc1.dsc_dtype == dtype_varying)
|
|
|
|
l = 2 + *(USHORT *) p1;
|
|
|
|
|
|
|
|
if (l)
|
2003-09-25 13:49:12 +02:00
|
|
|
do {
|
2001-05-23 15:26:42 +02:00
|
|
|
if (*p1++ != *p2++)
|
2003-09-10 19:52:12 +02:00
|
|
|
return true;
|
2003-09-25 13:49:12 +02:00
|
|
|
} while (--l);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-09-10 19:52:12 +02:00
|
|
|
return false;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-02-02 12:02:12 +01:00
|
|
|
static void top_break( qli_brk* control, qli_prt* print)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* t o p _ b r e a k
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Execute a control break.
|
|
|
|
*
|
|
|
|
**************************************/
|
2004-02-02 12:02:12 +01:00
|
|
|
qli_lls* stack;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
for (; control; control = control->brk_next) {
|
|
|
|
for (stack = control->brk_statisticals; stack;
|
2003-10-16 10:51:06 +02:00
|
|
|
stack = stack->lls_next)
|
|
|
|
{
|
2004-02-02 12:02:12 +01:00
|
|
|
EVAL_break_compute((qli_nod*) stack->lls_object);
|
2003-10-16 10:51:06 +02:00
|
|
|
}
|
2004-02-02 12:02:12 +01:00
|
|
|
FMT_print((qli_nod*) control->brk_line, print);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-02-02 12:02:12 +01:00
|
|
|
static void top_of_page(qli_prt* print,
|
2003-09-10 19:52:12 +02:00
|
|
|
bool first_flag)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* t o p _ o f _ p a g e
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Handle top of page condition.
|
|
|
|
*
|
|
|
|
**************************************/
|
2004-02-02 12:02:12 +01:00
|
|
|
qli_brk* control;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
++print->prt_page_number;
|
2004-02-02 12:02:12 +01:00
|
|
|
qli_rpt* report = print->prt_report;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (!first_flag) {
|
|
|
|
if (control = report->rpt_bottom_page)
|
2004-02-02 12:02:12 +01:00
|
|
|
FMT_print((qli_nod*) control->brk_line, print);
|
2001-05-23 15:26:42 +02:00
|
|
|
FMT_put("\f", print);
|
|
|
|
}
|
|
|
|
|
|
|
|
print->prt_lines_remaining = print->prt_lines_per_page;
|
|
|
|
|
|
|
|
if (control = report->rpt_top_page)
|
2004-02-02 12:02:12 +01:00
|
|
|
FMT_print((qli_nod*) control->brk_line, print);
|
2001-05-23 15:26:42 +02:00
|
|
|
else if (report->rpt_column_header) {
|
|
|
|
if (report->rpt_header)
|
|
|
|
FMT_put(report->rpt_header, print);
|
|
|
|
if (report->rpt_column_header)
|
|
|
|
FMT_put(report->rpt_column_header, print);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (report->rpt_bottom_page)
|
|
|
|
initialize_break(report->rpt_bottom_page);
|
|
|
|
}
|
2003-09-15 14:30:28 +02:00
|
|
|
|
2003-09-25 13:49:12 +02:00
|
|
|
|