Skip to content

Commit

Permalink
Fix MVU failure due to sys.format_datetime, sys.format_numeric and sy…
Browse files Browse the repository at this point in the history
…s.format functions (babelfish-for-postgresql#2023)

We are deprecating the older versions of sys.format_datetime, sys.format_numeric and sys.format functions in the
version 2.7.0, Hence while doing major version upgrade, sys.format_datetime(anyelement, nvarchar, character varying,
character varying) is not found. And similarly, sys.format_numeric(anyelement, NVARCHAR, VARCHAR, VARCHAR, int)
and sys.format(anyelement, NVARCHAR, VARCHAR) are also deprecated in older version which may cause an error.

This changes catches the above error and deprecates the format functions only when they exist.

Task: BABEL-4394
Signed-off-by: Sai Rohan Basa <[email protected]>
  • Loading branch information
basasairohan committed Nov 16, 2023
1 parent 2d20e6c commit bd1f578
Showing 1 changed file with 100 additions and 59 deletions.
159 changes: 100 additions & 59 deletions contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--3.3.0--3.4.0.sql
Original file line number Diff line number Diff line change
Expand Up @@ -4144,84 +4144,125 @@ CREATE OR REPLACE FUNCTION sys.babelfish_fts_rewrite(IN phrase text) RETURNS TEX
'babelfishpg_tsql', 'babelfish_fts_rewrite'
LANGUAGE C IMMUTABLE PARALLEL SAFE;

-- Rename function for dependencies
ALTER FUNCTION sys.format_datetime(anyelement, NVARCHAR, VARCHAR, VARCHAR) RENAME TO format_datetime_deprecated_3_4_0;
ALTER FUNCTION sys.format_numeric(anyelement, NVARCHAR, VARCHAR, VARCHAR, int) RENAME TO format_numeric_deprecated_3_4_0;
ALTER FUNCTION sys.FORMAT(anyelement, NVARCHAR, VARCHAR) RENAME TO format_deprecated_3_4_0;
DO $$
DECLARE
exception_message text;
BEGIN
-- Rename format_datetime function for dependencies
ALTER FUNCTION sys.format_datetime(anyelement, NVARCHAR, VARCHAR, VARCHAR) RENAME TO format_datetime_deprecated_3_4_0;

CREATE OR REPLACE FUNCTION sys.format_datetime(IN value anyelement, IN format_pattern sys.NVARCHAR,IN culture sys.VARCHAR, IN data_type sys.VARCHAR DEFAULT '') RETURNS sys.nvarchar
AS 'babelfishpg_tsql', 'format_datetime' LANGUAGE C IMMUTABLE PARALLEL UNSAFE;
GRANT EXECUTE ON FUNCTION sys.format_datetime(IN anyelement, IN sys.NVARCHAR, IN sys.VARCHAR, IN sys.VARCHAR) TO PUBLIC;
CREATE OR REPLACE FUNCTION sys.format_datetime(IN value anyelement, IN format_pattern sys.NVARCHAR,IN culture sys.VARCHAR, IN data_type sys.VARCHAR DEFAULT '') RETURNS sys.nvarchar
AS 'babelfishpg_tsql', 'format_datetime' LANGUAGE C IMMUTABLE PARALLEL UNSAFE;
GRANT EXECUTE ON FUNCTION sys.format_datetime(IN anyelement, IN sys.NVARCHAR, IN sys.VARCHAR, IN sys.VARCHAR) TO PUBLIC;

CREATE OR REPLACE FUNCTION sys.format_numeric(IN value anyelement, IN format_pattern sys.NVARCHAR,IN culture sys.VARCHAR, IN data_type sys.VARCHAR DEFAULT '', IN e_position INT DEFAULT -1) RETURNS sys.nvarchar
AS 'babelfishpg_tsql', 'format_numeric' LANGUAGE C IMMUTABLE PARALLEL UNSAFE;
GRANT EXECUTE ON FUNCTION sys.format_numeric(IN anyelement, IN sys.NVARCHAR, IN sys.VARCHAR, IN sys.VARCHAR, IN INT) TO PUBLIC;
-- === DROP format_datetime_deprecated_3_4_0
CALL sys.babelfish_drop_deprecated_object('function', 'sys', 'format_datetime_deprecated_3_4_0');

CREATE OR REPLACE FUNCTION sys.FORMAT(IN arg anyelement, IN p_format_pattern sys.NVARCHAR, IN p_culture sys.VARCHAR default 'en-us')
RETURNS sys.NVARCHAR
AS
$BODY$
EXCEPTION WHEN OTHERS THEN
GET STACKED DIAGNOSTICS
exception_message = MESSAGE_TEXT;
RAISE WARNING '%', exception_message;
END;
$$;

DO $$
DECLARE
arg_type regtype;
v_temp_integer INTEGER;
exception_message text;
BEGIN
arg_type := pg_typeof(arg);
-- Rename format_numeric for dependencies
ALTER FUNCTION sys.format_numeric(anyelement, NVARCHAR, VARCHAR, VARCHAR, int) RENAME TO format_numeric_deprecated_3_4_0;

CASE
WHEN arg_type IN ('time'::regtype ) THEN
RETURN sys.format_datetime(arg, p_format_pattern, p_culture, 'time');
CREATE OR REPLACE FUNCTION sys.format_numeric(IN value anyelement, IN format_pattern sys.NVARCHAR,IN culture sys.VARCHAR, IN data_type sys.VARCHAR DEFAULT '', IN e_position INT DEFAULT -1) RETURNS sys.nvarchar
AS 'babelfishpg_tsql', 'format_numeric' LANGUAGE C IMMUTABLE PARALLEL UNSAFE;
GRANT EXECUTE ON FUNCTION sys.format_numeric(IN anyelement, IN sys.NVARCHAR, IN sys.VARCHAR, IN sys.VARCHAR, IN INT) TO PUBLIC;

-- === DROP format_numeric_deprecated_3_4_0
CALL sys.babelfish_drop_deprecated_object('function', 'sys', 'format_numeric_deprecated_3_4_0');

WHEN arg_type IN ('date'::regtype, 'sys.datetime'::regtype, 'sys.smalldatetime'::regtype, 'sys.datetime2'::regtype ) THEN
RETURN sys.format_datetime(arg::timestamp, p_format_pattern, p_culture);
EXCEPTION WHEN OTHERS THEN
GET STACKED DIAGNOSTICS
exception_message = MESSAGE_TEXT;
RAISE WARNING '%', exception_message;
END;
$$;

DO $$
DECLARE
exception_message text;
BEGIN
-- Rename FORMAT for dependencies
ALTER FUNCTION sys.FORMAT(anyelement, NVARCHAR, VARCHAR) RENAME TO format_deprecated_3_4_0;

CREATE OR REPLACE FUNCTION sys.FORMAT(IN arg anyelement, IN p_format_pattern sys.NVARCHAR, IN p_culture sys.VARCHAR default 'en-us')
RETURNS sys.NVARCHAR
AS
$BODY$
DECLARE
arg_type regtype;
v_temp_integer INTEGER;
BEGIN
arg_type := pg_typeof(arg);

WHEN arg_type IN ('sys.tinyint'::regtype) THEN
RETURN sys.format_numeric(arg::SMALLINT, p_format_pattern, p_culture, 'tinyint');
CASE
WHEN arg_type IN ('time'::regtype ) THEN
RETURN sys.format_datetime(arg, p_format_pattern, p_culture, 'time');

WHEN arg_type IN ('smallint'::regtype) THEN
RETURN sys.format_numeric(arg::SMALLINT, p_format_pattern, p_culture, 'smallint');
WHEN arg_type IN ('date'::regtype, 'sys.datetime'::regtype, 'sys.smalldatetime'::regtype, 'sys.datetime2'::regtype ) THEN
RETURN sys.format_datetime(arg::timestamp, p_format_pattern, p_culture);

WHEN arg_type IN ('integer'::regtype) THEN
RETURN sys.format_numeric(arg, p_format_pattern, p_culture, 'integer');
WHEN arg_type IN ('sys.tinyint'::regtype) THEN
RETURN sys.format_numeric(arg::SMALLINT, p_format_pattern, p_culture, 'tinyint');

WHEN arg_type IN ('bigint'::regtype) THEN
WHEN arg_type IN ('smallint'::regtype) THEN
RETURN sys.format_numeric(arg::SMALLINT, p_format_pattern, p_culture, 'smallint');

WHEN arg_type IN ('integer'::regtype) THEN
RETURN sys.format_numeric(arg, p_format_pattern, p_culture, 'integer');

WHEN arg_type IN ('bigint'::regtype) THEN
RETURN sys.format_numeric(arg, p_format_pattern, p_culture, 'bigint');

WHEN arg_type IN ('numeric'::regtype) THEN
RETURN sys.format_numeric(arg, p_format_pattern, p_culture, 'numeric');
WHEN arg_type IN ('numeric'::regtype) THEN
RETURN sys.format_numeric(arg, p_format_pattern, p_culture, 'numeric');

WHEN arg_type IN ('sys.decimal'::regtype) THEN
RETURN sys.format_numeric(arg::numeric, p_format_pattern, p_culture, 'numeric');
WHEN arg_type IN ('sys.decimal'::regtype) THEN
RETURN sys.format_numeric(arg::numeric, p_format_pattern, p_culture, 'numeric');

WHEN arg_type IN ('real'::regtype) THEN
IF(p_format_pattern LIKE 'R%') THEN
v_temp_integer := length(nullif((regexp_matches(arg::real::text, '(?<=\d*\.).*(?=[eE].*)')::text[])[1], ''));
ELSE v_temp_integer:= -1;
END IF;
WHEN arg_type IN ('real'::regtype) THEN
IF(p_format_pattern LIKE 'R%') THEN
v_temp_integer := length(nullif((regexp_matches(arg::real::text, '(?<=\d*\.).*(?=[eE].*)')::text[])[1], ''));
ELSE v_temp_integer:= -1;
END IF;

RETURN sys.format_numeric(arg, p_format_pattern, p_culture, 'real', v_temp_integer);
RETURN sys.format_numeric(arg, p_format_pattern, p_culture, 'real', v_temp_integer);

WHEN arg_type IN ('float'::regtype) THEN
RETURN sys.format_numeric(arg, p_format_pattern, p_culture, 'float');
WHEN arg_type IN ('float'::regtype) THEN
RETURN sys.format_numeric(arg, p_format_pattern, p_culture, 'float');

WHEN pg_typeof(arg) IN ('sys.smallmoney'::regtype, 'sys.money'::regtype) THEN
RETURN sys.format_numeric(arg::numeric, p_format_pattern, p_culture, 'numeric');
ELSE
RAISE datatype_mismatch;
END CASE;
EXCEPTION
WHEN datatype_mismatch THEN
RAISE USING MESSAGE := format('Argument data type % is invalid for argument 1 of format function.', pg_typeof(arg)),
DETAIL := 'Invalid datatype.',
HINT := 'Convert it to valid datatype and try again.';
END;
$BODY$
LANGUAGE plpgsql IMMUTABLE PARALLEL UNSAFE;
GRANT EXECUTE ON FUNCTION sys.FORMAT(IN anyelement, IN sys.NVARCHAR, IN sys.VARCHAR) TO PUBLIC;
WHEN pg_typeof(arg) IN ('sys.smallmoney'::regtype, 'sys.money'::regtype) THEN
RETURN sys.format_numeric(arg::numeric, p_format_pattern, p_culture, 'numeric');
ELSE
RAISE datatype_mismatch;
END CASE;
EXCEPTION
WHEN datatype_mismatch THEN
RAISE USING MESSAGE := format('Argument data type % is invalid for argument 1 of format function.', pg_typeof(arg)),
DETAIL := 'Invalid datatype.',
HINT := 'Convert it to valid datatype and try again.';
END;
$BODY$
LANGUAGE plpgsql IMMUTABLE PARALLEL UNSAFE;
GRANT EXECUTE ON FUNCTION sys.FORMAT(IN anyelement, IN sys.NVARCHAR, IN sys.VARCHAR) TO PUBLIC;

-- === DROP format_deprecated_3_4_0
CALL sys.babelfish_drop_deprecated_object('function', 'sys', 'format_deprecated_3_4_0');

-- === DROP deprecated functions (if exists)
CALL sys.babelfish_drop_deprecated_object('function', 'sys', 'format_datetime_deprecated_3_4_0');
CALL sys.babelfish_drop_deprecated_object('function', 'sys', 'format_numeric_deprecated_3_4_0');
CALL sys.babelfish_drop_deprecated_object('function', 'sys', 'format_deprecated_3_4_0');
EXCEPTION WHEN OTHERS THEN
GET STACKED DIAGNOSTICS
exception_message = MESSAGE_TEXT;
RAISE WARNING '%', exception_message;
END;
$$;

CREATE OR REPLACE FUNCTION sys.bbf_pivot()
RETURNS setof record
Expand Down

0 comments on commit bd1f578

Please sign in to comment.