Skip to content

Commit

Permalink
Make NEWID() and NEWSEQUENTIALID() functions VOLATILE
Browse files Browse the repository at this point in the history
Altering a table to add a column with DEFAULT NEWID() makes
the values all the same value which is not the correct bheaviour.
This is because NEWID and NEWSEQUENTIALID are both STABLE when
then should be VOLATILE.

Task: BABEL-4923
Signed-off-by: Kristian Lejao <klejao@amazon.com>
  • Loading branch information
lejaokri committed May 2, 2024
1 parent 0a6871a commit 4a7f516
Show file tree
Hide file tree
Showing 32 changed files with 1,480 additions and 44 deletions.
4 changes: 2 additions & 2 deletions contrib/babelfishpg_common/sql/uniqueidentifier.sql
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ CREATE TYPE sys.UNIQUEIDENTIFIER (
CREATE OR REPLACE FUNCTION sys.newid()
RETURNS sys.UNIQUEIDENTIFIER
AS 'uuid-ossp', 'uuid_generate_v4' -- uuid-ossp was added as dependency
LANGUAGE C STABLE STRICT PARALLEL SAFE;
LANGUAGE C VOLATILE STRICT PARALLEL SAFE;

/*
* in tsql, NEWSEQUENTIALID() produces a new unique value
Expand All @@ -47,7 +47,7 @@ LANGUAGE C STABLE STRICT PARALLEL SAFE;
CREATE OR REPLACE FUNCTION sys.NEWSEQUENTIALID()
RETURNS sys.UNIQUEIDENTIFIER
AS 'uuid-ossp', 'uuid_generate_v4'
LANGUAGE C STABLE STRICT PARALLEL SAFE;
LANGUAGE C VOLATILE STRICT PARALLEL SAFE;

CREATE FUNCTION sys.uniqueidentifiereq(sys.UNIQUEIDENTIFIER, sys.UNIQUEIDENTIFIER)
RETURNS bool
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@

SELECT set_config('search_path', 'sys, '||current_setting('search_path'), false);

ALTER FUNCTION sys.newid() VOLATILE;
ALTER FUNCTION sys.NEWSEQUENTIALID() VOLATILE;

-- Operators between int4 and numeric
-- create support function for int4 and numeric comparison
CREATE OR REPLACE FUNCTION sys.int4_numeric_cmp (int4, numeric)
Expand Down
158 changes: 156 additions & 2 deletions test/JDBC/expected/BABEL-1858.out
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
-- tsql

USE master;
GO

Expand Down Expand Up @@ -31,18 +33,50 @@ int
~~END~~


TRUNCATE TABLE newid_volatile
GO


DECLARE @i INT = 1
DECLARE @num_iter INT = 5
WHILE @i <= @num_iter
BEGIN
INSERT INTO newid_volatile VALUES (NEWSEQUENTIALID())
SET @i = @i + 1
END
-- should be equal to @num_iter
select count(distinct u) from newid_volatile
go
~~ROW COUNT: 1~~

~~ROW COUNT: 1~~

~~ROW COUNT: 1~~

~~ROW COUNT: 1~~

~~ROW COUNT: 1~~

~~START~~
int
5
~~END~~


-- test volatility of function in procedure
-- should see different id values with each iteration
CREATE PROC p_newid AS
DECLARE @num_iter INT = 5
DECLARE @i INT = 1
CREATE TABLE newid_volatile_proc (u uniqueidentifier)
CREATE TABLE newid_volatile_proc (u uniqueidentifier, v uniqueidentifier)
WHILE @i <= @num_iter
BEGIN
INSERT INTO newid_volatile_proc VALUES (NEWID())
INSERT INTO newid_volatile_proc VALUES (NEWID(), NEWSEQUENTIALID())
SET @i = @i + 1
END
go


EXEC p_newid
-- should be equal to @num_iter
select count(distinct u) from newid_volatile_proc
Expand All @@ -63,8 +97,128 @@ int
~~END~~


select count(distinct v) from newid_volatile_proc
GO
~~START~~
int
5
~~END~~


DROP TABLE newid_volatile
DROP TABLE newid_volatile_proc
DROP PROCEDURE p_newid
GO

-- Add alter table coverage
CREATE TABLE TestNewId(
id INT,
name VARCHAR(32)
)
GO

insert into TestNewId values(1, 'aaa')
insert into TestNewId values(2, 'bbb')
insert into TestNewId values(3, 'ccc')
GO
~~ROW COUNT: 1~~

~~ROW COUNT: 1~~

~~ROW COUNT: 1~~


-- should be successful
ALTER TABLE TestNewId ADD uuid UNIQUEIDENTIFIER NOT NULL DEFAULT NEWID() PRIMARY KEY;
GO

INSERT INTO TestNewId SELECT generate_series(1, 1000, 1), 'hello', NEWID()
GO
~~ROW COUNT: 1000~~


-- should be 1000+3
SELECT COUNT(DISTINCT uuid) FROM TestNewId
GO
~~START~~
int
1003
~~END~~


-- psql
ANALYZE master_dbo.TestNewId
GO

-- tsql

select set_config('babelfishpg_tsql.explain_costs', 'off', false);
GO
~~START~~
text
off
~~END~~


-- cannot use indexscan with volatile anymore
SET BABELFISH_SHOWPLAN_ALL ON
SELECT * FROM TestNewId WHERE uuid=NEWID()
GO
~~START~~
text
Query Text: SELECT * FROM TestNewId WHERE uuid=NEWID()
Seq Scan on testnewid
Filter: (uuid = newid())
~~END~~


SET BABELFISH_SHOWPLAN_ALL OFF
GO

-- Repeat with NEWSEQUENTIALID instead of NEWID
ALTER TABLE TestNewId DROP COLUMN uuid
GO

ALTER TABLE TestNewId ADD uuid UNIQUEIDENTIFIER NOT NULL DEFAULT NEWSEQUENTIALID() PRIMARY KEY;
GO

-- psql
ANALYZE master_dbo.TestNewId
GO


-- tsql
select set_config('babelfishpg_tsql.explain_costs', 'off', false);
GO
~~START~~
text
off
~~END~~


-- cannot use indexscan with volatile anymore
SET BABELFISH_SHOWPLAN_ALL ON
SELECT * FROM TestNewId WHERE uuid=NEWID()
GO
~~START~~
text
Query Text: SELECT * FROM TestNewId WHERE uuid=NEWID()
Seq Scan on testnewid
Filter: (uuid = newid())
~~END~~


SET BABELFISH_SHOWPLAN_ALL OFF
GO

-- should still be 1003
SELECT COUNT(DISTINCT uuid) FROM TestNewId
GO
~~START~~
int
1003
~~END~~


DROP TABLE TestNewId
GO
9 changes: 9 additions & 0 deletions test/JDBC/expected/newid-vu-cleanup.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@

DROP PROC babel_4923_newid_proc
DROP PROC babel_4923_newid_proc_2
GO

DROP TABLE babel_4923_newid_tab2
DROP TABLE babel_4923_newid_tab3
DROP TABLE babel_4923_newid_tab4
GO
Loading

0 comments on commit 4a7f516

Please sign in to comment.