2013-03-08 44 views
9

我正在嘗試使用存儲的函數與準備好的語句,但沒有任何成功。使用存儲的函數與C API和編寫的語句

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 = (@[email protected]) * COS((@[email protected])/2); 
SET @y = (@lat2 - @lat1); 
RETURN (SQRT((@x*@x) + (@y*@y)) * @r); 
END 
// 
delimiter ; 

它可以在命令行預期,而代以硬編碼在SELECT語句,然後允許其達到預期效果加倍,所以周圍的代碼是罰款以及。

我已經啓用CLIENT_MULTI_STATEMENTS作爲MySQL連接參數,我懷疑它只涉及到調用過程,但它是一個值得緊抓的草。


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語句被硬代碼float(例如SELECT 2.3 .....)替換,然後按照預期返回硬編碼數字。

實際上,準備好的語句代碼是使用宏插入的,有數百條語句按需要工作,所以準備,綁定或執行語法不是問題(如果上面不正確,那麼它是我從宏是錯誤的),除非它需要與函數一起使用。

這些日誌條目時的輸入之一結合作爲輸出:


Prepare SELECT ? FROM mytable 
Execute SELECT 51.36000061035156 FROM mytable 

的是日誌條目時,我試圖使用功能:


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

如上所述,它在沒有執行語句的情況下以靜默方式失敗,在日誌或其他地方沒有錯誤。

任何線索,將不勝感激。

*要給予信貸,這是因爲,這個功能是從公式here

+0

你能舉一個你怎麼稱呼它的例子嗎?當它工作和不? – ethrbunny 2013-03-11 17:51:00

+0

@ethrbunny根據要求更新 – blankabout 2013-03-11 20:45:00

+0

如果您嘗試返回一些參數,您會得到什麼結果? (IE跳過代碼並檢查輸入是否合理) – ethrbunny 2013-03-11 21:02:36

回答

2

,我設計了一個簡單的例子來測試,是無法重現MySql上66年5月1日您的問題的。查看日誌中的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​​還是其他問題。

+0

@blankabout您是否嘗試編譯並運行我的答案中的代碼?我很想知道你是否解決了問題和解決方案。 – 2013-03-20 22:19:22