2016-10-04 3 views
1

Ich arbeite an der Portierung von Datenbank von Firebird zu PostgreSQL und viele Fehler im Zusammenhang mit Typ Besetzung. Zum Beispiel wollen wir eine einfache Funktion übernehmen:PostgreSQL - Auto Cast für Typen?

CREATE OR REPLACE FUNCTION f_Concat3 (
    s1 varchar, s2 varchar, s3 varchar 
) 
RETURNS varchar AS 
$body$ 
BEGIN 
    return s1||s2||s3; 
END; 
$body$ LANGUAGE 'plpgsql' IMMUTABLE CALLED ON NULL INPUT SECURITY INVOKER LEAKPROOF COST 100; 

Wie Firebird ziemlich flexibel Typen wurde diese Funktionen anders genannt: einige der Argumente könnte ein anderer Typ sein: integer/double precision/Zeitstempel. Und natürlich in Postgres Funktionsaufruf f_Concat3 ('1', 2, 345.345) verursacht ein Fehler wie:

function f_Concat3(unknown, integer, numeric) not found.

Die Dokumentation empfohlen wird wie eine explizite Umwandlung zu verwenden:

f_Concat3 ('1'::varchar, 2::varchar, 345.345::varchar) 

Auch kann ich eine Funktion Klone für alle möglichen Kombinationen erstellen von Typen, was auftreten könnte und es wird funktionieren. Ein Beispiel, um Fehler zu beheben:

CREATE OR REPLACE FUNCTION f_Concat3 (
    s1 varchar, s2 integer, s3 numeric 
) 
RETURNS varchar AS 
$body$ 
    BEGIN 
    return s1::varchar||s2::varchar||s3::varchar; 
    END; 

Allerdings ist dies sehr schlecht und hässlich und es wird nicht mit großen Funktionen arbeiten.

Wichtig: Wir haben eine allgemeine Codebasis für alle Datenbanken und verwenden unsere eigene Sprache, um Anwendungsobjekte (Formulare, Berichte usw.) zu erstellen, die ausgewählte Abfragen enthalten. Es ist nicht möglich explizite Cast-Funktionsaufrufe zu verwenden, da wir die Kompatibilität mit anderen DB verlieren.

Ich bin verwirrt, dass das Integer-Argument kann nicht auf die numeric oder double precision oder date/number zu einem string gegossen werden. Ich habe sogar Probleme mit integer bis smallint und umgekehrt. Die meisten Datenbanken verhalten sich nicht so.

Gibt es eine Best Practice für eine solche Situation?
Gibt es Alternativen für explizite Besetzung?

+1

Sie können einfach ':: varchar' verwenden, wenn Sie die Funktion aufrufen. –

+2

Warum möchten Sie eine neue Funktion erstellen? Postgres hat bereits eine 'concat()' -Funktion, die eine beliebige Anzahl von Argumenten akzeptiert? –

+0

@a_horse_with_no_name die Funktion concat() ist zum Beispiel. Stellen Sie sich einfach eine komplexe Funktion vor, bei der beliebige Eingabeargumente als Integer oder String geschrieben werden können. Firebird wird das erlauben. – Ice2burn

Antwort

4

SQL ist eine typisierte Sprache, und PostgreSQL nimmt dies ernster als andere relationale Datenbanken. Das bedeutet leider zusätzlichen Aufwand beim Portieren einer Anwendung mit schlampiger Codierung.

Es ist verlockend zu add implicit casts, aber the documentation warnt von Ihnen Abgüsse zwischen eingebauten Datentypen zu erstellen:

Additional casts can be added by the user with the CREATE CAST command. (This is usually done in conjunction with defining new data types. The set of casts between built-in types has been carefully crafted and is best not altered.)

wenn Sie Dies ist keine leere Warnung, weil function resolution und andere Dinge können plötzlich versagen oder sich schlecht benehmen Erstellen Sie neue Umwandlungen zwischen vorhandenen Typen.

Ich denke, wenn Sie wirklich nicht den Code aufräumen wollen (was es portabler für die Zukunft machen würde), haben Sie keine andere Wahl, als weitere Versionen Ihrer Funktionen hinzuzufügen.

Glücklicherweise hat PostgreSQL function overloading, die das möglich macht.

Sie können die Arbeit erleichtern, indem ein Argument mit einem polymorphic type in der Funktionsdefinition, wie folgt aus:

CREATE OR REPLACE FUNCTION f_concat3 (
    s1 text, s2 integer, s3 anyelement 
) RETURNS text 
    LANGUAGE sql IMMUTABLE LEAKPROOF AS 
'SELECT f_concat3(s1, s2::text, s3::text)'; 

Sie allerdings nicht mehr als ein anyelement Argument verwenden können, denn das wird nur dann, wenn alle so arbeiten Parameter sind vom selben Typ.

Wenn Sie das Überladen von Funktionen verwenden, achten Sie darauf, dass Sie keine Mehrdeutigkeiten erzeugen, die die Funktionsauflösung beeinträchtigen könnten.

+0

Es wäre wirklich schön, wenn Postgres erlauben würde, eine Funktion wie 'concat()' (die mit einem einzigen Parameter vom Typ '" any "' definiert ist) mit SQL oder PL/pgSQL zu erstellen, aber das scheint nur möglich mit C –

+0

Es gibt einige Legacy-Funktionen mit mehr als 13 Argumenten, daher ist das Überladen von Funktionen die letzte Option. Pseudo-Typ war meine letzte Hoffnung :) – Ice2burn