Example #1
0
/*
 * Generate a function call based on own signature.
 */
ProxyQuery *
plproxy_standard_query(ProxyFunction *func, bool add_types)
{
	StringInfoData sql;
	ProxyQuery *pq;
	const char *target;
	int			i,
				len;

	pq = plproxy_func_alloc(func, sizeof(*pq));
	pq->sql = NULL;
	pq->plan = NULL;
	pq->arg_count = func->arg_count;
	len = pq->arg_count * sizeof(int);
	pq->arg_lookup = plproxy_func_alloc(func, len);

	initStringInfo(&sql);
	appendStringInfo(&sql, "select ");

	/* try to fill in all result column names */
	if (func->ret_composite)
	{
		ProxyComposite *t = func->ret_composite;
		for (i = 0; i < t->tupdesc->natts; i++)
		{
			appendStringInfo(&sql, "%s%s::%s",
							 ((i > 0) ? ", " : ""),
							 t->name_list[i],
							 t->type_list[i]->name);
		}
	}
	else
		/* names not available, do a simple query */
		appendStringInfo(&sql, "r::%s", func->ret_scalar->name);

	/* function call */
	target = func->target_name ? func->target_name : func->name;
	appendStringInfo(&sql, " from %s(", target);

	/* fill in function arguments */
	for (i = 0; i < func->arg_count; i++)
	{
		if (i > 0)
			appendStringInfoChar(&sql, ',');

		add_ref(&sql, i, func, i, add_types);
		pq->arg_lookup[i] = i;
	}
	appendStringInfoChar(&sql, ')');

	/*
	 * Untyped RECORD needs types specified in AS (..) clause.
	 */
	if (func->dynamic_record)
	{
		ProxyComposite *t = func->ret_composite;
		appendStringInfo(&sql, " as (");
		for (i = 0; i < t->tupdesc->natts; i++)
		{
			appendStringInfo(&sql, "%s%s %s",
							((i > 0) ? ", " : ""),
							t->name_list[i],
							t->type_list[i]->name);
		}
		appendStringInfoChar(&sql, ')');
	}

	if (func->ret_scalar)
		appendStringInfo(&sql, " r");

	pq->sql = plproxy_func_strdup(func, sql.data);
	pfree(sql.data);

	return pq;
}
Example #2
0
/* Find info about scalar type */
ProxyType *
plproxy_find_type_info(ProxyFunction *func, Oid oid, bool for_send)
{
	ProxyType  *type;
	HeapTuple	t_type,
				t_nsp;
	Form_pg_type s_type;
	Form_pg_namespace s_nsp;
	char		namebuf[NAMEDATALEN * 4 + 2 + 1 + 2 + 1];
	Oid			nsoid;

	/* fetch pg_type row */
	t_type = SearchSysCache(TYPEOID, ObjectIdGetDatum(oid), 0, 0, 0);
	if (!HeapTupleIsValid(t_type))
		plproxy_error(func, "cache lookup failed for type %u", oid);

	/* typname, typnamespace, PG_CATALOG_NAMESPACE, PG_PUBLIC_NAMESPACE */
	s_type = (Form_pg_type) GETSTRUCT(t_type);
	nsoid = s_type->typnamespace;

	if (nsoid != PG_CATALOG_NAMESPACE)
	{
		t_nsp = SearchSysCache(NAMESPACEOID, ObjectIdGetDatum(nsoid), 0, 0, 0);
		if (!HeapTupleIsValid(t_nsp))
			plproxy_error(func, "cache lookup failed for namespace %u", nsoid);
		s_nsp = (Form_pg_namespace) GETSTRUCT(t_nsp);
		snprintf(namebuf, sizeof(namebuf), "%s.%s",
				quote_identifier(NameStr(s_nsp->nspname)),
				quote_identifier(NameStr(s_type->typname)));
		ReleaseSysCache(t_nsp);
	}
	else
	{
		snprintf(namebuf, sizeof(namebuf), "%s", quote_identifier(NameStr(s_type->typname)));
	}

	/* sanity check */
	switch (s_type->typtype)
	{
		default:
			plproxy_error(func, "unsupported type code: %s (%u)", namebuf, oid);
			break;
		case TYPTYPE_PSEUDO:
			if (oid != VOIDOID)
				plproxy_error(func, "unsupported pseudo type: %s (%u)",
							  namebuf, oid);
			break;
		case TYPTYPE_BASE:
		case TYPTYPE_COMPOSITE:
		case TYPTYPE_DOMAIN:
		case TYPTYPE_ENUM:
		case TYPTYPE_RANGE:
			break;
	}

	/* allocate & fill structure */
	type = plproxy_func_alloc(func, sizeof(*type));
	memset(type, 0, sizeof(*type));

	type->type_oid = oid;
	type->io_param = getTypeIOParam(t_type);
	type->for_send = for_send;
	type->by_value = s_type->typbyval;
	type->name = plproxy_func_strdup(func, namebuf);
	type->is_array = (s_type->typelem != 0 && s_type->typlen == -1);
	type->elem_type_oid = s_type->typelem;
	type->elem_type_t = NULL;
	type->alignment = s_type->typalign;
	type->length = s_type->typlen;

	/* decide what function is needed */
	if (for_send)
	{
		fmgr_info_cxt(s_type->typoutput, &type->io.out.output_func, func->ctx);
		if (OidIsValid(s_type->typsend) && usable_binary(oid))
		{
			fmgr_info_cxt(s_type->typsend, &type->io.out.send_func, func->ctx);
			type->has_send = 1;
		}
	}
	else
	{
		fmgr_info_cxt(s_type->typinput, &type->io.in.input_func, func->ctx);
		if (OidIsValid(s_type->typreceive) && usable_binary(oid))
		{
			fmgr_info_cxt(s_type->typreceive, &type->io.in.recv_func, func->ctx);
			type->has_recv = 1;
		}
	}

	ReleaseSysCache(t_type);

	return type;
}