Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix typmod value in case of nvarchar(max), varchar(max), varbinary(max) #2194

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions contrib/babelfishpg_tds/src/backend/tds/tdsresponse.c
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@
#define Max(x, y) ((x) > (y) ? (x) : (y))
#define Min(x, y) ((x) < (y) ? (x) : (y))
#define ROWVERSION_SIZE 8
#define VARBINARY_MAX_SCALE 8000

/*
* Local structures and functions copied from printtup.c
Expand Down Expand Up @@ -1860,8 +1861,13 @@ PrepareRowDescription(TupleDesc typeinfo, PlannedStmt *plannedstmt, List *target
if (!con->constisnull)
{
bytea *source = (bytea *) con->constvalue;

atttypmod = VARSIZE_ANY(source);
int32 actual_size = VARSIZE_ANY_EXHDR(source);

/* if the actual size is greater than 8000, it should be varbinary(max) case as we have set a limit on scale */
if (actual_size > VARBINARY_MAX_SCALE)
atttypmod = -1;
else
atttypmod = VARSIZE_ANY(source);
}
}
SetColMetadataForBinaryType(col, TDS_TYPE_VARBINARY, (atttypmod == -1) ?
Expand Down
3 changes: 0 additions & 3 deletions contrib/babelfishpg_tds/src/backend/tds/tdstypeio.c
Original file line number Diff line number Diff line change
Expand Up @@ -2648,9 +2648,6 @@ TdsSendTypeVarchar(FmgrInfo *finfo, Datum value, void *vMetaData)
}
else
{
/* We can store upto 2GB (2^31 - 1 bytes) for the varchar(max). */
if (unlikely(actualLen > VARCHAR_MAX))
elog(ERROR, "Number of bytes required for the field of varchar(max) exeeds 2GB");
TDSInstrumentation(INSTR_TDS_DATATYPE_VARCHAR_MAX);

rc = TdsSendPlpDataHelper(destBuf, actualLen);
Expand Down
39 changes: 36 additions & 3 deletions contrib/babelfishpg_tsql/src/pl_gram.y
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,8 @@
*/
#define YYMALLOC palloc
#define YYFREE pfree

#define VARCHAR_MAX_SCALE 8000
#define NVARCHAR_MAX_SCALE 4000
#define TEMPOBJ_QUALIFIER "TEMPORARY "

typedef struct
Expand Down Expand Up @@ -224,6 +225,10 @@ static tsql_exec_param *parse_sp_proc_param(int *endtoken, bool *flag);
static bool word_matches_sp_proc(int tok);
static PLtsql_stmt *parse_sp_proc(int tok, int lineno, int return_dno);
static void parse_sp_cursor_value(StringInfoData* pbuffer, int *pterm);
extern bool is_tsql_nchar_or_nvarchar_datatype(Oid oid);
extern bool is_tsql_varchar_or_char_datatype(Oid oid);
extern bool is_tsql_binary_or_varbinary_datatype(Oid oid);
extern bool is_tsql_datatype_with_max_scale_expr_allowed(Oid oid);

#define ereport_syntax_error(pos, msg, ...) \
ereport(ERROR, \
Expand Down Expand Up @@ -7185,9 +7190,11 @@ pltsql_sql_error_callback(void *arg)
PLtsql_type *
parse_datatype(const char *string, int location)
{
TypeName *typeName;
Oid type_id;
TypeName *typeName;
Oid type_id;
int32 typmod;
char *dataTypeName,
*schemaName;
sql_error_callback_arg cbarg;
ErrorContextCallback syntax_errcontext;

Expand Down Expand Up @@ -7219,6 +7226,32 @@ parse_datatype(const char *string, int location)
rewrite_plain_name(typeName->names);
typenameTypeIdAndMod(NULL, typeName, &type_id, &typmod);

/* in T-SQL, length-less (N)(VAR)CHAR's length is treated as 1 by default */
if (typmod == -1 && (is_tsql_varchar_or_char_datatype(type_id) || is_tsql_nchar_or_nvarchar_datatype(type_id)
|| is_tsql_binary_or_varbinary_datatype(type_id)))
typmod = 1 + VARHDRSZ;

/* for varchar/nvarchar/varbinary(MAX), set typmod back to -1 */
else if (typmod == TSQLMaxTypmod && is_tsql_datatype_with_max_scale_expr_allowed(type_id))
typmod = -1;

else if (typmod > (VARCHAR_MAX_SCALE + VARHDRSZ) && (is_tsql_varchar_or_char_datatype(type_id) || is_tsql_binary_or_varbinary_datatype(type_id)))
{
DeconstructQualifiedName(typeName->names, &schemaName, &dataTypeName);
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("The size '%d' exceeds the maximum allowed (%d) for '%s' datatype.",
typmod - VARHDRSZ, VARCHAR_MAX_SCALE, dataTypeName)));
}
else if (typmod > (NVARCHAR_MAX_SCALE + VARHDRSZ) && (is_tsql_nchar_or_nvarchar_datatype(type_id)))
{
DeconstructQualifiedName(typeName->names, &schemaName, &dataTypeName);
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("The size '%d' exceeds the maximum allowed (%d) for '%s' datatype.",
typmod - VARHDRSZ, NVARCHAR_MAX_SCALE, dataTypeName)));
}

/* Restore former ereport callback */
error_context_stack = syntax_errcontext.previous;

Expand Down
46 changes: 33 additions & 13 deletions contrib/babelfishpg_tsql/src/pltsql_utils.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,12 @@ bool suppress_string_truncation_error = false;

bool pltsql_suppress_string_truncation_error(void);

bool is_tsql_any_char_datatype(Oid oid); /* sys.char / sys.nchar /
* sys.varchar / sys.nvarchar */
bool is_tsql_varchar_or_char_datatype(Oid oid); /* sys.char / sys.varchar */
bool is_tsql_nchar_or_nvarchar_datatype(Oid oid); /* sys.nchar / sys.nvarchar */
bool is_tsql_binary_or_varbinary_datatype(Oid oid); /* sys.binary / sys.varbinary */
bool is_tsql_datatype_with_max_scale_expr_allowed(Oid oid); /* sys.varchar(max), sys.nvarchar(max), sys.varbinary(max) */
bool is_tsql_text_ntext_or_image_datatype(Oid oid);

bool is_tsql_binary_or_varbinary_datatype(Oid oid);

/* To cache oid of sys.varchar */
static Oid sys_varcharoid = InvalidOid;
Expand Down Expand Up @@ -152,7 +153,8 @@ pltsql_check_or_set_default_typmod(TypeName *typeName, int32 *typmod, bool is_ca
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("Incorrect syntax near the keyword '%s'.", typname)));
}
else if (*typmod > (max_allowed_varchar_length + VARHDRSZ) && (strcmp(typname, "varchar") == 0 || strcmp(typname, "bpchar") == 0))
else if (*typmod > (max_allowed_varchar_length + VARHDRSZ) && (strcmp(typname, "varchar") == 0 || strcmp(typname, "bpchar") == 0 ||
strcmp(typname, "varbinary") == 0 || strcmp(typname, "binary") == 0))
{
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
Expand Down Expand Up @@ -781,29 +783,47 @@ update_ViewStmt(Node *n, const char *view_schema)
stmt->view->schemaname = pstrdup(view_schema);
}

/* sys.char, sys.varchar */
bool
is_tsql_any_char_datatype(Oid oid)
is_tsql_varchar_or_char_datatype(Oid oid)
{
return (*common_utility_plugin_ptr->is_tsql_bpchar_datatype) (oid) ||
(*common_utility_plugin_ptr->is_tsql_nchar_datatype) (oid) ||
(*common_utility_plugin_ptr->is_tsql_varchar_datatype) (oid) ||
(*common_utility_plugin_ptr->is_tsql_nvarchar_datatype) (oid);
(*common_utility_plugin_ptr->is_tsql_varchar_datatype) (oid);
}

/* sys.nchar, sys.nvarchar */
bool
is_tsql_text_ntext_or_image_datatype(Oid oid)
is_tsql_nchar_or_nvarchar_datatype(Oid oid)
{
return (*common_utility_plugin_ptr->is_tsql_text_datatype) (oid) ||
(*common_utility_plugin_ptr->is_tsql_ntext_datatype) (oid) ||
(*common_utility_plugin_ptr->is_tsql_image_datatype) (oid);
return (*common_utility_plugin_ptr->is_tsql_nchar_datatype) (oid) ||
(*common_utility_plugin_ptr->is_tsql_nvarchar_datatype) (oid);
}

bool is_tsql_binary_or_varbinary_datatype(Oid oid)
/* sys.binary, sys.varbinary */
bool
is_tsql_binary_or_varbinary_datatype(Oid oid)
{
return (*common_utility_plugin_ptr->is_tsql_sys_binary_datatype) (oid) ||
(*common_utility_plugin_ptr->is_tsql_sys_varbinary_datatype) (oid);
}

/* varchar(max), nvarchar(max), varbinary(max) */
bool
is_tsql_datatype_with_max_scale_expr_allowed(Oid oid)
{
return (*common_utility_plugin_ptr->is_tsql_varchar_datatype) (oid) ||
(*common_utility_plugin_ptr->is_tsql_nvarchar_datatype) (oid) ||
(*common_utility_plugin_ptr->is_tsql_sys_varbinary_datatype) (oid);
}

bool
is_tsql_text_ntext_or_image_datatype(Oid oid)
{
return (*common_utility_plugin_ptr->is_tsql_text_datatype) (oid) ||
(*common_utility_plugin_ptr->is_tsql_ntext_datatype) (oid) ||
(*common_utility_plugin_ptr->is_tsql_image_datatype) (oid);
}

/*
* Try to acquire a lock with no wait
*/
Expand Down
20 changes: 1 addition & 19 deletions contrib/babelfishpg_tsql/src/tsqlIface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,7 @@ extern "C"
void report_antlr_error(ANTLR_result result);

extern PLtsql_type *parse_datatype(const char *string, int location);
extern bool is_tsql_any_char_datatype(Oid oid);
extern bool is_tsql_text_ntext_or_image_datatype(Oid oid);
extern bool is_tsql_binary_or_varbinary_datatype(Oid oid);

extern int CurrentLineNumber;

Expand Down Expand Up @@ -4052,14 +4050,6 @@ makeDeclareStmt(TSqlParser::Declare_statementContext *ctx)
const char *name = downcase_truncate_identifier(nameStr.c_str(), nameStr.length(), true);
check_dup_declare(name);
PLtsql_type *type = parse_datatype(typeStr.c_str(), 0);

/* (N)(VAR)CHAR and BINARY datatype length is treated as 1 when nothing is provided */
if (type->atttypmod == -1 && (is_tsql_any_char_datatype(type->typoid)
|| is_tsql_binary_or_varbinary_datatype(type->typoid)))
{
std::string newTypeStr = typeStr + "(1)";
type = parse_datatype(newTypeStr.c_str(), 0);
}

PLtsql_variable *var = pltsql_build_variable(name, 0, type, true);

Expand All @@ -4086,15 +4076,7 @@ makeDeclareStmt(TSqlParser::Declare_statementContext *ctx)
{
std::string typeStr = ::getFullText(local->data_type());
PLtsql_type *type = parse_datatype(typeStr.c_str(), 0); // FIXME: the second arg should be 'location'

/* (N)(VAR)CHAR and BINARY datatype length is treated as 1 when nothing is provided */
if (type->atttypmod == -1 && (is_tsql_any_char_datatype(type->typoid)
|| is_tsql_binary_or_varbinary_datatype(type->typoid)))
{
std::string newTypeStr = typeStr + "(1)";
type = parse_datatype(newTypeStr.c_str(), 0);
}
else if (is_tsql_text_ntext_or_image_datatype(type->typoid))
if (is_tsql_text_ntext_or_image_datatype(type->typoid))
{
throw PGErrorWrapperException(ERROR, ERRCODE_DATATYPE_MISMATCH, "The text, ntext, and image data types are invalid for local variables.", getLineAndPos(local->data_type()));
}
Expand Down
420 changes: 420 additions & 0 deletions test/JDBC/expected/BABEL-4547.out

Large diffs are not rendered by default.

Loading
Loading