static void fmtLogMsg(StringInfo dst, ErrorData *edata) { { char formattedLogTime[FORMATTED_TS_LEN]; /* timestamp with milliseconds */ formatNow(formattedLogTime, sizeof formattedLogTime); /* * Always present, non-nullable; don't need to write the N/P * header. */ appendStringInfoString(dst, formattedLogTime); appendStringInfoChar(dst, '\0'); } /* username */ if (MyProcPort) appendStringInfoPtr(dst, MyProcPort->user_name); else appendStringInfoPtr(dst, NULL); /* database name */ if (MyProcPort) appendStringInfoPtr(dst, MyProcPort->database_name); else appendStringInfoPtr(dst, NULL); /* Process id */ { uint32_t nPid = htobe32(savedPid); appendBinaryStringInfo(dst, (void *) &nPid, sizeof nPid); } /* Remote host and port */ if (MyProcPort && MyProcPort->remote_host) { /* 'present' string header, since this string is nullable */ appendStringInfoChar(dst, 'P'); appendStringInfoString(dst, MyProcPort->remote_host); if (MyProcPort->remote_port && MyProcPort->remote_port[0] != '\0') { appendStringInfoChar(dst, ':'); appendStringInfoString(dst, MyProcPort->remote_port); } appendStringInfoChar(dst, '\0'); } else appendStringInfoPtr(dst, NULL); /* session id; non-nullable */ appendStringInfo(dst, "%lx.%x", (long) MyStartTime, MyProcPid); appendStringInfoChar(dst, '\0'); /* Line number */ { uint64_t nSeqNum = htobe64(seqNum); appendBinaryStringInfo(dst, (void *) &nSeqNum, sizeof nSeqNum); } /* PS display */ if (MyProcPort) { StringInfoData msgbuf; const char *psdisp; int displen; initStringInfo(&msgbuf); psdisp = get_ps_display(&displen); appendBinaryStringInfo(&msgbuf, psdisp, displen); appendStringInfoChar(dst, 'P'); appendStringInfoString(dst, msgbuf.data); appendStringInfoChar(dst, '\0'); pfree(msgbuf.data); } else appendStringInfoPtr(dst, NULL); /* session start timestamp */ if (cachedBackendStartTime[0] == '\0') { /* Rebuild the cache if it was blown */ reCacheBackendStartTime(); } /* backend start time; non-nullable string */ appendStringInfoString(dst, cachedBackendStartTime); appendStringInfoChar(dst, '\0'); /* * Virtual transaction id * * keep VXID format in sync with lockfuncs.c */ if (MyProc != NULL && MyProc->backendId != InvalidBackendId) { appendStringInfoChar(dst, 'P'); appendStringInfo(dst, "%d/%u", MyProc->backendId, MyProc->lxid); appendStringInfoChar(dst, '\0'); } else appendStringInfoPtr(dst, NULL); /* * Transaction id * * This seems to be a mistake both here and in elog.c; in particular, it's * not clear how the epoch would get added here. However, leave room in * the protocol to fix this later by upcasting. */ { uint64_t nTxid = htobe64((uint64) GetTopTransactionIdIfAny()); appendBinaryStringInfo(dst, (void *) &nTxid, sizeof nTxid); } /* Error severity */ { uint32_t nelevel = htobe32(edata->elevel); appendBinaryStringInfo(dst, (void *) &nelevel, sizeof nelevel); } /* SQL state code */ appendStringInfoPtr(dst, unpack_sql_state(edata->sqlerrcode)); /* errmessage */ appendStringInfoPtr(dst, edata->message); /* errdetail or errdetail_log */ if (edata->detail_log) appendStringInfoPtr(dst, edata->detail_log); else appendStringInfoPtr(dst, edata->detail); /* errhint */ appendStringInfoPtr(dst, edata->hint); /* internal query */ appendStringInfoPtr(dst, edata->internalquery); /* if printed internal query, print internal pos too */ if (edata->internalpos > 0 && edata->internalquery != NULL) { uint32_t ninternalpos = htobe32(edata->internalpos); appendBinaryStringInfo(dst, (void *) &ninternalpos, sizeof ninternalpos); } else { uint32_t ninternalpos = htobe32(-1); appendBinaryStringInfo(dst, (void *) &ninternalpos, sizeof ninternalpos); } /* errcontext */ appendStringInfoPtr(dst, edata->context); /* * user query --- only reported if not disabled by the caller. * * Also include query position. */ if (isLogLevelOutput(edata->elevel, log_min_error_statement) && debug_query_string != NULL && !edata->hide_stmt) { uint32_t nCursorPos = htobe32(edata->cursorpos); appendStringInfoPtr(dst, debug_query_string); appendBinaryStringInfo(dst, (void *) &nCursorPos, sizeof nCursorPos); } else { uint32_t nCursorPos = htobe32(-1); appendStringInfoPtr(dst, NULL); appendBinaryStringInfo(dst, (void *) &nCursorPos, sizeof nCursorPos); } /* file error location */ if (Log_error_verbosity >= PGERROR_VERBOSE) { StringInfoData msgbuf; initStringInfo(&msgbuf); if (edata->funcname && edata->filename) appendStringInfo(&msgbuf, "%s, %s:%d", edata->funcname, edata->filename, edata->lineno); else if (edata->filename) appendStringInfo(&msgbuf, "%s:%d", edata->filename, edata->lineno); appendStringInfoChar(dst, 'P'); appendStringInfoString(dst, msgbuf.data); appendStringInfoChar(dst, '\0'); pfree(msgbuf.data); } else appendStringInfoPtr(dst, NULL); /* application name */ appendStringInfoPtr(dst, application_name); }
static Datum gp_aovisimap_hidden_info_internal(PG_FUNCTION_ARGS, Oid aoRelOid) { Datum values[3]; bool nulls[3]; HeapTuple tuple; Datum result; typedef struct Context { AppendOnlyVisimap visiMap; Relation parentRelation; FileSegInfo **appendonlySegfileInfo; AOCSFileSegInfo **aocsSegfileInfo; int segfile_info_total; int i; } Context; FuncCallContext *funcctx; Context *context; if (SRF_IS_FIRSTCALL()) { TupleDesc tupdesc; MemoryContext oldcontext; /* create a function context for cross-call persistence */ funcctx = SRF_FIRSTCALL_INIT(); /* * switch to memory context appropriate for multiple function * calls */ oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); /* build tupdesc for result tuples */ tupdesc = CreateTemplateTupleDesc(3, false); TupleDescInitEntry(tupdesc, (AttrNumber) 1, "segno", INT4OID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 2, "hidden_tupcount", INT8OID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 3, "total_tupcount", INT8OID, -1, 0); funcctx->tuple_desc = BlessTupleDesc(tupdesc); /* * Collect all the locking information that we will format and send * out as a result set. */ context = (Context *) palloc0(sizeof(Context)); context->parentRelation = heap_open(aoRelOid, AccessShareLock); if (!(RelationIsAoRows(context->parentRelation) || RelationIsAoCols(context->parentRelation))) { ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("Function not supported on relation"))); } if (RelationIsAoRows(context->parentRelation)) { context->appendonlySegfileInfo = GetAllFileSegInfo( context->parentRelation, SnapshotNow, &context->segfile_info_total); } else { Assert(RelationIsAoCols(context->parentRelation)); context->aocsSegfileInfo = GetAllAOCSFileSegInfo(context->parentRelation, SnapshotNow, &context->segfile_info_total); } context->i = 0; AppendOnlyVisimap_Init(&context->visiMap, context->parentRelation->rd_appendonly->visimaprelid, context->parentRelation->rd_appendonly->visimapidxid, AccessShareLock, SnapshotNow); funcctx->user_fctx = (void *) context; MemoryContextSwitchTo(oldcontext); } funcctx = SRF_PERCALL_SETUP(); context = (Context *) funcctx->user_fctx; while (context->i < context->segfile_info_total) { int64 tupcount; int segno; if (context->appendonlySegfileInfo) { FileSegInfo *fsinfo = context->appendonlySegfileInfo[context->i]; tupcount = fsinfo->total_tupcount; segno = fsinfo->segno; } else if (context->aocsSegfileInfo) { AOCSFileSegInfo *fsinfo = context->aocsSegfileInfo[context->i]; tupcount = fsinfo->total_tupcount; segno = fsinfo->segno; } else { Insist(false); } MemSet(values, 0, sizeof(values)); MemSet(nulls, false, sizeof(nulls)); values[0] = Int32GetDatum(segno); values[1] = Int64GetDatum(AppendOnlyVisimap_GetSegmentFileHiddenTupleCount( &context->visiMap, segno)); values[2] = Int64GetDatum(tupcount); tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls); result = HeapTupleGetDatum(tuple); context->i++; SRF_RETURN_NEXT(funcctx, result); } AppendOnlyVisimap_Finish(&context->visiMap, AccessShareLock); if (context->appendonlySegfileInfo) { FreeAllSegFileInfo(context->appendonlySegfileInfo, context->segfile_info_total); pfree(context->appendonlySegfileInfo); context->appendonlySegfileInfo = NULL; } if (context->aocsSegfileInfo) { FreeAllAOCSSegFileInfo(context->aocsSegfileInfo, context->segfile_info_total); pfree(context->aocsSegfileInfo); context->aocsSegfileInfo = NULL; } heap_close(context->parentRelation, AccessShareLock); pfree(context); funcctx->user_fctx = NULL; SRF_RETURN_DONE(funcctx); }
static Datum gp_aovisimap_entry_internal(PG_FUNCTION_ARGS, Oid aoRelOid) { Datum values[4]; bool nulls[4]; HeapTuple tuple; Datum result; typedef struct Context { AppendOnlyVisimap visiMap; Relation parentRelation; IndexScanDesc indexScan; text *bitmapBuffer; } Context; FuncCallContext *funcctx; Context *context; if (SRF_IS_FIRSTCALL()) { TupleDesc tupdesc; MemoryContext oldcontext; /* create a function context for cross-call persistence */ funcctx = SRF_FIRSTCALL_INIT(); /* * switch to memory context appropriate for multiple function * calls */ oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); /* build tupdesc for result tuples */ tupdesc = CreateTemplateTupleDesc(4, false); TupleDescInitEntry(tupdesc, (AttrNumber) 1, "segno", INT4OID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 2, "first_row_num", INT8OID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 3, "hidden_tupcount", INT4OID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 4, "bitmap", TEXTOID, -1, 0); funcctx->tuple_desc = BlessTupleDesc(tupdesc); /* * Collect all the locking information that we will format and send * out as a result set. */ context = (Context *) palloc0(sizeof(Context)); context->parentRelation = heap_open(aoRelOid, AccessShareLock); if (!(RelationIsAoRows(context->parentRelation) || RelationIsAoCols(context->parentRelation))) { ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("Function not supported on relation"))); } AppendOnlyVisimap_Init(&context->visiMap, context->parentRelation->rd_appendonly->visimaprelid, context->parentRelation->rd_appendonly->visimapidxid, AccessShareLock, SnapshotNow); context->indexScan = AppendOnlyVisimapStore_BeginScan(& context->visiMap.visimapStore, 0, NULL); context->bitmapBuffer = palloc0(VARHDRSZ + APPENDONLY_VISIMAP_MAX_RANGE + 1); funcctx->user_fctx = (void *) context; MemoryContextSwitchTo(oldcontext); } funcctx = SRF_PERCALL_SETUP(); context = (Context *) funcctx->user_fctx; if (AppendOnlyVisimapStore_GetNext(&context->visiMap.visimapStore, context->indexScan, ForwardScanDirection, &context->visiMap.visimapEntry, NULL)) { AppendOnlyVisimapEntry *visimapEntry = &context->visiMap.visimapEntry; MemSet(values, 0, sizeof(values)); MemSet(nulls, false, sizeof(nulls)); values[0] = Int32GetDatum(visimapEntry->segmentFileNum); values[1] = Int64GetDatum(visimapEntry->firstRowNum); values[2] = Int32GetDatum( (int32)AppendOnlyVisimapEntry_GetHiddenTupleCount(visimapEntry)); gp_aovisimap_encode_bitmap(VARDATA(context->bitmapBuffer), visimapEntry->bitmap); SET_VARSIZE(context->bitmapBuffer, APPENDONLY_VISIMAP_MAX_RANGE); values[3] = PointerGetDatum(context->bitmapBuffer); tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls); result = HeapTupleGetDatum(tuple); SRF_RETURN_NEXT(funcctx, result); } AppendOnlyVisimapStore_EndScan(&context->visiMap.visimapStore, context->indexScan); AppendOnlyVisimap_Finish(&context->visiMap, AccessShareLock); heap_close(context->parentRelation, AccessShareLock); pfree(context->bitmapBuffer); pfree(context); funcctx->user_fctx = NULL; SRF_RETURN_DONE(funcctx); }
/* * _bt_getroot() -- Get the root page of the btree. * * Since the root page can move around the btree file, we have to read * its location from the metadata page, and then read the root page * itself. If no root page exists yet, we have to create one. The * standard class of race conditions exists here; I think I covered * them all in the Hopi Indian rain dance of lock requests below. * * The access type parameter (BT_READ or BT_WRITE) controls whether * a new root page will be created or not. If access = BT_READ, * and no root page exists, we just return InvalidBuffer. For * BT_WRITE, we try to create the root page if it doesn't exist. * NOTE that the returned root page will have only a read lock set * on it even if access = BT_WRITE! * * The returned page is not necessarily the true root --- it could be * a "fast root" (a page that is alone in its level due to deletions). * Also, if the root page is split while we are "in flight" to it, * what we will return is the old root, which is now just the leftmost * page on a probably-not-very-wide level. For most purposes this is * as good as or better than the true root, so we do not bother to * insist on finding the true root. We do, however, guarantee to * return a live (not deleted or half-dead) page. * * On successful return, the root page is pinned and read-locked. * The metadata page is not locked or pinned on exit. */ Buffer _bt_getroot(Relation rel, int access) { Buffer metabuf; Page metapg; BTPageOpaque metaopaque; Buffer rootbuf; Page rootpage; BTPageOpaque rootopaque; BlockNumber rootblkno; uint32 rootlevel; BTMetaPageData *metad; /* * Try to use previously-cached metapage data to find the root. This * normally saves one buffer access per index search, which is a very * helpful savings in bufmgr traffic and hence contention. */ if (rel->rd_amcache != NULL) { metad = (BTMetaPageData *) rel->rd_amcache; /* We shouldn't have cached it if any of these fail */ Assert(metad->btm_magic == BTREE_MAGIC); Assert(metad->btm_version == BTREE_VERSION); Assert(metad->btm_root != P_NONE); rootblkno = metad->btm_fastroot; Assert(rootblkno != P_NONE); rootlevel = metad->btm_fastlevel; rootbuf = _bt_getbuf(rel, rootblkno, BT_READ); rootpage = BufferGetPage(rootbuf); rootopaque = (BTPageOpaque) PageGetSpecialPointer(rootpage); /* * Since the cache might be stale, we check the page more carefully * here than normal. We *must* check that it's not deleted. If it's * not alone on its level, then we reject too --- this may be overly * paranoid but better safe than sorry. Note we don't check P_ISROOT, * because that's not set in a "fast root". */ if (!P_IGNORE(rootopaque) && rootopaque->btpo.level == rootlevel && P_LEFTMOST(rootopaque) && P_RIGHTMOST(rootopaque)) { /* OK, accept cached page as the root */ return rootbuf; } _bt_relbuf(rel, rootbuf); /* Cache is stale, throw it away */ if (rel->rd_amcache) pfree(rel->rd_amcache); rel->rd_amcache = NULL; } metabuf = _bt_getbuf(rel, BTREE_METAPAGE, BT_READ); metapg = BufferGetPage(metabuf); metaopaque = (BTPageOpaque) PageGetSpecialPointer(metapg); metad = BTPageGetMeta(metapg); /* sanity-check the metapage */ if (!(metaopaque->btpo_flags & BTP_META) || metad->btm_magic != BTREE_MAGIC) ereport(ERROR, (errcode(ERRCODE_INDEX_CORRUPTED), errmsg("index \"%s\" is not a btree", RelationGetRelationName(rel)))); if (metad->btm_version != BTREE_VERSION) ereport(ERROR, (errcode(ERRCODE_INDEX_CORRUPTED), errmsg("version mismatch in index \"%s\": file version %d, code version %d", RelationGetRelationName(rel), metad->btm_version, BTREE_VERSION))); /* if no root page initialized yet, do it */ if (metad->btm_root == P_NONE) { /* If access = BT_READ, caller doesn't want us to create root yet */ if (access == BT_READ) { _bt_relbuf(rel, metabuf); return InvalidBuffer; } /* trade in our read lock for a write lock */ LockBuffer(metabuf, BUFFER_LOCK_UNLOCK); LockBuffer(metabuf, BT_WRITE); /* * Race condition: if someone else initialized the metadata between * the time we released the read lock and acquired the write lock, we * must avoid doing it again. */ if (metad->btm_root != P_NONE) { /* * Metadata initialized by someone else. In order to guarantee no * deadlocks, we have to release the metadata page and start all * over again. (Is that really true? But it's hardly worth trying * to optimize this case.) */ _bt_relbuf(rel, metabuf); return _bt_getroot(rel, access); } /* * Get, initialize, write, and leave a lock of the appropriate type on * the new root page. Since this is the first page in the tree, it's * a leaf as well as the root. */ rootbuf = _bt_getbuf(rel, P_NEW, BT_WRITE); rootblkno = BufferGetBlockNumber(rootbuf); rootpage = BufferGetPage(rootbuf); rootopaque = (BTPageOpaque) PageGetSpecialPointer(rootpage); rootopaque->btpo_prev = rootopaque->btpo_next = P_NONE; rootopaque->btpo_flags = (BTP_LEAF | BTP_ROOT); rootopaque->btpo.level = 0; rootopaque->btpo_cycleid = 0; /* NO ELOG(ERROR) till meta is updated */ START_CRIT_SECTION(); metad->btm_root = rootblkno; metad->btm_level = 0; metad->btm_fastroot = rootblkno; metad->btm_fastlevel = 0; MarkBufferDirty(rootbuf); MarkBufferDirty(metabuf); /* XLOG stuff */ if (RelationNeedsWAL(rel)) { xl_btree_newroot xlrec; XLogRecPtr recptr; XLogRecData rdata; xlrec.node = rel->rd_node; xlrec.rootblk = rootblkno; xlrec.level = 0; rdata.data = (char *) &xlrec; rdata.len = SizeOfBtreeNewroot; rdata.buffer = InvalidBuffer; rdata.next = NULL; recptr = XLogInsert(RM_BTREE_ID, XLOG_BTREE_NEWROOT, &rdata); PageSetLSN(rootpage, recptr); PageSetTLI(rootpage, ThisTimeLineID); PageSetLSN(metapg, recptr); PageSetTLI(metapg, ThisTimeLineID); } END_CRIT_SECTION(); /* * Send out relcache inval for metapage change (probably unnecessary * here, but let's be safe). */ CacheInvalidateRelcache(rel); /* * swap root write lock for read lock. There is no danger of anyone * else accessing the new root page while it's unlocked, since no one * else knows where it is yet. */ LockBuffer(rootbuf, BUFFER_LOCK_UNLOCK); LockBuffer(rootbuf, BT_READ); /* okay, metadata is correct, release lock on it */ _bt_relbuf(rel, metabuf); } else { rootblkno = metad->btm_fastroot; Assert(rootblkno != P_NONE); rootlevel = metad->btm_fastlevel; /* * Cache the metapage data for next time */ rel->rd_amcache = MemoryContextAlloc(rel->rd_indexcxt, sizeof(BTMetaPageData)); memcpy(rel->rd_amcache, metad, sizeof(BTMetaPageData)); /* * We are done with the metapage; arrange to release it via first * _bt_relandgetbuf call */ rootbuf = metabuf; for (;;) { rootbuf = _bt_relandgetbuf(rel, rootbuf, rootblkno, BT_READ); rootpage = BufferGetPage(rootbuf); rootopaque = (BTPageOpaque) PageGetSpecialPointer(rootpage); if (!P_IGNORE(rootopaque)) break; /* it's dead, Jim. step right one page */ if (P_RIGHTMOST(rootopaque)) elog(ERROR, "no live root page found in index \"%s\"", RelationGetRelationName(rel)); rootblkno = rootopaque->btpo_next; } /* Note: can't check btpo.level on deleted pages */ if (rootopaque->btpo.level != rootlevel) elog(ERROR, "root page %u of index \"%s\" has level %u, expected %u", rootblkno, RelationGetRelationName(rel), rootopaque->btpo.level, rootlevel); } /* * By here, we have a pin and read lock on the root page, and no lock set * on the metadata page. Return the root page's buffer. */ return rootbuf; }
static void process( char* edges_sql, char* points_sql, ArrayType *starts, ArrayType *ends, bool directed, char *driving_side, bool details, bool only_cost, General_path_element_t **result_tuples, size_t *result_count) { driving_side[0] = estimate_drivingSide(driving_side[0]); pgr_SPI_connect(); size_t size_start_pidsArr = 0; int64_t* start_pidsArr = pgr_get_bigIntArray(&size_start_pidsArr, starts); size_t size_end_pidsArr = 0; int64_t* end_pidsArr = pgr_get_bigIntArray(&size_end_pidsArr, ends); Point_on_edge_t *points = NULL; size_t total_points = 0; pgr_get_points(points_sql, &points, &total_points); char *edges_of_points_query = NULL; char *edges_no_points_query = NULL; get_new_queries( edges_sql, points_sql, &edges_of_points_query, &edges_no_points_query); pgr_edge_t *edges_of_points = NULL; size_t total_edges_of_points = 0; pgr_get_edges( edges_of_points_query, &edges_of_points, &total_edges_of_points); pgr_edge_t *edges = NULL; size_t total_edges = 0; pgr_get_edges(edges_no_points_query, &edges, &total_edges); free(edges_of_points_query); free(edges_no_points_query); if ((total_edges + total_edges_of_points) == 0) { pgr_SPI_finish(); return; } clock_t start_t = clock(); char* log_msg = NULL; char* notice_msg = NULL; char* err_msg = NULL; do_pgr_many_to_many_withPoints( edges, total_edges, points, total_points, edges_of_points, total_edges_of_points, start_pidsArr, size_start_pidsArr, end_pidsArr, size_end_pidsArr, driving_side[0], details, directed, only_cost, true, result_tuples, result_count, &log_msg, ¬ice_msg, &err_msg); if (only_cost) { time_msg("processing pgr_withPointsCost(one to one)", start_t, clock()); } else { time_msg("processing pgr_withPoints(one to one)", start_t, clock()); } if (err_msg && (*result_tuples)) { pfree(*result_tuples); (*result_count) = 0; (*result_tuples) = NULL; } pgr_global_report(log_msg, notice_msg, err_msg); #if 0 if (log_msg) pfree(log_msg); if (notice_msg) pfree(notice_msg); if (err_msg) pfree(err_msg); if (edges) pfree(edges); if (points) pfree(points); if (edges_of_points) pfree(edges_of_points); if (start_pidsArr) pfree(start_pidsArr); if (end_pidsArr) pfree(end_pidsArr); #endif pgr_SPI_finish(); }
/* * bms_free - free a bitmapset * * Same as pfree except for allowing NULL input */ void bms_free(Bitmapset *a) { if (a) pfree(a); }
void datum_to_bson(const char* field_name, mongo::BSONObjBuilder& builder, Datum val, bool is_null, Oid typid) { PGBSON_LOG << "BEGIN datum_to_bson, field_name=" << field_name << ", typeid=" << typid << PGBSON_ENDL; if (field_name == NULL) { field_name = ""; } if (is_null) { builder.appendNull(field_name); } else { switch(typid) { case BOOLOID: builder.append(field_name, DatumGetBool(val)); break; case CHAROID: { char c = DatumGetChar(val); builder.append(field_name, &c, 1); break; } case INT8OID: builder.append(field_name, (long long)DatumGetInt64(val)); break; case INT2OID: builder.append(field_name, DatumGetInt16(val)); break; case INT4OID: builder.append(field_name, DatumGetInt32(val)); break; case TEXTOID: case JSONOID: case XMLOID: { text* t = DatumGetTextP(val); builder.append(field_name, VARDATA(t), VARSIZE(t)-VARHDRSZ+1); break; } case FLOAT4OID: builder.append(field_name, DatumGetFloat4(val)); break; case FLOAT8OID: builder.append(field_name, DatumGetFloat8(val)); break; case RECORDOID: { mongo::BSONObjBuilder sub(builder.subobjStart(field_name)); composite_to_bson(sub, val); sub.done(); break; } case TIMESTAMPOID: { Timestamp ts = DatumGetTimestamp(val); #ifdef HAVE_INT64_TIMESTAMP mongo::Date_t date(ts); #else mongo::Date_t date(ts * 1000); #endif builder.append(field_name, date); break; } default: { PGBSON_LOG << "datum_to_bson - unknown type, using text output." << PGBSON_ENDL; PGBSON_LOG << "datum_to_bson - type=" << get_typename(typid) << PGBSON_ENDL; if (get_typename(typid) == "bson") { bytea* data = DatumGetBson(val); mongo::BSONObj obj(VARDATA_ANY(data)); builder.append(field_name, obj); } else { // use text output for the type bool typisvarlena = false; Oid typoutput; getTypeOutputInfo(typid, &typoutput, &typisvarlena); PGBSON_LOG << "datum_to_bson - typisvarlena=" << std::boolalpha << typisvarlena << PGBSON_ENDL; Datum out_val = val; /* * If we have a toasted datum, forcibly detoast it here to avoid * memory leakage inside the type's output routine. */ if (typisvarlena) { out_val = PointerGetDatum(PG_DETOAST_DATUM(val)); PGBSON_LOG << "datum_to_bson - var len valuie detoasted" << PGBSON_ENDL; } char* outstr = OidOutputFunctionCall(typoutput, out_val); builder.append(field_name, outstr); /* Clean up detoasted copy, if any */ if (val != out_val) pfree(DatumGetPointer(out_val)); } } } // switch } // if not null PGBSON_LOG << "END datum_to_bson, field_name=" << field_name << PGBSON_ENDL; }
/* * Delete error log of the specified relation. This returns true from master * iif all segments and master find the relation. */ Datum gp_truncate_error_log(PG_FUNCTION_ARGS) { text *relname; char *relname_str; RangeVar *relrv; Oid relid; bool allResults = true; relname = PG_GETARG_TEXT_P(0); relname_str = text_to_cstring(relname); if (strcmp(relname_str, "*.*") == 0) { /* * Only superuser is allowed to delete log files across database. */ if (!superuser()) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), (errmsg("must be superuser to delete all error log files")))); ErrorLogDelete(InvalidOid, InvalidOid); } else if (strcmp(relname_str, "*") == 0) { /* * Database owner can delete error log files. */ if (!pg_database_ownercheck(MyDatabaseId, GetUserId())) aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE, get_database_name(MyDatabaseId)); ErrorLogDelete(MyDatabaseId, InvalidOid); } else { AclResult aclresult; relrv = makeRangeVarFromNameList(textToQualifiedNameList(relname)); relid = RangeVarGetRelid(relrv, true); /* Return false if the relation does not exist. */ if (!OidIsValid(relid)) PG_RETURN_BOOL(false); /* * Allow only the table owner to truncate error log. */ aclresult = pg_class_aclcheck(relid, GetUserId(), ACL_TRUNCATE); if (aclresult != ACLCHECK_OK) aclcheck_error(aclresult, ACL_KIND_CLASS, relrv->relname); /* We don't care if this fails or not. */ ErrorLogDelete(MyDatabaseId, relid); } /* * Dispatch the work to segments. */ if (Gp_role == GP_ROLE_DISPATCH) { int i, resultCount = 0; StringInfoData sql, errbuf; PGresult **results; initStringInfo(&sql); initStringInfo(&errbuf); appendStringInfo(&sql, "SELECT pg_catalog.gp_truncate_error_log(%s)", quote_literal_internal(text_to_cstring(relname))); results = cdbdisp_dispatchRMCommand(sql.data, true, &errbuf, &resultCount); if (errbuf.len > 0) elog(ERROR, "%s", errbuf.data); Assert(resultCount > 0); for (i = 0; i < resultCount; i++) { Datum value; bool isnull; if (PQresultStatus(results[i]) != PGRES_TUPLES_OK) ereport(ERROR, (errmsg("unexpected result from segment: %d", PQresultStatus(results[i])))); value = ResultToDatum(results[i], 0, 0, boolin, &isnull); allResults &= (!isnull && DatumGetBool(value)); PQclear(results[i]); } pfree(errbuf.data); pfree(sql.data); } /* Return true iif all segments return true. */ PG_RETURN_BOOL(allResults); }
pg_tz * pg_tzenumerate_next(pg_tzenum *dir) { while (dir->depth >= 0) { struct dirent *direntry; char fullname[MAXPGPATH]; struct stat statbuf; direntry = ReadDir(dir->dirdesc[dir->depth], dir->dirname[dir->depth]); if (!direntry) { /* End of this directory */ FreeDir(dir->dirdesc[dir->depth]); pfree(dir->dirname[dir->depth]); dir->depth--; continue; } if (direntry->d_name[0] == '.') continue; snprintf(fullname, MAXPGPATH, "%s/%s", dir->dirname[dir->depth], direntry->d_name); if (stat(fullname, &statbuf) != 0) ereport(ERROR, (errcode_for_file_access(), errmsg("could not stat \"%s\": %m", fullname))); if (S_ISDIR(statbuf.st_mode)) { /* Step into the subdirectory */ if (dir->depth >= MAX_TZDIR_DEPTH - 1) ereport(ERROR, (errmsg("timezone directory stack overflow"))); dir->depth++; dir->dirname[dir->depth] = pstrdup(fullname); dir->dirdesc[dir->depth] = AllocateDir(fullname); if (!dir->dirdesc[dir->depth]) ereport(ERROR, (errcode_for_file_access(), errmsg("could not open directory \"%s\": %m", fullname))); /* Start over reading in the new directory */ continue; } /* * Load this timezone using tzload() not pg_tzset(), so we don't fill * the cache */ if (tzload(fullname + dir->baselen, dir->tz.TZname, &dir->tz.state, TRUE) != 0) { /* Zone could not be loaded, ignore it */ continue; } if (!tz_acceptable(&dir->tz)) { /* Ignore leap-second zones */ continue; } /* Timezone loaded OK. */ return &dir->tz; } /* Nothing more found */ return NULL; }
/* ---------------------------------------------------------------- * UpdateIndexRelation * ---------------------------------------------------------------- */ static void UpdateIndexRelation(Oid indexoid, Oid heapoid, IndexInfo *indexInfo, Oid *classOids, bool primary) { int16 indkey[INDEX_MAX_KEYS]; Oid indclass[INDEX_MAX_KEYS]; Datum exprsDatum; Datum predDatum; Datum values[Natts_pg_index]; char nulls[Natts_pg_index]; Relation pg_index; HeapTuple tuple; int i; /* * Copy the index key and opclass info into zero-filled vectors */ MemSet(indkey, 0, sizeof(indkey)); MemSet(indclass, 0, sizeof(indclass)); for (i = 0; i < indexInfo->ii_NumIndexAttrs; i++) { indkey[i] = indexInfo->ii_KeyAttrNumbers[i]; indclass[i] = classOids[i]; } /* * Convert the index expressions (if any) to a text datum */ if (indexInfo->ii_Expressions != NIL) { char *exprsString; exprsString = nodeToString(indexInfo->ii_Expressions); exprsDatum = DirectFunctionCall1(textin, CStringGetDatum(exprsString)); pfree(exprsString); } else exprsDatum = (Datum) 0; /* * Convert the index predicate (if any) to a text datum */ if (indexInfo->ii_Predicate != NIL) { char *predString; predString = nodeToString(indexInfo->ii_Predicate); predDatum = DirectFunctionCall1(textin, CStringGetDatum(predString)); pfree(predString); } else predDatum = (Datum) 0; /* * open the system catalog index relation */ pg_index = heap_openr(IndexRelationName, RowExclusiveLock); /* * Build a pg_index tuple */ MemSet(nulls, ' ', sizeof(nulls)); values[Anum_pg_index_indexrelid - 1] = ObjectIdGetDatum(indexoid); values[Anum_pg_index_indrelid - 1] = ObjectIdGetDatum(heapoid); values[Anum_pg_index_indkey - 1] = PointerGetDatum(indkey); values[Anum_pg_index_indclass - 1] = PointerGetDatum(indclass); values[Anum_pg_index_indnatts - 1] = Int16GetDatum(indexInfo->ii_NumIndexAttrs); values[Anum_pg_index_indisunique - 1] = BoolGetDatum(indexInfo->ii_Unique); values[Anum_pg_index_indisprimary - 1] = BoolGetDatum(primary); values[Anum_pg_index_indisclustered - 1] = BoolGetDatum(false); values[Anum_pg_index_indexprs - 1] = exprsDatum; if (exprsDatum == (Datum) 0) nulls[Anum_pg_index_indexprs - 1] = 'n'; values[Anum_pg_index_indpred - 1] = predDatum; if (predDatum == (Datum) 0) nulls[Anum_pg_index_indpred - 1] = 'n'; tuple = heap_formtuple(RelationGetDescr(pg_index), values, nulls); /* * insert the tuple into the pg_index catalog */ simple_heap_insert(pg_index, tuple); /* update the indexes on pg_index */ CatalogUpdateIndexes(pg_index, tuple); /* * close the relation and free the tuple */ heap_close(pg_index, RowExclusiveLock); heap_freetuple(tuple); }
/* * gp_read_error_log * * Returns set of error log tuples. */ Datum gp_read_error_log(PG_FUNCTION_ARGS) { FuncCallContext *funcctx; ReadErrorLogContext *context; HeapTuple tuple; Datum result; /* * First call setup */ if (SRF_IS_FIRSTCALL()) { MemoryContext oldcontext; FILE *fp; text *relname; funcctx = SRF_FIRSTCALL_INIT(); relname = PG_GETARG_TEXT_P(0); oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); context = palloc0(sizeof(ReadErrorLogContext)); funcctx->user_fctx = (void *) context; funcctx->tuple_desc = BlessTupleDesc(GetErrorTupleDesc()); /* * Though this function is usually executed on segment, we dispatch * the execution if it happens to be on QD, and combine the results * into one set. */ if (Gp_role == GP_ROLE_DISPATCH) { int resultCount = 0; PGresult **results = NULL; StringInfoData sql; StringInfoData errbuf; int i; initStringInfo(&sql); initStringInfo(&errbuf); /* * construct SQL */ appendStringInfo(&sql, "SELECT * FROM pg_catalog.gp_read_error_log(%s) ", quote_literal_internal(text_to_cstring(relname))); results = cdbdisp_dispatchRMCommand(sql.data, true, &errbuf, &resultCount); if (errbuf.len > 0) elog(ERROR, "%s", errbuf.data); Assert(resultCount > 0); for (i = 0; i < resultCount; i++) { if (PQresultStatus(results[i]) != PGRES_TUPLES_OK) elog(ERROR, "unexpected result from segment: %d", PQresultStatus(results[i])); context->numTuples += PQntuples(results[i]); } pfree(errbuf.data); pfree(sql.data); context->segResults = results; context->numSegResults = resultCount; } else { /* * In QE, read the error log. */ RangeVar *relrv; Oid relid; relrv = makeRangeVarFromNameList(textToQualifiedNameList(relname)); relid = RangeVarGetRelid(relrv, true); /* * If the relation has gone, silently return no tuples. */ if (OidIsValid(relid)) { AclResult aclresult; /* * Requires SELECT priv to read error log. */ aclresult = pg_class_aclcheck(relid, GetUserId(), ACL_SELECT); if (aclresult != ACLCHECK_OK) aclcheck_error(aclresult, ACL_KIND_CLASS, relrv->relname); ErrorLogFileName(context->filename, MyDatabaseId, relid); fp = AllocateFile(context->filename, "r"); context->fp = fp; } } MemoryContextSwitchTo(oldcontext); if (Gp_role != GP_ROLE_DISPATCH && !context->fp) { pfree(context); SRF_RETURN_DONE(funcctx); } } funcctx = SRF_PERCALL_SETUP(); context = (ReadErrorLogContext *) funcctx->user_fctx; /* * Read error log, probably on segments. We don't check Gp_role, however, * in case master also wants to read the file. */ if (context->fp) { pg_crc32 crc, written_crc; tuple = ErrorLogRead(context->fp, &written_crc); /* * CRC check. */ if (HeapTupleIsValid(tuple)) { INIT_CRC32C(crc); COMP_CRC32C(crc, tuple->t_data, tuple->t_len); FIN_CRC32C(crc); if (!EQ_CRC32C(crc, written_crc)) { elog(LOG, "incorrect checksum in error log %s", context->filename); tuple = NULL; } } /* * If we found a valid tuple, return it. Otherwise, fall through * in the DONE routine. */ if (HeapTupleIsValid(tuple)) { /* * We need to set typmod for the executor to understand * its type we just blessed. */ HeapTupleHeaderSetTypMod(tuple->t_data, funcctx->tuple_desc->tdtypmod); result = HeapTupleGetDatum(tuple); SRF_RETURN_NEXT(funcctx, result); } } /* * If we got results from dispatch, return all the tuples. */ while (context->currentResult < context->numSegResults) { Datum values[NUM_ERRORTABLE_ATTR]; bool isnull[NUM_ERRORTABLE_ATTR]; PGresult *segres = context->segResults[context->currentResult]; int row = context->currentRow; if (row >= PQntuples(segres)) { context->currentRow = 0; context->currentResult++; continue; } context->currentRow++; MemSet(isnull, false, sizeof(isnull)); values[0] = ResultToDatum(segres, row, 0, timestamptz_in, &isnull[0]); values[1] = ResultToDatum(segres, row, 1, textin, &isnull[1]); values[2] = ResultToDatum(segres, row, 2, textin, &isnull[2]); values[3] = ResultToDatum(segres, row, 3, int4in, &isnull[3]); values[4] = ResultToDatum(segres, row, 4, int4in, &isnull[4]); values[5] = ResultToDatum(segres, row, 5, textin, &isnull[5]); values[6] = ResultToDatum(segres, row, 6, textin, &isnull[6]); values[7] = ResultToDatum(segres, row, 7, byteain, &isnull[7]); tuple = heap_form_tuple(funcctx->tuple_desc, values, isnull); result = HeapTupleGetDatum(tuple); SRF_RETURN_NEXT(funcctx, result); } if (context->segResults != NULL) { int i; for (i = 0; i < context->numSegResults; i++) PQclear(context->segResults[i]); /* XXX: better to copy to palloc'ed area */ free(context->segResults); } /* * Close the file, if we have opened it. */ if (context->fp != NULL) { FreeFile(context->fp); context->fp = NULL; } SRF_RETURN_DONE(funcctx); }
/* * updateAclDependencies * Update the pg_shdepend info for an object's ACL during GRANT/REVOKE. * * classId, objectId, objsubId: identify the object whose ACL this is * ownerId: role owning the object * noldmembers, oldmembers: array of roleids appearing in old ACL * nnewmembers, newmembers: array of roleids appearing in new ACL * * We calculate the differences between the new and old lists of roles, * and then insert or delete from pg_shdepend as appropriate. * * Note that we can't just insert all referenced roles blindly during GRANT, * because we would end up with duplicate registered dependencies. We could * check for existence of the tuples before inserting, but that seems to be * more expensive than what we are doing here. Likewise we can't just delete * blindly during REVOKE, because the user may still have other privileges. * It is also possible that REVOKE actually adds dependencies, due to * instantiation of a formerly implicit default ACL (although at present, * all such dependencies should be for the owning role, which we ignore here). * * NOTE: Both input arrays must be sorted and de-duped. (Typically they * are extracted from an ACL array by aclmembers(), which takes care of * both requirements.) The arrays are pfreed before return. */ void updateAclDependencies(Oid classId, Oid objectId, int32 objsubId, Oid ownerId, int noldmembers, Oid *oldmembers, int nnewmembers, Oid *newmembers) { Relation sdepRel; int i; /* * Remove entries that are common to both lists; those represent existing * dependencies we don't need to change. * * OK to overwrite the inputs since we'll pfree them anyway. */ getOidListDiff(oldmembers, &noldmembers, newmembers, &nnewmembers); if (noldmembers > 0 || nnewmembers > 0) { sdepRel = heap_open(SharedDependRelationId, RowExclusiveLock); /* Add new dependencies that weren't already present */ for (i = 0; i < nnewmembers; i++) { Oid roleid = newmembers[i]; /* * Skip the owner: he has an OWNER shdep entry instead. (This is * not just a space optimization; it makes ALTER OWNER easier. See * notes in changeDependencyOnOwner.) */ if (roleid == ownerId) continue; /* Skip pinned roles; they don't need dependency entries */ if (isSharedObjectPinned(AuthIdRelationId, roleid, sdepRel)) continue; shdepAddDependency(sdepRel, classId, objectId, objsubId, AuthIdRelationId, roleid, SHARED_DEPENDENCY_ACL); } /* Drop no-longer-used old dependencies */ for (i = 0; i < noldmembers; i++) { Oid roleid = oldmembers[i]; /* Skip the owner, same as above */ if (roleid == ownerId) continue; /* Skip pinned roles */ if (isSharedObjectPinned(AuthIdRelationId, roleid, sdepRel)) continue; shdepDropDependency(sdepRel, classId, objectId, objsubId, false, /* exact match on objsubId */ AuthIdRelationId, roleid, SHARED_DEPENDENCY_ACL); } heap_close(sdepRel, RowExclusiveLock); } if (oldmembers) pfree(oldmembers); if (newmembers) pfree(newmembers); }
Datum xpath_table(PG_FUNCTION_ARGS) { /* Function parameters */ char *pkeyfield = text_to_cstring(PG_GETARG_TEXT_PP(0)); char *xmlfield = text_to_cstring(PG_GETARG_TEXT_PP(1)); char *relname = text_to_cstring(PG_GETARG_TEXT_PP(2)); char *xpathset = text_to_cstring(PG_GETARG_TEXT_PP(3)); char *condition = text_to_cstring(PG_GETARG_TEXT_PP(4)); /* SPI (input tuple) support */ SPITupleTable *tuptable; HeapTuple spi_tuple; TupleDesc spi_tupdesc; /* Output tuple (tuplestore) support */ Tuplestorestate *tupstore = NULL; TupleDesc ret_tupdesc; HeapTuple ret_tuple; ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo; AttInMetadata *attinmeta; MemoryContext per_query_ctx; MemoryContext oldcontext; char **values; xmlChar **xpaths; char *pos; const char *pathsep = "|"; int numpaths; int ret; int proc; int i; int j; int rownr; /* For issuing multiple rows from one original * document */ bool had_values; /* To determine end of nodeset results */ StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; /* We only have a valid tuple description in table function mode */ if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo)) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("set-valued function called in context that cannot accept a set"))); if (rsinfo->expectedDesc == NULL) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("xpath_table must be called as a table function"))); /* * We want to materialise because it means that we don't have to carry * libxml2 parser state between invocations of this function */ if (!(rsinfo->allowedModes & SFRM_Materialize)) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("xpath_table requires Materialize mode, but it is not " "allowed in this context"))); /* * The tuplestore must exist in a higher context than this function call * (per_query_ctx is used) */ per_query_ctx = rsinfo->econtext->ecxt_per_query_memory; oldcontext = MemoryContextSwitchTo(per_query_ctx); /* * Create the tuplestore - work_mem is the max in-memory size before a * file is created on disk to hold it. */ tupstore = tuplestore_begin_heap(rsinfo->allowedModes & SFRM_Materialize_Random, false, work_mem); MemoryContextSwitchTo(oldcontext); /* get the requested return tuple description */ ret_tupdesc = CreateTupleDescCopy(rsinfo->expectedDesc); /* must have at least one output column (for the pkey) */ if (ret_tupdesc->natts < 1) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("xpath_table must have at least one output column"))); /* * At the moment we assume that the returned attributes make sense for the * XPath specififed (i.e. we trust the caller). It's not fatal if they get * it wrong - the input function for the column type will raise an error * if the path result can't be converted into the correct binary * representation. */ attinmeta = TupleDescGetAttInMetadata(ret_tupdesc); /* Set return mode and allocate value space. */ rsinfo->returnMode = SFRM_Materialize; rsinfo->setDesc = ret_tupdesc; values = (char **) palloc(ret_tupdesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(ret_tupdesc->natts * sizeof(xmlChar *)); /* * Split XPaths. xpathset is a writable CString. * * Note that we stop splitting once we've done all needed for tupdesc */ numpaths = 0; pos = xpathset; while (numpaths < (ret_tupdesc->natts - 1)) { xpaths[numpaths++] = (xmlChar *) pos; pos = strstr(pos, pathsep); if (pos != NULL) { *pos = '\0'; pos++; } else break; } /* Now build query */ initStringInfo(&query_buf); /* Build initial sql statement */ appendStringInfo(&query_buf, "SELECT %s, %s FROM %s WHERE %s", pkeyfield, xmlfield, relname, condition); if ((ret = SPI_connect()) < 0) elog(ERROR, "xpath_table: SPI_connect returned %d", ret); if ((ret = SPI_exec(query_buf.data, 0)) != SPI_OK_SELECT) elog(ERROR, "xpath_table: SPI execution failed for query %s", query_buf.data); proc = SPI_processed; /* elog(DEBUG1,"xpath_table: SPI returned %d rows",proc); */ tuptable = SPI_tuptable; spi_tupdesc = tuptable->tupdesc; /* Switch out of SPI context */ MemoryContextSwitchTo(oldcontext); /* * Check that SPI returned correct result. If you put a comma into one of * the function parameters, this will catch it when the SPI query returns * e.g. 3 columns. */ if (spi_tupdesc->natts != 2) { ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("expression returning multiple columns is not valid in parameter list"), errdetail("Expected two columns in SPI result, got %d.", spi_tupdesc->natts))); } /* * Setup the parser. This should happen after we are done evaluating the * query, in case it calls functions that set up libxml differently. */ xmlerrcxt = pgxml_parser_init(PG_XML_STRICTNESS_LEGACY); PG_TRY(); { /* For each row i.e. document returned from SPI */ for (i = 0; i < proc; i++) { char *pkey; char *xmldoc; xmlXPathContextPtr ctxt; xmlXPathObjectPtr res; xmlChar *resstr; xmlXPathCompExprPtr comppath; /* Extract the row data as C Strings */ spi_tuple = tuptable->vals[i]; pkey = SPI_getvalue(spi_tuple, spi_tupdesc, 1); xmldoc = SPI_getvalue(spi_tuple, spi_tupdesc, 2); /* * Clear the values array, so that not-well-formed documents * return NULL in all columns. Note that this also means that * spare columns will be NULL. */ for (j = 0; j < ret_tupdesc->natts; j++) values[j] = NULL; /* Insert primary key */ values[0] = pkey; /* Parse the document */ if (xmldoc) doctree = xmlParseMemory(xmldoc, strlen(xmldoc)); else /* treat NULL as not well-formed */ doctree = NULL; if (doctree == NULL) { /* not well-formed, so output all-NULL tuple */ ret_tuple = BuildTupleFromCStrings(attinmeta, values); tuplestore_puttuple(tupstore, ret_tuple); heap_freetuple(ret_tuple); } else { /* New loop here - we have to deal with nodeset results */ rownr = 0; do { /* Now evaluate the set of xpaths. */ had_values = false; for (j = 0; j < numpaths; j++) { ctxt = xmlXPathNewContext(doctree); ctxt->node = xmlDocGetRootElement(doctree); /* compile the path */ comppath = xmlXPathCompile(xpaths[j]); if (comppath == NULL) xml_ereport(xmlerrcxt, ERROR, ERRCODE_EXTERNAL_ROUTINE_EXCEPTION, "XPath Syntax Error"); /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); if (res != NULL) { switch (res->type) { case XPATH_NODESET: /* We see if this nodeset has enough nodes */ if (res->nodesetval != NULL && rownr < res->nodesetval->nodeNr) { resstr = xmlXPathCastNodeToString(res->nodesetval->nodeTab[rownr]); had_values = true; } else resstr = NULL; break; case XPATH_STRING: resstr = xmlStrdup(res->stringval); break; default: elog(NOTICE, "unsupported XQuery result: %d", res->type); resstr = xmlStrdup((const xmlChar *) "<unsupported/>"); } /* * Insert this into the appropriate column in the * result tuple. */ values[j + 1] = (char *) resstr; } xmlXPathFreeContext(ctxt); } /* Now add the tuple to the output, if there is one. */ if (had_values) { ret_tuple = BuildTupleFromCStrings(attinmeta, values); tuplestore_puttuple(tupstore, ret_tuple); heap_freetuple(ret_tuple); } rownr++; } while (had_values); } if (doctree != NULL) xmlFreeDoc(doctree); doctree = NULL; if (pkey) pfree(pkey); if (xmldoc) pfree(xmldoc); } } PG_CATCH(); { if (doctree != NULL) xmlFreeDoc(doctree); pg_xml_done(xmlerrcxt, true); PG_RE_THROW(); } PG_END_TRY(); if (doctree != NULL) xmlFreeDoc(doctree); pg_xml_done(xmlerrcxt, false); tuplestore_donestoring(tupstore); SPI_finish(); rsinfo->setResult = tupstore; /* * SFRM_Materialize mode expects us to return a NULL Datum. The actual * tuples are in our tuplestore and passed back through rsinfo->setResult. * rsinfo->setDesc is set to the tuple description that we actually used * to build our tuples with, so the caller can verify we did what it was * expecting. */ return (Datum) 0; }
static void logfebe_emit_log_hook(ErrorData *edata) { int save_errno; StringInfoData buf; /* * This is one of the few places where we'd rather not inherit a static * variable's value from the postmaster. But since we will, reset it when * MyProcPid changes. */ if (savedPid != MyProcPid) { savedPid = MyProcPid; /* Invalidate all inherited values */ seqNum = 0; cachedBackendStartTime[0] = '\0'; if (outSockFd >= 0) { closeSocket(&outSockFd); } } /* * Increment log sequence number * * Done early on so this happens regardless if there are problems emitting * the log. */ seqNum += 1; /* * Early exit if the socket path is not set and isn't in the format of * an absolute path. * * The empty identity ("ident") is a valid one, so it is not rejected in * the same way an empty logUnixSocketPath is. */ if (logUnixSocketPath == NULL || strlen(logUnixSocketPath) <= 0 || logUnixSocketPath[0] != '/') { /* * Unsetting the GUCs via SIGHUP would leave a connection * dangling, if it exists, close it. */ if (outSockFd >= 0) { closeSocket(&outSockFd); } goto quickExit; } save_errno = errno; /* * Initialize StringInfoDatas early, because pfree is called * unconditionally at exit. */ initStringInfo(&buf); if (outSockFd < 0) { openSocket(&outSockFd, logUnixSocketPath); /* Couldn't get a valid socket; give up */ if (outSockFd < 0) goto exit; } /* * Make room for message type byte and length header. The length header * must be overwritten to the correct value at the end. */ { const char logHdr[5] = {'L', '\0', '\0', '\0', '\0'}; appendBinaryStringInfo(&buf, logHdr, sizeof logHdr); } /* * Format the output, and figure out how long it is, and frame it * for the protocol. */ { uint32_t *msgSize; fmtLogMsg(&buf, edata); /* * Check that buf is prepared properly, with enough space and * the placeholder length expected. */ Assert(buf.len > 5); Assert(buf.data[0] == 'L'); msgSize = (uint32_t *)(buf.data + 1); Assert(*msgSize == 0); /* * Fill in *msgSize: buf contains the msg header, which is not * included in length; subract and byte-swap to paste the * right length into place. */ *msgSize = htobe32(buf.len - 1); } /* Finally: try to send the constructed message */ sendOrInval(&outSockFd, buf.data, buf.len); exit: pfree(buf.data); errno = save_errno; quickExit: /* Call a previous hook, should it exist */ if (prev_emit_log_hook != NULL) prev_emit_log_hook(edata); }
static void compileTheSubstitute(DictThesaurus *d) { int i; for (i = 0; i < d->nsubst; i++) { TSLexeme *rem = d->subst[i].res, *outptr, *inptr; int n = 2; outptr = d->subst[i].res = (TSLexeme *) palloc(sizeof(TSLexeme) * n); outptr->lexeme = NULL; inptr = rem; while (inptr && inptr->lexeme) { TSLexeme *lexized, tmplex[2]; if (inptr->flags & DT_USEASIS) { /* do not lexize */ tmplex[0] = *inptr; tmplex[0].flags = 0; tmplex[1].lexeme = NULL; lexized = tmplex; } else { lexized = (TSLexeme *) DatumGetPointer( FunctionCall4( &(d->subdict->lexize), PointerGetDatum(d->subdict->dictData), PointerGetDatum(inptr->lexeme), Int32GetDatum(strlen(inptr->lexeme)), PointerGetDatum(NULL) ) ); } if (lexized && lexized->lexeme) { int toset = (lexized->lexeme && outptr != d->subst[i].res) ? (outptr - d->subst[i].res) : -1; while (lexized->lexeme) { if (outptr - d->subst[i].res + 1 >= n) { int diff = outptr - d->subst[i].res; n *= 2; d->subst[i].res = (TSLexeme *) repalloc(d->subst[i].res, sizeof(TSLexeme) * n); outptr = d->subst[i].res + diff; } *outptr = *lexized; outptr->lexeme = pstrdup(lexized->lexeme); outptr++; lexized++; } if (toset > 0) d->subst[i].res[toset].flags |= TSL_ADDPOS; } else if (lexized) { ereport(ERROR, (errcode(ERRCODE_CONFIG_FILE_ERROR), errmsg("thesaurus substitute word \"%s\" is a stop word (rule %d)", inptr->lexeme, i + 1))); } else { ereport(ERROR, (errcode(ERRCODE_CONFIG_FILE_ERROR), errmsg("thesaurus substitute word \"%s\" isn't recognized by subdictionary (rule %d)", inptr->lexeme, i + 1))); } if (inptr->lexeme) pfree(inptr->lexeme); inptr++; } if (outptr == d->subst[i].res) ereport(ERROR, (errcode(ERRCODE_CONFIG_FILE_ERROR), errmsg("thesaurus substitute phrase is empty (rule %d)", i + 1))); d->subst[i].reslen = outptr - d->subst[i].res; pfree(rem); } }
/* * input */ Datum bqarr_in(PG_FUNCTION_ARGS) { char *buf = (char *) PG_GETARG_POINTER(0); WORKSTATE state; int4 i; QUERYTYPE *query; int4 commonlen; ITEM *ptr; NODE *tmp; int4 pos = 0; #ifdef BS_DEBUG StringInfoData pbuf; #endif state.buf = buf; state.state = WAITOPERAND; state.count = 0; state.num = 0; state.str = NULL; /* make polish notation (postfix, but in reverse order) */ makepol(&state); if (!state.num) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("empty query"))); commonlen = COMPUTESIZE(state.num); query = (QUERYTYPE *) palloc(commonlen); SET_VARSIZE(query, commonlen); query->size = state.num; ptr = GETQUERY(query); for (i = state.num - 1; i >= 0; i--) { ptr[i].type = state.str->type; ptr[i].val = state.str->val; tmp = state.str->next; pfree(state.str); state.str = tmp; } pos = query->size - 1; findoprnd(ptr, &pos); #ifdef BS_DEBUG initStringInfo(&pbuf); for (i = 0; i < query->size; i++) { if (ptr[i].type == OPR) appendStringInfo(&pbuf, "%c(%d) ", ptr[i].val, ptr[i].left); else appendStringInfo(&pbuf, "%d ", ptr[i].val); } elog(DEBUG3, "POR: %s", pbuf.data); pfree(pbuf.data); #endif PG_RETURN_POINTER(query); }
/* * Inserts only one entry to the index, but it can add more than 1 ItemPointer. */ void ginEntryInsert(Relation index, GinState *ginstate, OffsetNumber attnum, Datum value, ItemPointerData *items, uint32 nitem, bool isBuild) { GinBtreeData btree; GinBtreeStack *stack; IndexTuple itup; Page page; prepareEntryScan(&btree, index, attnum, value, ginstate); stack = ginFindLeafPage(&btree, NULL); page = BufferGetPage(stack->buffer); if (btree.findItem(&btree, stack)) { /* found entry */ itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, stack->off)); if (GinIsPostingTree(itup)) { /* lock root of posting tree */ GinPostingTreeScan *gdi; BlockNumber rootPostingTree = GinGetPostingTree(itup); /* release all stack */ LockBuffer(stack->buffer, GIN_UNLOCK); freeGinBtreeStack(stack); /* insert into posting tree */ gdi = prepareScanPostingTree(index, rootPostingTree, FALSE); gdi->btree.isBuild = isBuild; insertItemPointer(gdi, items, nitem); return; } itup = addItemPointersToTuple(index, ginstate, stack, itup, items, nitem, isBuild); btree.isDelete = TRUE; } else { /* We suppose, that tuple can store at list one itempointer */ itup = GinFormTuple(ginstate, attnum, value, items, 1); if (itup == NULL || IndexTupleSize(itup) >= GinMaxItemSize) elog(ERROR, "huge tuple"); if (nitem > 1) { IndexTuple previtup = itup; itup = addItemPointersToTuple(index, ginstate, stack, previtup, items + 1, nitem - 1, isBuild); pfree(previtup); } } btree.entry = itup; ginInsertValue(&btree, stack); pfree(itup); }
static void infix(INFIX *in, bool first) { if (in->curpol->type == VAL) { RESIZEBUF(in, 11); sprintf(in->cur, "%d", in->curpol->val); in->cur = strchr(in->cur, '\0'); in->curpol--; } else if (in->curpol->val == (int4) '!') { bool isopr = false; RESIZEBUF(in, 1); *(in->cur) = '!'; in->cur++; *(in->cur) = '\0'; in->curpol--; if (in->curpol->type == OPR) { isopr = true; RESIZEBUF(in, 2); sprintf(in->cur, "( "); in->cur = strchr(in->cur, '\0'); } infix(in, isopr); if (isopr) { RESIZEBUF(in, 2); sprintf(in->cur, " )"); in->cur = strchr(in->cur, '\0'); } } else { int4 op = in->curpol->val; INFIX nrm; in->curpol--; if (op == (int4) '|' && !first) { RESIZEBUF(in, 2); sprintf(in->cur, "( "); in->cur = strchr(in->cur, '\0'); } nrm.curpol = in->curpol; nrm.buflen = 16; nrm.cur = nrm.buf = (char *) palloc(sizeof(char) * nrm.buflen); /* get right operand */ infix(&nrm, false); /* get & print left operand */ in->curpol = nrm.curpol; infix(in, false); /* print operator & right operand */ RESIZEBUF(in, 3 + (nrm.cur - nrm.buf)); sprintf(in->cur, " %c %s", op, nrm.buf); in->cur = strchr(in->cur, '\0'); pfree(nrm.buf); if (op == (int4) '|' && !first) { RESIZEBUF(in, 2); sprintf(in->cur, " )"); in->cur = strchr(in->cur, '\0'); } } }
/* * stat a file */ Datum pg_stat_file(PG_FUNCTION_ARGS) { text *filename_t = PG_GETARG_TEXT_PP(0); char *filename; struct stat fst; Datum values[6]; bool isnull[6]; HeapTuple tuple; TupleDesc tupdesc; bool missing_ok = false; if (!superuser()) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), (errmsg("must be superuser to get file information")))); /* check the optional argument */ if (PG_NARGS() == 2) missing_ok = PG_GETARG_BOOL(1); filename = convert_and_check_filename(filename_t); if (stat(filename, &fst) < 0) { if (missing_ok && errno == ENOENT) PG_RETURN_NULL(); else ereport(ERROR, (errcode_for_file_access(), errmsg("could not stat file \"%s\": %m", filename))); } /* * This record type had better match the output parameters declared for me * in pg_proc.h. */ tupdesc = CreateTemplateTupleDesc(6, false); TupleDescInitEntry(tupdesc, (AttrNumber) 1, "size", INT8OID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 2, "access", TIMESTAMPTZOID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 3, "modification", TIMESTAMPTZOID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 4, "change", TIMESTAMPTZOID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 5, "creation", TIMESTAMPTZOID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 6, "isdir", BOOLOID, -1, 0); BlessTupleDesc(tupdesc); memset(isnull, false, sizeof(isnull)); values[0] = Int64GetDatum((int64) fst.st_size); values[1] = TimestampTzGetDatum(time_t_to_timestamptz(fst.st_atime)); values[2] = TimestampTzGetDatum(time_t_to_timestamptz(fst.st_mtime)); /* Unix has file status change time, while Win32 has creation time */ #if !defined(WIN32) && !defined(__CYGWIN__) values[3] = TimestampTzGetDatum(time_t_to_timestamptz(fst.st_ctime)); isnull[4] = true; #else isnull[3] = true; values[4] = TimestampTzGetDatum(time_t_to_timestamptz(fst.st_ctime)); #endif values[5] = BoolGetDatum(S_ISDIR(fst.st_mode)); tuple = heap_form_tuple(tupdesc, values, isnull); pfree(filename); PG_RETURN_DATUM(HeapTupleGetDatum(tuple)); }
int64 cdbRelSize(Relation rel) { int64 size = 0; int i; int resultCount = 0; struct pg_result **results = NULL; StringInfoData errbuf; StringInfoData buffer; char *schemaName; char *relName; if (last_cache_entry >= 0) { for (i=0; i < relsize_cache_size; i++) { if (relsize_cache[i].relOid == RelationGetRelid(rel)) return relsize_cache[i].size; } } /* * Let's ask the QEs for the size of the relation */ initStringInfo(&buffer); initStringInfo(&errbuf); schemaName = get_namespace_name(RelationGetNamespace(rel)); if (schemaName == NULL) elog(ERROR, "cache lookup failed for namespace %d", RelationGetNamespace(rel)); relName = RelationGetRelationName(rel); /* * Safer to pass names than oids, just in case they get out of sync between QD and QE, * which might happen with a toast table or index, I think (but maybe not) */ appendStringInfo(&buffer, "select pg_relation_size('%s.%s')", quote_identifier(schemaName), quote_identifier(relName)); /* * In the future, it would be better to send the command to only one QE for the optimizer's needs, * but for ALTER TABLE, we need to be sure if the table has any rows at all. */ results = cdbdisp_dispatchRMCommand(buffer.data, true, &errbuf, &resultCount); if (errbuf.len > 0) { ereport(WARNING, (errmsg("cdbRelSize error (gathered %d results from cmd '%s')", resultCount, buffer.data), errdetail("%s", errbuf.data))); pfree(errbuf.data); pfree(buffer.data); return -1; } else { for (i = 0; i < resultCount; i++) { if (PQresultStatus(results[i]) != PGRES_TUPLES_OK) { elog(ERROR,"cdbRelSize: resultStatus not tuples_Ok: %s %s",PQresStatus(PQresultStatus(results[i])),PQresultErrorMessage(results[i])); } else { /* * Due to funkyness in the current dispatch agent code, instead of 1 result * per QE with 1 row each, we can get back 1 result per dispatch agent, with * one row per QE controlled by that agent. */ int j; for (j = 0; j < PQntuples(results[i]); j++) { int64 tempsize = 0; (void) scanint8(PQgetvalue(results[i], j, 0), false, &tempsize); if (tempsize > size) size = tempsize; } } } pfree(errbuf.data); pfree(buffer.data); for (i = 0; i < resultCount; i++) PQclear(results[i]); free(results); } if (size >= 0) /* Cache the size even if it is zero, as table might be empty */ { if (last_cache_entry < 0) last_cache_entry = 0; relsize_cache[last_cache_entry].relOid = RelationGetRelid(rel); relsize_cache[last_cache_entry].size = size; last_cache_entry = (last_cache_entry+1) % relsize_cache_size; } return size; }
/* * _bt_gettrueroot() -- Get the true root page of the btree. * * This is the same as the BT_READ case of _bt_getroot(), except * we follow the true-root link not the fast-root link. * * By the time we acquire lock on the root page, it might have been split and * not be the true root anymore. This is okay for the present uses of this * routine; we only really need to be able to move up at least one tree level * from whatever non-root page we were at. If we ever do need to lock the * one true root page, we could loop here, re-reading the metapage on each * failure. (Note that it wouldn't do to hold the lock on the metapage while * moving to the root --- that'd deadlock against any concurrent root split.) */ Buffer _bt_gettrueroot(Relation rel) { Buffer metabuf; Page metapg; BTPageOpaque metaopaque; Buffer rootbuf; Page rootpage; BTPageOpaque rootopaque; BlockNumber rootblkno; uint32 rootlevel; BTMetaPageData *metad; /* * We don't try to use cached metapage data here, since (a) this path is * not performance-critical, and (b) if we are here it suggests our cache * is out-of-date anyway. In light of point (b), it's probably safest to * actively flush any cached metapage info. */ if (rel->rd_amcache) pfree(rel->rd_amcache); rel->rd_amcache = NULL; metabuf = _bt_getbuf(rel, BTREE_METAPAGE, BT_READ); metapg = BufferGetPage(metabuf); metaopaque = (BTPageOpaque) PageGetSpecialPointer(metapg); metad = BTPageGetMeta(metapg); if (!(metaopaque->btpo_flags & BTP_META) || metad->btm_magic != BTREE_MAGIC) ereport(ERROR, (errcode(ERRCODE_INDEX_CORRUPTED), errmsg("index \"%s\" is not a btree", RelationGetRelationName(rel)))); if (metad->btm_version != BTREE_VERSION) ereport(ERROR, (errcode(ERRCODE_INDEX_CORRUPTED), errmsg("version mismatch in index \"%s\": file version %d, code version %d", RelationGetRelationName(rel), metad->btm_version, BTREE_VERSION))); /* if no root page initialized yet, fail */ if (metad->btm_root == P_NONE) { _bt_relbuf(rel, metabuf); return InvalidBuffer; } rootblkno = metad->btm_root; rootlevel = metad->btm_level; /* * We are done with the metapage; arrange to release it via first * _bt_relandgetbuf call */ rootbuf = metabuf; for (;;) { rootbuf = _bt_relandgetbuf(rel, rootbuf, rootblkno, BT_READ); rootpage = BufferGetPage(rootbuf); rootopaque = (BTPageOpaque) PageGetSpecialPointer(rootpage); if (!P_IGNORE(rootopaque)) break; /* it's dead, Jim. step right one page */ if (P_RIGHTMOST(rootopaque)) elog(ERROR, "no live root page found in index \"%s\"", RelationGetRelationName(rel)); rootblkno = rootopaque->btpo_next; } /* Note: can't check btpo.level on deleted pages */ if (rootopaque->btpo.level != rootlevel) elog(ERROR, "root page %u of index \"%s\" has level %u, expected %u", rootblkno, RelationGetRelationName(rel), rootopaque->btpo.level, rootlevel); return rootbuf; }
Datum tkd_query(PG_FUNCTION_ARGS){ char *command; int i, j; int ret, curdm; // return value, current dimetion int call_cntr; int max_calls; int *retarr; FuncCallContext *funcctx; // context switch variable AttInMetadata *attinmeta; // not known------------------------ TupleDesc tupdesc; // tuple descriptor, for getting data D = 0; /* * this section will be executed only for the first call of function * connect to postgres server and execute the first command and get data */ if(SRF_IS_FIRSTCALL()){ MemoryContext oldcontext; /* * create a function context for cross-call persistence */ funcctx = SRF_FIRSTCALL_INIT(); /* * switch to memory context appropriate for multiple function calls * */ oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); /* * get arguments, convert given text object to a C string that can be used by server * */ command = text_to_cstring(PG_GETARG_TEXT_P(0)); /* * arguments error * */ if(!PG_ARGISNULL(1)) K = PG_GETARG_INT32(1); else K = 1; if(!PG_ARGISNULL(2)) dominating_type = PG_GETARG_INT32(2); else dominating_type = 0; SPI_connect(); // open internal connection to database ret = SPI_exec(command, 0); // run the SQL command, 0 for no limit of returned row number N = SPI_processed; // save the number of rows dataset = (Dataset *)palloc(sizeof(Dataset)*(N+2)); candidateset = (int *)palloc(sizeof(int)*(N+2)); if(dataset == NULL){ exit(1); } /* * some rows are fetched * */ if(ret > 0 && SPI_tuptable != NULL){ TupleDesc tupdesc; SPITupleTable *tuptable; HeapTuple tuple; char *type_name; /* * get tuple description * */ tupdesc = SPI_tuptable->tupdesc; tuptable = SPI_tuptable; /* * for each colum, check type * */ for(i = 1; i <= tupdesc->natts; ++i){ type_name = SPI_gettype(tupdesc, i);// get type of data if(strcmp(type_name,"int4") == 0 || strcmp(type_name,"int2") ==0 )//add float4 or flat8 types if want (2) ++D; } /* * for each tuple * and palloc all memory needed * */ kesai = (int *)palloc(sizeof(int)*(N+2)); lbound = (int *)palloc(sizeof(int)*(N+2)); ubound = (int *)palloc(sizeof(int)*(N+2)); //ari = (int *)palloc(sizeof(int)*(N+2)); goods = (int *)palloc(sizeof(int)*(N+2)); goodv = (int *)palloc(sizeof(int)*(N+2)); Q = (int *)palloc(sizeof(int)*(N+2)); P = (int *)palloc(sizeof(int)*(N+2)); nonD = (int *)palloc(sizeof(int)*(N+2)); whichbin = (int *)palloc(sizeof(int)*(N+2)); incomparable = (int *)palloc(sizeof(int)*(N+2)); tagT = (int *)palloc(sizeof(int)*(N+2)); Pi = (int **)palloc(sizeof(int *)*(N+2)); Qi = (int **)palloc(sizeof(int *)*(N+2)); for(i = 0; i < N; ++i){ Pi[i] = (int *)palloc(sizeof(int)*(N+2)); Qi[i] = (int *)palloc(sizeof(int)*(N+2)); } arr = (int **)palloc(sizeof(int)*(D+2)); score = (int *)palloc(sizeof(int)*(N+2)); queue = (int *)palloc(sizeof(int)*(N+2)); missd = (int *)palloc(sizeof(int)*(D+2)); maxscore = (int *)palloc(sizeof(int)*(N+2)); for(i = 0; i < N; ++i){ dataset[i].missing = (int *)palloc(sizeof(int)*(D+2)); dataset[i].value = (int *)palloc(sizeof(int)*(D+2)); dataset[i].T = (int *)palloc(sizeof(int)*(D+2)); if(dataset[i].missing == NULL || dataset[i].value == NULL || dataset[i].T == NULL){ exit(1); } curdm = 0; tuple = tuptable->vals[i]; // get the ith tuple /* * for each dimention of a tuple * */ for(j = 1; j <= tupdesc->natts; ++j) { type_name = SPI_gettype(tupdesc, j); if(strcmp(type_name,"int4") == 0 || strcmp(type_name,"int2") == 0 ){ if(SPI_getvalue(tuple, tupdesc, j) == NULL) { // value is missing dataset[i].missing[curdm] = 1; /*if(dominating_type == 0) dataset[i].value[curdm] = T1MISS; else dataset[i].value[curdm] = T2MISS;*/ } else{ // value is not missing dataset[i].missing[curdm] = 0; dataset[i].value[curdm] = atof(SPI_getvalue(tuple, tupdesc, j)); } ++curdm; } } } } pfree(command); tkd_exec(); // call to execute tkd query funcctx->max_calls = K; /* * allocate local variable retstruct and store the result tuple init * */ retarr = (int *)palloc(sizeof(int)*(K+2)); if(retarr == NULL){ exit(1); } for(i = 0; i < K; ++i ) retarr[i] = candidateset[i+1]; funcctx->user_fctx = retarr; if(get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("function returning record called in context that cannot accept type record"))); /* Generate attribute metadata needed later to produce tuples from raw C strings */ attinmeta = TupleDescGetAttInMetadata(tupdesc); funcctx->attinmeta = attinmeta; /* MemoryContext switch to old context */ MemoryContextSwitchTo(oldcontext); } funcctx = SRF_PERCALL_SETUP(); call_cntr = funcctx->call_cntr; max_calls = funcctx->max_calls; attinmeta = funcctx->attinmeta; retarr = funcctx->user_fctx; if(call_cntr < max_calls){ char **values; HeapTuple tuple; HeapTuple ret_tuple; Datum result; TupleDesc tupdesc; SPITupleTable *tuptable; tupdesc = SPI_tuptable->tupdesc; tuptable = SPI_tuptable; /* * Prepare a values array for building the returned tuple. * This should be an array of C strings which will * be processed later by the type input functions. */ values = (char **)palloc((tupdesc->natts+2) * sizeof(char *)); values = (char **)palloc((tupdesc->natts+2) * sizeof(char *)); if(values == NULL){ exit(1); } for(i = 0; i < tupdesc->natts; ++i ){ tuple = tuptable->vals[retarr[call_cntr]]; values[i] = (SPI_getvalue(tuple, tupdesc, i+1)); } ret_tuple = BuildTupleFromCStrings(attinmeta, values); // build a return tuple result = HeapTupleGetDatum(ret_tuple); // make the tuple into a datum SRF_RETURN_NEXT(funcctx,result); } else{ SPI_finish(); SRF_RETURN_DONE(funcctx); } }
/* * ExecutorEnd hook: log results if needed */ static void explain_ExecutorEnd(QueryDesc *queryDesc) { if (queryDesc->totaltime && auto_explain_enabled()) { double msec; /* * Make sure stats accumulation is done. (Note: it's okay if several * levels of hook all do this.) */ InstrEndLoop(queryDesc->totaltime); /* Log plan if duration is exceeded. */ msec = queryDesc->totaltime->total * 1000.0; if (msec >= auto_explain_log_min_duration) { ExplainState es; ExplainInitState(&es); es.analyze = (queryDesc->instrument_options && auto_explain_log_analyze); es.verbose = auto_explain_log_verbose; es.buffers = (es.analyze && auto_explain_log_buffers); es.timing = (es.analyze && auto_explain_log_timing); es.summary = es.analyze; es.format = auto_explain_log_format; ExplainBeginOutput(&es); ExplainQueryText(&es, queryDesc); ExplainPrintPlan(&es, queryDesc); if (es.analyze && auto_explain_log_triggers) ExplainPrintTriggers(&es, queryDesc); ExplainEndOutput(&es); /* Remove last line break */ if (es.str->len > 0 && es.str->data[es.str->len - 1] == '\n') es.str->data[--es.str->len] = '\0'; /* Fix JSON to output an object */ if (auto_explain_log_format == EXPLAIN_FORMAT_JSON) { es.str->data[0] = '{'; es.str->data[es.str->len - 1] = '}'; } /* * Note: we rely on the existing logging of context or * debug_query_string to identify just which statement is being * reported. This isn't ideal but trying to do it here would * often result in duplication. */ ereport(LOG, (errmsg("duration: %.3f ms plan:\n%s", msec, es.str->data), errhidestmt(true))); pfree(es.str->data); } } if (prev_ExecutorEnd) prev_ExecutorEnd(queryDesc); else standard_ExecutorEnd(queryDesc); }
/* * DynamicScan_InitNextPartition * Prepares the next partition for scanning by calling various * helper methods to open relation, map dropped attributes, * initialize expressions etc. */ static bool DynamicScan_InitNextPartition(ScanState *scanState, PartitionInitMethod *partitionInitMethod, PartitionEndMethod *partitionEndMethod, PartitionReScanMethod *partitionReScanMethod) { Assert(isDynamicScan((Scan *)scanState->ps.plan)); AssertImply(scanState->scan_state != SCAN_INIT, NULL != scanState->ss_currentRelation); Scan *scan = (Scan *)scanState->ps.plan; DynamicTableScanInfo *partitionInfo = scanState->ps.state->dynamicTableScanInfo; Assert(partitionInfo->numScans >= scan->partIndex); int32 numSelectors = list_nth_int(partitionInfo->numSelectorsPerScanId, scan->partIndex); Oid newOid = DynamicScan_AdvanceIterator(scanState, numSelectors); if (!OidIsValid(newOid)) { return false; } Relation oldRelation = NULL; Relation newRelation = NULL; DynamicScan_ObtainRelations(scanState, newOid, &oldRelation, &newRelation); /* Either we have a new relation or this is the first relation */ if (oldRelation != newRelation || NULL == scanState->ss_currentRelation) { AttrNumber *attMap = DynamicScan_MapRelationColumns(scanState, oldRelation, newRelation); DynamicScan_RemapExpression(scanState, attMap, (Node*)scanState->ps.plan->qual); DynamicScan_RemapExpression(scanState, attMap, (Node*)scanState->ps.plan->targetlist); /* * We only initialize expression if this is the first partition * or if the column mapping changes between two partitions. * Otherwise, we reuse the previously initialized expression. */ bool initExpressions = (NULL != attMap || SCAN_INIT == scanState->scan_state); if (newRelation != oldRelation) { /* Close the old relation */ DynamicScan_CleanupOneRelation(scanState, oldRelation, partitionEndMethod); } DynamicScan_UpdateScanStateForNewPart(scanState, newRelation); if (initExpressions) { DynamicScan_InitExpr(scanState); } partitionInitMethod(scanState, attMap); if (NULL != attMap) { pfree(attMap); attMap = NULL; } } else { /* Rescan of the same part */ partitionReScanMethod(scanState); } /* Collect number of partitions scanned in EXPLAIN ANALYZE */ if(NULL != scanState->ps.instrument) { Instrumentation *instr = scanState->ps.instrument; instr->numPartScanned ++; } return true; }
/* * sepgsql_relation_post_create * * The post creation hook of relation/attribute */ void sepgsql_relation_post_create(Oid relOid) { Relation rel; ScanKeyData skey; SysScanDesc sscan; HeapTuple tuple; Form_pg_class classForm; ObjectAddress object; uint16 tclass; char *scontext; /* subject */ char *tcontext; /* schema */ char *rcontext; /* relation */ char *ccontext; /* column */ /* * Fetch catalog record of the new relation. Because pg_class entry is * not visible right now, we need to scan the catalog using SnapshotSelf. */ rel = heap_open(RelationRelationId, AccessShareLock); ScanKeyInit(&skey, ObjectIdAttributeNumber, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(relOid)); sscan = systable_beginscan(rel, ClassOidIndexId, true, SnapshotSelf, 1, &skey); tuple = systable_getnext(sscan); if (!HeapTupleIsValid(tuple)) elog(ERROR, "catalog lookup failed for relation %u", relOid); classForm = (Form_pg_class) GETSTRUCT(tuple); if (classForm->relkind == RELKIND_RELATION) tclass = SEPG_CLASS_DB_TABLE; else if (classForm->relkind == RELKIND_SEQUENCE) tclass = SEPG_CLASS_DB_SEQUENCE; else if (classForm->relkind == RELKIND_VIEW) tclass = SEPG_CLASS_DB_VIEW; else goto out; /* No need to assign individual labels */ /* * Compute a default security label when we create a new relation * object under the specified namespace. */ scontext = sepgsql_get_client_label(); tcontext = sepgsql_get_label(NamespaceRelationId, classForm->relnamespace, 0); rcontext = sepgsql_compute_create(scontext, tcontext, tclass); /* * Assign the default security label on the new relation */ object.classId = RelationRelationId; object.objectId = relOid; object.objectSubId = 0; SetSecurityLabel(&object, SEPGSQL_LABEL_TAG, rcontext); /* * We also assigns a default security label on columns of the new * regular tables. */ if (classForm->relkind == RELKIND_RELATION) { AttrNumber index; ccontext = sepgsql_compute_create(scontext, rcontext, SEPG_CLASS_DB_COLUMN); for (index = FirstLowInvalidHeapAttributeNumber + 1; index <= classForm->relnatts; index++) { if (index == InvalidAttrNumber) continue; if (index == ObjectIdAttributeNumber && !classForm->relhasoids) continue; object.classId = RelationRelationId; object.objectId = relOid; object.objectSubId = index; SetSecurityLabel(&object, SEPGSQL_LABEL_TAG, ccontext); } pfree(ccontext); } pfree(rcontext); out: systable_endscan(sscan); heap_close(rel, AccessShareLock); }
static void thesaurusRead(char *filename, DictThesaurus *d) { tsearch_readline_state trst; uint16 idsubst = 0; bool useasis = false; char *line; filename = get_tsearch_config_filename(filename, "ths"); if (!tsearch_readline_begin(&trst, filename)) ereport(ERROR, (errcode(ERRCODE_CONFIG_FILE_ERROR), errmsg("could not open thesaurus file \"%s\": %m", filename))); while ((line = tsearch_readline(&trst)) != NULL) { char *ptr; int state = TR_WAITLEX; char *beginwrd = NULL; uint16 posinsubst = 0; uint16 nwrd = 0; ptr = line; /* is it a comment? */ while (*ptr && t_isspace(ptr)) ptr += pg_mblen(ptr); if (t_iseq(ptr, '#') || *ptr == '\0' || t_iseq(ptr, '\n') || t_iseq(ptr, '\r')) { pfree(line); continue; } while (*ptr) { if (state == TR_WAITLEX) { if (t_iseq(ptr, ':')) { if (posinsubst == 0) ereport(ERROR, (errcode(ERRCODE_CONFIG_FILE_ERROR), errmsg("unexpected delimiter"))); state = TR_WAITSUBS; } else if (!t_isspace(ptr)) { beginwrd = ptr; state = TR_INLEX; } } else if (state == TR_INLEX) { if (t_iseq(ptr, ':')) { newLexeme(d, beginwrd, ptr, idsubst, posinsubst++); state = TR_WAITSUBS; } else if (t_isspace(ptr)) { newLexeme(d, beginwrd, ptr, idsubst, posinsubst++); state = TR_WAITLEX; } } else if (state == TR_WAITSUBS) { if (t_iseq(ptr, '*')) { useasis = true; state = TR_INSUBS; beginwrd = ptr + pg_mblen(ptr); } else if (t_iseq(ptr, '\\')) { useasis = false; state = TR_INSUBS; beginwrd = ptr + pg_mblen(ptr); } else if (!t_isspace(ptr)) { useasis = false; beginwrd = ptr; state = TR_INSUBS; } } else if (state == TR_INSUBS) { if (t_isspace(ptr)) { if (ptr == beginwrd) ereport(ERROR, (errcode(ERRCODE_CONFIG_FILE_ERROR), errmsg("unexpected end of line or lexeme"))); addWrd(d, beginwrd, ptr, idsubst, nwrd++, posinsubst, useasis); state = TR_WAITSUBS; } } else elog(ERROR, "unrecognized thesaurus state: %d", state); ptr += pg_mblen(ptr); } if (state == TR_INSUBS) { if (ptr == beginwrd) ereport(ERROR, (errcode(ERRCODE_CONFIG_FILE_ERROR), errmsg("unexpected end of line or lexeme"))); addWrd(d, beginwrd, ptr, idsubst, nwrd++, posinsubst, useasis); } idsubst++; if (!(nwrd && posinsubst)) ereport(ERROR, (errcode(ERRCODE_CONFIG_FILE_ERROR), errmsg("unexpected end of line"))); pfree(line); } d->nsubst = idsubst; tsearch_readline_end(&trst); }
static Datum gp_aovisimap_internal(PG_FUNCTION_ARGS, Oid aoRelOid) { Datum values[3]; bool nulls[3]; HeapTuple tuple; Datum result; typedef struct Context { Relation aorel; AppendOnlyVisimapScan visiMapScan; AOTupleId aoTupleId; } Context; FuncCallContext *funcctx; Context *context; if (SRF_IS_FIRSTCALL()) { TupleDesc tupdesc; MemoryContext oldcontext; /* create a function context for cross-call persistence */ funcctx = SRF_FIRSTCALL_INIT(); /* * switch to memory context appropriate for multiple function * calls */ oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); /* build tupdesc for result tuples */ tupdesc = CreateTemplateTupleDesc(3, false); TupleDescInitEntry(tupdesc, (AttrNumber) 1, "tid", TIDOID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 2, "segno", INT4OID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 3, "row_num", INT8OID, -1, 0); funcctx->tuple_desc = BlessTupleDesc(tupdesc); /* * Collect all the locking information that we will format and send * out as a result set. */ context = (Context *) palloc0(sizeof(Context)); context->aorel = heap_open(aoRelOid, AccessShareLock); if (!(RelationIsAoRows(context->aorel) || RelationIsAoCols(context->aorel))) { ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("Function not supported on relation"))); } AppendOnlyVisimapScan_Init(&context->visiMapScan, context->aorel->rd_appendonly->visimaprelid, context->aorel->rd_appendonly->visimapidxid, AccessShareLock, SnapshotNow); AOTupleIdInit_Init(&context->aoTupleId); funcctx->user_fctx = (void *) context; MemoryContextSwitchTo(oldcontext); } funcctx = SRF_PERCALL_SETUP(); context = (Context *) funcctx->user_fctx; while (true) { if (!AppendOnlyVisimapScan_GetNextInvisible( &context->visiMapScan, &context->aoTupleId)) { break; } MemSet(values, 0, sizeof(values)); MemSet(nulls, false, sizeof(nulls)); values[0] = ItemPointerGetDatum((ItemPointer)&context->aoTupleId); values[1] = Int32GetDatum(AOTupleIdGet_segmentFileNum(&context->aoTupleId)); values[2] = Int64GetDatum(AOTupleIdGet_rowNum(&context->aoTupleId)); tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls); result = HeapTupleGetDatum(tuple); SRF_RETURN_NEXT(funcctx, result); } AppendOnlyVisimapScan_Finish(&context->visiMapScan, AccessShareLock); heap_close(context->aorel, AccessShareLock); pfree(context); funcctx->user_fctx = NULL; SRF_RETURN_DONE(funcctx); }
static void compileTheLexeme(DictThesaurus *d) { int i, nnw = 0, tnm = 16; TheLexeme *newwrds = (TheLexeme *) palloc(sizeof(TheLexeme) * tnm), *ptrwrds; for (i = 0; i < d->nwrds; i++) { TSLexeme *ptr; if (strcmp(d->wrds[i].lexeme, "?") == 0) /* Is stop word marker? */ newwrds = addCompiledLexeme(newwrds, &nnw, &tnm, NULL, d->wrds[i].entries, 0); else { ptr = (TSLexeme *) DatumGetPointer(FunctionCall4(&(d->subdict->lexize), PointerGetDatum(d->subdict->dictData), PointerGetDatum(d->wrds[i].lexeme), Int32GetDatum(strlen(d->wrds[i].lexeme)), PointerGetDatum(NULL))); if (!ptr) ereport(ERROR, (errcode(ERRCODE_CONFIG_FILE_ERROR), errmsg("thesaurus sample word \"%s\" isn't recognized by subdictionary (rule %d)", d->wrds[i].lexeme, d->wrds[i].entries->idsubst + 1))); else if (!(ptr->lexeme)) ereport(ERROR, (errcode(ERRCODE_CONFIG_FILE_ERROR), errmsg("thesaurus sample word \"%s\" is a stop word (rule %d)", d->wrds[i].lexeme, d->wrds[i].entries->idsubst + 1), errhint("Use \"?\" to represent a stop word within a sample phrase."))); else { while (ptr->lexeme) { TSLexeme *remptr = ptr + 1; int tnvar = 1; int curvar = ptr->nvariant; /* compute n words in one variant */ while (remptr->lexeme) { if (remptr->nvariant != (remptr - 1)->nvariant) break; tnvar++; remptr++; } remptr = ptr; while (remptr->lexeme && remptr->nvariant == curvar) { newwrds = addCompiledLexeme(newwrds, &nnw, &tnm, remptr, d->wrds[i].entries, tnvar); remptr++; } ptr = remptr; } } } pfree(d->wrds[i].lexeme); pfree(d->wrds[i].entries); } if (d->wrds) pfree(d->wrds); d->wrds = newwrds; d->nwrds = nnw; d->ntwrds = tnm; if (d->nwrds > 1) { qsort(d->wrds, d->nwrds, sizeof(TheLexeme), cmpTheLexeme); /* uniq */ newwrds = d->wrds; ptrwrds = d->wrds + 1; while (ptrwrds - d->wrds < d->nwrds) { if (cmpLexeme(ptrwrds, newwrds) == 0) { if (cmpLexemeInfo(ptrwrds->entries, newwrds->entries)) { ptrwrds->entries->nextentry = newwrds->entries; newwrds->entries = ptrwrds->entries; } else pfree(ptrwrds->entries); if (ptrwrds->lexeme) pfree(ptrwrds->lexeme); } else { newwrds++; *newwrds = *ptrwrds; } ptrwrds++; } d->nwrds = newwrds - d->wrds + 1; d->wrds = (TheLexeme *) repalloc(d->wrds, sizeof(TheLexeme) * d->nwrds); } }
/* * Attempt to negotiate SSL connection. */ static int open_server_SSL(Port *port) { int r; int err; Assert(!port->ssl); Assert(!port->peer); if (!(port->ssl = SSL_new(SSL_context))) { ereport(COMMERROR, (errcode(ERRCODE_PROTOCOL_VIOLATION), errmsg("could not initialize SSL connection: %s", SSLerrmessage()))); close_SSL(port); return -1; } if (!my_SSL_set_fd(port->ssl, port->sock)) { ereport(COMMERROR, (errcode(ERRCODE_PROTOCOL_VIOLATION), errmsg("could not set SSL socket: %s", SSLerrmessage()))); close_SSL(port); return -1; } aloop: r = SSL_accept(port->ssl); if (r <= 0) { err = SSL_get_error(port->ssl, r); switch (err) { case SSL_ERROR_WANT_READ: case SSL_ERROR_WANT_WRITE: #ifdef WIN32 pgwin32_waitforsinglesocket(SSL_get_fd(port->ssl), (err == SSL_ERROR_WANT_READ) ? FD_READ | FD_CLOSE | FD_ACCEPT : FD_WRITE | FD_CLOSE, INFINITE); #endif goto aloop; case SSL_ERROR_SYSCALL: if (r < 0) ereport(COMMERROR, (errcode_for_socket_access(), errmsg("could not accept SSL connection: %m"))); else ereport(COMMERROR, (errcode(ERRCODE_PROTOCOL_VIOLATION), errmsg("could not accept SSL connection: EOF detected"))); break; case SSL_ERROR_SSL: ereport(COMMERROR, (errcode(ERRCODE_PROTOCOL_VIOLATION), errmsg("could not accept SSL connection: %s", SSLerrmessage()))); break; case SSL_ERROR_ZERO_RETURN: ereport(COMMERROR, (errcode(ERRCODE_PROTOCOL_VIOLATION), errmsg("could not accept SSL connection: EOF detected"))); break; default: ereport(COMMERROR, (errcode(ERRCODE_PROTOCOL_VIOLATION), errmsg("unrecognized SSL error code: %d", err))); break; } close_SSL(port); return -1; } port->count = 0; /* Get client certificate, if available. */ port->peer = SSL_get_peer_certificate(port->ssl); /* and extract the Common Name from it. */ port->peer_cn = NULL; if (port->peer != NULL) { int len; len = X509_NAME_get_text_by_NID(X509_get_subject_name(port->peer), NID_commonName, NULL, 0); if (len != -1) { char *peer_cn; peer_cn = MemoryContextAlloc(TopMemoryContext, len + 1); r = X509_NAME_get_text_by_NID(X509_get_subject_name(port->peer), NID_commonName, peer_cn, len + 1); peer_cn[len] = '\0'; if (r != len) { /* shouldn't happen */ pfree(peer_cn); close_SSL(port); return -1; } /* * Reject embedded NULLs in certificate common name to prevent * attacks like CVE-2009-4034. */ if (len != strlen(peer_cn)) { ereport(COMMERROR, (errcode(ERRCODE_PROTOCOL_VIOLATION), errmsg("SSL certificate's common name contains embedded null"))); pfree(peer_cn); close_SSL(port); return -1; } port->peer_cn = peer_cn; } } ereport(DEBUG2, (errmsg("SSL connection from \"%s\"", port->peer_cn ? port->peer_cn : "(anonymous)"))); /* set up debugging/info callback */ SSL_CTX_set_info_callback(SSL_context, info_cb); return 0; }
/* * Given an invalid Fd in *dst, try to open a unix socket connection to the * given path. */ static void openSocket(int *dst, char *path) { const int save_errno = errno; struct sockaddr_un addr; bool formed; int fd = -1; StringInfoData startup; /* * This procedure is only defined on the domain of invalidated file * descriptors */ Assert(*dst < 0); /* Begin attempting connection, first by forming the address */ formed = formAddr(&addr, path); if (!formed) { /* Didn't work, give up */ goto err; } /* Get socket fd, or die */ fd = socket(AF_LOCAL, SOCK_STREAM, 0); if (fd < 0) goto err; /* Connect socket to server. Or die. */ Assert(formed); do { int res; errno = 0; res = connect(fd, (void *) &addr, sizeof addr); if (res < 0 || (errno != EINTR && errno != 0)) goto err; } while (errno == EINTR); /* * Connection established. * * Try to send start-up information as a service to the caller. Should * this fail, sendOrInval will close and invalidate the socket, though. */ Assert(fd >= 0); initStringInfo(&startup); /* Prepare startup: protocol version ('V') frame */ { const uint32_t nVlen = htobe32((sizeof PROTO_VERSION) + sizeof(u_int32_t)); appendStringInfoChar(&startup, 'V'); appendBinaryStringInfo(&startup, (void *) &nVlen, sizeof nVlen); appendBinaryStringInfo(&startup, PROTO_VERSION, sizeof PROTO_VERSION); } /* Prepare startup: system identification ('I') frame */ { char *payload; int payloadLen; uint32_t nPayloadLen; if (ident == NULL) payload = ""; else payload = ident; payloadLen = strlen(payload) + sizeof '\0'; nPayloadLen = htobe32(payloadLen + sizeof nPayloadLen); appendStringInfoChar(&startup, 'I'); appendBinaryStringInfo(&startup, (void *) &nPayloadLen, sizeof nPayloadLen); appendBinaryStringInfo(&startup, (void *) payload, payloadLen); } /* * Try to send the prepared startup packet, invaliding fd if things go * awry. */ sendOrInval(&fd, startup.data, startup.len); pfree(startup.data); *dst = fd; goto exit; err: /* Close and invalidate 'fd' if it got made */ if (fd >= 0) { closeSocket(&fd); Assert(fd < 0); } Assert(*dst < 0); goto exit; exit: /* Universal post-condition */ errno = save_errno; return; }