static jvalue _Array_coerceDatum(Type self, Datum arg) { jvalue result; jsize idx; Type elemType = Type_getElementType(self); int16 elemLength = Type_getLength(elemType); char elemAlign = Type_getAlign(elemType); bool elemByValue = Type_isByValue(elemType); ArrayType* v = DatumGetArrayTypeP(arg); jsize nElems = (jsize)ArrayGetNItems(ARR_NDIM(v), ARR_DIMS(v)); jobjectArray objArray = JNI_newObjectArray(nElems, Type_getJavaClass(elemType), 0); const char* values = ARR_DATA_PTR(v); bits8* nullBitMap = ARR_NULLBITMAP(v); for(idx = 0; idx < nElems; ++idx) { if(arrayIsNull(nullBitMap, idx)) JNI_setObjectArrayElement(objArray, idx, 0); else { Datum value = fetch_att(values, elemByValue, elemLength); jvalue obj = Type_coerceDatum(elemType, value); JNI_setObjectArrayElement(objArray, idx, obj.l); JNI_deleteLocalRef(obj.l); values = att_addlength_datum(values, elemLength, PointerGetDatum(values)); values = (char*)att_align_nominal(values, elemAlign); } } result.l = (jobject)objArray; return result; }
/* * make_variant_int: Converts our external (Variant) representation to a VariantInt. */ static VariantInt make_variant_int(Variant v, FunctionCallInfo fcinfo, IOFuncSelector func) { VariantCache *cache; VariantInt vi; long data_length; /* long instead of size_t because we're subtracting */ Pointer ptr; uint flags; /* Ensure v is fully detoasted */ Assert(!VARATT_IS_EXTENDED(v)); /* May need to be careful about what context this stuff is palloc'd in */ vi = palloc0(sizeof(VariantDataInt)); vi->typid = get_oid(v, &flags); #ifdef VARIANT_TEST_OID vi->typid -= OID_MASK; #endif vi->typmod = v->typmod; vi->isnull = (flags & VAR_ISNULL ? true : false); cache = get_cache(fcinfo, vi, func); /* * by-value type. We do special things with all pass-by-reference when we * store, so we only use this for typbyval even though fetch_att supports * pass-by-reference. * * Note that fetch_att sanity-checks typlen for us (because we're only passing typbyval). */ if(cache->typbyval) { if(!vi->isnull) { Pointer p = VDATAPTR_ALIGN(v, cache->typalign); vi->data = fetch_att(p, cache->typbyval, cache->typlen); } return vi; } /* we don't store a varlena header for varlena data; instead we compute * it's size based on ours: * * Our size - our header size - overflow byte (if present) * * For cstring, we don't store the trailing NUL */ data_length = VARSIZE(v) - VHDRSZ - (flags & VAR_OVERFLOW ? 1 : 0); if( data_length < 0 ) elog(ERROR, "Negative data_length %li", data_length); if (cache->typlen == -1) /* varlena */ { ptr = palloc0(data_length + VARHDRSZ); SET_VARSIZE(ptr, data_length + VARHDRSZ); memcpy(VARDATA(ptr), VDATAPTR(v), data_length); } else if(cache->typlen == -2) /* cstring */ { ptr = palloc(data_length + 1); /* Need space for NUL terminator */ memcpy(ptr, VDATAPTR(v), data_length); *(ptr + data_length + 1) = '\0'; } else /* Fixed size, pass by reference */ { if(vi->isnull) { vi->data = (Datum) 0; return vi; } Assert(data_length == cache->typlen); ptr = palloc0(data_length); Assert(ptr == (char *) att_align_nominal(ptr, cache->typalign)); memcpy(ptr, VDATAPTR(v), data_length); } vi->data = PointerGetDatum(ptr); return vi; }
/* * Reading quantiles from an input array, based mostly on * array_to_text_internal (it's a modified copy). This expects * to receive a single-dimensional float8 array as input, fails * otherwise. */ static double * array_to_double(FunctionCallInfo fcinfo, ArrayType *v, int * len) { double *result; int nitems, *dims, ndims; Oid element_type; int typlen; bool typbyval; char typalign; char *p; int i, idx = 0; ArrayMetaState *my_extra; ndims = ARR_NDIM(v); dims = ARR_DIMS(v); nitems = ArrayGetNItems(ndims, dims); /* this is a special-purpose function for single-dimensional arrays */ if (ndims != 1) { elog(ERROR, "error, array_to_double expects a single-dimensional array" "(dims = %d)", ndims); } /* if there are no elements, set the length to 0 and return NULL */ if (nitems == 0) { (*len) = 0; return NULL; } element_type = ARR_ELEMTYPE(v); result = (double*)palloc(nitems * sizeof(double)); /* * We arrange to look up info about element type, including its output * conversion proc, only once per series of calls, assuming the element * type doesn't change underneath us. */ my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra; if (my_extra == NULL) { fcinfo->flinfo->fn_extra = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt, sizeof(ArrayMetaState)); my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra; my_extra->element_type = ~element_type; } if (my_extra->element_type != element_type) { /* * Get info about element type, including its output conversion proc */ get_type_io_data(element_type, IOFunc_output, &my_extra->typlen, &my_extra->typbyval, &my_extra->typalign, &my_extra->typdelim, &my_extra->typioparam, &my_extra->typiofunc); fmgr_info_cxt(my_extra->typiofunc, &my_extra->proc, fcinfo->flinfo->fn_mcxt); my_extra->element_type = element_type; } typlen = my_extra->typlen; typbyval = my_extra->typbyval; typalign = my_extra->typalign; p = ARR_DATA_PTR(v); for (i = 0; i < nitems; i++) { Datum itemvalue = fetch_att(p, typbyval, typlen); double val = DatumGetFloat8(itemvalue); result[idx++] = val; p = att_addlength_pointer(p, typlen, p); p = (char *) att_align_nominal(p, typalign); } (*len) = idx; return result; }
Datum serialize_array(PG_FUNCTION_ARGS) { ArrayType *v = PG_GETARG_ARRAYTYPE_P(0); Oid element_type = ARR_ELEMTYPE(v); int16 typlen; bool typbyval; char typalign; char typdelim; char *p, *value; char type_category; bool needComma = false; bits8 *bitmap; int bitmask; int nitems, i; int ndim, *dims; Oid typioparam, typiofunc; HeapTuple type_tuple; FmgrInfo proc, flinfo; StringInfoData buf; // FILE* log; // log = fopen("/var/lib/postgresql/serializer.log", "a"); // fprintf(log, "Doing serialize_array\n"); // fflush(log); /* * Get info about element type, including its output conversion proc */ get_type_io_data(element_type, IOFunc_output, &typlen, &typbyval, &typalign, &typdelim, &typioparam, &typiofunc); fmgr_info_cxt( typiofunc, &proc, fcinfo->flinfo->fn_mcxt ); ndim = ARR_NDIM(v); dims = ARR_DIMS(v); nitems = ArrayGetNItems(ndim, dims); if( ndim > 1 ) elog( ERROR, "multidimensional arrays doesn't supported" ); p = ARR_DATA_PTR(v); bitmap = ARR_NULLBITMAP(v); bitmask = 1; /* obtain type information from pg_catalog */ type_tuple = SearchSysCache1( TYPEOID, ObjectIdGetDatum(element_type) ); if (!HeapTupleIsValid( type_tuple )) elog(ERROR, "cache lookup failed for relation %u", element_type); type_category = ((Form_pg_type) GETSTRUCT( type_tuple ))->typcategory; ReleaseSysCache( type_tuple ); /* Build the result string */ initStringInfo(&buf); appendStringInfoChar(&buf, '['); for (i = 0; i < nitems; i++) { if (needComma) appendStringInfoChar(&buf, ','); needComma = true; /* Get source element, checking for NULL */ if (bitmap && (*bitmap & bitmask) == 0) { // append null appendStringInfoString(&buf, "null"); } else { /* get item value and advance array data pointer */ Datum itemvalue = fetch_att(p, typbyval, typlen); p = att_addlength_pointer(p, typlen, p); p = (char *) att_align_nominal(p, typalign); //------------------------ switch( type_category ) { // http://www.postgresql.org/docs/current/static/catalog-pg-type.html#CATALOG-TYPCATEGORY-TABLE case 'A': //array - impossible case break; case 'C': //composite //call to serialize_record( ... ) MemSet( &flinfo, 0, sizeof( flinfo ) ); flinfo.fn_addr = serialize_record; flinfo.fn_nargs = 1; flinfo.fn_mcxt = fcinfo->flinfo->fn_mcxt; value = PG_TEXT_DATUM_GET_CSTR( FunctionCall1( &flinfo, itemvalue ) ); appendStringInfoString(&buf, value); break; case 'N': //numeric // get column text value value = OutputFunctionCall( &proc, itemvalue ); appendStringInfoString(&buf, value); break; default: //another // get column text value value = OutputFunctionCall( &proc, itemvalue ); appendStringInfoQuotedString(&buf, value); } } /* advance bitmap pointer if any */ if (bitmap) { bitmask <<= 1; if (bitmask == 0x100) { bitmap++; bitmask = 1; } } } appendStringInfoChar(&buf, ']'); // fclose(log); //PG_RETURN_CSTRING(retval); PG_RETURN_TEXT_P( PG_CSTR_GET_TEXT( buf.data ) ); }
static PyObject * PLyList_FromArray_recurse(PLyDatumToOb *elm, int *dims, int ndim, int dim, char **dataptr_p, bits8 **bitmap_p, int *bitmask_p) { int i; PyObject *list; list = PyList_New(dims[dim]); if (!list) return NULL; if (dim < ndim - 1) { /* Outer dimension. Recurse for each inner slice. */ for (i = 0; i < dims[dim]; i++) { PyObject *sublist; sublist = PLyList_FromArray_recurse(elm, dims, ndim, dim + 1, dataptr_p, bitmap_p, bitmask_p); PyList_SET_ITEM(list, i, sublist); } } else { /* * Innermost dimension. Fill the list with the values from the array * for this slice. */ char *dataptr = *dataptr_p; bits8 *bitmap = *bitmap_p; int bitmask = *bitmask_p; for (i = 0; i < dims[dim]; i++) { /* checking for NULL */ if (bitmap && (*bitmap & bitmask) == 0) { Py_INCREF(Py_None); PyList_SET_ITEM(list, i, Py_None); } else { Datum itemvalue; itemvalue = fetch_att(dataptr, elm->typbyval, elm->typlen); PyList_SET_ITEM(list, i, elm->func(elm, itemvalue)); dataptr = att_addlength_pointer(dataptr, elm->typlen, dataptr); dataptr = (char *) att_align_nominal(dataptr, elm->typalign); } /* advance bitmap pointer if any */ if (bitmap) { bitmask <<= 1; if (bitmask == 0x100 /* (1<<8) */ ) { bitmap++; bitmask = 1; } } } *dataptr_p = dataptr; *bitmap_p = bitmap; *bitmask_p = bitmask; } return list; }
/* * load_auth_entries: read pg_authid into auth_entry[] * * auth_info_out: pointer to auth_entry * where address to auth_entry[] should be stored * total_roles_out: pointer to int where num of total roles should be stored */ static void load_auth_entries(Relation rel_authid, auth_entry **auth_info_out, int *total_roles_out) { BlockNumber totalblocks; HeapScanDesc scan; HeapTuple tuple; int curr_role = 0; int total_roles = 0; int est_rows; auth_entry *auth_info; /* * Read pg_authid and fill temporary data structures. Note we must read * all roles, even those without rolcanlogin. */ totalblocks = RelationGetNumberOfBlocks(rel_authid); totalblocks = totalblocks ? totalblocks : 1; est_rows = totalblocks * (BLCKSZ / (sizeof(HeapTupleHeaderData) + sizeof(FormData_pg_authid))); auth_info = (auth_entry *) palloc(est_rows * sizeof(auth_entry)); scan = heap_beginscan(rel_authid, SnapshotNow, 0, NULL); while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL) { Form_pg_authid aform = (Form_pg_authid) GETSTRUCT(tuple); HeapTupleHeader tup = tuple->t_data; char *tp; /* ptr to tuple data */ long off; /* offset in tuple data */ bits8 *bp = tup->t_bits; /* ptr to null bitmask in tuple */ Datum datum; if (curr_role >= est_rows) { est_rows *= 2; auth_info = (auth_entry *) repalloc(auth_info, est_rows * sizeof(auth_entry)); } auth_info[curr_role].roleid = HeapTupleGetOid(tuple); auth_info[curr_role].rolsuper = aform->rolsuper; auth_info[curr_role].rolcanlogin = aform->rolcanlogin; auth_info[curr_role].rolname = pstrdup(NameStr(aform->rolname)); auth_info[curr_role].member_of = NIL; /* * We can't use heap_getattr() here because during startup we will not * have any tupdesc for pg_authid. Fortunately it's not too hard to * work around this. rolpassword is the first possibly-null field so * we can compute its offset directly. */ tp = (char *) tup + tup->t_hoff; off = offsetof(FormData_pg_authid, rolpassword); if (HeapTupleHasNulls(tuple) && att_isnull(Anum_pg_authid_rolpassword - 1, bp)) { /* passwd is null, emit as an empty string */ auth_info[curr_role].rolpassword = pstrdup(""); } else { /* assume passwd is pass-by-ref */ datum = PointerGetDatum(tp + off); /* * The password probably shouldn't ever be out-of-line toasted; if * it is, ignore it, since we can't handle that in startup mode. */ if (VARATT_IS_EXTERNAL(DatumGetPointer(datum))) auth_info[curr_role].rolpassword = pstrdup(""); else auth_info[curr_role].rolpassword = DatumGetCString(DirectFunctionCall1(textout, datum)); /* assume passwd has attlen -1 */ off = att_addlength(off, -1, PointerGetDatum(tp + off)); } if (HeapTupleHasNulls(tuple) && att_isnull(Anum_pg_authid_rolvaliduntil - 1, bp)) { /* rolvaliduntil is null, emit as an empty string */ auth_info[curr_role].rolvaliduntil = pstrdup(""); } else { /* * rolvaliduntil is timestamptz, which we assume is double * alignment and pass-by-value. */ off = att_align(off, 'd'); datum = fetch_att(tp + off, true, sizeof(TimestampTz)); auth_info[curr_role].rolvaliduntil = DatumGetCString(DirectFunctionCall1(timestamptz_out, datum)); } /* * Check for illegal characters in the user name and password. */ if (!name_okay(auth_info[curr_role].rolname)) { ereport(LOG, (errmsg("invalid role name \"%s\"", auth_info[curr_role].rolname))); continue; } if (!name_okay(auth_info[curr_role].rolpassword)) { ereport(LOG, (errmsg("invalid role password \"%s\"", auth_info[curr_role].rolpassword))); continue; } curr_role++; total_roles++; } heap_endscan(scan); *auth_info_out = auth_info; *total_roles_out = total_roles; }
Datum count_distinct_elements_append(PG_FUNCTION_ARGS) { int i; element_set_t *eset = NULL; /* info for anyarray */ Oid input_type; Oid element_type; /* array data */ ArrayType *input; int ndims; int *dims; int nitems; bits8 *null_bitmap; char *arr_ptr; Datum element; /* memory contexts */ MemoryContext oldcontext; MemoryContext aggcontext; /* * If the new value is NULL, we simply return the current aggregate state * (it might be NULL, so check it). In this case we don't really care about * the types etc. * * We may still get NULL elements in the array, but to check that we would * have to walk the array, which does not qualify as cheap check. Also we * assume that there's at least one non-NULL element, and we'll walk the * array just once. It's possible we'll get empty set this way. */ if (PG_ARGISNULL(1) && PG_ARGISNULL(0)) PG_RETURN_NULL(); else if (PG_ARGISNULL(1)) PG_RETURN_DATUM(PG_GETARG_DATUM(0)); /* from now on we know the new value is not NULL */ /* get the type of array elements */ input_type = get_fn_expr_argtype(fcinfo->flinfo, 1); element_type = get_element_type(input_type); /* * parse the array contents (we know we got non-NULL value) */ input = PG_GETARG_ARRAYTYPE_P(1); ndims = ARR_NDIM(input); dims = ARR_DIMS(input); nitems = ArrayGetNItems(ndims, dims); null_bitmap = ARR_NULLBITMAP(input); arr_ptr = ARR_DATA_PTR(input); /* make sure we're running as part of aggregate function */ GET_AGG_CONTEXT("count_distinct_elements_append", fcinfo, aggcontext); oldcontext = MemoryContextSwitchTo(aggcontext); /* add all array elements to the set */ for (i = 0; i < nitems; i++) { /* ignore nulls */ if (null_bitmap && !(null_bitmap[i / 8] & (1 << (i % 8)))) continue; /* init the hash table, if needed */ if (eset == NULL) { if (PG_ARGISNULL(0)) { int16 typlen; bool typbyval; char typalign; /* get type information for the second parameter (anyelement item) */ get_typlenbyvalalign(element_type, &typlen, &typbyval, &typalign); /* we can't handle varlena types yet or values passed by reference */ if ((typlen < 0) || (! typbyval)) elog(ERROR, "count_distinct_elements handles only arrays of fixed-length types passed by value"); eset = init_set(typlen, typalign, aggcontext); } else eset = (element_set_t *)PG_GETARG_POINTER(0); } element = fetch_att(arr_ptr, true, eset->item_size); add_element(eset, (char*)&element); /* advance array pointer */ arr_ptr = att_addlength_pointer(arr_ptr, eset->item_size, arr_ptr); arr_ptr = (char *) att_align_nominal(arr_ptr, eset->typalign); } MemoryContextSwitchTo(oldcontext); if (eset == NULL) PG_RETURN_NULL(); else PG_RETURN_POINTER(eset); }
static text* plvsubst_string(text *template_in, ArrayType *vals_in, text *c_subst, FunctionCallInfo fcinfo) { ArrayType *v = vals_in; int nitems, *dims, ndims; char *p; int16 typlen; bool typbyval; char typalign; char typdelim; Oid typelem; Oid typiofunc; FmgrInfo proc; int i = 0, items = 0; StringInfo sinfo; const char *template_str; int template_len; char *sizes; int *positions; int subst_mb_len; int subst_len; const bits8 *bitmap; int bitmask; if (v != NULL && (ndims = ARR_NDIM(v)) > 0) { if (ndims != 1) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("invalid parameter"), errdetail("Array of arguments has wrong dimension: %d", ndims))); p = ARR_DATA_PTR(v); dims = ARR_DIMS(v); nitems = ArrayGetNItems(ndims, dims); bitmap = ARR_NULLBITMAP(v); get_type_io_data(ARR_ELEMTYPE(v), IOFunc_output, &typlen, &typbyval, &typalign, &typdelim, &typelem, &typiofunc); fmgr_info_cxt(typiofunc, &proc, fcinfo->flinfo->fn_mcxt); } else { nitems = 0; p = NULL; bitmap = NULL; } template_str = VARDATA(template_in); template_len = ora_mb_strlen(template_in, &sizes, &positions); subst_mb_len = ora_mb_strlen1(c_subst); subst_len = VARSIZE_ANY_EXHDR(c_subst); sinfo = makeStringInfo(); bitmask = 1; for (i = 0; i < template_len; i++) { if (strncmp(&template_str[positions[i]], VARDATA(c_subst), subst_len) == 0) { Datum itemvalue; char *value; if (items++ < nitems) { if (bitmap && (*bitmap & bitmask) == 0) value = pstrdup("NULL"); else { itemvalue = fetch_att(p, typbyval, typlen); value = DatumGetCString(FunctionCall3(&proc, itemvalue, ObjectIdGetDatum(typelem), Int32GetDatum(-1))); p = att_addlength_pointer(p, typlen, p); p = (char *) att_align_nominal(p, typalign); } appendStringInfoString(sinfo, value); pfree(value); if (bitmap) { bitmask <<= 1; if (bitmask == 0x100) { bitmap++; bitmask = 1; } } } else ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("too few parameters specified for template string"))); i += subst_mb_len - 1; } else appendBinaryStringInfo(sinfo, &template_str[positions[i]], sizes[i]); } return cstring_to_text(sinfo->data); }