<null>-Transport bei Firebird 2.5 und 3 unterschiedlich

Themen rund um den praktischen Einsatz von Firebird. Fragen zu SQL, Performance, Datenbankstrukturen, etc.

Moderator: thorben.braun

vr2
Beiträge: 102
Registriert: Fr 13. Apr 2018, 00:13

Hi,

folgende Abfrage liefert ausgeführt in einer 2.5.9er und einer 3.0.7er DB unterschiedliche Ergebnisse:

Code: Alles auswählen

select substr, string, position(substr, string) pos, char_length(substr) len
from (
  select cast('aa' as varchar(10)) substr, 'aabbaabb' string from rdb$database
  union all
  select null, 'aabbaabb' from rdb$database
  union all
  select 'aa', null from rdb$database
  union all
  select null, null from rdb$database)
In der 3er DB werden die <null>s erhalten (wie es sein sollte), in der 2.5.9er werden sie zu Leerstrings!

Grüße, Volker
Benutzeravatar
martin.koeditz
Beiträge: 283
Registriert: Sa 31. Mär 2018, 14:35

Hallo Volker,

guter Hinweis. Mit dieser Einschränkung in 2.5 werden wir wohl leben müssen, da diese Version seit 2019 nicht mehr weiterentwickelt wird.

Nebenbei:
Version 4.0 wurde mittlerweile als Release Candidate 1 markiert. Im 4.0 ist das Ergebnis identisch zu 3.0.

Gruß
Martin
Martin Köditz
it & synergy GmbH
bfuerchau
Beiträge: 276
Registriert: Mo 7. Mai 2018, 18:09

Das kann ich natürlich nicht so stehen lassen.
Das Problem ist, dass "select null ..." nicht typisiert ist.
Aber

select cast(null as varchar(1)) from ...

funkioniert. Somit würde man auch kompatibel zu zukünftigen Versionen bleiben.
Zumal man dabei auch noch im SQL-Standard bleibt.
vr2
Beiträge: 102
Registriert: Fr 13. Apr 2018, 00:13

Doch, es ist typisiert, die erste Spalte explizit und die zweite implizit durch den Wert des ersten Satzes im union. Wenn Du nur das innere select ausführst:

Code: Alles auswählen

select cast('aa' as varchar(10)) substr, 'aabbaabb' string from rdb$database
union all
select null, 'aabbaabb' from rdb$database
union all
select 'aa', null from rdb$database
union all
select null, null from rdb$database
verhalten sich 2.5 und 3 korrekt und beide liefern das gleiche Ergebnis und die <null>s nach außen.

Man muss nicht jedesmal, wenn man eine derived table um ein statement wickelt, explizit typisieren, sonst wäre das Konstrukt ziemlich unbrauchbar.

Und andersrum, wenn man jeden Wert der unions explizit typisiert, nicht nur den ersten Satz, bleibt es bei Firebird 2.5 trotzdem falsch, hier mal bei der ersten Spalte umgesetzt:

Code: Alles auswählen

select substr, string, position(substr, string) pos, char_length(substr) len
from (
  select cast('aa' as varchar(10)) substr, 'aabbaabb' string from rdb$database
  union all
  select cast(null as varchar(10)), 'aabbaabb' from rdb$database
  union all
  select cast('aa' as varchar(10)), null from rdb$database
  union all
  select cast(null as varchar(10)), null from rdb$database)
Und schließlich, wenn kein union im Spiel ist, wird <null> nach außen transportiert, auch bei Firebird 2.5, und ohne Typisierung:

Code: Alles auswählen

select str from
(select str from
 (select null str
  from rdb$database))
Das scheint ein Bug im Zusammenhang mit unions zu sein, und eine der Firebird-Versionen macht es falsch. Tendiere zu Firebird 2.5, denn die Ausgabe von Leerstrings statt <null>s bedeutet ja, dass Firebird den Wert als String interpretiert, aber die <null> nicht erhält. Alle Datentypen der Datenbank können <null>, es gibt hier keinen Grund, es auf einen echten Wert abzubilden.

Viele Grüße, Volker
bfuerchau
Beiträge: 276
Registriert: Mo 7. Mai 2018, 18:09

Bei mir klappts mit dem Union halt auch korrekt, wenn ich den NULL im 2. Unionblock typisiere.
Es scheint eine spezifische Automatisierung von Firebird zu sein, die allerdings nicht SQL-Standard ist. Ähnliches erlebe ich auch beim SQL-Server was dann zu unnötigen Suchereien in den SQL's führt um einen daraus resultierenden Fehler zu ermitteln.
Bei anderen DB's bekomme ich einen Fehlerhinweis, wenn ich NULL eben nicht typisiere.
Da Firebird eben ständig erweitert wird, gibt es auch bzgl. der automtischen Features ständig Erweiterungen, manchmal allerdings auch nachteilig wenn ich dann wieder untersuchen muss warum denn wieder mal kein Index verwendet werden kann.
Nicht typisierte NULL's können mangels Typ auch keinen Index verwenden.

Über Sinn oder Unsinn streite ich mich da nicht. Das bleibt einem selber überlassen. Allerdings entzieht sich mir der Sinn, in einer derived Table eine leeres Feld mit NULL überhaupt erst zu erstellen.
Gerd
Beiträge: 176
Registriert: Di 1. Okt 2019, 17:13

vr2 hat geschrieben: Mi 6. Jan 2021, 05:51 Hi,

folgende Abfrage liefert ausgeführt in einer 2.5.9er und einer 3.0.7er DB unterschiedliche Ergebnisse:

Code: Alles auswählen

select substr, string, position(substr, string) pos, char_length(substr) len
from (
  select cast('aa' as varchar(10)) substr, 'aabbaabb' string from rdb$database
  union all
  select null, 'aabbaabb' from rdb$database
  union all
  select 'aa', null from rdb$database
  union all
  select null, null from rdb$database)
In der 3er DB werden die <null>s erhalten (wie es sein sollte), in der 2.5.9er werden sie zu Leerstrings!

Grüße, Volker
Hallo.

Ich erlaube mir mich mal mit einzuklinken und bitte um Verständnis.
Bei mir in der v4 RC1 habe ich dieses Ausgabeergebnis. Welcher Firebird-Version bitte entspricht es, der 2.59er oder 3.0.7er (beide habe ich leider nicht am Laufen.)?

Code: Alles auswählen

gerd@gerd-MS-7641:~$ isql adressen.fdb
Database: adressen.fdb, User: GERD
SQL> select substr, string, position(substr, string) pos, char_length(substr) len
CON> from (
CON>   select cast('aa' as varchar(10)) substr, 'aabbaabb' string from rdb$database
CON>   union all
CON>   select null, 'aabbaabb' from rdb$database
CON>   union all
CON>   select 'aa', null from rdb$database
CON>   union all
CON>   select null, null from rdb$database);

SUBSTR     STRING            POS          LEN 
========== ======== ============ ============ 
aa         aabbaabb            1            2 
<null>     aabbaabb       <null>       <null> 
aa         <null>         <null>            2 
<null>     <null>         <null>       <null> 

SQL> 
Viele Grüße
Gerd
Linux Mint 20.1 Ulyana Cinnamon 4.8.6
Firebird 4.0 RC 1, Superserver - ISQL: LI-V4.0.0.2439
Lazarus 2.0.10 - FPC 3.2.0
bfuerchau
Beiträge: 276
Registriert: Mo 7. Mai 2018, 18:09

Nach obiger Beschreibung der 3.x.
Da nun mal 4.0 nicht neu entwickelt wurde sondern eher auf 3.0 basiert, wird das Ergebnis logischerweise nich dem von 2.5ff entsprechen :) .
Gerd
Beiträge: 176
Registriert: Di 1. Okt 2019, 17:13

Hallo bfuerchau.

Danke, weiß ich bescheid.


Viele Grüße
Gerd
Linux Mint 20.1 Ulyana Cinnamon 4.8.6
Firebird 4.0 RC 1, Superserver - ISQL: LI-V4.0.0.2439
Lazarus 2.0.10 - FPC 3.2.0
vr2
Beiträge: 102
Registriert: Fr 13. Apr 2018, 00:13

bfuerchau hat geschrieben: Sa 9. Jan 2021, 12:46 Allerdings entzieht sich mir der Sinn, in einer derived Table eine leeres Feld mit NULL überhaupt erst zu erstellen.
das war hier zu Demozwecken, muss aber korrekt funktionieren, wenn es zulässig ist. Oder eben eine Fehlermeldung bringen, wenn es im Funktionsumfang nicht vorgesehen ist. Anwendungsfall wäre bspw die Initialisierung des root-Elements einer rekursiven CTE ohne physische Tabelle.

Viele Grüße, Volker
bfuerchau
Beiträge: 276
Registriert: Mo 7. Mai 2018, 18:09

Und gerade letzteres (root) funktioniert nicht ohne Typisierung.
Antworten