|
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 | return InvalidOid;
|
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, int nargs) |
| 319 | +{ |
| 320 | + FuncCandidateList resultList = NULL; |
| 321 | + char *catalogname; |
| 322 | + char *schemaname = NULL; |
| 323 | + char *funcname = NULL; |
| 324 | + Oid namespaceId; |
| 325 | + CatCList *catlist; |
| 326 | + int i; |
| 327 | + |
| 328 | + /* deconstruct the name list */ |
| 329 | + switch (length(names)) |
| 330 | + { |
| 331 | + case 1: |
| 332 | + funcname = strVal(lfirst(names)); |
| 333 | + break; |
| 334 | + case 2: |
| 335 | + schemaname = strVal(lfirst(names)); |
| 336 | + funcname = strVal(lsecond(names)); |
| 337 | + break; |
| 338 | + case 3: |
| 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 | + HeapTuple proctup = &catlist->members[i]->tuple; |
| 378 | + Form_pg_proc procform = (Form_pg_proc) GETSTRUCT(proctup); |
| 379 | + int pathpos = 0; |
| 380 | + FuncCandidateList newResult; |
| 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 | + FuncCandidateList prevResult; |
| 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 | + return resultList; |
| 472 | +} |
| 473 | + |
304 | 474 | /*
|
305 | 475 | * QualifiedNameGetCreationNamespace
|
306 | 476 | * Given a possibly-qualified name for an object (in List-of-Values
|
|
0 commit comments