What does SELECT ... PROCEDURE procedure_name do? - mysql

In reading through the documentation, I noticed that MySQL's SELECT syntax has a clause that I had never really caught before:
SELECT
...
[PROCEDURE procedure_name(argument_list)]
...
I am intrigued, since from what little I could understand from their terse explanation and their example with PROCEDURE ANALYSE, one can pass data (and possibly metadata as well?) from a SELECT statement into a stored procedure. However, searching elsewhere for more details didn't yield any results, and the source for the ANALYSE procedure proved elusive to SHOW PROCEDURE calls in every database.
I ask more out of curiosity, since I know nothing about it, but what is this clause for, and what can I do with it?

Here is an explanation by
Morgan Tocker (MySQL Community Manager)
http://www.tocker.ca/2015/06/29/plan-to-deprecate-procedure-analyse.html

Related

Stored procedure returning values: bug, artefact, undocumented feature?

I couldn't help noticing that stored procedures are able to return values:
create table foo(foo int);
insert into foo values (42);
create procedure get_foo() select * from foo;
call get_foo();
+------+
| foo |
+------+
| 42 |
+------+
More intriguing, wrapper such as python's MySQLdb do pass through the procedure's output to the caller.
However, no such behavior is documented. The documented way to get results out of the procedure is using OUT procedure arguments. I find this return value of stored procedure hardly used or indeed mentioned anywhere, yet it seems to be a useful behavior.
My question is, is this an artifact of stored procedures, or is it implemented on purpose but undocumented for some reason? How long has it been so, and can one rely on it?
(I tested on MariaDB 10.3 and don't know how this extends to MySQL as well).
This is the way stored procedures are designed to work in MySQL, since they were introduced circa 2005.
https://dev.mysql.com/doc/refman/8.0/en/stored-routines-syntax.html
MySQL supports a very useful extension that enables the use of regular SELECT statements (that is, without using cursors or local variables) inside a stored procedure. The result set of such a query is simply sent directly to the client. Multiple SELECT statements generate multiple result sets, so the client must use a MySQL client library that supports multiple result sets.
I couldn't find a similar statement in the MariaDB documentation on stored procedures. I can't explain why they didn't choose to document this feature. As far as I know, they have not changed it since they forked from MySQL in 2010.
Since the first implementation (afaik it was in MySQL 5.0, written by Per Erik Martin), stored procedures in MariaDB/MySQL were able to return result sets.
It is very well documented in both MySQL and MariaDB documentation which kind of SQL statements are not supported.
Please also note, that not only a SELECT but also an INSERT might return a result set.

Having a hard time creating a procedure in SQL

I need to create a procedure for class, but I think the sql version in the book is VERY old. For example, I don't think I can't use "Create or replace" like the book says, but "create", "drop", "create", but that is beyond the scope.
My issue is that I am having trouble setting the %TYPE. I use WAMP, I created the procedure in Notepad++, and pasted it to the console. I then opened up phpmyadmin, pasted it into the query window, and was rewarded with more verbose error message. Book: "A guide to SQL" by Phil Pratt and Mary Last, Ninth Edition https://www.amazon.com/Guide-SQL-Philip-J-Pratt/dp/111152727X . Book has TAL Distributers, SOLARIS comdominium group, and COLONIAL adventure tours databases it that helps anyone. The instructor provided the sql file to create the databases as a time saver. This is for the last chapter, ch.8 Creation code:
delimiter ;;
use tal;;
CREATE PROCEDURE CHANGE_ITEM_PRICE(I_ITEM_NUM IN item.item_num%TYPE, I_NEW_PRICE IN item.price%TYPE) AS
BEGIN
UPDATE item SET price = I_NEW_PRICE
WHERE item_num = I_ITEM_NUM;
END;;
delimiter ;
2 Errors:
Unrecognized data type. (near "IN" at position 56)
and another for position 91.
Any thoughts? I'm not looking to be spoon fed here, I just need a little guidance please.
Edit: Thank you #Bill Karwin. The corrected working syntax follows:
delimiter ;;
use tal;;
CREATE PROCEDURE CHANGE_ITEM_PRICE(IN I_ITEM_NUM char(4), IN I_NEW_PRICE decimal(6,2))
BEGIN
UPDATE item SET price = I_NEW_PRICE
WHERE item_num = I_ITEM_NUM;
END;;
delimiter ;
I_ITEM_NUM IN item.item_num%TYPE
This is not a valid procedure argument declaration for MySQL. You have to name the type with something like INT or DATE or VARCHAR(length) or another known type. MySQL has no syntax like you show to dynamically query the type of a named column.
Out of curiosity, where did you get that syntax? Is it part of some other brand of SQL database? I've never seen it before.
Aha, I found it:
https://www.postgresql.org/docs/current/static/sql-createfunction.html says:
The type of a column is referenced by writing table_name.column_name%TYPE. Using this feature can sometimes help make a function independent of changes to the definition of a table.
That's in the PostgreSQL documentation. PostgreSQL and MySQL are not the same software, and there are many examples of syntax and features that each has that the other does not.
This syntax is also supported by Oracle: %TYPE attribute. Actually, I assume Oracle did it before PostgreSQL.
Re your comment:
var IN char(4)" does not work either
You said you were interested in a little guidance. The simplest guidance is that when you're learning a new syntax, it helps to read the reference documentation. :-)
I've used MySQL a lot over the past 16 years. I am a regular speaker at MySQL Conferences and users' groups. I'm a published author. And even I open the documentation pages as a first step when I'm doing something that isn't immediately familiar to me.
Here: http://dev.mysql.com/doc/refman/5.7/en/create-procedure.html
Notice when declaring procedure parameters, it's IN param_name type, not param_name IN type.
now the error is "syntax near ' AS....'
Again, refer to the documentation. There's no AS in the stored procedure syntax for MySQL. That's also Oracle syntax.
You may need to get a different book if you're going to use MySQL instead of Oracle. For example, I suggest MySQL Stored Procedure Programming: Building High-Performance Web Applications in MySQL.
But honestly, I am not a fan of using stored procedures in MySQL at all. MySQL's implementation of stored procedures is far inferior to that of Oracle. MySQL procedures have no packages or libraries, there's no procedure debugger, they're not compiled, and they don't scale well.
Most developers who use MySQL put more logic in their application code instead of stored procedures. This allows them to scale out their performance to numerous application servers, instead of piling up the load on the database server.
I don't believe MySQL has an equivalent for Oracle's %TYPE operator. You will need to specify the data types directly, for example:
CREATE PROCEDURE CHANGE_ITEM_PRICE(I_ITEM_NUM INT, I_NEW_PRICE DECIMAL) ...
I checked through the function and operator list in the most recent MySQL manual to see if they have recently added this function, but did not find it there.

Why is SELECT..PROCEDURE a MySQL syntax error? [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
I want to run a MySQL query and then process all the result sets. The MySQL
5.7 documentation says that the way to do is to use SELECT ... PROCEDURE
stored_procedure_name(parameters). I created a stored procedure that does what I want without any problems. I used it in a SELECT ... PROCEDURE query and got this syntax error:
ComposeStatement (identifier) is not valid at this position
(where ComposeStatement is the name of my stored procedure). I checked I have the proper number of parameters and they are of the proper type. Using a
different procedure gives the same error (with the obvious change in name).
The documentation shows an example of this syntax using a procedure called
ANALYSE (which I understand from another post is now deprecated, but I really don't care about using ANALYSE specifically). When I tried the example I get the same error, with ANALYSE as the identifier. The errors I'm getting are
not in the procedures themselves, which is why many earlier posts don't apply.
Any suggestions? The SELECT..PROCEDURE construct sounds like it's exactly
what I need.
The MySQL feature #LarryGriffith references has nothing to do with stored procedures.
It's related to this deprecated feature: https://dev.mysql.com/doc/refman/5.7/en/procedure-analyse.html
SELECT col1, col2 FROM table1 PROCEDURE ANALYSE(10, 2000);
This use of the PROCEDURE query modifier is like putting a filter function on the result set from a query. It's analogous to a pipeline in the shell:
ls | grep myfile
The thing is, the "procedure" you use (ANALYSE() in the example) is not a stored procedure of the type you can write with CREATE PROCEDURE.
You would have to code the filtering function in C++ and compile it with the MySQL source.
The ANALYZE() example was originally meant as a proof of concept or example that developers could follow if they wanted to develop their own query filters. But I've never heard of anyone who actually did create a query filter of their own.
Last year it was announced that the SELECT ... PROCEDURE ANALYZE() feature was intended to be deprecated in MySQL 8. http://www.tocker.ca/2015/06/29/plan-to-deprecate-procedure-analyse.html
If you need to post-filter a query result, it's far easier to write a script (in Python or whatever your favorite language is), which fetches the raw data from the query result, and then does whatever you need to do with it.

Stored Procedure slow from Entity Framework because of date parameter

I have discovered an interesting issue where a Stored Procedure executes very slowly from Entity Framework. I have already solved the problem, but I would like to hear if anyone can tell me why the solution works.
Issue
I have a Stored Procedure GetLoginCount that receives a #date parameter of type DATETIME. When I execute this Stored Procedure directly on the database it executes within a second. When executing through my application via Entity Framework, it takes around 45 seconds.
I have tried using WITH RECOMPILE on the Stored Procedure and cleared execution plans on the server, to ensure it hadn't cached some slow version of the execution plan that didn't use the correct index.
Fast forward after 2 days of experiments, I found that if I simply put the following in the beginning of my Stored Procedure: DECLARE #date1 DATETIME = #date and use #date1 instead, the Stored Procedure executes in 1 second, also from Entity Framework.
WHY?
I have solved my problem and that's all good and fine, but I need to know why this specific solution works.
Martin Smith gave the correct answer in a comment, but as he hasn't put it as an answer, I'm inserting it here, so I can correctly mark the question as answered:
"Assigning to a variable and using the variable disables parameter sniffing. i.e. SQL Server no longer has a specific date it can look up in the statistics to get selectivity estimates and just guesses as per OPTIMIZE FOR UNKNOWN"
Using OPTIMIZE FOR UNKNOWN indeed solves the problem.

Can stored procedure in MySql 5.0.x be encrypted?

In Microsoft Sql it is possible to encrypted stored procedures with
CREATE PROCEDURE dbo.foo
WITH ENCRYPTION
AS
BEGIN
SELECT 'foo'
END
This stops people looking at stored procedures code.
How can I do this in MySql 5.0.x ?
You can not do this in MySQL. See bug #4210.
[Edit]: The comment from Leonidas on another answer to this question needs to be out there for anyone to read, so I'm quoting it here:
Obfuscation can be reversed. I found
at least one product via Google, that
promises to reveal the SP-code. So I
think/hope that the MySQL-team won't
bother with "security by obscurity" or
even worse "intellectual asset
protection" (as described in the bug
4210).
It looks like its been requested before but I don't know if they're considering it.