cannot insert datetime field with stored procedure into mysql database - mysql

I am getting this syntax error when trying to insert a datetime into mysql database.
pymysql.err.ProgrammingError: (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 '00:00:01)' at line 1")
I am using pymysql and flask-mysql. This is my code:
cursor.execute("""DROP TABLE IF EXISTS test_table_2;""")
cursor.execute("""DROP PROCEDURE IF EXISTS updateTestProc2;""")
testTable = """CREATE TABLE IF NOT EXISTS test_table_2 (
time DATETIME,
PRIMARY KEY (time)
);
"""
testProc = """
CREATE PROCEDURE updateTestProc2(
IN ptime DATETIME
)
BEGIN
SET #queryStr = CONCAT('INSERT INTO test_table_2(time) VALUES ( ',
ptime,
')
;'
);
PREPARE query FROM #queryStr;
EXECUTE query;
DEALLOCATE PREPARE query;
END
"""
cursor.execute(testTable)
cursor.execute(testProc)
proc_input = ('1990-05-23 00:00:01',)
cursor.callproc('updateTestProc2', proc_input)

Do not use string concatenation to get values into statement. That's error prone and might make your program vulnerable to SQL injection attacks. Use parameters. Change your procedure's code to:
...
SET #queryStr = 'INSERT INTO test_table_2 (time) VALUES (?)';
PREPARE query FROM #queryStr;
EXECUTE query USING ptime;
DEALLOCATE PREPARE query;
...
? is a parameter placeholder that is replaced with the value of the expression you pass with USING when you do EXECUTE. That way don't need to care about escaping, quoting etc. and can't do it wrong.

Related

Error Executing This Mysql Sp For Make Refresh Of The Fields Saved In Log Table Through Trigger But I Don't See The Error

This sp generate this Error but when I get the #queryString value and execute it, It's working:
Query 1 ERROR: 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 'CREATE TRIGGER triggers_after_insert AFTER INSERT ON mydb.mytable F' at line 2
This error is generated when I execute:
CALL prcTriggersLogsRefreshFields('mydb','mytable','myidtable');
This is the code:
DROP PROCEDURE "prcTriggersLogsRefreshFields";
CREATE PROCEDURE "prcTriggersLogsRefreshFields"(
par_dbName text,
par_tableName text,
par_keyField text
)
BEGIN
SET #strJsonObj = null;
SET #change_object = par_dbName||'.'||par_tableName;
SELECT GROUP_CONCAT('\'',COLUMN_NAME, '\',', COLUMN_NAME) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = par_dbName AND TABLE_NAME = par_tableName INTO #strJsonObj;
SET #queryString = 'DROP TRIGGER `triggers_after_insert`;
CREATE TRIGGER `triggers_after_insert` AFTER INSERT ON `'||par_dbName||'`.`'||par_tableName||'` FOR EACH ROW BEGIN
SELECT JSON_ARRAYAGG(JSON_OBJECT('||#strJsonObj||')) change_obj FROM `'||par_dbName||'`.`'||par_tableName||'` WHERE '||par_keyField||'=New.'||par_keyField||' INTO #jsonRow;
INSERT INTO mylog_db.table_log (`change_id`, `change_date`, `db_name`, `table_name`, `change_object`, `change_event_name`, `previous_content`, `change_content`, `change_user`) VALUES (DEFAULT, NOW(), '''||par_dbName||''', '''||par_tableName||''', '''||#change_object||''', \'insert\', \'{}\', #jsonRow, New.user_created);
END;';
-- select #queryString;
PREPARE stmt FROM #queryString;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END;
https://dev.mysql.com/doc/refman/8.0/en/sql-prepared-statements.html says:
SQL syntax for prepared statements does not support multi-statements (that is, multiple statements within a single string separated by ; characters).
You have to run the statements one at a time if you use PREPARE.
There's no need to include the DROP TRIGGER in your prepared statement. You can run the DROP TRIGGER without prepare & execute, since there is no dynamic part in it. Then format the CREATE TRIGGER as a single statement and prepare and execute it.

How do I call stored procedure with JSON parameter in MySQL?

Here is the stored procedure and it's call
Stored Procedure (test)
BEGIN
DECLARE Query1 VARCHAR(500);
...
...
SET #Query1 = CONCAT('INSERT INTO tblName (col1, col2) values("',v_value1,'","',v_value2,'")'
);
PREPARE
stmt
FROM
#Query1;
EXECUTE
stmt;
Stored Procedure Call to test
CALL test( "abc",'{"pqr":true,"xyz":false}' );
When I try below then it's working fine but it's not working when I try to give parameters with above double quotes
CALL test( "abc","{'pqr':true,'xyz':false}" ); //Working fine
Error
1064 - You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use
near 'pqr":true,"xyz":false'
Even if it's a late answer...
It has to do with the way MySQL handles quotes
Whenever you include something into single quotes MySQL is going to treat it as a string.
For example:
"1" - could be treated as an integer if it is inserted into integer
field...
But
'1' - is going to be treated as a string no matter what.

MySQL SQL syntax error near '0' at line 1

I have tried various modifications to make this work but I can't seem to remove the error. My SQLQuery string is much larger than the one below but same set up. I tried using a CONCAT(' ') statement but had issues. So I tried using this format but still receive the same error. any suggestions?
CREATE DEFINER=`root`#`%` PROCEDURE `stp_Select_GetTbl`(IN strWhereClause
VARCHAR(255))
BEGIN
DECLARE SQLQuery varchar(1000);
SET SQLQuery = '
SELECT `Part Num` AS `PPNumber`,
`Shop Num` as `SOrder`
FROM `track`.`s list` WHERE ';
SET #SQLQuery = #SQLQuery + strWhereClause + '';
PREPARE stmt FROM #SQLQuery;
EXECUTE stmt;
END
ERROR:
`Error Code: 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 '0' at line 1
`
I have tried not declaring SQLQuery... changing varchar size... reorganizing and even using the example below
SET #getList =
CONCAT('SELECT (t1, t2, t3) FROM (SELECT t1, t2, t3) as mainSelect WHERE ', strWhereClause, '');
PREPARE stmt FROM #getList;
EXECUTE stmt;
END
but get error at
.... MySQL server version for the right syntax to use near '0
I need to define a string for my SELECT statement because I create the WHERE clause in my stored procedure.

Mysql insert from stored procedure gives error 1064

For some strange reason, inserting from stored procedure is not working.
This is what Im trying to do:
DROP TABLE IF EXISTS test;
CREATE TABLE IF NOT EXISTS test(
id INT(9) NOT NULL AUTO_INCREMENT
,name VARCHAR(30) NOT NULL
,PRIMARY KEY (id)
) DEFAULT CHARSET=utf8;
insert into test (name) values('A');
Inserting from command line works with no problems.
Then I created a stored procedure to do the same kind of insert:
DROP PROCEDURE IF EXISTS storedtest;
DELIMITER $$
CREATE PROCEDURE storedtest()
BEGIN
declare insert_sql varchar(200);
SET insert_sql = 'insert into test (name) values(3)';
SELECT insert_sql;
PREPARE mystm FROM #insert_sql;
EXECUTE mystm;
END$$
DELIMITER ;
call storedtest();
This gives me the error:
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'NULL' at line 1
NULL? Where did NULL came from?
I also tried changing the sql-insert to look like this (dont know if it is a good way):
SET insert_sql = "insert into test (name) values('3')";
But mysql gives me exactly the same error.
Anyone has a clue?
The NULL MySQL is reporting is an empty user variable #insert_sql, which is different from the local stored procedure local variable insert_sql which you allocated with DECLARE.
MySQL's DECLARE is used for variables local to a stored program, but according to the documentation, PREPARE stmt FROM ... expects either a string literal or a user variable, which are the type preceded with #.
PREPARE stmt_name FROM preparable_stmt
preparable_stmt is either a string literal or a user variable that contains the text of the SQL statement.
You can allocate the untyped user variable with SET so there is no need for DECLARE. You may wish to set it to NULL when you're finished.
DROP PROCEDURE IF EXISTS storedtest;
DELIMITER $$
CREATE PROCEDURE storedtest()
BEGIN
-- Just SET the user variable
SET #insert_sql = 'insert into test (name) VALUES (3)';
SELECT #insert_sql;
-- Prepare & execute
PREPARE mystm FROM #insert_sql;
EXECUTE mystm;
-- Deallocate the statement and set the var to NULL
DEALLOCATE PREPARE mystm;
SET #insert_sql = NULL;
END$$
DELIMITER ;

How to write a mysql function with dynamic table name?

I'm trying to write a my sql function doing the following things:
1- get the table name used in join as a parameter.
but I get mysql syntax 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 'table DETERMINISTIC
BEGIN select `r`.`id` AS `id`, (case ' at line 2
This is my query
DELIMITER $$
CREATE FUNCTION getTranslation (tablename varchar(50),entity varchar(20),itemid int,lang char(3))
RETURNS table
DETERMINISTIC
BEGIN
select
`r`.`id` AS `id`,
(case
when isnull(`t`.`descr`) then `r`.`descr_ml`
else `t`.`descr`
end) AS `descr`
from
(tablename `r`
left join `g001_translation` `t` ON ((`t`.`item_id` = `r`.`id`)))
END$$
DELIMITER ;
I the select part works fine with static table name by the way.
First up as mentioned by #eggyal this isn't the best way to go about things. But it can be done by using prepared statements. I.e.
DROP PROCEDURE IF EXISTS `exampleOfPrepareStatement`;
CREATE DEFINER = `user`#`%` PROCEDURE `exampleOfPrepareStatement`(inTableName VARCHAR(100))
MODIFIES SQL DATA
SQL SECURITY INVOKER
BEGIN
SET #hr1 = CONCAT('
INSERT INTO `',inTableName,'` (
-- fields (can use parameters same as table name if needed)
)
-- either VALUES () or SELECT here
');
-- Prepare, execute, deallocate
PREPARE hrStmt1 FROM #hr1;
EXECUTE hrStmt1;
DEALLOCATE PREPARE hrStmt1;
END;
You can of course add in field names etc. as needed, or use a SELECT or UPDATE etc. This is not ideal, but will do what you are looking for.
I have had to use this in some places before where the same maintenance is being performed on multiple tables which have different field names ( / table names ) and so instead of writing the same function 20 times, instead I use this type of stored procedure which can then be called to do the indexing etc.
As also mentioned by #eggyal , while this may do as you ask, it might not do as you need. If you can provide more information then you may get a better solution.
Give this a try
SET #ex = CONCAT('select `r`.`id` AS `id`,(case when isnull(`t`.`descr`) then `r`.`descr_ml` else `t`.`descr` end) AS `descr` from (',tablename,' `r` left join `g001_translation` `t` ON ((`t`.`item_id` = `r`.`id`)));');
PREPARE stmt FROM #ex;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
You will notice that ',tablename,' will use the parameter passed.