LCOV - code coverage report
Current view: top level - src/backend/commands - amcmds.c (source / functions) Hit Total Coverage
Test: PostgreSQL Lines: 65 77 84.4 %
Date: 2017-09-29 15:12:54 Functions: 7 8 87.5 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * amcmds.c
       4             :  *    Routines for SQL commands that manipulate access methods.
       5             :  *
       6             :  * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
       7             :  * Portions Copyright (c) 1994, Regents of the University of California
       8             :  *
       9             :  *
      10             :  * IDENTIFICATION
      11             :  *    src/backend/commands/amcmds.c
      12             :  *-------------------------------------------------------------------------
      13             :  */
      14             : #include "postgres.h"
      15             : 
      16             : #include "access/heapam.h"
      17             : #include "access/htup_details.h"
      18             : #include "catalog/dependency.h"
      19             : #include "catalog/indexing.h"
      20             : #include "catalog/pg_am.h"
      21             : #include "catalog/pg_proc.h"
      22             : #include "catalog/pg_type.h"
      23             : #include "commands/defrem.h"
      24             : #include "miscadmin.h"
      25             : #include "parser/parse_func.h"
      26             : #include "utils/builtins.h"
      27             : #include "utils/lsyscache.h"
      28             : #include "utils/rel.h"
      29             : #include "utils/syscache.h"
      30             : 
      31             : 
      32             : static Oid  lookup_index_am_handler_func(List *handler_name, char amtype);
      33             : static const char *get_am_type_string(char amtype);
      34             : 
      35             : 
      36             : /*
      37             :  * CreateAccessMethod
      38             :  *      Registers a new access method.
      39             :  */
      40             : ObjectAddress
      41           1 : CreateAccessMethod(CreateAmStmt *stmt)
      42             : {
      43             :     Relation    rel;
      44             :     ObjectAddress myself;
      45             :     ObjectAddress referenced;
      46             :     Oid         amoid;
      47             :     Oid         amhandler;
      48             :     bool        nulls[Natts_pg_am];
      49             :     Datum       values[Natts_pg_am];
      50             :     HeapTuple   tup;
      51             : 
      52           1 :     rel = heap_open(AccessMethodRelationId, RowExclusiveLock);
      53             : 
      54             :     /* Must be super user */
      55           1 :     if (!superuser())
      56           0 :         ereport(ERROR,
      57             :                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
      58             :                  errmsg("permission denied to create access method \"%s\"",
      59             :                         stmt->amname),
      60             :                  errhint("Must be superuser to create an access method.")));
      61             : 
      62             :     /* Check if name is used */
      63           1 :     amoid = GetSysCacheOid1(AMNAME, CStringGetDatum(stmt->amname));
      64           1 :     if (OidIsValid(amoid))
      65             :     {
      66           0 :         ereport(ERROR,
      67             :                 (errcode(ERRCODE_DUPLICATE_OBJECT),
      68             :                  errmsg("access method \"%s\" already exists",
      69             :                         stmt->amname)));
      70             :     }
      71             : 
      72             :     /*
      73             :      * Get the handler function oid, verifying the AM type while at it.
      74             :      */
      75           1 :     amhandler = lookup_index_am_handler_func(stmt->handler_name, stmt->amtype);
      76             : 
      77             :     /*
      78             :      * Insert tuple into pg_am.
      79             :      */
      80           1 :     memset(values, 0, sizeof(values));
      81           1 :     memset(nulls, false, sizeof(nulls));
      82             : 
      83           1 :     values[Anum_pg_am_amname - 1] =
      84           1 :         DirectFunctionCall1(namein, CStringGetDatum(stmt->amname));
      85           1 :     values[Anum_pg_am_amhandler - 1] = ObjectIdGetDatum(amhandler);
      86           1 :     values[Anum_pg_am_amtype - 1] = CharGetDatum(stmt->amtype);
      87             : 
      88           1 :     tup = heap_form_tuple(RelationGetDescr(rel), values, nulls);
      89             : 
      90           1 :     amoid = CatalogTupleInsert(rel, tup);
      91           1 :     heap_freetuple(tup);
      92             : 
      93           1 :     myself.classId = AccessMethodRelationId;
      94           1 :     myself.objectId = amoid;
      95           1 :     myself.objectSubId = 0;
      96             : 
      97             :     /* Record dependency on handler function */
      98           1 :     referenced.classId = ProcedureRelationId;
      99           1 :     referenced.objectId = amhandler;
     100           1 :     referenced.objectSubId = 0;
     101             : 
     102           1 :     recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
     103             : 
     104           1 :     recordDependencyOnCurrentExtension(&myself, false);
     105             : 
     106           1 :     heap_close(rel, RowExclusiveLock);
     107             : 
     108           1 :     return myself;
     109             : }
     110             : 
     111             : /*
     112             :  * Guts of access method deletion.
     113             :  */
     114             : void
     115           1 : RemoveAccessMethodById(Oid amOid)
     116             : {
     117             :     Relation    relation;
     118             :     HeapTuple   tup;
     119             : 
     120           1 :     if (!superuser())
     121           0 :         ereport(ERROR,
     122             :                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
     123             :                  errmsg("must be superuser to drop access methods")));
     124             : 
     125           1 :     relation = heap_open(AccessMethodRelationId, RowExclusiveLock);
     126             : 
     127           1 :     tup = SearchSysCache1(AMOID, ObjectIdGetDatum(amOid));
     128           1 :     if (!HeapTupleIsValid(tup))
     129           0 :         elog(ERROR, "cache lookup failed for access method %u", amOid);
     130             : 
     131           1 :     CatalogTupleDelete(relation, &tup->t_self);
     132             : 
     133           1 :     ReleaseSysCache(tup);
     134             : 
     135           1 :     heap_close(relation, RowExclusiveLock);
     136           1 : }
     137             : 
     138             : /*
     139             :  * get_am_type_oid
     140             :  *      Worker for various get_am_*_oid variants
     141             :  *
     142             :  * If missing_ok is false, throw an error if access method not found.  If
     143             :  * true, just return InvalidOid.
     144             :  *
     145             :  * If amtype is not '\0', an error is raised if the AM found is not of the
     146             :  * given type.
     147             :  */
     148             : static Oid
     149         102 : get_am_type_oid(const char *amname, char amtype, bool missing_ok)
     150             : {
     151             :     HeapTuple   tup;
     152         102 :     Oid         oid = InvalidOid;
     153             : 
     154         102 :     tup = SearchSysCache1(AMNAME, CStringGetDatum(amname));
     155         102 :     if (HeapTupleIsValid(tup))
     156             :     {
     157          87 :         Form_pg_am  amform = (Form_pg_am) GETSTRUCT(tup);
     158             : 
     159         169 :         if (amtype != '\0' &&
     160          82 :             amform->amtype != amtype)
     161           0 :             ereport(ERROR,
     162             :                     (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
     163             :                      errmsg("access method \"%s\" is not of type %s",
     164             :                             NameStr(amform->amname),
     165             :                             get_am_type_string(amtype))));
     166             : 
     167          87 :         oid = HeapTupleGetOid(tup);
     168          87 :         ReleaseSysCache(tup);
     169             :     }
     170             : 
     171         102 :     if (!OidIsValid(oid) && !missing_ok)
     172          14 :         ereport(ERROR,
     173             :                 (errcode(ERRCODE_UNDEFINED_OBJECT),
     174             :                  errmsg("access method \"%s\" does not exist", amname)));
     175          88 :     return oid;
     176             : }
     177             : 
     178             : /*
     179             :  * get_index_am_oid - given an access method name, look up its OID
     180             :  *      and verify it corresponds to an index AM.
     181             :  */
     182             : Oid
     183          94 : get_index_am_oid(const char *amname, bool missing_ok)
     184             : {
     185          94 :     return get_am_type_oid(amname, AMTYPE_INDEX, missing_ok);
     186             : }
     187             : 
     188             : /*
     189             :  * get_am_oid - given an access method name, look up its OID.
     190             :  *      The type is not checked.
     191             :  */
     192             : Oid
     193           8 : get_am_oid(const char *amname, bool missing_ok)
     194             : {
     195           8 :     return get_am_type_oid(amname, '\0', missing_ok);
     196             : }
     197             : 
     198             : /*
     199             :  * get_am_name - given an access method OID name and type, look up its name.
     200             :  */
     201             : char *
     202          12 : get_am_name(Oid amOid)
     203             : {
     204             :     HeapTuple   tup;
     205          12 :     char       *result = NULL;
     206             : 
     207          12 :     tup = SearchSysCache1(AMOID, ObjectIdGetDatum(amOid));
     208          12 :     if (HeapTupleIsValid(tup))
     209             :     {
     210          12 :         Form_pg_am  amform = (Form_pg_am) GETSTRUCT(tup);
     211             : 
     212          12 :         result = pstrdup(NameStr(amform->amname));
     213          12 :         ReleaseSysCache(tup);
     214             :     }
     215          12 :     return result;
     216             : }
     217             : 
     218             : /*
     219             :  * Convert single-character access method type into string for error reporting.
     220             :  */
     221             : static const char *
     222           0 : get_am_type_string(char amtype)
     223             : {
     224           0 :     switch (amtype)
     225             :     {
     226             :         case AMTYPE_INDEX:
     227           0 :             return "INDEX";
     228             :         default:
     229             :             /* shouldn't happen */
     230           0 :             elog(ERROR, "invalid access method type '%c'", amtype);
     231             :             return NULL;        /* keep compiler quiet */
     232             :     }
     233             : }
     234             : 
     235             : /*
     236             :  * Convert a handler function name to an Oid.  If the return type of the
     237             :  * function doesn't match the given AM type, an error is raised.
     238             :  *
     239             :  * This function either return valid function Oid or throw an error.
     240             :  */
     241             : static Oid
     242           1 : lookup_index_am_handler_func(List *handler_name, char amtype)
     243             : {
     244             :     Oid         handlerOid;
     245             :     static const Oid funcargtypes[1] = {INTERNALOID};
     246             : 
     247           1 :     if (handler_name == NIL)
     248           0 :         ereport(ERROR,
     249             :                 (errcode(ERRCODE_UNDEFINED_FUNCTION),
     250             :                  errmsg("handler function is not specified")));
     251             : 
     252             :     /* handlers have one argument of type internal */
     253           1 :     handlerOid = LookupFuncName(handler_name, 1, funcargtypes, false);
     254             : 
     255             :     /* check that handler has the correct return type */
     256           1 :     switch (amtype)
     257             :     {
     258             :         case AMTYPE_INDEX:
     259           1 :             if (get_func_rettype(handlerOid) != INDEX_AM_HANDLEROID)
     260           0 :                 ereport(ERROR,
     261             :                         (errcode(ERRCODE_WRONG_OBJECT_TYPE),
     262             :                          errmsg("function %s must return type %s",
     263             :                                 NameListToString(handler_name),
     264             :                                 "index_am_handler")));
     265           1 :             break;
     266             :         default:
     267           0 :             elog(ERROR, "unrecognized access method type \"%c\"", amtype);
     268             :     }
     269             : 
     270           1 :     return handlerOid;
     271             : }

Generated by: LCOV version 1.11