Esempio n. 1
0
/* Similar mechanism as in parse_oper.ci, in particular
 * in the static function oper_select_candidate */
Oid find_equality_operator(Oid ltypeId, Oid rtypeId)
{
  List * const equals=list_make1(makeString("="));

  FuncCandidateList clist;
  Oid inputOids[2] = {ltypeId,rtypeId};
  int ncandidates;
  
  Oid result = binary_oper_exact(equals, ltypeId, rtypeId);

  if(result!=InvalidOid)
    return result;

  clist = OpernameGetCandidates(equals, 'b', false);

  ncandidates = func_match_argtypes(2, inputOids,
      clist, &clist);

  if (ncandidates == 0)
    return InvalidOid;
  else if (ncandidates == 1)
    return clist->oid;
  
  clist = func_select_candidate(2, inputOids, clist);

  if(clist)
    return clist->oid;
  else
    return InvalidOid;
}
Esempio n. 2
0
/* left_oper() -- search for a unary left operator (prefix operator)
 * Given operator name and type of arg, return oper struct.
 *
 * IMPORTANT: the returned operator (if any) is only promised to be
 * coercion-compatible with the input datatype.  Do not use this if
 * you need an exact- or binary-compatible match.
 *
 * If no matching operator found, return NULL if noError is true,
 * raise an error if it is false.  pstate and location are used only to report
 * the error position; pass NULL/-1 if not available.
 *
 * NOTE: on success, the returned object is a syscache entry.  The caller
 * must ReleaseSysCache() the entry when done with it.
 */
Operator
left_oper(ParseState *pstate, List *op, Oid arg, bool noError, int location)
{
	Oid			operOid;
	FuncDetailCode fdresult = FUNCDETAIL_NOTFOUND;
	HeapTuple	tup = NULL;

	/*
	 * First try for an "exact" match.
	 */
	operOid = OpernameGetOprid(op, InvalidOid, arg);
	if (!OidIsValid(operOid))
	{
		/*
		 * Otherwise, search for the most suitable candidate.
		 */
		FuncCandidateList clist;

		/* Get prefix operators of given name */
		clist = OpernameGetCandidates(op, 'l');

		/* No operators found? Then fail... */
		if (clist != NULL)
		{
			/*
			 * The returned list has args in the form (0, oprright). Move the
			 * useful data into args[0] to keep oper_select_candidate simple.
			 * XXX we are assuming here that we may scribble on the list!
			 */
			FuncCandidateList clisti;

			for (clisti = clist; clisti != NULL; clisti = clisti->next)
			{
				clisti->args[0] = clisti->args[1];
			}

			/*
			 * We must run oper_select_candidate even if only one candidate,
			 * otherwise we may falsely return a non-type-compatible operator.
			 */
			fdresult = oper_select_candidate(1, &arg, clist, &operOid);
		}
	}

	if (OidIsValid(operOid))
		tup = SearchSysCache(OPEROID,
							 ObjectIdGetDatum(operOid),
							 0, 0, 0);

	if (!HeapTupleIsValid(tup) && !noError)
		op_error(pstate, op, 'l', InvalidOid, arg, fdresult, location);

	return (Operator) tup;
}
Esempio n. 3
0
/* oper() -- search for a binary operator
 * Given operator name, types of arg1 and arg2, return oper struct.
 *
 * IMPORTANT: the returned operator (if any) is only promised to be
 * coercion-compatible with the input datatypes.  Do not use this if
 * you need an exact- or binary-compatible match; see compatible_oper.
 *
 * If no matching operator found, return NULL if noError is true,
 * raise an error if it is false.  pstate and location are used only to report
 * the error position; pass NULL/-1 if not available.
 *
 * NOTE: on success, the returned object is a syscache entry.  The caller
 * must ReleaseSysCache() the entry when done with it.
 */
Operator
oper(ParseState *pstate, List *opname, Oid ltypeId, Oid rtypeId,
	 bool noError, int location)
{
	Oid			operOid;
	FuncDetailCode fdresult = FUNCDETAIL_NOTFOUND;
	HeapTuple	tup = NULL;

	/*
	 * First try for an "exact" match.
	 */
	operOid = binary_oper_exact(opname, ltypeId, rtypeId);
	if (!OidIsValid(operOid))
	{
		/*
		 * Otherwise, search for the most suitable candidate.
		 */
		FuncCandidateList clist;

		/* Get binary operators of given name */
		clist = OpernameGetCandidates(opname, 'b');

		/* No operators found? Then fail... */
		if (clist != NULL)
		{
			/*
			 * Unspecified type for one of the arguments? then use the other
			 * (XXX this is probably dead code?)
			 */
			Oid			inputOids[2];

			if (rtypeId == InvalidOid)
				rtypeId = ltypeId;
			else if (ltypeId == InvalidOid)
				ltypeId = rtypeId;
			inputOids[0] = ltypeId;
			inputOids[1] = rtypeId;
			fdresult = oper_select_candidate(2, inputOids, clist, &operOid);
		}
	}

	if (OidIsValid(operOid))
		tup = SearchSysCache(OPEROID,
							 ObjectIdGetDatum(operOid),
							 0, 0, 0);

	if (!HeapTupleIsValid(tup) && !noError)
		op_error(pstate, opname, 'b', ltypeId, rtypeId, fdresult, location);

	return (Operator) tup;
}
Esempio n. 4
0
/*
 * to_regoper		- converts "oprname" to operator OID
 *
 * If the name is not found, we return NULL.
 */
Datum
to_regoper(PG_FUNCTION_ARGS)
{
	char	   *opr_name = PG_GETARG_CSTRING(0);
	List	   *names;
	FuncCandidateList clist;

	/*
	 * Parse the name into components and see if it matches any pg_operator
	 * entries in the current search path.
	 */
	names = stringToQualifiedNameList(opr_name);
	clist = OpernameGetCandidates(names, '\0', true);

	if (clist == NULL || clist->next != NULL)
		PG_RETURN_NULL();

	PG_RETURN_OID(clist->oid);
}
Esempio n. 5
0
/* right_oper() -- search for a unary right operator (postfix operator)
 * Given operator name and type of arg, return oper struct.
 *
 * IMPORTANT: the returned operator (if any) is only promised to be
 * coercion-compatible with the input datatype.  Do not use this if
 * you need an exact- or binary-compatible match.
 *
 * If no matching operator found, return NULL if noError is true,
 * raise an error if it is false.  pstate and location are used only to report
 * the error position; pass NULL/-1 if not available.
 *
 * NOTE: on success, the returned object is a syscache entry.  The caller
 * must ReleaseSysCache() the entry when done with it.
 */
Operator
right_oper(ParseState *pstate, List *op, Oid arg, bool noError, int location)
{
	Oid			operOid;
	FuncDetailCode fdresult = FUNCDETAIL_NOTFOUND;
	HeapTuple	tup = NULL;

	/*
	 * First try for an "exact" match.
	 */
	operOid = OpernameGetOprid(op, arg, InvalidOid);
	if (!OidIsValid(operOid))
	{
		/*
		 * Otherwise, search for the most suitable candidate.
		 */
		FuncCandidateList clist;

		/* Get postfix operators of given name */
		clist = OpernameGetCandidates(op, 'r');

		/* No operators found? Then fail... */
		if (clist != NULL)
		{
			/*
			 * We must run oper_select_candidate even if only one candidate,
			 * otherwise we may falsely return a non-type-compatible operator.
			 */
			fdresult = oper_select_candidate(1, &arg, clist, &operOid);
		}
	}

	if (OidIsValid(operOid))
		tup = SearchSysCache(OPEROID,
							 ObjectIdGetDatum(operOid),
							 0, 0, 0);

	if (!HeapTupleIsValid(tup) && !noError)
		op_error(pstate, op, 'r', arg, InvalidOid, fdresult, location);

	return (Operator) tup;
}
Esempio n. 6
0
/*
 * regoperout		- converts operator OID to "opr_name"
 */
Datum
regoperout(PG_FUNCTION_ARGS)
{
	Oid			oprid = PG_GETARG_OID(0);
	char	   *result;
	HeapTuple	opertup;

	if (oprid == InvalidOid)
	{
		result = pstrdup("0");
		PG_RETURN_CSTRING(result);
	}

	opertup = SearchSysCache1(OPEROID, ObjectIdGetDatum(oprid));

	if (HeapTupleIsValid(opertup))
	{
		Form_pg_operator operform = (Form_pg_operator) GETSTRUCT(opertup);
		char	   *oprname = NameStr(operform->oprname);

		/*
		 * In bootstrap mode, skip the fancy namespace stuff and just return
		 * the oper name.  (This path is only needed for debugging output
		 * anyway.)
		 */
		if (IsBootstrapProcessingMode())
			result = pstrdup(oprname);
		else
		{
			FuncCandidateList clist;

			/*
			 * Would this oper be found (uniquely!) by regoperin? If not,
			 * qualify it.
			 */
			clist = OpernameGetCandidates(list_make1(makeString(oprname)),
										  '\0');
			if (clist != NULL && clist->next == NULL &&
				clist->oid == oprid)
				result = pstrdup(oprname);
			else
			{
				const char *nspname;

				nspname = get_namespace_name(operform->oprnamespace);
				nspname = quote_identifier(nspname);
				result = (char *) palloc(strlen(nspname) + strlen(oprname) + 2);
				sprintf(result, "%s.%s", nspname, oprname);
			}
		}

		ReleaseSysCache(opertup);
	}
	else
	{
		/*
		 * If OID doesn't match any pg_operator entry, return it numerically
		 */
		result = (char *) palloc(NAMEDATALEN);
		snprintf(result, NAMEDATALEN, "%u", oprid);
	}

	PG_RETURN_CSTRING(result);
}
Esempio n. 7
0
/*
 * regoperin		- converts "oprname" to operator OID
 *
 * We also accept a numeric OID, for symmetry with the output routine.
 *
 * '0' signifies unknown (OID 0).  In all other cases, the input must
 * match an existing pg_operator entry.
 */
Datum
regoperin(PG_FUNCTION_ARGS)
{
	char	   *opr_name_or_oid = PG_GETARG_CSTRING(0);
	Oid			result = InvalidOid;
	List	   *names;
	FuncCandidateList clist;

	/* '0' ? */
	if (strcmp(opr_name_or_oid, "0") == 0)
		PG_RETURN_OID(InvalidOid);

	/* Numeric OID? */
	if (opr_name_or_oid[0] >= '0' &&
		opr_name_or_oid[0] <= '9' &&
		strspn(opr_name_or_oid, "0123456789") == strlen(opr_name_or_oid))
	{
		result = DatumGetObjectId(DirectFunctionCall1(oidin,
										  CStringGetDatum(opr_name_or_oid)));
		PG_RETURN_OID(result);
	}

	/* Else it's a name, possibly schema-qualified */

	/*
	 * In bootstrap mode we assume the given name is not schema-qualified, and
	 * just search pg_operator for a unique match.	This is needed for
	 * initializing other system catalogs (pg_namespace may not exist yet, and
	 * certainly there are no schemas other than pg_catalog).
	 */
	if (IsBootstrapProcessingMode())
	{
		int			matches = 0;
		Relation	hdesc;
		ScanKeyData skey[1];
		SysScanDesc sysscan;
		HeapTuple	tuple;

		ScanKeyInit(&skey[0],
					Anum_pg_operator_oprname,
					BTEqualStrategyNumber, F_NAMEEQ,
					CStringGetDatum(opr_name_or_oid));

		hdesc = heap_open(OperatorRelationId, AccessShareLock);
		sysscan = systable_beginscan(hdesc, OperatorNameNspIndexId, true,
									 NULL, 1, skey);

		while (HeapTupleIsValid(tuple = systable_getnext(sysscan)))
		{
			result = HeapTupleGetOid(tuple);
			if (++matches > 1)
				break;
		}

		systable_endscan(sysscan);
		heap_close(hdesc, AccessShareLock);

		if (matches == 0)
			ereport(ERROR,
					(errcode(ERRCODE_UNDEFINED_FUNCTION),
					 errmsg("operator does not exist: %s", opr_name_or_oid)));
		else if (matches > 1)
			ereport(ERROR,
					(errcode(ERRCODE_AMBIGUOUS_FUNCTION),
					 errmsg("more than one operator named %s",
							opr_name_or_oid)));

		PG_RETURN_OID(result);
	}

	/*
	 * Normal case: parse the name into components and see if it matches any
	 * pg_operator entries in the current search path.
	 */
	names = stringToQualifiedNameList(opr_name_or_oid);
	clist = OpernameGetCandidates(names, '\0');

	if (clist == NULL)
		ereport(ERROR,
				(errcode(ERRCODE_UNDEFINED_FUNCTION),
				 errmsg("operator does not exist: %s", opr_name_or_oid)));
	else if (clist->next != NULL)
		ereport(ERROR,
				(errcode(ERRCODE_AMBIGUOUS_FUNCTION),
				 errmsg("more than one operator named %s",
						opr_name_or_oid)));

	result = clist->oid;

	PG_RETURN_OID(result);
}
Esempio n. 8
0
/*
 * regoperin		- converts "oprname" to operator OID
 *
 * We also accept a numeric OID, for symmetry with the output routine.
 *
 * '0' signifies unknown (OID 0).  In all other cases, the input must
 * match an existing pg_operator entry.
 */
Datum
regoperin(PG_FUNCTION_ARGS)
{
	char	   *opr_name_or_oid = PG_GETARG_CSTRING(0);
	Oid			result = InvalidOid;
	List	   *names;
	FuncCandidateList clist;

	/* '0' ? */
	if (strcmp(opr_name_or_oid, "0") == 0)
		PG_RETURN_OID(InvalidOid);

	/* Numeric OID? */
	if (opr_name_or_oid[0] >= '0' &&
		opr_name_or_oid[0] <= '9' &&
		strspn(opr_name_or_oid, "0123456789") == strlen(opr_name_or_oid))
	{
		result = DatumGetObjectId(DirectFunctionCall1(oidin,
										  CStringGetDatum(opr_name_or_oid)));
		PG_RETURN_OID(result);
	}

	/* Else it's a name, possibly schema-qualified */

	/*
	 * In bootstrap mode we assume the given name is not schema-qualified, and
	 * just search pg_operator for a unique match.	This is needed for
	 * initializing other system catalogs (pg_namespace may not exist yet, and
	 * certainly there are no schemas other than pg_catalog).
	 */
	if (IsBootstrapProcessingMode())
	{
		int			matches = 0;

		result = 
				caql_getoid_plus(
						NULL,
						&matches,
						NULL,
						cql("SELECT oid FROM pg_operator "
							" WHERE oprname = :1 ",
							CStringGetDatum(opr_name_or_oid)));

		if (matches == 0)
			ereport(ERROR,
					(errcode(ERRCODE_UNDEFINED_FUNCTION),
					 errmsg("operator does not exist: %s", opr_name_or_oid)));
		else if (matches > 1)
			ereport(ERROR,
					(errcode(ERRCODE_AMBIGUOUS_FUNCTION),
					 errmsg("more than one operator named %s",
							opr_name_or_oid)));

		PG_RETURN_OID(result);
	}

	/*
	 * Normal case: parse the name into components and see if it matches any
	 * pg_operator entries in the current search path.
	 */
	names = stringToQualifiedNameList(opr_name_or_oid, "regoperin");
	clist = OpernameGetCandidates(names, '\0');

	if (clist == NULL)
		ereport(ERROR,
				(errcode(ERRCODE_UNDEFINED_FUNCTION),
				 errmsg("operator does not exist: %s", opr_name_or_oid)));
	else if (clist->next != NULL)
		ereport(ERROR,
				(errcode(ERRCODE_AMBIGUOUS_FUNCTION),
				 errmsg("more than one operator named %s",
						opr_name_or_oid)));

	result = clist->oid;

	PG_RETURN_OID(result);
}
Esempio n. 9
0
/*
 * regoperatorin		- converts "oprname(args)" to operator OID
 *
 * We also accept a numeric OID, for symmetry with the output routine.
 *
 * '0' signifies unknown (OID 0).  In all other cases, the input must
 * match an existing pg_operator entry.
 */
Datum
regoperatorin(PG_FUNCTION_ARGS)
{
	char	   *opr_name_or_oid = PG_GETARG_CSTRING(0);
	Oid			result = InvalidOid;
	List	   *names;
	int			nargs;
	Oid			argtypes[FUNC_MAX_ARGS];
	char		oprkind;
	FuncCandidateList clist;

	/* '0' ? */
	if (strcmp(opr_name_or_oid, "0") == 0)
		PG_RETURN_OID(InvalidOid);

	/* Numeric OID? */
	if (opr_name_or_oid[0] >= '0' &&
		opr_name_or_oid[0] <= '9' &&
		strspn(opr_name_or_oid, "0123456789") == strlen(opr_name_or_oid))
	{
		result = DatumGetObjectId(DirectFunctionCall1(oidin,
									  CStringGetDatum(opr_name_or_oid)));
		PG_RETURN_OID(result);
	}

	/*
	 * Else it's a name and arguments.  Parse the name and arguments, look
	 * up potential matches in the current namespace search list, and scan
	 * to see which one exactly matches the given argument types.  (There
	 * will not be more than one match.)
	 *
	 * XXX at present, this code will not work in bootstrap mode, hence this
	 * datatype cannot be used for any system column that needs to receive
	 * data during bootstrap.
	 */
	parseNameAndArgTypes(opr_name_or_oid, "regoperatorin", true,
						 &names, &nargs, argtypes);
	if (nargs == 1)
		ereport(ERROR,
				(errcode(ERRCODE_UNDEFINED_PARAMETER),
				 errmsg("missing argument"),
				 errhint("Use NONE to denote the missing argument of a unary operator.")));
	if (nargs != 2)
		ereport(ERROR,
				(errcode(ERRCODE_TOO_MANY_ARGUMENTS),
				 errmsg("too many arguments"),
				 errhint("Provide two argument types for operator.")));

	if (argtypes[0] == InvalidOid)
		oprkind = 'l';
	else if (argtypes[1] == InvalidOid)
		oprkind = 'r';
	else
		oprkind = 'b';

	clist = OpernameGetCandidates(names, oprkind);

	for (; clist; clist = clist->next)
	{
		if (memcmp(clist->args, argtypes, 2 * sizeof(Oid)) == 0)
			break;
	}

	if (clist == NULL)
		ereport(ERROR,
				(errcode(ERRCODE_UNDEFINED_FUNCTION),
				 errmsg("operator does not exist: %s", opr_name_or_oid)));

	result = clist->oid;

	PG_RETURN_OID(result);
}
Esempio n. 10
0
/* right_oper() -- search for a unary right operator (postfix operator)
 * Given operator name and type of arg, return oper struct.
 *
 * IMPORTANT: the returned operator (if any) is only promised to be
 * coercion-compatible with the input datatype.  Do not use this if
 * you need an exact- or binary-compatible match.
 *
 * If no matching operator found, return NULL if noError is true,
 * raise an error if it is false.  pstate and location are used only to report
 * the error position; pass NULL/-1 if not available.
 *
 * NOTE: on success, the returned object is a syscache entry.  The caller
 * must ReleaseSysCache() the entry when done with it.
 */
Operator
right_oper(ParseState *pstate, List *op, Oid arg, bool noError, int location)
{
	Oid			operOid;
	OprCacheKey key;
	bool		key_ok;
	FuncDetailCode fdresult = FUNCDETAIL_NOTFOUND;
	HeapTuple	tup = NULL;

	/*
	 * Try to find the mapping in the lookaside cache.
	 */
	key_ok = make_oper_cache_key(pstate, &key, op, arg, InvalidOid, location);

	if (key_ok)
	{
		operOid = find_oper_cache_entry(&key);
		if (OidIsValid(operOid))
		{
			tup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operOid));
			if (HeapTupleIsValid(tup))
				return (Operator) tup;
		}
	}

	/*
	 * First try for an "exact" match.
	 */
	operOid = OpernameGetOprid(op, arg, InvalidOid);
	if (!OidIsValid(operOid))
	{
		/*
		 * Otherwise, search for the most suitable candidate.
		 */
		FuncCandidateList clist;

		/* Get postfix operators of given name */
		clist = OpernameGetCandidates(op, 'r', false);

		/* No operators found? Then fail... */
		if (clist != NULL)
		{
			/*
			 * We must run oper_select_candidate even if only one candidate,
			 * otherwise we may falsely return a non-type-compatible operator.
			 */
			fdresult = oper_select_candidate(1, &arg, clist, &operOid);
		}
	}

	if (OidIsValid(operOid))
		tup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operOid));

	if (HeapTupleIsValid(tup))
	{
		if (key_ok)
			make_oper_cache_entry(&key, operOid);
	}
	else if (!noError)
		op_error(pstate, op, 'r', arg, InvalidOid, fdresult, location);

	return (Operator) tup;
}