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 formatting issue in CAST MONEY to CHAR/VARCHAR #3367

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
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,27 @@ LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
* So make sure that any SQL statement (DDL/DML) being added here can be executed multiple times without affecting
* final behaviour.
*/
CREATE OR REPLACE FUNCTION sys.fixeddecimal2varchar(sys.FIXEDDECIMAL, integer, BOOLEAN)
RETURNS sys.VARCHAR
AS 'babelfishpg_common', 'fixeddecimal2varchar'
LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;

CREATE OR REPLACE FUNCTION sys.fixeddecimal2bpchar(sys.FIXEDDECIMAL, integer, BOOLEAN)
RETURNS sys.BPCHAR
AS 'babelfishpg_common', 'fixeddecimal2bpchar'
LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;

CREATE CAST (sys.FIXEDDECIMAL AS sys.VARCHAR)
WITH FUNCTION sys.fixeddecimal2varchar(sys.FIXEDDECIMAL, integer, BOOLEAN) AS IMPLICIT;

CREATE CAST (sys.FIXEDDECIMAL AS pg_catalog.VARCHAR)
WITH FUNCTION sys.fixeddecimal2varchar(sys.FIXEDDECIMAL, integer, BOOLEAN) AS IMPLICIT;

CREATE CAST (sys.FIXEDDECIMAL AS sys.BPCHAR)
WITH FUNCTION sys.fixeddecimal2bpchar(sys.FIXEDDECIMAL, integer, BOOLEAN) AS IMPLICIT;

CREATE CAST (sys.FIXEDDECIMAL AS pg_catalog.BPCHAR)
WITH FUNCTION sys.fixeddecimal2bpchar(sys.FIXEDDECIMAL, integer, BOOLEAN) AS IMPLICIT;

-- Reset search_path to not affect any subsequent scripts
SELECT set_config('search_path', trim(leading 'sys, ' from current_setting('search_path')), false);
22 changes: 22 additions & 0 deletions contrib/babelfishpg_common/sql/varchar.sql
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,28 @@ LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
CREATE CAST (sys.VARCHAR AS pg_catalog.NUMERIC)
WITH FUNCTION sys.varchar2numeric(sys.VARCHAR) AS IMPLICIT;

CREATE OR REPLACE FUNCTION sys.fixeddecimal2varchar(sys.FIXEDDECIMAL, integer, BOOLEAN)
RETURNS sys.VARCHAR
AS 'babelfishpg_common', 'fixeddecimal2varchar'
LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;

CREATE OR REPLACE FUNCTION sys.fixeddecimal2bpchar(sys.FIXEDDECIMAL, integer, BOOLEAN)
RETURNS sys.BPCHAR
AS 'babelfishpg_common', 'fixeddecimal2bpchar'
LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;

CREATE CAST (sys.FIXEDDECIMAL AS sys.VARCHAR)
WITH FUNCTION sys.fixeddecimal2varchar(sys.FIXEDDECIMAL, integer, BOOLEAN) AS IMPLICIT;

CREATE CAST (sys.FIXEDDECIMAL AS pg_catalog.VARCHAR)
WITH FUNCTION sys.fixeddecimal2varchar(sys.FIXEDDECIMAL, integer, BOOLEAN) AS IMPLICIT;

CREATE CAST (sys.FIXEDDECIMAL AS sys.BPCHAR)
WITH FUNCTION sys.fixeddecimal2bpchar(sys.FIXEDDECIMAL, integer, BOOLEAN) AS IMPLICIT;

CREATE CAST (sys.FIXEDDECIMAL AS pg_catalog.BPCHAR)
WITH FUNCTION sys.fixeddecimal2bpchar(sys.FIXEDDECIMAL, integer, BOOLEAN) AS IMPLICIT;

CREATE OR REPLACE FUNCTION sys.nvarchar_larger(sys.NVARCHAR, sys.NVARCHAR)
RETURNS sys.NVARCHAR
AS 'text_larger'
Expand Down
86 changes: 86 additions & 0 deletions contrib/babelfishpg_common/src/varchar.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,12 @@ static inline int varcharTruelen(VarChar *arg);

#define DEFAULT_LCID 1033

/* Linkage to function in fixeddecimal module */
typedef char *(*fixeddecimal2str_t) (int64 val, char *buffer,
int64 fixeddecimal_multiplier,
int64 fixeddecimal_scale);
static fixeddecimal2str_t fixeddecimal2str_p = NULL;

/*
* is_basetype_nchar_nvarchar - given datatype is nvarchar or nchar
* or created over nvarchar or nchar.
Expand Down Expand Up @@ -554,6 +560,8 @@ PG_FUNCTION_INFO_V1(varchar2date);
PG_FUNCTION_INFO_V1(varchar2time);
PG_FUNCTION_INFO_V1(varchar2money);
PG_FUNCTION_INFO_V1(varchar2numeric);
PG_FUNCTION_INFO_V1(fixeddecimal2varchar);
PG_FUNCTION_INFO_V1(fixeddecimal2bpchar);

/*****************************************************************************
* varchar - varchar(n)
Expand Down Expand Up @@ -1102,6 +1110,84 @@ varchar2numeric(PG_FUNCTION_ARGS)
PG_RETURN_NUMERIC(result);
}

#define FIXEDDECIMAL_2_VARCHAR_MULTIPLIER 100LL
#define FIXEDDECIMAL_2_VARCHAR_SCALE 2
Datum
fixeddecimal2varchar(PG_FUNCTION_ARGS)
{
int64 val = PG_GETARG_INT64(0);
int32 maxByteLen = PG_GETARG_INT32(1);
char buf[MAXINT8LEN + 1];
char *end;
int32 len;
Datum res;

/* fetch function pointer for cross-module calls. */
if (fixeddecimal2str_p == NULL)
fixeddecimal2str_p = (fixeddecimal2str_t)
load_external_function("$libdir/babelfishpg_money", "fixeddecimal2str", true, NULL);

end = fixeddecimal2str_p(val, buf, FIXEDDECIMAL_2_VARCHAR_MULTIPLIER, FIXEDDECIMAL_2_VARCHAR_SCALE);
len = (end - buf);

if (maxByteLen < 0)
maxByteLen = len + VARHDRSZ;
maxByteLen -= VARHDRSZ;
if (len > maxByteLen)
ereport(ERROR,
(errcode(ERRCODE_STRING_DATA_RIGHT_TRUNCATION),
errmsg("There is insufficient result space to convert a money/smallmoney value to varchar/nvarchar.")));

res = DirectFunctionCall3(varcharin,
CStringGetDatum(buf),
ObjectIdGetDatum(0),
Int32GetDatum(-1));

PG_RETURN_DATUM(res);
}

Datum
fixeddecimal2bpchar(PG_FUNCTION_ARGS)
{
int64 val = PG_GETARG_INT64(0);
int32 maxByteLen = PG_GETARG_INT32(1);
char buf[MAXINT8LEN + 1];
char *buf_padded;
char *end;
int32 len;
Datum res;

/* fetch function pointer for cross-module calls. */
if (fixeddecimal2str_p == NULL)
fixeddecimal2str_p = (fixeddecimal2str_t)
load_external_function("$libdir/babelfishpg_money", "fixeddecimal2str", true, NULL);

end = fixeddecimal2str_p(val, buf, FIXEDDECIMAL_2_VARCHAR_MULTIPLIER, FIXEDDECIMAL_2_VARCHAR_SCALE);
len = (end - buf);

if (maxByteLen < 0)
maxByteLen = len + VARHDRSZ;
maxByteLen -= VARHDRSZ;
if (len > maxByteLen)
rishabhtanwar29 marked this conversation as resolved.
Show resolved Hide resolved
ereport(ERROR,
(errcode(ERRCODE_STRING_DATA_RIGHT_TRUNCATION),
errmsg("There is insufficient result space to convert a money/smallmoney value to varchar/nvarchar.")));

/* Left pad money value with the spaces */
buf_padded = (char *) palloc(maxByteLen + 1);
memset(buf_padded, ' ', maxByteLen - len);
memcpy(buf_padded + maxByteLen - len, buf, len);
buf_padded[maxByteLen] = '\0';
res = DirectFunctionCall3(bpcharin,
CStringGetDatum(buf_padded),
ObjectIdGetDatum(0),
Int32GetDatum(-1));

PG_RETURN_DATUM(res);
}
#undef FIXEDDECIMAL_2_VARCHAR_MULTIPLIER
#undef FIXEDDECIMAL_2_VARCHAR_SCALE

/*****************************************************************************
* bpchar - char() *
*****************************************************************************/
Expand Down
36 changes: 29 additions & 7 deletions contrib/babelfishpg_money/fixeddecimal.c
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,9 @@ static int64 scanfixeddecimal(const char *str, int *precision, int *scale);
static FixedDecimalAggState *makeFixedDecimalAggState(FunctionCallInfo fcinfo);
static void fixeddecimal_accum(FixedDecimalAggState *state, int64 newval);
static int64 int8fixeddecimal_internal(int64 arg, const char *typename);
extern PGDLLEXPORT char *fixeddecimal2str(int64 val, char *buffer,
int64 fixeddecimal_multiplier,
int64 fixeddecimal_scale);

/***********************************************************************
**
Expand Down Expand Up @@ -393,12 +396,31 @@ pg_int64tostr_zeropad(char *str, int64 value, int64 padding)
* Prints the fixeddecimal 'val' to buffer as a string.
* Returns a pointer to the end of the written string.
*/
static char *
fixeddecimal2str(int64 val, char *buffer)
char *
fixeddecimal2str(int64 val, char *buffer,
int64 fixeddecimal_multiplier,
int64 fixeddecimal_scale)
rishabhtanwar29 marked this conversation as resolved.
Show resolved Hide resolved
{
char *ptr = buffer;
int64 integralpart = val / FIXEDDECIMAL_MULTIPLIER;
int64 fractionalpart = val % FIXEDDECIMAL_MULTIPLIER;
int64 integralpart;
int64 fractionalpart;

/*
* By default, fixeddecimal contains 4 digits after decimal but if we only need
* 2 decimal points, remove last two decimal digits, round off remaining value.
*/
if (fixeddecimal_scale < 4)
rishabhtanwar29 marked this conversation as resolved.
Show resolved Hide resolved
rishabhtanwar29 marked this conversation as resolved.
Show resolved Hide resolved
{
int64 scale_factor = FIXEDDECIMAL_MULTIPLIER / (fixeddecimal_multiplier * 10);
int64 last_digit = abs(val / scale_factor) % 10;

val = val / fixeddecimal_multiplier;
if (last_digit >= 5)
val = val >= 0 ? val + 1LL : val - 1LL;
}

integralpart = val / fixeddecimal_multiplier;
fractionalpart = val % fixeddecimal_multiplier;

if (val < 0)
{
Expand All @@ -414,7 +436,7 @@ fixeddecimal2str(int64 val, char *buffer)
}
ptr = pg_int64tostr(ptr, integralpart);
*ptr++ = '.';
ptr = pg_int64tostr_zeropad(ptr, fractionalpart, FIXEDDECIMAL_SCALE);
ptr = pg_int64tostr_zeropad(ptr, fractionalpart, fixeddecimal_scale);
return ptr;
}

Expand Down Expand Up @@ -811,7 +833,7 @@ fixeddecimalout(PG_FUNCTION_ARGS)
{
int64 val = PG_GETARG_INT64(0);
char buf[MAXINT8LEN + 1];
char *end = fixeddecimal2str(val, buf);
char *end = fixeddecimal2str(val, buf, FIXEDDECIMAL_MULTIPLIER, FIXEDDECIMAL_SCALE);

PG_RETURN_CSTRING(pnstrdup(buf, end - buf));
}
Expand Down Expand Up @@ -2930,7 +2952,7 @@ fixeddecimalaggstateout(PG_FUNCTION_ARGS)
char buf[MAXINT8LEN + 1 + MAXINT8LEN + 1];
char *p;

p = fixeddecimal2str(state->sumX, buf);
p = fixeddecimal2str(state->sumX, buf, FIXEDDECIMAL_MULTIPLIER, FIXEDDECIMAL_SCALE);
*p++ = ':';
p = pg_int64tostr(p, state->N);

Expand Down
11 changes: 6 additions & 5 deletions contrib/babelfishpg_tsql/src/pltsql_coerce.c
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,11 @@ tsql_cast_raw_info_t tsql_cast_raw_infos[] =
{TSQL_CAST_ENTRY, "sys", "varchar", "pg_catalog", "name", "varchar_to_name", 'i', 'f'},
{TSQL_CAST_ENTRY, "sys", "nvarchar", "sys", "bbf_varbinary", "nvarcharvarbinary", 'a', 'f'},
{TSQL_CAST_ENTRY, "sys", "nvarchar", "sys", "bbf_binary", "nvarcharbinary", 'a', 'f'},
/* fixeddecimal */
{PG_CAST_ENTRY, "sys", "fixeddecimal", "pg_catalog", "bpchar", NULL, 'i', 'f'},
{PG_CAST_ENTRY, "sys", "fixeddecimal", "sys", "bpchar", NULL, 'i', 'f'},
{PG_CAST_ENTRY, "sys", "fixeddecimal", "pg_catalog", "varchar", NULL, 'i', 'f'},
{PG_CAST_ENTRY, "sys", "fixeddecimal", "sys", "varchar", NULL, 'i', 'f'},
/* string -> float8 via I/O */
{TSQL_CAST_WITHOUT_FUNC_ENTRY, "pg_catalog", "text", "pg_catalog", "float8", NULL, 'i', 'i'},
{TSQL_CAST_WITHOUT_FUNC_ENTRY, "pg_catalog", "bpchar", "pg_catalog", "float8", NULL, 'i', 'i'},
Expand Down Expand Up @@ -306,11 +311,7 @@ tsql_cast_raw_info_t tsql_cast_raw_infos[] =
{TSQL_CAST_WITHOUT_FUNC_ENTRY, "pg_catalog", "numeric", "sys", "varchar", NULL, 'i', 'i'},
/* // fixeddecimal -> string via I/O */
{TSQL_CAST_WITHOUT_FUNC_ENTRY, "sys", "fixeddecimal", "pg_catalog", "text", NULL, 'i', 'i'},
{TSQL_CAST_WITHOUT_FUNC_ENTRY, "sys", "fixeddecimal", "pg_catalog", "bpchar", NULL, 'i', 'i'},
{TSQL_CAST_WITHOUT_FUNC_ENTRY, "sys", "fixeddecimal", "sys", "bpchar", NULL, 'i', 'i'},
{TSQL_CAST_WITHOUT_FUNC_ENTRY, "sys", "fixeddecimal", "pg_catalog", "varchar", NULL, 'i', 'i'},
{TSQL_CAST_WITHOUT_FUNC_ENTRY, "sys", "fixeddecimal", "sys", "varchar", NULL, 'i', 'i'},
/* fixeddecimal -> string via I/O */
/* uniqueidentifier -> string via I/O */
{TSQL_CAST_WITHOUT_FUNC_ENTRY, "sys", "uniqueidentifier", "pg_catalog", "text", NULL, 'i', 'i'},
{TSQL_CAST_WITHOUT_FUNC_ENTRY, "sys", "uniqueidentifier", "pg_catalog", "bpchar", NULL, 'i', 'i'},
{TSQL_CAST_WITHOUT_FUNC_ENTRY, "sys", "uniqueidentifier", "sys", "bpchar", NULL, 'i', 'i'},
Expand Down
14 changes: 7 additions & 7 deletions test/JDBC/expected/BABEL-1193.out
Original file line number Diff line number Diff line change
Expand Up @@ -221,9 +221,9 @@ SELECT * FROM t14;
GO
~~START~~
varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar
12#!#4553#!#123456#!#12.345#!#2344.456#!#12.34#!#456.3334#!#1123.6777
-12#!#-1234#!#-123456#!#-12.345#!#-2344.456#!#12.34#!#-456.3334#!#-1123.6777
0#!#0#!#0#!#0#!#0#!#0.00#!#0.0000#!#0.0000
12#!#4553#!#123456#!#12.345#!#2344.456#!#12.34#!#456.33#!#1123.68
-12#!#-1234#!#-123456#!#-12.345#!#-2344.456#!#12.34#!#-456.33#!#-1123.68
0#!#0#!#0#!#0#!#0#!#0.00#!#0.00#!#0.00
~~END~~

-- numeric types -> char(10)
Expand All @@ -237,9 +237,9 @@ SELECT * FROM t15;
GO
~~START~~
char#!#char#!#char#!#char#!#char#!#char#!#char#!#char
12 #!#4553 #!#123456 #!#12.345 #!#2344.456 #!#12.34 #!#456.3334 #!#1123.6777
-12 #!#-1234 #!#-123456 #!#-12.345 #!#-2344.456 #!#12.34 #!#-456.3334 #!#-1123.6777
0 #!#0 #!#0 #!#0 #!#0 #!#0.00 #!#0.0000 #!#0.0000
12 #!#4553 #!#123456 #!#12.345 #!#2344.456 #!#12.34 #!# 456.33#!# 1123.68
-12 #!#-1234 #!#-123456 #!#-12.345 #!#-2344.456 #!#12.34 #!# -456.33#!# -1123.68
0 #!#0 #!#0 #!#0 #!#0 #!#0.00 #!# 0.00#!# 0.00
~~END~~


Expand All @@ -248,7 +248,7 @@ select upper(cast (1 as smallint)), upper(cast (1 as int)), upper(cast (1 as big
GO
~~START~~
varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar
1#!#1#!#1#!#1#!#1#!#2.1#!#1.0000#!#1.0000
1#!#1#!#1#!#1#!#1#!#2.1#!#1.00#!#1.00
~~END~~

select round(cast ('123' as text), 1), round(cast ('123' as char(3)), 1), round(cast ('123' as varchar(3)), 1);
Expand Down
4 changes: 2 additions & 2 deletions test/JDBC/expected/BABEL-3486-before-17_3-vu-verify.out
Original file line number Diff line number Diff line change
Expand Up @@ -1586,7 +1586,7 @@ SELECT * FROM BABEL_3486_vu_prepare_v63
GO
~~START~~
varchar
1.0000
1.00
~~END~~

DROP VIEW BABEL_3486_vu_prepare_v63
Expand All @@ -1596,7 +1596,7 @@ EXEC BABEL_3486_vu_prepare_p63
GO
~~START~~
varchar
1.0000
1.00
~~END~~

DROP PROCEDURE BABEL_3486_vu_prepare_p63
Expand Down
4 changes: 2 additions & 2 deletions test/JDBC/expected/BABEL-3486-vu-verify.out
Original file line number Diff line number Diff line change
Expand Up @@ -1586,7 +1586,7 @@ SELECT * FROM BABEL_3486_vu_prepare_v63
GO
~~START~~
varchar
1.0000
1.00
~~END~~

DROP VIEW BABEL_3486_vu_prepare_v63
Expand All @@ -1596,7 +1596,7 @@ EXEC BABEL_3486_vu_prepare_p63
GO
~~START~~
varchar
1.0000
1.00
~~END~~

DROP PROCEDURE BABEL_3486_vu_prepare_p63
Expand Down
4 changes: 2 additions & 2 deletions test/JDBC/expected/BABEL-889-vu-verify.out
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ select cast(cast(cast('$123.123' as money) as sql_variant) as varchar);
go
~~START~~
varchar
123.1230
123.12
~~END~~

-- smallmoney
Expand All @@ -146,7 +146,7 @@ select cast(cast(cast('$123.123' as smallmoney) as sql_variant) as varchar);
go
~~START~~
varchar
123.1230
123.12
~~END~~

-- bigint
Expand Down
4 changes: 2 additions & 2 deletions test/JDBC/expected/BABEL-889.out
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ select cast(cast(cast('$123.123' as money) as sql_variant) as varchar);
go
~~START~~
varchar
123.1230
123.12
~~END~~

-- smallmoney
Expand All @@ -146,7 +146,7 @@ select cast(cast(cast('$123.123' as smallmoney) as sql_variant) as varchar);
go
~~START~~
varchar
123.1230
123.12
~~END~~

-- bigint
Expand Down
Loading