问题
I am using Alembic to load a stored procedure into the MySQL database. Following the cookbook, I was able to create the required objects for creating and dropping the procedure. Now that I want to upgrade the version to actually load the procedure, I am getting SQL syntax near the DELIMITER $$
which I need for procedure definition. I have also tried to remove the DELIMITER
and replace AS
for starting the procedure, but that didn't work either. I even tried the simple example function in the cookbook, but that also gave me the same syntax error near $
.
class ReplaceableObject:
def __init__(self, name, sqltext):
self.name = name
self.sqltext = sqltext
class ReversibleOp(MigrateOperation):
def __init__(self, target):
self.target = target
@classmethod
def invoke_for_target(cls, operations, target):
op = cls(target)
return operations.invoke(op)
def reverse(self):
raise NotImplementedError()
@classmethod
def _get_object_from_version(cls, operations, ident):
version, objname = ident.split(".")
module = operations.get_context().script.get_revision(version).module
obj = getattr(module, objname)
return obj
@classmethod
def replace(cls, operations, target, replaces=None, replace_with=None):
if replaces:
old_obj = cls._get_object_from_version(operations, replaces)
drop_old = cls(old_obj).reverse()
create_new = cls(target)
elif replace_with:
old_obj = cls._get_object_from_version(operations, replace_with)
drop_old = cls(target).reverse()
create_new = cls(old_obj)
else:
raise TypeError("replaces or replace_with is required")
operations.invoke(drop_old)
operations.invoke(create_new)
@Operations.register_operation("create_sp", "invoke_for_target")
@Operations.register_operation("replace_sp", "replace")
class CreateSPOp(ReversibleOp):
def reverse(self):
return DropSPOp(self.target)
@Operations.register_operation("drop_sp", "invoke_for_target")
class DropSPOp(ReversibleOp):
def reverse(self):
return CreateSPOp(self.target)
@Operations.implementation_for(CreateSPOp)
def create_sp(operations, operation):
operations.execute(
"""
DELIMITER $$
CREATE PROCEDURE %s %s
DELIMITER ;
""" % (
operation.target.name, operation.target.sqltext
)
)
@Operations.implementation_for(DropSPOp)
def drop_sp(operations, operation):
operations.execute("DROP PROCEDURE IF EXISTS %s" % operation.target.name)
And this is how I'm trying to create it:
my_procedure = ReplaceableObject(
"my_procedure(IN arg1 TEXT, IN arg2 TEXT, OUT res TEXT)",
"""
BEGIN
-- procedure implementation
END $$
"""
)
def upgrade():
op.create_sp(my_procedure)
def downgrade():
op.drop_sp(my_procedure)
And this is the error (I'm using pymysql
as client):
sqlalchemy.exc.ProgrammingError: (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 'DELIMITER $$\n CREATE PROCEDURE my_procedure(IN arg1 TEXT, IN arg2 TEXT, OU' at line 1")
回答1:
You don't need DELIMITER
except in an environment that supports a series of semicolon-separated statements — the MySQL client.
In fact, the DELIMITER
command is a mysql client builtin, and it's not recognized by the MySQL Server.
You must not use DELIMITER
when submitting statements to the MySQL Server through an API, even if it's CREATE PROCEDURE
.
来源:https://stackoverflow.com/questions/57916385/stored-procedure-with-alembic-mysql-syntax-error