Create a mysql function while installing a compone

2019-06-14 10:24发布

问题:

I want to include the creation of a mysql function in my installer of a Joomla 2.5 component. This is the function:

DELIMITER $$

DROP FUNCTION IF EXISTS getDistance $$


CREATE FUNCTION `getDistance` (
    lat1 DECIMAL( 18, 12 ) ,
    lng1 DECIMAL( 18, 12 ) ,
    lat2 DECIMAL( 18, 12 ) ,
    lng2 DECIMAL( 18, 12 )
    ) 
    RETURNS DECIMAL( 18, 12 ) DETERMINISTIC 

BEGIN 
DECLARE `distance` DECIMAL( 18, 12 ) ;

SELECT ( 
    6371 * 
    acos( cos( radians( lat1 ) ) * 
    cos( radians( lat2 ) ) * 
    cos( 
        radians( lng2 ) - radians( lng1 ) ) + 
    sin( radians( lat1 ) ) * 
    sin( radians( lat2 ) ) ) )
INTO `distance`;

RETURN `distance`;

END $$

DELIMITER ;

If I login to phpmyadmin with the site user and password, the function gets created just fine.

I have tried:

  • inserting it into the .sql file that creates the tables,
  • running it from the post install script (my preferred method as I can handle errors)
  • running from a button in the admin toolbar
  • using a different delimiter: ££
  • replacing the distance identifier with #__distance

None work.

The sql file is utf8 without bom.

This is the error shown twice if I use the sql installer:

JInstaller: :Install: Error SQL DB function failed with error number 1327
Undeclared variable: distance SQL=SELECT ( 6371 * acos( cos( radians( lat1 ) ) * cos( radians( lat2 ) ) * cos( radians( lng2 ) - radians( lng1 ) ) + sin( radians( lat1 ) ) * sin( radians( lat2 ) ) ) ) INTO `distance`;
SQL =

SELECT ( 
    6371 * 
    acos( cos( radians( lat1 ) ) * 
    cos( radians( lat2 ) ) * 
    cos( 
        radians( lng2 ) - radians( lng1 ) ) + 
    sin( radians( lat1 ) ) * 
    sin( radians( lat2 ) ) ) )
INTO `distance`;

This is the error I get querying $db->getErrorMsg() if I run it from within the component's controller.

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 ££' at line 1 SQL=DELIMITER ££ DROP FUNCTION IF EXISTS getDistance ££ CREATE FUNCTION `xxyx_getDistance` ( lat1 DECIMAL( 18, 12 ) , lng1 DECIMAL( 18, 12 ) , lat2 DECIMAL( 18, 12 ) , lng2 DECIMAL( 18, 12 ) ) RETURNS DECIMAL( 18, 12 ) DETERMINISTIC BEGIN DECLARE `xxyx_distance` DECIMAL( 18, 12 ) ; SELECT ( 6371 * acos( cos( radians( lat1 ) ) * cos( radians( lat2 ) ) * cos( radians( lng2 ) - radians( lng1 ) ) + sin( radians( lat1 ) ) * sin( radians( lat2 ) ) ) ) INTO `xxyx_distance`; RETURN `xxyx_distance`; END ££ DELIMITER ;

回答1:

DELIMITER is a client construct, telling the client where the end of the statement is, rather than the server.

If you craft a string with everything from "CREATE FUNCTION" all the way through the final "END" of the function definition ... no "DELIMITER" statement and no "$$" or other symbol needed after the "END" ... and execute that string as a query against your connection object, the server should understand it. Same thing goes for "DROP FUNCTION IF EXISTS function_name", executed first.