SQL alter recursive function - sql-server-2008

I'm using SQL Server 2008.
I want to execute an ALTER on a recursive function. The alter adds parameters, it seems to choke on that.
The function has no dependencies so I can safely do a DROP+CREATE, but what should be done when the function does have dependencies?
The error message is this one
Msg 8144, Level 16, State 2, Server TESTSERVER, Procedure fn_IsOwnerFunction, Line 177
Procedure or function dbo.fn_IsOwnerFunction has too many arguments specified.
The message appears a few more times, each time for a line where the function refers to itself. Note: it refers to its new version that has more parameters. After DROP+CREATE, the ALTER script works without errors.

It is ok to drop a function that is used from other functions or stored procedures.
Of course, after you drop/create the function you need to alter the functions and stored procedures that uses the function to add the new parameters.

If the error is "too many arguments specified" then your calling code is passing in too many parameters. This could mean that the ALTER FUNCTION statement you ran earlier didn't actually process fully. That could be because of a syntax error or something similar. Run the Alter statement again and check the error message there.
EDIT:
Add a DROP FUNCTION statement before your CREATE FUNCTION statement:
if exists (select * from information_schema.routines Where routine_name = 'udf_FunctionName')
drop function udf_FunctionName
GO
CREATE FUNCTION [dbo].[udf_FunctionName]
...

Related

MySQL Stored Procedure Read Replica Issue - Strange Stored Procedure/Function Behavior

UPDATE 11.15.2022
I have conducted extensive testing and found the pattern of problem here. Once again, what's strange is this ONLY happens if you pass a function as a parameter to the originating Stored Procedure; passing a hardcoded value or variable works just fine.
The issue is when the Stored Procedure calls another Stored Procedure that checks ##read_only to see if it can WRITE to the database. I confirmed removing any code that writes data fixes the issue -- so ultimately it appears passing a STATIC value to the SP causes the procedure execution to bypass any writing (as expected) because of the IF ##read_only = FALSE THEN ...write...
It seems passing a function somehow causes MySQL to compile a "tree" of calls and subcalls to see if they CAN write rather than if they DO write.
It appears the only way to work around this is to pass the parameters as variables rather than function calls. We can do this, but it will require substantial refactoring.
I just wonder why MySQL is doing this - why passing a function is causing the system to look ahead and see IF it COULD write rather than if it does.
We have a Read Replica that's up and running just fine. We can execute reads against it without a problem.
We can do this:
CALL get_table_data(1, 1, "SELECT * from PERSON where ID=1;", #out_result, #out_result_value);
And it executes fine. Note it's READS SQL DATA tagged. It does not write anything out.
We can also do this:
SELECT get_value("OBJECT_BASE", "NAME");
Which is SELECT function that is READ ONLY.
However, if we try to execute this:
CALL get_table_data(1, get_value("OBJECT_BASE", "NAME"), "SELECT * from PERSON where ID=1;", #out_result, #out_result_value);
We get the error:
Error: ER_OPTION_PREVENTS_STATEMENT: The MySQL server is running with the --read-only option so it cannot execute this statement
We're baffled at what could cause this. Both the SP and function are read-only and execute individually just fine, but the second we embed the function result in the call of the SP, the system chokes.
Any ideas?
So AWS cannot figure this out. The issue only happens when a function is passed as a parameter to a stored procedure that calls another stored procedure (not even passing the value of the function) that has a ##read_only check before doing an INSERT or UPDATE. So for some reason, the system is doing a pre-scan check when a function is passed vs. a variable or hardcoded value.
The workaround is to pass the function value as a variable.
I'm going to report this issue to Oracle as it might be some sort of bug, especially given the function is DETERMINISTIC.

Creating a procedure inside a query

I'm trying to implement a MySQL procedure (with if/else statements) inside a Granada query. The only issue is it won't let me create my procedure and call it from the same query...
ERROR
db query error: Error 1064: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'CALL tester(true)' at line 44
I'm confident the issue isn't with my syntax, but here's how the query looks:
CREATE PROCEDURE tester(
IN is_empty BOOLEAN
)
BEGIN
IF(is_empty) THEN
SELECT
...
from $dbName.table1
where KernelName IN ($KernelNameFilter) AND `gpu-id` in ($gpuFilter) AND `Index` in ($DispatchIDFilter)
union SELECT
...
from $dbName.table1
where KernelName IN ($KernelNameFilter) AND `gpu-id` in ($gpuFilter) AND `Index` in ($DispatchIDFilter)
ELSE
SELECT
...
from $dbName.table1
where KernelName IN ($KernelNameFilter) AND `gpu-id` in ($gpuFilter) AND `Index` in ($DispatchIDFilter);
END IF;
END;
CALL tester(true);
They seem to work on their own, but I have no idea why Grafana doesn't like this syntax. Any ideas?
NOTE:
Yes, it is necessary for me to create the procedure in Grafana query b/c I need to reference local Grafana variables (i.e. $KernelNameFilter, $gpuFilter, ...)
It's likely that you can't create procedure and call the procedure in a single call to the query interface. Most query interfaces do not support multi-query.
Even if the query interface supports multi-query, you can't use it to define a stored routine. Multi-query interfaces assume semicolon terminates the statement, so the first semicolon inside the body of your procedure would terminate the whole CREATE PROCEDURE statement. That's not what you want.
The MySQL client solves this by requiring you to change the statement terminator to something that doesn't appear in the body of the CREATE PROCEDURE statement. See https://dev.mysql.com/doc/refman/8.0/en/stored-programs-defining.html for details.
I need to reference local Grafana variables (i.e. $KernelNameFilter, $gpuFilter, ...)
You should make a procedure that takes your Grafana variables as parameters, and uses them in the queries within the procedure body — not create a brand new procedure each time you need to run the procedure.

How to execute a MySQL stored procedure or function in Flask-SQLAlchemy

I made a Stored Procedure with MySQLWorkbench and tested it on that platform. The Stored Procedure runs fine on MySQLWorkbench but if I run the Stored Procedure with Flask-SQLAlchemy, I don't get any error but I don't see the results in the table.
I have tried the following ways of executing a stored procedure:
db.engine.execute("CALL stored_procedure_name(%s, %s)", (parm_1, parm_2))
This results in no error, but the function doesn't give the same results (in the database) as if i run the same function (with the same parameters) as in MySQLWorkbench.
I also tried:
db.engine.execute(func.stored_procedure_name(parm_1, parm_2))
It returned that stored_procedure_name was not a function, so I also created a function that was (almost) identical to the stored procedure, and run it using the same code, but it still doesn't run the function properly and does not return an error.
So after some reading of the documentation I found the answer. I still want to keep the question, because I think it is useful for some people.
You can run a function (so not a stored procedure) with the following code
db.engine.execute(text("SELECT function_name(:parm_1, :parm_2)").execution_options(autocommit=True), :parm_1 = :parm_1, :parm_2 = :parm_2)

MYSQL Error #2014: in stored procedure when resultset is empty

I am trying to make a stored procedure in MYSQL(v5.7.21) with phpmyadmin(v4.7.9) that will sometimes return an empty result set.
CREATE DEFINER=`my_database`#`%` PROCEDURE `emptytest`(IN `_id` INT(11))
NOT DETERMINISTIC NO SQL SQL SECURITY DEFINER
select * from my_table where id=_id
and next call it with:
call emptytest(1);
this works fine when the id exists in the table:
id name
--------
1 bob
but throws an error when there are no rows to return:
call emptytest(11);
#2014 - Commands out of sync; you can't run this command now
However i would expect it to return the same as running the SQL statement:
select * from my_table where id=11
Which is an empty list:
id name
--------
I've been looking on StackOverflow for similar questions but most of them address issues with multiple queries which is not my case.
As far as I know MySQL documentation states that procedures should be able to return tables.
For the example I am showing the default options used by phpmyadmin, but i tried to tweak them to no avail.
What am I missing?
Nothing wrong with the procedure.
It is phpMyAdmin which does not handle stored procedures when executed using CALL in SQL tab.
You can run the procedure by clicking the icon in front of the procedure name in the left navigation tree.
Stored procedures tend to be 'fussier' about errors than simple statements (see below), so you need to put a handler in for that error.
DECLARE EXIT HANDLER FOR 2014 BEGIN select 'empty set' as `Error`; END;
The principle here is that you can't really handle these sort of errors in a simple query, so, from necessity, they are ignored; you can handle them in an SP, so, well, handle them...

Can we write a sql code with create function statements that all runs together at one time?

I have a piece of code (select and drop tables) where i use functions as well.
But if run function with other codes, it says:-
CREATE FUNCTION MUST BE THE ONLY STATEMENT IN THE BATCH
So can i only run the function code once and then remove it from the weekly job code (the creating and dropping of tables) ?
Or do i do something else.
This is one of the functions iam using:-
CREATE FUNCTION dbo.getyrs(#parm Integer)
RETURNS INTEGER
AS
BEGIN
RETURN #parm
END;
But if i use drop function after this it gives an error (i can't run both drop and create functions together like i can run create and drop tables)
Put GO before the CREATE FUNCTION statement.
Also put it before any other statement that creates an object.
The GO statement signifies the start of a new Batch so any time you get an error about how a certain statement needs to be the first statement in a batch, or the only statement in a batch, you can use the GO statement to separate the code into batches.
This code works for me, no errors:
Go
CREATE FUNCTION dbo.getyrs(#parm Integer)
RETURNS INTEGER
AS
BEGIN
RETURN #parm
END;
GO
DROP FUNCTION dbo.getyrs;
Why would you need to keep creating and dropping the function. Normally =you would create it once, and then call it for example like
SELECT schema.functionname(#paramatername)
Or you reference it in an outer apply or a create table etc