Our App is developed with the following requirements
Front end: HTML and Google apps script
Back end: Google Cloud SQL,MySQL VER 5.6.21, engine= InnoDB
We are using Stored Procedures to access CLOUD SQL.
This stored procedure will be called via Google Apps Script.
Example Stored Procedure and the process of execution via Google Apps Script as below...
Step 1: Store procedure will create a user and giving grant access for store procedures, tables,triggers, views
DROP PROCEDURE IF EXISTS SP_TEST;
CREATE PROCEDURE SP_TEST(OUT SUCCESS_MESSAGE TEXT)
BEGIN
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
ROLLBACK;
SET SUCCESS_MESSAGE=0;
END;
START TRANSACTION;
SET AUTOCOMMIT = 0;
DROP USER TESTUSER;
CREATE USER 'TESTUSER'#'%' IDENTIFIED BY 'TESTUSER';
GRANT EXECUTE ON PROCEDURE PROC_NAME1 TO 'TESTUSER'#'%';
GRANT EXECUTE ON PROCEDURE PROC_NAME2 TO 'TESTUSER'#'%';
SET SUCCESS_MESSAGE=1;
COMMIT;
END;
Step 2: script used in Google apps script to call store procedure/access sql table
try
{
//OPEN CONNECTION
var conn=Jdbc.getCloudSqlConnection("jdbc:google:rdbms://" + DB_INSTANCE + "/" + DB_SCHEMA, DB_USER, DB_PASSWORD);
conn.setAutoCommit(false);
//CALL STORE PROCEDURE
var create_stmt = conn.createStatement();
create_stmt.execute("CALL SP_TEST (#SUCCESS_MESSAGE)”);
create_stmt.close();
//SELECT RESULT RETURNED FROM STORE PROCEDURE
var stmt_rolecrinsrtflag = conn.createStatement()
var flag_rolecrinsrtselect="SELECT #SUCCESS_MESSAGE";
var flag_rolecrinsrtrs=stmt_rolecrinsrtflag.executeQuery(flag_rolecrinsrtselect);
if(flag_rolecrinsrtrs.next())
var flag_rolecrinsrtinsert=flag_rolecrinsrtrs.getString("#SUCCESS_MESSAGE");
flag_rolecrinsrtrs.close();
stmt_rolecrinsrtflag.close();
conn.commit();
//CLOSE CONNECTION
conn.close();
return flag_rolecrinsrtinsert;
}
catch(err)
{
//to do rollback,if any exception..
conn.rollback();
}
We have more than 200 sp’s and 98 tables.
All the stored procedure and all tables will be loaded in Google Cloud Sql via root like user only.
After calling the Store Procedure via Google apps script , user will be created in user table and given stored procedure will be granted access for the created user.
But Sometimes we are getting the following issues when we call any store procedure/ accessing the sql table via Google Apps Script . Initially it worked well, but recently, only we are facing these issues.
Error 1:"INVALID CONNECTION ID" is thrown and the following things are
observed
TESTUSER wiped in the mysql.user table as below
Execute permission revoked for the PROC_NAME1,PROC_NAME2.
Some Store procedure which is created already has been automatically
dropped such as PROC_NAME2
cant able to proceed with the remaining execution of Apps Script
Error 2: "THIS CONNECTION IS CLOSED"
We cant able to proceed the remaining execution..
In script side if any issue/exception occurs , we need to proceed the execution, i.e., we need to drop the temp table created during the STORE PROCEDURE execution process.
Since the above issues occurs, we can't able to proceed the script execution further.
And also when we execute the store procedure, sometime we are getting issue like
Error 3: "Incorrect key file for table './mysql/procs_priv.MYI'; try to repair it"
After this issue, cant able to execute or run any Store Procedure/
access Google cloud Sql.
Pls refer the below link..
Having Result of sample Stored Procedure that is given above-Before Issue and After Issue...
https://docs.google.com/a/ssomens.com/document/d/1N5_-O2UfescCmWe9IorteUZUh7gtgkF9-RwubvF4MhM/edit
The 'jdbc:google:rdbms' way to connect is deprecated and the preferred way to connect to Cloud SQL from an external application is to use the IP connectivity via the 'jdbc:mysql' (docs).
This looks like common connection timeout due to instance inactivity (remeber that Cloud SQL has two billing plans and most users choose the per-use plan which implies that instance is not always up and running).
As a general rule-of-thumb, it's always advisable to implement some kind of exponential backoff to cope with occasional connection errors like this one, which might happen from time to time due to the already mentioned inactivity timeouts, Cloud SQL instance restarts, and possibly other unforeseen reasons.
Please read "How should I manage connections?" section [1] of the public documentation.
[1] https://cloud.google.com/sql/faq#connections
Related
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)
I have a data cleanup script that I execute in Mysql Workbench in Windows. At the beginning of the script I have:
select ##hostname;
-- WARNING: it HAS to be `srv-datatest`
(+ the rest of the script)
I want the script to stop at that line if the condition (##hostname = 'srv-datatest') is not met.
Things that I've tried:
How to throw an exception:
DECLARE invalid_database CONDITION FOR 1051;
SIGNAL invalid_database;
-- DECLARE is not accepted by my workbench, and it lacks the "if" part anyway
How to do an IF on a select:
SELECT IF(##hostname='srv-datatest','yes','no');
-- It lacks the "stop here" part
create a stored procedure that will perform your process and test.
your script in mysql workbench should only call your stored procedure
It is possible to run it without stored procedures, using this ingenious solution:
SET #hostname := (SELECT ##hostname);
SET #condition = (#hostname='srv-datatest');
SET SESSION sql_mode = if(#condition, ##SESSION.sql_mode, 'Script stopped. Check condition.');
In this code:
If #condition=1, the script will run smoothly.
If #condition=0 it will throw an exception, showing the message error.
For a Google CloudSQL 2nd generation instance, with Failover replication was enabled. After that when tried to import the database it is not allowing to create the procedure. Receiving below error.
Error Code: 1419. You do not have the SUPER privilege and binary
logging is enabled (you might want to use the less safe
log_bin_trust_function_creators variable)
Is it true that CloudSQL with failover will not support function ?
Sample execute query
DELIMITER ;;
CREATE FUNCTION `stutzen`(amount INT) RETURNS int(11)
DETERMINISTIC
BEGIN
DECLARE charges FLOAT DEFAULT 1.0;
SELECT valuesettings INTO charges FROM dreamer_tbl WHERE namesettings='stutzen.co';
RETURN FLOOR((amount / 100) * charges) ;
END ;;
DELIMITER ;
You just need to set 'log_bin_trust_function_creators' to ON
To do it, open https://console.cloud.google.com
Select SQL
Select your instance
Select EDIT
DB signals
Add:
log_bin_trust_function_creators on
general_log on
SAVE
You should run:
gcloud sql instances patch [INSTANCE_NAME] --database-flags
log_bin_trust_function_creators=ON
as mentioned here
Google Cloud SQL support both, stored procedures and functions.
In your case the problem seems to be that you're trying to import a sql file that has some kind of routine that needs the SUPER privilege, and this is not permitted.
That is not a Stored Procedure, that is a User Defined Function.
You would need to rewrite this UDF as a Stored Procedure, which would work.
I tried using the SET GLOBAL log_bin_trust_function_creators, which should allow creating functions without the SUPER privilege but setting that variable is also not allowed in Cloud SQL. It needs SUPER privilege for setting it.
Calling a stored procedure results in this exception:
SQLException1 java.sql.SQLException: User does not have access to
metadata required to determine stored procedure parameter types. If
rights can not be granted, configure connection with
"noAccessToProcedureBodies=true" to have driver generate parameters
that represent INOUT strings irregardless of actual parameter types.
To resolve this, I tried:
Connection c = DriverManager.getConnection("jdbc:mysql://localhost:3306
/database?useInformationSchema=true&noAccessToProcedureBodies=true",
"user_name", "pasword");
But it still does not work.
I am using shared hosting.
I am using
Software version: 5.0.91-community-log - MySQL Community Edition (GPL)
Protocol version: 10
Java 1.6
mysql-connector-java-5.1.14-bin.jar
One of my stored procedures is:
DROP PROCEDURE IF EXISTS `share_message`
DELIMITER //
CREATE PROCEDURE share_message(in messageid1 int(200),in received_by1 int(20),
in sent_by1 int(20),in shared_of1 int(20),author1 int(20), OUT query_status1 TINYINT)
BEGIN
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
-- ERROR
SET query_status1 = -1;
rollback;
END;
DECLARE EXIT HANDLER FOR SQLWARNING
BEGIN
-- WARNING
SET query_status1 = -1;
rollback;
END;
START TRANSACTION;
SET query_status1 = 0;
INSERT INTO post_message_users(messageid,received_by,sent_by,shared_of,author)
VALUES(messageid1,received_by1,sent_by1,shared_of1,author1);
UPDATE post_messages SET total_share=total_share+1 WHERE messageid=messageid1;
SET query_status1 =1;
COMMIT;
END//
DELIMITER ;
This is working properly with my local database.
It seems that the stored procedure you are attempting to use needs access to MySQL's INFORMATION_SCHEMA. That's a (fake) database built in every MySQL server; it's used to fetch descriptions of tables, columns, indexes, and the like.
It looks like the user id you're using doesn't have access to the INFORMATION_SCHEMA. That's understandable on a hosting service.
Go on MyPhpAdmin and try a query like this to be sure about that.
SELECT table_schema, table_name
FROM information_schema.columns
WHERE column_name = 'something'
AND table_schema = 'your database name'
If you get some kind of error saying you don't have permission, this is definitely your problem.
You could try rewriting your stored proc, or you could ask your hosting service to grant you the appropriate priv.
TLDR; Change your Java code, make the CallableStatement reference parameters by index instead of name.
After having a similar problem I updated my JDBC driver mysql-connector-java-5.1.26-bin.jar.
The error then changed from
User does not have access to metadata required to determine stored
procedure parameter types. If rights can not be granted, configure
connection with "noAccessToProcedureBodies=true" to have driver
generate parameters that represent INOUT strings irregardless of
actual parameter types.
to
No access to parameters by name when connection has been configured not to access procedure bodies
I changed my Callable Statement to reference parameters by index instead of name, and hey presto it works.
Updating the driver may not be necessary, just knowing to use indexes instead of names when you don't have metadata access or routine body access.
Good Luck
I'm dipping my toe into using stored functions with MySQL and am having trouble.
Having created a function and tested it, I don't seem to be able to allow other users to execute it. From the documentation, it seems that I need to grant EXECUTE access to the other users, but that doesn't appear to be sufficient.
I've put together a couple of scripts that I believe demonstrate the problem:
# This script creates two databases with a stored function in each.
#
# On one database, tester in granted all privileges.
# On the other, tester only gets a few.
#
# We want to find the minimum privileges required to allow tester to execute the
# stored function.
#
# This script must be run by an administrative user, i.e. root
CREATE DATABASE test1;
DELIMITER $$
CREATE FUNCTION test1.foo () RETURNS VARCHAR(255) DETERMINISTIC
BEGIN
RETURN ('garp');
END$$
DELIMITER ;
GRANT ALL PRIVILEGES ON test1.* TO 'tester'#'localhost';
#
CREATE DATABASE test2;
DELIMITER $$
CREATE FUNCTION test2.foo () RETURNS VARCHAR(255) DETERMINISTIC
BEGIN
RETURN ('garp');
END$$
DELIMITER ;
GRANT EXECUTE ON PROCEDURE test2.foo TO 'tester'#'localhost';
and
# This script tests whether tester can access the stored functions
#
# It should be executed by tester
SELECT 'test1.foo(): ', test1.foo ();
SELECT 'test2.foo(): ', test2.foo ();
When I run execute the second script, I get an error:
$ mysql --user=tester --password=tester --skip-column-names < testScript2.sql
test1.foo(): garp
ERROR 1370 (42000) at line 6: execute command denied to user 'tester'#'localhost' for routine 'test2.foo'
I have no doubt that I'm missing something obvious, but I can't see what that is. I imagine that I've got something wrong in the GRANT EXECUTE... statement in the first script, and am deeply suspicious of my use of single quotes, but I recall trying most of the combinations of placement and inclusion of single quotes without success.
I'd be really grateful to anyone who can point out my error.
For reference, I'm running Server version: 5.1.67-0ubuntu0.10.04.1 (Ubuntu) (on Ubuntu!).
Thanks
test2.foo is a function not a procedure.
Try:
GRANT EXECUTE ON FUNCTION test2.foo TO 'tester'#'localhost';
(I was able to reproduce the problem locally and confirm that this change works.)