Esempio n. 1
0
/*
 * build_function_result_tupdesc_t
 *
 * Given a pg_proc row for a function, return a tuple descriptor for the
 * result rowtype, or NULL if the function does not have OUT parameters.
 *
 * Note that this does not handle resolution of polymorphic types;
 * that is deliberate.
 */
TupleDesc
build_function_result_tupdesc_t(HeapTuple procTuple)
{
	Form_pg_proc procform = (Form_pg_proc) GETSTRUCT(procTuple);
	Datum		proallargtypes;
	Datum		proargmodes;
	Datum		proargnames;
	bool		isnull;

	/* Return NULL if the function isn't declared to return RECORD */
	if (procform->prorettype != RECORDOID)
		return NULL;

	/* If there are no OUT parameters, return NULL */
	if (heap_attisnull(procTuple, Anum_pg_proc_proallargtypes, NULL) ||
		heap_attisnull(procTuple, Anum_pg_proc_proargmodes, NULL))
		return NULL;

	/* Get the data out of the tuple */
	proallargtypes = SysCacheGetAttr(PROCOID, procTuple,
									 Anum_pg_proc_proallargtypes,
									 &isnull);
	Assert(!isnull);
	proargmodes = SysCacheGetAttr(PROCOID, procTuple,
								  Anum_pg_proc_proargmodes,
								  &isnull);
	Assert(!isnull);
	proargnames = SysCacheGetAttr(PROCOID, procTuple,
								  Anum_pg_proc_proargnames,
								  &isnull);
	if (isnull)
		proargnames = PointerGetDatum(NULL);	/* just to be sure */

	return build_function_result_tupdesc_d(procform->prokind,
										   proallargtypes,
										   proargmodes,
										   proargnames);
}
Esempio n. 2
0
/*
 * get_func_result_name
 *
 * If the function has exactly one output parameter, and that parameter
 * is named, return the name (as a palloc'd string).  Else return NULL.
 *
 * This is used to determine the default output column name for functions
 * returning scalar types.
 */
char *
get_func_result_name(Oid functionId)
{
	char	   *result;
	HeapTuple	procTuple;
	Datum		proargmodes;
	Datum		proargnames;
	bool		isnull;
	ArrayType  *arr;
	int			numargs;
	char	   *argmodes;
	Datum	   *argnames;
	int			numoutargs;
	int			nargnames;
	int			i;

	/* First fetch the function's pg_proc row */
	procTuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(functionId));
	if (!HeapTupleIsValid(procTuple))
		elog(ERROR, "cache lookup failed for function %u", functionId);

	/* If there are no named OUT parameters, return NULL */
	if (heap_attisnull(procTuple, Anum_pg_proc_proargmodes) ||
		heap_attisnull(procTuple, Anum_pg_proc_proargnames))
		result = NULL;
	else
	{
		/* Get the data out of the tuple */
		proargmodes = SysCacheGetAttr(PROCOID, procTuple,
									  Anum_pg_proc_proargmodes,
									  &isnull);
		Assert(!isnull);
		proargnames = SysCacheGetAttr(PROCOID, procTuple,
									  Anum_pg_proc_proargnames,
									  &isnull);
		Assert(!isnull);

		/*
		 * We expect the arrays to be 1-D arrays of the right types; verify
		 * that.  For the char array, we don't need to use deconstruct_array()
		 * since the array data is just going to look like a C array of
		 * values.
		 */
		arr = DatumGetArrayTypeP(proargmodes);	/* ensure not toasted */
		numargs = ARR_DIMS(arr)[0];
		if (ARR_NDIM(arr) != 1 ||
			numargs < 0 ||
			ARR_HASNULL(arr) ||
			ARR_ELEMTYPE(arr) != CHAROID)
			elog(ERROR, "proargmodes is not a 1-D char array");
		argmodes = (char *) ARR_DATA_PTR(arr);
		arr = DatumGetArrayTypeP(proargnames);	/* ensure not toasted */
		if (ARR_NDIM(arr) != 1 ||
			ARR_DIMS(arr)[0] != numargs ||
			ARR_HASNULL(arr) ||
			ARR_ELEMTYPE(arr) != TEXTOID)
			elog(ERROR, "proargnames is not a 1-D text array");
		deconstruct_array(arr, TEXTOID, -1, false, 'i',
						  &argnames, NULL, &nargnames);
		Assert(nargnames == numargs);

		/* scan for output argument(s) */
		result = NULL;
		numoutargs = 0;
		for (i = 0; i < numargs; i++)
		{
			if (argmodes[i] == PROARGMODE_IN ||
				argmodes[i] == PROARGMODE_VARIADIC)
				continue;
			Assert(argmodes[i] == PROARGMODE_OUT ||
				   argmodes[i] == PROARGMODE_INOUT ||
				   argmodes[i] == PROARGMODE_TABLE);
			if (++numoutargs > 1)
			{
				/* multiple out args, so forget it */
				result = NULL;
				break;
			}
			result = TextDatumGetCString(argnames[i]);
			if (result == NULL || result[0] == '\0')
			{
				/* Parameter is not named, so forget it */
				result = NULL;
				break;
			}
		}
	}

	ReleaseSysCache(procTuple);

	return result;
}
Esempio n. 3
0
int32
RelationPurge(char *relationName,
	      char *absoluteTimeString,
	      char *relativeTimeString)
{
    register		i;
    AbsoluteTime		absoluteTime = INVALID_ABSTIME;
    RelativeTime		relativeTime = INVALID_RELTIME;
    bits8			dateTag;
    Relation		relation;
    HeapScanDesc		scan;
    static ScanKeyData	key[1] = {
	{ 0, Anum_pg_class_relname, F_NAMEEQ }
    };
    Buffer			buffer;
    HeapTuple		newTuple, oldTuple;
    AbsoluteTime		currentTime;
    char			*values[Natts_pg_class];
    char			nulls[Natts_pg_class];
    char			replace[Natts_pg_class];
    Relation		idescs[Num_pg_class_indices];
    
    /*
     * XXX for some reason getmyrelids (in inval.c) barfs when
     * you heap_replace tuples from these classes.  i thought
     * setheapoverride would fix it but it didn't.  for now,
     * just disallow purge on these classes.
     */
    if (strcmp(RelationRelationName, relationName) == 0 ||
	strcmp(AttributeRelationName, relationName)  == 0 ||
	strcmp(AccessMethodRelationName, relationName) == 0 ||
	strcmp(AccessMethodOperatorRelationName, relationName) == 0) {
	elog(WARN, "%s: cannot purge catalog \"%s\"",
	     cmdname, relationName);
    }
    
    if (PointerIsValid(absoluteTimeString)) {
	absoluteTime = (int32) nabstimein(absoluteTimeString);
	absoluteTimeString[0] = '\0';
	if (absoluteTime == INVALID_ABSTIME) {
	    elog(NOTICE, "%s: bad absolute time string \"%s\"",
		 cmdname, absoluteTimeString);
	    elog(WARN, "purge not executed");
	}
    }
    
#ifdef	PURGEDEBUG
    elog(DEBUG, "%s: absolute time `%s' is %d.",
	 cmdname, absoluteTimeString, absoluteTime);
#endif	/* defined(PURGEDEBUG) */
    
    if (PointerIsValid(relativeTimeString)) {
	if (isreltime(relativeTimeString, NULL, NULL, NULL) != 1) {
	    elog(WARN, "%s: bad relative time string \"%s\"",
		 cmdname, relativeTimeString);
	}
	relativeTime = reltimein(relativeTimeString);
	
#ifdef	PURGEDEBUG
	elog(DEBUG, "%s: relative time `%s' is %d.",
	     cmdname, relativeTimeString, relativeTime);
#endif	/* defined(PURGEDEBUG) */
    }
    
    /*
     * Find the RELATION relation tuple for the given relation.
     */
    relation = heap_openr(RelationRelationName);
    key[0].sk_argument = PointerGetDatum(relationName);
    fmgr_info(key[0].sk_procedure, &key[0].sk_func, &key[0].sk_nargs);
    
    scan = heap_beginscan(relation, 0, NowTimeQual, 1, key);
    oldTuple = heap_getnext(scan, 0, &buffer);
    if (!HeapTupleIsValid(oldTuple)) {
	heap_endscan(scan);
	heap_close(relation);
	elog(WARN, "%s: no such relation: %s", cmdname, relationName);
	return(0);
    }
    
    /*
     * Dig around in the tuple.
     */
    currentTime = GetCurrentTransactionStartTime();
    if (!RelativeTimeIsValid(relativeTime)) {
	dateTag = ABSOLUTE;
	if (!AbsoluteTimeIsValid(absoluteTime))
	    absoluteTime = currentTime;
    } else if (!AbsoluteTimeIsValid(absoluteTime))
	dateTag = RELATIVE;
    else
	dateTag = ABSOLUTE | RELATIVE;
    
    for (i = 0; i < Natts_pg_class; ++i) {
	nulls[i] = heap_attisnull(oldTuple, i+1) ? 'n' : ' ';
	values[i] = NULL;
	replace[i] = ' ';
    }
    if (dateTag & ABSOLUTE) {
	values[Anum_pg_class_relexpires-1] =
	    (char *) UInt32GetDatum(absoluteTime);
	replace[Anum_pg_class_relexpires-1] = 'r';
    }
    if (dateTag & RELATIVE) {
	values[Anum_pg_class_relpreserved-1] =
	    (char *) UInt32GetDatum(relativeTime);
	replace[Anum_pg_class_relpreserved-1] = 'r';
    }
    
    /*
     * Change the RELATION relation tuple for the given relation.
     */
    newTuple = heap_modifytuple(oldTuple, buffer, relation, (Datum*)values,
				nulls, replace);
    
    /* XXX How do you detect an insertion error?? */
    (void) heap_replace(relation, &newTuple->t_ctid, newTuple);
    
    /* keep the system catalog indices current */
    CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices, idescs);
    CatalogIndexInsert(idescs, Num_pg_class_indices, relation, newTuple);
    CatalogCloseIndices(Num_pg_class_indices, idescs);
    
    pfree(newTuple);
    
    heap_endscan(scan);
    heap_close(relation);
    return(1);
}