/* * 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; }
/* 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; }