9

我正在尝试使用带有准备好的语句的存储函数,但没有任何成功。

MySQL 准备好语句但不执行它,没有给出错误,它只是默默地失败。

这是*函数:


drop function if exists lineDistanceC;
delimiter //
CREATE FUNCTION lineDistanceC (la1 DOUBLE, lo1 DOUBLE, la2 DOUBLE, lo2 DOUBLE) RETURNS DOUBLE 
BEGIN 
SET @r = 6371;
SET @lat1 = RADIANS(la1);
SET @lon1 = RADIANS(lo1);
SET @lat2 = RADIANS(la2);
SET @lon2 = RADIANS(lo2);
SET @x = (@lon2-@lon1) * COS((@lat1+@lat2)/2);
SET @y = (@lat2 - @lat1);
RETURN (SQRT((@x*@x) + (@y*@y)) * @r);
END
//
delimiter ;

它按预期在命令行上工作,并在 SELECT 语句中替换硬编码的双精度然后允许它按预期工作,因此周围的代码也很好。

我已启用 CLIENT_MULTI_STATEMENTS 作为 MySQL 连接参数,我怀疑它仅与 CALLing 过程有关,但它是一根值得抓住的稻草。

该声明是使用以下方法准备的:


strcpy (sqlStr, "SELECT lineDistanceC(Y(pnt),X(pnt), ?, ?) FROM mytable");
MYSQL_STMT *statement;
if (mysql_stmt_prepare(statement, sqlStr, strlen(sqlStr))) {
    fprintf(stderr, "ERROR:mysql_stmt_prepare() failed. Error:%s\nsql:%s\n", mysql_stmt_error(statement), sqlStr);
}

随后是参数和结果所需的绑定语句,然后使用以下命令执行:


if (mysql_stmt_execute(statement)) {
    fprintf(stderr, "mysql_stmt_execute(), failed. Error:%s\n", mysql_stmt_error(statement));
}

如前所述,如果上述 SELECT 语句中的函数被替换为硬编码浮点数(例如 SELECT 2.3 .....),那么它将按预期返回硬编码数字。

实际上,准备好的语句代码是使用宏插入的,有数百个语句按要求工作,因此准备、绑定或执行语法不是问题(如果上面不正确,那么是我从宏中翻译的错误) 除非它需要与函数一起使用而有所不同。

这些是输入之一绑定为输出时的日志条目:


Prepare SELECT ? FROM mytable
Execute SELECT 51.36000061035156 FROM mytable

这是我尝试使用该功能时的日志条目:


Prepare SELECT lineDistanceC(latitude, longitude, ?, ?) FROM mytable;

如上所述,它在不执行语句的情况下静默失败,日志或其他地方也没有错误。

任何线索将不胜感激。

*为了给予应得的荣誉,这个函数是从这里的一个公式推导出来的

4

1 回答 1

4

我编写了一个快速示例进行测试,但无法在 MySql 5.1.66 上重现您的问题。看到Prepare日志中的语句表明查询在语法上是正确的,并且服务器现在已准备好接受参数。如果您未能正确绑定输入参数,您将看不到Query日志消息。

您可能应该再次验证您的绑定宏正在生成正确的 C 代码。下面的代码片段显示了一组功能性的 API 调用,它们可能会给你一些进一步的想法来帮助调试。我对您的函数所做的唯一更改是添加DETERMINISTIC子句以避免系统上的二进制日志记录错误。

从这样的表开始:

mysql> select * from mytable;
+----+-------+
| id | value |
+----+-------+
|  1 |     1 |
|  2 |     2 |
|  3 |     3 |
+----+-------+
3 rows in set (0.00 sec)

然后执行以下查询会给出以下结果:

mysql> SELECT lineDistanceC(1.0, 2.0, 3.0, value) FROM mytable;
+-------------------------------------+
| lineDistanceC(1.0, 2.0, 3.0, value) |
+-------------------------------------+
|                    248.609129229989 |
|                    222.389853289118 |
|                    248.609129229989 |
+-------------------------------------+
3 rows in set (0.00 sec)

以下 C 代码尝试相同的查询,但使用的是 MySql API。请注意,尚未实施内存管理和正确的错误检查。

/* mysql_test.c */

#include <string.h>
#include <stdio.h>
#include <stdlib.h>

#include <mysql.h>


int main(int argc, char * argv[])
{
    char sqlStr[300];


    MYSQL *mysql = mysql_init(NULL);
    if (mysql == NULL) {
        fprintf(stderr, "ERROR:mysql_init() failed.\n");
        exit(1);
    }

    const char* host = "localhost";
    const char* user = "root";
    const char* passwd = NULL;
    const char* db = "mysql_test";

    if (mysql_real_connect(mysql, host, user, passwd, db, 0, NULL, 0) == NULL) {
        fprintf(stderr, "ERROR:mysql_real_connect() failed.\n");
        exit(1);
    }


    MYSQL_STMT *statement = NULL;
    statement = mysql_stmt_init(mysql);
    if (statement == NULL) {
        fprintf(stderr, "ERROR:mysql_stmt_init() failed.\n");
        exit(1);
    }

    strcpy (sqlStr, "SELECT lineDistanceC(1.0, 2.0, ?, value) FROM mytable");

    if (mysql_stmt_prepare(statement, sqlStr, strlen(sqlStr))) {
        fprintf(stderr, "ERROR:mysql_stmt_prepare() failed. Error:%s\nsql:%s\n", mysql_stmt_error(statement), sqlStr);
        exit(1);
    }

    MYSQL_BIND input_bind[1];
    memset(input_bind, 0, sizeof(input_bind));
    float v1 = 3.0;
    unsigned long v1_len = sizeof(v1);

    input_bind[0].buffer_type = MYSQL_TYPE_FLOAT;
    input_bind[0].buffer = &v1;
    input_bind[0].buffer_length = sizeof(v1);
    input_bind[0].length = &v1_len;
    input_bind[0].is_null = (my_bool*)0;

    if (mysql_stmt_bind_param(statement, input_bind)) {
        fprintf(stderr, "ERROR:mysql_stmt_bind_param failed\n");
        exit(1);
    }

    if (mysql_stmt_execute(statement)) {
        fprintf(stderr, "mysql_stmt_execute(), failed. Error:%s\n", mysql_stmt_error(statement));
        exit(1);
    }

    /* Fetch result set meta information */
    MYSQL_RES* prepare_meta_result = mysql_stmt_result_metadata(statement);
    if (!prepare_meta_result)
    {
        fprintf(stderr,
                " mysql_stmt_result_metadata(), \
                returned no meta information\n");
        fprintf(stderr, " %s\n", mysql_stmt_error(statement));
        exit(1);
    }

    /* Get total columns in the query */
    int column_count= mysql_num_fields(prepare_meta_result);
    if (column_count != 1) /* validate column count */
    {
        fprintf(stderr, " invalid column count returned by MySQL\n");
        exit(1);
    }

    /* Bind single result column, expected to be a double. */
    MYSQL_BIND result_bind[1];
    memset(result_bind, 0, sizeof(result_bind));

    my_bool result_is_null[1];
    double result_double;
    unsigned long result_len = 0;

    result_bind[0].buffer_type = MYSQL_TYPE_DOUBLE;
    result_bind[0].buffer = &result_double;
    result_bind[0].buffer_length = sizeof(result_double);
    result_bind[0].length = &result_len;
    result_bind[0].is_null = &result_is_null[1];

    if (mysql_stmt_bind_result(statement, result_bind)) {
        fprintf(stderr, "mysql_stmt_bind_Result(), failed. Error:%s\n", mysql_stmt_error(statement));
        exit(1);
    }

    while (!mysql_stmt_fetch(statement)) {
        printf("%.12f\n", result_double);
    }

}

编译:

gcc -o mysql_test mysql_test.c -lmysqlclient

这是输出:

248.609129229989
222.389853289118
248.609129229989

这与使用 mysql 命令行客户端执行的语句的输出相匹配。

您应该能够在您的系统上编译和运行它,以确定问题是您使用 API 还是其他问题。

于 2013-03-18T00:07:25.313 回答