예제 #1
0
파일: main.c 프로젝트: mpihlak/plproxy-dev
/*
 * The PostgreSQL function & trigger manager calls this function
 * for execution of PL/Proxy procedures.
 *
 * Main entry point for rest of the code.
 */
Datum
plproxy_call_handler(PG_FUNCTION_ARGS)
{
	ProxyFunction *func;
	Datum		ret;

	if (CALLED_AS_TRIGGER(fcinfo))
		elog(ERROR, "PL/Proxy procedures can't be used as triggers");

	/* clean old results */
	if (!fcinfo->flinfo->fn_retset || SRF_IS_FIRSTCALL())
		run_maint();

	if (fcinfo->flinfo->fn_retset)
	{
		ret = handle_ret_set(fcinfo);
	}
	else
	{
		func = compile_and_execute(fcinfo);
		if (func->cur_cluster->ret_total != 1)
			plproxy_error(func, "Non-SETOF function requires 1 row from remote query, got %d",
						  func->cur_cluster->ret_total);
		ret = plproxy_result(func, fcinfo);
		plproxy_clean_results(func->cur_cluster);
	}
	return ret;
}
예제 #2
0
/*
 * Execute ProxyQuery locally.
 *
 * Result will be in SPI_tuptable.
 */
void
plproxy_query_exec(ProxyFunction *func, FunctionCallInfo fcinfo, ProxyQuery *q,
				   DatumArray **array_params, int array_row)
{
	int			i,
				idx,
				err;
	char		arg_nulls[FUNC_MAX_ARGS];
	Datum		arg_values[FUNC_MAX_ARGS];

	/* fill args */
	for (i = 0; i < q->arg_count; i++)
	{
		idx = q->arg_lookup[i];

		if (PG_ARGISNULL(idx))
		{
			arg_nulls[i] = 'n';
			arg_values[i] = (Datum) NULL;
		}
		else if (array_params && IS_SPLIT_ARG(func, idx))
		{
			DatumArray *ats = array_params[idx];

			arg_nulls[i] = ats->nulls[array_row] ? 'n' : ' ';
			arg_values[i] = ats->nulls[array_row] ? (Datum) NULL : ats->values[array_row];
		}
		else
		{
			arg_nulls[i] = ' ';
			arg_values[i] = PG_GETARG_DATUM(idx);
		}
	}

	/* run query */
	err = SPI_execute_plan(q->plan, arg_values, arg_nulls, true, 0);
	if (err != SPI_OK_SELECT)
		plproxy_error(func, "query '%s' failed: %s",
					  q->sql, SPI_result_code_string(err));
}
예제 #3
0
파일: main.c 프로젝트: Apsalar/plproxy
/*
 * Do compilation and execution under SPI.
 *
 * Result conversion will be done without SPI.
 */
static ProxyFunction *
compile_and_execute(FunctionCallInfo fcinfo)
{
	int			err;
	ProxyFunction *func;
	ProxyCluster *cluster;

	/* prepare SPI */
	err = SPI_connect();
	if (err != SPI_OK_CONNECT)
		elog(ERROR, "SPI_connect: %s", SPI_result_code_string(err));

	/* do the initialization also under SPI */
	plproxy_startup_init();

	/* compile code */
	func = plproxy_compile_and_cache(fcinfo);

	/* get actual cluster to run on */
	cluster = plproxy_find_cluster(func, fcinfo);

	/* Don't allow nested calls on the same cluster */
	if (cluster->busy)
		plproxy_error(func, "Nested PL/Proxy calls to the same cluster are not supported.");

	/* fetch PGresults */
	func->cur_cluster = cluster;
	plproxy_exec(func, fcinfo);

	/* done with SPI */
	err = SPI_finish();
	if (err != SPI_OK_FINISH)
		elog(ERROR, "SPI_finish: %s", SPI_result_code_string(err));

	return func;
}
예제 #4
0
/* some error happened */
static void
conn_error(ProxyFunction *func, ProxyConnection *conn, const char *desc)
{
	plproxy_error(func, "%s: %s",
				  desc, PQerrorMessage(conn->db));
}
예제 #5
0
파일: type.c 프로젝트: plproxy/plproxy
/* 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;
}