/* * Allocate working buffers needed for WAL record construction. */ void InitXLogInsert(void) { /* Initialize the working areas */ if (xloginsert_cxt == NULL) { xloginsert_cxt = AllocSetContextCreate(TopMemoryContext, "WAL record construction", ALLOCSET_DEFAULT_MINSIZE, ALLOCSET_DEFAULT_INITSIZE, ALLOCSET_DEFAULT_MAXSIZE); } if (registered_buffers == NULL) { registered_buffers = (registered_buffer *) MemoryContextAllocZero(xloginsert_cxt, sizeof(registered_buffer) * (XLR_NORMAL_MAX_BLOCK_ID + 1)); max_registered_buffers = XLR_NORMAL_MAX_BLOCK_ID + 1; } if (rdatas == NULL) { rdatas = MemoryContextAlloc(xloginsert_cxt, sizeof(XLogRecData) * XLR_NORMAL_RDATAS); max_rdatas = XLR_NORMAL_RDATAS; } /* * Allocate a buffer to hold the header information for a WAL record. */ if (hdr_scratch == NULL) hdr_scratch = MemoryContextAllocZero(xloginsert_cxt, HEADER_SCRATCH_SIZE); }
char *lookup_analysis_thing(MemoryContext cxt, char *thing) { char *definition = ""; StringInfo query; SPI_connect(); query = makeStringInfo(); appendStringInfo(query, "select (to_json(name) || ':' || definition) from %s;", TextDatumGetCString(DirectFunctionCall1(quote_ident, CStringGetTextDatum(thing)))); if (SPI_execute(query->data, true, 0) != SPI_OK_SELECT) elog(ERROR, "Problem looking up analysis thing with query: %s", query->data); if (SPI_processed > 0) { StringInfo json = makeStringInfo(); int i; for (i = 0; i < SPI_processed; i++) { if (i > 0) appendStringInfoCharMacro(json, ','); appendStringInfo(json, "%s", SPI_getvalue(SPI_tuptable->vals[i], SPI_tuptable->tupdesc, 1)); } definition = (char *) MemoryContextAllocZero(cxt, (Size) json->len + 1); memcpy(definition, json->data, json->len); } SPI_finish(); return definition; }
/* * Construct a PLySavedArgs struct representing the current values of the * procedure's arguments in its globals dict. This can be used to restore * those values when exiting a recursive call level or returning control to a * set-returning function. * * This would not be necessary except for an ancient decision to make args * available via the proc's globals :-( ... but we're stuck with that now. */ static PLySavedArgs * PLy_function_save_args(PLyProcedure *proc) { PLySavedArgs *result; /* saved args are always allocated in procedure's context */ result = (PLySavedArgs *) MemoryContextAllocZero(proc->mcxt, offsetof(PLySavedArgs, namedargs) + proc->nargs * sizeof(PyObject *)); result->nargs = proc->nargs; /* Fetch the "args" list */ result->args = PyDict_GetItemString(proc->globals, "args"); Py_XINCREF(result->args); /* Fetch all the named arguments */ if (proc->argnames) { int i; for (i = 0; i < result->nargs; i++) { if (proc->argnames[i]) { result->namedargs[i] = PyDict_GetItemString(proc->globals, proc->argnames[i]); Py_XINCREF(result->namedargs[i]); } } } return result; }
char *lookup_field_mapping(MemoryContext cxt, Oid tableRelId, char *fieldname) { char *definition = NULL; StringInfo query; SPI_connect(); query = makeStringInfo(); appendStringInfo(query, "select definition from zdb_mappings where table_name = %d::regclass and field_name = %s;", tableRelId, TextDatumGetCString(DirectFunctionCall1(quote_literal, CStringGetTextDatum(fieldname)))); if (SPI_execute(query->data, true, 2) != SPI_OK_SELECT) elog(ERROR, "Problem looking up analysis thing with query: %s", query->data); if (SPI_processed > 1) { elog(ERROR, "Too many mappings found"); } else if (SPI_processed == 1) { char *json = SPI_getvalue(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 1); Size len = strlen(json); definition = (char *) MemoryContextAllocZero(cxt, (Size) len + 1); memcpy(definition, json, len); } SPI_finish(); return definition; }
/* * ResourceOwnerCreate * Create an empty ResourceOwner. * * All ResourceOwner objects are kept in TopMemoryContext, since they should * only be freed explicitly. */ ResourceOwner ResourceOwnerCreate(ResourceOwner parent, const char *name) { ResourceOwner owner; owner = (ResourceOwner) MemoryContextAllocZero(TopMemoryContext, sizeof(ResourceOwnerData)); owner->name = name; if (parent) { owner->parent = parent; owner->nextchild = parent->firstchild; parent->firstchild = owner; } ResourceArrayInit(&(owner->bufferarr), BufferGetDatum(InvalidBuffer)); ResourceArrayInit(&(owner->catrefarr), PointerGetDatum(NULL)); ResourceArrayInit(&(owner->catlistrefarr), PointerGetDatum(NULL)); ResourceArrayInit(&(owner->relrefarr), PointerGetDatum(NULL)); ResourceArrayInit(&(owner->planrefarr), PointerGetDatum(NULL)); ResourceArrayInit(&(owner->tupdescarr), PointerGetDatum(NULL)); ResourceArrayInit(&(owner->snapshotarr), PointerGetDatum(NULL)); ResourceArrayInit(&(owner->filearr), FileGetDatum(-1)); ResourceArrayInit(&(owner->dsmarr), PointerGetDatum(NULL)); ResourceArrayInit(&(owner->jitarr), PointerGetDatum(NULL)); return owner; }
static TSVectorStat * ts_accum(MemoryContext persistentContext, TSVectorStat *stat, Datum data) { TSVector txt = DatumGetTSVector(data); uint32 i, nbit = 0, offset; if (stat == NULL) { /* Init in first */ stat = MemoryContextAllocZero(persistentContext, sizeof(TSVectorStat)); stat->maxdepth = 1; } /* simple check of correctness */ if (txt == NULL || txt->size == 0) { if (txt && txt != (TSVector) DatumGetPointer(data)) pfree(txt); return stat; } i = txt->size - 1; for (; i > 0; i >>= 1) nbit++; nbit = 1 << nbit; offset = (nbit - txt->size) / 2; insertStatEntry(persistentContext, stat, txt, (nbit >> 1) - offset); chooseNextStatEntry(persistentContext, stat, txt, 0, nbit, offset); return stat; }
/* * AtStart_Inval * Initialize inval lists at start of a main transaction. */ void AtStart_Inval(void) { Assert(transInvalInfo == NULL); transInvalInfo = (TransInvalidationInfo *) MemoryContextAllocZero(TopTransactionContext, sizeof(TransInvalidationInfo)); transInvalInfo->my_level = GetCurrentTransactionNestLevel(); }
static struct brokerstate * local_amqp_get_a_bs(broker_id) { struct brokerstate *bs; for(bs = HEAD_BS; bs; bs = bs->next) { if(bs->broker_id == broker_id) return bs; } bs = MemoryContextAllocZero(TopMemoryContext, sizeof(*bs)); bs->broker_id = broker_id; bs->next = HEAD_BS; HEAD_BS = bs; return bs; }
Segment * CopySegment(Segment *src, MemoryContext cxt) { MemoryContext valid_cxt = cxt ? cxt : CurrentMemoryContext; Segment *dest = MemoryContextAllocZero(valid_cxt, sizeof(Segment)); memcpy(dest, src, sizeof(Segment)); /* memory leak risk! */ dest->hostname = MemoryContextStrdup(valid_cxt, src->hostname); dest->hostip = MemoryContextStrdup(valid_cxt, src->hostip); return dest; }
/* * AtSubStart_Inval * Initialize inval lists at start of a subtransaction. */ void AtSubStart_Inval(void) { TransInvalidationInfo *myInfo; Assert(transInvalInfo != NULL); myInfo = (TransInvalidationInfo *) MemoryContextAllocZero(TopTransactionContext, sizeof(TransInvalidationInfo)); myInfo->parent = transInvalInfo; myInfo->my_level = GetCurrentTransactionNestLevel(); transInvalInfo = myInfo; }
/* * CreatePortal * Returns a new portal given a name. * * allowDup: if true, automatically drop any pre-existing portal of the * same name (if false, an error is raised). * * dupSilent: if true, don't even emit a WARNING. */ Portal CreatePortal(const char *name, bool allowDup, bool dupSilent) { Portal portal; AssertArg(PointerIsValid(name)); portal = GetPortalByName(name); if (PortalIsValid(portal)) { if (!allowDup) ereport(ERROR, (errcode(ERRCODE_DUPLICATE_CURSOR), errmsg("cursor \"%s\" already exists", name))); if (!dupSilent) ereport(WARNING, (errcode(ERRCODE_DUPLICATE_CURSOR), errmsg("closing existing cursor \"%s\"", name))); PortalDrop(portal, false); } /* make new portal structure */ portal = (Portal) MemoryContextAllocZero(PortalMemory, sizeof *portal); /* initialize portal heap context; typically it won't store much */ portal->heap = AllocSetContextCreate(PortalMemory, "PortalHeapMemory", ALLOCSET_SMALL_MINSIZE, ALLOCSET_SMALL_INITSIZE, ALLOCSET_SMALL_MAXSIZE); /* create a resource owner for the portal */ portal->resowner = ResourceOwnerCreate(CurTransactionResourceOwner, "Portal"); /* initialize portal fields that don't start off zero */ portal->cleanup = PortalCleanup; portal->createSubid = GetCurrentSubTransactionId(); portal->strategy = PORTAL_MULTI_QUERY; portal->cursorOptions = CURSOR_OPT_NO_SCROLL; portal->atStart = true; portal->atEnd = true; /* disallow fetches until query is set */ /* put portal in table (sets portal->name) */ PortalHashTableInsert(portal, name); return portal; }
static struct PgqTriggerInfo *find_trigger_info(struct PgqTableInfo *info, Oid tgoid, bool create) { struct PgqTriggerInfo *tgargs = info->tg_cache; for (tgargs = info->tg_cache; tgargs; tgargs = tgargs->next) { if (tgargs->tgoid == tgoid) return tgargs; } if (!create) return NULL; tgargs = MemoryContextAllocZero(tbl_cache_ctx, sizeof(*tgargs)); tgargs->tgoid = tgoid; tgargs->next = info->tg_cache; info->tg_cache = tgargs; return tgargs; }
void plx_result_insert_cache(FunctionCallInfo fcinfo, PlxFn *plx_fn, PGresult *pg_result) { PlxResultCacheEntry *hentry; bool found; PlxResult *plx_result; plx_result = MemoryContextAllocZero(plx_result_mctx, sizeof(PlxResult)); plx_result->plx_fn = plx_fn; plx_result->pg_result = pg_result; hentry = hash_search(plx_result_cache, &fcinfo, HASH_ENTER, &found); if (found) elog(ERROR, "%s (fcinfo = %p) already has plx_result in cache", plx_fn->name, fcinfo); hentry->plx_result = plx_result; }
/* * ResourceOwnerCreate * Create an empty ResourceOwner. * * All ResourceOwner objects are kept in TopMemoryContext, since they should * only be freed explicitly. */ ResourceOwner ResourceOwnerCreate(ResourceOwner parent, const char *name) { ResourceOwner owner; owner = (ResourceOwner) MemoryContextAllocZero(TopMemoryContext, sizeof(ResourceOwnerData)); owner->name = name; if (parent) { owner->parent = parent; owner->nextchild = parent->firstchild; parent->firstchild = owner; } return owner; }
static int newLOfd(LargeObjectDesc *lobjCookie) { int i, newsize; /* Try to find a free slot */ for (i = 0; i < cookies_size; i++) { if (cookies[i] == NULL) { cookies[i] = lobjCookie; return i; } } /* No free slot, so make the array bigger */ if (cookies_size <= 0) { /* First time through, arbitrarily make 64-element array */ i = 0; newsize = 64; cookies = (LargeObjectDesc **) MemoryContextAllocZero(fscxt, newsize * sizeof(LargeObjectDesc *)); cookies_size = newsize; } else { /* Double size of array */ i = cookies_size; newsize = cookies_size * 2; cookies = (LargeObjectDesc **) repalloc(cookies, newsize * sizeof(LargeObjectDesc *)); MemSet(cookies + cookies_size, 0, (newsize - cookies_size) * sizeof(LargeObjectDesc *)); cookies_size = newsize; } Assert(cookies[i] == NULL); cookies[i] = lobjCookie; return i; }
PlxQuery * create_plx_query_from_plx_fn(PlxFn *plx_fn) { PlxQuery *plx_q = new_plx_query(plx_fn->mctx); int i; appendStringInfo(plx_q->sql, "%s", plx_fn->name); appendStringInfo(plx_q->sql, "("); for (i = 1; i <= plx_fn->nargs; i++) appendStringInfo(plx_q->sql, "$%d%s", i, i < plx_fn->nargs ? "," : ""); appendStringInfo(plx_q->sql, ")"); plx_q->plx_fn_arg_indexes = MemoryContextAllocZero(plx_fn->mctx, sizeof(int) * plx_fn->nargs); for (i = 0; i < plx_fn->nargs; i++) plx_q->plx_fn_arg_indexes[i] = i; plx_q->nargs = plx_fn->nargs; return plx_q; }
/* * Initialize, or re-initialize, per-column output info for a composite type. * * This is separate from PLy_output_setup_func() because in cases involving * anonymous record types, we need to be passed the tupdesc explicitly. * It's caller's responsibility that the tupdesc has adequate lifespan * in such cases. If the tupdesc is for a named composite or registered * record type, it does not need to be long-lived. */ void PLy_output_setup_tuple(PLyObToDatum *arg, TupleDesc desc, PLyProcedure *proc) { int i; /* We should be working on a previously-set-up struct */ Assert(arg->func == PLyObject_ToComposite); /* Save pointer to tupdesc, but only if this is an anonymous record type */ if (arg->typoid == RECORDOID && arg->typmod < 0) arg->u.tuple.recdesc = desc; /* (Re)allocate atts array as needed */ if (arg->u.tuple.natts != desc->natts) { if (arg->u.tuple.atts) pfree(arg->u.tuple.atts); arg->u.tuple.natts = desc->natts; arg->u.tuple.atts = (PLyObToDatum *) MemoryContextAllocZero(arg->mcxt, desc->natts * sizeof(PLyObToDatum)); } /* Fill the atts entries, except for dropped columns */ for (i = 0; i < desc->natts; i++) { Form_pg_attribute attr = TupleDescAttr(desc, i); PLyObToDatum *att = &arg->u.tuple.atts[i]; if (attr->attisdropped) continue; if (att->typoid == attr->atttypid && att->typmod == attr->atttypmod) continue; /* already set up this entry */ PLy_output_setup_func(att, arg->mcxt, attr->atttypid, attr->atttypmod, proc); } }
/* * PrepareInvalidationState * Initialize inval lists for the current (sub)transaction. */ static void PrepareInvalidationState(void) { TransInvalidationInfo *myInfo; if (transInvalInfo != NULL && transInvalInfo->my_level == GetCurrentTransactionNestLevel()) return; myInfo = (TransInvalidationInfo *) MemoryContextAllocZero(TopTransactionContext, sizeof(TransInvalidationInfo)); myInfo->parent = transInvalInfo; myInfo->my_level = GetCurrentTransactionNestLevel(); /* * If there's any previous entry, this one should be for a deeper nesting * level. */ Assert(transInvalInfo == NULL || myInfo->my_level > transInvalInfo->my_level); transInvalInfo = myInfo; }
/* * Recursively initialize the PLyObToDatum structure(s) needed to construct * a SQL value of the specified typeOid/typmod from a Python value. * (But note that at this point we may have RECORDOID/-1, ie, an indeterminate * record type.) * proc is used to look up transform functions. */ void PLy_output_setup_func(PLyObToDatum *arg, MemoryContext arg_mcxt, Oid typeOid, int32 typmod, PLyProcedure *proc) { TypeCacheEntry *typentry; char typtype; Oid trfuncid; Oid typinput; /* Since this is recursive, it could theoretically be driven to overflow */ check_stack_depth(); arg->typoid = typeOid; arg->typmod = typmod; arg->mcxt = arg_mcxt; /* * Fetch typcache entry for the target type, asking for whatever info * we'll need later. RECORD is a special case: just treat it as composite * without bothering with the typcache entry. */ if (typeOid != RECORDOID) { typentry = lookup_type_cache(typeOid, TYPECACHE_DOMAIN_BASE_INFO); typtype = typentry->typtype; arg->typbyval = typentry->typbyval; arg->typlen = typentry->typlen; arg->typalign = typentry->typalign; } else { typentry = NULL; typtype = TYPTYPE_COMPOSITE; /* hard-wired knowledge about type RECORD: */ arg->typbyval = false; arg->typlen = -1; arg->typalign = 'd'; } /* * Choose conversion method. Note that transform functions are checked * for composite and scalar types, but not for arrays or domains. This is * somewhat historical, but we'd have a problem allowing them on domains, * since we drill down through all levels of a domain nest without looking * at the intermediate levels at all. */ if (typtype == TYPTYPE_DOMAIN) { /* Domain */ arg->func = PLyObject_ToDomain; arg->u.domain.domain_info = NULL; /* Recursively set up conversion info for the element type */ arg->u.domain.base = (PLyObToDatum *) MemoryContextAllocZero(arg_mcxt, sizeof(PLyObToDatum)); PLy_output_setup_func(arg->u.domain.base, arg_mcxt, typentry->domainBaseType, typentry->domainBaseTypmod, proc); } else if (typentry && OidIsValid(typentry->typelem) && typentry->typlen == -1) { /* Standard varlena array (cf. get_element_type) */ arg->func = PLySequence_ToArray; /* Get base type OID to insert into constructed array */ /* (note this might not be the same as the immediate child type) */ arg->u.array.elmbasetype = getBaseType(typentry->typelem); /* Recursively set up conversion info for the element type */ arg->u.array.elm = (PLyObToDatum *) MemoryContextAllocZero(arg_mcxt, sizeof(PLyObToDatum)); PLy_output_setup_func(arg->u.array.elm, arg_mcxt, typentry->typelem, typmod, proc); } else if ((trfuncid = get_transform_tosql(typeOid, proc->langid, proc->trftypes))) { arg->func = PLyObject_ToTransform; fmgr_info_cxt(trfuncid, &arg->u.transform.typtransform, arg_mcxt); } else if (typtype == TYPTYPE_COMPOSITE) { /* Named composite type, or RECORD */ arg->func = PLyObject_ToComposite; /* We'll set up the per-field data later */ arg->u.tuple.recdesc = NULL; arg->u.tuple.typentry = typentry; arg->u.tuple.tupdescseq = typentry ? typentry->tupDescSeqNo - 1 : 0; arg->u.tuple.atts = NULL; arg->u.tuple.natts = 0; /* Mark this invalid till needed, too */ arg->u.tuple.recinfunc.fn_oid = InvalidOid; } else { /* Scalar type, but we have a couple of special cases */ switch (typeOid) { case BOOLOID: arg->func = PLyObject_ToBool; break; case BYTEAOID: arg->func = PLyObject_ToBytea; break; default: arg->func = PLyObject_ToScalar; getTypeInputInfo(typeOid, &typinput, &arg->u.scalar.typioparam); fmgr_info_cxt(typinput, &arg->u.scalar.typfunc, arg_mcxt); break; } } }
/** * @brief This function learns the topics of words in a document and is the * main step of a Gibbs sampling iteration. The word topic counts and * corpus topic counts are passed to this function in the first call and * then transfered to the rest calls through args.mSysInfo->user_fctx for * efficiency. * @param args[0] The unique words in the documents * @param args[1] The counts of each unique words * @param args[2] The topic counts and topic assignments in the document * @param args[3] The model (word topic counts and corpus topic * counts) * @param args[4] The Dirichlet parameter for per-document topic * multinomial, i.e. alpha * @param args[5] The Dirichlet parameter for per-topic word * multinomial, i.e. beta * @param args[6] The size of vocabulary * @param args[7] The number of topics * @param args[8] The number of iterations (=1:training, >1:prediction) * @return The updated topic counts and topic assignments for * the document **/ AnyType lda_gibbs_sample::run(AnyType & args) { ArrayHandle<int32_t> words = args[0].getAs<ArrayHandle<int32_t> >(); ArrayHandle<int32_t> counts = args[1].getAs<ArrayHandle<int32_t> >(); MutableArrayHandle<int32_t> doc_topic = args[2].getAs<MutableArrayHandle<int32_t> >(); double alpha = args[4].getAs<double>(); double beta = args[5].getAs<double>(); int32_t voc_size = args[6].getAs<int32_t>(); int32_t topic_num = args[7].getAs<int32_t>(); int32_t iter_num = args[8].getAs<int32_t>(); if(alpha <= 0) throw std::invalid_argument("invalid argument - alpha"); if(beta <= 0) throw std::invalid_argument("invalid argument - beta"); if(voc_size <= 0) throw std::invalid_argument( "invalid argument - voc_size"); if(topic_num <= 0) throw std::invalid_argument( "invalid argument - topic_num"); if(iter_num <= 0) throw std::invalid_argument( "invalid argument - iter_num"); if(words.size() != counts.size()) throw std::invalid_argument( "dimensions mismatch: words.size() != counts.size()"); if(__min(words) < 0 || __max(words) >= voc_size) throw std::invalid_argument( "invalid values in words"); if(__min(counts) <= 0) throw std::invalid_argument( "invalid values in counts"); int32_t word_count = __sum(counts); if(doc_topic.size() != (size_t)(word_count + topic_num)) throw std::invalid_argument( "invalid dimension - doc_topic.size() != word_count + topic_num"); if(__min(doc_topic, 0, topic_num) < 0) throw std::invalid_argument("invalid values in topic_count"); if( __min(doc_topic, topic_num, word_count) < 0 || __max(doc_topic, topic_num, word_count) >= topic_num) throw std::invalid_argument( "invalid values in topic_assignment"); if (!args.getUserFuncContext()) { if(args[3].isNull()) throw std::invalid_argument("invalid argument - the model \ parameter should not be null for the first call"); ArrayHandle<int64_t> model = args[3].getAs<ArrayHandle<int64_t> >(); if(model.size() != (size_t)((voc_size + 1) * topic_num)) throw std::invalid_argument( "invalid dimension - model.size() != (voc_size + 1) * topic_num"); if(__min(model) < 0) throw std::invalid_argument("invalid topic counts in model"); int64_t * state = static_cast<int64_t *>( MemoryContextAllocZero( args.getCacheMemoryContext(), model.size() * sizeof(int64_t))); memcpy(state, model.ptr(), model.size() * sizeof(int64_t)); args.setUserFuncContext(state); } int64_t * state = static_cast<int64_t *>(args.getUserFuncContext()); if(NULL == state){ throw std::runtime_error("args.mSysInfo->user_fctx is null"); } int32_t unique_word_count = static_cast<int32_t>(words.size()); for(int32_t it = 0; it < iter_num; it++){ int32_t word_index = topic_num; for(int32_t i = 0; i < unique_word_count; i++) { int32_t wordid = words[i]; for(int32_t j = 0; j < counts[i]; j++){ int32_t topic = doc_topic[word_index]; int32_t retopic = __lda_gibbs_sample( topic_num, topic, doc_topic.ptr(), state + wordid * topic_num, state + voc_size * topic_num, alpha, beta); doc_topic[word_index] = retopic; doc_topic[topic]--; doc_topic[retopic]++; if(iter_num == 1){ state[voc_size * topic_num + topic]--; state[voc_size * topic_num + retopic]++; state[wordid * topic_num + topic]--; state[wordid * topic_num + retopic]++; } word_index++; } } } return doc_topic; }
static TSVectorStat * ts_stat_sql(MemoryContext persistentContext, text *txt, text *ws) { char *query = text_to_cstring(txt); int i; TSVectorStat *stat; bool isnull; Portal portal; SPIPlanPtr plan; if ((plan = SPI_prepare(query, 0, NULL)) == NULL) /* internal error */ elog(ERROR, "SPI_prepare(\"%s\") failed", query); if ((portal = SPI_cursor_open(NULL, plan, NULL, NULL, true)) == NULL) /* internal error */ elog(ERROR, "SPI_cursor_open(\"%s\") failed", query); SPI_cursor_fetch(portal, true, 100); if (SPI_tuptable == NULL || SPI_tuptable->tupdesc->natts != 1 || !IsBinaryCoercible(SPI_gettypeid(SPI_tuptable->tupdesc, 1), TSVECTOROID)) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("ts_stat query must return one tsvector column"))); stat = MemoryContextAllocZero(persistentContext, sizeof(TSVectorStat)); stat->maxdepth = 1; if (ws) { char *buf; buf = VARDATA(ws); while (buf - VARDATA(ws) < VARSIZE(ws) - VARHDRSZ) { if (pg_mblen(buf) == 1) { switch (*buf) { case 'A': case 'a': stat->weight |= 1 << 3; break; case 'B': case 'b': stat->weight |= 1 << 2; break; case 'C': case 'c': stat->weight |= 1 << 1; break; case 'D': case 'd': stat->weight |= 1; break; default: stat->weight |= 0; } } buf += pg_mblen(buf); } } while (SPI_processed > 0) { for (i = 0; i < SPI_processed; i++) { Datum data = SPI_getbinval(SPI_tuptable->vals[i], SPI_tuptable->tupdesc, 1, &isnull); if (!isnull) stat = ts_accum(persistentContext, stat, data); } SPI_freetuptable(SPI_tuptable); SPI_cursor_fetch(portal, true, 100); } SPI_freetuptable(SPI_tuptable); SPI_cursor_close(portal); SPI_freeplan(plan); pfree(query); return stat; }
/* * Recursively initialize the PLyDatumToOb structure(s) needed to construct * a Python value from a SQL value of the specified typeOid/typmod. * (But note that at this point we may have RECORDOID/-1, ie, an indeterminate * record type.) * proc is used to look up transform functions. */ void PLy_input_setup_func(PLyDatumToOb *arg, MemoryContext arg_mcxt, Oid typeOid, int32 typmod, PLyProcedure *proc) { TypeCacheEntry *typentry; char typtype; Oid trfuncid; Oid typoutput; bool typisvarlena; /* Since this is recursive, it could theoretically be driven to overflow */ check_stack_depth(); arg->typoid = typeOid; arg->typmod = typmod; arg->mcxt = arg_mcxt; /* * Fetch typcache entry for the target type, asking for whatever info * we'll need later. RECORD is a special case: just treat it as composite * without bothering with the typcache entry. */ if (typeOid != RECORDOID) { typentry = lookup_type_cache(typeOid, TYPECACHE_DOMAIN_BASE_INFO); typtype = typentry->typtype; arg->typbyval = typentry->typbyval; arg->typlen = typentry->typlen; arg->typalign = typentry->typalign; } else { typentry = NULL; typtype = TYPTYPE_COMPOSITE; /* hard-wired knowledge about type RECORD: */ arg->typbyval = false; arg->typlen = -1; arg->typalign = 'd'; } /* * Choose conversion method. Note that transform functions are checked * for composite and scalar types, but not for arrays or domains. This is * somewhat historical, but we'd have a problem allowing them on domains, * since we drill down through all levels of a domain nest without looking * at the intermediate levels at all. */ if (typtype == TYPTYPE_DOMAIN) { /* Domain --- we don't care, just recurse down to the base type */ PLy_input_setup_func(arg, arg_mcxt, typentry->domainBaseType, typentry->domainBaseTypmod, proc); } else if (typentry && OidIsValid(typentry->typelem) && typentry->typlen == -1) { /* Standard varlena array (cf. get_element_type) */ arg->func = PLyList_FromArray; /* Recursively set up conversion info for the element type */ arg->u.array.elm = (PLyDatumToOb *) MemoryContextAllocZero(arg_mcxt, sizeof(PLyDatumToOb)); PLy_input_setup_func(arg->u.array.elm, arg_mcxt, typentry->typelem, typmod, proc); } else if ((trfuncid = get_transform_fromsql(typeOid, proc->langid, proc->trftypes))) { arg->func = PLyObject_FromTransform; fmgr_info_cxt(trfuncid, &arg->u.transform.typtransform, arg_mcxt); } else if (typtype == TYPTYPE_COMPOSITE) { /* Named composite type, or RECORD */ arg->func = PLyDict_FromComposite; /* We'll set up the per-field data later */ arg->u.tuple.recdesc = NULL; arg->u.tuple.typentry = typentry; arg->u.tuple.tupdescseq = typentry ? typentry->tupDescSeqNo - 1 : 0; arg->u.tuple.atts = NULL; arg->u.tuple.natts = 0; } else { /* Scalar type, but we have a couple of special cases */ switch (typeOid) { case BOOLOID: arg->func = PLyBool_FromBool; break; case FLOAT4OID: arg->func = PLyFloat_FromFloat4; break; case FLOAT8OID: arg->func = PLyFloat_FromFloat8; break; case NUMERICOID: arg->func = PLyDecimal_FromNumeric; break; case INT2OID: arg->func = PLyInt_FromInt16; break; case INT4OID: arg->func = PLyInt_FromInt32; break; case INT8OID: arg->func = PLyLong_FromInt64; break; case OIDOID: arg->func = PLyLong_FromOid; break; case BYTEAOID: arg->func = PLyBytes_FromBytea; break; default: arg->func = PLyString_FromScalar; getTypeOutputInfo(typeOid, &typoutput, &typisvarlena); fmgr_info_cxt(typoutput, &arg->u.scalar.typfunc, arg_mcxt); break; } } }
/* * Create a WaitEventSet with space for nevents different events to wait for. * * These events can then efficiently waited upon together, using * WaitEventSetWait(). */ WaitEventSet * CreateWaitEventSet(MemoryContext context, int nevents) { WaitEventSet *set; char *data; Size sz = 0; sz += sizeof(WaitEventSet); sz += sizeof(WaitEvent) * nevents; #if defined(WAIT_USE_EPOLL) sz += sizeof(struct epoll_event) * nevents; #elif defined(WAIT_USE_POLL) sz += sizeof(struct pollfd) * nevents; #elif defined(WAIT_USE_WIN32) /* need space for the pgwin32_signal_event */ sz += sizeof(HANDLE) * (nevents + 1); #endif data = (char *) MemoryContextAllocZero(context, sz); set = (WaitEventSet *) data; data += sizeof(WaitEventSet); set->events = (WaitEvent *) data; data += sizeof(WaitEvent) * nevents; #if defined(WAIT_USE_EPOLL) set->epoll_ret_events = (struct epoll_event *) data; data += sizeof(struct epoll_event) * nevents; #elif defined(WAIT_USE_POLL) set->pollfds = (struct pollfd *) data; data += sizeof(struct pollfd) * nevents; #elif defined(WAIT_USE_WIN32) set->handles = (HANDLE) data; data += sizeof(HANDLE) * nevents; #endif set->latch = NULL; set->nevents_space = nevents; #if defined(WAIT_USE_EPOLL) set->epoll_fd = epoll_create(nevents); if (set->epoll_fd < 0) elog(ERROR, "epoll_create failed: %m"); #elif defined(WAIT_USE_WIN32) /* * To handle signals while waiting, we need to add a win32 specific event. * We accounted for the additional event at the top of this routine. See * port/win32/signal.c for more details. * * Note: pgwin32_signal_event should be first to ensure that it will be * reported when multiple events are set. We want to guarantee that * pending signals are serviced. */ set->handles[0] = pgwin32_signal_event; StaticAssertStmt(WSA_INVALID_EVENT == NULL, ""); #endif return set; }
/* function subhandler */ Datum PLy_exec_function(FunctionCallInfo fcinfo, PLyProcedure *proc) { Datum rv; PyObject *volatile plargs = NULL; PyObject *volatile plrv = NULL; FuncCallContext *volatile funcctx = NULL; PLySRFState *volatile srfstate = NULL; ErrorContextCallback plerrcontext; /* * If the function is called recursively, we must push outer-level * arguments into the stack. This must be immediately before the PG_TRY * to ensure that the corresponding pop happens. */ PLy_global_args_push(proc); PG_TRY(); { if (proc->is_setof) { /* First Call setup */ if (SRF_IS_FIRSTCALL()) { funcctx = SRF_FIRSTCALL_INIT(); srfstate = (PLySRFState *) MemoryContextAllocZero(funcctx->multi_call_memory_ctx, sizeof(PLySRFState)); /* Immediately register cleanup callback */ srfstate->callback.func = plpython_srf_cleanup_callback; srfstate->callback.arg = (void *) srfstate; MemoryContextRegisterResetCallback(funcctx->multi_call_memory_ctx, &srfstate->callback); funcctx->user_fctx = (void *) srfstate; } /* Every call setup */ funcctx = SRF_PERCALL_SETUP(); Assert(funcctx != NULL); srfstate = (PLySRFState *) funcctx->user_fctx; } if (srfstate == NULL || srfstate->iter == NULL) { /* * Non-SETOF function or first time for SETOF function: build * args, then actually execute the function. */ plargs = PLy_function_build_args(fcinfo, proc); plrv = PLy_procedure_call(proc, "args", plargs); Assert(plrv != NULL); } else { /* * Second or later call for a SETOF function: restore arguments in * globals dict to what they were when we left off. We must do * this in case multiple evaluations of the same SETOF function * are interleaved. It's a bit annoying, since the iterator may * not look at the arguments at all, but we have no way to know * that. Fortunately this isn't terribly expensive. */ if (srfstate->savedargs) PLy_function_restore_args(proc, srfstate->savedargs); srfstate->savedargs = NULL; /* deleted by restore_args */ } /* * If it returns a set, call the iterator to get the next return item. * We stay in the SPI context while doing this, because PyIter_Next() * calls back into Python code which might contain SPI calls. */ if (proc->is_setof) { if (srfstate->iter == NULL) { /* first time -- do checks and setup */ ReturnSetInfo *rsi = (ReturnSetInfo *) fcinfo->resultinfo; if (!rsi || !IsA(rsi, ReturnSetInfo) || (rsi->allowedModes & SFRM_ValuePerCall) == 0) { ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("unsupported set function return mode"), errdetail("PL/Python set-returning functions only support returning one value per call."))); } rsi->returnMode = SFRM_ValuePerCall; /* Make iterator out of returned object */ srfstate->iter = PyObject_GetIter(plrv); Py_DECREF(plrv); plrv = NULL; if (srfstate->iter == NULL) ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("returned object cannot be iterated"), errdetail("PL/Python set-returning functions must return an iterable object."))); } /* Fetch next from iterator */ plrv = PyIter_Next(srfstate->iter); if (plrv == NULL) { /* Iterator is exhausted or error happened */ bool has_error = (PyErr_Occurred() != NULL); Py_DECREF(srfstate->iter); srfstate->iter = NULL; if (has_error) PLy_elog(ERROR, "error fetching next item from iterator"); /* Pass a null through the data-returning steps below */ Py_INCREF(Py_None); plrv = Py_None; } else { /* * This won't be last call, so save argument values. We do * this again each time in case the iterator is changing those * values. */ srfstate->savedargs = PLy_function_save_args(proc); } } /* * Disconnect from SPI manager and then create the return values datum * (if the input function does a palloc for it this must not be * allocated in the SPI memory context because SPI_finish would free * it). */ if (SPI_finish() != SPI_OK_FINISH) elog(ERROR, "SPI_finish failed"); plerrcontext.callback = plpython_return_error_callback; plerrcontext.previous = error_context_stack; error_context_stack = &plerrcontext; /* * If the function is declared to return void, the Python return value * must be None. For void-returning functions, we also treat a None * return value as a special "void datum" rather than NULL (as is the * case for non-void-returning functions). */ if (proc->result.out.d.typoid == VOIDOID) { if (plrv != Py_None) ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("PL/Python function with return type \"void\" did not return None"))); fcinfo->isnull = false; rv = (Datum) 0; } else if (plrv == Py_None) { fcinfo->isnull = true; /* * In a SETOF function, the iteration-ending null isn't a real * value; don't pass it through the input function, which might * complain. */ if (srfstate && srfstate->iter == NULL) rv = (Datum) 0; else if (proc->result.is_rowtype < 1) rv = InputFunctionCall(&proc->result.out.d.typfunc, NULL, proc->result.out.d.typioparam, -1); else /* Tuple as None */ rv = (Datum) NULL; } else if (proc->result.is_rowtype >= 1) { TupleDesc desc; /* make sure it's not an unnamed record */ Assert((proc->result.out.d.typoid == RECORDOID && proc->result.out.d.typmod != -1) || (proc->result.out.d.typoid != RECORDOID && proc->result.out.d.typmod == -1)); desc = lookup_rowtype_tupdesc(proc->result.out.d.typoid, proc->result.out.d.typmod); rv = PLyObject_ToCompositeDatum(&proc->result, desc, plrv); fcinfo->isnull = (rv == (Datum) NULL); ReleaseTupleDesc(desc); } else { fcinfo->isnull = false; rv = (proc->result.out.d.func) (&proc->result.out.d, -1, plrv); } } PG_CATCH(); { /* Pop old arguments from the stack if they were pushed above */ PLy_global_args_pop(proc); Py_XDECREF(plargs); Py_XDECREF(plrv); /* * If there was an error within a SRF, the iterator might not have * been exhausted yet. Clear it so the next invocation of the * function will start the iteration again. (This code is probably * unnecessary now; plpython_srf_cleanup_callback should take care of * cleanup. But it doesn't hurt anything to do it here.) */ if (srfstate) { Py_XDECREF(srfstate->iter); srfstate->iter = NULL; /* And drop any saved args; we won't need them */ if (srfstate->savedargs) PLy_function_drop_args(srfstate->savedargs); srfstate->savedargs = NULL; } PG_RE_THROW(); } PG_END_TRY(); error_context_stack = plerrcontext.previous; /* Pop old arguments from the stack if they were pushed above */ PLy_global_args_pop(proc); Py_XDECREF(plargs); Py_DECREF(plrv); if (srfstate) { /* We're in a SRF, exit appropriately */ if (srfstate->iter == NULL) { /* Iterator exhausted, so we're done */ SRF_RETURN_DONE(funcctx); } else if (fcinfo->isnull) SRF_RETURN_NEXT_NULL(funcctx); else SRF_RETURN_NEXT(funcctx, rv); } /* Plain function, just return the Datum value (possibly null) */ return rv; }
/** * @brief This function learns the topics of words in a document and is the * main step of a Gibbs sampling iteration. The word topic counts and * corpus topic counts are passed to this function in the first call and * then transfered to the rest calls through args.mSysInfo->user_fctx for * efficiency. * @param args[0] The unique words in the documents * @param args[1] The counts of each unique words * @param args[2] The topic counts and topic assignments in the document * @param args[3] The model (word topic counts and corpus topic * counts) * @param args[4] The Dirichlet parameter for per-document topic * multinomial, i.e. alpha * @param args[5] The Dirichlet parameter for per-topic word * multinomial, i.e. beta * @param args[6] The size of vocabulary * @param args[7] The number of topics * @param args[8] The number of iterations (=1:training, >1:prediction) * @return The updated topic counts and topic assignments for * the document **/ AnyType lda_gibbs_sample::run(AnyType & args) { ArrayHandle<int32_t> words = args[0].getAs<ArrayHandle<int32_t> >(); ArrayHandle<int32_t> counts = args[1].getAs<ArrayHandle<int32_t> >(); MutableArrayHandle<int32_t> doc_topic = args[2].getAs<MutableArrayHandle<int32_t> >(); double alpha = args[4].getAs<double>(); double beta = args[5].getAs<double>(); int32_t voc_size = args[6].getAs<int32_t>(); int32_t topic_num = args[7].getAs<int32_t>(); int32_t iter_num = args[8].getAs<int32_t>(); size_t model64_size = static_cast<size_t>(voc_size * (topic_num + 1) + 1) * sizeof(int32_t) / sizeof(int64_t); if(alpha <= 0) throw std::invalid_argument("invalid argument - alpha"); if(beta <= 0) throw std::invalid_argument("invalid argument - beta"); if(voc_size <= 0) throw std::invalid_argument( "invalid argument - voc_size"); if(topic_num <= 0) throw std::invalid_argument( "invalid argument - topic_num"); if(iter_num <= 0) throw std::invalid_argument( "invalid argument - iter_num"); if(words.size() != counts.size()) throw std::invalid_argument( "dimensions mismatch: words.size() != counts.size()"); if(__min(words) < 0 || __max(words) >= voc_size) throw std::invalid_argument( "invalid values in words"); if(__min(counts) <= 0) throw std::invalid_argument( "invalid values in counts"); int32_t word_count = __sum(counts); if(doc_topic.size() != (size_t)(word_count + topic_num)) throw std::invalid_argument( "invalid dimension - doc_topic.size() != word_count + topic_num"); if(__min(doc_topic, 0, topic_num) < 0) throw std::invalid_argument("invalid values in topic_count"); if( __min(doc_topic, topic_num, word_count) < 0 || __max(doc_topic, topic_num, word_count) >= topic_num) throw std::invalid_argument( "invalid values in topic_assignment"); if (!args.getUserFuncContext()) { ArrayHandle<int64_t> model64 = args[3].getAs<ArrayHandle<int64_t> >(); if (model64.size() != model64_size) { std::stringstream ss; ss << "invalid dimension: model64.size() = " << model64.size(); throw std::invalid_argument(ss.str()); } if (__min(model64) < 0) { throw std::invalid_argument("invalid topic counts in model"); } int32_t *context = static_cast<int32_t *>( MemoryContextAllocZero( args.getCacheMemoryContext(), model64.size() * sizeof(int64_t) + topic_num * sizeof(int64_t))); memcpy(context, model64.ptr(), model64.size() * sizeof(int64_t)); int32_t *model = context; int64_t *running_topic_counts = reinterpret_cast<int64_t *>( context + model64_size * sizeof(int64_t) / sizeof(int32_t)); for (int i = 0; i < voc_size; i ++) { for (int j = 0; j < topic_num; j ++) { running_topic_counts[j] += model[i * (topic_num + 1) + j]; } } args.setUserFuncContext(context); } int32_t *context = static_cast<int32_t *>(args.getUserFuncContext()); if (context == NULL) { throw std::runtime_error("args.mSysInfo->user_fctx is null"); } int32_t *model = context; int64_t *running_topic_counts = reinterpret_cast<int64_t *>( context + model64_size * sizeof(int64_t) / sizeof(int32_t)); int32_t unique_word_count = static_cast<int32_t>(words.size()); for(int32_t it = 0; it < iter_num; it++){ int32_t word_index = topic_num; for(int32_t i = 0; i < unique_word_count; i++) { int32_t wordid = words[i]; for(int32_t j = 0; j < counts[i]; j++){ int32_t topic = doc_topic[word_index]; int32_t retopic = __lda_gibbs_sample( topic_num, topic, doc_topic.ptr(), model + wordid * (topic_num + 1), running_topic_counts, alpha, beta); doc_topic[word_index] = retopic; doc_topic[topic]--; doc_topic[retopic]++; if(iter_num == 1) { if (model[wordid * (topic_num + 1) + retopic] <= 2e9) { running_topic_counts[topic] --; running_topic_counts[retopic] ++; model[wordid * (topic_num + 1) + topic]--; model[wordid * (topic_num + 1) + retopic]++; } else { model[wordid * (topic_num + 1) + topic_num] = 1; } } word_index++; } } } return doc_topic; }
/* * Fetch local cache of AM-specific info about the index, initializing it * if necessary */ SpGistCache * spgGetCache(Relation index) { SpGistCache *cache; if (index->rd_amcache == NULL) { Oid atttype; spgConfigIn in; FmgrInfo *procinfo; Buffer metabuffer; SpGistMetaPageData *metadata; cache = MemoryContextAllocZero(index->rd_indexcxt, sizeof(SpGistCache)); /* SPGiST doesn't support multi-column indexes */ Assert(index->rd_att->natts == 1); /* * Get the actual data type of the indexed column from the index * tupdesc. We pass this to the opclass config function so that * polymorphic opclasses are possible. */ atttype = index->rd_att->attrs[0]->atttypid; /* Call the config function to get config info for the opclass */ in.attType = atttype; procinfo = index_getprocinfo(index, 1, SPGIST_CONFIG_PROC); FunctionCall2Coll(procinfo, index->rd_indcollation[0], PointerGetDatum(&in), PointerGetDatum(&cache->config)); /* Get the information we need about each relevant datatype */ fillTypeDesc(&cache->attType, atttype); fillTypeDesc(&cache->attPrefixType, cache->config.prefixType); fillTypeDesc(&cache->attLabelType, cache->config.labelType); /* Last, get the lastUsedPages data from the metapage */ metabuffer = ReadBuffer(index, SPGIST_METAPAGE_BLKNO); LockBuffer(metabuffer, BUFFER_LOCK_SHARE); metadata = SpGistPageGetMeta(BufferGetPage(metabuffer)); if (metadata->magicNumber != SPGIST_MAGIC_NUMBER) elog(ERROR, "index \"%s\" is not an SP-GiST index", RelationGetRelationName(index)); cache->lastUsedPages = metadata->lastUsedPages; UnlockReleaseBuffer(metabuffer); index->rd_amcache = (void *) cache; } else { /* assume it's up to date */ cache = (SpGistCache *) index->rd_amcache; } return cache; }
/* * This is a mocked version of palloc0 to be used in ExecWorkFile_Create. * It asserts that it is executed in the TopMemoryContext. */ void * execWorkfile_palloc0_mock(Size size) { assert_int_equal(CurrentMemoryContext, TopMemoryContext); return MemoryContextAllocZero(CurrentMemoryContext, size); }
Relation DirectOpen_Open( DirectOpen *direct, Oid relationId, Oid tablespace, Oid database, Oid relfilenode, FormData_pg_class *pgClass, FormData_pg_attribute *attrArray, FormData_pg_am *pgAm, FormData_pg_index *pgIndex, int2 *indKeyArray, Oid *indClassArray, bool relHasOid) { int natts; int i; Assert(pgClass != NULL); natts = pgClass->relnatts; if (relationId == -1) relationId = pgClass->relfilenode; // Assume it is ok to use the relfilenode as the relationId in our limited usage. if (relfilenode == -1) relfilenode = pgClass->relfilenode; if (!direct->isInit) { /* * Lots of Hard-coded construction of the gp_persistent* RelationS and * dependent objects like tuple descriptors, etc. */ direct->relationData.rd_refcnt = 0; direct->relationData.rd_isvalid = true; direct->relationData.rd_id = relationId; direct->relationData.rd_rel = pgClass; if (pgIndex != NULL) { int pgIndexFixedLen = offsetof(FormData_pg_index, indkey); int indKeyVectorLen = Int2VectorSize(natts); int2vector *indKeyVector; oidvector *indClassVector; uint16 amstrategies; uint16 amsupport; Oid *operator; RegProcedure *support; FmgrInfo *supportinfo; Assert(pgAm != NULL); Assert(indKeyArray != NULL); Assert(indClassArray != NULL); /* * Allocate Formdata_pg_index with fields through indkey * where indkey is a variable length int2vector with indKeyArray values. */ direct->relationData.rd_index = (FormData_pg_index*)palloc( pgIndexFixedLen + indKeyVectorLen); memcpy(direct->relationData.rd_index, pgIndex, pgIndexFixedLen); indKeyVector = buildint2vector( indKeyArray, natts); memcpy( &direct->relationData.rd_index->indkey, indKeyVector, indKeyVectorLen); pfree(indKeyVector); direct->relationData.rd_am = pgAm; amstrategies = pgAm->amstrategies; amsupport = pgAm->amsupport; direct->relationData.rd_indexcxt = TopMemoryContext; /* * Allocate arrays to hold data */ direct->relationData.rd_aminfo = (RelationAmInfo *) MemoryContextAllocZero(TopMemoryContext, sizeof(RelationAmInfo)); direct->relationData.rd_opfamily = (Oid *) MemoryContextAllocZero(TopMemoryContext, natts * sizeof(Oid)); direct->relationData.rd_opcintype = (Oid *) MemoryContextAllocZero(TopMemoryContext, natts * sizeof(Oid)); if (amstrategies > 0) operator = (Oid *) MemoryContextAllocZero(TopMemoryContext, natts * amstrategies * sizeof(Oid)); else operator = NULL; if (amsupport > 0) { int nsupport = natts * amsupport; support = (RegProcedure *) MemoryContextAllocZero(TopMemoryContext, nsupport * sizeof(RegProcedure)); supportinfo = (FmgrInfo *) MemoryContextAllocZero(TopMemoryContext, nsupport * sizeof(FmgrInfo)); } else { support = NULL; supportinfo = NULL; } direct->relationData.rd_operator = operator; direct->relationData.rd_support = support; direct->relationData.rd_supportinfo = supportinfo; direct->relationData.rd_indoption = (int16 *) MemoryContextAllocZero(TopMemoryContext, natts * sizeof(int16)); /* * Create oidvector in rd_indclass with values from indClassArray. */ indClassVector = buildoidvector(indClassArray, natts); /* * Fill the operator and support procedure OID arrays. (aminfo and * supportinfo are left as zeroes, and are filled on-the-fly when used) */ IndexSupportInitialize(indClassVector, operator, support, direct->relationData.rd_opfamily, direct->relationData.rd_opcintype, amstrategies, amsupport, natts); /* * expressions and predicate cache will be filled later. */ direct->relationData.rd_indexprs = NIL; direct->relationData.rd_indpred = NIL; direct->relationData.rd_amcache = NULL; } // Not much in terms of contraints. direct->constrData.has_not_null = true; /* * Setup tuple descriptor for columns. */ direct->descData.natts = pgClass->relnatts; // Make the array of pointers. direct->descData.attrs = (Form_pg_attribute*) MemoryContextAllocZero( TopMemoryContext, sizeof(Form_pg_attribute*) * pgClass->relnatts); for (i = 0; i < pgClass->relnatts; i++) { direct->descData.attrs[i] = (Form_pg_attribute) MemoryContextAllocZero( TopMemoryContext, sizeof(FormData_pg_attribute)); memcpy(direct->descData.attrs[i], &(attrArray[i]), sizeof(FormData_pg_attribute)); // Patch up relation id. direct->descData.attrs[i]->attrelid = relationId; } direct->descData.constr = &direct->constrData; direct->descData.tdtypeid = pgClass->reltype; direct->descData.tdtypmod = -1; direct->descData.tdqdtypmod = -1; direct->descData.tdhasoid = relHasOid; direct->descData.tdrefcount = 1; direct->relationData.rd_att = &direct->descData; direct->pgStat.t_id = relationId; direct->pgStat.t_shared = 1; direct->relationData.pgstat_info = &direct->pgStat; direct->isInit = true; } // UNDONE: Should verify for NON-SHARED relations we don't open relations in different databases / or // UNDONE: open different relations in same database at same time !!! direct->relationData.rd_node.spcNode = tablespace; direct->relationData.rd_node.dbNode = database; direct->relationData.rd_node.relNode = relfilenode; direct->relationData.rd_targblock = InvalidBlockNumber; for (i = 0; i < direct->relationData.rd_rel->relnatts; i++) { Assert(direct->descData.attrs[i] != NULL); // Patch up relation id. direct->descData.attrs[i]->attrelid = direct->relationData.rd_id; } direct->relationData.rd_refcnt++; RelationOpenSmgr(&direct->relationData); return &direct->relationData; }
/* * init_MultiFuncCall * Create an empty FuncCallContext data structure * and do some other basic Multi-function call setup * and error checking */ FuncCallContext * init_MultiFuncCall(PG_FUNCTION_ARGS) { FuncCallContext *retval; /* * Bail if we're called in the wrong context */ if (fcinfo->resultinfo == NULL || !IsA(fcinfo->resultinfo, ReturnSetInfo)) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("set-valued function called in context that cannot accept a set"))); if (fcinfo->flinfo->fn_extra == NULL) { /* * First call */ ReturnSetInfo *rsi = (ReturnSetInfo *) fcinfo->resultinfo; MemoryContext multi_call_ctx; /* * Create a suitably long-lived context to hold cross-call data */ multi_call_ctx = AllocSetContextCreate(fcinfo->flinfo->fn_mcxt, "SRF multi-call context", ALLOCSET_SMALL_MINSIZE, ALLOCSET_SMALL_INITSIZE, ALLOCSET_SMALL_MAXSIZE); /* * Allocate suitably long-lived space and zero it */ retval = (FuncCallContext *) MemoryContextAllocZero(multi_call_ctx, sizeof(FuncCallContext)); /* * initialize the elements */ retval->call_cntr = 0; retval->max_calls = 0; retval->slot = NULL; retval->user_fctx = NULL; retval->attinmeta = NULL; retval->tuple_desc = NULL; retval->multi_call_memory_ctx = multi_call_ctx; /* * save the pointer for cross-call use */ fcinfo->flinfo->fn_extra = retval; /* * Ensure we will get shut down cleanly if the exprcontext is not run * to completion. */ RegisterExprContextCallback(rsi->econtext, shutdown_MultiFuncCall, PointerGetDatum(fcinfo->flinfo)); } else { /* second and subsequent calls */ elog(ERROR, "init_MultiFuncCall cannot be called more than once"); /* never reached, but keep compiler happy */ retval = NULL; } return retval; }