forked from gleu/pgdocs_fr
-
Notifications
You must be signed in to change notification settings - Fork 0
/
typeconv.xml
989 lines (871 loc) · 33.1 KB
/
typeconv.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
<?xml version="1.0" encoding="ISO-8859-15"?>
<!-- Dernière modification
le $Date$
par $Author$
révision $Revision$ -->
<chapter id="typeconv">
<title>Conversion de types</title>
<indexterm zone="typeconv">
<primary>type de données</primary>
<secondary>conversion</secondary>
</indexterm>
<para>
Le mélange de différents types de données dans la même expression peut
être requis, intentionnellement ou pas, par les instructions
<acronym>SQL</acronym>. <productname>PostgreSQL</productname> possède des
fonctionnalités étendues pour évaluer les expressions de type mixte.
</para>
<para>
Dans la plupart des cas, un utilisateur n'aura pas besoin de
comprendre les détails du mécanisme de conversion des types.
Cependant, les conversions implicites faites par
<productname>PostgreSQL</productname> peuvent affecter le résultat
d'une requête. Quand cela est nécessaire, ces résultats peuvent être
atteints directement en utilisant
la conversion <emphasis>explicite</emphasis> de types.
</para>
<para>
Ce chapitre introduit les mécanismes et les conventions sur les conversions
de types dans <productname>PostgreSQL</productname>. Référez-vous aux
sections appropriées du <xref linkend="datatype"/> et du
<xref linkend="functions"/> pour plus d'informations sur les types de
données spécifiques, les fonctions et les opérateurs autorisés.
</para>
<sect1 id="typeconv-overview">
<title>Aperçu</title>
<para>
<acronym>SQL</acronym> est un langage fortement typé. C'est-à-dire que
chaque élément de données est associé à un type de données qui détermine
son comportement et son utilisation permise.
<productname>PostgreSQL</productname> a un système de types extensible
qui est beaucoup plus général et flexible que les autres
implémentations de <acronym>SQL</acronym>. Par conséquent, la plupart
des comportements de conversion de types dans
<productname>PostgreSQL</productname> est régie par des règles
générales plutôt que par une heuristique <foreignphrase>ad hoc</foreignphrase>. Cela
permet aux expressions de types mixtes d'être significatives même
avec des types définis par l'utilisateur.
</para>
<para>
L'analyseur de <productname>PostgreSQL</productname> divise
les éléments lexicaux en seulement cinq catégories fondamentales :
les entiers, les nombres non entiers, les chaînes de caractères, les
identifieurs et
les mots-clé. Les constantes de la plupart des types non-numériques
sont d'abord classifiées comme chaînes de caractères. La définition du
langage <acronym>SQL</acronym> permet de spécifier le nom des types
avec une chaîne et ce mécanisme peut être utilisé dans
<productname>PostgreSQL</productname> pour lancer l'analyseur sur le
bon chemin. Par exemple, la requête
<screen>SELECT text 'Origin' AS "label", point '(0,0)' AS "value";
label | value
--------+-------
Origin | (0,0)
(1 row)</screen>
a deux constantes littérales, de type <type>text</type> et
<type>point</type>. Si un type n'est pas spécifié pour une chaîne
littérale, alors le type <type>unknown</type> est assigné
initialement pour être résolu dans les étapes ultérieures comme décrit
plus bas.
</para>
<para>
Il y a quatre constructions <acronym>SQL</acronym> fondamentales
qui exigent des règles distinctes de conversion de types dans l'analyseur
de <productname>PostgreSQL</productname> :
<variablelist>
<varlistentry>
<term>
Les appels de fonctions
</term>
<listitem>
<para>
Une grande partie du système de types de
<productname>PostgreSQL</productname> est construit autour d'un riche
ensemble de fonctions. Les fonctions peuvent avoir un ou
plusieurs arguments. Puisque que
<productname>PostgreSQL</productname> permet la surcharge des
fonctions, le nom seul de la fonction n'identifie pas de manière unique la
fonction à appeler ; l'analyseur doit sélectionner la bonne fonction
par rapport aux types des arguments fournis.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
Les opérateurs
</term>
<listitem>
<para>
<productname>PostgreSQL</productname> autorise les expressions avec
des opérateurs de préfixe et de suffixe unaires (un argument) aussi bien
que binaires (deux arguments). Comme les fonctions, les opérateurs peuvent être
surchargés. Du coup, le même problème existe pour sélectionner le bon opérateur.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
Le stockage des valeurs
</term>
<listitem>
<para>
Les instructions <acronym>SQL</acronym> <command>INSERT</command> et
<command>UPDATE</command> placent le résultat des expressions dans
une table. Les expressions dans une instruction doivent être en accord avec
le type des colonnes cibles et peuvent être converties vers celles-ci.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
Les constructions <literal>UNION</literal>, <literal>CASE</literal> et des
constructions relatives
</term>
<listitem>
<para>
Comme toutes les requêtes issues d'une instruction
<command>SELECT</command> utilisant une union doivent apparaître dans
un ensemble unique de colonnes, les types de résultats de chaque
instruction <command>SELECT</command> doivent être assortis et convertis en un
ensemble uniforme. De façon similaire, les expressions de résultats d'une
construction <literal>CASE</literal> doivent être converties vers un type commun
de façon à ce que l'ensemble de l'expression <literal>CASE</literal> ait un
type de sortie connu. Cela est la même chose pour les constructions
avec <literal>ARRAY</literal> et pour les fonctions <function>GREATEST</function>
et <function>LEAST</function>.
</para>
</listitem>
</varlistentry>
</variablelist>
</para>
<para>
Les catalogues systèmes stockent les informations concernant la
validité des conversions entre les types de données et la façon
d'exécuter ces conversions. Les conversions sont appelées
<firstterm>casts</firstterm> en anglais. Des conversions de types
supplémentaires peuvent être ajoutées par l'utilisateur avec la commande
<xref linkend="sql-createcast" endterm="sql-createcast-title"/> (c'est
habituellement réalisé en
conjonction avec la définition de nouveaux types de données.
L'ensemble des conversions entre les types prédéfinis a été
soigneusement choisi et le mieux est de ne pas le modifier).
</para>
<indexterm>
<primary>type de données</primary>
<secondary>catégorie</secondary>
</indexterm>
<para>
Concernant les types <acronym>SQL</acronym> standards, une heuristique
additionnelle est fournie dans l'analyseur pour permettre de meilleures
estimations du comportement approprié. Il y a plusieurs
<firstterm>catégories de types</firstterm> basiques définies :
<type>boolean</type>, <type>numeric</type>, <type>string</type>,
<type>bitstring</type>, <type>datetime</type>, <type>timespan</type>,
<type>geometric</type>, <type>network</type> et utilisateurs. Chaque
catégorie, à l'exception des types définis par l'utilisateur, a un ou plusieurs
<firstterm>types pré-définis</firstterm> qui sont préférentiellement
choisis quand il y a une ambiguïté. Dans la catégorie des types
utilisateurs, chaque type est son propre type préféré. Les
expressions ambiguës (celles avec de multiples solutions d'analyse
candidates) peuvent souvent être résolues quand il y a de nombreux
types pré-définis possibles mais elles soulèveront une erreur quand il
existe des choix multiples pour des types utilisateurs.
</para>
<para>
Toutes les règles de conversions de types sont écrites en gardant à l'esprit
plusieurs principes :
<itemizedlist>
<listitem>
<para>
Les conversions implicites ne doivent jamais avoir de résultats
surprenants ou imprévisibles.
</para>
</listitem>
<listitem>
<para>
Les types utilisateurs dont l'analyseur n'a pas
à priori connaissance, devraient être
<quote>plus hauts</quote> dans la hiérarchie des types. Dans les
expressions de types mixtes, les types natifs doivent toujours être
convertis en un type utilisateur (seulement si la conversion est
nécessaire bien sûr).
</para>
</listitem>
<listitem>
<para>
Les types utilisateurs ne sont pas liés. Actuellement,
<productname>PostgreSQL</productname> n'a pas d'informations
disponibles sur les relations entre les types, autres que celles fournies
par les heuristiques codées en dur pour les types natifs et les relations
implicites basées sur les fonctions et les conversions disponibles.
</para>
</listitem>
<listitem>
<para>
Il n'y aura pas de surcharge depuis l'analyseur ou l'exécuteur si une
requête n'a pas besoin d'une conversion implicite de types. C'est-à-dire que
si une requête est bien formulée et si les types sont déjà bien distinguables,
alors la requête devra s'exécuter sans perte de temps supplémentaire et sans
introduire à l'intérieur de celle-ci des appels à des conversions
implicites non nécessaires.
</para>
<para>
De plus, si une requête nécessite habituellement une conversion
implicite pour une fonction et si l'utilisateur définit une nouvelle
fonction avec les types des arguments corrects, l'analyseur devrait
utiliser cette nouvelle fonction et ne fera plus des conversions
implicites en utilisant l'ancienne fonction.
</para>
</listitem>
</itemizedlist>
</para>
</sect1>
<sect1 id="typeconv-oper">
<title>Opérateurs</title>
<indexterm zone="typeconv-oper">
<primary>opérateur</primary>
<secondary>résolution de types dans un appel</secondary>
</indexterm>
<para>
L'opérateur spécifique à employer dans un appel d'opérateurs
est déterminé par la procédure ci-dessous. Notez que cette
procédure est indirectement affectée par l'ordre d'insertion des
opérateurs. Voir la <xref linkend="sql-precedence"/> pour plus
de détails.
</para>
<procedure>
<title>Résolution de types pour les opérateurs</title>
<step performance="required">
<para>
Sélectionner les opérateurs à examiner depuis le catalogue système
<classname>pg_operator</classname>. Si un nom non-qualifié
d'opérateur était utilisé (le cas habituel), les opérateurs examinés
sont ceux avec un nom et un nombre d'arguments corrects et qui sont
visibles dans le chemin de recherche courant (voir la
<xref linkend="ddl-schemas-path"/>). Si un nom qualifié d'opérateur
a été donné, seuls les opérateurs dans le schéma spécifié sont
examinés.
</para>
<substeps>
<step performance="optional">
<para>
Si un chemin de recherche trouve de nombreux opérateurs avec des types
d'arguments identiques, seul sera examiné celui apparaissant le plus tôt dans
le chemin. Mais les opérateurs avec des types d'arguments différents sont
examinés sur une base d'égalité indépendamment de leur position dans le chemin
de recherche.
</para>
</step>
</substeps>
</step>
<step performance="required">
<para>
Vérifier que l'opérateur accepte le type exact des arguments en
entrée. Si un opérateur existe (il peut en avoir uniquement un qui
corresponde exactement dans l'ensemble des opérateurs considérés),
utiliser cet opérateur.
</para>
<substeps>
<step performance="optional">
<para>
Si un argument lors d'une invocation d'opérateur binaire est de type
<type>unknown</type> (NdT : inconnu), alors considérer pour ce contrôle
que c'est le même type que l'autre argument. Les autres cas impliquant le
type <type>unknown</type> ne trouveront jamais une correspondance à ce
niveau.
</para>
</step>
</substeps>
</step>
<step performance="required">
<para>
Rechercher la meilleure correspondance.
</para>
<substeps>
<step performance="required">
<para>
Se débarrasser des opérateurs candidats pour lesquels les types en
entrée ne correspondent pas et qui ne peuvent pas être convertis (en
utilisant une conversion implicite) dans le type correspondant.
Le type <type>unknown</type> est supposé être convertible vers tout.
Si un candidat reste, l'utiliser, sinon aller à la
prochaine étape.
</para>
</step>
<step performance="required">
<para>
Parcourir tous les candidats et garder ceux avec la correspondance la
plus exacte par rapport aux types en entrée (les domaines sont
considérés de la même façon que leur type de base pour cette étape).
Garder tous les candidats si aucun n'a de correspondance exacte. Si
un seul candidat reste, l'utiliser ; sinon, aller à la prochaine
étape.
</para>
</step>
<step performance="required">
<para>
Parcourir tous les candidats et garder ceux qui acceptent les types
préférés (de la catégorie des types de données en entrée) aux positions
où la conversion de types aurait été requise.
Garder tous les candidats si aucun n'accepte les types préférés. Si
seulement un candidat reste, l'utiliser ; sinon aller à la prochaine
étape.
</para>
</step>
<step performance="required">
<para>
Si des arguments en entrée sont <type>inconnus</type>, vérifier la
catégorie des types acceptés à la position de ces arguments par les
candidats restants. À chaque position, sélectionner la catégorie
<type>chaîne de caractères</type> si un des candidats accepte cette
catégorie (cette préférence vers les chaînes de caractères est
appropriée car le terme type-inconnu ressemble à une chaîne de
caractères). Dans le cas contraire, si tous les candidats restants
acceptent la même catégorie de types, sélectionner cette catégorie.
Dans le cas contraire, échouer car le choix correct ne peut pas être
déduit sans plus d'indices. Se débarrasser maintenant des candidats qui
n'acceptent pas la catégorie sélectionnée. De plus, si des candidats
acceptent un type préféré comme argument donné, se débarrasser des
candidats qui acceptent, pour cet argument, les types qui ne sont pas
préférés.
</para>
</step>
<step performance="required">
<para>
Si un seul candidat reste, l'utiliser. Sinon, échouer.
</para>
</step>
</substeps>
</step>
</procedure>
<para>
Quelques exemples suivent.
</para>
<example>
<title>Résolution du type d'opérateur factoriel</title>
<para>
Il n'existe qu'un seul opérateur factoriel (<literal>!</literal> postfix)
défini dans le catalogue standard. Il prend un argument de type
<type>bigint</type>. Le scanner affecte au début le type <type>integer</type>
à l'argument dans cette expression :
<screen>
SELECT 40 ! AS "40 factorial";
40 factorial
--------------------------------------------------
815915283247897734345611269596115894272000000000
(1 row)
</screen>
L'analyseur fait donc une conversion de types sur l'opérande et
la requête est équivalente à
<screen>SELECT CAST(40 AS bigint) ! AS "40 factorial";</screen>
</para>
</example>
<example>
<title>Résolution de types pour les opérateurs de concaténation de chaînes</title>
<para>
La syntaxe d'une chaîne de caractères est utilisée pour travailler avec
les types chaînes mais aussi avec les types d'extensions complexes.
Les chaînes de caractères avec un type non spécifié sont comparées avec
les opérateurs candidats probables.
</para>
<para>
Un exemple avec un argument non spécifié :
<screen>SELECT text 'abc' || 'def' AS "text and unknown";
text and unknown
------------------
abcdef
(1 row)</screen>
</para>
<para>
Dans ce cas, l'analyseur cherche à voir s'il existe un opérateur
prenant <type>text</type> pour ses deux arguments. Comme il y en a,
il suppose que le second argument devra être interprété comme un type
<type>text</type>.
</para>
<para>
Voici une concaténation sur des types non spécifiés :
<screen>SELECT 'abc' || 'def' AS "unspecified";
unspecified
-------------
abcdef
(1 row)</screen>
</para>
<para>
Dans ce cas, il n'y a aucune allusion initiale sur quel type utiliser
puisqu'aucun type n'est spécifié dans la requête. Donc, l'analyseur
regarde pour tous les opérateurs candidats et trouve qu'il existe des
candidats acceptant en entrée la catégorie chaîne de caractères
(string) et la catégorie morceaux de chaînes (bit-string). Puisque la
catégorie chaînes de caractères est préférée quand elle est disponible,
cette catégorie est sélectionnée. Le type préféré pour la catégorie
chaînes étant <type>text</type>, ce type est utilisé comme le type
spécifique pour résoudre les types inconnus.
</para>
</example>
<example>
<title>Résolution de types pour les opérateurs de valeur absolue et de négation</title>
<para>
Le catalogue d'opérateurs de <productname>PostgreSQL</productname> a
plusieurs entrées pour l'opérateur de préfixe <literal>@</literal>. Ces entrées
implémentent toutes des opérations de valeur absolue pour des types de
données numériques variées. Une de ces entrées est pour le type
<type>float8</type> (réel) qui est le type préféré dans la catégorie
des numériques. Par conséquent, <productname>PostgreSQL</productname>
utilisera cette entrée quand il sera en face d'un argument de type
<type>unknown</type> :
<screen>SELECT @ '-4.5' AS "abs";
abs
-----
4.5
(1 row)</screen>
Le système a compris implicitement que le litéral de type
<type>unknown</type> est de type <type>float8</type> (réel) avant d'appliquer l'opérateur choisi. Nous
pouvons vérifier que <type>float8</type>, et pas un autre type, a été
utilisé :
<screen>SELECT @ '-4.5e500' AS "abs";
ERROR: "-4.5e500" is out of range for type double precision</screen>
</para>
<para>
D'un autre côté, l'opérateur préfixe <literal>~</literal> (négation bit par bit) est
défini seulement pour les types entiers et non pas pour
<type>float8</type> (réel). Ainsi, si nous essayons un cas similaire
avec <literal>~</literal>, nous obtenons :
<screen>SELECT ~ '20' AS "negation";
ERROR: operator is not unique: ~ "unknown"
HINT: Could not choose a best candidate operator. You might need to add explicit
type casts.</screen>
Ceci se produit parce que le système ne peut pas décider quel opérateur
doit être préféré parmi les différents opérateurs <literal>~</literal>
possibles. Nous pouvons l'aider avec une conversion explicite :
<screen>SELECT ~ CAST('20' AS int8) AS "negation";
negation
----------
-21
(1 row)</screen>
</para>
</example>
</sect1>
<sect1 id="typeconv-func">
<title>Fonctions</title>
<indexterm zone="typeconv-func">
<primary>fonction</primary>
<secondary>résolution de types dans un appel</secondary>
</indexterm>
<para>
La fonction spécifique à utiliser dans un appel de fonction
est déterminée selon les étapes suivantes.
</para>
<procedure>
<title>Résolution de types pour les fonctions</title>
<step performance="required">
<para>
Sélectionner les fonctions à examiner depuis le catalogue système
<classname>pg_proc</classname>. Si un nom non-qualifié de fonction
était utilisé, les fonctions examinées sont celles avec un nom et un
nombre d'arguments corrects et qui sont visibles dans le chemin de
recherche courant (voir la <xref linkend="ddl-schemas-path"/>). Si
un nom qualifié de fonctions a été donné, seules les fonctions dans le
schéma spécifique sont examinées.
</para>
<substeps>
<step performance="optional">
<para>
Si un chemin de recherche trouve de nombreuses fonctions avec des types
d'arguments identiques, seule celle apparaissant le plus tôt dans le
chemin sera examinée. Mais les fonctions avec des types d'arguments
différents sont examinées sur une base d'égalité indépendamment de leur
position dans le chemin de recherche.
</para>
</step>
</substeps>
</step>
<step performance="required">
<para>
Vérifier que la fonction accepte le type exact des arguments en entrée.
Si une fonction existe (il peut en avoir uniquement une qui correspond
exactement dans tout l'ensemble des fonctions considérées), utiliser cette
fonction (les cas impliquant le type <type>unknown</type> ne
trouveront jamais de correspondance à cette étape).
</para>
</step>
<step performance="required">
<para>
Si aucune correspondance n'est trouvée, vérifier si l'appel à la
fonction apparaît être une requête spéciale de conversion de types.
Cela arrive si l'appel à la fonction a juste un argument et si le nom
de la fonction est le même que le nom (interne) de certains types de
données. De plus, l'argument de la fonction doit être soit un type
inconnu soit un type qui a une compatibilité binaire avec le type de
données nommés, soit un type qui peut être converti dans le type de données
indiqué en appliquant les fonctions d'entrées/sorties du type (c'est-à-dire
que la conversion est vers ou à partir d'un type standard de chaîne). Quand
ces conditions sont rencontrées, l'appel de la fonction est traité sous la
forme d'une spécification <literal>CAST</literal>.
<footnote>
<para>
La raison de cette étape est le support des spécifications de conversion
au format fonction pour les cas où la vraie fonction de conversion
n'existe pas. S'il existe une fonction de conversion, elle est
habituellement nommée suivant le nom du type en sortie et donc il n'est
pas nécessaire d'avoir un cas spécial. Pour plus d'informations, voir
<xref linkend="sql-createcast" endterm="sql-createcast-title"/>.
</para>
</footnote>
</para>
</step>
<step performance="required">
<para>
Regarder pour la meilleure correspondance.
</para>
<substeps>
<step performance="required">
<para>
Se débarrasser des fonctions candidates pour lesquelles les types en
entrée ne correspondent pas et qui ne peuvent pas être convertis (en
utilisant une conversion implicite) pour correspondre. Le type
<type>unknown</type> est supposé être convertible vers n'importe quoi.
Si un seul candidat reste, utiliser le ; sinon, aller à la prochaine
étape.
</para>
</step>
<step performance="required">
<para>
Parcourir tous les candidats et garder ceux avec la correspondance la
plus exacte par rapport aux types en entrée (les domaines sont
considérés de la même façon que leur type de base pour cette étape).
Garder tous les candidats si aucun n'a de correspondance exacte. Si
un seul candidat reste, utiliser le ; sinon, aller à la prochaine
étape.
</para>
</step>
<step performance="required">
<para>
Parcourir tous les candidats et garder ceux qui acceptent les types
préférés (de la catégorie des types de données en entrée) aux positions
où la conversion de types aurait été requise. Garder tous les candidats
si aucun n'accepte les types préférés. Si un seul candidat
reste, utiliser le ; sinon, aller à la prochaine étape.
</para>
</step>
<step performance="required">
<para>
Si des arguments en entrée sont <type>unknown</type>, vérifier les
catégories de types acceptées à la position de ces arguments par les
candidats restants. À chaque position, sélectionner la catégorie
<type>chaîne de caractères</type> si un des candidats accepte cette
catégorie (cette préférence envers les chaînes de caractères est
appropriée depuis que le terme type-inconnu ressemble à une chaîne de
caractères). Dans le cas contraire, si tous les candidats restants
acceptent la même catégorie de types, sélectionner cette catégorie.
Dans le cas contraire, échouer car le choix correct ne peut pas être
déduit sans plus d'indices. Se débarrasser maintenant des candidats qui
n'acceptent pas la catégorie sélectionnée. De plus, si des candidats
acceptent un type préféré comme argument donné, se débarrasser des
candidats qui acceptent, pour cet argument, les types qui ne sont pas
préférés.
</para>
</step>
<step performance="required">
<para>
Si un seul candidat reste, utiliser le. Sinon, échouer.
</para>
</step>
</substeps>
</step>
</procedure>
<para>
Notez que les règles de <quote>correspondance optimale</quote> sont
identiques pour la résolution de types concernant les opérateurs et les
fonctions. Quelques exemples suivent.
</para>
<example>
<title>Résolution de types pour les arguments de la fonction arrondie</title>
<para>
Il n'existe qu'une seule fonction <function>round</function>
avec deux arguments (le premier est un <type>numeric</type>, le
second est un <type>integer</type>). Ainsi, la requête suivante
convertie automatiquement le type du premier argument de
<type>integer</type> vers <type>numeric</type>.
<screen>SELECT round(4, 4);
round
--------
4.0000
(1 row)</screen>
La requête est en fait transformée par l'analyseur en
<screen>SELECT round(CAST (4 AS numeric), 4);</screen>
</para>
<para>
Puisque le type <type>numeric</type> est initialement assigné aux
constantes numériques avec un point décimal, la requête suivante ne
requièrera pas une conversion de types et pourra par conséquent être
un peu plus efficace :
<screen>SELECT round(4.0, 4);</screen>
</para>
</example>
<example>
<title>Résolution de types pour les fonctions retournant un segment de chaîne</title>
<para>
Il existe plusieurs fonctions <function>substr</function>, une d'entre
elles prend les types <type>text</type> et <type>integer</type>. Si
cette fonction est appelée avec une constante de chaînes d'un type
inconnu, le système choisi la fonction candidate qui accepte un
argument issu de la catégorie préférée <type>string</type>
(c'est-à-dire de type <type>text</type>).
<screen>SELECT substr('1234', 3);
substr
--------
34
(1 row)</screen>
</para>
<para>
Si la chaîne de caractères est déclarée comme étant du type
<type>varchar</type> (chaîne de caractères de longueur variable), ce
qui peut être le cas si elle vient d'une table, alors l'analyseur
essayera de la convertir en <type>text</type> :
<screen>SELECT substr(varchar '1234', 3);
substr
--------
34
(1 row)</screen>
Ceci est transformé par l'analyseur en
<screen>SELECT substr(CAST (varchar '1234' AS text), 3);</screen>
</para>
<para>
<note>
<para>
L'analyseur apprend depuis le catalogue <structname>pg_cast</structname> que les
types <type>text</type> et <type>varchar</type> ont une compatibilité
binaire, ce qui veut dire que l'un peut être passé à une fonction qui
accepte l'autre sans avoir à faire aucune conversion physique. Par
conséquent, aucun appel de conversion de types n'est
réellement inséré dans ce cas.
</para>
</note>
</para>
<para>
Et si la fonction est appelée avec un argument de type
<type>integer</type>, l'analyseur essaie de le convertir en
<type>text</type> :
<screen>
SELECT substr(1234, 3);
ERROR: function substr(integer, integer) does not exist
HINT: No function matches the given name and argument types. You might need
to add explicit type casts.
</screen>
Ceci ne fonctionne pas car <type>integer</type> n'a pas de conversion
implicite vers <type>text</type>. Néanmoins, une conversion explicite
fonctionnera :
<screen>
SELECT substr(CAST (1234 AS text), 3);
substr
--------
34
(1 row)
</screen>
</para>
</example>
</sect1>
<sect1 id="typeconv-query">
<title>Stockage de valeurs</title>
<para>
Les valeurs qui doivent être insérées dans une table sont converties
vers le type de données de la colonne de destination selon les
règles suivantes.
</para>
<procedure>
<title>Conversion de types pour le stockage de valeurs</title>
<step performance="required">
<para>
Vérifier qu'il y a une correspondance exacte avec la cible.
</para>
</step>
<step performance="required">
<para>
Dans le cas contraire, essayer de convertir l'expression vers le type
cible. Cela réussira s'il y a une conversion (cast) enregistrée entre
ces deux types. Si une expression est de type inconnu, le contenu de
la chaîne littérale sera fourni à l'entrée de la routine de conversion
pour le type cible.
</para>
</step>
<step performance="required">
<para>
Vérifier s'il y a une conversion de taille pour le type cible. Une conversion
de taille est une conversion d'un type vers lui-même. Si elle est trouvée dans
le catalogue <structname>pg_cast</structname>, appliquez-la à l'expression avant de la
stocker dans la colonne de destination. La fonction d'implémentation pour une
telle conversion prend toujours un paramètre supplémentaire de type
<type>integer</type>, qui reçoit la longueur déclarée de la colonne de
destination (en fait, il s'agit de la valeur <structfield>atttypmod</structfield> ;
l'interprétation de <structfield>atttypmod</structfield> varie pour les différents types de
données). La fonction de conversion est responsable de l'application de toute
sémantique dépendante de la longueur comme la vérification de la taille ou une
troncature.
</para>
</step>
</procedure>
<example>
<title>Conversion de types pour le stockage de <type>character</type></title>
<para>
Pour une colonne cible déclarée comme <type>character(20)</type>, la
déclaration suivante assure que la valeur stockée a la taille correcte :
<screen>CREATE TABLE vv (v character(20));
INSERT INTO vv SELECT 'abc' || 'def';
SELECT v, length(v) FROM vv;
v | length
----------------------+--------
abcdef | 20
(1 row)</screen>
</para>
<para>
Voici ce qui s'est réellement passé ici : les deux types inconnus
sont résolus en <type>text</type> par défaut, permettant à l'opérateur
<literal>||</literal> de les résoudre comme une concaténation de
<type>text</type>. Ensuite, le résultat <type>text</type> de
l'opérateur est converti en <type>bpchar</type> (
<quote>blank-padded char</quote>, le nom interne du type de données
<type>character</type> (caractère)) pour correspondre au type de la
colonne cible (comme les types <type>text</type> et
<type>bpchar</type> ont une compatibilité binaire, cette conversion
n'insère aucun appel réel à une fonction). Enfin, la fonction de
taille <literal>bpchar(bpchar, integer)</literal> est trouvée dans le
catalogue système et appliquée au résultat de l'opérateur et à la
longueur de la colonne stockée. Cette fonction de type spécifique
effectue le contrôle de la longueur requise et ajoute des espaces pour
combler la chaîne.
</para>
</example>
</sect1>
<sect1 id="typeconv-union-case">
<title>Constructions <literal>UNION</literal>, <literal>CASE</literal> et
constructions relatives</title>
<indexterm zone="typeconv-union-case">
<primary>UNION</primary>
<secondary>détermination du type de résultat</secondary>
</indexterm>
<indexterm zone="typeconv-union-case">
<primary>CASE</primary>
<secondary>détermination du type de résultat</secondary>
</indexterm>
<indexterm zone="typeconv-union-case">
<primary>ARRAY</primary>
<secondary>détermination du type de résultat</secondary>
</indexterm>
<indexterm zone="typeconv-union-case">
<primary>VALUES</primary>
<secondary>détermination du type de résultat</secondary>
</indexterm>
<indexterm zone="typeconv-union-case">
<primary>GREATEST</primary>
<secondary>détermination du type de résultat</secondary>
</indexterm>
<indexterm zone="typeconv-union-case">
<primary>LEAST</primary>
<secondary>détermination du type de résultat</secondary>
</indexterm>
<para>
Les constructions SQL avec des <literal>UNION</literal> doivent
potentiellement faire correspondre des types différents pour avoir un
ensemble unique dans le résultat. L'algorithme de résolution est
appliqué séparément à chaque colonne de sortie d'une requête d'union.
Les constructions <literal>INTERSECT</literal> et <literal>EXCEPT</literal> résolvent
des types différents de la même manière qu'<literal>UNION</literal>. Les
constructions <literal>CASE</literal>, <literal>ARRAY</literal>,
<function>VALUES</function>, <function>GREATEST</function> et
<function>LEAST</function> utilisent le même
algorithme pour faire correspondre les expressions qui les composent et
sélectionner un type de résultat.
</para>
<procedure>
<title>Résolution des types pour <literal>UNION</literal>,
<literal>CASE</literal> et les constructions relatives</title>
<step performance="required">
<para>
Si toutes les entrées sont du même type et qu'il ne s'agit pas du type
<type>unknown</type>, résoudre comme étant de ce type. Sinon, remplacer
tous les types de domaine dans la liste avec les types de base sous-jacents.
</para>
</step>
<step performance="required">
<para>
Si toutes les entrées sont du type <type>unknown</type>, résoudre comme
étant du type <type>text</type> (le type préféré de la catégorie
chaîne). Dans le cas contraire, les entrées
<type>unknown</type> seront ignorées.
</para>
</step>
<step performance="required">
<para>
Si toutes les entrées non-inconnues ne sont pas toutes de la même
catégorie, échouer.
</para>
</step>
<step performance="required">
<para>
Choisir la première entrée non-inconnue qui est un type préféré dans
sa catégorie, s'il y en a une.
</para>
</step>
<step performance="required">
<para>
Sinon, choisir le dernier type en entrée qui ne soit pas inconnu et qui
permet à toutes les entrées précédentes qui ne sont pas inconnues à être
implicitement converties. (Il y a toujours un type de ce genre car au moins
le premier type dans la liste doit satisfaire cette condition.)
</para>
</step>
<step performance="required">
<para>
Convertir toutes les entrées du type sélectionné. Échoue s'il n'y a pas de
conversion à partir de l'entrée donnée vers le type sélectionné.
</para>
</step>
</procedure>
<para>
Quelques exemples suivent.
</para>
<example>
<title>Résolution de types avec des types sous-spécifiés dans une union</title>
<para>
<screen>SELECT text 'a' AS "text" UNION SELECT 'b';
text
------
a
b
(2 rows)</screen>
Ici, la chaîne de type inconnu <literal>'b'</literal> sera convertie
vers le type <type>text</type>.
</para>
</example>
<example>
<title>Résolution de types dans une union simple</title>
<para>
<screen>SELECT 1.2 AS "numeric" UNION SELECT 1;
numeric
---------
1
1.2
(2 rows)</screen>
Le littéral <literal>1.2</literal> est du type <type>numeric</type> et la valeur
<literal>1</literal>, de type <type>integer</type>, peut
être convertie implicitement vers un type <type>numeric</type>, donc ce
type est utilisé.
</para>
</example>
<example>
<title>Résolution de types dans une union transposée</title>
<para>
<screen>SELECT 1 AS "real" UNION SELECT CAST('2.2' AS REAL);
real
------
1
2.2
(2 rows)</screen>
Dans cet exemple, le type <type>real</type> (réel) ne peut pas être
implicitement converti en <type>integer</type> (entier) mais un
<type>integer</type> peut être implicitement converti en <type>real</type> ; le
résultat de l'union est résolu comme étant un <type>real</type>.
</para>
</example>
</sect1>
</chapter>