7
7
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
8
8
* Portions Copyright (c) 1994, Regents of the University of California
9
9
*
10
- * $PostgreSQL: pgsql/src/backend/utils/adt/xml.c,v 1.49 2007/10/13 20:46:47 tgl Exp $
10
+ * $PostgreSQL: pgsql/src/backend/utils/adt/xml.c,v 1.50 2007/11/05 22:23:07 tgl Exp $
11
11
*
12
12
*-------------------------------------------------------------------------
13
13
*/
73
73
#include "utils/xml.h"
74
74
75
75
76
+ /* GUC variables */
77
+ XmlBinaryType xmlbinary ;
78
+ XmlOptionType xmloption ;
79
+
76
80
#ifdef USE_LIBXML
77
81
78
82
static StringInfo xml_err_buf = NULL ;
@@ -104,11 +108,6 @@ static const char * map_sql_typecoll_to_xmlschema_types(List *tupdesc_list);
104
108
static const char * map_sql_type_to_xmlschema_type (Oid typeoid , int typmod );
105
109
static void SPI_sql_row_to_xmlelement (int rownum , StringInfo result , char * tablename , bool nulls , bool tableforest , const char * targetns , bool top_level );
106
110
107
-
108
- XmlBinaryType xmlbinary ;
109
- XmlOptionType xmloption ;
110
-
111
-
112
111
#define NO_XML_SUPPORT () \
113
112
ereport(ERROR, \
114
113
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED), \
@@ -217,7 +216,8 @@ xml_out_internal(xmltype *x, pg_enc target_encoding)
217
216
}
218
217
219
218
xml_ereport_by_code (WARNING , ERRCODE_INTERNAL_ERROR ,
220
- "could not parse XML declaration in stored value" , res_code );
219
+ "could not parse XML declaration in stored value" ,
220
+ res_code );
221
221
#endif
222
222
return str ;
223
223
}
@@ -540,52 +540,92 @@ xmlelement(XmlExprState *xmlExpr, ExprContext *econtext)
540
540
{
541
541
#ifdef USE_LIBXML
542
542
XmlExpr * xexpr = (XmlExpr * ) xmlExpr -> xprstate .expr ;
543
+ xmltype * result ;
544
+ List * named_arg_strings ;
545
+ List * arg_strings ;
543
546
int i ;
544
547
ListCell * arg ;
545
548
ListCell * narg ;
546
- bool isnull ;
547
- xmltype * result ;
548
- Datum value ;
549
- char * str ;
550
-
551
549
xmlBufferPtr buf ;
552
550
xmlTextWriterPtr writer ;
553
551
554
- buf = xmlBufferCreate ();
555
- writer = xmlNewTextWriterMemory (buf , 0 );
556
-
557
- xmlTextWriterStartElement (writer , (xmlChar * ) xexpr -> name );
558
-
552
+ /*
553
+ * We first evaluate all the arguments, then start up libxml and
554
+ * create the result. This avoids issues if one of the arguments
555
+ * involves a call to some other function or subsystem that wants to use
556
+ * libxml on its own terms.
557
+ */
558
+ named_arg_strings = NIL ;
559
559
i = 0 ;
560
- forboth (arg , xmlExpr -> named_args , narg , xexpr -> arg_names )
560
+ foreach (arg , xmlExpr -> named_args )
561
561
{
562
562
ExprState * e = (ExprState * ) lfirst (arg );
563
- char * argname = strVal (lfirst (narg ));
563
+ Datum value ;
564
+ bool isnull ;
565
+ char * str ;
564
566
565
567
value = ExecEvalExpr (e , econtext , & isnull , NULL );
566
- if (!isnull )
567
- {
568
+ if (isnull )
569
+ str = NULL ;
570
+ else
568
571
str = OutputFunctionCall (& xmlExpr -> named_outfuncs [i ], value );
569
- xmlTextWriterWriteAttribute (writer , (xmlChar * ) argname , (xmlChar * ) str );
570
- pfree (str );
571
- }
572
+ named_arg_strings = lappend (named_arg_strings , str );
572
573
i ++ ;
573
574
}
574
575
576
+ arg_strings = NIL ;
575
577
foreach (arg , xmlExpr -> args )
576
578
{
577
579
ExprState * e = (ExprState * ) lfirst (arg );
580
+ Datum value ;
581
+ bool isnull ;
582
+ char * str ;
578
583
579
584
value = ExecEvalExpr (e , econtext , & isnull , NULL );
585
+ /* here we can just forget NULL elements immediately */
580
586
if (!isnull )
581
- xmlTextWriterWriteRaw (writer , (xmlChar * ) map_sql_value_to_xml_value (value , exprType ((Node * ) e -> expr )));
587
+ {
588
+ str = map_sql_value_to_xml_value (value ,
589
+ exprType ((Node * ) e -> expr ));
590
+ arg_strings = lappend (arg_strings , str );
591
+ }
592
+ }
593
+
594
+ /* now safe to run libxml */
595
+ xml_init ();
596
+
597
+ buf = xmlBufferCreate ();
598
+ writer = xmlNewTextWriterMemory (buf , 0 );
599
+
600
+ xmlTextWriterStartElement (writer , (xmlChar * ) xexpr -> name );
601
+
602
+ forboth (arg , named_arg_strings , narg , xexpr -> arg_names )
603
+ {
604
+ char * str = (char * ) lfirst (arg );
605
+ char * argname = strVal (lfirst (narg ));
606
+
607
+ if (str )
608
+ {
609
+ xmlTextWriterWriteAttribute (writer ,
610
+ (xmlChar * ) argname ,
611
+ (xmlChar * ) str );
612
+ pfree (str );
613
+ }
614
+ }
615
+
616
+ foreach (arg , arg_strings )
617
+ {
618
+ char * str = (char * ) lfirst (arg );
619
+
620
+ xmlTextWriterWriteRaw (writer , (xmlChar * ) str );
582
621
}
583
622
584
623
xmlTextWriterEndElement (writer );
585
624
xmlFreeTextWriter (writer );
586
625
587
626
result = xmlBuffer_to_xmltype (buf );
588
627
xmlBufferFree (buf );
628
+
589
629
return result ;
590
630
#else
591
631
NO_XML_SUPPORT ();
@@ -733,9 +773,10 @@ xmlvalidate(PG_FUNCTION_ARGS)
733
773
734
774
xml_init ();
735
775
736
- /* We use a PG_TRY block to ensure libxml is cleaned up on error */
776
+ /* We use a PG_TRY block to ensure libxml parser is cleaned up on error */
737
777
PG_TRY ();
738
778
{
779
+ xmlInitParser ();
739
780
ctxt = xmlNewParserCtxt ();
740
781
if (ctxt == NULL )
741
782
xml_ereport (ERROR , ERRCODE_INTERNAL_ERROR ,
@@ -860,43 +901,64 @@ xml_is_document(xmltype *arg)
860
901
#ifdef USE_LIBXML
861
902
862
903
/*
863
- * Container for some init stuff (not good design!)
864
- * TODO xmlChar is utf8-char, make proper tuning (initdb with enc!=utf8 and check)
904
+ * Set up for use of libxml --- this should be called by each function that
905
+ * is about to use libxml facilities.
906
+ *
907
+ * TODO: xmlChar is utf8-char, make proper tuning (initdb with enc!=utf8 and
908
+ * check)
865
909
*/
866
910
static void
867
911
xml_init (void )
868
912
{
869
- /*
870
- * Currently, we have no pure UTF-8 support for internals -- check
871
- * if we can work.
872
- */
873
- if (sizeof (char ) != sizeof (xmlChar ))
874
- ereport (ERROR ,
875
- (errmsg ("could not initialize XML library" ),
876
- errdetail ("libxml2 has incompatible char type: sizeof(char)=%u, sizeof(xmlChar)=%u." ,
877
- (int ) sizeof (char ), (int ) sizeof (xmlChar ))));
913
+ static bool first_time = true;
878
914
879
- if (xml_err_buf == NULL )
915
+ if (first_time )
880
916
{
881
- /* First time through: create error buffer in permanent context */
917
+ /* Stuff we need do only once per session */
882
918
MemoryContext oldcontext ;
883
919
920
+ /*
921
+ * Currently, we have no pure UTF-8 support for internals -- check
922
+ * if we can work.
923
+ */
924
+ if (sizeof (char ) != sizeof (xmlChar ))
925
+ ereport (ERROR ,
926
+ (errmsg ("could not initialize XML library" ),
927
+ errdetail ("libxml2 has incompatible char type: sizeof(char)=%u, sizeof(xmlChar)=%u." ,
928
+ (int ) sizeof (char ), (int ) sizeof (xmlChar ))));
929
+
930
+ /* create error buffer in permanent context */
884
931
oldcontext = MemoryContextSwitchTo (TopMemoryContext );
885
932
xml_err_buf = makeStringInfo ();
886
933
MemoryContextSwitchTo (oldcontext );
934
+
935
+ /* Now that xml_err_buf exists, safe to call xml_errorHandler */
936
+ xmlSetGenericErrorFunc (NULL , xml_errorHandler );
937
+
938
+ /* Set up memory allocation our way, too */
939
+ xmlMemSetup (xml_pfree , xml_palloc , xml_repalloc , xml_pstrdup );
940
+
941
+ /* Check library compatibility */
942
+ LIBXML_TEST_VERSION ;
943
+
944
+ first_time = false;
887
945
}
888
946
else
889
947
{
890
948
/* Reset pre-existing buffer to empty */
949
+ Assert (xml_err_buf != NULL );
891
950
resetStringInfo (xml_err_buf );
892
- }
893
- /* Now that xml_err_buf exists, safe to call xml_errorHandler */
894
- xmlSetGenericErrorFunc (NULL , xml_errorHandler );
895
-
896
- xmlMemSetup (xml_pfree , xml_palloc , xml_repalloc , xml_pstrdup );
897
951
898
- xmlInitParser ();
899
- LIBXML_TEST_VERSION ;
952
+ /*
953
+ * We re-establish the callback functions every time. This makes it
954
+ * safe for other subsystems (PL/Perl, say) to also use libxml with
955
+ * their own callbacks ... so long as they likewise set up the
956
+ * callbacks on every use. It's cheap enough to not be worth
957
+ * worrying about, anyway.
958
+ */
959
+ xmlSetGenericErrorFunc (NULL , xml_errorHandler );
960
+ xmlMemSetup (xml_pfree , xml_palloc , xml_repalloc , xml_pstrdup );
961
+ }
900
962
}
901
963
902
964
@@ -1071,9 +1133,10 @@ print_xml_decl(StringInfo buf, const xmlChar *version, pg_enc encoding, int stan
1071
1133
appendStringInfo (buf , " version=\"%s\"" , PG_XML_DEFAULT_VERSION );
1072
1134
1073
1135
if (encoding && encoding != PG_UTF8 )
1074
- /* XXX might be useful to convert this to IANA names
1075
- * (ISO-8859-1 instead of LATIN1 etc.); needs field
1076
- * experience */
1136
+ /*
1137
+ * XXX might be useful to convert this to IANA names
1138
+ * (ISO-8859-1 instead of LATIN1 etc.); needs field experience
1139
+ */
1077
1140
appendStringInfo (buf , " encoding=\"%s\"" , pg_encoding_to_char (encoding ));
1078
1141
1079
1142
if (standalone == 1 )
@@ -1115,9 +1178,10 @@ xml_parse(text *data, XmlOptionType xmloption_arg, bool preserve_whitespace, xml
1115
1178
1116
1179
xml_init ();
1117
1180
1118
- /* We use a PG_TRY block to ensure libxml is cleaned up on error */
1181
+ /* We use a PG_TRY block to ensure libxml parser is cleaned up on error */
1119
1182
PG_TRY ();
1120
1183
{
1184
+ xmlInitParser ();
1121
1185
ctxt = xmlNewParserCtxt ();
1122
1186
if (ctxt == NULL )
1123
1187
xml_ereport (ERROR , ERRCODE_INTERNAL_ERROR ,
@@ -1780,7 +1844,7 @@ schema_get_xml_visible_tables(Oid nspid)
1780
1844
StringInfoData query ;
1781
1845
1782
1846
initStringInfo (& query );
1783
- appendStringInfo (& query , "SELECT oid FROM pg_class WHERE relnamespace = %u AND relkind IN ('r', 'v') AND has_table_privilege (oid, 'SELECT') ORDER BY relname;" , nspid );
1847
+ appendStringInfo (& query , "SELECT oid FROM pg_catalog. pg_class WHERE relnamespace = %u AND relkind IN ('r', 'v') AND pg_catalog. has_table_privilege (oid, 'SELECT') ORDER BY relname;" , nspid );
1784
1848
1785
1849
return query_to_oid_list (query .data );
1786
1850
}
@@ -1792,7 +1856,7 @@ schema_get_xml_visible_tables(Oid nspid)
1792
1856
*/
1793
1857
#define XML_VISIBLE_SCHEMAS_EXCLUDE "nspname LIKE 'pg_%' ESCAPE '' OR nspname = 'information_schema'"
1794
1858
1795
- #define XML_VISIBLE_SCHEMAS "SELECT oid FROM pg_namespace WHERE has_schema_privilege (oid, 'USAGE') AND NOT (" XML_VISIBLE_SCHEMAS_EXCLUDE ")"
1859
+ #define XML_VISIBLE_SCHEMAS "SELECT oid FROM pg_catalog. pg_namespace WHERE pg_catalog. has_schema_privilege (oid, 'USAGE') AND NOT (" XML_VISIBLE_SCHEMAS_EXCLUDE ")"
1796
1860
1797
1861
1798
1862
static List *
@@ -1806,7 +1870,7 @@ static List *
1806
1870
database_get_xml_visible_tables (void )
1807
1871
{
1808
1872
/* At the moment there is no order required here. */
1809
- return query_to_oid_list ("SELECT oid FROM pg_class WHERE relkind IN ('r', 'v') AND has_table_privilege (pg_class.oid, 'SELECT') AND relnamespace IN (" XML_VISIBLE_SCHEMAS ");" );
1873
+ return query_to_oid_list ("SELECT oid FROM pg_catalog. pg_class WHERE relkind IN ('r', 'v') AND pg_catalog. has_table_privilege (pg_class.oid, 'SELECT') AND relnamespace IN (" XML_VISIBLE_SCHEMAS ");" );
1810
1874
}
1811
1875
1812
1876
@@ -2973,7 +3037,6 @@ SPI_sql_row_to_xmlelement(int rownum, StringInfo result, char *tablename, bool n
2973
3037
{
2974
3038
if (nulls )
2975
3039
appendStringInfo (result , " <%s xsi:nil='true'/>\n" , colname );
2976
-
2977
3040
}
2978
3041
else
2979
3042
appendStringInfo (result , " <%s>%s</%s>\n" ,
@@ -3170,10 +3233,12 @@ xpath(PG_FUNCTION_ARGS)
3170
3233
3171
3234
xml_init ();
3172
3235
3236
+ /* We use a PG_TRY block to ensure libxml parser is cleaned up on error */
3173
3237
PG_TRY ();
3174
3238
{
3239
+ xmlInitParser ();
3175
3240
/*
3176
- * redundant XML parsing (two parsings for the same value *
3241
+ * redundant XML parsing (two parsings for the same value
3177
3242
* during one command execution are possible)
3178
3243
*/
3179
3244
ctxt = xmlNewParserCtxt ();
0 commit comments