|
13 | 13 | * Portions Copyright (c) 1994, Regents of the University of California
|
14 | 14 | *
|
15 | 15 | * IDENTIFICATION
|
16 |
| - * $Header: /cvsroot/pgsql/src/backend/catalog/namespace.c,v 1.5 2002/04/01 03:34:25 tgl Exp $ |
| 16 | + * $Header: /cvsroot/pgsql/src/backend/catalog/namespace.c,v 1.6 2002/04/06 06:59:21 tgl Exp $ |
17 | 17 | *
|
18 | 18 | *-------------------------------------------------------------------------
|
19 | 19 | */
|
|
26 | 26 | #include"catalog/namespace.h"
|
27 | 27 | #include"catalog/pg_inherits.h"
|
28 | 28 | #include"catalog/pg_namespace.h"
|
| 29 | +#include"catalog/pg_proc.h" |
29 | 30 | #include"catalog/pg_shadow.h"
|
30 | 31 | #include"miscadmin.h"
|
31 | 32 | #include"nodes/makefuncs.h"
|
32 | 33 | #include"storage/backendid.h"
|
33 | 34 | #include"utils/builtins.h"
|
34 | 35 | #include"utils/fmgroids.h"
|
35 | 36 | #include"utils/guc.h"
|
| 37 | +#include"utils/catcache.h" |
36 | 38 | #include"utils/lsyscache.h"
|
37 | 39 | #include"utils/syscache.h"
|
38 | 40 |
|
@@ -301,6 +303,174 @@ TypenameGetTypid(const char *typname)
|
301 | 303 | returnInvalidOid;
|
302 | 304 | }
|
303 | 305 |
|
| 306 | +/* |
| 307 | + * FuncnameGetCandidates |
| 308 | + *Given a possibly-qualified function name and argument count, |
| 309 | + *retrieve a list of the possible matches. |
| 310 | + * |
| 311 | + * We search a single namespace if the function name is qualified, else |
| 312 | + * all namespaces in the search path. The return list will never contain |
| 313 | + * multiple entries with identical argument types --- in the multiple- |
| 314 | + * namespace case, we arrange for entries in earlier namespaces to mask |
| 315 | + * identical entries in later namespaces. |
| 316 | + */ |
| 317 | +FuncCandidateList |
| 318 | +FuncnameGetCandidates(List*names,intnargs) |
| 319 | +{ |
| 320 | +FuncCandidateListresultList=NULL; |
| 321 | +char*catalogname; |
| 322 | +char*schemaname=NULL; |
| 323 | +char*funcname=NULL; |
| 324 | +OidnamespaceId; |
| 325 | +CatCList*catlist; |
| 326 | +inti; |
| 327 | + |
| 328 | +/* deconstruct the name list */ |
| 329 | +switch (length(names)) |
| 330 | +{ |
| 331 | +case1: |
| 332 | +funcname=strVal(lfirst(names)); |
| 333 | +break; |
| 334 | +case2: |
| 335 | +schemaname=strVal(lfirst(names)); |
| 336 | +funcname=strVal(lsecond(names)); |
| 337 | +break; |
| 338 | +case3: |
| 339 | +catalogname=strVal(lfirst(names)); |
| 340 | +schemaname=strVal(lsecond(names)); |
| 341 | +funcname=strVal(lfirst(lnext(lnext(names)))); |
| 342 | +/* |
| 343 | + * We check the catalog name and then ignore it. |
| 344 | + */ |
| 345 | +if (strcmp(catalogname,DatabaseName)!=0) |
| 346 | +elog(ERROR,"Cross-database references are not implemented"); |
| 347 | +break; |
| 348 | +default: |
| 349 | +elog(ERROR,"Improper qualified name (too many dotted names)"); |
| 350 | +break; |
| 351 | +} |
| 352 | + |
| 353 | +if (schemaname) |
| 354 | +{ |
| 355 | +/* use exact schema given */ |
| 356 | +namespaceId=GetSysCacheOid(NAMESPACENAME, |
| 357 | +CStringGetDatum(schemaname), |
| 358 | +0,0,0); |
| 359 | +if (!OidIsValid(namespaceId)) |
| 360 | +elog(ERROR,"Namespace \"%s\" does not exist", |
| 361 | +schemaname); |
| 362 | +} |
| 363 | +else |
| 364 | +{ |
| 365 | +/* flag to indicate we need namespace search */ |
| 366 | +namespaceId=InvalidOid; |
| 367 | +} |
| 368 | + |
| 369 | +/* Search syscache by name and nargs only */ |
| 370 | +catlist=SearchSysCacheList(PROCNAME,2, |
| 371 | +CStringGetDatum(funcname), |
| 372 | +Int16GetDatum(nargs), |
| 373 | +0,0); |
| 374 | + |
| 375 | +for (i=0;i<catlist->n_members;i++) |
| 376 | +{ |
| 377 | +HeapTupleproctup=&catlist->members[i]->tuple; |
| 378 | +Form_pg_procprocform= (Form_pg_proc)GETSTRUCT(proctup); |
| 379 | +intpathpos=0; |
| 380 | +FuncCandidateListnewResult; |
| 381 | + |
| 382 | +if (OidIsValid(namespaceId)) |
| 383 | +{ |
| 384 | +/* Consider only procs in specified namespace */ |
| 385 | +if (procform->pronamespace!=namespaceId) |
| 386 | +continue; |
| 387 | +/* No need to check args, they must all be different */ |
| 388 | +} |
| 389 | +else |
| 390 | +{ |
| 391 | +/* Consider only procs that are in the search path */ |
| 392 | +if (pathContainsSystemNamespace|| |
| 393 | +procform->pronamespace!=PG_CATALOG_NAMESPACE) |
| 394 | +{ |
| 395 | +List*nsp; |
| 396 | + |
| 397 | +foreach(nsp,namespaceSearchPath) |
| 398 | +{ |
| 399 | +pathpos++; |
| 400 | +if (procform->pronamespace== (Oid)lfirsti(nsp)) |
| 401 | +break; |
| 402 | +} |
| 403 | +if (nsp==NIL) |
| 404 | +continue;/* proc is not in search path */ |
| 405 | +} |
| 406 | + |
| 407 | +/* |
| 408 | + * Okay, it's in the search path, but does it have the same |
| 409 | + * arguments as something we already accepted? If so, keep |
| 410 | + * only the one that appears earlier in the search path. |
| 411 | + * |
| 412 | + * If we have an ordered list from SearchSysCacheList (the |
| 413 | + * normal case), then any conflicting proc must immediately |
| 414 | + * adjoin this one in the list, so we only need to look at |
| 415 | + * the newest result item. If we have an unordered list, |
| 416 | + * we have to scan the whole result list. |
| 417 | + */ |
| 418 | +if (resultList) |
| 419 | +{ |
| 420 | +FuncCandidateListprevResult; |
| 421 | + |
| 422 | +if (catlist->ordered) |
| 423 | +{ |
| 424 | +if (memcmp(procform->proargtypes,resultList->args, |
| 425 | +nargs*sizeof(Oid))==0) |
| 426 | +prevResult=resultList; |
| 427 | +else |
| 428 | +prevResult=NULL; |
| 429 | +} |
| 430 | +else |
| 431 | +{ |
| 432 | +for (prevResult=resultList; |
| 433 | +prevResult; |
| 434 | +prevResult=prevResult->next) |
| 435 | +{ |
| 436 | +if (memcmp(procform->proargtypes,prevResult->args, |
| 437 | +nargs*sizeof(Oid))==0) |
| 438 | +break; |
| 439 | +} |
| 440 | +} |
| 441 | +if (prevResult) |
| 442 | +{ |
| 443 | +/* We have a match with a previous result */ |
| 444 | +Assert(pathpos!=prevResult->pathpos); |
| 445 | +if (pathpos>prevResult->pathpos) |
| 446 | +continue;/* keep previous result */ |
| 447 | +/* replace previous result */ |
| 448 | +prevResult->pathpos=pathpos; |
| 449 | +prevResult->oid=proctup->t_data->t_oid; |
| 450 | +continue;/* args are same, of course */ |
| 451 | +} |
| 452 | +} |
| 453 | +} |
| 454 | + |
| 455 | +/* |
| 456 | + * Okay to add it to result list |
| 457 | + */ |
| 458 | +newResult= (FuncCandidateList) |
| 459 | +palloc(sizeof(struct_FuncCandidateList)-sizeof(Oid) |
| 460 | ++nargs*sizeof(Oid)); |
| 461 | +newResult->pathpos=pathpos; |
| 462 | +newResult->oid=proctup->t_data->t_oid; |
| 463 | +memcpy(newResult->args,procform->proargtypes,nargs*sizeof(Oid)); |
| 464 | + |
| 465 | +newResult->next=resultList; |
| 466 | +resultList=newResult; |
| 467 | +} |
| 468 | + |
| 469 | +ReleaseSysCacheList(catlist); |
| 470 | + |
| 471 | +returnresultList; |
| 472 | +} |
| 473 | + |
304 | 474 | /*
|
305 | 475 | * QualifiedNameGetCreationNamespace
|
306 | 476 | *Given a possibly-qualified name for an object (in List-of-Values
|
|