Skip to content

Commit

Permalink
FETCH from CURSOR inside a function should be disabled without a dest…
Browse files Browse the repository at this point in the history
…ination (#2411)

SELECT statements included within a function cannot return data to a client. This operation was not blocked with the FETCH CURSOR operation. This commit aim to restrict defining such function.

Issues Resolved: BABEL-4584

Signed-off-by: Shard Gupta <[email protected]>
  • Loading branch information
shardgupta committed Apr 17, 2024
1 parent fdb469e commit f129c68
Show file tree
Hide file tree
Showing 3 changed files with 249 additions and 2 deletions.
6 changes: 6 additions & 0 deletions contrib/babelfishpg_tsql/src/tsqlIface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4777,6 +4777,12 @@ makeFetchCurosrStatement(TSqlParser::Fetch_cursorContext *ctx)
auto targetText = ::getFullText(ctx->cursor_name());
result->curvar = lookup_cursor_variable(targetText.c_str())->dno;

/* FETCH CURSOR without destination should be blocked inside a function. */

if (is_compiling_create_function() && !ctx->INTO())
{
throw PGErrorWrapperException(ERROR, ERRCODE_INVALID_FUNCTION_DEFINITION, "SELECT statements included within a function cannot return data to a client.", getLineAndPos(ctx));
}
/* fetch option */
if (ctx->NEXT()) {
result->direction = FETCH_FORWARD;
Expand Down
131 changes: 130 additions & 1 deletion test/JDBC/expected/BABEL-2218.out
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,12 @@ go

CREATE TABLE t2218(c1 INT)
INSERT INTO t2218 VALUES (2218);
INSERT INTO t2218 VALUES (2219);
GO
~~ROW COUNT: 1~~

~~ROW COUNT: 1~~


-- should throw an error
CREATE FUNCTION f2218()
Expand Down Expand Up @@ -42,10 +45,136 @@ DECLARE @ret INT;
SET @ret = f2218();
SELECT @ret;
DROP FUNCTION f2218;
DROP TABLE t2218;
GO
~~START~~
int
2219
~~END~~


-- Throw error if cursor for select doesn't have a destination(INTO @variable) inside a function BABEL-4586
CREATE FUNCTION f_getval()RETURNS INTEGER
AS
BEGIN
DECLARE temp_cursor CURSOR FOR SELECT c1 FROM t2218
OPEN temp_cursor
FETCH NEXT FROM temp_cursor
CLOSE temp_cursor
RETURN 1
END
go
~~ERROR (Code: 33557097)~~

~~ERROR (Message: SELECT statements included within a function cannot return data to a client.)~~


-- cursor for select work if the destination(INTO @variable) is provided inside a function BABEL-4586
CREATE FUNCTION f_getval() RETURNS INTEGER
AS
BEGIN
DECLARE @my_var int
DECLARE temp_cursor CURSOR FOR SELECT c1 FROM t2218
OPEN temp_cursor
FETCH NEXT FROM temp_cursor INTO @my_var
CLOSE temp_cursor
RETURN @my_var
END
go

DROP FUNCTION f_getval;
GO

-- cursor for select work with multiple fetch if the destination(INTO @variable) is provided inside a function BABEL-4586
CREATE FUNCTION f_getval() RETURNS INTEGER
AS
BEGIN
DECLARE @my_var int
DECLARE temp_cursor CURSOR FOR SELECT c1 FROM t2218
OPEN temp_cursor
FETCH NEXT FROM temp_cursor INTO @my_var
FETCH NEXT FROM temp_cursor INTO @my_var
CLOSE temp_cursor
RETURN @my_var
END
go

DROP FUNCTION f_getval;
GO

-- cursor for select should throw error even if one fetch tries to return results to client
CREATE FUNCTION f_getval() RETURNS INTEGER
AS
BEGIN
DECLARE @my_var int
DECLARE temp_cursor CURSOR FOR SELECT c1 FROM t2218
OPEN temp_cursor
FETCH NEXT FROM temp_cursor INTO @my_var
FETCH NEXT FROM temp_cursor
CLOSE temp_cursor
RETURN @my_var
END
GO
~~ERROR (Code: 33557097)~~

~~ERROR (Message: SELECT statements included within a function cannot return data to a client.)~~


-- cursor for select should work for procedure
CREATE PROCEDURE proc_with_cursor_fetch
AS
BEGIN
DECLARE temp_cursor CURSOR FOR SELECT c1 FROM t2218
OPEN temp_cursor
FETCH NEXT FROM temp_cursor
CLOSE temp_cursor
END
GO

DROP PROCEDURE proc_with_cursor_fetch;
GO

-- cursor for select should work for procedure with INTO
CREATE PROCEDURE proc_with_cursor_fetch
AS
BEGIN
DECLARE temp_cursor CURSOR FOR SELECT c1 FROM t2218
DECLARE @my_var int
OPEN temp_cursor
FETCH NEXT FROM temp_cursor INTO @my_var
CLOSE temp_cursor
END
GO

DROP PROCEDURE proc_with_cursor_fetch;
GO

CREATE TRIGGER trg1 ON t2218 AFTER INSERT AS
DECLARE temp_cursor CURSOR FOR SELECT c1 FROM t2218
DECLARE @my_var int
OPEN temp_cursor
FETCH NEXT FROM temp_cursor INTO @my_var
CLOSE temp_cursor
GO

CREATE TRIGGER trg2 ON t2218 AFTER INSERT AS
DECLARE temp_cursor1 CURSOR FOR SELECT c1 FROM t2218
OPEN temp_cursor1
FETCH NEXT FROM temp_cursor1
CLOSE temp_cursor1
GO

-- Trigger after insert
INSERT INTO t2218 VALUES (2218);
GO
~~START~~
int
2218
~~END~~

~~ROW COUNT: 1~~


DROP TRIGGER trg1
DROP TRIGGER trg2
DROP TABLE t2218
GO
114 changes: 113 additions & 1 deletion test/JDBC/input/BABEL-2218.sql
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ go

CREATE TABLE t2218(c1 INT)
INSERT INTO t2218 VALUES (2218);
INSERT INTO t2218 VALUES (2219);
GO

-- should throw an error
Expand Down Expand Up @@ -36,5 +37,116 @@ SET @ret = f2218();
SELECT @ret;

DROP FUNCTION f2218;
DROP TABLE t2218;
GO

-- Throw error if cursor for select doesn't have a destination(INTO @variable) inside a function BABEL-4586
CREATE FUNCTION f_getval()RETURNS INTEGER
AS
BEGIN
DECLARE temp_cursor CURSOR FOR SELECT c1 FROM t2218
OPEN temp_cursor
FETCH NEXT FROM temp_cursor
CLOSE temp_cursor
RETURN 1
END
go

-- cursor for select work if the destination(INTO @variable) is provided inside a function BABEL-4586
CREATE FUNCTION f_getval() RETURNS INTEGER
AS
BEGIN
DECLARE @my_var int
DECLARE temp_cursor CURSOR FOR SELECT c1 FROM t2218
OPEN temp_cursor
FETCH NEXT FROM temp_cursor INTO @my_var
CLOSE temp_cursor
RETURN @my_var
END
go

DROP FUNCTION f_getval;
GO

-- cursor for select work with multiple fetch if the destination(INTO @variable) is provided inside a function BABEL-4586
CREATE FUNCTION f_getval() RETURNS INTEGER
AS
BEGIN
DECLARE @my_var int
DECLARE temp_cursor CURSOR FOR SELECT c1 FROM t2218
OPEN temp_cursor
FETCH NEXT FROM temp_cursor INTO @my_var
FETCH NEXT FROM temp_cursor INTO @my_var
CLOSE temp_cursor
RETURN @my_var
END
go

DROP FUNCTION f_getval;
GO

-- cursor for select should throw error even if one fetch tries to return results to client
CREATE FUNCTION f_getval() RETURNS INTEGER
AS
BEGIN
DECLARE @my_var int
DECLARE temp_cursor CURSOR FOR SELECT c1 FROM t2218
OPEN temp_cursor
FETCH NEXT FROM temp_cursor INTO @my_var
FETCH NEXT FROM temp_cursor
CLOSE temp_cursor
RETURN @my_var
END
GO

-- cursor for select should work for procedure
CREATE PROCEDURE proc_with_cursor_fetch
AS
BEGIN
DECLARE temp_cursor CURSOR FOR SELECT c1 FROM t2218
OPEN temp_cursor
FETCH NEXT FROM temp_cursor
CLOSE temp_cursor
END
GO

DROP PROCEDURE proc_with_cursor_fetch;
GO

-- cursor for select should work for procedure with INTO
CREATE PROCEDURE proc_with_cursor_fetch
AS
BEGIN
DECLARE temp_cursor CURSOR FOR SELECT c1 FROM t2218
DECLARE @my_var int
OPEN temp_cursor
FETCH NEXT FROM temp_cursor INTO @my_var
CLOSE temp_cursor
END
GO

DROP PROCEDURE proc_with_cursor_fetch;
GO

CREATE TRIGGER trg1 ON t2218 AFTER INSERT AS
DECLARE temp_cursor CURSOR FOR SELECT c1 FROM t2218
DECLARE @my_var int
OPEN temp_cursor
FETCH NEXT FROM temp_cursor INTO @my_var
CLOSE temp_cursor
GO

CREATE TRIGGER trg2 ON t2218 AFTER INSERT AS
DECLARE temp_cursor1 CURSOR FOR SELECT c1 FROM t2218
OPEN temp_cursor1
FETCH NEXT FROM temp_cursor1
CLOSE temp_cursor1
GO

-- Trigger after insert
INSERT INTO t2218 VALUES (2218);
GO

DROP TRIGGER trg1
DROP TRIGGER trg2
DROP TABLE t2218
GO

0 comments on commit f129c68

Please sign in to comment.