8
0
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:
dimitr 2014-12-21 13:45:26 +00:00
parent dc0d56ed6d
commit 237c91d82b
17 changed files with 870 additions and 129 deletions

View File

@ -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);
}

View File

@ -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);

View File

@ -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);
}
}

View File

@ -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);

View File

@ -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},

View File

@ -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)
{

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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);
}

View File

@ -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);
}
}

View File

@ -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.

View File

@ -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);

View File

@ -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)

View File

@ -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);
}
}

View File

@ -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

View File

@ -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.

View File

@ -89,6 +89,7 @@ enum kwwords_t {
KW_RELEASE,
KW_RELEASE_REQUESTS,
KW_RETURNING,
KW_RETURNING_VALUES,
KW_ROLE,
KW_ROLLBACK,
KW_R_BRACE,