Hallo,
wenn ich in PL/Perl eine SELECT Abfrage formuliere, die einen boolean zurückgeben sollte, dann bekomme ich “HASH(0x9a70578)” zurück.
Wie komme ich an “den Kern des Ganzen”? Oder habe ich hier eine riesige Verständnislücke?
Bin gerade dabei plperl zu lernen/verstehen.
Die Abfrage lautet:
my $sel = spi_exec_query(“SELECT ST_INTERSECTS(x.first_set,y.second_set) FROM
(SELECT poly AS first_set FROM polys WHERE id=$eins) AS x,
(SELECT poly AS second_set FROM polys WHERE id=$zwei) AS y;”);
ST_INTERSECTS ist eine von postgis bereitgestellte Funktion. poly ist eine Tabelle mit einer Spalte voller Polygone (polys).
Die Abfrage soll mir sagen, ob sich zwei überlappen oder nicht?
Unten habe ich die ganze Funktion angehängt. Ich würde mir gerne das Ergebnis des SELECT als boolean zurückgeben lassen.
CREATE OR REPLACE FUNCTION ueberschneidung(INTEGER, INTEGER)
RETURNS boolean
AS
$$
my $ueber = false;
my $eins = $_[0];
my $zwei = $_[1];
elog(NOTICE,"ausgabe: $eins");
elog(NOTICE,"ausgabe: $zwei");
my $sel = spi_exec_query("SELECT ST_INTERSECTS(x.first_set,y.second_set) FROM
(SELECT poly AS first_set FROM polys WHERE id=$eins) AS x,
(SELECT poly AS second_set FROM polys WHERE id=$zwei) AS y;");
elog(NOTICE,"select: $sel");
my $status = $sel->{status};
my $nrows = $sel->{processed};
elog(NOTICE,"status: $status");
elog(NOTICE,"nrows: $nrows");
my $row = $sel->{rows}[0];
elog(NOTICE,"row: $row");
return $ueber;
$$
LANGUAGE plperl;
SELECT * FROM ueberschneidung(1,2);
In dem link wird ja auf “Seite 366” explizit auf “daten” zugegriffen. Leider liefert meine Select-Anfrage aber keinen Spaltennamen wie “daten”. Wie kann ich denn bei der ST_INTERSECT Funktion drauf zugreifen. Das verstehe ich leider nicht. Kannst Du es mir bitte näher erläutern?
SELECT ST_INTERSECTS(x.first_set,y.second_set) AS spalte1
Und $row ist letztendlich nur wieder ein Zeiger auf ein Array. Du musst also da drin noch auf den passenden Schlüssel zugreifen.
Wenn du die untrusted Version von pl/Perl verwendest (das wäre “plperlu”), könntest du mittels dem Modul Data: umper in die jeweiligen Variablen hineinschauen.
vielen, vielen Dank. Das benenne mit AS klappt wunderbar, denn dann habe ich ja einen “Namen” auf den ich zugreifen kann. plperlu werde ich im Hinterkopf behalten. Als Neuling in Datenbanken & co war mir das Attribut untrusted zu abschreckend. So nach dem Motto “wer nicht weiß was er tut sollte lieber die Finger…”
In dem Fall empfehle ich dir mal die Dokumentation zu CREATE LANGUAGE. Dort werden die Unterschiede zwischen trusted und untrusted Sprachen dargestellt.
Ist es möglich die Funktion - wenn sie einmal angelegt ist - auch “direkt” aufzurufen. Also innerhalb einer anderen plperl Funktion nur über den Namen und Attribute? Würde es gerne in einer if-Abfrage nutzen.
Oder grundsätzlich auch aus anderen plperl Funktionen heraus nur in der Form
my $sel = spi_exec_query("SELECT * FROM ueberschneidung($i,$j);");
my $sel0 = $sel->{rows}[0]->{ueberschneidung};
if($sel0 eq t)
Finde das etwas umständlich. Direktes auswerten in der Form
if(ueberschneidung(X,Y) == true)
wäre eleganter. Ist das irgendwie möglich? Ich gebe zu, mein Verständnis von dem prozeduralen Ansatz scheint sich noch in Grenzen zu halten.
Nein. Die Funktionen sind ja nur innerhalb der Datenbank bekannt.
Was du allerdings machen könntest: deine in der Datenbank erstellte Funktion ist bloß ein Wrapper über deine eigentliche Funktion.
Die richtige Funktion stellst du dann in einem Modul bereit und rufst sie wahlweise aus Perl heraus oder aus dem Wrapper aus der Datenbank heraus auf.
Ok. Denke ich werde es erstmal einfach so belassen. Aber eine viel wichtigere Frage:
Scheinbar werden Änderungen, die per spi_exec_query("UPDATE… abgeschickt werden und auch mit “status: SPI_OK_UPDATE” quittiert werden nicht sofort ausgeführt. Kann das sein? In meinem Fall müssen die Änderungen unbedingt sofort ausgeführt werden.
Was genau meinst du mit “werden nicht sofort ausgeführt”?
Deine Stored Procedure läuft innerhalb einer Transaktion. Erst wenn diese beendet ist, werden sämtliche Änderungen committed und damit für andere sichtbar.
Deine eigene Transaktion sieht die Änderungen jedoch sofort.
Zu dem Thema solltest du dich mal zur Isolation von Transaktionen belesen.
Also folgendes Szenario. Eine Tabelle mit Postgis Polygonen existiert. In einer plperl Funktion frage ich ab, ob sich 2 postgis Polygone überschneiden. Ist das der Fall, dann speichere ich den Überschneidungsbereich als neues Polygon in die Tabelle und beschneide die zwei anderen um den Überschneidungs-Bereich.
Wenn ich nun innerhalb der Funktion, nachdem diese drei Operationen stattgefunden haben, abfrage, wie viele Polygone in der Tabelle sind, dann erhalte ich einen erhöhten Wert im Vergleich zum Ausgangszustand. Allerdings liefert die Abfrage nach den Abmaßen der Polygone die Ausgangs-Abmessungen und nicht die veränderten! Folglich scheitern weitere Beschneidungen daran, dass nicht die korrekten (durch vorherige Schnitte entstandenen) Abmessungen abgefragt werden können. Innerhalb der Funktion läuft eine Schleife, die jedes Polygon mit jedem verschneiden soll.
Lag wohl an meiner Programmstruktur. Habe mich etwas zu “Isolation von Transaktionen” schlau gemacht und einzelne Funktionen für einzelne Aufgaben geschrieben. Jetzt werden auch die korrekten Abmessungen geholt. Der nächste Knackpunkt ist auch schon da. Der ist allerdings Kopfarbeit und nicht “Technik”.
Eine Nachfrage zum Thema “Änderungen übernehmen”. Wieso die Änderungen nicht “sofort übernommen” werden ist mir jetzt klar. In den postgresql doc PostgreSQL: Documentation: Manuals: PostgreSQL 8.3: COMMIT
hört es sich für mich so an, als wenn man auch manuell ein COMMIT senden könnte. Ich würde das gerne aus plperl heraus tun, und meine gelesen zu haben, dass es sowohl aus plperl, wie auch plpython heraus gehen müsste. Allein, wie ist die Syntax für den COMMIT-Befehl? Etwa so:
spi_exec_query(“SELECT COMMIT;”);
Und worauf sollte man achten bezüglich Zeitpunkt der Ausführung?