LCOV - differential code coverage report
Current view: top level - src/backend/commands - tsearchcmds.c (source / functions) Coverage Total Hit UNC LBC UIC UBC GBC GIC GNC CBC EUB ECB DUB DCB
Current: Differential Code Coverage HEAD vs 15 Lines: 84.0 % 692 581 3 33 39 36 27 125 51 378 45 161 3 9
Current Date: 2023-04-08 17:13:01 Functions: 95.2 % 21 20 1 7 3 10 1 7
Baseline: 15 Line coverage date bins:
Baseline Date: 2023-04-08 15:09:40 (120,180] days: 94.4 % 54 51 3 51 1
Legend: Lines: hit not hit (240..) days: 83.1 % 638 530 33 39 36 27 125 378 39 133
Function coverage date bins:
(240..) days: 71.4 % 28 20 1 7 3 10 1 6

 Age         Owner                  TLA  Line data    Source code
                                  1                 : /*-------------------------------------------------------------------------
                                  2                 :  *
                                  3                 :  * tsearchcmds.c
                                  4                 :  *
                                  5                 :  *    Routines for tsearch manipulation commands
                                  6                 :  *
                                  7                 :  * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
                                  8                 :  * Portions Copyright (c) 1994, Regents of the University of California
                                  9                 :  *
                                 10                 :  *
                                 11                 :  * IDENTIFICATION
                                 12                 :  *    src/backend/commands/tsearchcmds.c
                                 13                 :  *
                                 14                 :  *-------------------------------------------------------------------------
                                 15                 :  */
                                 16                 : #include "postgres.h"
                                 17                 : 
                                 18                 : #include <ctype.h>
                                 19                 : 
                                 20                 : #include "access/genam.h"
                                 21                 : #include "access/htup_details.h"
                                 22                 : #include "access/table.h"
                                 23                 : #include "access/xact.h"
                                 24                 : #include "catalog/catalog.h"
                                 25                 : #include "catalog/dependency.h"
                                 26                 : #include "catalog/indexing.h"
                                 27                 : #include "catalog/objectaccess.h"
                                 28                 : #include "catalog/pg_namespace.h"
                                 29                 : #include "catalog/pg_proc.h"
                                 30                 : #include "catalog/pg_ts_config.h"
                                 31                 : #include "catalog/pg_ts_config_map.h"
                                 32                 : #include "catalog/pg_ts_dict.h"
                                 33                 : #include "catalog/pg_ts_parser.h"
                                 34                 : #include "catalog/pg_ts_template.h"
                                 35                 : #include "catalog/pg_type.h"
                                 36                 : #include "commands/alter.h"
                                 37                 : #include "commands/defrem.h"
                                 38                 : #include "commands/event_trigger.h"
                                 39                 : #include "common/string.h"
                                 40                 : #include "miscadmin.h"
                                 41                 : #include "nodes/makefuncs.h"
                                 42                 : #include "parser/parse_func.h"
                                 43                 : #include "tsearch/ts_cache.h"
                                 44                 : #include "tsearch/ts_utils.h"
                                 45                 : #include "utils/builtins.h"
                                 46                 : #include "utils/fmgroids.h"
                                 47                 : #include "utils/lsyscache.h"
                                 48                 : #include "utils/rel.h"
                                 49                 : #include "utils/syscache.h"
                                 50                 : 
                                 51                 : 
                                 52                 : static void MakeConfigurationMapping(AlterTSConfigurationStmt *stmt,
                                 53                 :                                      HeapTuple tup, Relation relMap);
                                 54                 : static void DropConfigurationMapping(AlterTSConfigurationStmt *stmt,
                                 55                 :                                      HeapTuple tup, Relation relMap);
                                 56                 : static DefElem *buildDefItem(const char *name, const char *val,
                                 57                 :                              bool was_quoted);
                                 58                 : 
                                 59                 : 
                                 60                 : /* --------------------- TS Parser commands ------------------------ */
                                 61                 : 
                                 62                 : /*
                                 63                 :  * lookup a parser support function and return its OID (as a Datum)
                                 64                 :  *
                                 65                 :  * attnum is the pg_ts_parser column the function will go into
                                 66                 :  */
                                 67                 : static Datum
 5710 tgl                        68 CBC          69 : get_ts_parser_func(DefElem *defel, int attnum)
                                 69                 : {
                                 70              69 :     List       *funcName = defGetQualifiedName(defel);
                                 71                 :     Oid         typeId[3];
                                 72                 :     Oid         retTypeId;
                                 73                 :     int         nargs;
                                 74                 :     Oid         procOid;
                                 75                 : 
                                 76              69 :     retTypeId = INTERNALOID;    /* correct for most */
                                 77              69 :     typeId[0] = INTERNALOID;
                                 78              69 :     switch (attnum)
                                 79                 :     {
                                 80              17 :         case Anum_pg_ts_parser_prsstart:
                                 81              17 :             nargs = 2;
                                 82              17 :             typeId[1] = INT4OID;
                                 83              17 :             break;
                                 84              17 :         case Anum_pg_ts_parser_prstoken:
                                 85              17 :             nargs = 3;
                                 86              17 :             typeId[1] = INTERNALOID;
                                 87              17 :             typeId[2] = INTERNALOID;
                                 88              17 :             break;
                                 89              17 :         case Anum_pg_ts_parser_prsend:
                                 90              17 :             nargs = 1;
                                 91              17 :             retTypeId = VOIDOID;
                                 92              17 :             break;
                                 93               1 :         case Anum_pg_ts_parser_prsheadline:
                                 94               1 :             nargs = 3;
 5709                            95               1 :             typeId[1] = INTERNALOID;
 5710                            96               1 :             typeId[2] = TSQUERYOID;
                                 97               1 :             break;
                                 98              17 :         case Anum_pg_ts_parser_prslextype:
                                 99              17 :             nargs = 1;
                                100                 : 
                                101                 :             /*
                                102                 :              * Note: because the lextype method returns type internal, it must
                                103                 :              * have an internal-type argument for security reasons.  The
                                104                 :              * argument is not actually used, but is just passed as a zero.
                                105                 :              */
                                106              17 :             break;
 5710 tgl                       107 UBC           0 :         default:
                                108                 :             /* should not be here */
 5611                           109               0 :             elog(ERROR, "unrecognized attribute for text search parser: %d",
                                110                 :                  attnum);
                                111                 :             nargs = 0;          /* keep compiler quiet */
                                112                 :     }
                                113                 : 
 5710 tgl                       114 CBC          69 :     procOid = LookupFuncName(funcName, nargs, typeId, false);
                                115              69 :     if (get_func_rettype(procOid) != retTypeId)
 5710 tgl                       116 UBC           0 :         ereport(ERROR,
                                117                 :                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
                                118                 :                  errmsg("function %s should return type %s",
                                119                 :                         func_signature_string(funcName, nargs, NIL, typeId),
                                120                 :                         format_type_be(retTypeId))));
                                121                 : 
 5710 tgl                       122 CBC          69 :     return ObjectIdGetDatum(procOid);
                                123                 : }
                                124                 : 
                                125                 : /*
                                126                 :  * make pg_depend entries for a new pg_ts_parser entry
                                127                 :  *
                                128                 :  * Return value is the address of said new entry.
                                129                 :  */
                                130                 : static ObjectAddress
                                131              17 : makeParserDependencies(HeapTuple tuple)
                                132                 : {
                                133              17 :     Form_pg_ts_parser prs = (Form_pg_ts_parser) GETSTRUCT(tuple);
                                134                 :     ObjectAddress myself,
                                135                 :                 referenced;
                                136                 :     ObjectAddresses *addrs;
                                137                 : 
  946 michael                   138              17 :     ObjectAddressSet(myself, TSParserRelationId, prs->oid);
                                139                 : 
                                140                 :     /* dependency on extension */
 4278 tgl                       141              17 :     recordDependencyOnCurrentExtension(&myself, false);
                                142                 : 
  946 michael                   143              17 :     addrs = new_object_addresses();
                                144                 : 
                                145                 :     /* dependency on namespace */
                                146              17 :     ObjectAddressSet(referenced, NamespaceRelationId, prs->prsnamespace);
                                147              17 :     add_exact_object_address(&referenced, addrs);
                                148                 : 
                                149                 :     /* dependencies on functions */
                                150              17 :     ObjectAddressSet(referenced, ProcedureRelationId, prs->prsstart);
                                151              17 :     add_exact_object_address(&referenced, addrs);
                                152                 : 
 5710 tgl                       153              17 :     referenced.objectId = prs->prstoken;
  946 michael                   154              17 :     add_exact_object_address(&referenced, addrs);
                                155                 : 
 5710 tgl                       156              17 :     referenced.objectId = prs->prsend;
  946 michael                   157              17 :     add_exact_object_address(&referenced, addrs);
                                158                 : 
 5710 tgl                       159              17 :     referenced.objectId = prs->prslextype;
  946 michael                   160              17 :     add_exact_object_address(&referenced, addrs);
                                161                 : 
 5710 tgl                       162              17 :     if (OidIsValid(prs->prsheadline))
                                163                 :     {
                                164               1 :         referenced.objectId = prs->prsheadline;
  946 michael                   165               1 :         add_exact_object_address(&referenced, addrs);
                                166                 :     }
                                167                 : 
                                168              17 :     record_object_address_dependencies(&myself, addrs, DEPENDENCY_NORMAL);
                                169              17 :     free_object_addresses(addrs);
                                170                 : 
 2959 alvherre                  171              17 :     return myself;
                                172                 : }
                                173                 : 
                                174                 : /*
                                175                 :  * CREATE TEXT SEARCH PARSER
                                176                 :  */
                                177                 : ObjectAddress
 5710 tgl                       178              20 : DefineTSParser(List *names, List *parameters)
                                179                 : {
                                180                 :     char       *prsname;
                                181                 :     ListCell   *pl;
                                182                 :     Relation    prsRel;
                                183                 :     HeapTuple   tup;
                                184                 :     Datum       values[Natts_pg_ts_parser];
                                185                 :     bool        nulls[Natts_pg_ts_parser];
                                186                 :     NameData    pname;
                                187                 :     Oid         prsOid;
                                188                 :     Oid         namespaceoid;
                                189                 :     ObjectAddress address;
                                190                 : 
                                191              20 :     if (!superuser())
 5710 tgl                       192 UBC           0 :         ereport(ERROR,
                                193                 :                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
                                194                 :                  errmsg("must be superuser to create text search parsers")));
                                195                 : 
 1539 andres                    196 CBC          20 :     prsRel = table_open(TSParserRelationId, RowExclusiveLock);
                                197                 : 
                                198                 :     /* Convert list of names to a name and namespace */
 5710 tgl                       199              20 :     namespaceoid = QualifiedNameGetCreationNamespace(names, &prsname);
                                200                 : 
                                201                 :     /* initialize tuple fields with name/namespace */
                                202              20 :     memset(values, 0, sizeof(values));
 5271                           203              20 :     memset(nulls, false, sizeof(nulls));
                                204                 : 
 1601 andres                    205              20 :     prsOid = GetNewOidWithIndex(prsRel, TSParserOidIndexId,
                                206                 :                                 Anum_pg_ts_parser_oid);
                                207              20 :     values[Anum_pg_ts_parser_oid - 1] = ObjectIdGetDatum(prsOid);
 5710 tgl                       208              20 :     namestrcpy(&pname, prsname);
                                209              20 :     values[Anum_pg_ts_parser_prsname - 1] = NameGetDatum(&pname);
                                210              20 :     values[Anum_pg_ts_parser_prsnamespace - 1] = ObjectIdGetDatum(namespaceoid);
                                211                 : 
                                212                 :     /*
                                213                 :      * loop over the definition list and extract the information we need.
                                214                 :      */
                                215              89 :     foreach(pl, parameters)
                                216                 :     {
                                217              72 :         DefElem    *defel = (DefElem *) lfirst(pl);
                                218                 : 
 1899                           219              72 :         if (strcmp(defel->defname, "start") == 0)
                                220                 :         {
 5710                           221              17 :             values[Anum_pg_ts_parser_prsstart - 1] =
                                222              17 :                 get_ts_parser_func(defel, Anum_pg_ts_parser_prsstart);
                                223                 :         }
 1899                           224              55 :         else if (strcmp(defel->defname, "gettoken") == 0)
                                225                 :         {
 5710                           226              17 :             values[Anum_pg_ts_parser_prstoken - 1] =
                                227              17 :                 get_ts_parser_func(defel, Anum_pg_ts_parser_prstoken);
                                228                 :         }
 1899                           229              38 :         else if (strcmp(defel->defname, "end") == 0)
                                230                 :         {
 5710                           231              17 :             values[Anum_pg_ts_parser_prsend - 1] =
                                232              17 :                 get_ts_parser_func(defel, Anum_pg_ts_parser_prsend);
                                233                 :         }
 1899                           234              21 :         else if (strcmp(defel->defname, "headline") == 0)
                                235                 :         {
 5710                           236               1 :             values[Anum_pg_ts_parser_prsheadline - 1] =
                                237               1 :                 get_ts_parser_func(defel, Anum_pg_ts_parser_prsheadline);
                                238                 :         }
 1899                           239              20 :         else if (strcmp(defel->defname, "lextypes") == 0)
                                240                 :         {
 5710                           241              17 :             values[Anum_pg_ts_parser_prslextype - 1] =
                                242              17 :                 get_ts_parser_func(defel, Anum_pg_ts_parser_prslextype);
                                243                 :         }
                                244                 :         else
                                245               3 :             ereport(ERROR,
                                246                 :                     (errcode(ERRCODE_SYNTAX_ERROR),
                                247                 :                      errmsg("text search parser parameter \"%s\" not recognized",
                                248                 :                             defel->defname)));
                                249                 :     }
                                250                 : 
                                251                 :     /*
                                252                 :      * Validation
                                253                 :      */
                                254              17 :     if (!OidIsValid(DatumGetObjectId(values[Anum_pg_ts_parser_prsstart - 1])))
 5710 tgl                       255 UBC           0 :         ereport(ERROR,
                                256                 :                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
                                257                 :                  errmsg("text search parser start method is required")));
                                258                 : 
 5710 tgl                       259 CBC          17 :     if (!OidIsValid(DatumGetObjectId(values[Anum_pg_ts_parser_prstoken - 1])))
 5710 tgl                       260 UBC           0 :         ereport(ERROR,
                                261                 :                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
                                262                 :                  errmsg("text search parser gettoken method is required")));
                                263                 : 
 5710 tgl                       264 CBC          17 :     if (!OidIsValid(DatumGetObjectId(values[Anum_pg_ts_parser_prsend - 1])))
 5710 tgl                       265 UBC           0 :         ereport(ERROR,
                                266                 :                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
                                267                 :                  errmsg("text search parser end method is required")));
                                268                 : 
 5710 tgl                       269 CBC          17 :     if (!OidIsValid(DatumGetObjectId(values[Anum_pg_ts_parser_prslextype - 1])))
 5710 tgl                       270 UBC           0 :         ereport(ERROR,
                                271                 :                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
                                272                 :                  errmsg("text search parser lextypes method is required")));
                                273                 : 
                                274                 :     /*
                                275                 :      * Looks good, insert
                                276                 :      */
 5271 tgl                       277 CBC          17 :     tup = heap_form_tuple(prsRel->rd_att, values, nulls);
                                278                 : 
 1601 andres                    279              17 :     CatalogTupleInsert(prsRel, tup);
                                280                 : 
 2959 alvherre                  281              17 :     address = makeParserDependencies(tup);
                                282                 : 
                                283                 :     /* Post creation hook for new text search parser */
 3686 rhaas                     284              17 :     InvokeObjectPostCreateHook(TSParserRelationId, prsOid, 0);
                                285                 : 
 5710 tgl                       286              17 :     heap_freetuple(tup);
                                287                 : 
 1539 andres                    288              17 :     table_close(prsRel, RowExclusiveLock);
                                289                 : 
 2959 alvherre                  290              17 :     return address;
                                291                 : }
                                292                 : 
                                293                 : /* ---------------------- TS Dictionary commands -----------------------*/
                                294                 : 
                                295                 : /*
                                296                 :  * make pg_depend entries for a new pg_ts_dict entry
                                297                 :  *
                                298                 :  * Return value is address of the new entry
                                299                 :  */
                                300                 : static ObjectAddress
 5710 tgl                       301            8545 : makeDictionaryDependencies(HeapTuple tuple)
                                302                 : {
                                303            8545 :     Form_pg_ts_dict dict = (Form_pg_ts_dict) GETSTRUCT(tuple);
                                304                 :     ObjectAddress myself,
                                305                 :                 referenced;
                                306                 :     ObjectAddresses *addrs;
                                307                 : 
  946 michael                   308            8545 :     ObjectAddressSet(myself, TSDictionaryRelationId, dict->oid);
                                309                 : 
                                310                 :     /* dependency on owner */
 5710 tgl                       311            8545 :     recordDependencyOnOwner(myself.classId, myself.objectId, dict->dictowner);
                                312                 : 
                                313                 :     /* dependency on extension */
 4278                           314            8545 :     recordDependencyOnCurrentExtension(&myself, false);
                                315                 : 
  946 michael                   316            8545 :     addrs = new_object_addresses();
                                317                 : 
                                318                 :     /* dependency on namespace */
                                319            8545 :     ObjectAddressSet(referenced, NamespaceRelationId, dict->dictnamespace);
                                320            8545 :     add_exact_object_address(&referenced, addrs);
                                321                 : 
                                322                 :     /* dependency on template */
                                323            8545 :     ObjectAddressSet(referenced, TSTemplateRelationId, dict->dicttemplate);
                                324            8545 :     add_exact_object_address(&referenced, addrs);
                                325                 : 
                                326            8545 :     record_object_address_dependencies(&myself, addrs, DEPENDENCY_NORMAL);
                                327            8545 :     free_object_addresses(addrs);
                                328                 : 
 2959 alvherre                  329            8545 :     return myself;
                                330                 : }
                                331                 : 
                                332                 : /*
                                333                 :  * verify that a template's init method accepts a proposed option list
                                334                 :  */
                                335                 : static void
 5709 tgl                       336            8577 : verify_dictoptions(Oid tmplId, List *dictoptions)
                                337                 : {
                                338                 :     HeapTuple   tup;
                                339                 :     Form_pg_ts_template tform;
                                340                 :     Oid         initmethod;
                                341                 : 
                                342                 :     /*
                                343                 :      * Suppress this test when running in a standalone backend.  This is a
                                344                 :      * hack to allow initdb to create prefab dictionaries that might not
                                345                 :      * actually be usable in template1's encoding (due to using external files
                                346                 :      * that can't be translated into template1's encoding).  We want to create
                                347                 :      * them anyway, since they might be usable later in other databases.
                                348                 :      */
                                349            8577 :     if (!IsUnderPostmaster)
                                350            8484 :         return;
                                351                 : 
 4802 rhaas                     352              93 :     tup = SearchSysCache1(TSTEMPLATEOID, ObjectIdGetDatum(tmplId));
 5709 tgl                       353              93 :     if (!HeapTupleIsValid(tup)) /* should not happen */
 5709 tgl                       354 UBC           0 :         elog(ERROR, "cache lookup failed for text search template %u",
                                355                 :              tmplId);
 5709 tgl                       356 CBC          93 :     tform = (Form_pg_ts_template) GETSTRUCT(tup);
                                357                 : 
                                358              93 :     initmethod = tform->tmplinit;
                                359                 : 
                                360              93 :     if (!OidIsValid(initmethod))
                                361                 :     {
                                362                 :         /* If there is no init method, disallow any options */
 5709 tgl                       363 UBC           0 :         if (dictoptions)
                                364               0 :             ereport(ERROR,
                                365                 :                     (errcode(ERRCODE_SYNTAX_ERROR),
                                366                 :                      errmsg("text search template \"%s\" does not accept options",
                                367                 :                             NameStr(tform->tmplname))));
                                368                 :     }
                                369                 :     else
                                370                 :     {
                                371                 :         /*
                                372                 :          * Copy the options just in case init method thinks it can scribble on
                                373                 :          * them ...
                                374                 :          */
 5709 tgl                       375 CBC          93 :         dictoptions = copyObject(dictoptions);
                                376                 : 
                                377                 :         /*
                                378                 :          * Call the init method and see if it complains.  We don't worry about
                                379                 :          * it leaking memory, since our command will soon be over anyway.
                                380                 :          */
                                381              93 :         (void) OidFunctionCall1(initmethod, PointerGetDatum(dictoptions));
                                382                 :     }
                                383                 : 
                                384              77 :     ReleaseSysCache(tup);
                                385                 : }
                                386                 : 
                                387                 : /*
                                388                 :  * CREATE TEXT SEARCH DICTIONARY
                                389                 :  */
                                390                 : ObjectAddress
 5710                           391            8557 : DefineTSDictionary(List *names, List *parameters)
                                392                 : {
                                393                 :     ListCell   *pl;
                                394                 :     Relation    dictRel;
                                395                 :     HeapTuple   tup;
                                396                 :     Datum       values[Natts_pg_ts_dict];
                                397                 :     bool        nulls[Natts_pg_ts_dict];
                                398                 :     NameData    dname;
 5709                           399            8557 :     Oid         templId = InvalidOid;
                                400            8557 :     List       *dictoptions = NIL;
                                401                 :     Oid         dictOid;
                                402                 :     Oid         namespaceoid;
                                403                 :     AclResult   aclresult;
                                404                 :     char       *dictname;
                                405                 :     ObjectAddress address;
                                406                 : 
                                407                 :     /* Convert list of names to a name and namespace */
 5710                           408            8557 :     namespaceoid = QualifiedNameGetCreationNamespace(names, &dictname);
                                409                 : 
                                410                 :     /* Check we have creation rights in target namespace */
  147 peter                     411 GNC        8557 :     aclresult = object_aclcheck(NamespaceRelationId, namespaceoid, GetUserId(), ACL_CREATE);
 5710 tgl                       412 CBC        8557 :     if (aclresult != ACLCHECK_OK)
 1954 peter_e                   413 UBC           0 :         aclcheck_error(aclresult, OBJECT_SCHEMA,
 5710 tgl                       414               0 :                        get_namespace_name(namespaceoid));
                                415                 : 
                                416                 :     /*
                                417                 :      * loop over the definition list and extract the information we need.
                                418                 :      */
 5710 tgl                       419 CBC       30243 :     foreach(pl, parameters)
                                420                 :     {
                                421           21686 :         DefElem    *defel = (DefElem *) lfirst(pl);
                                422                 : 
 1899                           423           21686 :         if (strcmp(defel->defname, "template") == 0)
                                424                 :         {
 4630 rhaas                     425            8557 :             templId = get_ts_template_oid(defGetQualifiedName(defel), false);
                                426                 :         }
                                427                 :         else
                                428                 :         {
                                429                 :             /* Assume it's an option for the dictionary itself */
 5709 tgl                       430           13129 :             dictoptions = lappend(dictoptions, defel);
                                431                 :         }
                                432                 :     }
                                433                 : 
                                434                 :     /*
                                435                 :      * Validation
                                436                 :      */
                                437            8557 :     if (!OidIsValid(templId))
 5710 tgl                       438 UBC           0 :         ereport(ERROR,
                                439                 :                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
                                440                 :                  errmsg("text search template is required")));
                                441                 : 
 5709 tgl                       442 CBC        8557 :     verify_dictoptions(templId, dictoptions);
                                443                 : 
                                444                 : 
 1539 andres                    445            8545 :     dictRel = table_open(TSDictionaryRelationId, RowExclusiveLock);
                                446                 : 
                                447                 :     /*
                                448                 :      * Looks good, insert
                                449                 :      */
 5709 tgl                       450            8545 :     memset(values, 0, sizeof(values));
 5271                           451            8545 :     memset(nulls, false, sizeof(nulls));
                                452                 : 
 1601 andres                    453            8545 :     dictOid = GetNewOidWithIndex(dictRel, TSDictionaryOidIndexId,
                                454                 :                                  Anum_pg_ts_dict_oid);
                                455            8545 :     values[Anum_pg_ts_dict_oid - 1] = ObjectIdGetDatum(dictOid);
 5709 tgl                       456            8545 :     namestrcpy(&dname, dictname);
                                457            8545 :     values[Anum_pg_ts_dict_dictname - 1] = NameGetDatum(&dname);
                                458            8545 :     values[Anum_pg_ts_dict_dictnamespace - 1] = ObjectIdGetDatum(namespaceoid);
                                459            8545 :     values[Anum_pg_ts_dict_dictowner - 1] = ObjectIdGetDatum(GetUserId());
                                460            8545 :     values[Anum_pg_ts_dict_dicttemplate - 1] = ObjectIdGetDatum(templId);
                                461            8545 :     if (dictoptions)
                                462            8524 :         values[Anum_pg_ts_dict_dictinitoption - 1] =
                                463            8524 :             PointerGetDatum(serialize_deflist(dictoptions));
                                464                 :     else
 5271                           465              21 :         nulls[Anum_pg_ts_dict_dictinitoption - 1] = true;
                                466                 : 
                                467            8545 :     tup = heap_form_tuple(dictRel->rd_att, values, nulls);
                                468                 : 
 1601 andres                    469            8545 :     CatalogTupleInsert(dictRel, tup);
                                470                 : 
 2959 alvherre                  471            8545 :     address = makeDictionaryDependencies(tup);
                                472                 : 
                                473                 :     /* Post creation hook for new text search dictionary */
 3686 rhaas                     474            8545 :     InvokeObjectPostCreateHook(TSDictionaryRelationId, dictOid, 0);
                                475                 : 
 5710 tgl                       476            8545 :     heap_freetuple(tup);
                                477                 : 
 1539 andres                    478            8545 :     table_close(dictRel, RowExclusiveLock);
                                479                 : 
 2959 alvherre                  480            8545 :     return address;
                                481                 : }
                                482                 : 
                                483                 : /*
                                484                 :  * ALTER TEXT SEARCH DICTIONARY
                                485                 :  */
                                486                 : ObjectAddress
 5624 bruce                     487              20 : AlterTSDictionary(AlterTSDictionaryStmt *stmt)
                                488                 : {
                                489                 :     HeapTuple   tup,
                                490                 :                 newtup;
                                491                 :     Relation    rel;
                                492                 :     Oid         dictId;
                                493                 :     ListCell   *pl;
                                494                 :     List       *dictoptions;
                                495                 :     Datum       opt;
                                496                 :     bool        isnull;
                                497                 :     Datum       repl_val[Natts_pg_ts_dict];
                                498                 :     bool        repl_null[Natts_pg_ts_dict];
                                499                 :     bool        repl_repl[Natts_pg_ts_dict];
                                500                 :     ObjectAddress address;
                                501                 : 
 4630 rhaas                     502              20 :     dictId = get_ts_dict_oid(stmt->dictname, false);
                                503                 : 
 1539 andres                    504              20 :     rel = table_open(TSDictionaryRelationId, RowExclusiveLock);
                                505                 : 
 4802 rhaas                     506              20 :     tup = SearchSysCache1(TSDICTOID, ObjectIdGetDatum(dictId));
                                507                 : 
 5710 tgl                       508              20 :     if (!HeapTupleIsValid(tup))
 5710 tgl                       509 UBC           0 :         elog(ERROR, "cache lookup failed for text search dictionary %u",
                                510                 :              dictId);
                                511                 : 
                                512                 :     /* must be owner */
  147 peter                     513 GNC          20 :     if (!object_ownercheck(TSDictionaryRelationId, dictId, GetUserId()))
 1954 peter_e                   514 UBC           0 :         aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_TSDICTIONARY,
 5710 tgl                       515               0 :                        NameListToString(stmt->dictname));
                                516                 : 
                                517                 :     /* deserialize the existing set of options */
 5709 tgl                       518 CBC          20 :     opt = SysCacheGetAttr(TSDICTOID, tup,
                                519                 :                           Anum_pg_ts_dict_dictinitoption,
                                520                 :                           &isnull);
                                521              20 :     if (isnull)
                                522               3 :         dictoptions = NIL;
                                523                 :     else
                                524              17 :         dictoptions = deserialize_deflist(opt);
                                525                 : 
                                526                 :     /*
                                527                 :      * Modify the options list as per specified changes
                                528                 :      */
 5710                           529              68 :     foreach(pl, stmt->options)
                                530                 :     {
                                531              48 :         DefElem    *defel = (DefElem *) lfirst(pl);
                                532                 :         ListCell   *cell;
                                533                 : 
                                534                 :         /*
                                535                 :          * Remove any matches ...
                                536                 :          */
 1364                           537             226 :         foreach(cell, dictoptions)
                                538                 :         {
 5709                           539             178 :             DefElem    *oldel = (DefElem *) lfirst(cell);
                                540                 : 
 1899                           541             178 :             if (strcmp(oldel->defname, defel->defname) == 0)
 1364                           542              36 :                 dictoptions = foreach_delete_current(dictoptions, cell);
                                543                 :         }
                                544                 : 
                                545                 :         /*
                                546                 :          * and add new value if it's got one
                                547                 :          */
 5709                           548              48 :         if (defel->arg)
                                549              48 :             dictoptions = lappend(dictoptions, defel);
                                550                 :     }
                                551                 : 
                                552                 :     /*
                                553                 :      * Validate
                                554                 :      */
                                555              20 :     verify_dictoptions(((Form_pg_ts_dict) GETSTRUCT(tup))->dicttemplate,
                                556                 :                        dictoptions);
                                557                 : 
                                558                 :     /*
                                559                 :      * Looks good, update
                                560                 :      */
                                561              16 :     memset(repl_val, 0, sizeof(repl_val));
 5271                           562              16 :     memset(repl_null, false, sizeof(repl_null));
                                563              16 :     memset(repl_repl, false, sizeof(repl_repl));
                                564                 : 
 5709                           565              16 :     if (dictoptions)
                                566              16 :         repl_val[Anum_pg_ts_dict_dictinitoption - 1] =
                                567              16 :             PointerGetDatum(serialize_deflist(dictoptions));
                                568                 :     else
 5271 tgl                       569 UBC           0 :         repl_null[Anum_pg_ts_dict_dictinitoption - 1] = true;
 5271 tgl                       570 CBC          16 :     repl_repl[Anum_pg_ts_dict_dictinitoption - 1] = true;
                                571                 : 
                                572              16 :     newtup = heap_modify_tuple(tup, RelationGetDescr(rel),
                                573                 :                                repl_val, repl_null, repl_repl);
                                574                 : 
 2259 alvherre                  575              16 :     CatalogTupleUpdate(rel, &newtup->t_self, newtup);
                                576                 : 
 3675 rhaas                     577              16 :     InvokeObjectPostAlterHook(TSDictionaryRelationId, dictId, 0);
                                578                 : 
 2959 alvherre                  579              16 :     ObjectAddressSet(address, TSDictionaryRelationId, dictId);
                                580                 : 
                                581                 :     /*
                                582                 :      * NOTE: because we only support altering the options, not the template,
                                583                 :      * there is no need to update dependencies.  This might have to change if
                                584                 :      * the options ever reference inside-the-database objects.
                                585                 :      */
                                586                 : 
 5710 tgl                       587              16 :     heap_freetuple(newtup);
                                588              16 :     ReleaseSysCache(tup);
                                589                 : 
 1539 andres                    590              16 :     table_close(rel, RowExclusiveLock);
                                591                 : 
 2959 alvherre                  592              16 :     return address;
                                593                 : }
                                594                 : 
                                595                 : /* ---------------------- TS Template commands -----------------------*/
                                596                 : 
                                597                 : /*
                                598                 :  * lookup a template support function and return its OID (as a Datum)
                                599                 :  *
                                600                 :  * attnum is the pg_ts_template column the function will go into
                                601                 :  */
                                602                 : static Datum
 5710 tgl                       603             631 : get_ts_template_func(DefElem *defel, int attnum)
                                604                 : {
                                605             631 :     List       *funcName = defGetQualifiedName(defel);
                                606                 :     Oid         typeId[4];
                                607                 :     Oid         retTypeId;
                                608                 :     int         nargs;
                                609                 :     Oid         procOid;
                                610                 : 
                                611             631 :     retTypeId = INTERNALOID;
                                612             631 :     typeId[0] = INTERNALOID;
                                613             631 :     typeId[1] = INTERNALOID;
                                614             631 :     typeId[2] = INTERNALOID;
                                615             631 :     typeId[3] = INTERNALOID;
                                616             631 :     switch (attnum)
                                617                 :     {
                                618             309 :         case Anum_pg_ts_template_tmplinit:
                                619             309 :             nargs = 1;
                                620             309 :             break;
                                621             322 :         case Anum_pg_ts_template_tmpllexize:
                                622             322 :             nargs = 4;
                                623             322 :             break;
 5710 tgl                       624 UBC           0 :         default:
                                625                 :             /* should not be here */
 5611                           626               0 :             elog(ERROR, "unrecognized attribute for text search template: %d",
                                627                 :                  attnum);
                                628                 :             nargs = 0;          /* keep compiler quiet */
                                629                 :     }
                                630                 : 
 5710 tgl                       631 CBC         631 :     procOid = LookupFuncName(funcName, nargs, typeId, false);
                                632             631 :     if (get_func_rettype(procOid) != retTypeId)
 5710 tgl                       633 UBC           0 :         ereport(ERROR,
                                634                 :                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
                                635                 :                  errmsg("function %s should return type %s",
                                636                 :                         func_signature_string(funcName, nargs, NIL, typeId),
                                637                 :                         format_type_be(retTypeId))));
                                638                 : 
 5710 tgl                       639 CBC         631 :     return ObjectIdGetDatum(procOid);
                                640                 : }
                                641                 : 
                                642                 : /*
                                643                 :  * make pg_depend entries for a new pg_ts_template entry
                                644                 :  */
                                645                 : static ObjectAddress
                                646             322 : makeTSTemplateDependencies(HeapTuple tuple)
                                647                 : {
                                648             322 :     Form_pg_ts_template tmpl = (Form_pg_ts_template) GETSTRUCT(tuple);
                                649                 :     ObjectAddress myself,
                                650                 :                 referenced;
                                651                 :     ObjectAddresses *addrs;
                                652                 : 
  946 michael                   653             322 :     ObjectAddressSet(myself, TSTemplateRelationId, tmpl->oid);
                                654                 : 
                                655                 :     /* dependency on extension */
 4278 tgl                       656             322 :     recordDependencyOnCurrentExtension(&myself, false);
                                657                 : 
  946 michael                   658             322 :     addrs = new_object_addresses();
                                659                 : 
                                660                 :     /* dependency on namespace */
                                661             322 :     ObjectAddressSet(referenced, NamespaceRelationId, tmpl->tmplnamespace);
                                662             322 :     add_exact_object_address(&referenced, addrs);
                                663                 : 
                                664                 :     /* dependencies on functions */
                                665             322 :     ObjectAddressSet(referenced, ProcedureRelationId, tmpl->tmpllexize);
                                666             322 :     add_exact_object_address(&referenced, addrs);
                                667                 : 
 5710 tgl                       668             322 :     if (OidIsValid(tmpl->tmplinit))
                                669                 :     {
                                670             309 :         referenced.objectId = tmpl->tmplinit;
  946 michael                   671             309 :         add_exact_object_address(&referenced, addrs);
                                672                 :     }
                                673                 : 
                                674             322 :     record_object_address_dependencies(&myself, addrs, DEPENDENCY_NORMAL);
                                675             322 :     free_object_addresses(addrs);
                                676                 : 
 2959 alvherre                  677             322 :     return myself;
                                678                 : }
                                679                 : 
                                680                 : /*
                                681                 :  * CREATE TEXT SEARCH TEMPLATE
                                682                 :  */
                                683                 : ObjectAddress
 5710 tgl                       684             325 : DefineTSTemplate(List *names, List *parameters)
                                685                 : {
                                686                 :     ListCell   *pl;
                                687                 :     Relation    tmplRel;
                                688                 :     HeapTuple   tup;
                                689                 :     Datum       values[Natts_pg_ts_template];
                                690                 :     bool        nulls[Natts_pg_ts_template];
                                691                 :     NameData    dname;
                                692                 :     int         i;
                                693                 :     Oid         tmplOid;
                                694                 :     Oid         namespaceoid;
                                695                 :     char       *tmplname;
                                696                 :     ObjectAddress address;
                                697                 : 
                                698             325 :     if (!superuser())
 5710 tgl                       699 UBC           0 :         ereport(ERROR,
                                700                 :                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
                                701                 :                  errmsg("must be superuser to create text search templates")));
                                702                 : 
                                703                 :     /* Convert list of names to a name and namespace */
 5710 tgl                       704 CBC         325 :     namespaceoid = QualifiedNameGetCreationNamespace(names, &tmplname);
                                705                 : 
 1539 andres                    706             325 :     tmplRel = table_open(TSTemplateRelationId, RowExclusiveLock);
                                707                 : 
 5710 tgl                       708            1950 :     for (i = 0; i < Natts_pg_ts_template; i++)
                                709                 :     {
 5271                           710            1625 :         nulls[i] = false;
 5710                           711            1625 :         values[i] = ObjectIdGetDatum(InvalidOid);
                                712                 :     }
                                713                 : 
 1601 andres                    714             325 :     tmplOid = GetNewOidWithIndex(tmplRel, TSTemplateOidIndexId,
                                715                 :                                  Anum_pg_ts_dict_oid);
                                716             325 :     values[Anum_pg_ts_template_oid - 1] = ObjectIdGetDatum(tmplOid);
 5710 tgl                       717             325 :     namestrcpy(&dname, tmplname);
                                718             325 :     values[Anum_pg_ts_template_tmplname - 1] = NameGetDatum(&dname);
                                719             325 :     values[Anum_pg_ts_template_tmplnamespace - 1] = ObjectIdGetDatum(namespaceoid);
                                720                 : 
                                721                 :     /*
                                722                 :      * loop over the definition list and extract the information we need.
                                723                 :      */
                                724             956 :     foreach(pl, parameters)
                                725                 :     {
                                726             634 :         DefElem    *defel = (DefElem *) lfirst(pl);
                                727                 : 
 1899                           728             634 :         if (strcmp(defel->defname, "init") == 0)
                                729                 :         {
 5710                           730             309 :             values[Anum_pg_ts_template_tmplinit - 1] =
                                731             309 :                 get_ts_template_func(defel, Anum_pg_ts_template_tmplinit);
 5271                           732             309 :             nulls[Anum_pg_ts_template_tmplinit - 1] = false;
                                733                 :         }
 1899                           734             325 :         else if (strcmp(defel->defname, "lexize") == 0)
                                735                 :         {
 5710                           736             322 :             values[Anum_pg_ts_template_tmpllexize - 1] =
                                737             322 :                 get_ts_template_func(defel, Anum_pg_ts_template_tmpllexize);
 5271                           738             322 :             nulls[Anum_pg_ts_template_tmpllexize - 1] = false;
                                739                 :         }
                                740                 :         else
 5710                           741               3 :             ereport(ERROR,
                                742                 :                     (errcode(ERRCODE_SYNTAX_ERROR),
                                743                 :                      errmsg("text search template parameter \"%s\" not recognized",
                                744                 :                             defel->defname)));
                                745                 :     }
                                746                 : 
                                747                 :     /*
                                748                 :      * Validation
                                749                 :      */
                                750             322 :     if (!OidIsValid(DatumGetObjectId(values[Anum_pg_ts_template_tmpllexize - 1])))
 5710 tgl                       751 UBC           0 :         ereport(ERROR,
                                752                 :                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
                                753                 :                  errmsg("text search template lexize method is required")));
                                754                 : 
                                755                 :     /*
                                756                 :      * Looks good, insert
                                757                 :      */
 5271 tgl                       758 CBC         322 :     tup = heap_form_tuple(tmplRel->rd_att, values, nulls);
                                759                 : 
 1601 andres                    760             322 :     CatalogTupleInsert(tmplRel, tup);
                                761                 : 
 2959 alvherre                  762             322 :     address = makeTSTemplateDependencies(tup);
                                763                 : 
                                764                 :     /* Post creation hook for new text search template */
 3686 rhaas                     765             322 :     InvokeObjectPostCreateHook(TSTemplateRelationId, tmplOid, 0);
                                766                 : 
 5710 tgl                       767             322 :     heap_freetuple(tup);
                                768                 : 
 1539 andres                    769             322 :     table_close(tmplRel, RowExclusiveLock);
                                770                 : 
 2959 alvherre                  771             322 :     return address;
                                772                 : }
                                773                 : 
                                774                 : /* ---------------------- TS Configuration commands -----------------------*/
                                775                 : 
                                776                 : /*
                                777                 :  * Finds syscache tuple of configuration.
                                778                 :  * Returns NULL if no such cfg.
                                779                 :  */
                                780                 : static HeapTuple
 5710 tgl                       781           25548 : GetTSConfigTuple(List *names)
                                782                 : {
                                783                 :     HeapTuple   tup;
                                784                 :     Oid         cfgId;
                                785                 : 
 4630 rhaas                     786           25548 :     cfgId = get_ts_config_oid(names, true);
 5710 tgl                       787           25548 :     if (!OidIsValid(cfgId))
 5710 tgl                       788 UBC           0 :         return NULL;
                                789                 : 
 4802 rhaas                     790 CBC       25548 :     tup = SearchSysCache1(TSCONFIGOID, ObjectIdGetDatum(cfgId));
                                791                 : 
 5710 tgl                       792           25548 :     if (!HeapTupleIsValid(tup)) /* should not happen */
 5710 tgl                       793 UBC           0 :         elog(ERROR, "cache lookup failed for text search configuration %u",
                                794                 :              cfgId);
                                795                 : 
 5710 tgl                       796 CBC       25548 :     return tup;
                                797                 : }
                                798                 : 
                                799                 : /*
                                800                 :  * make pg_depend entries for a new or updated pg_ts_config entry
                                801                 :  *
                                802                 :  * Pass opened pg_ts_config_map relation if there might be any config map
                                803                 :  * entries for the config.
                                804                 :  */
                                805                 : static ObjectAddress
                                806           34073 : makeConfigurationDependencies(HeapTuple tuple, bool removeOld,
                                807                 :                               Relation mapRel)
                                808                 : {
                                809           34073 :     Form_pg_ts_config cfg = (Form_pg_ts_config) GETSTRUCT(tuple);
                                810                 :     ObjectAddresses *addrs;
                                811                 :     ObjectAddress myself,
                                812                 :                 referenced;
                                813                 : 
                                814           34073 :     myself.classId = TSConfigRelationId;
 1601 andres                    815           34073 :     myself.objectId = cfg->oid;
 5710 tgl                       816           34073 :     myself.objectSubId = 0;
                                817                 : 
                                818                 :     /* for ALTER case, first flush old dependencies, except extension deps */
                                819           34073 :     if (removeOld)
                                820                 :     {
 4443                           821           25548 :         deleteDependencyRecordsFor(myself.classId, myself.objectId, true);
 5190                           822           25548 :         deleteSharedDependencyRecordsFor(myself.classId, myself.objectId, 0);
                                823                 :     }
                                824                 : 
                                825                 :     /*
                                826                 :      * We use an ObjectAddresses list to remove possible duplicate
                                827                 :      * dependencies from the config map info.  The pg_ts_config items
                                828                 :      * shouldn't be duplicates, but might as well fold them all into one call.
                                829                 :      */
 5710                           830           34073 :     addrs = new_object_addresses();
                                831                 : 
                                832                 :     /* dependency on namespace */
                                833           34073 :     referenced.classId = NamespaceRelationId;
                                834           34073 :     referenced.objectId = cfg->cfgnamespace;
                                835           34073 :     referenced.objectSubId = 0;
                                836           34073 :     add_exact_object_address(&referenced, addrs);
                                837                 : 
                                838                 :     /* dependency on owner */
                                839           34073 :     recordDependencyOnOwner(myself.classId, myself.objectId, cfg->cfgowner);
                                840                 : 
                                841                 :     /* dependency on extension */
 4278                           842           34073 :     recordDependencyOnCurrentExtension(&myself, removeOld);
                                843                 : 
                                844                 :     /* dependency on parser */
 5710                           845           34073 :     referenced.classId = TSParserRelationId;
                                846           34073 :     referenced.objectId = cfg->cfgparser;
                                847           34073 :     referenced.objectSubId = 0;
                                848           34073 :     add_exact_object_address(&referenced, addrs);
                                849                 : 
                                850                 :     /* dependencies on dictionaries listed in config map */
                                851           34073 :     if (mapRel)
                                852                 :     {
                                853                 :         ScanKeyData skey;
                                854                 :         SysScanDesc scan;
                                855                 :         HeapTuple   maptup;
                                856                 : 
                                857                 :         /* CCI to ensure we can see effects of caller's changes */
                                858           25581 :         CommandCounterIncrement();
                                859                 : 
                                860           25581 :         ScanKeyInit(&skey,
                                861                 :                     Anum_pg_ts_config_map_mapcfg,
                                862                 :                     BTEqualStrategyNumber, F_OIDEQ,
                                863                 :                     ObjectIdGetDatum(myself.objectId));
                                864                 : 
                                865           25581 :         scan = systable_beginscan(mapRel, TSConfigMapIndexId, true,
                                866                 :                                   NULL, 1, &skey);
                                867                 : 
                                868          435048 :         while (HeapTupleIsValid((maptup = systable_getnext(scan))))
                                869                 :         {
                                870          409467 :             Form_pg_ts_config_map cfgmap = (Form_pg_ts_config_map) GETSTRUCT(maptup);
                                871                 : 
                                872          409467 :             referenced.classId = TSDictionaryRelationId;
                                873          409467 :             referenced.objectId = cfgmap->mapdict;
                                874          409467 :             referenced.objectSubId = 0;
                                875          409467 :             add_exact_object_address(&referenced, addrs);
                                876                 :         }
                                877                 : 
                                878           25581 :         systable_endscan(scan);
                                879                 :     }
                                880                 : 
                                881                 :     /* Record 'em (this includes duplicate elimination) */
                                882           34073 :     record_object_address_dependencies(&myself, addrs, DEPENDENCY_NORMAL);
                                883                 : 
                                884           34073 :     free_object_addresses(addrs);
                                885                 : 
 2959 alvherre                  886           34073 :     return myself;
                                887                 : }
                                888                 : 
                                889                 : /*
                                890                 :  * CREATE TEXT SEARCH CONFIGURATION
                                891                 :  */
                                892                 : ObjectAddress
 2937                           893            8525 : DefineTSConfiguration(List *names, List *parameters, ObjectAddress *copied)
                                894                 : {
                                895                 :     Relation    cfgRel;
 5710 tgl                       896            8525 :     Relation    mapRel = NULL;
                                897                 :     HeapTuple   tup;
                                898                 :     Datum       values[Natts_pg_ts_config];
                                899                 :     bool        nulls[Natts_pg_ts_config];
                                900                 :     AclResult   aclresult;
                                901                 :     Oid         namespaceoid;
                                902                 :     char       *cfgname;
                                903                 :     NameData    cname;
                                904            8525 :     Oid         sourceOid = InvalidOid;
                                905            8525 :     Oid         prsOid = InvalidOid;
                                906                 :     Oid         cfgOid;
                                907                 :     ListCell   *pl;
                                908                 :     ObjectAddress address;
                                909                 : 
                                910                 :     /* Convert list of names to a name and namespace */
                                911            8525 :     namespaceoid = QualifiedNameGetCreationNamespace(names, &cfgname);
                                912                 : 
                                913                 :     /* Check we have creation rights in target namespace */
  147 peter                     914 GNC        8525 :     aclresult = object_aclcheck(NamespaceRelationId, namespaceoid, GetUserId(), ACL_CREATE);
 5710 tgl                       915 CBC        8525 :     if (aclresult != ACLCHECK_OK)
 1954 peter_e                   916 UBC           0 :         aclcheck_error(aclresult, OBJECT_SCHEMA,
 5710 tgl                       917               0 :                        get_namespace_name(namespaceoid));
                                918                 : 
                                919                 :     /*
                                920                 :      * loop over the definition list and extract the information we need.
                                921                 :      */
 5710 tgl                       922 CBC       17050 :     foreach(pl, parameters)
                                923                 :     {
                                924            8525 :         DefElem    *defel = (DefElem *) lfirst(pl);
                                925                 : 
 1899                           926            8525 :         if (strcmp(defel->defname, "parser") == 0)
 4630 rhaas                     927            8492 :             prsOid = get_ts_parser_oid(defGetQualifiedName(defel), false);
 1899 tgl                       928              33 :         else if (strcmp(defel->defname, "copy") == 0)
 4630 rhaas                     929              33 :             sourceOid = get_ts_config_oid(defGetQualifiedName(defel), false);
                                930                 :         else
 5710 tgl                       931 UBC           0 :             ereport(ERROR,
                                932                 :                     (errcode(ERRCODE_SYNTAX_ERROR),
                                933                 :                      errmsg("text search configuration parameter \"%s\" not recognized",
                                934                 :                             defel->defname)));
                                935                 :     }
                                936                 : 
 5709 tgl                       937 CBC        8525 :     if (OidIsValid(sourceOid) && OidIsValid(prsOid))
 5709 tgl                       938 UBC           0 :         ereport(ERROR,
                                939                 :                 (errcode(ERRCODE_SYNTAX_ERROR),
                                940                 :                  errmsg("cannot specify both PARSER and COPY options")));
                                941                 : 
                                942                 :     /* make copied tsconfig available to callers */
 2937 alvherre                  943 CBC        8525 :     if (copied && OidIsValid(sourceOid))
                                944                 :     {
                                945              33 :         ObjectAddressSet(*copied,
                                946                 :                          TSConfigRelationId,
                                947                 :                          sourceOid);
                                948                 :     }
                                949                 : 
                                950                 :     /*
                                951                 :      * Look up source config if given.
                                952                 :      */
 5709 tgl                       953            8525 :     if (OidIsValid(sourceOid))
                                954                 :     {
                                955                 :         Form_pg_ts_config cfg;
                                956                 : 
 4802 rhaas                     957              33 :         tup = SearchSysCache1(TSCONFIGOID, ObjectIdGetDatum(sourceOid));
 5710 tgl                       958              33 :         if (!HeapTupleIsValid(tup))
 5710 tgl                       959 UBC           0 :             elog(ERROR, "cache lookup failed for text search configuration %u",
                                960                 :                  sourceOid);
                                961                 : 
 5710 tgl                       962 CBC          33 :         cfg = (Form_pg_ts_config) GETSTRUCT(tup);
                                963                 : 
                                964                 :         /* use source's parser */
 5709                           965              33 :         prsOid = cfg->cfgparser;
                                966                 : 
 5710                           967              33 :         ReleaseSysCache(tup);
                                968                 :     }
                                969                 : 
                                970                 :     /*
                                971                 :      * Validation
                                972                 :      */
                                973            8525 :     if (!OidIsValid(prsOid))
 5710 tgl                       974 UBC           0 :         ereport(ERROR,
                                975                 :                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
                                976                 :                  errmsg("text search parser is required")));
                                977                 : 
 1539 andres                    978 CBC        8525 :     cfgRel = table_open(TSConfigRelationId, RowExclusiveLock);
                                979                 : 
                                980                 :     /*
                                981                 :      * Looks good, build tuple and insert
                                982                 :      */
 5710 tgl                       983            8525 :     memset(values, 0, sizeof(values));
 5271                           984            8525 :     memset(nulls, false, sizeof(nulls));
                                985                 : 
 1601 andres                    986            8525 :     cfgOid = GetNewOidWithIndex(cfgRel, TSConfigOidIndexId,
                                987                 :                                 Anum_pg_ts_config_oid);
                                988            8525 :     values[Anum_pg_ts_config_oid - 1] = ObjectIdGetDatum(cfgOid);
 5710 tgl                       989            8525 :     namestrcpy(&cname, cfgname);
                                990            8525 :     values[Anum_pg_ts_config_cfgname - 1] = NameGetDatum(&cname);
                                991            8525 :     values[Anum_pg_ts_config_cfgnamespace - 1] = ObjectIdGetDatum(namespaceoid);
                                992            8525 :     values[Anum_pg_ts_config_cfgowner - 1] = ObjectIdGetDatum(GetUserId());
                                993            8525 :     values[Anum_pg_ts_config_cfgparser - 1] = ObjectIdGetDatum(prsOid);
                                994                 : 
 5271                           995            8525 :     tup = heap_form_tuple(cfgRel->rd_att, values, nulls);
                                996                 : 
 1601 andres                    997            8525 :     CatalogTupleInsert(cfgRel, tup);
                                998                 : 
 5710 tgl                       999            8525 :     if (OidIsValid(sourceOid))
                               1000                 :     {
                               1001                 :         /*
                               1002                 :          * Copy token-dicts map from source config
                               1003                 :          */
                               1004                 :         ScanKeyData skey;
                               1005                 :         SysScanDesc scan;
                               1006                 :         HeapTuple   maptup;
                               1007                 :         TupleDesc   mapDesc;
                               1008                 :         TupleTableSlot **slot;
                               1009                 :         CatalogIndexState indstate;
                               1010                 :         int         max_slots,
                               1011                 :                     slot_init_count,
                               1012                 :                     slot_stored_count;
                               1013                 : 
 1539 andres                   1014 GIC          33 :         mapRel = table_open(TSConfigMapRelationId, RowExclusiveLock);
  144 michael                  1015 GNC          33 :         mapDesc = RelationGetDescr(mapRel);
                               1016                 : 
                               1017              33 :         indstate = CatalogOpenIndexes(mapRel);
                               1018                 : 
                               1019                 :         /*
                               1020                 :          * Allocate the slots to use, but delay costly initialization until we
                               1021                 :          * know that they will be used.
                               1022                 :          */
                               1023              33 :         max_slots = MAX_CATALOG_MULTI_INSERT_BYTES / sizeof(FormData_pg_ts_config_map);
                               1024              33 :         slot = palloc(sizeof(TupleTableSlot *) * max_slots);
                               1025                 : 
 5710 tgl                      1026 GIC          33 :         ScanKeyInit(&skey,
                               1027                 :                     Anum_pg_ts_config_map_mapcfg,
                               1028                 :                     BTEqualStrategyNumber, F_OIDEQ,
                               1029                 :                     ObjectIdGetDatum(sourceOid));
 5710 tgl                      1030 ECB             : 
 5710 tgl                      1031 CBC          33 :         scan = systable_beginscan(mapRel, TSConfigMapIndexId, true,
                               1032                 :                                   NULL, 1, &skey);
 5710 tgl                      1033 ECB             : 
                               1034                 :         /* number of slots currently storing tuples */
  144 michael                  1035 GNC          33 :         slot_stored_count = 0;
                               1036                 :         /* number of slots currently initialized */
                               1037              33 :         slot_init_count = 0;
                               1038                 : 
 5710 tgl                      1039 GIC         696 :         while (HeapTupleIsValid((maptup = systable_getnext(scan))))
                               1040                 :         {
                               1041             663 :             Form_pg_ts_config_map cfgmap = (Form_pg_ts_config_map) GETSTRUCT(maptup);
 5710 tgl                      1042 ECB             : 
  144 michael                  1043 GNC         663 :             if (slot_init_count < max_slots)
                               1044                 :             {
                               1045             663 :                 slot[slot_stored_count] = MakeSingleTupleTableSlot(mapDesc,
                               1046                 :                                                                    &TTSOpsHeapTuple);
                               1047             663 :                 slot_init_count++;
                               1048                 :             }
                               1049                 : 
                               1050             663 :             ExecClearTuple(slot[slot_stored_count]);
                               1051                 : 
                               1052             663 :             memset(slot[slot_stored_count]->tts_isnull, false,
                               1053             663 :                    slot[slot_stored_count]->tts_tupleDescriptor->natts * sizeof(bool));
                               1054                 : 
                               1055             663 :             slot[slot_stored_count]->tts_values[Anum_pg_ts_config_map_mapcfg - 1] = cfgOid;
                               1056             663 :             slot[slot_stored_count]->tts_values[Anum_pg_ts_config_map_maptokentype - 1] = cfgmap->maptokentype;
                               1057             663 :             slot[slot_stored_count]->tts_values[Anum_pg_ts_config_map_mapseqno - 1] = cfgmap->mapseqno;
                               1058             663 :             slot[slot_stored_count]->tts_values[Anum_pg_ts_config_map_mapdict - 1] = cfgmap->mapdict;
                               1059                 : 
                               1060             663 :             ExecStoreVirtualTuple(slot[slot_stored_count]);
                               1061             663 :             slot_stored_count++;
                               1062                 : 
                               1063                 :             /* If slots are full, insert a batch of tuples */
                               1064             663 :             if (slot_stored_count == max_slots)
                               1065                 :             {
  144 michael                  1066 UNC           0 :                 CatalogTuplesMultiInsertWithInfo(mapRel, slot, slot_stored_count,
                               1067                 :                                                  indstate);
                               1068               0 :                 slot_stored_count = 0;
                               1069                 :             }
                               1070                 :         }
 5710 tgl                      1071 ECB             : 
                               1072                 :         /* Insert any tuples left in the buffer */
  144 michael                  1073 GNC          33 :         if (slot_stored_count > 0)
                               1074              33 :             CatalogTuplesMultiInsertWithInfo(mapRel, slot, slot_stored_count,
                               1075                 :                                              indstate);
                               1076                 : 
                               1077             696 :         for (int i = 0; i < slot_init_count; i++)
                               1078             663 :             ExecDropSingleTupleTableSlot(slot[i]);
                               1079                 : 
 5710 tgl                      1080 GIC          33 :         systable_endscan(scan);
  144 michael                  1081 GNC          33 :         CatalogCloseIndexes(indstate);
 5710 tgl                      1082 ECB             :     }
                               1083                 : 
 2959 alvherre                 1084 CBC        8525 :     address = makeConfigurationDependencies(tup, false, mapRel);
                               1085                 : 
 4518 rhaas                    1086 ECB             :     /* Post creation hook for new text search configuration */
 3686 rhaas                    1087 GIC        8525 :     InvokeObjectPostCreateHook(TSConfigRelationId, cfgOid, 0);
 4518 rhaas                    1088 ECB             : 
 5710 tgl                      1089 GIC        8525 :     heap_freetuple(tup);
                               1090                 : 
 5710 tgl                      1091 CBC        8525 :     if (mapRel)
 1539 andres                   1092 GIC          33 :         table_close(mapRel, RowExclusiveLock);
 1539 andres                   1093 CBC        8525 :     table_close(cfgRel, RowExclusiveLock);
 3759 rhaas                    1094 ECB             : 
 2959 alvherre                 1095 GIC        8525 :     return address;
 5710 tgl                      1096 ECB             : }
                               1097                 : 
                               1098                 : /*
                               1099                 :  * Guts of TS configuration deletion.
                               1100                 :  */
                               1101                 : void
 5710 tgl                      1102 CBC          21 : RemoveTSConfigurationById(Oid cfgId)
                               1103                 : {
                               1104                 :     Relation    relCfg,
 5710 tgl                      1105 ECB             :                 relMap;
                               1106                 :     HeapTuple   tup;
 5710 tgl                      1107 EUB             :     ScanKeyData skey;
                               1108                 :     SysScanDesc scan;
                               1109                 : 
                               1110                 :     /* Remove the pg_ts_config entry */
 1539 andres                   1111 GIC          21 :     relCfg = table_open(TSConfigRelationId, RowExclusiveLock);
                               1112                 : 
 4802 rhaas                    1113              21 :     tup = SearchSysCache1(TSCONFIGOID, ObjectIdGetDatum(cfgId));
 5710 tgl                      1114 ECB             : 
 5710 tgl                      1115 CBC          21 :     if (!HeapTupleIsValid(tup))
 5710 tgl                      1116 UIC           0 :         elog(ERROR, "cache lookup failed for text search dictionary %u",
                               1117                 :              cfgId);
 5710 tgl                      1118 ECB             : 
 2258 tgl                      1119 CBC          21 :     CatalogTupleDelete(relCfg, &tup->t_self);
                               1120                 : 
 5710                          1121              21 :     ReleaseSysCache(tup);
 5710 tgl                      1122 ECB             : 
 1539 andres                   1123 GIC          21 :     table_close(relCfg, RowExclusiveLock);
                               1124                 : 
 5710 tgl                      1125 ECB             :     /* Remove any pg_ts_config_map entries */
 1539 andres                   1126 GIC          21 :     relMap = table_open(TSConfigMapRelationId, RowExclusiveLock);
                               1127                 : 
 5710 tgl                      1128 CBC          21 :     ScanKeyInit(&skey,
                               1129                 :                 Anum_pg_ts_config_map_mapcfg,
 5710 tgl                      1130 ECB             :                 BTEqualStrategyNumber, F_OIDEQ,
                               1131                 :                 ObjectIdGetDatum(cfgId));
                               1132                 : 
 5710 tgl                      1133 CBC          21 :     scan = systable_beginscan(relMap, TSConfigMapIndexId, true,
 3568 rhaas                    1134 ECB             :                               NULL, 1, &skey);
                               1135                 : 
 5710 tgl                      1136 CBC         363 :     while (HeapTupleIsValid((tup = systable_getnext(scan))))
                               1137                 :     {
 2258 tgl                      1138 GIC         342 :         CatalogTupleDelete(relMap, &tup->t_self);
                               1139                 :     }
                               1140                 : 
 5710                          1141              21 :     systable_endscan(scan);
                               1142                 : 
 1539 andres                   1143 CBC          21 :     table_close(relMap, RowExclusiveLock);
 5710 tgl                      1144 GIC          21 : }
                               1145                 : 
                               1146                 : /*
                               1147                 :  * ALTER TEXT SEARCH CONFIGURATION - main entry point
                               1148                 :  */
                               1149                 : ObjectAddress
 5624 bruce                    1150           25548 : AlterTSConfiguration(AlterTSConfigurationStmt *stmt)
                               1151                 : {
 5710 tgl                      1152 ECB             :     HeapTuple   tup;
                               1153                 :     Oid         cfgId;
 5709                          1154                 :     Relation    relMap;
                               1155                 :     ObjectAddress address;
 5710                          1156                 : 
 5710 tgl                      1157 EUB             :     /* Find the configuration */
 5710 tgl                      1158 GIC       25548 :     tup = GetTSConfigTuple(stmt->cfgname);
                               1159           25548 :     if (!HeapTupleIsValid(tup))
 5710 tgl                      1160 LBC           0 :         ereport(ERROR,
                               1161                 :                 (errcode(ERRCODE_UNDEFINED_OBJECT),
 5710 tgl                      1162 ECB             :                  errmsg("text search configuration \"%s\" does not exist",
                               1163                 :                         NameListToString(stmt->cfgname))));
                               1164                 : 
 1601 andres                   1165 GIC       25548 :     cfgId = ((Form_pg_ts_config) GETSTRUCT(tup))->oid;
                               1166                 : 
 5710 tgl                      1167 ECB             :     /* must be owner */
  147 peter                    1168 GNC       25548 :     if (!object_ownercheck(TSConfigRelationId, cfgId, GetUserId()))
 1954 peter_e                  1169 LBC           0 :         aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_TSCONFIGURATION,
 5710 tgl                      1170 UIC           0 :                        NameListToString(stmt->cfgname));
                               1171                 : 
 1539 andres                   1172 GIC       25548 :     relMap = table_open(TSConfigMapRelationId, RowExclusiveLock);
                               1173                 : 
 5709 tgl                      1174 ECB             :     /* Add or drop mappings */
 5710 tgl                      1175 GIC       25548 :     if (stmt->dicts)
 5709                          1176           25548 :         MakeConfigurationMapping(stmt, tup, relMap);
 5710 tgl                      1177 LBC           0 :     else if (stmt->tokentype)
 5709 tgl                      1178 UIC           0 :         DropConfigurationMapping(stmt, tup, relMap);
 5710 tgl                      1179 ECB             : 
                               1180                 :     /* Update dependencies */
 5709 tgl                      1181 GIC       25548 :     makeConfigurationDependencies(tup, true, relMap);
 5710 tgl                      1182 ECB             : 
 1601 andres                   1183 GIC       25548 :     InvokeObjectPostAlterHook(TSConfigRelationId, cfgId, 0);
 3675 rhaas                    1184 ECB             : 
 2299 sfrost                   1185 CBC       25548 :     ObjectAddressSet(address, TSConfigRelationId, cfgId);
                               1186                 : 
 1539 andres                   1187 GIC       25548 :     table_close(relMap, RowExclusiveLock);
                               1188                 : 
 5710 tgl                      1189           25548 :     ReleaseSysCache(tup);
                               1190                 : 
 2959 alvherre                 1191 CBC       25548 :     return address;
                               1192                 : }
                               1193                 : 
                               1194                 : /*
                               1195                 :  * Translate a list of token type names to an array of token type numbers
                               1196                 :  */
                               1197                 : static int *
 5710 tgl                      1198 GIC       25548 : getTokenTypes(Oid prsId, List *tokennames)
 5710 tgl                      1199 ECB             : {
 5710 tgl                      1200 CBC       25548 :     TSParserCacheEntry *prs = lookup_ts_parser_cache(prsId);
 5710 tgl                      1201 EUB             :     LexDescr   *list;
                               1202                 :     int        *res,
                               1203                 :                 i,
                               1204                 :                 ntoken;
                               1205                 :     ListCell   *tn;
 5710 tgl                      1206 ECB             : 
 5710 tgl                      1207 GIC       25548 :     ntoken = list_length(tokennames);
                               1208           25548 :     if (ntoken == 0)
 5710 tgl                      1209 CBC           9 :         return NULL;
 5710 tgl                      1210 GBC       25539 :     res = (int *) palloc(sizeof(int) * ntoken);
 5710 tgl                      1211 EUB             : 
 5710 tgl                      1212 GIC       25539 :     if (!OidIsValid(prs->lextypeOid))
 5710 tgl                      1213 LBC           0 :         elog(ERROR, "method lextype isn't defined for text search parser %u",
                               1214                 :              prsId);
                               1215                 : 
 4380 tgl                      1216 ECB             :     /* lextype takes one dummy argument */
 5710 tgl                      1217 CBC       25539 :     list = (LexDescr *) DatumGetPointer(OidFunctionCall1(prs->lextypeOid,
 5710 tgl                      1218 EUB             :                                                          (Datum) 0));
                               1219                 : 
 5710 tgl                      1220 GIC       25539 :     i = 0;
                               1221          186861 :     foreach(tn, tokennames)
 5710 tgl                      1222 ECB             :     {
  577 peter                    1223 GIC      161322 :         String     *val = lfirst_node(String, tn);
 5710 tgl                      1224 CBC      161322 :         bool        found = false;
                               1225                 :         int         j;
 5710 tgl                      1226 ECB             : 
 5710 tgl                      1227 GIC      161322 :         j = 0;
 5710 tgl                      1228 CBC     1816875 :         while (list && list[j].lexid)
                               1229                 :         {
                               1230         1816875 :             if (strcmp(strVal(val), list[j].alias) == 0)
                               1231                 :             {
                               1232          161322 :                 res[i] = list[j].lexid;
 5710 tgl                      1233 GIC      161322 :                 found = true;
                               1234          161322 :                 break;
                               1235                 :             }
                               1236         1655553 :             j++;
                               1237                 :         }
                               1238          161322 :         if (!found)
 5710 tgl                      1239 LBC           0 :             ereport(ERROR,
                               1240                 :                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
 5710 tgl                      1241 ECB             :                      errmsg("token type \"%s\" does not exist",
                               1242                 :                             strVal(val))));
 5710 tgl                      1243 GIC      161322 :         i++;
                               1244                 :     }
                               1245                 : 
                               1246           25539 :     return res;
                               1247                 : }
 5710 tgl                      1248 ECB             : 
                               1249                 : /*
                               1250                 :  * ALTER TEXT SEARCH CONFIGURATION ADD/ALTER MAPPING
                               1251                 :  */
                               1252                 : static void
 5624 bruce                    1253 CBC       25548 : MakeConfigurationMapping(AlterTSConfigurationStmt *stmt,
 5709 tgl                      1254 EUB             :                          HeapTuple tup, Relation relMap)
                               1255                 : {
                               1256                 :     Form_pg_ts_config tsform;
                               1257                 :     Oid         cfgId;
 5710 tgl                      1258 ECB             :     ScanKeyData skey[2];
                               1259                 :     SysScanDesc scan;
                               1260                 :     HeapTuple   maptup;
                               1261                 :     int         i;
                               1262                 :     int         j;
                               1263                 :     Oid         prsId;
                               1264                 :     int        *tokens,
                               1265                 :                 ntoken;
                               1266                 :     Oid        *dictIds;
                               1267                 :     int         ndict;
                               1268                 :     ListCell   *c;
                               1269                 :     CatalogIndexState indstate;
                               1270                 : 
 1601 andres                   1271 GIC       25548 :     tsform = (Form_pg_ts_config) GETSTRUCT(tup);
 1601 andres                   1272 CBC       25548 :     cfgId = tsform->oid;
 1601 andres                   1273 GIC       25548 :     prsId = tsform->cfgparser;
 5710 tgl                      1274 ECB             : 
 5710 tgl                      1275 CBC       25548 :     tokens = getTokenTypes(prsId, stmt->tokentype);
                               1276           25548 :     ntoken = list_length(stmt->tokentype);
                               1277                 : 
                               1278           25548 :     if (stmt->override)
                               1279                 :     {
 5710 tgl                      1280 ECB             :         /*
 5710 tgl                      1281 EUB             :          * delete maps for tokens if they exist and command was ALTER
                               1282                 :          */
 5710 tgl                      1283 GIC          59 :         for (i = 0; i < ntoken; i++)
                               1284                 :         {
 5710 tgl                      1285 CBC          49 :             ScanKeyInit(&skey[0],
                               1286                 :                         Anum_pg_ts_config_map_mapcfg,
                               1287                 :                         BTEqualStrategyNumber, F_OIDEQ,
 5710 tgl                      1288 ECB             :                         ObjectIdGetDatum(cfgId));
 5710 tgl                      1289 GIC          49 :             ScanKeyInit(&skey[1],
                               1290                 :                         Anum_pg_ts_config_map_maptokentype,
                               1291                 :                         BTEqualStrategyNumber, F_INT4EQ,
                               1292              49 :                         Int32GetDatum(tokens[i]));
                               1293                 : 
                               1294              49 :             scan = systable_beginscan(relMap, TSConfigMapIndexId, true,
 3568 rhaas                    1295 ECB             :                                       NULL, 2, skey);
                               1296                 : 
 5710 tgl                      1297 GIC         107 :             while (HeapTupleIsValid((maptup = systable_getnext(scan))))
                               1298                 :             {
 2258                          1299              58 :                 CatalogTupleDelete(relMap, &maptup->t_self);
                               1300                 :             }
                               1301                 : 
 5710                          1302              49 :             systable_endscan(scan);
                               1303                 :         }
                               1304                 :     }
                               1305                 : 
                               1306                 :     /*
                               1307                 :      * Convert list of dictionary names to array of dict OIDs
                               1308                 :      */
                               1309           25548 :     ndict = list_length(stmt->dicts);
                               1310           25548 :     dictIds = (Oid *) palloc(sizeof(Oid) * ndict);
                               1311           25548 :     i = 0;
                               1312           51144 :     foreach(c, stmt->dicts)
 5710 tgl                      1313 ECB             :     {
 5710 tgl                      1314 CBC       25596 :         List       *names = (List *) lfirst(c);
 5710 tgl                      1315 ECB             : 
 4630 rhaas                    1316 GIC       25596 :         dictIds[i] = get_ts_dict_oid(names, false);
 5710 tgl                      1317 CBC       25596 :         i++;
 5710 tgl                      1318 ECB             :     }
                               1319                 : 
  144 michael                  1320 GNC       25548 :     indstate = CatalogOpenIndexes(relMap);
                               1321                 : 
 5710 tgl                      1322 CBC       25548 :     if (stmt->replace)
                               1323                 :     {
                               1324                 :         /*
                               1325                 :          * Replace a specific dictionary in existing entries
                               1326                 :          */
                               1327               9 :         Oid         dictOld = dictIds[0],
 5710 tgl                      1328 GIC           9 :                     dictNew = dictIds[1];
 5710 tgl                      1329 ECB             : 
 5710 tgl                      1330 GIC           9 :         ScanKeyInit(&skey[0],
                               1331                 :                     Anum_pg_ts_config_map_mapcfg,
                               1332                 :                     BTEqualStrategyNumber, F_OIDEQ,
 5710 tgl                      1333 ECB             :                     ObjectIdGetDatum(cfgId));
                               1334                 : 
 5710 tgl                      1335 GIC           9 :         scan = systable_beginscan(relMap, TSConfigMapIndexId, true,
 3568 rhaas                    1336 ECB             :                                   NULL, 1, skey);
                               1337                 : 
 5710 tgl                      1338 CBC         261 :         while (HeapTupleIsValid((maptup = systable_getnext(scan))))
                               1339                 :         {
 5710 tgl                      1340 GIC         252 :             Form_pg_ts_config_map cfgmap = (Form_pg_ts_config_map) GETSTRUCT(maptup);
 5710 tgl                      1341 ECB             : 
                               1342                 :             /*
                               1343                 :              * check if it's one of target token types
                               1344                 :              */
 5710 tgl                      1345 GIC         252 :             if (tokens)
 5710 tgl                      1346 ECB             :             {
 5710 tgl                      1347 UIC           0 :                 bool        tokmatch = false;
                               1348                 : 
                               1349               0 :                 for (j = 0; j < ntoken; j++)
                               1350                 :                 {
                               1351               0 :                     if (cfgmap->maptokentype == tokens[j])
                               1352                 :                     {
 5710 tgl                      1353 LBC           0 :                         tokmatch = true;
                               1354               0 :                         break;
 5710 tgl                      1355 ECB             :                     }
                               1356                 :                 }
 5710 tgl                      1357 UIC           0 :                 if (!tokmatch)
 5710 tgl                      1358 LBC           0 :                     continue;
                               1359                 :             }
 5710 tgl                      1360 ECB             : 
                               1361                 :             /*
                               1362                 :              * replace dictionary if match
                               1363                 :              */
 5710 tgl                      1364 CBC         252 :             if (cfgmap->mapdict == dictOld)
                               1365                 :             {
 5710 tgl                      1366 ECB             :                 Datum       repl_val[Natts_pg_ts_config_map];
                               1367                 :                 bool        repl_null[Natts_pg_ts_config_map];
                               1368                 :                 bool        repl_repl[Natts_pg_ts_config_map];
                               1369                 :                 HeapTuple   newtup;
                               1370                 : 
 5710 tgl                      1371 CBC          81 :                 memset(repl_val, 0, sizeof(repl_val));
 5271                          1372              81 :                 memset(repl_null, false, sizeof(repl_null));
 5271 tgl                      1373 GIC          81 :                 memset(repl_repl, false, sizeof(repl_repl));
 5710 tgl                      1374 ECB             : 
 5710 tgl                      1375 GIC          81 :                 repl_val[Anum_pg_ts_config_map_mapdict - 1] = ObjectIdGetDatum(dictNew);
 5271                          1376              81 :                 repl_repl[Anum_pg_ts_config_map_mapdict - 1] = true;
                               1377                 : 
                               1378              81 :                 newtup = heap_modify_tuple(maptup,
 5050 bruce                    1379 ECB             :                                            RelationGetDescr(relMap),
                               1380                 :                                            repl_val, repl_null, repl_repl);
  144 michael                  1381 GNC          81 :                 CatalogTupleUpdateWithInfo(relMap, &newtup->t_self, newtup, indstate);
 5710 tgl                      1382 ECB             :             }
                               1383                 :         }
                               1384                 : 
 5710 tgl                      1385 GIC           9 :         systable_endscan(scan);
                               1386                 :     }
                               1387                 :     else
                               1388                 :     {
                               1389                 :         TupleTableSlot **slot;
  144 michael                  1390 GNC       25539 :         int         slotCount = 0;
                               1391                 :         int         nslots;
                               1392                 : 
                               1393                 :         /* Allocate the slots to use and initialize them */
                               1394           25539 :         nslots = Min(ntoken * ndict,
                               1395                 :                      MAX_CATALOG_MULTI_INSERT_BYTES / sizeof(FormData_pg_ts_config_map));
                               1396           25539 :         slot = palloc(sizeof(TupleTableSlot *) * nslots);
                               1397          186942 :         for (i = 0; i < nslots; i++)
                               1398          161403 :             slot[i] = MakeSingleTupleTableSlot(RelationGetDescr(relMap),
                               1399                 :                                                &TTSOpsHeapTuple);
                               1400                 : 
 5710 tgl                      1401 ECB             :         /*
                               1402                 :          * Insertion of new entries
 5710 tgl                      1403 EUB             :          */
 5710 tgl                      1404 GIC      186861 :         for (i = 0; i < ntoken; i++)
 5710 tgl                      1405 EUB             :         {
 5710 tgl                      1406 GIC      322725 :             for (j = 0; j < ndict; j++)
 5710 tgl                      1407 EUB             :             {
  144 michael                  1408 GNC      161403 :                 ExecClearTuple(slot[slotCount]);
  144 michael                  1409 EUB             : 
  144 michael                  1410 GNC      161403 :                 memset(slot[slotCount]->tts_isnull, false,
                               1411          161403 :                        slot[slotCount]->tts_tupleDescriptor->natts * sizeof(bool));
                               1412                 : 
                               1413          161403 :                 slot[slotCount]->tts_values[Anum_pg_ts_config_map_mapcfg - 1] = ObjectIdGetDatum(cfgId);
                               1414          161403 :                 slot[slotCount]->tts_values[Anum_pg_ts_config_map_maptokentype - 1] = Int32GetDatum(tokens[i]);
                               1415          161403 :                 slot[slotCount]->tts_values[Anum_pg_ts_config_map_mapseqno - 1] = Int32GetDatum(j + 1);
                               1416          161403 :                 slot[slotCount]->tts_values[Anum_pg_ts_config_map_mapdict - 1] = ObjectIdGetDatum(dictIds[j]);
                               1417                 : 
                               1418          161403 :                 ExecStoreVirtualTuple(slot[slotCount]);
                               1419          161403 :                 slotCount++;
                               1420                 : 
                               1421                 :                 /* If slots are full, insert a batch of tuples */
                               1422          161403 :                 if (slotCount == nslots)
                               1423                 :                 {
                               1424           25539 :                     CatalogTuplesMultiInsertWithInfo(relMap, slot, slotCount,
                               1425                 :                                                      indstate);
                               1426           25539 :                     slotCount = 0;
                               1427                 :                 }
                               1428                 :             }
                               1429                 :         }
                               1430                 : 
                               1431                 :         /* Insert any tuples left in the buffer */
                               1432           25539 :         if (slotCount > 0)
  144 michael                  1433 UNC           0 :             CatalogTuplesMultiInsertWithInfo(relMap, slot, slotCount,
                               1434                 :                                              indstate);
                               1435                 : 
  144 michael                  1436 GNC      186942 :         for (i = 0; i < nslots; i++)
                               1437          161403 :             ExecDropSingleTupleTableSlot(slot[i]);
                               1438                 :     }
                               1439                 : 
                               1440                 :     /* clean up */
                               1441           25548 :     CatalogCloseIndexes(indstate);
                               1442                 : 
 2890 alvherre                 1443 GIC       25548 :     EventTriggerCollectAlterTSConfig(stmt, cfgId, dictIds, ndict);
 5710 tgl                      1444           25548 : }
 5710 tgl                      1445 ECB             : 
                               1446                 : /*
                               1447                 :  * ALTER TEXT SEARCH CONFIGURATION DROP MAPPING
                               1448                 :  */
                               1449                 : static void
 5624 bruce                    1450 LBC           0 : DropConfigurationMapping(AlterTSConfigurationStmt *stmt,
                               1451                 :                          HeapTuple tup, Relation relMap)
 5710 tgl                      1452 ECB             : {
                               1453                 :     Form_pg_ts_config tsform;
                               1454                 :     Oid         cfgId;
                               1455                 :     ScanKeyData skey[2];
                               1456                 :     SysScanDesc scan;
                               1457                 :     HeapTuple   maptup;
                               1458                 :     int         i;
                               1459                 :     Oid         prsId;
                               1460                 :     int        *tokens;
                               1461                 :     ListCell   *c;
                               1462                 : 
 1601 andres                   1463 UIC           0 :     tsform = (Form_pg_ts_config) GETSTRUCT(tup);
 1601 andres                   1464 LBC           0 :     cfgId = tsform->oid;
 1601 andres                   1465 UIC           0 :     prsId = tsform->cfgparser;
                               1466                 : 
 5710 tgl                      1467               0 :     tokens = getTokenTypes(prsId, stmt->tokentype);
 5710 tgl                      1468 ECB             : 
 5710 tgl                      1469 UIC           0 :     i = 0;
 5710 tgl                      1470 LBC           0 :     foreach(c, stmt->tokentype)
 5710 tgl                      1471 ECB             :     {
  577 peter                    1472 LBC           0 :         String     *val = lfirst_node(String, c);
 5710 tgl                      1473 UIC           0 :         bool        found = false;
                               1474                 : 
                               1475               0 :         ScanKeyInit(&skey[0],
                               1476                 :                     Anum_pg_ts_config_map_mapcfg,
                               1477                 :                     BTEqualStrategyNumber, F_OIDEQ,
 5710 tgl                      1478 ECB             :                     ObjectIdGetDatum(cfgId));
 5710 tgl                      1479 UIC           0 :         ScanKeyInit(&skey[1],
 5710 tgl                      1480 ECB             :                     Anum_pg_ts_config_map_maptokentype,
                               1481                 :                     BTEqualStrategyNumber, F_INT4EQ,
 5710 tgl                      1482 LBC           0 :                     Int32GetDatum(tokens[i]));
                               1483                 : 
                               1484               0 :         scan = systable_beginscan(relMap, TSConfigMapIndexId, true,
 3568 rhaas                    1485 ECB             :                                   NULL, 2, skey);
                               1486                 : 
 5710 tgl                      1487 LBC           0 :         while (HeapTupleIsValid((maptup = systable_getnext(scan))))
 5710 tgl                      1488 ECB             :         {
 2258 tgl                      1489 LBC           0 :             CatalogTupleDelete(relMap, &maptup->t_self);
 5710                          1490               0 :             found = true;
                               1491                 :         }
 5710 tgl                      1492 ECB             : 
 5710 tgl                      1493 LBC           0 :         systable_endscan(scan);
                               1494                 : 
 5710 tgl                      1495 UIC           0 :         if (!found)
 5710 tgl                      1496 ECB             :         {
 5710 tgl                      1497 UIC           0 :             if (!stmt->missing_ok)
 5710 tgl                      1498 ECB             :             {
 5710 tgl                      1499 UIC           0 :                 ereport(ERROR,
 5710 tgl                      1500 ECB             :                         (errcode(ERRCODE_UNDEFINED_OBJECT),
                               1501                 :                          errmsg("mapping for token type \"%s\" does not exist",
                               1502                 :                                 strVal(val))));
                               1503                 :             }
                               1504                 :             else
                               1505                 :             {
 5710 tgl                      1506 LBC           0 :                 ereport(NOTICE,
 5710 tgl                      1507 EUB             :                         (errmsg("mapping for token type \"%s\" does not exist, skipping",
                               1508                 :                                 strVal(val))));
                               1509                 :             }
 5710 tgl                      1510 ECB             :         }
                               1511                 : 
 5710 tgl                      1512 UIC           0 :         i++;
                               1513                 :     }
                               1514                 : 
 2890 alvherre                 1515 LBC           0 :     EventTriggerCollectAlterTSConfig(stmt, cfgId, NULL, 0);
 5710 tgl                      1516 UIC           0 : }
 5709 tgl                      1517 ECB             : 
                               1518                 : 
                               1519                 : /*
                               1520                 :  * Serialize dictionary options, producing a TEXT datum from a List of DefElem
                               1521                 :  *
                               1522                 :  * This is used to form the value stored in pg_ts_dict.dictinitoption.
                               1523                 :  * For the convenience of pg_dump, the output is formatted exactly as it
 5709 tgl                      1524 EUB             :  * would need to appear in CREATE TEXT SEARCH DICTIONARY to reproduce the
                               1525                 :  * same options.
                               1526                 :  */
                               1527                 : text *
 5709 tgl                      1528 GIC        8540 : serialize_deflist(List *deflist)
                               1529                 : {
                               1530                 :     text       *result;
                               1531                 :     StringInfoData buf;
                               1532                 :     ListCell   *l;
                               1533                 : 
                               1534            8540 :     initStringInfo(&buf);
                               1535                 : 
                               1536           21698 :     foreach(l, deflist)
 5709 tgl                      1537 EUB             :     {
 5709 tgl                      1538 GBC       13158 :         DefElem    *defel = (DefElem *) lfirst(l);
                               1539           13158 :         char       *val = defGetString(defel);
                               1540                 : 
                               1541           13158 :         appendStringInfo(&buf, "%s = ",
 5624 bruce                    1542 GIC       13158 :                          quote_identifier(defel->defname));
 1125 tgl                      1543 EUB             : 
                               1544                 :         /*
                               1545                 :          * If the value is a T_Integer or T_Float, emit it without quotes,
                               1546                 :          * otherwise with quotes.  This is essential to allow correct
                               1547                 :          * reconstruction of the node type as well as the value.
                               1548                 :          */
 1125 tgl                      1549 GBC       13158 :         if (IsA(defel->arg, Integer) || IsA(defel->arg, Float))
 1125 tgl                      1550 GIC           7 :             appendStringInfoString(&buf, val);
                               1551                 :         else
                               1552                 :         {
 1125 tgl                      1553 EUB             :             /* If backslashes appear, force E syntax to quote them safely */
 1125 tgl                      1554 GIC       13151 :             if (strchr(val, '\\'))
 1125 tgl                      1555 UIC           0 :                 appendStringInfoChar(&buf, ESCAPE_STRING_SYNTAX);
 1125 tgl                      1556 GBC       13151 :             appendStringInfoChar(&buf, '\'');
 1125 tgl                      1557 GIC      105857 :             while (*val)
 1125 tgl                      1558 EUB             :             {
 1125 tgl                      1559 GIC       92706 :                 char        ch = *val++;
                               1560                 : 
 1125 tgl                      1561 GBC       92706 :                 if (SQL_STR_DOUBLE(ch, true))
 1125 tgl                      1562 UIC           0 :                     appendStringInfoChar(&buf, ch);
 5709 tgl                      1563 GBC       92706 :                 appendStringInfoChar(&buf, ch);
 1125 tgl                      1564 EUB             :             }
 1125 tgl                      1565 GIC       13151 :             appendStringInfoChar(&buf, '\'');
                               1566                 :         }
 1364 tgl                      1567 GBC       13158 :         if (lnext(deflist, l) != NULL)
 3447 rhaas                    1568 GIC        4618 :             appendStringInfoString(&buf, ", ");
 5709 tgl                      1569 EUB             :     }
                               1570                 : 
 5493 tgl                      1571 GBC        8540 :     result = cstring_to_text_with_len(buf.data, buf.len);
 5709 tgl                      1572 GIC        8540 :     pfree(buf.data);
 5709 tgl                      1573 GBC        8540 :     return result;
                               1574                 : }
                               1575                 : 
                               1576                 : /*
                               1577                 :  * Deserialize dictionary options, reconstructing a List of DefElem from TEXT
                               1578                 :  *
                               1579                 :  * This is also used for prsheadline options, so for backward compatibility
 5709 tgl                      1580 EUB             :  * we need to accept a few things serialize_deflist() will never emit:
                               1581                 :  * in particular, unquoted and double-quoted strings.
                               1582                 :  */
                               1583                 : List *
 5709 tgl                      1584 GIC         131 : deserialize_deflist(Datum txt)
                               1585                 : {
 2118 tgl                      1586 GBC         131 :     text       *in = DatumGetTextPP(txt);   /* in case it's toasted */
 5709 tgl                      1587 GIC         131 :     List       *result = NIL;
 2219 noah                     1588             131 :     int         len = VARSIZE_ANY_EXHDR(in);
 5709 tgl                      1589 EUB             :     char       *ptr,
                               1590                 :                *endptr,
                               1591                 :                *workspace,
 5709 tgl                      1592 GIC         131 :                *wsptr = NULL,
                               1593             131 :                *startvalue = NULL;
                               1594                 :     typedef enum
                               1595                 :     {
                               1596                 :         CS_WAITKEY,
                               1597                 :         CS_INKEY,
                               1598                 :         CS_INQKEY,
                               1599                 :         CS_WAITEQ,
                               1600                 :         CS_WAITVALUE,
                               1601                 :         CS_INSQVALUE,
 5709 tgl                      1602 ECB             :         CS_INDQVALUE,
                               1603                 :         CS_INWVALUE
                               1604                 :     } ds_state;
 5709 tgl                      1605 GIC         131 :     ds_state    state = CS_WAITKEY;
                               1606                 : 
 2118                          1607             131 :     workspace = (char *) palloc(len + 1);   /* certainly enough room */
 2219 noah                     1608 CBC         131 :     ptr = VARDATA_ANY(in);
 5709 tgl                      1609 GIC         131 :     endptr = ptr + len;
 5709 tgl                      1610 CBC        6049 :     for (; ptr < endptr; ptr++)
                               1611                 :     {
                               1612            5918 :         switch (state)
 5709 tgl                      1613 ECB             :         {
 5709 tgl                      1614 GIC         548 :             case CS_WAITKEY:
 5709 tgl                      1615 CBC         548 :                 if (isspace((unsigned char) *ptr) || *ptr == ',')
                               1616             264 :                     continue;
 5709 tgl                      1617 GIC         284 :                 if (*ptr == '"')
                               1618                 :                 {
 5709 tgl                      1619 UIC           0 :                     wsptr = workspace;
                               1620               0 :                     state = CS_INQKEY;
                               1621                 :                 }
                               1622                 :                 else
 5709 tgl                      1623 ECB             :                 {
 5709 tgl                      1624 CBC         284 :                     wsptr = workspace;
 5709 tgl                      1625 GIC         284 :                     *wsptr++ = *ptr;
                               1626             284 :                     state = CS_INKEY;
                               1627                 :                 }
 5709 tgl                      1628 CBC         284 :                 break;
 5709 tgl                      1629 GBC        2509 :             case CS_INKEY:
 5709 tgl                      1630 CBC        2509 :                 if (isspace((unsigned char) *ptr))
 5709 tgl                      1631 ECB             :                 {
 5709 tgl                      1632 GIC         227 :                     *wsptr++ = '\0';
 5709 tgl                      1633 CBC         227 :                     state = CS_WAITEQ;
                               1634                 :                 }
                               1635            2282 :                 else if (*ptr == '=')
 5709 tgl                      1636 EUB             :                 {
 5709 tgl                      1637 CBC          57 :                     *wsptr++ = '\0';
 5709 tgl                      1638 GIC          57 :                     state = CS_WAITVALUE;
 5709 tgl                      1639 ECB             :                 }
                               1640                 :                 else
                               1641                 :                 {
 5709 tgl                      1642 CBC        2225 :                     *wsptr++ = *ptr;
                               1643                 :                 }
 5709 tgl                      1644 GIC        2509 :                 break;
 5709 tgl                      1645 LBC           0 :             case CS_INQKEY:
                               1646               0 :                 if (*ptr == '"')
 5709 tgl                      1647 ECB             :                 {
 5624 bruce                    1648 UIC           0 :                     if (ptr + 1 < endptr && ptr[1] == '"')
                               1649                 :                     {
                               1650                 :                         /* copy only one of the two quotes */
 5709 tgl                      1651               0 :                         *wsptr++ = *ptr++;
                               1652                 :                     }
                               1653                 :                     else
                               1654                 :                     {
                               1655               0 :                         *wsptr++ = '\0';
                               1656               0 :                         state = CS_WAITEQ;
                               1657                 :                     }
 5709 tgl                      1658 ECB             :                 }
                               1659                 :                 else
                               1660                 :                 {
 5709 tgl                      1661 LBC           0 :                     *wsptr++ = *ptr;
 5709 tgl                      1662 ECB             :                 }
 5709 tgl                      1663 UIC           0 :                 break;
 5709 tgl                      1664 GIC         227 :             case CS_WAITEQ:
                               1665             227 :                 if (*ptr == '=')
 5709 tgl                      1666 CBC         227 :                     state = CS_WAITVALUE;
 5709 tgl                      1667 LBC           0 :                 else if (!isspace((unsigned char) *ptr))
 5709 tgl                      1668 UIC           0 :                     ereport(ERROR,
                               1669                 :                             (errcode(ERRCODE_SYNTAX_ERROR),
                               1670                 :                              errmsg("invalid parameter list format: \"%s\"",
                               1671                 :                                     text_to_cstring(in))));
 5709 tgl                      1672 GIC         227 :                 break;
                               1673             511 :             case CS_WAITVALUE:
                               1674             511 :                 if (*ptr == '\'')
                               1675                 :                 {
                               1676             188 :                     startvalue = wsptr;
                               1677             188 :                     state = CS_INSQVALUE;
                               1678                 :                 }
 5624 bruce                    1679 CBC         323 :                 else if (*ptr == 'E' && ptr + 1 < endptr && ptr[1] == '\'')
                               1680                 :                 {
 5709 tgl                      1681 LBC           0 :                     ptr++;
                               1682               0 :                     startvalue = wsptr;
                               1683               0 :                     state = CS_INSQVALUE;
 5709 tgl                      1684 ECB             :                 }
 5709 tgl                      1685 GIC         323 :                 else if (*ptr == '"')
 5709 tgl                      1686 ECB             :                 {
 5709 tgl                      1687 UIC           0 :                     startvalue = wsptr;
 5709 tgl                      1688 LBC           0 :                     state = CS_INDQVALUE;
 5709 tgl                      1689 ECB             :                 }
 5709 tgl                      1690 CBC         323 :                 else if (!isspace((unsigned char) *ptr))
 5709 tgl                      1691 ECB             :                 {
 5709 tgl                      1692 GIC          96 :                     startvalue = wsptr;
 5709 tgl                      1693 GBC          96 :                     *wsptr++ = *ptr;
                               1694              96 :                     state = CS_INWVALUE;
                               1695                 :                 }
 5709 tgl                      1696 GIC         511 :                 break;
                               1697            2035 :             case CS_INSQVALUE:
 5709 tgl                      1698 CBC        2035 :                 if (*ptr == '\'')
 5709 tgl                      1699 ECB             :                 {
 5624 bruce                    1700 CBC         188 :                     if (ptr + 1 < endptr && ptr[1] == '\'')
                               1701                 :                     {
 5709 tgl                      1702 ECB             :                         /* copy only one of the two quotes */
 5709 tgl                      1703 LBC           0 :                         *wsptr++ = *ptr++;
 5709 tgl                      1704 ECB             :                     }
                               1705                 :                     else
                               1706                 :                     {
 5709 tgl                      1707 CBC         188 :                         *wsptr++ = '\0';
 5709 tgl                      1708 GIC         188 :                         result = lappend(result,
 1125 tgl                      1709 CBC         188 :                                          buildDefItem(workspace,
                               1710                 :                                                       startvalue,
 1125 tgl                      1711 ECB             :                                                       true));
 5709 tgl                      1712 CBC         188 :                         state = CS_WAITKEY;
                               1713                 :                     }
                               1714                 :                 }
 5709 tgl                      1715 GIC        1847 :                 else if (*ptr == '\\')
 5709 tgl                      1716 ECB             :                 {
 5624 bruce                    1717 UIC           0 :                     if (ptr + 1 < endptr && ptr[1] == '\\')
 5709 tgl                      1718 ECB             :                     {
 5709 tgl                      1719 EUB             :                         /* copy only one of the two backslashes */
 5709 tgl                      1720 UBC           0 :                         *wsptr++ = *ptr++;
                               1721                 :                     }
 5709 tgl                      1722 EUB             :                     else
 5709 tgl                      1723 UIC           0 :                         *wsptr++ = *ptr;
                               1724                 :                 }
 5709 tgl                      1725 EUB             :                 else
                               1726                 :                 {
 5709 tgl                      1727 GIC        1847 :                     *wsptr++ = *ptr;
                               1728                 :                 }
 5709 tgl                      1729 GBC        2035 :                 break;
 5709 tgl                      1730 UBC           0 :             case CS_INDQVALUE:
 5709 tgl                      1731 UIC           0 :                 if (*ptr == '"')
                               1732                 :                 {
 5624 bruce                    1733               0 :                     if (ptr + 1 < endptr && ptr[1] == '"')
                               1734                 :                     {
 5709 tgl                      1735 EUB             :                         /* copy only one of the two quotes */
 5709 tgl                      1736 UIC           0 :                         *wsptr++ = *ptr++;
 5709 tgl                      1737 EUB             :                     }
 5709 tgl                      1738 ECB             :                     else
                               1739                 :                     {
 5709 tgl                      1740 LBC           0 :                         *wsptr++ = '\0';
 5709 tgl                      1741 UBC           0 :                         result = lappend(result,
 1125                          1742               0 :                                          buildDefItem(workspace,
                               1743                 :                                                       startvalue,
                               1744                 :                                                       true));
 5709 tgl                      1745 UIC           0 :                         state = CS_WAITKEY;
 5709 tgl                      1746 ECB             :                     }
                               1747                 :                 }
                               1748                 :                 else
                               1749                 :                 {
 5709 tgl                      1750 LBC           0 :                     *wsptr++ = *ptr;
 5709 tgl                      1751 ECB             :                 }
 5709 tgl                      1752 UIC           0 :                 break;
 5709 tgl                      1753 CBC          88 :             case CS_INWVALUE:
 5709 tgl                      1754 GIC          88 :                 if (*ptr == ',' || isspace((unsigned char) *ptr))
 5709 tgl                      1755 EUB             :                 {
 5709 tgl                      1756 GBC          39 :                     *wsptr++ = '\0';
                               1757              39 :                     result = lappend(result,
 1125 tgl                      1758 GIC          39 :                                      buildDefItem(workspace,
 1125 tgl                      1759 ECB             :                                                   startvalue,
                               1760                 :                                                   false));
 5709 tgl                      1761 GBC          39 :                     state = CS_WAITKEY;
 5709 tgl                      1762 EUB             :                 }
                               1763                 :                 else
 5709 tgl                      1764 ECB             :                 {
 5709 tgl                      1765 GIC          49 :                     *wsptr++ = *ptr;
 5709 tgl                      1766 ECB             :                 }
 5709 tgl                      1767 CBC          88 :                 break;
 5709 tgl                      1768 LBC           0 :             default:
 5709 tgl                      1769 UIC           0 :                 elog(ERROR, "unrecognized deserialize_deflist state: %d",
 5709 tgl                      1770 ECB             :                      state);
                               1771                 :         }
                               1772                 :     }
                               1773                 : 
 5709 tgl                      1774 CBC         131 :     if (state == CS_INWVALUE)
                               1775                 :     {
 5709 tgl                      1776 GIC          57 :         *wsptr++ = '\0';
 5709 tgl                      1777 GBC          57 :         result = lappend(result,
 1125 tgl                      1778 GIC          57 :                          buildDefItem(workspace,
                               1779                 :                                       startvalue,
                               1780                 :                                       false));
 5709 tgl                      1781 ECB             :     }
 5709 tgl                      1782 CBC          74 :     else if (state != CS_WAITKEY)
 5709 tgl                      1783 LBC           0 :         ereport(ERROR,
                               1784                 :                 (errcode(ERRCODE_SYNTAX_ERROR),
                               1785                 :                  errmsg("invalid parameter list format: \"%s\"",
 5493 tgl                      1786 ECB             :                         text_to_cstring(in))));
                               1787                 : 
 5709 tgl                      1788 GIC         131 :     pfree(workspace);
 5709 tgl                      1789 ECB             : 
 5709 tgl                      1790 GIC         131 :     return result;
 5709 tgl                      1791 EUB             : }
                               1792                 : 
                               1793                 : /*
 1125                          1794                 :  * Build one DefElem for deserialize_deflist
                               1795                 :  */
                               1796                 : static DefElem *
 1125 tgl                      1797 GBC         284 : buildDefItem(const char *name, const char *val, bool was_quoted)
                               1798                 : {
                               1799                 :     /* If input was quoted, always emit as string */
 1125 tgl                      1800 GIC         284 :     if (!was_quoted && val[0] != '\0')
 1125 tgl                      1801 ECB             :     {
                               1802                 :         int         v;
                               1803                 :         char       *endptr;
 1125 tgl                      1804 EUB             : 
                               1805                 :         /* Try to parse as an integer */
 1125 tgl                      1806 GIC          96 :         errno = 0;
 1125 tgl                      1807 GBC          96 :         v = strtoint(val, &endptr, 10);
 1125 tgl                      1808 GIC          96 :         if (errno == 0 && *endptr == '\0')
                               1809              69 :             return makeDefElem(pstrdup(name),
 1125 tgl                      1810 GBC          61 :                                (Node *) makeInteger(v),
                               1811                 :                                -1);
                               1812                 :         /* Nope, how about as a float? */
 1125 tgl                      1813 GIC          35 :         errno = 0;
 1125 tgl                      1814 GBC          35 :         (void) strtod(val, &endptr);
                               1815              35 :         if (errno == 0 && *endptr == '\0')
                               1816               5 :             return makeDefElem(pstrdup(name),
 1125 tgl                      1817 GIC           5 :                                (Node *) makeFloat(pstrdup(val)),
                               1818                 :                                -1);
  450 peter                    1819 EUB             : 
  450 peter                    1820 GIC          30 :         if (strcmp(val, "true") == 0)
                               1821               3 :             return makeDefElem(pstrdup(name),
                               1822               3 :                                (Node *) makeBoolean(true),
                               1823                 :                                -1);
  450 peter                    1824 GBC          27 :         if (strcmp(val, "false") == 0)
  450 peter                    1825 UIC           0 :             return makeDefElem(pstrdup(name),
  450 peter                    1826 UBC           0 :                                (Node *) makeBoolean(false),
  450 peter                    1827 ECB             :                                -1);
 1125 tgl                      1828                 :     }
                               1829                 :     /* Just make it a string */
 1125 tgl                      1830 CBC         215 :     return makeDefElem(pstrdup(name),
                               1831             215 :                        (Node *) makeString(pstrdup(val)),
 1125 tgl                      1832 ECB             :                        -1);
                               1833                 : }
        

Generated by: LCOV version v1.16-55-g56c0a2a