PostgreSQL Externe C-Funktion



  • Nach meiner letzten Veränderung sieht der Code jetzt so aus.

    //------------------------------------------------------------------------------
    
    double return_of_spl_string(const char*s)
    {
      int n=0;
      double d;
      double sum;
      s=strchr(s,'\'')+1;
      while( 1==sscanf(s+=n,"%lf%*1[ ,]%n",&d,&n) ) 
      {
    	  sum += pow(d, 2);  
      }
      return pow(sum, 0.5);
    }
    
    //------------------------------------------------------------------------------
    PG_FUNCTION_INFO_V1(FCT_Norm);
    PGDLLEXPORT 
    Datum
    FCT_Norm(PG_FUNCTION_ARGS)
    	{
    
        FuncCallContext     *funcctx;
        int                  call_cntr;
        int                  max_calls;
        char       *_str = PG_GETARG_CSTRING(0);
    
    	if (SRF_IS_FIRSTCALL())
    
    			{
    			MemoryContext   oldcontext;
    
    			//create a function context for cross-call persistence 
    			funcctx = SRF_FIRSTCALL_INIT();
    
    			// switch to memory context appropriate for multiple function calls 
    			oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
    
    			/* total number of tuples to be returned */
    			funcctx->max_calls = PG_GETARG_UINT32(0);
    			MemoryContextSwitchTo(oldcontext);
    
    			}	
    
    				call_cntr = funcctx->call_cntr;
    				max_calls = funcctx->max_calls;
    				funcctx = SRF_PERCALL_SETUP();
    
    				while(call_cntr < max_calls)
    				{
    
    				double ergebnis;
    				ergebnis = return_of_spl_string(_str);
    
    				SRF_RETURN_NEXT(funcctx,ergebnis);
    				}
    				//When he finish the last row the function is done
    					if(call_cntr = max_calls)
    						{
    						SRF_RETURN_DONE(funcctx);
    						}
    }
    

    Er baut auch brav, die Funktion lässt sich auch mit CREATE ... einfügen bloß scheitert es an der Abfrage der Daten.

    Als Fehlermeldung kriege ich dann

    FEHLER:  Funktion mit Mengenergebnis in einem Zusammenhang aufgerufen, der keine Mengenergebnisse verarbeiten kann
    
    ********** Fehler **********
    
    FEHLER: Funktion mit Mengenergebnis in einem Zusammenhang aufgerufen, der keine Mengenergebnisse verarbeiten kann
    SQL Status:0A000
    


  • Diesen ganzen Kram mit dem Kontext und so brauchst Du doch nicht, oder?
    Ich meine Du bekommst einen LINESTRING und gibst da die Norm zurück.

    Würde dementsprechend nicht reichen:

    PG_FUNCTION_INFO_V1(FCT_Norm);
    PGDLLEXPORT
    Datum
    FCT_Norm(PG_FUNCTION_ARGS)
    {
      // ©Wutz (https://www.c-plusplus.net/forum/329834)
      int n=0;
      double d;
      double sum=0.0;
      const char *s=strchr(PG_GETARG_CSTRING(0),'\'')+1;
      while( 1==sscanf(s+=n,"%lf%*1[ ,]%n",&d,&n) )
      {
        sum += d*d;
      }
      PG_RETURN_FLOAT8(sqrt(sum)); 
    }
    


  • Solange er mir durch die Spalte geht ist mir das recht egal 😃

    Danke für den Ansatz ich werde es morgen früh sofort versuchen (bin heute nicht mehr auf der Arbeit)

    🙂



  • Geht leider nicht bei dem Aufruf der Funktion in SQL schmiert mir die Verbindung komplett ab 😞 Also er bricht die Verbindung komplett ab



  • sataide schrieb:

    Geht leider nicht bei dem Aufruf der Funktion in SQL schmiert mir die Verbindung komplett ab 😞 Also er bricht die Verbindung komplett ab

    Ähm...ich glaube auch, dass s falsch initialisiert wird.

    Ein Linestring sieht so aus, oder:

    LINESTRING(0 0,1 1,1 2)

    ?

    Insbesondere fehlt das einfache Anführungszeichen ' .

    Also musst Du in strchr() nach einer öffnenden Klammer suchen '(', nicht nach '\''.



  • Ich trim den Linestring vor der Abfrage.

    Meine Abfrage sieht so aus :

    select FCT_Norm(trim(')' from trim('LINESTRING(' from st_AsText (coordinates)))) from germany.ttopology ;
    

    Als ausgabe gibts nur :

    ********** Fehler **********
    
    no connection to the server
    
    Verbindung zurückgesetzt.
    


  • Tohuwabohu hier...
    Wutz wollte den kompletten Linestring.

    Wenn Du in SQL trimst und dann ab der ersten Zahl übergibst, dann

    const char *s=PG_GETARG_CSTRING(0);
    


  • Hö? Wie meinste jetzt?



  • sataide schrieb:

    Hö? Wie meinste jetzt?

    Der const char *s im code wurde auf das erste Zeichen nach einem Anführungszeichen gesetzt.
    Weil der String so angenommen wurde:
    Linestring('0 0,1 1,1 2')

    Mittlerweile ist mir klar, dass der String so aussieht:
    Linestring(0 0,1 1,1 2)

    Und Du trimst weiterhin in SQL, dann kommt ja nur noch
    0 0,1 1,1 2
    an.
    D.h. s muss auch gar nicht angepasst werden und kann direkt auf PG_GETARG_CSTRING(0) gesetzt werden.

    PG_FUNCTION_INFO_V1(FCT_Norm);
    PGDLLEXPORT
    Datum
    FCT_Norm(PG_FUNCTION_ARGS)
    {
      // ©Wutz (https://www.c-plusplus.net/forum/329834)
      int n=0;
      double d;
      double sum=0.0;
      const char *s=PG_GETARG_CSTRING(0);
      while( 1==sscanf(s+=n,"%lf%*1[ ,]%n",&d,&n) )
      {
        sum += d*d;
      }
      PG_RETURN_FLOAT8(sqrt(sum));
    }
    


  • Wird direkt ausprobiert 🙂



  • Interessant.

    Bei der Abfrage :

    select FCT_Norm(trim(')' from trim('LINESTRING(' from st_AsText (coordinates)))) from germany_.ttopology LIMIT 100 ;
    

    Gibt er mir 100 Zeilen mit 0 aus.(In paar Ms)
    Geb ich aber 1000 ein hört er gar nicht mehr auf. Bin jetzt schon bei 3 Minuten.



  • Evtl. ist die Frage mittlerweile besser im DB Subforum aufgehoben.

    Ich selbst habe auch keine Erfahrung mit Postgresql.

    Kannst Du es nicht mal testen mit einer Kommandozeile o.ä.?

    SELECT FCT_Norm('0 0,1 1,1 2');
    


  • Da gibt er mir auch ne 0 aus.

    Wir wissen aber das er die C-Funktion benutzt, da er mir die Werte als double precission zurückgibt. Die Frage ist nur warum er mir eine 0 zurückgibt und keinen berechneten Wert.



  • Ich überfliege gerade dies: http://www.postgresql.org/docs/9.4/static/xfunc-c.html
    Demnach müssen wir das Ergebnis palloc() en und einen pointer darauf zurückgeben.

    Das musst Du nochmal genauer lesen.
    Insbesondere diesen Tipp: "Hence, the standard internal function library is a rich source of coding examples for user-defined C functions." Solltest Du berücksichtigen und Dir ein paar Beispiele anschauen.



  • Die Seite hab ich schon nebenbei auf 🙂

    Problem ist das meine Programmierkenntnisse noch ziemlich klein sind und mir diese Zeigergeschichte überhaupt nicht liegt.

    Ich versuchs mal und meld mich dann wieder 🙂



  • Btw.

    Muss ich den String auch pallocen oder nur das Ergebnis?



  • sataide schrieb:

    Muss ich den String auch pallocen oder nur das Ergebnis?

    Ich bin mir nicht einmal mehr sicher, ob das Ergebnis alloziert werden muss. 🙂

    Sorry: da musst Du jemanden fragen, der sich damit auskennt. Chancen sind im Datenbank-Subforum besser.



  • Ich hab den Fehler. Es war kein PG_GETARG_CSTRING sondern ein PG_GETARG_TEXT_P. Nach ein paar Änderungen im Code läuft es endlich einwandfrei und hat die Abfragezeit um mehr als die Hälfte verkürzt.
    Wollte mich nur für die Hilfe bedanken 🙂

    Wenns wieder Probleme gibt meld ich mich 😃



  • Eine Frage hätte ich noch?

    Wie kann ich diese Splitfunktion in eine eigene funktion aufteilen?

    Zum Beispiel

    void string_split(*hier kommt der String rein 😉

    und dann

    meine eigene Funktion, die diese Hilfsfunktion anwendet
    PG_Function...

    s*char string_split(*string*)

    ...



  • sataide schrieb:

    Eine Frage hätte ich noch?

    Wie kann ich diese Splitfunktion in eine eigene funktion aufteilen?

    Wie Du Funktionen schreibst mit Parametern und Rückgabewerten?
    Das sollte in jedem C Buch erklärt werden.
    Oder ich verstehe die Frage miß...

    Dein Entwurf von weiter oben im Thread

    double return_of_spl_string(const char*s);
    

    sieht jedenfalls ganz vielversprechend aus.

    Freut mich übrigens, dass Deine Arbeit wirklich zu einer Performanzsteigerung führt.
    Allerdings ist mir die Lösung, statt PG_GETARG_CSTRING einfach PG_GETARG_TEXT_P zu nehmen nicht ganz geheuer...


Anmelden zum Antworten