/* * worker_fetch_partition_file fetches a partition file from the remote node. * The function assumes an upstream compute task depends on this partition file, * and therefore directly fetches the file into the upstream task's directory. */ Datum worker_fetch_partition_file(PG_FUNCTION_ARGS) { uint64 jobId = PG_GETARG_INT64(0); uint32 partitionTaskId = PG_GETARG_UINT32(1); uint32 partitionFileId = PG_GETARG_UINT32(2); uint32 upstreamTaskId = PG_GETARG_UINT32(3); text *nodeNameText = PG_GETARG_TEXT_P(4); uint32 nodePort = PG_GETARG_UINT32(5); char *nodeName = NULL; /* remote filename is <jobId>/<partitionTaskId>/<partitionFileId> */ StringInfo remoteDirectoryName = TaskDirectoryName(jobId, partitionTaskId); StringInfo remoteFilename = PartitionFilename(remoteDirectoryName, partitionFileId); /* local filename is <jobId>/<upstreamTaskId>/<partitionTaskId> */ StringInfo taskDirectoryName = TaskDirectoryName(jobId, upstreamTaskId); StringInfo taskFilename = TaskFilename(taskDirectoryName, partitionTaskId); /* * If we are the first function to fetch a file for the upstream task, the * task directory does not exist. We then lock and create the directory. */ bool taskDirectoryExists = DirectoryExists(taskDirectoryName); if (!taskDirectoryExists) { InitTaskDirectory(jobId, upstreamTaskId); } nodeName = text_to_cstring(nodeNameText); FetchRegularFile(nodeName, nodePort, remoteFilename, taskFilename); PG_RETURN_VOID(); }
/* * shards_colocated checks if given two shards are co-located or not. If they are * co-located, this function returns true. */ Datum shards_colocated(PG_FUNCTION_ARGS) { uint32 leftShardId = PG_GETARG_UINT32(0); uint32 rightShardId = PG_GETARG_UINT32(1); ShardInterval *leftShard = LoadShardInterval(leftShardId); ShardInterval *rightShard = LoadShardInterval(rightShardId); bool shardsColocated = ShardsColocated(leftShard, rightShard); PG_RETURN_BOOL(shardsColocated); }
Datum uint48(PG_FUNCTION_ARGS) { uint32 arg = PG_GETARG_UINT32(0); PG_RETURN_UINT64((uint64) arg); }
/* Returns the task status of an already existing task. */ Datum task_tracker_task_status(PG_FUNCTION_ARGS) { uint64 jobId = PG_GETARG_INT64(0); uint32 taskId = PG_GETARG_UINT32(1); WorkerTask *workerTask = NULL; uint32 taskStatus = 0; bool taskTrackerRunning = TaskTrackerRunning(); if (taskTrackerRunning) { LWLockAcquire(&WorkerTasksSharedState->taskHashLock, LW_SHARED); workerTask = WorkerTasksHashFind(jobId, taskId); if (workerTask == NULL) { ereport(ERROR, (errmsg("could not find the worker task"), errdetail("Task jobId: " UINT64_FORMAT " and taskId: %u", jobId, taskId))); } taskStatus = (uint32) workerTask->taskStatus; LWLockRelease(&WorkerTasksSharedState->taskHashLock); } else { ereport(ERROR, (errcode(ERRCODE_CANNOT_CONNECT_NOW), errmsg("the task tracker has been disabled or shut down"))); } PG_RETURN_UINT32(taskStatus); }
/* * Initialize the state. */ Datum tsm_bernoulli_init(PG_FUNCTION_ARGS) { TableSampleDesc *tsdesc = (TableSampleDesc *) PG_GETARG_POINTER(0); uint32 seed = PG_GETARG_UINT32(1); float4 percent = PG_ARGISNULL(2) ? -1 : PG_GETARG_FLOAT4(2); HeapScanDesc scan = tsdesc->heapScan; BernoulliSamplerData *sampler; if (percent < 0 || percent > 100) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("invalid sample size"), errhint("Sample size must be numeric value between 0 and 100 (inclusive)."))); sampler = palloc0(sizeof(BernoulliSamplerData)); /* Remember initial values for reinit */ sampler->seed = seed; sampler->startblock = scan->rs_startblock; sampler->nblocks = scan->rs_nblocks; sampler->blockno = InvalidBlockNumber; sampler->probability = percent / 100; sampler->lt = InvalidOffsetNumber; sampler_random_init_state(sampler->seed, sampler->randstate); tsdesc->tsmdata = (void *) sampler; PG_RETURN_VOID(); }
/* * DML Functions */ Datum pr_set(PG_FUNCTION_ARGS) { text * key_arg = PG_GETARG_TEXT_P(0); text * value_arg = PG_GETARG_TEXT_P(1); int expire = PG_GETARG_UINT32(2); int ret; char * key = NULL; char * value = NULL; if (!pgredis || !pgredis->redis_server) { elog(ERROR, "Unable to set, redis instance missing"); PG_RETURN_FALSE; } key = DatumGetCString(DirectFunctionCall1(textout, PointerGetDatum(key_arg))); value = DatumGetCString(DirectFunctionCall1(textout, PointerGetDatum(value_arg))); if (!key || !value) { elog(ERROR, "Key/value incomplete in pgredis set"); PG_RETURN_FALSE; } ret = credis_set(pgredis->redis_server, key, value); if (ret == CREDIS_OK) { ret = credis_expire(pgredis->redis_server, key, expire); } PG_RETURN_BOOL(ret == CREDIS_OK); }
Datum uint8shr(PG_FUNCTION_ARGS) { uint64 arg1 = PG_GETARG_UINT64(0); uint32 arg2 = PG_GETARG_UINT32(1); PG_RETURN_UINT64(arg1 >> arg2); }
Datum uint48ge(PG_FUNCTION_ARGS) { uint32 val1 = PG_GETARG_UINT32(0); uint64 val2 = PG_GETARG_UINT64(1); PG_RETURN_BOOL(val1 >= val2); }
Datum uint84lt(PG_FUNCTION_ARGS) { uint64 val1 = PG_GETARG_UINT64(0); uint32 val2 = PG_GETARG_UINT32(1); PG_RETURN_BOOL(val1 < val2); }
/* * cms_topn_add_agg_with_parameters is a aggregate function to add items. It * allows to specify parameters of created CmsTopn structure. In addition to * cms_topn_add_agg function, it takes error bound and confidence interval * parameters as the forth and fifth parameters. */ Datum cms_topn_add_agg_with_parameters(PG_FUNCTION_ARGS) { CmsTopn *currentCmsTopn = NULL; CmsTopn *updatedCmsTopn = NULL; uint32 topnItemCount = PG_GETARG_UINT32(2); float8 errorBound = PG_GETARG_FLOAT8(3); float8 confidenceInterval = PG_GETARG_FLOAT8(4); Datum newItem = 0; TypeCacheEntry *newItemTypeCacheEntry = NULL; Oid newItemType = InvalidOid; if (!AggCheckCallContext(fcinfo, NULL)) { ereport(ERROR, (errcode(ERRCODE_DATA_EXCEPTION), errmsg("cms_topn_add_agg_with_parameters called in " "non-aggregate context"))); } /* check whether cms_topn is null and create if it is */ if (PG_ARGISNULL(0)) { currentCmsTopn = CreateCmsTopn(topnItemCount, errorBound, confidenceInterval); } else { currentCmsTopn = (CmsTopn *) PG_GETARG_VARLENA_P(0); } /* if new item is null, return current CmsTopn */ if (PG_ARGISNULL(1)) { PG_RETURN_POINTER(currentCmsTopn); } /* * Keep type cache entry between subsequent calls in order to get rid of * cache lookup overhead. */ newItem = PG_GETARG_DATUM(1); if (fcinfo->flinfo->fn_extra == NULL) { newItemType = get_fn_expr_argtype(fcinfo->flinfo, 1); newItemTypeCacheEntry = lookup_type_cache(newItemType, 0); fcinfo->flinfo->fn_extra = newItemTypeCacheEntry; } else { newItemTypeCacheEntry = fcinfo->flinfo->fn_extra; } updatedCmsTopn = UpdateCmsTopn(currentCmsTopn, newItem, newItemTypeCacheEntry); PG_RETURN_POINTER(updatedCmsTopn); }
Datum get_raw_page(PG_FUNCTION_ARGS) { text *relname = PG_GETARG_TEXT_P(0); uint32 blkno = PG_GETARG_UINT32(1); Relation rel; RangeVar *relrv; bytea *raw_page; char *raw_page_data; Buffer buf; if (!superuser()) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), (errmsg("must be superuser to use raw functions")))); relrv = makeRangeVarFromNameList(textToQualifiedNameList(relname)); rel = relation_openrv(relrv, AccessShareLock); /* Check that this relation has storage */ if (rel->rd_rel->relkind == RELKIND_VIEW) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("cannot get raw page from view \"%s\"", RelationGetRelationName(rel)))); if (rel->rd_rel->relkind == RELKIND_COMPOSITE_TYPE) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("cannot get raw page from composite type \"%s\"", RelationGetRelationName(rel)))); if (blkno >= RelationGetNumberOfBlocks(rel)) elog(ERROR, "block number %u is out of range for relation \"%s\"", blkno, RelationGetRelationName(rel)); /* Initialize buffer to copy to */ raw_page = (bytea *) palloc(BLCKSZ + VARHDRSZ); SET_VARSIZE(raw_page, BLCKSZ + VARHDRSZ); raw_page_data = VARDATA(raw_page); /* Take a verbatim copy of the page */ buf = ReadBuffer(rel, blkno); LockBuffer(buf, BUFFER_LOCK_SHARE); memcpy(raw_page_data, BufferGetPage(buf), BLCKSZ); LockBuffer(buf, BUFFER_LOCK_UNLOCK); ReleaseBuffer(buf); relation_close(rel, AccessShareLock); PG_RETURN_BYTEA_P(raw_page); }
/* * cms_topn is a user-facing UDF which creates new cms_topn with given parameters. * The first parameter is for the number of top items which will be kept, the others * are for error bound(e) and confidence interval(p) respectively. Given e and p, * estimated frequency can be at most (e*||a||) more than real frequency with the * probability p while ||a|| is the sum of frequencies of all items according to * this paper: http://dimacs.rutgers.edu/~graham/pubs/papers/cm-full.pdf. */ Datum cms_topn(PG_FUNCTION_ARGS) { int32 topnItemCount = PG_GETARG_UINT32(0); float8 errorBound = PG_GETARG_FLOAT8(1); float8 confidenceInterval = PG_GETARG_FLOAT8(2); CmsTopn *cmsTopn = CreateCmsTopn(topnItemCount, errorBound, confidenceInterval); PG_RETURN_POINTER(cmsTopn); }
Datum uint48mi(PG_FUNCTION_ARGS) { uint32 arg1 = PG_GETARG_UINT32(0); uint64 arg2 = PG_GETARG_UINT64(1); if (arg2 > arg1) report_out_of_range(); PG_RETURN_UINT64(arg1 - arg2); }
Datum uint48pl(PG_FUNCTION_ARGS) { uint32 arg1 = PG_GETARG_UINT32(0); uint64 arg2 = PG_GETARG_UINT64(1); if (arg2 > ULONG_LONG_MAX - arg1) report_out_of_range(); PG_RETURN_UINT64(arg1 + arg2); }
Datum uint84div(PG_FUNCTION_ARGS) { uint64 arg1 = PG_GETARG_UINT64(0); uint32 arg2 = PG_GETARG_UINT32(1); if (arg2 == 0) report_division_by_zero(); PG_RETURN_UINT64(arg1 / arg2); }
Datum uint48div(PG_FUNCTION_ARGS) { uint32 arg1 = PG_GETARG_UINT32(0); uint64 arg2 = PG_GETARG_UINT64(1); if (arg2 == 0) report_division_by_zero(); /* No overflow is possible */ PG_RETURN_UINT64((uint64) arg1 / arg2); }
Datum uint48mul(PG_FUNCTION_ARGS) { uint32 arg1 = PG_GETARG_UINT32(0); uint64 arg2 = PG_GETARG_UINT64(1); uint64 result; result = arg1 * arg2; if (arg2 != 0 && arg2 > UINT_MAX && result / arg2 != arg1) report_out_of_range(); PG_RETURN_UINT64(result); }
/* * SQL-callable wrapper to obtain commit time of a transaction */ Datum pg_xact_commit_timestamp(PG_FUNCTION_ARGS) { TransactionId xid = PG_GETARG_UINT32(0); TimestampTz ts; bool found; found = TransactionIdGetCommitTsData(xid, &ts, NULL); if (!found) PG_RETURN_NULL(); PG_RETURN_TIMESTAMPTZ(ts); }
Datum get_raw_page_fork(PG_FUNCTION_ARGS) { text *relname = PG_GETARG_TEXT_P(0); text *forkname = PG_GETARG_TEXT_P(1); uint32 blkno = PG_GETARG_UINT32(2); bytea *raw_page; ForkNumber forknum; forknum = forkname_to_number(text_to_cstring(forkname)); raw_page = get_raw_page_internal(relname, forknum, blkno); PG_RETURN_BYTEA_P(raw_page); }
/* * For given Transaction ID, check if transaction is committed or aborted */ Datum pgxc_is_committed(PG_FUNCTION_ARGS) { TransactionId tid = (TransactionId) PG_GETARG_UINT32(0); XidStatus xidstatus; xidstatus = TransactionLogFetch(tid); if (xidstatus == TRANSACTION_STATUS_COMMITTED) PG_RETURN_BOOL(true); else if (xidstatus == TRANSACTION_STATUS_ABORTED) PG_RETURN_BOOL(false); else PG_RETURN_NULL(); }
/* * worker_merge_files_into_table creates a task table within the job's schema, * which should have already been created by the task tracker protocol, and * copies files in its task directory into this table. If the schema doesn't * exist, the function defaults to the 'public' schema. Note that, unlike * partitioning functions, this function is not always idempotent. On success, * the function creates the table and loads data, and subsequent calls to the * function error out because the table already exist. On failure, the task * table creation commands are rolled back, and the function can be called * again. */ Datum worker_merge_files_into_table(PG_FUNCTION_ARGS) { uint64 jobId = PG_GETARG_INT64(0); uint32 taskId = PG_GETARG_UINT32(1); ArrayType *columnNameObject = PG_GETARG_ARRAYTYPE_P(2); ArrayType *columnTypeObject = PG_GETARG_ARRAYTYPE_P(3); StringInfo jobSchemaName = JobSchemaName(jobId); StringInfo taskTableName = TaskTableName(taskId); StringInfo taskDirectoryName = TaskDirectoryName(jobId, taskId); bool schemaExists = false; List *columnNameList = NIL; List *columnTypeList = NIL; /* we should have the same number of column names and types */ int32 columnNameCount = ArrayObjectCount(columnNameObject); int32 columnTypeCount = ArrayObjectCount(columnTypeObject); if (columnNameCount != columnTypeCount) { ereport(ERROR, (errmsg("column name array size: %d and type array size: %d" " do not match", columnNameCount, columnTypeCount))); } /* * If the schema for the job isn't already created by the task tracker * protocol, we fall to using the default 'public' schema. */ schemaExists = JobSchemaExists(jobSchemaName); if (!schemaExists) { resetStringInfo(jobSchemaName); appendStringInfoString(jobSchemaName, "public"); } /* create the task table and copy files into the table */ columnNameList = ArrayObjectToCStringList(columnNameObject); columnTypeList = ArrayObjectToCStringList(columnTypeObject); CreateTaskTable(jobSchemaName, taskTableName, columnNameList, columnTypeList); CopyTaskFilesFromDirectory(jobSchemaName, taskTableName, taskDirectoryName); PG_RETURN_VOID(); }
/* * pgmpc_set_volume * Set volume on server. */ Datum pgmpc_set_volume(PG_FUNCTION_ARGS) { unsigned int volume = PG_GETARG_UINT32(0); /* Check for incorrect values */ if (volume > 100) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("Volume value needs to be between 0 and 100"))); /* Run the command */ pgmpc_init(); if (!mpd_run_set_volume(mpd_conn, volume)) pgmpc_print_error(); pgmpc_reset(); PG_RETURN_VOID(); }
/* * Initializes the state. */ Datum tsm_system_time_init(PG_FUNCTION_ARGS) { TableSampleDesc *tsdesc = (TableSampleDesc *) PG_GETARG_POINTER(0); uint32 seed = PG_GETARG_UINT32(1); int32 time = PG_ARGISNULL(2) ? -1 : PG_GETARG_INT32(2); HeapScanDesc scan = tsdesc->heapScan; SystemSamplerData *sampler; if (time < 1) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("invalid time limit"), errhint("Time limit must be positive integer value."))); sampler = palloc0(sizeof(SystemSamplerData)); /* Remember initial values for reinit */ sampler->seed = seed; sampler->nblocks = scan->rs_nblocks; sampler->lt = InvalidOffsetNumber; sampler->estblocks = 2; sampler->doneblocks = 0; sampler->time = time; sampler->start_time = GetCurrentTimestamp(); sampler->end_time = TimestampTzPlusMilliseconds(sampler->start_time, sampler->time); sampler_random_init_state(sampler->seed, sampler->randstate); /* Find relative prime as step size for linear probing. */ sampler->step = random_relative_prime(sampler->nblocks, sampler->randstate); /* * Randomize start position so that blocks close to step size don't have * higher probability of being chosen on very short scan. */ sampler->lb = sampler_random_fract(sampler->randstate) * (sampler->nblocks / sampler->step); tsdesc->tsmdata = (void *) sampler; PG_RETURN_VOID(); }
Datum avalon_fp(PG_FUNCTION_ARGS) { CROMol mol; MolBitmapFingerPrint fp; BitmapFingerPrint *sfp; fcinfo->flinfo->fn_extra = SearchMolCache( fcinfo->flinfo->fn_extra, fcinfo->flinfo->fn_mcxt, PG_GETARG_DATUM(0), NULL, &mol, NULL); fp = makeAvalonBFP(mol, PG_GETARG_BOOL(1), /* isQuery */ PG_GETARG_UINT32(2) /* flags */ ); sfp = deconstructMolBitmapFingerPrint(fp); freeMolBitmapFingerPrint(fp); PG_RETURN_BITMAPFINGERPRINT_P(sfp); }
Datum get_raw_page(PG_FUNCTION_ARGS) { text *relname = PG_GETARG_TEXT_P(0); uint32 blkno = PG_GETARG_UINT32(1); bytea *raw_page; /* * We don't normally bother to check the number of arguments to a C * function, but here it's needed for safety because early 8.4 beta * releases mistakenly redefined get_raw_page() as taking three arguments. */ if (PG_NARGS() != 2) ereport(ERROR, (errmsg("wrong number of arguments to get_raw_page()"), errhint("Run the updated pageinspect.sql script."))); raw_page = get_raw_page_internal(relname, MAIN_FORKNUM, blkno); PG_RETURN_BYTEA_P(raw_page); }
Datum spoof_next_xid(PG_FUNCTION_ARGS) { TransactionId desiredXid = PG_GETARG_UINT32(0); TransactionId oldXid = ShmemVariableCache->nextXid; ShmemVariableCache->nextXid = desiredXid; /* * If we're raising the xid, the intent is presumably to cross some * threshold and make assertions about expected behavior. * On the other hand, lowering the xid is meant to be a tear down of * a completed test case. Because of this distinction, only when * we're raising the xid, do we take extra precaution to zero out * the new pg_clog/pg_subtrans/pg_distributedlog files. (We don't * want to zero out existing files...) */ if (TransactionIdFollows(desiredXid, oldXid)) { /* * The nature of xid arithmetic is such that we only bother zeroing out * new pages of transaction files when we've crossed page boundaries. * So, here we fool the following routines into zeroing out the desired * pages of transaction metadata by lowering the input xid to the first * of its corresponding page. */ #define CLOG_XACTS_PER_BYTE 4 #define CLOG_XACTS_PER_PAGE (BLCKSZ * CLOG_XACTS_PER_BYTE) #define TransactionIdToPgIndex(xid) ((xid) % (TransactionId) CLOG_XACTS_PER_PAGE) ExtendCLOG(desiredXid - TransactionIdToPgIndex(desiredXid)); #define SUBTRANS_XACTS_PER_PAGE (BLCKSZ / sizeof(SubTransData)) #define TransactionIdToEntry(xid) ((xid) % (uint32) SUBTRANS_XACTS_PER_PAGE) ExtendSUBTRANS(desiredXid - TransactionIdToEntry(desiredXid)); #undef TransactionIdToEntry #define ENTRIES_PER_PAGE (BLCKSZ / sizeof(DistributedLogEntry)) #define TransactionIdToEntry(localXid) ((localXid) % (TransactionId) ENTRIES_PER_PAGE) DistributedLog_Extend(desiredXid - TransactionIdToEntry(desiredXid)); } PG_RETURN_XID(oldXid); }
Datum chr (PG_FUNCTION_ARGS) { uint32 cvalue = PG_GETARG_UINT32(0); text *result; int encoding = GetDatabaseEncoding(); if (encoding == PG_UTF8 && cvalue > 127) { /* for Unicode we treat the argument as a code point */ int bytes; char *wch; /* We only allow valid Unicode code points */ if (cvalue > 0x001fffff) ereport(ERROR, (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), errmsg("requested character too large for encoding: %d", cvalue))); if (cvalue > 0xffff) bytes = 4; else if (cvalue > 0x07ff) bytes = 3; else bytes = 2; result = (text *) palloc(VARHDRSZ + bytes); SET_VARSIZE(result, VARHDRSZ + bytes); wch = VARDATA(result); if (bytes == 2) { wch[0] = 0xC0 | ((cvalue >> 6) & 0x1F); wch[1] = 0x80 | (cvalue & 0x3F);; }
Datum normal_rand(PG_FUNCTION_ARGS) { FuncCallContext *funcctx; int call_cntr; int max_calls; normal_rand_fctx *fctx; float8 mean; float8 stddev; float8 carry_val; bool use_carry; MemoryContext oldcontext; /* stuff done only on the first call of the function */ if (SRF_IS_FIRSTCALL()) { /* 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); /* total number of tuples to be returned */ funcctx->max_calls = PG_GETARG_UINT32(0); /* allocate memory for user context */ fctx = (normal_rand_fctx *) palloc(sizeof(normal_rand_fctx)); /* * Use fctx to keep track of upper and lower bounds from call to call. * It will also be used to carry over the spare value we get from the * Box-Muller algorithm so that we only actually calculate a new value * every other call. */ fctx->mean = PG_GETARG_FLOAT8(1); fctx->stddev = PG_GETARG_FLOAT8(2); fctx->carry_val = 0; fctx->use_carry = false; funcctx->user_fctx = fctx; MemoryContextSwitchTo(oldcontext); } /* stuff done on every call of the function */ funcctx = SRF_PERCALL_SETUP(); call_cntr = funcctx->call_cntr; max_calls = funcctx->max_calls; fctx = funcctx->user_fctx; mean = fctx->mean; stddev = fctx->stddev; carry_val = fctx->carry_val; use_carry = fctx->use_carry; if (call_cntr < max_calls) /* do when there is more left to send */ { float8 result; if (use_carry) { /* * reset use_carry and use second value obtained on last pass */ fctx->use_carry = false; result = carry_val; } else { float8 normval_1; float8 normval_2; /* Get the next two normal values */ get_normal_pair(&normval_1, &normval_2); /* use the first */ result = mean + (stddev * normval_1); /* and save the second */ fctx->carry_val = mean + (stddev * normval_2); fctx->use_carry = true; } /* send the result */ SRF_RETURN_NEXT(funcctx, Float8GetDatum(result)); } else /* do when there is no more left */ SRF_RETURN_DONE(funcctx); }
/* * task_tracker_assign_task creates a new task in the shared hash or updates an * already existing task. The function also creates a schema for the job if it * doesn't already exist. */ Datum task_tracker_assign_task(PG_FUNCTION_ARGS) { uint64 jobId = PG_GETARG_INT64(0); uint32 taskId = PG_GETARG_UINT32(1); text *taskCallStringText = PG_GETARG_TEXT_P(2); StringInfo jobSchemaName = JobSchemaName(jobId); bool schemaExists = false; WorkerTask *workerTask = NULL; char *taskCallString = text_to_cstring(taskCallStringText); uint32 taskCallStringLength = strlen(taskCallString); /* check that we have a running task tracker on this host */ bool taskTrackerRunning = TaskTrackerRunning(); if (!taskTrackerRunning) { ereport(ERROR, (errcode(ERRCODE_CANNOT_CONNECT_NOW), errmsg("the task tracker has been disabled or shut down"))); } /* check that we have enough space in our shared hash for this string */ if (taskCallStringLength >= TASK_CALL_STRING_SIZE) { ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("task call string exceeds maximum assignable length"))); } /* * If the schema does not exist, we create it. However, the schema does not * become visible to other processes until the transaction commits, and we * therefore do not release the resource lock in this case. Otherwise, the * schema is already visible, and we immediately release the resource lock. */ LockJobResource(jobId, AccessExclusiveLock); schemaExists = JobSchemaExists(jobSchemaName); if (!schemaExists) { /* lock gets automatically released upon return from this function */ CreateJobSchema(jobSchemaName); } else { UnlockJobResource(jobId, AccessExclusiveLock); } LWLockAcquire(&WorkerTasksSharedState->taskHashLock, LW_EXCLUSIVE); /* check if we already have the task in our shared hash */ workerTask = WorkerTasksHashFind(jobId, taskId); if (workerTask == NULL) { CreateTask(jobId, taskId, taskCallString); } else { UpdateTask(workerTask, taskCallString); } LWLockRelease(&WorkerTasksSharedState->taskHashLock); PG_RETURN_VOID(); }
/* * get_raw_page * * Returns a copy of a page from shared buffers as a bytea, with hole * filled with zeros or simply without hole, with the length of the page * offset to be able to reconstitute the page entirely using the data * returned by this function. */ Datum get_raw_page(PG_FUNCTION_ARGS) { Oid relid = PG_GETARG_OID(0); uint32 blkno = PG_GETARG_UINT32(1); bool with_hole = PG_GETARG_BOOL(2); bytea *raw_page; Relation rel; char raw_page_data[BLCKSZ]; Buffer buf; TupleDesc tupdesc; Datum result; Datum values[2]; bool nulls[2]; HeapTuple tuple; PageHeader page_header; int16 hole_offset, hole_length; if (!superuser()) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), (errmsg("must be superuser to use raw functions")))); rel = relation_open(relid, AccessShareLock); /* Check that this relation has storage */ if (rel->rd_rel->relkind == RELKIND_VIEW) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("cannot get raw page from view \"%s\"", RelationGetRelationName(rel)))); if (rel->rd_rel->relkind == RELKIND_COMPOSITE_TYPE) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("cannot get raw page from composite type \"%s\"", RelationGetRelationName(rel)))); if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("cannot get raw page from foreign table \"%s\"", RelationGetRelationName(rel)))); /* * Reject attempts to read non-local temporary relations; we would be * likely to get wrong data since we have no visibility into the owning * session's local buffers. */ if (RELATION_IS_OTHER_TEMP(rel)) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("cannot access temporary tables of other sessions"))); if (blkno >= RelationGetNumberOfBlocksInFork(rel, MAIN_FORKNUM)) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("block number %u is out of range for relation \"%s\"", blkno, RelationGetRelationName(rel)))); /* Build a tuple descriptor for our result type */ if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) elog(ERROR, "return type must be a row type"); /* Take a copy of the page to work on */ buf = ReadBufferExtended(rel, MAIN_FORKNUM, blkno, RBM_NORMAL, NULL); LockBuffer(buf, BUFFER_LOCK_SHARE); memcpy(raw_page_data, BufferGetPage(buf), BLCKSZ); LockBuffer(buf, BUFFER_LOCK_UNLOCK); ReleaseBuffer(buf); relation_close(rel, AccessShareLock); page_header = (PageHeader) raw_page_data; hole_length = page_header->pd_upper - page_header->pd_lower; hole_offset = page_header->pd_lower; /* * If hole is wanted in the page returned, fill it with zeros. * If not, copy to the return buffer the page without the hole. */ if (with_hole) { raw_page = (bytea *) palloc(BLCKSZ + VARHDRSZ); SET_VARSIZE(raw_page, BLCKSZ + VARHDRSZ); memcpy(VARDATA(raw_page), raw_page_data, BLCKSZ); MemSet(raw_page_data + hole_offset, 0, hole_length); } else { raw_page = (bytea *) palloc(BLCKSZ + VARHDRSZ - hole_length); SET_VARSIZE(raw_page, BLCKSZ + VARHDRSZ - hole_length); memcpy(VARDATA(raw_page), raw_page_data, hole_offset); memcpy(VARDATA(raw_page) + hole_offset, raw_page_data + hole_offset + hole_length, BLCKSZ - (hole_offset + hole_length)); } /* Build and return the tuple. */ values[0] = PointerGetDatum(raw_page); if (with_hole) values[1] = UInt16GetDatum(0); else values[1] = UInt16GetDatum(hole_offset); memset(nulls, 0, sizeof(nulls)); tuple = heap_form_tuple(tupdesc, values, nulls); result = HeapTupleGetDatum(tuple); PG_RETURN_DATUM(result); }