uint64 lookup_pkey(Oid heapRelOid, char *pkeyFieldname, ItemPointer ctid) { Relation heapRel; HeapTupleData tuple; Buffer buffer; Datum pkey; bool isnull; heapRel = RelationIdGetRelation(heapRelOid); tuple.t_self = *ctid; if (!heap_fetch(heapRel, SnapshotAny, &tuple, &buffer, false, NULL)) elog(ERROR, "Unable to fetch heap page from index"); pkey = heap_getattr(&tuple, get_attnum(heapRelOid, pkeyFieldname), RelationGetDescr(heapRel), &isnull); if (isnull) elog(ERROR, "detected NULL key value. Cannot update row"); ReleaseBuffer(buffer); RelationClose(heapRel); return DatumGetInt64(pkey); }
Datum partition_insert_trigger(PG_FUNCTION_ARGS) { TriggerData *trigdata = (TriggerData *) fcinfo->context; char *date_time; char child_table[sizeof(TABLE)+sizeof("2012_09_10")] = TABLE; int partition_field; Relation child_table_id; Oid child_table_oid; BulkInsertState bistate = GetBulkInsertState(); TupleTableSlot *slot; EState *estate = CreateExecutorState(); ResultRelInfo *resultRelInfo = makeNode(ResultRelInfo); List *recheckIndexes = NIL; /* make sure it's called as a trigger at all */ if (!CALLED_AS_TRIGGER(fcinfo)) elog(ERROR, "partition_insert_trigger: not called by trigger manager"); /* Sanity checks */ if (!TRIGGER_FIRED_BY_INSERT(trigdata->tg_event) || !TRIGGER_FIRED_BEFORE(trigdata->tg_event)) elog(ERROR, "partition_insert_trigger: not called on insert before"); #ifdef DEBUG elog(INFO, "Trigger Called for: %s", SPI_getrelname(trigdata->tg_relation)); #endif // Get the field number for the partition partition_field = SPI_fnumber(trigdata->tg_relation->rd_att, PARTITION_COLUMN); // Get the value for the partition_field date_time = SPI_getvalue(trigdata->tg_trigtuple, trigdata->tg_relation->rd_att, partition_field); //make sure date was specified if (!date_time) elog(ERROR, "You cannot insert data without specifying a value for the column %s", PARTITION_COLUMN); #ifdef DEBUG elog(INFO, "Trying to insert date_time=%s", date_time); #endif //add date_time, child_table_2012_01_23 strncpy(child_table + sizeof(TABLE) -1 , date_time, 4); //2012 child_table[sizeof(TABLE) + 3] = SEPARATOR; //2012_ strncpy(child_table + sizeof(TABLE) + 4 , date_time + 5, 2); //2012_01 child_table[sizeof(TABLE) + 6] = SEPARATOR; //2012_01_ strncpy(child_table + sizeof(TABLE) + 7 , date_time + 8, 2); //2012_01_23 #ifdef DEBUG elog(INFO, "New table will be %s", child_table); #endif pfree(date_time); //if you care about triggers on the child tables, call ExecBRInsertTriggers //don't care, continue //get the OID of the table we are looking for to insert child_table_oid = RelnameGetRelid(child_table); //Look for child child_table if (child_table_oid == InvalidOid){ elog(INFO, "partition_insert_trigger: Invalid child table %s, inserting data to main table %s", child_table, TABLE); return PointerGetDatum(trigdata->tg_trigtuple); } //get the descriptor of the table we are looking for child_table_id = RelationIdGetRelation(child_table_oid); //Get the child relation descriptor if (child_table_id == NULL){ elog(ERROR, "partition_insert_trigger: Failed to locate relation for child table %s, inserting data to main table %s", child_table, TABLE); return PointerGetDatum(trigdata->tg_trigtuple); } //set the resultRelInfo resultRelInfo->ri_RangeTableIndex = 1; /* dummy */ resultRelInfo->ri_RelationDesc = child_table_id; //setup the estate, not sure why estate->es_result_relations = resultRelInfo; estate->es_num_result_relations = 1; estate->es_result_relation_info = resultRelInfo; /* Set up a tuple slot not sure why yet */ slot = MakeSingleTupleTableSlot(trigdata->tg_relation->rd_att); ExecStoreTuple(trigdata->tg_trigtuple, slot, InvalidBuffer, false); //heap_insert(child_table_id, trigdata->tg_trigtuple, GetCurrentCommandId(true), use_wal, bistate); simple_heap_insert(child_table_id, trigdata->tg_trigtuple); if (resultRelInfo->ri_NumIndices > 0) recheckIndexes = ExecInsertIndexTuples(slot, &(trigdata->tg_trigtuple->t_self), estate); // not sure if this would work CatalogUpdateIndexes(child_table_id, trigdata->tg_trigtuple) //free the used memory list_free(recheckIndexes); ExecDropSingleTupleTableSlot(slot); //saw this somewhere :P RelationClose(child_table_id); //Must be called to free the relation memory page FreeBulkInsertState(bistate); // ? not sure if needed ? //If return next line will add to the regular table //return PointerGetDatum(trigdata->tg_trigtuple); //Return Null data, still have to figure out to return a proper X rows affected return PointerGetDatum(NULL); }
/* * gp_persistent_relation_node_check() * * Reads the physical filesystem for every defined filespace and returns the * list of relfilenodes that actually exist. This list should match the set of * relfilenodes tracked in gp_persistent_relation_node. */ Datum gp_persistent_relation_node_check(PG_FUNCTION_ARGS) { FuncCallContext *fcontext; node_check_data *fdata; ReturnSetInfo *rsinfo; MemoryContext oldcontext; Oid relfilenode = InvalidOid; int32 segnum = 0; HeapTuple tuple; char *primaryPath = NULL; char *mirrorPath = NULL; if (SRF_IS_FIRSTCALL()) { Relation rel; TupleDesc tupdesc; fcontext = SRF_FIRSTCALL_INIT(); rsinfo = (ReturnSetInfo *) fcinfo->resultinfo; /* * The fdata cannot be allocated in the multi_call_ctx because the * multi_call_context gets cleaned up by the MultiFuncCall callback * function which gets called before the callback this function * registers to cleanup the fdata structure. So instead we allocate * in the parent context fn_mcxt. */ oldcontext = MemoryContextSwitchTo(fcinfo->flinfo->fn_mcxt); fdata = (node_check_data*) palloc0(sizeof(node_check_data)); fcontext->user_fctx = fdata; /* * Register a call to cleanup when the function ends. */ RegisterExprContextCallback(rsinfo->econtext, nodeCheckCleanup, PointerGetDatum(fdata)); /* * Setup the main loop over the list of tablespaces */ fdata->tablespaceRelation = heap_open(TableSpaceRelationId, AccessShareLock); fdata->scandesc = heap_beginscan(fdata->tablespaceRelation, SnapshotNow, 0, NULL); /* * Bless a tuple descriptor for the return type */ MemoryContextSwitchTo(fcontext->multi_call_memory_ctx); rel = RelationIdGetRelation(GpPersistentRelationNodeRelationId); tupdesc = RelationGetDescr(rel); fcontext->tuple_desc = BlessTupleDesc(tupdesc); relation_close(rel, NoLock); MemoryContextSwitchTo(oldcontext); } fcontext = SRF_PERCALL_SETUP(); fdata = fcontext->user_fctx; /* * The code here is basically a nested loop that has been unwound so that * it can be wrapped up into a set-returning function. * * Basic structure is: * - Loop over tablespace relation * - Loop over database directories in the tablespace * - Loop over relfilenodes in the directory * - Return each tablespace, database, relfilenode, segment_number. * * The complicating factor is that we return from this function and * reenter the loop at the innermost level, so the entire loop is turned * inside-out. */ while (true) { /* Innermost loop */ if (fdata->databaseDir) { struct dirent *dent; Datum values[Natts_gp_persistent_relation_node]; bool nulls[Natts_gp_persistent_relation_node]; dent = ReadDir(fdata->databaseDir, fdata->databaseDirName); if (!dent) { /* step out of innermost loop */ FreeDir(fdata->databaseDir); fdata->databaseDir = NULL; continue; } /* skip the boring stuff */ if (strcmp(dent->d_name, ".") == 0 || strcmp(dent->d_name, "..") == 0) continue; /* Skip things that don't look like relfilenodes */ if (!strToRelfilenode(dent->d_name, &relfilenode, &segnum)) continue; /* Return relfilenodes as we find them */ MemSet(nulls, true, sizeof(nulls)); nulls[Anum_gp_persistent_relation_node_tablespace_oid-1] = false; nulls[Anum_gp_persistent_relation_node_database_oid-1] = false; nulls[Anum_gp_persistent_relation_node_relfilenode_oid-1] = false; nulls[Anum_gp_persistent_relation_node_segment_file_num-1] = false; values[Anum_gp_persistent_relation_node_tablespace_oid-1] = ObjectIdGetDatum(fdata->tablespaceOid); values[Anum_gp_persistent_relation_node_database_oid-1] = ObjectIdGetDatum(fdata->databaseOid); values[Anum_gp_persistent_relation_node_relfilenode_oid-1] = ObjectIdGetDatum(relfilenode); values[Anum_gp_persistent_relation_node_segment_file_num-1] = Int32GetDatum(segnum); tuple = heap_form_tuple(fcontext->tuple_desc, values, nulls); SRF_RETURN_NEXT(fcontext, HeapTupleGetDatum(tuple)); } /* Loop over database directories in the tablespace */ if (fdata->tablespaceDir) { struct dirent *dent; dent = ReadDir(fdata->tablespaceDir, fdata->tablespaceDirName); if (!dent) { /* step out of database loop */ FreeDir(fdata->tablespaceDir); fdata->tablespaceDir = NULL; continue; } /* skip the borring stuff */ if (strcmp(dent->d_name, ".") == 0 || strcmp(dent->d_name, "..") == 0) continue; /* Skip things that don't look like database oids */ if (strlen(dent->d_name) != strspn(dent->d_name, "0123456789")) continue; /* convert the string to an oid */ fdata->databaseOid = pg_atoi(dent->d_name, 4, 0); /* form a database path using this oid */ snprintf(fdata->databaseDirName, MAXPGPATH, "%s/%s", fdata->tablespaceDirName, dent->d_name); oldcontext = MemoryContextSwitchTo(fcontext->multi_call_memory_ctx); fdata->databaseDir = AllocateDir(fdata->databaseDirName); MemoryContextSwitchTo(oldcontext); if (fdata->databaseDir == NULL) ereport(ERROR, (errcode_for_file_access(), errmsg("could not open directory \"%s\": %m", fdata->databaseDirName))); continue; } /* Outermost loop over tablespaces */ tuple = heap_getnext(fdata->scandesc, ForwardScanDirection); if (!HeapTupleIsValid(tuple)) SRF_RETURN_DONE(fcontext); /* FINAL return */ fdata->tablespaceOid = HeapTupleGetOid(tuple); PersistentTablespace_GetPrimaryAndMirrorFilespaces( fdata->tablespaceOid, &primaryPath, &mirrorPath); /* Find the location of this tablespace on disk */ FormTablespacePath(fdata->tablespaceDirName, primaryPath, fdata->tablespaceOid); /* * Primary path is null for the pg_system filespace, additionally * Mirror path is null if there are no mirrors */ if (primaryPath) { pfree(primaryPath); primaryPath = NULL; } if (mirrorPath) { pfree(mirrorPath); mirrorPath = NULL; } oldcontext = MemoryContextSwitchTo(fcontext->multi_call_memory_ctx); fdata->tablespaceDir = AllocateDir(fdata->tablespaceDirName); MemoryContextSwitchTo(oldcontext); if (fdata->tablespaceDir == NULL) ereport(ERROR, (errcode_for_file_access(), errmsg("could not open directory \"%s\": %m", fdata->tablespaceDirName))); /* The global tablespace doesn't have database directories */ if (fdata->tablespaceOid == GLOBALTABLESPACE_OID) { fdata->databaseOid = 0; /* Skip to the innermost loop */ fdata->databaseDir = fdata->tablespaceDir; fdata->tablespaceDir = NULL; strncpy(fdata->databaseDirName, fdata->tablespaceDirName, MAXPGPATH); } } /* Unreachable */ SRF_RETURN_DONE(fcontext); }
static Datum caql_scan_in_memory_pg_class_private(PG_FUNCTION_ARGS, bool isForward) { text *inText = PG_GETARG_TEXT_P(0); char *inStr = text_to_cstring(inText);; FuncCallContext *funcctx; Datum result; MemoryContext oldcontext; TupleDesc tupdesc; HeapTuple restuple; //int count = 0; HeapTuple readtup = NULL; cqContext *pcqCtx; StringInfoData buf; initStringInfo(&buf); if (SRF_IS_FIRSTCALL()) { funcctx = SRF_FIRSTCALL_INIT(); /* switch context when allocating stuff to be used in later calls */ oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); tupdesc = CreateTemplateTupleDesc(NUM_COLS, false /*hasoid*/); TupleDescInitEntry(tupdesc, (AttrNumber) 1, "relname", TEXTOID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 2, "relkind", CHAROID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 3, "oid", OIDOID, -1, 0); funcctx->tuple_desc = BlessTupleDesc(tupdesc); /* create tuples for pg_class table */ pcqCtx = caql_beginscan( NULL, cql("SELECT * FROM pg_class " " WHERE relname = :1", CStringGetDatum((char *) inStr))); funcctx->user_fctx = pcqCtx; /* return to original context when allocating transient memory */ MemoryContextSwitchTo(oldcontext); } funcctx = SRF_PERCALL_SETUP(); pcqCtx = (cqContext *)funcctx->user_fctx; if (NULL != (readtup = getnext(pcqCtx, isForward))) { Datum values[NUM_COLS]; bool nulls[NUM_COLS]; Relation relation = RelationIdGetRelation(RelationRelationId); TupleDesc tupleDesc = RelationGetDescr(relation); char *nspname = DatumGetCString(tuple_getattr(readtup, tupleDesc, Anum_pg_class_relname)); text *t = cstring_to_text(nspname); values[0] = PointerGetDatum(t); nulls[0] = false; values[1] = CharGetDatum(tuple_getattr(readtup, tupleDesc, Anum_pg_class_relkind)); nulls[1] = false; values[2] = ObjectIdGetDatum(HeapTupleGetOid(readtup)); nulls[2] = false; /* build tuple */ restuple = heap_form_tuple(funcctx->tuple_desc, values, nulls); /* make the tuple into a datum */ result = HeapTupleGetDatum(restuple); elog(DEBUG1, "Reloid: %d", HeapTupleGetOid(readtup)); RelationClose(relation); SRF_RETURN_NEXT(funcctx, result); } else { caql_endscan(pcqCtx); SRF_RETURN_DONE(funcctx); } }