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:
parent
f80d135842
commit
ebd0d3c813
@ -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.
|
||||
|
@ -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)
|
||||
---------------------------------
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
;
|
||||
|
||||
|
@ -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
|
||||
|
@ -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*);
|
||||
|
@ -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
|
||||
|
@ -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},
|
||||
|
Loading…
Reference in New Issue
Block a user