diff --git a/src/dsql/ExprNodes.cpp b/src/dsql/ExprNodes.cpp index bcac5b55f6..a6681398b5 100644 --- a/src/dsql/ExprNodes.cpp +++ b/src/dsql/ExprNodes.cpp @@ -63,6 +63,7 @@ using namespace Jrd; namespace Jrd { +static const long LONG_POS_MAX = 2147483647; static const SINT64 MAX_INT64_LIMIT = MAX_SINT64 / 10; static const SINT64 MIN_INT64_LIMIT = MIN_SINT64 / 10; static const SINT64 SECONDS_PER_DAY = 24 * 60 * 60; @@ -9492,9 +9493,20 @@ bool SubstringNode::setParameterType(DsqlCompilerScratch* dsqlScratch, void SubstringNode::genBlr(DsqlCompilerScratch* dsqlScratch) { dsqlScratch->appendUChar(blr_substring); + GEN_expr(dsqlScratch, expr); GEN_expr(dsqlScratch, start); - GEN_expr(dsqlScratch, length); + + if (length) + GEN_expr(dsqlScratch, length); + else + { + dsqlScratch->appendUChar(blr_literal); + dsqlScratch->appendUChar(blr_long); + dsqlScratch->appendUChar(0); + dsqlScratch->appendUShort(LONG_POS_MAX); + dsqlScratch->appendUShort(LONG_POS_MAX >> 16); + } } void SubstringNode::make(DsqlCompilerScratch* dsqlScratch, dsc* desc) @@ -9503,9 +9515,10 @@ void SubstringNode::make(DsqlCompilerScratch* dsqlScratch, dsc* desc) MAKE_desc(dsqlScratch, &desc1, expr); MAKE_desc(dsqlScratch, &desc2, start); - MAKE_desc(dsqlScratch, &desc3, length); + if (length) + MAKE_desc(dsqlScratch, &desc3, length); - DSqlDataTypeUtil(dsqlScratch).makeSubstr(desc, &desc1, &desc2, &desc3); + DSqlDataTypeUtil(dsqlScratch).makeSubstr(desc, &desc1, &desc2, (length ? &desc3 : NULL)); } void SubstringNode::getDesc(thread_db* tdbb, CompilerScratch* csb, dsc* desc) diff --git a/src/dsql/parse.y b/src/dsql/parse.y index 40ab39e0e0..0a94a6a114 100644 --- a/src/dsql/parse.y +++ b/src/dsql/parse.y @@ -101,7 +101,6 @@ const long SHRT_POS_MAX = 32767; const long SHRT_UNSIGNED_MAX = 65535; const long SHRT_NEG_MAX = 32768; -const long LONG_POS_MAX = 2147483647; const int POSITIVE = 0; const int NEGATIVE = 1; const int UNSIGNED = 2; @@ -6255,7 +6254,7 @@ substring_function %type string_length_opt string_length_opt - : /* nothing */ { $$ = MAKE_const_slong(LONG_POS_MAX); } + : /* nothing */ { $$ = NULL; } | FOR value { $$ = $2; } ; diff --git a/src/jrd/DataTypeUtil.cpp b/src/jrd/DataTypeUtil.cpp index f085f68da5..5b2b6f41ee 100644 --- a/src/jrd/DataTypeUtil.cpp +++ b/src/jrd/DataTypeUtil.cpp @@ -28,6 +28,7 @@ #include "../jrd/DataTypeUtil.h" #include "../jrd/SysFunction.h" #include "../jrd/align.h" +#include "../common/cvt.h" #include "../common/dsc.h" #include "../jrd/ibase.h" #include "../jrd/intl.h" @@ -300,10 +301,17 @@ void DataTypeUtilBase::makeSubstr(dsc* result, const dsc* value, const dsc* offs } result->setTextType(value->getTextType()); - result->setNullable(value->isNullable() || offset->isNullable() || length->isNullable()); + result->setNullable(value->isNullable() || offset->isNullable() || (length && length->isNullable())); if (result->isText()) - result->dsc_length = fixLength(result, convertLength(value, result)) + sizeof(USHORT); + { + SLONG len = convertLength(value, result); + + if (length && length->dsc_address) // constant + len = MIN(len, CVT_get_long(length, 0, ERR_post) * maxBytesPerChar(result->getCharSet())); + + result->dsc_length = fixLength(result, len) + sizeof(USHORT); + } }