8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-27 18:03:04 +01:00
firebird-mirror/src/gpre/cmp.cpp

1753 lines
42 KiB
C++
Raw Normal View History

2001-05-23 15:26:42 +02:00
//____________________________________________________________
2008-12-05 02:20:14 +01:00
//
2001-05-23 15:26:42 +02:00
// PROGRAM: C preprocessor
// MODULE: cmp.cpp
// DESCRIPTION: Request compiler
2008-12-05 02:20:14 +01:00
//
2001-05-23 15:26:42 +02:00
// 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
2008-12-05 02:20:14 +01:00
//
2001-05-23 15:26:42 +02:00
// 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.
2008-12-05 02:20:14 +01:00
//
2001-05-23 15:26:42 +02:00
// The Original Code was created by Inprise Corporation
// and its predecessors. Portions created by Inprise Corporation are
// Copyright (C) Inprise Corporation.
2008-12-05 02:20:14 +01:00
//
2001-05-23 15:26:42 +02:00
// All Rights Reserved.
// Contributor(s): ______________________________________.
// TMN (Mike Nordell) 11.APR.2001 - Reduce compiler warnings
2008-12-05 02:20:14 +01:00
//
2001-05-23 15:26:42 +02:00
//
//____________________________________________________________
//
//
#include "firebird.h"
2001-05-23 15:26:42 +02:00
#include <stdlib.h>
#include <string.h>
2003-11-08 17:40:17 +01:00
#include "../jrd/ibase.h"
#include "../gpre/gpre.h"
2001-05-23 15:26:42 +02:00
#include "../jrd/align.h"
#include "../gpre/cmd_proto.h"
#include "../gpre/cme_proto.h"
#include "../gpre/cmp_proto.h"
#include "../gpre/gpre_proto.h"
#include "../gpre/gpre_meta.h"
#include "../gpre/msc_proto.h"
#include "../gpre/par_proto.h"
static void cmp_any(gpre_req*);
static void cmp_assignment(gpre_nod*, gpre_req*);
static void cmp_blob(blb*, bool);
static void cmp_blr(gpre_req*);
static void cmp_erase(act*, gpre_req*);
static void cmp_fetch(act*);
2004-02-02 12:02:12 +01:00
static void cmp_field(gpre_req*, const gpre_fld*, const ref*);
static void cmp_for(gpre_req*);
static void cmp_loop(gpre_req*);
static void cmp_modify(act*, gpre_req*);
static void cmp_port(gpre_port*, gpre_req*);
static void cmp_procedure(gpre_req*);
static void cmp_ready(gpre_req*);
static void cmp_sdl_fudge(gpre_req*, SLONG);
static bool cmp_sdl_loop(gpre_req*, USHORT, const slc*, const ary*);
static void cmp_sdl_number(gpre_req*, SLONG);
2009-04-26 12:24:44 +02:00
static void cmp_sdl_subscript(gpre_req*, USHORT, const slc*);
static void cmp_sdl_value(gpre_req*, const gpre_nod*);
static void cmp_set_generator(gpre_req*);
static void cmp_slice(gpre_req*);
static void cmp_store(gpre_req*);
static void expand_references(ref*);
static gpre_port* make_port(gpre_req*, ref*);
static void make_receive(gpre_port*, gpre_req*);
static void make_send(gpre_port*, gpre_req*);
static void update_references(ref*);
2001-05-23 15:26:42 +02:00
static gpre_nod* lit0;
static gpre_nod* lit1;
static gpre_fld* eof_field;
static gpre_fld* count_field;
static gpre_fld* slack_byte_field;
static ULONG next_ident;
2001-05-23 15:26:42 +02:00
//#define STUFF(blr) *request->req_blr++ = (UCHAR)(blr)
//#define STUFF_WORD(blr) {STUFF (blr); STUFF ((blr) >> 8);}
//#define STUFF_LONG(blr) {STUFF (blr); STUFF ((blr) >> 8); STUFF ((blr) >>16); STUFF ((blr) >> 24);}
//#define STUFF_INT(blr) STUFF (blr); STUFF ((blr) >> 8); STUFF ((blr) >> 16); STUFF ((blr) >> 24)
2001-05-23 15:26:42 +02:00
2003-10-15 00:22:32 +02:00
const int MAX_TPB = 4000;
2001-05-23 15:26:42 +02:00
//____________________________________________________________
2008-12-05 02:20:14 +01:00
//
2001-05-23 15:26:42 +02:00
// Check to make sure that generated blr string is not about to
// over the memory allocated for it. If so, allocate an extra
// couple of hundred bytes to be safe.
2008-12-05 02:20:14 +01:00
//
2001-05-23 15:26:42 +02:00
void CMP_check( gpre_req* request, SSHORT min_reqd)
2001-05-23 15:26:42 +02:00
{
2009-04-26 12:24:44 +02:00
const int length = request->req_blr - request->req_base;
2008-06-03 08:14:59 +02:00
if (!min_reqd && (length < request->req_length - 100))
2001-05-23 15:26:42 +02:00
return;
const int n = ((length + min_reqd + 100) > request->req_length * 2) ?
2001-05-23 15:26:42 +02:00
length + min_reqd + 100 : request->req_length * 2;
UCHAR* const old = request->req_base;
2008-03-10 09:31:35 +01:00
UCHAR* p = MSC_alloc(n);
request->req_base = p;
2001-05-23 15:26:42 +02:00
request->req_length = n;
request->req_blr = request->req_base + length;
2008-03-10 09:31:35 +01:00
memcpy(p, old, length);
2001-05-23 15:26:42 +02:00
2003-10-15 03:18:01 +02:00
MSC_free(old);
2001-05-23 15:26:42 +02:00
}
//____________________________________________________________
2008-12-05 02:20:14 +01:00
//
2001-05-23 15:26:42 +02:00
// Compile a single request, but do not generate any text.
// Generate port blocks, assign parameter numbers, message
// numbers, and internal idents. Compute length of request.
2008-12-05 02:20:14 +01:00
//
2001-05-23 15:26:42 +02:00
void CMP_compile_request( gpre_req* request)
2001-05-23 15:26:42 +02:00
{
// if there isn't a request handle specified, make one!
2001-05-23 15:26:42 +02:00
2009-06-25 12:44:37 +02:00
if (!request->req_handle && (request->req_type != REQ_procedure))
{
2008-03-10 09:31:35 +01:00
request->req_handle = (TEXT*) MSC_alloc(20);
sprintf(request->req_handle, gpreGlob.ident_pattern, CMP_next_ident());
2001-05-23 15:26:42 +02:00
}
if (!request->req_trans)
request->req_trans = gpreGlob.transaction_name;
2001-05-23 15:26:42 +02:00
if (!request->req_request_level)
request->req_request_level = "0";
request->req_ident = CMP_next_ident();
// If this is an SQL blob cursor, compile the blob and get out fast.
2001-05-23 15:26:42 +02:00
2009-06-25 12:44:37 +02:00
if (request->req_flags & (REQ_sql_blob_open | REQ_sql_blob_create))
{
for (blb* blob = request->req_blobs; blob; blob = blob->blb_next)
cmp_blob(blob, true);
2001-05-23 15:26:42 +02:00
return;
}
// Before we get too far, make sure an eof field has been
// constructed. If not, do so now.
2001-05-23 15:26:42 +02:00
ref* reference;
if (!eof_field)
{
eof_field = MET_make_field(gpreGlob.utility_name, dtype_short, sizeof(SSHORT), false);
count_field = MET_make_field(gpreGlob.count_name, dtype_long, sizeof(SLONG), false);
slack_byte_field = MET_make_field(gpreGlob.slack_name, dtype_text, 1, false);
reference = (ref*) MSC_alloc(REF_LEN);
2001-05-23 15:26:42 +02:00
reference->ref_value = "0";
lit0 = MSC_unary(nod_literal, (gpre_nod*) reference);
2001-05-23 15:26:42 +02:00
reference = (ref*) MSC_alloc(REF_LEN);
2001-05-23 15:26:42 +02:00
reference->ref_value = "1";
lit1 = MSC_unary(nod_literal, (gpre_nod*) reference);
2001-05-23 15:26:42 +02:00
}
// Handle different request types differently
2001-05-23 15:26:42 +02:00
2009-01-14 09:22:32 +01:00
switch (request->req_type)
{
2001-05-23 15:26:42 +02:00
case REQ_create_database:
case REQ_ddl:
CMD_compile_ddl(request);
return;
case REQ_slice:
cmp_slice(request);
return;
case REQ_ready:
cmp_ready(request);
return;
case REQ_procedure:
cmp_procedure(request);
return;
}
// expand any incomplete references or values
2001-05-23 15:26:42 +02:00
expand_references(request->req_references);
expand_references(request->req_values);
// Initialize the blr string
2001-05-23 15:26:42 +02:00
2008-03-10 09:31:35 +01:00
request->req_blr = request->req_base = MSC_alloc(500);
2001-05-23 15:26:42 +02:00
request->req_length = 500;
if (request->req_flags & REQ_blr_version4)
request->add_byte(blr_version4);
2001-05-23 15:26:42 +02:00
else
request->add_byte(blr_version5);
2001-05-23 15:26:42 +02:00
// If there are values to be transmitted, make a port
// to hold them
2001-05-23 15:26:42 +02:00
if (request->req_values)
request->req_vport = make_port(request, request->req_values);
// If this is a FOR type request, an eof field reference needs
// to be generated. Do it.
2001-05-23 15:26:42 +02:00
switch (request->req_type)
{
case REQ_for:
case REQ_cursor:
case REQ_any:
reference = (ref*) MSC_alloc(REF_LEN);
2001-05-23 15:26:42 +02:00
reference->ref_field = eof_field;
reference->ref_next = request->req_references;
break;
case REQ_mass_update:
reference = (ref*) MSC_alloc(REF_LEN);
2001-05-23 15:26:42 +02:00
reference->ref_field = count_field;
reference->ref_next = request->req_references;
break;
default:
2001-05-23 15:26:42 +02:00
reference = request->req_references;
}
2001-05-23 15:26:42 +02:00
// Assume that a general port needs to be constructed.
2001-05-23 15:26:42 +02:00
gpre_port* port;
if ((request->req_type != REQ_insert) && (request->req_type != REQ_store2) &&
(request->req_type != REQ_set_generator))
{
2001-05-23 15:26:42 +02:00
request->req_primary = port = make_port(request, reference);
}
2001-05-23 15:26:42 +02:00
// Loop thru actions looking for something interesting to do. Not
// all action types are "interesting", so don't worry about missing
// ones.
2001-05-23 15:26:42 +02:00
upd* update;
for (act* action = request->req_actions; action; action = action->act_next)
{
2009-01-14 09:22:32 +01:00
switch (action->act_type)
{
2001-05-23 15:26:42 +02:00
case ACT_modify:
case ACT_erase:
case ACT_update:
update = (upd*) action->act_object;
2001-05-23 15:26:42 +02:00
expand_references(update->upd_references);
update->upd_port = make_port(request, update->upd_references);
if (!request->req_sync)
request->req_sync = make_port(request, 0);
break;
case ACT_store:
2009-06-25 12:44:37 +02:00
if (request->req_type == REQ_store2)
{
2001-05-23 15:26:42 +02:00
request->req_primary = make_port(request, action->act_object);
update_references(request->req_primary->por_references);
}
break;
case ACT_store2:
update = (upd*) action->act_object;
2001-05-23 15:26:42 +02:00
expand_references(update->upd_references);
update->upd_port = make_port(request, update->upd_references);
update_references(update->upd_port->por_references);
break;
case ACT_select:
case ACT_fetch:
cmp_fetch(action);
break;
}
}
2001-05-23 15:26:42 +02:00
cmp_blr(request);
request->add_byte(blr_eoc);
2001-05-23 15:26:42 +02:00
// Compute out final blr lengths
2001-05-23 15:26:42 +02:00
request->req_length = request->req_blr - request->req_base;
request->req_blr = request->req_base;
// Finally, assign identifiers to any blobs that may have been referenced
2001-05-23 15:26:42 +02:00
for (blb* blob = request->req_blobs; blob; blob = blob->blb_next)
cmp_blob(blob, false);
2001-05-23 15:26:42 +02:00
}
//____________________________________________________________
2008-12-05 02:20:14 +01:00
//
2001-05-23 15:26:42 +02:00
// Stuff field datatype info into request.
// Text fields are not remapped to process text type.
// This is used by the CAST & COLLATE operators to
// indicate cast datatypes.
2008-12-05 02:20:14 +01:00
//
2001-05-23 15:26:42 +02:00
2004-02-02 12:02:12 +01:00
void CMP_external_field( gpre_req* request, const gpre_fld* field)
2001-05-23 15:26:42 +02:00
{
2009-01-14 09:22:32 +01:00
switch (field->fld_dtype)
{
2001-05-23 15:26:42 +02:00
case dtype_cstring:
request->add_byte(blr_text2);
request->add_word(field->fld_ttype);
request->add_word(field->fld_length - 1);
2001-05-23 15:26:42 +02:00
break;
case dtype_text:
request->add_byte(blr_text2);
request->add_word(field->fld_ttype);
request->add_word(field->fld_length);
2001-05-23 15:26:42 +02:00
break;
case dtype_varying:
request->add_byte(blr_varying2);
request->add_word(field->fld_ttype);
request->add_word(field->fld_length);
2001-05-23 15:26:42 +02:00
break;
default:
cmp_field(request, field, 0);
break;
}
}
//____________________________________________________________
2008-12-05 02:20:14 +01:00
//
2001-05-23 15:26:42 +02:00
// Initialize (or re-initialize) for request compilation. This is
// called at most once per module.
2008-12-05 02:20:14 +01:00
//
2001-05-23 15:26:42 +02:00
void CMP_init()
2001-05-23 15:26:42 +02:00
{
lit0 = lit1 = NULL;
count_field = slack_byte_field = eof_field = NULL;
next_ident = 0;
}
//____________________________________________________________
2008-12-05 02:20:14 +01:00
//
2001-05-23 15:26:42 +02:00
// Give out next identifier.
2008-12-05 02:20:14 +01:00
//
2001-05-23 15:26:42 +02:00
ULONG CMP_next_ident()
2001-05-23 15:26:42 +02:00
{
return next_ident++;
}
//____________________________________________________________
2008-12-05 02:20:14 +01:00
//
2001-05-23 15:26:42 +02:00
// Stuff a symbol.
2008-12-05 02:20:14 +01:00
//
2001-05-23 15:26:42 +02:00
2004-02-02 12:02:12 +01:00
void CMP_stuff_symbol( gpre_req* request, const gpre_sym* symbol)
2001-05-23 15:26:42 +02:00
{
request->add_byte(strlen(symbol->sym_string));
2001-05-23 15:26:42 +02:00
for (const TEXT* p = symbol->sym_string; *p; p++)
request->add_byte(*p);
2001-05-23 15:26:42 +02:00
}
//____________________________________________________________
2008-12-05 02:20:14 +01:00
//
2001-05-23 15:26:42 +02:00
// Take a transaction block with (potentially) a
// lot of relation lock blocks, and generate TPBs
2008-12-05 02:20:14 +01:00
//
2001-05-23 15:26:42 +02:00
// We'll always generate TPB's, and link them
2009-01-14 09:22:32 +01:00
// into the gpre_dbb for that database so they get
2001-05-23 15:26:42 +02:00
// generated. If there's no lock list, we generate
2008-12-05 02:20:14 +01:00
// a simple TPB for every database in the program.
2001-05-23 15:26:42 +02:00
// If there is a lock list, we generate a more complex
// TPB for each database referenced.
2008-12-05 02:20:14 +01:00
//
2001-05-23 15:26:42 +02:00
void CMP_t_start( gpre_tra* trans)
2001-05-23 15:26:42 +02:00
{
char rrl_buffer[MAX_TPB];
char tpb_buffer[MAX_TRA_OPTIONS + 1];
// fill out a standard tpb buffer ahead of time so we know
// how large it is
2001-05-23 15:26:42 +02:00
char* text = tpb_buffer;
2003-11-08 17:40:17 +01:00
*text++ = isc_tpb_version1;
*text++ = (trans->tra_flags & TRA_ro) ? isc_tpb_read : isc_tpb_write;
2001-05-23 15:26:42 +02:00
if (trans->tra_flags & TRA_con)
2003-11-08 17:40:17 +01:00
*text++ = isc_tpb_consistency;
2001-05-23 15:26:42 +02:00
else if (trans->tra_flags & TRA_read_committed)
2003-11-08 17:40:17 +01:00
*text++ = isc_tpb_read_committed;
2001-05-23 15:26:42 +02:00
else
2003-11-08 17:40:17 +01:00
*text++ = isc_tpb_concurrency;
*text++ = (trans->tra_flags & TRA_nw) ? isc_tpb_nowait : isc_tpb_wait;
2001-05-23 15:26:42 +02:00
if (trans->tra_flags & TRA_read_committed) {
*text++ = (trans->tra_flags & TRA_rec_version) ? isc_tpb_rec_version : isc_tpb_no_rec_version;
}
2001-05-23 15:26:42 +02:00
if (trans->tra_flags & TRA_autocommit)
2003-11-08 17:40:17 +01:00
*text++ = isc_tpb_autocommit;
2001-05-23 15:26:42 +02:00
if (trans->tra_flags & TRA_no_auto_undo)
2003-11-08 17:40:17 +01:00
*text++ = isc_tpb_no_auto_undo;
2001-05-23 15:26:42 +02:00
*text = 0;
const USHORT tpb_len = text - tpb_buffer;
2001-05-23 15:26:42 +02:00
2009-01-14 09:22:32 +01:00
for (gpre_dbb* database = gpreGlob.isc_databases; database; database = database->dbb_next)
{
// figure out if this is a simple transaction or a reserving
// transaction. Allocate a TPB of the right size in either
// case.
2001-05-23 15:26:42 +02:00
tpb* new_tpb = 0;
if (trans->tra_flags & TRA_inc)
{
2009-06-25 12:44:37 +02:00
if (database->dbb_flags & DBB_in_trans)
{
2003-10-15 03:18:01 +02:00
new_tpb = (tpb*) MSC_alloc(TPB_LEN(tpb_len));
2003-09-05 12:14:08 +02:00
new_tpb->tpb_length = tpb_len;
2001-05-23 15:26:42 +02:00
database->dbb_flags &= ~DBB_in_trans;
}
else
continue;
}
else if (!(trans->tra_flags & TRA_rrl))
{
2003-10-15 03:18:01 +02:00
new_tpb = (tpb*) MSC_alloc(TPB_LEN(tpb_len));
2003-09-05 12:14:08 +02:00
new_tpb->tpb_length = tpb_len;
2001-05-23 15:26:42 +02:00
}
else if (database->dbb_rrls)
{
char* p = rrl_buffer;
for (const rrl* lock_block = database->dbb_rrls; lock_block;
lock_block = lock_block->rrl_next)
{
2001-05-23 15:26:42 +02:00
*p++ = lock_block->rrl_lock_mode;
const char* q = lock_block->rrl_relation->rel_symbol->sym_string;
2001-05-23 15:26:42 +02:00
*p++ = strlen(q);
while (*q)
*p++ = *q++;
*p++ = lock_block->rrl_lock_level;
}
*p = 0;
const USHORT buff_len = (p - rrl_buffer);
2003-10-15 03:18:01 +02:00
new_tpb = (tpb*) MSC_alloc(TPB_LEN(buff_len + tpb_len));
2003-09-05 12:14:08 +02:00
new_tpb->tpb_length = buff_len + tpb_len;
2001-05-23 15:26:42 +02:00
database->dbb_rrls = NULL;
}
2008-12-05 02:20:14 +01:00
else // this database isn't referenced
2001-05-23 15:26:42 +02:00
continue;
// link this into the TPB chains (gpre_tra and gpre_dbb)
2001-05-23 15:26:42 +02:00
2003-09-05 12:14:08 +02:00
new_tpb->tpb_database = database;
new_tpb->tpb_dbb_next = database->dbb_tpbs;
database->dbb_tpbs = new_tpb;
new_tpb->tpb_tra_next = trans->tra_tpb;
trans->tra_tpb = new_tpb;
2001-05-23 15:26:42 +02:00
trans->tra_db_count++;
2008-12-05 02:20:14 +01:00
// fill in the standard TPB and concatenate the relation names
2001-05-23 15:26:42 +02:00
2003-09-05 12:14:08 +02:00
new_tpb->tpb_ident = CMP_next_ident();
2001-05-23 15:26:42 +02:00
2003-09-05 12:14:08 +02:00
text = reinterpret_cast<char*>(new_tpb->tpb_string);
for (const char* pb = tpb_buffer; *pb;)
*text++ = *pb++;
2001-05-23 15:26:42 +02:00
if (trans->tra_flags & TRA_rrl)
strcpy(text, rrl_buffer);
}
}
//____________________________________________________________
2008-12-05 02:20:14 +01:00
//
2001-05-23 15:26:42 +02:00
// Generate blr tree for free standing ANY expression.
2008-12-05 02:20:14 +01:00
//
2001-05-23 15:26:42 +02:00
static void cmp_any( gpre_req* request)
2001-05-23 15:26:42 +02:00
{
// Build the primary send statement
2001-05-23 15:26:42 +02:00
gpre_port* port = request->req_primary;
2001-05-23 15:26:42 +02:00
make_send(port, request);
request->add_byte(blr_if);
request->add_byte(blr_any);
2001-05-23 15:26:42 +02:00
CME_rse(request->req_rse, request);
gpre_nod* value = MSC_unary(nod_value, (gpre_nod*) port->por_references);
2001-05-23 15:26:42 +02:00
// Make a send to signal end of file
2001-05-23 15:26:42 +02:00
request->add_byte(blr_assignment);
2001-05-23 15:26:42 +02:00
CME_expr(lit1, request);
CME_expr(value, request);
request->add_byte(blr_assignment);
2001-05-23 15:26:42 +02:00
CME_expr(lit0, request);
CME_expr(value, request);
port = request->req_vport;
2009-06-25 12:44:37 +02:00
if (port)
{
for (ref* reference = port->por_references; reference; reference = reference->ref_next)
{
ref* source = (ref*) MSC_alloc(REF_LEN);
reference->ref_source = source;
2001-05-23 15:26:42 +02:00
source->ref_ident = CMP_next_ident();
}
}
2001-05-23 15:26:42 +02:00
}
//____________________________________________________________
2008-12-05 02:20:14 +01:00
//
2001-05-23 15:26:42 +02:00
// Compile a build assignment statement.
2008-12-05 02:20:14 +01:00
//
2001-05-23 15:26:42 +02:00
static void cmp_assignment( gpre_nod* node, gpre_req* request)
2001-05-23 15:26:42 +02:00
{
CMP_check(request, 0);
request->add_byte(blr_assignment);
2001-05-23 15:26:42 +02:00
CME_expr(node->nod_arg[0], request);
CME_expr(node->nod_arg[1], request);
}
//____________________________________________________________
2008-12-05 02:20:14 +01:00
//
2001-05-23 15:26:42 +02:00
// Compile a blob parameter block, if required.
2008-12-05 02:20:14 +01:00
//
2001-05-23 15:26:42 +02:00
static void cmp_blob(blb* blob, bool sql_flag)
2001-05-23 15:26:42 +02:00
{
blob->blb_ident = CMP_next_ident();
blob->blb_buff_ident = CMP_next_ident();
blob->blb_len_ident = CMP_next_ident();
2009-06-25 12:44:37 +02:00
if (sql_flag)
{
for (ref* reference = blob->blb_reference; reference; reference = reference->ref_next)
{
reference->ref_port = make_port(reference->ref_context->ctx_request, reference);
}
}
2001-05-23 15:26:42 +02:00
if (!blob->blb_const_to_type && !blob->blb_type)
return;
blob->blb_bpb_ident = CMP_next_ident();
UCHAR* p = blob->blb_bpb;
2003-11-08 17:40:17 +01:00
*p++ = isc_bpb_version1;
2001-05-23 15:26:42 +02:00
2009-06-25 12:44:37 +02:00
if (blob->blb_const_to_type)
{
2003-11-08 17:40:17 +01:00
*p++ = isc_bpb_target_type;
2001-05-23 15:26:42 +02:00
*p++ = 2;
*p++ = (UCHAR) blob->blb_const_to_type;
*p++ = blob->blb_const_to_type >> 8;
}
2009-06-25 12:44:37 +02:00
if (blob->blb_const_from_type)
{
2003-11-08 17:40:17 +01:00
*p++ = isc_bpb_source_type;
2001-05-23 15:26:42 +02:00
*p++ = 2;
*p++ = (UCHAR) blob->blb_const_from_type;
*p++ = blob->blb_const_from_type >> 8;
}
2009-06-25 12:44:37 +02:00
if (blob->blb_type)
{
2003-11-08 17:40:17 +01:00
*p++ = isc_bpb_type;
2001-05-23 15:26:42 +02:00
*p++ = 1;
*p++ = (UCHAR) blob->blb_type;
}
2009-06-25 12:44:37 +02:00
if (blob->blb_from_charset)
{
2008-12-05 02:20:14 +01:00
// create bpb instruction for source character set
2001-05-23 15:26:42 +02:00
2003-11-08 17:40:17 +01:00
*p++ = isc_bpb_source_interp;
2001-05-23 15:26:42 +02:00
*p++ = 2;
*p++ = (UCHAR) blob->blb_from_charset;
*p++ = blob->blb_from_charset >> 8;
}
2009-06-25 12:44:37 +02:00
if (blob->blb_to_charset)
{
2001-05-23 15:26:42 +02:00
2008-12-05 02:20:14 +01:00
// create bpb instruction for target character set
2001-05-23 15:26:42 +02:00
2003-11-08 17:40:17 +01:00
*p++ = isc_bpb_target_interp;
2001-05-23 15:26:42 +02:00
*p++ = 2;
*p++ = (UCHAR) blob->blb_to_charset;
*p++ = blob->blb_to_charset >> 8;
}
blob->blb_bpb_length = p - blob->blb_bpb;
}
//____________________________________________________________
2008-12-05 02:20:14 +01:00
//
2001-05-23 15:26:42 +02:00
// Build a request tree for a request.
2008-12-05 02:20:14 +01:00
//
2001-05-23 15:26:42 +02:00
static void cmp_blr( gpre_req* request)
2001-05-23 15:26:42 +02:00
{
request->add_byte(blr_begin);
2001-05-23 15:26:42 +02:00
// build message definition for each port
2001-05-23 15:26:42 +02:00
gpre_port* port;
2001-05-23 15:26:42 +02:00
for (port = request->req_ports; port; port = port->por_next)
cmp_port(port, request);
// See if there is a receive to be built
2001-05-23 15:26:42 +02:00
if ((request->req_type == REQ_store) || (request->req_type == REQ_store2))
port = request->req_primary;
else
port = request->req_vport;
if (port)
make_receive(port, request);
// Compile up request
2001-05-23 15:26:42 +02:00
2009-01-14 09:22:32 +01:00
switch (request->req_type)
{
2001-05-23 15:26:42 +02:00
case REQ_cursor:
case REQ_for:
cmp_for(request);
break;
case REQ_insert:
case REQ_store:
case REQ_store2:
cmp_store(request);
break;
case REQ_mass_update:
cmp_loop(request);
break;
case REQ_any:
cmp_any(request);
break;
case REQ_set_generator:
cmp_set_generator(request);
break;
default:
CPR_error("*** unknown request type node ***");
}
request->add_byte(blr_end);
2001-05-23 15:26:42 +02:00
}
//____________________________________________________________
2008-12-05 02:20:14 +01:00
//
2001-05-23 15:26:42 +02:00
// Generate blr for ERASE action.
2008-12-05 02:20:14 +01:00
//
2001-05-23 15:26:42 +02:00
static void cmp_erase( act* action, gpre_req* request)
2001-05-23 15:26:42 +02:00
{
upd* update = (upd*) action->act_object;
gpre_ctx* source = update->upd_source;
2001-05-23 15:26:42 +02:00
make_receive(update->upd_port, request);
if (action->act_error)
request->add_byte(blr_handler);
2001-05-23 15:26:42 +02:00
request->add_byte(blr_erase);
request->add_byte(source->ctx_internal);
2001-05-23 15:26:42 +02:00
}
//____________________________________________________________
2008-12-05 02:20:14 +01:00
//
2001-05-23 15:26:42 +02:00
// Go over an SQL fetch list and expand
// references to indicator variables.
// Not tough.
2008-12-05 02:20:14 +01:00
//
2001-05-23 15:26:42 +02:00
static void cmp_fetch( act* action)
2001-05-23 15:26:42 +02:00
{
gpre_nod* list = (gpre_nod*) action->act_object;
if (!list)
2001-05-23 15:26:42 +02:00
return;
if (list->nod_type != nod_list)
CPR_error("invalid fetch action");
gpre_nod** ptr = list->nod_arg;
for (const gpre_nod* const* const end = ptr + list->nod_count; ptr < end; ptr++)
{
ref* var = (ref*) *ptr;
2001-05-23 15:26:42 +02:00
if (var->ref_null_value && !var->ref_null)
2008-12-27 19:15:50 +01:00
{
2001-05-23 15:26:42 +02:00
if (var->ref_friend)
var->ref_null = var->ref_friend->ref_null;
2008-12-27 19:15:50 +01:00
}
2001-05-23 15:26:42 +02:00
}
}
//____________________________________________________________
2008-12-05 02:20:14 +01:00
//
2001-05-23 15:26:42 +02:00
// Stuff field datatype info into request.
2008-12-05 02:20:14 +01:00
//
2001-05-23 15:26:42 +02:00
2004-02-02 12:02:12 +01:00
static void cmp_field( gpre_req* request, const gpre_fld* field,
const ref* reference)
2001-05-23 15:26:42 +02:00
{
if (reference && reference->ref_value && (reference->ref_flags & REF_array_elem))
{
field = field->fld_array;
}
2001-05-23 15:26:42 +02:00
2003-11-04 00:59:24 +01:00
fb_assert(field != NULL);
fb_assert(field->fld_dtype);
fb_assert(field->fld_length);
2001-05-23 15:26:42 +02:00
2009-01-14 09:22:32 +01:00
switch (field->fld_dtype)
{
2001-05-23 15:26:42 +02:00
case dtype_cstring:
2009-06-25 12:44:37 +02:00
if (!(field->fld_flags & FLD_charset) && field->fld_ttype)
{
request->add_byte(blr_cstring);
request->add_word(field->fld_length);
2001-05-23 15:26:42 +02:00
}
2009-06-25 12:44:37 +02:00
else
{
2008-12-05 02:20:14 +01:00
// 3.2j has new, tagged blr instruction for cstring
2001-05-23 15:26:42 +02:00
request->add_byte(blr_cstring2);
request->add_word(field->fld_ttype);
request->add_word(field->fld_length);
2001-05-23 15:26:42 +02:00
}
break;
case dtype_text:
2009-06-25 12:44:37 +02:00
if (!(field->fld_flags & FLD_charset) && field->fld_ttype)
{
request->add_byte(blr_text);
request->add_word(field->fld_length);
2001-05-23 15:26:42 +02:00
}
2009-06-25 12:44:37 +02:00
else
{
2008-12-05 02:20:14 +01:00
// 3.2j has new, tagged blr instruction for text too
2001-05-23 15:26:42 +02:00
request->add_byte(blr_text2);
request->add_word(field->fld_ttype);
request->add_word(field->fld_length);
2001-05-23 15:26:42 +02:00
}
break;
case dtype_varying:
2009-06-25 12:44:37 +02:00
if (!(field->fld_flags & FLD_charset) && field->fld_ttype)
{
request->add_byte(blr_varying);
request->add_word(field->fld_length);
2001-05-23 15:26:42 +02:00
}
2009-06-25 12:44:37 +02:00
else
{
2008-12-05 02:20:14 +01:00
// 3.2j has new, tagged blr instruction for varying also
2001-05-23 15:26:42 +02:00
request->add_byte(blr_varying2);
request->add_word(field->fld_ttype);
request->add_word(field->fld_length);
2001-05-23 15:26:42 +02:00
}
break;
case dtype_short:
request->add_byte(blr_short);
request->add_byte(field->fld_scale);
2001-05-23 15:26:42 +02:00
break;
case dtype_long:
request->add_byte(blr_long);
request->add_byte(field->fld_scale);
2001-05-23 15:26:42 +02:00
break;
case dtype_blob:
case dtype_quad:
request->add_byte(blr_quad);
request->add_byte(field->fld_scale);
2001-05-23 15:26:42 +02:00
break;
// Begin sql date/time/timestamp
2001-05-23 15:26:42 +02:00
case dtype_sql_date:
request->add_byte(blr_sql_date);
2001-05-23 15:26:42 +02:00
break;
case dtype_sql_time:
request->add_byte(blr_sql_time);
2001-05-23 15:26:42 +02:00
break;
case dtype_timestamp:
request->add_byte(blr_timestamp);
2001-05-23 15:26:42 +02:00
break;
// Begin sql date/time/timestamp
2001-05-23 15:26:42 +02:00
case dtype_int64:
request->add_byte(blr_int64);
request->add_byte(field->fld_scale);
2001-05-23 15:26:42 +02:00
break;
case dtype_real:
request->add_byte(blr_float);
2001-05-23 15:26:42 +02:00
break;
case dtype_double:
if (gpreGlob.sw_d_float)
request->add_byte(blr_d_float);
2001-05-23 15:26:42 +02:00
else
request->add_byte(blr_double);
2001-05-23 15:26:42 +02:00
break;
default:
{
TEXT s[50];
sprintf(s, "datatype %d not understood", field->fld_dtype);
CPR_error(s);
}
2001-05-23 15:26:42 +02:00
}
}
//____________________________________________________________
2008-12-05 02:20:14 +01:00
//
2001-05-23 15:26:42 +02:00
// Generate blr tree for for statement
2008-12-05 02:20:14 +01:00
//
2001-05-23 15:26:42 +02:00
static void cmp_for( gpre_req* request)
2001-05-23 15:26:42 +02:00
{
request->add_byte(blr_begin);
2001-05-23 15:26:42 +02:00
if (request->req_type == REQ_cursor && request->req_sync)
make_receive(request->req_sync, request);
request->add_byte(blr_for);
2001-05-23 15:26:42 +02:00
if (request->req_flags & REQ_sql_cursor)
{
2001-05-23 15:26:42 +02:00
if (!request->req_rse->rse_sort && !request->req_rse->rse_reduced)
for (gpre_ctx* context = (gpre_ctx*) request->req_contexts; context;
context = context->ctx_next)
{
if (context->ctx_scope_level == request->req_scope_level && context->ctx_procedure)
{
request->add_byte(blr_stall);
2001-05-23 15:26:42 +02:00
break;
}
}
}
CME_rse(request->req_rse, request);
// Loop thru actions looking for primary port. While we're at it,
// count the number of update actions.
2001-05-23 15:26:42 +02:00
bool updates = false;
for (act* action = request->req_actions; action; action = action->act_next)
{
2009-01-14 09:22:32 +01:00
switch (action->act_type)
{
2001-05-23 15:26:42 +02:00
case ACT_modify:
case ACT_update:
case ACT_erase:
updates = true;
break;
2001-05-23 15:26:42 +02:00
}
}
2008-12-05 02:20:14 +01:00
2001-05-23 15:26:42 +02:00
if (updates)
request->add_byte(blr_begin);
2001-05-23 15:26:42 +02:00
// Build the primary send statement
2001-05-23 15:26:42 +02:00
gpre_port* port = request->req_primary;
2001-05-23 15:26:42 +02:00
make_send(port, request);
gpre_nod* field = MSC_node(nod_field, 1);
gpre_nod* value = MSC_node(nod_value, 1);
request->add_byte(blr_begin);
2001-05-23 15:26:42 +02:00
for (ref* reference = port->por_references; reference; reference = reference->ref_next)
{
2001-05-23 15:26:42 +02:00
CMP_check(request, 0);
if (reference->ref_master)
continue;
request->add_byte(blr_assignment);
2009-06-25 12:44:37 +02:00
if (reference->ref_field == eof_field)
{
2001-05-23 15:26:42 +02:00
request->req_eof = reference;
CME_expr(lit1, request);
}
else if (reference->ref_field == slack_byte_field)
CME_expr(lit0, request);
2009-06-25 12:44:37 +02:00
else
{
2001-05-23 15:26:42 +02:00
if (reference->ref_expr)
CME_expr(reference->ref_expr, request);
2009-06-25 12:44:37 +02:00
else
{
field->nod_arg[0] = (gpre_nod*) reference;
2001-05-23 15:26:42 +02:00
CME_expr(field, request);
}
}
value->nod_arg[0] = (gpre_nod*) reference;
2001-05-23 15:26:42 +02:00
CME_expr(value, request);
}
request->add_byte(blr_end);
2001-05-23 15:26:42 +02:00
// If there are any actions, handle them here
2001-05-23 15:26:42 +02:00
if (updates)
{
request->add_byte(blr_label);
request->add_byte(0);
request->add_byte(blr_loop);
request->add_byte(blr_select);
2001-05-23 15:26:42 +02:00
make_receive(request->req_sync, request);
request->add_byte(blr_leave);
request->add_byte(0);
2001-05-23 15:26:42 +02:00
for (act* action = request->req_actions; action; action = action->act_next)
{
2009-01-14 09:22:32 +01:00
switch (action->act_type)
{
2001-05-23 15:26:42 +02:00
case ACT_endmodify:
case ACT_update:
cmp_modify(action, request);
break;
case ACT_erase:
cmp_erase(action, request);
break;
}
}
request->add_byte(blr_end);
request->add_byte(blr_end);
2001-05-23 15:26:42 +02:00
}
// Make a send to signal end of file
2001-05-23 15:26:42 +02:00
make_send(port, request);
request->add_byte(blr_assignment);
2001-05-23 15:26:42 +02:00
CME_expr(lit0, request);
value->nod_arg[0] = (gpre_nod*) request->req_eof;
2001-05-23 15:26:42 +02:00
CME_expr(value, request);
request->add_byte(blr_end);
2001-05-23 15:26:42 +02:00
}
//____________________________________________________________
2008-12-05 02:20:14 +01:00
//
2001-05-23 15:26:42 +02:00
// Compile a mass looping update statement.
2008-12-05 02:20:14 +01:00
//
2001-05-23 15:26:42 +02:00
static void cmp_loop( gpre_req* request)
2001-05-23 15:26:42 +02:00
{
gpre_nod* node = request->req_node;
gpre_rse* selection = request->req_rse;
2001-05-23 15:26:42 +02:00
gpre_port* primary = request->req_primary;
2001-05-23 15:26:42 +02:00
make_send(primary, request);
request->add_byte(blr_begin);
gpre_nod* counter = MSC_node(nod_value, 1);
for (ref* reference = primary->por_references; reference; reference = reference->ref_next)
2003-09-11 04:13:46 +02:00
{
2008-12-05 02:20:14 +01:00
if (reference->ref_field == count_field)
counter->nod_arg[0] = (gpre_nod*) reference;
2003-09-11 04:13:46 +02:00
}
2001-05-23 15:26:42 +02:00
request->add_byte(blr_assignment);
2001-05-23 15:26:42 +02:00
CME_expr(lit0, request);
CME_expr(counter, request);
gpre_ctx* for_context = selection->rse_context[0];
gpre_ctx* update_context = request->req_update;
2001-05-23 15:26:42 +02:00
request->add_byte(blr_for);
2003-09-05 12:14:08 +02:00
CME_rse(selection, request);
request->add_byte(blr_begin);
2001-05-23 15:26:42 +02:00
2004-02-02 12:02:12 +01:00
switch (node->nod_type)
{
case nod_modify:
2003-09-11 04:13:46 +02:00
{
request->add_byte(blr_modify);
request->add_byte(for_context->ctx_internal);
request->add_byte(update_context->ctx_internal);
gpre_nod* list = node->nod_arg[0];
request->add_byte(blr_begin);
gpre_nod** ptr = list->nod_arg;
for (const gpre_nod* const* const end = ptr + list->nod_count; ptr < end; ptr++)
{
cmp_assignment(*ptr, request);
}
request->add_byte(blr_end);
2003-09-11 04:13:46 +02:00
}
2009-06-25 12:44:37 +02:00
break;
2004-02-02 12:02:12 +01:00
case nod_store:
2003-09-11 04:13:46 +02:00
{
update_context = (gpre_ctx*) node->nod_arg[0];
request->add_byte(blr_store);
CME_relation(update_context, request);
gpre_nod* list = node->nod_arg[1];
request->add_byte(blr_begin);
gpre_nod** ptr = list->nod_arg;
for (const gpre_nod* const* const end = ptr + list->nod_count; ptr < end; ptr++)
{
cmp_assignment(*ptr, request);
}
request->add_byte(blr_end);
2003-09-11 04:13:46 +02:00
}
2009-06-25 12:44:37 +02:00
break;
2004-02-02 12:02:12 +01:00
case nod_erase:
request->add_byte(blr_erase);
request->add_byte(for_context->ctx_internal);
2004-02-02 12:02:12 +01:00
break;
default:
fb_assert(false);
2001-05-23 15:26:42 +02:00
}
request->add_byte(blr_assignment);
request->add_byte(blr_add);
2001-05-23 15:26:42 +02:00
CME_expr(lit1, request);
CME_expr(counter, request);
CME_expr(counter, request);
request->add_byte(blr_end);
request->add_byte(blr_end);
2001-05-23 15:26:42 +02:00
}
//____________________________________________________________
2008-12-05 02:20:14 +01:00
//
2001-05-23 15:26:42 +02:00
// Generate a receive and modify tree for a modify action.
2008-12-05 02:20:14 +01:00
//
2001-05-23 15:26:42 +02:00
static void cmp_modify( act* action, gpre_req* request)
2001-05-23 15:26:42 +02:00
{
upd* update = (upd*) action->act_object;
gpre_port* port = update->upd_port;
2001-05-23 15:26:42 +02:00
make_receive(port, request);
if (action->act_error)
request->add_byte(blr_handler);
2001-05-23 15:26:42 +02:00
request->add_byte(blr_modify);
request->add_byte(update->upd_source->ctx_internal);
request->add_byte(update->upd_update->ctx_internal);
2001-05-23 15:26:42 +02:00
// count the references and build an assignment block
2001-05-23 15:26:42 +02:00
gpre_nod* list = update->upd_assignments;
request->add_byte(blr_begin);
2001-05-23 15:26:42 +02:00
gpre_nod** ptr = list->nod_arg;
for (const gpre_nod* const* const end = ptr + list->nod_count; ptr < end; ptr++)
{
const gpre_nod* field_node = (*ptr)->nod_arg[1];
const ref* reference = (ref*) field_node->nod_arg[0];
2001-05-23 15:26:42 +02:00
if ((field_node->nod_type != nod_field) || !reference->ref_master)
cmp_assignment(*ptr, request);
}
request->add_byte(blr_end);
2001-05-23 15:26:42 +02:00
}
//____________________________________________________________
2008-12-05 02:20:14 +01:00
//
2001-05-23 15:26:42 +02:00
// Build a request tree for a request.
2008-12-05 02:20:14 +01:00
//
2001-05-23 15:26:42 +02:00
static void cmp_port( gpre_port* port, gpre_req* request)
2001-05-23 15:26:42 +02:00
{
// build message definition for each port
2001-05-23 15:26:42 +02:00
request->add_byte(blr_message);
request->add_byte(port->por_msg_number);
request->add_word(port->por_count);
2001-05-23 15:26:42 +02:00
for (ref* reference = port->por_references; reference; reference = reference->ref_next)
{
2001-05-23 15:26:42 +02:00
CMP_check(request, 0);
cmp_field(request, reference->ref_field, reference);
}
}
//____________________________________________________________
2008-12-05 02:20:14 +01:00
//
// Compile a EXECUTE PROCEDURE request.
//
2001-05-23 15:26:42 +02:00
static void cmp_procedure( gpre_req* request)
2001-05-23 15:26:42 +02:00
{
act* action = request->req_actions;
gpre_prc* procedure = (gpre_prc*) action->act_object;
2001-05-23 15:26:42 +02:00
// Remember the order of the references. The exec_proc blr verb
// requires parameters to be in parameter order which may be changed
// when there references are expanded.
2001-05-23 15:26:42 +02:00
2004-02-02 12:02:12 +01:00
gpre_lls* outputs = NULL;
ref* reference = request->req_references;
2009-06-25 12:44:37 +02:00
if (reference)
{
for (gpre_lls** list = &outputs; reference; reference = reference->ref_next)
{
MSC_push((gpre_nod*) reference, list);
2001-05-23 15:26:42 +02:00
list = &(*list)->lls_next;
}
}
2001-05-23 15:26:42 +02:00
// Expand any incomplete references or values.
2001-05-23 15:26:42 +02:00
expand_references(request->req_values);
expand_references(request->req_references);
2008-03-10 09:31:35 +01:00
request->req_blr = request->req_base = MSC_alloc(500);
2001-05-23 15:26:42 +02:00
request->req_length = 500;
if (request->req_flags & REQ_blr_version4)
request->add_byte(blr_version4);
2001-05-23 15:26:42 +02:00
else
request->add_byte(blr_version5);
request->add_byte(blr_begin);
2001-05-23 15:26:42 +02:00
2009-06-25 12:44:37 +02:00
if (request->req_values)
{
2001-05-23 15:26:42 +02:00
request->req_vport = make_port(request, request->req_values);
request->req_values = request->req_vport->por_references;
}
else
request->req_count++;
request->req_primary = make_port(request, request->req_references);
request->req_references = request->req_primary->por_references;
// build message definition for each port
2001-05-23 15:26:42 +02:00
for (gpre_port* port = request->req_ports; port; port = port->por_next)
2001-05-23 15:26:42 +02:00
cmp_port(port, request);
2009-06-25 12:44:37 +02:00
if (request->req_values)
{
request->add_byte(blr_begin);
2001-05-23 15:26:42 +02:00
make_send(request->req_vport, request);
}
2009-06-25 12:44:37 +02:00
if (gpreGlob.sw_ids)
{
request->add_byte(blr_exec_pid);
request->add_word(procedure->prc_id);
2001-05-23 15:26:42 +02:00
}
2009-06-25 12:44:37 +02:00
else
{
request->add_byte(blr_exec_proc);
2001-05-23 15:26:42 +02:00
CMP_stuff_symbol(request, procedure->prc_symbol);
}
2009-06-25 12:44:37 +02:00
if (procedure->prc_in_count)
{
request->add_word(procedure->prc_in_count);
gpre_nod** ptr = request->req_node->nod_arg;
for (const gpre_nod* const* const end = ptr + procedure->prc_in_count; ptr < end; ptr++)
{
2001-05-23 15:26:42 +02:00
CME_expr(*ptr, request);
}
2001-05-23 15:26:42 +02:00
}
else
request->add_word(0);
2001-05-23 15:26:42 +02:00
2009-06-25 12:44:37 +02:00
if (request->req_references)
{
gpre_nod* node = MSC_node(nod_value, 1);
request->add_word(procedure->prc_out_count);
2009-06-25 12:44:37 +02:00
for (; outputs; outputs = outputs->lls_next)
{
2001-05-23 15:26:42 +02:00
node->nod_arg[0] = outputs->lls_object;
CME_expr(node, request);
}
}
else
request->add_word(0);
2001-05-23 15:26:42 +02:00
if (request->req_values)
request->add_byte(blr_end);
request->add_byte(blr_end);
request->add_byte(blr_eoc);
2001-05-23 15:26:42 +02:00
request->req_length = request->req_blr - request->req_base;
request->req_blr = request->req_base;
}
//____________________________________________________________
2008-12-05 02:20:14 +01:00
//
2001-05-23 15:26:42 +02:00
// Generate parameter buffer for READY with
// buffercount.
2008-12-05 02:20:14 +01:00
//
2001-05-23 15:26:42 +02:00
static void cmp_ready( gpre_req* request)
2001-05-23 15:26:42 +02:00
{
2009-01-14 09:22:32 +01:00
gpre_dbb* db = request->req_database;
2001-05-23 15:26:42 +02:00
//act* action = request->req_actions;
2003-10-15 03:18:01 +02:00
request->req_blr = request->req_base = MSC_alloc(250);
2001-05-23 15:26:42 +02:00
request->req_length = 250;
request->req_flags |= REQ_exp_hand;
request->add_byte(isc_dpb_version1);
2001-05-23 15:26:42 +02:00
#ifdef NOT_USED_OR_REPLACED
2009-06-25 12:44:37 +02:00
if (db->dbb_allocation)
{
request->add_byte(isc_dpb_allocation);
request->add_byte(4);
request->add_long(db->dbb_allocation);
2001-05-23 15:26:42 +02:00
}
#endif
2001-05-23 15:26:42 +02:00
2009-06-25 12:44:37 +02:00
if (db->dbb_pagesize)
{
request->add_byte(isc_dpb_page_size);
request->add_byte(4);
request->add_long(db->dbb_pagesize);
2001-05-23 15:26:42 +02:00
}
2009-06-25 12:44:37 +02:00
if (db->dbb_buffercount)
{
request->add_byte(isc_dpb_num_buffers);
request->add_byte(4);
request->add_long(db->dbb_buffercount);
2001-05-23 15:26:42 +02:00
}
const TEXT* p;
SSHORT l;
2008-12-05 02:20:14 +01:00
2009-06-25 12:44:37 +02:00
if (db->dbb_c_user && !db->dbb_r_user)
{
request->add_byte(isc_dpb_user_name);
2001-05-23 15:26:42 +02:00
l = strlen(db->dbb_c_user);
request->add_byte(l);
2001-05-23 15:26:42 +02:00
p = db->dbb_c_user;
while (l--)
request->add_byte(*p++);
2001-05-23 15:26:42 +02:00
}
2009-06-25 12:44:37 +02:00
if (db->dbb_c_password && !db->dbb_r_password)
{
request->add_byte(isc_dpb_password);
2001-05-23 15:26:42 +02:00
l = strlen(db->dbb_c_password);
request->add_byte(l);
2001-05-23 15:26:42 +02:00
p = db->dbb_c_password;
while (l--)
request->add_byte(*p++);
2001-05-23 15:26:42 +02:00
}
2009-06-25 12:44:37 +02:00
if (db->dbb_c_sql_role && !db->dbb_r_sql_role)
{
request->add_byte(isc_dpb_sql_role_name);
2001-05-23 15:26:42 +02:00
l = strlen(db->dbb_c_sql_role);
request->add_byte(l);
2001-05-23 15:26:42 +02:00
p = db->dbb_c_sql_role;
while (l--)
request->add_byte(*p++);
2001-05-23 15:26:42 +02:00
}
2009-06-25 12:44:37 +02:00
if (db->dbb_c_lc_messages && !db->dbb_r_lc_messages)
{
2008-12-05 02:20:14 +01:00
// Language must be an ASCII string
request->add_byte(isc_dpb_lc_messages);
2001-05-23 15:26:42 +02:00
l = strlen(db->dbb_c_lc_messages);
request->add_byte(l);
2001-05-23 15:26:42 +02:00
p = db->dbb_c_lc_messages;
while (l--)
request->add_byte(*p++);
2001-05-23 15:26:42 +02:00
}
2009-06-25 12:44:37 +02:00
if (db->dbb_c_lc_ctype && !db->dbb_r_lc_ctype)
{
2008-12-05 02:20:14 +01:00
// Character Format must be an ASCII string
request->add_byte(isc_dpb_lc_ctype);
2001-05-23 15:26:42 +02:00
l = strlen(db->dbb_c_lc_ctype);
request->add_byte(l);
2001-05-23 15:26:42 +02:00
p = db->dbb_c_lc_ctype;
while (l--)
request->add_byte(*p++);
2001-05-23 15:26:42 +02:00
}
*request->req_blr = 0;
request->req_length = request->req_blr - request->req_base;
if (request->req_length == 1)
request->req_length = 0;
request->req_blr = request->req_base;
}
//____________________________________________________________
2008-12-05 02:20:14 +01:00
//
2001-05-23 15:26:42 +02:00
// Build in a fudge to bias the language specific subscript to the
// declared array subscript [i.e. C subscripts are zero based].
2008-12-05 02:20:14 +01:00
//
2001-05-23 15:26:42 +02:00
static void cmp_sdl_fudge( gpre_req* request, SLONG lower_bound)
2001-05-23 15:26:42 +02:00
{
2009-01-14 09:22:32 +01:00
switch (gpreGlob.sw_language)
{
2001-05-23 15:26:42 +02:00
case lang_c:
case lang_cxx:
case lang_internal:
2001-05-23 15:26:42 +02:00
if (!lower_bound)
break;
request->add_byte(isc_sdl_add);
2001-05-23 15:26:42 +02:00
cmp_sdl_number(request, lower_bound);
break;
case lang_fortran:
if (lower_bound == 1)
break;
request->add_byte(isc_sdl_add);
2001-05-23 15:26:42 +02:00
cmp_sdl_number(request, lower_bound - 1);
break;
}
}
//____________________________________________________________
2008-12-05 02:20:14 +01:00
//
2001-05-23 15:26:42 +02:00
// Build an SDL loop for GET_SLICE/PUT_SLICE unless the upper and
// lower bounds are constant. Return true if a loop has been built,
// otherwise false.
2008-12-05 02:20:14 +01:00
//
2001-05-23 15:26:42 +02:00
static bool cmp_sdl_loop(gpre_req* request,
USHORT index,
const slc* slice,
const ary* array)
2001-05-23 15:26:42 +02:00
{
const slc::slc_repeat* ranges = slice->slc_rpt + index;
2001-05-23 15:26:42 +02:00
if (ranges->slc_upper == ranges->slc_lower) {
return false;
2001-05-23 15:26:42 +02:00
}
const ary::ary_repeat* bounds = array->ary_rpt + index;
2001-05-23 15:26:42 +02:00
request->add_byte(isc_sdl_do2);
request->add_byte(slice->slc_parameters + index);
2001-05-23 15:26:42 +02:00
cmp_sdl_fudge(request, bounds->ary_lower);
cmp_sdl_value(request, ranges->slc_lower);
cmp_sdl_fudge(request, bounds->ary_lower);
cmp_sdl_value(request, ranges->slc_upper);
return true;
2001-05-23 15:26:42 +02:00
}
//____________________________________________________________
2008-12-05 02:20:14 +01:00
//
2001-05-23 15:26:42 +02:00
// Write the number in the 'smallest'
// form possible to the SDL string.
2008-12-05 02:20:14 +01:00
//
2001-05-23 15:26:42 +02:00
static void cmp_sdl_number( gpre_req* request, SLONG number)
2001-05-23 15:26:42 +02:00
{
2009-06-25 12:44:37 +02:00
if ((number > -16) && (number < 15))
{
request->add_byte(isc_sdl_tiny_integer);
request->add_byte(number);
2001-05-23 15:26:42 +02:00
}
2009-06-25 12:44:37 +02:00
else if ((number > -32768) && (number < 32767))
{
request->add_byte(isc_sdl_short_integer);
request->add_word(number);
2001-05-23 15:26:42 +02:00
}
2009-06-25 12:44:37 +02:00
else
{
request->add_byte(isc_sdl_long_integer);
request->add_long(number);
2001-05-23 15:26:42 +02:00
}
}
//____________________________________________________________
2008-12-05 02:20:14 +01:00
//
2001-05-23 15:26:42 +02:00
// Build an SDL loop for GET_SLICE/PUT_SLICE unless the upper and
// lower bounds are constant.
2008-12-05 02:20:14 +01:00
//
2001-05-23 15:26:42 +02:00
2009-04-26 12:24:44 +02:00
static void cmp_sdl_subscript(gpre_req* request, USHORT index, const slc* slice)
2001-05-23 15:26:42 +02:00
{
const slc::slc_repeat* ranges = slice->slc_rpt + index;
2001-05-23 15:26:42 +02:00
2009-06-25 12:44:37 +02:00
if (ranges->slc_upper == ranges->slc_lower)
{
2001-05-23 15:26:42 +02:00
cmp_sdl_value(request, ranges->slc_upper);
return;
}
request->add_byte(isc_sdl_variable);
request->add_byte(slice->slc_parameters + index);
2001-05-23 15:26:42 +02:00
}
//____________________________________________________________
2008-12-05 02:20:14 +01:00
//
2001-05-23 15:26:42 +02:00
// Stuff a slice description language value.
2008-12-05 02:20:14 +01:00
//
2001-05-23 15:26:42 +02:00
static void cmp_sdl_value( gpre_req* request, const gpre_nod* node)
2001-05-23 15:26:42 +02:00
{
const ref* reference = (ref*) node->nod_arg[0];
2001-05-23 15:26:42 +02:00
2009-01-14 09:22:32 +01:00
switch (node->nod_type)
{
2001-05-23 15:26:42 +02:00
case nod_literal:
cmp_sdl_number(request, atoi(reference->ref_value));
return;
case nod_value:
request->add_byte(isc_sdl_variable);
request->add_byte(reference->ref_id);
2001-05-23 15:26:42 +02:00
return;
default:
CPR_error("cmp_sdl_value: node not understood");
}
}
//____________________________________________________________
2008-12-05 02:20:14 +01:00
//
2001-05-23 15:26:42 +02:00
// generate blr for set generator
2008-12-05 02:20:14 +01:00
//
2001-05-23 15:26:42 +02:00
static void cmp_set_generator( gpre_req* request)
2001-05-23 15:26:42 +02:00
{
act* action = request->req_actions;
2001-05-23 15:26:42 +02:00
request->add_byte(blr_set_generator);
const set_gen* setgen = (set_gen*) action->act_object;
const TEXT* string = setgen->sgen_name;
const SLONG value = setgen->sgen_value;
const SINT64 int64value = setgen->sgen_int64value;
request->add_byte(strlen(string));
2001-05-23 15:26:42 +02:00
while (*string)
request->add_byte(*string++);
request->add_byte(blr_literal);
2009-06-25 12:44:37 +02:00
if (setgen->sgen_dialect == SQL_DIALECT_V5)
{
request->add_byte(blr_long);
request->add_byte(0);
request->add_word(value);
request->add_word(value >> 16);
2001-05-23 15:26:42 +02:00
}
2009-06-25 12:44:37 +02:00
else
{
request->add_byte(blr_int64);
request->add_byte(0);
request->add_word(int64value);
request->add_word(int64value >> 16);
request->add_word(int64value >> 32);
request->add_word(int64value >> 48);
2001-05-23 15:26:42 +02:00
}
}
//____________________________________________________________
2008-12-05 02:20:14 +01:00
//
//
2001-05-23 15:26:42 +02:00
static void cmp_slice( gpre_req* request)
2001-05-23 15:26:42 +02:00
{
slc* slice = request->req_slice;
const gpre_fld* field = slice->slc_field;
gpre_fld* element = field->fld_array;
const ary* array = field->fld_array_info;
2001-05-23 15:26:42 +02:00
// Process variable references
2001-05-23 15:26:42 +02:00
for (ref* reference = request->req_values; reference; reference = reference->ref_next)
{
reference->ref_id = slice->slc_parameters++;
}
2001-05-23 15:26:42 +02:00
2008-03-10 09:31:35 +01:00
request->req_blr = request->req_base = MSC_alloc(500);
2001-05-23 15:26:42 +02:00
request->req_length = 500;
request->add_byte(isc_sdl_version1);
request->add_byte(isc_sdl_struct);
request->add_byte(1);
2001-05-23 15:26:42 +02:00
cmp_field(request, element, 0);
request->add_byte(isc_sdl_relation);
2001-05-23 15:26:42 +02:00
CMP_stuff_symbol(request, field->fld_relation->rel_symbol);
request->add_byte(isc_sdl_field);
2001-05-23 15:26:42 +02:00
CMP_stuff_symbol(request, field->fld_symbol);
bool loop_flags[MAX_ARRAY_DIMENSIONS];
{ // scope block
fb_assert(slice->slc_dimensions <= MAX_ARRAY_DIMENSIONS);
USHORT n = 0;
for (bool* p = loop_flags; n < slice->slc_dimensions; n++, p++)
*p = cmp_sdl_loop(request, n, slice, array);
} // end scope block
2008-12-05 02:20:14 +01:00
request->add_byte(isc_sdl_element);
request->add_byte(1);
request->add_byte(isc_sdl_scalar);
request->add_byte(0);
request->add_byte(slice->slc_dimensions);
{ // scope block
USHORT n = 0;
2009-06-25 12:44:37 +02:00
for (const bool* p = loop_flags; n < slice->slc_dimensions; n++, p++)
{
if (!*p)
cmp_sdl_fudge(request, array->ary_rpt[n].ary_lower);
2009-04-26 12:24:44 +02:00
cmp_sdl_subscript(request, n, slice);
}
} // end scope block
2001-05-23 15:26:42 +02:00
request->add_byte(isc_sdl_eoc);
2001-05-23 15:26:42 +02:00
request->req_length = request->req_blr - request->req_base;
request->req_blr = request->req_base;
}
//____________________________________________________________
2008-12-05 02:20:14 +01:00
//
2001-05-23 15:26:42 +02:00
// Generate blr for a store request.
2008-12-05 02:20:14 +01:00
//
2001-05-23 15:26:42 +02:00
static void cmp_store( gpre_req* request)
2001-05-23 15:26:42 +02:00
{
// Make the store statement under the receive
2001-05-23 15:26:42 +02:00
if (request->req_type == REQ_store2)
request->add_byte(blr_store2);
2001-05-23 15:26:42 +02:00
else
request->add_byte(blr_store);
2001-05-23 15:26:42 +02:00
CME_relation(request->req_contexts, request);
// Make an assignment list
2001-05-23 15:26:42 +02:00
gpre_nod* list = request->req_node;
request->add_byte(blr_begin);
2001-05-23 15:26:42 +02:00
gpre_nod** ptr = list->nod_arg;
for (const gpre_nod* const* const end = ptr + list->nod_count; ptr < end; ptr++)
{
2001-05-23 15:26:42 +02:00
cmp_assignment(*ptr, request);
}
2001-05-23 15:26:42 +02:00
request->add_byte(blr_end);
2001-05-23 15:26:42 +02:00
if (request->req_type == REQ_store2)
{
2008-12-05 02:20:14 +01:00
// whip through actions to find return list
2001-05-23 15:26:42 +02:00
act* action;
2009-06-25 12:44:37 +02:00
for (action = request->req_actions;; action = action->act_next)
{
2001-05-23 15:26:42 +02:00
if (action->act_type == ACT_store2)
break;
}
request->add_byte(blr_begin);
upd* update = (upd*) action->act_object;
gpre_port* port = update->upd_port;
2001-05-23 15:26:42 +02:00
make_send(port, request);
list = update->upd_assignments;
const SSHORT count = list->nod_count;
if (count > 1)
request->add_byte(blr_begin);
2004-05-12 21:39:17 +02:00
gpre_nod** ptr2 = list->nod_arg;
for (const gpre_nod* const* const end = ptr2 + count; ptr2 < end; ptr2++)
cmp_assignment(*ptr2, request);
2001-05-23 15:26:42 +02:00
if (count > 1)
request->add_byte(blr_end);
request->add_byte(blr_end);
2001-05-23 15:26:42 +02:00
}
}
//____________________________________________________________
2008-12-05 02:20:14 +01:00
//
2001-05-23 15:26:42 +02:00
// During the parsing of an SQL statement
// we may have run into an indicator variable.
// If so, all we've got now is its name, and
// we really ought to build a full reference
// block for it before we forget.
2008-12-05 02:20:14 +01:00
//
2001-05-23 15:26:42 +02:00
static void expand_references( ref* reference)
2001-05-23 15:26:42 +02:00
{
2009-06-25 12:44:37 +02:00
for (; reference; reference = reference->ref_next)
{
if (reference->ref_null_value && !reference->ref_null)
{
ref* flag = (ref*) MSC_alloc(REF_LEN);
2001-05-23 15:26:42 +02:00
flag->ref_next = reference->ref_next;
reference->ref_next = reference->ref_null = flag;
flag->ref_master = reference;
flag->ref_value = reference->ref_null_value;
flag->ref_field = PAR_null_field();
}
}
}
//____________________________________________________________
2008-12-05 02:20:14 +01:00
//
2001-05-23 15:26:42 +02:00
// Make up a port block and process a linked list
// of field references.
2008-12-05 02:20:14 +01:00
//
2001-05-23 15:26:42 +02:00
static gpre_port* make_port( gpre_req* request, ref* reference)
2001-05-23 15:26:42 +02:00
{
gpre_port* port = (gpre_port*) MSC_alloc(POR_LEN);
2001-05-23 15:26:42 +02:00
port->por_ident = CMP_next_ident();
port->por_msg_number = request->req_count++;
port->por_next = request->req_ports;
request->req_ports = port;
// Hmmm -- no references. Not going to fly.
// Make up a dummy reference.
2001-05-23 15:26:42 +02:00
2009-06-25 12:44:37 +02:00
if (!reference)
{
reference = (ref*) MSC_alloc(REF_LEN);
2001-05-23 15:26:42 +02:00
reference->ref_field = eof_field;
}
ref* misc = 0;
ref* alignments[3];
alignments[0] = alignments[1] = alignments[2] = NULL;
2001-05-23 15:26:42 +02:00
for (ref* temp = reference; temp; temp = reference)
{
2001-05-23 15:26:42 +02:00
reference = reference->ref_next;
gpre_fld* field = temp->ref_field;
if (!field)
2001-05-23 15:26:42 +02:00
CPR_bugcheck("missing prototype field for value");
if (temp->ref_value && (temp->ref_flags & REF_array_elem))
field = field->fld_array;
2009-06-25 12:44:37 +02:00
if ((field->fld_length & 7) == 0)
{
2001-05-23 15:26:42 +02:00
temp->ref_next = alignments[2];
alignments[2] = temp;
}
2009-06-25 12:44:37 +02:00
else if ((field->fld_length & 3) == 0)
{
2001-05-23 15:26:42 +02:00
temp->ref_next = alignments[1];
alignments[1] = temp;
}
2009-06-25 12:44:37 +02:00
else if ((field->fld_length & 1) == 0)
{
2001-05-23 15:26:42 +02:00
temp->ref_next = alignments[0];
alignments[0] = temp;
}
2009-06-25 12:44:37 +02:00
else
{
2001-05-23 15:26:42 +02:00
temp->ref_next = misc;
misc = temp;
}
}
for (int i = 0; i <= 2; i++)
2009-06-25 12:44:37 +02:00
while (reference = alignments[i])
{
2001-05-23 15:26:42 +02:00
alignments[i] = reference->ref_next;
reference->ref_next = misc;
misc = reference;
}
port->por_references = misc;
for (reference = misc; reference; reference = reference->ref_next)
{
gpre_fld* field = reference->ref_field;
2001-05-23 15:26:42 +02:00
if (reference->ref_value && (reference->ref_flags & REF_array_elem))
field = field->fld_array;
reference->ref_ident = CMP_next_ident();
reference->ref_parameter = port->por_count++;
reference->ref_port = port;
#ifdef GPRE_FORTRAN
2001-05-23 15:26:42 +02:00
reference->ref_offset = port->por_length;
#endif
2001-05-23 15:26:42 +02:00
port->por_length += field->fld_length;
}
return port;
}
//____________________________________________________________
2008-12-05 02:20:14 +01:00
//
2001-05-23 15:26:42 +02:00
// Make a receive node for a given port.
2008-12-05 02:20:14 +01:00
//
2001-05-23 15:26:42 +02:00
static void make_receive( gpre_port* port, gpre_req* request)
2001-05-23 15:26:42 +02:00
{
request->add_byte(blr_receive);
request->add_byte(port->por_msg_number);
2001-05-23 15:26:42 +02:00
}
//____________________________________________________________
2008-12-05 02:20:14 +01:00
//
2001-05-23 15:26:42 +02:00
// Make a receive node for a given port.
2008-12-05 02:20:14 +01:00
//
2001-05-23 15:26:42 +02:00
static void make_send( gpre_port* port, gpre_req* request)
2001-05-23 15:26:42 +02:00
{
request->add_byte(blr_send);
request->add_byte(port->por_msg_number);
2001-05-23 15:26:42 +02:00
}
//____________________________________________________________
2008-12-05 02:20:14 +01:00
//
2001-05-23 15:26:42 +02:00
// where a duplicate reference list is used
// to build the port, fix request_references
2008-12-05 02:20:14 +01:00
//
2001-05-23 15:26:42 +02:00
static void update_references( ref* references)
2001-05-23 15:26:42 +02:00
{
2009-06-25 12:44:37 +02:00
for (ref* re = references; re; re = re->ref_next)
{
ref* source = re->ref_source;
2003-09-05 16:55:59 +02:00
source->ref_port = re->ref_port;
source->ref_parameter = re->ref_parameter;
source->ref_ident = re->ref_ident;
2001-05-23 15:26:42 +02:00
}
}