From be859980ea09552a1c92e561eb4dc1f9fa9ce830 Mon Sep 17 00:00:00 2001 From: asfernandes Date: Thu, 7 Jan 2010 00:16:50 +0000 Subject: [PATCH] Feature CORE-832 - Parameterized exceptions --- doc/sql.extensions/README.exception_handling | 40 +++++++++ lang_helpers/gds_codes.ftn | 2 + lang_helpers/gds_codes.pas | 1 + src/common/classes/MsgPrint.cpp | 85 +++++++++++--------- src/common/classes/MsgPrint.h | 10 ++- src/common/classes/SafeArg.h | 5 +- src/dsql/StmtNodes.cpp | 80 ++++++++++++++---- src/dsql/StmtNodes.h | 6 +- src/dsql/gen.cpp | 20 ----- src/dsql/gen_proto.h | 7 ++ src/dsql/parse.y | 2 + src/include/gen/codetext.h | 1 + src/include/gen/iberror.h | 6 +- src/include/gen/msgs.h | 1 + src/include/gen/sql_code.h | 1 + src/include/gen/sql_state.h | 1 + src/jrd/blr.h | 15 ++-- src/jrd/gds.cpp | 20 ++++- src/msgs/facilities2.sql | 2 +- src/msgs/messages2.sql | 1 + src/msgs/system_errors2.sql | 1 + 21 files changed, 215 insertions(+), 92 deletions(-) diff --git a/doc/sql.extensions/README.exception_handling b/doc/sql.extensions/README.exception_handling index 0699c0eb5ea..715a8a71f51 100644 --- a/doc/sql.extensions/README.exception_handling +++ b/doc/sql.extensions/README.exception_handling @@ -75,3 +75,43 @@ Run-time error codes (FB 1.5) See also: README.context_variables + + +Parameterized exceptions (FB 3.0) +--------------------------------- + + Function: + Allow to define exception message with slots for parameters and pass the parameters when + raising the exception. + + Author: + Adriano dos Santos Fernandes + + Syntax: + EXCEPTION USING ( ) + + Example: + create exception e_invalid_val 'Invalid value @1 for the field @2'; + + ... + if (val < 1000) then + thing = val; + else + exception e_invalid_val using (val, 'thing'); + end + + Notes: + The status vector is generated using that codes combination: + isc_except, , + isc_formatted_exception, , + + The client library formats isc_formatted_exception in an special way, using the exception + parameters as argument to the exception message, instead of formatting all arguments of + isc_formatted_exception for a predefined internal text. That's important for any code that + formats status vectors without the help of the client library. Also, the client library older + than 3.0 will not be able to correctly format exceptions raised in this new way. + + @N means the N parameter (where N starts at 1) passed in the exception raise command. If a N + parameter is not passed, the text is not substituted. If NULL is passed, it's replaced by string + '*** null ***'. If more parameters is passed than used in the exception message, they are + ignored. diff --git a/lang_helpers/gds_codes.ftn b/lang_helpers/gds_codes.ftn index 99a0ed58965..cfb938ab536 100644 --- a/lang_helpers/gds_codes.ftn +++ b/lang_helpers/gds_codes.ftn @@ -1442,6 +1442,8 @@ C -- PARAMETER (GDS__invalid_timestamp_val = 335545014) INTEGER*4 GDS__invalid_index_val PARAMETER (GDS__invalid_index_val = 335545015) + INTEGER*4 GDS__formatted_exception + PARAMETER (GDS__formatted_exception = 335545016) INTEGER*4 GDS__gfix_db_name PARAMETER (GDS__gfix_db_name = 335740929) INTEGER*4 GDS__gfix_invalid_sw diff --git a/lang_helpers/gds_codes.pas b/lang_helpers/gds_codes.pas index cd1cc54b3c7..9f2665ca2e1 100644 --- a/lang_helpers/gds_codes.pas +++ b/lang_helpers/gds_codes.pas @@ -728,6 +728,7 @@ gds_invalid_time_val = 335545013; gds_invalid_timestamp_val = 335545014; gds_invalid_index_val = 335545015; + gds_formatted_exception = 335545016; gds_gfix_db_name = 335740929; gds_gfix_invalid_sw = 335740930; gds_gfix_incmp_sw = 335740932; diff --git a/src/common/classes/MsgPrint.cpp b/src/common/classes/MsgPrint.cpp index 5a8f7f3b726..68c8d39d09e 100644 --- a/src/common/classes/MsgPrint.cpp +++ b/src/common/classes/MsgPrint.cpp @@ -28,10 +28,12 @@ #include "../jrd/common.h" #include "BaseStream.h" #include "MsgPrint.h" +#include "array.h" #include #include "../jrd/gds_proto.h" #include "../common/utils_proto.h" #include "../jrd/file_params.h" +#include "../jrd/msg_encode.h" namespace MsgFormat @@ -233,7 +235,7 @@ int MsgPrintHelper(BaseStream& out_stream, const safe_cell& item) // Prints the whole chain of arguments, according to format and in the specified stream. -int MsgPrint(BaseStream& out_stream, const char* format, const SafeArg& arg) +int MsgPrint(BaseStream& out_stream, const char* format, const SafeArg& arg, bool userFormatting) { int out_bytes = 0; for (const char* iter = format; true; ++iter) @@ -247,25 +249,37 @@ int MsgPrint(BaseStream& out_stream, const char* format, const SafeArg& arg) switch (iter[1]) { case 0: - out_bytes += out_stream.write("@(EOF)", 6); + if (userFormatting) + out_bytes += out_stream.write("@", 1); + else + out_bytes += out_stream.write("@(EOF)", 6); return out_bytes; case '@': out_bytes += out_stream.write(iter, 1); break; default: { - const int pos = iter[1] - '0'; - if (pos > 0 && static_cast(pos) <= arg.m_count) + const int start = userFormatting ? 1 : 0; + const int pos = start + iter[1] - '0'; + if (pos > start && static_cast(pos) <= arg.m_count) out_bytes += MsgPrintHelper(out_stream, arg.m_arguments[pos - 1]); - else if (pos >= 0 && pos <= 9) + else { - // Show the missing or out of range param number. - out_bytes += MsgPrint(out_stream, - "", - SafeArg() << pos); + if (userFormatting) + { + out_bytes += out_stream.write("@", 1); + out_bytes += out_stream.write(iter + 1, 1); + } + else if (pos >= 0 && pos <= 9) + { + // Show the missing or out of range param number. + out_bytes += MsgPrint(out_stream, + "", + SafeArg() << pos); + } + else // Something not a number following @, invalid. + out_bytes += out_stream.write("(error)", 7); } - else // Something not a number following @, invalid. - out_bytes += out_stream.write("(error)", 7); } } ++iter; @@ -308,10 +322,10 @@ int MsgPrint(BaseStream& out_stream, const char* format, const SafeArg& arg) // Shortcut version to format a string with arguments on standard output. -int MsgPrint(const char* format, const SafeArg& arg) +int MsgPrint(const char* format, const SafeArg& arg, bool userFormatting) { StdioStream st(stdout); - return MsgPrint(st, format, arg); + return MsgPrint(st, format, arg, userFormatting); } @@ -327,44 +341,28 @@ int MsgPrint(const char* format) // Shortcut version to format a string with arguments on a string output // of a given size. -int MsgPrint(char* plainstring, unsigned int s_size, const char* format, const SafeArg& arg) +int MsgPrint(char* plainstring, unsigned int s_size, const char* format, const SafeArg& arg, + bool userFormatting) { StringStream st(plainstring, s_size); - return MsgPrint(st, format, arg); + return MsgPrint(st, format, arg, userFormatting); } // Shortcut version to format a string with arguments on standard error. -int MsgPrintErr(const char* format, const SafeArg& arg) +int MsgPrintErr(const char* format, const SafeArg& arg, bool userFormatting) { StdioStream st(stderr, true); // flush - return MsgPrint(st, format, arg); + return MsgPrint(st, format, arg, userFormatting); } } // namespace -int fb_msg_format(void* handle, - USHORT facility, - USHORT number, - unsigned int bsize, - TEXT* buffer, - const MsgFormat::SafeArg& arg) +// Lookup and format message. Return as much of formatted string as fits in caller's buffer. +int fb_msg_format(void* handle, USHORT facility, USHORT number, unsigned int bsize, TEXT* buffer, + const MsgFormat::SafeArg& arg) { -/************************************** - * - * f b _ m s g _ f o r m a t - * - ************************************** - * - * Functional description - * Lookup and format message. Return as much of formatted string - * as fits in caller's buffer. - * - **************************************/ - - using MsgFormat::MsgPrint; - // The field MESSAGES.TEXT is 118 bytes long. int total_msg = 0; char msg[120] = ""; @@ -380,7 +378,18 @@ int fb_msg_format(void* handle, total_msg = fb_utils::snprintf(buffer, bsize, msg, rep[0], rep[1], rep[2], rep[3], rep[4]); } else - total_msg = MsgPrint(buffer, bsize, msg, arg); + { + if (ENCODE_ISC_MSG(number, facility) == isc_formatted_exception && arg.getCount() > 0) + { + Firebird::HalfStaticArray msgBuffer(bsize); + MsgFormat::StringStream msgStream(msgBuffer.begin(), bsize); + MsgPrintHelper(msgStream, arg.getCell(0)); + + total_msg = MsgPrint(buffer, bsize, msgBuffer.begin(), arg, 1); + } + else + total_msg = MsgPrint(buffer, bsize, msg, arg); + } } else { diff --git a/src/common/classes/MsgPrint.h b/src/common/classes/MsgPrint.h index 2118b4043d5..54ebf712de3 100644 --- a/src/common/classes/MsgPrint.h +++ b/src/common/classes/MsgPrint.h @@ -80,19 +80,21 @@ class BaseStream; // A. The basic routine. -int MsgPrint(BaseStream& out_stream, const char* format, const SafeArg& arg); +int MsgPrint(BaseStream& out_stream, const char* format, const SafeArg& arg, + bool userFormatting = false); // B. Printf replacement. Output to stdout. -int MsgPrint(const char* format, const SafeArg& arg); +int MsgPrint(const char* format, const SafeArg& arg, bool userFormatting = false); // C. Print without arguments to stdout. int MsgPrint(const char* format); // D. Print to a string, without buffer overrun. -int MsgPrint(char* plainstring, unsigned int s_size, const char* format, const SafeArg& arg); +int MsgPrint(char* plainstring, unsigned int s_size, const char* format, const SafeArg& arg, + bool userFormatting = false); // E. Prints a formatted string into stderr and flushed the buffer. -int MsgPrintErr(const char* format, const SafeArg& arg); +int MsgPrintErr(const char* format, const SafeArg& arg, bool userFormatting = false); } // namespace // Type safe replacement of the old gds__msg_format. diff --git a/src/common/classes/SafeArg.h b/src/common/classes/SafeArg.h index adc5f772c02..1db500478f6 100644 --- a/src/common/classes/SafeArg.h +++ b/src/common/classes/SafeArg.h @@ -166,11 +166,14 @@ class SafeArg void dump(const TEXT* target[], size_t v_size) const; const safe_cell& getCell(size_t index) const; size_t getCount() const; + private: size_t m_count; safe_cell m_arguments[SAFEARG_MAX_ARG]; const void* m_extras; // Formatting, etc. - friend int MsgPrint(BaseStream& out_stream, const char* format, const SafeArg& arg); + + friend int MsgPrint(BaseStream& out_stream, const char* format, const SafeArg& arg, + bool userFormatting); }; inline SafeArg::SafeArg() diff --git a/src/dsql/StmtNodes.cpp b/src/dsql/StmtNodes.cpp index 8c34ebe8476..d4445b6ac9e 100644 --- a/src/dsql/StmtNodes.cpp +++ b/src/dsql/StmtNodes.cpp @@ -674,7 +674,7 @@ DmlNode* ExceptionNode::parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch UCHAR /*blrOp*/) { ExceptionNode* node = FB_NEW(pool) ExceptionNode(pool); - const bool flag = (csb->csb_blr_reader.peekByte() == blr_exception_msg); + const UCHAR type = csb->csb_blr_reader.peekByte(); const USHORT codeType = csb->csb_blr_reader.getByte(); // Don't create PsqlException if blr_raise is used. @@ -707,6 +707,7 @@ DmlNode* ExceptionNode::parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch case blr_exception: case blr_exception_msg: + case blr_exception_params: { item.xcp_type = xcp_xcp_code; PAR_name(csb, node->name); @@ -726,7 +727,18 @@ DmlNode* ExceptionNode::parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch } } - if (flag) + if (type == blr_exception_params) + { + USHORT count = csb->csb_blr_reader.getWord(); + + node->parameters = PAR_make_node(tdbb, count); + node->parameters->nod_type = nod_list; + node->parameters->nod_count = count; + + for (unsigned i = 0; i < count; ++i) + node->parameters->nod_arg[i] = PAR_parse_node(tdbb, csb, VALUE); + } + else if (type == blr_exception_msg) node->messageExpr = PAR_parse_node(tdbb, csb, VALUE); return node; @@ -739,6 +751,7 @@ StmtNode* ExceptionNode::internalDsqlPass() node->dsqlScratch = dsqlScratch; node->name = name; node->dsqlMessageExpr = PASS1_node(dsqlScratch, dsqlMessageExpr); + node->dsqlParameters = PASS1_node(dsqlScratch, dsqlParameters); return SavepointEncloseNode::make(getPool(), dsqlScratch, node); } @@ -766,17 +779,28 @@ void ExceptionNode::genBlr() return; } - // If exception value is defined, it means we have user-defined exception message here, - // so blr_exception_msg verb should be generated. - if (dsqlMessageExpr) + // If exception parameters or value is defined, it means we have user-defined exception message + // here, so blr_exception_msg verb should be generated. + if (dsqlParameters) + stuff(statement, blr_exception_params); + else if (dsqlMessageExpr) stuff(statement, blr_exception_msg); else // Otherwise go usual way, i.e. generate blr_exception. stuff(statement, blr_exception); stuff_cstring(statement, name.c_str()); - // If exception value is defined, generate appropriate BLR verbs. - if (dsqlMessageExpr) + // If exception parameters or value is defined, generate appropriate BLR verbs. + if (dsqlParameters) + { + stuff_word(statement, dsqlParameters->nod_count); + + dsql_nod** ptr = dsqlParameters->nod_arg; + const dsql_nod* const* end = ptr + dsqlParameters->nod_count; + while (ptr < end) + GEN_expr(dsqlScratch, *ptr++); + } + else if (dsqlMessageExpr) GEN_expr(dsqlScratch, dsqlMessageExpr); } @@ -784,6 +808,7 @@ void ExceptionNode::genBlr() ExceptionNode* ExceptionNode::pass1(thread_db* tdbb, CompilerScratch* csb) { messageExpr = CMP_pass1(tdbb, csb, messageExpr); + parameters = CMP_pass1(tdbb, csb, parameters); return this; } @@ -791,6 +816,7 @@ ExceptionNode* ExceptionNode::pass1(thread_db* tdbb, CompilerScratch* csb) ExceptionNode* ExceptionNode::pass2(thread_db* tdbb, CompilerScratch* csb) { messageExpr = CMP_pass2(tdbb, csb, messageExpr, node); + parameters = CMP_pass2(tdbb, csb, parameters, node); return this; } @@ -901,24 +927,50 @@ void ExceptionNode::setError(thread_db* tdbb) const else s = NULL; - if (s && exName.length()) + Arg::StatusVector status; + ISC_STATUS msgCode = parameters ? isc_formatted_exception : isc_random; + + if (s && exName.hasData()) { - ERR_post(Arg::Gds(isc_except) << Arg::Num(xcpCode) << - Arg::Gds(isc_random) << Arg::Str(exName) << - Arg::Gds(isc_random) << Arg::Str(s)); + status << Arg::Gds(isc_except) << Arg::Num(xcpCode) << + Arg::Gds(isc_random) << Arg::Str(exName) << + Arg::Gds(msgCode) << Arg::Str(s); } else if (s) { - ERR_post(Arg::Gds(isc_except) << Arg::Num(xcpCode) << - Arg::Gds(isc_random) << Arg::Str(s)); + status << Arg::Gds(isc_except) << Arg::Num(xcpCode) << + Arg::Gds(msgCode) << Arg::Str(s); } - else if (exName.length()) + else if (exName.hasData()) { ERR_post(Arg::Gds(isc_except) << Arg::Num(xcpCode) << Arg::Gds(isc_random) << Arg::Str(exName)); } else ERR_post(Arg::Gds(isc_except) << Arg::Num(xcpCode)); + + // Preallocate the strings, because Arg::StatusVector store the pointers. + ObjectsArray paramsStr; + + if (parameters) + { + for (unsigned i = 0; i < parameters->nod_count; ++i) + { + const dsc* value = EVL_expr(tdbb, parameters->nod_arg[i]); + + if (!value || (request->req_flags & req_null)) + paramsStr.push(NULL_STRING_MARK); + else + paramsStr.push(MOV_make_string2(tdbb, value, ttype_metadata)); + } + + // And add the values to the status vector only when they are all created and will + // not move in paramsStr. + for (unsigned i = 0; i < parameters->nod_count; ++i) + status << paramsStr[i]; + } + + ERR_post(status); } default: diff --git a/src/dsql/StmtNodes.h b/src/dsql/StmtNodes.h index dd2431ed6ac..3c0c5460f3d 100644 --- a/src/dsql/StmtNodes.h +++ b/src/dsql/StmtNodes.h @@ -145,11 +145,13 @@ class ExceptionNode : public StmtNode { public: explicit ExceptionNode(MemoryPool& pool, const Firebird::MetaName& aName = "", - dsql_nod* aDsqlMessageExpr = NULL) + dsql_nod* aDsqlMessageExpr = NULL, dsql_nod* aDsqlParameters = NULL) : StmtNode(pool), name(pool, aName), dsqlMessageExpr(aDsqlMessageExpr), + dsqlParameters(aDsqlParameters), messageExpr(NULL), + parameters(NULL), exception(NULL) { } @@ -173,7 +175,9 @@ class ExceptionNode : public StmtNode public: Firebird::MetaName name; dsql_nod* dsqlMessageExpr; + dsql_nod* dsqlParameters; jrd_nod* messageExpr; + jrd_nod* parameters; PsqlException* exception; }; diff --git a/src/dsql/gen.cpp b/src/dsql/gen.cpp index 6ac3bc2a3f7..8e9367b356b 100644 --- a/src/dsql/gen.cpp +++ b/src/dsql/gen.cpp @@ -91,7 +91,6 @@ static void gen_udf(DsqlCompilerScratch*, const dsql_nod*); static void gen_union(DsqlCompilerScratch*, const dsql_nod*); static void stuff_context(DsqlCompiledStatement*, const dsql_ctx*); static void stuff_meta_string(DsqlCompiledStatement*, const char*); -static void stuff_word(DsqlCompiledStatement*, USHORT); // STUFF is defined in dsql.h for use in common with ddl.c @@ -3085,22 +3084,3 @@ static void stuff_meta_string(DsqlCompiledStatement* dsqlScratch, const char* st { dsqlScratch->append_meta_string(string); } - - -/** - - stuff_word - - @brief Cram a word into the blr buffer. If the buffer is getting - ready to overflow, expand it. - - - @param dsqlScratch - @param word - - **/ -static void stuff_word(DsqlCompiledStatement* dsqlScratch, USHORT word) -{ - stuff(dsqlScratch, word); - stuff(dsqlScratch, word >> 8); -} diff --git a/src/dsql/gen_proto.h b/src/dsql/gen_proto.h index 6cb82def4f1..878f35b4d7d 100644 --- a/src/dsql/gen_proto.h +++ b/src/dsql/gen_proto.h @@ -39,6 +39,13 @@ inline void stuff(Jrd::DsqlCompiledStatement* statement, const UCHAR byte) statement->getBlrData().add(byte); } +// Cram a word into the blr buffer. +inline void stuff_word(Jrd::DsqlCompiledStatement* dsqlScratch, USHORT word) +{ + stuff(dsqlScratch, word); + stuff(dsqlScratch, word >> 8); +} + // Write out a string with one byte of length. inline void stuff_string(Jrd::DsqlCompiledStatement* statement, const char* string, int len) { diff --git a/src/dsql/parse.y b/src/dsql/parse.y index c26f2973136..ccab9086b91 100644 --- a/src/dsql/parse.y +++ b/src/dsql/parse.y @@ -2269,6 +2269,8 @@ excp_statement { $$ = FB_NEW(getPool()) ExceptionNode(getPool(), toName($2)); } | EXCEPTION symbol_exception_name value { $$ = FB_NEW(getPool()) ExceptionNode(getPool(), toName($2), $3); } + | EXCEPTION symbol_exception_name USING '(' value_list ')' + { $$ = FB_NEW(getPool()) ExceptionNode(getPool(), toName($2), NULL, make_list($5)); } ; raise_statement diff --git a/src/include/gen/codetext.h b/src/include/gen/codetext.h index fecba96e1d0..b69f6c0b3f9 100644 --- a/src/include/gen/codetext.h +++ b/src/include/gen/codetext.h @@ -717,6 +717,7 @@ static const struct { {"invalid_time_val", 335545013}, {"invalid_timestamp_val", 335545014}, {"invalid_index_val", 335545015}, + {"formatted_exception", 335545016}, {"gfix_db_name", 335740929}, {"gfix_invalid_sw", 335740930}, {"gfix_incmp_sw", 335740932}, diff --git a/src/include/gen/iberror.h b/src/include/gen/iberror.h index 54d05391e98..1f482c6b4ff 100644 --- a/src/include/gen/iberror.h +++ b/src/include/gen/iberror.h @@ -751,6 +751,7 @@ const ISC_STATUS isc_invalid_date_val = 335545012L; const ISC_STATUS isc_invalid_time_val = 335545013L; const ISC_STATUS isc_invalid_timestamp_val = 335545014L; const ISC_STATUS isc_invalid_index_val = 335545015L; +const ISC_STATUS isc_formatted_exception = 335545016L; const ISC_STATUS isc_gfix_db_name = 335740929L; const ISC_STATUS isc_gfix_invalid_sw = 335740930L; const ISC_STATUS isc_gfix_incmp_sw = 335740932L; @@ -1119,7 +1120,7 @@ const ISC_STATUS isc_trace_switch_user_only = 337182757L; const ISC_STATUS isc_trace_switch_param_miss = 337182758L; const ISC_STATUS isc_trace_param_act_notcompat = 337182759L; const ISC_STATUS isc_trace_mandatory_switch_miss = 337182760L; -const ISC_STATUS isc_err_max = 1063; +const ISC_STATUS isc_err_max = 1064; #else /* c definitions */ @@ -1840,6 +1841,7 @@ const ISC_STATUS isc_err_max = 1063; #define isc_invalid_time_val 335545013L #define isc_invalid_timestamp_val 335545014L #define isc_invalid_index_val 335545015L +#define isc_formatted_exception 335545016L #define isc_gfix_db_name 335740929L #define isc_gfix_invalid_sw 335740930L #define isc_gfix_incmp_sw 335740932L @@ -2208,7 +2210,7 @@ const ISC_STATUS isc_err_max = 1063; #define isc_trace_switch_param_miss 337182758L #define isc_trace_param_act_notcompat 337182759L #define isc_trace_mandatory_switch_miss 337182760L -#define isc_err_max 1063 +#define isc_err_max 1064 #endif diff --git a/src/include/gen/msgs.h b/src/include/gen/msgs.h index 2f150ed7d0b..da37263a020 100644 --- a/src/include/gen/msgs.h +++ b/src/include/gen/msgs.h @@ -720,6 +720,7 @@ Data source : @4"}, /* eds_statement */ {335545013, "Invalid time"}, /* invalid_time_val */ {335545014, "Invalid timestamp"}, /* invalid_timestamp_val */ {335545015, "Invalid index @1"}, /* invalid_index_val */ + {335545016, "@1"}, /* formatted_exception */ {335740929, "data base file name (@1) already given"}, /* gfix_db_name */ {335740930, "invalid switch @1"}, /* gfix_invalid_sw */ {335740932, "incompatible switch combination"}, /* gfix_incmp_sw */ diff --git a/src/include/gen/sql_code.h b/src/include/gen/sql_code.h index beead7bcbce..0be0219d3f3 100644 --- a/src/include/gen/sql_code.h +++ b/src/include/gen/sql_code.h @@ -716,6 +716,7 @@ static const struct { {335545013, -901}, /* 693 invalid_time_val */ {335545014, -901}, /* 694 invalid_timestamp_val */ {335545015, -901}, /* 695 invalid_index_val */ + {335545016, -836}, /* 696 formatted_exception */ {335740929, -901}, /* 1 gfix_db_name */ {335740930, -901}, /* 2 gfix_invalid_sw */ {335740932, -901}, /* 4 gfix_incmp_sw */ diff --git a/src/include/gen/sql_state.h b/src/include/gen/sql_state.h index 36343602b4f..4f72058e741 100644 --- a/src/include/gen/sql_state.h +++ b/src/include/gen/sql_state.h @@ -716,6 +716,7 @@ static const struct { {335545013, "22003"}, // 693 invalid_time_val {335545014, "22003"}, // 694 invalid_timestamp_val {335545015, "22003"}, // 695 invalid_index_val + {335545016, "00000"}, // 696 formatted_exception {335740929, "00000"}, // 1 gfix_db_name {335740930, "00000"}, // 2 gfix_invalid_sw {335740932, "00000"}, // 4 gfix_incmp_sw diff --git a/src/jrd/blr.h b/src/jrd/blr.h index 4b0cfe6ffdc..06e69706dc1 100644 --- a/src/jrd/blr.h +++ b/src/jrd/blr.h @@ -79,13 +79,14 @@ #define blr_right (unsigned char)2 #define blr_full (unsigned char)3 -#define blr_gds_code (unsigned char)0 -#define blr_sql_code (unsigned char)1 -#define blr_exception (unsigned char)2 -#define blr_trigger_code (unsigned char)3 -#define blr_default_code (unsigned char)4 -#define blr_raise (unsigned char)5 -#define blr_exception_msg (unsigned char)6 +#define blr_gds_code (unsigned char)0 +#define blr_sql_code (unsigned char)1 +#define blr_exception (unsigned char)2 +#define blr_trigger_code (unsigned char)3 +#define blr_default_code (unsigned char)4 +#define blr_raise (unsigned char)5 +#define blr_exception_msg (unsigned char)6 +#define blr_exception_params (unsigned char)7 #define blr_version4 (unsigned char)4 #define blr_version5 (unsigned char)5 diff --git a/src/jrd/gds.cpp b/src/jrd/gds.cpp index b165b9f5a68..2c97a13389c 100644 --- a/src/jrd/gds.cpp +++ b/src/jrd/gds.cpp @@ -191,7 +191,7 @@ static void blr_indent(gds_ctl*, SSHORT); static void blr_print_blr(gds_ctl*, UCHAR); static SCHAR blr_print_byte(gds_ctl*); static SCHAR blr_print_char(gds_ctl*); -static void blr_print_cond(gds_ctl*); +static void blr_print_cond(gds_ctl*, SSHORT); static int blr_print_dtype(gds_ctl*); static void blr_print_join(gds_ctl*); static SLONG blr_print_line(gds_ctl*, SSHORT); @@ -2815,7 +2815,7 @@ static SCHAR blr_print_char(gds_ctl* control) } -static void blr_print_cond(gds_ctl* control) +static void blr_print_cond(gds_ctl* control, SSHORT level) { /************************************** * @@ -2830,6 +2830,7 @@ static void blr_print_cond(gds_ctl* control) SSHORT n; const USHORT ctype = control->ctl_blr_reader.getByte(); + SLONG offset = control->ctl_blr_reader.getOffset(); switch (ctype) { @@ -2855,6 +2856,17 @@ static void blr_print_cond(gds_ctl* control) blr_print_verb(control, 0); break; + case blr_exception_params: + blr_format(control, "blr_exception_params, "); + n = blr_print_byte(control); + while (--n >= 0) + blr_print_char(control); + n = blr_print_word(control); + blr_print_line(control, (SSHORT) offset); + while (--n >= 0) + blr_print_verb(control, level); + break; + case blr_sql_code: blr_format(control, "blr_sql_code, "); blr_print_word(control); @@ -3241,13 +3253,13 @@ static void blr_print_verb(gds_ctl* control, SSHORT level) while (--n >= 0) { blr_indent(control, level); - blr_print_cond(control); + blr_print_cond(control, level); offset = blr_print_line(control, (SSHORT) offset); } break; case op_set_error: - blr_print_cond(control); + blr_print_cond(control, level); break; case op_indent: diff --git a/src/msgs/facilities2.sql b/src/msgs/facilities2.sql index 7420d3886da..44b7d4eb0af 100644 --- a/src/msgs/facilities2.sql +++ b/src/msgs/facilities2.sql @@ -1,7 +1,7 @@ /* MAX_NUMBER is the next number to be used, always one more than the highest message number. */ set bulk_insert INSERT INTO FACILITIES (LAST_CHANGE, FACILITY, FAC_CODE, MAX_NUMBER) VALUES (?, ?, ?, ?); -- -('2010-01-03 07:08:38', 'JRD', 0, 696) +('2010-01-05 16:36:00', 'JRD', 0, 697) ('2009-07-16 05:41:59', 'QLI', 1, 530) -- --('2008-11-28 20:27:04', 'GDEF', 2, 346) diff --git a/src/msgs/messages2.sql b/src/msgs/messages2.sql index 2c2285cdbef..58ef4346d4d 100644 --- a/src/msgs/messages2.sql +++ b/src/msgs/messages2.sql @@ -803,6 +803,7 @@ Data source : @4', NULL, NULL) ('invalid_time_val', 'ValueImpl::setTime', 'ValueImpl.cpp', NULL, 0, 693, NULL, 'Invalid time', NULL, NULL) ('invalid_timestamp_val', 'ValueImpl::setTimeStamp', 'ValueImpl.cpp', NULL, 0, 694, NULL, 'Invalid timestamp', NULL, NULL) ('invalid_index_val', 'ValuesImpl::getValue', 'ValuesImpl.cpp', NULL, 0, 695, NULL, 'Invalid index @1', NULL, NULL) +('formatted_exception', 'ExceptionNode::setError', 'StmtNodes.cpp', NULL, 0, 696, NULL, '@1', NULL, NULL) -- QLI (NULL, NULL, NULL, NULL, 1, 0, NULL, 'expected type', NULL, NULL); (NULL, NULL, NULL, NULL, 1, 1, NULL, 'bad block type', NULL, NULL); diff --git a/src/msgs/system_errors2.sql b/src/msgs/system_errors2.sql index e086fb3ac1c..e113db3f2de 100644 --- a/src/msgs/system_errors2.sql +++ b/src/msgs/system_errors2.sql @@ -701,6 +701,7 @@ set bulk_insert INSERT INTO SYSTEM_ERRORS (SQL_CODE, SQL_CLASS, SQL_SUBCLASS, FA (-901, '22', '003', 0, 693, 'invalid_time_val', NULL, NULL) (-901, '22', '003', 0, 694, 'invalid_timestamp_val', NULL, NULL) (-901, '22', '003', 0, 695, 'invalid_index_val', NULL, NULL) +(-836, '00', '000', 0, 696, 'formatted_exception', NULL, 'ERROR') -- GFIX (-901, '00', '000', 3, 1, 'gfix_db_name', NULL, NULL) (-901, '00', '000', 3, 2, 'gfix_invalid_sw', NULL, NULL)