mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-01-23 02:03:04 +01:00
Front-ported CORE-4437 and CORE-4438.
This commit is contained in:
parent
dc0d56ed6d
commit
237c91d82b
@ -2487,15 +2487,36 @@ static void gen_loop( const act* action, int column)
|
||||
gen_s_start(action, column);
|
||||
const gpre_req* request = action->act_request;
|
||||
const gpre_port* port = request->req_primary;
|
||||
|
||||
printa(column, "if (!SQLCODE) ");
|
||||
column += INDENT;
|
||||
begin(column);
|
||||
|
||||
gen_receive(action, column, port);
|
||||
|
||||
endp(column);
|
||||
column -= INDENT;
|
||||
|
||||
gen_name(name, port->por_references, true);
|
||||
printa(column, "if (!SQLCODE && !%s)", name);
|
||||
printa(column + INDENT, "SQLCODE = 100;");
|
||||
endp(column);
|
||||
column -= INDENT;
|
||||
|
||||
if (request->req_flags & REQ_sql_returning)
|
||||
{
|
||||
printa(column, "if (!SQLCODE && %s)", name);
|
||||
column += INDENT;
|
||||
begin(column);
|
||||
|
||||
gpre_nod* var_list = (gpre_nod*) action->act_object;
|
||||
for (int i = 0; var_list && i < var_list->nod_count; i++)
|
||||
{
|
||||
align(column);
|
||||
asgn_to(action, (ref*) (var_list->nod_arg[i]), column);
|
||||
}
|
||||
|
||||
endp(column);
|
||||
column -= INDENT;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -3023,12 +3044,43 @@ static void gen_s_start( const act* action, int column)
|
||||
{
|
||||
make_ok_test(action, request, column);
|
||||
column += INDENT;
|
||||
begin(column);
|
||||
}
|
||||
|
||||
gen_start(action, port, column, false);
|
||||
set_sqlcode(action, column);
|
||||
|
||||
if (action->act_error || (action->act_flags & ACT_sql))
|
||||
{
|
||||
endp(column);
|
||||
column -= INDENT;
|
||||
}
|
||||
|
||||
if (request->req_type == REQ_insert && (request->req_flags & REQ_sql_returning))
|
||||
{
|
||||
printa(column, "if (!SQLCODE) ");
|
||||
column += INDENT;
|
||||
begin(column);
|
||||
|
||||
gen_receive(action, column, request->req_primary);
|
||||
|
||||
endp(column);
|
||||
column -= INDENT;
|
||||
|
||||
printa(column, "if (!SQLCODE) ");
|
||||
column += INDENT;
|
||||
begin(column);
|
||||
|
||||
gpre_nod* var_list = (gpre_nod*) action->act_object;
|
||||
for (int i = 0; var_list && i < var_list->nod_count; i++)
|
||||
{
|
||||
align(column);
|
||||
asgn_to(action, (ref*) (var_list->nod_arg[i]), column);
|
||||
}
|
||||
|
||||
endp(column);
|
||||
column -= INDENT;
|
||||
}
|
||||
|
||||
if (action->act_type == ACT_open)
|
||||
{
|
||||
@ -3037,8 +3089,6 @@ static void gen_s_start( const act* action, int column)
|
||||
endp(column);
|
||||
column -= INDENT;
|
||||
}
|
||||
|
||||
set_sqlcode(action, column);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1469,7 +1469,11 @@ static void cmp_field( const gpre_nod* node, gpre_req* request)
|
||||
if (!field)
|
||||
puts("cmp_field: symbol missing");
|
||||
|
||||
if (field->fld_flags & FLD_dbkey)
|
||||
if (context->ctx_flags & CTX_null)
|
||||
{
|
||||
request->add_byte(blr_null);
|
||||
}
|
||||
else if (field->fld_flags & FLD_dbkey)
|
||||
{
|
||||
request->add_byte(blr_dbkey);
|
||||
request->add_byte(context->ctx_internal);
|
||||
|
167
src/gpre/cmp.cpp
167
src/gpre/cmp.cpp
@ -45,6 +45,7 @@
|
||||
|
||||
static void cmp_any(gpre_req*);
|
||||
static void cmp_assignment(gpre_nod*, gpre_req*);
|
||||
static void cmp_assignment_list(gpre_nod*, gpre_req*);
|
||||
static void cmp_blob(blb*, bool);
|
||||
static void cmp_blr(gpre_req*);
|
||||
static void cmp_erase(act*, gpre_req*);
|
||||
@ -56,6 +57,7 @@ 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_returning(gpre_req*, gpre_nod*);
|
||||
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);
|
||||
@ -63,7 +65,7 @@ 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 cmp_store(gpre_req*, gpre_nod*);
|
||||
static void expand_references(ref*);
|
||||
static gpre_port* make_port(gpre_req*, ref*);
|
||||
static void make_receive(gpre_port*, gpre_req*);
|
||||
@ -227,8 +229,9 @@ void CMP_compile_request( gpre_req* request)
|
||||
// Assume that a general port needs to be constructed.
|
||||
|
||||
gpre_port* port;
|
||||
if ((request->req_type != REQ_insert) && (request->req_type != REQ_store2) &&
|
||||
(request->req_type != REQ_set_generator))
|
||||
if ((request->req_flags & REQ_sql_returning) ||
|
||||
((request->req_type != REQ_insert) && (request->req_type != REQ_store2)
|
||||
&& (request->req_type != REQ_set_generator)))
|
||||
{
|
||||
request->req_primary = port = make_port(request, reference);
|
||||
}
|
||||
@ -266,6 +269,8 @@ void CMP_compile_request( gpre_req* request)
|
||||
break;
|
||||
case ACT_select:
|
||||
case ACT_fetch:
|
||||
case ACT_loop:
|
||||
case ACT_insert:
|
||||
cmp_fetch(action);
|
||||
break;
|
||||
}
|
||||
@ -528,6 +533,26 @@ static void cmp_assignment( gpre_nod* node, gpre_req* request)
|
||||
}
|
||||
|
||||
|
||||
//____________________________________________________________
|
||||
//
|
||||
// Compile a build assignment statement.
|
||||
//
|
||||
|
||||
static void cmp_assignment_list( gpre_nod* list, gpre_req* request)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
//____________________________________________________________
|
||||
//
|
||||
// Compile a blob parameter block, if required.
|
||||
@ -639,7 +664,7 @@ static void cmp_blr( gpre_req* request)
|
||||
case REQ_insert:
|
||||
case REQ_store:
|
||||
case REQ_store2:
|
||||
cmp_store(request);
|
||||
cmp_store(request, request->req_node);
|
||||
break;
|
||||
|
||||
case REQ_mass_update:
|
||||
@ -967,7 +992,7 @@ static void cmp_for( gpre_req* request)
|
||||
|
||||
static void cmp_loop( gpre_req* request)
|
||||
{
|
||||
gpre_nod* node = request->req_node;
|
||||
gpre_nod* req_node = request->req_node;
|
||||
gpre_rse* selection = request->req_rse;
|
||||
|
||||
gpre_port* primary = request->req_primary;
|
||||
@ -991,41 +1016,38 @@ static void cmp_loop( gpre_req* request)
|
||||
CME_rse(selection, request);
|
||||
request->add_byte(blr_begin);
|
||||
|
||||
gpre_nod* node = (req_node->nod_type == nod_list) ? req_node->nod_arg[0] : req_node;
|
||||
|
||||
switch (node->nod_type)
|
||||
{
|
||||
case nod_modify:
|
||||
{
|
||||
request->add_byte(blr_modify);
|
||||
const int blr_op = (request->req_flags & REQ_sql_returning) ? blr_modify2 : blr_modify;
|
||||
request->add_byte(blr_op);
|
||||
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);
|
||||
cmp_assignment_list(node->nod_arg[0], request);
|
||||
if (request->req_flags & REQ_sql_returning)
|
||||
cmp_returning(request, node->nod_arg[1]);
|
||||
}
|
||||
break;
|
||||
case nod_store:
|
||||
{
|
||||
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);
|
||||
}
|
||||
cmp_store(request, node);
|
||||
break;
|
||||
case nod_erase:
|
||||
request->add_byte(blr_erase);
|
||||
request->add_byte(for_context->ctx_internal);
|
||||
if (request->req_flags & REQ_sql_returning)
|
||||
{
|
||||
request->add_byte(blr_begin);
|
||||
cmp_returning(request, node->nod_arg[0]);
|
||||
request->add_byte(blr_erase);
|
||||
request->add_byte(for_context->ctx_internal);
|
||||
request->add_byte(blr_end);
|
||||
}
|
||||
else
|
||||
{
|
||||
request->add_byte(blr_erase);
|
||||
request->add_byte(for_context->ctx_internal);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
fb_assert(false);
|
||||
@ -1038,6 +1060,29 @@ static void cmp_loop( gpre_req* request)
|
||||
CME_expr(counter, request);
|
||||
|
||||
request->add_byte(blr_end);
|
||||
|
||||
if (req_node->nod_type == nod_list)
|
||||
{
|
||||
request->add_byte(blr_if);
|
||||
request->add_byte(blr_eql);
|
||||
CME_expr(counter, request);
|
||||
CME_expr(lit0, request);
|
||||
|
||||
request->add_byte(blr_begin);
|
||||
|
||||
node = req_node->nod_arg[1];
|
||||
for_context->ctx_flags |= CTX_null;
|
||||
cmp_store(request, node);
|
||||
for_context->ctx_flags &= ~CTX_null;
|
||||
|
||||
request->add_byte(blr_assignment);
|
||||
CME_expr(lit1, request);
|
||||
CME_expr(counter, request);
|
||||
|
||||
request->add_byte(blr_end);
|
||||
request->add_byte(blr_end);
|
||||
}
|
||||
|
||||
request->add_byte(blr_end);
|
||||
}
|
||||
|
||||
@ -1306,6 +1351,30 @@ static void cmp_ready( gpre_req* request)
|
||||
}
|
||||
|
||||
|
||||
//____________________________________________________________
|
||||
//
|
||||
// Build assignments for values to be returned.
|
||||
//
|
||||
|
||||
static void cmp_returning(gpre_req* request, gpre_nod* ret_list)
|
||||
{
|
||||
gpre_nod* value = MSC_node(nod_value, 1);
|
||||
|
||||
request->add_byte(blr_begin);
|
||||
|
||||
for (int i = 0; i < ret_list->nod_count; i++)
|
||||
{
|
||||
request->add_byte(blr_assignment);
|
||||
CME_expr(ret_list->nod_arg[i]->nod_arg[0], request);
|
||||
ref* reference = (ref*) ret_list->nod_arg[i]->nod_arg[1];
|
||||
value->nod_arg[0] = (gpre_nod*) reference->ref_friend;
|
||||
CME_expr(value, request);
|
||||
}
|
||||
|
||||
request->add_byte(blr_end);
|
||||
}
|
||||
|
||||
|
||||
//____________________________________________________________
|
||||
//
|
||||
// Build in a fudge to bias the language specific subscript to the
|
||||
@ -1546,31 +1615,37 @@ static void cmp_slice( gpre_req* request)
|
||||
// Generate blr for a store request.
|
||||
//
|
||||
|
||||
static void cmp_store( gpre_req* request)
|
||||
static void cmp_store( gpre_req* request, gpre_nod* node)
|
||||
{
|
||||
gpre_ctx* context = (gpre_ctx*) node->nod_arg[0];
|
||||
gpre_nod* list = node->nod_arg[1];
|
||||
gpre_nod* ret_list = node->nod_arg[2];
|
||||
|
||||
// Make the store statement under the receive
|
||||
|
||||
if (request->req_type == REQ_store2)
|
||||
if (request->req_flags & REQ_sql_returning)
|
||||
{
|
||||
if (request->req_type == REQ_insert)
|
||||
make_send(request->req_primary, request);
|
||||
|
||||
request->add_byte(blr_store2);
|
||||
}
|
||||
else if (request->req_type == REQ_store2)
|
||||
request->add_byte(blr_store2);
|
||||
else
|
||||
request->add_byte(blr_store);
|
||||
|
||||
CME_relation(request->req_contexts, request);
|
||||
CME_relation(context, request);
|
||||
|
||||
// Make an assignment list
|
||||
|
||||
gpre_nod* list = request->req_node;
|
||||
request->add_byte(blr_begin);
|
||||
cmp_assignment_list(list, request);
|
||||
|
||||
gpre_nod** ptr = list->nod_arg;
|
||||
for (const gpre_nod* const* const end = ptr + list->nod_count; ptr < end; ptr++)
|
||||
if (request->req_flags & REQ_sql_returning)
|
||||
{
|
||||
cmp_assignment(*ptr, request);
|
||||
cmp_returning(request, ret_list);
|
||||
}
|
||||
|
||||
request->add_byte(blr_end);
|
||||
|
||||
if (request->req_type == REQ_store2)
|
||||
else if (request->req_type == REQ_store2)
|
||||
{
|
||||
// whip through actions to find return list
|
||||
|
||||
@ -1584,15 +1659,7 @@ static void cmp_store( gpre_req* request)
|
||||
upd* update = (upd*) action->act_object;
|
||||
gpre_port* port = update->upd_port;
|
||||
make_send(port, request);
|
||||
list = update->upd_assignments;
|
||||
const SSHORT count = list->nod_count;
|
||||
if (count > 1)
|
||||
request->add_byte(blr_begin);
|
||||
gpre_nod** ptr2 = list->nod_arg;
|
||||
for (const gpre_nod* const* const end = ptr2 + count; ptr2 < end; ptr2++)
|
||||
cmp_assignment(*ptr2, request);
|
||||
if (count > 1)
|
||||
request->add_byte(blr_end);
|
||||
cmp_assignment_list(update->upd_assignments, request);
|
||||
request->add_byte(blr_end);
|
||||
}
|
||||
}
|
||||
|
@ -1242,7 +1242,8 @@ enum req_flags_vals {
|
||||
REQ_sql_blob_open = 8192, // request is SQL open blob cursor
|
||||
REQ_sql_blob_create = 16384, // request is SQL create blob cursor
|
||||
REQ_sql_database_dyn = 32768, // request is to generate DYN to add files o database
|
||||
REQ_blr_version4 = 65536 // request must generate blr_version4
|
||||
REQ_blr_version4 = 65536, // request must generate blr_version4
|
||||
REQ_sql_returning = 131072 // RETURNING clause is present
|
||||
};
|
||||
|
||||
const size_t REQ_LEN = sizeof(gpre_req);
|
||||
@ -1261,6 +1262,11 @@ struct gpre_ctx {
|
||||
gpre_prc* ctx_procedure; // procedure for context
|
||||
gpre_nod* ctx_prc_inputs; // procedure input parameters
|
||||
gpre_rse* ctx_stream; // stream for context
|
||||
USHORT ctx_flags; // misc flags
|
||||
};
|
||||
|
||||
enum ctx_flags_vals {
|
||||
CTX_null = 1 // context evaluates to NULL
|
||||
};
|
||||
|
||||
const size_t CTX_LEN = sizeof(gpre_ctx);
|
||||
|
@ -328,7 +328,8 @@
|
||||
{"RESOURCE", KW_RESOURCE},
|
||||
{"RESTRICT", KW_RESTRICT},
|
||||
{"RETAIN", KW_RETAIN},
|
||||
{"RETURNING_VALUES", KW_RETURNING},
|
||||
{"RETURNING", KW_RETURNING},
|
||||
{"RETURNING_VALUES", KW_RETURNING_VALUES},
|
||||
{"RETURNS", KW_RETURNS},
|
||||
{"REVOKE", KW_REVOKE},
|
||||
{"RIGHT", KW_RIGHT},
|
||||
|
@ -2201,17 +2201,36 @@ static void gen_loop( const act* action, int column)
|
||||
gen_s_start(action, column);
|
||||
gpre_req* request = action->act_request;
|
||||
gpre_port* port = request->req_primary;
|
||||
|
||||
printa(column, "if SQLCODE = 0 then");
|
||||
column += INDENT;
|
||||
|
||||
gen_receive(action, column, port);
|
||||
|
||||
column -= INDENT;
|
||||
endif(column);
|
||||
|
||||
TEXT name[MAX_REF_SIZE];
|
||||
gen_name(name, port->por_references, true);
|
||||
printa(column, "if (SQLCODE = 0) and (%s = 0) then", name);
|
||||
printa(column + INDENT, "SQLCODE := 100;");
|
||||
endif(column);
|
||||
column -= INDENT;
|
||||
endif(column);
|
||||
|
||||
if (request->req_flags & REQ_sql_returning)
|
||||
{
|
||||
printa(column, "if (SQLCODE = 0) and (%s /= 0) then", name);
|
||||
column += INDENT;
|
||||
|
||||
gpre_nod* var_list = (gpre_nod*) action->act_object;
|
||||
for (int i = 0; var_list && i < var_list->nod_count; i++)
|
||||
{
|
||||
align(column);
|
||||
asgn_to(action, (ref*) (var_list->nod_arg[i]), column);
|
||||
}
|
||||
|
||||
column -= INDENT;
|
||||
endif(column);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -2733,13 +2752,37 @@ static void gen_s_start( const act* action, int column)
|
||||
asgn_from(action, port->por_references, column);
|
||||
|
||||
if (action->act_error || (action->act_flags & ACT_sql))
|
||||
{
|
||||
make_ok_test(action, request, column);
|
||||
gen_start(action, port, column + INDENT);
|
||||
|
||||
gen_start(action, port, column);
|
||||
set_sqlcode(action);
|
||||
|
||||
if (action->act_error || (action->act_flags & ACT_sql))
|
||||
endif(column);
|
||||
|
||||
if (request->req_type == REQ_insert && (request->req_flags & REQ_sql_returning))
|
||||
{
|
||||
printa(column, "if (SQLCODE = 0) then");
|
||||
column += INDENT;
|
||||
|
||||
gen_receive(action, column, request->req_primary);
|
||||
|
||||
endif(column);
|
||||
column -= INDENT;
|
||||
|
||||
printa(column, "if (SQLCODE = 0) then");
|
||||
column += INDENT;
|
||||
|
||||
gpre_nod* var_list = (gpre_nod*) action->act_object;
|
||||
for (int i = 0; var_list && i < var_list->nod_count; i++)
|
||||
{
|
||||
align(column);
|
||||
asgn_to(action, (ref*) (var_list->nod_arg[i]), column);
|
||||
}
|
||||
|
||||
endif(column);
|
||||
column -= INDENT;
|
||||
}
|
||||
else
|
||||
gen_start(action, port, column);
|
||||
|
||||
if (action->act_type == ACT_open)
|
||||
{
|
||||
|
@ -21,7 +21,7 @@
|
||||
// All Rights Reserved.
|
||||
// Contributor(s): ______________________________________.
|
||||
// Solaris x86 changes - Konstantin Kuznetsov, Neil McCalden
|
||||
// 8-Mar-2002 FSG (Frank Schlottmann-Gödde) tiny cobol support
|
||||
// 8-Mar-2002 FSG (Frank Schlottmann-G<EFBFBD>dde) tiny cobol support
|
||||
// fixed Bug No. 526204*
|
||||
//
|
||||
//
|
||||
@ -2713,16 +2713,30 @@ static void gen_loop( const act* action)
|
||||
{
|
||||
gen_s_start(action);
|
||||
const gpre_req* request = action->act_request;
|
||||
printa(names[COLUMN], false, "IF SQLCODE = 0 THEN");
|
||||
const gpre_port* port = request->req_primary;
|
||||
|
||||
printa(names[COLUMN], false, "IF SQLCODE = 0 THEN");
|
||||
gen_receive(action, port);
|
||||
printa(names[COLUMN], false, "END-IF");
|
||||
|
||||
TEXT name[MAX_REF_SIZE];
|
||||
gen_name(name, port->por_references, true);
|
||||
printa(names[COLUMN], false, "IF SQLCODE = 0 AND %s = 0 THEN ", name);
|
||||
printa(names[COLUMN], false, "MOVE 100 TO SQLCODE");
|
||||
printa(names[COLUMN], false, "END-IF");
|
||||
printa(names[COLUMN], false, "END-IF");
|
||||
|
||||
if (request->req_flags & REQ_sql_returning)
|
||||
{
|
||||
printa(names[COLUMN], false, "IF SQLCODE = 0 AND %s NOT = 0 THEN", name);
|
||||
|
||||
gpre_nod* var_list = (gpre_nod*) action->act_object;
|
||||
for (int i = 0; var_list && i < var_list->nod_count; i++)
|
||||
{
|
||||
asgn_to(action, (ref*) (var_list->nod_arg[i]));
|
||||
}
|
||||
|
||||
printa(names[COLUMN], false, "END-IF");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -3233,10 +3247,28 @@ static void gen_s_start( const act* action)
|
||||
}
|
||||
|
||||
gen_start(action, port);
|
||||
set_sqlcode(action);
|
||||
|
||||
if (action->act_error || (action->act_flags & ACT_sql))
|
||||
printa(names[COLUMN], false, "END-IF");
|
||||
|
||||
if (request->req_type == REQ_insert && (request->req_flags & REQ_sql_returning))
|
||||
{
|
||||
printa(names[COLUMN], false, "IF SQLCODE NOT = 0 THEN");
|
||||
gen_receive(action, column, request->req_primary);
|
||||
printa(names[COLUMN], false, "END-IF");
|
||||
|
||||
printa(names[COLUMN], false, "IF SQLCODE NOT = 0 THEN");
|
||||
|
||||
gpre_nod* var_list = (gpre_nod*) action->act_object;
|
||||
for (int i = 0; var_list && i < var_list->nod_count; i++)
|
||||
{
|
||||
asgn_to(action, (ref*) (var_list->nod_arg[i]));
|
||||
}
|
||||
|
||||
printa(names[COLUMN], false, "END-IF");
|
||||
}
|
||||
|
||||
if (action->act_type == ACT_open)
|
||||
{
|
||||
printa(names[COLUMN], false, "END-IF");
|
||||
@ -3244,7 +3276,6 @@ static void gen_s_start( const act* action)
|
||||
if (gpreGlob.sw_auto)
|
||||
printa(names[COLUMN], false, "END-IF");
|
||||
printa(names[COLUMN], false, "END-IF");
|
||||
set_sqlcode(action);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2497,17 +2497,31 @@ static void gen_get_segment(const act* action)
|
||||
|
||||
static void gen_loop(const act* action)
|
||||
{
|
||||
TEXT name[MAX_REF_SIZE];
|
||||
|
||||
gen_s_start(action);
|
||||
const gpre_req* request = action->act_request;
|
||||
const gpre_port* port = request->req_primary;
|
||||
|
||||
printa(COLUMN, "IF (SQLCODE .EQ. 0) THEN");
|
||||
gen_receive(action, port);
|
||||
printa(COLUMN, "END IF");
|
||||
|
||||
TEXT name[MAX_REF_SIZE];
|
||||
gen_name(name, port->por_references, true);
|
||||
printa(COLUMN, "IF (SQLCODE .EQ. 0 .AND. %s .EQ. 0) ", name);
|
||||
printa(CONTINUE, "SQLCODE = 100");
|
||||
printa(COLUMN, "END IF");
|
||||
|
||||
if (request->req_flags & REQ_sql_returning)
|
||||
{
|
||||
printa(COLUMN, "IF (SQLCODE .EQ. 0 .AND. %s .NE. 0) THEN", name);
|
||||
|
||||
gpre_nod* var_list = (gpre_nod*) action->act_object;
|
||||
for (int i = 0; var_list && i < var_list->nod_count; i++)
|
||||
{
|
||||
asgn_to(action, (ref*) (var_list->nod_arg[i]));
|
||||
}
|
||||
|
||||
printa(COLUMN, "END IF");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -3101,16 +3115,33 @@ static void gen_s_start(const act* action)
|
||||
make_ok_test(action, request);
|
||||
|
||||
gen_start(action, port);
|
||||
status_and_stop(action);
|
||||
|
||||
if (action->act_error || (action->act_flags & ACT_sql))
|
||||
printa(COLUMN, "END IF");
|
||||
|
||||
if (request->req_type == REQ_insert && (request->req_flags & REQ_sql_returning))
|
||||
{
|
||||
printa(COLUMN, "IF (SQLCODE .EQ. 0) THEN");
|
||||
gen_receive(action, column, request->req_primary);
|
||||
printa(COLUMN, "END IF");
|
||||
|
||||
printa(COLUMN, "IF (SQLCODE .EQ. 0) THEN");
|
||||
|
||||
gpre_nod* var_list = (gpre_nod*) action->act_object;
|
||||
for (int i = 0; var_list && i < var_list->nod_count; i++)
|
||||
{
|
||||
asgn_to(action, (ref*) (var_list->nod_arg[i]));
|
||||
}
|
||||
|
||||
printa(COLUMN, "END IF");
|
||||
}
|
||||
|
||||
if (action->act_type == ACT_open)
|
||||
{
|
||||
printa(COLUMN, "END IF");
|
||||
printa(COLUMN, "END IF");
|
||||
printa(COLUMN, "END IF");
|
||||
status_and_stop(action);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2149,22 +2149,40 @@ static void gen_get_segment( const act* action, int column)
|
||||
|
||||
static void gen_loop( const act* action, int column)
|
||||
{
|
||||
const gpre_req* request;
|
||||
gpre_port* port;
|
||||
TEXT name[MAX_REF_SIZE];
|
||||
|
||||
gen_s_start(action, column);
|
||||
request = action->act_request;
|
||||
port = request->req_primary;
|
||||
const gpre_req* request = action->act_request;
|
||||
gpre_port* port = request->req_primary;
|
||||
|
||||
printa(column, "if SQLCODE = 0 then");
|
||||
column += INDENT;
|
||||
begin(column);
|
||||
|
||||
gen_receive(action, column, port);
|
||||
|
||||
endp(column);
|
||||
column -= INDENT;
|
||||
|
||||
TEXT name[MAX_REF_SIZE];
|
||||
gen_name(name, port->por_references, true);
|
||||
printa(column, "if (SQLCODE = 0) and (%s = 0)", name);
|
||||
printa(column + INDENT, "then SQLCODE := 100;");
|
||||
endp(column);
|
||||
column -= INDENT;
|
||||
|
||||
if (request->req_flags & REQ_sql_returning)
|
||||
{
|
||||
printa(column, "if (SQLCODE = 0) and (%s <> 0)", name);
|
||||
column += INDENT;
|
||||
begin(column);
|
||||
|
||||
gpre_nod* var_list = (gpre_nod*) action->act_object;
|
||||
for (int i = 0; var_list && i < var_list->nod_count; i++)
|
||||
{
|
||||
align(column);
|
||||
asgn_to(action, (ref*) (var_list->nod_arg[i]), column);
|
||||
}
|
||||
|
||||
endp(column);
|
||||
column -= INDENT;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -2686,12 +2704,43 @@ static void gen_s_start( const act* action, int column)
|
||||
{
|
||||
make_ok_test(action, request, column);
|
||||
column += INDENT;
|
||||
begin(column);
|
||||
}
|
||||
|
||||
gen_start(action, port, column);
|
||||
set_sqlcode(action, column);
|
||||
|
||||
if (action->act_error || (action->act_flags & ACT_sql))
|
||||
{
|
||||
endp(column);
|
||||
column -= INDENT;
|
||||
}
|
||||
|
||||
if (request->req_type == REQ_insert && (request->req_flags & REQ_sql_returning))
|
||||
{
|
||||
printa(column, "if (SQLCODE = 0) ");
|
||||
column += INDENT;
|
||||
begin(column);
|
||||
|
||||
gen_receive(action, column, request->req_primary);
|
||||
|
||||
endp(column);
|
||||
column -= INDENT;
|
||||
|
||||
printa(column, "if (SQLCODE = 0) ");
|
||||
column += INDENT;
|
||||
begin(column);
|
||||
|
||||
gpre_nod* var_list = (gpre_nod*) action->act_object;
|
||||
for (int i = 0; var_list && i < var_list->nod_count; i++)
|
||||
{
|
||||
align(column);
|
||||
asgn_to(action, (ref*) (var_list->nod_arg[i]), column);
|
||||
}
|
||||
|
||||
endp(column);
|
||||
column -= INDENT;
|
||||
}
|
||||
|
||||
if (action->act_type == ACT_open)
|
||||
{
|
||||
@ -2702,8 +2751,6 @@ static void gen_s_start( const act* action, int column)
|
||||
ends(column);
|
||||
column -= INDENT;
|
||||
}
|
||||
|
||||
set_sqlcode(action, column);
|
||||
}
|
||||
|
||||
|
||||
|
@ -2816,16 +2816,30 @@ static void gen_loop( const act* action)
|
||||
{
|
||||
gen_s_start(action);
|
||||
const gpre_req* request = action->act_request;
|
||||
printa(names[COLUMN], false, "IF SQLCODE = 0 THEN");
|
||||
const gpre_port* port = request->req_primary;
|
||||
|
||||
printa(names[COLUMN], false, "IF SQLCODE = 0 THEN");
|
||||
gen_receive(action, port);
|
||||
printa(names[COLUMN], false, "END-IF");
|
||||
|
||||
TEXT name[MAX_REF_SIZE];
|
||||
gen_name(name, port->por_references, true);
|
||||
printa(names[COLUMN], false, "IF SQLCODE = 0 AND %s = 0 THEN ", name);
|
||||
printa(names[COLUMN], false, "MOVE 100 TO SQLCODE");
|
||||
printa(names[COLUMN], false, "END-IF");
|
||||
printa(names[COLUMN], false, "END-IF");
|
||||
|
||||
if (request->req_flags & REQ_sql_returning)
|
||||
{
|
||||
printa(names[COLUMN], false, "IF SQLCODE = 0 AND %s NOT = 0 THEN", name);
|
||||
|
||||
gpre_nod* var_list = (gpre_nod*) action->act_object;
|
||||
for (int i = 0; var_list && i < var_list->nod_count; i++)
|
||||
{
|
||||
asgn_to(action, (ref*) (var_list->nod_arg[i]));
|
||||
}
|
||||
|
||||
printa(names[COLUMN], false, "END-IF");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -3358,10 +3372,28 @@ static void gen_s_start( const act* action)
|
||||
}
|
||||
|
||||
gen_start(action, port);
|
||||
set_sqlcode(action);
|
||||
|
||||
if (action->act_error || (action->act_flags & ACT_sql))
|
||||
printa(names[COLUMN], false, "END-IF");
|
||||
|
||||
if (request->req_type == REQ_insert && (request->req_flags & REQ_sql_returning))
|
||||
{
|
||||
printa(names[COLUMN], false, "IF SQLCODE = 0 THEN");
|
||||
gen_receive(action, column, request->req_primary);
|
||||
printa(names[COLUMN], false, "END-IF");
|
||||
|
||||
printa(names[COLUMN], false, "IF SQLCODE = 0 THEN");
|
||||
|
||||
gpre_nod* var_list = (gpre_nod*) action->act_object;
|
||||
for (int i = 0; var_list && i < var_list->nod_count; i++)
|
||||
{
|
||||
asgn_to(action, (ref*) (var_list->nod_arg[i]));
|
||||
}
|
||||
|
||||
printa(names[COLUMN], false, "END-IF");
|
||||
}
|
||||
|
||||
if (action->act_type == ACT_open)
|
||||
{
|
||||
printa(names[COLUMN], false, "END-IF");
|
||||
@ -3369,7 +3401,6 @@ static void gen_s_start( const act* action)
|
||||
if (gpreGlob.sw_auto)
|
||||
printa(names[COLUMN], false, "END-IF");
|
||||
printa(names[COLUMN], false, "END-IF");
|
||||
set_sqlcode(action);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -472,6 +472,22 @@ gpre_sym* MSC_symbol(sym_t type, const TEXT* string, USHORT length, gpre_ctx* ob
|
||||
}
|
||||
|
||||
|
||||
//____________________________________________________________
|
||||
//
|
||||
// Make a ternary node.
|
||||
//
|
||||
|
||||
gpre_nod* MSC_ternary(nod_t type, gpre_nod* arg1, gpre_nod* arg2, gpre_nod* arg3)
|
||||
{
|
||||
gpre_nod* node = MSC_node(type, 3);
|
||||
node->nod_arg[0] = arg1;
|
||||
node->nod_arg[1] = arg2;
|
||||
node->nod_arg[2] = arg3;
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
|
||||
//____________________________________________________________
|
||||
//
|
||||
// Make a unary node.
|
||||
|
@ -46,6 +46,7 @@ ref* MSC_reference(ref**);
|
||||
gpre_req* MSC_request(req_t);
|
||||
SCHAR* MSC_string(const TEXT*);
|
||||
gpre_sym* MSC_symbol(sym_t, const TEXT*, USHORT, gpre_ctx*);
|
||||
gpre_nod* MSC_ternary(nod_t, gpre_nod*, gpre_nod*, gpre_nod*);
|
||||
gpre_nod* MSC_unary(nod_t, gpre_nod*);
|
||||
gpre_usn* MSC_username(const SCHAR*, USHORT);
|
||||
|
||||
|
@ -241,7 +241,7 @@ act* PAR_action(const TEXT* base_dir)
|
||||
return cur_statement = par_ready();
|
||||
case KW_RELEASE_REQUESTS:
|
||||
return cur_statement = par_release();
|
||||
case KW_RETURNING:
|
||||
case KW_RETURNING_VALUES:
|
||||
return par_returning_values();
|
||||
case KW_START_STREAM:
|
||||
return cur_statement = par_start_stream();
|
||||
@ -1981,7 +1981,8 @@ static act* par_end_store(bool special)
|
||||
}
|
||||
|
||||
gpre_nod* const assignments = MSC_node(nod_list, (SSHORT) count);
|
||||
request->req_node = assignments;
|
||||
request->req_node =
|
||||
MSC_ternary(nod_store, (gpre_nod*) request->req_contexts, assignments, NULL);
|
||||
count = 0;
|
||||
|
||||
for (ref* reference = request->req_references; reference; reference = reference->ref_next)
|
||||
@ -2723,7 +2724,8 @@ static act* par_returning_values()
|
||||
}
|
||||
|
||||
gpre_nod* assignments = MSC_node(nod_list, (SSHORT) count);
|
||||
request->req_node = assignments;
|
||||
request->req_node =
|
||||
MSC_ternary(nod_store, (gpre_nod*) request->req_contexts, assignments, NULL);
|
||||
count = 0;
|
||||
|
||||
for (ref* reference = request->req_references; reference; reference = reference->ref_next)
|
||||
|
@ -174,7 +174,7 @@ static const ops stat_ops[] =
|
||||
static const nod_t relationals[] =
|
||||
{
|
||||
nod_eq, nod_ne, nod_gt, nod_ge, nod_le, nod_lt, nod_containing,
|
||||
nod_starting, nod_matches, nod_any, nod_missing, nod_between, nod_like,
|
||||
nod_starting, nod_matches, nod_any, nod_missing, nod_equiv, nod_between, nod_like,
|
||||
nod_and, nod_or, nod_not, nod_ansi_any, nod_ansi_all, nod_nothing
|
||||
};
|
||||
|
||||
@ -929,11 +929,13 @@ ref* SQE_post_reference(gpre_req* request, gpre_fld* field, gpre_ctx* context, g
|
||||
// otherwise false.
|
||||
//
|
||||
|
||||
bool SQE_resolve(gpre_nod* node, gpre_req* request, gpre_rse* selection)
|
||||
bool SQE_resolve(gpre_nod** node_ptr, gpre_req* request, gpre_rse* selection)
|
||||
{
|
||||
bool result = false;
|
||||
act* slice_action = 0;
|
||||
|
||||
gpre_nod* node = *node_ptr;
|
||||
|
||||
assert_IS_REQ(request);
|
||||
assert_IS_NOD(node);
|
||||
|
||||
@ -968,7 +970,7 @@ bool SQE_resolve(gpre_nod* node, gpre_req* request, gpre_rse* selection)
|
||||
gpre_nod** ptr = node->nod_arg;
|
||||
const gpre_nod* const* const end = ptr + node->nod_count;
|
||||
for (; ptr < end; ptr++)
|
||||
result |= SQE_resolve(*ptr, request, selection);
|
||||
result |= SQE_resolve(ptr, request, selection);
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -979,7 +981,7 @@ bool SQE_resolve(gpre_nod* node, gpre_req* request, gpre_rse* selection)
|
||||
case nod_agg_count:
|
||||
if (node->nod_arg[0])
|
||||
{
|
||||
SQE_resolve(node->nod_arg[0], request, selection);
|
||||
SQE_resolve(&node->nod_arg[0], request, selection);
|
||||
gpre_nod* node_arg = node->nod_arg[0];
|
||||
const ref* reference = (ref*) node_arg->nod_arg[0];
|
||||
if (node_arg->nod_type == nod_field && reference &&
|
||||
@ -996,22 +998,22 @@ bool SQE_resolve(gpre_nod* node, gpre_req* request, gpre_rse* selection)
|
||||
gpre_nod** ptr = node->nod_arg[0]->nod_arg;
|
||||
const gpre_nod* const* const end = ptr + node->nod_arg[0]->nod_count;
|
||||
for (; ptr < end; ptr++)
|
||||
result |= SQE_resolve(*ptr, request, selection);
|
||||
result |= SQE_resolve(ptr, request, selection);
|
||||
}
|
||||
return result;
|
||||
|
||||
case nod_gen_id:
|
||||
return SQE_resolve(node->nod_arg[0], request, selection);
|
||||
return SQE_resolve(&node->nod_arg[0], request, selection);
|
||||
|
||||
// Begin date/time/timestamp support
|
||||
case nod_extract:
|
||||
result |= SQE_resolve(node->nod_arg[1], request, selection);
|
||||
result |= SQE_resolve(&node->nod_arg[1], request, selection);
|
||||
return result;
|
||||
// End date/time/timestamp support
|
||||
|
||||
case nod_coalesce:
|
||||
for (int i = 0; i < node->nod_count; i++)
|
||||
result |= SQE_resolve(node->nod_arg[0]->nod_arg[i], request, selection);
|
||||
result |= SQE_resolve(&node->nod_arg[0]->nod_arg[i], request, selection);
|
||||
return result;
|
||||
|
||||
case nod_deferred:
|
||||
@ -1073,12 +1075,7 @@ bool SQE_resolve(gpre_nod* node, gpre_req* request, gpre_rse* selection)
|
||||
reference->ref_context = context;
|
||||
reference->ref_slice = (slc*) slice_action;
|
||||
|
||||
// do not reinit if this is a nod_deffered type
|
||||
if (node->nod_type != nod_deferred)
|
||||
node->nod_count = 0;
|
||||
|
||||
node->nod_type = nod_field;
|
||||
node->nod_arg[0] = (gpre_nod*) reference;
|
||||
*node_ptr = MSC_unary(nod_field, (gpre_nod*) reference);
|
||||
|
||||
return false;
|
||||
}
|
||||
@ -2230,7 +2227,7 @@ static gpre_nod* par_not( gpre_req* request, USHORT* paren_count)
|
||||
node->nod_arg[0] = (gpre_nod*) selection;
|
||||
if (field)
|
||||
{
|
||||
SQE_resolve(field, 0, selection);
|
||||
SQE_resolve(&field, 0, selection);
|
||||
gpre_nod* expr = MSC_unary(nod_missing, field);
|
||||
selection->rse_boolean = merge(negate(expr), selection->rse_boolean);
|
||||
}
|
||||
@ -2756,11 +2753,21 @@ static gpre_nod* par_relational(gpre_req* request,
|
||||
{
|
||||
if (MSC_match(KW_NOT))
|
||||
negation = !negation;
|
||||
if (!MSC_match(KW_NULL))
|
||||
CPR_s_error("NULL");
|
||||
if (expr1->nod_type == nod_array)
|
||||
expr1->nod_type = nod_field;
|
||||
node = MSC_unary(nod_missing, expr1);
|
||||
if (MSC_match(KW_NULL))
|
||||
{
|
||||
if (expr1->nod_type == nod_array)
|
||||
expr1->nod_type = nod_field;
|
||||
node = MSC_unary(nod_missing, expr1);
|
||||
}
|
||||
else if (MSC_match(KW_DISTINCT))
|
||||
{
|
||||
if (!MSC_match(KW_FROM))
|
||||
CPR_s_error("FROM");
|
||||
node = MSC_binary(nod_equiv, expr1, SQE_value(request, false, NULL, NULL));
|
||||
pair(node->nod_arg[0], node->nod_arg[1]);
|
||||
}
|
||||
else
|
||||
CPR_s_error("NULL or DISTINCT");
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -2823,7 +2830,7 @@ static bool resolve_fields(gpre_nod*& fields, gpre_rse* selection)
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
gpre_nod* node = ptr[i];
|
||||
gpre_nod*& node = ptr[i];
|
||||
|
||||
if (node->nod_type == nod_asterisk)
|
||||
{
|
||||
@ -2835,7 +2842,7 @@ static bool resolve_fields(gpre_nod*& fields, gpre_rse* selection)
|
||||
}
|
||||
else
|
||||
{
|
||||
aggregate |= SQE_resolve(node, NULL, selection);
|
||||
aggregate |= SQE_resolve(&node, NULL, selection);
|
||||
pair(node, 0);
|
||||
}
|
||||
}
|
||||
|
@ -33,9 +33,10 @@ gpre_nod* SQE_list(pfn_SQE_list_cb, gpre_req*, bool);
|
||||
ref* SQE_parameter(gpre_req*);
|
||||
void SQE_post_field(gpre_nod*, gpre_fld*);
|
||||
ref* SQE_post_reference(gpre_req*, gpre_fld*, gpre_ctx*, gpre_nod*);
|
||||
bool SQE_resolve(gpre_nod*, gpre_req*, gpre_rse*);
|
||||
bool SQE_resolve(gpre_nod**, gpre_req*, gpre_rse*);
|
||||
gpre_rse* SQE_select(gpre_req*, bool);
|
||||
gpre_nod* SQE_value(gpre_req*, bool, USHORT*, bool*);
|
||||
gpre_nod* SQE_value_or_null(gpre_req*, bool, USHORT*, bool*);
|
||||
gpre_nod* SQE_variable(gpre_req*, bool, USHORT*, bool*);
|
||||
|
||||
#endif // GPRE_SQE_PROTO_H
|
||||
|
440
src/gpre/sql.cpp
440
src/gpre/sql.cpp
@ -49,6 +49,9 @@
|
||||
|
||||
const int DEFAULT_BLOB_SEGMENT_LENGTH = 80; // bytes
|
||||
|
||||
const char* const OLD_CONTEXT = "OLD";
|
||||
const char* const NEW_CONTEXT = "NEW";
|
||||
|
||||
static act* act_alter();
|
||||
static act* act_alter_database();
|
||||
static act* act_alter_domain();
|
||||
@ -95,6 +98,7 @@ static act* act_set_statistics();
|
||||
static act* act_set_transaction();
|
||||
static act* act_transaction(act_t);
|
||||
static act* act_update();
|
||||
static act* act_upsert();
|
||||
static act* act_whenever();
|
||||
|
||||
static bool check_filename(const TEXT *);
|
||||
@ -127,6 +131,7 @@ static cnstrt* par_table_constraint(gpre_req*);
|
||||
static bool par_transaction_modes(gpre_tra*, bool);
|
||||
static bool par_using(dyn*);
|
||||
static USHORT resolve_dtypes(kwwords_t, bool);
|
||||
static gpre_nod* return_values(gpre_req*, gpre_nod*, gpre_nod*);
|
||||
static bool tail_database(act_t, gpre_dbb*);
|
||||
static void to_upcase(const TEXT*, TEXT*, int);
|
||||
|
||||
@ -2689,9 +2694,31 @@ static act* act_delete()
|
||||
if (where)
|
||||
selection->rse_boolean = SQE_boolean(request, 0);
|
||||
|
||||
request->req_node = MSC_node(nod_erase, 0);
|
||||
gpre_nod* ret_list = NULL;
|
||||
ref* ref_list = NULL;
|
||||
|
||||
if (MSC_match(KW_RETURNING))
|
||||
{
|
||||
gpre_nod* value_list = SQE_list(SQE_value_or_null, request, false);
|
||||
|
||||
if (!MSC_match(KW_INTO))
|
||||
CPR_s_error("INTO");
|
||||
|
||||
gpre_nod* var_list = SQE_list(SQE_variable, request, false);
|
||||
|
||||
ret_list = return_values(request, value_list, var_list);
|
||||
|
||||
into(request, value_list, var_list);
|
||||
ref_list = (ref*) var_list;
|
||||
|
||||
request->req_flags |= REQ_sql_returning;
|
||||
selection->rse_flags |= RSE_singleton;
|
||||
}
|
||||
|
||||
request->req_node = MSC_unary(nod_erase, ret_list);
|
||||
|
||||
act* action = MSC_action(request, ACT_loop);
|
||||
action->act_object = ref_list;
|
||||
action->act_whenever = gen_whenever();
|
||||
|
||||
if (hsh_rm)
|
||||
@ -3450,6 +3477,9 @@ static act* act_insert()
|
||||
EXP_match_paren();
|
||||
}
|
||||
|
||||
gpre_nod* ret_list = NULL;
|
||||
ref* ref_list = NULL;
|
||||
|
||||
gpre_lls* values = NULL;
|
||||
if (MSC_match(KW_VALUES))
|
||||
{
|
||||
@ -3458,10 +3488,7 @@ static act* act_insert()
|
||||
EXP_left_paren(0);
|
||||
for (;;)
|
||||
{
|
||||
if (MSC_match(KW_NULL))
|
||||
MSC_push(MSC_node(nod_null, 0), &values);
|
||||
else
|
||||
MSC_push(SQE_value(request, false, NULL, NULL), &values);
|
||||
MSC_push(SQE_value_or_null(request, false, NULL, NULL), &values);
|
||||
count2++;
|
||||
if (!MSC_match(KW_COMMA))
|
||||
break;
|
||||
@ -3474,7 +3501,6 @@ static act* act_insert()
|
||||
PAR_error("count of values doesn't match count of columns");
|
||||
|
||||
gpre_nod* vlist = MSC_node(nod_list, (SSHORT) count);
|
||||
request->req_node = vlist;
|
||||
gpre_nod** ptr = &vlist->nod_arg[count];
|
||||
|
||||
while (values)
|
||||
@ -3486,9 +3512,30 @@ static act* act_insert()
|
||||
*--ptr = assignment;
|
||||
}
|
||||
|
||||
if (MSC_match(KW_RETURNING))
|
||||
{
|
||||
gpre_nod* value_list = SQE_list(SQE_value_or_null, request, false);
|
||||
|
||||
if (!MSC_match(KW_INTO))
|
||||
CPR_s_error("INTO");
|
||||
|
||||
gpre_nod* var_list = SQE_list(SQE_variable, request, false);
|
||||
|
||||
ret_list = return_values(request, value_list, var_list);
|
||||
|
||||
into(request, value_list, var_list);
|
||||
ref_list = (ref*) var_list;
|
||||
|
||||
request->req_flags |= REQ_sql_returning;
|
||||
}
|
||||
|
||||
request->req_node = MSC_ternary(nod_store, (gpre_nod*) context, vlist, ret_list);
|
||||
|
||||
if (context->ctx_symbol)
|
||||
HSH_remove(context->ctx_symbol);
|
||||
|
||||
act* action = MSC_action(request, ACT_insert);
|
||||
action->act_object = ref_list;
|
||||
action->act_whenever = gen_whenever();
|
||||
return action;
|
||||
}
|
||||
@ -3529,13 +3576,33 @@ static act* act_insert()
|
||||
*--ptr = assignment;
|
||||
}
|
||||
|
||||
gpre_nod* store = MSC_binary(nod_store, (gpre_nod*) context, alist);
|
||||
if (MSC_match(KW_RETURNING))
|
||||
{
|
||||
gpre_nod* value_list = SQE_list(SQE_value_or_null, request, false);
|
||||
|
||||
if (!MSC_match(KW_INTO))
|
||||
CPR_s_error("INTO");
|
||||
|
||||
gpre_nod* var_list = SQE_list(SQE_variable, request, false);
|
||||
|
||||
ret_list = return_values(request, value_list, var_list);
|
||||
|
||||
into(request, value_list, var_list);
|
||||
ref_list = (ref*) var_list;
|
||||
|
||||
request->req_flags |= REQ_sql_returning;
|
||||
select->rse_flags |= RSE_singleton;
|
||||
}
|
||||
|
||||
gpre_nod* store = MSC_ternary(nod_store, (gpre_nod*) context, alist, ret_list);
|
||||
request->req_node = store;
|
||||
EXP_rse_cleanup(select);
|
||||
|
||||
if (context->ctx_symbol)
|
||||
HSH_remove(context->ctx_symbol);
|
||||
|
||||
act* action = MSC_action(request, ACT_loop);
|
||||
action->act_object = ref_list;
|
||||
action->act_whenever = gen_whenever();
|
||||
|
||||
return action;
|
||||
@ -3932,7 +3999,7 @@ static act* act_procedure()
|
||||
gpre_lls* values = NULL;
|
||||
|
||||
SSHORT inputs = 0;
|
||||
if (gpreGlob.token_global.tok_keyword != KW_RETURNING &&
|
||||
if (gpreGlob.token_global.tok_keyword != KW_RETURNING_VALUES &&
|
||||
gpreGlob.token_global.tok_keyword != KW_SEMI_COLON)
|
||||
{
|
||||
// parse input references
|
||||
@ -3960,7 +4027,7 @@ static act* act_procedure()
|
||||
}
|
||||
|
||||
SSHORT outputs = 0;
|
||||
if (MSC_match(KW_RETURNING))
|
||||
if (MSC_match(KW_RETURNING_VALUES))
|
||||
{
|
||||
// parse output references
|
||||
|
||||
@ -4423,6 +4490,9 @@ static act* act_transaction(act_t type)
|
||||
|
||||
static act* act_update()
|
||||
{
|
||||
if (MSC_match(KW_OR) && MSC_match(KW_INSERT))
|
||||
return act_upsert();
|
||||
|
||||
const TEXT* transaction = NULL;
|
||||
|
||||
par_options(&transaction);
|
||||
@ -4463,10 +4533,7 @@ static act* act_update()
|
||||
set_item->nod_arg[1] = SQE_field(NULL, false);
|
||||
if (!MSC_match(KW_EQUALS))
|
||||
CPR_s_error("assignment operator");
|
||||
if (MSC_match(KW_NULL))
|
||||
set_item->nod_arg[0] = MSC_node(nod_null, 0);
|
||||
else
|
||||
set_item->nod_arg[0] = SQE_value(request, false, NULL, NULL);
|
||||
set_item->nod_arg[0] = SQE_value_or_null(request, false, NULL, NULL);
|
||||
MSC_push(set_item, &stack);
|
||||
count++;
|
||||
} while (MSC_match(KW_COMMA));
|
||||
@ -4542,7 +4609,7 @@ static act* act_update()
|
||||
for (ptr = set_list->nod_arg; ptr < end_list; ptr++)
|
||||
{
|
||||
gpre_nod* set_item = *ptr;
|
||||
SQE_resolve(set_item->nod_arg[0], request, 0);
|
||||
SQE_resolve(&set_item->nod_arg[0], request, 0);
|
||||
pair(set_item->nod_arg[0], set_item->nod_arg[1]);
|
||||
}
|
||||
|
||||
@ -4563,7 +4630,7 @@ static act* act_update()
|
||||
for (ptr = set_list->nod_arg; ptr < end_list; ptr++)
|
||||
{
|
||||
gpre_nod* set_item = *ptr;
|
||||
SQE_resolve(set_item->nod_arg[1], request, 0);
|
||||
SQE_resolve(&set_item->nod_arg[1], request, 0);
|
||||
ref* field_ref = (ref*) ((set_item->nod_arg[1])->nod_arg[0]);
|
||||
|
||||
slc* slice = NULL;
|
||||
@ -4635,7 +4702,7 @@ static act* act_update()
|
||||
for (ptr = set_list->nod_arg; ptr < end_list; ptr++)
|
||||
{
|
||||
gpre_nod* set_item = *ptr;
|
||||
SQE_resolve(set_item->nod_arg[0], request, select);
|
||||
SQE_resolve(&set_item->nod_arg[0], request, select);
|
||||
}
|
||||
|
||||
// Process boolean, if any
|
||||
@ -4655,7 +4722,7 @@ static act* act_update()
|
||||
for (ptr = set_list->nod_arg; ptr < end_list; ptr++)
|
||||
{
|
||||
gpre_nod* set_item = *ptr;
|
||||
SQE_resolve(set_item->nod_arg[1], request, 0);
|
||||
SQE_resolve(&set_item->nod_arg[1], request, 0);
|
||||
ref* field_ref = (ref*) ((set_item->nod_arg[1])->nod_arg[0]);
|
||||
|
||||
act* slice_action = (act*) field_ref->ref_slice;
|
||||
@ -4687,11 +4754,44 @@ static act* act_update()
|
||||
pair(set_item->nod_arg[0], set_item->nod_arg[1]);
|
||||
}
|
||||
|
||||
gpre_nod* modify = MSC_node(nod_modify, 1);
|
||||
gpre_nod* ret_list = NULL;
|
||||
ref* ref_list = NULL;
|
||||
|
||||
if (MSC_match(KW_RETURNING))
|
||||
{
|
||||
gpre_nod* value_list = SQE_list(SQE_value_or_null, NULL, false);
|
||||
|
||||
if (!MSC_match(KW_INTO))
|
||||
CPR_s_error("INTO");
|
||||
|
||||
gpre_nod* var_list = SQE_list(SQE_variable, request, false);
|
||||
|
||||
gpre_sym* old_ctx_sym = MSC_symbol(SYM_context, OLD_CONTEXT, strlen(OLD_CONTEXT), input_context);
|
||||
HSH_insert(old_ctx_sym);
|
||||
|
||||
gpre_sym* new_ctx_sym = MSC_symbol(SYM_context, NEW_CONTEXT, strlen(NEW_CONTEXT), update_context);
|
||||
HSH_insert(new_ctx_sym);
|
||||
|
||||
ret_list = return_values(request, value_list, var_list);
|
||||
|
||||
for (int i = 0; i < value_list->nod_count; i++)
|
||||
SQE_resolve(&value_list->nod_arg[i], request, NULL);
|
||||
|
||||
into(request, value_list, var_list);
|
||||
ref_list = (ref*) var_list;
|
||||
|
||||
HSH_remove(new_ctx_sym);
|
||||
HSH_remove(old_ctx_sym);
|
||||
|
||||
request->req_flags |= REQ_sql_returning;
|
||||
select->rse_flags |= RSE_singleton;
|
||||
}
|
||||
|
||||
gpre_nod* modify = MSC_binary(nod_modify, set_list, ret_list);
|
||||
request->req_node = modify;
|
||||
modify->nod_arg[0] = set_list;
|
||||
|
||||
act* action = MSC_action(request, ACT_loop);
|
||||
action->act_object = ref_list;
|
||||
action->act_whenever = gen_whenever();
|
||||
|
||||
if (alias)
|
||||
@ -4701,6 +4801,286 @@ static act* act_update()
|
||||
}
|
||||
|
||||
|
||||
//____________________________________________________________
|
||||
//
|
||||
// Process SQL UPDATE OR INSERT statement.
|
||||
//
|
||||
|
||||
static act* act_upsert(void)
|
||||
{
|
||||
const TEXT* transaction = NULL;
|
||||
|
||||
par_options(&transaction);
|
||||
|
||||
if (!MSC_match(KW_INTO))
|
||||
CPR_s_error("INTO");
|
||||
|
||||
gpre_req* request = MSC_request(REQ_mass_update);
|
||||
request->req_trans = transaction;
|
||||
gpre_ctx* context = SQE_context(request);
|
||||
gpre_rel* relation = context->ctx_relation;
|
||||
|
||||
int count = 0;
|
||||
gpre_lls* fields = NULL;
|
||||
|
||||
// Pick up a field list
|
||||
|
||||
if (!MSC_match(KW_LEFT_PAREN))
|
||||
{
|
||||
gpre_nod* list = MET_fields(context);
|
||||
count = list->nod_count;
|
||||
for (int i = 0; i < count; i++)
|
||||
MSC_push(list->nod_arg[i], &fields);
|
||||
}
|
||||
else
|
||||
{
|
||||
do
|
||||
{
|
||||
gpre_nod* node = SQE_field(request, false);
|
||||
|
||||
if (node->nod_type == nod_array)
|
||||
{
|
||||
node->nod_type = nod_field;
|
||||
|
||||
// Make sure no subscripts are specified
|
||||
|
||||
if (node->nod_arg[1]) {
|
||||
PAR_error("Partial insert of arrays not permitted");
|
||||
}
|
||||
}
|
||||
|
||||
// Dialect 1 program may not insert new datatypes
|
||||
if ((SQL_DIALECT_V5 == gpreGlob.sw_sql_dialect) &&
|
||||
(nod_field == node->nod_type))
|
||||
{
|
||||
const USHORT field_dtype =
|
||||
((ref*) (node->nod_arg[0]))->ref_field->fld_dtype;
|
||||
|
||||
if ((dtype_sql_date == field_dtype)
|
||||
|| (dtype_sql_time == field_dtype)
|
||||
|| (dtype_int64 == field_dtype))
|
||||
{
|
||||
SQL_dialect1_bad_type(field_dtype);
|
||||
}
|
||||
}
|
||||
|
||||
MSC_push(node, &fields);
|
||||
count++;
|
||||
} while (MSC_match(KW_COMMA));
|
||||
|
||||
EXP_match_paren();
|
||||
}
|
||||
|
||||
gpre_nod* field_list = MSC_node(nod_list, (SSHORT) count);
|
||||
gpre_nod** ptr = &field_list->nod_arg[count];
|
||||
while (fields)
|
||||
*--ptr = (gpre_nod*) MSC_pop(&fields);
|
||||
|
||||
// Now pick up a value list
|
||||
|
||||
if (!MSC_match(KW_VALUES))
|
||||
CPR_s_error("VALUES");
|
||||
|
||||
EXP_left_paren(0);
|
||||
gpre_nod* value_list = SQE_list(SQE_value_or_null, request, false);
|
||||
EXP_match_paren();
|
||||
|
||||
if (count != value_list->nod_count)
|
||||
PAR_error("count of values doesn't match count of columns");
|
||||
|
||||
// Pick up a matching list
|
||||
|
||||
nod_t cmp_op = nod_equiv;
|
||||
|
||||
gpre_lls* matches = NULL;
|
||||
if (MSC_match(KW_MATCHES))
|
||||
{
|
||||
EXP_left_paren(0);
|
||||
for (;;)
|
||||
{
|
||||
MSC_push(SQE_field(request, false), &matches);
|
||||
if (!(MSC_match(KW_COMMA)))
|
||||
break;
|
||||
}
|
||||
EXP_match_paren();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (relation->rel_view_rse)
|
||||
PAR_error("MATCHING clause is required for views");
|
||||
|
||||
gpre_lls* pk_fields =
|
||||
MET_get_primary_key(relation->rel_database, relation->rel_symbol->sym_string);
|
||||
|
||||
while (pk_fields)
|
||||
{
|
||||
const TEXT* field_name = (TEXT*) MSC_pop(&pk_fields);
|
||||
gpre_fld* field = MET_field(relation, field_name);
|
||||
ref* reference = (ref*) MSC_alloc(REF_LEN);
|
||||
reference->ref_field = field;
|
||||
reference->ref_context = context;
|
||||
MSC_push(MSC_unary(nod_field, (gpre_nod*) reference), &matches);
|
||||
}
|
||||
|
||||
cmp_op = nod_eq;
|
||||
}
|
||||
|
||||
if (!matches)
|
||||
PAR_error("Either MATCHING list or primary key is required");
|
||||
|
||||
// Create selection
|
||||
|
||||
gpre_rse* select = (gpre_rse*) MSC_alloc(RSE_LEN(1));
|
||||
request->req_rse = select;
|
||||
select->rse_count = 1;
|
||||
select->rse_context[0] = context;
|
||||
|
||||
// Introduce the update context
|
||||
|
||||
gpre_ctx* update_context = MSC_context(request);
|
||||
update_context->ctx_relation = relation;
|
||||
request->req_update = update_context;
|
||||
|
||||
// Introduce the insertion context
|
||||
|
||||
gpre_ctx* insert_context = MSC_context(request);
|
||||
insert_context->ctx_relation = relation;
|
||||
|
||||
// Make assignment lists for both update and insert contexts
|
||||
|
||||
gpre_nod* upd_list = MSC_node(nod_list, (SSHORT) count);
|
||||
gpre_nod* ins_list = MSC_node(nod_list, (SSHORT) count);
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
ref* org_ref = (ref*) field_list->nod_arg[i]->nod_arg[0];
|
||||
|
||||
ref* new_ref = (ref*) MSC_alloc(REF_LEN);
|
||||
new_ref->ref_field = org_ref->ref_field;
|
||||
new_ref->ref_context = update_context;
|
||||
|
||||
gpre_nod* assignment = MSC_node(nod_assignment, 2);
|
||||
assignment->nod_arg[0] = value_list->nod_arg[i];
|
||||
assignment->nod_arg[1] = MSC_unary(nod_field, (gpre_nod*) new_ref);
|
||||
pair(assignment->nod_arg[0], assignment->nod_arg[1]);
|
||||
|
||||
upd_list->nod_arg[i] = assignment;
|
||||
|
||||
new_ref = (ref*) MSC_alloc(REF_LEN);
|
||||
new_ref->ref_field = org_ref->ref_field;
|
||||
new_ref->ref_context = insert_context;
|
||||
|
||||
assignment = MSC_node(nod_assignment, 2);
|
||||
assignment->nod_arg[0] = value_list->nod_arg[i];
|
||||
assignment->nod_arg[1] = MSC_unary(nod_field, (gpre_nod*) new_ref);
|
||||
pair(assignment->nod_arg[0], assignment->nod_arg[1]);
|
||||
|
||||
ins_list->nod_arg[i] = assignment;
|
||||
}
|
||||
|
||||
// Create boolean
|
||||
|
||||
gpre_nod* boolean = NULL;
|
||||
while (matches)
|
||||
{
|
||||
gpre_nod* match = MSC_pop(&matches);
|
||||
ref* match_ref = (ref*) match->nod_arg[0];
|
||||
gpre_fld* match_field = match_ref->ref_field;
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
gpre_nod* from = value_list->nod_arg[i];
|
||||
gpre_nod* to = field_list->nod_arg[i];
|
||||
ref* to_ref = (ref*) to->nod_arg[0];
|
||||
gpre_fld* to_field = to_ref->ref_field;
|
||||
|
||||
if (!strcmp(match_field->fld_symbol->sym_string,
|
||||
to_field->fld_symbol->sym_string))
|
||||
{
|
||||
gpre_nod* eql = MSC_binary(cmp_op, match, from);
|
||||
|
||||
if (boolean)
|
||||
boolean = MSC_binary(nod_and, boolean, eql);
|
||||
else
|
||||
boolean = eql;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!boolean)
|
||||
PAR_error("Invalid MATCHING list");
|
||||
|
||||
select->rse_boolean = boolean;
|
||||
|
||||
// Process a returning clause
|
||||
|
||||
ref* ref_list = NULL;
|
||||
gpre_nod* upd_ret_list = NULL;
|
||||
gpre_nod* ins_ret_list = NULL;
|
||||
|
||||
if (MSC_match(KW_RETURNING))
|
||||
{
|
||||
gpre_nod* value_list = SQE_list(SQE_value_or_null, NULL, false);
|
||||
|
||||
if (!MSC_match(KW_INTO))
|
||||
CPR_s_error("INTO");
|
||||
|
||||
gpre_nod* var_list = SQE_list(SQE_variable, request, false);
|
||||
|
||||
gpre_sym* old_ctx_sym = MSC_symbol(SYM_context, OLD_CONTEXT, strlen(OLD_CONTEXT), context);
|
||||
HSH_insert(old_ctx_sym);
|
||||
|
||||
// temporarily hide the insertion context
|
||||
|
||||
fb_assert(request->req_contexts == insert_context);
|
||||
request->req_contexts = request->req_contexts->ctx_next;
|
||||
|
||||
gpre_sym* new_ctx_sym = MSC_symbol(SYM_context, NEW_CONTEXT, strlen(NEW_CONTEXT), update_context);
|
||||
HSH_insert(new_ctx_sym);
|
||||
|
||||
upd_ret_list = return_values(request, value_list, var_list);
|
||||
|
||||
// restore the insertion context back
|
||||
|
||||
fb_assert(request->req_contexts == update_context);
|
||||
request->req_contexts = insert_context;
|
||||
|
||||
new_ctx_sym->sym_object = insert_context;
|
||||
|
||||
ins_ret_list = return_values(request, value_list, var_list);
|
||||
|
||||
for (int i = 0; i < value_list->nod_count; i++)
|
||||
SQE_resolve(&value_list->nod_arg[i], request, NULL);
|
||||
|
||||
into(request, value_list, var_list);
|
||||
ref_list = (ref*) var_list;
|
||||
|
||||
HSH_remove(new_ctx_sym);
|
||||
HSH_remove(old_ctx_sym);
|
||||
|
||||
request->req_flags |= REQ_sql_returning;
|
||||
select->rse_flags |= RSE_singleton;
|
||||
}
|
||||
|
||||
// Create the final node
|
||||
|
||||
gpre_nod* compound = MSC_node(nod_list, 2);
|
||||
compound->nod_arg[0] = MSC_binary(nod_modify, upd_list, upd_ret_list);
|
||||
compound->nod_arg[1] = MSC_ternary(nod_store, (gpre_nod*) insert_context, ins_list, ins_ret_list);
|
||||
request->req_node = compound;
|
||||
|
||||
if (context->ctx_symbol)
|
||||
HSH_remove(context->ctx_symbol);
|
||||
|
||||
act* action = MSC_action(request, ACT_loop);
|
||||
action->act_object = ref_list;
|
||||
action->act_whenever = gen_whenever();
|
||||
return action;
|
||||
}
|
||||
|
||||
|
||||
//____________________________________________________________
|
||||
//
|
||||
// Handle an SQL whenever statement. This is declaratory,
|
||||
@ -6122,6 +6502,28 @@ static USHORT resolve_dtypes(kwwords_t typ, bool sql_date)
|
||||
}
|
||||
|
||||
|
||||
//____________________________________________________________
|
||||
//
|
||||
// Generate the assignment list for the RETURNING clause
|
||||
//
|
||||
|
||||
static gpre_nod* return_values(gpre_req* request, gpre_nod* src_list, gpre_nod* dst_list)
|
||||
{
|
||||
gpre_nod* ret_list = MSC_node(nod_list, src_list->nod_count);
|
||||
|
||||
for (int i = 0; i < src_list->nod_count; i++)
|
||||
{
|
||||
gpre_nod* assignment = MSC_node(nod_assignment, 2);
|
||||
assignment->nod_arg[0] = src_list->nod_arg[i];
|
||||
SQE_resolve(&assignment->nod_arg[0], request, NULL);
|
||||
assignment->nod_arg[1] = dst_list->nod_arg[i];
|
||||
ret_list->nod_arg[i] = assignment;
|
||||
}
|
||||
|
||||
return ret_list;
|
||||
}
|
||||
|
||||
|
||||
//____________________________________________________________
|
||||
//
|
||||
// Parse the tail of a CREATE DATABASE statement.
|
||||
|
@ -89,6 +89,7 @@ enum kwwords_t {
|
||||
KW_RELEASE,
|
||||
KW_RELEASE_REQUESTS,
|
||||
KW_RETURNING,
|
||||
KW_RETURNING_VALUES,
|
||||
KW_ROLE,
|
||||
KW_ROLLBACK,
|
||||
KW_R_BRACE,
|
||||
|
Loading…
Reference in New Issue
Block a user