2013-03-08 2 views
9

Ich versuche, eine gespeicherte Funktion mit einer vorbereiteten Anweisung zu verwenden, aber keinen Erfolg.Verwenden der gespeicherten Funktion mit C-API & vorbereiteten Anweisungen

MySQL bereitet die Anweisung vor, führt sie aber nicht aus, es wird kein Fehler ausgegeben, es wird nur stillschweigend fehlgeschlagen.

Dies ist die * Funktion:


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 ; 

Es ist auf der Kommandozeile funktioniert wie erwartet, und dann ist es wie erwartet zu arbeiten, so dass der umgebende Code ist in Ordnung, erlaubt in der SELECT-Anweisung ein hartcodiert Doppel Substituieren auch.

Ich habe CLIENT_MULTI_STATEMENTS als MySQL-Verbindungsparameter aktiviert, ich vermute, dass es sich nur um CALLing-Prozeduren handelt, aber es war ein Strohhalm, den es wert ist, gepackt zu werden.

Die Anweisung wird unter Verwendung von:


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

Gefolgt von den erforderlichen Bind-Anweisungen für die Parameter und die Ergebnisse dann ausgeführt werden:


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

Wie bereits erwähnt, wenn die Funktion in den obigen SELECT-Anweisung wird durch einen harten Code-Float (zB SELECT 2.3 .....) ersetzt, dann gibt es die fest codierte Zahl wie erwartet zurück.

In der Realität wird der vorbereitete Anweisungscode mit Makros eingefügt, es gibt viele hundert Anweisungen, die wie erforderlich funktionieren, so dass die Vorbereitung, Bindung oder Ausführungssyntax nicht das Problem ist (und wenn es oben falsch ist, dann ist es meine Übersetzung aus der Makros, die falsch sind), es sei denn, sie müssen für die Verwendung mit Funktionen unterschiedlich sein.

Hier sind die Einträge Protokoll, wenn eines der Eingangssignale als die Ausgabe gebunden ist:


Prepare SELECT ? FROM mytable 
Execute SELECT 51.36000061035156 FROM mytable 

Das ist der Protokolleintrag, wenn ich die Funktion zu benutzen versuchen:


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

Wie oben erwähnt Es schlägt automatisch fehl, ohne die Anweisung auszuführen, keine Fehler im Protokoll oder an anderer Stelle.

Alle Hinweise würden geschätzt werden.

* Um Kredit zu geben, wo sie fällig ist, wurde diese Funktion aus einer Formel abgeleitete here

+0

Können Sie ein Beispiel hinzufügen, wie Sie es nennen? Sowohl wenn es funktioniert und nicht? – ethrbunny

+0

@ethrbunny Aktualisiert wie angefordert – blankabout

+0

Was erhalten Sie, wenn Sie einige Parameter zurückgeben? (IE überspringen Sie den Code und überprüfen Sie einfach, dass Ihre Eingaben sind rational) – ethrbunny

Antwort

2

ich ein kurzes Beispiel zu testen, gehackt und war nicht in der Lage das Problem auf MySql 5.1.66 zu reproduzieren. Wenn Sie die Prepare -Anweisung in Ihrem Protokoll sehen, zeigt dies an, dass die Abfrage syntaktisch korrekt ist und der Server nun bereit ist, die Parameter zu akzeptieren. Wenn Sie die Eingabeparameter nicht ordnungsgemäß binden, wird die Protokollnachricht Query nicht angezeigt.

Sie sollten wahrscheinlich erneut verifizieren, dass Ihre Bindemakros den richtigen C-Code erzeugen. Der folgende Code-Schnipsel zeigt eine funktionierende Reihe von API-Aufrufen, die Ihnen weitere Ideen zum Debuggen geben könnten. Die einzige Änderung, die ich an Ihrer Funktion vorgenommen habe, ist die DETERMINISTIC-Klausel hinzuzufügen, um Fehler bei der Binärprotokollierung auf meinem System zu vermeiden.

Beginnend mit einer Tabelle wie folgt aus:

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

Dann die folgende Abfrage Ausführung gibt diese Ergebnisse:

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) 

Der folgende C-Code versucht, die gleiche Abfrage, aber die MySql-API. Beachten Sie, dass die Speicherverwaltung und die korrekte Fehlerprüfung nicht implementiert wurden.

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

} 

Compile mit:

gcc -o mysql_test mysql_test.c -lmysqlclient 

Hier ist der Ausgang:

248.609129229989 
222.389853289118 
248.609129229989 

Dies entspricht der Ausgabe der Anweisung, um die MySQL-Kommandozeilen-Client ausgeführt werden.

Sie sollten in der Lage sein, dies zu kompilieren und auf Ihrem System auszuführen, um festzustellen, ob das Problem mit Ihrer Verwendung der API oder einem anderen Problem zusammenhängt.

+0

@blankabout Haben Sie versucht, den Code in meiner Antwort zu kompilieren und auszuführen? Ich wäre interessiert zu wissen, ob Sie das Problem und die Lösung gelöst haben. –

Verwandte Themen