2010-10-25 4 views
9

nach Stunden von Dokumentationen/Boards/Mailinglisten und keine Fortschritte Ich kann Sie fragen: Wie kann ich meine Daten 'codieren', um es für den binären Transport mit libpq PQexecParams(.) zu verwenden?PostgreSQLs libpq: Kodierung für den binären Transport von ARRAY [] - Daten?

Einfache Variablen sind nur in Big-Endian-Reihenfolge:

PGconn *conn; 
PGresult *res; 
char *paramValues[1]; 
int paramLengths[1]; 
int paramFormats[1]; 

conn = PQconnectdb(CONNINFO); 

// -- (1) -- send a float value 
float val_f = 0.123456789; // float precision: ~7 decimal digits 
// alloc some memory & write float (in big endian) into 
paramValues[0] = (char *) malloc(sizeof(val_f)); 
*((uint32_t*) paramValues[0]) = htobe32(*((uint32_t*) &val_f)); // host to big endian 

paramLengths[0] = sizeof(val_f); 
paramFormats[0] = 1; // binary 

res = PQexecParams(conn, "SELECT $1::real ;", // 
     1, // number parameters 
     NULL, // let the backend deduce param type 
     paramValues, // 
     paramLengths, // 
     paramFormats, // 
     0); // return text 
printf("sent float: %s \n", PQgetvalue(res, 0, 0)); 
// --> sent float: 0.123457 

und wie diese auch doppelt, int, etc ...

Aber wie wäre es ARRAYs?

float vals_f[] = {1.23, 9.87}; 
    // alloc some memory 
    paramValues[0] = (char *) malloc(sizeof(float) * 2); 

// ???? paramValues[0] = ?????? 

    paramLengths[0] = sizeof(float) * 2; 
    paramFormats[0] = 1; // binary 


    res = PQexecParams(conn, "SELECT $1::real[] ;", // 
      1, // number parameters 
      NULL, // let the backend deduce param type 
      paramValues, // 
      paramLengths, // 
      paramFormats, // 
      0); // return text 
    printf("sent float array: %s \n", PQgetvalue(res, 0, 0)); 

Gibt es ein funktionierendes Beispiel für die Übertragung von ARRAY-Daten im PostgreSQL-Binärformat? Der Code in backend/utils/adt/ hilft mir nicht viel (außer ich weiß jetzt, da ein arraytype ist, aber nicht, wie sie zu benutzen) :-(

Ich brauche nur eine Funktion char* to_PQbin(float [] input, int length) für paramValues[.] zu vorbei ...

vielen Dank, Tebas

PS: Was ist die vorgeschlagene Art und Weise einfache Variablen der Umwandlung (und nicht meine htobe32(.))

Antwort

4

Als ccuter bereits erwähnt, müssen Sie Ihre eigene API erstellen. Der folgende Code extrahiert ein 1-dimensionales Array von und ignoriert alle NULL-Werte.

#define INT4OID 23 

/*! Structure of array header to determine array type */ 
struct array_int4 { 
    int32_t ndim; /* Number of dimensions */ 
    int32_t _ign; /* offset for data, removed by libpq */ 
    Oid elemtype; /* type of element in the array */ 

    /* First dimension */ 
    int32_t size; /* Number of elements */ 
    int32_t index; /* Index of first element */ 
    int32_t first_value; /* Beginning of integer data */ 
}; 

static int extract_int4_array (char *raw_array, 
           int32_t **values, 
           int *num_values) { 
    /* Array information header */ 
    struct array_int4 *array = (struct array_int4 *) raw_array; 
    /* Pointer to traverse int array */ 
    int32_t *p_value = &(array->first_value); 
    /* int value in host byte order */ 
    int32_t hval; 

    /* Check if we have a 1-dimensional INT4 array */ 
    if (ntohl(array->ndim) != 1 
    || ntohl(array->elemtype) != INT4OID) { 
    return -1; 
    } 
    /* Number of elements including NULLs */ 
    int array_elements = ntohl (array->size); 

    *num_values = 0; 
    /* Get size of array */ 
    for (int i=0; i<array_elements; ++i) { 
    /* Check size to see if this is a NULL value */ 
    hval = ntohl (*p_value); 
    if (hval != -1) { 
     ++p_value; 
     (*num_values) += 1; 
    } 

    ++p_value; 
    } 
    *values = malloc (*num_values * sizeof **values); 

    /* Fill output int array. Skip every other value as it contains the size of 
    * the element */ 
    *num_values = 0; /* Use num_values as the index of the output array */ 
    p_value = &(array->first_value); 
    for (int i=0; i<array_elements; ++i) { 
    /* Check size to see if this is a NULL value */ 
    hval = ntohl (*p_value); 
    if (hval != -1) { 
     ++p_value; 
    (*values)[*num_values] = ntohl (*p_value); 
     (*num_values) += 1; 
    } 

    ++p_value; 
    } 

    return 0; 
} 

Es scheint auch eine Bibliothek zu sein genannt libpqtypes, die für diese Art der Umwandlung hilft.

3

http://git.postgresql.org/gitweb?p=postgresql.git;a=blob;f=src/include/utils/array.h;h=7f7e744cb12bc872f628f90dad99dfdf074eb314;hb=master beschreibt für Arrays Binärformat des Postgres Wenn uns. Geben Sie in libpq den vl_len_-Abschnitt aus. Zum Beispiel würde ein Array von 4 ganzen Zahlen wie folgt aussehen:

0x00000001 0x00000000 0x00000017 0x00000004 0x00000001 0x00000004 0x00000004 0x00000004 0x00000004

Diese OID hat 1007 (INT4ARRAYOID). Die erste Ganzzahl ist 1 Dimension, die zweite Ganzzahl ist keine NULL-Bitmap (also ist keiner der Werte des Arrays NULL), die dritte Ganzzahl ist die OID der Elemente (23, INT4OID), die vierte Ganzzahl ist wie groß die erste Dimension ist (4) ist die fünfte ganze Zahl der Startindex der ersten Dimension. Danach sind rohe Array-Daten in sequentieller Reihenfolge, jedes Element mit vorangestellter Länge (4 Bytes für jede ganze Zahl).