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

More context variables for error handlers, see CORE-1132 and CORE-2040. (#46)

* Implement some parts of CORE-1132 and CORE-2040.

* Change per Adriano's suggestion.
This commit is contained in:
Dmitry Yemanov 2016-09-06 21:12:03 +03:00 committed by GitHub
parent f80d135842
commit ebd0d3c813
8 changed files with 187 additions and 27 deletions

View File

@ -12,7 +12,7 @@ CURRENT_CONNECTION / CURRENT_TRANSACTION (FB 1.5)
statement is executed.
Author:
Dmitry Yemanov <yemanov@yandex.ru>
Dmitry Yemanov <dimitr@firebirdsql.org>
Syntax rules:
CURRENT_CONNECTION / CURRENT_TRANSACTION
@ -40,7 +40,7 @@ ROW_COUNT (FB 1.5)
Returns number of rows, affected by the last SQL statement.
Author:
Dmitry Yemanov <yemanov@yandex.ru>
Dmitry Yemanov <dimitr@firebirdsql.org>
Syntax rules:
ROW_COUNT
@ -75,7 +75,7 @@ SQLCODE / GDSCODE (FB 1.5)
Returns numeric error code for the active exception.
Author:
Dmitry Yemanov <yemanov@yandex.ru>
Dmitry Yemanov <dimitr@firebirdsql.org>
Syntax rules:
SQLCODE / GDSCODE
@ -112,9 +112,6 @@ SQLCODE / GDSCODE (FB 1.5)
variables contain zero, regardless of the exception handling
block type.
See also:
README.exception_handling
INSERTING / UPDATING / DELETING (FB 1.5)
----------------------------------------
@ -123,7 +120,7 @@ INSERTING / UPDATING / DELETING (FB 1.5)
Determines type of row operation being executed.
Author:
Dmitry Yemanov <yemanov@yandex.ru>
Dmitry Yemanov <dimitr@firebirdsql.org>
Syntax rules:
INSERTING / UPDATING / DELETING
@ -140,3 +137,96 @@ INSERTING / UPDATING / DELETING (FB 1.5)
See also:
README.universal_triggers
SQLSTATE (FB 2.5)
-----------------
Function:
Returns character-encoded state for the active exception.
Author:
Dmitry Yemanov <dimitr@firebirdsql.org>
Syntax rules:
SQLSTATE
Type:
CHAR(5) CHARACTER SET ASCII
Scope:
PSQL, context of the exception handling block.
Example(s):
BEGIN
...
WHEN SQLSTATE '44000' DO
EXCEPTION E_CHECK_VIOLATION;
WHEN ANY DO
EXECUTE PROCEDURE P_ANY_EXCEPTION(SQLSTATE);
END
Note(s):
1. SQLSTATE always evaluates to NULL outside the exception handling block.
EXCEPTION (FB 4.0)
------------------
Function:
Returns name of the active user-defined exception.
Author:
Dmitry Yemanov <dimitr@firebirdsql.org>
Syntax rules:
EXCEPTION
Type:
VARCHAR(63) CHARACTER SET UTF8
Scope:
PSQL, context of the exception handling block.
Example(s):
BEGIN
...
WHEN ANY DO
IF (EXCEPTION IS NOT NULL)
EXECUTE PROCEDURE P_USR_EXCEPTION(EXCEPTION);
ELSE
EXECUTE PROCEDURE P_SYS_EXCEPTION;
END
Note(s):
1. EXCEPTION always contains NULL outside the exception handling block.
2. If system exception is thrown, EXCEPTION also contains NULL.
ERROR_MESSAGE (FB 4.0)
----------------------
Function:
Returns interpreted text for the active exception.
Author:
Dmitry Yemanov <dimitr@firebirdsql.org>
Syntax rules:
ERROR_MESSAGE
Type:
VARCHAR(1024) CHARACTER SET UTF8
Scope:
PSQL, context of the exception handling block.
Example(s):
BEGIN
...
WHEN ANY DO
EXECUTE PROCEDURE P_LOG_EXCEPTION(ERROR_MESSAGE);
END
Note(s):
1. ERROR_MESSAGE always contains NULL outside the exception handling block.

View File

@ -58,25 +58,6 @@ Exception re-raise semantics (FB 1.5)
Evaluates to no-op if used outside the exception handling block.
Run-time error codes (FB 1.5)
-----------------------------
Function:
Allows to get a numeric error code for the catched exception.
Author:
Dmitry Yemanov <yemanov@yandex.ru>
Syntax rules:
SQLCODE / GDSCODE;
Scope:
PSQL, context of the exception handling block
See also:
README.context_variables
Parameterized exceptions (FB 3.0)
---------------------------------

View File

@ -6037,6 +6037,14 @@ void InternalInfoNode::make(DsqlCompilerScratch* /*dsqlScratch*/, dsc* desc)
desc->makeText(FB_SQLSTATE_LENGTH, ttype_ascii);
break;
case INFO_TYPE_EXCEPTION:
desc->makeVarying(MAX_SQL_IDENTIFIER_LEN, ttype_metadata);
break;
case INFO_TYPE_ERROR_MSG:
desc->makeVarying(MAX_ERROR_MSG_LENGTH, ttype_utf8);
break;
case INFO_TYPE_CONNECTION_ID:
case INFO_TYPE_TRANSACTION_ID:
case INFO_TYPE_ROWS_AFFECTED:
@ -6070,6 +6078,14 @@ void InternalInfoNode::getDesc(thread_db* tdbb, CompilerScratch* csb, dsc* desc)
desc->makeText(FB_SQLSTATE_LENGTH, ttype_ascii);
break;
case INFO_TYPE_EXCEPTION:
desc->makeVarying(MAX_SQL_IDENTIFIER_LEN, ttype_metadata);
break;
case INFO_TYPE_ERROR_MSG:
desc->makeVarying(MAX_ERROR_MSG_LENGTH, ttype_utf8);
break;
case INFO_TYPE_CONNECTION_ID:
case INFO_TYPE_TRANSACTION_ID:
case INFO_TYPE_ROWS_AFFECTED:
@ -6129,6 +6145,41 @@ dsc* InternalInfoNode::execute(thread_db* tdbb, jrd_req* request) const
return &impure->vlu_desc;
}
else if (infoType == INFO_TYPE_EXCEPTION)
{
if (request->req_last_xcp.success())
return NULL;
const SLONG xcpCode = request->req_last_xcp.as_xcpcode();
if (!xcpCode)
return NULL;
MetaName xcpName;
MET_lookup_exception(tdbb, xcpCode, xcpName, NULL);
if (xcpName.isEmpty())
return NULL;
dsc desc;
desc.makeText(xcpName.length(), ttype_metadata, (UCHAR*) xcpName.c_str());
EVL_make_value(tdbb, &desc, impure);
return &impure->vlu_desc;
}
else if (infoType == INFO_TYPE_ERROR_MSG)
{
if (request->req_last_xcp.success())
return NULL;
const string errorText = request->req_last_xcp.as_text();
dsc desc;
desc.makeText(errorText.length(), ttype_utf8, (UCHAR*) errorText.c_str());
EVL_make_value(tdbb, &desc, impure);
return &impure->vlu_desc;
}
SLONG result32 = 0;
SINT64 result64 = 0;

View File

@ -592,6 +592,7 @@ using namespace Firebird;
// tokens added for Firebird 4.0
%token <metaNamePtr> CUME_DIST
%token <metaNamePtr> ERROR_MESSAGE
%token <metaNamePtr> EXCLUDE
%token <metaNamePtr> FOLLOWING
%token <metaNamePtr> NTILE
@ -6838,6 +6839,10 @@ internal_info
{ $$ = newNode<InternalInfoNode>(MAKE_const_slong(INFO_TYPE_SQLSTATE)); }
| ROW_COUNT
{ $$ = newNode<InternalInfoNode>(MAKE_const_slong(INFO_TYPE_ROWS_AFFECTED)); }
| EXCEPTION
{ $$ = newNode<InternalInfoNode>(MAKE_const_slong(INFO_TYPE_EXCEPTION)); }
| ERROR_MESSAGE
{ $$ = newNode<InternalInfoNode>(MAKE_const_slong(INFO_TYPE_ERROR_MSG)); }
;
%type <intlStringPtr> sql_string
@ -7969,6 +7974,7 @@ non_reserved_word
| RDB_ROLE_IN_USE
| RDB_SYSTEM_PRIVILEGE
| SYSTEM
| ERROR_MESSAGE
| TIES
;

View File

@ -287,6 +287,8 @@ enum InfoType
INFO_TYPE_ROWS_AFFECTED = 5,
INFO_TYPE_TRIGGER_ACTION = 6,
INFO_TYPE_SQLSTATE = 7,
INFO_TYPE_EXCEPTION = 8,
INFO_TYPE_ERROR_MSG = 9,
MAX_INFO_TYPE
};
@ -452,4 +454,7 @@ const int OPT_STATIC_ITEMS = 64;
const int WITH_GRANT_OPTION = 1;
const int WITH_ADMIN_OPTION = 2;
// Max length of the string returned by ERROR_TEXT context variable
const USHORT MAX_ERROR_MSG_LENGTH = 1024 * METADATA_BYTES_PER_CHAR; // 1024 UTF-8 characters
#endif // JRD_CONSTANTS_H

View File

@ -192,6 +192,30 @@ void StatusXcp::as_sqlstate(char* sqlstate) const
fb_sqlstate(sqlstate, status->getErrors());
}
SLONG StatusXcp::as_xcpcode() const
{
return (status->getErrors()[1] == isc_except) ? (SLONG) status->getErrors()[3] : 0;
}
string StatusXcp::as_text() const
{
const ISC_STATUS* status_ptr = status->getErrors();
string errorText;
TEXT buffer[BUFFER_LARGE];
while (fb_interpret(buffer, sizeof(buffer), &status_ptr))
{
if (errorText.hasData())
errorText += "\n";
errorText += buffer;
}
return errorText;
}
static void execute_looper(thread_db*, jrd_req*, jrd_tra*, const StmtNode*, jrd_req::req_s);
static void looper_seh(thread_db*, jrd_req*, const StmtNode*);
static void release_blobs(thread_db*, jrd_req*);

View File

@ -631,6 +631,8 @@ public:
SLONG as_gdscode() const;
SLONG as_sqlcode() const;
void as_sqlstate(char*) const;
SLONG as_xcpcode() const;
Firebird::string as_text() const;
};
// must correspond to the declared size of RDB$EXCEPTIONS.RDB$MESSAGE

View File

@ -181,6 +181,7 @@ static const TOK tokens[] =
{END, "END", false},
{ENGINE, "ENGINE", true},
{ENTRY_POINT, "ENTRY_POINT", false},
{ERROR_MESSAGE, "ERROR_MESSAGE", true},
{ESCAPE, "ESCAPE", false},
{EXCEPTION, "EXCEPTION", false},
{EXCLUDE, "EXCLUDE", false},