8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-31 23:23:04 +01:00
firebird-mirror/src/qli/report.cpp

368 lines
9.1 KiB
C++
Raw Normal View History

2001-05-23 15:26:42 +02:00
/*
* PROGRAM: JRD Command Oriented Query Language
* 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): ______________________________________.
*/
#include "firebird.h"
2004-04-29 00:36:29 +02:00
#include <stdio.h>
2001-05-23 15:26:42 +02:00
#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
2004-11-24 10:22:07 +01: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.
*
**************************************/
// 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;
// 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);
// 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 (;;) {
// 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)) {
swap_uchar(message->msg_buffer, report->rpt_buffer);
2001-05-23 15:26:42 +02:00
bottom_break(control, print);
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
// 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
// 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);
// Get the next record. If we're at end, we're almost done.
2001-05-23 15:26:42 +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;
}
// Force BOTTOM breaks for all fields
2001-05-23 15:26:42 +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;
UCHAR *p2;
2001-05-23 15:26:42 +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;
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;
// 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;
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)
do {
2001-05-23 15:26:42 +02:00
if (*p1++ != *p2++)
2003-09-10 19:52:12 +02:00
return true;
} 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);
}