/* * int2out - converts short to "num" */ datum_t int2out(PG_FUNC_ARGS) { int16 arg1 = ARG_INT16(0); char *result = (char*) palloc(7); /* sign, 5 digits, '\0' */ pg_itoa(arg1, result); RET_CSTRING(result); }
/* * int2out - converts short to "num" */ Datum int2out(PG_FUNCTION_ARGS) { int16 arg1 = PG_GETARG_INT16(0); char *result = (char *) palloc(7); /* sign, 5 digits, '\0' */ pg_itoa(arg1, result); PG_RETURN_CSTRING(result); }
Datum int2_text(PG_FUNCTION_ARGS) { int16 arg1 = PG_GETARG_INT16(0); text *result = (text *) palloc(7 + VARHDRSZ); /* sign,5 digits, '\0' */ pg_itoa(arg1, VARDATA(result)); VARATT_SIZEP(result) = strlen(VARDATA(result)) + VARHDRSZ; PG_RETURN_TEXT_P(result); }
/* * int2vectorout - converts internal form to "num num ..." */ datum_t int2vectorout(PG_FUNC_ARGS) { int2_vector_s *int2Array = (int2_vector_s *) ARG_POINTER(0); int num, nnums = int2Array->dim1; char *rp; char *result; /* assumes sign, 5 digits, ' ' */ rp = result = (char *)palloc(nnums * 7 + 1); for (num = 0; num < nnums; num++) { if (num != 0) *rp++ = ' '; pg_itoa(int2Array->values[num], rp); while (*++rp != '\0') ; } *rp = '\0'; RET_CSTRING(result); }
/* * Create a set of logical tapes in a temporary underlying file. * * Each tape is initialized in write state. Serial callers pass ntapes, * NULL argument for shared, and -1 for worker. Parallel worker callers * pass ntapes, a shared file handle, NULL shared argument, and their own * worker number. Leader callers, which claim shared worker tapes here, * must supply non-sentinel values for all arguments except worker number, * which should be -1. * * Leader caller is passing back an array of metadata each worker captured * when LogicalTapeFreeze() was called for their final result tapes. Passed * tapes array is actually sized ntapes - 1, because it includes only * worker tapes, whereas leader requires its own leader tape. Note that we * rely on the assumption that reclaimed worker tapes will only be read * from once by leader, and never written to again (tapes are initialized * for writing, but that's only to be consistent). Leader may not write to * its own tape purely due to a restriction in the shared buffile * infrastructure that may be lifted in the future. */ LogicalTapeSet * LogicalTapeSetCreate(int ntapes, TapeShare *shared, SharedFileSet *fileset, int worker) { LogicalTapeSet *lts; LogicalTape *lt; int i; /* * Create top-level struct including per-tape LogicalTape structs. */ Assert(ntapes > 0); lts = (LogicalTapeSet *) palloc(offsetof(LogicalTapeSet, tapes) + ntapes * sizeof(LogicalTape)); lts->nBlocksAllocated = 0L; lts->nBlocksWritten = 0L; lts->nHoleBlocks = 0L; lts->forgetFreeSpace = false; lts->blocksSorted = true; /* a zero-length array is sorted ... */ lts->freeBlocksLen = 32; /* reasonable initial guess */ lts->freeBlocks = (long *) palloc(lts->freeBlocksLen * sizeof(long)); lts->nFreeBlocks = 0; lts->nTapes = ntapes; /* * Initialize per-tape structs. Note we allocate the I/O buffer and the * first block for a tape only when it is first actually written to. This * avoids wasting memory space when tuplesort.c overestimates the number * of tapes needed. */ for (i = 0; i < ntapes; i++) { lt = <s->tapes[i]; lt->writing = true; lt->frozen = false; lt->dirty = false; lt->firstBlockNumber = -1L; lt->curBlockNumber = -1L; lt->nextBlockNumber = -1L; lt->offsetBlockNumber = 0L; lt->buffer = NULL; lt->buffer_size = 0; /* palloc() larger than MaxAllocSize would fail */ lt->max_size = MaxAllocSize; lt->pos = 0; lt->nbytes = 0; } /* * Create temp BufFile storage as required. * * Leader concatenates worker tapes, which requires special adjustment to * final tapeset data. Things are simpler for the worker case and the * serial case, though. They are generally very similar -- workers use a * shared fileset, whereas serial sorts use a conventional serial BufFile. */ if (shared) ltsConcatWorkerTapes(lts, shared, fileset); else if (fileset) { char filename[MAXPGPATH]; pg_itoa(worker, filename); lts->pfile = BufFileCreateShared(fileset, filename); } else lts->pfile = BufFileCreateTemp(false); return lts; }
/* * Claim ownership of a set of logical tapes from existing shared BufFiles. * * Caller should be leader process. Though tapes are marked as frozen in * workers, they are not frozen when opened within leader, since unfrozen tapes * use a larger read buffer. (Frozen tapes have smaller read buffer, optimized * for random access.) */ static void ltsConcatWorkerTapes(LogicalTapeSet *lts, TapeShare *shared, SharedFileSet *fileset) { LogicalTape *lt = NULL; long tapeblocks = 0L; long nphysicalblocks = 0L; int i; /* Should have at least one worker tape, plus leader's tape */ Assert(lts->nTapes >= 2); /* * Build concatenated view of all BufFiles, remembering the block number * where each source file begins. No changes are needed for leader/last * tape. */ for (i = 0; i < lts->nTapes - 1; i++) { char filename[MAXPGPATH]; BufFile *file; int64 filesize; lt = <s->tapes[i]; pg_itoa(i, filename); file = BufFileOpenShared(fileset, filename); filesize = BufFileSize(file); /* * Stash first BufFile, and concatenate subsequent BufFiles to that. * Store block offset into each tape as we go. */ lt->firstBlockNumber = shared[i].firstblocknumber; if (i == 0) { lts->pfile = file; lt->offsetBlockNumber = 0L; } else { lt->offsetBlockNumber = BufFileAppend(lts->pfile, file); } /* Don't allocate more for read buffer than could possibly help */ lt->max_size = Min(MaxAllocSize, filesize); tapeblocks = filesize / BLCKSZ; nphysicalblocks += tapeblocks; } /* * Set # of allocated blocks, as well as # blocks written. Use extent of * new BufFile space (from 0 to end of last worker's tape space) for this. * Allocated/written blocks should include space used by holes left * between concatenated BufFiles. */ lts->nBlocksAllocated = lt->offsetBlockNumber + tapeblocks; lts->nBlocksWritten = lts->nBlocksAllocated; /* * Compute number of hole blocks so that we can later work backwards, and * instrument number of physical blocks. We don't simply use physical * blocks directly for instrumentation because this would break if we ever * subsequently wrote to the leader tape. * * Working backwards like this keeps our options open. If shared BufFiles * ever support being written to post-export, logtape.c can automatically * take advantage of that. We'd then support writing to the leader tape * while recycling space from worker tapes, because the leader tape has a * zero offset (write routines won't need to have extra logic to apply an * offset). * * The only thing that currently prevents writing to the leader tape from * working is the fact that BufFiles opened using BufFileOpenShared() are * read-only by definition, but that could be changed if it seemed * worthwhile. For now, writing to the leader tape will raise a "Bad file * descriptor" error, so tuplesort must avoid writing to the leader tape * altogether. */ lts->nHoleBlocks = lts->nBlocksAllocated - nphysicalblocks; }