//____________________________________________________________ // // PROGRAM: C preprocessor // MODULE: cmp.cpp // DESCRIPTION: Request compiler // // 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): ______________________________________. // TMN (Mike Nordell) 11.APR.2001 - Reduce compiler warnings // // //____________________________________________________________ // // $Id: cmp.cpp,v 1.12 2003-02-27 16:05:13 brodsom Exp $ // #include "firebird.h" #include #include #include "../jrd/gds.h" #include "gpre.h" #include "../gpre/form.h" #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" extern "C" { extern TEXT *ident_pattern, *utility_name, *count_name, *slack_name, *transaction_name; static void cmp_any(GPRE_REQ); static void cmp_assignment(GPRE_NOD, GPRE_REQ); static void cmp_blob(BLB, BOOLEAN); static void cmp_blr(GPRE_REQ); static void cmp_erase(ACT, GPRE_REQ); static void cmp_fetch(ACT); static void cmp_field(GPRE_REQ, GPRE_FLD, REF); static void cmp_for(GPRE_REQ); #ifdef PYXIS static void cmp_form(GPRE_REQ); #endif static void cmp_loop(GPRE_REQ); #ifdef PYXIS static void cmp_menu(GPRE_REQ); #endif static void cmp_modify(ACT, GPRE_REQ); static void cmp_port(POR, GPRE_REQ); static void cmp_procedure(GPRE_REQ); static void cmp_ready(GPRE_REQ); static void cmp_sdl_fudge(GPRE_REQ, SLONG); static BOOLEAN cmp_sdl_loop(GPRE_REQ, USHORT, SLC, ARY); static void cmp_sdl_number(GPRE_REQ, SLONG); static void cmp_sdl_subscript(GPRE_REQ, USHORT, SLC, ARY); static void cmp_sdl_value(GPRE_REQ, 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 POR make_port(GPRE_REQ, REF); static void make_receive(POR, GPRE_REQ); static void make_send(POR, GPRE_REQ); static void update_references(REF); static GPRE_NOD lit0, lit1; static GPRE_FLD eof_field, count_field, slack_byte_field; static USHORT next_ident; #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) #define MAX_TPB 4000 #define BLR_LENGTH request->req_length = request->req_blr - request->req_base; request->req_blr = request->req_base //____________________________________________________________ // // 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. // void CMP_check( GPRE_REQ request, SSHORT min_reqd) { UCHAR *p, *q, *old; int length, n; length = request->req_blr - request->req_base; if (!(min_reqd) && (length < request->req_length - 100)) return; n = ((length + min_reqd + 100) > request->req_length * 2) ? length + min_reqd + 100 : request->req_length * 2; q = old = request->req_base; request->req_base = p = (UCHAR *) ALLOC(n); request->req_length = n; request->req_blr = request->req_base + length; do *p++ = *q++; while (--length); FREE(old); } //____________________________________________________________ // // 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. // void CMP_compile_request( GPRE_REQ request) { POR port; REF reference; ACT action; BLB blob; UPD update; #ifdef SCROLLABLE_CURSORS GPRE_FLD direction_field, offset_field; #endif // if there isn't a request handle specified, make one! if (!request->req_handle && (request->req_type != REQ_procedure)) { request->req_handle = (TEXT *) ALLOC(20); sprintf(request->req_handle, ident_pattern, CMP_next_ident()); } if (!request->req_trans) request->req_trans = transaction_name; 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. if (request->req_flags & (REQ_sql_blob_open | REQ_sql_blob_create)) { for (blob = request->req_blobs; blob; blob = blob->blb_next) cmp_blob(blob, TRUE); return; } // Before we get too far, make sure an eof field has been // constructed. If not, do so now. if (!eof_field) { eof_field = MET_make_field(utility_name, dtype_short, sizeof(SSHORT), FALSE); count_field = MET_make_field(count_name, dtype_long, sizeof(SLONG), FALSE); slack_byte_field = MET_make_field(slack_name, dtype_text, 1, FALSE); reference = (REF) ALLOC(REF_LEN); reference->ref_value = "0"; lit0 = MSC_unary(nod_literal, (GPRE_NOD) reference); reference = (REF) ALLOC(REF_LEN); reference->ref_value = "1"; lit1 = MSC_unary(nod_literal, (GPRE_NOD) reference); } // Handle different request types differently switch (request->req_type) { case REQ_create_database: case REQ_ddl: CMD_compile_ddl(request); return; #ifdef PYXIS case REQ_menu: cmp_menu(request); return; #endif case REQ_slice: cmp_slice(request); return; case REQ_ready: cmp_ready(request); return; #ifdef PYXIS case REQ_form: cmp_form(request); return; #endif case REQ_procedure: cmp_procedure(request); return; } // expand any incomplete references or values expand_references(request->req_references); expand_references(request->req_values); // Initialize the blr string request->req_blr = request->req_base = (UCHAR *) ALLOC(500); request->req_length = 500; if (request->req_flags & REQ_blr_version4) STUFF(blr_version4); else STUFF(blr_version5); // If there are values to be transmitted, make a port // to hold them if (request->req_values) request->req_vport = make_port(request, request->req_values); #ifdef SCROLLABLE_CURSORS // If there is an asynchronous message to be sent, make a port for it if (request->req_flags & REQ_sql_cursor && request->req_database->dbb_base_level >= 5) { direction_field = MET_make_field("direction", dtype_short, sizeof(SSHORT), FALSE); offset_field = MET_make_field("offset", dtype_long, sizeof(SLONG), FALSE); reference = request->req_avalues; reference->ref_field = direction_field; reference = reference->ref_next; reference->ref_field = offset_field; request->req_aport = make_port(request, request->req_avalues); } #endif // If this is a FOR type request, an eof field reference needs // to be generated. Do it. if (request->req_type == REQ_for || request->req_type == REQ_cursor || request->req_type == REQ_any) { reference = (REF) ALLOC(REF_LEN); reference->ref_field = eof_field; reference->ref_next = request->req_references; } else if (request->req_type == REQ_mass_update) { reference = (REF) ALLOC(REF_LEN); reference->ref_field = count_field; reference->ref_next = request->req_references; } else reference = request->req_references; // Assume that a general port needs to be constructed. if ((request->req_type != REQ_insert) && (request->req_type != REQ_store2) && (request->req_type != REQ_set_generator)) request->req_primary = port = make_port(request, reference); // Loop thru actions looking for something interesting to do. Not // all action types are "interesting", so don't worry about missing // ones. for (action = request->req_actions; action; action = action->act_next) switch (action->act_type) { case ACT_modify: case ACT_erase: case ACT_update: update = (UPD) action->act_object; 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: if (request->req_type == REQ_store2) { 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; 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; } cmp_blr(request); STUFF(blr_eoc); // Compute out final blr lengths 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 for (blob = request->req_blobs; blob; blob = blob->blb_next) cmp_blob(blob, FALSE); } #ifdef PYXIS //____________________________________________________________ // // CMP_display_code is called by the code generators to compute // the option words code for the form DISPLAY statement on a // field by field basis. If the user has specificed explicit // override of the field, -1 is returned. // int CMP_display_code(FINT display, REF reference) { int code; if (MSC_member((GPRE_NOD) reference, display->fint_override_fields)) return -1; code = 0; // Handle display attribute if (display->fint_flags & FINT_display_all) code |= PYXIS_OPT_DISPLAY; else if (MSC_member((GPRE_NOD) reference, display->fint_display_fields)) code |= PYXIS_OPT_DISPLAY; // Handle update attribute if (display->fint_flags & FINT_update_all) code |= PYXIS_OPT_UPDATE; else if (MSC_member((GPRE_NOD) reference, display->fint_update_fields)) code |= PYXIS_OPT_UPDATE; // Handle wakeup attribute if (display->fint_flags & FINT_wakeup_all) code |= PYXIS_OPT_WAKEUP; else if (MSC_member((GPRE_NOD) reference, display->fint_wakeup_fields)) code |= PYXIS_OPT_WAKEUP; // Handle cursor position attribute if (MSC_member((GPRE_NOD) reference, display->fint_position_fields)) code |= PYXIS_OPT_POSITION; return code; } #endif //____________________________________________________________ // // 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. // void CMP_external_field( GPRE_REQ request, GPRE_FLD field) { switch (field->fld_dtype) { case dtype_cstring: STUFF(blr_text2); STUFF_WORD(field->fld_ttype); STUFF_WORD(field->fld_length - 1); break; case dtype_text: STUFF(blr_text2); STUFF_WORD(field->fld_ttype); STUFF_WORD(field->fld_length); break; case dtype_varying: STUFF(blr_varying2); STUFF_WORD(field->fld_ttype); STUFF_WORD(field->fld_length); break; default: cmp_field(request, field, 0); break; } } //____________________________________________________________ // // Initialize (or re-initialize) for request compilation. This is // called at most once per module. // void CMP_init(void) { lit0 = lit1 = NULL; count_field = slack_byte_field = eof_field = NULL; next_ident = 0; } //____________________________________________________________ // // Give out next identifier. // USHORT CMP_next_ident(void) { return next_ident++; } //____________________________________________________________ // // Stuff a symbol. // void CMP_stuff_symbol( GPRE_REQ request, SYM symbol) { TEXT *p; STUFF(strlen(symbol->sym_string)); for (p = symbol->sym_string; *p; p++) STUFF(*p); } //____________________________________________________________ // // Take a transaction block with (potentially) a // lot of relation lock blocks, and generate TPBs // // We'll always generate TPB's, and link them // into the DBB for that database so they get // generated. If there's no lock list, we generate // a simple TPB for every database in the program. // If there is a lock list, we generate a more complex // TPB for each database referenced. // void CMP_t_start( GPRE_TRA trans) { char rrl_buffer[MAX_TPB]; char tpb_buffer[MAX_TRA_OPTIONS + 1]; char *text; char *p; char *q; DBB database; RRL lock_block; USHORT buff_len, tpb_len; TPB tpb; // fill out a standard tpb buffer ahead of time so we know // how large it is text = tpb_buffer; *text++ = gds_tpb_version1; *text++ = (trans->tra_flags & TRA_ro) ? gds_tpb_read : gds_tpb_write; if (trans->tra_flags & TRA_con) *text++ = gds_tpb_consistency; else if (trans->tra_flags & TRA_read_committed) *text++ = gds_tpb_read_committed; else *text++ = gds_tpb_concurrency; *text++ = (trans->tra_flags & TRA_nw) ? gds_tpb_nowait : gds_tpb_wait; if (trans->tra_flags & TRA_read_committed) *text++ = (trans-> tra_flags & TRA_rec_version) ? gds_tpb_rec_version : gds_tpb_no_rec_version; if (trans->tra_flags & TRA_autocommit) *text++ = gds_tpb_autocommit; if (trans->tra_flags & TRA_no_auto_undo) *text++ = gds_tpb_no_auto_undo; *text = 0; tpb_len = text - tpb_buffer; for (database = 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. */ if (trans->tra_flags & TRA_inc) { if (database->dbb_flags & DBB_in_trans) { tpb = (TPB) ALLOC(TPB_LEN(tpb_len)); tpb->tpb_length = tpb_len; database->dbb_flags &= ~DBB_in_trans; } else continue; } else if (!(trans->tra_flags & TRA_rrl)) { tpb = (TPB) ALLOC(TPB_LEN(tpb_len)); tpb->tpb_length = tpb_len; } else if (database->dbb_rrls) { p = rrl_buffer; for (lock_block = database->dbb_rrls; lock_block; lock_block = lock_block->rrl_next) { *p++ = lock_block->rrl_lock_mode; q = lock_block->rrl_relation->rel_symbol->sym_string; *p++ = strlen(q); while (*q) *p++ = *q++; *p++ = lock_block->rrl_lock_level; } *p = 0; buff_len = (p - rrl_buffer); tpb = (TPB) ALLOC(TPB_LEN(buff_len + tpb_len)); tpb->tpb_length = buff_len + tpb_len; database->dbb_rrls = NULL; } else /* this database isn't referenced */ continue; /* link this into the TPB chains (GPRE_TRA and DBB) */ tpb->tpb_database = database; tpb->tpb_dbb_next = database->dbb_tpbs; database->dbb_tpbs = tpb; tpb->tpb_tra_next = trans->tra_tpb; trans->tra_tpb = tpb; trans->tra_db_count++; /* fill in the standard TPB and concatenate the relation names */ tpb->tpb_ident = CMP_next_ident(); text = reinterpret_cast < char *>(tpb->tpb_string); for (p = tpb_buffer; *p;) *text++ = *p++; if (trans->tra_flags & TRA_rrl) strcpy(text, rrl_buffer); } } //____________________________________________________________ // // Generate blr tree for free standing ANY expression. // static void cmp_any( GPRE_REQ request) { GPRE_NOD value; POR port; REF reference, source; // Build the primary send statement port = request->req_primary; make_send(port, request); STUFF(blr_if); STUFF(blr_any); CME_rse(request->req_rse, request); value = MSC_unary(nod_value, (GPRE_NOD) port->por_references); // Make a send to signal end of file STUFF(blr_assignment); CME_expr(lit1, request); CME_expr(value, request); STUFF(blr_assignment); CME_expr(lit0, request); CME_expr(value, request); if (port = request->req_vport) for (reference = port->por_references; reference; reference = reference->ref_next) { reference->ref_source = source = (REF) ALLOC(REF_LEN); source->ref_ident = CMP_next_ident(); } } //____________________________________________________________ // // Compile a build assignment statement. // static void cmp_assignment( GPRE_NOD node, GPRE_REQ request) { CMP_check(request, 0); STUFF(blr_assignment); CME_expr(node->nod_arg[0], request); CME_expr(node->nod_arg[1], request); } //____________________________________________________________ // // Compile a blob parameter block, if required. // static void cmp_blob( BLB blob, BOOLEAN sql_flag) { UCHAR *p; REF reference; blob->blb_ident = CMP_next_ident(); blob->blb_buff_ident = CMP_next_ident(); blob->blb_len_ident = CMP_next_ident(); if (sql_flag) for (reference = blob->blb_reference; reference; reference = reference->ref_next) reference->ref_port = make_port(reference->ref_context->ctx_request, reference); if (!blob->blb_const_to_type && !blob->blb_type) return; blob->blb_bpb_ident = CMP_next_ident(); p = blob->blb_bpb; *p++ = gds_bpb_version1; if (blob->blb_const_to_type) { *p++ = gds_bpb_target_type; *p++ = 2; *p++ = (UCHAR) blob->blb_const_to_type; *p++ = blob->blb_const_to_type >> 8; } if (blob->blb_const_from_type) { *p++ = gds_bpb_source_type; *p++ = 2; *p++ = (UCHAR) blob->blb_const_from_type; *p++ = blob->blb_const_from_type >> 8; } if (blob->blb_type) { *p++ = gds_bpb_type; *p++ = 1; *p++ = (UCHAR) blob->blb_type; } if (blob->blb_from_charset) { /* create bpb instruction for source character set */ *p++ = gds_bpb_source_interp; *p++ = 2; *p++ = (UCHAR) blob->blb_from_charset; *p++ = blob->blb_from_charset >> 8; } if (blob->blb_to_charset) { /* create bpb instruction for target character set */ *p++ = gds_bpb_target_interp; *p++ = 2; *p++ = (UCHAR) blob->blb_to_charset; *p++ = blob->blb_to_charset >> 8; } blob->blb_bpb_length = p - blob->blb_bpb; } //____________________________________________________________ // // Build a request tree for a request. // static void cmp_blr( GPRE_REQ request) { POR port; STUFF(blr_begin); // build message definition for each port for (port = request->req_ports; port; port = port->por_next) cmp_port(port, request); // See if there is a receive to be built 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 switch (request->req_type) { 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 ***"); } STUFF(blr_end); } //____________________________________________________________ // // Generate blr for ERASE action. // static void cmp_erase( ACT action, GPRE_REQ request) { UPD update; GPRE_CTX source; update = (UPD) action->act_object; source = update->upd_source; make_receive(update->upd_port, request); if (action->act_error) STUFF(blr_handler); STUFF(blr_erase); STUFF(source->ctx_internal); } //____________________________________________________________ // // Go over an SQL fetch list and expand // references to indicator variables. // Not tough. // static void cmp_fetch( ACT action) { REF var; GPRE_NOD *ptr, *end, list; if (!(list = (GPRE_NOD) action->act_object)) return; if (list->nod_type != nod_list) CPR_error("invalid fetch action"); for (ptr = list->nod_arg, end = ptr + list->nod_count; ptr < end; ptr++) { var = (REF) * ptr; if (var->ref_null_value && !var->ref_null) if (var->ref_friend) var->ref_null = var->ref_friend->ref_null; } } //____________________________________________________________ // // Stuff field datatype info into request. // static void cmp_field( GPRE_REQ request, GPRE_FLD field, REF reference) { TEXT s[50]; if (reference && reference->ref_value && (reference->ref_flags & REF_array_elem)) field = field->fld_array; assert(field != NULL); assert(field->fld_dtype); assert(field->fld_length); switch (field->fld_dtype) { case dtype_cstring: if (!(field->fld_flags & FLD_charset)) { STUFF(blr_cstring); STUFF_WORD(field->fld_length); } else { /* 3.2j has new, tagged blr instruction for cstring */ STUFF(blr_cstring2); STUFF_WORD(field->fld_ttype); STUFF_WORD(field->fld_length); } break; case dtype_text: if (!(field->fld_flags & FLD_charset)) { STUFF(blr_text); STUFF_WORD(field->fld_length); } else { /* 3.2j has new, tagged blr instruction for text too */ STUFF(blr_text2); STUFF_WORD(field->fld_ttype); STUFF_WORD(field->fld_length); } break; case dtype_varying: if (!(field->fld_flags & FLD_charset)) { STUFF(blr_varying); STUFF_WORD(field->fld_length); } else { /* 3.2j has new, tagged blr instruction for varying also */ STUFF(blr_varying2); STUFF_WORD(field->fld_ttype); STUFF_WORD(field->fld_length); } break; case dtype_short: STUFF(blr_short); STUFF(field->fld_scale); break; case dtype_long: STUFF(blr_long); STUFF(field->fld_scale); break; case dtype_blob: #ifdef PYXIS if (request->req_type == REQ_form) { STUFF(blr_blob_id); STUFF_WORD(field->fld_sub_type); break; } #endif case dtype_quad: STUFF(blr_quad); STUFF(field->fld_scale); break; // ** Begin sql date/time/timestamp * case dtype_sql_date: STUFF(blr_sql_date); break; case dtype_sql_time: STUFF(blr_sql_time); break; case dtype_timestamp: STUFF(blr_timestamp); break; // ** Begin sql date/time/timestamp * case dtype_int64: STUFF(blr_int64); STUFF(field->fld_scale); break; case dtype_real: STUFF(blr_float); break; case dtype_double: if (sw_d_float) STUFF(blr_d_float); else STUFF(blr_double); break; default: sprintf(s, "datatype %d not understood", field->fld_dtype); CPR_error(s); } } //____________________________________________________________ // // Generate blr tree for for statement // static void cmp_for( GPRE_REQ request) { GPRE_NOD field, value; POR port; ACT action; REF reference; BOOLEAN updates; GPRE_CTX context; STUFF(blr_begin); if (request->req_type == REQ_cursor && request->req_sync) make_receive(request->req_sync, request); STUFF(blr_for); if (request->req_flags & REQ_sql_cursor) { if (!request->req_rse->rse_sort && !request->req_rse->rse_reduced) for (context = (GPRE_CTX) request->req_contexts; context; context = context->ctx_next) { if ((context->ctx_scope_level == request->req_scope_level) && context->ctx_procedure) { STUFF(blr_stall); 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. updates = FALSE; for (action = request->req_actions; action; action = action->act_next) switch (action->act_type) { case ACT_modify: case ACT_update: case ACT_erase: updates = TRUE; break; } if (updates) STUFF(blr_begin); // Build the primary send statement port = request->req_primary; make_send(port, request); field = MAKE_NODE(nod_field, 1); value = MAKE_NODE(nod_value, 1); STUFF(blr_begin); for (reference = port->por_references; reference; reference = reference->ref_next) { CMP_check(request, 0); if (reference->ref_master) continue; STUFF(blr_assignment); if (reference->ref_field == eof_field) { request->req_eof = reference; CME_expr(lit1, request); } else if (reference->ref_field == slack_byte_field) CME_expr(lit0, request); else { if (reference->ref_expr) CME_expr(reference->ref_expr, request); else { field->nod_arg[0] = (GPRE_NOD) reference; CME_expr(field, request); } } value->nod_arg[0] = (GPRE_NOD) reference; CME_expr(value, request); } STUFF(blr_end); // If there are any actions, handle them here if (updates) { STUFF(blr_label); STUFF(0); STUFF(blr_loop); STUFF(blr_select); make_receive(request->req_sync, request); STUFF(blr_leave); STUFF(0); for (action = request->req_actions; action; action = action->act_next) switch (action->act_type) { case ACT_endmodify: case ACT_update: cmp_modify(action, request); break; case ACT_erase: cmp_erase(action, request); break; } STUFF(blr_end); STUFF(blr_end); } // Make a send to signal end of file make_send(port, request); STUFF(blr_assignment); CME_expr(lit0, request); value->nod_arg[0] = (GPRE_NOD) request->req_eof; CME_expr(value, request); STUFF(blr_end); } #ifdef PYXIS //____________________________________________________________ // // Compile a FORM request. // This has very little to do with a BLR request. // static void cmp_form( GPRE_REQ request) { REF reference, option, parent; POR port; GPRE_FLD field; FORM form; form = request->req_form; if (!form->form_handle) { form->form_handle = (TEXT *) ALLOC(20); sprintf(form->form_handle, ident_pattern, CMP_next_ident()); } if (!request->req_form_handle) request->req_form_handle = form->form_handle; request->req_blr = request->req_base = (UCHAR *) ALLOC(500); request->req_length = 500; STUFF(PYXIS_MAP_VERSION1); make_port(request, request->req_references); port = request->req_ports; // If the request had no references, we need to generate the // bogus, one-field reference structure within the routine // but NOT generate the field into the blr message. Gawd. reference = port->por_references; if (reference->ref_field == eof_field) { STUFF(blr_message); STUFF(0); /* port->por_msg_number */ STUFF_WORD(0); /* port->por_count */ } else cmp_port(port, request); if (field = form->form_field) { STUFF(PYXIS_MAP_SUB_FORM); CMP_stuff_symbol(request, field->fld_symbol); } if (request->req_flags & REQ_transparent) STUFF(PYXIS_MAP_TRANSPARENT); if (request->req_flags & REQ_form_tag) STUFF(PYXIS_MAP_TAG); reference = port->por_references; if (!(reference->ref_field == eof_field)) for (; reference; reference = reference->ref_next) if (!(reference->ref_flags & REF_pseudo)) { CMP_check(request, 0); field = reference->ref_field; option = reference->ref_null; if (parent = reference->ref_friend) { STUFF(PYXIS_MAP_SUB_FIELD); CMP_stuff_symbol(request, parent->ref_field->fld_symbol); } else STUFF((option) ? PYXIS_MAP_FIELD2 : PYXIS_MAP_FIELD1); CMP_stuff_symbol(request, field->fld_symbol); STUFF_WORD(reference->ref_parameter); if (option) STUFF_WORD(option->ref_parameter); } if (reference = request->req_eof) { STUFF(PYXIS_MAP_TERMINATOR); STUFF_WORD(reference->ref_parameter); } if (reference = request->req_term_field) { STUFF(PYXIS_MAP_TERMINATING_FIELD); STUFF_WORD(reference->ref_parameter); } if (reference = request->req_index) { STUFF(PYXIS_MAP_ITEM_INDEX); STUFF_WORD(reference->ref_parameter); } STUFF(PYXIS_MAP_END); request->req_length = request->req_blr - request->req_base; request->req_blr = request->req_base; } #endif //____________________________________________________________ // // Compile a mass looping update statement. // static void cmp_loop( GPRE_REQ request) { GPRE_NOD node, list, *ptr, *end, counter; POR primary; GPRE_CTX for_context, update_context; RSE rse; REF reference; node = request->req_node; rse = request->req_rse; primary = request->req_primary; make_send(primary, request); STUFF(blr_begin); counter = MAKE_NODE(nod_value, 1); for (reference = primary->por_references; reference; reference = reference->ref_next) if (reference->ref_field == count_field) counter->nod_arg[0] = (GPRE_NOD) reference; STUFF(blr_assignment); CME_expr(lit0, request); CME_expr(counter, request); for_context = rse->rse_context[0]; update_context = request->req_update; STUFF(blr_for); CME_rse(rse, request); STUFF(blr_begin); if (node->nod_type == nod_modify) { STUFF(blr_modify); STUFF(for_context->ctx_internal); STUFF(update_context->ctx_internal); list = node->nod_arg[0]; STUFF(blr_begin); for (ptr = list->nod_arg, end = ptr + list->nod_count; ptr < end; ptr++) cmp_assignment(*ptr, request); STUFF(blr_end); } else if (node->nod_type == nod_store) { update_context = (GPRE_CTX) node->nod_arg[0]; STUFF(blr_store); CME_relation(update_context, request); list = node->nod_arg1; STUFF(blr_begin); for (ptr = list->nod_arg, end = ptr + list->nod_count; ptr < end; ptr++) cmp_assignment(*ptr, request); STUFF(blr_end); } else if (node->nod_type == nod_erase) { STUFF(blr_erase); STUFF(for_context->ctx_internal); } STUFF(blr_assignment); STUFF(blr_add); CME_expr(lit1, request); CME_expr(counter, request); CME_expr(counter, request); STUFF(blr_end); STUFF(blr_end); } #ifdef PYXIS //____________________________________________________________ // // Compile a MENU request. This has very little to do // with a BLR request. // static void cmp_menu( GPRE_REQ request) { ACT action, temp; TEXT *p; USHORT l, count; // Do not generate anything for for_menu and form_menu_item requests. if ((request->req_flags & REQ_menu_for) || (request->req_flags & REQ_menu_for_item)) return; request->req_blr = request->req_base = (UCHAR *) ALLOC(500); request->req_length = 500; STUFF(PYXIS_MENU_VERSION1); count = 0; // Reverse actions so menu will come out in right order for (temp = NULL; action = request->req_actions;) { request->req_actions = action->act_next; action->act_next = temp; temp = action; } request->req_actions = temp; if (request->req_flags & REQ_menu_tag) STUFF(PYXIS_MENU_HORIZONTAL); else if (request->req_flags & REQ_menu_pop_up) STUFF(PYXIS_MENU_VERTICAL); if (request->req_flags & REQ_transparent) STUFF(PYXIS_MENU_TRANSPARENT); for (action = request->req_actions; action; action = action->act_next) switch (action->act_type) { case ACT_menu_entree: STUFF(PYXIS_MENU_ENTREE); action->act_count = ++count; STUFF(action->act_count); p = (TEXT *) action->act_object; l = strlen(p); STUFF(l); while (*p) STUFF(*p++); break; case ACT_menu: STUFF(PYXIS_MENU_LABEL); p = (TEXT *) action->act_object; l = strlen(p); STUFF(l); while (*p) STUFF(*p++); break; } STUFF(PYXIS_MENU_END); request->req_length = request->req_blr - request->req_base; request->req_blr = request->req_base; } #endif //____________________________________________________________ // // Generate a receive and modify tree for a modify action. // static void cmp_modify( ACT action, GPRE_REQ request) { UPD update; GPRE_NOD list, field_node, *ptr, *end; REF reference; POR port; update = (UPD) action->act_object; port = update->upd_port; make_receive(port, request); if (action->act_error) STUFF(blr_handler); STUFF(blr_modify); STUFF(update->upd_source->ctx_internal); STUFF(update->upd_update->ctx_internal); // count the references and build an assignment block list = update->upd_assignments; STUFF(blr_begin); for (ptr = list->nod_arg, end = ptr + list->nod_count; ptr < end; ptr++) { field_node = (*ptr)->nod_arg[1]; reference = (REF) field_node->nod_arg[0]; if ((field_node->nod_type != nod_field) || !reference->ref_master) cmp_assignment(*ptr, request); } STUFF(blr_end); } //____________________________________________________________ // // Build a request tree for a request. // static void cmp_port( POR port, GPRE_REQ request) { REF reference; // build message definition for each port STUFF(blr_message); STUFF(port->por_msg_number); STUFF_WORD(port->por_count); for (reference = port->por_references; reference; reference = reference->ref_next) { CMP_check(request, 0); cmp_field(request, reference->ref_field, reference); } } //____________________________________________________________ // // Compile a EXECUTE PROCEDURE request. // static void cmp_procedure( GPRE_REQ request) { ACT action; POR port; GPRE_PRC procedure; REF reference; LLS outputs, *list; GPRE_NOD *ptr, *end, node; action = request->req_actions; procedure = (GPRE_PRC) action->act_object; // 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. outputs = NULL; if (reference = request->req_references) for (list = &outputs; reference; reference = reference->ref_next) { PUSH((GPRE_NOD) reference, list); list = &(*list)->lls_next; } // Expand any incomplete references or values. expand_references(request->req_values); expand_references(request->req_references); request->req_blr = request->req_base = (UCHAR *) ALLOC(500); request->req_length = 500; if (request->req_flags & REQ_blr_version4) STUFF(blr_version4); else STUFF(blr_version5); STUFF(blr_begin); if (request->req_values) { 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 for (port = request->req_ports; port; port = port->por_next) cmp_port(port, request); if (request->req_values) { STUFF(blr_begin); make_send(request->req_vport, request); } if (sw_ids) { STUFF(blr_exec_pid); STUFF_WORD(procedure->prc_id); } else { STUFF(blr_exec_proc); CMP_stuff_symbol(request, procedure->prc_symbol); } if (procedure->prc_in_count) { STUFF_WORD(procedure->prc_in_count); ptr = request->req_node->nod_arg; for (end = ptr + procedure->prc_in_count; ptr < end; ptr++) CME_expr(*ptr, request); } else STUFF_WORD(0); if (request->req_references) { node = MAKE_NODE(nod_value, 1); STUFF_WORD(procedure->prc_out_count); for (; outputs; outputs = outputs->lls_next) { node->nod_arg[0] = outputs->lls_object; CME_expr(node, request); } } else STUFF_WORD(0); if (request->req_values) STUFF(blr_end); STUFF(blr_end); STUFF(blr_eoc); request->req_length = request->req_blr - request->req_base; request->req_blr = request->req_base; } //____________________________________________________________ // // Generate parameter buffer for READY with // buffercount. // static void cmp_ready( GPRE_REQ request) { DBB db; ACT action; TEXT *p; SSHORT l; db = request->req_database; action = request->req_actions; request->req_blr = request->req_base = ALLOC(250); request->req_length = 250; request->req_flags |= REQ_exp_hand; STUFF(gds_dpb_version1); if (db->dbb_allocation) { STUFF(gds_dpb_allocation); STUFF(4); STUFF_INT(db->dbb_allocation); } if (db->dbb_pagesize) { STUFF(gds_dpb_page_size); STUFF(4); STUFF_INT(db->dbb_pagesize); } if (db->dbb_buffercount) { STUFF(gds_dpb_num_buffers); STUFF(4); STUFF_INT(db->dbb_buffercount); } if (db->dbb_buffersize) { STUFF(gds_dpb_buffer_length); STUFF(4); STUFF_INT(db->dbb_buffersize); } if (db->dbb_users) { STUFF(gds_dpb_number_of_users); STUFF(4); STUFF_INT(db->dbb_users); } if (db->dbb_c_user && !db->dbb_r_user) { STUFF(gds_dpb_user_name); l = strlen(db->dbb_c_user); STUFF(l); p = db->dbb_c_user; while (l--) STUFF(*p++); } if (db->dbb_c_password && !db->dbb_r_password) { STUFF(gds_dpb_password); l = strlen(db->dbb_c_password); STUFF(l); p = db->dbb_c_password; while (l--) STUFF(*p++); } if (db->dbb_c_sql_role && !db->dbb_r_sql_role) { STUFF(isc_dpb_sql_role_name); l = strlen(db->dbb_c_sql_role); STUFF(l); p = db->dbb_c_sql_role; while (l--) STUFF(*p++); } if (db->dbb_c_lc_messages && !db->dbb_r_lc_messages) { /* Language must be an ASCII string */ STUFF(gds_dpb_lc_messages); l = strlen(db->dbb_c_lc_messages); STUFF(l); p = db->dbb_c_lc_messages; while (l--) STUFF(*p++); } if (db->dbb_c_lc_ctype && !db->dbb_r_lc_ctype) { /* Character Format must be an ASCII string */ STUFF(gds_dpb_lc_ctype); l = strlen(db->dbb_c_lc_ctype); STUFF(l); p = db->dbb_c_lc_ctype; while (l--) STUFF(*p++); } *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; } //____________________________________________________________ // // Build in a fudge to bias the language specific subscript to the // declared array subscript [i.e. C subscripts are zero based]. // static void cmp_sdl_fudge( GPRE_REQ request, SLONG lower_bound) { switch (sw_language) { case lang_c: case lang_cxx: case lang_internal: if (!lower_bound) break; STUFF(gds_sdl_add); cmp_sdl_number(request, lower_bound); break; case lang_fortran: if (lower_bound == 1) break; STUFF(gds_sdl_add); cmp_sdl_number(request, lower_bound - 1); break; } } //____________________________________________________________ // // 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. // static BOOLEAN cmp_sdl_loop( GPRE_REQ request, USHORT index, SLC slice, ARY array) { slc::slc_repeat * ranges = slice->slc_rpt + index; if (ranges->slc_upper == ranges->slc_lower) { return FALSE; } ary::ary_repeat * bounds = array->ary_rpt + index; STUFF(gds_sdl_do2); STUFF(slice->slc_parameters + index); 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; } //____________________________________________________________ // // Write the number in the 'smallest' // form possible to the SDL string. // static void cmp_sdl_number( GPRE_REQ request, SLONG number) { if ((number > -16) && (number < 15)) { STUFF(gds_sdl_tiny_integer); STUFF(number); } else if ((number > -32768) && (number < 32767)) { STUFF(gds_sdl_short_integer); STUFF_WORD(number); } else { STUFF(gds_sdl_long_integer); STUFF_LONG(number); } } //____________________________________________________________ // // Build an SDL loop for GET_SLICE/PUT_SLICE unless the upper and // lower bounds are constant. // static void cmp_sdl_subscript( GPRE_REQ request, USHORT index, SLC slice, ARY array) { slc::slc_repeat * ranges = slice->slc_rpt + index; if (ranges->slc_upper == ranges->slc_lower) { cmp_sdl_value(request, ranges->slc_upper); return; } STUFF(gds_sdl_variable); STUFF(slice->slc_parameters + index); } //____________________________________________________________ // // Stuff a slice description language value. // static void cmp_sdl_value( GPRE_REQ request, GPRE_NOD node) { REF reference; reference = (REF) node->nod_arg[0]; switch (node->nod_type) { case nod_literal: cmp_sdl_number(request, atoi(reference->ref_value)); return; case nod_value: STUFF(gds_sdl_variable); STUFF(reference->ref_id); return; default: CPR_error("cmp_sdl_value: node not understood"); } } //____________________________________________________________ // // generate blr for set generator // static void cmp_set_generator( GPRE_REQ request) { SGEN setgen; TEXT *string; SLONG value; SINT64 int64value; ACT action; action = request->req_actions; STUFF(blr_set_generator); setgen = (SGEN) action->act_object; string = setgen->sgen_name; value = setgen->sgen_value; int64value = setgen->sgen_int64value; STUFF(strlen(string)); while (*string) STUFF(*string++); STUFF(blr_literal); if (setgen->sgen_dialect == SQL_DIALECT_V5) { STUFF(blr_long); STUFF(0); STUFF_WORD(value); STUFF_WORD(value >> 16); } else { STUFF(blr_int64); STUFF(0); STUFF_WORD(int64value); STUFF_WORD(int64value >> 16); STUFF_WORD(int64value >> 32); STUFF_WORD(int64value >> 48); } } //____________________________________________________________ // // static void cmp_slice( GPRE_REQ request) { SLC slice; GPRE_FLD field, element; ARY array; REF reference; USHORT n; BOOLEAN loop_flags[16], *p; slice = request->req_slice; field = slice->slc_field; element = field->fld_array; array = field->fld_array_info; // Process variable references for (reference = request->req_values; reference; reference = reference->ref_next) reference->ref_id = slice->slc_parameters++; request->req_blr = request->req_base = (UCHAR *) ALLOC(500); request->req_length = 500; STUFF(gds_sdl_version1); STUFF(gds_sdl_struct); STUFF(1); cmp_field(request, element, 0); STUFF(gds_sdl_relation); CMP_stuff_symbol(request, field->fld_relation->rel_symbol); STUFF(gds_sdl_field); CMP_stuff_symbol(request, field->fld_symbol); for (n = 0, p = loop_flags; n < slice->slc_dimensions; n++, p++) *p = cmp_sdl_loop(request, n, slice, array); STUFF(gds_sdl_element); STUFF(1); STUFF(gds_sdl_scalar); STUFF(0); STUFF(slice->slc_dimensions); for (n = 0, p = loop_flags; n < slice->slc_dimensions; n++, p++) { if (!*p) cmp_sdl_fudge(request, array->ary_rpt[n].ary_lower); cmp_sdl_subscript(request, n, slice, array); } STUFF(gds_sdl_eoc); request->req_length = request->req_blr - request->req_base; request->req_blr = request->req_base; } //____________________________________________________________ // // Generate blr for a store request. // static void cmp_store( GPRE_REQ request) { POR port; GPRE_NOD list, *ptr, *end; ACT action; UPD update; SSHORT count; // Make the store statement under the receive if (request->req_type == REQ_store2) STUFF(blr_store2); else STUFF(blr_store); CME_relation(request->req_contexts, request); // Make an assignment list list = request->req_node; STUFF(blr_begin); for (ptr = list->nod_arg, end = ptr + list->nod_count; ptr < end; ptr++) cmp_assignment(*ptr, request); STUFF(blr_end); if (request->req_type == REQ_store2) { /* whip through actions to find return list */ for (action = request->req_actions;; action = action->act_next) if (action->act_type == ACT_store2) break; STUFF(blr_begin); update = (UPD) action->act_object; port = update->upd_port; make_send(port, request); list = update->upd_assignments; if ((count = list->nod_count) > 1) STUFF(blr_begin); for (ptr = list->nod_arg, end = ptr + count; ptr < end; ptr++) cmp_assignment(*ptr, request); if (count > 1) STUFF(blr_end); STUFF(blr_end); } } //____________________________________________________________ // // 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. // static void expand_references( REF reference) { REF flag; for (; reference; reference = reference->ref_next) { if (reference->ref_null_value && !reference->ref_null) { flag = (REF) ALLOC(REF_LEN); 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(); } } } //____________________________________________________________ // // Make up a port block and process a linked list // of field references. // static POR make_port( GPRE_REQ request, REF reference) { POR port; GPRE_FLD field; REF misc, temp, alignments[3]; SSHORT i; port = (POR) ALLOC(POR_LEN); 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. if (!reference) { reference = (REF) ALLOC(REF_LEN); reference->ref_field = eof_field; } misc = alignments[0] = alignments[1] = alignments[2] = NULL; while (temp = reference) { reference = reference->ref_next; if (!(field = temp->ref_field)) CPR_bugcheck("missing prototype field for value"); if (temp->ref_value && (temp->ref_flags & REF_array_elem)) field = field->fld_array; if ((field->fld_length & 7) == 0) { temp->ref_next = alignments[2]; alignments[2] = temp; } else if ((field->fld_length & 3) == 0) { temp->ref_next = alignments[1]; alignments[1] = temp; } else if ((field->fld_length & 1) == 0) { temp->ref_next = alignments[0]; alignments[0] = temp; } else { temp->ref_next = misc; misc = temp; } } for (i = 0; i <= 2; i++) while (reference = alignments[i]) { alignments[i] = reference->ref_next; reference->ref_next = misc; misc = reference; } port->por_references = misc; for (reference = misc; reference; reference = reference->ref_next) { field = reference->ref_field; 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; reference->ref_offset = port->por_length; port->por_length += field->fld_length; } return port; } //____________________________________________________________ // // Make a receive node for a given port. // static void make_receive( POR port, GPRE_REQ request) { STUFF(blr_receive); STUFF(port->por_msg_number); } //____________________________________________________________ // // Make a receive node for a given port. // static void make_send( POR port, GPRE_REQ request) { STUFF(blr_send); STUFF(port->por_msg_number); } //____________________________________________________________ // // where a duplicate reference list is used // to build the port, fix request_references // static void update_references( REF references) { REF ref, source; for (ref = references; ref; ref = ref->ref_next) { source = ref->ref_source; source->ref_port = ref->ref_port; source->ref_parameter = ref->ref_parameter; source->ref_ident = ref->ref_ident; } } } // extern "C"