2016-09-01 2 views
2

Ich habe folgende benutzerdefinierten Typ:Zugriffs Array von benutzerdefinierten Typ in einer PostgreSQL C Funktion

CREATE TYPE int2_lo_hi AS (
    lo int2, 
    hi int2 
); 

Ich möchte diese als Array passieren (int2_lo_hi[]) in eine C-Funktion. Ich kenne jedoch nicht den richtigen Weg, um auf Elemente zuzugreifen.

Hier ist mein Code so weit, bearbeitet:

Header (nicht mehr verwendet):

typedef struct 
{ 
    short lo, 
      hi; 
} Int2_lo_hi; 

C:

PG_FUNCTION_INFO_V1(array_test); 

PGMODULEEXPORT Datum array_test(PG_FUNCTION_ARGS) 
{ 
    ArrayType *a = PG_GETARG_ARRAYTYPE_P(0); 

    if (ARR_NDIM(a) > 1) 
    { 
     ereport(ERROR, (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), errmsg("1-dimensional array needed"))); 
    } 

    Datum *datums; 
    bool *nulls; 
    int elemWidth, count; 
    Oid elemType = ARR_ELEMTYPE(a); 
    bool elemTypeByVal, isNull; 
    char elemAlignmentCode; 
    get_typlenbyvalalign(elemType, &elemWidth, &elemTypeByVal, &elemAlignmentCode); 
    deconstruct_array(a, elemType, elemWidth, elemTypeByVal, elemAlignmentCode, &datums, &nulls, &count); 
    int result = 0; 
    HeapTupleHeader lt; 
    short *field; 

    for (int i = 0; i < count; i++) 
    { 
     if (nulls[i]) 
     { 
      result = -result; 
     } 
     else 
     { 
      lt = DatumGetHeapTupleHeader(datums[i]); 
/*   field = (short*)GetAttributeByNum(lt, 1, &isNull); 

      if (!isNull) 
      { 
       //result += *field; 
      } 

      field = (short*)GetAttributeByNum(lt, 2, &isNull); 

      if (!isNull) 
      { 
       //result += *field; 
      }*/ 
     } 
    } 

    PG_RETURN_INT32(result); 
} 

Der Teil, der einen Fehler auf Kommentar wirft.

Hinweis: Ich erhalte einen Fehler, der angibt, dass die OID ungültig ist. Sein Wert ist 28642010, auf den ich keine Dokumentation finden kann.

+1

Ich glaube, Sie den genaue Array Elementtyp in 'deconstruct_array' Funktion anstelle von' ANYELEMENTOID' angeben müssen. Um den Array-Typ zu bestimmen, können Sie 'AARR_ELEMTYPE' Makros verwenden. Siehe [hier] (https://www.postgresql.org/message-id/3162247.QRym21llNv%40abook) das Beispiel von meinem Kollegen geschrieben, wie man es (in Anhang) –

+0

verwenden und das vierte Argument sollte wahrscheinlich sein false "wenn Sie Ihre Elemente palloc –

+0

Danke @IldarMusin. Ich habe die Deconstruct-Zeile in deconstruct_array (a, ObjectIdGetDatum (a), 4, false, i, & datums & nulls & count); 'geändert und in' Int2_lo_hi * elem = palloc (sizeof (Int2_lo_hi)); 'geändert, aber das erzeugt einen Fehler (trennt den Server). Habe ich etwas in deinem Vorschlag vermisst? – IamIC

Antwort

4

Nach kleineren Korrekturen dieser Code funktioniert:

PG_FUNCTION_INFO_V1(array_test); 

Datum 
array_test(PG_FUNCTION_ARGS) 
{ 
    ArrayType *a = PG_GETARG_ARRAYTYPE_P(0); 
    Datum *datums; 
    bool *nulls; 
    int  count; 
    int16 elemWidth; 
    Oid  elemType = ARR_ELEMTYPE(a); 
    bool elemTypeByVal, isNull; 
    char elemAlignmentCode; 
    int  result = 0; 
    HeapTupleHeader lt; 
    short field; 

    if (ARR_NDIM(a) > 1) 
     ereport(ERROR, (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), errmsg("1-dimensional array needed"))); 

    get_typlenbyvalalign(elemType, &elemWidth, &elemTypeByVal, &elemAlignmentCode); 
    deconstruct_array(a, elemType, elemWidth, elemTypeByVal, elemAlignmentCode, &datums, &nulls, &count); 

    for (int i = 0; i < count; i++) 
    { 
     if (nulls[i]) 
     { 
      result = -result; 
     } 
     else 
     { 
      lt = DatumGetHeapTupleHeader(datums[i]); 

      field = DatumGetInt16(GetAttributeByNum(lt, 1, &isNull)); 
      if (!isNull) 
       result += field; 

      field = DatumGetInt16(GetAttributeByNum(lt, 2, &isNull)); 
      if (!isNull) 
       result += field; 
     } 
    } 

    PG_RETURN_INT32(result); 
} 
+0

Nochmals vielen Dank, @Ildar Musin – IamIC

Verwandte Themen