text:
#include "postgres.h"

#include <ctype.h>

#include "access/genam.h"
#include "access/htup_details.h"
#include "access/table.h"
#include "access/xact.h"
#include "catalog/catalog.h"
#include "catalog/dependency.h"
#include "catalog/indexing.h"
#include "catalog/objectaccess.h"
#include "catalog/oid_dispatch.h"
#include "catalog/pg_namespace.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_ts_config.h"
#include "catalog/pg_ts_config_map.h"
#include "catalog/pg_ts_dict.h"
#include "catalog/pg_ts_parser.h"
#include "catalog/pg_ts_template.h"
#include "catalog/pg_type.h"
#include "commands/alter.h"
#include "commands/defrem.h"
#include "commands/event_trigger.h"
#include "miscadmin.h"
#include "nodes/makefuncs.h"
#include "parser/parse_func.h"
#include "tsearch/ts_cache.h"
#include "tsearch/ts_utils.h"
#include "utils/builtins.h"
#include "utils/fmgroids.h"
#include "utils/lsyscache.h"
#include "utils/rel.h"
#include "utils/syscache.h"

#include "cdb/cdbvars.h"
#include "cdb/cdbdisp_query.h"

static void MakeConfigurationMapping(AlterTSConfigurationStmt *stmt,
									 HeapTuple tup, Relation relMap);
static void DropConfigurationMapping(AlterTSConfigurationStmt *stmt,
									 HeapTuple tup, Relation relMap);

/* --------------------- TS Parser commands ------------------------ */

/*
 * lookup a parser support function and return its OID (as a Datum)
 *
 * attnum is the pg_ts_parser column the function will go into
 */
static Datum
get_ts_parser_func(DefElem *defel, int attnum)
{
	List	   *funcName = defGetQualifiedName(defel);
	Oid			typeId[3];
	Oid			retTypeId;
	int			nargs;
	Oid			procOid;

	retTypeId = INTERNALOID;	/* correct for most */
	typeId[0] = INTERNALOID;
	switch (attnum)
	{
		case Anum_pg_ts_parser_prsstart:
			nargs = 2;
			typeId[1] = INT4OID;
			break;
		case Anum_pg_ts_parser_prstoken:
			nargs = 3;
			typeId[1] = INTERNALOID;
			typeId[2] = INTERNALOID;
			break;
		case Anum_pg_ts_parser_prsend:
			nargs = 1;
			retTypeId = VOIDOID;
			break;
		case Anum_pg_ts_parser_prsheadline:
			nargs = 3;
			typeId[1] = INTERNALOID;
			typeId[2] = TSQUERYOID;
			break;
		case Anum_pg_ts_parser_prslextype:
			nargs = 1;

			/*
			 * Note: because the lextype method returns type internal, it must
			 * have an internal-type argument for security reasons.  The
			 * argument is not actually used, but is just passed as a zero.
			 */
			break;
		default:
			/* should not be here */
			elog(ERROR, "unrecognized attribute for text search parser: %d",
				 attnum);
			nargs = 0;			/* keep compiler quiet */
	}

	procOid = LookupFuncName(funcName, nargs, typeId, false);
	if (get_func_rettype(procOid) != retTypeId)
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
				 errmsg("function %s should return type %s",
						func_signature_string(funcName, nargs, NIL, typeId),
						format_type_be(retTypeId))));

	return ObjectIdGetDatum(procOid);
}

/*
 * make pg_depend entries for a new pg_ts_parser entry
 *
 * Return value is the address of said new entry.
 */
static ObjectAddress
makeParserDependencies(HeapTuple tuple)
{
	Form_pg_ts_parser prs = (Form_pg_ts_parser) GETSTRUCT(tuple);
	ObjectAddress myself,
				referenced;

	myself.classId = TSParserRelationId;
	myself.objectId = prs->oid;
	myself.objectSubId = 0;

	/* dependency on namespace */
	referenced.classId = NamespaceRelationId;
	referenced.objectId = prs->prsnamespace;
	referenced.objectSubId = 0;
	recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);

	/* dependency on extension */
	recordDependencyOnCurrentExtension(&myself, false);

	/* dependencies on functions */
	referenced.classId = ProcedureRelationId;
	referenced.objectSubId = 0;

	referenced.objectId = prs->prsstart;
	recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);

	referenced.objectId = prs->prstoken;
	recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);

	referenced.objectId = prs->prsend;
	recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);

	referenced.objectId = prs->prslextype;
	recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);

	if (OidIsValid(prs->prsheadline))
	{
		referenced.objectId = prs->prsheadline;
		recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
	}

	return myself;
}

/*
 * CREATE TEXT SEARCH PARSER
 */
ObjectAddress
DefineTSParser(List *names, List *parameters)
{
	char	   *prsname;
	ListCell   *pl;
	Relation	prsRel;
	HeapTuple	tup;
	Datum		values[Natts_pg_ts_parser];
	bool		nulls[Natts_pg_ts_parser];
	NameData	pname;
	Oid			prsOid;
	Oid			namespaceoid;
	ObjectAddress address;

	if (!superuser())
		ereport(ERROR,
				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
				 errmsg("must be superuser to create text search parsers")));

	prsRel = table_open(TSParserRelationId, RowExclusiveLock);

	/* Convert list of names to a name and namespace */
	namespaceoid = QualifiedNameGetCreationNamespace(names, &prsname);

	/* initialize tuple fields with name/namespace */
	memset(values, 0, sizeof(values));
	memset(nulls, false, sizeof(nulls));

	prsOid = GetNewOidForTSParser(prsRel, TSParserOidIndexId,
								  Anum_pg_ts_parser_oid,
								  prsname, namespaceoid);
	values[Anum_pg_ts_parser_oid - 1] = ObjectIdGetDatum(prsOid);
	namestrcpy(&pname, prsname);
	values[Anum_pg_ts_parser_prsname - 1] = NameGetDatum(&pname);
	values[Anum_pg_ts_parser_prsnamespace - 1] = ObjectIdGetDatum(namespaceoid);

	/*
	 * loop over the definition list and extract the information we need.
	 */
	foreach(pl, parameters)
	{
		DefElem    *defel = (DefElem *) lfirst(pl);

		if (strcmp(defel->defname, "start") == 0)
		{
			values[Anum_pg_ts_parser_prsstart - 1] =
				get_ts_parser_func(defel, Anum_pg_ts_parser_prsstart);
		}
		else if (strcmp(defel->defname, "gettoken") == 0)
		{
			values[Anum_pg_ts_parser_prstoken - 1] =
				get_ts_parser_func(defel, Anum_pg_ts_parser_prstoken);
		}
		else if (strcmp(defel->defname, "end") == 0)
		{
			values[Anum_pg_ts_parser_prsend - 1] =
				get_ts_parser_func(defel, Anum_pg_ts_parser_prsend);
		}
		else if (strcmp(defel->defname, "headline") == 0)
		{
			values[Anum_pg_ts_parser_prsheadline - 1] =
				get_ts_parser_func(defel, Anum_pg_ts_parser_prsheadline);
		}
		else if (strcmp(defel->defname, "lextypes") == 0)
		{
			values[Anum_pg_ts_parser_prslextype - 1] =
				get_ts_parser_func(defel, Anum_pg_ts_parser_prslextype);
		}
		else
			ereport(ERROR,
					(errcode(ERRCODE_SYNTAX_ERROR),
					 errmsg("text search parser parameter \"%s\" not recognized",
							defel->defname)));
	}

	/*
	 * Validation
	 */
	if (!OidIsValid(DatumGetObjectId(values[Anum_pg_ts_parser_prsstart - 1])))
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
				 errmsg("text search parser start method is required")));

	if (!OidIsValid(DatumGetObjectId(values[Anum_pg_ts_parser_prstoken - 1])))
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
				 errmsg("text search parser gettoken method is required")));

	if (!OidIsValid(DatumGetObjectId(values[Anum_pg_ts_parser_prsend - 1])))
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
				 errmsg("text search parser end method is required")));

	if (!OidIsValid(DatumGetObjectId(values[Anum_pg_ts_parser_prslextype - 1])))
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
				 errmsg("text search parser lextypes method is required")));

	/*
	 * Looks good, insert
	 */
	tup = heap_form_tuple(prsRel->rd_att, values, nulls);

	CatalogTupleInsert(prsRel, tup);

	address = makeParserDependencies(tup);

	/* Post creation hook for new text search parser */
	InvokeObjectPostCreateHook(TSParserRelationId, prsOid, 0);

	heap_freetuple(tup);

	table_close(prsRel, RowExclusiveLock);

	if (Gp_role == GP_ROLE_DISPATCH)
	{
		DefineStmt *stmt = makeNode(DefineStmt);

		stmt->kind = OBJECT_TSPARSER;
		stmt->oldstyle = false;
		stmt->defnames = names;
		stmt->args = NIL;
		stmt->definition = parameters;

		CdbDispatchUtilityStatement((Node *) stmt,
									DF_CANCEL_ON_ERROR |
									DF_NEED_TWO_PHASE |
									DF_WITH_SNAPSHOT,
									GetAssignedOidsForDispatch(),
									NULL);
	}

	return address;
}

/*
 * Guts of TS parser deletion.
 */
void
RemoveTSParserById(Oid prsId)
{
	Relation	relation;
	HeapTuple	tup;

	relation = table_open(TSParserRelationId, RowExclusiveLock);

	tup = SearchSysCache1(TSPARSEROID, ObjectIdGetDatum(prsId));

	if (!HeapTupleIsValid(tup))
		elog(ERROR, "cache lookup failed for text search parser %u", prsId);

	CatalogTupleDelete(relation, &tup->t_self);

	ReleaseSysCache(tup);

	table_close(relation, RowExclusiveLock);
}

/* ---------------------- TS Dictionary commands -----------------------*/

/*
 * make pg_depend entries for a new pg_ts_dict entry
 *
 * Return value is address of the new entry
 */
static ObjectAddress
makeDictionaryDependencies(HeapTuple tuple)
{
	Form_pg_ts_dict dict = (Form_pg_ts_dict) GETSTRUCT(tuple);
	ObjectAddress myself,
				referenced;

	myself.classId = TSDictionaryRelationId;
	myself.objectId = dict->oid;
	myself.objectSubId = 0;

	/* dependency on namespace */
	referenced.classId = NamespaceRelationId;
	referenced.objectId = dict->dictnamespace;
	referenced.objectSubId = 0;
	recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);

	/* dependency on owner */
	recordDependencyOnOwner(myself.classId, myself.objectId, dict->dictowner);

	/* dependency on extension */
	recordDependencyOnCurrentExtension(&myself, false);

	/* dependency on template */
	referenced.classId = TSTemplateRelationId;
	referenced.objectId = dict->dicttemplate;
	referenced.objectSubId = 0;
	recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);

	return myself;
}

/*
 * verify that a template's init method accepts a proposed option list
 */
static void
verify_dictoptions(Oid tmplId, List *dictoptions)
{
	HeapTuple	tup;
	Form_pg_ts_template tform;
	Oid			initmethod;

	/*
	 * Suppress this test when running in a standalone backend.  This is a
	 * hack to allow initdb to create prefab dictionaries that might not
	 * actually be usable in template1's encoding (due to using external files
	 * that can't be translated into template1's encoding).  We want to create
	 * them anyway, since they might be usable later in other databases.
	 */
	if (!IsUnderPostmaster)
		return;

	tup = SearchSysCache1(TSTEMPLATEOID, ObjectIdGetDatum(tmplId));
	if (!HeapTupleIsValid(tup)) /* should not happen */
		elog(ERROR, "cache lookup failed for text search template %u",
			 tmplId);
	tform = (Form_pg_ts_template) GETSTRUCT(tup);

	initmethod = tform->tmplinit;

	if (!OidIsValid(initmethod))
	{
		/* If there is no init method, disallow any options */
		if (dictoptions)
			ereport(ERROR,
					(errcode(ERRCODE_SYNTAX_ERROR),
					 errmsg("text search template \"%s\" does not accept options",
							NameStr(tform->tmplname))));
	}
	else
	{
		/*
		 * Copy the options just in case init method thinks it can scribble on
		 * them ...
		 */
		dictoptions = copyObject(dictoptions);

		/*
		 * Call the init method and see if it complains.  We don't worry about
		 * it leaking memory, since our command will soon be over anyway.
		 */
		(void) OidFunctionCall1(initmethod, PointerGetDatum(dictoptions));
	}

	ReleaseSysCache(tup);
}

/*
 * CREATE TEXT SEARCH DICTIONARY
 */
ObjectAddress
DefineTSDictionary(List *names, List *parameters)
{
	ListCell   *pl;
	Relation	dictRel;
	HeapTuple	tup;
	Datum		values[Natts_pg_ts_dict];
	bool		nulls[Natts_pg_ts_dict];
	NameData	dname;
	Oid			templId = InvalidOid;
	List	   *dictoptions = NIL;
	Oid			dictOid;
	Oid			namespaceoid;
	AclResult	aclresult;
	char	   *dictname;
	ObjectAddress address;

	/* Convert list of names to a name and namespace */
	namespaceoid = QualifiedNameGetCreationNamespace(names, &dictname);

	/* Check we have creation rights in target namespace */
	aclresult = pg_namespace_aclcheck(namespaceoid, GetUserId(), ACL_CREATE);
	if (aclresult != ACLCHECK_OK)
		aclcheck_error(aclresult, OBJECT_SCHEMA,
					   get_namespace_name(namespaceoid));

	/*
	 * loop over the definition list and extract the information we need.
	 */
	foreach(pl, parameters)
	{
		DefElem    *defel = (DefElem *) lfirst(pl);

		if (strcmp(defel->defname, "template") == 0)
		{
			templId = get_ts_template_oid(defGetQualifiedName(defel), false);
		}
		else
		{
			/* Assume it's an option for the dictionary itself */
			dictoptions = lappend(dictoptions, defel);
		}
	}

	/*
	 * Validation
	 */
	if (!OidIsValid(templId))
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
				 errmsg("text search template is required")));

	verify_dictoptions(templId, dictoptions);

	dictRel = table_open(TSDictionaryRelationId, RowExclusiveLock);

	/*
	 * Looks good, insert
	 */
	memset(values, 0, sizeof(values));
	memset(nulls, false, sizeof(nulls));

	dictOid = GetNewOidForTSDictionary(dictRel, TSDictionaryOidIndexId,
									   Anum_pg_ts_dict_oid,
									   dictname, namespaceoid);
	values[Anum_pg_ts_dict_oid - 1] = ObjectIdGetDatum(dictOid);
	namestrcpy(&dname, dictname);
	values[Anum_pg_ts_dict_dictname - 1] = NameGetDatum(&dname);
	values[Anum_pg_ts_dict_dictnamespace - 1] = ObjectIdGetDatum(namespaceoid);
	values[Anum_pg_ts_dict_dictowner - 1] = ObjectIdGetDatum(GetUserId());
	values[Anum_pg_ts_dict_dicttemplate - 1] = ObjectIdGetDatum(templId);
	if (dictoptions)
		values[Anum_pg_ts_dict_dictinitoption - 1] =
			PointerGetDatum(serialize_deflist(dictoptions));
	else
		nulls[Anum_pg_ts_dict_dictinitoption - 1] = true;

	tup = heap_form_tuple(dictRel->rd_att, values, nulls);

	CatalogTupleInsert(dictRel, tup);

	address = makeDictionaryDependencies(tup);

	/* Post creation hook for new text search dictionary */
	InvokeObjectPostCreateHook(TSDictionaryRelationId, dictOid, 0);

	heap_freetuple(tup);

	table_close(dictRel, RowExclusiveLock);

	if (Gp_role == GP_ROLE_DISPATCH)
	{
		DefineStmt *stmt = makeNode(DefineStmt);
		stmt->kind = OBJECT_TSDICTIONARY;
		stmt->oldstyle = false;
		stmt->defnames = names;
		stmt->args = NIL;
		stmt->definition = parameters;
		CdbDispatchUtilityStatement((Node *) stmt,
									DF_CANCEL_ON_ERROR |
									DF_NEED_TWO_PHASE |
									DF_WITH_SNAPSHOT,
									GetAssignedOidsForDispatch(),
									NULL);
	}

	return address;
}

/*
 * Guts of TS dictionary deletion.
 */
void
RemoveTSDictionaryById(Oid dictId)
{
	Relation	relation;
	HeapTuple	tup;

	relation = table_open(TSDictionaryRelationId, RowExclusiveLock);

	tup = SearchSysCache1(TSDICTOID, ObjectIdGetDatum(dictId));

	if (!HeapTupleIsValid(tup))
		elog(ERROR, "cache lookup failed for text search dictionary %u",
			 dictId);

	CatalogTupleDelete(relation, &tup->t_self);

	ReleaseSysCache(tup);

	table_close(relation, RowExclusiveLock);
}

/*
 * ALTER TEXT SEARCH DICTIONARY
 */
ObjectAddress
AlterTSDictionary(AlterTSDictionaryStmt *stmt)
{
	HeapTuple	tup,
				newtup;
	Relation	rel;
	Oid			dictId;
	ListCell   *pl;
	List	   *dictoptions;
	Datum		opt;
	bool		isnull;
	Datum		repl_val[Natts_pg_ts_dict];
	bool		repl_null[Natts_pg_ts_dict];
	bool		repl_repl[Natts_pg_ts_dict];
	ObjectAddress address;

	dictId = get_ts_dict_oid(stmt->dictname, false);

	rel = table_open(TSDictionaryRelationId, RowExclusiveLock);

	tup = SearchSysCache1(TSDICTOID, ObjectIdGetDatum(dictId));

	if (!HeapTupleIsValid(tup))
		elog(ERROR, "cache lookup failed for text search dictionary %u",
			 dictId);

	/* must be owner */
	if (!pg_ts_dict_ownercheck(dictId, GetUserId()))
		aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_TSDICTIONARY,
					   NameListToString(stmt->dictname));

	/* deserialize the existing set of options */
	opt = SysCacheGetAttr(TSDICTOID, tup,
						  Anum_pg_ts_dict_dictinitoption,
						  &isnull);
	if (isnull)
		dictoptions = NIL;
	else
		dictoptions = deserialize_deflist(opt);

	/*
	 * Modify the options list as per specified changes
	 */
	foreach(pl, stmt->options)
	{
		DefElem    *defel = (DefElem *) lfirst(pl);
		ListCell   *cell;
		ListCell   *prev;
		ListCell   *next;

		/*
		 * Remove any matches ...
		 */
		prev = NULL;
		for (cell = list_head(dictoptions); cell; cell = next)
		{
			DefElem    *oldel = (DefElem *) lfirst(cell);

			next = lnext(cell);
			if (strcmp(oldel->defname, defel->defname) == 0)
				dictoptions = list_delete_cell(dictoptions, cell, prev);
			else
				prev = cell;
		}

		/*
		 * and add new value if it's got one
		 */
		if (defel->arg)
			dictoptions = lappend(dictoptions, defel);
	}

	/*
	 * Validate
	 */
	verify_dictoptions(((Form_pg_ts_dict) GETSTRUCT(tup))->dicttemplate,
					   dictoptions);

	/*
	 * Looks good, update
	 */
	memset(repl_val, 0, sizeof(repl_val));
	memset(repl_null, false, sizeof(repl_null));
	memset(repl_repl, false, sizeof(repl_repl));

	if (dictoptions)
		repl_val[Anum_pg_ts_dict_dictinitoption - 1] =
			PointerGetDatum(serialize_deflist(dictoptions));
	else
		repl_null[Anum_pg_ts_dict_dictinitoption - 1] = true;
	repl_repl[Anum_pg_ts_dict_dictinitoption - 1] = true;

	newtup = heap_modify_tuple(tup, RelationGetDescr(rel),
							   repl_val, repl_null, repl_repl);

	CatalogTupleUpdate(rel, &newtup->t_self, newtup);

	InvokeObjectPostAlterHook(TSDictionaryRelationId, dictId, 0);

	ObjectAddressSet(address, TSDictionaryRelationId, dictId);

	/*
	 * NOTE: because we only support altering the options, not the template,
	 * there is no need to update dependencies.  This might have to change if
	 * the options ever reference inside-the-database objects.
	 */

	heap_freetuple(newtup);
	ReleaseSysCache(tup);

	table_close(rel, RowExclusiveLock);

	if (Gp_role == GP_ROLE_DISPATCH)
		CdbDispatchUtilityStatement((Node *) stmt,
									DF_CANCEL_ON_ERROR |
									DF_NEED_TWO_PHASE |
									DF_WITH_SNAPSHOT,
									NIL,
									NULL);

	return address;
}

/* ---------------------- TS Template commands -----------------------*/

/*
 * lookup a template support function and return its OID (as a Datum)
 *
 * attnum is the pg_ts_template column the function will go into
 */
static Datum
get_ts_template_func(DefElem *defel, int attnum)
{
	List	   *funcName = defGetQualifiedName(defel);
	Oid			typeId[4];
	Oid			retTypeId;
	int			nargs;
	Oid			procOid;

	retTypeId = INTERNALOID;
	typeId[0] = INTERNALOID;
	typeId[1] = INTERNALOID;
	typeId[2] = INTERNALOID;
	typeId[3] = INTERNALOID;
	switch (attnum)
	{
		case Anum_pg_ts_template_tmplinit:
			nargs = 1;
			break;
		case Anum_pg_ts_template_tmpllexize:
			nargs = 4;
			break;
		default:
			/* should not be here */
			elog(ERROR, "unrecognized attribute for text search template: %d",
				 attnum);
			nargs = 0;			/* keep compiler quiet */
	}

	procOid = LookupFuncName(funcName, nargs, typeId, false);
	if (get_func_rettype(procOid) != retTypeId)
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
				 errmsg("function %s should return type %s",
						func_signature_string(funcName, nargs, NIL, typeId),
						format_type_be(retTypeId))));

	return ObjectIdGetDatum(procOid);
}

/*
 * make pg_depend entries for a new pg_ts_template entry
 */
static ObjectAddress
makeTSTemplateDependencies(HeapTuple tuple)
{
	Form_pg_ts_template tmpl = (Form_pg_ts_template) GETSTRUCT(tuple);
	ObjectAddress myself,
				referenced;

	myself.classId = TSTemplateRelationId;
	myself.objectId = tmpl->oid;
	myself.objectSubId = 0;

	/* dependency on namespace */
	referenced.classId = NamespaceRelationId;
	referenced.objectId = tmpl->tmplnamespace;
	referenced.objectSubId = 0;
	recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);

	/* dependency on extension */
	recordDependencyOnCurrentExtension(&myself, false);

	/* dependencies on functions */
	referenced.classId = ProcedureRelationId;
	referenced.objectSubId = 0;

	referenced.objectId = tmpl->tmpllexize;
	recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);

	if (OidIsValid(tmpl->tmplinit))
	{
		referenced.objectId = tmpl->tmplinit;
		recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
	}

	return myself;
}

/*
 * CREATE TEXT SEARCH TEMPLATE
 */
ObjectAddress
DefineTSTemplate(List *names, List *parameters)
{
	ListCell   *pl;
	Relation	tmplRel;
	HeapTuple	tup;
	Datum		values[Natts_pg_ts_template];
	bool		nulls[Natts_pg_ts_template];
	NameData	dname;
	int			i;
	Oid			tmplOid;
	Oid			namespaceoid;
	char	   *tmplname;
	ObjectAddress address;

	if (!superuser())
		ereport(ERROR,
				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
				 errmsg("must be superuser to create text search templates")));

	/* Convert list of names to a name and namespace */
	namespaceoid = QualifiedNameGetCreationNamespace(names, &tmplname);

	tmplRel = table_open(TSTemplateRelationId, RowExclusiveLock);

	for (i = 0; i < Natts_pg_ts_template; i++)
	{
		nulls[i] = false;
		values[i] = ObjectIdGetDatum(InvalidOid);
	}

	tmplOid = GetNewOidForTSTemplate(tmplRel, TSTemplateOidIndexId,
									 Anum_pg_ts_dict_oid,
									 tmplname, namespaceoid);
	values[Anum_pg_ts_template_oid - 1] = ObjectIdGetDatum(tmplOid);
	namestrcpy(&dname, tmplname);
	values[Anum_pg_ts_template_tmplname - 1] = NameGetDatum(&dname);
	values[Anum_pg_ts_template_tmplnamespace - 1] = ObjectIdGetDatum(namespaceoid);

	/*
	 * loop over the definition list and extract the information we need.
	 */
	foreach(pl, parameters)
	{
		DefElem    *defel = (DefElem *) lfirst(pl);

		if (strcmp(defel->defname, "init") == 0)
		{
			values[Anum_pg_ts_template_tmplinit - 1] =
				get_ts_template_func(defel, Anum_pg_ts_template_tmplinit);
			nulls[Anum_pg_ts_template_tmplinit - 1] = false;
		}
		else if (strcmp(defel->defname, "lexize") == 0)
		{
			values[Anum_pg_ts_template_tmpllexize - 1] =
				get_ts_template_func(defel, Anum_pg_ts_template_tmpllexize);
			nulls[Anum_pg_ts_template_tmpllexize - 1] = false;
		}
		else
			ereport(ERROR,
					(errcode(ERRCODE_SYNTAX_ERROR),
					 errmsg("text search template parameter \"%s\" not recognized",
							defel->defname)));
	}

	/*
	 * Validation
	 */
	if (!OidIsValid(DatumGetObjectId(values[Anum_pg_ts_template_tmpllexize - 1])))
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
				 errmsg("text search template lexize method is required")));

	/*
	 * Looks good, insert
	 */
	tup = heap_form_tuple(tmplRel->rd_att, values, nulls);

	CatalogTupleInsert(tmplRel, tup);

	address = makeTSTemplateDependencies(tup);

	/* Post creation hook for new text search template */
	InvokeObjectPostCreateHook(TSTemplateRelationId, tmplOid, 0);

	heap_freetuple(tup);

	table_close(tmplRel, RowExclusiveLock);

	if (Gp_role == GP_ROLE_DISPATCH)
	{
		DefineStmt *stmt = makeNode(DefineStmt);
		stmt->kind = OBJECT_TSTEMPLATE;
		stmt->oldstyle = false;
		stmt->defnames = names;
		stmt->args = NIL;
		stmt->definition = parameters;
		CdbDispatchUtilityStatement((Node *) stmt,
									DF_CANCEL_ON_ERROR |
									DF_NEED_TWO_PHASE |
									DF_WITH_SNAPSHOT,
									GetAssignedOidsForDispatch(),
									NULL);
	}

	return address;
}

/*
 * Guts of TS template deletion.
 */
void
RemoveTSTemplateById(Oid tmplId)
{
	Relation	relation;
	HeapTuple	tup;

	relation = table_open(TSTemplateRelationId, RowExclusiveLock);

	tup = SearchSysCache1(TSTEMPLATEOID, ObjectIdGetDatum(tmplId));

	if (!HeapTupleIsValid(tup))
		elog(ERROR, "cache lookup failed for text search template %u",
			 tmplId);

	CatalogTupleDelete(relation, &tup->t_self);

	ReleaseSysCache(tup);

	table_close(relation, RowExclusiveLock);
}

/* ---------------------- TS Configuration commands -----------------------*/

/*
 * Finds syscache tuple of configuration.
 * Returns NULL if no such cfg.
 */
static HeapTuple
GetTSConfigTuple(List *names)
{
	HeapTuple	tup;
	Oid			cfgId;

	cfgId = get_ts_config_oid(names, true);
	if (!OidIsValid(cfgId))
		return NULL;

	tup = SearchSysCache1(TSCONFIGOID, ObjectIdGetDatum(cfgId));

	if (!HeapTupleIsValid(tup)) /* should not happen */
		elog(ERROR, "cache lookup failed for text search configuration %u",
			 cfgId);

	return tup;
}

/*
 * make pg_depend entries for a new or updated pg_ts_config entry
 *
 * Pass opened pg_ts_config_map relation if there might be any config map
 * entries for the config.
 */
static ObjectAddress
makeConfigurationDependencies(HeapTuple tuple, bool removeOld,
							  Relation mapRel)
{
	Form_pg_ts_config cfg = (Form_pg_ts_config) GETSTRUCT(tuple);
	ObjectAddresses *addrs;
	ObjectAddress myself,
				referenced;

	myself.classId = TSConfigRelationId;
	myself.objectId = cfg->oid;
	myself.objectSubId = 0;

	/* for ALTER case, first flush old dependencies, except extension deps */
	if (removeOld)
	{
		deleteDependencyRecordsFor(myself.classId, myself.objectId, true);
		deleteSharedDependencyRecordsFor(myself.classId, myself.objectId, 0);
	}

	/*
	 * We use an ObjectAddresses list to remove possible duplicate
	 * dependencies from the config map info.  The pg_ts_config items
	 * shouldn't be duplicates, but might as well fold them all into one call.
	 */
	addrs = new_object_addresses();

	/* dependency on namespace */
	referenced.classId = NamespaceRelationId;
	referenced.objectId = cfg->cfgnamespace;
	referenced.objectSubId = 0;
	add_exact_object_address(&referenced, addrs);

	/* dependency on owner */
	recordDependencyOnOwner(myself.classId, myself.objectId, cfg->cfgowner);

	/* dependency on extension */
	recordDependencyOnCurrentExtension(&myself, removeOld);

	/* dependency on parser */
	referenced.classId = TSParserRelationId;
	referenced.objectId = cfg->cfgparser;
	referenced.objectSubId = 0;
	add_exact_object_address(&referenced, addrs);

	/* dependencies on dictionaries listed in config map */
	if (mapRel)
	{
		ScanKeyData skey;
		SysScanDesc scan;
		HeapTuple	maptup;

		/* CCI to ensure we can see effects of caller's changes */
		CommandCounterIncrement();

		ScanKeyInit(&skey,
					Anum_pg_ts_config_map_mapcfg,
					BTEqualStrategyNumber, F_OIDEQ,
					ObjectIdGetDatum(myself.objectId));

		scan = systable_beginscan(mapRel, TSConfigMapIndexId, true,
								  NULL, 1, &skey);

		while (HeapTupleIsValid((maptup = systable_getnext(scan))))
		{
			Form_pg_ts_config_map cfgmap = (Form_pg_ts_config_map) GETSTRUCT(maptup);

			referenced.classId = TSDictionaryRelationId;
			referenced.objectId = cfgmap->mapdict;
			referenced.objectSubId = 0;
			add_exact_object_address(&referenced, addrs);
		}

		systable_endscan(scan);
	}

	/* Record 'em (this includes duplicate elimination) */
	record_object_address_dependencies(&myself, addrs, DEPENDENCY_NORMAL);

	free_object_addresses(addrs);

	return myself;
}

/*
 * CREATE TEXT SEARCH CONFIGURATION
 */
ObjectAddress
DefineTSConfiguration(List *names, List *parameters, ObjectAddress *copied)
{
	Relation	cfgRel;
	Relation	mapRel = NULL;
	HeapTuple	tup;
	Datum		values[Natts_pg_ts_config];
	bool		nulls[Natts_pg_ts_config];
	AclResult	aclresult;
	Oid			namespaceoid;
	char	   *cfgname;
	NameData	cname;
	Oid			sourceOid = InvalidOid;
	Oid			prsOid = InvalidOid;
	Oid			cfgOid;
	ListCell   *pl;
	ObjectAddress address;

	/* Convert list of names to a name and namespace */
	namespaceoid = QualifiedNameGetCreationNamespace(names, &cfgname);

	/* Check we have creation rights in target namespace */
	aclresult = pg_namespace_aclcheck(namespaceoid, GetUserId(), ACL_CREATE);
	if (aclresult != ACLCHECK_OK)
		aclcheck_error(aclresult, OBJECT_SCHEMA,
					   get_namespace_name(namespaceoid));

	/*
	 * loop over the definition list and extract the information we need.
	 */
	foreach(pl, parameters)
	{
		DefElem    *defel = (DefElem *) lfirst(pl);

		if (strcmp(defel->defname, "parser") == 0)
			prsOid = get_ts_parser_oid(defGetQualifiedName(defel), false);
		else if (strcmp(defel->defname, "copy") == 0)
			sourceOid = get_ts_config_oid(defGetQualifiedName(defel), false);
		else
			ereport(ERROR,
					(errcode(ERRCODE_SYNTAX_ERROR),
					 errmsg("text search configuration parameter \"%s\" not recognized",
							defel->defname)));
	}

	if (OidIsValid(sourceOid) && OidIsValid(prsOid))
		ereport(ERROR,
				(errcode(ERRCODE_SYNTAX_ERROR),
				 errmsg("cannot specify both PARSER and COPY options")));

	/* make copied tsconfig available to callers */
	if (copied && OidIsValid(sourceOid))
	{
		ObjectAddressSet(*copied,
						 TSConfigRelationId,
						 sourceOid);
	}

	/*
	 * Look up source config if given.
	 */
	if (OidIsValid(sourceOid))
	{
		Form_pg_ts_config cfg;

		tup = SearchSysCache1(TSCONFIGOID, ObjectIdGetDatum(sourceOid));
		if (!HeapTupleIsValid(tup))
			elog(ERROR, "cache lookup failed for text search configuration %u",
				 sourceOid);

		cfg = (Form_pg_ts_config) GETSTRUCT(tup);

		/* use source's parser */
		prsOid = cfg->cfgparser;

		ReleaseSysCache(tup);
	}

	/*
	 * Validation
	 */
	if (!OidIsValid(prsOid))
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
				 errmsg("text search parser is required")));

	cfgRel = table_open(TSConfigRelationId, RowExclusiveLock);

	/*
	 * Looks good, build tuple and insert
	 */
	memset(values, 0, sizeof(values));
	memset(nulls, false, sizeof(nulls));

	cfgOid = GetNewOidForTSConfig(cfgRel, TSConfigOidIndexId,
								  Anum_pg_ts_config_oid,
								  cfgname, namespaceoid);
	values[Anum_pg_ts_config_oid - 1] = ObjectIdGetDatum(cfgOid);
	namestrcpy(&cname, cfgname);
	values[Anum_pg_ts_config_cfgname - 1] = NameGetDatum(&cname);
	values[Anum_pg_ts_config_cfgnamespace - 1] = ObjectIdGetDatum(namespaceoid);
	values[Anum_pg_ts_config_cfgowner - 1] = ObjectIdGetDatum(GetUserId());
	values[Anum_pg_ts_config_cfgparser - 1] = ObjectIdGetDatum(prsOid);

	tup = heap_form_tuple(cfgRel->rd_att, values, nulls);

	CatalogTupleInsert(cfgRel, tup);

	if (OidIsValid(sourceOid))
	{
		/*
		 * Copy token-dicts map from source config
		 */
		ScanKeyData skey;
		SysScanDesc scan;
		HeapTuple	maptup;

		mapRel = table_open(TSConfigMapRelationId, RowExclusiveLock);

		ScanKeyInit(&skey,
					Anum_pg_ts_config_map_mapcfg,
					BTEqualStrategyNumber, F_OIDEQ,
					ObjectIdGetDatum(sourceOid));

		scan = systable_beginscan(mapRel, TSConfigMapIndexId, true,
								  NULL, 1, &skey);

		while (HeapTupleIsValid((maptup = systable_getnext(scan))))
		{
			Form_pg_ts_config_map cfgmap = (Form_pg_ts_config_map) GETSTRUCT(maptup);
			HeapTuple	newmaptup;
			Datum		mapvalues[Natts_pg_ts_config_map];
			bool		mapnulls[Natts_pg_ts_config_map];

			memset(mapvalues, 0, sizeof(mapvalues));
			memset(mapnulls, false, sizeof(mapnulls));

			mapvalues[Anum_pg_ts_config_map_mapcfg - 1] = cfgOid;
			mapvalues[Anum_pg_ts_config_map_maptokentype - 1] = cfgmap->maptokentype;
			mapvalues[Anum_pg_ts_config_map_mapseqno - 1] = cfgmap->mapseqno;
			mapvalues[Anum_pg_ts_config_map_mapdict - 1] = cfgmap->mapdict;

			newmaptup = heap_form_tuple(mapRel->rd_att, mapvalues, mapnulls);

			CatalogTupleInsert(mapRel, newmaptup);

			heap_freetuple(newmaptup);
		}

		systable_endscan(scan);
	}

	address = makeConfigurationDependencies(tup, false, mapRel);

	/* Post creation hook for new text search configuration */
	InvokeObjectPostCreateHook(TSConfigRelationId, cfgOid, 0);

	heap_freetuple(tup);

	if (mapRel)
		table_close(mapRel, RowExclusiveLock);
	table_close(cfgRel, RowExclusiveLock);

	if (Gp_role == GP_ROLE_DISPATCH)
	{
		DefineStmt *stmt = makeNode(DefineStmt);
		stmt->kind = OBJECT_TSCONFIGURATION;
		stmt->oldstyle = false;
		stmt->defnames = names;
		stmt->args = NIL;
		stmt->definition = parameters;
		CdbDispatchUtilityStatement((Node *) stmt,
									DF_CANCEL_ON_ERROR |
									DF_NEED_TWO_PHASE |
									DF_WITH_SNAPSHOT,
									GetAssignedOidsForDispatch(),
									NULL);
	}

	return address;
}

/*
 * Guts of TS configuration deletion.
 */
void
RemoveTSConfigurationById(Oid cfgId)
{
	Relation	relCfg,
				relMap;
	HeapTuple	tup;
	ScanKeyData skey;
	SysScanDesc scan;

	/* Remove the pg_ts_config entry */
	relCfg = table_open(TSConfigRelationId, RowExclusiveLock);

	tup = SearchSysCache1(TSCONFIGOID, ObjectIdGetDatum(cfgId));

	if (!HeapTupleIsValid(tup))
		elog(ERROR, "cache lookup failed for text search dictionary %u",
			 cfgId);

	CatalogTupleDelete(relCfg, &tup->t_self);

	ReleaseSysCache(tup);

	table_close(relCfg, RowExclusiveLock);

	/* Remove any pg_ts_config_map entries */
	relMap = table_open(TSConfigMapRelationId, RowExclusiveLock);

	ScanKeyInit(&skey,
				Anum_pg_ts_config_map_mapcfg,
				BTEqualStrategyNumber, F_OIDEQ,
				ObjectIdGetDatum(cfgId));

	scan = systable_beginscan(relMap, TSConfigMapIndexId, true,
							  NULL, 1, &skey);

	while (HeapTupleIsValid((tup = systable_getnext(scan))))
	{
		CatalogTupleDelete(relMap, &tup->t_self);
	}

	systable_endscan(scan);

	table_close(relMap, RowExclusiveLock);
}

/*
 * ALTER TEXT SEARCH CONFIGURATION - main entry point
 */
ObjectAddress
AlterTSConfiguration(AlterTSConfigurationStmt *stmt)
{
	HeapTuple	tup;
	Oid			cfgId;
	Relation	relMap;
	ObjectAddress address;

	/* Find the configuration */
	tup = GetTSConfigTuple(stmt->cfgname);
	if (!HeapTupleIsValid(tup))
		ereport(ERROR,
				(errcode(ERRCODE_UNDEFINED_OBJECT),
				 errmsg("text search configuration \"%s\" does not exist",
						NameListToString(stmt->cfgname))));

	cfgId = ((Form_pg_ts_config) GETSTRUCT(tup))->oid;

	/* must be owner */
	if (!pg_ts_config_ownercheck(cfgId, GetUserId()))
		aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_TSCONFIGURATION,
					   NameListToString(stmt->cfgname));

	relMap = table_open(TSConfigMapRelationId, RowExclusiveLock);

	/* Add or drop mappings */
	if (stmt->dicts)
		MakeConfigurationMapping(stmt, tup, relMap);
	else if (stmt->tokentype)
		DropConfigurationMapping(stmt, tup, relMap);

	/* Update dependencies */
	makeConfigurationDependencies(tup, true, relMap);

	InvokeObjectPostAlterHook(TSConfigRelationId, cfgId, 0);

	ObjectAddressSet(address, TSConfigRelationId, cfgId);

	table_close(relMap, RowExclusiveLock);

	ReleaseSysCache(tup);

	if (Gp_role == GP_ROLE_DISPATCH)
		CdbDispatchUtilityStatement((Node *) stmt,
									DF_CANCEL_ON_ERROR |
									DF_NEED_TWO_PHASE |
									DF_WITH_SNAPSHOT,
									NIL,
									NULL);

	return address;
}

/*
 * Translate a list of token type names to an array of token type numbers
 */
static int *
getTokenTypes(Oid prsId, List *tokennames)
{
	TSParserCacheEntry *prs = lookup_ts_parser_cache(prsId);
	LexDescr   *list;
	int		   *res,
				i,
				ntoken;
	ListCell   *tn;

	ntoken = list_length(tokennames);
	if (ntoken == 0)
		return NULL;
	res = (int *) palloc(sizeof(int) * ntoken);

	if (!OidIsValid(prs->lextypeOid))
		elog(ERROR, "method lextype isn't defined for text search parser %u",
			 prsId);

	/* lextype takes one dummy argument */
	list = (LexDescr *) DatumGetPointer(OidFunctionCall1(prs->lextypeOid,
														 (Datum) 0));

	i = 0;
	foreach(tn, tokennames)
	{
		Value	   *val = (Value *) lfirst(tn);
		bool		found = false;
		int			j;

		j = 0;
		while (list && list[j].lexid)
		{
			if (strcmp(strVal(val), list[j].alias) == 0)
			{
				res[i] = list[j].lexid;
				found = true;
				break;
			}
			j++;
		}
		if (!found)
			ereport(ERROR,
					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
					 errmsg("token type \"%s\" does not exist",
							strVal(val))));
		i++;
	}

	return res;
}

/*
 * ALTER TEXT SEARCH CONFIGURATION ADD/ALTER MAPPING
 */
static void
MakeConfigurationMapping(AlterTSConfigurationStmt *stmt,
						 HeapTuple tup, Relation relMap)
{
	Form_pg_ts_config tsform;
	Oid			cfgId;
	ScanKeyData skey[2];
	SysScanDesc scan;
	HeapTuple	maptup;
	int			i;
	int			j;
	Oid			prsId;
	int		   *tokens,
				ntoken;
	Oid		   *dictIds;
	int			ndict;
	ListCell   *c;

	tsform = (Form_pg_ts_config) GETSTRUCT(tup);
	cfgId = tsform->oid;
	prsId = tsform->cfgparser;

	tokens = getTokenTypes(prsId, stmt->tokentype);
	ntoken = list_length(stmt->tokentype);

	if (stmt->override)
	{
		/*
		 * delete maps for tokens if they exist and command was ALTER
		 */
		for (i = 0; i < ntoken; i++)
		{
			ScanKeyInit(&skey[0],
						Anum_pg_ts_config_map_mapcfg,
						BTEqualStrategyNumber, F_OIDEQ,
						ObjectIdGetDatum(cfgId));
			ScanKeyInit(&skey[1],
						Anum_pg_ts_config_map_maptokentype,
						BTEqualStrategyNumber, F_INT4EQ,
						Int32GetDatum(tokens[i]));

			scan = systable_beginscan(relMap, TSConfigMapIndexId, true,
									  NULL, 2, skey);

			while (HeapTupleIsValid((maptup = systable_getnext(scan))))
			{
				CatalogTupleDelete(relMap, &maptup->t_self);
			}

			systable_endscan(scan);
		}
	}

	/*
	 * Convert list of dictionary names to array of dict OIDs
	 */
	ndict = list_length(stmt->dicts);
	dictIds = (Oid *) palloc(sizeof(Oid) * ndict);
	i = 0;
	foreach(c, stmt->dicts)
	{
		List	   *names = (List *) lfirst(c);

		dictIds[i] = get_ts_dict_oid(names, false);
		i++;
	}

	if (stmt->replace)
	{
		/*
		 * Replace a specific dictionary in existing entries
		 */
		Oid			dictOld = dictIds[0],
					dictNew = dictIds[1];

		ScanKeyInit(&skey[0],
					Anum_pg_ts_config_map_mapcfg,
					BTEqualStrategyNumber, F_OIDEQ,
					ObjectIdGetDatum(cfgId));

		scan = systable_beginscan(relMap, TSConfigMapIndexId, true,
								  NULL, 1, skey);

		while (HeapTupleIsValid((maptup = systable_getnext(scan))))
		{
			Form_pg_ts_config_map cfgmap = (Form_pg_ts_config_map) GETSTRUCT(maptup);

			/*
			 * check if it's one of target token types
			 */
			if (tokens)
			{
				bool		tokmatch = false;

				for (j = 0; j < ntoken; j++)
				{
					if (cfgmap->maptokentype == tokens[j])
					{
						tokmatch = true;
						break;
					}
				}
				if (!tokmatch)
					continue;
			}

			/*
			 * replace dictionary if match
			 */
			if (cfgmap->mapdict == dictOld)
			{
				Datum		repl_val[Natts_pg_ts_config_map];
				bool		repl_null[Natts_pg_ts_config_map];
				bool		repl_repl[Natts_pg_ts_config_map];
				HeapTuple	newtup;

				memset(repl_val, 0, sizeof(repl_val));
				memset(repl_null, false, sizeof(repl_null));
				memset(repl_repl, false, sizeof(repl_repl));

				repl_val[Anum_pg_ts_config_map_mapdict - 1] = ObjectIdGetDatum(dictNew);
				repl_repl[Anum_pg_ts_config_map_mapdict - 1] = true;

				newtup = heap_modify_tuple(maptup,
										   RelationGetDescr(relMap),
										   repl_val, repl_null, repl_repl);
				CatalogTupleUpdate(relMap, &newtup->t_self, newtup);
			}
		}

		systable_endscan(scan);
	}
	else
	{
		/*
		 * Insertion of new entries
		 */
		for (i = 0; i < ntoken; i++)
		{
			for (j = 0; j < ndict; j++)
			{
				Datum		values[Natts_pg_ts_config_map];
				bool		nulls[Natts_pg_ts_config_map];

				memset(nulls, false, sizeof(nulls));
				values[Anum_pg_ts_config_map_mapcfg - 1] = ObjectIdGetDatum(cfgId);
				values[Anum_pg_ts_config_map_maptokentype - 1] = Int32GetDatum(tokens[i]);
				values[Anum_pg_ts_config_map_mapseqno - 1] = Int32GetDatum(j + 1);
				values[Anum_pg_ts_config_map_mapdict - 1] = ObjectIdGetDatum(dictIds[j]);

				tup = heap_form_tuple(relMap->rd_att, values, nulls);
				CatalogTupleInsert(relMap, tup);

				heap_freetuple(tup);
			}
		}
	}

	EventTriggerCollectAlterTSConfig(stmt, cfgId, dictIds, ndict);
}

/*
 * ALTER TEXT SEARCH CONFIGURATION DROP MAPPING
 */
static void
DropConfigurationMapping(AlterTSConfigurationStmt *stmt,
						 HeapTuple tup, Relation relMap)
{
	Form_pg_ts_config tsform;
	Oid			cfgId;
	ScanKeyData skey[2];
	SysScanDesc scan;
	HeapTuple	maptup;
	int			i;
	Oid			prsId;
	int		   *tokens;
	ListCell   *c;

	tsform = (Form_pg_ts_config) GETSTRUCT(tup);
	cfgId = tsform->oid;
	prsId = tsform->cfgparser;

	tokens = getTokenTypes(prsId, stmt->tokentype);

	i = 0;
	foreach(c, stmt->tokentype)
	{
		Value	   *val = (Value *) lfirst(c);
		bool		found = false;

		ScanKeyInit(&skey[0],
					Anum_pg_ts_config_map_mapcfg,
					BTEqualStrategyNumber, F_OIDEQ,
					ObjectIdGetDatum(cfgId));
		ScanKeyInit(&skey[1],
					Anum_pg_ts_config_map_maptokentype,
					BTEqualStrategyNumber, F_INT4EQ,
					Int32GetDatum(tokens[i]));

		scan = systable_beginscan(relMap, TSConfigMapIndexId, true,
								  NULL, 2, skey);

		while (HeapTupleIsValid((maptup = systable_getnext(scan))))
		{
			CatalogTupleDelete(relMap, &maptup->t_self);
			found = true;
		}

		systable_endscan(scan);

		if (!found)
		{
			if (!stmt->missing_ok)
			{
				ereport(ERROR,
						(errcode(ERRCODE_UNDEFINED_OBJECT),
						 errmsg("mapping for token type \"%s\" does not exist",
								strVal(val))));
			}
			else
			{
				ereport(NOTICE,
						(errmsg("mapping for token type \"%s\" does not exist, skipping",
								strVal(val))));
			}
		}

		i++;
	}

	EventTriggerCollectAlterTSConfig(stmt, cfgId, NULL, 0);
}

/*
 * Serialize dictionary options, producing a TEXT datum from a List of DefElem
 *
 * This is used to form the value stored in pg_ts_dict.dictinitoption.
 * For the convenience of pg_dump, the output is formatted exactly as it
 * would need to appear in CREATE TEXT SEARCH DICTIONARY to reproduce the
 * same options.
 *
 * Note that we assume that only the textual representation of an option's
 * value is interesting --- hence, non-string DefElems get forced to strings.
 */
text *
serialize_deflist(List *deflist)
{
	text	   *result;
	StringInfoData buf;
	ListCell   *l;

	initStringInfo(&buf);

	foreach(l, deflist)
	{
		DefElem    *defel = (DefElem *) lfirst(l);
		char	   *val = defGetString(defel);

		appendStringInfo(&buf, "%s = ",
						 quote_identifier(defel->defname));
		/* If backslashes appear, force E syntax to determine their handling */
		if (strchr(val, '\\'))
			appendStringInfoChar(&buf, ESCAPE_STRING_SYNTAX);
		appendStringInfoChar(&buf, '\'');
		while (*val)
		{
			char		ch = *val++;

			if (SQL_STR_DOUBLE(ch, true))
				appendStringInfoChar(&buf, ch);
			appendStringInfoChar(&buf, ch);
		}
		appendStringInfoChar(&buf, '\'');
		if (lnext(l) != NULL)
			appendStringInfoString(&buf, ", ");
	}

	result = cstring_to_text_with_len(buf.data, buf.len);
	pfree(buf.data);
	return result;
}

/*
 * Deserialize dictionary options, reconstructing a List of DefElem from TEXT
 *
 * This is also used for prsheadline options, so for backward compatibility
 * we need to accept a few things serialize_deflist() will never emit:
 * in particular, unquoted and double-quoted values.
 */
List *
deserialize_deflist(Datum txt)
{
	text	   *in = DatumGetTextPP(txt);	/* in case it's toasted */
	List	   *result = NIL;
	int			len = VARSIZE_ANY_EXHDR(in);
	char	   *ptr,
			   *endptr,
			   *workspace,
			   *wsptr = NULL,
			   *startvalue = NULL;
	typedef enum
	{
		CS_WAITKEY,
		CS_INKEY,
		CS_INQKEY,
		CS_WAITEQ,
		CS_WAITVALUE,
		CS_INSQVALUE,
		CS_INDQVALUE,
		CS_INWVALUE
	} ds_state;
	ds_state	state = CS_WAITKEY;

	workspace = (char *) palloc(len + 1);	/* certainly enough room */
	ptr = VARDATA_ANY(in);
	endptr = ptr + len;
	for (; ptr < endptr; ptr++)
	{
		switch (state)
		{
			case CS_WAITKEY:
				if (isspace((unsigned char) *ptr) || *ptr == ',')
					continue;
				if (*ptr == '"')
				{
					wsptr = workspace;
					state = CS_INQKEY;
				}
				else
				{
					wsptr = workspace;
					*wsptr++ = *ptr;
					state = CS_INKEY;
				}
				break;
			case CS_INKEY:
				if (isspace((unsigned char) *ptr))
				{
					*wsptr++ = '\0';
					state = CS_WAITEQ;
				}
				else if (*ptr == '=')
				{
					*wsptr++ = '\0';
					state = CS_WAITVALUE;
				}
				else
				{
					*wsptr++ = *ptr;
				}
				break;
			case CS_INQKEY:
				if (*ptr == '"')
				{
					if (ptr + 1 < endptr && ptr[1] == '"')
					{
						/* copy only one of the two quotes */
						*wsptr++ = *ptr++;
					}
					else
					{
						*wsptr++ = '\0';
						state = CS_WAITEQ;
					}
				}
				else
				{
					*wsptr++ = *ptr;
				}
				break;
			case CS_WAITEQ:
				if (*ptr == '=')
					state = CS_WAITVALUE;
				else if (!isspace((unsigned char) *ptr))
					ereport(ERROR,
							(errcode(ERRCODE_SYNTAX_ERROR),
							 errmsg("invalid parameter list format: \"%s\"",
									text_to_cstring(in))));
				break;
			case CS_WAITVALUE:
				if (*ptr == '\'')
				{
					startvalue = wsptr;
					state = CS_INSQVALUE;
				}
				else if (*ptr == 'E' && ptr + 1 < endptr && ptr[1] == '\'')
				{
					ptr++;
					startvalue = wsptr;
					state = CS_INSQVALUE;
				}
				else if (*ptr == '"')
				{
					startvalue = wsptr;
					state = CS_INDQVALUE;
				}
				else if (!isspace((unsigned char) *ptr))
				{
					startvalue = wsptr;
					*wsptr++ = *ptr;
					state = CS_INWVALUE;
				}
				break;
			case CS_INSQVALUE:
				if (*ptr == '\'')
				{
					if (ptr + 1 < endptr && ptr[1] == '\'')
					{
						/* copy only one of the two quotes */
						*wsptr++ = *ptr++;
					}
					else
					{
						*wsptr++ = '\0';
						result = lappend(result,
										 makeDefElem(pstrdup(workspace),
													 (Node *) makeString(pstrdup(startvalue)), -1));
						state = CS_WAITKEY;
					}
				}
				else if (*ptr == '\\')
				{
					if (ptr + 1 < endptr && ptr[1] == '\\')
					{
						/* copy only one of the two backslashes */
						*wsptr++ = *ptr++;
					}
					else
						*wsptr++ = *ptr;
				}
				else
				{
					*wsptr++ = *ptr;
				}
				break;
			case CS_INDQVALUE:
				if (*ptr == '"')
				{
					if (ptr + 1 < endptr && ptr[1] == '"')
					{
						/* copy only one of the two quotes */
						*wsptr++ = *ptr++;
					}
					else
					{
						*wsptr++ = '\0';
						result = lappend(result,
										 makeDefElem(pstrdup(workspace),
													 (Node *) makeString(pstrdup(startvalue)), -1));
						state = CS_WAITKEY;
					}
				}
				else
				{
					*wsptr++ = *ptr;
				}
				break;
			case CS_INWVALUE:
				if (*ptr == ',' || isspace((unsigned char) *ptr))
				{
					*wsptr++ = '\0';
					result = lappend(result,
									 makeDefElem(pstrdup(workspace),
												 (Node *) makeString(pstrdup(startvalue)), -1));
					state = CS_WAITKEY;
				}
				else
				{
					*wsptr++ = *ptr;
				}
				break;
			default:
				elog(ERROR, "unrecognized deserialize_deflist state: %d",
					 state);
		}
	}

	if (state == CS_INWVALUE)
	{
		*wsptr++ = '\0';
		result = lappend(result,
						 makeDefElem(pstrdup(workspace),
									 (Node *) makeString(pstrdup(startvalue)), -1));
	}
	else if (state != CS_WAITKEY)
		ereport(ERROR,
				(errcode(ERRCODE_SYNTAX_ERROR),
				 errmsg("invalid parameter list format: \"%s\"",
						text_to_cstring(in))));

	pfree(workspace);

	return result;
}

redpajama_set_name: RedPajamaGithub


text:
Argentina beat Dutch to reach World Cup final
Argentina beat the Netherlands 4-2 on penalties to reach the World Cup final after a dire two hours of defence-dominated football failed to provide a semi-final Continue Reading

QU in pact with QF to set up doctorate programmes
Qatar University (QU) and Qatar Foundation Research & Development (QF R&D) yesterday signed an agreement to establish an interdisciplinary PhD pro Continue Reading

Almana Motors rolls out Ramadan offers
Ford customers are in for "affordable treats" as Almana Motors Company, the Ford and Lincoln importer-dealer in Qatar, recently announced it Continue Reading

PM receives, Indian official Anil Wadhwa, Secretary for Eastern countries at the Indian foreign ministry,
HE the Prime Minister and Interior Minister Sheikh Abdullah bin Nasser bin Khalifa al-Thani holding talks with Anil Wadhwa, Secretary for Eastern countries at t Continue Reading

QPI and Shell sign deal on partnership in Brazil
Qatar Petroleum International (QPI) and Shell yesterday signed a memorandum of co-operation in support of their new international upstream partnership in Brazil Continue Reading

Emir hosts Iftar banquet
HH the Emir Sheikh Tamim bin Hamad al-Thani yesterday hosted an Iftar banquet at Al Wajbah Palace for members of the royal family and prominent figures in soc Continue Reading

Qatar Petroleum Celebrates 40th Anniversary
Qatar Petroleum Celebrates 40th Anniversary Continue Reading

Traffic Violations saw a considerable decline in May
Though there was an increasae in cases related to non renewal of driving licenses, overall traffic violations saw a considerable decline in May 2014. There was Continue Reading

Ramadan 2014 to begin Saturday night
Holy Ramadan Fasting 2014 will start on June 29th 2014 in Qatar with reference to the Islamic calendar year 1435 A.H. Qatar's Ministry of Awqaf and Islamic Continue Reading

Best Prepaid local calling offer from Vodafone | Ramadan offer
Vodafone Qatar has announced their "best Prepaid local calling offer ever" for the holy month of Ramadan. With Swalif Ramadan, Vodafone Prepaid customers Continue Reading

redpajama_set_name: RedPajamaCommonCrawl


text:
3 charged with scheming to sell stolen handwritten lyrics to "Hotel California" and other hits by the Eagles
A rock memorabilia dealer and two other men were charged Tuesday with scheming to sell allegedly ill-gotten, handwritten lyrics to the classic rock juggernaut "Hotel California" and other hits by the Eagles.
Prosecutors said the trio lied to auction houses and buyers about the manuscripts' fuzzy chain of origin, coaching the person who provided the material about what to say. Meanwhile, the men tried to thwart Eagles co-founder Don Henley's efforts to reclaim the items, according to prosecutors.
"They made up stories about the origin of the documents and their right to possess them so they could turn a profit," Manhattan District Attorney Alvin Bragg said.
Through their lawyers, rock auctioneer Edward Kosinski and co-defendants Glenn Horowitz and Craig Inciardi pleaded not guilty to conspiracy charges. Kosinski and Inciardi were also charged with criminal possession of stolen property, and Horowitz was charged with attempted criminal possession of stolen property and two counts of hindering prosecution. They were released without bail.
Edward Kosinski, left, departs criminal court after being indicted for conspiracy involving handwritten notes for the Eagles album "Hotel California," Tuesday, July 12, 2022, in New York.
John Minchillo / AP
Their lawyers insist the men are innocent.
"The DA's office alleges criminality where none exists and unfairly tarnishes the reputations of well-respected professionals," defense attorneys Antonia Apps, Jonathan Bach and Stacey Richman said in a statement vowing to "fight these unjustified charges vigorously."
Apps, who represents Kosinski, later called the charges "the weakest criminal case I have seen in my entire career," characterizing it as a "civil dispute" over ownership.
"Despite six years of investigating the case, the DA hasn't included a single factual allegation in the indictment showing that my client did anything wrong," she said in a statement.
The trove of documents included Henley's notes and lyrics for "Hotel California" and two other singles from that eponymous, blockbuster album: "Life in the Fast Lane" and "New Kid In Town." Prosecutors valued the material at over $1 million.
The writings are "irreplaceable pieces of musical history" and "an integral part of the legacy Don Henley has created over the course of his 50-plus-year career," longtime Eagles manager Irving Azoff said in a statement.
He thanked prosecutors for bringing a case that exposes "the truth about music memorabilia sales of highly personal, stolen items hidden behind a facade of legitimacy."
The chart-topping, Grammy-Award-winning single "Hotel California" is a touchstone of 1970s rock, with one of the era's most memorable guitar solos capping a musical tale of being lured into a glitzy, mysterious hotel where "you can check out any time you like, but you can never leave."
Theories about its meaning abound. When asked what the song means during a 2016 interview with CBS News, Henley said, "Well, I always say, it's a journey from innocence to experience. It's not really about California; it's about America."
"It's about the dark underbelly of the American dream," he said. "It's about excess, it's about narcissism. It's about the music business. It's about a lot of different. … It can have a million interpretations."
Eagles members Glenn Frey, left, and Don Henley perform Hotel California at the Hollywood Bowl.
Allen J. Schaben/Los Angeles Times via Getty Images
The Grammy-winning album has sold more than 26 million copies since its release in 1976, making it one of the best selling in history.
According to prosecutors and an indictment, Horowitz bought the documents around 2005 from a writer who worked on a never-published book about the Eagles in the late '70s.
The writer, who isn't identified in the indictment, gave a variety of explanations to Horowitz over the years of where the documents came from.
In one email included in the indictment, the writer says Henley's assistant sent them from the musician's Malibu, California, home after the writer picked them out; in another, the writer found them discarded in a dressing room backstage at an Eagles concert; in another, someone who worked for the band gave them to him.
"It was about 35 years ago and my memory is foggy!" the writer said in a 2012 email.
By then, Kosinski and Inciardi had bought the documents from Horowitz; Kosinski had listed them for sale on his online auction site and inquiries about their origins were looming.
In subsequent emails, Horowitz and Inciardi worked to have the writer's "'explanation' shaped into a communication" – eventually, an April 2012 email saying that he didn't remember who gave him the documents. Kosinski sent it to Henley's lawyer, according to the indictment.
Later that month, Kosinski sold some "Hotel California" lyric sheets to Henley for $8,500, according to the indictment.
Inciardi and Kosinski then tried to peddle more of the Eagles documents to other potential buyers through Christie's and Sotheby's auction houses, while also offering to sell some to Henley, according to the indictment.
By 2017, with not only Henley's lawyers but the district attorney's office asking questions, Horowitz asked the writer whether he'd gotten the materials from another founding Eagles member, Glenn Frey, the indictment said. Frey had died the year before.
"Once you identify GF as the source of the tablet, you and I are out of this picture for good," Horowitz wrote in a follow-up email.
The writer then provided a note to that effect, according to the indictment.
InNew York
Previous post TikTok Launches Follow Me for Small Business Users
Next post New WHO Global Evidence Review on Health and Migration underscores how the implementation of inclusive immunization plans is critical for Member States to achieve universal health coverage
Vir Das on comedy and controversy
Vir Das on comedy and controversy - CBS News Watch CBS News Comedian Vir Das is known for his sharp...
MOMOLAND members leave MLD Entertainment after 7 years
[Source]K-pop girl group MOMOLAND are calling it quits with longtime label MLD Entertainment after seven years. In a press statement...
Brianne Howey on starring in Netflix series "Ginny & Georgia"
Brianne Howey on starring in Netflix series "Ginny & Georgia" - CBS News Watch CBS News Actor Brianne Howey stars...
MSG Entertainment faces probe over use of facial recognition technology
The New York attorney-general is probing allegations that the owners of Manhattan's Madison Square Garden arena used facial recognition technology...
Nominations announced for the 95th annual Academy Awards
Nominations announced for the 95th annual Academy Awards - CBS News Watch CBS News This year's Academy Awards nominations have...
'The Bachelor': Baton Rouge's Vanessa Dinh competing | Entertainment/Life
Louisiana fans of "The Bachelor" have someone to root for in the ABC reality series' 27th season — Vanessa Dinh.The Baton Rouge...
Previous post:TikTok Launches Follow Me for Small Business Users
Next post:New WHO Global Evidence Review on Health and Migration underscores how the implementation of inclusive immunization plans is critical for Member States to achieve universal health coverage


text:
RENKEI Summer School 2014 in Sendai, Japan
Experiences from the first part of the programme, the Summer School in Sendai, Japan.
Representing the University of Southampton at the RENKEI 2014 summer school were Professor Bahaj (Head, Energy and Climate Change Division), Leo Bourikas and Phil Wu. The summer school took place at the Tohoku University in Sendai, Japan. The theme of the summer school was "Energy Supply within Traditional and Environmentally Conscious Growth models".
Sendai is the largest city in the Tohoku region (population of ~1,000,000 people) and home of the Tohoku University who hosted the event. Sendai was one of the cities closest to the centre of the earthquake activity and the region that suffered together with Fukushima Prefecture the largest damage from the tsunami.
RENKEI is an initiative of the British Council Japan. The role of RENKEI is to offer a common platform for twelve prestigious Japanese and UK universities to come together along with representatives of industry in order to develop collaborations and exchange knowledge in the fields of technology, science and universities' social engagement. The objectives of RENKEI are to support the development of large networks in education and industry and to initiate activities that will produce advantages for the global society.
[portfolio_slideshow id=3965]
Several distinguished lecturers took part into the summer school initiating the discussions on a variety of topics related to energy supply, sustainability and climate change.
• Prof. Bahaj was the first to talk on economic growth and resource efficiency. In his talk he identified cities as the key driver for sustainability and growth. At the same time he analysed the constraints opposed by a "global consumer society" lifestyle.
• Prof, Nakata (Tohoku) laid down the characteristics for community energy systems. He introduced the "Glocal scale" (Global and local) as the scale for highly efficient, local specific energy generation and distribution systems.
• Mr. Suzuki from the Fukushima Prefectural Government shared with us the view and the plans of local government to set make Fukushima as a global example of renewable energy generation. Their plans include a very large increase into solar PV and wind energy capacity that on top of biomass and hydro will cover the 100% of Fukushima's primary energy demand by 2040.
• Mr. Tsuruoka from the( Higashimatsushima City Reconstruction Plan) offered another perspective on the discussions with the presentation of the tsunami-afflicted areas and the everyday problems the people face even 3 years after the devastation. It is to admire the courage the communities have showed and the collaborative efforts made to accomplish the massive reconstruction plans.
• Several other speakers gave lectures on subjects as diverse as passive energy design of buildings; smart grid integration of photovoltaics; climate impacts on agriculture yields and farming; environmental economics and effects of user behaviour on energy demand.
Field trips covered aspects ranging from history and social issues to scientific and technological knowledge exchange, including:
• Miyagi Province Toyota factory: after the earthquake critical infrastructure at the nearby settlements stayed without electricity for days. The Toyota factory decided to install a Combined Heat and Power (CHP) engine to cover its own needs in electricity but also give electricity to the nearby City Hall and the Evacuation shelters when the grid fails to. The waste heat is used in an innovative project of combined agricultural production at greenhouses on site.
• The tsunami afflicted region near Sendai. There are only a couple buildings left to remind people of the tragedy. It is shocking how much force the water had and the disaster it caused where it hit the coastline.The restoration plans include elevated roads, tree planting and moving residential settlements are further inland leaving the coastline to industrial and agricultural use. Large PV parks have been installed where debris and ruined land was before and massive amounts of earth are crushed and moved with belts and trucks from nearby hills to the seashore. The scale of the works is tremendous.
Return to the Homepage of RENKEI Southampton Spring School


Sept. 14, 2010 | LITTLE ROCK – Get a jump on Halloween by attending the Eighth Annual Tiny Hands Monster Bash, a fundraiser benefiting the University of Arkansas for Medical Sciences (UAMS) Family Home and the UAMS Medical Center neonatal intensive care unit. The event is scheduled for 7-11:30 p.m. Oct. 16 at Next Level Events at the Train Station.
Guests are invited to come in costume if they choose and enjoy cocktails, a silent and live auction, hors d'oeuvres and dancing. Music will be provided by The Rockets. Tickets are $50 and may be purchased online at www.uamsfamilyhome.org or by calling (501) 920-2328.
"Since becoming involved with the UAMS Family Home, I am able to see first hand the vital role this facility plays in the lives of these patients and their families," said this year's event chairman Lee Fleming, M.D.


Iceland is gearing up to become the first country to do away with fossil fuels completely. The Iceland government pledges to change over to hydrogen-based fuels and has already made the initial moves in the direction.
The country has set up a joint venture company called the 'Icelandic New Energy Limited'. The owners of the company are VistOrka, an Icelandic holding company owned by group of public and private enterprises and institutions that are enthusiastic about the development of hydrogen-based fuels in Iceland or new industrial projects. The foreign owners include multinationals DaimlerChrysler, Shell Hydrogen and Norsk Hydro.
The estimated amount of hydrogen that the transport and vessel sector in Iceland would require is 80 to 90 thousand tonnes of hydrogen. To produce that amount of hydrogen will require only about 8 to 10 per cent of the economically usable renewable energy in Iceland.
Iceland has a chance of becoming a carbon-dioxide free economic system because the electricity to make hydrogen from electrolysis of water will come from hydro or geothermal power and not fossil fuels.
What type of fuel will be used has not been fully decided by the industry, but what ever type of 'hydrogen-based fuel' that will be the future choice for powering the transport sector, the fuel cell itself will help in changing from conventional fossil fuels to hydrogen based fuels.


text:
Teaching Plate Tectonics
Astronomy, Satellite, Space
Geologic Hazards
General Geology
Geology Articles
Also known as calcrete, hardpan, and duricrust
Caliche: This specimen of caliche is composed of rounded rock fragments and fine-grained sediments, bound together with a calcium carbonate cement.
What Is Caliche?
"Caliche" is a shallow layer of soil or sediment in which the particles have been cemented together by the precipitation of mineral matter in their interstitial spaces. The cement is usually calcium carbonate; however, cements of magnesium carbonate, gypsum, silica, iron oxide, and a combination of these materials are known.
Caliche Horizon: A caliche over one meter thick with mineralization that is heaviest at the top and decreases downwards. USGS photo of an outcrop in Mohave County, Arizona.
Caliche is a common feature of arid or semiarid areas throughout the world. In the United States, caliche is a familiar deposit in many parts of the Southwest, especially in Arizona, California, Nevada, New Mexico, and Texas. There, caliche is associated with problems such as poor soil drainage, difficult soil conditions for plant growth, and excavation problems at construction sites. In some locations there are multiple ancient caliche layers in the subsurface.
The name "caliche" originates from a Spanish word for porous materials that have been cemented by calcium carbonate. The name is used to refer to a piece of the material or the layer from which it was broken, or the cement itself that binds the materials together. Caliche is known by many other names, the more common of which are calcrete, hardpan, duricrust, and calcic soil.
"Caliche Conglomerate": A conglomerate-like boulder consisting of caliche-cemented gravels. USGS photo taken in the Providence Mountains area, San Bernardino County, California.
What Does Caliche Look Like?
Typical caliche colors are white, gray, brown and reddish-brown. Well-developed caliche can have an appearance that resembles conglomerate, breccia, coquina, or sandstone if the cemented particles are of the proper type and size. Caliche can be a very hard, dense, heavy, and durable material if it is firmly bound by a cement that completely fills the interstitial voids between the soil or sediment particles. It can also be a weak and friable material if it is poorly cemented.
In excavations and outcrops, a well-developed caliche usually stands out as a competent, well-cemented sediment or soil with loose friable material below. Sometimes it is overlain by uncemented surface material. Plant roots might not penetrate a well-developed caliche.
"Caliche Terraces": Caliche-cemented gravels form the flat, resistant, horizontal "cap rocks" on the Pleistocene terraces on the banks of the modern dry wash that crosses the area shown in this photo. The mountains in the distance are composed mainly of Paleozoic limestones and dolomites. Weathering of these rocks provided much of the calcium carbonate that enabled caliche formation in the valley.
How Does Caliche Form?
Caliche has a diversity of origins. The major process of forming caliche begins when calcium carbonate is leached from upper soil horizons by downward-percolating solutions. Dissolved calcium carbonate might also be delivered to the site in runoff and then percolate into the soil. The calcium carbonate then precipitates in a deeper soil horizon to form the caliche layer.
At first the calcium carbonate precipitates as small grains or thin coatings on sediment grains or soil particles. As the grain coatings thicken, adjacent grains will be cemented together, and nodules consisting of multiple grains and their surrounding cement will form. As cementing continues, a continuous subsurface layer might form.
In an advanced stage, a solid caliche layer can develop. These can become so dense and impermeable that they can resist the downward percolation of water and erosion by wind or water. The caliche layer generally has a higher density at the top and decreases downward. Advanced caliche formation can produce a layer that is over one meter thick and have a lateral extent of hundreds of square kilometers or more.
Some caliche forms by the upward movement of water through capillary action. As the water evaporates, dissolved materials precipitate, and, over time, can cement the soil or sediment.
Caliche can also form beneath vegetation that extracts water from the ground and transpires it into the atmosphere. As large amounts of water are removed by the plants, mineral materials that the plants do not remove become concentrated in the subsurface waters. When the concentration becomes high enough, or evaporation occurs, precipitation begins and can form caliche over time.
Caliche Outcrop: A caliche outcrop near Sulfur Springs Draw, Texas. This Pleistocene/Pliocene deposit hosts uranium-vanadate minerals. USGS photo by Susan Hall. Enlarge image.
Caliche Problems and Uses
The presence of caliche in a soil or sediment has many practical implications. These might include:
Caliche can be a barrier to the downward infiltration of water.
Caliche can be a barrier to erosion by wind or water. When it is breached, downward erosion can be rapid, channeled and severe.
Caliche can be extremely durable and present problems at construction sites.
Gems and Metallic Ores in Caliche: Caliche can be a host rock for a variety of secondary minerals, including metallic ores and gem materials. Shown in the photo above are yellow oxides of uranium found near the Sulphur Springs Draw uranium deposit, Martin County, west Texas. Photograph by the United States Geological Survey.
Caliche layers in terraced sediments can strongly influence topography.
Caliche layers in aquifers can result in the stratified flow of groundwater.
Caliche development can incorporate gold, gemstones, and other valuable minerals.
Caliche porosity can serve as the deposition site of valuable secondary minerals, including ores of uranium and vanadium, and gem materials such as turquoise and malachite.
Caliche deposits are sometimes correlated and used as relative age and stratigraphic markers.
Caliche development indicates a time interval of tectonic, sedimentary, erosional and hydrologic stability.
Caliche is often a challenge to agriculture. It interferes with proper soil drainage, the formation of plant roots, and it also can contain soluble minerals that are not beneficial to the plants.
Caliche is sometimes crushed and used as fill, aggregate, or as a raw material for making portland cement. It is usually used when higher grade materials are not available or when minimal quality material is sufficient.
The Many Uses of Marble
Plate Tectonics Map - Plate Boundary Map
Turkey Map and Satellite Image
Satellite Image of Rhode Island
Singapore Map and Satellite Image
The World of Fluorescent Minerals
World Map - Political
You Can Find Gold With a Metal Detector
Lebanon Map and Satellite Image
Copyright 2021 \ Geology and Earth Sciences news, articles, photos, maps, and more \ Caliche


text:
Herpes virus 'likely' main cause of multiple sclerosis, study finds
Joe Pinkstone
January 13, 2022, 2:01 PM ·3 min read
The Epstein-Barr virus (EBV) - one of the most common viruses in the world - increases the chance of multiple sclerosis 32-fold
The virus that causes herpes is likely the main cause of multiple sclerosis (MS), a groundbreaking study has suggested.
Harvard academics found that the Epstein-Barr virus (EBV) - one of the most common viruses in the world - increases the chance of multiple sclerosis 32-fold.
Scientists have long speculated that the virus may be linked to the condition, but have been unable to provide any evidence to back this up.
"This is the first study providing compelling evidence of causality," said Alberto Ascherio, professor of epidemiology and nutrition at Harvard Chan School and senior author of the study.
"This is a big step because it suggests that most MS cases could be prevented by stopping EBV infection, and that targeting EBV could lead to the discovery of a cure for MS."
There is currently no cure for multiple sclerosis (MS), which is a condition that affects around 110,000 people in the UK.
Unpredictable symptoms
The National Multiple Sclerosis Society says the risk of developing MS in the general population is around one in 1,000.
MS is a chronic inflammatory disease of the central nervous system that attacks the myelin sheaths protecting neurons in the brain and spinal cord, and its cause remains elusive.
The symptoms are unpredictable and can range from physical disabilities like mobility problems to mental health conditions, such as depression.
Many people with MS report feeling an overwhelming sense of exhaustion, making simple tasks a struggle. In around a quarter of cases, the first noticeable symptom is a problem with one of the patient's eyes, including colour blindness and double vision.
In contrast, Epstein-Barr Virus infection is astoundingly common, and can be found in around 95 per cent of people.
EBV infection can leave people feeling tired and sore, and is also known as mono or herpes. After a person contracts the pathogen, it remains in their system forever, often without any symptoms but occasionally reactivating.
Prof Daniel Davis, professor of immunology at the University of Manchester, who was not involved with the research, said: "Well over 9 in 10 people are infected with this virus worldwide, usually in childhood, and only very rarely does a problem arise.
"We already knew that this virus increases the risk of some cancer types, and now we know that it is also possibly a factor in multiple sclerosis, although it's important to note for most people that have the virus, it will not cause them any problems.
"Crucially, we do not know why only a small fraction of people infected with this virus develop a problem."
He added that other factors will be at play, such as genetics, and a cure may only be found once these have been identified.
The US-based researchers studied the medical records of more than ten million people enlisted in the US military, of which 955 developed multiple sclerosis during their period of service.
Blood samples taken twice a year by the military were analysed by the researchers to determine if the person had the virus, and this was cross-referenced against a later MS diagnosis, which normally only begins to manifest ten years after the identification of EBV.
The risk of a person was found to be 32 times greater in people who tested positive for the herpes virus than in the minority of people who do not have EBV.
A protein and biomarker for nerve degeneration called NfL only increased in those who had been infected with the virus, the researchers write in their study, published in the journal Science.
Their findings cannot be explained by any other known risk factors for MS and suggest EBV may therefore be the leading cause.
Professor Ascherio said: "Currently there is no way to effectively prevent or treat EBV infection, but an EBV vaccine or targeting the virus with EBV-specific antiviral drugs could ultimately prevent or cure MS."
Reasons Doctors Prescribe Marijuana Most
There's been plenty of evidence that finds using marijuana for certain medicinal purposes is highly beneficial. It's proven to be helpful for patients who experience seizures, have autism, severe nausea or vomiting caused by cancer treatment, Alzheimer's disease, Amyotrophic lateral sclerosis (ALS), HIV/AIDS, Crohn's disease, epilepsy and seizures, glaucoma, multiple sclerosis and muscle spasms, among other medical conditions. In addition, doctors are suggesting marijuana for other reasons and
Yahoo Canada Style
This early warning sign of dementia is often overlooked, according to a new study
Forgetfulness or something more? Here's what to do if you suspect your loved one has dementia.
What to know about isolation, masking and more if you're still testing positive late into a COVID-19 infection.
If I'd Listened To My Doctor, I Would Be Dead Right Now
"The doctor told me there was no rush, even though the radiology report stated my tumor was 'of concern.' In fact, she was going on vacation for two weeks and her schedule was full."
Chris Evert's ovarian cancer diagnosis: What to know about prevention
Tennis legend Chris Evert recently revealed that she is battling stage 1C ovarian cancer. The 67-year-old tennis legend who has won 18 Grand Slam singles titles and three Grand Slam doubles titles during her career, opened up about her diagnosis on Twitter and in an ESPN report that she co-wrote with her colleague, Chris McKendry.
Do you need an 'armpit detox?' Myths about aluminum and deodorant, explained
One of the recent trends that caught my eye is the "armpit detox" with people looking to move from traditional antiperspirant to "natural deodorant."
USA TODAY Opinion
My triple-vaxxed, 85-year-old mother caught COVID. Medical triage made her doctor useless.
Treatment for COVID-19 is the Wild West. Prescription for Paxlovid? Forget about it. Monoclonal antibody infusion? If you are lucky.
Woman loses more than 100 pounds following 'lazy keto' diet
Nearly two years ago, Megan Faraday, a now 25-year-old woman from Ontario, Canada, decided she was ready to make a change to her health. Faraday has since lost more than 100 pounds following "lazy keto," a version of the popular ketogenic, or keto, diet, known for its focus on foods high in fat and low in carbohydrates. For Faraday, following a "lazy keto" diet meant skipping counting every macronutrient, like proteins and fats, she was eating and focusing solely instead on the amount of carbohydrates, or carbs, she was eating every day.
Scientists believe the country has "reached a turning point in this pandemic," and their experience, along with similar pictures emerging in the U.K. and New York, is cause for optimism.
COVID Patient Flown to Texas After Minnesota Doctors Decided to Pull Plug on Ventilator
Photo Illustration by The Daily Beast/HandoutA Minnesota woman whose husband neared death from COVID appealed to the courts to force his hospital to halt their plans to pull the plug on the man's ventilator.Scott Quiner, 55, a reportedly unvaccinated man who had been battling COVID in Mercy Hospital's ICU in Coon Rapids since November, was set to have his ventilator shut off on Jan. 13, according to a petition filed in court one day before the deadline by his wife, Anne Quiner.Quiner said the de
Biden administration to provide hundreds of millions of free N95 masks
The Biden administration will be distributing hundreds of millions of free N95 masks from the Strategic National Stockpile, a White House official confirmed Wednesday.
Americans Can Now Get Free Rapid COVID Tests Sent Directly to Their Homes — Here's How
Every home in the US now has access to four free rapid COVID-19 tests through a new, federally-run website
A California woman said she would "definitely eat sushi again" even after suffering from a severe stomachache the day after binge-eating 32 all-you-can-eat sushi rolls, among other dishes. Danielle Shapiro, 24, shared what happened in a TikTok on Dec. 23, 2021 which she titled "All you can eat sushi gone wrong," according to the New York Post. Shapiro went to Sushi 85, a buffet restaurant in Mountain View, California, in December 2021, when her friend Amanda was visiting from out of town, LADbible reported.
Jenna Jameson misdiagnosed with rare autoimmune disease: What is Guillain-Barré Syndrome?
Jenna Jameson's husband revealed to fans the star was misdiagnosed with a are autoimmune disorder.
Pakistan says trial of Chinese traditional medicine for COVID-19 successful
Pakistani health authorities on Monday announced the completion of a successful clinical trial of Chinese traditional herbal medicine for treating COVID-19, as the South Asian nation enters a fifth wave of the pandemic driven by the Omicron variant. The Chinese medicine, Jinhua Qinggan Granules (JHQG) manufactured by Juxiechang (Beijing) pharmaceutical Co Ltd, is already being used in treatment of COVID-19 patients in China. "Since it was tried on patients with different variants of COVID-19, we expect it to be effective on Omicron as on other variants," Professor Iqbal Chaudhry, director of the International Center for Chemical and Biological Science (ICCBS) where trials were conducted, told reporters.
Kaiser says thousands in San Francisco area may have received low dose of COVID-19 vaccine
Kaiser Permanente says thousands in the San Francisco area may have received a low dose of the COVID-19 vaccine.The company said around 3,900 people who visited Kaiser Permanente Walnut Creek Medical Center on both Oct. 25 and Dec. 10 may have received 0.01 ml to 0.04 ml less than the recommended dose of 0.30 ml, a discrepancy it said is "not considered significant.""We took immediate steps to confirm that the issue was isolated and promptly...
This New Tool Predicts COVID Survival From a Blood Sample
Frederic J. Brown/AFP via Getty ImagesAs the Omicron variant rages across the U.S. and the rest of the globe, we're seeing hospitals everywhere maxing out their capacity to treat critically ill COVID-19 patients—not all of whom have an obvious risk factor. In the ICU, it's often difficult to determine who might survive and beat the infection, and who might end up succumbing to the disease.That could change very soon thanks to a new AI tool that can predict the survival outcome of severe cases of
Data: Our World in Data; Chart: Baidi Wang/AxiosThe Omicron wave is likely beginning to recede in the U.S., experts say.Why it matters: Omicron is still wreaking havoc in parts of the country, but infectious disease experts are optimistic that relief is around the corner.Stay on top of the latest market trends and economic insights with Axios Markets. Subscribe for freeDetails: In South Africa and in the U.K., which experienced their Omicron waves before the U.S., cases spiked dramatically and t
They relied on rapid coronavirus tests to gather safely. Some wish they hadn't.
Rona MacInnes, 54, was determined to do everything possible to protect her elderly mother as her family prepared to gather for Christmas in Pennington, N.J. With her son returning from study in Dublin, MacInnes hoped serial at-home coronavirus tests would catch a coronavirus infection he might bring home. The college junior would take six rapid tests before the holiday, all of which returned negative results. But it would become clear only later - after he had spent time with his grandmother - t
Scientists may have discovered what causes a mysterious space phenomenon
Covid variants: How many strains are in circulation and causing concern around the world?
How Ghislaine Maxwell met Jeffrey Epstein
Study on 4th dose of COVID-19 vaccine shows effectiveness
This New Study Suggests Pfizer, BioNTech Are Losing The Omicron Battle
Who is Virginia Giuffre and what are her allegations against Prince Andrew?
Boston's Long Wharf pounded by rough surf, high tide
Security guard tackles armed man trying to rob game room
Danger still looms for Fayetteville area after Sunday's storm
The Fayetteville Observer


Established in 1898 with the completion of The Principal London (formerly The Hotel Russell), Principal is a collection of city-centre hotels based in landmark buildings in exceptional locations across the UK. Their distinctive heritage and the relationships that they have with the neighbourhoods and cities in which they are located are the cornerstones of the Principal brand – from the elegant Georgian townhouses that form the core of The Principal Edinburgh (formerly The George Hotel) to the clock tower that's synonymous with The Principal Manchester (formerly The Palace Hotel), and its history as the headquarters for The Refuge Assurance Company. Each of the hotels has a story to tell – of its history, its design and architecture, its quirks and characters, and its role in shaping the city and forging relationships with local partners, whether corporate or creative.
Over the course of 2018, the brand will grow to include Blythswood Square and The Grand Central Hotel in Glasgow; St David's Hotel in Cardiff; The Hotel Russell in London and The Roxburghe in Edinburgh. Along with the conversion of the former Martins Bank in Liverpool, The Grand on Colmore Row in Birmingham as well as The Met in Leeds.
A particular feature of the group is the creation of destination bars and restaurants in partnership with leading chefs and restaurateurs: Colin Fleming (ex. Tom Kitchin and Martin Wishart) oversees The Printing Press Bar & Kitchen at The Principal Edinburgh. In York, The Refectory Kitchen & Terrace and Chapter House bar were conceived in partnership with Des McDonald (The Ivy, Scott's Holborn Dining Room); and in Manchester, The Refuge Dining Room and Public Bar has been created in partnership with the team from Volta, Manchester Restaurant of the Year 2015.
Other touch points include vintage letterboxes in each lobby; a 'corner shop' selling treats to stock the mini bar as well as essentials that guests might have left behind; a tuck box of complimentary snacks, plus fresh milk and mineral water in the mini bar; and a fully fledged Concierge to guide guests to hidden gems and must-see shows alike.
Check out the Principal hotel website to find out more about their roles and how to apply for opportunities.
"Our industry provides people with the unique opportunity to grow and nurture their careers with no glass ceiling based on academic or social background. The majority of great leaders have worked their way up through the business whether they were initially waiters, kitchen porters or a receptionist. It is the most rewarding career out there!"


text:
Kelly/Flickr/CC (Image has been cropped)
CEOs Come and Go, but Their Scandals Live on
By Adam Brinegar
Companies affected by a scandal at the top of the corporate pyramid can't undo the damage to its reputation simply by firing the offending CEO. A new analysis shows that it can take years to regain investors' confidence, Jeff Green explains at Bloomberg:
The fallout from a lying, cheating, embezzling or offensive CEO can linger to soil the reputation of a company by an average of five years after an incident has passed, according to a Stanford University analysis, being released this week, that studied 38 examples of bosses behaving badly from 2000 to 2015. …
The offenses reviewed in the Stanford study, which included 13 examples of lying, eight sexual affairs and six incidences of questionable finances, resulted in an average of 258 news articles that spanned 4.9 years, the study found. Six of the CEOs expressed objectionable language or behavior, and five others aired controversial views in public.
Share prices declined an average of 3.1 percent as well, according to the study. The analysis noted that Hewlett Packard Co. stock dropped almost 9 percent in the three-day period following reports in 2010 that CEO Mark Hurd had a personal relationship with a female contractor.
This is an interesting perspective. In some of our previous work on employee engagement, we looked at the impact of scandals and found a strong initial dip of engagement as the scandal rages (12 percent on average) and then a relatively quick boost back to normal levels of engagement in about 21 months. So they do have a long tail, but employees seem to quit punishing the company for them a little faster than investors do, if the Stanford analysis is correct.
Management // CEOs • Employee Engagement • Scandals


County Clerk of Los Angeles County on 03/27/2015.
SOUTHERN AVE. #B, SOUTH GATE, CA 90280.
MARIA HERNANDEZ, 4978 SOUTHERN AVE.
KIMLIM BEAUTY SALON NAIL & SPA, 2950 E.
County Clerk of Los Angeles County on 03/30/2015.
of registrant(s) is (are) CRYSTAL LAMB, 727 W.
by: AN INDIVIDUAL. Signed; CRYSTAL LAMB.
L.A., CA 90063, ELIZABETH MUNOZ, 935 N.
County Clerk of Los Angeles County on 04/01/2015.
BLVD. STE 200, REDONDO BEACH, CA 90278.
HENG CHUM, 1290 S. LA BREA, L.A., CA 90019.
INDIVIDUAL. Signed; J. CRUZ MARIN-PULIDO.
WAGNER, 432 S. MAIN ST. #9, L.A., CA 90013.
N. ATLANTIC BLVD. #F, ALHAMBRA, CA 91801.
of registrant(s) is (are) OSCAR LOPEZ, 902 S.
VALINDA AVE., WEST COVINA, CA 91790.
BRIARGATE LANE, GLENDORA, CA 91724.
name of registrant(s) is (are) ZULEYMA G.
County Clerk of Los Angeles County on 04/02/2015.
JOHNNY JEN KUO, 1218 TEMPLE CITY BLVD.
by: AN INDIVIDUAL. Signed; JOHNNY JEN KUO.
800 W. CARSON ST. #35, TORRANCE, CA 90502.
as: SHOE CLICK US, 17360 COLIMA RD.
COLIMA RD. #771, ROWLAND HTS., CA 91748.
12120 NASHVILLE AVE., LA MIRADA, CA 90638.
County Clerk of Los Angeles County on 03/31/2015.
13645 CAMILLA ST., WHITTIER, CA 90601.
is (are) THE CRACK OF DAWN, LLC, 418 N.
PACIFIC AVE. #D, LONG BEACH, CA 90813.
1021 PACIFIC AVE. #D, LONG BEACH, CA 90813.
INVESTMENT CORP., 19811 E. COLIMA RD.
INDIVIDUAL. Signed; RAGANA JUNE LYONS.
INDIVIDUAL. Signed; RENE VASQUEZ GARCIA.
Angeles. The original file number of 2012204489.
County Clerk of Los Angeles County on 03/20/2015.
is (are) VIOLETA J. CUEVAS ROMERO, 226 N.
VISTA BONITA AVE., GLENDORA, CA 91741.
as: A MASSAGE, 5615 E. WHITTIER BLVD.
registrant(s) is (are) ESTHER ZAPATA, 10423 S.
451 W. LAMBERT RD. STE 208, BREA, CA 92821.
N. STONEMAN AVE., ALHAMBRA, CA 91801.
(are) MARIA ELENA RAMOSVELASCO, 4061 S.
JANET CABRERA, 15361 GUNDRY AVE.
County Clerk of Los Angeles County on 03/25/2015.
County Clerk of Los Angeles County on 03/23/2015.
REALTY GROUP, 1750 E. OCEAN BLVD.
9550 LEMORAN AVE., DOWNEY, CA 90240.
ELLIOTT AVE. SP. 476, EL MONTE, CA 91732.
Full name of registrant(s) is (are) JUAN M.
AN INDIVIDUAL. Signed; JUAN M. MERLOS.
as: FRIDA CUTTING SERVICE, 1700 S.


text:
Merlin's Musings
All Flavors of Entertainment
Masters of Storytelling
Tuesday Review
Anime and Cartoons
Challenge Index
15-Day Doctor Who Challenge
30-Day Anime Challenge
30-Day Anime Pick 5 Challenge
30-Day Zelda Challenge
Blogging Awards
This Week on TV
Weekly Lineup
Sunday's Wisdom
Index of Wisdom
Muse-ings
Shared Music Videos
A Question For You
Cineversity
My Fan Theories
Indexed Reviews
TV Index
← Anime Review: Dream Eater Merry
MCU Copycatting: The Arrowverse →
A "Gifted" Introduction
Posted on October 10, 2017	by Merlin
I watched the first episode, and my immediate reaction was, "Oh, I'm definitely adding this one to my weekly lineup!." 🙂
Following in the wake of Legion earlier this year, The Gifted is Fox's latest contribution to the X-Men franchise, in partnership with Marvel. Officially, it's connected to the film series but set in an alternate timeline where the X-Men have disappeared, along with their archenemies the Brotherhood. Functionally, it's just like the movies, a cinematic universe in name only. Personally, I figure I'll just enjoy it as its own independent story.
In the wake of whatever happened to the X-Men, things have not gotten better for mutants. Outcast, hated, and hunted like terrorists, life as a mutant is rather terrifying right now, especially in the United States, where public fear has given the government license to do whatever they like. There is a movement, a loose connection of mutants referred to as "the Underground," which helps mutants in trouble get to safety in other countries, but without either the respect garnered by the X-Men or the fear created by the Brotherhood, it's especially dangerous to be different right now.
Enter the Strucker family, no confirmed relation to any other Struckers in Marvel.
Reed is a district attorney, and apparently one who specializes in mutant-related cases. He's been working to build a case against the Underground, for the good of public safety, and thus the safety of his family. While he sees something wrong with how things are, he's trying to make the best of a bad situation. His wife Caitlin struggles just to balance her work as a nurse with her personal life with Reed and their two children. She's less dominant than Reed, but make no mistake, she does love him and she will protect her children.
Speaking of, Lauren and Andy are two fairly normal teenagers, going through fairly normal things, including school dances and struggling with bullies. When the latter goes very wrong in close proximity to the former, it's revealed that they are mutants, powerful ones (and original characters created just for this show), and they're assigned all the blame for what happened. If that's not bad enough, it's not the regular police who show up for them, but Sentinel Services (ah-hah, "SS," I see what you did there), and that is what tips Reed over from trying to safeguard his family through the law, to trying to protect them from the "law."
Fortunately, Reed has an ace up his sleeve. He pulls some strings to get in touch with the Underground, and he offers a straight-up exchange of services. If they help his family escape to Mexico, then he will help them rescue their most recently-captured member, Polaris. It's even more compelling because she is pregnant, and the man he speaks with is the father.
So, whether they like each other or not, the Struckers and the Underground are quickly wrapped up in the same mess together, because two men are simply fighting to save their families.
That's a pretty powerful setup, I have to say. A climate of fear, statism run rampant, people with abilities blamed for things they are not responsible for and made to disappear, the awful nature of bullying, and the importance of family, all of that is wrapped up within the first episode alone. Not a bad introduction!
I can't wait to see where this goes!
Between the action, the drama, the social commentary, the characters, and everything else, The Gifted has definitely earned a place in my lineup. If they keep going like this, it could prove an impressive show in its own right.
Rating: for now, I give it 9 stars out of 10.
Grade: A.
This entry was posted in This Week on TV, Tuesday Review, TV Shows and tagged The Gifted, X-Men. Bookmark the permalink.
Follow Merlin's Musings on WordPress.com
My Anime Justice League
5 Anime Voice Actors
5 Comedy/Gag Anime
Why I Still Love Anime: A Handful of Reasons
5 Anime "Ships"
My Anime Harem
Let Them Be Anime-ted: The Make it Anime Tag
How Excited Am I for Infinity War?
Movie Review: Ant-Man and the Wasp
That Time I Realized Slimes Can Be Protagonists