diff --git a/contrib/postgres_fdw/option.c b/contrib/postgres_fdw/option.c index 95dde056eb..c0bcf489a7 100644 --- a/contrib/postgres_fdw/option.c +++ b/contrib/postgres_fdw/option.c @@ -222,36 +222,25 @@ InitPgFdwOptions(void) /* non-libpq FDW-specific FDW options */ static const PgFdwOption non_libpq_options[] = { - {"schema_name", ForeignTableRelationId, false}, - {"table_name", ForeignTableRelationId, false}, + /* async_capable is available on both server and table */ + {"async_capable", ForeignServerRelationId, false}, + {"async_capable", ForeignTableRelationId, false}, + /* batch_size is available on both server and table */ + {"batch_size", ForeignServerRelationId, false}, + {"batch_size", ForeignTableRelationId, false}, {"column_name", AttributeRelationId, false}, - /* use_remote_estimate is available on both server and table */ - {"use_remote_estimate", ForeignServerRelationId, false}, - {"use_remote_estimate", ForeignTableRelationId, false}, - /* cost factors */ - {"fdw_startup_cost", ForeignServerRelationId, false}, - {"fdw_tuple_cost", ForeignServerRelationId, false}, /* shippable extensions */ {"extensions", ForeignServerRelationId, false}, - /* updatable is available on both server and table */ - {"updatable", ForeignServerRelationId, false}, - {"updatable", ForeignTableRelationId, false}, - /* truncatable is available on both server and table */ - {"truncatable", ForeignServerRelationId, false}, - {"truncatable", ForeignTableRelationId, false}, + {"fdw_startup_cost", ForeignServerRelationId, false}, + {"fdw_tuple_cost", ForeignServerRelationId, false}, /* fetch_size is available on both server and table */ {"fetch_size", ForeignServerRelationId, false}, {"fetch_size", ForeignTableRelationId, false}, - /* batch_size is available on both server and table */ - {"batch_size", ForeignServerRelationId, false}, - {"batch_size", ForeignTableRelationId, false}, - /* async_capable is available on both server and table */ - {"async_capable", ForeignServerRelationId, false}, - {"async_capable", ForeignTableRelationId, false}, - {"parallel_commit", ForeignServerRelationId, false}, + /* cost factors */ {"keep_connections", ForeignServerRelationId, false}, + {"parallel_commit", ForeignServerRelationId, false}, {"password_required", UserMappingRelationId, false}, - + {"schema_name", ForeignTableRelationId, false}, /* * sslcert and sslkey are in fact libpq options, but we repeat them * here to allow them to appear in both foreign server context (when @@ -259,7 +248,16 @@ InitPgFdwOptions(void) */ {"sslcert", UserMappingRelationId, true}, {"sslkey", UserMappingRelationId, true}, - + {"table_name", ForeignTableRelationId, false}, + /* truncatable is available on both server and table */ + {"truncatable", ForeignServerRelationId, false}, + {"truncatable", ForeignTableRelationId, false}, + /* updatable is available on both server and table */ + {"updatable", ForeignServerRelationId, false}, + {"updatable", ForeignTableRelationId, false}, + /* use_remote_estimate is available on both server and table */ + {"use_remote_estimate", ForeignServerRelationId, false}, + {"use_remote_estimate", ForeignTableRelationId, false}, {NULL, InvalidOid, false} }; diff --git a/src/backend/foreign/foreign.c b/src/backend/foreign/foreign.c index cf222fc3e9..fc4afb1e0b 100644 --- a/src/backend/foreign/foreign.c +++ b/src/backend/foreign/foreign.c @@ -560,19 +560,19 @@ struct ConnectionOption */ static const struct ConnectionOption libpq_conninfo_options[] = { {"authtype", ForeignServerRelationId}, - {"service", ForeignServerRelationId}, - {"user", UserMappingRelationId}, - {"password", UserMappingRelationId}, {"connect_timeout", ForeignServerRelationId}, {"dbname", ForeignServerRelationId}, {"host", ForeignServerRelationId}, {"hostaddr", ForeignServerRelationId}, - {"port", ForeignServerRelationId}, - {"tty", ForeignServerRelationId}, + {"gsslib", ForeignServerRelationId}, {"options", ForeignServerRelationId}, + {"password", UserMappingRelationId}, + {"port", ForeignServerRelationId}, {"requiressl", ForeignServerRelationId}, + {"service", ForeignServerRelationId}, {"sslmode", ForeignServerRelationId}, - {"gsslib", ForeignServerRelationId}, + {"tty", ForeignServerRelationId}, + {"user", UserMappingRelationId}, {NULL, InvalidOid} }; diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c index 8cefef20d1..f5d05f13f4 100644 --- a/src/interfaces/libpq/fe-connect.c +++ b/src/interfaces/libpq/fe-connect.c @@ -186,25 +186,18 @@ typedef struct _internalPQconninfoOption } internalPQconninfoOption; static const internalPQconninfoOption PQconninfoOptions[] = { - {"service", "PGSERVICE", NULL, NULL, - "Database-Service", "", 20, -1}, - - {"user", "PGUSER", NULL, NULL, - "Database-User", "", 20, - offsetof(struct pg_conn, pguser)}, - - {"password", "PGPASSWORD", NULL, NULL, - "Database-Password", "*", 20, - offsetof(struct pg_conn, pgpass)}, - - {"passfile", "PGPASSFILE", NULL, NULL, - "Database-Password-File", "", 64, - offsetof(struct pg_conn, pgpassfile)}, + {"application_name", "PGAPPNAME", NULL, NULL, + "Application-Name", "", 64, + offsetof(struct pg_conn, appname)}, {"channel_binding", "PGCHANNELBINDING", DefaultChannelBinding, NULL, "Channel-Binding", "", 8, /* sizeof("require") == 8 */ offsetof(struct pg_conn, channel_binding)}, + {"client_encoding", "PGCLIENTENCODING", NULL, NULL, + "Client-Encoding", "", 10, + offsetof(struct pg_conn, client_encoding_initial)}, + {"connect_timeout", "PGCONNECT_TIMEOUT", NULL, NULL, "Connect-timeout", "", 10, /* strlen(INT32_MAX) == 10 */ offsetof(struct pg_conn, connect_timeout)}, @@ -213,6 +206,10 @@ static const internalPQconninfoOption PQconninfoOptions[] = { "Database-Name", "", 20, offsetof(struct pg_conn, dbName)}, + {"fallback_application_name", NULL, NULL, NULL, + "Fallback-Application-Name", "", 64, + offsetof(struct pg_conn, fbappname)}, + {"host", "PGHOST", NULL, NULL, "Database-Host", "", 40, offsetof(struct pg_conn, pghost)}, @@ -221,30 +218,26 @@ static const internalPQconninfoOption PQconninfoOptions[] = { "Database-Host-IP-Address", "", 45, offsetof(struct pg_conn, pghostaddr)}, - {"port", "PGPORT", DEF_PGPORT_STR, NULL, - "Database-Port", "", 6, - offsetof(struct pg_conn, pgport)}, - - {"client_encoding", "PGCLIENTENCODING", NULL, NULL, - "Client-Encoding", "", 10, - offsetof(struct pg_conn, client_encoding_initial)}, - - {"options", "PGOPTIONS", DefaultOption, NULL, - "Backend-Options", "", 40, - offsetof(struct pg_conn, pgoptions)}, - - {"application_name", "PGAPPNAME", NULL, NULL, - "Application-Name", "", 64, - offsetof(struct pg_conn, appname)}, + /* + * As with SSL, all GSS options are exposed even in builds that don't have + * support. + */ + {"gssencmode", "PGGSSENCMODE", DefaultGSSMode, NULL, + "GSSENC-Mode", "", 8, /* sizeof("disable") == 8 */ + offsetof(struct pg_conn, gssencmode)}, - {"fallback_application_name", NULL, NULL, NULL, - "Fallback-Application-Name", "", 64, - offsetof(struct pg_conn, fbappname)}, + {"gsslib", "PGGSSLIB", NULL, NULL, + "GSS-library", "", 7, /* sizeof("gssapi") == 7 */ + offsetof(struct pg_conn, gsslib)}, {"keepalives", NULL, NULL, NULL, "TCP-Keepalives", "", 1, /* should be just '0' or '1' */ offsetof(struct pg_conn, keepalives)}, + {"keepalives_count", NULL, NULL, NULL, + "TCP-Keepalives-Count", "", 10, /* strlen(INT32_MAX) == 10 */ + offsetof(struct pg_conn, keepalives_count)}, + {"keepalives_idle", NULL, NULL, NULL, "TCP-Keepalives-Idle", "", 10, /* strlen(INT32_MAX) == 10 */ offsetof(struct pg_conn, keepalives_idle)}, @@ -253,13 +246,37 @@ static const internalPQconninfoOption PQconninfoOptions[] = { "TCP-Keepalives-Interval", "", 10, /* strlen(INT32_MAX) == 10 */ offsetof(struct pg_conn, keepalives_interval)}, - {"keepalives_count", NULL, NULL, NULL, - "TCP-Keepalives-Count", "", 10, /* strlen(INT32_MAX) == 10 */ - offsetof(struct pg_conn, keepalives_count)}, + /* Kerberos and GSSAPI authentication support specifying the service name */ + {"krbsrvname", "PGKRBSRVNAME", PG_KRB_SRVNAM, NULL, + "Kerberos-service-name", "", 20, + offsetof(struct pg_conn, krbsrvname)}, - {"tcp_user_timeout", NULL, NULL, NULL, - "TCP-User-Timeout", "", 10, /* strlen(INT32_MAX) == 10 */ - offsetof(struct pg_conn, pgtcp_user_timeout)}, + {"options", "PGOPTIONS", DefaultOption, NULL, + "Backend-Options", "", 40, + offsetof(struct pg_conn, pgoptions)}, + + {"password", "PGPASSWORD", NULL, NULL, + "Database-Password", "*", 20, + offsetof(struct pg_conn, pgpass)}, + + {"passfile", "PGPASSFILE", NULL, NULL, + "Database-Password-File", "", 64, + offsetof(struct pg_conn, pgpassfile)}, + + {"port", "PGPORT", DEF_PGPORT_STR, NULL, + "Database-Port", "", 6, + offsetof(struct pg_conn, pgport)}, + + {"replication", NULL, NULL, NULL, + "Replication", "D", 5, + offsetof(struct pg_conn, replication)}, + + {"requirepeer", "PGREQUIREPEER", NULL, NULL, + "Require-Peer", "", 10, + offsetof(struct pg_conn, requirepeer)}, + + {"service", "PGSERVICE", NULL, NULL, + "Database-Service", "", 20, -1}, /* * ssl options are allowed even without client SSL support because the @@ -267,22 +284,30 @@ static const internalPQconninfoOption PQconninfoOptions[] = { * parameters have no effect on non-SSL connections, so there is no reason * to exclude them since none of them are mandatory. */ - {"sslmode", "PGSSLMODE", DefaultSSLMode, NULL, - "SSL-Mode", "", 12, /* sizeof("verify-full") == 12 */ - offsetof(struct pg_conn, sslmode)}, + {"sslcert", "PGSSLCERT", NULL, NULL, + "SSL-Client-Cert", "", 64, + offsetof(struct pg_conn, sslcert)}, {"sslcompression", "PGSSLCOMPRESSION", "0", NULL, "SSL-Compression", "", 1, offsetof(struct pg_conn, sslcompression)}, - {"sslcert", "PGSSLCERT", NULL, NULL, - "SSL-Client-Cert", "", 64, - offsetof(struct pg_conn, sslcert)}, + {"sslcrl", "PGSSLCRL", NULL, NULL, + "SSL-Revocation-List", "", 64, + offsetof(struct pg_conn, sslcrl)}, + + {"sslcrldir", "PGSSLCRLDIR", NULL, NULL, + "SSL-Revocation-List-Dir", "", 64, + offsetof(struct pg_conn, sslcrldir)}, {"sslkey", "PGSSLKEY", NULL, NULL, "SSL-Client-Key", "", 64, offsetof(struct pg_conn, sslkey)}, + {"sslmode", "PGSSLMODE", DefaultSSLMode, NULL, + "SSL-Mode", "", 12, /* sizeof("verify-full") == 12 */ + offsetof(struct pg_conn, sslmode)}, + {"sslpassword", NULL, NULL, NULL, "SSL-Client-Key-Password", "*", 20, offsetof(struct pg_conn, sslpassword)}, @@ -291,56 +316,31 @@ static const internalPQconninfoOption PQconninfoOptions[] = { "SSL-Root-Certificate", "", 64, offsetof(struct pg_conn, sslrootcert)}, - {"sslcrl", "PGSSLCRL", NULL, NULL, - "SSL-Revocation-List", "", 64, - offsetof(struct pg_conn, sslcrl)}, - - {"sslcrldir", "PGSSLCRLDIR", NULL, NULL, - "SSL-Revocation-List-Dir", "", 64, - offsetof(struct pg_conn, sslcrldir)}, - {"sslsni", "PGSSLSNI", "1", NULL, "SSL-SNI", "", 1, offsetof(struct pg_conn, sslsni)}, - {"requirepeer", "PGREQUIREPEER", NULL, NULL, - "Require-Peer", "", 10, - offsetof(struct pg_conn, requirepeer)}, - - {"ssl_min_protocol_version", "PGSSLMINPROTOCOLVERSION", "TLSv1.2", NULL, - "SSL-Minimum-Protocol-Version", "", 8, /* sizeof("TLSv1.x") == 8 */ - offsetof(struct pg_conn, ssl_min_protocol_version)}, - {"ssl_max_protocol_version", "PGSSLMAXPROTOCOLVERSION", NULL, NULL, "SSL-Maximum-Protocol-Version", "", 8, /* sizeof("TLSv1.x") == 8 */ offsetof(struct pg_conn, ssl_max_protocol_version)}, - /* - * As with SSL, all GSS options are exposed even in builds that don't have - * support. - */ - {"gssencmode", "PGGSSENCMODE", DefaultGSSMode, NULL, - "GSSENC-Mode", "", 8, /* sizeof("disable") == 8 */ - offsetof(struct pg_conn, gssencmode)}, - - /* Kerberos and GSSAPI authentication support specifying the service name */ - {"krbsrvname", "PGKRBSRVNAME", PG_KRB_SRVNAM, NULL, - "Kerberos-service-name", "", 20, - offsetof(struct pg_conn, krbsrvname)}, - - {"gsslib", "PGGSSLIB", NULL, NULL, - "GSS-library", "", 7, /* sizeof("gssapi") == 7 */ - offsetof(struct pg_conn, gsslib)}, - - {"replication", NULL, NULL, NULL, - "Replication", "D", 5, - offsetof(struct pg_conn, replication)}, + {"ssl_min_protocol_version", "PGSSLMINPROTOCOLVERSION", "TLSv1.2", NULL, + "SSL-Minimum-Protocol-Version", "", 8, /* sizeof("TLSv1.x") == 8 */ + offsetof(struct pg_conn, ssl_min_protocol_version)}, {"target_session_attrs", "PGTARGETSESSIONATTRS", DefaultTargetSessionAttrs, NULL, "Target-Session-Attrs", "", 15, /* sizeof("prefer-standby") = 15 */ offsetof(struct pg_conn, target_session_attrs)}, + {"tcp_user_timeout", NULL, NULL, NULL, + "TCP-User-Timeout", "", 10, /* strlen(INT32_MAX) == 10 */ + offsetof(struct pg_conn, pgtcp_user_timeout)}, + + {"user", "PGUSER", NULL, NULL, + "Database-User", "", 20, + offsetof(struct pg_conn, pguser)}, + /* Terminating entry --- MUST BE LAST */ {NULL, NULL, NULL, NULL, NULL, NULL, 0} diff --git a/src/test/regress/expected/foreign_data.out b/src/test/regress/expected/foreign_data.out index 33505352cc..d5ffc4f16a 100644 --- a/src/test/regress/expected/foreign_data.out +++ b/src/test/regress/expected/foreign_data.out @@ -329,7 +329,7 @@ CREATE SERVER s6 VERSION '16.0' FOREIGN DATA WRAPPER foo OPTIONS (host 'a', dbna CREATE SERVER s7 TYPE 'oracle' VERSION '17.0' FOREIGN DATA WRAPPER foo OPTIONS (host 'a', dbname 'b'); CREATE SERVER s8 FOREIGN DATA WRAPPER postgresql OPTIONS (foo '1'); -- ERROR ERROR: invalid option "foo" -HINT: Valid options in this context are: authtype, service, connect_timeout, dbname, host, hostaddr, port, tty, options, requiressl, sslmode, gsslib +HINT: Valid options in this context are: authtype, connect_timeout, dbname, host, hostaddr, gsslib, options, port, requiressl, service, sslmode, tty CREATE SERVER s8 FOREIGN DATA WRAPPER postgresql OPTIONS (host 'localhost', dbname 's8db'); \des+ List of foreign servers @@ -440,7 +440,7 @@ ERROR: permission denied for foreign-data wrapper foo RESET ROLE; ALTER SERVER s8 OPTIONS (foo '1'); -- ERROR option validation ERROR: invalid option "foo" -HINT: Valid options in this context are: authtype, service, connect_timeout, dbname, host, hostaddr, port, tty, options, requiressl, sslmode, gsslib +HINT: Valid options in this context are: authtype, connect_timeout, dbname, host, hostaddr, gsslib, options, port, requiressl, service, sslmode, tty ALTER SERVER s8 OPTIONS (connect_timeout '30', SET dbname 'db1', DROP host); SET ROLE regress_test_role; ALTER SERVER s1 OWNER TO regress_test_indirect; -- ERROR @@ -597,7 +597,7 @@ ERROR: user mapping for "regress_foreign_data_user" already exists for server " CREATE USER MAPPING FOR public SERVER s4 OPTIONS ("this mapping" 'is public'); CREATE USER MAPPING FOR user SERVER s8 OPTIONS (username 'test', password 'secret'); -- ERROR ERROR: invalid option "username" -HINT: Valid options in this context are: user, password +HINT: Valid options in this context are: password, user CREATE USER MAPPING FOR user SERVER s8 OPTIONS (user 'test', password 'secret'); ALTER SERVER s5 OWNER TO regress_test_role; ALTER SERVER s6 OWNER TO regress_test_indirect; @@ -636,7 +636,7 @@ ALTER USER MAPPING FOR public SERVER s5 OPTIONS (gotcha 'true'); -- E ERROR: user mapping for "public" does not exist for server "s5" ALTER USER MAPPING FOR current_user SERVER s8 OPTIONS (username 'test'); -- ERROR ERROR: invalid option "username" -HINT: Valid options in this context are: user, password +HINT: Valid options in this context are: password, user ALTER USER MAPPING FOR current_user SERVER s8 OPTIONS (DROP user, SET password 'public'); SET ROLE regress_test_role; ALTER USER MAPPING FOR current_user SERVER s5 OPTIONS (ADD modified '1');