8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-23 18:43:03 +01:00

1. Reworked internal_info implementation in both DSQL and JRD.

New helper class created to serve it properly.
2. Added exception re-raise semantics.
Syntax: EXCEPTION;
If there was handled exception, re-initiate it, otherwise evaluate to no-op.
3. Implemented run-time exception messages.
Syntax: EXCEPTION <exception_name> [<value>];
If <value> is specified, evaluate it and use instead of RDB$EXCEPTION_MESSAGE.
4. Added new SQLCODE and GDSCODE system variables.
Available in procedures/triggers only.
If there wasn't any exception raised, return zero (success), otherwise return an error code.
5. Implemented ROWS_AFFECTED system variable.
Available in procedures/triggers only.
Count rows affected by the last INSERT/UPDATE/DELETE statement.
For any other statement, result is always zero.
This commit is contained in:
dimitr 2002-09-28 14:04:35 +00:00
parent 6a497e85f9
commit 536d8c0552
19 changed files with 3638 additions and 3876 deletions

View File

@ -29,7 +29,7 @@
* *
*/ */
/* /*
$Id: dsql.cpp,v 1.23 2002-09-25 17:12:06 skidder Exp $ $Id: dsql.cpp,v 1.24 2002-09-28 14:03:39 dimitr Exp $
*/ */
/************************************************************** /**************************************************************
V4 Multi-threading changes. V4 Multi-threading changes.
@ -2046,6 +2046,7 @@ void DSQL_pretty(NOD node, int column)
verb = "insert"; verb = "insert";
break; break;
case nod_internal_info: case nod_internal_info:
case nod_proc_internal_info:
verb = "internal info"; verb = "internal info";
break; break;
case nod_join: case nod_join:

View File

@ -246,3 +246,4 @@
#define USING 502 #define USING 502
#define NULLS 503 #define NULLS 503
#define LAST 504 #define LAST 504
#define ROWS_AFFECTED 505

View File

@ -20,12 +20,14 @@
* All Rights Reserved. * All Rights Reserved.
* Contributor(s): ______________________________________ * Contributor(s): ______________________________________
* 2001.6.21 Claudio Valderrama: BREAK and SUBSTRING. * 2001.6.21 Claudio Valderrama: BREAK and SUBSTRING.
* 2001.07.28: John Bellardo: Added code to generate blr_skip. * 2001.07.28 John Bellardo: Added code to generate blr_skip.
* 2002.07.30: Arno Brinkman: Added code, procedures to generate COALESCE, CASE * 2002.07.30 Arno Brinkman: Added code, procedures to generate COALESCE, CASE
* * 2002.09.28 Dmitry Yemanov: Reworked internal_info stuff, enhanced
* exception handling in SPs/triggers,
* implemented ROWS_AFFECTED system variable
*/ */
/* /*
$Id: gen.cpp,v 1.11 2002-09-25 17:12:06 skidder Exp $ $Id: gen.cpp,v 1.12 2002-09-28 14:03:39 dimitr Exp $
*/ */
#include "firebird.h" #include "firebird.h"
@ -43,6 +45,7 @@ $Id: gen.cpp,v 1.11 2002-09-25 17:12:06 skidder Exp $
#include "../dsql/gen_proto.h" #include "../dsql/gen_proto.h"
#include "../dsql/make_proto.h" #include "../dsql/make_proto.h"
#include "../dsql/metd_proto.h" #include "../dsql/metd_proto.h"
#include "../dsql/misc_func.h"
#include "../jrd/thd_proto.h" #include "../jrd/thd_proto.h"
#include "../jrd/dsc_proto.h" #include "../jrd/dsc_proto.h"
#include "gen/iberror.h" #include "gen/iberror.h"
@ -83,15 +86,6 @@ static CONST SCHAR db_key_name[] = "DB_KEY";
#define NEGATE_VALUE TRUE #define NEGATE_VALUE TRUE
#define USE_VALUE FALSE #define USE_VALUE FALSE
/* Internal info request types */
enum internal_info_req
{
connection_id = 1,
transaction_id = 2
};
UCHAR GEN_expand_buffer( REQ request, UCHAR byte) UCHAR GEN_expand_buffer( REQ request, UCHAR byte)
{ {
/************************************** /**************************************
@ -440,6 +434,7 @@ void GEN_expr( REQ request, NOD node)
break; break;
case nod_internal_info: case nod_internal_info:
case nod_proc_internal_info:
operator_ = blr_internal_info; operator_ = blr_internal_info;
break; break;
case nod_upcase: case nod_upcase:
@ -889,8 +884,7 @@ void GEN_statement( REQ request, NOD node)
NOD temp, *ptr, *end; NOD temp, *ptr, *end;
CTX context; CTX context;
MSG message; MSG message;
STR name; STR name, string;
STR string;
TEXT *p; TEXT *p;
ULONG id_length; ULONG id_length;
@ -1048,8 +1042,8 @@ void GEN_statement( REQ request, NOD node)
return; return;
case nod_breakleave: case nod_breakleave:
STUFF (blr_leave); STUFF(blr_leave);
STUFF ((int) node->nod_arg [e_break_number]); STUFF((int) node->nod_arg[e_break_number]);
return; return;
case nod_store: case nod_store:
@ -1077,17 +1071,46 @@ void GEN_statement( REQ request, NOD node)
case nod_exception_stmt: case nod_exception_stmt:
STUFF(blr_abort); STUFF(blr_abort);
STUFF(blr_exception); string = (STR) node->nod_arg[e_xcp_name];
string = (STR) node->nod_arg[0]; temp = node->nod_arg[e_xcp_msg];
if (!(string->str_flags & STR_delimited_id)) { /* if exception name is undefined,
it means we have re-initiate semantics here,
so blr_raise verb should be generated */
if (!string)
{
STUFF(blr_raise);
return;
}
/* if exception value is defined,
it means we have user-defined exception message here,
so blr_exception_msg verb should be generated */
if (temp)
{
STUFF(blr_exception_msg);
}
/* otherwise go usual way,
i.e. generate blr_exception */
else
{
STUFF(blr_exception);
}
if (!(string->str_flags & STR_delimited_id))
{
id_length = string->str_length; id_length = string->str_length;
for (p = reinterpret_cast < char *>(string->str_data); *p; for (p = reinterpret_cast<char*>(string->str_data); *p;
id_length--) { id_length--)
{
*p = UPPER(*p); *p = UPPER(*p);
*p++; *p++;
} }
} }
STUFF_CSTRING(string->str_data); STUFF_CSTRING(string->str_data);
/* if exception value is defined,
generate appropriate BLR verbs */
if (temp)
{
GEN_expr(request, temp);
}
return; return;
case nod_while: case nod_while:
@ -2198,20 +2221,11 @@ static void gen_select( REQ request, NOD rse)
parameter->par_name = parameter->par_alias = "USER"; parameter->par_name = parameter->par_alias = "USER";
else if (item->nod_type == nod_current_role) else if (item->nod_type == nod_current_role)
parameter->par_name = parameter->par_alias = "ROLE"; parameter->par_name = parameter->par_alias = "ROLE";
else if (item->nod_type == nod_internal_info) else if (item->nod_type == nod_internal_info || item->nod_type == nod_proc_internal_info)
{ {
internal_info_req request = internal_info_id id =
*reinterpret_cast<internal_info_req*>(item->nod_arg[0]->nod_desc.dsc_address); *reinterpret_cast<internal_info_id*>(item->nod_arg[0]->nod_desc.dsc_address);
parameter->par_name = parameter->par_alias = InternalInfo::getAlias(id);
switch (request)
{
case connection_id:
parameter->par_name = parameter->par_alias = "CONNECTION_ID";
break;
case transaction_id:
parameter->par_name = parameter->par_alias = "TRANSACTION_ID";
break;
}
} }
else if (item->nod_type == nod_substr) { else if (item->nod_type == nod_substr) {
/* CVC: SQL starts at 1 but C starts at zero. */ /* CVC: SQL starts at 1 but C starts at zero. */

View File

@ -28,7 +28,7 @@
* Contributor(s): * Contributor(s):
* *
* *
* $Id: keywords.cpp,v 1.7 2002-09-10 18:28:19 skidder Exp $ * $Id: keywords.cpp,v 1.8 2002-09-28 14:03:39 dimitr Exp $
* *
*/ */
@ -232,6 +232,7 @@ static CONST TOK tokens [] = {
{RIGHT, "RIGHT", 1}, {RIGHT, "RIGHT", 1},
{ROLE, "ROLE", 1}, {ROLE, "ROLE", 1},
{ROLLBACK, "ROLLBACK", 1}, {ROLLBACK, "ROLLBACK", 1},
{ROWS_AFFECTED, "ROWS_AFFECTED", 2},
{DATABASE, "SCHEMA", 1}, /* Alias of DATABASE */ {DATABASE, "SCHEMA", 1}, /* Alias of DATABASE */
{SECOND, "SECOND", 2}, {SECOND, "SECOND", 2},
{SEGMENT, "SEGMENT", 1}, {SEGMENT, "SEGMENT", 1},

View File

@ -929,6 +929,7 @@ void MAKE_desc( DSC * desc, NOD node)
return; return;
case nod_internal_info: case nod_internal_info:
case nod_proc_internal_info:
desc->dsc_dtype = dtype_long; desc->dsc_dtype = dtype_long;
desc->dsc_scale = 0; desc->dsc_scale = 0;
desc->dsc_flags = 0; desc->dsc_flags = 0;

40
src/dsql/misc_func.cpp Normal file
View File

@ -0,0 +1,40 @@
/*
* PROGRAM: Miscellaneous internal functions support (DSQL layer)
* MODULE: misc_func.cpp
* DESCRIPTION: DSQL helper.
*
* The contents of this file are subject to the Interbase Public
* License Version 1.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy
* of the License at http://www.Inprise.com/IPL.html
*
* Software distributed under the License is distributed on an
* "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express
* or implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code was created by Inprise Corporation
* and its predecessors. Portions created by Inprise Corporation are
* Copyright (C) Inprise Corporation.
*
* All Rights Reserved.
* Contributor(s): ______________________________________
*
* 2002.09.20 Dmitry Yemanov: Created all this stuff
*/
#include "../dsql/misc_func.h"
char* InternalInfo::alias_array[max_internal_id] = {
"<UNKNOWN>",
"CONNECTION_ID",
"TRANSACTION_ID",
"GDSCODE",
"SQLCODE",
"ROWS_AFFECTED"
};
char *InternalInfo::getAlias(internal_info_id info_id)
{
return alias_array[info_id];
}

38
src/dsql/misc_func.h Normal file
View File

@ -0,0 +1,38 @@
/*
* PROGRAM: Miscellaneous internal functions support (DSQL layer)
* MODULE: misc_func.h
* DESCRIPTION: DSQL helper.
*
* The contents of this file are subject to the Interbase Public
* License Version 1.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy
* of the License at http://www.Inprise.com/IPL.html
*
* Software distributed under the License is distributed on an
* "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express
* or implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code was created by Inprise Corporation
* and its predecessors. Portions created by Inprise Corporation are
* Copyright (C) Inprise Corporation.
*
* All Rights Reserved.
* Contributor(s): ______________________________________
*
* 2002.09.20 Dmitry Yemanov: Created all this stuff
*/
#ifndef _DSQL_MISC_FUNC_H_
#define _DSQL_MISC_FUNC_H_
#include "../jrd/misc_func_ids.h"
class InternalInfo {
private:
static char *alias_array[max_internal_id];
public:
static char *getAlias(internal_info_id);
};
#endif // _DSQL_MISC_FUNC_H_

View File

@ -315,6 +315,7 @@ typedef ENUM nod_t
nod_redef_procedure, /* allows silent creation/overwriting of a procedure. */ nod_redef_procedure, /* allows silent creation/overwriting of a procedure. */
nod_exec_sql, /* EXECUTE VARCHAR */ nod_exec_sql, /* EXECUTE VARCHAR */
nod_internal_info, /* internal engine info */ nod_internal_info, /* internal engine info */
nod_proc_internal_info,
nod_searched_case, /* searched CASE function */ nod_searched_case, /* searched CASE function */
nod_simple_case, /* simple CASE function */ nod_simple_case, /* simple CASE function */
nod_coalesce, /* COALESCE function */ nod_coalesce, /* COALESCE function */
@ -436,6 +437,10 @@ typedef nod *NOD;
#define e_internal_info 0 /* nod_internal_info */ #define e_internal_info 0 /* nod_internal_info */
#define e_internal_info_count 1 #define e_internal_info_count 1
#define e_xcp_name 0 /* nod_exception_stmt */
#define e_xcp_msg 1
#define e_xcp_count 2
#define e_rtn_procedure 0 /* nod_procedure */ #define e_rtn_procedure 0 /* nod_procedure */
#define e_rtn_count 1 #define e_rtn_count 1

File diff suppressed because it is too large Load Diff

View File

@ -51,9 +51,11 @@
* 2002.08.07 Dmitry Yemanov: INT64/LARGEINT are replaced with BIGINT and available in dialect 3 only * 2002.08.07 Dmitry Yemanov: INT64/LARGEINT are replaced with BIGINT and available in dialect 3 only
* 2002.08.31 Dmitry Yemanov: allowed user-defined index names for PK/FK/UK constraints * 2002.08.31 Dmitry Yemanov: allowed user-defined index names for PK/FK/UK constraints
* 2002.09.01 Dmitry Yemanov: RECREATE VIEW * 2002.09.01 Dmitry Yemanov: RECREATE VIEW
* 2002.09.28 Dmitry Yemanov: Reworked internal_info stuff, enhanced
* exception handling in SPs/triggers,
* implemented ROWS_AFFECTED system variable
*/ */
#if defined(DEV_BUILD) && defined(WIN32) && defined(SUPERSERVER) #if defined(DEV_BUILD) && defined(WIN32) && defined(SUPERSERVER)
#include <windows.h> #include <windows.h>
/*#include <wincon.h>*/ /*#include <wincon.h>*/
@ -78,9 +80,9 @@
#include "../dsql/make_proto.h" #include "../dsql/make_proto.h"
#include "../dsql/parse_proto.h" #include "../dsql/parse_proto.h"
#include "../dsql/keywords.h" #include "../dsql/keywords.h"
#include "../dsql/misc_func.h"
#include "../jrd/gds_proto.h" #include "../jrd/gds_proto.h"
#include "../jrd/thd_proto.h" #include "../jrd/thd_proto.h"
/* #include "../jrd/err_proto.h" */
#include "../wal/wal.h" #include "../wal/wal.h"
/* Can't include ../jrd/err_proto.h here because it pulls jrd.h. */ /* Can't include ../jrd/err_proto.h here because it pulls jrd.h. */
@ -408,6 +410,7 @@ static void yyerror (TEXT *);
%token USING %token USING
%token NULLS %token NULLS
%token LAST %token LAST
%token ROWS_AFFECTED
/* precedence declarations for expression evaluation */ /* precedence declarations for expression evaluation */
@ -1434,21 +1437,16 @@ proc_block : proc_statement
| full_proc_block | full_proc_block
; ;
full_proc_block : BEGIN full_proc_block : BEGIN full_proc_block_body END
END { $$ = $2; }
{ $$ = make_node (nod_block, e_blk_count, ;
NULL, NULL);}
| BEGIN full_proc_block_body : proc_statements
proc_statements { $$ = make_node (nod_block, e_blk_count, make_list ($1), NULL); }
END | proc_statements excp_hndl_statements
{ $$ = make_node (nod_block, e_blk_count, { $$ = make_node (nod_block, e_blk_count, make_list ($1), make_list ($2)); }
make_list ($2), NULL);} |
| BEGIN { $$ = make_node (nod_block, e_blk_count, NULL, NULL);}
proc_statements
excp_statements
END
{ $$ = make_node (nod_block, e_blk_count,
make_list ($2), make_list ($3));}
; ;
proc_statements : proc_block proc_statements : proc_block
@ -1458,8 +1456,8 @@ proc_statements : proc_block
proc_statement : assignment ';' proc_statement : assignment ';'
| delete ';' | delete ';'
| EXCEPTION symbol_exception_name ';' | excp_statement
{ $$ = make_node (nod_exception_stmt, 1, $2); } | raise_statement
| exec_procedure | exec_procedure
| exec_sql | exec_sql
| for_select | for_select
@ -1478,6 +1476,16 @@ proc_statement : assignment ';'
{ $$ = make_node (nod_breakleave, e_break_count, NULL); } { $$ = make_node (nod_breakleave, e_break_count, NULL); }
; ;
excp_statement : EXCEPTION symbol_exception_name ';'
{ $$ = make_node (nod_exception_stmt, e_xcp_count, $2, NULL); }
| EXCEPTION symbol_exception_name value ';'
{ $$ = make_node (nod_exception_stmt, e_xcp_count, $2, $3); }
;
raise_statement : EXCEPTION ';'
{ $$ = make_node (nod_exception_stmt, e_xcp_count, NULL, NULL); }
;
exec_procedure : EXECUTE PROCEDURE symbol_procedure_name proc_inputs proc_outputs ';' exec_procedure : EXECUTE PROCEDURE symbol_procedure_name proc_inputs proc_outputs ';'
{ $$ = make_node (nod_exec_procedure, e_exe_count, $3, { $$ = make_node (nod_exec_procedure, e_exe_count, $3,
$4, $5); } $4, $5); }
@ -1542,12 +1550,12 @@ cursor_def : AS CURSOR symbol_cursor_name
| |
{ $$ = NULL; } { $$ = NULL; }
; ;
excp_statements : excp_statement excp_hndl_statements : excp_hndl_statement
| excp_statements excp_statement | excp_hndl_statements excp_hndl_statement
{ $$ = make_node (nod_list, 2, $1, $2); } { $$ = make_node (nod_list, 2, $1, $2); }
; ;
excp_statement : WHEN errors DO proc_block excp_hndl_statement : WHEN errors DO proc_block
{ $$ = make_node (nod_on_error, e_err_count, { $$ = make_node (nod_on_error, e_err_count,
make_list ($2), $4); } make_list ($2), $4); }
; ;
@ -3319,6 +3327,8 @@ value : column_name
| current_role | current_role
| internal_info | internal_info
{ $$ = $1; } { $$ = $1; }
| proc_internal_info
{ $$ = $1; }
| DB_KEY | DB_KEY
{ $$ = make_node (nod_dbkey, 1, NULL); } { $$ = make_node (nod_dbkey, 1, NULL); }
| symbol_table_alias_name '.' DB_KEY | symbol_table_alias_name '.' DB_KEY
@ -3433,24 +3443,6 @@ u_constant : u_numeric_constant
{ $$ = MAKE_constant ((STR) $2, CONSTANT_TIMESTAMP); } { $$ = MAKE_constant ((STR) $2, CONSTANT_TIMESTAMP); }
; ;
constant_list : constant
| parameter
| current_user
| current_role
| internal_info
| constant_list ',' constant
{ $$ = make_node (nod_list, 2, $1, $3); }
| constant_list ',' parameter
{ $$ = make_node (nod_list, 2, $1, $3); }
| constant_list ',' current_user
{ $$ = make_node (nod_list, 2, $1, $3); }
| constant_list ',' current_role
{ $$ = make_node (nod_list, 2, $1, $3); }
| constant_list ',' internal_info
{ $$ = make_node (nod_list, 2, $1, $3); }
;
parameter : '?' parameter : '?'
{ $$ = make_node (nod_parameter, 0, NULL); } { $$ = make_node (nod_parameter, 0, NULL); }
; ;
@ -3467,10 +3459,21 @@ current_role : CURRENT_ROLE
internal_info : CONNECTION_ID internal_info : CONNECTION_ID
{ $$ = make_node (nod_internal_info, e_internal_info_count, { $$ = make_node (nod_internal_info, e_internal_info_count,
MAKE_constant ((STR) 1, CONSTANT_SLONG)); } MAKE_constant ((STR) internal_connection_id, CONSTANT_SLONG)); }
| TRANSACTION_ID | TRANSACTION_ID
{ $$ = make_node (nod_internal_info, e_internal_info_count, { $$ = make_node (nod_internal_info, e_internal_info_count,
MAKE_constant ((STR) 2, CONSTANT_SLONG)); } MAKE_constant ((STR) internal_transaction_id, CONSTANT_SLONG)); }
;
proc_internal_info : GDSCODE
{ $$ = make_node (nod_proc_internal_info, e_internal_info_count,
MAKE_constant ((STR) internal_gdscode, CONSTANT_SLONG)); }
| SQLCODE
{ $$ = make_node (nod_proc_internal_info, e_internal_info_count,
MAKE_constant ((STR) internal_sqlcode, CONSTANT_SLONG)); }
| ROWS_AFFECTED
{ $$ = make_node (nod_proc_internal_info, e_internal_info_count,
MAKE_constant ((STR) internal_rows_affected, CONSTANT_SLONG)); }
; ;
sql_string : STRING /* string in current charset */ sql_string : STRING /* string in current charset */

View File

@ -95,6 +95,10 @@
* 2002.08.07 Dmitry Yemanov: Disabled BREAK statement in triggers * 2002.08.07 Dmitry Yemanov: Disabled BREAK statement in triggers
* *
* 2002.08.10 Dmitry Yemanov: ALTER VIEW * 2002.08.10 Dmitry Yemanov: ALTER VIEW
*
* 2002.09.28 Dmitry Yemanov: Reworked internal_info stuff, enhanced
* exception handling in SPs/triggers,
* implemented ROWS_AFFECTED system variable
*/ */
#include "firebird.h" #include "firebird.h"
@ -116,6 +120,7 @@
#include "../dsql/make_proto.h" #include "../dsql/make_proto.h"
#include "../dsql/metd_proto.h" #include "../dsql/metd_proto.h"
#include "../dsql/pass1_proto.h" #include "../dsql/pass1_proto.h"
#include "../dsql/misc_func.h"
#include "../jrd/dsc_proto.h" #include "../jrd/dsc_proto.h"
#include "../jrd/thd_proto.h" #include "../jrd/thd_proto.h"
@ -753,6 +758,16 @@ NOD PASS1_node(REQ request, NOD input, USHORT proc_flag)
node->nod_desc = input->nod_desc; node->nod_desc = input->nod_desc;
return node; return node;
case nod_proc_internal_info:
{
internal_info_id id =
*reinterpret_cast<internal_info_id*>(input->nod_arg[0]->nod_desc.dsc_address);
if (!(request->req_flags & REQ_procedure))
ERRD_post(gds_sqlerr, gds_arg_number, (SLONG) - 104, gds_arg_gds, gds_token_err, /* Token unknown */
gds_arg_gds, gds_random, gds_arg_string, InternalInfo::getAlias(id), 0);
}
break;
default: default:
break; break;
} }
@ -1173,7 +1188,20 @@ NOD PASS1_statement(REQ request, NOD input, USHORT proc_flag)
case nod_exception_stmt: case nod_exception_stmt:
node = input; node = input;
if (request->req_error_handlers) { /* if exception value is defined,
pass value node */
if (input->nod_arg[e_xcp_msg])
{
node->nod_arg[e_xcp_msg] = PASS1_node(request,
input->nod_arg[e_xcp_msg],
proc_flag);
}
else
{
node->nod_arg[e_xcp_msg] = 0;
}
if (request->req_error_handlers)
{
temp = MAKE_node(nod_list, 3); temp = MAKE_node(nod_list, 3);
temp->nod_arg[0] = MAKE_node(nod_start_savepoint, 0); temp->nod_arg[0] = MAKE_node(nod_start_savepoint, 0);
temp->nod_arg[1] = input; temp->nod_arg[1] = input;
@ -1756,6 +1784,7 @@ static NOD copy_field( NOD field, CTX context)
case nod_subtract2: case nod_subtract2:
case nod_upcase: case nod_upcase:
case nod_internal_info: case nod_internal_info:
case nod_proc_internal_info:
case nod_extract: case nod_extract:
case nod_list: case nod_list:
temp = MAKE_node(field->nod_type, field->nod_count); temp = MAKE_node(field->nod_type, field->nod_count);
@ -2254,6 +2283,7 @@ static BOOLEAN invalid_reference(REQ request, NOD node, NOD list, BOOLEAN exact_
case nod_user_name: case nod_user_name:
case nod_current_role: case nod_current_role:
case nod_internal_info: case nod_internal_info:
case nod_proc_internal_info:
return FALSE; return FALSE;
} }

View File

@ -21,6 +21,9 @@
* Contributor(s): ______________________________________. * Contributor(s): ______________________________________.
* *
* Claudio Valderrama: 2001.6.18: Add blr_current_role. * Claudio Valderrama: 2001.6.18: Add blr_current_role.
* 2002.09.28 Dmitry Yemanov: Reworked internal_info stuff, enhanced
* exception handling in SPs/triggers,
* implemented ROWS_AFFECTED system variable
*/ */
#ifndef _JRD_BLR_H_ #ifndef _JRD_BLR_H_
@ -65,6 +68,8 @@
#define blr_exception (unsigned char)2 #define blr_exception (unsigned char)2
#define blr_trigger_code (unsigned char)3 #define blr_trigger_code (unsigned char)3
#define blr_default_code (unsigned char)4 #define blr_default_code (unsigned char)4
#define blr_raise (unsigned char)5
#define blr_exception_msg (unsigned char)6
#define blr_version4 (unsigned char)4 #define blr_version4 (unsigned char)4
#define blr_version5 (unsigned char)5 #define blr_version5 (unsigned char)5

View File

@ -28,9 +28,12 @@
* if source is blob and should check implementation limits on field lengths. * if source is blob and should check implementation limits on field lengths.
* 2002.02.25 Claudio Valderrama: concatenate() should be a civilized function. * 2002.02.25 Claudio Valderrama: concatenate() should be a civilized function.
* This closes the heart of SF Bug #518282. * This closes the heart of SF Bug #518282.
* 2002.09.28 Dmitry Yemanov: Reworked internal_info stuff, enhanced
* exception handling in SPs/triggers,
* implemented ROWS_AFFECTED system variable
*/ */
/* /*
$Id: cmp.cpp,v 1.13 2002-09-27 22:59:23 skidder Exp $ $Id: cmp.cpp,v 1.14 2002-09-28 14:04:34 dimitr Exp $
*/ */
#include "firebird.h" #include "firebird.h"
@ -299,6 +302,9 @@ REQ DLL_EXPORT CMP_clone_request(TDBB tdbb,
clone->req_top_node = request->req_top_node; clone->req_top_node = request->req_top_node;
clone->req_trg_name = request->req_trg_name; clone->req_trg_name = request->req_trg_name;
clone->req_flags = request->req_flags & REQ_FLAGS_CLONE_MASK; clone->req_flags = request->req_flags & REQ_FLAGS_CLONE_MASK;
clone->req_last_xcp.xcp_type = request->req_last_xcp.xcp_type;
clone->req_last_xcp.xcp_code = request->req_last_xcp.xcp_code;
clone->req_last_xcp.xcp_msg = request->req_last_xcp.xcp_msg;
rpb1 = clone->req_rpb; rpb1 = clone->req_rpb;
end = rpb1 + clone->req_count; end = rpb1 + clone->req_count;
@ -1736,6 +1742,8 @@ REQ DLL_EXPORT CMP_make_request(TDBB tdbb, CSB * csb_ptr)
request->req_access = csb->csb_access; request->req_access = csb->csb_access;
request->req_variables = csb->csb_variables; request->req_variables = csb->csb_variables;
request->req_resources = csb->csb_resources; request->req_resources = csb->csb_resources;
request->req_last_xcp.xcp_type = 0;
request->req_last_xcp.xcp_msg = 0;
if (csb->csb_g_flags & csb_blr_version4) { if (csb->csb_g_flags & csb_blr_version4) {
request->req_flags |= req_blr_version4; request->req_flags |= req_blr_version4;
} }
@ -2151,6 +2159,8 @@ void DLL_EXPORT CMP_release(TDBB tdbb, REQ request)
break; break;
} }
delete request->req_last_xcp.xcp_msg;
delete request->req_pool; delete request->req_pool;
} }

View File

@ -19,7 +19,7 @@
* *
* All Rights Reserved. * All Rights Reserved.
* Contributor(s): ______________________________________. * Contributor(s): ______________________________________.
* $Id: evl.cpp,v 1.17 2002-09-27 01:28:26 bellardo Exp $ * $Id: evl.cpp,v 1.18 2002-09-28 14:04:35 dimitr Exp $
*/ */
/* /*
@ -54,6 +54,9 @@
* 2002.2.15 Claudio Valderrama: divide2() should not mangle negative values. * 2002.2.15 Claudio Valderrama: divide2() should not mangle negative values.
* 2002.04.16 Paul Beach HP10 Port - (UCHAR*) desc.dsc_address = p; modified for HP * 2002.04.16 Paul Beach HP10 Port - (UCHAR*) desc.dsc_address = p; modified for HP
* Compiler * Compiler
* 2002.09.28 Dmitry Yemanov: Reworked internal_info stuff, enhanced
* exception handling in SPs/triggers,
* implemented ROWS_AFFECTED system variable
*/ */
#include "firebird.h" #include "firebird.h"
@ -105,6 +108,7 @@
#include "../jrd/align.h" #include "../jrd/align.h"
#include "../jrd/met_proto.h" #include "../jrd/met_proto.h"
#include "../jrd/cvt_proto.h" #include "../jrd/cvt_proto.h"
#include "../jrd/misc_func_ids.h"
//#include "../jrd/authenticate.h" //#include "../jrd/authenticate.h"
#if defined(WIN_NT) && defined(_MSC_VER) #if defined(WIN_NT) && defined(_MSC_VER)
@ -126,15 +130,6 @@
extern double MTH$CVT_D_G(), MTH$CVT_G_D(); extern double MTH$CVT_D_G(), MTH$CVT_G_D();
#endif #endif
/* Internal info request types */
enum internal_info_req
{
connection_id = 1,
transaction_id = 2
};
/* *** DANGER DANGER WILL ROBINSON *** /* *** DANGER DANGER WILL ROBINSON ***
* add(), multiply(), and divide() all take the same three arguments, but * add(), multiply(), and divide() all take the same three arguments, but
* they don't all take them in the same order. Be careful out there. * they don't all take them in the same order. Be careful out there.
@ -3931,7 +3926,6 @@ static DSC *lock_state(TDBB tdbb, NOD node, VLU impure)
struct lck temp_lock; struct lck temp_lock;
/* fill out a lock block, zeroing it out first */ /* fill out a lock block, zeroing it out first */
MOVE_CLEAR(&temp_lock, sizeof(struct lck));
temp_lock.lck_parent = dbb->dbb_lock; temp_lock.lck_parent = dbb->dbb_lock;
temp_lock.lck_type = LCK_attachment; temp_lock.lck_type = LCK_attachment;
temp_lock.lck_owner_handle = temp_lock.lck_owner_handle =
@ -5035,17 +5029,30 @@ static DSC *internal_info(TDBB tdbb, DSC * value, VLU impure)
**************************************/ **************************************/
EVL_make_value(tdbb, value, impure); EVL_make_value(tdbb, value, impure);
internal_info_req request = internal_info_id id =
*reinterpret_cast<internal_info_req*>(impure->vlu_desc.dsc_address); *reinterpret_cast<internal_info_id*>(impure->vlu_desc.dsc_address);
switch (request) switch (id)
{ {
case connection_id: case internal_connection_id:
impure->vlu_misc.vlu_long = PAG_attachment_id(); impure->vlu_misc.vlu_long = PAG_attachment_id();
break; break;
case transaction_id: case internal_transaction_id:
impure->vlu_misc.vlu_long = tdbb->tdbb_transaction->tra_number; impure->vlu_misc.vlu_long = tdbb->tdbb_transaction->tra_number;
break; break;
case internal_gdscode:
impure->vlu_misc.vlu_long =
(tdbb->tdbb_request->req_last_xcp.xcp_type == xcp_gds_code) ?
tdbb->tdbb_request->req_last_xcp.xcp_code : 0;
break;
case internal_sqlcode:
impure->vlu_misc.vlu_long =
(tdbb->tdbb_request->req_last_xcp.xcp_type == xcp_sql_code) ?
tdbb->tdbb_request->req_last_xcp.xcp_code : 0;
break;
case internal_rows_affected:
impure->vlu_misc.vlu_long = tdbb->tdbb_request->req_records_affected;
break;
default: default:
BUGCHECK(232); /* msg 232 EVL_expr: invalid operation */ BUGCHECK(232); /* msg 232 EVL_expr: invalid operation */
} }

View File

@ -29,9 +29,12 @@
* being reported instead of one. * being reported instead of one.
* 2001.12.03 Claudio Valderrama: new visit to the same issue: views need * 2001.12.03 Claudio Valderrama: new visit to the same issue: views need
* to count virtual operations, not real I/O on the underlying tables. * to count virtual operations, not real I/O on the underlying tables.
* 2002.09.28 Dmitry Yemanov: Reworked internal_info stuff, enhanced
* exception handling in SPs/triggers,
* implemented ROWS_AFFECTED system variable
*/ */
/* /*
$Id: exe.cpp,v 1.19 2002-09-27 01:28:26 bellardo Exp $ $Id: exe.cpp,v 1.20 2002-09-28 14:04:35 dimitr Exp $
*/ */
#include "firebird.h" #include "firebird.h"
@ -129,10 +132,10 @@ static void seek_rsb(TDBB, REQ, RSB, USHORT, SLONG);
#endif #endif
static NOD selct(TDBB, register NOD); static NOD selct(TDBB, register NOD);
static NOD send_msg(TDBB, register NOD); static NOD send_msg(TDBB, register NOD);
static void set_error(TDBB, XCP); static void set_error(TDBB, XCP, NOD);
static NOD stall(TDBB, register NOD); static NOD stall(TDBB, register NOD);
static NOD store(TDBB, register NOD, SSHORT); static NOD store(TDBB, register NOD, SSHORT);
static BOOLEAN test_error(TDBB, const XCP); static BOOLEAN test_and_fixup_error(TDBB, const XCP, REQ);
static void trigger_failure(TDBB, REQ); static void trigger_failure(TDBB, REQ);
static void validate(TDBB, NOD); static void validate(TDBB, NOD);
@ -215,7 +218,6 @@ private:
#endif #endif
void EXE_assignment(TDBB tdbb, NOD node) void EXE_assignment(TDBB tdbb, NOD node)
{ {
/************************************** /**************************************
@ -1234,10 +1236,12 @@ static NOD erase(TDBB tdbb, NOD node, SSHORT which_trig)
if (relation == request->req_top_view_erase) { if (relation == request->req_top_view_erase) {
if (which_trig == ALL_TRIGS || which_trig == POST_TRIG) { if (which_trig == ALL_TRIGS || which_trig == POST_TRIG) {
request->req_records_deleted++; request->req_records_deleted++;
request->req_records_affected++;
} }
} }
else if (relation->rel_file || !relation->rel_view_rse) { else if (relation->rel_file || !relation->rel_view_rse) {
request->req_records_deleted++; request->req_records_deleted++;
request->req_records_affected++;
} }
if (transaction != dbb->dbb_sys_trans) { if (transaction != dbb->dbb_sys_trans) {
@ -1293,6 +1297,7 @@ static void execute_looper(
request->req_flags &= ~req_stall; request->req_flags &= ~req_stall;
request->req_operation = next_state; request->req_operation = next_state;
looper(tdbb, request, request->req_next); looper(tdbb, request, request->req_next);
/* If any requested modify/delete/insert ops have completed, forget them */ /* If any requested modify/delete/insert ops have completed, forget them */
@ -1806,6 +1811,8 @@ static NOD looper(TDBB tdbb, REQ request, NOD in_node)
// Execute stuff until we drop // Execute stuff until we drop
request->req_records_affected = 0;
while (node && !(request->req_flags & req_stall)) while (node && !(request->req_flags & req_stall))
{ {
try { try {
@ -1820,6 +1827,7 @@ static NOD looper(TDBB tdbb, REQ request, NOD in_node)
#if defined(DEBUG_GDS_ALLOC) && FALSE #if defined(DEBUG_GDS_ALLOC) && FALSE
int node_type = node->nod_type; int node_type = node->nod_type;
#endif #endif
switch (node->nod_type) { switch (node->nod_type) {
case nod_asn_list: case nod_asn_list:
if (request->req_operation == req::req_evaluate) { if (request->req_operation == req::req_evaluate) {
@ -1936,7 +1944,34 @@ static NOD looper(TDBB tdbb, REQ request, NOD in_node)
case nod_abort: case nod_abort:
switch (request->req_operation) { switch (request->req_operation) {
case req::req_evaluate: case req::req_evaluate:
set_error(tdbb, reinterpret_cast < xcp * >(node->nod_arg[0])); {
XCP xcp_node = reinterpret_cast<XCP>(node->nod_arg[0]);
if (xcp_node)
{
/* XCP is defined,
so throw an exception */
set_error(tdbb, xcp_node, node->nod_arg[1]);
}
else if (request->req_last_xcp.xcp_type != 0)
{
/* XCP is undefined, but there was a known exception before,
so re-initiate it */
struct xcp last_error;
last_error.xcp_count = 1;
last_error.xcp_rpt[0].xcp_type = request->req_last_xcp.xcp_type;
last_error.xcp_rpt[0].xcp_code = request->req_last_xcp.xcp_code;
last_error.xcp_rpt[0].xcp_msg = request->req_last_xcp.xcp_msg;
request->req_last_xcp.xcp_type = 0;
request->req_last_xcp.xcp_msg = 0;
set_error(tdbb, &last_error, node->nod_arg[1]);
}
else
{
/* XCP is undefined and there weren't any exceptions before,
so just do nothing */
request->req_operation = req::req_return;
}
}
default: default:
node = node->nod_parent; node = node->nod_parent;
@ -2051,16 +2086,18 @@ static NOD looper(TDBB tdbb, REQ request, NOD in_node)
end = ptr + handlers->nod_count; ptr < end; end = ptr + handlers->nod_count; ptr < end;
ptr++) ptr++)
{ {
const XCP pXcp = const XCP xcp_node =
reinterpret_cast<XCP>((*ptr)->nod_arg[e_err_conditions]); reinterpret_cast<XCP>((*ptr)->nod_arg[e_err_conditions]);
if (test_error(tdbb, pXcp)) if (test_and_fixup_error(tdbb, xcp_node, request))
{ {
request->req_operation = req::req_evaluate; request->req_operation = req::req_evaluate;
node = (*ptr)->nod_arg[e_err_action]; node = (*ptr)->nod_arg[e_err_action];
error_pending = FALSE; error_pending = FALSE;
/* On entering looper old_request etc. are saved. /* On entering looper old_request etc. are saved.
On recursive calling we will loose the actual old On recursive calling we will loose the actual old
request for that invocation of looper. Avoid this. */ request for that invocation of looper. Avoid this. */
tdbb->tdbb_default = old_pool; tdbb->tdbb_default = old_pool;
tdbb->tdbb_request = old_request; tdbb->tdbb_request = old_request;
@ -2091,8 +2128,10 @@ static NOD looper(TDBB tdbb, REQ request, NOD in_node)
tdbb->tdbb_default = request->req_pool; tdbb->tdbb_default = request->req_pool;
tdbb->tdbb_request = request; tdbb->tdbb_request = request;
/* The error is dealt with by the application, cleanup /* The error is dealt with by the application, cleanup
this block's savepoint. */ this block's savepoint. */
if (transaction != dbb->dbb_sys_trans) if (transaction != dbb->dbb_sys_trans)
{ {
for (save_point = transaction->tra_save_point; for (save_point = transaction->tra_save_point;
@ -2144,6 +2183,7 @@ static NOD looper(TDBB tdbb, REQ request, NOD in_node)
node = node->nod_parent; node = node->nod_parent;
if (request->req_operation == req::req_unwind) if (request->req_operation == req::req_unwind)
node = node->nod_parent; node = node->nod_parent;
request->req_last_xcp.xcp_type = 0;
break; break;
case nod_label: case nod_label:
@ -2788,10 +2828,12 @@ static NOD modify(TDBB tdbb, register NOD node, SSHORT which_trig)
if (relation == request->req_top_view_modify) { if (relation == request->req_top_view_modify) {
if (which_trig == ALL_TRIGS || which_trig == POST_TRIG) { if (which_trig == ALL_TRIGS || which_trig == POST_TRIG) {
request->req_records_updated++; request->req_records_updated++;
request->req_records_affected++;
} }
} }
else if (relation->rel_file || !relation->rel_view_rse) { else if (relation->rel_file || !relation->rel_view_rse) {
request->req_records_updated++; request->req_records_updated++;
request->req_records_affected++;
} }
if (which_trig != PRE_TRIG) { if (which_trig != PRE_TRIG) {
@ -3374,7 +3416,7 @@ static NOD set_bookmark(TDBB tdbb, NOD node)
#endif #endif
static void set_error(TDBB tdbb, XCP condition) static void set_error(TDBB tdbb, XCP condition, NOD node)
{ {
/************************************** /**************************************
* *
@ -3388,9 +3430,32 @@ static void set_error(TDBB tdbb, XCP condition)
* *
**************************************/ **************************************/
register REQ request; register REQ request;
TEXT name[32], relation_name[32], message[82], *s, *r; TEXT name[32], relation_name[32], message[82], temp[82], *s, *r;
UCHAR *string = 0;
USHORT length = 0;
SET_TDBB(tdbb); SET_TDBB(tdbb);
if (condition->xcp_rpt[0].xcp_msg)
{
/* pick up message from already initiated exception */
length = condition->xcp_rpt[0].xcp_msg->str_length;
memcpy(message, condition->xcp_rpt[0].xcp_msg->str_data, length);
delete condition->xcp_rpt[0].xcp_msg;
condition->xcp_rpt[0].xcp_msg = 0;
}
else if (node)
{
/* evaluate exception message and convert it to string */
length = MOV_make_string(EVL_expr(tdbb, node),
ttype_none,
&string,
reinterpret_cast<VARY*>(temp),
sizeof(temp));
memcpy(message, string, length);
}
message[length] = 0;
request = tdbb->tdbb_request; request = tdbb->tdbb_request;
switch (condition->xcp_rpt[0].xcp_type) { switch (condition->xcp_rpt[0].xcp_type) {
@ -3414,9 +3479,11 @@ static void set_error(TDBB tdbb, XCP condition)
case xcp_xcp_code: case xcp_xcp_code:
MET_lookup_exception(tdbb, condition->xcp_rpt[0].xcp_code, MET_lookup_exception(tdbb, condition->xcp_rpt[0].xcp_code,
name, message); name, temp);
if (message[0]) if (message[0])
s = message; s = message;
else if (temp[0])
s = temp;
else if (name[0]) else if (name[0])
s = name; s = name;
else else
@ -3629,10 +3696,12 @@ static NOD store(TDBB tdbb, register NOD node, SSHORT which_trig)
if (relation == request->req_top_view_store) { if (relation == request->req_top_view_store) {
if (which_trig == ALL_TRIGS || which_trig == POST_TRIG) { if (which_trig == ALL_TRIGS || which_trig == POST_TRIG) {
request->req_records_inserted++; request->req_records_inserted++;
request->req_records_affected++;
} }
} }
else if (relation->rel_file || !relation->rel_view_rse) { else if (relation->rel_file || !relation->rel_view_rse) {
request->req_records_inserted++; request->req_records_inserted++;
request->req_records_affected++;
} }
if (transaction != dbb->dbb_sys_trans) { if (transaction != dbb->dbb_sys_trans) {
@ -3729,29 +3798,48 @@ static NOD stream(TDBB tdbb, register NOD node)
#endif #endif
static BOOLEAN test_error(TDBB tdbb, const XCP conditions) static BOOLEAN test_and_fixup_error(TDBB tdbb, XCP conditions, REQ request)
{ {
/************************************** /**************************************
* *
* t e s t _ e r r o r * t e s t _ a n d _ f i x u p _ e r r o r
* *
************************************** **************************************
* *
* Functional description * Functional description
* Test for match of current state with list of error conditions. * Test for match of current state with list of error conditions.
* Fix type and code of the exception.
* *
**************************************/ **************************************/
SSHORT i, sqlcode;
STATUS *status_vector;
SET_TDBB(tdbb); SET_TDBB(tdbb);
STATUS* status_vector = tdbb->tdbb_status_vector; status_vector = tdbb->tdbb_status_vector;
SSHORT sqlcode = gds__sqlcode(status_vector); sqlcode = gds__sqlcode(status_vector);
for (SSHORT i = 0; i < conditions->xcp_count; ++i) const SLONG XCP_SQLCODE = -836;
delete request->req_last_xcp.xcp_msg;
request->req_last_xcp.xcp_msg = 0;
for (i = 0; i < conditions->xcp_count; i++)
{ {
switch (conditions->xcp_rpt[i].xcp_type) switch (conditions->xcp_rpt[i].xcp_type)
{ {
case xcp_sql_code: case xcp_sql_code:
if (sqlcode == conditions->xcp_rpt[i].xcp_code) { if (sqlcode == conditions->xcp_rpt[i].xcp_code)
{
if ((sqlcode != XCP_SQLCODE) || (status_vector[1] != gds_except))
{
request->req_last_xcp.xcp_type = xcp_sql_code;
request->req_last_xcp.xcp_code = sqlcode;
}
else
{
request->req_last_xcp.xcp_type = xcp_xcp_code;
request->req_last_xcp.xcp_code = status_vector[3];
}
status_vector[0] = 0; status_vector[0] = 0;
status_vector[1] = 0; status_vector[1] = 0;
return TRUE; return TRUE;
@ -3759,7 +3847,10 @@ static BOOLEAN test_error(TDBB tdbb, const XCP conditions)
break; break;
case xcp_gds_code: case xcp_gds_code:
if (status_vector[1] == conditions->xcp_rpt[i].xcp_code) { if (status_vector[1] == conditions->xcp_rpt[i].xcp_code)
{
request->req_last_xcp.xcp_type = xcp_gds_code;
request->req_last_xcp.xcp_code = status_vector[1];
status_vector[0] = 0; status_vector[0] = 0;
status_vector[1] = 0; status_vector[1] = 0;
return TRUE; return TRUE;
@ -3770,6 +3861,16 @@ static BOOLEAN test_error(TDBB tdbb, const XCP conditions)
if ((status_vector[1] == gds_except) && if ((status_vector[1] == gds_except) &&
(status_vector[3] == conditions->xcp_rpt[i].xcp_code)) (status_vector[3] == conditions->xcp_rpt[i].xcp_code))
{ {
request->req_last_xcp.xcp_type = xcp_xcp_code;
request->req_last_xcp.xcp_code = status_vector[3];
TEXT *msg = reinterpret_cast<TEXT*>(status_vector[7]);
if (msg)
{
USHORT len = strlen(msg);
request->req_last_xcp.xcp_msg = FB_NEW_RPT(*getDefaultMemoryPool(), len + 1) str();
request->req_last_xcp.xcp_msg->str_length = len;
memcpy(request->req_last_xcp.xcp_msg->str_data, msg, len + 1);
}
status_vector[0] = 0; status_vector[0] = 0;
status_vector[1] = 0; status_vector[1] = 0;
return TRUE; return TRUE;
@ -3777,11 +3878,37 @@ static BOOLEAN test_error(TDBB tdbb, const XCP conditions)
break; break;
case xcp_default: case xcp_default:
if (sqlcode && (sqlcode != XCP_SQLCODE))
{
request->req_last_xcp.xcp_type = xcp_sql_code;
request->req_last_xcp.xcp_code = sqlcode;
}
else
{
if (status_vector[1] != gds_except)
{
request->req_last_xcp.xcp_type = xcp_gds_code;
request->req_last_xcp.xcp_code = status_vector[1];
}
else
{
request->req_last_xcp.xcp_type = xcp_xcp_code;
request->req_last_xcp.xcp_code = status_vector[3];
TEXT *msg = reinterpret_cast<TEXT*>(status_vector[7]);
if (msg)
{
USHORT len = strlen(msg);
request->req_last_xcp.xcp_msg = FB_NEW_RPT(*getDefaultMemoryPool(), len + 1) str();
request->req_last_xcp.xcp_msg->str_length = len;
memcpy(request->req_last_xcp.xcp_msg->str_data, msg, len + 1);
}
}
}
status_vector[0] = 0; status_vector[0] = 0;
status_vector[1] = 0; status_vector[1] = 0;
return TRUE; return TRUE;
} }
} }
return FALSE; return FALSE;
} }

View File

@ -21,6 +21,9 @@
* Contributor(s): ______________________________________. * Contributor(s): ______________________________________.
* *
* 2001.07.28: Added rse_skip to struct rse to support LIMIT. * 2001.07.28: Added rse_skip to struct rse to support LIMIT.
* 2002.09.28 Dmitry Yemanov: Reworked internal_info stuff, enhanced
* exception handling in SPs/triggers,
* implemented ROWS_AFFECTED system variable
*/ */
#ifndef _JRD_EXE_H_ #ifndef _JRD_EXE_H_
@ -522,11 +525,11 @@ struct csb_repeat
struct idx* csb_idx; /* Packed description of indices */ struct idx* csb_idx; /* Packed description of indices */
struct str* csb_idx_allocation; /* Memory allocated to hold index descriptions */ struct str* csb_idx_allocation; /* Memory allocated to hold index descriptions */
nod* csb_message; /* Msg for send/receive */ nod* csb_message; /* Msg for send/receive */
struct fmt* csb_format; /* Default fmt for stream */ struct fmt* csb_format; /* Default fmt for stream */
struct sbm* csb_fields; /* Fields referenced */ struct sbm* csb_fields; /* Fields referenced */
float csb_cardinality; /* Cardinality of relation */ float csb_cardinality; /* Cardinality of relation */
nod* csb_plan; /* user-specified plan for this relation */ nod* csb_plan; /* user-specified plan for this relation */
UCHAR* csb_map; /* Stream map for views */ UCHAR* csb_map; /* Stream map for views */
struct rsb** csb_rsb_ptr; /* point to rsb for nod_stream */ struct rsb** csb_rsb_ptr; /* point to rsb for nod_stream */
}; };
@ -607,12 +610,13 @@ typedef Csb* CSB;
#define csb_update 16384 /* Erase or modify for relation */ #define csb_update 16384 /* Erase or modify for relation */
#define csb_made_river 32768 /* stream has been included in a river */ #define csb_made_river 32768 /* stream has been included in a river */
/* Exception condition list */ /* Exception condition list */
struct xcp_repeat {
SSHORT xcp_type; struct xcp_repeat {
SLONG xcp_code; SSHORT xcp_type;
}; SLONG xcp_code;
class str *xcp_msg;
};
class xcp : public pool_alloc_rpt<xcp_repeat, type_xcp> class xcp : public pool_alloc_rpt<xcp_repeat, type_xcp>
{ {

40
src/jrd/misc_func_ids.h Normal file
View File

@ -0,0 +1,40 @@
/*
* PROGRAM: Miscellaneous internal functions support (JRD layer)
* MODULE: misc_func_ids.h
* DESCRIPTION: Constants.
*
* The contents of this file are subject to the Interbase Public
* License Version 1.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy
* of the License at http://www.Inprise.com/IPL.html
*
* Software distributed under the License is distributed on an
* "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express
* or implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code was created by Inprise Corporation
* and its predecessors. Portions created by Inprise Corporation are
* Copyright (C) Inprise Corporation.
*
* All Rights Reserved.
* Contributor(s): ______________________________________
*
* 2002.09.20 Dmitry Yemanov: Created all this stuff
*/
#ifndef _JRD_MISC_FUNC_IDS_H_
#define _JRD_MISC_FUNC_IDS_H_
enum internal_info_id
{
internal_unknown = 0,
internal_connection_id = 1,
internal_transaction_id = 2,
internal_gdscode = 3,
internal_sqlcode = 4,
internal_rows_affected = 5,
max_internal_id
};
#endif // _JRD_MISC_FUNC_IDS_H_

View File

@ -23,9 +23,12 @@
* 27-May-2001 Claudio Valderrama: par_plan() no longer uppercases * 27-May-2001 Claudio Valderrama: par_plan() no longer uppercases
* an index's name before doing a lookup of such index. * an index's name before doing a lookup of such index.
* 2001.07.28: Added parse code for blr_skip to support LIMIT. * 2001.07.28: Added parse code for blr_skip to support LIMIT.
* 2002.09.28 Dmitry Yemanov: Reworked internal_info stuff, enhanced
* exception handling in SPs/triggers,
* implemented ROWS_AFFECTED system variable
*/ */
/* /*
$Id: par.cpp,v 1.12 2002-09-25 17:12:10 skidder Exp $ $Id: par.cpp,v 1.13 2002-09-28 14:04:35 dimitr Exp $
*/ */
#include "firebird.h" #include "firebird.h"
@ -783,9 +786,18 @@ static XCP par_condition(TDBB tdbb, CSB * csb)
/* allocate a node to represent the conditions list */ /* allocate a node to represent the conditions list */
code_type = BLR_BYTE;
/* don't create XCP if blr_raise is used,
just return NULL */
if (code_type == blr_raise)
{
return NULL;
}
exception_list = FB_NEW_RPT(*tdbb->tdbb_default, 1) xcp(); exception_list = FB_NEW_RPT(*tdbb->tdbb_default, 1) xcp();
exception_list->xcp_count = 1; exception_list->xcp_count = 1;
code_type = BLR_BYTE;
switch (code_type) { switch (code_type) {
case blr_sql_code: case blr_sql_code:
exception_list->xcp_rpt[0].xcp_type = xcp_sql_code; exception_list->xcp_rpt[0].xcp_type = xcp_sql_code;
@ -805,6 +817,7 @@ static XCP par_condition(TDBB tdbb, CSB * csb)
break; break;
case blr_exception: case blr_exception:
case blr_exception_msg:
exception_list->xcp_rpt[0].xcp_type = xcp_xcp_code; exception_list->xcp_rpt[0].xcp_type = xcp_xcp_code;
par_name(csb, name); par_name(csb, name);
if (!(exception_list->xcp_rpt[0].xcp_code = if (!(exception_list->xcp_rpt[0].xcp_code =
@ -823,6 +836,8 @@ static XCP par_condition(TDBB tdbb, CSB * csb)
break; break;
} }
exception_list->xcp_rpt[0].xcp_msg = 0;
return exception_list; return exception_list;
} }
@ -2632,8 +2647,15 @@ static NOD parse(TDBB tdbb, register CSB * csb, USHORT expected)
break; break;
case blr_abort: case blr_abort:
{
bool flag = (BLR_PEEK == blr_exception_msg);
node->nod_arg[0] = (NOD) par_condition(tdbb, csb); node->nod_arg[0] = (NOD) par_condition(tdbb, csb);
if (flag)
{
node->nod_arg[1] = parse(tdbb, csb, sub_type);
}
break; break;
}
case blr_if: case blr_if:
node->nod_arg[e_if_boolean] = parse(tdbb, csb, BOOL); node->nod_arg[e_if_boolean] = parse(tdbb, csb, BOOL);

View File

@ -19,6 +19,10 @@
* *
* All Rights Reserved. * All Rights Reserved.
* Contributor(s): ______________________________________. * Contributor(s): ______________________________________.
*
* 2002.09.28 Dmitry Yemanov: Reworked internal_info stuff, enhanced
* exception handling in SPs/triggers,
* implemented ROWS_AFFECTED system variable
*/ */
#ifndef _JRD_REQ_H_ #ifndef _JRD_REQ_H_
@ -27,6 +31,8 @@
#include "../jrd/jrd_blks.h" #include "../jrd/jrd_blks.h"
#include "../include/fb_blk.h" #include "../include/fb_blk.h"
#include "../jrd/exe.h"
#include <vector> #include <vector>
/* record parameter block */ /* record parameter block */
@ -151,6 +157,8 @@ public:
ULONG req_records_updated; /* count of records updated by request */ ULONG req_records_updated; /* count of records updated by request */
ULONG req_records_deleted; /* count of records deleted by request */ ULONG req_records_deleted; /* count of records deleted by request */
ULONG req_records_affected; /* count of records affected by the last statement */
USHORT req_view_flags; /* special flags for virtual ops on views */ USHORT req_view_flags; /* special flags for virtual ops on views */
struct rel* req_top_view_store; /* the top view in store(), if any */ struct rel* req_top_view_store; /* the top view in store(), if any */
struct rel* req_top_view_modify; /* the top view in modify(), if any */ struct rel* req_top_view_modify; /* the top view in modify(), if any */
@ -175,6 +183,8 @@ public:
req_unwind req_unwind
} req_operation; /* operation for next node */ } req_operation; /* operation for next node */
struct xcp_repeat req_last_xcp; /* last known exception */
rpb req_rpb[1]; /* record parameter blocks */ rpb req_rpb[1]; /* record parameter blocks */
}; };
typedef req *REQ; typedef req *REQ;