Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit0fdc6c4

Browse files
committed
Create a validator for plpgsql, so that some minimal syntax checking
is done at creation time for plpgsql functions. Improve createlang anddroplang to support adding/dropping validators for PLs. Initial stepstowards producing a syntax error position from plpgsql syntax errors(this part is a work in progress, and will change depending on outcomeof current discussions).
1 parent74ffc77 commit0fdc6c4

File tree

7 files changed

+300
-67
lines changed

7 files changed

+300
-67
lines changed

‎src/bin/scripts/createlang.c

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
66
* Portions Copyright (c) 1994, Regents of the University of California
77
*
8-
* $PostgreSQL: pgsql/src/bin/scripts/createlang.c,v 1.7 2003/11/29 19:52:07pgsql Exp $
8+
* $PostgreSQL: pgsql/src/bin/scripts/createlang.c,v 1.8 2004/03/19 18:58:07tgl Exp $
99
*
1010
*-------------------------------------------------------------------------
1111
*/
@@ -49,8 +49,10 @@ main(int argc, char *argv[])
4949

5050
char*p;
5151
boolhandlerexists;
52+
boolvalidatorexists;
5253
booltrusted;
5354
char*handler;
55+
char*validator=NULL;
5456
char*object;
5557

5658
PQExpBufferDatasql;
@@ -169,6 +171,7 @@ main(int argc, char *argv[])
169171
{
170172
trusted= true;
171173
handler="plpgsql_call_handler";
174+
validator="plpgsql_validator";
172175
object="plpgsql";
173176
}
174177
elseif (strcmp(langname,"pltcl")==0)
@@ -229,13 +232,26 @@ main(int argc, char *argv[])
229232
/*
230233
* Check whether the call handler exists
231234
*/
232-
printfPQExpBuffer(&sql,"SELECT oid FROM pg_proc WHERE proname = '%s' AND prorettype =(SELECT oid FROM pg_type WHERE typname = 'language_handler') AND pronargs = 0;",handler);
235+
printfPQExpBuffer(&sql,"SELECT oid FROM pg_proc WHERE proname = '%s' AND prorettype ='pg_catalog.language_handler'::regtype AND pronargs = 0;",handler);
233236
result=executeQuery(conn,sql.data,progname,echo);
234237
handlerexists= (PQntuples(result)>0);
235238
PQclear(result);
236239

237240
/*
238-
* Create the call handler and the language
241+
* Check whether the validator exists
242+
*/
243+
if (validator)
244+
{
245+
printfPQExpBuffer(&sql,"SELECT oid FROM pg_proc WHERE proname = '%s' AND proargtypes[0] = 'pg_catalog.oid'::regtype AND pronargs = 1;",validator);
246+
result=executeQuery(conn,sql.data,progname,echo);
247+
validatorexists= (PQntuples(result)>0);
248+
PQclear(result);
249+
}
250+
else
251+
validatorexists= true;/* don't try to create it */
252+
253+
/*
254+
* Create the function(s) and the language
239255
*/
240256
resetPQExpBuffer(&sql);
241257

@@ -244,10 +260,20 @@ main(int argc, char *argv[])
244260
"CREATE FUNCTION \"%s\" () RETURNS language_handler AS '%s/%s' LANGUAGE C;\n",
245261
handler,pglib,object);
246262

263+
if (!validatorexists)
264+
appendPQExpBuffer(&sql,
265+
"CREATE FUNCTION \"%s\" (oid) RETURNS void AS '%s/%s' LANGUAGE C;\n",
266+
validator,pglib,object);
267+
247268
appendPQExpBuffer(&sql,
248-
"CREATE %sLANGUAGE \"%s\" HANDLER \"%s\";\n",
269+
"CREATE %sLANGUAGE \"%s\" HANDLER \"%s\"",
249270
(trusted ?"TRUSTED " :""),langname,handler);
250271

272+
if (validator)
273+
appendPQExpBuffer(&sql," VALIDATOR \"%s\"",validator);
274+
275+
appendPQExpBuffer(&sql,";\n");
276+
251277
if (echo)
252278
printf("%s",sql.data);
253279
result=PQexec(conn,sql.data);

‎src/bin/scripts/droplang.c

Lines changed: 49 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
66
* Portions Copyright (c) 1994, Regents of the University of California
77
*
8-
* $PostgreSQL: pgsql/src/bin/scripts/droplang.c,v 1.6 2003/11/29 19:52:07pgsql Exp $
8+
* $PostgreSQL: pgsql/src/bin/scripts/droplang.c,v 1.7 2004/03/19 18:58:07tgl Exp $
99
*
1010
*-------------------------------------------------------------------------
1111
*/
@@ -14,6 +14,8 @@
1414
#include"common.h"
1515
#include"print.h"
1616

17+
#defineatooid(x) ((Oid) strtoul((x), NULL, 10))
18+
1719

1820
staticvoidhelp(constchar*progname);
1921

@@ -46,9 +48,12 @@ main(int argc, char *argv[])
4648
char*langname=NULL;
4749

4850
char*p;
49-
char*lanplcallfoid;
51+
Oidlanplcallfoid;
52+
Oidlanvalidator;
5053
char*handler;
54+
char*validator;
5155
boolkeephandler;
56+
boolkeepvalidator;
5257

5358
PQExpBufferDatasql;
5459

@@ -159,10 +164,10 @@ main(int argc, char *argv[])
159164
conn=connectDatabase(dbname,host,port,username,password,progname);
160165

161166
/*
162-
* Make sure the language is installed and find theOID of the handler
163-
*function
167+
* Make sure the language is installed and find theOIDs of the handler
168+
*and validator functions
164169
*/
165-
printfPQExpBuffer(&sql,"SELECT lanplcallfoid FROM pg_language WHERE lanname = '%s' AND lanispl;",langname);
170+
printfPQExpBuffer(&sql,"SELECT lanplcallfoid, lanvalidator FROM pg_language WHERE lanname = '%s' AND lanispl;",langname);
166171
result=executeQuery(conn,sql.data,progname,echo);
167172
if (PQntuples(result)==0)
168173
{
@@ -171,8 +176,9 @@ main(int argc, char *argv[])
171176
progname,langname,dbname);
172177
exit(1);
173178
}
174-
lanplcallfoid=PQgetvalue(result,0,0);
175-
/* result not cleared! */
179+
lanplcallfoid=atooid(PQgetvalue(result,0,0));
180+
lanvalidator=atooid(PQgetvalue(result,0,1));
181+
PQclear(result);
176182

177183
/*
178184
* Check that there are no functions left defined in that language
@@ -192,7 +198,7 @@ main(int argc, char *argv[])
192198
/*
193199
* Check that the handler function isn't used by some other language
194200
*/
195-
printfPQExpBuffer(&sql,"SELECT count(*) FROM pg_language WHERE lanplcallfoid = %s AND lanname <> '%s';",lanplcallfoid,langname);
201+
printfPQExpBuffer(&sql,"SELECT count(*) FROM pg_language WHERE lanplcallfoid = %u AND lanname <> '%s';",lanplcallfoid,langname);
196202
result=executeQuery(conn,sql.data,progname,echo);
197203
if (strcmp(PQgetvalue(result,0,0),"0")==0)
198204
keephandler= false;
@@ -205,20 +211,51 @@ main(int argc, char *argv[])
205211
*/
206212
if (!keephandler)
207213
{
208-
printfPQExpBuffer(&sql,"SELECT proname FROM pg_proc WHERE oid = %s;",lanplcallfoid);
214+
printfPQExpBuffer(&sql,"SELECT proname FROM pg_proc WHERE oid = %u;",lanplcallfoid);
209215
result=executeQuery(conn,sql.data,progname,echo);
210-
handler=PQgetvalue(result,0,0);
211-
/*result not cleared! */
216+
handler=strdup(PQgetvalue(result,0,0));
217+
PQclear(result);
212218
}
213219
else
214220
handler=NULL;
215221

216222
/*
217-
* Drop the language
223+
* Check that the validator function isn't used by some other language
224+
*/
225+
if (OidIsValid(lanvalidator))
226+
{
227+
printfPQExpBuffer(&sql,"SELECT count(*) FROM pg_language WHERE lanvalidator = %u AND lanname <> '%s';",lanvalidator,langname);
228+
result=executeQuery(conn,sql.data,progname,echo);
229+
if (strcmp(PQgetvalue(result,0,0),"0")==0)
230+
keepvalidator= false;
231+
else
232+
keepvalidator= true;
233+
PQclear(result);
234+
}
235+
else
236+
keepvalidator= true;/* don't try to delete it */
237+
238+
/*
239+
* Find the validator name
240+
*/
241+
if (!keepvalidator)
242+
{
243+
printfPQExpBuffer(&sql,"SELECT proname FROM pg_proc WHERE oid = %u;",lanvalidator);
244+
result=executeQuery(conn,sql.data,progname,echo);
245+
validator=strdup(PQgetvalue(result,0,0));
246+
PQclear(result);
247+
}
248+
else
249+
validator=NULL;
250+
251+
/*
252+
* Drop the language and the functions
218253
*/
219254
printfPQExpBuffer(&sql,"DROP LANGUAGE \"%s\";\n",langname);
220255
if (!keephandler)
221256
appendPQExpBuffer(&sql,"DROP FUNCTION \"%s\" ();\n",handler);
257+
if (!keepvalidator)
258+
appendPQExpBuffer(&sql,"DROP FUNCTION \"%s\" (oid);\n",validator);
222259
if (echo)
223260
printf("%s",sql.data);
224261
result=PQexec(conn,sql.data);

‎src/include/catalog/pg_type.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
99
* Portions Copyright (c) 1994, Regents of the University of California
1010
*
11-
* $PostgreSQL: pgsql/src/include/catalog/pg_type.h,v 1.150 2004/02/24 22:59:10 tgl Exp $
11+
* $PostgreSQL: pgsql/src/include/catalog/pg_type.h,v 1.151 2004/03/19 18:58:07 tgl Exp $
1212
*
1313
* NOTES
1414
* the genbki.sh script reads this file and generates .bki
@@ -402,6 +402,7 @@ DATA(insert OID = 1003 ( _name PGNSP PGUID -1 f b t \054 019 array_in array_
402402
DATA(insertOID=1005 (_int2PGNSPPGUID-1fbt \054021array_inarray_outarray_recvarray_send-ixf0-10_null__null_ ));
403403
DATA(insertOID=1006 (_int2vectorPGNSPPGUID-1fbt \054022array_inarray_outarray_recvarray_send-ixf0-10_null__null_ ));
404404
DATA(insertOID=1007 (_int4PGNSPPGUID-1fbt \054023array_inarray_outarray_recvarray_send-ixf0-10_null__null_ ));
405+
#defineINT4ARRAYOID1007
405406
DATA(insertOID=1008 (_regprocPGNSPPGUID-1fbt \054024array_inarray_outarray_recvarray_send-ixf0-10_null__null_ ));
406407
DATA(insertOID=1009 (_textPGNSPPGUID-1fbt \054025array_inarray_outarray_recvarray_send-ixf0-10_null__null_ ));
407408
DATA(insertOID=1028 (_oidPGNSPPGUID-1fbt \054026array_inarray_outarray_recvarray_send-ixf0-10_null__null_ ));

‎src/pl/plpgsql/src/pl_comp.c

Lines changed: 46 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* procedural language
44
*
55
* IDENTIFICATION
6-
* $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_comp.c,v 1.73 2004/01/07 18:56:30 neilc Exp $
6+
* $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_comp.c,v 1.74 2004/03/19 18:58:07 tgl Exp $
77
*
88
* This software is copyrighted by Jan Wieck - Hamburg.
99
*
@@ -101,13 +101,15 @@ typedef struct plpgsql_hashent
101101
*/
102102
staticPLpgSQL_function*do_compile(FunctionCallInfofcinfo,
103103
HeapTupleprocTup,
104-
PLpgSQL_func_hashkey*hashkey);
104+
PLpgSQL_func_hashkey*hashkey,
105+
boolforValidator);
105106
staticvoidplpgsql_compile_error_callback(void*arg);
106107
staticchar**fetchArgNames(HeapTupleprocTup,intnargs);
107108
staticPLpgSQL_type*build_datatype(HeapTupletypeTup,int32typmod);
108109
staticvoidcompute_function_hashkey(FunctionCallInfofcinfo,
109110
Form_pg_procprocStruct,
110-
PLpgSQL_func_hashkey*hashkey);
111+
PLpgSQL_func_hashkey*hashkey,
112+
boolforValidator);
111113
staticPLpgSQL_function*plpgsql_HashTableLookup(PLpgSQL_func_hashkey*func_key);
112114
staticvoidplpgsql_HashTableInsert(PLpgSQL_function*function,
113115
PLpgSQL_func_hashkey*func_key);
@@ -134,12 +136,15 @@ perm_fmgr_info(Oid functionId, FmgrInfo *finfo)
134136
/* ----------
135137
* plpgsql_compileMake an execution tree for a PL/pgSQL function.
136138
*
139+
* If forValidator is true, we're only compiling for validation purposes,
140+
* and so some checks are skipped.
141+
*
137142
* Note: it's important for this to fall through quickly if the function
138143
* has already been compiled.
139144
* ----------
140145
*/
141146
PLpgSQL_function*
142-
plpgsql_compile(FunctionCallInfofcinfo)
147+
plpgsql_compile(FunctionCallInfofcinfo,boolforValidator)
143148
{
144149
OidfuncOid=fcinfo->flinfo->fn_oid;
145150
HeapTupleprocTup;
@@ -171,7 +176,7 @@ plpgsql_compile(FunctionCallInfo fcinfo)
171176
plpgsql_HashTableInit();
172177

173178
/* Compute hashkey using function signature and actual arg types */
174-
compute_function_hashkey(fcinfo,procStruct,&hashkey);
179+
compute_function_hashkey(fcinfo,procStruct,&hashkey,forValidator);
175180
hashkey_valid= true;
176181

177182
/* And do the lookup */
@@ -205,12 +210,13 @@ plpgsql_compile(FunctionCallInfo fcinfo)
205210
* the completed function.
206211
*/
207212
if (!hashkey_valid)
208-
compute_function_hashkey(fcinfo,procStruct,&hashkey);
213+
compute_function_hashkey(fcinfo,procStruct,&hashkey,
214+
forValidator);
209215

210216
/*
211217
* Do the hard part.
212218
*/
213-
function=do_compile(fcinfo,procTup,&hashkey);
219+
function=do_compile(fcinfo,procTup,&hashkey,forValidator);
214220
}
215221

216222
ReleaseSysCache(procTup);
@@ -232,7 +238,8 @@ plpgsql_compile(FunctionCallInfo fcinfo)
232238
staticPLpgSQL_function*
233239
do_compile(FunctionCallInfofcinfo,
234240
HeapTupleprocTup,
235-
PLpgSQL_func_hashkey*hashkey)
241+
PLpgSQL_func_hashkey*hashkey,
242+
boolforValidator)
236243
{
237244
Form_pg_procprocStruct= (Form_pg_proc)GETSTRUCT(procTup);
238245
intfunctype=CALLED_AS_TRIGGER(fcinfo) ?T_TRIGGER :T_FUNCTION;
@@ -308,7 +315,8 @@ do_compile(FunctionCallInfo fcinfo,
308315
/*
309316
* Check for a polymorphic returntype. If found, use the
310317
* actual returntype type from the caller's FuncExpr node, if
311-
* we have one.
318+
* we have one. (In validation mode we arbitrarily assume we
319+
* are dealing with integers.)
312320
*
313321
* Note: errcode is FEATURE_NOT_SUPPORTED because it should
314322
* always work; if it doesn't we're in some context that fails
@@ -317,7 +325,15 @@ do_compile(FunctionCallInfo fcinfo,
317325
rettypeid=procStruct->prorettype;
318326
if (rettypeid==ANYARRAYOID||rettypeid==ANYELEMENTOID)
319327
{
320-
rettypeid=get_fn_expr_rettype(fcinfo->flinfo);
328+
if (forValidator)
329+
{
330+
if (rettypeid==ANYARRAYOID)
331+
rettypeid=INT4ARRAYOID;
332+
else
333+
rettypeid=INT4OID;
334+
}
335+
else
336+
rettypeid=get_fn_expr_rettype(fcinfo->flinfo);
321337
if (!OidIsValid(rettypeid))
322338
ereport(ERROR,
323339
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
@@ -1758,22 +1774,6 @@ plpgsql_add_initdatums(int **varnos)
17581774
}
17591775

17601776

1761-
/* ---------
1762-
* plpgsql_yyerrorHandle parser error
1763-
* ---------
1764-
*/
1765-
1766-
void
1767-
plpgsql_yyerror(constchar*s)
1768-
{
1769-
plpgsql_error_lineno=plpgsql_scanner_lineno();
1770-
ereport(ERROR,
1771-
(errcode(ERRCODE_SYNTAX_ERROR),
1772-
/* translator: first %s is a phrase like "syntax error" */
1773-
errmsg("%s at or near \"%s\"",s,plpgsql_yytext)));
1774-
}
1775-
1776-
17771777
/*
17781778
* Compute the hashkey for a given function invocation
17791779
*
@@ -1782,7 +1782,8 @@ plpgsql_yyerror(const char *s)
17821782
staticvoid
17831783
compute_function_hashkey(FunctionCallInfofcinfo,
17841784
Form_pg_procprocStruct,
1785-
PLpgSQL_func_hashkey*hashkey)
1785+
PLpgSQL_func_hashkey*hashkey,
1786+
boolforValidator)
17861787
{
17871788
inti;
17881789

@@ -1792,8 +1793,12 @@ compute_function_hashkey(FunctionCallInfo fcinfo,
17921793
/* get function OID */
17931794
hashkey->funcOid=fcinfo->flinfo->fn_oid;
17941795

1795-
/* if trigger, get relation OID */
1796-
if (CALLED_AS_TRIGGER(fcinfo))
1796+
/*
1797+
* if trigger, get relation OID. In validation mode we do not know what
1798+
* relation is intended to be used, so we leave trigrelOid zero; the
1799+
* hash entry built in this case will never really be used.
1800+
*/
1801+
if (CALLED_AS_TRIGGER(fcinfo)&& !forValidator)
17971802
{
17981803
TriggerData*trigdata= (TriggerData*)fcinfo->context;
17991804

@@ -1808,14 +1813,25 @@ compute_function_hashkey(FunctionCallInfo fcinfo,
18081813
/*
18091814
* Check for polymorphic arguments. If found, use the actual
18101815
* parameter type from the caller's FuncExpr node, if we have one.
1816+
* (In validation mode we arbitrarily assume we are dealing with
1817+
* integers. This lets us build a valid, if possibly useless,
1818+
* function hashtable entry.)
18111819
*
18121820
* We can support arguments of type ANY the same way as normal
18131821
* polymorphic arguments.
18141822
*/
18151823
if (argtypeid==ANYARRAYOID||argtypeid==ANYELEMENTOID||
18161824
argtypeid==ANYOID)
18171825
{
1818-
argtypeid=get_fn_expr_argtype(fcinfo->flinfo,i);
1826+
if (forValidator)
1827+
{
1828+
if (argtypeid==ANYARRAYOID)
1829+
argtypeid=INT4ARRAYOID;
1830+
else
1831+
argtypeid=INT4OID;
1832+
}
1833+
else
1834+
argtypeid=get_fn_expr_argtype(fcinfo->flinfo,i);
18191835
if (!OidIsValid(argtypeid))
18201836
ereport(ERROR,
18211837
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp