/* ** The GiST Consistent method for _intments ** Should return false if for all data items x below entry, ** the predicate x op query == FALSE, where op is the oper ** corresponding to strategy in the pg_amop table. */ Datum g_int_consistent(PG_FUNCTION_ARGS) { GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0); ArrayType *query = (ArrayType *) PG_DETOAST_DATUM_COPY(PG_GETARG_POINTER(1)); StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2); bool retval; if (strategy == BooleanSearchStrategy) { retval =execconsistent((QUERYTYPE *) query, (ArrayType *) DatumGetPointer(entry->key), ISLEAFKEY((ArrayType *) DatumGetPointer(entry->key))); pfree( query ); PG_RETURN_BOOL(retval); } /* sort query for fast search, key is already sorted */ if (ARRISVOID(query)) { pfree( query ); PG_RETURN_BOOL(false); } PREPAREARR(query); switch (strategy) { case RTOverlapStrategyNumber: retval = inner_int_overlap((ArrayType *) DatumGetPointer(entry->key), query); break; case RTSameStrategyNumber: if (GIST_LEAF(entry)) DirectFunctionCall3( g_int_same, entry->key, PointerGetDatum(query), PointerGetDatum(&retval) ); else retval = inner_int_contains((ArrayType *) DatumGetPointer(entry->key), query); break; case RTContainsStrategyNumber: retval = inner_int_contains((ArrayType *) DatumGetPointer(entry->key), query); break; case RTContainedByStrategyNumber: if (GIST_LEAF(entry)) retval = inner_int_contains(query, (ArrayType *) DatumGetPointer(entry->key)); else retval = inner_int_overlap((ArrayType *) DatumGetPointer(entry->key), query); break; default: retval = FALSE; } pfree( query ); PG_RETURN_BOOL(retval); }
Datum intarray_del_elem(PG_FUNCTION_ARGS) { ArrayType *a = (ArrayType *) DatumGetPointer(PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(0))); int32 elem = PG_GETARG_INT32(1); int32 c; int32 *aa; int32 n = 0, i; CHECKARRVALID(a); if (!ARRISVOID(a)) { c = ARRNELEMS(a); aa = ARRPTR(a); for (i = 0; i < c; i++) { if (aa[i] != elem) { if (i > n) aa[n++] = aa[i]; else n++; } } a = resize_intArrayType(a, n); } PG_RETURN_POINTER(a); }
Datum LWGEOM_set_srid(PG_FUNCTION_ARGS) { GSERIALIZED *g = (GSERIALIZED *)PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(0)); int srid = PG_GETARG_INT32(1); gserialized_set_srid(g, srid); PG_RETURN_POINTER(g); }
Datum boolop(PG_FUNCTION_ARGS) { ArrayType *val = (ArrayType *) PG_DETOAST_DATUM_COPY(PG_GETARG_POINTER(0)); QUERYTYPE *query = (QUERYTYPE *) PG_DETOAST_DATUM(PG_GETARG_POINTER(1)); CHKVAL chkval; bool result; CHECKARRVALID(val); if (ARRISVOID(val)) { pfree(val); PG_FREE_IF_COPY(query, 1); PG_RETURN_BOOL(false); } PREPAREARR(val); chkval.arrb = ARRPTR(val); chkval.arre = chkval.arrb + ARRNELEMS(val); result = execute( GETQUERY(query) + query->size - 1, &chkval, true, checkcondition_arr ); pfree(val); PG_FREE_IF_COPY(query, 1); PG_RETURN_BOOL(result); }
Datum sort(PG_FUNCTION_ARGS) { ArrayType *a = (ArrayType *) DatumGetPointer(PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(0))); text *dirstr = (fcinfo->nargs == 2) ? PG_GETARG_TEXT_P(1) : NULL; int32 dc = (dirstr) ? VARSIZE(dirstr) - VARHDRSZ : 0; char *d = (dirstr) ? VARDATA(dirstr) : NULL; int dir = -1; CHECKARRVALID(a); if (ARRISVOID(a) || ARRNELEMS(a) < 2) PG_RETURN_POINTER(a); if (dirstr == NULL || (dc == 3 && (d[0] == 'A' || d[0] == 'a') && (d[1] == 'S' || d[1] == 's') && (d[2] == 'C' || d[2] == 'c'))) dir = 1; else if (dc == 4 && (d[0] == 'D' || d[0] == 'd') && (d[1] == 'E' || d[1] == 'e') && (d[2] == 'S' || d[2] == 's') && (d[3] == 'C' || d[3] == 'c')) dir = 0; if (dir == -1) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("second parameter must be \"ASC\" or \"DESC\""))); QSORT(a, dir); PG_RETURN_POINTER(a); }
Datum _int_same(PG_FUNCTION_ARGS) { ArrayType *a = (ArrayType *) DatumGetPointer(PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(0))); ArrayType *b = (ArrayType *) DatumGetPointer(PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(1))); int na, nb; int n; int *da, *db; bool result; bool avoid; bool bvoid; CHECKARRVALID(a); CHECKARRVALID(b); avoid = ARRISVOID(a); bvoid = ARRISVOID(b); if (avoid || bvoid) return (avoid && bvoid) ? TRUE : FALSE; na = ARRNELEMS(a); nb = ARRNELEMS(b); da = ARRPTR(a); db = ARRPTR(b); result = FALSE; if (na == nb) { SORT(a); SORT(b); result = TRUE; for (n = 0; n < na; n++) if (da[n] != db[n]) { result = FALSE; break; } } pfree(a); pfree(b); PG_RETURN_BOOL(result); }
Datum intset_subtract(PG_FUNCTION_ARGS) { ArrayType *a = (ArrayType *) DatumGetPointer(PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(0))); ArrayType *b = (ArrayType *) DatumGetPointer(PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(1))); ArrayType *result; int32 ca; int32 cb; int32 *aa, *bb, *r; int32 n = 0, i = 0, k = 0; CHECKARRVALID(a); CHECKARRVALID(b); QSORT(a, 1); a = _int_unique(a); ca = ARRNELEMS(a); QSORT(b, 1); b = _int_unique(b); cb = ARRNELEMS(b); result = new_intArrayType(ca); aa = ARRPTR(a); bb = ARRPTR(b); r = ARRPTR(result); while (i < ca) { if (k == cb || aa[i] < bb[k]) r[n++] = aa[i++]; else if (aa[i] == bb[k]) { i++; k++; } else k++; } result = resize_intArrayType(result, n); pfree(a); pfree(b); PG_RETURN_POINTER(result); }
Datum transform(PG_FUNCTION_ARGS) { GSERIALIZED *geom; GSERIALIZED *result=NULL; LWGEOM *lwgeom; projPJ input_pj, output_pj; int32 output_srid, input_srid; output_srid = PG_GETARG_INT32(1); if (output_srid == SRID_UNKNOWN) { elog(ERROR,"%d is an invalid target SRID",SRID_UNKNOWN); PG_RETURN_NULL(); } geom = (GSERIALIZED *)PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(0)); input_srid = gserialized_get_srid(geom); if ( input_srid == SRID_UNKNOWN ) { PG_FREE_IF_COPY(geom, 0); elog(ERROR,"Input geometry has unknown (%d) SRID",SRID_UNKNOWN); PG_RETURN_NULL(); } /* * If input SRID and output SRID are equal, return geometry * without transform it */ if ( input_srid == output_srid ) PG_RETURN_POINTER(PG_GETARG_DATUM(0)); if ( GetProjectionsUsingFCInfo(fcinfo, input_srid, output_srid, &input_pj, &output_pj) == LW_FAILURE ) { PG_FREE_IF_COPY(geom, 0); elog(ERROR,"Failure reading projections from spatial_ref_sys."); PG_RETURN_NULL(); } /* now we have a geometry, and input/output PJ structs. */ lwgeom = lwgeom_from_gserialized(geom); lwgeom_transform(lwgeom, input_pj, output_pj); lwgeom->srid = output_srid; /* Re-compute bbox if input had one (COMPUTE_BBOX TAINTING) */ if ( lwgeom->bbox ) { lwgeom_drop_bbox(lwgeom); lwgeom_add_bbox(lwgeom); } result = geometry_serialize(lwgeom); lwgeom_free(lwgeom); PG_FREE_IF_COPY(geom, 0); PG_RETURN_POINTER(result); /* new geometry */ }
Datum _int_contains(PG_FUNCTION_ARGS) { ArrayType *a = (ArrayType *) DatumGetPointer(PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(0))); ArrayType *b = (ArrayType *) DatumGetPointer(PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(1))); bool res; CHECKARRVALID(a); CHECKARRVALID(b); if (ARRISVOID(a) || ARRISVOID(b)) return FALSE; PREPAREARR(a); PREPAREARR(b); res = inner_int_contains(a, b); pfree(a); pfree(b); PG_RETURN_BOOL(res); }
Datum sort_desc(PG_FUNCTION_ARGS) { ArrayType *a = (ArrayType *) DatumGetPointer(PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(0))); CHECKARRVALID(a); if (ARRISVOID(a)) PG_RETURN_POINTER(a); QSORT(a, 0); PG_RETURN_POINTER(a); }
Datum uniq(PG_FUNCTION_ARGS) { ArrayType *a = (ArrayType *) DatumGetPointer(PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(0))); CHECKARRVALID(a); if (ARRISVOID(a) || ARRNELEMS(a) < 2) PG_RETURN_POINTER(a); a = _int_unique(a); PG_RETURN_POINTER(a); }
Datum tsquery_rewrite_query(PG_FUNCTION_ARGS) { QUERYTYPE *query = (QUERYTYPE *) DatumGetPointer(PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(0))); QUERYTYPE *ex = (QUERYTYPE *) DatumGetPointer(PG_DETOAST_DATUM(PG_GETARG_DATUM(1))); QUERYTYPE *subst = (QUERYTYPE *) DatumGetPointer(PG_DETOAST_DATUM(PG_GETARG_DATUM(2))); QUERYTYPE *rewrited = query; QTNode *tree, *qex, *subs = NULL; if (query->size == 0 || ex->size == 0) { PG_FREE_IF_COPY(ex, 1); PG_FREE_IF_COPY(subst, 2); PG_RETURN_POINTER(rewrited); } tree = QT2QTN(GETQUERY(query), GETOPERAND(query)); QTNTernary(tree); QTNSort(tree); qex = QT2QTN(GETQUERY(ex), GETOPERAND(ex)); QTNTernary(qex); QTNSort(qex); if (subst->size) subs = QT2QTN(GETQUERY(subst), GETOPERAND(subst)); tree = findsubquery(tree, qex, PlainMemory, subs, NULL); QTNFree(qex); QTNFree(subs); if (!tree) { rewrited->len = HDRSIZEQT; rewrited->size = 0; PG_FREE_IF_COPY(ex, 1); PG_FREE_IF_COPY(subst, 2); PG_RETURN_POINTER(rewrited); } else { QTNBinary(tree); rewrited = QTN2QT(tree, PlainMemory); QTNFree(tree); } PG_FREE_IF_COPY(query, 0); PG_FREE_IF_COPY(ex, 1); PG_FREE_IF_COPY(subst, 2); PG_RETURN_POINTER(rewrited); }
/* _int_overlap -- does a overlap b? */ Datum _int_overlap(PG_FUNCTION_ARGS) { ArrayType *a = (ArrayType *) DatumGetPointer(PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(0))); ArrayType *b = (ArrayType *) DatumGetPointer(PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(1))); bool result; CHECKARRVALID(a); CHECKARRVALID(b); if (ARRISVOID(a) || ARRISVOID(b)) return FALSE; SORT(a); SORT(b); result = inner_int_overlap(a, b); pfree(a); pfree(b); PG_RETURN_BOOL(result); }
Datum _int_inter(PG_FUNCTION_ARGS) { ArrayType *a = (ArrayType *) DatumGetPointer(PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(0))); ArrayType *b = (ArrayType *) DatumGetPointer(PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(1))); ArrayType *result; CHECKARRVALID(a); CHECKARRVALID(b); if (ARRISVOID(a) || ARRISVOID(b)) PG_RETURN_POINTER(new_intArrayType(0)); SORT(a); SORT(b); result = inner_int_inter(a, b); pfree(a); pfree(b); PG_RETURN_POINTER(result); }
Datum rank_cd(PG_FUNCTION_ARGS) { ArrayType *win; tsvector *txt = (tsvector *) PG_DETOAST_DATUM(PG_GETARG_DATUM(1)); QUERYTYPE *query = (QUERYTYPE *) PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(2)); int method = DEF_NORM_METHOD; float4 res; /* * Pre-8.2, rank_cd took just a plain int as its first argument. * It was a mistake to keep the same C function name while changing the * signature, but it's too late to fix that. Instead, do a runtime test * to make sure the expected datatype has been passed. This is needed * to prevent core dumps if tsearch2 function definitions from an old * database are loaded into an 8.2 server. */ if (get_fn_expr_argtype(fcinfo->flinfo, 0) != FLOAT4ARRAYOID) ereport(ERROR, (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), errmsg("rank_cd() now takes real[] as its first argument, not integer"))); /* now safe to dereference the first arg */ win = (ArrayType *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); if (ARR_NDIM(win) != 1) ereport(ERROR, (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), errmsg("array of weight must be one-dimensional"))); if (ARRNELEMS(win) < lengthof(weights)) ereport(ERROR, (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), errmsg("array of weight is too short"))); if (ARR_HASNULL(win)) ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), errmsg("array of weight must not contain nulls"))); if (PG_NARGS() == 4) method = PG_GETARG_INT32(3); res = calc_rank_cd((float4 *) ARR_DATA_PTR(win), txt, query, method); PG_FREE_IF_COPY(win, 0); PG_FREE_IF_COPY(txt, 1); PG_FREE_IF_COPY(query, 2); PG_RETURN_FLOAT4(res); }
Datum rank_cd_def(PG_FUNCTION_ARGS) { tsvector *txt = (tsvector *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); QUERYTYPE *query = (QUERYTYPE *) PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(1)); float4 res; res = calc_rank_cd(weights, txt, query, (PG_NARGS() == 3) ? PG_GETARG_DATUM(2) : DEF_NORM_METHOD); PG_FREE_IF_COPY(txt, 0); PG_FREE_IF_COPY(query, 1); PG_RETURN_FLOAT4(res); }
Datum anyold_transfn(PG_FUNCTION_ARGS) { Oid type; Datum state; MemoryContext aggcontext, oldcontext; int16 typlen; bool typbyval; char typalign; if (!AggCheckCallContext(fcinfo, &aggcontext)) { /* cannot be called directly because of internal-type argument */ elog(ERROR, "anyold_transfn called in non-aggregate context"); } if (PG_ARGISNULL(0)) { if (PG_ARGISNULL(1)) PG_RETURN_NULL(); /* First non-null value --- initialize */ oldcontext = MemoryContextSwitchTo(aggcontext); type = get_fn_expr_argtype(fcinfo->flinfo, 1); if (type == InvalidOid) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("could not determine input data type"))); get_typlenbyvalalign(type, &typlen, &typbyval, &typalign); /* Copy initial value */ if (typlen == -1) state = PointerGetDatum(PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(1))); else state = datumCopy(PG_GETARG_DATUM(1), typbyval, typlen); MemoryContextSwitchTo(oldcontext); } else { state = PG_GETARG_DATUM(0); } PG_RETURN_DATUM(state); }
static void argm_copy_datum(bool is_null, Datum src, ArgmDatumWithType *dest, bool free) { if (free && !dest->typbyval && !dest->is_null) pfree(DatumGetPointer(dest->value)); if (is_null) dest->is_null = true; else { dest->is_null = false; if (dest->typlen == -1) dest->value = PointerGetDatum(PG_DETOAST_DATUM_COPY(src)); else dest->value = datumCopy(src, dest->typbyval, dest->typlen); } }
Datum geography_from_geometry(PG_FUNCTION_ARGS) { GSERIALIZED *geom = (GSERIALIZED*)PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(0)); LWGEOM *lwgeom = NULL; GSERIALIZED *g_ser = NULL; geography_valid_type(gserialized_get_type(geom)); lwgeom = lwgeom_from_gserialized(geom); /* Force default SRID */ if ( (int)lwgeom->srid <= 0 ) { lwgeom->srid = SRID_DEFAULT; } /* Error on any SRID != default */ srid_is_latlong(fcinfo, lwgeom->srid); /* Force the geometry to have valid geodetic coordinate range. */ lwgeom_nudge_geodetic(lwgeom); if ( lwgeom_force_geodetic(lwgeom) == LW_TRUE ) { ereport(NOTICE, ( errmsg_internal("Coordinate values were coerced into range [-180 -90, 180 90] for GEOGRAPHY" )) ); } /* ** Serialize our lwgeom and set the geodetic flag so subsequent ** functions do the right thing. */ lwgeom_set_geodetic(lwgeom, true); /* Recalculate the boxes after re-setting the geodetic bit */ lwgeom_drop_bbox(lwgeom); lwgeom_add_bbox(lwgeom); g_ser = geography_serialize(lwgeom); /* ** Replace the unaligned lwgeom with a new aligned one based on GSERIALIZED. */ lwgeom_free(lwgeom); PG_FREE_IF_COPY(geom, 0); PG_RETURN_POINTER(g_ser); }
Datum tsquery_rewrite(PG_FUNCTION_ARGS) { QUERYTYPE *query = (QUERYTYPE *) DatumGetPointer(PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(0))); text *in = PG_GETARG_TEXT_P(1); QUERYTYPE *rewrited = query; QTNode *tree; char *buf; void *plan; Portal portal; bool isnull; int i; if (query->size == 0) { PG_FREE_IF_COPY(in, 1); PG_RETURN_POINTER(rewrited); } tree = QT2QTN(GETQUERY(query), GETOPERAND(query)); QTNTernary(tree); QTNSort(tree); buf = (char *) palloc(VARSIZE(in)); memcpy(buf, VARDATA(in), VARSIZE(in) - VARHDRSZ); buf[VARSIZE(in) - VARHDRSZ] = '\0'; SPI_connect(); if (tsqOid == InvalidOid) get_tsq_Oid(); if ((plan = SPI_prepare(buf, 0, NULL)) == NULL) elog(ERROR, "SPI_prepare('%s') returns NULL", buf); if ((portal = SPI_cursor_open(NULL, plan, NULL, NULL, false)) == NULL) elog(ERROR, "SPI_cursor_open('%s') returns NULL", buf); SPI_cursor_fetch(portal, true, 100); if (SPI_tuptable->tupdesc->natts != 2) elog(ERROR, "number of fields doesn't equal to 2"); if (SPI_gettypeid(SPI_tuptable->tupdesc, 1) != tsqOid) elog(ERROR, "column #1 isn't of tsquery type"); if (SPI_gettypeid(SPI_tuptable->tupdesc, 2) != tsqOid) elog(ERROR, "column #2 isn't of tsquery type"); while (SPI_processed > 0 && tree) { for (i = 0; i < SPI_processed && tree; i++) { Datum qdata = SPI_getbinval(SPI_tuptable->vals[i], SPI_tuptable->tupdesc, 1, &isnull); Datum sdata; if (isnull) continue; sdata = SPI_getbinval(SPI_tuptable->vals[i], SPI_tuptable->tupdesc, 2, &isnull); if (!isnull) { QUERYTYPE *qtex = (QUERYTYPE *) DatumGetPointer(PG_DETOAST_DATUM(qdata)); QUERYTYPE *qtsubs = (QUERYTYPE *) DatumGetPointer(PG_DETOAST_DATUM(sdata)); QTNode *qex, *qsubs = NULL; if (qtex->size == 0) { if (qtex != (QUERYTYPE *) DatumGetPointer(qdata)) pfree(qtex); if (qtsubs != (QUERYTYPE *) DatumGetPointer(sdata)) pfree(qtsubs); continue; } qex = QT2QTN(GETQUERY(qtex), GETOPERAND(qtex)); QTNTernary(qex); QTNSort(qex); if (qtsubs->size) qsubs = QT2QTN(GETQUERY(qtsubs), GETOPERAND(qtsubs)); tree = findsubquery(tree, qex, SPIMemory, qsubs, NULL); QTNFree(qex); if (qtex != (QUERYTYPE *) DatumGetPointer(qdata)) pfree(qtex); QTNFree(qsubs); if (qtsubs != (QUERYTYPE *) DatumGetPointer(sdata)) pfree(qtsubs); } } SPI_freetuptable(SPI_tuptable); SPI_cursor_fetch(portal, true, 100); } SPI_freetuptable(SPI_tuptable); SPI_cursor_close(portal); SPI_freeplan(plan); SPI_finish(); if (tree) { QTNBinary(tree); rewrited = QTN2QT(tree, PlainMemory); QTNFree(tree); PG_FREE_IF_COPY(query, 0); } else { rewrited->len = HDRSIZEQT; rewrited->size = 0; } pfree(buf); PG_FREE_IF_COPY(in, 1); PG_RETURN_POINTER(rewrited); }
Datum rewrite_accum(PG_FUNCTION_ARGS) { QUERYTYPE *acc = (QUERYTYPE *) PG_GETARG_POINTER(0); ArrayType *qa = (ArrayType *) DatumGetPointer(PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(1))); QUERYTYPE *q; QTNode *qex, *subs = NULL, *acctree; bool isfind = false; Datum *elemsp; int nelemsp; AggregateContext = ((AggState *) fcinfo->context)->aggcontext; if (acc == NULL || PG_ARGISNULL(0)) { acc = (QUERYTYPE *) MEMALLOC(AggMemory, sizeof(QUERYTYPE)); acc->len = HDRSIZEQT; acc->size = 0; } if (qa == NULL || PG_ARGISNULL(1)) { PG_FREE_IF_COPY(qa, 1); PG_RETURN_POINTER(acc); } if (ARR_NDIM(qa) != 1) elog(ERROR, "array must be one-dimensional, not %d dimension", ARR_NDIM(qa)); if (ArrayGetNItems(ARR_NDIM(qa), ARR_DIMS(qa)) != 3) elog(ERROR, "array should have only three elements"); if (tsqOid == InvalidOid) { SPI_connect(); get_tsq_Oid(); SPI_finish(); } if (ARR_ELEMTYPE(qa) != tsqOid) elog(ERROR, "array should contain tsquery type"); deconstruct_array(qa, tsqOid, -1, false, 'i', &elemsp, NULL, &nelemsp); q = (QUERYTYPE *) DatumGetPointer(elemsp[0]); if (q->size == 0) { pfree(elemsp); PG_RETURN_POINTER(acc); } if (!acc->size) { if (acc->len > HDRSIZEQT) { pfree(elemsp); PG_RETURN_POINTER(acc); } else acctree = QT2QTN(GETQUERY(q), GETOPERAND(q)); } else acctree = QT2QTN(GETQUERY(acc), GETOPERAND(acc)); QTNTernary(acctree); QTNSort(acctree); q = (QUERYTYPE *) DatumGetPointer(elemsp[1]); if (q->size == 0) { pfree(elemsp); PG_RETURN_POINTER(acc); } qex = QT2QTN(GETQUERY(q), GETOPERAND(q)); QTNTernary(qex); QTNSort(qex); q = (QUERYTYPE *) DatumGetPointer(elemsp[2]); if (q->size) subs = QT2QTN(GETQUERY(q), GETOPERAND(q)); acctree = findsubquery(acctree, qex, PlainMemory, subs, &isfind); if (isfind || !acc->size) { /* pfree( acc ); do not pfree(p), because nodeAgg.c will */ if (acctree) { QTNBinary(acctree); acc = QTN2QT(acctree, AggMemory); } else { acc = (QUERYTYPE *) MEMALLOC(AggMemory, HDRSIZEQT * 2); acc->len = HDRSIZEQT * 2; acc->size = 0; } } pfree(elemsp); QTNFree(qex); QTNFree(subs); QTNFree(acctree); PG_RETURN_POINTER(acc); }
Datum transform_geom(PG_FUNCTION_ARGS) { GSERIALIZED *geom; GSERIALIZED *result=NULL; LWGEOM *lwgeom; projPJ input_pj, output_pj; char *input_proj4, *output_proj4; text *input_proj4_text; text *output_proj4_text; int32 result_srid ; char *pj_errstr; result_srid = PG_GETARG_INT32(3); if (result_srid == SRID_UNKNOWN) { elog(ERROR,"tranform: destination SRID = %d",SRID_UNKNOWN); PG_RETURN_NULL(); } geom = (GSERIALIZED *)PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(0)); if (gserialized_get_srid(geom) == SRID_UNKNOWN) { pfree(geom); elog(ERROR,"transform_geom: source SRID = %d",SRID_UNKNOWN); PG_RETURN_NULL(); } /* Set the search path if we haven't already */ SetPROJ4LibPath(); /* Read the arguments */ input_proj4_text = (PG_GETARG_TEXT_P(1)); output_proj4_text = (PG_GETARG_TEXT_P(2)); /* Convert from text to cstring for libproj */ input_proj4 = text2cstring(input_proj4_text); output_proj4 = text2cstring(output_proj4_text); /* make input and output projection objects */ input_pj = lwproj_from_string(input_proj4); if ( input_pj == NULL ) { pj_errstr = pj_strerrno(*pj_get_errno_ref()); if ( ! pj_errstr ) pj_errstr = ""; /* we need this for error reporting */ /* pfree(input_proj4); */ pfree(output_proj4); pfree(geom); elog(ERROR, "transform_geom: could not parse proj4 string '%s' %s", input_proj4, pj_errstr); PG_RETURN_NULL(); } pfree(input_proj4); output_pj = lwproj_from_string(output_proj4); if ( output_pj == NULL ) { pj_errstr = pj_strerrno(*pj_get_errno_ref()); if ( ! pj_errstr ) pj_errstr = ""; /* we need this for error reporting */ /* pfree(output_proj4); */ pj_free(input_pj); pfree(geom); elog(ERROR, "transform_geom: couldn't parse proj4 output string: '%s': %s", output_proj4, pj_errstr); PG_RETURN_NULL(); } pfree(output_proj4); /* now we have a geometry, and input/output PJ structs. */ lwgeom = lwgeom_from_gserialized(geom); lwgeom_transform(lwgeom, input_pj, output_pj); lwgeom->srid = result_srid; /* clean up */ pj_free(input_pj); pj_free(output_pj); /* Re-compute bbox if input had one (COMPUTE_BBOX TAINTING) */ if ( lwgeom->bbox ) { lwgeom_drop_bbox(lwgeom); lwgeom_add_bbox(lwgeom); } result = geometry_serialize(lwgeom); lwgeom_free(lwgeom); PG_FREE_IF_COPY(geom, 0); PG_RETURN_POINTER(result); /* new geometry */ }
Datum get_covers(PG_FUNCTION_ARGS) { tsvector *txt = (tsvector *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); QUERYTYPE *query = (QUERYTYPE *) PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(1)); WordEntry *pptr = ARRPTR(txt); int i, dlen = 0, j, cur = 0, len = 0, rlen; DocWord *dw, *dwptr; text *out; char *cptr; DocRepresentation *doc; int olddwpos = 0; int ncover = 1; Extention ext; doc = get_docrep(txt, query, &rlen); if (!doc) { out = palloc(VARHDRSZ); VARATT_SIZEP(out) = VARHDRSZ; PG_FREE_IF_COPY(txt, 0); PG_FREE_IF_COPY(query, 1); PG_RETURN_POINTER(out); } for (i = 0; i < txt->size; i++) { if (!pptr[i].haspos) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("no pos info"))); dlen += POSDATALEN(txt, &(pptr[i])); } dwptr = dw = palloc(sizeof(DocWord) * dlen); memset(dw, 0, sizeof(DocWord) * dlen); for (i = 0; i < txt->size; i++) { WordEntryPos *posdata = POSDATAPTR(txt, &(pptr[i])); for (j = 0; j < POSDATALEN(txt, &(pptr[i])); j++) { dw[cur].w = STRPTR(txt) + pptr[i].pos; dw[cur].len = pptr[i].len; dw[cur].pos = WEP_GETPOS(posdata[j]); cur++; } len += (pptr[i].len + 1) * (int) POSDATALEN(txt, &(pptr[i])); } qsort((void *) dw, dlen, sizeof(DocWord), compareDocWord); MemSet(&ext, 0, sizeof(Extention)); while (Cover(doc, rlen, query, &ext)) { dwptr = dw + olddwpos; while (dwptr->pos < ext.p && dwptr - dw < dlen) dwptr++; olddwpos = dwptr - dw; dwptr->start = ncover; while (dwptr->pos < ext.q + 1 && dwptr - dw < dlen) dwptr++; (dwptr - 1)->finish = ncover; len += 4 /* {}+two spaces */ + 2 * 16 /* numbers */ ; ncover++; } out = palloc(VARHDRSZ + len); cptr = ((char *) out) + VARHDRSZ; dwptr = dw; while (dwptr - dw < dlen) { if (dwptr->start) { sprintf(cptr, "{%d ", dwptr->start); cptr = strchr(cptr, '\0'); } memcpy(cptr, dwptr->w, dwptr->len); cptr += dwptr->len; *cptr = ' '; cptr++; if (dwptr->finish) { sprintf(cptr, "}%d ", dwptr->finish); cptr = strchr(cptr, '\0'); } dwptr++; } VARATT_SIZEP(out) = cptr - ((char *) out); pfree(dw); for (i = 0; i < rlen; i++) if (doc[i].needfree) pfree(doc[i].item); pfree(doc); PG_FREE_IF_COPY(txt, 0); PG_FREE_IF_COPY(query, 1); PG_RETURN_POINTER(out); }
Datum ginint4_queryextract(PG_FUNCTION_ARGS) { int32 *nentries = (int32 *) PG_GETARG_POINTER(1); StrategyNumber strategy = PG_GETARG_UINT16(2); Datum *res = NULL; *nentries = 0; if (strategy == BooleanSearchStrategy) { QUERYTYPE *query = (QUERYTYPE *) PG_DETOAST_DATUM_COPY(PG_GETARG_POINTER(0)); ITEM *items = GETQUERY(query); int i; if (query->size == 0) PG_RETURN_POINTER(NULL); if (shorterquery(items, query->size) == 0) elog(ERROR, "Query requires full scan, GIN doesn't support it"); pfree(query); query = (QUERYTYPE *) PG_DETOAST_DATUM(PG_GETARG_POINTER(0)); items = GETQUERY(query); res = (Datum *) palloc(sizeof(Datum) * query->size); *nentries = 0; for (i = 0; i < query->size; i++) if (items[i].type == VAL) { res[*nentries] = Int32GetDatum(items[i].val); (*nentries)++; } } else { ArrayType *query = PG_GETARG_ARRAYTYPE_P(0); int4 *arr; uint32 i; CHECKARRVALID(query); *nentries = ARRNELEMS(query); if (*nentries > 0) { res = (Datum *) palloc(sizeof(Datum) * (*nentries)); arr = ARRPTR(query); for (i = 0; i < *nentries; i++) res[i] = Int32GetDatum(arr[i]); } } if (*nentries == 0) { switch (strategy) { case BooleanSearchStrategy: case RTOverlapStrategyNumber: *nentries = -1; /* nobody can be found */ break; default: /* require fullscan: GIN can't find void * arrays */ break; } } PG_RETURN_POINTER(res); }
/* * hstoreUpgrade: PG_DETOAST_DATUM plus support for conversion of old hstores */ HStore * hstoreUpgrade(Datum orig) { HStore *hs = (HStore *) PG_DETOAST_DATUM(orig); int valid_new; int valid_old; bool writable; /* Return immediately if no conversion needed */ if ((hs->size_ & HS_FLAG_NEWVERSION) || hs->size_ == 0 || (VARSIZE(hs) < 32768 && HSE_ISFIRST((ARRPTR(hs)[0])))) return hs; valid_new = hstoreValidNewFormat(hs); valid_old = hstoreValidOldFormat(hs); /* Do we have a writable copy? */ writable = ((void *) hs != (void *) DatumGetPointer(orig)); if (!valid_old || hs->size_ == 0) { if (valid_new) { /* * force the "new version" flag and the correct varlena length, * but only if we have a writable copy already (which we almost * always will, since short new-format values won't come through * here) */ if (writable) { HS_SETCOUNT(hs, HS_COUNT(hs)); HS_FIXSIZE(hs, HS_COUNT(hs)); } return hs; } else { elog(ERROR, "invalid hstore value found"); } } /* * this is the tricky edge case. It is only possible in some quite extreme * cases (the hstore must have had a lot of wasted padding space at the * end). But the only way a "new" hstore value could get here is if we're * upgrading in place from a pre-release version of hstore-new (NOT * contrib/hstore), so we work off the following assumptions: 1. If you're * moving from old contrib/hstore to hstore-new, you're required to fix up * any potential conflicts first, e.g. by running ALTER TABLE ... USING * col::text::hstore; on all hstore columns before upgrading. 2. If you're * moving from old contrib/hstore to new contrib/hstore, then "new" values * are impossible here 3. If you're moving from pre-release hstore-new to * hstore-new, then "old" values are impossible here 4. If you're moving * from pre-release hstore-new to new contrib/hstore, you're not doing so * as an in-place upgrade, so there is no issue So the upshot of all this * is that we can treat all the edge cases as "new" if we're being built * as hstore-new, and "old" if we're being built as contrib/hstore. * * XXX the WARNING can probably be downgraded to DEBUG1 once this has been * beta-tested. But for now, it would be very useful to know if anyone can * actually reach this case in a non-contrived setting. */ if (valid_new) { #if HSTORE_IS_HSTORE_NEW elog(WARNING, "ambiguous hstore value resolved as hstore-new"); /* * force the "new version" flag and the correct varlena length, but * only if we have a writable copy already (which we almost always * will, since short new-format values won't come through here) */ if (writable) { HS_SETCOUNT(hs, HS_COUNT(hs)); HS_FIXSIZE(hs, HS_COUNT(hs)); } return hs; #else elog(WARNING, "ambiguous hstore value resolved as hstore-old"); #endif } /* * must have an old-style value. Overwrite it in place as a new-style one, * making sure we have a writable copy first. */ if (!writable) hs = (HStore *) PG_DETOAST_DATUM_COPY(orig); { int count = hs->size_; HEntry *new_entries = ARRPTR(hs); HOldEntry *old_entries = (HOldEntry *) ARRPTR(hs); int i; for (i = 0; i < count; ++i) { uint32 pos = old_entries[i].pos; uint32 keylen = old_entries[i].keylen; uint32 vallen = old_entries[i].vallen; bool isnull = old_entries[i].valisnull; if (isnull) vallen = 0; new_entries[2 * i].entry = (pos + keylen) & HENTRY_POSMASK; new_entries[2 * i + 1].entry = (((pos + keylen + vallen) & HENTRY_POSMASK) | ((isnull) ? HENTRY_ISNULL : 0)); } if (count) new_entries[0].entry |= HENTRY_ISFIRST; HS_SETCOUNT(hs, count); HS_FIXSIZE(hs, count); } return hs; }
/* ** GiST Compress and Decompress methods */ Datum g_int_compress(PG_FUNCTION_ARGS) { GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0); GISTENTRY *retval; ArrayType *r; int len; int *dr; int i, min, cand; if (entry->leafkey) { r = (ArrayType *) PG_DETOAST_DATUM_COPY(entry->key); PREPAREARR(r); r->flags |= LEAFKEY; retval = palloc(sizeof(GISTENTRY)); gistentryinit(*retval, PointerGetDatum(r), entry->rel, entry->page, entry->offset, VARSIZE(r), FALSE); PG_RETURN_POINTER(retval); } r = (ArrayType *) PG_DETOAST_DATUM(entry->key); if (ISLEAFKEY(r) || ARRISVOID(r)) { if (r != (ArrayType *) DatumGetPointer(entry->key)) pfree(r); PG_RETURN_POINTER(entry); } if ((len = ARRNELEMS(r)) >= 2 * MAXNUMRANGE) { /* compress */ if (r == (ArrayType *) DatumGetPointer(entry->key)) r = (ArrayType *) PG_DETOAST_DATUM_COPY(entry->key); r = resize_intArrayType(r, 2 * (len)); dr = ARRPTR(r); for (i = len - 1; i >= 0; i--) dr[2 * i] = dr[2 * i + 1] = dr[i]; len *= 2; cand = 1; while (len > MAXNUMRANGE * 2) { min = 0x7fffffff; for (i = 2; i < len; i += 2) if (min > (dr[i] - dr[i - 1])) { min = (dr[i] - dr[i - 1]); cand = i; } memmove((void *) &dr[cand - 1], (void *) &dr[cand + 1], (len - cand - 1) * sizeof(int)); len -= 2; } r = resize_intArrayType(r, len); retval = palloc(sizeof(GISTENTRY)); gistentryinit(*retval, PointerGetDatum(r), entry->rel, entry->page, entry->offset, VARSIZE(r), FALSE); PG_RETURN_POINTER(retval); } else PG_RETURN_POINTER(entry); PG_RETURN_POINTER(entry); }
/* * This function accepts an array, and returns one item for each entry in the * array */ Datum int_enum(PG_FUNCTION_ARGS) { PGARRAY *p = (PGARRAY *) PG_GETARG_POINTER(0); CTX *pc; ReturnSetInfo *rsi = (ReturnSetInfo *) fcinfo->resultinfo; if (!rsi || !IsA(rsi, ReturnSetInfo)) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("int_enum called in context that cannot accept a set"))); if (!p) { elog(WARNING, "no data sent"); PG_RETURN_NULL(); } if (!fcinfo->flinfo->fn_extra) { /* Allocate working state */ MemoryContext oldcontext; oldcontext = MemoryContextSwitchTo(fcinfo->flinfo->fn_mcxt); pc = (CTX *) palloc(sizeof(CTX)); /* Don't copy attribute if you don't need to */ if (VARATT_IS_EXTENDED(p)) { /* Toasted!!! */ pc->p = (PGARRAY *) PG_DETOAST_DATUM_COPY(p); pc->flags = TOASTED; } else { /* Untoasted */ pc->p = p; pc->flags = 0; } /* Now that we have a detoasted array, verify dimensions */ /* We'll treat a zero-D array as empty, below */ if (pc->p->a.ndim > 1) elog(ERROR, "int_enum only accepts 1-D arrays"); pc->num = 0; fcinfo->flinfo->fn_extra = (void *) pc; MemoryContextSwitchTo(oldcontext); } else /* use existing working state */ pc = (CTX *) fcinfo->flinfo->fn_extra; /* Are we done yet? */ if (pc->p->a.ndim < 1 || pc->num >= pc->p->items) { /* We are done */ if (pc->flags & TOASTED) pfree(pc->p); pfree(pc); fcinfo->flinfo->fn_extra = NULL; rsi->isDone = ExprEndResult; } else { /* nope, return the next value */ int val = pc->p->array[pc->num++]; rsi->isDone = ExprMultipleResult; PG_RETURN_INT32(val); } PG_RETURN_NULL(); }
/* ** GiST Compress and Decompress methods */ Datum g_int_compress(PG_FUNCTION_ARGS) { GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0); GISTENTRY *retval; ArrayType *r; int len; int *dr; int i, min, cand; if (entry->leafkey) { r = (ArrayType *) PG_DETOAST_DATUM_COPY(entry->key); CHECKARRVALID(r); PREPAREARR(r); if (ARRNELEMS(r) >= 2 * MAXNUMRANGE) elog(NOTICE, "input array is too big (%d maximum allowed, %d current), use gist__intbig_ops opclass instead", 2 * MAXNUMRANGE - 1, ARRNELEMS(r)); retval = palloc(sizeof(GISTENTRY)); gistentryinit(*retval, PointerGetDatum(r), entry->rel, entry->page, entry->offset, FALSE); PG_RETURN_POINTER(retval); } /* * leaf entries never compress one more time, only when entry->leafkey * ==true, so now we work only with internal keys */ r = (ArrayType *) PG_DETOAST_DATUM(entry->key); CHECKARRVALID(r); if (ARRISVOID(r)) { if (r != (ArrayType *) DatumGetPointer(entry->key)) pfree(r); PG_RETURN_POINTER(entry); } if ((len = ARRNELEMS(r)) >= 2 * MAXNUMRANGE) { /* compress */ if (r == (ArrayType *) DatumGetPointer(entry->key)) r = (ArrayType *) PG_DETOAST_DATUM_COPY(entry->key); r = resize_intArrayType(r, 2 * (len)); dr = ARRPTR(r); for (i = len - 1; i >= 0; i--) dr[2 * i] = dr[2 * i + 1] = dr[i]; len *= 2; cand = 1; while (len > MAXNUMRANGE * 2) { min = 0x7fffffff; for (i = 2; i < len; i += 2) if (min > (dr[i] - dr[i - 1])) { min = (dr[i] - dr[i - 1]); cand = i; } memmove((void *) &dr[cand - 1], (void *) &dr[cand + 1], (len - cand - 1) * sizeof(int32)); len -= 2; } r = resize_intArrayType(r, len); retval = palloc(sizeof(GISTENTRY)); gistentryinit(*retval, PointerGetDatum(r), entry->rel, entry->page, entry->offset, FALSE); PG_RETURN_POINTER(retval); } else PG_RETURN_POINTER(entry); PG_RETURN_POINTER(entry); }
/* * Copied from Postgres' src/backend/optimizer/util/clauses.c * * evaluate_expr: pre-evaluate a constant expression * * We use the executor's routine ExecEvalExpr() to avoid duplication of * code and ensure we get the same result as the executor would get. */ Expr * evaluate_expr(Expr *expr, Oid result_type, int32 result_typmod, Oid result_collation) { EState *estate; ExprState *exprstate; MemoryContext oldcontext; Datum const_val; bool const_is_null; int16 resultTypLen; bool resultTypByVal; /* * To use the executor, we need an EState. */ estate = CreateExecutorState(); /* We can use the estate's working context to avoid memory leaks. */ oldcontext = MemoryContextSwitchTo(estate->es_query_cxt); /* Make sure any opfuncids are filled in. */ fix_opfuncids((Node *) expr); /* * Prepare expr for execution. (Note: we can't use ExecPrepareExpr * because it'd result in recursively invoking eval_const_expressions.) */ exprstate = ExecInitExpr(expr, NULL); /* * And evaluate it. * * It is OK to use a default econtext because none of the ExecEvalExpr() * code used in this situation will use econtext. That might seem * fortuitous, but it's not so unreasonable --- a constant expression does * not depend on context, by definition, n'est ce pas? */ const_val = ExecEvalExprSwitchContext(exprstate, GetPerTupleExprContext(estate), &const_is_null, NULL); /* Get info needed about result datatype */ get_typlenbyval(result_type, &resultTypLen, &resultTypByVal); /* Get back to outer memory context */ MemoryContextSwitchTo(oldcontext); /* * Must copy result out of sub-context used by expression eval. * * Also, if it's varlena, forcibly detoast it. This protects us against * storing TOAST pointers into plans that might outlive the referenced * data. (makeConst would handle detoasting anyway, but it's worth a few * extra lines here so that we can do the copy and detoast in one step.) */ if (!const_is_null) { if (resultTypLen == -1) const_val = PointerGetDatum(PG_DETOAST_DATUM_COPY(const_val)); else const_val = datumCopy(const_val, resultTypByVal, resultTypLen); } /* Release all the junk we just created */ FreeExecutorState(estate); /* * Make the constant result node. */ return (Expr *) makeConst(result_type, result_typmod, result_collation, resultTypLen, const_val, const_is_null, resultTypByVal); }