bla*_*out 9 c mysql prepared-statement mysql-connector
我试图使用带有预准备语句的存储函数但没有取得任何成功.
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 ;
Run Code Online (Sandbox Code Playgroud)
它按预期在命令行上工作,并在SELECT语句中替换硬编码的double然后允许它按预期工作,因此周围的代码也很好.
我已经启用了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);
}
Run Code Online (Sandbox Code Playgroud)
接下来是参数和结果所需的绑定语句,然后执行:
if (mysql_stmt_execute(statement)) {
fprintf(stderr, "mysql_stmt_execute(), failed. Error:%s\n", mysql_stmt_error(statement));
}
Run Code Online (Sandbox Code Playgroud)
如前所述,如果上面的SELECT语句中的函数被硬代码浮点(例如SELECT 2.3 .....)替换,那么它会按预期返回硬编码的数字.
实际上,准备好的语句代码是使用宏插入的,有数百个语句按需要工作,因此准备,绑定或执行语法不是问题(如果上面不正确则那么我从宏中的翻译是错误的)除非与功能一起使用需要不同.
当其中一个输入绑定为输出时,这些是日志条目:
Prepare SELECT ? FROM mytable
Execute SELECT 51.36000061035156 FROM mytable
Run Code Online (Sandbox Code Playgroud)
当我尝试使用该函数时,它是日志条目:
Prepare SELECT lineDistanceC(latitude, longitude, ?, ?) FROM mytable;
Run Code Online (Sandbox Code Playgroud)
如上所述,它在没有执行语句的情况下无声地失败,在日志或其他地方没有错误.
任何线索将不胜感激.
*为了给予应有的信用,这个函数来自这里的公式
我编写了一个快速示例来测试,但无法在 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)
Run Code Online (Sandbox Code Playgroud)
然后执行以下查询会得到以下结果:
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)
Run Code Online (Sandbox Code Playgroud)
以下 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);
}
}
Run Code Online (Sandbox Code Playgroud)
编译:
gcc -o mysql_test mysql_test.c -lmysqlclient
Run Code Online (Sandbox Code Playgroud)
这是输出:
248.609129229989
222.389853289118
248.609129229989
Run Code Online (Sandbox Code Playgroud)
这与使用 mysql 命令行客户端执行的语句的输出相匹配。
您应该能够在您的系统上编译并运行它,以确定问题是否出在您对 API 的使用或其他问题上。
| 归档时间: |
|
| 查看次数: |
3535 次 |
| 最近记录: |