mirror of
https://github.com/postgres/postgres.git
synced 2025-08-10 00:03:33 -04:00
Compare commits
No commits in common. "5b5318c387451e3eb89eddb4574e57a61297102f" and "6b14404b0b97530af080a1f5edb940d30464aa0a" have entirely different histories.
5b5318c387
...
6b14404b0b
@ -107,7 +107,6 @@ do { \
|
|||||||
static IndexScanDesc index_beginscan_internal(Relation indexRelation,
|
static IndexScanDesc index_beginscan_internal(Relation indexRelation,
|
||||||
int nkeys, int norderbys, Snapshot snapshot,
|
int nkeys, int norderbys, Snapshot snapshot,
|
||||||
ParallelIndexScanDesc pscan, bool temp_snap);
|
ParallelIndexScanDesc pscan, bool temp_snap);
|
||||||
static inline void validate_relation_kind(Relation r);
|
|
||||||
|
|
||||||
|
|
||||||
/* ----------------------------------------------------------------
|
/* ----------------------------------------------------------------
|
||||||
@ -136,30 +135,12 @@ index_open(Oid relationId, LOCKMODE lockmode)
|
|||||||
|
|
||||||
r = relation_open(relationId, lockmode);
|
r = relation_open(relationId, lockmode);
|
||||||
|
|
||||||
validate_relation_kind(r);
|
if (r->rd_rel->relkind != RELKIND_INDEX &&
|
||||||
|
r->rd_rel->relkind != RELKIND_PARTITIONED_INDEX)
|
||||||
return r;
|
ereport(ERROR,
|
||||||
}
|
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
|
||||||
|
errmsg("\"%s\" is not an index",
|
||||||
/* ----------------
|
RelationGetRelationName(r))));
|
||||||
* try_index_open - open a index relation by relation OID
|
|
||||||
*
|
|
||||||
* Same as index_open, except return NULL instead of failing
|
|
||||||
* if the relation does not exist.
|
|
||||||
* ----------------
|
|
||||||
*/
|
|
||||||
Relation
|
|
||||||
try_index_open(Oid relationId, LOCKMODE lockmode)
|
|
||||||
{
|
|
||||||
Relation r;
|
|
||||||
|
|
||||||
r = try_relation_open(relationId, lockmode);
|
|
||||||
|
|
||||||
/* leave if index does not exist */
|
|
||||||
if (!r)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
validate_relation_kind(r);
|
|
||||||
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
@ -187,24 +168,6 @@ index_close(Relation relation, LOCKMODE lockmode)
|
|||||||
UnlockRelationId(&relid, lockmode);
|
UnlockRelationId(&relid, lockmode);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
|
||||||
* validate_relation_kind - check the relation's kind
|
|
||||||
*
|
|
||||||
* Make sure relkind is an index or a partitioned index.
|
|
||||||
* ----------------
|
|
||||||
*/
|
|
||||||
static inline void
|
|
||||||
validate_relation_kind(Relation r)
|
|
||||||
{
|
|
||||||
if (r->rd_rel->relkind != RELKIND_INDEX &&
|
|
||||||
r->rd_rel->relkind != RELKIND_PARTITIONED_INDEX)
|
|
||||||
ereport(ERROR,
|
|
||||||
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
|
|
||||||
errmsg("\"%s\" is not an index",
|
|
||||||
RelationGetRelationName(r))));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
* index_insert - insert an index tuple into a relation
|
* index_insert - insert an index tuple into a relation
|
||||||
* ----------------
|
* ----------------
|
||||||
|
@ -3633,24 +3633,7 @@ reindex_index(Oid indexId, bool skip_constraint_checks, char persistence,
|
|||||||
* Open the target index relation and get an exclusive lock on it, to
|
* Open the target index relation and get an exclusive lock on it, to
|
||||||
* ensure that no one else is touching this particular index.
|
* ensure that no one else is touching this particular index.
|
||||||
*/
|
*/
|
||||||
if ((params->options & REINDEXOPT_MISSING_OK) != 0)
|
iRel = index_open(indexId, AccessExclusiveLock);
|
||||||
iRel = try_index_open(indexId, AccessExclusiveLock);
|
|
||||||
else
|
|
||||||
iRel = index_open(indexId, AccessExclusiveLock);
|
|
||||||
|
|
||||||
/* if index relation is gone, leave */
|
|
||||||
if (!iRel)
|
|
||||||
{
|
|
||||||
/* Roll back any GUC changes */
|
|
||||||
AtEOXact_GUC(false, save_nestlevel);
|
|
||||||
|
|
||||||
/* Restore userid and security context */
|
|
||||||
SetUserIdAndSecContext(save_userid, save_sec_context);
|
|
||||||
|
|
||||||
/* Close parent heap relation, but keep locks */
|
|
||||||
table_close(heapRelation, NoLock);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (progress)
|
if (progress)
|
||||||
pgstat_progress_update_param(PROGRESS_CREATEIDX_ACCESS_METHOD_OID,
|
pgstat_progress_update_param(PROGRESS_CREATEIDX_ACCESS_METHOD_OID,
|
||||||
|
@ -139,7 +139,6 @@ typedef struct IndexOrderByDistance
|
|||||||
#define IndexScanIsValid(scan) PointerIsValid(scan)
|
#define IndexScanIsValid(scan) PointerIsValid(scan)
|
||||||
|
|
||||||
extern Relation index_open(Oid relationId, LOCKMODE lockmode);
|
extern Relation index_open(Oid relationId, LOCKMODE lockmode);
|
||||||
extern Relation try_index_open(Oid relationId, LOCKMODE lockmode);
|
|
||||||
extern void index_close(Relation relation, LOCKMODE lockmode);
|
extern void index_close(Relation relation, LOCKMODE lockmode);
|
||||||
|
|
||||||
extern bool index_insert(Relation indexRelation,
|
extern bool index_insert(Relation indexRelation,
|
||||||
|
@ -32,9 +32,8 @@ DATA = plpgsql.control plpgsql--1.0.sql
|
|||||||
|
|
||||||
REGRESS_OPTS = --dbname=$(PL_TESTDB)
|
REGRESS_OPTS = --dbname=$(PL_TESTDB)
|
||||||
|
|
||||||
REGRESS = plpgsql_array plpgsql_cache plpgsql_call plpgsql_control \
|
REGRESS = plpgsql_array plpgsql_call plpgsql_control plpgsql_copy plpgsql_domain \
|
||||||
plpgsql_copy plpgsql_domain plpgsql_misc \
|
plpgsql_record plpgsql_cache plpgsql_simple plpgsql_transaction \
|
||||||
plpgsql_record plpgsql_simple plpgsql_transaction \
|
|
||||||
plpgsql_trap plpgsql_trigger plpgsql_varprops
|
plpgsql_trap plpgsql_trigger plpgsql_varprops
|
||||||
|
|
||||||
# where to find gen_keywordlist.pl and subsidiary files
|
# where to find gen_keywordlist.pl and subsidiary files
|
||||||
|
@ -1,31 +0,0 @@
|
|||||||
--
|
|
||||||
-- Miscellaneous topics
|
|
||||||
--
|
|
||||||
-- Verify that we can parse new-style CREATE FUNCTION/PROCEDURE
|
|
||||||
do
|
|
||||||
$$
|
|
||||||
declare procedure int; -- check we still recognize non-keywords as vars
|
|
||||||
begin
|
|
||||||
create function test1() returns int
|
|
||||||
begin atomic
|
|
||||||
select 2 + 2;
|
|
||||||
end;
|
|
||||||
create or replace procedure test2(x int)
|
|
||||||
begin atomic
|
|
||||||
select x + 2;
|
|
||||||
end;
|
|
||||||
end
|
|
||||||
$$;
|
|
||||||
\sf test1
|
|
||||||
CREATE OR REPLACE FUNCTION public.test1()
|
|
||||||
RETURNS integer
|
|
||||||
LANGUAGE sql
|
|
||||||
BEGIN ATOMIC
|
|
||||||
SELECT (2 + 2);
|
|
||||||
END
|
|
||||||
\sf test2
|
|
||||||
CREATE OR REPLACE PROCEDURE public.test2(IN x integer)
|
|
||||||
LANGUAGE sql
|
|
||||||
BEGIN ATOMIC
|
|
||||||
SELECT (x + 2);
|
|
||||||
END
|
|
@ -76,13 +76,12 @@ tests += {
|
|||||||
'regress': {
|
'regress': {
|
||||||
'sql': [
|
'sql': [
|
||||||
'plpgsql_array',
|
'plpgsql_array',
|
||||||
'plpgsql_cache',
|
|
||||||
'plpgsql_call',
|
'plpgsql_call',
|
||||||
'plpgsql_control',
|
'plpgsql_control',
|
||||||
'plpgsql_copy',
|
'plpgsql_copy',
|
||||||
'plpgsql_domain',
|
'plpgsql_domain',
|
||||||
'plpgsql_misc',
|
|
||||||
'plpgsql_record',
|
'plpgsql_record',
|
||||||
|
'plpgsql_cache',
|
||||||
'plpgsql_simple',
|
'plpgsql_simple',
|
||||||
'plpgsql_transaction',
|
'plpgsql_transaction',
|
||||||
'plpgsql_trap',
|
'plpgsql_trap',
|
||||||
|
@ -76,8 +76,7 @@ static PLpgSQL_expr *read_sql_expression2(int until, int until2,
|
|||||||
int *endtoken);
|
int *endtoken);
|
||||||
static PLpgSQL_expr *read_sql_stmt(void);
|
static PLpgSQL_expr *read_sql_stmt(void);
|
||||||
static PLpgSQL_type *read_datatype(int tok);
|
static PLpgSQL_type *read_datatype(int tok);
|
||||||
static PLpgSQL_stmt *make_execsql_stmt(int firsttoken, int location,
|
static PLpgSQL_stmt *make_execsql_stmt(int firsttoken, int location);
|
||||||
PLword *word);
|
|
||||||
static PLpgSQL_stmt_fetch *read_fetch_direction(void);
|
static PLpgSQL_stmt_fetch *read_fetch_direction(void);
|
||||||
static void complete_direction(PLpgSQL_stmt_fetch *fetch,
|
static void complete_direction(PLpgSQL_stmt_fetch *fetch,
|
||||||
bool *check_FROM);
|
bool *check_FROM);
|
||||||
@ -1972,15 +1971,15 @@ loop_body : proc_sect K_END K_LOOP opt_label ';'
|
|||||||
*/
|
*/
|
||||||
stmt_execsql : K_IMPORT
|
stmt_execsql : K_IMPORT
|
||||||
{
|
{
|
||||||
$$ = make_execsql_stmt(K_IMPORT, @1, NULL);
|
$$ = make_execsql_stmt(K_IMPORT, @1);
|
||||||
}
|
}
|
||||||
| K_INSERT
|
| K_INSERT
|
||||||
{
|
{
|
||||||
$$ = make_execsql_stmt(K_INSERT, @1, NULL);
|
$$ = make_execsql_stmt(K_INSERT, @1);
|
||||||
}
|
}
|
||||||
| K_MERGE
|
| K_MERGE
|
||||||
{
|
{
|
||||||
$$ = make_execsql_stmt(K_MERGE, @1, NULL);
|
$$ = make_execsql_stmt(K_MERGE, @1);
|
||||||
}
|
}
|
||||||
| T_WORD
|
| T_WORD
|
||||||
{
|
{
|
||||||
@ -1991,7 +1990,7 @@ stmt_execsql : K_IMPORT
|
|||||||
if (tok == '=' || tok == COLON_EQUALS ||
|
if (tok == '=' || tok == COLON_EQUALS ||
|
||||||
tok == '[' || tok == '.')
|
tok == '[' || tok == '.')
|
||||||
word_is_not_variable(&($1), @1);
|
word_is_not_variable(&($1), @1);
|
||||||
$$ = make_execsql_stmt(T_WORD, @1, &($1));
|
$$ = make_execsql_stmt(T_WORD, @1);
|
||||||
}
|
}
|
||||||
| T_CWORD
|
| T_CWORD
|
||||||
{
|
{
|
||||||
@ -2002,7 +2001,7 @@ stmt_execsql : K_IMPORT
|
|||||||
if (tok == '=' || tok == COLON_EQUALS ||
|
if (tok == '=' || tok == COLON_EQUALS ||
|
||||||
tok == '[' || tok == '.')
|
tok == '[' || tok == '.')
|
||||||
cword_is_not_variable(&($1), @1);
|
cword_is_not_variable(&($1), @1);
|
||||||
$$ = make_execsql_stmt(T_CWORD, @1, NULL);
|
$$ = make_execsql_stmt(T_CWORD, @1);
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
@ -2920,13 +2919,8 @@ read_datatype(int tok)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Read a generic SQL statement. We have already read its first token;
|
|
||||||
* firsttoken is that token's code and location its starting location.
|
|
||||||
* If firsttoken == T_WORD, pass its yylval value as "word", else pass NULL.
|
|
||||||
*/
|
|
||||||
static PLpgSQL_stmt *
|
static PLpgSQL_stmt *
|
||||||
make_execsql_stmt(int firsttoken, int location, PLword *word)
|
make_execsql_stmt(int firsttoken, int location)
|
||||||
{
|
{
|
||||||
StringInfoData ds;
|
StringInfoData ds;
|
||||||
IdentifierLookup save_IdentifierLookup;
|
IdentifierLookup save_IdentifierLookup;
|
||||||
@ -2939,16 +2933,9 @@ make_execsql_stmt(int firsttoken, int location, PLword *word)
|
|||||||
bool have_strict = false;
|
bool have_strict = false;
|
||||||
int into_start_loc = -1;
|
int into_start_loc = -1;
|
||||||
int into_end_loc = -1;
|
int into_end_loc = -1;
|
||||||
int paren_depth = 0;
|
|
||||||
int begin_depth = 0;
|
|
||||||
bool in_routine_definition = false;
|
|
||||||
int token_count = 0;
|
|
||||||
char tokens[4]; /* records the first few tokens */
|
|
||||||
|
|
||||||
initStringInfo(&ds);
|
initStringInfo(&ds);
|
||||||
|
|
||||||
memset(tokens, 0, sizeof(tokens));
|
|
||||||
|
|
||||||
/* special lookup mode for identifiers within the SQL text */
|
/* special lookup mode for identifiers within the SQL text */
|
||||||
save_IdentifierLookup = plpgsql_IdentifierLookup;
|
save_IdentifierLookup = plpgsql_IdentifierLookup;
|
||||||
plpgsql_IdentifierLookup = IDENTIFIER_LOOKUP_EXPR;
|
plpgsql_IdentifierLookup = IDENTIFIER_LOOKUP_EXPR;
|
||||||
@ -2957,12 +2944,6 @@ make_execsql_stmt(int firsttoken, int location, PLword *word)
|
|||||||
* Scan to the end of the SQL command. Identify any INTO-variables
|
* Scan to the end of the SQL command. Identify any INTO-variables
|
||||||
* clause lurking within it, and parse that via read_into_target().
|
* clause lurking within it, and parse that via read_into_target().
|
||||||
*
|
*
|
||||||
* The end of the statement is defined by a semicolon ... except that
|
|
||||||
* semicolons within parentheses or BEGIN/END blocks don't terminate a
|
|
||||||
* statement. We follow psql's lead in not recognizing BEGIN/END except
|
|
||||||
* after CREATE [OR REPLACE] {FUNCTION|PROCEDURE}. END can also appear
|
|
||||||
* within a CASE construct, so we treat CASE/END like BEGIN/END.
|
|
||||||
*
|
|
||||||
* Because INTO is sometimes used in the main SQL grammar, we have to be
|
* Because INTO is sometimes used in the main SQL grammar, we have to be
|
||||||
* careful not to take any such usage of INTO as a PL/pgSQL INTO clause.
|
* careful not to take any such usage of INTO as a PL/pgSQL INTO clause.
|
||||||
* There are currently three such cases:
|
* There are currently three such cases:
|
||||||
@ -2988,50 +2969,13 @@ make_execsql_stmt(int firsttoken, int location, PLword *word)
|
|||||||
* break this logic again ... beware!
|
* break this logic again ... beware!
|
||||||
*/
|
*/
|
||||||
tok = firsttoken;
|
tok = firsttoken;
|
||||||
if (tok == T_WORD && strcmp(word->ident, "create") == 0)
|
|
||||||
tokens[token_count] = 'c';
|
|
||||||
token_count++;
|
|
||||||
|
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
prev_tok = tok;
|
prev_tok = tok;
|
||||||
tok = yylex();
|
tok = yylex();
|
||||||
if (have_into && into_end_loc < 0)
|
if (have_into && into_end_loc < 0)
|
||||||
into_end_loc = yylloc; /* token after the INTO part */
|
into_end_loc = yylloc; /* token after the INTO part */
|
||||||
/* Detect CREATE [OR REPLACE] {FUNCTION|PROCEDURE} */
|
if (tok == ';')
|
||||||
if (tokens[0] == 'c' && token_count < sizeof(tokens))
|
|
||||||
{
|
|
||||||
if (tok == K_OR)
|
|
||||||
tokens[token_count] = 'o';
|
|
||||||
else if (tok == T_WORD &&
|
|
||||||
strcmp(yylval.word.ident, "replace") == 0)
|
|
||||||
tokens[token_count] = 'r';
|
|
||||||
else if (tok == T_WORD &&
|
|
||||||
strcmp(yylval.word.ident, "function") == 0)
|
|
||||||
tokens[token_count] = 'f';
|
|
||||||
else if (tok == T_WORD &&
|
|
||||||
strcmp(yylval.word.ident, "procedure") == 0)
|
|
||||||
tokens[token_count] = 'f'; /* treat same as "function" */
|
|
||||||
if (tokens[1] == 'f' ||
|
|
||||||
(tokens[1] == 'o' && tokens[2] == 'r' && tokens[3] == 'f'))
|
|
||||||
in_routine_definition = true;
|
|
||||||
token_count++;
|
|
||||||
}
|
|
||||||
/* Track paren nesting (needed for CREATE RULE syntax) */
|
|
||||||
if (tok == '(')
|
|
||||||
paren_depth++;
|
|
||||||
else if (tok == ')' && paren_depth > 0)
|
|
||||||
paren_depth--;
|
|
||||||
/* We need track BEGIN/END nesting only in a routine definition */
|
|
||||||
if (in_routine_definition && paren_depth == 0)
|
|
||||||
{
|
|
||||||
if (tok == K_BEGIN || tok == K_CASE)
|
|
||||||
begin_depth++;
|
|
||||||
else if (tok == K_END && begin_depth > 0)
|
|
||||||
begin_depth--;
|
|
||||||
}
|
|
||||||
/* Command-ending semicolon? */
|
|
||||||
if (tok == ';' && paren_depth == 0 && begin_depth == 0)
|
|
||||||
break;
|
break;
|
||||||
if (tok == 0)
|
if (tok == 0)
|
||||||
yyerror("unexpected end of function definition");
|
yyerror("unexpected end of function definition");
|
||||||
|
@ -1,22 +0,0 @@
|
|||||||
--
|
|
||||||
-- Miscellaneous topics
|
|
||||||
--
|
|
||||||
|
|
||||||
-- Verify that we can parse new-style CREATE FUNCTION/PROCEDURE
|
|
||||||
do
|
|
||||||
$$
|
|
||||||
declare procedure int; -- check we still recognize non-keywords as vars
|
|
||||||
begin
|
|
||||||
create function test1() returns int
|
|
||||||
begin atomic
|
|
||||||
select 2 + 2;
|
|
||||||
end;
|
|
||||||
create or replace procedure test2(x int)
|
|
||||||
begin atomic
|
|
||||||
select x + 2;
|
|
||||||
end;
|
|
||||||
end
|
|
||||||
$$;
|
|
||||||
|
|
||||||
\sf test1
|
|
||||||
\sf test2
|
|
@ -5,7 +5,6 @@
|
|||||||
use strict;
|
use strict;
|
||||||
use warnings;
|
use warnings;
|
||||||
use PostgreSQL::Test::Cluster;
|
use PostgreSQL::Test::Cluster;
|
||||||
use PostgreSQL::Test::Utils;
|
|
||||||
use Test::More;
|
use Test::More;
|
||||||
|
|
||||||
my ($node_publisher, $node_subscriber, $publisher_connstr, $result, $offset);
|
my ($node_publisher, $node_subscriber, $publisher_connstr, $result, $offset);
|
||||||
@ -307,91 +306,81 @@ expect_replication("alice.unpartitioned", 3, 17, 21,
|
|||||||
# If the subscription connection requires a password ('password_required'
|
# If the subscription connection requires a password ('password_required'
|
||||||
# is true) then a non-superuser must specify that password in the connection
|
# is true) then a non-superuser must specify that password in the connection
|
||||||
# string.
|
# string.
|
||||||
SKIP:
|
$ENV{"PGPASSWORD"} = 'secret';
|
||||||
|
|
||||||
|
my $node_publisher1 = PostgreSQL::Test::Cluster->new('publisher1');
|
||||||
|
my $node_subscriber1 = PostgreSQL::Test::Cluster->new('subscriber1');
|
||||||
|
$node_publisher1->init(allows_streaming => 'logical');
|
||||||
|
$node_subscriber1->init;
|
||||||
|
$node_publisher1->start;
|
||||||
|
$node_subscriber1->start;
|
||||||
|
my $publisher_connstr1 =
|
||||||
|
$node_publisher1->connstr . ' user=regress_test_user dbname=postgres';
|
||||||
|
my $publisher_connstr2 =
|
||||||
|
$node_publisher1->connstr
|
||||||
|
. ' user=regress_test_user dbname=postgres password=secret';
|
||||||
|
|
||||||
|
for my $node ($node_publisher1, $node_subscriber1)
|
||||||
{
|
{
|
||||||
skip
|
$node->safe_psql(
|
||||||
"subscription password_required test cannot run without Unix-domain sockets",
|
|
||||||
3
|
|
||||||
unless $use_unix_sockets;
|
|
||||||
|
|
||||||
my $node_publisher1 = PostgreSQL::Test::Cluster->new('publisher1');
|
|
||||||
my $node_subscriber1 = PostgreSQL::Test::Cluster->new('subscriber1');
|
|
||||||
$node_publisher1->init(allows_streaming => 'logical');
|
|
||||||
$node_subscriber1->init;
|
|
||||||
$node_publisher1->start;
|
|
||||||
$node_subscriber1->start;
|
|
||||||
my $publisher_connstr1 =
|
|
||||||
$node_publisher1->connstr . ' user=regress_test_user dbname=postgres';
|
|
||||||
my $publisher_connstr2 =
|
|
||||||
$node_publisher1->connstr
|
|
||||||
. ' user=regress_test_user dbname=postgres password=secret';
|
|
||||||
|
|
||||||
for my $node ($node_publisher1, $node_subscriber1)
|
|
||||||
{
|
|
||||||
$node->safe_psql(
|
|
||||||
'postgres', qq(
|
|
||||||
CREATE ROLE regress_test_user PASSWORD 'secret' LOGIN REPLICATION;
|
|
||||||
GRANT CREATE ON DATABASE postgres TO regress_test_user;
|
|
||||||
GRANT PG_CREATE_SUBSCRIPTION TO regress_test_user;
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
$node_publisher1->safe_psql(
|
|
||||||
'postgres', qq(
|
'postgres', qq(
|
||||||
SET SESSION AUTHORIZATION regress_test_user;
|
CREATE ROLE regress_test_user PASSWORD 'secret' LOGIN REPLICATION;
|
||||||
CREATE PUBLICATION regress_test_pub;
|
GRANT CREATE ON DATABASE postgres TO regress_test_user;
|
||||||
));
|
GRANT PG_CREATE_SUBSCRIPTION TO regress_test_user;
|
||||||
$node_subscriber1->safe_psql(
|
));
|
||||||
'postgres', qq(
|
|
||||||
CREATE SUBSCRIPTION regress_test_sub CONNECTION '$publisher_connstr1' PUBLICATION regress_test_pub;
|
|
||||||
));
|
|
||||||
|
|
||||||
# Wait for initial sync to finish
|
|
||||||
$node_subscriber1->wait_for_subscription_sync($node_publisher1,
|
|
||||||
'regress_test_sub');
|
|
||||||
|
|
||||||
my $save_pgpassword = $ENV{"PGPASSWORD"};
|
|
||||||
$ENV{"PGPASSWORD"} = 'secret';
|
|
||||||
|
|
||||||
# Setup pg_hba configuration so that logical replication connection without
|
|
||||||
# password is not allowed.
|
|
||||||
unlink($node_publisher1->data_dir . '/pg_hba.conf');
|
|
||||||
$node_publisher1->append_conf('pg_hba.conf',
|
|
||||||
qq{local all regress_test_user md5});
|
|
||||||
$node_publisher1->reload;
|
|
||||||
|
|
||||||
# Change the subscription owner to a non-superuser
|
|
||||||
$node_subscriber1->safe_psql(
|
|
||||||
'postgres', qq(
|
|
||||||
ALTER SUBSCRIPTION regress_test_sub OWNER TO regress_test_user;
|
|
||||||
));
|
|
||||||
|
|
||||||
# Non-superuser must specify password in the connection string
|
|
||||||
my ($ret, $stdout, $stderr) = $node_subscriber1->psql(
|
|
||||||
'postgres', qq(
|
|
||||||
SET SESSION AUTHORIZATION regress_test_user;
|
|
||||||
ALTER SUBSCRIPTION regress_test_sub REFRESH PUBLICATION;
|
|
||||||
));
|
|
||||||
isnt($ret, 0,
|
|
||||||
"non zero exit for subscription whose owner is a non-superuser must specify password parameter of the connection string"
|
|
||||||
);
|
|
||||||
ok( $stderr =~
|
|
||||||
m/DETAIL: Non-superusers must provide a password in the connection string./,
|
|
||||||
'subscription whose owner is a non-superuser must specify password parameter of the connection string'
|
|
||||||
);
|
|
||||||
|
|
||||||
$ENV{"PGPASSWORD"} = $save_pgpassword;
|
|
||||||
|
|
||||||
# It should succeed after including the password parameter of the connection
|
|
||||||
# string.
|
|
||||||
($ret, $stdout, $stderr) = $node_subscriber1->psql(
|
|
||||||
'postgres', qq(
|
|
||||||
SET SESSION AUTHORIZATION regress_test_user;
|
|
||||||
ALTER SUBSCRIPTION regress_test_sub CONNECTION '$publisher_connstr2';
|
|
||||||
ALTER SUBSCRIPTION regress_test_sub REFRESH PUBLICATION;
|
|
||||||
));
|
|
||||||
is($ret, 0,
|
|
||||||
"Non-superuser will be able to refresh the publication after specifying the password parameter of the connection string"
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$node_publisher1->safe_psql(
|
||||||
|
'postgres', qq(
|
||||||
|
SET SESSION AUTHORIZATION regress_test_user;
|
||||||
|
CREATE PUBLICATION regress_test_pub;
|
||||||
|
));
|
||||||
|
$node_subscriber1->safe_psql(
|
||||||
|
'postgres', qq(
|
||||||
|
CREATE SUBSCRIPTION regress_test_sub CONNECTION '$publisher_connstr1' PUBLICATION regress_test_pub;
|
||||||
|
));
|
||||||
|
|
||||||
|
# Wait for initial sync to finish
|
||||||
|
$node_subscriber1->wait_for_subscription_sync($node_publisher1,
|
||||||
|
'regress_test_sub');
|
||||||
|
|
||||||
|
# Setup pg_hba configuration so that logical replication connection without
|
||||||
|
# password is not allowed.
|
||||||
|
unlink($node_publisher1->data_dir . '/pg_hba.conf');
|
||||||
|
$node_publisher1->append_conf('pg_hba.conf',
|
||||||
|
qq{local all regress_test_user md5});
|
||||||
|
$node_publisher1->reload;
|
||||||
|
|
||||||
|
# Change the subscription owner to a non-superuser
|
||||||
|
$node_subscriber1->safe_psql(
|
||||||
|
'postgres', qq(
|
||||||
|
ALTER SUBSCRIPTION regress_test_sub OWNER TO regress_test_user;
|
||||||
|
));
|
||||||
|
|
||||||
|
# Non-superuser must specify password in the connection string
|
||||||
|
my ($ret, $stdout, $stderr) = $node_subscriber1->psql(
|
||||||
|
'postgres', qq(
|
||||||
|
SET SESSION AUTHORIZATION regress_test_user;
|
||||||
|
ALTER SUBSCRIPTION regress_test_sub REFRESH PUBLICATION;
|
||||||
|
));
|
||||||
|
isnt($ret, 0,
|
||||||
|
"non zero exit for subscription whose owner is a non-superuser must specify password parameter of the connection string"
|
||||||
|
);
|
||||||
|
ok( $stderr =~ m/DETAIL: Non-superusers must provide a password in the connection string./,
|
||||||
|
'subscription whose owner is a non-superuser must specify password parameter of the connection string'
|
||||||
|
);
|
||||||
|
|
||||||
|
delete $ENV{"PGPASSWORD"};
|
||||||
|
|
||||||
|
# It should succeed after including the password parameter of the connection
|
||||||
|
# string.
|
||||||
|
($ret, $stdout, $stderr) = $node_subscriber1->psql(
|
||||||
|
'postgres', qq(
|
||||||
|
SET SESSION AUTHORIZATION regress_test_user;
|
||||||
|
ALTER SUBSCRIPTION regress_test_sub CONNECTION '$publisher_connstr2';
|
||||||
|
ALTER SUBSCRIPTION regress_test_sub REFRESH PUBLICATION;
|
||||||
|
));
|
||||||
|
is($ret, 0,
|
||||||
|
"Non-superuser will be able to refresh the publication after specifying the password parameter of the connection string"
|
||||||
|
);
|
||||||
done_testing();
|
done_testing();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user