2013-03-08 16 views
9

Próbuję użyć funkcji przechowywanej z przygotowanym oświadczeniem, ale bez powodzenia.Używanie przechowywanej funkcji z API C i gotowymi instrukcjami

MySQL przygotowuje instrukcję, ale potem jej nie wykonuje, nie podano żadnego błędu, po prostu cicho zawiedzie.

Jest to funkcja *:


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 ; 

To działa w wierszu polecenia zgodnie z oczekiwaniami, i zastępując ciężko kodowana dwukrotnie w SELECT następnie pozwala jej działać zgodnie z oczekiwaniami, więc otaczający kod jest w porządku także.

Mam włączone CLIENT_MULTI_STATEMENTS jako parametr połączenia MySQL, podejrzewam, że odnosi się on tylko do procedur CALLING, ale było to słowne, które warto było ściskać.

Stwierdzenie wytwarza się stosując:


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); 
} 

przestrzeganymi przez wymagane instrukcje wiążą parametrów i wyników, a następnie wykonywane przy użyciu:


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

Jak wspomniano wcześniej, jeśli działają w powyższym Instrukcja SELECT jest zamieniana na twardy float (np. SELECT 2.3 .....), a następnie zwraca zakodowany numer zgodnie z oczekiwaniami.

W rzeczywistości kod przygotowanego oświadczenia jest wstawiany za pomocą makr, istnieje wieleset instrukcji, które działają zgodnie z wymaganiami, więc składanie instrukcji, powiązanie lub wykonywanie nie jest problemem (a jeśli jest niepoprawny powyżej, to jest to moje tłumaczenie z niepoprawne makra), chyba że musi być inny w przypadku użycia z funkcjami.

Są to wpisy dziennika, gdy jedno z wejść jest związany jako wyjście:


Prepare SELECT ? FROM mytable 
Execute SELECT 51.36000061035156 FROM mytable 

IS wpis dziennika, gdy próbuję użyć funkcji:


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

Jak wspomniano powyżej , cicho zawiedzie bez wykonywania instrukcji, bez błędów w dzienniku lub w innym miejscu.

Wszelkie wskazówki będą mile widziane.

* Aby dać kredyt w którym jest należny, funkcja ta pochodzi od formuły here

+0

Czy możesz podać przykład tego, jak to nazywasz? Zarówno gdy działa i nie działa? – ethrbunny

+0

@ethrbunny Zaktualizowany zgodnie z wymaganiami – blankabout

+0

Co otrzymasz, jeśli spróbujesz zwrócić niektóre z parametrów? (IE pomiń kod i po prostu sprawdź, czy twoje dane wejściowe są racjonalne) – ethrbunny

Odpowiedz

2

I włamał się krótki przykład, aby przetestować i nie był w stanie odtworzyć problemu na MySQL 5.1.66. Wyświetlenie w dzienniku instrukcji Prepare wskazuje, że zapytanie jest poprawne pod względem składni i że serwer jest teraz gotowy do zaakceptowania parametrów. Jeśli nie uda ci się poprawnie powiązać parametrów wejściowych, nie zobaczysz komunikatu rejestru Query.

Powinieneś prawdopodobnie jeszcze raz potwierdzić, że twoje makra powiązań generują poprawny kod C. Poniższy fragment pokazuje funkcjonujący zestaw wywołań interfejsu API, który może dostarczyć dalszych pomysłów na debugowanie. Jedyną zmianą, jaką wprowadziłem do twojej funkcji, było dodanie klauzuli DETERMINISTIC, aby uniknąć błędów przy logowaniu binarnym w moim systemie.

Począwszy tabeli tak:

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

to wykonanie następującego zapytania daje następujące wyniki:

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) 

Następujący kod C próbuje samo zapytanie, ale przy użyciu API MySql. Należy pamiętać, że zarządzanie pamięcią i prawidłowe sprawdzanie błędów nie zostało zaimplementowane.

/* 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); 
    } 

} 

skompilować z:

gcc -o mysql_test mysql_test.c -lmysqlclient 

Oto wynik:

248.609129229989 
222.389853289118 
248.609129229989 

Dopasowuje wyjście instrukcji wykonywanych za pomocą klienta wiersza poleceń mysql.

Powinieneś być w stanie skompilować i uruchomić to w swoim systemie, aby ustalić, czy problem dotyczy korzystania z API lub innego problemu.

+0

@blankabout Czy próbowałeś skompilować i uruchomić kod w mojej odpowiedzi? Byłbym zainteresowany, gdybyś rozwiązał problem i rozwiązanie. –

Powiązane problemy