|
37 | 37 | #include"libpq-fe.h"
|
38 | 38 |
|
39 | 39 | #include"access/htup_details.h"
|
| 40 | +#include"access/reloptions.h" |
40 | 41 | #include"catalog/indexing.h"
|
41 | 42 | #include"catalog/namespace.h"
|
| 43 | +#include"catalog/pg_foreign_server.h" |
42 | 44 | #include"catalog/pg_type.h"
|
| 45 | +#include"catalog/pg_user_mapping.h" |
43 | 46 | #include"executor/spi.h"
|
44 | 47 | #include"foreign/foreign.h"
|
45 | 48 | #include"funcapi.h"
|
@@ -113,6 +116,8 @@ static char *escape_param_str(const char *from);
|
113 | 116 | staticvoidvalidate_pkattnums(Relationrel,
|
114 | 117 | int2vector*pkattnums_arg,int32pknumatts_arg,
|
115 | 118 | int**pkattnums,int*pknumatts);
|
| 119 | +staticboolis_valid_dblink_option(constPQconninfoOption*options, |
| 120 | +constchar*option,Oidcontext); |
116 | 121 |
|
117 | 122 | /* Global */
|
118 | 123 | staticremoteConn*pconn=NULL;
|
@@ -1912,6 +1917,75 @@ dblink_get_notify(PG_FUNCTION_ARGS)
|
1912 | 1917 | return (Datum)0;
|
1913 | 1918 | }
|
1914 | 1919 |
|
| 1920 | +/* |
| 1921 | + * Validate the options given to a dblink foreign server or user mapping. |
| 1922 | + * Raise an error if any option is invalid. |
| 1923 | + * |
| 1924 | + * We just check the names of options here, so semantic errors in options, |
| 1925 | + * such as invalid numeric format, will be detected at the attempt to connect. |
| 1926 | + */ |
| 1927 | +PG_FUNCTION_INFO_V1(dblink_fdw_validator); |
| 1928 | +Datum |
| 1929 | +dblink_fdw_validator(PG_FUNCTION_ARGS) |
| 1930 | +{ |
| 1931 | +List*options_list=untransformRelOptions(PG_GETARG_DATUM(0)); |
| 1932 | +Oidcontext=PG_GETARG_OID(1); |
| 1933 | +ListCell*cell; |
| 1934 | + |
| 1935 | +staticconstPQconninfoOption*options=NULL; |
| 1936 | + |
| 1937 | +/* |
| 1938 | + * Get list of valid libpq options. |
| 1939 | + * |
| 1940 | + * To avoid unnecessary work, we get the list once and use it throughout |
| 1941 | + * the lifetime of this backend process. We don't need to care about |
| 1942 | + * memory context issues, because PQconndefaults allocates with malloc. |
| 1943 | + */ |
| 1944 | +if (!options) |
| 1945 | +{ |
| 1946 | +options=PQconndefaults(); |
| 1947 | +if (!options)/* assume reason for failure is OOM */ |
| 1948 | +ereport(ERROR, |
| 1949 | +(errcode(ERRCODE_FDW_OUT_OF_MEMORY), |
| 1950 | +errmsg("out of memory"), |
| 1951 | +errdetail("could not get libpq's default connection options"))); |
| 1952 | +} |
| 1953 | + |
| 1954 | +/* Validate each supplied option. */ |
| 1955 | +foreach(cell,options_list) |
| 1956 | +{ |
| 1957 | +DefElem*def= (DefElem*)lfirst(cell); |
| 1958 | + |
| 1959 | +if (!is_valid_dblink_option(options,def->defname,context)) |
| 1960 | +{ |
| 1961 | +/* |
| 1962 | + * Unknown option, or invalid option for the context specified, |
| 1963 | + * so complain about it. Provide a hint with list of valid |
| 1964 | + * options for the context. |
| 1965 | + */ |
| 1966 | +StringInfoDatabuf; |
| 1967 | +constPQconninfoOption*opt; |
| 1968 | + |
| 1969 | +initStringInfo(&buf); |
| 1970 | +for (opt=options;opt->keyword;opt++) |
| 1971 | +{ |
| 1972 | +if (is_valid_dblink_option(options,opt->keyword,context)) |
| 1973 | +appendStringInfo(&buf,"%s%s", |
| 1974 | + (buf.len>0) ?", " :"", |
| 1975 | +opt->keyword); |
| 1976 | +} |
| 1977 | +ereport(ERROR, |
| 1978 | +(errcode(ERRCODE_FDW_OPTION_NAME_NOT_FOUND), |
| 1979 | +errmsg("invalid option \"%s\"",def->defname), |
| 1980 | +errhint("Valid options in this context are: %s", |
| 1981 | +buf.data))); |
| 1982 | +} |
| 1983 | +} |
| 1984 | + |
| 1985 | +PG_RETURN_VOID(); |
| 1986 | +} |
| 1987 | + |
| 1988 | + |
1915 | 1989 | /*************************************************************
|
1916 | 1990 | * internal functions
|
1917 | 1991 | */
|
@@ -2768,3 +2842,59 @@ validate_pkattnums(Relation rel,
|
2768 | 2842 | errmsg("invalid attribute number %d",pkattnum)));
|
2769 | 2843 | }
|
2770 | 2844 | }
|
| 2845 | + |
| 2846 | +/* |
| 2847 | + * Check if the specified connection option is valid. |
| 2848 | + * |
| 2849 | + * We basically allow whatever libpq thinks is an option, with these |
| 2850 | + * restrictions: |
| 2851 | + *debug options: disallowed |
| 2852 | + *"client_encoding": disallowed |
| 2853 | + *"user": valid only in USER MAPPING options |
| 2854 | + *secure options (eg password): valid only in USER MAPPING options |
| 2855 | + *others: valid only in FOREIGN SERVER options |
| 2856 | + * |
| 2857 | + * We disallow client_encoding because it would be overridden anyway via |
| 2858 | + * PQclientEncoding; allowing it to be specified would merely promote |
| 2859 | + * confusion. |
| 2860 | + */ |
| 2861 | +staticbool |
| 2862 | +is_valid_dblink_option(constPQconninfoOption*options,constchar*option, |
| 2863 | +Oidcontext) |
| 2864 | +{ |
| 2865 | +constPQconninfoOption*opt; |
| 2866 | + |
| 2867 | +/* Look up the option in libpq result */ |
| 2868 | +for (opt=options;opt->keyword;opt++) |
| 2869 | +{ |
| 2870 | +if (strcmp(opt->keyword,option)==0) |
| 2871 | +break; |
| 2872 | +} |
| 2873 | +if (opt->keyword==NULL) |
| 2874 | +return false; |
| 2875 | + |
| 2876 | +/* Disallow debug options (particularly "replication") */ |
| 2877 | +if (strchr(opt->dispchar,'D')) |
| 2878 | +return false; |
| 2879 | + |
| 2880 | +/* Disallow "client_encoding" */ |
| 2881 | +if (strcmp(opt->keyword,"client_encoding")==0) |
| 2882 | +return false; |
| 2883 | + |
| 2884 | +/* |
| 2885 | + * If the option is "user" or marked secure, it should be specified only |
| 2886 | + * in USER MAPPING. Others should be specified only in SERVER. |
| 2887 | + */ |
| 2888 | +if (strcmp(opt->keyword,"user")==0||strchr(opt->dispchar,'*')) |
| 2889 | +{ |
| 2890 | +if (context!=UserMappingRelationId) |
| 2891 | +return false; |
| 2892 | +} |
| 2893 | +else |
| 2894 | +{ |
| 2895 | +if (context!=ForeignServerRelationId) |
| 2896 | +return false; |
| 2897 | +} |
| 2898 | + |
| 2899 | +return true; |
| 2900 | +} |