Header And Logo

PostgreSQL
| The world's most advanced open source database.

collationcmds.c

Go to the documentation of this file.
00001 /*-------------------------------------------------------------------------
00002  *
00003  * collationcmds.c
00004  *    collation-related commands support code
00005  *
00006  * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
00007  * Portions Copyright (c) 1994, Regents of the University of California
00008  *
00009  *
00010  * IDENTIFICATION
00011  *    src/backend/commands/collationcmds.c
00012  *
00013  *-------------------------------------------------------------------------
00014  */
00015 #include "postgres.h"
00016 
00017 #include "access/heapam.h"
00018 #include "access/htup_details.h"
00019 #include "access/xact.h"
00020 #include "catalog/dependency.h"
00021 #include "catalog/indexing.h"
00022 #include "catalog/namespace.h"
00023 #include "catalog/pg_collation.h"
00024 #include "catalog/pg_collation_fn.h"
00025 #include "commands/alter.h"
00026 #include "commands/collationcmds.h"
00027 #include "commands/dbcommands.h"
00028 #include "commands/defrem.h"
00029 #include "mb/pg_wchar.h"
00030 #include "miscadmin.h"
00031 #include "utils/builtins.h"
00032 #include "utils/lsyscache.h"
00033 #include "utils/pg_locale.h"
00034 #include "utils/rel.h"
00035 #include "utils/syscache.h"
00036 
00037 /*
00038  * CREATE COLLATION
00039  */
00040 Oid
00041 DefineCollation(List *names, List *parameters)
00042 {
00043     char       *collName;
00044     Oid         collNamespace;
00045     AclResult   aclresult;
00046     ListCell   *pl;
00047     DefElem    *fromEl = NULL;
00048     DefElem    *localeEl = NULL;
00049     DefElem    *lccollateEl = NULL;
00050     DefElem    *lcctypeEl = NULL;
00051     char       *collcollate = NULL;
00052     char       *collctype = NULL;
00053     Oid         newoid;
00054 
00055     collNamespace = QualifiedNameGetCreationNamespace(names, &collName);
00056 
00057     aclresult = pg_namespace_aclcheck(collNamespace, GetUserId(), ACL_CREATE);
00058     if (aclresult != ACLCHECK_OK)
00059         aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
00060                        get_namespace_name(collNamespace));
00061 
00062     foreach(pl, parameters)
00063     {
00064         DefElem    *defel = (DefElem *) lfirst(pl);
00065         DefElem   **defelp;
00066 
00067         if (pg_strcasecmp(defel->defname, "from") == 0)
00068             defelp = &fromEl;
00069         else if (pg_strcasecmp(defel->defname, "locale") == 0)
00070             defelp = &localeEl;
00071         else if (pg_strcasecmp(defel->defname, "lc_collate") == 0)
00072             defelp = &lccollateEl;
00073         else if (pg_strcasecmp(defel->defname, "lc_ctype") == 0)
00074             defelp = &lcctypeEl;
00075         else
00076         {
00077             ereport(ERROR,
00078                     (errcode(ERRCODE_SYNTAX_ERROR),
00079                      errmsg("collation attribute \"%s\" not recognized",
00080                             defel->defname)));
00081             break;
00082         }
00083 
00084         *defelp = defel;
00085     }
00086 
00087     if ((localeEl && (lccollateEl || lcctypeEl))
00088         || (fromEl && list_length(parameters) != 1))
00089         ereport(ERROR,
00090                 (errcode(ERRCODE_SYNTAX_ERROR),
00091                  errmsg("conflicting or redundant options")));
00092 
00093     if (fromEl)
00094     {
00095         Oid         collid;
00096         HeapTuple   tp;
00097 
00098         collid = get_collation_oid(defGetQualifiedName(fromEl), false);
00099         tp = SearchSysCache1(COLLOID, ObjectIdGetDatum(collid));
00100         if (!HeapTupleIsValid(tp))
00101             elog(ERROR, "cache lookup failed for collation %u", collid);
00102 
00103         collcollate = pstrdup(NameStr(((Form_pg_collation) GETSTRUCT(tp))->collcollate));
00104         collctype = pstrdup(NameStr(((Form_pg_collation) GETSTRUCT(tp))->collctype));
00105 
00106         ReleaseSysCache(tp);
00107     }
00108 
00109     if (localeEl)
00110     {
00111         collcollate = defGetString(localeEl);
00112         collctype = defGetString(localeEl);
00113     }
00114 
00115     if (lccollateEl)
00116         collcollate = defGetString(lccollateEl);
00117 
00118     if (lcctypeEl)
00119         collctype = defGetString(lcctypeEl);
00120 
00121     if (!collcollate)
00122         ereport(ERROR,
00123                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
00124                  errmsg("parameter \"lc_collate\" must be specified")));
00125 
00126     if (!collctype)
00127         ereport(ERROR,
00128                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
00129                  errmsg("parameter \"lc_ctype\" must be specified")));
00130 
00131     check_encoding_locale_matches(GetDatabaseEncoding(), collcollate, collctype);
00132 
00133     newoid = CollationCreate(collName,
00134                              collNamespace,
00135                              GetUserId(),
00136                              GetDatabaseEncoding(),
00137                              collcollate,
00138                              collctype);
00139 
00140     /* check that the locales can be loaded */
00141     CommandCounterIncrement();
00142     (void) pg_newlocale_from_collation(newoid);
00143 
00144     return newoid;
00145 }
00146 
00147 /*
00148  * Subroutine for ALTER COLLATION SET SCHEMA and RENAME
00149  *
00150  * Is there a collation with the same name of the given collation already in
00151  * the given namespace?  If so, raise an appropriate error message.
00152  */
00153 void
00154 IsThereCollationInNamespace(const char *collname, Oid nspOid)
00155 {
00156     /* make sure the name doesn't already exist in new schema */
00157     if (SearchSysCacheExists3(COLLNAMEENCNSP,
00158                               CStringGetDatum(collname),
00159                               Int32GetDatum(GetDatabaseEncoding()),
00160                               ObjectIdGetDatum(nspOid)))
00161         ereport(ERROR,
00162                 (errcode(ERRCODE_DUPLICATE_OBJECT),
00163                  errmsg("collation \"%s\" for encoding \"%s\" already exists in schema \"%s\"",
00164                         collname, GetDatabaseEncodingName(),
00165                         get_namespace_name(nspOid))));
00166 
00167     /* mustn't match an any-encoding entry, either */
00168     if (SearchSysCacheExists3(COLLNAMEENCNSP,
00169                               CStringGetDatum(collname),
00170                               Int32GetDatum(-1),
00171                               ObjectIdGetDatum(nspOid)))
00172         ereport(ERROR,
00173                 (errcode(ERRCODE_DUPLICATE_OBJECT),
00174                  errmsg("collation \"%s\" already exists in schema \"%s\"",
00175                         collname, get_namespace_name(nspOid))));
00176 }