Beispiel #1
0
static int
pg_callable_func(lua_State *L)
{
	MemoryContext m;
	int i;
	FunctionCallInfoData fcinfo;
	Lua_pgfunc *fi;

	fi = (Lua_pgfunc *) lua_touserdata(L, lua_upvalueindex(1));

	InitFunctionCallInfoData(fcinfo, &fi->fi, fi->numargs, InvalidOid, NULL, NULL);

	if(tmpcontext_usage> RESET_CONTEXT_AFTER ){
		MemoryContextReset(tmpcontext);
		tmpcontext_usage = 0;
	}
	++tmpcontext_usage;

	m = MemoryContextSwitchTo(tmpcontext);

	for (i=0; i<fi->numargs; ++i){
		fcinfo.arg[i] = luaP_todatum(L, fi->argtypes[i], 0, &fcinfo.argnull[i], i+1);
	}

	if(!fi->options.only_internal && fi->options.throwable){
		SPI_push();
		PG_TRY();
		{
			Datum d = FunctionCallInvoke(&fcinfo);
			MemoryContextSwitchTo(m);
			if (fcinfo.isnull) {
				lua_pushnil(L);
			} else {
				luaP_pushdatum(L, d, fi->prorettype);
			}
			SPI_pop();
		}
		PG_CATCH();
		{
			lua_pop(L, lua_gettop(L));
			push_spi_error(L, m); /*context switch to m inside push_spi_error*/
			SPI_pop();
			return lua_error(L);
		}PG_END_TRY();
	}else{
		Datum d = FunctionCallInvoke(&fcinfo);
		MemoryContextSwitchTo(m);
		if (fcinfo.isnull) {
			lua_pushnil(L);
		} else {
			luaP_pushdatum(L, d, fi->prorettype);
		}
	}

	return 1;
}
Beispiel #2
0
/*
 * def load_module(fullname) -> types.ModuleType
 *
 * Evaluate the function's code in a new module
 * or if the fullname exists in sys.modules, return
 * the existing module. [PEP302]
 *
 * This code must go through pl_handler in order to properly load the
 * module. The execution context can dictate much about what happens during
 * load time.
 *
 * i.e., tricky shit happens here. It may be preferrable to make the execution
 * context rigging more accessible, but for now, it's the handler's job.
 */
static PyObj
load_module(PyObj self, PyObj args, PyObj kw)
{
	MemoryContext former = CurrentMemoryContext;
	volatile PyObj rob = NULL;
	FmgrInfo flinfo;
	FunctionCallInfoData fcinfo;

	if (invalid_fullname(self, args, kw))
		return(NULL);

	/*
	 * Disallow execution of "anonymous" functions.
	 */
	flinfo.fn_addr = PyPgFunction_GetPGFunction(self);
	flinfo.fn_oid = PyPgFunction_GetOid(self);
	flinfo.fn_retset = false;
	if (flinfo.fn_addr == NULL || flinfo.fn_oid == InvalidOid)
	{
		PyErr_SetString(PyExc_TypeError, "internal functions cannot be preloaded");
		return(NULL);
	}

	flinfo.fn_nargs = -1;
	flinfo.fn_extra = NULL;
	flinfo.fn_mcxt = CurrentMemoryContext;
	flinfo.fn_expr = NULL;
	fcinfo.nargs = -1;
	fcinfo.flinfo = &flinfo;
	fcinfo.context = NULL;
	fcinfo.resultinfo = NULL;
	/*
	 * Better be true afterwards.
	 */
	fcinfo.isnull = false;

	SPI_push();
	PG_TRY();
	{
		rob = (PyObj) DatumGetPointer(FunctionCallInvoke(&fcinfo));
	}
	PG_CATCH();
	{
		rob = NULL;
		PyErr_SetPgError(false);
	}
	PG_END_TRY();
	SPI_pop();
	MemoryContextSwitchTo(former);

	if (fcinfo.isnull == false)
	{
		PyErr_SetString(PyExc_RuntimeError,
			"function module load protocol did not set isnull");
		rob = NULL;
	}

	Py_XINCREF(rob);
	return(rob);
}
Beispiel #3
0
static void
_SPI_disc(bool pop)
{
    int		ret;

    if( (ret = SPI_finish()) != SPI_OK_FINISH )
        elog( ERROR, "SPI_finish returned %s", SPI_result_code_string(ret));
    if(pop)
        SPI_pop();
}
Beispiel #4
0
size_t append_datum(char* buf, Datum val, bool isnull, Oid typeoid)
{
    HeapTuple typeTup;
    Form_pg_type typeStruct;
    FmgrInfo tmp_flinfo;
    char *str;
    size_t len;

    typeTup = SearchSysCache(TYPEOID, ObjectIdGetDatum(typeoid), 0, 0, 0);
    if (!HeapTupleIsValid(typeTup)) {
        elog(ERROR, "Cache lookup failed for %u", typeoid);
    }
    typeStruct = (Form_pg_type)GETSTRUCT(typeTup);

    if (typeStruct->typtype != 'b') {
        // Non-basic type
        elog(ERROR, "Don't support non-basic types (%s)",
             format_type_be(typeoid));
    }

    fmgr_info_cxt(typeStruct->typoutput, &tmp_flinfo, CurTransactionContext);

    ReleaseSysCache(typeTup);
    
    if (!isnull) {
        if (typeoid == INT4OID) {
            *((int*)buf) = DatumGetInt32(val);
            return 4;
        }
        
        SPI_push();
        str = OutputFunctionCall(&tmp_flinfo, val);
        SPI_pop();
        len = strlen(str);
        strncpy(buf, str, len);
        return len;
    }

    return 0;
}
Beispiel #5
0
Datum pl_bf_call_handler(PG_FUNCTION_ARGS)
{
    FmgrInfo flinfo;
    Datum retval, proc_source_datum;
    Form_pg_proc procStruct;
    Form_pg_type typeStruct;
    HeapTuple procTup;
    HeapTuple typeTup;
    bool isnull;
    Oid resultTypeIOParam, returnTypeOID;
    char *proc_source;
    char *a, *p;
    int i;

    // Get the function tuple
    procTup = SearchSysCache(PROCOID, ObjectIdGetDatum(fcinfo->flinfo->fn_oid),
                             0, 0, 0);
    if (!HeapTupleIsValid(procTup)) {
        elog(ERROR, "Cache lookup failed for procedure %u",
             fcinfo->flinfo->fn_oid);
    }
    procStruct = (Form_pg_proc)GETSTRUCT(procTup);
    
    // Get the function source
    proc_source_datum = SysCacheGetAttr(PROCOID, procTup,
                                        Anum_pg_proc_prosrc, &isnull);
    if (isnull) {
        elog(ERROR, "Function source is null");
    }
    proc_source = DatumGetCString(DirectFunctionCall1(textout,
                                                      proc_source_datum));

    // Get the return type tuple
    typeTup = SearchSysCache(TYPEOID, ObjectIdGetDatum(procStruct->prorettype),
                             0, 0, 0);
    if (!HeapTupleIsValid(typeTup)) {
        elog(ERROR, "Cache lookup failed for type %u", procStruct->prorettype);
    }
    typeStruct = (Form_pg_type)GETSTRUCT(typeTup);
    
    resultTypeIOParam = getTypeIOParam(typeTup);
    returnTypeOID = procStruct -> prorettype;

    a = calloc(5000, 1);
    if (!a) {
        elog(ERROR, "BAD A!");
    }

    p = a;
    for (i = 0; i < procStruct->pronargs; i++) {
        p += append_datum(p, fcinfo->arg[i], fcinfo->argnull[i],
                          procStruct->proargtypes.values[i]);
    }
    
    interpret(a, 0, proc_source);

    fmgr_info_cxt(typeStruct->typinput, &flinfo, TopMemoryContext);

    if (returnTypeOID != VOIDOID) {
        if (returnTypeOID == INT4OID) {
            retval = Int32GetDatum(*((int*)a));
        } else {
            SPI_push();
            if (returnTypeOID == BOOLOID)
                retval = InputFunctionCall(&flinfo, a[0] ? "TRUE" : "FALSE",
                                           resultTypeIOParam, -1);
            else {
                retval = InputFunctionCall(&flinfo, pstrdup(a),
                                           resultTypeIOParam, -1);
            }
            SPI_pop();
        }
    }

    ReleaseSysCache(procTup);
    ReleaseSysCache(typeTup);
    free(a);

    SPI_finish();
    
    return retval;
}
Beispiel #6
0
static PyObj
func_call(PyObj self, PyObj args, PyObj kw)
{
	MemoryContext former = CurrentMemoryContext;
	PyObj fn_input, fn_output, input, rob = NULL;
	TupleDesc td;
	FmgrInfo flinfo;
	FunctionCallInfoData fcinfo;
	volatile Datum datum = 0;

	/*
	 * Disallow execution of "anonymous" functions.
	 */
	flinfo.fn_addr = PyPgFunction_GetPGFunction(self);
	flinfo.fn_oid = PyPgFunction_GetOid(self);
	flinfo.fn_retset = PyPgFunction_GetReturnsSet(self);
	if (flinfo.fn_addr == NULL || flinfo.fn_oid == InvalidOid)
	{
		PyErr_SetString(PyExc_TypeError, "internal functions are not directly callable");
		return(NULL);
	}
	if (flinfo.fn_retset)
	{
		PyErr_SetString(PyExc_NotImplementedError,
			"cannot directly execute set returning functions");
		return(NULL);
	}

	fn_input = PyPgFunction_GetInput(self);
	fn_output = PyPgFunction_GetOutput(self);
	if (PyPgTupleDesc_IsPolymorphic(fn_input) ||
		PyPgType_IsPolymorphic(fn_output))
	{
		PyErr_SetString(PyExc_NotImplementedError,
			"cannot directly execute polymorphic functions");
		return(NULL);
	}

	if (PyPgType_GetOid(fn_output) == TRIGGEROID)
	{
		PyErr_SetString(PyExc_NotImplementedError,
			"cannot directly execute TRIGGER returning functions");
		return(NULL);
	}

	/* No access if failed transaction */
	if (DB_IS_NOT_READY())
		return(NULL);

	td = PyPgTupleDesc_GetTupleDesc(fn_input);

	/*
	 * Normalize the parameters.
	 */
	input = PyTuple_FromTupleDescAndParameters(td, args, kw);
	if (input == NULL)
		return(NULL);

	flinfo.fn_nargs = td->natts;
	flinfo.fn_extra = NULL;
	flinfo.fn_mcxt = CurrentMemoryContext;
	flinfo.fn_expr = NULL;
	fcinfo.flinfo = &flinfo;
	fcinfo.context = NULL;
	fcinfo.resultinfo = NULL;
	fcinfo.isnull = false;
	/*
	 * Custom built descriptor; no dropped attributes.
	 */
	fcinfo.nargs = td->natts;

	SPI_push();
	PG_TRY();
	{
		Py_BuildDatumsAndNulls(td,
			PyPgTupleDesc_GetTypesTuple(fn_input),
			input, fcinfo.arg, fcinfo.argnull);

		datum = FunctionCallInvoke(&fcinfo);

		/*
		 * Special casing void to avoid the singleton.
		 */
		if (fcinfo.isnull ||
			PyPgType_GetOid(fn_output) == VOIDOID)
		{
			rob = Py_None;
			Py_INCREF(rob);
		}
		else
		{
			/*
			 * Some functions will return a parameter that its given.
			 * This is problematic if we are going to free the output
			 * after re-allocating as a Postgres.Object.
			 */
			if (PyPgType_ShouldFree(fn_output))
			{
				int i;

				/*
				 * Scan for !typbyval parameters.
				 * When one is found, compare the datum to the result datum.
				 */
				for (i = 0; i < PyTuple_GET_SIZE(input); ++i)
				{
					PyObj param = PyTuple_GET_ITEM(input, i);
					/*
					 * It's tempting to check the types first, but in situations
					 * of functions doing binary compatible coercion, it would be a
					 * mistake.
					 */
					if (PyPgType_ShouldFree(Py_TYPE(param)))
					{
						if (PyPgObject_GetDatum(param) == datum)
						{
							/*
							 * It's the same Datum of an argument,
							 * inc the ref and return the param.
							 */
							if (fn_output == (PyObj) Py_TYPE(param))
							{
								rob = param;
								Py_INCREF(rob);
							}
							else
							{
								/*
								 * It's the same Datum, but a different type.
								 * Make a Copy.
								 */
								rob = PyPgObject_New(fn_output, datum);
							}

							break;
						}
					}
				}

				/*
				 * It's a newly allocated result? (not an argument)
				 */
				if (rob == NULL)
				{
					/*
					 * New result, Datum is copied into the PythonMemoryContext
					 */
					rob = PyPgObject_New(fn_output, datum);
					/*
					 * Cleanup.
					 */
					pfree(DatumGetPointer(datum));
				}
			}
			else
			{
				/* Not pfree'ing typbyval, so no need to check parameters. */
				rob = PyPgObject_New(fn_output, datum);
			}
		}
	}
	PG_CATCH();
	{
		Py_XDECREF(rob);
		rob = NULL;
		PyErr_SetPgError(false);
	}
	PG_END_TRY();
	SPI_pop();

	Py_DECREF(input);

	MemoryContextSwitchTo(former);
	return(rob);
}