Beispiel #1
0
static jvalue _Array_coerceDatum(Type self, Datum arg)
{
	jvalue result;
	jsize idx;
	Type  elemType    = Type_getElementType(self);
	int16 elemLength  = Type_getLength(elemType);
	char  elemAlign   = Type_getAlign(elemType);
	bool  elemByValue = Type_isByValue(elemType);
	ArrayType* v = DatumGetArrayTypeP(arg);
	jsize nElems = (jsize)ArrayGetNItems(ARR_NDIM(v), ARR_DIMS(v));
	jobjectArray objArray = JNI_newObjectArray(nElems, Type_getJavaClass(elemType), 0);
	const char* values = ARR_DATA_PTR(v);
	bits8* nullBitMap = ARR_NULLBITMAP(v);

	for(idx = 0; idx < nElems; ++idx)
	{
		if(arrayIsNull(nullBitMap, idx))
			JNI_setObjectArrayElement(objArray, idx, 0);
		else
		{
			Datum value = fetch_att(values, elemByValue, elemLength);
			jvalue obj = Type_coerceDatum(elemType, value);
			JNI_setObjectArrayElement(objArray, idx, obj.l);
			JNI_deleteLocalRef(obj.l);

			values = att_addlength_datum(values, elemLength, PointerGetDatum(values));
			values = (char*)att_align_nominal(values, elemAlign);

		}
	}
	result.l = (jobject)objArray;
	return result;
}
Beispiel #2
0
/*
 * make_variant_int: Converts our external (Variant) representation to a VariantInt.
 */
static VariantInt
make_variant_int(Variant v, FunctionCallInfo fcinfo, IOFuncSelector func)
{
    VariantCache	*cache;
    VariantInt		vi;
    long 					data_length; /* long instead of size_t because we're subtracting */
    Pointer 			ptr;
    uint					flags;


    /* Ensure v is fully detoasted */
    Assert(!VARATT_IS_EXTENDED(v));

    /* May need to be careful about what context this stuff is palloc'd in */
    vi = palloc0(sizeof(VariantDataInt));

    vi->typid = get_oid(v, &flags);

#ifdef VARIANT_TEST_OID
    vi->typid -= OID_MASK;
#endif

    vi->typmod = v->typmod;
    vi->isnull = (flags & VAR_ISNULL ? true : false);

    cache = get_cache(fcinfo, vi, func);

    /*
     * by-value type. We do special things with all pass-by-reference when we
     * store, so we only use this for typbyval even though fetch_att supports
     * pass-by-reference.
     *
     * Note that fetch_att sanity-checks typlen for us (because we're only passing typbyval).
     */
    if(cache->typbyval)
    {
        if(!vi->isnull)
        {
            Pointer p = VDATAPTR_ALIGN(v, cache->typalign);
            vi->data = fetch_att(p, cache->typbyval, cache->typlen);
        }
        return vi;
    }

    /* we don't store a varlena header for varlena data; instead we compute
     * it's size based on ours:
     *
     * Our size - our header size - overflow byte (if present)
     *
     * For cstring, we don't store the trailing NUL
     */
    data_length = VARSIZE(v) - VHDRSZ - (flags & VAR_OVERFLOW ? 1 : 0);
    if( data_length < 0 )
        elog(ERROR, "Negative data_length %li", data_length);

    if (cache->typlen == -1) /* varlena */
    {
        ptr = palloc0(data_length + VARHDRSZ);
        SET_VARSIZE(ptr, data_length + VARHDRSZ);
        memcpy(VARDATA(ptr), VDATAPTR(v), data_length);
    }
    else if(cache->typlen == -2) /* cstring */
    {
        ptr = palloc(data_length + 1); /* Need space for NUL terminator */
        memcpy(ptr, VDATAPTR(v), data_length);
        *(ptr + data_length + 1) = '\0';
    }
    else /* Fixed size, pass by reference */
    {
        if(vi->isnull)
        {
            vi->data = (Datum) 0;
            return vi;
        }

        Assert(data_length == cache->typlen);
        ptr = palloc0(data_length);
        Assert(ptr == (char *) att_align_nominal(ptr, cache->typalign));
        memcpy(ptr, VDATAPTR(v), data_length);
    }
    vi->data = PointerGetDatum(ptr);

    return vi;
}
Beispiel #3
0
/*
 * Reading quantiles from an input array, based mostly on
 * array_to_text_internal (it's a modified copy). This expects
 * to receive a single-dimensional float8 array as input, fails
 * otherwise.
 */
static double *
array_to_double(FunctionCallInfo fcinfo, ArrayType *v, int * len)
{
    double     *result;
    int         nitems,
               *dims,
                ndims;
    Oid         element_type;
    int         typlen;
    bool        typbyval;
    char        typalign;
    char       *p;
    int         i, idx = 0;
    
    ArrayMetaState *my_extra;

    ndims = ARR_NDIM(v);
    dims = ARR_DIMS(v);
    nitems = ArrayGetNItems(ndims, dims);
    
    /* this is a special-purpose function for single-dimensional arrays */
    if (ndims != 1) {
        elog(ERROR, "error, array_to_double expects a single-dimensional array"
                    "(dims = %d)", ndims);
    }

    /* if there are no elements, set the length to 0 and return NULL */
    if (nitems == 0) {
        (*len) = 0;
        return NULL;
    }
    
    element_type = ARR_ELEMTYPE(v);
    
    result = (double*)palloc(nitems * sizeof(double));

    /*
     * We arrange to look up info about element type, including its output
     * conversion proc, only once per series of calls, assuming the element
     * type doesn't change underneath us.
     */
    my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
    if (my_extra == NULL)
    {
        fcinfo->flinfo->fn_extra = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
                                                      sizeof(ArrayMetaState));
        my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
        my_extra->element_type = ~element_type;
    }

    if (my_extra->element_type != element_type)
    {
        /*
         * Get info about element type, including its output conversion proc
         */
        get_type_io_data(element_type, IOFunc_output,
                         &my_extra->typlen, &my_extra->typbyval,
                         &my_extra->typalign, &my_extra->typdelim,
                         &my_extra->typioparam, &my_extra->typiofunc);
        fmgr_info_cxt(my_extra->typiofunc, &my_extra->proc,
                      fcinfo->flinfo->fn_mcxt);
        my_extra->element_type = element_type;
    }
    
    typlen = my_extra->typlen;
    typbyval = my_extra->typbyval;
    typalign = my_extra->typalign;
    
    p = ARR_DATA_PTR(v);

    for (i = 0; i < nitems; i++) {

        Datum itemvalue = fetch_att(p, typbyval, typlen);
        
        double val = DatumGetFloat8(itemvalue);
        
        result[idx++] = val;
        
        p = att_addlength_pointer(p, typlen, p);
        p = (char *) att_align_nominal(p, typalign);

    }
    
    (*len) = idx;

    return result;
}
Datum serialize_array(PG_FUNCTION_ARGS)
{
	ArrayType  *v = PG_GETARG_ARRAYTYPE_P(0);
	Oid		 element_type = ARR_ELEMTYPE(v);
	int16		typlen;
	bool		typbyval;
	char		typalign;
	char		typdelim;
	char	   *p, *value;
	char 		type_category;
	bool		needComma = false;

	bits8	  *bitmap;
	int		 bitmask;
	int		 nitems, i;
	int		 ndim, *dims;

	Oid			typioparam, typiofunc;
	HeapTuple 	type_tuple;
	FmgrInfo	proc, flinfo;

	StringInfoData buf;

//	FILE* log;

//	log = fopen("/var/lib/postgresql/serializer.log", "a");

//	fprintf(log, "Doing serialize_array\n");
//	fflush(log);

	/*
	 * Get info about element type, including its output conversion proc
	 */
	get_type_io_data(element_type, IOFunc_output,
					 &typlen, &typbyval,
					 &typalign, &typdelim,
					 &typioparam, &typiofunc);

	fmgr_info_cxt( typiofunc, &proc, fcinfo->flinfo->fn_mcxt );

	ndim = ARR_NDIM(v);
	dims = ARR_DIMS(v);
	nitems = ArrayGetNItems(ndim, dims);

	if( ndim > 1 )
		elog( ERROR, "multidimensional arrays doesn't supported" );

	p = ARR_DATA_PTR(v);
	bitmap = ARR_NULLBITMAP(v);
	bitmask = 1;

	/* obtain type information from pg_catalog */
	type_tuple = SearchSysCache1( TYPEOID, ObjectIdGetDatum(element_type) );
	if (!HeapTupleIsValid( type_tuple ))
		elog(ERROR, "cache lookup failed for relation %u", element_type);

	type_category = ((Form_pg_type) GETSTRUCT( type_tuple ))->typcategory;

	ReleaseSysCache( type_tuple );

	/* Build the result string */
	initStringInfo(&buf);

	appendStringInfoChar(&buf, '[');
	for (i = 0; i < nitems; i++)
	{
		if (needComma)
			appendStringInfoChar(&buf, ',');
		needComma = true;

		/* Get source element, checking for NULL */
		if (bitmap && (*bitmap & bitmask) == 0)
		{
			// append null
			appendStringInfoString(&buf, "null");
		}
		else
		{
			/* get item value and advance array data pointer */
			Datum itemvalue = fetch_att(p, typbyval, typlen);
			p = att_addlength_pointer(p, typlen, p);
			p = (char *) att_align_nominal(p, typalign);

			//------------------------
			switch( type_category )
			{
				// http://www.postgresql.org/docs/current/static/catalog-pg-type.html#CATALOG-TYPCATEGORY-TABLE

				case 'A': //array - impossible case
				break;

				case 'C': //composite
					//call to serialize_record( ... )
					MemSet( &flinfo, 0, sizeof( flinfo ) );
					flinfo.fn_addr = serialize_record;
					flinfo.fn_nargs = 1;
					flinfo.fn_mcxt = fcinfo->flinfo->fn_mcxt;

					value = PG_TEXT_DATUM_GET_CSTR( FunctionCall1( &flinfo, itemvalue ) );

					appendStringInfoString(&buf, value);
				break;

				case 'N': //numeric

					// get column text value
					value = OutputFunctionCall( &proc, itemvalue );

					appendStringInfoString(&buf, value);
				break;

				default: //another

					// get column text value
					value = OutputFunctionCall( &proc, itemvalue );

					appendStringInfoQuotedString(&buf, value);
			}
		}

		/* advance bitmap pointer if any */
		if (bitmap)
		{
			bitmask <<= 1;
			if (bitmask == 0x100)
			{
				bitmap++;
				bitmask = 1;
			}
		}
	}
	appendStringInfoChar(&buf, ']');

//	fclose(log);

	//PG_RETURN_CSTRING(retval);
	PG_RETURN_TEXT_P( PG_CSTR_GET_TEXT( buf.data ) );
}
Beispiel #5
0
static PyObject *
PLyList_FromArray_recurse(PLyDatumToOb *elm, int *dims, int ndim, int dim,
						  char **dataptr_p, bits8 **bitmap_p, int *bitmask_p)
{
	int			i;
	PyObject   *list;

	list = PyList_New(dims[dim]);
	if (!list)
		return NULL;

	if (dim < ndim - 1)
	{
		/* Outer dimension. Recurse for each inner slice. */
		for (i = 0; i < dims[dim]; i++)
		{
			PyObject   *sublist;

			sublist = PLyList_FromArray_recurse(elm, dims, ndim, dim + 1,
												dataptr_p, bitmap_p, bitmask_p);
			PyList_SET_ITEM(list, i, sublist);
		}
	}
	else
	{
		/*
		 * Innermost dimension. Fill the list with the values from the array
		 * for this slice.
		 */
		char	   *dataptr = *dataptr_p;
		bits8	   *bitmap = *bitmap_p;
		int			bitmask = *bitmask_p;

		for (i = 0; i < dims[dim]; i++)
		{
			/* checking for NULL */
			if (bitmap && (*bitmap & bitmask) == 0)
			{
				Py_INCREF(Py_None);
				PyList_SET_ITEM(list, i, Py_None);
			}
			else
			{
				Datum		itemvalue;

				itemvalue = fetch_att(dataptr, elm->typbyval, elm->typlen);
				PyList_SET_ITEM(list, i, elm->func(elm, itemvalue));
				dataptr = att_addlength_pointer(dataptr, elm->typlen, dataptr);
				dataptr = (char *) att_align_nominal(dataptr, elm->typalign);
			}

			/* advance bitmap pointer if any */
			if (bitmap)
			{
				bitmask <<= 1;
				if (bitmask == 0x100 /* (1<<8) */ )
				{
					bitmap++;
					bitmask = 1;
				}
			}
		}

		*dataptr_p = dataptr;
		*bitmap_p = bitmap;
		*bitmask_p = bitmask;
	}

	return list;
}
Beispiel #6
0
/*
 * load_auth_entries: read pg_authid into auth_entry[]
 *
 * auth_info_out: pointer to auth_entry * where address to auth_entry[] should be stored
 * total_roles_out: pointer to int where num of total roles should be stored
 */
static void
load_auth_entries(Relation rel_authid, auth_entry **auth_info_out, int *total_roles_out)
{
	BlockNumber totalblocks;
	HeapScanDesc scan;
	HeapTuple   tuple;
	int         curr_role = 0;
	int         total_roles = 0;
	int         est_rows;
	auth_entry *auth_info;

	/*
	 * Read pg_authid and fill temporary data structures.  Note we must read
	 * all roles, even those without rolcanlogin.
	 */
	totalblocks = RelationGetNumberOfBlocks(rel_authid);
	totalblocks = totalblocks ? totalblocks : 1;
	est_rows = totalblocks * (BLCKSZ / (sizeof(HeapTupleHeaderData) + sizeof(FormData_pg_authid)));
	auth_info = (auth_entry *) palloc(est_rows * sizeof(auth_entry));

	scan = heap_beginscan(rel_authid, SnapshotNow, 0, NULL);
	while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
	{
		Form_pg_authid aform = (Form_pg_authid) GETSTRUCT(tuple);
		HeapTupleHeader tup = tuple->t_data;
		char	   *tp;			/* ptr to tuple data */
		long		off;		/* offset in tuple data */
		bits8	   *bp = tup->t_bits;	/* ptr to null bitmask in tuple */
		Datum		datum;

		if (curr_role >= est_rows)
		{
			est_rows *= 2;
			auth_info = (auth_entry *)
				repalloc(auth_info, est_rows * sizeof(auth_entry));
		}

		auth_info[curr_role].roleid = HeapTupleGetOid(tuple);
		auth_info[curr_role].rolsuper = aform->rolsuper;
		auth_info[curr_role].rolcanlogin = aform->rolcanlogin;
		auth_info[curr_role].rolname = pstrdup(NameStr(aform->rolname));
		auth_info[curr_role].member_of = NIL;

		/*
		 * We can't use heap_getattr() here because during startup we will not
		 * have any tupdesc for pg_authid.  Fortunately it's not too hard to
		 * work around this.  rolpassword is the first possibly-null field so
		 * we can compute its offset directly.
		 */
		tp = (char *) tup + tup->t_hoff;
		off = offsetof(FormData_pg_authid, rolpassword);

		if (HeapTupleHasNulls(tuple) &&
			att_isnull(Anum_pg_authid_rolpassword - 1, bp))
		{
			/* passwd is null, emit as an empty string */
			auth_info[curr_role].rolpassword = pstrdup("");
		}
		else
		{
			/* assume passwd is pass-by-ref */
			datum = PointerGetDatum(tp + off);

			/*
			 * The password probably shouldn't ever be out-of-line toasted; if
			 * it is, ignore it, since we can't handle that in startup mode.
			 */
			if (VARATT_IS_EXTERNAL(DatumGetPointer(datum)))
				auth_info[curr_role].rolpassword = pstrdup("");
			else
				auth_info[curr_role].rolpassword = DatumGetCString(DirectFunctionCall1(textout, datum));

			/* assume passwd has attlen -1 */
			off = att_addlength(off, -1, PointerGetDatum(tp + off));
		}

		if (HeapTupleHasNulls(tuple) &&
			att_isnull(Anum_pg_authid_rolvaliduntil - 1, bp))
		{
			/* rolvaliduntil is null, emit as an empty string */
			auth_info[curr_role].rolvaliduntil = pstrdup("");
		}
		else
		{
			/*
			 * rolvaliduntil is timestamptz, which we assume is double
			 * alignment and pass-by-value.
			 */
			off = att_align(off, 'd');
			datum = fetch_att(tp + off, true, sizeof(TimestampTz));
			auth_info[curr_role].rolvaliduntil = DatumGetCString(DirectFunctionCall1(timestamptz_out, datum));
		}

		/*
		 * Check for illegal characters in the user name and password.
		 */
		if (!name_okay(auth_info[curr_role].rolname))
		{
			ereport(LOG,
					(errmsg("invalid role name \"%s\"",
							auth_info[curr_role].rolname)));
			continue;
		}
		if (!name_okay(auth_info[curr_role].rolpassword))
		{
			ereport(LOG,
					(errmsg("invalid role password \"%s\"",
							auth_info[curr_role].rolpassword)));
			continue;
		}

		curr_role++;
		total_roles++;
	}
	heap_endscan(scan);

	*auth_info_out = auth_info;
	*total_roles_out = total_roles;
}
Datum
count_distinct_elements_append(PG_FUNCTION_ARGS)
{
    int             i;
    element_set_t  *eset = NULL;

    /* info for anyarray */
    Oid input_type;
    Oid element_type;

    /* array data */
    ArrayType  *input;
    int         ndims;
    int        *dims;
    int         nitems;
    bits8      *null_bitmap;
    char       *arr_ptr;
    Datum       element;

    /* memory contexts */
    MemoryContext oldcontext;
    MemoryContext aggcontext;

    /*
     * If the new value is NULL, we simply return the current aggregate state
     * (it might be NULL, so check it). In this case we don't really care about
     * the types etc.
     *
     * We may still get NULL elements in the array, but to check that we would
     * have to walk the array, which does not qualify as cheap check. Also we
     * assume that there's at least one non-NULL element, and we'll walk the
     * array just once. It's possible we'll get empty set this way.
     */
    if (PG_ARGISNULL(1) && PG_ARGISNULL(0))
        PG_RETURN_NULL();
    else if (PG_ARGISNULL(1))
        PG_RETURN_DATUM(PG_GETARG_DATUM(0));

    /* from now on we know the new value is not NULL */

    /* get the type of array elements */
    input_type = get_fn_expr_argtype(fcinfo->flinfo, 1);
    element_type = get_element_type(input_type);

    /*
     * parse the array contents (we know we got non-NULL value)
     */
    input = PG_GETARG_ARRAYTYPE_P(1);
    ndims = ARR_NDIM(input);
    dims = ARR_DIMS(input);
    nitems = ArrayGetNItems(ndims, dims);
    null_bitmap = ARR_NULLBITMAP(input);
    arr_ptr = ARR_DATA_PTR(input);

    /* make sure we're running as part of aggregate function */
    GET_AGG_CONTEXT("count_distinct_elements_append", fcinfo, aggcontext);

    oldcontext = MemoryContextSwitchTo(aggcontext);

    /* add all array elements to the set */
    for (i = 0; i < nitems; i++)
    {
        /* ignore nulls */
        if (null_bitmap && !(null_bitmap[i / 8] & (1 << (i % 8))))
            continue;

        /* init the hash table, if needed */
        if (eset == NULL)
        {
            if (PG_ARGISNULL(0))
            {
                int16       typlen;
                bool        typbyval;
                char        typalign;

                /* get type information for the second parameter (anyelement item) */
                get_typlenbyvalalign(element_type, &typlen, &typbyval, &typalign);

                /* we can't handle varlena types yet or values passed by reference */
                if ((typlen < 0) || (! typbyval))
                    elog(ERROR, "count_distinct_elements handles only arrays of fixed-length types passed by value");

                eset = init_set(typlen, typalign, aggcontext);
            }
            else
                eset = (element_set_t *)PG_GETARG_POINTER(0);
        }

        element = fetch_att(arr_ptr, true, eset->item_size);

        add_element(eset, (char*)&element);

        /* advance array pointer */
        arr_ptr = att_addlength_pointer(arr_ptr, eset->item_size, arr_ptr);
        arr_ptr = (char *) att_align_nominal(arr_ptr, eset->typalign);
    }

    MemoryContextSwitchTo(oldcontext);

    if (eset == NULL)
        PG_RETURN_NULL();
    else
        PG_RETURN_POINTER(eset);
}
Beispiel #8
0
static text*
plvsubst_string(text *template_in, ArrayType *vals_in, text *c_subst, FunctionCallInfo fcinfo)
{
	ArrayType	   *v = vals_in;
	int				nitems,
				   *dims,
					ndims;
	char		   *p;
	int16			typlen;
	bool			typbyval;
	char			typalign;
	char			typdelim;
	Oid				typelem;
	Oid				typiofunc;
	FmgrInfo		proc;
	int				i = 0, items = 0;
	StringInfo		sinfo;
	const char	   *template_str;
	int				template_len;
	char		   *sizes;
	int			   *positions;
	int				subst_mb_len;
	int				subst_len;
	const bits8	   *bitmap;
	int				bitmask;

	if (v != NULL && (ndims = ARR_NDIM(v)) > 0)
	{
		if (ndims != 1)
			ereport(ERROR,
					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
					 errmsg("invalid parameter"),
					 errdetail("Array of arguments has wrong dimension: %d", ndims)));

		p = ARR_DATA_PTR(v);
		dims = ARR_DIMS(v);
		nitems = ArrayGetNItems(ndims, dims);
		bitmap = ARR_NULLBITMAP(v);
		get_type_io_data(ARR_ELEMTYPE(v), IOFunc_output,
							&typlen, &typbyval,
							&typalign, &typdelim,
							&typelem, &typiofunc);
		fmgr_info_cxt(typiofunc, &proc, fcinfo->flinfo->fn_mcxt);
	}
	else
	{
		nitems = 0;
		p = NULL;
		bitmap = NULL;
	}

	template_str = VARDATA(template_in);
	template_len = ora_mb_strlen(template_in, &sizes, &positions);
	subst_mb_len = ora_mb_strlen1(c_subst);
	subst_len = VARSIZE_ANY_EXHDR(c_subst);
	sinfo = makeStringInfo();

	bitmask = 1;
	for (i = 0; i < template_len; i++)
	{
		if (strncmp(&template_str[positions[i]], VARDATA(c_subst), subst_len) == 0)
		{
			Datum    itemvalue;
			char     *value;

			if (items++ < nitems)
			{
				if (bitmap && (*bitmap & bitmask) == 0)
					value = pstrdup("NULL");
				else
				{
					itemvalue = fetch_att(p, typbyval, typlen);
					value = DatumGetCString(FunctionCall3(&proc,
								itemvalue,
								ObjectIdGetDatum(typelem),
								Int32GetDatum(-1)));

					p = att_addlength_pointer(p, typlen, p);
					p = (char *) att_align_nominal(p, typalign);
				}
				appendStringInfoString(sinfo, value);
				pfree(value);

				if (bitmap)
				{
					bitmask <<= 1;
					if (bitmask == 0x100)
					{
						bitmap++;
						bitmask = 1;
					}
				}
			}
			else
				ereport(ERROR,
						(errcode(ERRCODE_SYNTAX_ERROR),
						 errmsg("too few parameters specified for template string")));

			i += subst_mb_len - 1;
		}
		else
			appendBinaryStringInfo(sinfo, &template_str[positions[i]], sizes[i]);
	}

	return cstring_to_text(sinfo->data);
}