summaryrefslogtreecommitdiffstats
path: root/contrib
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--contrib/amcheck/expected/check_btree.out23
-rw-r--r--contrib/amcheck/sql/check_btree.sql17
-rw-r--r--contrib/amcheck/verify_nbtree.c49
-rw-r--r--contrib/postgres_fdw/connection.c8
-rw-r--r--contrib/postgres_fdw/deparse.c25
-rw-r--r--contrib/postgres_fdw/expected/postgres_fdw.out93
-rw-r--r--contrib/postgres_fdw/postgres_fdw.c18
-rw-r--r--contrib/postgres_fdw/sql/postgres_fdw.sql32
-rw-r--r--contrib/xml2/xpath.c11
-rw-r--r--contrib/xml2/xslt_proc.c10
10 files changed, 225 insertions, 61 deletions
diff --git a/contrib/amcheck/expected/check_btree.out b/contrib/amcheck/expected/check_btree.out
index 38791bb..2acbc98 100644
--- a/contrib/amcheck/expected/check_btree.out
+++ b/contrib/amcheck/expected/check_btree.out
@@ -199,6 +199,28 @@ SELECT bt_index_check('bttest_a_expr_idx', true);
(1 row)
+-- Check support of both 1B and 4B header sizes of short varlena datum
+CREATE TABLE varlena_bug (v text);
+ALTER TABLE varlena_bug ALTER column v SET storage plain;
+INSERT INTO varlena_bug VALUES ('x');
+COPY varlena_bug from stdin;
+CREATE INDEX varlena_bug_idx on varlena_bug(v);
+SELECT bt_index_check('varlena_bug_idx', true);
+ bt_index_check
+----------------
+
+(1 row)
+
+-- Also check that we compress varlena values, which were previously stored
+-- uncompressed in index.
+INSERT INTO varlena_bug VALUES (repeat('Test', 250));
+ALTER TABLE varlena_bug ALTER COLUMN v SET STORAGE extended;
+SELECT bt_index_check('varlena_bug_idx', true);
+ bt_index_check
+----------------
+
+(1 row)
+
-- cleanup
DROP TABLE bttest_a;
DROP TABLE bttest_b;
@@ -208,3 +230,4 @@ DROP TABLE toast_bug;
DROP FUNCTION ifun(int8);
DROP OWNED BY regress_bttest_role; -- permissions
DROP ROLE regress_bttest_role;
+DROP TABLE varlena_bug;
diff --git a/contrib/amcheck/sql/check_btree.sql b/contrib/amcheck/sql/check_btree.sql
index 033c04b..e2f47fc 100644
--- a/contrib/amcheck/sql/check_btree.sql
+++ b/contrib/amcheck/sql/check_btree.sql
@@ -135,6 +135,22 @@ CREATE INDEX bttest_a_expr_idx ON bttest_a ((ifun(id) + ifun(0)))
SELECT bt_index_check('bttest_a_expr_idx', true);
+-- Check support of both 1B and 4B header sizes of short varlena datum
+CREATE TABLE varlena_bug (v text);
+ALTER TABLE varlena_bug ALTER column v SET storage plain;
+INSERT INTO varlena_bug VALUES ('x');
+COPY varlena_bug from stdin;
+x
+\.
+CREATE INDEX varlena_bug_idx on varlena_bug(v);
+SELECT bt_index_check('varlena_bug_idx', true);
+
+-- Also check that we compress varlena values, which were previously stored
+-- uncompressed in index.
+INSERT INTO varlena_bug VALUES (repeat('Test', 250));
+ALTER TABLE varlena_bug ALTER COLUMN v SET STORAGE extended;
+SELECT bt_index_check('varlena_bug_idx', true);
+
-- cleanup
DROP TABLE bttest_a;
DROP TABLE bttest_b;
@@ -144,3 +160,4 @@ DROP TABLE toast_bug;
DROP FUNCTION ifun(int8);
DROP OWNED BY regress_bttest_role; -- permissions
DROP ROLE regress_bttest_role;
+DROP TABLE varlena_bug;
diff --git a/contrib/amcheck/verify_nbtree.c b/contrib/amcheck/verify_nbtree.c
index 1886bd2..c08f19f 100644
--- a/contrib/amcheck/verify_nbtree.c
+++ b/contrib/amcheck/verify_nbtree.c
@@ -23,6 +23,7 @@
*/
#include "postgres.h"
+#include "access/heaptoast.h"
#include "access/htup_details.h"
#include "access/nbtree.h"
#include "access/table.h"
@@ -2641,7 +2642,7 @@ bt_normalize_tuple(BtreeCheckState *state, IndexTuple itup)
TupleDesc tupleDescriptor = RelationGetDescr(state->rel);
Datum normalized[INDEX_MAX_KEYS];
bool isnull[INDEX_MAX_KEYS];
- bool toast_free[INDEX_MAX_KEYS];
+ bool need_free[INDEX_MAX_KEYS];
bool formnewtup = false;
IndexTuple reformed;
int i;
@@ -2660,7 +2661,7 @@ bt_normalize_tuple(BtreeCheckState *state, IndexTuple itup)
att = TupleDescAttr(tupleDescriptor, i);
/* Assume untoasted/already normalized datum initially */
- toast_free[i] = false;
+ need_free[i] = false;
normalized[i] = index_getattr(itup, att->attnum,
tupleDescriptor,
&isnull[i]);
@@ -2679,15 +2680,48 @@ bt_normalize_tuple(BtreeCheckState *state, IndexTuple itup)
ItemPointerGetBlockNumber(&(itup->t_tid)),
ItemPointerGetOffsetNumber(&(itup->t_tid)),
RelationGetRelationName(state->rel))));
+ else if (!VARATT_IS_COMPRESSED(DatumGetPointer(normalized[i])) &&
+ VARSIZE(DatumGetPointer(normalized[i])) > TOAST_INDEX_TARGET &&
+ (att->attstorage == TYPSTORAGE_EXTENDED ||
+ att->attstorage == TYPSTORAGE_MAIN))
+ {
+ /*
+ * This value will be compressed by index_form_tuple() with the
+ * current storage settings. We may be here because this tuple
+ * was formed with different storage settings. So, force forming.
+ */
+ formnewtup = true;
+ }
else if (VARATT_IS_COMPRESSED(DatumGetPointer(normalized[i])))
{
formnewtup = true;
normalized[i] = PointerGetDatum(PG_DETOAST_DATUM(normalized[i]));
- toast_free[i] = true;
+ need_free[i] = true;
+ }
+
+ /*
+ * Short tuples may have 1B or 4B header. Convert 4B header of short
+ * tuples to 1B
+ */
+ else if (VARATT_CAN_MAKE_SHORT(DatumGetPointer(normalized[i])))
+ {
+ /* convert to short varlena */
+ Size len = VARATT_CONVERTED_SHORT_SIZE(DatumGetPointer(normalized[i]));
+ char *data = palloc(len);
+
+ SET_VARSIZE_SHORT(data, len);
+ memcpy(data + 1, VARDATA(DatumGetPointer(normalized[i])), len - 1);
+
+ formnewtup = true;
+ normalized[i] = PointerGetDatum(data);
+ need_free[i] = true;
}
}
- /* Easier case: Tuple has varlena datums, none of which are compressed */
+ /*
+ * Easier case: Tuple has varlena datums, none of which are compressed or
+ * short with 4B header
+ */
if (!formnewtup)
return itup;
@@ -2697,6 +2731,11 @@ bt_normalize_tuple(BtreeCheckState *state, IndexTuple itup)
* (normalized input datums). This is rather naive, but shouldn't be
* necessary too often.
*
+ * In the heap, tuples may contain short varlena datums with both 1B
+ * header and 4B headers. But the corresponding index tuple should always
+ * have such varlena's with 1B headers. So, if there is a short varlena
+ * with 4B header, we need to convert it for for fingerprinting.
+ *
* Note that we rely on deterministic index_form_tuple() TOAST compression
* of normalized input.
*/
@@ -2705,7 +2744,7 @@ bt_normalize_tuple(BtreeCheckState *state, IndexTuple itup)
/* Cannot leak memory here */
for (i = 0; i < tupleDescriptor->natts; i++)
- if (toast_free[i])
+ if (need_free[i])
pfree(DatumGetPointer(normalized[i]));
return reformed;
diff --git a/contrib/postgres_fdw/connection.c b/contrib/postgres_fdw/connection.c
index 5187ea8..db2a2c4 100644
--- a/contrib/postgres_fdw/connection.c
+++ b/contrib/postgres_fdw/connection.c
@@ -612,10 +612,12 @@ configure_remote_session(PGconn *conn)
* anyway. However it makes the regression test outputs more predictable.
*
* We don't risk setting remote zone equal to ours, since the remote
- * server might use a different timezone database. Instead, use UTC
- * (quoted, because very old servers are picky about case).
+ * server might use a different timezone database. Instead, use GMT
+ * (quoted, because very old servers are picky about case). That's
+ * guaranteed to work regardless of the remote's timezone database,
+ * because pg_tzset() hard-wires it (at least in PG 9.2 and later).
*/
- do_sql_command(conn, "SET timezone = 'UTC'");
+ do_sql_command(conn, "SET timezone = 'GMT'");
/*
* Set values needed to ensure unambiguous data output from remote. (This
diff --git a/contrib/postgres_fdw/deparse.c b/contrib/postgres_fdw/deparse.c
index 8f4d8a5..d7235a5 100644
--- a/contrib/postgres_fdw/deparse.c
+++ b/contrib/postgres_fdw/deparse.c
@@ -3624,13 +3624,12 @@ appendOrderByClause(List *pathkeys, bool has_final_sort,
{
ListCell *lcell;
int nestlevel;
- const char *delim = " ";
StringInfo buf = context->buf;
+ bool gotone = false;
/* Make sure any constants in the exprs are printed portably */
nestlevel = set_transmission_modes();
- appendStringInfoString(buf, " ORDER BY");
foreach(lcell, pathkeys)
{
PathKey *pathkey = lfirst(lcell);
@@ -3664,6 +3663,26 @@ appendOrderByClause(List *pathkeys, bool has_final_sort,
em_expr = em->em_expr;
/*
+ * If the member is a Const expression then we needn't add it to the
+ * ORDER BY clause. This can happen in UNION ALL queries where the
+ * union child targetlist has a Const. Adding these would be
+ * wasteful, but also, for INT columns, an integer literal would be
+ * seen as an ordinal column position rather than a value to sort by.
+ * deparseConst() does have code to handle this, but it seems less
+ * effort on all accounts just to skip these for ORDER BY clauses.
+ */
+ if (IsA(em_expr, Const))
+ continue;
+
+ if (!gotone)
+ {
+ appendStringInfoString(buf, " ORDER BY ");
+ gotone = true;
+ }
+ else
+ appendStringInfoString(buf, ", ");
+
+ /*
* Lookup the operator corresponding to the strategy in the opclass.
* The datatype used by the opfamily is not necessarily the same as
* the expression type (for array types for example).
@@ -3677,7 +3696,6 @@ appendOrderByClause(List *pathkeys, bool has_final_sort,
pathkey->pk_strategy, em->em_datatype, em->em_datatype,
pathkey->pk_opfamily);
- appendStringInfoString(buf, delim);
deparseExpr(em_expr, context);
/*
@@ -3687,7 +3705,6 @@ appendOrderByClause(List *pathkeys, bool has_final_sort,
appendOrderBySuffix(oprid, exprType((Node *) em_expr),
pathkey->pk_nulls_first, context);
- delim = ", ";
}
reset_transmission_modes(nestlevel);
}
diff --git a/contrib/postgres_fdw/expected/postgres_fdw.out b/contrib/postgres_fdw/expected/postgres_fdw.out
index d21a3d8..d7fdc6b 100644
--- a/contrib/postgres_fdw/expected/postgres_fdw.out
+++ b/contrib/postgres_fdw/expected/postgres_fdw.out
@@ -893,32 +893,6 @@ SELECT * FROM ft2 WHERE c1 = ANY (ARRAY(SELECT c1 FROM ft1 WHERE c1 < 5));
4 | 4 | 00004 | Mon Jan 05 00:00:00 1970 PST | Mon Jan 05 00:00:00 1970 | 4 | 4 | foo
(4 rows)
--- we should not push order by clause with volatile expressions or unsafe
--- collations
-EXPLAIN (VERBOSE, COSTS OFF)
- SELECT * FROM ft2 ORDER BY ft2.c1, random();
- QUERY PLAN
--------------------------------------------------------------------------------
- Sort
- Output: c1, c2, c3, c4, c5, c6, c7, c8, (random())
- Sort Key: ft2.c1, (random())
- -> Foreign Scan on public.ft2
- Output: c1, c2, c3, c4, c5, c6, c7, c8, random()
- Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1"
-(6 rows)
-
-EXPLAIN (VERBOSE, COSTS OFF)
- SELECT * FROM ft2 ORDER BY ft2.c1, ft2.c3 collate "C";
- QUERY PLAN
--------------------------------------------------------------------------------
- Sort
- Output: c1, c2, c3, c4, c5, c6, c7, c8, ((c3)::text)
- Sort Key: ft2.c1, ft2.c3 COLLATE "C"
- -> Foreign Scan on public.ft2
- Output: c1, c2, c3, c4, c5, c6, c7, c8, c3
- Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1"
-(6 rows)
-
-- user-defined operator/function
CREATE FUNCTION postgres_fdw_abs(int) RETURNS int AS $$
BEGIN
@@ -1184,6 +1158,73 @@ WHERE c1 = 642 AND length(to_tsvector('custom_search'::regconfig, c3)) > 0;
(1 row)
-- ===================================================================
+-- ORDER BY queries
+-- ===================================================================
+-- we should not push order by clause with volatile expressions or unsafe
+-- collations
+EXPLAIN (VERBOSE, COSTS OFF)
+ SELECT * FROM ft2 ORDER BY ft2.c1, random();
+ QUERY PLAN
+-------------------------------------------------------------------------------
+ Sort
+ Output: c1, c2, c3, c4, c5, c6, c7, c8, (random())
+ Sort Key: ft2.c1, (random())
+ -> Foreign Scan on public.ft2
+ Output: c1, c2, c3, c4, c5, c6, c7, c8, random()
+ Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1"
+(6 rows)
+
+EXPLAIN (VERBOSE, COSTS OFF)
+ SELECT * FROM ft2 ORDER BY ft2.c1, ft2.c3 collate "C";
+ QUERY PLAN
+-------------------------------------------------------------------------------
+ Sort
+ Output: c1, c2, c3, c4, c5, c6, c7, c8, ((c3)::text)
+ Sort Key: ft2.c1, ft2.c3 COLLATE "C"
+ -> Foreign Scan on public.ft2
+ Output: c1, c2, c3, c4, c5, c6, c7, c8, c3
+ Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1"
+(6 rows)
+
+-- Ensure we don't push ORDER BY expressions which are Consts at the UNION
+-- child level to the foreign server.
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT * FROM (
+ SELECT 1 AS type,c1 FROM ft1
+ UNION ALL
+ SELECT 2 AS type,c1 FROM ft2
+) a ORDER BY type,c1;
+ QUERY PLAN
+---------------------------------------------------------------------------------
+ Merge Append
+ Sort Key: (1), ft1.c1
+ -> Foreign Scan on public.ft1
+ Output: 1, ft1.c1
+ Remote SQL: SELECT "C 1" FROM "S 1"."T 1" ORDER BY "C 1" ASC NULLS LAST
+ -> Foreign Scan on public.ft2
+ Output: 2, ft2.c1
+ Remote SQL: SELECT "C 1" FROM "S 1"."T 1" ORDER BY "C 1" ASC NULLS LAST
+(8 rows)
+
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT * FROM (
+ SELECT 1 AS type,c1 FROM ft1
+ UNION ALL
+ SELECT 2 AS type,c1 FROM ft2
+) a ORDER BY type;
+ QUERY PLAN
+---------------------------------------------------
+ Merge Append
+ Sort Key: (1)
+ -> Foreign Scan on public.ft1
+ Output: 1, ft1.c1
+ Remote SQL: SELECT "C 1" FROM "S 1"."T 1"
+ -> Foreign Scan on public.ft2
+ Output: 2, ft2.c1
+ Remote SQL: SELECT "C 1" FROM "S 1"."T 1"
+(8 rows)
+
+-- ===================================================================
-- JOIN queries
-- ===================================================================
-- Analyze ft4 and ft5 so that we have better statistics. These tables do not
diff --git a/contrib/postgres_fdw/postgres_fdw.c b/contrib/postgres_fdw/postgres_fdw.c
index b08b314..e3b9b8d 100644
--- a/contrib/postgres_fdw/postgres_fdw.c
+++ b/contrib/postgres_fdw/postgres_fdw.c
@@ -6968,14 +6968,16 @@ postgresForeignAsyncConfigureWait(AsyncRequest *areq)
{
/*
* This is the case when the in-process request was made by another
- * Append. Note that it might be useless to process the request,
- * because the query might not need tuples from that Append anymore.
- * If there are any child subplans of the same parent that are ready
- * for new requests, skip the given request. Likewise, if there are
- * any configured events other than the postmaster death event, skip
- * it. Otherwise, process the in-process request, then begin a fetch
- * to configure the event below, because we might otherwise end up
- * with no configured events other than the postmaster death event.
+ * Append. Note that it might be useless to process the request made
+ * by that Append, because the query might not need tuples from that
+ * Append anymore; so we avoid processing it to begin a fetch for the
+ * given request if possible. If there are any child subplans of the
+ * same parent that are ready for new requests, skip the given
+ * request. Likewise, if there are any configured events other than
+ * the postmaster death event, skip it. Otherwise, process the
+ * in-process request, then begin a fetch to configure the event
+ * below, because we might otherwise end up with no configured events
+ * other than the postmaster death event.
*/
if (!bms_is_empty(requestor->as_needrequest))
return;
diff --git a/contrib/postgres_fdw/sql/postgres_fdw.sql b/contrib/postgres_fdw/sql/postgres_fdw.sql
index 80aa7fb..fdbbb4f 100644
--- a/contrib/postgres_fdw/sql/postgres_fdw.sql
+++ b/contrib/postgres_fdw/sql/postgres_fdw.sql
@@ -354,12 +354,6 @@ WHERE a.c2 = 6 AND b.c1 = a.c1 AND a.c8 = 'foo' AND b.c7 = upper(a.c7);
-- bug before 9.3.5 due to sloppy handling of remote-estimate parameters
SELECT * FROM ft1 WHERE c1 = ANY (ARRAY(SELECT c1 FROM ft2 WHERE c1 < 5));
SELECT * FROM ft2 WHERE c1 = ANY (ARRAY(SELECT c1 FROM ft1 WHERE c1 < 5));
--- we should not push order by clause with volatile expressions or unsafe
--- collations
-EXPLAIN (VERBOSE, COSTS OFF)
- SELECT * FROM ft2 ORDER BY ft2.c1, random();
-EXPLAIN (VERBOSE, COSTS OFF)
- SELECT * FROM ft2 ORDER BY ft2.c1, ft2.c3 collate "C";
-- user-defined operator/function
CREATE FUNCTION postgres_fdw_abs(int) RETURNS int AS $$
@@ -452,6 +446,32 @@ SELECT c1, to_tsvector('custom_search'::regconfig, c3) FROM ft1
WHERE c1 = 642 AND length(to_tsvector('custom_search'::regconfig, c3)) > 0;
-- ===================================================================
+-- ORDER BY queries
+-- ===================================================================
+-- we should not push order by clause with volatile expressions or unsafe
+-- collations
+EXPLAIN (VERBOSE, COSTS OFF)
+ SELECT * FROM ft2 ORDER BY ft2.c1, random();
+EXPLAIN (VERBOSE, COSTS OFF)
+ SELECT * FROM ft2 ORDER BY ft2.c1, ft2.c3 collate "C";
+
+-- Ensure we don't push ORDER BY expressions which are Consts at the UNION
+-- child level to the foreign server.
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT * FROM (
+ SELECT 1 AS type,c1 FROM ft1
+ UNION ALL
+ SELECT 2 AS type,c1 FROM ft2
+) a ORDER BY type,c1;
+
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT * FROM (
+ SELECT 1 AS type,c1 FROM ft1
+ UNION ALL
+ SELECT 2 AS type,c1 FROM ft2
+) a ORDER BY type;
+
+-- ===================================================================
-- JOIN queries
-- ===================================================================
-- Analyze ft4 and ft5 so that we have better statistics. These tables do not
diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c
index 9464193..b999b1f 100644
--- a/contrib/xml2/xpath.c
+++ b/contrib/xml2/xpath.c
@@ -74,8 +74,6 @@ pgxml_parser_init(PgXmlStrictness strictness)
/* Initialize libxml */
xmlInitParser();
- xmlSubstituteEntitiesDefault(1);
-
return xmlerrcxt;
}
@@ -379,8 +377,9 @@ pgxml_xpath(text *document, xmlChar *xpath, xpath_workspace *workspace)
PG_TRY();
{
- workspace->doctree = xmlParseMemory((char *) VARDATA_ANY(document),
- docsize);
+ workspace->doctree = xmlReadMemory((char *) VARDATA_ANY(document),
+ docsize, NULL, NULL,
+ XML_PARSE_NOENT);
if (workspace->doctree != NULL)
{
workspace->ctxt = xmlXPathNewContext(workspace->doctree);
@@ -623,7 +622,9 @@ xpath_table(PG_FUNCTION_ARGS)
/* Parse the document */
if (xmldoc)
- doctree = xmlParseMemory(xmldoc, strlen(xmldoc));
+ doctree = xmlReadMemory(xmldoc, strlen(xmldoc),
+ NULL, NULL,
+ XML_PARSE_NOENT);
else /* treat NULL as not well-formed */
doctree = NULL;
diff --git a/contrib/xml2/xslt_proc.c b/contrib/xml2/xslt_proc.c
index 2189bca..f30a3a4 100644
--- a/contrib/xml2/xslt_proc.c
+++ b/contrib/xml2/xslt_proc.c
@@ -85,16 +85,18 @@ xslt_process(PG_FUNCTION_ARGS)
bool xslt_sec_prefs_error;
/* Parse document */
- doctree = xmlParseMemory((char *) VARDATA_ANY(doct),
- VARSIZE_ANY_EXHDR(doct));
+ doctree = xmlReadMemory((char *) VARDATA_ANY(doct),
+ VARSIZE_ANY_EXHDR(doct), NULL, NULL,
+ XML_PARSE_NOENT);
if (doctree == NULL)
xml_ereport(xmlerrcxt, ERROR, ERRCODE_EXTERNAL_ROUTINE_EXCEPTION,
"error parsing XML document");
/* Same for stylesheet */
- ssdoc = xmlParseMemory((char *) VARDATA_ANY(ssheet),
- VARSIZE_ANY_EXHDR(ssheet));
+ ssdoc = xmlReadMemory((char *) VARDATA_ANY(ssheet),
+ VARSIZE_ANY_EXHDR(ssheet), NULL, NULL,
+ XML_PARSE_NOENT);
if (ssdoc == NULL)
xml_ereport(xmlerrcxt, ERROR, ERRCODE_EXTERNAL_ROUTINE_EXCEPTION,