Пример #1
0
    Datum
turn_restrict_shortest_path_edge(PG_FUNCTION_ARGS)
{

    FuncCallContext     *funcctx;
    uint32_t                  call_cntr;
    uint32_t                  max_calls;
    TupleDesc            tuple_desc;
    path_element_t      *path;
    char *               sql;

    // stuff done only on the first call of the function 
    if (SRF_IS_FIRSTCALL()) {
        MemoryContext   oldcontext;
        size_t path_count = 0;
#ifdef DEBUG
        int ret = -1;
#endif
        int i;
        double s_pos;
        double e_pos;

        // create a function context for cross-call persistence
        funcctx = SRF_FIRSTCALL_INIT();

        // switch to memory context appropriate for multiple function calls
        oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);

        // verify that the first 5 args are not NULL
        for (i=0; i<7; i++) {
            if(i==2 || i==4) continue;
            if(PG_ARGISNULL(i)) {
                elog(ERROR, "turn_restrict_shortest_path(): Argument %i may not be NULL", i+1);
            }
        }

        if (PG_ARGISNULL(2))
            s_pos = 0.5;
        else {
            s_pos = PG_GETARG_FLOAT8(2);
            if (s_pos < 0.0) s_pos = 0.5;
            if (s_pos > 1.0) s_pos = 0.5;
        }

        if (PG_ARGISNULL(4))
            e_pos = 0.5;
        else {
            e_pos = PG_GETARG_FLOAT8(4);
            if (e_pos < 0.0) e_pos = 0.5;
            if (e_pos > 1.0) e_pos = 0.5;
        }

        if (PG_ARGISNULL(7))
            sql = NULL;
        else {
            sql = pgr_text2char(PG_GETARG_TEXT_P(7));
            if (strlen(sql) == 0)
                sql = NULL;
        }

        PGR_DBG("Calling compute_trsp");

#ifdef DEBUG
        ret =
#endif
            compute_trsp(pgr_text2char(PG_GETARG_TEXT_P(0)),
                    0,  //sdo edge
                    PG_GETARG_INT32(1),
                    s_pos,
                    PG_GETARG_INT32(3),
                    e_pos,
                    PG_GETARG_BOOL(5),
                    PG_GETARG_BOOL(6), 
                    sql,
                    &path, &path_count);
#ifdef DEBUG
        double total_cost = 0;
        PGR_DBG("Ret is %i", ret);
        if (ret >= 0) 
        {
            int i;
            for (i = 0; i < path_count; i++) 
            {
                //     PGR_DBG("Step %i vertex_id  %i ", i, path[i].vertex_id);
                //   PGR_DBG("        edge_id    %i ", path[i].edge_id);
                // PGR_DBG("        cost       %f ", path[i].cost);
                total_cost+=path[i].cost;
            }
        }
        PGR_DBG("Total cost is: %f",total_cost);
#endif

        // total number of tuples to be returned 
        funcctx->max_calls = (uint32_t)path_count;
        funcctx->user_fctx = path;

        funcctx->tuple_desc = 
            BlessTupleDesc(RelationNameGetTupleDesc("pgr_costResult"));

        MemoryContextSwitchTo(oldcontext);
    }

    // stuff done on every call of the function 
    funcctx = SRF_PERCALL_SETUP();

    call_cntr = funcctx->call_cntr;
    max_calls = funcctx->max_calls;
    tuple_desc = funcctx->tuple_desc;
    path = (path_element_t*) funcctx->user_fctx;

    if (call_cntr < max_calls)    // do when there is more left to send 
    {
        HeapTuple    tuple;
        Datum        result;
        Datum *values;
        bool* nulls;

        values = palloc(4 * sizeof(Datum));
        nulls = palloc(4 * sizeof(bool));

        values[0] = Int32GetDatum(call_cntr);
        nulls[0] = false;
        values[1] = Int32GetDatum(path[call_cntr].vertex_id);
        nulls[1] = false;
        values[2] = Int32GetDatum(path[call_cntr].edge_id);
        nulls[2] = false;
        values[3] = Float8GetDatum(path[call_cntr].cost);
        nulls[3] = false;

        tuple = heap_form_tuple(tuple_desc, values, nulls);

        // make the tuple into a datum 
        result = HeapTupleGetDatum(tuple);

        // clean up (this is not really necessary) 
        pfree(values);
        pfree(nulls);

        SRF_RETURN_NEXT(funcctx, result);
    }
    else    // do when there is no more left 
    {
        PGR_DBG("Going to free path");
        if (path) free(path);
        SRF_RETURN_DONE(funcctx);
    }
}
Пример #2
0
Datum fft_agg_finalfn(PG_FUNCTION_ARGS)
{
	ArrayType *input, *result = NULL;
	Oid        eltype;
	int16      typlen;
	bool       typbyval;
	char       typalign;
	Datum     *data;
	int        i, n;
	int        ndims, *dims;
  kiss_fft_cfg cfg;
  kiss_fft_cpx *cx_in = NULL, *cx_out = NULL;

	if (!AggCheckCallContext(fcinfo, NULL)) 
		elog(ERROR, "fft_agg_finalfn() Not aggregate context");

	if (PG_ARGISNULL(0))
		elog(ERROR, "fft_agg_finalfn() args cannot be null");

	/* elog(INFO, "fft_agg_finalfn() nargs: %d", PG_NARGS()); */
	/* elog(INFO, "p1 %p", PG_GETARG_POINTER(0)); */

	/* state array */
	input = PG_GETARG_ARRAYTYPE_P(0);

	/* elog(INFO, "arg 0 array type: 0x%p", input); */

	/* get various pieces of data from the input array */
	ndims  = ARR_NDIM(input);
	dims   = ARR_DIMS(input);
	eltype = ARR_ELEMTYPE(input);
	/* elog(INFO, "input ndims: %d dims: %d elemtype: %d", ndims, *dims, eltype); */

  Assert(ndims == 1);
	Assert(eltype == FLOAT4OID);

	/* get input array element type */
	get_typlenbyvalalign(eltype, &typlen, &typbyval, &typalign);
  /* elog(INFO, "olen: %d obyval: %d align: %d", typlen, typbyval, typalign); */

	/* get src data */
	deconstruct_array(input, eltype, typlen, typbyval, typalign, &data, NULL, &n);
  /* elog(INFO, "idata: %p n: %d", data, n); */

	Assert(*dims == n);

	cx_in  = palloc0(*dims * sizeof(kiss_fft_cpx));
	cx_out = palloc0(*dims * sizeof(kiss_fft_cpx));

	/* apply scale */
	for (i=0; i<*dims; i++)  {
	  cx_in[i].r = DatumGetFloat4(data[i]);
    /* elog(INFO, "%d %f %f", i, DatumGetFloat4(data[i]), cx_in[i].i); */
  }

  if ((cfg = kiss_fft_alloc(*dims, 0, 0, 0)) == NULL)
		elog(ERROR, "kiss_fft_alloc() failed");

  kiss_fft(cfg, cx_in, cx_out);

	for (i=0; i<*dims; i++) {
    ((float *)data)[i] = (cx_out[i].r * cx_out[i].r + cx_out[i].i * cx_out[i].i) / ((double)*dims);
    /*
    printf("%23.15e  %23.15e\n", freq / (double)n * (double)i,
		    (cx_out[i].r * cx_out[i].r + cx_out[i].i * cx_out[i].i) / (double)n);
    */
		/* elog(INFO, "data %d %f", i, (double)(data[i])); */
	}

  /*
  elog(INFO, "odata: %p dims: %d otype: %d olen: %d obyval: %d align: %d",
      data, *dims, eltype, typlen, typbyval, typalign);
	*/

	result = construct_array((void *)data, *dims, eltype, typlen, typbyval, typalign);

  free(cfg);

	pfree(data);
	pfree(cx_in);
	pfree(cx_out);

	PG_RETURN_ARRAYTYPE_P(result);
}
Пример #3
0
Datum
pg_file_rename(PG_FUNCTION_ARGS)
{
	char	   *fn1,
			   *fn2,
			   *fn3;
	int			rc;

	requireSuperuser();

	if (PG_ARGISNULL(0) || PG_ARGISNULL(1))
		PG_RETURN_NULL();

	fn1 = convert_and_check_filename(PG_GETARG_TEXT_P(0), false);
	fn2 = convert_and_check_filename(PG_GETARG_TEXT_P(1), false);
	if (PG_ARGISNULL(2))
		fn3 = 0;
	else
		fn3 = convert_and_check_filename(PG_GETARG_TEXT_P(2), false);

	if (access(fn1, W_OK) < 0)
	{
		ereport(WARNING,
				(errcode_for_file_access(),
				 errmsg("file \"%s\" is not accessible: %m", fn1)));

		PG_RETURN_BOOL(false);
	}

	if (fn3 && access(fn2, W_OK) < 0)
	{
		ereport(WARNING,
				(errcode_for_file_access(),
				 errmsg("file \"%s\" is not accessible: %m", fn2)));

		PG_RETURN_BOOL(false);
	}

	rc = access(fn3 ? fn3 : fn2, 2);
	if (rc >= 0 || errno != ENOENT)
	{
		ereport(ERROR,
				(ERRCODE_DUPLICATE_FILE,
				 errmsg("cannot rename to target file \"%s\"",
						fn3 ? fn3 : fn2)));
	}

	if (fn3)
	{
		if (rename(fn2, fn3) != 0)
		{
			ereport(ERROR,
					(errcode_for_file_access(),
					 errmsg("could not rename \"%s\" to \"%s\": %m",
							fn2, fn3)));
		}
		if (rename(fn1, fn2) != 0)
		{
			ereport(WARNING,
					(errcode_for_file_access(),
					 errmsg("could not rename \"%s\" to \"%s\": %m",
							fn1, fn2)));

			if (rename(fn3, fn2) != 0)
			{
				ereport(ERROR,
						(errcode_for_file_access(),
						 errmsg("could not rename \"%s\" back to \"%s\": %m",
								fn3, fn2)));
			}
			else
			{
				ereport(ERROR,
						(ERRCODE_UNDEFINED_FILE,
						 errmsg("renaming \"%s\" to \"%s\" was reverted",
								fn2, fn3)));
			}
		}
	}
	else if (rename(fn1, fn2) != 0)
	{
		ereport(ERROR,
				(errcode_for_file_access(),
				 errmsg("could not rename \"%s\" to \"%s\": %m", fn1, fn2)));
	}

	PG_RETURN_BOOL(true);
}
Пример #4
0
/*! UDA transition function for the fmsketch aggregate. */
Datum __fmsketch_trans(PG_FUNCTION_ARGS)
{
    bytea *     transblob = (bytea *)PG_GETARG_BYTEA_P(0);
    fmtransval *transval;
    Oid         element_type = get_fn_expr_argtype(fcinfo->flinfo, 1);
    Oid         funcOid;
    bool        typIsVarlena;
    Datum       retval;
    Datum       inval;

    if (!OidIsValid(element_type))
        elog(ERROR, "could not determine data type of input");

    /*
     * This is Postgres boilerplate for UDFs that modify the data in their own context.
     * Such UDFs can only be correctly called in an agg context since regular scalar
     * UDFs are essentially stateless across invocations.
     */
    if (!(fcinfo->context &&
          (IsA(fcinfo->context, AggState)
    #ifdef NOTGP
           || IsA(fcinfo->context, WindowAggState)
    #endif
          )))
        elog(
            ERROR,
            "UDF call to a function that only works for aggs (destructive pass by reference)");


    /* get the provided element, being careful in case it's NULL */
    if (!PG_ARGISNULL(1)) {
        inval = PG_GETARG_DATUM(1);

        /*
         * if this is the first call, initialize transval to hold a sortasort
         * on the first call, we should have the empty string (if the agg was declared properly!)
         */
        if (VARSIZE(transblob) <= VARHDRSZ) {
            size_t blobsz = VARHDRSZ + sizeof(fmtransval) +
                            SORTASORT_INITIAL_STORAGE;

            transblob = (bytea *)palloc0(blobsz);
            SET_VARSIZE(transblob, blobsz);
            transval = (fmtransval *)VARDATA(transblob);

            transval->typOid = element_type;
            /* figure out the outfunc for this type */
            getTypeOutputInfo(element_type, &funcOid, &typIsVarlena);
            get_typlenbyval(element_type, &(transval->typLen), &(transval->typByVal));
            transval->status = SMALL;
            sortasort_init((sortasort *)transval->storage,
                           MINVALS,
                           SORTASORT_INITIAL_STORAGE, 
                           transval->typLen,
                           transval->typByVal);
        }
        else {
            /* extract the existing transval from the transblob */
            transval = (fmtransval *)VARDATA(transblob);
        }

        /*
         * if we've seen < MINVALS distinct values, place datum into the sortasort
         * XXXX Would be cleaner to try the sortasort insert and if it fails, then continue.
         */
        if (transval->status == SMALL
            && ((sortasort *)(transval->storage))->num_vals <
            MINVALS) {
            int len = ExtractDatumLen(inval, transval->typLen, transval->typByVal);
            
            retval =
                PointerGetDatum(fmsketch_sortasort_insert(
                                    transblob,
                                    inval, len));
            PG_RETURN_DATUM(retval);
        }

        /*
         * if we've seen exactly MINVALS distinct values, create FM bitmaps
         * and load the contents of the sortasort into the FM sketch
         */
        else if (transval->status == SMALL
                 && ((sortasort *)(transval->storage))->num_vals ==
                 MINVALS) {
            int        i;
            sortasort  *s = (sortasort *)(transval->storage);
            bytea      *newblob = fm_new(transval);
            
            transval = (fmtransval *)VARDATA(newblob);
            
            /*
             * "catch up" on the past as if we were doing FM from the beginning:
             * apply the FM sketching algorithm to each value previously stored in the sortasort
             */
            for (i = 0; i < MINVALS; i++)
                __fmsketch_trans_c(newblob, 
                                   PointerExtractDatum(SORTASORT_GETVAL(s,i), s->typByVal));

            /*
             * XXXX would like to pfree the old transblob, but the memory allocator doesn't like it
             * XXXX Meanwhile we know that this memory "leak" is of fixed size and will get
             * XXXX deallocated "soon" when the memory context is destroyed.
             */
            /* drop through to insert the current datum in "BIG" mode */
            transblob = newblob;
        }

        /*
         * if we're here we've seen >=MINVALS distinct values and are in BIG mode.
         * Just for sanity, let's check.
         */
        if (transval->status != BIG)
            elog(
                ERROR,
                "FM sketch failed internal sanity check");

        /* Apply FM algorithm to this datum */
        retval = __fmsketch_trans_c(transblob, inval);
        PG_RETURN_DATUM(retval);
    }
    else PG_RETURN_NULL();
}
Datum RASTER_dwithin(PG_FUNCTION_ARGS)
{
	const int set_count = 2;
	rt_pgraster *pgrast[2];
	int pgrastpos[2] = {-1, -1};
	rt_raster rast[2] = {NULL};
	uint32_t bandindex[2] = {0};
	uint32_t hasbandindex[2] = {0};
	double distance = 0;

	uint32_t i;
	uint32_t j;
	uint32_t k;
	uint32_t numBands;
	int rtn;
	int result;

	for (i = 0, j = 0; i < set_count; i++) {
		/* pgrast is null, return null */
		if (PG_ARGISNULL(j)) {
			for (k = 0; k < i; k++) {
				rt_raster_destroy(rast[k]);
				PG_FREE_IF_COPY(pgrast[k], pgrastpos[k]);
			}
			PG_RETURN_NULL();
		}
		pgrast[i] = (rt_pgraster *) PG_DETOAST_DATUM(PG_GETARG_DATUM(j));
		pgrastpos[i] = j;
		j++;

		/* raster */
		rast[i] = rt_raster_deserialize(pgrast[i], FALSE);
		if (!rast[i]) {
			for (k = 0; k <= i; k++) {
				if (k < i)
					rt_raster_destroy(rast[k]);
				PG_FREE_IF_COPY(pgrast[k], pgrastpos[k]);
			}
			elog(ERROR, "RASTER_dwithin: Could not deserialize the %s raster", i < 1 ? "first" : "second");
			PG_RETURN_NULL();
		}

		/* numbands */
		numBands = rt_raster_get_num_bands(rast[i]);
		if (numBands < 1) {
			elog(NOTICE, "The %s raster provided has no bands", i < 1 ? "first" : "second");
			if (i > 0) i++;
			for (k = 0; k < i; k++) {
				rt_raster_destroy(rast[k]);
				PG_FREE_IF_COPY(pgrast[k], pgrastpos[k]);
			}
			PG_RETURN_NULL();
		}

		/* band index */
		if (!PG_ARGISNULL(j)) {
			bandindex[i] = PG_GETARG_INT32(j);
			if (bandindex[i] < 1 || bandindex[i] > numBands) {
				elog(NOTICE, "Invalid band index (must use 1-based) for the %s raster. Returning NULL", i < 1 ? "first" : "second");
				if (i > 0) i++;
				for (k = 0; k < i; k++) {
					rt_raster_destroy(rast[k]);
					PG_FREE_IF_COPY(pgrast[k], pgrastpos[k]);
				}
				PG_RETURN_NULL();
			}
			hasbandindex[i] = 1;
		}
		else
			hasbandindex[i] = 0;
		POSTGIS_RT_DEBUGF(4, "hasbandindex[%d] = %d", i, hasbandindex[i]);
		POSTGIS_RT_DEBUGF(4, "bandindex[%d] = %d", i, bandindex[i]);
		j++;
	}

	/* distance */
	if (PG_ARGISNULL(4)) {
		elog(NOTICE, "Distance cannot be NULL.  Returning NULL");
		for (k = 0; k < set_count; k++) {
			rt_raster_destroy(rast[k]);
			PG_FREE_IF_COPY(pgrast[k], pgrastpos[k]);
		}
		PG_RETURN_NULL();
	}

	distance = PG_GETARG_FLOAT8(4);
	if (distance < 0) {
		elog(NOTICE, "Distance cannot be less than zero.  Returning NULL");
		for (k = 0; k < set_count; k++) {
			rt_raster_destroy(rast[k]);
			PG_FREE_IF_COPY(pgrast[k], pgrastpos[k]);
		}
		PG_RETURN_NULL();
	}

	/* hasbandindex must be balanced */
	if (
		(hasbandindex[0] && !hasbandindex[1]) ||
		(!hasbandindex[0] && hasbandindex[1])
	) {
		elog(NOTICE, "Missing band index.  Band indices must be provided for both rasters if any one is provided");
		for (k = 0; k < set_count; k++) {
			rt_raster_destroy(rast[k]);
			PG_FREE_IF_COPY(pgrast[k], pgrastpos[k]);
		}
		PG_RETURN_NULL();
	}

	/* SRID must match */
	if (rt_raster_get_srid(rast[0]) != rt_raster_get_srid(rast[1])) {
		for (k = 0; k < set_count; k++) {
			rt_raster_destroy(rast[k]);
			PG_FREE_IF_COPY(pgrast[k], pgrastpos[k]);
		}
		elog(ERROR, "The two rasters provided have different SRIDs");
		PG_RETURN_NULL();
	}

	rtn = rt_raster_within_distance(
		rast[0], (hasbandindex[0] ? bandindex[0] - 1 : -1),
		rast[1], (hasbandindex[1] ? bandindex[1] - 1 : -1),
		distance,
		&result
	);
	for (k = 0; k < set_count; k++) {
		rt_raster_destroy(rast[k]);
		PG_FREE_IF_COPY(pgrast[k], pgrastpos[k]);
	}

	if (rtn != ES_NONE) {
		elog(ERROR, "RASTER_dwithin: Could not test that the two rasters are within the specified distance of each other");
		PG_RETURN_NULL();
	}

	PG_RETURN_BOOL(result);
}
Пример #6
0
/*
 * similar_escape()
 * Convert a SQL:2008 regexp pattern to POSIX style, so it can be used by
 * our regexp engine.
 */
Datum
similar_escape(PG_FUNCTION_ARGS)
{
	text	   *pat_text;
	text	   *esc_text;
	text	   *result;
	char	   *p,
			   *e,
			   *r;
	int			plen,
				elen;
	bool		afterescape = false;
	bool		incharclass = false;
	int			nquotes = 0;

	/* This function is not strict, so must test explicitly */
	if (PG_ARGISNULL(0))
		PG_RETURN_NULL();
	pat_text = PG_GETARG_TEXT_PP(0);
	p = VARDATA_ANY(pat_text);
	plen = VARSIZE_ANY_EXHDR(pat_text);
	if (PG_ARGISNULL(1))
	{
		/* No ESCAPE clause provided; default to backslash as escape */
		e = "\\";
		elen = 1;
	}
	else
	{
		esc_text = PG_GETARG_TEXT_PP(1);
		e = VARDATA_ANY(esc_text);
		elen = VARSIZE_ANY_EXHDR(esc_text);
		if (elen == 0)
			e = NULL;			/* no escape character */
		else
		{
			int			escape_mblen = pg_mbstrlen_with_len(e, elen);

			if (escape_mblen > 1)
				ereport(ERROR,
						(errcode(ERRCODE_INVALID_ESCAPE_SEQUENCE),
						 errmsg("invalid escape string"),
						 errhint("Escape string must be empty or one character.")));
		}
	}

	/*----------
	 * We surround the transformed input string with
	 *			^(?: ... )$
	 * which requires some explanation.  We need "^" and "$" to force
	 * the pattern to match the entire input string as per SQL99 spec.
	 * The "(?:" and ")" are a non-capturing set of parens; we have to have
	 * parens in case the string contains "|", else the "^" and "$" will
	 * be bound into the first and last alternatives which is not what we
	 * want, and the parens must be non capturing because we don't want them
	 * to count when selecting output for SUBSTRING.
	 *----------
	 */

	/*
	 * We need room for the prefix/postfix plus as many as 3 output bytes per
	 * input byte; since the input is at most 1GB this can't overflow
	 */
	result = (text *) palloc(VARHDRSZ + 6 + 3 * plen);
	r = VARDATA(result);

	*r++ = '^';
	*r++ = '(';
	*r++ = '?';
	*r++ = ':';

	while (plen > 0)
	{
		char		pchar = *p;

		/*
		 * If both the escape character and the current character from the
		 * pattern are multi-byte, we need to take the slow path.
		 *
		 * But if one of them is single-byte, we can process the pattern one
		 * byte at a time, ignoring multi-byte characters.  (This works
		 * because all server-encodings have the property that a valid
		 * multi-byte character representation cannot contain the
		 * representation of a valid single-byte character.)
		 */

		if (elen > 1)
		{
			int mblen = pg_mblen(p);
			if (mblen > 1)
			{
				/* slow, multi-byte path */
				if (afterescape)
				{
					*r++ = '\\';
					memcpy(r, p, mblen);
					r += mblen;
					afterescape = false;
				}
				else if (e && elen == mblen && memcmp(e, p, mblen) == 0)
				{
					/* SQL99 escape character; do not send to output */
					afterescape = true;
				}
				else
				{
					/*
					 * We know it's a multi-byte character, so we don't need
					 * to do all the comparisons to single-byte characters
					 * that we do below.
					 */
					memcpy(r, p, mblen);
					r += mblen;
				}

				p += mblen;
				plen -= mblen;

				continue;
			}
		}

		/* fast path */
		if (afterescape)
		{
			if (pchar == '"' && !incharclass)	/* for SUBSTRING patterns */
				*r++ = ((nquotes++ % 2) == 0) ? '(' : ')';
			else
			{
				*r++ = '\\';
				*r++ = pchar;
			}
			afterescape = false;
		}
		else if (e && pchar == *e)
		{
			/* SQL99 escape character; do not send to output */
			afterescape = true;
		}
		else if (incharclass)
		{
			if (pchar == '\\')
				*r++ = '\\';
			*r++ = pchar;
			if (pchar == ']')
				incharclass = false;
		}
		else if (pchar == '[')
		{
			*r++ = pchar;
			incharclass = true;
		}
		else if (pchar == '%')
		{
			*r++ = '.';
			*r++ = '*';
		}
		else if (pchar == '_')
			*r++ = '.';
		else if (pchar == '(')
		{
			/* convert to non-capturing parenthesis */
			*r++ = '(';
			*r++ = '?';
			*r++ = ':';
		}
		else if (pchar == '\\' || pchar == '.' ||
				 pchar == '^' || pchar == '$')
		{
			*r++ = '\\';
			*r++ = pchar;
		}
		else
			*r++ = pchar;
		p++, plen--;
	}

	*r++ = ')';
	*r++ = '$';

	SET_VARSIZE(result, r - ((char *) result));

	PG_RETURN_TEXT_P(result);
}
Пример #7
0
Datum
hstore_from_record(PG_FUNCTION_ARGS)
{
	HeapTupleHeader rec;
	int32		buflen;
	HStore	   *out;
	Pairs	   *pairs;
	Oid			tupType;
	int32		tupTypmod;
	TupleDesc	tupdesc;
	HeapTupleData tuple;
	RecordIOData *my_extra;
	int			ncolumns;
	int			i,
				j;
	Datum	   *values;
	bool	   *nulls;

	if (PG_ARGISNULL(0))
	{
		Oid			argtype = get_fn_expr_argtype(fcinfo->flinfo, 0);

		/*
		 * have no tuple to look at, so the only source of type info is the
		 * argtype. The lookup_rowtype_tupdesc call below will error out if we
		 * don't have a known composite type oid here.
		 */
		tupType = argtype;
		tupTypmod = -1;

		rec = NULL;
	}
	else
	{
		rec = PG_GETARG_HEAPTUPLEHEADER(0);

		/* Extract type info from the tuple itself */
		tupType = HeapTupleHeaderGetTypeId(rec);
		tupTypmod = HeapTupleHeaderGetTypMod(rec);
	}

	tupdesc = lookup_rowtype_tupdesc(tupType, tupTypmod);
	ncolumns = tupdesc->natts;

	/*
	 * We arrange to look up the needed I/O info just once per series of
	 * calls, assuming the record type doesn't change underneath us.
	 */
	my_extra = (RecordIOData *) fcinfo->flinfo->fn_extra;
	if (my_extra == NULL ||
		my_extra->ncolumns != ncolumns)
	{
		fcinfo->flinfo->fn_extra =
			MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
							   sizeof(RecordIOData) - sizeof(ColumnIOData)
							   + ncolumns * sizeof(ColumnIOData));
		my_extra = (RecordIOData *) fcinfo->flinfo->fn_extra;
		my_extra->record_type = InvalidOid;
		my_extra->record_typmod = 0;
	}

	if (my_extra->record_type != tupType ||
		my_extra->record_typmod != tupTypmod)
	{
		MemSet(my_extra, 0,
			   sizeof(RecordIOData) - sizeof(ColumnIOData)
			   + ncolumns * sizeof(ColumnIOData));
		my_extra->record_type = tupType;
		my_extra->record_typmod = tupTypmod;
		my_extra->ncolumns = ncolumns;
	}

	Assert(ncolumns <= MaxTupleAttributeNumber);		/* thus, no overflow */
	pairs = palloc(ncolumns * sizeof(Pairs));

	if (rec)
	{
		/* Build a temporary HeapTuple control structure */
		tuple.t_len = HeapTupleHeaderGetDatumLength(rec);
		ItemPointerSetInvalid(&(tuple.t_self));
		tuple.t_tableOid = InvalidOid;
		tuple.t_data = rec;

		values = (Datum *) palloc(ncolumns * sizeof(Datum));
		nulls = (bool *) palloc(ncolumns * sizeof(bool));

		/* Break down the tuple into fields */
		heap_deform_tuple(&tuple, tupdesc, values, nulls);
	}
	else
	{
		values = NULL;
		nulls = NULL;
	}

	for (i = 0, j = 0; i < ncolumns; ++i)
	{
		ColumnIOData *column_info = &my_extra->columns[i];
		Oid			column_type = tupdesc->attrs[i]->atttypid;
		char	   *value;

		/* Ignore dropped columns in datatype */
		if (tupdesc->attrs[i]->attisdropped)
			continue;

		pairs[j].key = NameStr(tupdesc->attrs[i]->attname);
		pairs[j].keylen = hstoreCheckKeyLen(strlen(NameStr(tupdesc->attrs[i]->attname)));

		if (!nulls || nulls[i])
		{
			pairs[j].val = NULL;
			pairs[j].vallen = 4;
			pairs[j].isnull = true;
			pairs[j].needfree = false;
			++j;
			continue;
		}

		/*
		 * Convert the column value to text
		 */
		if (column_info->column_type != column_type)
		{
			bool		typIsVarlena;

			getTypeOutputInfo(column_type,
							  &column_info->typiofunc,
							  &typIsVarlena);
			fmgr_info_cxt(column_info->typiofunc, &column_info->proc,
						  fcinfo->flinfo->fn_mcxt);
			column_info->column_type = column_type;
		}

		value = OutputFunctionCall(&column_info->proc, values[i]);

		pairs[j].val = value;
		pairs[j].vallen = hstoreCheckValLen(strlen(value));
		pairs[j].isnull = false;
		pairs[j].needfree = false;
		++j;
	}

	ncolumns = hstoreUniquePairs(pairs, j, &buflen);

	out = hstorePairs(pairs, ncolumns, buflen);

	ReleaseTupleDesc(tupdesc);

	PG_RETURN_POINTER(out);
}
Пример #8
0
/*
 * The step function for aggregating the class counts while doing Reduce Error Pruning (REP).
 *
 * Parameters:
 *      class_count_array   The array used to store the accumulated information.
 *                          [0]: the total number of mis-classified cases
 *                          [i]: the number of cases belonging to the ith class
 *      classified_class    The predicted class based on our trained DT model.
 *      original_class      The real class value provided in the validation set.
 *      max_num_of_classes  The total number of distinct class values.
 * Return:
 *      An updated state array.
 */
Datum rep_aggr_class_count_sfunc(PG_FUNCTION_ARGS)
{
    ArrayType *class_count_array    = NULL;
    int array_dim                   = 0;
    int *p_array_dim                = NULL;
    int array_length                = 0;
    int64 *class_count_data         = NULL;
    int classified_class    		= PG_GETARG_INT32(1);
    int original_class      		= PG_GETARG_INT32(2);
    int max_num_of_classes  		= PG_GETARG_INT32(3);
    bool need_reconstruct_array     = false;


    check_error_value
		(
			max_num_of_classes >= 2,
			"invalid value: %d. The number of classes must be greater than or equal to 2",
			max_num_of_classes
		);

    check_error_value
		(
			original_class > 0 && original_class <= max_num_of_classes,
			"invalid real class value: %d. It must be in range from 1 to the number of classes",
			original_class
		);

    check_error_value
		(
			classified_class > 0 && classified_class <= max_num_of_classes,
			"invalid classified class value: %d. It must be in range from 1 to the number of classes",
			classified_class
		);
    
    /* test if the first argument (class count array) is null */
    if (PG_ARGISNULL(0))
    {
    	/*
    	 * We assume the maximum number of classes is limited (up to millions),
    	 * so that the allocated array won't break our memory limitation.
    	 */
        class_count_data		= palloc0(sizeof(int64) * (max_num_of_classes + 1));
        array_length 			= max_num_of_classes + 1;
        need_reconstruct_array 	= true;

    }
    else
    {
        if (fcinfo->context && IsA(fcinfo->context, AggState))
            class_count_array = PG_GETARG_ARRAYTYPE_P(0);
        else
            class_count_array = PG_GETARG_ARRAYTYPE_P_COPY(0);
        
        check_error
    		(
    			class_count_array,
    			"invalid aggregation state array"
    		);

        array_dim = ARR_NDIM(class_count_array);

        check_error_value
    		(
    			array_dim == 1,
    			"invalid array dimension: %d. The dimension of class count array must be equal to 1",
    			array_dim
    		);

        p_array_dim         = ARR_DIMS(class_count_array);
        array_length        = ArrayGetNItems(array_dim,p_array_dim);
        class_count_data    = (int64 *)ARR_DATA_PTR(class_count_array);

        check_error_value
    		(
    			array_length == max_num_of_classes + 1,
    			"invalid array length: %d. The length of class count array must be equal to the total number classes + 1",
    			array_length
    		);
    }

    /*
     * If the condition is met, then the current record has been mis-classified.
     * Therefore, we will need to increase the first element.
     */
    if(original_class != classified_class)
        ++class_count_data[0];

    /* In any case, we will update the original class count */
    ++class_count_data[original_class];

    if( need_reconstruct_array )
    {
        /* construct a new array to keep the aggr states. */
        class_count_array =
        	construct_array(
        		(Datum *)class_count_data,
                array_length,
                INT8OID,
                sizeof(int64),
                true,
                'd'
                );

    }
    PG_RETURN_ARRAYTYPE_P(class_count_array);
}
Пример #9
0
/*
 * The pre-function for REP. It takes two class count arrays
 * produced by the sfunc and combine them together.
 *
 * Parameters:
 *      1 arg:         The array returned by sfun1
 *      2 arg:         The array returned by sfun2
 * Return:
 *      The array with the combined information
 */
Datum rep_aggr_class_count_prefunc(PG_FUNCTION_ARGS)
{
    ArrayType *class_count_array    = NULL;
    int array_dim                   = 0;
    int *p_array_dim                = NULL;
    int array_length                = 0;
    int64 *class_count_data         = NULL;

    ArrayType *class_count_array2   = NULL;
    int array_dim2                  = 0;
    int *p_array_dim2               = NULL;
    int array_length2               = 0;
    int64 *class_count_data2        = NULL;

    if (PG_ARGISNULL(0) && PG_ARGISNULL(1))
        PG_RETURN_NULL();
    else
    if (PG_ARGISNULL(1) || PG_ARGISNULL(0))
    {
        /* If one of the two array is null, just return the non-null array directly */
    	PG_RETURN_ARRAYTYPE_P(PG_ARGISNULL(1) ? PG_GETARG_ARRAYTYPE_P(0) : PG_GETARG_ARRAYTYPE_P(1));
    }
    else
    {
        /*
         *  If both arrays are not null, we will merge them together.
         */
        if (fcinfo->context && IsA(fcinfo->context, AggState))
            class_count_array = PG_GETARG_ARRAYTYPE_P(0);
        else
            class_count_array = PG_GETARG_ARRAYTYPE_P_COPY(0);
        
        check_error
    		(
    			class_count_array,
    			"invalid aggregation state array"
    		);

        array_dim = ARR_NDIM(class_count_array);

        check_error_value
    		(
    			array_dim == 1,
    			"invalid array dimension: %d. The dimension of class count array must be equal to 1",
    			array_dim
    		);

        p_array_dim             = ARR_DIMS(class_count_array);
        array_length            = ArrayGetNItems(array_dim,p_array_dim);
        class_count_data        = (int64 *)ARR_DATA_PTR(class_count_array);

        class_count_array2      = PG_GETARG_ARRAYTYPE_P(1);
        array_dim2              = ARR_NDIM(class_count_array2);
        check_error_value
    		(
    			array_dim2 == 1,
    			"invalid array dimension: %d. The dimension of class count array must be equal to 1",
    			array_dim2
    		);

        p_array_dim2            = ARR_DIMS(class_count_array2);
        array_length2           = ArrayGetNItems(array_dim2,p_array_dim2);
        class_count_data2       = (int64 *)ARR_DATA_PTR(class_count_array2);

        check_error
    		(
    			array_length == array_length2,
    			"the size of the two array must be the same in prefunction"
    		);

        for (int index = 0; index < array_length; index++)
            class_count_data[index] += class_count_data2[index];

        PG_RETURN_ARRAYTYPE_P(class_count_array);
    }

}
Пример #10
0
/*
 * pg_prewarm(regclass, mode text, fork text,
 *			  first_block int8, last_block int8)
 *
 * The first argument is the relation to be prewarmed; the second controls
 * how prewarming is done; legal options are 'prefetch', 'read', and 'buffer'.
 * The third is the name of the relation fork to be prewarmed.  The fourth
 * and fifth arguments specify the first and last block to be prewarmed.
 * If the fourth argument is NULL, it will be taken as 0; if the fifth argument
 * is NULL, it will be taken as the number of blocks in the relation.  The
 * return value is the number of blocks successfully prewarmed.
 */
Datum
pg_prewarm(PG_FUNCTION_ARGS)
{
	Oid			relOid;
	text	   *forkName;
	text	   *type;
	int64		first_block;
	int64		last_block;
	int64		nblocks;
	int64		blocks_done = 0;
	int64		block;
	Relation	rel;
	ForkNumber	forkNumber;
	char	   *forkString;
	char	   *ttype;
	PrewarmType ptype;
	AclResult	aclresult;

	/* Basic sanity checking. */
	if (PG_ARGISNULL(0))
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
				 errmsg("relation cannot be null")));
	relOid = PG_GETARG_OID(0);
	if (PG_ARGISNULL(1))
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
				 (errmsg("prewarm type cannot be null"))));
	type = PG_GETARG_TEXT_P(1);
	ttype = text_to_cstring(type);
	if (strcmp(ttype, "prefetch") == 0)
		ptype = PREWARM_PREFETCH;
	else if (strcmp(ttype, "read") == 0)
		ptype = PREWARM_READ;
	else if (strcmp(ttype, "buffer") == 0)
		ptype = PREWARM_BUFFER;
	else
	{
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
				 errmsg("invalid prewarm type"),
				 errhint("Valid prewarm types are \"prefetch\", \"read\", and \"buffer\".")));
		PG_RETURN_INT64(0);		/* Placate compiler. */
	}
	if (PG_ARGISNULL(2))
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
				 (errmsg("relation fork cannot be null"))));
	forkName = PG_GETARG_TEXT_P(2);
	forkString = text_to_cstring(forkName);
	forkNumber = forkname_to_number(forkString);

	/* Open relation and check privileges. */
	rel = relation_open(relOid, AccessShareLock);
	aclresult = pg_class_aclcheck(relOid, GetUserId(), ACL_SELECT);
	if (aclresult != ACLCHECK_OK)
		aclcheck_error(aclresult, ACL_KIND_CLASS, get_rel_name(relOid));

	/* Check that the fork exists. */
	RelationOpenSmgr(rel);
	if (!smgrexists(rel->rd_smgr, forkNumber))
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
				 errmsg("fork \"%s\" does not exist for this relation",
						forkString)));

	/* Validate block numbers, or handle nulls. */
	nblocks = RelationGetNumberOfBlocksInFork(rel, forkNumber);
	if (PG_ARGISNULL(3))
		first_block = 0;
	else
	{
		first_block = PG_GETARG_INT64(3);
		if (first_block < 0 || first_block >= nblocks)
			ereport(ERROR,
					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
					 errmsg("starting block number must be between 0 and " INT64_FORMAT,
							nblocks - 1)));
	}
	if (PG_ARGISNULL(4))
		last_block = nblocks - 1;
	else
	{
		last_block = PG_GETARG_INT64(4);
		if (last_block < 0 || last_block >= nblocks)
			ereport(ERROR,
					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
			errmsg("ending block number must be between 0 and " INT64_FORMAT,
				   nblocks - 1)));
	}

	/* Now we're ready to do the real work. */
	if (ptype == PREWARM_PREFETCH)
	{
#ifdef USE_PREFETCH

		/*
		 * In prefetch mode, we just hint the OS to read the blocks, but we
		 * don't know whether it really does it, and we don't wait for it to
		 * finish.
		 *
		 * It would probably be better to pass our prefetch requests in chunks
		 * of a megabyte or maybe even a whole segment at a time, but there's
		 * no practical way to do that at present without a gross modularity
		 * violation, so we just do this.
		 */
		for (block = first_block; block <= last_block; ++block)
		{
			CHECK_FOR_INTERRUPTS();
			PrefetchBuffer(rel, forkNumber, block);
			++blocks_done;
		}
#else
		ereport(ERROR,
				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
				 errmsg("prefetch is not supported by this build")));
#endif
	}
	else if (ptype == PREWARM_READ)
	{
		/*
		 * In read mode, we actually read the blocks, but not into shared
		 * buffers.  This is more portable than prefetch mode (it works
		 * everywhere) and is synchronous.
		 */
		for (block = first_block; block <= last_block; ++block)
		{
			CHECK_FOR_INTERRUPTS();
			smgrread(rel->rd_smgr, forkNumber, block, blockbuffer);
			++blocks_done;
		}
	}
	else if (ptype == PREWARM_BUFFER)
	{
		/*
		 * In buffer mode, we actually pull the data into shared_buffers.
		 */
		for (block = first_block; block <= last_block; ++block)
		{
			Buffer		buf;

			CHECK_FOR_INTERRUPTS();
			buf = ReadBufferExtended(rel, forkNumber, block, RBM_NORMAL, NULL);
			ReleaseBuffer(buf);
			++blocks_done;
		}
	}

	/* Close relation, release lock. */
	relation_close(rel, AccessShareLock);

	PG_RETURN_INT64(blocks_done);
}
Пример #11
0
Файл: file.c Проект: 50wu/gpdb
/*
 * FUNCTION UTL_FILE.FOPEN(location text,
 *			   filename text,
 *			   open_mode text,
 *			   max_linesize integer)
 *          RETURNS UTL_FILE.FILE_TYPE;
 *
 * The FOPEN function opens specified file and returns file handle.
 *  open_mode: ['R', 'W', 'A']
 *  max_linesize: [1 .. 32767]
 *
 * Exceptions:
 *  INVALID_MODE, INVALID_OPERATION, INVALID_PATH, INVALID_MAXLINESIZE
 */
Datum
utl_file_fopen(PG_FUNCTION_ARGS)
{
	text	   *open_mode;
	int			max_linesize;
	int			encoding;
	const char *mode = NULL;
	FILE	   *file;
	char	   *fullname;
	int			d;

	NOT_NULL_ARG(0);
	NOT_NULL_ARG(1);
	NOT_NULL_ARG(2);
	NOT_NULL_ARG(3);

	open_mode = PG_GETARG_TEXT_P(2);

	NON_EMPTY_TEXT(open_mode);

	max_linesize = PG_GETARG_INT32(3);
	CHECK_LINESIZE(max_linesize);

	if (PG_NARGS() > 4 && !PG_ARGISNULL(4))
	{
		const char *encname = NameStr(*PG_GETARG_NAME(4));
		encoding = pg_char_to_encoding(encname);
		if (encoding < 0)
			ereport(ERROR,
				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
				 errmsg("invalid encoding name \"%s\"", encname)));
	}
	else
		encoding = GetDatabaseEncoding();

	if (VARSIZE(open_mode) - VARHDRSZ != 1)
		CUSTOM_EXCEPTION(INVALID_MODE, "open mode is different than [R,W,A]");

	switch (*((char*)VARDATA(open_mode)))
	{
		case 'a':
		case 'A':
			mode = "a";
			break;

		case 'r':
		case 'R':
			mode = "r";
			break;

		case 'w':
		case 'W':
			mode = "w";
			break;

		default:
			CUSTOM_EXCEPTION(INVALID_MODE, "open mode is different than [R,W,A]");
	}

	/* open file */
	fullname = get_safe_path(PG_GETARG_TEXT_P(0), PG_GETARG_TEXT_P(1));

	/*
	 * We cannot use AllocateFile here because those files are automatically
	 * closed at the end of (sub)transactions, but we want to keep them open
	 * for oracle compatibility.
	 */
#if NOT_USED
	fullname = convert_encoding_server_to_platform(fullname);
#endif
	file = fopen(fullname, mode);
	if (!file)
		IO_EXCEPTION();

	d = get_descriptor(file, max_linesize, encoding);
	if (d == INVALID_SLOTID)
	{
		fclose(file);
		ereport(ERROR,
		    (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
		     errmsg("program limit exceeded"),
		     errdetail("Too much concurent opened files"),
		     errhint("You can only open a maximum of ten files for each session")));
	}

	PG_RETURN_INT32(d);
}
Пример #12
0
/*
 * Helper function for the various SQL callable logical decoding functions.
 */
static Datum
pg_logical_slot_get_changes_guts(FunctionCallInfo fcinfo, bool confirm, bool binary)
{
	Name		name;
	XLogRecPtr	upto_lsn;
	int32		upto_nchanges;
	ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
	MemoryContext per_query_ctx;
	MemoryContext oldcontext;
	XLogRecPtr	end_of_wal;
	XLogRecPtr	startptr;
	LogicalDecodingContext *ctx;
	ResourceOwner old_resowner = CurrentResourceOwner;
	ArrayType  *arr;
	Size		ndim;
	List	   *options = NIL;
	DecodingOutputState *p;

	check_permissions();

	CheckLogicalDecodingRequirements();

	if (PG_ARGISNULL(0))
		ereport(ERROR,
				(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
				 errmsg("slot name must not be null")));
	name = PG_GETARG_NAME(0);

	if (PG_ARGISNULL(1))
		upto_lsn = InvalidXLogRecPtr;
	else
		upto_lsn = PG_GETARG_LSN(1);

	if (PG_ARGISNULL(2))
		upto_nchanges = InvalidXLogRecPtr;
	else
		upto_nchanges = PG_GETARG_INT32(2);

	if (PG_ARGISNULL(3))
		ereport(ERROR,
				(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
				 errmsg("options array must not be null")));
	arr = PG_GETARG_ARRAYTYPE_P(3);

	/* check to see if caller supports us returning a tuplestore */
	if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
		ereport(ERROR,
				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
				 errmsg("set-valued function called in context that cannot accept a set")));
	if (!(rsinfo->allowedModes & SFRM_Materialize))
		ereport(ERROR,
				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
				 errmsg("materialize mode required, but it is not allowed in this context")));

	/* state to write output to */
	p = palloc0(sizeof(DecodingOutputState));

	p->binary_output = binary;

	/* Build a tuple descriptor for our result type */
	if (get_call_result_type(fcinfo, NULL, &p->tupdesc) != TYPEFUNC_COMPOSITE)
		elog(ERROR, "return type must be a row type");

	per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
	oldcontext = MemoryContextSwitchTo(per_query_ctx);

	/* Deconstruct options array */
	ndim = ARR_NDIM(arr);
	if (ndim > 1)
	{
		ereport(ERROR,
				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
				 errmsg("array must be one-dimensional")));
	}
	else if (array_contains_nulls(arr))
	{
		ereport(ERROR,
				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
				 errmsg("array must not contain nulls")));
	}
	else if (ndim == 1)
	{
		int			nelems;
		Datum	   *datum_opts;
		int			i;

		Assert(ARR_ELEMTYPE(arr) == TEXTOID);

		deconstruct_array(arr, TEXTOID, -1, false, 'i',
						  &datum_opts, NULL, &nelems);

		if (nelems % 2 != 0)
			ereport(ERROR,
					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
					 errmsg("array must have even number of elements")));

		for (i = 0; i < nelems; i += 2)
		{
			char	   *name = TextDatumGetCString(datum_opts[i]);
			char	   *opt = TextDatumGetCString(datum_opts[i + 1]);

			options = lappend(options, makeDefElem(name, (Node *) makeString(opt), -1));
		}
	}

	p->tupstore = tuplestore_begin_heap(true, false, work_mem);
	rsinfo->returnMode = SFRM_Materialize;
	rsinfo->setResult = p->tupstore;
	rsinfo->setDesc = p->tupdesc;

	/*
	 * Compute the current end-of-wal and maintain ThisTimeLineID.
	 * RecoveryInProgress() will update ThisTimeLineID on promotion.
	 */
	if (!RecoveryInProgress())
		end_of_wal = GetFlushRecPtr();
	else
		end_of_wal = GetXLogReplayRecPtr(&ThisTimeLineID);

	ReplicationSlotAcquire(NameStr(*name));

	PG_TRY();
	{
		/* restart at slot's confirmed_flush */
		ctx = CreateDecodingContext(InvalidXLogRecPtr,
									options,
									logical_read_local_xlog_page,
									LogicalOutputPrepareWrite,
									LogicalOutputWrite);

		MemoryContextSwitchTo(oldcontext);

		/*
		 * Check whether the output plugin writes textual output if that's
		 * what we need.
		 */
		if (!binary &&
			ctx->options.output_type !=OUTPUT_PLUGIN_TEXTUAL_OUTPUT)
			ereport(ERROR,
					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
					 errmsg("logical decoding output plugin \"%s\" produces binary output, but function \"%s\" expects textual data",
							NameStr(MyReplicationSlot->data.plugin),
							format_procedure(fcinfo->flinfo->fn_oid))));

		ctx->output_writer_private = p;

		/*
		 * Decoding of WAL must start at restart_lsn so that the entirety of
		 * xacts that committed after the slot's confirmed_flush can be
		 * accumulated into reorder buffers.
		 */
		startptr = MyReplicationSlot->data.restart_lsn;

		CurrentResourceOwner = ResourceOwnerCreate(CurrentResourceOwner, "logical decoding");

		/* invalidate non-timetravel entries */
		InvalidateSystemCaches();

		/* Decode until we run out of records */
		while ((startptr != InvalidXLogRecPtr && startptr < end_of_wal) ||
			   (ctx->reader->EndRecPtr != InvalidXLogRecPtr && ctx->reader->EndRecPtr < end_of_wal))
		{
			XLogRecord *record;
			char	   *errm = NULL;

			record = XLogReadRecord(ctx->reader, startptr, &errm);
			if (errm)
				elog(ERROR, "%s", errm);

			/*
			 * Now that we've set up the xlog reader state, subsequent calls
			 * pass InvalidXLogRecPtr to say "continue from last record"
			 */
			startptr = InvalidXLogRecPtr;

			/*
			 * The {begin_txn,change,commit_txn}_wrapper callbacks above will
			 * store the description into our tuplestore.
			 */
			if (record != NULL)
				LogicalDecodingProcessRecord(ctx, ctx->reader);

			/* check limits */
			if (upto_lsn != InvalidXLogRecPtr &&
				upto_lsn <= ctx->reader->EndRecPtr)
				break;
			if (upto_nchanges != 0 &&
				upto_nchanges <= p->returned_rows)
				break;
			CHECK_FOR_INTERRUPTS();
		}

		tuplestore_donestoring(tupstore);

		CurrentResourceOwner = old_resowner;

		/*
		 * Next time, start where we left off. (Hunting things, the family
		 * business..)
		 */
		if (ctx->reader->EndRecPtr != InvalidXLogRecPtr && confirm)
		{
			LogicalConfirmReceivedLocation(ctx->reader->EndRecPtr);
			/*
			 * If only the confirmed_flush_lsn has changed the slot won't get
			 * marked as dirty by the above. Callers on the walsender interface
			 * are expected to keep track of their own progress and don't need
			 * it written out. But SQL-interface users cannot specify their own
			 * start positions and it's harder for them to keep track of their
			 * progress, so we should make more of an effort to save it for them.
			 *
			 * Dirty the slot so it's written out at the next checkpoint. We'll
			 * still lose its position on crash, as documented, but it's better
			 * than always losing the position even on clean restart.
			 */
			ReplicationSlotMarkDirty();
		}

		/* free context, call shutdown callback */
		FreeDecodingContext(ctx);

		ReplicationSlotRelease();
		InvalidateSystemCaches();
	}
	PG_CATCH();
	{
		/* clear all timetravel entries */
		InvalidateSystemCaches();

		PG_RE_THROW();
	}
	PG_END_TRY();

	return (Datum) 0;
}
Пример #13
0
Datum array_mad(PG_FUNCTION_ARGS) {
	// The formal PostgreSQL array object
	ArrayType *array;

	// The array element type
	Oid arrayElementType;

	// The array element type width
	int16 arrayElementTypeWidth;

	// The array element type "is passed by value" flags (not used, should always be true)
	bool arrayElementTypeByValue;

	// The array element type alignment codes (not used)
	char arrayElementTypeAlignmentCode;

	// The array contents, as PostgreSQL "datum" objects
	Datum *arrayContent;

	// List of "is null" flags for the array contents
	bool *arrayNullFlags;

	// The size of each array
	int arrayLength;

	int i,j, nelem;
	double median, mad;
	double *inarray;

	if (PG_ARGISNULL(0)) 
		ereport(ERROR, (errmsg("Null arrays not accepted")));

	// Get array from input
	array = PG_GETARG_ARRAYTYPE_P(0);

	if (ARR_NDIM(array) != 1) 
		ereport(ERROR, (errmsg("One-dimesional arrays are required")));

	if (array_contains_nulls(array)) 
		ereport(ERROR, (errmsg("Array contains null elements")));

	arrayLength = (ARR_DIMS(array))[0];
	arrayElementType = ARR_ELEMTYPE(array);
	get_typlenbyvalalign(arrayElementType, &arrayElementTypeWidth, &arrayElementTypeByValue, &arrayElementTypeAlignmentCode);
	deconstruct_array(array, arrayElementType, arrayElementTypeWidth, arrayElementTypeByValue, arrayElementTypeAlignmentCode, &arrayContent, &arrayNullFlags, &arrayLength);
	
	inarray = (double*)malloc(arrayLength*sizeof(double));  
	for (i=0; i<arrayLength; i++) {
		inarray[i] = DatumGetFloat4(arrayContent[i]);
	}

	gsl_sort (inarray, 1, arrayLength);

	median = gsl_stats_median_from_sorted_data (inarray, 1, arrayLength);
	for (i=0; i<arrayLength; i++) {
		inarray[i] = fabs(inarray[i]-median);
	}
	gsl_sort (inarray, 1, arrayLength);
	mad = 1.486 * gsl_stats_median_from_sorted_data (inarray, 1, arrayLength);

	PG_RETURN_FLOAT8(mad);
}
Пример #14
0
Datum
dbms_pipe_create_pipe (PG_FUNCTION_ARGS)
{
	text *pipe_name = NULL;
	int   limit = 0;
	bool  is_private;
	bool  limit_is_valid = false;
	bool  created;
	float8 endtime;
	int cycle = 0;
	int timeout = 10;

	if (PG_ARGISNULL(0))
		ereport(ERROR,
				(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
				 errmsg("pipe name is NULL"),
				 errdetail("Pipename may not be NULL.")));
	else
		pipe_name = PG_GETARG_TEXT_P(0);

	if (!PG_ARGISNULL(1))
	{
		limit = PG_GETARG_INT32(1);
		limit_is_valid = true;
	}

	is_private = PG_ARGISNULL(2) ? false : PG_GETARG_BOOL(2);

	WATCH_PRE(timeout, endtime, cycle);
	if (ora_lock_shmem(SHMEMMSGSZ, MAX_PIPES,MAX_EVENTS,MAX_LOCKS,false))
	{
		pipe *p;
		if (NULL != (p = find_pipe(pipe_name, &created, false)))
		{
			if (!created)
			{
				LWLockRelease(shmem_lockid);
				ereport(ERROR,
						(errcode(ERRCODE_DUPLICATE_OBJECT),
						 errmsg("pipe creation error"),
						 errdetail("Pipe is registered.")));
			}
			if (is_private)
			{
				char *user;

				p->uid = GetUserId();

#if PG_VERSION_NUM >= 90500

				user = (char*)DirectFunctionCall1(namein,
					    CStringGetDatum(GetUserNameFromId(p->uid, false)));

#else

				user = (char*)DirectFunctionCall1(namein, CStringGetDatum(GetUserNameFromId(p->uid)));
#endif

				p->creator = ora_sstrcpy(user);
				pfree(user);
			}
			p->limit = limit_is_valid ? limit : -1;
			p->registered = true;

			LWLockRelease(shmem_lockid);
			PG_RETURN_VOID();
		}
	}
	WATCH_POST(timeout, endtime, cycle);
	LOCK_ERROR();

	PG_RETURN_VOID();
}
Пример #15
0
Datum 
text_unpivot(PG_FUNCTION_ARGS)
{
	FuncCallContext      *funcctx;
	unpivot_fctx         *fctx;
	MemoryContext         oldcontext;
	Datum                 d[2];
	bool                  isna[2];

	/* stuff done only on the first call of the function */
	if (SRF_IS_FIRSTCALL())
	{
		TupleDesc  tupdesc;
		ArrayType *labels;
		ArrayType *data;
		Oid        eltype1;
		Oid        eltype2;

		/* see if we were given an explicit step size */
		if (PG_NARGS() != 2)
			ereport(ERROR,
					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
					 errmsg("number of parameters != 2")));

		/* 
		 * Type check inputs:
		 *    0: label text[]
		 *    1: value anyarray
		 */
		eltype1 = get_fn_expr_argtype(fcinfo->flinfo, 0);
		eltype2 = get_fn_expr_argtype(fcinfo->flinfo, 1);

		if (!OidIsValid(eltype1))
			elog(ERROR, "could not determine data type of input 'label'");
		if (!OidIsValid(eltype2))
			elog(ERROR, "could not determine data type of input 'value'");

		/* Strict function, return null on null input */
		if (PG_ARGISNULL(0) || PG_ARGISNULL(1))
			PG_RETURN_NULL();
		
		/* create a function context for cross-call persistence */
		funcctx = SRF_FIRSTCALL_INIT();

		/* switch to memory context appropriate for multiple function calls */
		oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);

        /* Build a tuple descriptor for our result type */
        if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
            ereport(ERROR,
                    (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                     errmsg("function returning record called in context "
                            "that cannot accept type record")));
		funcctx->tuple_desc = BlessTupleDesc(tupdesc);

		/* allocate memory for user context */
		fctx = (unpivot_fctx *) palloc(sizeof(unpivot_fctx));

		/* Use fctx to keep state from call to call */
		labels = PG_GETARG_ARRAYTYPE_P(0);
		data   = PG_GETARG_ARRAYTYPE_P(1);
		array_loop(labels, ARR_LBOUND(labels)[0], &fctx->label_iter);
		array_loop(data,   ARR_LBOUND(labels)[0], &fctx->data_iter);		

		funcctx->user_fctx = fctx;
		MemoryContextSwitchTo(oldcontext);
	}

	/* stuff done on every call of the function */
	funcctx = SRF_PERCALL_SETUP();

	/* get the saved state and use current as the result for this iteration */
	fctx = (unpivot_fctx*) funcctx->user_fctx;

	if (array_next(&fctx->label_iter, &d[0], &isna[0]))
	{
		HeapTuple tuple;

		array_next(&fctx->data_iter, &d[1], &isna[1]);
		tuple = heap_form_tuple(funcctx->tuple_desc, d, isna);
		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));		
	}
	else
	{
		SRF_RETURN_DONE(funcctx);
	}
}
Пример #16
0
/*
 * The step function for the aggregation of splitting criteria values. It accumulates
 * all the information for scv calculation and stores to a fourteen element array.  
 *
 * Parameters:
 *      scv_state_array    The array used to accumulate all the information for the 
 *                         calculation of splitting criteria values. Please refer to
 *                         the definition of SCV_STATE_ARRAY_INDEX.
 *      split_criterion    1- infogain; 2- gainratio; 3- gini.
 *      feature_val        The feature value of current record under processing.
 *      class              The class of current record under processing.
 *      is_cont_feature    True- The feature is continuous. False- The feature is
 *                         discrete.
 *      less               Count of elements less than or equal to feature_val.
 *      great              Count of elements greater than feature_val.
 *      true_total_count   If there is any missing value, true_total_count is larger than
 *                         the total count computed in the aggregation. Thus, we should  
 *                         multiply a ratio for the computed gain.
 * Return:
 *      A fourteen element array. Please refer to the definition of 
 *      SCV_STATE_ARRAY_INDEX for the detailed information of this
 *      array.
 */
Datum scv_aggr_sfunc(PG_FUNCTION_ARGS)
{
    ArrayType*	scv_state_array	= NULL;
    if (fcinfo->context && IsA(fcinfo->context, AggState))
        scv_state_array = PG_GETARG_ARRAYTYPE_P(0);
    else
        scv_state_array = PG_GETARG_ARRAYTYPE_P_COPY(0);

	check_error
		(
			scv_state_array,
			"invalid aggregation state array"
		);

    int	 array_dim 		= ARR_NDIM(scv_state_array);

    check_error_value
		(
			array_dim == 1,
			"invalid array dimension: %d. The dimension of scv state array must be equal to 1",
			array_dim
		);

    int* p_array_dim	= ARR_DIMS(scv_state_array);
    int  array_length	= ArrayGetNItems(array_dim, p_array_dim);

    check_error_value
		(
			array_length == SCV_STATE_MAX_CLASS_ELEM_COUNT + 1,
			"invalid array length: %d",
			array_length
		);

    float8 *scv_state_data = (float8 *)ARR_DATA_PTR(scv_state_array);
	check_error
		(
			scv_state_data,
			"invalid aggregation data array"
		);

    int    split_criterion		= PG_GETARG_INT32(1);
    bool   is_null_fval         = PG_ARGISNULL(2);
    float8 feature_val			= PG_GETARG_FLOAT8(2);
    float8 class				= PG_ARGISNULL(3) ? -1 : PG_GETARG_FLOAT8(3);
    bool   is_cont_feature 		= PG_ARGISNULL(4) ? false : PG_GETARG_BOOL(4);
    float8 less					= PG_ARGISNULL(5) ? 0 : PG_GETARG_FLOAT8(5);
    float8 great				= PG_ARGISNULL(6) ? 0 : PG_GETARG_FLOAT8(6);
    float8 true_total_count 	= PG_ARGISNULL(7) ? 0 : PG_GETARG_FLOAT8(7);

	check_error_value
		(
			(SC_INFOGAIN  == split_criterion ||
			SC_GAINRATIO  == split_criterion ||
			SC_GINI       == split_criterion),
			"invalid split criterion: %d. It must be 1(infogain), 2(gainratio) or 3(gini)",
			split_criterion
		);

    /*
     *  If the count for total element is still zero
     *  it is the first time that step function is
     *  invoked. In that case, we should initialize
     *  several elements.
     */ 
    if (is_float_zero(scv_state_data[SCV_STATE_TOTAL_ELEM_COUNT]))
    {
        scv_state_data[SCV_STATE_SPLIT_CRIT] 		= split_criterion;
        if (SC_GINI      == split_criterion)
        {
            scv_state_data[SCV_STATE_INIT_SCV] 	    = 1;
        }
        else
        {
            scv_state_data[SCV_STATE_INIT_SCV] 	    = 0;
        }
        scv_state_data[SCV_STATE_IS_CONT] 			= is_cont_feature ? 1 : 0;
        scv_state_data[SCV_STATE_TRUE_TOTAL_COUNT] 	= true_total_count;
        dtelog(NOTICE,"true_total_count:%lf",true_total_count);
    }

    float8 temp_float = 0;

    if( is_null_fval )
    {
        dtelog(NOTICE,"is_null_fval:%d",is_null_fval);
        if( !is_cont_feature ) 
        {
            if(  class <0 )
            {
                scv_state_data[SCV_STATE_TOTAL_ELEM_COUNT] = less;
                dtelog(NOTICE,"SCV_STATE_TOTAL_ELEM_COUNT:%lf",less);
            }
            else
            {
                if (scv_state_data[SCV_STATE_MAX_CLASS_ELEM_COUNT] < less)
                {
                    scv_state_data[SCV_STATE_MAX_CLASS_ELEM_COUNT] = less;
                    scv_state_data[SCV_STATE_MAX_CLASS_ID] = class;
                }
                accumulate_pre_split_scv(
                        scv_state_data, 
                        less, 
                        scv_state_data[SCV_STATE_TOTAL_ELEM_COUNT],
                        split_criterion);
            }
        }
Пример #17
0
/*
 * Returns activity of PG backends.
 */
Datum
pg_stat_get_activity(PG_FUNCTION_ARGS)
{
#define PG_STAT_GET_ACTIVITY_COLS	23
	int			num_backends = pgstat_fetch_stat_numbackends();
	int			curr_backend;
	int			pid = PG_ARGISNULL(0) ? -1 : PG_GETARG_INT32(0);
	ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
	TupleDesc	tupdesc;
	Tuplestorestate *tupstore;
	MemoryContext per_query_ctx;
	MemoryContext oldcontext;

	/* check to see if caller supports us returning a tuplestore */
	if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
		ereport(ERROR,
				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
				 errmsg("set-valued function called in context that cannot accept a set")));
	if (!(rsinfo->allowedModes & SFRM_Materialize))
		ereport(ERROR,
				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
				 errmsg("materialize mode required, but it is not " \
						"allowed in this context")));

	/* Build a tuple descriptor for our result type */
	if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
		elog(ERROR, "return type must be a row type");

	per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
	oldcontext = MemoryContextSwitchTo(per_query_ctx);

	tupstore = tuplestore_begin_heap(true, false, work_mem);
	rsinfo->returnMode = SFRM_Materialize;
	rsinfo->setResult = tupstore;
	rsinfo->setDesc = tupdesc;

	MemoryContextSwitchTo(oldcontext);

	/* 1-based index */
	for (curr_backend = 1; curr_backend <= num_backends; curr_backend++)
	{
		/* for each row */
		Datum		values[PG_STAT_GET_ACTIVITY_COLS];
		bool		nulls[PG_STAT_GET_ACTIVITY_COLS];
		LocalPgBackendStatus *local_beentry;
		PgBackendStatus *beentry;
		PGPROC	   *proc;
		const char *wait_event_type;
		const char *wait_event;

		MemSet(values, 0, sizeof(values));
		MemSet(nulls, 0, sizeof(nulls));

		if (pid != -1)
		{
			/* Skip any which are not the one we're looking for. */
			PgBackendStatus *be = pgstat_fetch_stat_beentry(curr_backend);

			if (!be || be->st_procpid != pid)
				continue;

		}

		/* Get the next one in the list */
		local_beentry = pgstat_fetch_stat_local_beentry(curr_backend);
		if (!local_beentry)
			continue;

		beentry = &local_beentry->backendStatus;
		if (!beentry)
		{
			int			i;

			for (i = 0; i < sizeof(nulls) / sizeof(nulls[0]); i++)
				nulls[i] = true;

			nulls[5] = false;
			values[5] = CStringGetTextDatum("<backend information not available>");

			tuplestore_putvalues(tupstore, tupdesc, values, nulls);
			continue;
		}

		/* Values available to all callers */
		values[0] = ObjectIdGetDatum(beentry->st_databaseid);
		values[1] = Int32GetDatum(beentry->st_procpid);
		values[2] = ObjectIdGetDatum(beentry->st_userid);
		if (beentry->st_appname)
			values[3] = CStringGetTextDatum(beentry->st_appname);
		else
			nulls[3] = true;

		if (TransactionIdIsValid(local_beentry->backend_xid))
			values[15] = TransactionIdGetDatum(local_beentry->backend_xid);
		else
			nulls[15] = true;

		if (TransactionIdIsValid(local_beentry->backend_xmin))
			values[16] = TransactionIdGetDatum(local_beentry->backend_xmin);
		else
			nulls[16] = true;

		if (beentry->st_ssl)
		{
			values[17] = BoolGetDatum(true);	/* ssl */
			values[18] = CStringGetTextDatum(beentry->st_sslstatus->ssl_version);
			values[19] = CStringGetTextDatum(beentry->st_sslstatus->ssl_cipher);
			values[20] = Int32GetDatum(beentry->st_sslstatus->ssl_bits);
			values[21] = BoolGetDatum(beentry->st_sslstatus->ssl_compression);
			values[22] = CStringGetTextDatum(beentry->st_sslstatus->ssl_clientdn);
		}
		else
		{
			values[17] = BoolGetDatum(false);	/* ssl */
			nulls[18] = nulls[19] = nulls[20] = nulls[21] = nulls[22] = true;
		}

		/* Values only available to role member */
		if (has_privs_of_role(GetUserId(), beentry->st_userid))
		{
			SockAddr	zero_clientaddr;

			switch (beentry->st_state)
			{
				case STATE_IDLE:
					values[4] = CStringGetTextDatum("idle");
					break;
				case STATE_RUNNING:
					values[4] = CStringGetTextDatum("active");
					break;
				case STATE_IDLEINTRANSACTION:
					values[4] = CStringGetTextDatum("idle in transaction");
					break;
				case STATE_FASTPATH:
					values[4] = CStringGetTextDatum("fastpath function call");
					break;
				case STATE_IDLEINTRANSACTION_ABORTED:
					values[4] = CStringGetTextDatum("idle in transaction (aborted)");
					break;
				case STATE_DISABLED:
					values[4] = CStringGetTextDatum("disabled");
					break;
				case STATE_UNDEFINED:
					nulls[4] = true;
					break;
			}

			values[5] = CStringGetTextDatum(beentry->st_activity);

			proc = BackendPidGetProc(beentry->st_procpid);
			wait_event_type = pgstat_get_wait_event_type(proc->wait_event_info);
			if (wait_event_type)
				values[6] = CStringGetTextDatum(wait_event_type);
			else
				nulls[6] = true;

			wait_event = pgstat_get_wait_event(proc->wait_event_info);
			if (wait_event)
				values[7] = CStringGetTextDatum(wait_event);
			else
				nulls[7] = true;

			if (beentry->st_xact_start_timestamp != 0)
				values[8] = TimestampTzGetDatum(beentry->st_xact_start_timestamp);
			else
				nulls[8] = true;

			if (beentry->st_activity_start_timestamp != 0)
				values[9] = TimestampTzGetDatum(beentry->st_activity_start_timestamp);
			else
				nulls[9] = true;

			if (beentry->st_proc_start_timestamp != 0)
				values[10] = TimestampTzGetDatum(beentry->st_proc_start_timestamp);
			else
				nulls[10] = true;

			if (beentry->st_state_start_timestamp != 0)
				values[11] = TimestampTzGetDatum(beentry->st_state_start_timestamp);
			else
				nulls[11] = true;

			/* A zeroed client addr means we don't know */
			memset(&zero_clientaddr, 0, sizeof(zero_clientaddr));
			if (memcmp(&(beentry->st_clientaddr), &zero_clientaddr,
					   sizeof(zero_clientaddr)) == 0)
			{
				nulls[12] = true;
				nulls[13] = true;
				nulls[14] = true;
			}
			else
			{
				if (beentry->st_clientaddr.addr.ss_family == AF_INET
#ifdef HAVE_IPV6
					|| beentry->st_clientaddr.addr.ss_family == AF_INET6
#endif
					)
				{
					char		remote_host[NI_MAXHOST];
					char		remote_port[NI_MAXSERV];
					int			ret;

					remote_host[0] = '\0';
					remote_port[0] = '\0';
					ret = pg_getnameinfo_all(&beentry->st_clientaddr.addr,
											 beentry->st_clientaddr.salen,
											 remote_host, sizeof(remote_host),
											 remote_port, sizeof(remote_port),
											 NI_NUMERICHOST | NI_NUMERICSERV);
					if (ret == 0)
					{
						clean_ipv6_addr(beentry->st_clientaddr.addr.ss_family, remote_host);
						values[12] = DirectFunctionCall1(inet_in,
											   CStringGetDatum(remote_host));
						if (beentry->st_clienthostname &&
							beentry->st_clienthostname[0])
							values[13] = CStringGetTextDatum(beentry->st_clienthostname);
						else
							nulls[13] = true;
						values[14] = Int32GetDatum(atoi(remote_port));
					}
					else
					{
						nulls[12] = true;
						nulls[13] = true;
						nulls[14] = true;
					}
				}
				else if (beentry->st_clientaddr.addr.ss_family == AF_UNIX)
				{
					/*
					 * Unix sockets always reports NULL for host and -1 for
					 * port, so it's possible to tell the difference to
					 * connections we have no permissions to view, or with
					 * errors.
					 */
					nulls[12] = true;
					nulls[13] = true;
					values[14] = DatumGetInt32(-1);
				}
				else
				{
					/* Unknown address type, should never happen */
					nulls[12] = true;
					nulls[13] = true;
					nulls[14] = true;
				}
			}
		}
		else
		{
			/* No permissions to view data about this session */
			values[5] = CStringGetTextDatum("<insufficient privilege>");
			nulls[4] = true;
			nulls[6] = true;
			nulls[7] = true;
			nulls[8] = true;
			nulls[9] = true;
			nulls[10] = true;
			nulls[11] = true;
			nulls[12] = true;
			nulls[13] = true;
			nulls[14] = true;
		}

		tuplestore_putvalues(tupstore, tupdesc, values, nulls);

		/* If only a single backend was requested, and we found it, break. */
		if (pid != -1)
			break;
	}

	/* clean up and return the tuplestore */
	tuplestore_donestoring(tupstore);

	return (Datum) 0;
}
Пример #18
0
Datum
spell_init(PG_FUNCTION_ARGS)
{
	DictISpell *d;
	Map		   *cfg,
			   *pcfg;
	text	   *in;
	bool		affloaded = false,
				dictloaded = false,
				stoploaded = false;

	if (PG_ARGISNULL(0) || PG_GETARG_POINTER(0) == NULL)
		ereport(ERROR,
				(errcode(ERRCODE_CONFIG_FILE_ERROR),
				 errmsg("ISpell confguration error")));

	d = (DictISpell *) malloc(sizeof(DictISpell));
	if (!d)
		ereport(ERROR,
				(errcode(ERRCODE_OUT_OF_MEMORY),
				 errmsg("out of memory")));
	memset(d, 0, sizeof(DictISpell));
	d->stoplist.wordop = lowerstr;

	in = PG_GETARG_TEXT_P(0);
	parse_cfgdict(in, &cfg);
	PG_FREE_IF_COPY(in, 0);
	pcfg = cfg;
	while (pcfg->key)
	{
		if (strcasecmp("DictFile", pcfg->key) == 0)
		{
			if (dictloaded)
			{
				freeDictISpell(d);
				ereport(ERROR,
					  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
					   errmsg("dictionary already loaded")));
			}
			if (ImportDictionary(&(d->obj), pcfg->value))
			{
				freeDictISpell(d);
				ereport(ERROR,
						(errcode(ERRCODE_CONFIG_FILE_ERROR),
						 errmsg("could not load dictionary file \"%s\"",
								pcfg->value)));
			}
			dictloaded = true;
		}
		else if (strcasecmp("AffFile", pcfg->key) == 0)
		{
			if (affloaded)
			{
				freeDictISpell(d);
				ereport(ERROR,
					  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
					   errmsg("affixes already loaded")));
			}
			if (ImportAffixes(&(d->obj), pcfg->value))
			{
				freeDictISpell(d);
				ereport(ERROR,
						(errcode(ERRCODE_CONFIG_FILE_ERROR),
						 errmsg("could not load affix file \"%s\"",
								pcfg->value)));
			}
			affloaded = true;
		}
		else if (strcasecmp("StopFile", pcfg->key) == 0)
		{
			text	   *tmp = char2text(pcfg->value);

			if (stoploaded)
			{
				freeDictISpell(d);
				ereport(ERROR,
					  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
					   errmsg("stop words already loaded")));
			}
			readstoplist(tmp, &(d->stoplist));
			sortstoplist(&(d->stoplist));
			pfree(tmp);
			stoploaded = true;
		}
		else
		{
			freeDictISpell(d);
			ereport(ERROR,
					(errcode(ERRCODE_SYNTAX_ERROR),
					 errmsg("unrecognized option: %s => %s",
							pcfg->key, pcfg->value)));
		}
		pfree(pcfg->key);
		pfree(pcfg->value);
		pcfg++;
	}
	pfree(cfg);

	if (affloaded && dictloaded)
	{
		SortDictionary(&(d->obj));
		SortAffixes(&(d->obj));
	}
	else if (!affloaded)
	{
		freeDictISpell(d);
		ereport(ERROR,
				(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
				 errmsg("no affixes")));
	}
	else
	{
		freeDictISpell(d);
		ereport(ERROR,
				(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
				 errmsg("no dictionary")));
	}

	PG_RETURN_POINTER(d);
}
Пример #19
0
Datum
hstore_from_arrays(PG_FUNCTION_ARGS)
{
	int32		buflen;
	HStore	   *out;
	Pairs	   *pairs;
	Datum	   *key_datums;
	bool	   *key_nulls;
	int			key_count;
	Datum	   *value_datums;
	bool	   *value_nulls;
	int			value_count;
	ArrayType  *key_array;
	ArrayType  *value_array;
	int			i;

	if (PG_ARGISNULL(0))
		PG_RETURN_NULL();

	key_array = PG_GETARG_ARRAYTYPE_P(0);

	Assert(ARR_ELEMTYPE(key_array) == TEXTOID);

	/*
	 * must check >1 rather than != 1 because empty arrays have 0 dimensions,
	 * not 1
	 */

	if (ARR_NDIM(key_array) > 1)
		ereport(ERROR,
				(errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
				 errmsg("wrong number of array subscripts")));

	deconstruct_array(key_array,
					  TEXTOID, -1, false, 'i',
					  &key_datums, &key_nulls, &key_count);

	/* see discussion in hstoreArrayToPairs() */
	if (key_count > MaxAllocSize / sizeof(Pairs))
		ereport(ERROR,
				(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
			  errmsg("number of pairs (%d) exceeds the maximum allowed (%d)",
					 key_count, (int) (MaxAllocSize / sizeof(Pairs)))));

	/* value_array might be NULL */

	if (PG_ARGISNULL(1))
	{
		value_array = NULL;
		value_count = key_count;
		value_datums = NULL;
		value_nulls = NULL;
	}
	else
	{
		value_array = PG_GETARG_ARRAYTYPE_P(1);

		Assert(ARR_ELEMTYPE(value_array) == TEXTOID);

		if (ARR_NDIM(value_array) > 1)
			ereport(ERROR,
					(errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
					 errmsg("wrong number of array subscripts")));

		if ((ARR_NDIM(key_array) > 0 || ARR_NDIM(value_array) > 0) &&
			(ARR_NDIM(key_array) != ARR_NDIM(value_array) ||
			 ARR_DIMS(key_array)[0] != ARR_DIMS(value_array)[0] ||
			 ARR_LBOUND(key_array)[0] != ARR_LBOUND(value_array)[0]))
			ereport(ERROR,
					(errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
					 errmsg("arrays must have same bounds")));

		deconstruct_array(value_array,
						  TEXTOID, -1, false, 'i',
						  &value_datums, &value_nulls, &value_count);

		Assert(key_count == value_count);
	}

	pairs = palloc(key_count * sizeof(Pairs));

	for (i = 0; i < key_count; ++i)
	{
		if (key_nulls[i])
			ereport(ERROR,
					(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
					 errmsg("null value not allowed for hstore key")));

		if (!value_nulls || value_nulls[i])
		{
			pairs[i].key = VARDATA_ANY(key_datums[i]);
			pairs[i].val = NULL;
			pairs[i].keylen = hstoreCheckKeyLen(VARSIZE_ANY_EXHDR(key_datums[i]));
			pairs[i].vallen = 4;
			pairs[i].isnull = true;
			pairs[i].needfree = false;
		}
		else
		{
			pairs[i].key = VARDATA_ANY(key_datums[i]);
			pairs[i].val = VARDATA_ANY(value_datums[i]);
			pairs[i].keylen = hstoreCheckKeyLen(VARSIZE_ANY_EXHDR(key_datums[i]));
			pairs[i].vallen = hstoreCheckValLen(VARSIZE_ANY_EXHDR(value_datums[i]));
			pairs[i].isnull = false;
			pairs[i].needfree = false;
		}
	}

	key_count = hstoreUniquePairs(pairs, key_count, &buflen);

	out = hstorePairs(pairs, key_count, buflen);

	PG_RETURN_POINTER(out);
}
Пример #20
0
Datum
tuple_data_split(PG_FUNCTION_ARGS)
{
	Oid			relid;
	bytea	   *raw_data;
	uint16		t_infomask;
	uint16		t_infomask2;
	char	   *t_bits_str;
	bool		do_detoast = false;
	bits8	   *t_bits = NULL;
	Datum		res;

	relid = PG_GETARG_OID(0);
	raw_data = PG_ARGISNULL(1) ? NULL : PG_GETARG_BYTEA_P(1);
	t_infomask = PG_GETARG_INT16(2);
	t_infomask2 = PG_GETARG_INT16(3);
	t_bits_str = PG_ARGISNULL(4) ? NULL :
		text_to_cstring(PG_GETARG_TEXT_PP(4));

	if (PG_NARGS() >= 6)
		do_detoast = PG_GETARG_BOOL(5);

	if (!superuser())
		ereport(ERROR,
				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
				 errmsg("must be superuser to use raw page functions")));

	if (!raw_data)
		PG_RETURN_NULL();

	/*
	 * Convert t_bits string back to the bits8 array as represented in the
	 * tuple header.
	 */
	if (t_infomask & HEAP_HASNULL)
	{
		int			bits_str_len;
		int			bits_len;

		bits_len = (t_infomask2 & HEAP_NATTS_MASK) / 8 + 1;
		if (!t_bits_str)
			ereport(ERROR,
					(errcode(ERRCODE_DATA_CORRUPTED),
					 errmsg("argument of t_bits is null, but it is expected to be null and %d character long",
							bits_len * 8)));

		bits_str_len = strlen(t_bits_str);
		if ((bits_str_len % 8) != 0)
			ereport(ERROR,
					(errcode(ERRCODE_DATA_CORRUPTED),
					 errmsg("length of t_bits is not a multiple of eight")));

		if (bits_len * 8 != bits_str_len)
			ereport(ERROR,
					(errcode(ERRCODE_DATA_CORRUPTED),
					 errmsg("unexpected length of t_bits %u, expected %d",
							bits_str_len, bits_len * 8)));

		/* do the conversion */
		t_bits = text_to_bits(t_bits_str, bits_str_len);
	}
	else
	{
		if (t_bits_str)
			ereport(ERROR,
					(errcode(ERRCODE_DATA_CORRUPTED),
					 errmsg("t_bits string is expected to be NULL, but instead it is %zu bytes length",
							strlen(t_bits_str))));
	}

	/* Split tuple data */
	res = tuple_data_split_internal(relid, (char *) raw_data + VARHDRSZ,
									VARSIZE(raw_data) - VARHDRSZ,
									t_infomask, t_infomask2, t_bits,
									do_detoast);

	if (t_bits)
		pfree(t_bits);

	PG_RETURN_ARRAYTYPE_P(res);
}
Пример #21
0
Datum
hstore_populate_record(PG_FUNCTION_ARGS)
{
	Oid			argtype = get_fn_expr_argtype(fcinfo->flinfo, 0);
	HStore	   *hs;
	HEntry	   *entries;
	char	   *ptr;
	HeapTupleHeader rec;
	Oid			tupType;
	int32		tupTypmod;
	TupleDesc	tupdesc;
	HeapTupleData tuple;
	HeapTuple	rettuple;
	RecordIOData *my_extra;
	int			ncolumns;
	int			i;
	Datum	   *values;
	bool	   *nulls;

	if (!type_is_rowtype(argtype))
		ereport(ERROR,
				(errcode(ERRCODE_DATATYPE_MISMATCH),
				 errmsg("first argument must be a rowtype")));

	if (PG_ARGISNULL(0))
	{
		if (PG_ARGISNULL(1))
			PG_RETURN_NULL();

		rec = NULL;

		/*
		 * have no tuple to look at, so the only source of type info is the
		 * argtype. The lookup_rowtype_tupdesc call below will error out if we
		 * don't have a known composite type oid here.
		 */
		tupType = argtype;
		tupTypmod = -1;
	}
	else
	{
		rec = PG_GETARG_HEAPTUPLEHEADER(0);

		if (PG_ARGISNULL(1))
			PG_RETURN_POINTER(rec);

		/* Extract type info from the tuple itself */
		tupType = HeapTupleHeaderGetTypeId(rec);
		tupTypmod = HeapTupleHeaderGetTypMod(rec);
	}

	hs = PG_GETARG_HS(1);
	entries = ARRPTR(hs);
	ptr = STRPTR(hs);

	/*
	 * if the input hstore is empty, we can only skip the rest if we were
	 * passed in a non-null record, since otherwise there may be issues with
	 * domain nulls.
	 */

	if (HS_COUNT(hs) == 0 && rec)
		PG_RETURN_POINTER(rec);

	tupdesc = lookup_rowtype_tupdesc(tupType, tupTypmod);
	ncolumns = tupdesc->natts;

	if (rec)
	{
		/* Build a temporary HeapTuple control structure */
		tuple.t_len = HeapTupleHeaderGetDatumLength(rec);
		ItemPointerSetInvalid(&(tuple.t_self));
		tuple.t_tableOid = InvalidOid;
		tuple.t_data = rec;
	}

	/*
	 * We arrange to look up the needed I/O info just once per series of
	 * calls, assuming the record type doesn't change underneath us.
	 */
	my_extra = (RecordIOData *) fcinfo->flinfo->fn_extra;
	if (my_extra == NULL ||
		my_extra->ncolumns != ncolumns)
	{
		fcinfo->flinfo->fn_extra =
			MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
							   sizeof(RecordIOData) - sizeof(ColumnIOData)
							   + ncolumns * sizeof(ColumnIOData));
		my_extra = (RecordIOData *) fcinfo->flinfo->fn_extra;
		my_extra->record_type = InvalidOid;
		my_extra->record_typmod = 0;
	}

	if (my_extra->record_type != tupType ||
		my_extra->record_typmod != tupTypmod)
	{
		MemSet(my_extra, 0,
			   sizeof(RecordIOData) - sizeof(ColumnIOData)
			   + ncolumns * sizeof(ColumnIOData));
		my_extra->record_type = tupType;
		my_extra->record_typmod = tupTypmod;
		my_extra->ncolumns = ncolumns;
	}

	values = (Datum *) palloc(ncolumns * sizeof(Datum));
	nulls = (bool *) palloc(ncolumns * sizeof(bool));

	if (rec)
	{
		/* Break down the tuple into fields */
		heap_deform_tuple(&tuple, tupdesc, values, nulls);
	}
	else
	{
		for (i = 0; i < ncolumns; ++i)
		{
			values[i] = (Datum) 0;
			nulls[i] = true;
		}
	}

	for (i = 0; i < ncolumns; ++i)
	{
		ColumnIOData *column_info = &my_extra->columns[i];
		Oid			column_type = tupdesc->attrs[i]->atttypid;
		char	   *value;
		int			idx;
		int			vallen;

		/* Ignore dropped columns in datatype */
		if (tupdesc->attrs[i]->attisdropped)
		{
			nulls[i] = true;
			continue;
		}

		idx = hstoreFindKey(hs, 0,
							NameStr(tupdesc->attrs[i]->attname),
							strlen(NameStr(tupdesc->attrs[i]->attname)));

		/*
		 * we can't just skip here if the key wasn't found since we might have
		 * a domain to deal with. If we were passed in a non-null record
		 * datum, we assume that the existing values are valid (if they're
		 * not, then it's not our fault), but if we were passed in a null,
		 * then every field which we don't populate needs to be run through
		 * the input function just in case it's a domain type.
		 */
		if (idx < 0 && rec)
			continue;

		/*
		 * Prepare to convert the column value from text
		 */
		if (column_info->column_type != column_type)
		{
			getTypeInputInfo(column_type,
							 &column_info->typiofunc,
							 &column_info->typioparam);
			fmgr_info_cxt(column_info->typiofunc, &column_info->proc,
						  fcinfo->flinfo->fn_mcxt);
			column_info->column_type = column_type;
		}

		if (idx < 0 || HS_VALISNULL(entries, idx))
		{
			/*
			 * need InputFunctionCall to happen even for nulls, so that domain
			 * checks are done
			 */
			values[i] = InputFunctionCall(&column_info->proc, NULL,
										  column_info->typioparam,
										  tupdesc->attrs[i]->atttypmod);
			nulls[i] = true;
		}
		else
		{
			vallen = HS_VALLEN(entries, idx);
			value = palloc(1 + vallen);
			memcpy(value, HS_VAL(entries, ptr, idx), vallen);
			value[vallen] = 0;

			values[i] = InputFunctionCall(&column_info->proc, value,
										  column_info->typioparam,
										  tupdesc->attrs[i]->atttypmod);
			nulls[i] = false;
		}
	}

	rettuple = heap_form_tuple(tupdesc, values, nulls);

	ReleaseTupleDesc(tupdesc);

	PG_RETURN_DATUM(HeapTupleGetDatum(rettuple));
}
Пример #22
0
/*
 * Preliminary segment-level calculation function for multi-linear regression
 * aggregates.
 */
Datum
float8_mregr_combine(PG_FUNCTION_ARGS)
{
	ArrayType  *state1, *state2, *result;
	float8     *state1Data, *state2Data, *resultData;
	uint32     len;
	uint64     statelen, i;
	Size       size;
	
	/* We should be strict, but it doesn't hurt to be paranoid */
	if (PG_ARGISNULL(0))
	{
		if (PG_ARGISNULL(1))
			PG_RETURN_NULL();
		PG_RETURN_ARRAYTYPE_P(PG_GETARG_ARRAYTYPE_P(1));
	}
	if (PG_ARGISNULL(1))
		PG_RETURN_ARRAYTYPE_P(PG_GETARG_ARRAYTYPE_P(0));
	
	state1 = PG_GETARG_ARRAYTYPE_P(0);	
	state2 = PG_GETARG_ARRAYTYPE_P(1);
	
	/* Ensure that both arrays are single dimensional float8[] arrays */
	if (ARR_NULLBITMAP(state1) || ARR_NULLBITMAP(state2) || 
		ARR_NDIM(state1) != 1 || ARR_NDIM(state2) != 1 || 
		ARR_ELEMTYPE(state1) != FLOAT8OID || ARR_ELEMTYPE(state2) != FLOAT8OID)
	{
		ereport(ERROR, 
				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
				 errmsg("preliminary segment-level calculation function \"%s\" called with invalid parameters",
					format_procedure(fcinfo->flinfo->fn_oid))));
	}
	
	/* 
	 * Remember that we initialized to {0}, so if either array is still at
	 * the initial value then just return the other one 
	 */
	if (ARR_DIMS(state1)[0] == 1)
		PG_RETURN_ARRAYTYPE_P(state2);
	if (ARR_DIMS(state2)[0] == 1)
		PG_RETURN_ARRAYTYPE_P(state1);
	
	state1Data = (float8*) ARR_DATA_PTR(state1);
	state2Data = (float8*) ARR_DATA_PTR(state2);
	
	if (ARR_DIMS(state1)[0] != ARR_DIMS(state2)[0] || 
		state1Data[0] != state2Data[0])
	{
		ereport(ERROR, 
				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
				 errmsg("preliminary segment-level calculation function \"%s\" called with invalid parameters",
					format_procedure(fcinfo->flinfo->fn_oid)),
				 errdetail("The independent-variable array is not of constant width.")));
	}
	len = state1Data[0];
	statelen = STATE_LEN(len);
	
	/*
	 * Violation of any of the following conditions indicates bogus inputs.
	 */
	if (state1Data[0] > UINT32_MAX ||
		(uint64) ARR_DIMS(state1)[0] != statelen ||
		!IS_FEASIBLE_STATE_LEN(statelen))
	{
		ereport(ERROR, 
				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
				 errmsg("preliminary segment-level calculation function \"%s\" called with invalid parameters",
					format_procedure(fcinfo->flinfo->fn_oid))));
	}
	
	/* Validations pass, allocate memory for result and do work */

	/*
	 * Precondition:
	 *     IS_FEASIBLE_STATE_LEN(statelen)
	 */
	size = statelen * sizeof(float8) + ARR_OVERHEAD_NONULLS(1);
	result = (ArrayType *) palloc(size);
	SET_VARSIZE(result, size);
	result->ndim = 1;
	result->dataoffset = 0;
	result->elemtype = FLOAT8OID;
	ARR_DIMS(result)[0] = statelen;
	ARR_LBOUND(result)[0] = 1;
	resultData = (float8*) ARR_DATA_PTR(result);
	memset(resultData, 0, statelen * sizeof(float8));
	
	/* 
	 * Contents of 'state' are as follows:
	 *   [0]     = len(X[])
	 *   [1]     = count
	 *   [2]     = sum(y)
	 *   [3]     = sum(y*y)
	 *   [4:N]   = sum(X'[] * y) 
	 *   [N+1:M] = sum(X[] * X'[])
	 *   N       = 3 + len(X)
	 *   M       = N + len(X)*len(X)
	 */
	resultData[0] = len;
	for (i = 1; i < statelen; i++)
		resultData[i] = state1Data[i] + state2Data[i];	
	PG_RETURN_ARRAYTYPE_P(result);
}
Пример #23
0
Datum RASTER_sameAlignment(PG_FUNCTION_ARGS)
{
	const int set_count = 2;
	rt_pgraster *pgrast[2];
	int pgrastpos[2] = {-1, -1};
	rt_raster rast[2] = {NULL};

	uint32_t i;
	uint32_t j;
	uint32_t k;
	int rtn;
	int aligned = 0;
	char *reason = NULL;

	for (i = 0, j = 0; i < set_count; i++) {
		/* pgrast is null, return null */
		if (PG_ARGISNULL(j)) {
			for (k = 0; k < i; k++) {
				rt_raster_destroy(rast[k]);
				PG_FREE_IF_COPY(pgrast[k], pgrastpos[k]);
			}
			PG_RETURN_NULL();
		}
		pgrast[i] = (rt_pgraster *) PG_DETOAST_DATUM_SLICE(PG_GETARG_DATUM(j), 0, sizeof(struct rt_raster_serialized_t));
		pgrastpos[i] = j;
		j++;

		/* raster */
		rast[i] = rt_raster_deserialize(pgrast[i], TRUE);
		if (!rast[i]) {
			for (k = 0; k <= i; k++) {
				if (k < i)
					rt_raster_destroy(rast[k]);
				PG_FREE_IF_COPY(pgrast[k], pgrastpos[k]);
			}
			elog(ERROR, "RASTER_sameAlignment: Could not deserialize the %s raster", i < 1 ? "first" : "second");
			PG_RETURN_NULL();
		}
	}

	rtn = rt_raster_same_alignment(
		rast[0],
		rast[1],
		&aligned,
		&reason
	);
	for (k = 0; k < set_count; k++) {
		rt_raster_destroy(rast[k]);
		PG_FREE_IF_COPY(pgrast[k], pgrastpos[k]);
	}

	if (rtn != ES_NONE) {
		elog(ERROR, "RASTER_sameAlignment: Could not test for alignment on the two rasters");
		PG_RETURN_NULL();
	}

	/* only output reason if not aligned */
	if (reason != NULL && !aligned)
		elog(NOTICE, "%s", reason);

	PG_RETURN_BOOL(aligned);
}
Пример #24
0
static bool
float8_mregr_accum_get_args(FunctionCallInfo fcinfo,
							MRegrAccumArgs *outArgs)
{
	float8      *stateData;
	uint32      len, i;
	uint64      statelen;
	
	/* We should be strict, but it doesn't hurt to be paranoid */
	if (PG_ARGISNULL(0) || PG_ARGISNULL(1) || PG_ARGISNULL(2))
		return false;
	
	outArgs->stateAsArray = PG_GETARG_ARRAYTYPE_P(0);	
   	outArgs->newY = PG_GETARG_FLOAT8(1);
	outArgs->newXAsArray = PG_GETARG_ARRAYTYPE_P(2);
	outArgs->newX  = (float8*) ARR_DATA_PTR(outArgs->newXAsArray);
	
	/* Ensure that both arrays are single dimensional float8[] arrays */
	if (ARR_NULLBITMAP(outArgs->stateAsArray) ||
		ARR_NDIM(outArgs->stateAsArray) != 1 || 
		ARR_ELEMTYPE(outArgs->stateAsArray) != FLOAT8OID ||
		ARR_NDIM(outArgs->newXAsArray) != 1 ||
		ARR_ELEMTYPE(outArgs->newXAsArray) != FLOAT8OID)
		ereport(ERROR, 
				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
				 errmsg("transition function \"%s\" called with invalid parameters",
					format_procedure(fcinfo->flinfo->fn_oid))));
	
	/* Only callable as a transition function */
	if (!(fcinfo->context && IsA(fcinfo->context, AggState)))
		ereport(ERROR, 
				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
				 errmsg("transition function \"%s\" not called from aggregate",
					format_procedure(fcinfo->flinfo->fn_oid))));
	
	/* newXAsArray with nulls will be ignored */
	if (ARR_NULLBITMAP(outArgs->newXAsArray))
		return false;
	
	/* See MPP-14102. Avoid overflow while initializing len */
	if (ARR_DIMS(outArgs->newXAsArray)[0] > UINT32_MAX)
		ereport(ERROR, 
				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
				 errmsg("number of independent variables cannot exceed %lu",
				 (unsigned long) UINT32_MAX)));
	len = ARR_DIMS(outArgs->newXAsArray)[0];
		
	/*
	 * See MPP-13580. At least on certain platforms and with certain versions,
	 * LAPACK will run into an infinite loop if pinv() is called for non-finite
	 * matrices. We extend the check also to the dependent variables.
	 */
	for (i = 0; i < len; i++)
		if (!isfinite(outArgs->newX[i]))
			ereport(ERROR, 
				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
				 errmsg("design matrix is not finite")));
	if (!isfinite(outArgs->newY))
		ereport(ERROR, 
				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
				 errmsg("dependent variables are not finite")));
	
	/*
	 * See MPP-14102. We want to avoid (a) long int overflows and (b) making
	 * oversized allocation requests.
	 * We could compute the maximum number of variables so that the transition-
	 * state length still fits into MaxAllocSize, but (assuming MaxAllocSize may
	 * change in the future) this calculation requires taking the root out of a
	 * 64-bit long int. Since there is no standard library function for that, and
	 * displaying this number of merely of theoretical interest (the actual
	 * limit is a lot lower), we simply report that the number of independent
	 * variables is too large.
	 * Precondition:
	 *     len < 2^32.
	 */
	statelen = STATE_LEN(len);
	if (!IS_FEASIBLE_STATE_LEN(statelen))
		ereport(ERROR, 
				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
				 errmsg("number of independent variables is too large")));

	/*
	 * If length(outArgs->stateAsArray) == 1 then it is an unitialized state.
	 * We extend as needed.
	 */
	if (ARR_DIMS(outArgs->stateAsArray)[0] == 1)
	{
		/*
		 * Precondition:
		 *     IS_FEASIBLE_STATE_LEN(statelen)
		 */
		Size size = statelen * sizeof(float8) + ARR_OVERHEAD_NONULLS(1);
		outArgs->stateAsArray = (ArrayType *) palloc(size);
		SET_VARSIZE(outArgs->stateAsArray, size);
		outArgs->stateAsArray->ndim = 1;
		outArgs->stateAsArray->dataoffset = 0;
		outArgs->stateAsArray->elemtype = FLOAT8OID;
		ARR_DIMS(outArgs->stateAsArray)[0] = statelen;
		ARR_LBOUND(outArgs->stateAsArray)[0] = 1;
		stateData = (float8*) ARR_DATA_PTR(outArgs->stateAsArray);
		memset(stateData, 0, statelen * sizeof(float8));
		stateData[0] = len;
	}
	
	/* 
	 * Contents of 'state' are as follows:
	 *   [0]     = len(X[])
	 *   [1]     = count
	 *   [2]     = sum(y)
	 *   [3]     = sum(y*y)
	 *   [4:N]   = sum(X'[] * y) 
	 *   [N+1:M] = sum(X[] * X'[])
	 *   N       = 3 + len(X)
	 *   M       = N + len(X)*len(X)
	 */
	outArgs->len = (float8*) ARR_DATA_PTR(outArgs->stateAsArray);
	outArgs->count = outArgs->len + 1;
	outArgs->sumy = outArgs->len + 2;
	outArgs->sumy2 = outArgs->len + 3;
	outArgs->Xty = outArgs->len + 4;
	outArgs->XtX = outArgs->len + 4 + len;
	
	/* It is an error if the number of indepent variables is not constant */
	if (*outArgs->len != len)
	{
		ereport(ERROR, 
				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
				 errmsg("transition function \"%s\" called with invalid parameters",
					format_procedure(fcinfo->flinfo->fn_oid)),
				 errdetail("The independent-variable array is not of constant width.")));
	}
	
	/* Something is seriously fishy if our state has the wrong length */
	if ((uint64) ARR_DIMS(outArgs->stateAsArray)[0] != statelen)
	{
		ereport(ERROR, 
				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
				 errmsg("transition function \"%s\" called with invalid parameters",
					format_procedure(fcinfo->flinfo->fn_oid))));
	}
	
	/* Okay... All's good now do the work */
	return true;
}
Пример #25
0
/*
 * similar_escape()
 * Convert a SQL:2008 regexp pattern to POSIX style, so it can be used by
 * our regexp engine.
 */
Datum
similar_escape(PG_FUNCTION_ARGS)
{
	text	   *pat_text;
	text	   *esc_text;
	text	   *result;
	char	   *p,
			   *e,
			   *r;
	int			plen,
				elen;
	bool		afterescape = false;
	bool		incharclass = false;
	int			nquotes = 0;

	/* This function is not strict, so must test explicitly */
	if (PG_ARGISNULL(0))
		PG_RETURN_NULL();
	pat_text = PG_GETARG_TEXT_PP(0);
	p = VARDATA_ANY(pat_text);
	plen = VARSIZE_ANY_EXHDR(pat_text);
	if (PG_ARGISNULL(1))
	{
		/* No ESCAPE clause provided; default to backslash as escape */
		e = "\\";
		elen = 1;
	}
	else
	{
		esc_text = PG_GETARG_TEXT_PP(1);
		e = VARDATA_ANY(esc_text);
		elen = VARSIZE_ANY_EXHDR(esc_text);
		if (elen == 0)
			e = NULL;			/* no escape character */
		else if (elen != 1)
			ereport(ERROR,
					(errcode(ERRCODE_INVALID_ESCAPE_SEQUENCE),
					 errmsg("invalid escape string"),
				  errhint("Escape string must be empty or one character.")));
	}

	/*----------
	 * We surround the transformed input string with
	 *			^(?: ... )$
	 * which requires some explanation.  We need "^" and "$" to force
	 * the pattern to match the entire input string as per SQL99 spec.
	 * The "(?:" and ")" are a non-capturing set of parens; we have to have
	 * parens in case the string contains "|", else the "^" and "$" will
	 * be bound into the first and last alternatives which is not what we
	 * want, and the parens must be non capturing because we don't want them
	 * to count when selecting output for SUBSTRING.
	 *----------
	 */

	/*
	 * We need room for the prefix/postfix plus as many as 3 output bytes per
	 * input byte; since the input is at most 1GB this can't overflow
	 */
	result = (text *) palloc(VARHDRSZ + 6 + 3 * plen);
	r = VARDATA(result);

	*r++ = '^';
	*r++ = '(';
	*r++ = '?';
	*r++ = ':';

	while (plen > 0)
	{
		char		pchar = *p;

		if (afterescape)
		{
			if (pchar == '"' && !incharclass)	/* for SUBSTRING patterns */
				*r++ = ((nquotes++ % 2) == 0) ? '(' : ')';
			else
			{
				*r++ = '\\';
				*r++ = pchar;
			}
			afterescape = false;
		}
		else if (e && pchar == *e)
		{
			/* SQL99 escape character; do not send to output */
			afterescape = true;
		}
		else if (incharclass)
		{
			if (pchar == '\\')
				*r++ = '\\';
			*r++ = pchar;
			if (pchar == ']')
				incharclass = false;
		}
		else if (pchar == '[')
		{
			*r++ = pchar;
			incharclass = true;
		}
		else if (pchar == '%')
		{
			*r++ = '.';
			*r++ = '*';
		}
		else if (pchar == '_')
			*r++ = '.';
		else if (pchar == '(')
		{
			/* convert to non-capturing parenthesis */
			*r++ = '(';
			*r++ = '?';
			*r++ = ':';
		}
		else if (pchar == '\\' || pchar == '.' ||
				 pchar == '^' || pchar == '$')
		{
			*r++ = '\\';
			*r++ = pchar;
		}
		else
			*r++ = pchar;
		p++, plen--;
	}

	*r++ = ')';
	*r++ = '$';

	SET_VARSIZE(result, r - ((char *) result));

	PG_RETURN_TEXT_P(result);
}
Пример #26
0
Datum
pg_stat_get_activity(PG_FUNCTION_ARGS)
{
	FuncCallContext *funcctx;

	if (SRF_IS_FIRSTCALL())
	{
		MemoryContext oldcontext;
		TupleDesc	tupdesc;
		int			nattr = 13;

		funcctx = SRF_FIRSTCALL_INIT();

		oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);

		tupdesc = CreateTemplateTupleDesc(nattr, false);
		TupleDescInitEntry(tupdesc, (AttrNumber) 1, "datid", OIDOID, -1, 0);
		TupleDescInitEntry(tupdesc, (AttrNumber) 2, "procpid", INT4OID, -1, 0);
		TupleDescInitEntry(tupdesc, (AttrNumber) 3, "usesysid", OIDOID, -1, 0);
		TupleDescInitEntry(tupdesc, (AttrNumber) 4, "application_name", TEXTOID, -1, 0);
		TupleDescInitEntry(tupdesc, (AttrNumber) 5, "current_query", TEXTOID, -1, 0);
		TupleDescInitEntry(tupdesc, (AttrNumber) 6, "waiting", BOOLOID, -1, 0);
		TupleDescInitEntry(tupdesc, (AttrNumber) 7, "act_start", TIMESTAMPTZOID, -1, 0);
		TupleDescInitEntry(tupdesc, (AttrNumber) 8, "query_start", TIMESTAMPTZOID, -1, 0);
		TupleDescInitEntry(tupdesc, (AttrNumber) 9, "backend_start", TIMESTAMPTZOID, -1, 0);
		TupleDescInitEntry(tupdesc, (AttrNumber) 10, "client_addr", INETOID, -1, 0);
		TupleDescInitEntry(tupdesc, (AttrNumber) 11, "client_port", INT4OID, -1, 0);
		TupleDescInitEntry(tupdesc, (AttrNumber) 12, "sess_id", INT4OID, -1, 0);  /* GPDB */

		if (nattr > 12)
			TupleDescInitEntry(tupdesc, (AttrNumber) 13, "waiting_for", TEXTOID, -1, 0);

		funcctx->tuple_desc = BlessTupleDesc(tupdesc);

		funcctx->user_fctx = palloc0(sizeof(int));
		if (PG_ARGISNULL(0))
		{
			/* Get all backends */
			funcctx->max_calls = pgstat_fetch_stat_numbackends();
		}
		else
		{
			/*
			 * Get one backend - locate by pid.
			 *
			 * We lookup the backend early, so we can return zero rows if it
			 * doesn't exist, instead of returning a single row full of NULLs.
			 */
			int			pid = PG_GETARG_INT32(0);
			int			i;
			int			n = pgstat_fetch_stat_numbackends();

			for (i = 1; i <= n; i++)
			{
				PgBackendStatus *be = pgstat_fetch_stat_beentry(i);

				if (be)
				{
					if (be->st_procpid == pid)
					{
						*(int *) (funcctx->user_fctx) = i;
						break;
					}
				}
			}

			if (*(int *) (funcctx->user_fctx) == 0)
				/* Pid not found, return zero rows */
				funcctx->max_calls = 0;
			else
				funcctx->max_calls = 1;
		}

		MemoryContextSwitchTo(oldcontext);
	}

	/* stuff done on every call of the function */
	funcctx = SRF_PERCALL_SETUP();

	if (funcctx->call_cntr < funcctx->max_calls)
	{
		/* for each row */
		Datum		values[13];
		bool		nulls[13];
		HeapTuple	tuple;
		PgBackendStatus *beentry;
		SockAddr	zero_clientaddr;

		MemSet(values, 0, sizeof(values));
		MemSet(nulls, 0, sizeof(nulls));

		if (*(int *) (funcctx->user_fctx) > 0)
		{
			/* Get specific pid slot */
			beentry = pgstat_fetch_stat_beentry(*(int *) (funcctx->user_fctx));
		}
		else
		{
			/* Get the next one in the list */
			beentry = pgstat_fetch_stat_beentry(funcctx->call_cntr + 1);		/* 1-based index */
		}
		if (!beentry)
		{
			int			i;

			for (i = 0; i < sizeof(nulls) / sizeof(nulls[0]); i++)
				nulls[i] = true;

			nulls[4] = false;
			values[4] = CStringGetTextDatum("<backend information not available>");

			tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
			SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
		}

		/* Values available to all callers */
		values[0] = ObjectIdGetDatum(beentry->st_databaseid);
		values[1] = Int32GetDatum(beentry->st_procpid);
		values[2] = ObjectIdGetDatum(beentry->st_userid);
		if (beentry->st_appname)
			values[3] = CStringGetTextDatum(beentry->st_appname);
		else
			nulls[3] = true;

		/* Values only available to same user or superuser */
		if (superuser() || beentry->st_userid == GetUserId())
		{
			bool		waiting;

			if (*(beentry->st_activity) == '\0')
			{
				values[4] = CStringGetTextDatum("<command string not enabled>");
			}
			else
			{
				values[4] = CStringGetTextDatum(beentry->st_activity);
			}

			waiting = beentry->st_waiting != PGBE_WAITING_NONE;
			values[5] = BoolGetDatum(beentry->st_waiting);

			if (beentry->st_xact_start_timestamp != 0)
				values[6] = TimestampTzGetDatum(beentry->st_xact_start_timestamp);
			else
				nulls[6] = true;

			if (beentry->st_activity_start_timestamp != 0)
				values[7] = TimestampTzGetDatum(beentry->st_activity_start_timestamp);
			else
				nulls[7] = true;

			if (beentry->st_proc_start_timestamp != 0)
				values[8] = TimestampTzGetDatum(beentry->st_proc_start_timestamp);
			else
				nulls[8] = true;

			/* A zeroed client addr means we don't know */
			memset(&zero_clientaddr, 0, sizeof(zero_clientaddr));
			if (memcmp(&(beentry->st_clientaddr), &zero_clientaddr,
					   sizeof(zero_clientaddr) == 0))
			{
				nulls[9] = true;
				nulls[10] = true;
			}
			else
			{
				if (beentry->st_clientaddr.addr.ss_family == AF_INET
#ifdef HAVE_IPV6
					|| beentry->st_clientaddr.addr.ss_family == AF_INET6
#endif
					)
				{
					char		remote_host[NI_MAXHOST];
					char		remote_port[NI_MAXSERV];
					int			ret;

					remote_host[0] = '\0';
					remote_port[0] = '\0';
					ret = pg_getnameinfo_all(&beentry->st_clientaddr.addr,
											 beentry->st_clientaddr.salen,
											 remote_host, sizeof(remote_host),
											 remote_port, sizeof(remote_port),
											 NI_NUMERICHOST | NI_NUMERICSERV);
					if (ret)
					{
						nulls[9] = true;
						nulls[10] = true;
					}
					else
					{
						clean_ipv6_addr(beentry->st_clientaddr.addr.ss_family, remote_host);
						values[9] = DirectFunctionCall1(inet_in,
											   CStringGetDatum(remote_host));
						values[10] = Int32GetDatum(atoi(remote_port));
					}
				}
				else if (beentry->st_clientaddr.addr.ss_family == AF_UNIX)
				{
					/*
					 * Unix sockets always reports NULL for host and -1 for
					 * port, so it's possible to tell the difference to
					 * connections we have no permissions to view, or with
					 * errors.
					 */
					nulls[9] = true;
					values[10] = DatumGetInt32(-1);
				}
				else
				{
					/* Unknown address type, should never happen */
					nulls[9] = true;
					nulls[10] = true;
				}
			}
			values[11] = Int32GetDatum(beentry->st_session_id);  /* GPDB */

			if (funcctx->tuple_desc->natts > 12)
			{
				char	st_waiting = beentry->st_waiting;
				char   *reason;

				reason = pgstat_waiting_string(st_waiting);

				if (reason != NULL)
					values[12] = CStringGetTextDatum(reason);
				else
					nulls[12] = true;
			}

		}
		else
		{
			/* No permissions to view data about this session */
			values[4] = CStringGetTextDatum("<insufficient privilege>");
			nulls[5] = true;
			nulls[6] = true;
			nulls[7] = true;
			nulls[8] = true;
			nulls[9] = true;
			nulls[10] = true;
			values[11] = Int32GetDatum(beentry->st_session_id);
			if (funcctx->tuple_desc->natts > 12)
				nulls[12] = true;
		}

		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);

		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
	}
	else
	{
		/* nothing left */
		SRF_RETURN_DONE(funcctx);
	}
}
Пример #27
0
Datum
pseudoinverse(PG_FUNCTION_ARGS)
{
    /*
     * A note on types: PostgreSQL array dimensions are of type int. See, e.g.,
     * the macro definition ARR_DIMS
     */
    int         rows, columns;
    float8     *A, *Aplus;
    ArrayType  *A_PG, *Aplus_PG;
    int lbs[2], dims[2];

    /*
     * Perform all the error checking needed to ensure that no one is
     * trying to call this in some sort of crazy way.
     */
    if (PG_NARGS() != 1)
    {
        ereport(ERROR,
                (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                 errmsg("pseudoinverse called with %d arguments",
                        PG_NARGS())));
    }
    if (PG_ARGISNULL(0))
        PG_RETURN_NULL();

    A_PG = PG_GETARG_ARRAYTYPE_P(0);

    if (ARR_ELEMTYPE(A_PG) != FLOAT8OID)
        ereport(ERROR,
                (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                 errmsg("pseudoinverse only defined over float8[]")));
    if (ARR_NDIM(A_PG) != 2)
        ereport(ERROR,
                (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                 errmsg("pseudoinverse only defined over 2 dimensional arrays"))
               );
    if (ARR_NULLBITMAP(A_PG))
        ereport(ERROR,
                (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
                 errmsg("null array element not allowed in this context")));

    /* Extract rows, columns, and data */
    rows = ARR_DIMS(A_PG)[0];
    columns = ARR_DIMS(A_PG)[1];
    A = (float8 *) ARR_DATA_PTR(A_PG);


    /*  Allocate a PG array for the result, "Aplus" is A+, the pseudo inverse of A */
    lbs[0] = 1;
    lbs[1] = 1;
    dims[0] = columns;
    dims[1] = rows;
    Aplus_PG = construct_md_array(NULL, NULL, 2, dims, lbs, FLOAT8OID,
                                  sizeof(float8), true, 'd');

    Aplus = (float8 *) ARR_DATA_PTR(Aplus_PG);

    pinv(rows,columns,A,Aplus);

    PG_RETURN_ARRAYTYPE_P(Aplus_PG);
}
Пример #28
0
/*
 * pivot_accum() - Pivot and accumulate
 */
static Datum oid_pivot_accum(FunctionCallInfo fcinfo, Oid type)
{
	ArrayType  *data;
	ArrayType  *labels;
	text       *attr;
	int         i;
	
	/* Simple argument validation */
	if (PG_NARGS() != 4)
		ereport(ERROR, 
				(errcode(ERRCODE_DATATYPE_MISMATCH),
				 errmsg("pivot_accum called with %d input arguments",
						PG_NARGS())));
	if (PG_ARGISNULL(1) || PG_ARGISNULL(2) || PG_ARGISNULL(3))
	{
		if (PG_ARGISNULL(0))
			PG_RETURN_NULL();
		PG_RETURN_ARRAYTYPE_P(PG_GETARG_ARRAYTYPE_P(0));
	}
    labels = PG_GETARG_ARRAYTYPE_P(1);
	attr   = PG_GETARG_TEXT_P(2);
	
	/* Do nothing if the attr isn't in the labels array. */
	if ((i = pivot_find(labels, attr)) < 0)
	{
		if (PG_ARGISNULL(0))
			PG_RETURN_NULL();
		PG_RETURN_ARRAYTYPE_P(PG_GETARG_ARRAYTYPE_P(0));
	}
	
	/* Get the data array, or make it if null */
	if (!PG_ARGISNULL(0))
	{
		data = PG_GETARG_ARRAYTYPE_P(0);
		Assert(ARR_DIMS(labels)[0] == ARR_DIMS(data)[0]);
	}
	else
	{
		int elsize, size, nelem;

		switch (type) {
			case INT4OID:
				elsize = 4;
				break;
			case INT8OID:
			case FLOAT8OID:
				elsize = 8; 
				break;
			default:
				elsize = 0;  /* Fixes complier warnings */
				Assert(false);
		}
		nelem = ARR_DIMS(labels)[0];
		size = nelem * elsize + ARR_OVERHEAD_NONULLS(1);
		data = (ArrayType *) palloc(size);
		SET_VARSIZE(data, size);
		data->ndim = 1;
		data->dataoffset = 0;
		data->elemtype = type;
		ARR_DIMS(data)[0] = nelem;
		ARR_LBOUND(data)[0] = 1;
		memset(ARR_DATA_PTR(data), 0, nelem * elsize);
	}
	
	
	/*   
	 * Should we think about upconverting the arrays? Or is the assumption that 
	 * the pivot isn't usually doing much aggregation?
	 */
	switch (type) {
		case INT4OID:
		{
			int32 *datap = (int32*) ARR_DATA_PTR(data);
			int32  value = PG_GETARG_INT32(3);
			datap[i] += value;
			break;
		}
		case INT8OID:
		{
			int64 *datap = (int64*) ARR_DATA_PTR(data);
			int64  value = PG_GETARG_INT64(3);
			datap[i] += value;
			break;
		}
		case FLOAT8OID:
		{
			float8 *datap = (float8*) ARR_DATA_PTR(data);
			float8  value = PG_GETARG_FLOAT8(3);
			datap[i] += value;
			break;
		}
		default:
			Assert(false);
	}
	PG_RETURN_ARRAYTYPE_P(data);
}
Пример #29
0
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);
}
Пример #30
0
/**
 * Returns a mean from an array of numbers.
 * by Paul A. Jungwirth
 */
Datum
array_to_mean(PG_FUNCTION_ARGS)
{
  // Our arguments:
  ArrayType *vals;

  // The array element type:
  Oid valsType;

  // The array element type widths for our input array:
  int16 valsTypeWidth;

  // The array element type "is passed by value" flags (not really used):
  bool valsTypeByValue;

  // The array element type alignment codes (not really used):
  char valsTypeAlignmentCode;

  // The array contents, as PostgreSQL "Datum" objects:
  Datum *valsContent;

  // List of "is null" flags for the array contents (not used):
  bool *valsNullFlags;

  // The size of the input array:
  int valsLength;

  float8 v = 0;
  int i;

  if (PG_ARGISNULL(0)) {
    ereport(ERROR, (errmsg("Null arrays not accepted")));
  }

  vals = PG_GETARG_ARRAYTYPE_P(0);

  if (ARR_NDIM(vals) == 0) {
    PG_RETURN_NULL();
  }
  if (ARR_NDIM(vals) > 1) {
    ereport(ERROR, (errmsg("One-dimesional arrays are required")));
  }

  if (array_contains_nulls(vals)) {
    ereport(ERROR, (errmsg("Array contains null elements")));
  }

  // Determine the array element types.
  valsType = ARR_ELEMTYPE(vals);

  if (valsType != INT2OID &&
      valsType != INT4OID &&
      valsType != INT8OID &&
      valsType != FLOAT4OID &&
      valsType != FLOAT8OID) {
    ereport(ERROR, (errmsg("Mean subject must be SMALLINT, INTEGER, BIGINT, REAL, or DOUBLE PRECISION values")));
  }

  valsLength = (ARR_DIMS(vals))[0];

  if (valsLength == 0) PG_RETURN_NULL();

  get_typlenbyvalalign(valsType, &valsTypeWidth, &valsTypeByValue, &valsTypeAlignmentCode);

  // Extract the array contents (as Datum objects).
  deconstruct_array(vals, valsType, valsTypeWidth, valsTypeByValue, valsTypeAlignmentCode,
&valsContent, &valsNullFlags, &valsLength);

  // Iterate through the contents and sum things up,
  // then return the mean:
  // Watch out for overflow:
  // http://stackoverflow.com/questions/1930454/what-is-a-good-solution-for-calculating-an-average-where-the-sum-of-all-values-e/1934266#1934266

  switch (valsType) {
    case INT2OID:
      for (i = 0; i < valsLength; i++) {
        v += (DatumGetInt16(valsContent[i]) - v) / (i + 1);
      }
      break;
    case INT4OID:
      for (i = 0; i < valsLength; i++) {
        v += (DatumGetInt32(valsContent[i]) - v) / (i + 1);
      }
      break;
    case INT8OID:
      for (i = 0; i < valsLength; i++) {
        v += (DatumGetInt64(valsContent[i]) - v) / (i + 1);
      }
      break;
    case FLOAT4OID:
      for (i = 0; i < valsLength; i++) {
        v += (DatumGetFloat4(valsContent[i]) - v) / (i + 1);
      }
      break;
    case FLOAT8OID:
      for (i = 0; i < valsLength; i++) {
        v += (DatumGetFloat8(valsContent[i]) - v) / (i + 1);
      }
      break;
    default:
      ereport(ERROR, (errmsg("Mean subject must be SMALLINT, INTEGER, BIGINT, REAL, or DOUBLE PRECISION values")));
      break;
  }
  PG_RETURN_FLOAT8(v);
}