diff --git a/src/backend/columnar/Makefile b/src/backend/columnar/Makefile new file mode 100644 index 000000000..9927ff38c --- /dev/null +++ b/src/backend/columnar/Makefile @@ -0,0 +1,35 @@ +MODULE_big = columnar +OBJS = mem_primitives_lib.o \ + memcpy_s.o \ + safe_str_constraint.o \ + safe_mem_constraint.o \ + ignore_handler_s.o \ + abort_handler_s.o \ + columnar.o \ + columnar_tableam.o \ + columnar_storage.o \ + columnar_compression.o \ + columnar_customscan.o \ + columnar_debug.o \ + columnar_metadata.o \ + columnar_reader.o \ + columnar_writer.o \ + mod.o \ + write_state_management.o + +safestringlib_srcdir = $(citus_abs_top_srcdir)/vendor/safestringlib +PG_CPPFLAGS += -I$(libpq_srcdir) -I$(safestringlib_srcdir)/include +EXTENSION = columnar + +DATA = $(wildcard sql/*--*.sql) +REGRESS = columnar + +ifdef USE_PGXS +PG_CONFIG = pg_config +PGXS := $(shell $(PG_CONFIG) --pgxs) +include $(PGXS) +else +subdir = src/backend/columnar +top_builddir = ../../.. +include $(top_builddir)/Makefile.global +endif diff --git a/src/backend/columnar/abort_handler_s.c b/src/backend/columnar/abort_handler_s.c new file mode 100644 index 000000000..d956bfdaa --- /dev/null +++ b/src/backend/columnar/abort_handler_s.c @@ -0,0 +1,74 @@ +/*------------------------------------------------------------------ + * abort_handler_s.c + * + * 2012, Jonathan Toppins + * + * Copyright (c) 2012 Cisco Systems + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + *------------------------------------------------------------------ + */ + +#include "safeclib_private.h" + +/** + * NAME + * abort_handler_s + * + * SYNOPSIS + * #include "safe_lib.h" + * void abort_handler_s(const char *msg, void *ptr, errno_t error) + * + * DESCRIPTION + * This function writes a message on the standard error stream in + * an implementation-defined format. The message shall include the + * string pointed to by msg. The abort_handler_s function then calls + * the abort function. + * + * SPECIFIED IN + * ISO/IEC JTC1 SC22 WG14 N1172, Programming languages, environments + * and system software interfaces, Extensions to the C Library, + * Part I: Bounds-checking interfaces + * + * INPUT PARAMETERS + * msg Pointer to the message describing the error + * + * ptr Pointer to aassociated data. Can be NULL. + * + * error The error code encountered. + * + * RETURN VALUE + * Does not return to caller. + * + * ALSO SEE + * ignore_handler_s() + * + */ + +void abort_handler_s(const char *msg, void *ptr, errno_t error) +{ + slprintf("ABORT CONSTRAINT HANDLER: (%u) %s\n", error, + (msg) ? msg : "Null message"); + slabort(); +} +EXPORT_SYMBOL(abort_handler_s) diff --git a/src/backend/columnar/columnar.c b/src/backend/columnar/columnar.c index 35a6f6da9..af0d4fe52 100644 --- a/src/backend/columnar/columnar.c +++ b/src/backend/columnar/columnar.c @@ -23,6 +23,8 @@ #include "citus_version.h" #include "columnar/columnar.h" +PG_MODULE_MAGIC; + /* Default values for option parameters */ #define DEFAULT_STRIPE_ROW_COUNT 150000 #define DEFAULT_CHUNK_ROW_COUNT 10000 diff --git a/src/backend/columnar/columnar.control b/src/backend/columnar/columnar.control new file mode 100644 index 000000000..1a24e6dd9 --- /dev/null +++ b/src/backend/columnar/columnar.control @@ -0,0 +1,6 @@ +# Columnar extension +comment = 'Columnar extension' +default_version = '11.0-1' +module_pathname = '$libdir/columnar' +relocatable = false +schema = pg_catalog diff --git a/src/backend/columnar/columnar_tableam.c b/src/backend/columnar/columnar_tableam.c index ff6e6cffc..17508b519 100644 --- a/src/backend/columnar/columnar_tableam.c +++ b/src/backend/columnar/columnar_tableam.c @@ -171,7 +171,7 @@ columnar_beginscan(Relation relation, Snapshot snapshot, ParallelTableScanDesc parallel_scan, uint32 flags) { - CheckCitusVersion(ERROR); + //CheckCitusVersion(ERROR); int natts = relation->rd_att->natts; @@ -418,7 +418,7 @@ columnar_parallelscan_reinitialize(Relation rel, ParallelTableScanDesc pscan) static IndexFetchTableData * columnar_index_fetch_begin(Relation rel) { - CheckCitusVersion(ERROR); + //CheckCitusVersion(ERROR); Oid relfilenode = rel->rd_node.relNode; if (PendingWritesInUpperTransactions(relfilenode, GetCurrentSubTransactionId())) @@ -643,7 +643,7 @@ static bool columnar_tuple_satisfies_snapshot(Relation rel, TupleTableSlot *slot, Snapshot snapshot) { - CheckCitusVersion(ERROR); + //CheckCitusVersion(ERROR); uint64 rowNumber = tid_to_row_number(slot->tts_tid); StripeMetadata *stripeMetadata = FindStripeByRowNumber(rel, rowNumber, snapshot); @@ -656,7 +656,7 @@ static TransactionId columnar_index_delete_tuples(Relation rel, TM_IndexDeleteOp *delstate) { - CheckCitusVersion(ERROR); + //CheckCitusVersion(ERROR); /* * XXX: We didn't bother implementing index_delete_tuple for neither of @@ -717,7 +717,7 @@ static void columnar_tuple_insert(Relation relation, TupleTableSlot *slot, CommandId cid, int options, BulkInsertState bistate) { - CheckCitusVersion(ERROR); + //CheckCitusVersion(ERROR); /* * columnar_init_write_state allocates the write state in a longer @@ -765,7 +765,7 @@ static void columnar_multi_insert(Relation relation, TupleTableSlot **slots, int ntuples, CommandId cid, int options, BulkInsertState bistate) { - CheckCitusVersion(ERROR); + //CheckCitusVersion(ERROR); ColumnarWriteState *writeState = columnar_init_write_state(relation, RelationGetDescr(relation), @@ -841,7 +841,7 @@ columnar_relation_set_new_filenode(Relation rel, TransactionId *freezeXid, MultiXactId *minmulti) { - CheckCitusVersion(ERROR); + //CheckCitusVersion(ERROR); if (persistence == RELPERSISTENCE_UNLOGGED) { @@ -878,7 +878,7 @@ columnar_relation_set_new_filenode(Relation rel, static void columnar_relation_nontransactional_truncate(Relation rel) { - CheckCitusVersion(ERROR); + //CheckCitusVersion(ERROR); RelFileNode relfilenode = rel->rd_node; @@ -926,7 +926,7 @@ columnar_relation_copy_for_cluster(Relation OldHeap, Relation NewHeap, double *tups_vacuumed, double *tups_recently_dead) { - CheckCitusVersion(ERROR); + //CheckCitusVersion(ERROR); TupleDesc sourceDesc = RelationGetDescr(OldHeap); TupleDesc targetDesc = RelationGetDescr(NewHeap); @@ -1024,14 +1024,14 @@ static void columnar_vacuum_rel(Relation rel, VacuumParams *params, BufferAccessStrategy bstrategy) { - if (!CheckCitusVersion(WARNING)) - { - /* - * Skip if the extension catalogs are not up-to-date, but avoid - * erroring during auto-vacuum. - */ - return; - } + // if (!CheckCitusVersion(WARNING)) + // { + // /* + // * Skip if the extension catalogs are not up-to-date, but avoid + // * erroring during auto-vacuum. + // */ + // return; + // } /* * If metapage version of relation is older, then we hint users to VACUUM @@ -1342,7 +1342,7 @@ columnar_index_build_range_scan(Relation columnarRelation, void *callback_state, TableScanDesc scan) { - CheckCitusVersion(ERROR); + //CheckCitusVersion(ERROR); if (start_blockno != 0 || numblocks != InvalidBlockNumber) { @@ -1592,7 +1592,7 @@ columnar_index_validate_scan(Relation columnarRelation, ValidateIndexState * validateIndexState) { - CheckCitusVersion(ERROR); +// CheckCitusVersion(ERROR); ColumnarReportTotalVirtualBlocks(columnarRelation, snapshot, PROGRESS_SCAN_BLOCKS_TOTAL); @@ -1764,7 +1764,7 @@ TupleSortSkipSmallerItemPointers(Tuplesortstate *tupleSort, ItemPointer targetIt static uint64 columnar_relation_size(Relation rel, ForkNumber forkNumber) { - CheckCitusVersion(ERROR); + //CheckCitusVersion(ERROR); uint64 nblocks = 0; @@ -1791,7 +1791,7 @@ columnar_relation_size(Relation rel, ForkNumber forkNumber) static bool columnar_relation_needs_toast_table(Relation rel) { - CheckCitusVersion(ERROR); + //CheckCitusVersion(ERROR); return false; } @@ -1802,7 +1802,7 @@ columnar_estimate_rel_size(Relation rel, int32 *attr_widths, BlockNumber *pages, double *tuples, double *allvisfrac) { - CheckCitusVersion(ERROR); + //CheckCitusVersion(ERROR); RelationOpenSmgr(rel); *pages = smgrnblocks(rel->rd_smgr, MAIN_FORKNUM); @@ -1975,7 +1975,7 @@ ColumnarTableDropHook(Oid relid) if (IsColumnarTableAmTable(relid)) { - CheckCitusVersion(ERROR); + //CheckCitusVersion(ERROR); /* * Drop metadata. No need to drop storage here since for @@ -2100,7 +2100,7 @@ ColumnarProcessUtility(PlannedStmt *pstmt, if (rel->rd_tableam == GetColumnarTableAmRoutine()) { - CheckCitusVersion(ERROR); + //CheckCitusVersion(ERROR); if (!ColumnarSupportsIndexAM(indexStmt->accessMethod)) { @@ -2323,7 +2323,7 @@ PG_FUNCTION_INFO_V1(alter_columnar_table_set); Datum alter_columnar_table_set(PG_FUNCTION_ARGS) { - CheckCitusVersion(ERROR); + //CheckCitusVersion(ERROR); Oid relationId = PG_GETARG_OID(0); @@ -2443,7 +2443,7 @@ PG_FUNCTION_INFO_V1(alter_columnar_table_reset); Datum alter_columnar_table_reset(PG_FUNCTION_ARGS) { - CheckCitusVersion(ERROR); + //CheckCitusVersion(ERROR); Oid relationId = PG_GETARG_OID(0); @@ -2507,6 +2507,21 @@ alter_columnar_table_reset(PG_FUNCTION_ARGS) PG_RETURN_VOID(); } +/* + * Check that the current user has owner rights to relationId, error out if + * not. Superusers are regarded as owners. + */ +void +EnsureTableOwner(Oid relationId) +{ + if (!pg_class_ownercheck(relationId, GetUserId())) + { + aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_TABLE, + get_rel_name(relationId)); + } +} + + /* * upgrade_columnar_storage - upgrade columnar storage to the current diff --git a/src/backend/columnar/ignore_handler_s.c b/src/backend/columnar/ignore_handler_s.c new file mode 100644 index 000000000..412e0cb71 --- /dev/null +++ b/src/backend/columnar/ignore_handler_s.c @@ -0,0 +1,72 @@ +/*------------------------------------------------------------------ + * ignore_handler_s.c + * + * 2012, Jonathan Toppins + * + * Copyright (c) 2012 Cisco Systems + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + *------------------------------------------------------------------ + */ + +#include "safeclib_private.h" + +/** + * NAME + * ignore_handler_s + * + * SYNOPSIS + * #include "safe_lib.h" + * void ignore_handler_s(const char *msg, void *ptr, errno_t error) + * + * DESCRIPTION + * This function simply returns to the caller. + * + * SPECIFIED IN + * ISO/IEC JTC1 SC22 WG14 N1172, Programming languages, environments + * and system software interfaces, Extensions to the C Library, + * Part I: Bounds-checking interfaces + * + * INPUT PARAMETERS + * msg Pointer to the message describing the error + * + * ptr Pointer to aassociated data. Can be NULL. + * + * error The error code encountered. + * + * RETURN VALUE + * Returns no value. + * + * ALSO SEE + * abort_handler_s() + * + */ + +void ignore_handler_s(const char *msg, void *ptr, errno_t error) +{ + + sldebug_printf("IGNORE CONSTRAINT HANDLER: (%u) %s\n", error, + (msg) ? msg : "Null message"); + return; +} +EXPORT_SYMBOL(ignore_handler_s) diff --git a/src/backend/columnar/mem_primitives_lib.c b/src/backend/columnar/mem_primitives_lib.c new file mode 100644 index 000000000..54b596d02 --- /dev/null +++ b/src/backend/columnar/mem_primitives_lib.c @@ -0,0 +1,855 @@ +/*------------------------------------------------------------------ + * mem_primitives_lib.c - Unguarded Memory Copy Routines + * + * February 2005, Bo Berry + * + * Copyright (c) 2005-2009 Cisco Systems + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + *------------------------------------------------------------------ + */ + +#include "mem_primitives_lib.h" + +#pragma GCC diagnostic ignored "-Wpragmas" +#pragma GCC diagnostic ignored "-Wimplicit-fallthrough" +/* + * mem_primitives_lib.c provides unguarded memory routines + * that are used by the safe_mem_library. These routines + * may also be used by an application, but the application + * is responsible for all parameter validation and alignment. + */ + +/** + * NAME + * mem_prim_set - Sets memory to value + * + * SYNOPSIS + * #include "mem_primitives_lib.h" + * void + * mem_prim_set(void *dest, uint32_t len, uint8_t value) + * + * DESCRIPTION + * Sets len bytes starting at dest to the specified value + * + * INPUT PARAMETERS + * dest - pointer to memory that will be set to value + * + * len - number of bytes to be set + * + * value - byte value + * + * OUTPUT PARAMETERS + * dest - is updated + * + * RETURN VALUE + * none + * + */ +void +mem_prim_set (void *dest, uint32_t len, uint8_t value) +{ + uint8_t *dp; + uint32_t count; + uint32_t lcount; + + uint32_t *lp; + uint32_t value32; + + count = len; + + dp = dest; + + value32 = value | (value << 8) | (value << 16) | (value << 24); + + /* + * First, do the few bytes to get uint32_t aligned. + */ + for (; count && ( (uintptr_t)dp & (sizeof(uint32_t)-1) ); count--) { + *dp++ = value; + } + + /* + * Then do the uint32_ts, unrolled the loop for performance + */ + lp = (uint32_t *)dp; + lcount = count >> 2; + + while (lcount != 0) { + + switch (lcount) { + /* + * Here we do blocks of 8. Once the remaining count + * drops below 8, take the fast track to finish up. + */ + default: + *lp++ = value32; *lp++ = value32; *lp++ = value32; *lp++ = value32; + *lp++ = value32; *lp++ = value32; *lp++ = value32; *lp++ = value32; + *lp++ = value32; *lp++ = value32; *lp++ = value32; *lp++ = value32; + *lp++ = value32; *lp++ = value32; *lp++ = value32; *lp++ = value32; + lcount -= 16; + break; + + case 15: *lp++ = value32; + case 14: *lp++ = value32; + case 13: *lp++ = value32; + case 12: *lp++ = value32; + case 11: *lp++ = value32; + case 10: *lp++ = value32; + case 9: *lp++ = value32; + case 8: *lp++ = value32; + + case 7: *lp++ = value32; + case 6: *lp++ = value32; + case 5: *lp++ = value32; + case 4: *lp++ = value32; + case 3: *lp++ = value32; + case 2: *lp++ = value32; + case 1: *lp++ = value32; + lcount = 0; + break; + } + } /* end while */ + + + dp = (uint8_t *)lp; + + /* + * compute the number of remaining bytes + */ + count &= (sizeof(uint32_t)-1); + + /* + * remaining bytes + */ + for (; count; dp++, count--) { + *dp = value; + } + + return; +} + + +/** + * NAME + * mem_prim_set16 - Sets memory to value + * + * SYNOPSIS + * #include "mem_primitives_lib.h" + * void + * mem_prim_set16(uint16_t *dp, uint32_t len, uint16_t value) + * + * DESCRIPTION + * Sets len uint16_ts starting at dest to the specified value. + * Pointers must meet system alignment requirements. + * + * INPUT PARAMETERS + * dest - pointer to memory that will be set to value + * + * len - number of uint16_ts to be set + * + * value - uint16_t value + * + * OUTPUT PARAMETERS + * dest - is updated + * + * RETURN VALUE + * none + * + */ +void +mem_prim_set16 (uint16_t *dp, uint32_t len, uint16_t value) +{ + + while (len != 0) { + + switch (len) { + /* + * Here we do blocks of 8. Once the remaining count + * drops below 8, take the fast track to finish up. + */ + default: + *dp++ = value; *dp++ = value; *dp++ = value; *dp++ = value; + *dp++ = value; *dp++ = value; *dp++ = value; *dp++ = value; + *dp++ = value; *dp++ = value; *dp++ = value; *dp++ = value; + *dp++ = value; *dp++ = value; *dp++ = value; *dp++ = value; + len -= 16; + break; + + case 15: *dp++ = value; + case 14: *dp++ = value; + case 13: *dp++ = value; + case 12: *dp++ = value; + case 11: *dp++ = value; + case 10: *dp++ = value; + case 9: *dp++ = value; + case 8: *dp++ = value; + + case 7: *dp++ = value; + case 6: *dp++ = value; + case 5: *dp++ = value; + case 4: *dp++ = value; + case 3: *dp++ = value; + case 2: *dp++ = value; + case 1: *dp++ = value; + len = 0; + break; + } + } /* end while */ + + return; +} + + +/** + * NAME + * mem_prim_set32 - Sets memory to the uint32_t value + * + * SYNOPSIS + * #include "mem_primitives_lib.h" + * void + * mem_prim_set32(uint32_t *dp, uint32_t len, uint32_t value) + * + * DESCRIPTION + * Sets len uint32_ts starting at dest to the specified value + * Pointers must meet system alignment requirements. + * + * INPUT PARAMETERS + * dest - pointer to memory that will be set to value + * + * len - number of uint32_ts to be set + * + * value - uint32_t value + * + * OUTPUT PARAMETERS + * dest - is updated + * + * RETURN VALUE + * none + * + */ +void +mem_prim_set32 (uint32_t *dp, uint32_t len, uint32_t value) +{ + + while (len != 0) { + + switch (len) { + /* + * Here we do blocks of 8. Once the remaining count + * drops below 8, take the fast track to finish up. + */ + default: + *dp++ = value; *dp++ = value; *dp++ = value; *dp++ = value; + *dp++ = value; *dp++ = value; *dp++ = value; *dp++ = value; + *dp++ = value; *dp++ = value; *dp++ = value; *dp++ = value; + *dp++ = value; *dp++ = value; *dp++ = value; *dp++ = value; + len -= 16; + break; + + case 15: *dp++ = value; + case 14: *dp++ = value; + case 13: *dp++ = value; + case 12: *dp++ = value; + case 11: *dp++ = value; + case 10: *dp++ = value; + case 9: *dp++ = value; + case 8: *dp++ = value; + + case 7: *dp++ = value; + case 6: *dp++ = value; + case 5: *dp++ = value; + case 4: *dp++ = value; + case 3: *dp++ = value; + case 2: *dp++ = value; + case 1: *dp++ = value; + len = 0; + break; + } + } /* end while */ + + return; +} + + +/** + * NAME + * mem_prim_move - Move (handles overlap) memory + * + * SYNOPSIS + * #include "mem_primitives_lib.h" + * void + * mem_prim_move(void *dest, const void *src, uint32_t len) + * + * DESCRIPTION + * Moves at most slen bytes from src to dest, up to dmax + * bytes. Dest may overlap with src. + * + * INPUT PARAMETERS + * dest - pointer to the memory that will be replaced by src. + * + * src - pointer to the memory that will be copied + * to dest + * + * len - maximum number bytes of src that can be copied + * + * OUTPUT PARAMETERS + * dest - is updated + * + * RETURN VALUE + * none + * + */ +void +mem_prim_move (void *dest, const void *src, uint32_t len) +{ + +#define wsize sizeof(uint32_t) +#define wmask (wsize - 1) + + uint8_t *dp = dest; + const uint8_t *sp = src; + + uint32_t tsp; + + /* + * Determine if we need to copy forward or backward (overlap) + */ + if ((uintptr_t)dp < (uintptr_t)sp) { + /* + * Copy forward. + */ + + /* + * get a working copy of src for bit operations + */ + tsp = (uintptr_t)sp; + + /* + * Try to align both operands. This cannot be done + * unless the low bits match. + */ + if ((tsp | (uintptr_t)dp) & wmask) { + /* + * determine how many bytes to copy to align operands + */ + if ((tsp ^ (uintptr_t)dp) & wmask || len < wsize) { + tsp = len; + + } else { + tsp = wsize - (tsp & wmask); + } + + len -= tsp; + + /* + * make the alignment + */ + do { + *dp++ = *sp++; + } while (--tsp); + } + + /* + * Now copy, then mop up any trailing bytes. + */ + tsp = len / wsize; + + if (tsp > 0) { + + do { + *(uint32_t *)dp = *(uint32_t *)sp; + + sp += wsize; + dp += wsize; + } while (--tsp); + } + + /* + * copy over the remaining bytes and we're done + */ + tsp = len & wmask; + + if (tsp > 0) { + do { + *dp++ = *sp++; + } while (--tsp); + } + + } else { + /* + * This section is used to copy backwards, to handle any + * overlap. The alignment requires (tps&wmask) bytes to + * align. + */ + + /* + * go to end of the memory to copy + */ + sp += len; + dp += len; + + /* + * get a working copy of src for bit operations + */ + tsp = (uintptr_t)sp; + + /* + * Try to align both operands. + */ + if ((tsp | (uintptr_t)dp) & wmask) { + + if ((tsp ^ (uintptr_t)dp) & wmask || len <= wsize) { + tsp = len; + } else { + tsp &= wmask; + } + + len -= tsp; + + /* + * make the alignment + */ + do { + *--dp = *--sp; + } while (--tsp); + } + + /* + * Now copy in uint32_t units, then mop up any trailing bytes. + */ + tsp = len / wsize; + + if (tsp > 0) { + do { + sp -= wsize; + dp -= wsize; + + *(uint32_t *)dp = *(uint32_t *)sp; + } while (--tsp); + } + + /* + * copy over the remaining bytes and we're done + */ + tsp = len & wmask; + if (tsp > 0) { + tsp = len & wmask; + do { + *--dp = *--sp; + } while (--tsp); + } + } + + return; +} + + +/** + * NAME + * mem_prim_move8 - Move (handles overlap) memory + * + * SYNOPSIS + * #include "mem_primitives_lib.h" + * void + * mem_prim_move8(void *dest, const void *src, uint32_t len) + * + * DESCRIPTION + * Moves at most len uint8_ts from sp to dp. + * The destination may overlap with source. + * + * INPUT PARAMETERS + * dp - pointer to the memory that will be replaced by sp. + * + * sp - pointer to the memory that will be copied + * to dp + * + * len - maximum number uint8_t of sp that can be copied + * + * OUTPUT PARAMETERS + * dp - pointer to the memory that will be replaced by sp. + * + * RETURN VALUE + * none + * + */ +void +mem_prim_move8 (uint8_t *dp, const uint8_t *sp, uint32_t len) +{ + + /* + * Determine if we need to copy forward or backward (overlap) + */ + if (dp < sp) { + /* + * Copy forward. + */ + + while (len != 0) { + + switch (len) { + /* + * Here we do blocks of 8. Once the remaining count + * drops below 8, take the fast track to finish up. + */ + default: + *dp++ = *sp++; *dp++ = *sp++; *dp++ = *sp++; *dp++ = *sp++; + *dp++ = *sp++; *dp++ = *sp++; *dp++ = *sp++; *dp++ = *sp++; + *dp++ = *sp++; *dp++ = *sp++; *dp++ = *sp++; *dp++ = *sp++; + *dp++ = *sp++; *dp++ = *sp++; *dp++ = *sp++; *dp++ = *sp++; + len -= 16; + break; + + case 15: *dp++ = *sp++; + case 14: *dp++ = *sp++; + case 13: *dp++ = *sp++; + case 12: *dp++ = *sp++; + case 11: *dp++ = *sp++; + case 10: *dp++ = *sp++; + case 9: *dp++ = *sp++; + case 8: *dp++ = *sp++; + + case 7: *dp++ = *sp++; + case 6: *dp++ = *sp++; + case 5: *dp++ = *sp++; + case 4: *dp++ = *sp++; + case 3: *dp++ = *sp++; + case 2: *dp++ = *sp++; + case 1: *dp++ = *sp++; + len = 0; + break; + } + } /* end while */ + + } else { + /* + * This section is used to copy backwards, to handle any + * overlap. The alignment requires (tps&wmask) bytes to + * align. + */ + + + /* + * go to end of the memory to copy + */ + sp += len; + dp += len; + + while (len != 0) { + + switch (len) { + /* + * Here we do blocks of 8. Once the remaining count + * drops below 8, take the fast track to finish up. + */ + default: + *--dp = *--sp; *--dp = *--sp; *--dp = *--sp; *--dp = *--sp; + *--dp = *--sp; *--dp = *--sp; *--dp = *--sp; *--dp = *--sp; + *--dp = *--sp; *--dp = *--sp; *--dp = *--sp; *--dp = *--sp; + *--dp = *--sp; *--dp = *--sp; *--dp = *--sp; *--dp = *--sp; + len -= 16; + break; + + case 15: *--dp = *--sp; + case 14: *--dp = *--sp; + case 13: *--dp = *--sp; + case 12: *--dp = *--sp; + case 11: *--dp = *--sp; + case 10: *--dp = *--sp; + case 9: *--dp = *--sp; + case 8: *--dp = *--sp; + + case 7: *--dp = *--sp; + case 6: *--dp = *--sp; + case 5: *--dp = *--sp; + case 4: *--dp = *--sp; + case 3: *--dp = *--sp; + case 2: *--dp = *--sp; + case 1: *--dp = *--sp; + len = 0; + break; + } + } /* end while */ + } + + return; +} + + +/** + * NAME + * mem_prim_move16 - Move (handles overlap) memory + * + * SYNOPSIS + * #include "mem_primitives_lib.h" + * void + * mem_prim_move16(void *dest, const void *src, uint32_t len) + * + * DESCRIPTION + * Moves at most len uint16_ts from sp to dp. + * The destination may overlap with source. + * + * INPUT PARAMETERS + * dp - pointer to the memory that will be replaced by sp. + * + * sp - pointer to the memory that will be copied + * to dp + * + * len - maximum number uint16_t of sp that can be copied + * + * OUTPUT PARAMETERS + * dp - is updated + * + * RETURN VALUE + * none + * + */ +void +mem_prim_move16 (uint16_t *dp, const uint16_t *sp, uint32_t len) +{ + + /* + * Determine if we need to copy forward or backward (overlap) + */ + if (dp < sp) { + /* + * Copy forward. + */ + + while (len != 0) { + + switch (len) { + /* + * Here we do blocks of 8. Once the remaining count + * drops below 8, take the fast track to finish up. + */ + default: + *dp++ = *sp++; *dp++ = *sp++; *dp++ = *sp++; *dp++ = *sp++; + *dp++ = *sp++; *dp++ = *sp++; *dp++ = *sp++; *dp++ = *sp++; + *dp++ = *sp++; *dp++ = *sp++; *dp++ = *sp++; *dp++ = *sp++; + *dp++ = *sp++; *dp++ = *sp++; *dp++ = *sp++; *dp++ = *sp++; + len -= 16; + break; + + case 15: *dp++ = *sp++; + case 14: *dp++ = *sp++; + case 13: *dp++ = *sp++; + case 12: *dp++ = *sp++; + case 11: *dp++ = *sp++; + case 10: *dp++ = *sp++; + case 9: *dp++ = *sp++; + case 8: *dp++ = *sp++; + + case 7: *dp++ = *sp++; + case 6: *dp++ = *sp++; + case 5: *dp++ = *sp++; + case 4: *dp++ = *sp++; + case 3: *dp++ = *sp++; + case 2: *dp++ = *sp++; + case 1: *dp++ = *sp++; + len = 0; + break; + } + } /* end while */ + + } else { + /* + * This section is used to copy backwards, to handle any + * overlap. The alignment requires (tps&wmask) bytes to + * align. + */ + + /* + * go to end of the memory to copy + */ + sp += len; + dp += len; + + while (len != 0) { + + switch (len) { + /* + * Here we do blocks of 8. Once the remaining count + * drops below 8, take the fast track to finish up. + */ + default: + *--dp = *--sp; *--dp = *--sp; *--dp = *--sp; *--dp = *--sp; + *--dp = *--sp; *--dp = *--sp; *--dp = *--sp; *--dp = *--sp; + *--dp = *--sp; *--dp = *--sp; *--dp = *--sp; *--dp = *--sp; + *--dp = *--sp; *--dp = *--sp; *--dp = *--sp; *--dp = *--sp; + len -= 16; + break; + + case 15: *--dp = *--sp; + case 14: *--dp = *--sp; + case 13: *--dp = *--sp; + case 12: *--dp = *--sp; + case 11: *--dp = *--sp; + case 10: *--dp = *--sp; + case 9: *--dp = *--sp; + case 8: *--dp = *--sp; + + case 7: *--dp = *--sp; + case 6: *--dp = *--sp; + case 5: *--dp = *--sp; + case 4: *--dp = *--sp; + case 3: *--dp = *--sp; + case 2: *--dp = *--sp; + case 1: *--dp = *--sp; + len = 0; + break; + } + } /* end while */ + } + + return; +} + + +/** + * NAME + * mem_prim_move32 - Move (handles overlap) memory + * + * SYNOPSIS + * #include "mem_primitives_lib.h" + * void + * mem_prim_move32(void *dest, const void *src, uint32_t len) + * + * DESCRIPTION + * Moves at most len uint32_ts from sp to dp. + * The destination may overlap with source. + * + * INPUT PARAMETERS + * dp - pointer to the memory that will be replaced by sp. + * + * sp - pointer to the memory that will be copied + * to dp + * + * len - maximum number uint32_t of sp that can be copied + * + * OUTPUT PARAMETERS + * dp - is updated + * + * RETURN VALUE + * none + * + */ +void +mem_prim_move32 (uint32_t *dp, const uint32_t *sp, uint32_t len) +{ + + /* + * Determine if we need to copy forward or backward (overlap) + */ + if (dp < sp) { + /* + * Copy forward. + */ + + while (len != 0) { + + switch (len) { + /* + * Here we do blocks of 8. Once the remaining count + * drops below 8, take the fast track to finish up. + */ + default: + *dp++ = *sp++; *dp++ = *sp++; *dp++ = *sp++; *dp++ = *sp++; + *dp++ = *sp++; *dp++ = *sp++; *dp++ = *sp++; *dp++ = *sp++; + *dp++ = *sp++; *dp++ = *sp++; *dp++ = *sp++; *dp++ = *sp++; + *dp++ = *sp++; *dp++ = *sp++; *dp++ = *sp++; *dp++ = *sp++; + len -= 16; + break; + + case 15: *dp++ = *sp++; + case 14: *dp++ = *sp++; + case 13: *dp++ = *sp++; + case 12: *dp++ = *sp++; + case 11: *dp++ = *sp++; + case 10: *dp++ = *sp++; + case 9: *dp++ = *sp++; + case 8: *dp++ = *sp++; + + case 7: *dp++ = *sp++; + case 6: *dp++ = *sp++; + case 5: *dp++ = *sp++; + case 4: *dp++ = *sp++; + case 3: *dp++ = *sp++; + case 2: *dp++ = *sp++; + case 1: *dp++ = *sp++; + len = 0; + break; + } + } /* end while */ + + } else { + /* + * This section is used to copy backwards, to handle any + * overlap. + */ + + /* + * go to end of the memory to copy + */ + sp += len; + dp += len; + + while (len != 0) { + + switch (len) { + /* + * Here we do blocks of 8. Once the remaining count + * drops below 8, take the fast track to finish up. + */ + default: + *--dp = *--sp; *--dp = *--sp; *--dp = *--sp; *--dp = *--sp; + *--dp = *--sp; *--dp = *--sp; *--dp = *--sp; *--dp = *--sp; + *--dp = *--sp; *--dp = *--sp; *--dp = *--sp; *--dp = *--sp; + *--dp = *--sp; *--dp = *--sp; *--dp = *--sp; *--dp = *--sp; + len -= 16; + break; + + case 15: *--dp = *--sp; + case 14: *--dp = *--sp; + case 13: *--dp = *--sp; + case 12: *--dp = *--sp; + case 11: *--dp = *--sp; + case 10: *--dp = *--sp; + case 9: *--dp = *--sp; + case 8: *--dp = *--sp; + + case 7: *--dp = *--sp; + case 6: *--dp = *--sp; + case 5: *--dp = *--sp; + case 4: *--dp = *--sp; + case 3: *--dp = *--sp; + case 2: *--dp = *--sp; + case 1: *--dp = *--sp; + len = 0; + break; + } + } /* end while */ + } + + return; +} diff --git a/src/backend/columnar/mem_primitives_lib.h b/src/backend/columnar/mem_primitives_lib.h new file mode 100644 index 000000000..26c83d858 --- /dev/null +++ b/src/backend/columnar/mem_primitives_lib.h @@ -0,0 +1,74 @@ +/*------------------------------------------------------------------ + * mem_primitives_lib.h - Unguarded Memory Copy Routines + * + * October 2008, Bo Berry + * + * Copyright (c) 2008-2011 by Cisco Systems, Inc + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + *------------------------------------------------------------------ + */ + +#ifndef __MEM_PRIMITIVES_LIB_H__ +#define __MEM_PRIMITIVES_LIB_H__ + +#include "safeclib_private.h" + +/* + * These are prototypes for _unguarded_ memory routines. The caller must + * validate all parameters prior to invocation. Useful for diagnostics + * and system initialization processing. + */ + +/* moves (handles overlap) memory */ +extern void +mem_prim_move(void *dest, const void *src, uint32_t length); + + +/* uint8_t moves (handles overlap) memory */ +extern void +mem_prim_move8(uint8_t *dest, const uint8_t *src, uint32_t length); + +/* uint16_t moves (handles overlap) memory */ +extern void +mem_prim_move16(uint16_t *dest, const uint16_t *src, uint32_t length); + +/* uint32_t moves (handles overlap) memory */ +extern void +mem_prim_move32(uint32_t *dest, const uint32_t *src, uint32_t length); + + +/* set bytes */ +extern void +mem_prim_set(void *dest, uint32_t dmax, uint8_t value); + +/* set uint16_ts */ +extern void +mem_prim_set16(uint16_t *dest, uint32_t dmax, uint16_t value); + +/* set uint32_ts */ +extern void +mem_prim_set32(uint32_t *dest, uint32_t dmax, uint32_t value); + + +#endif /* __MEM_PRIMITIVES_LIB_H__ */ diff --git a/src/backend/columnar/memcpy_s.c b/src/backend/columnar/memcpy_s.c new file mode 100644 index 000000000..a5c77b7c6 --- /dev/null +++ b/src/backend/columnar/memcpy_s.c @@ -0,0 +1,163 @@ +/*------------------------------------------------------------------ + * memcpy_s + * + * October 2008, Bo Berry + * + * Copyright (c) 2008-2011 Cisco Systems + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + *------------------------------------------------------------------ + */ + +#include "safeclib_private.h" +#include "safe_mem_constraint.h" +#include "mem_primitives_lib.h" +#include "safe_mem_lib.h" + + +/** + * NAME + * memcpy_s + * + * SYNOPSIS + * #include "safe_mem_lib.h" + * errno_t + * memcpy_s(void *dest, rsize_t dmax, const void *src, rsize_t smax) + * + * DESCRIPTION + * This function copies at most smax bytes from src to dest, up to + * dmax. The size values are unsigned values. + * + * AR: Dave - verify ISO spec requires unsigned + * + * SPECIFIED IN + * ISO/IEC JTC1 SC22 WG14 N1172, Programming languages, environments + * and system software interfaces, Extensions to the C Library, + * Part I: Bounds-checking interfaces + * + * INPUT PARAMETERS + * dest pointer to memory that will be replaced by src. + * + * dmax maximum length of the resulting dest + * + * src pointer to the memory that will be copied to dest + * + * smax maximum number bytes of src to copy + * + * OUTPUT PARAMETERS + * dest is updated + * + * RUNTIME CONSTRAINTS + * Neither dest nor src shall be a null pointer. + * Neither dmax nor smax shall be zero. + * dmax shall not be greater than RSIZE_MAX_MEM. + * smax shall not be greater than dmax. + * Copying shall not take place between regions that overlap. + * If there is a runtime-constraint violation, the memcpy_s function + * stores zeros in the first dmax bytes of the region pointed to + * by dest if dest is not a null pointer and smax is valid. + * + * RETURN VALUE + * EOK successful operation + * ESNULLP NULL pointer + * ESZEROL zero length + * ESLEMAX length exceeds max limit + * ESOVRLP source memory overlaps destination + * + * ALSO SEE + * memcpy16_s(), memcpy32_s(), memmove_s(), memmove16_s(), + * memmove32_s() + * + */ +errno_t +memcpy_s (void *dest, rsize_t dmax, const void *src, rsize_t smax) +{ + uint8_t *dp; + const uint8_t *sp; + + dp = dest; + sp = src; + + if (dp == NULL) { + invoke_safe_mem_constraint_handler("memcpy_s: dest is NULL", + NULL, ESNULLP); + return RCNEGATE(ESNULLP); + } + + if (dmax == 0) { + invoke_safe_mem_constraint_handler("memcpy_s: dmax is 0", + NULL, ESZEROL); + return RCNEGATE(ESZEROL); + } + + if (dmax > RSIZE_MAX_MEM) { + invoke_safe_mem_constraint_handler("memcpy_s: dmax exceeds max", + NULL, ESLEMAX); + return RCNEGATE(ESLEMAX); + } + + // AR: This is not a requirement according to the ISO spec - Change? + // AR: documentation needed on use of the error handlers - + // AR: default err handler should output to stderr on DEBUG + // AR: update docs to define return RCNEGATE of the error number + if (smax == 0) { + mem_prim_set(dp, dmax, 0); + invoke_safe_mem_constraint_handler("memcpy_s: smax is 0", + NULL, ESZEROL); + return RCNEGATE(ESZEROL); + } + + if (smax > dmax) { + mem_prim_set(dp, dmax, 0); + invoke_safe_mem_constraint_handler("memcpy_s: smax exceeds dmax", + NULL, ESLEMAX); + return RCNEGATE(ESLEMAX); + } + + if (sp == NULL) { + mem_prim_set(dp, dmax, 0); + invoke_safe_mem_constraint_handler("memcpy_s: src is NULL", + NULL, ESNULLP); + return RCNEGATE(ESNULLP); + } + + + /* + * overlap is undefined behavior, do not allow + */ + if( ((dp > sp) && (dp < (sp+smax))) || + ((sp > dp) && (sp < (dp+dmax))) ) { + mem_prim_set(dp, dmax, 0); + invoke_safe_mem_constraint_handler("memcpy_s: overlap undefined", + NULL, ESOVRLP); + return RCNEGATE(ESOVRLP); + } + + /* + * now perform the copy + */ + mem_prim_move(dp, sp, smax); + + return RCNEGATE(EOK); +} +EXPORT_SYMBOL(memcpy_s) diff --git a/src/backend/columnar/mod.c b/src/backend/columnar/mod.c index 8908ad618..9f58e9943 100644 --- a/src/backend/columnar/mod.c +++ b/src/backend/columnar/mod.c @@ -22,16 +22,20 @@ #include "columnar/columnar_tableam.h" +void _PG_init(void); +void _PG_fini(void); + +//columnar_init void -columnar_init(void) +_PG_init(void) { columnar_init_gucs(); columnar_tableam_init(); } - +//columnar_fini void -columnar_fini(void) +_PG_fini(void) { columnar_tableam_finish(); } diff --git a/src/backend/columnar/safe_mem_constraint.c b/src/backend/columnar/safe_mem_constraint.c new file mode 100644 index 000000000..9fafe9e89 --- /dev/null +++ b/src/backend/columnar/safe_mem_constraint.c @@ -0,0 +1,142 @@ +/*------------------------------------------------------------------ + * safe_mem_constraint.c + * + * October 2008, Bo Berry + * 2012, Jonathan Toppins + * + * Copyright (c) 2008-2012 Cisco Systems + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + *------------------------------------------------------------------ + */ + +#include "safeclib_private.h" +#include "safe_mem_constraint.h" +#include "safe_mem_lib.h" + + +static constraint_handler_t mem_handler = NULL; + + +/** + * NAME + * set_mem_constraint_handler_s + * + * SYNOPSIS + * #include "safe_mem_lib.h" + * constraint_handler_t + * set_mem_constraint_handler_straint_handler_t handler) + * + * DESCRIPTION + * The set_mem_constraint_handler_s function sets the runtime-constraint + * handler to be handler. The runtime-constraint handler is the function to + * be called when a library function detects a runtime-constraint + * order: + * 1. A pointer to a character string describing the + * runtime-constraint violation. + * 2. A null pointer or a pointer to an implementation defined + * object. + * 3. If the function calling the handler has a return type declared + * as errno_t, the return value of the function is passed. + * Otherwise, a positive value of type errno_t is passed. + * The implementation has a default constraint handler that is used if no + * calls to the set_constraint_handler_s function have been made. The + * behavior of the default handler is implementation-defined, and it may + * cause the program to exit or abort. If the handler argument to + * set_constraint_handler_s is a null pointer, the implementation default + * handler becomes the current constraint handler. + * + * SPECIFIED IN + * ISO/IEC JTC1 SC22 WG14 N1172, Programming languages, environments + * and system software interfaces, Extensions to the C Library, + * Part I: Bounds-checking interfaces + * + * INPUT PARAMETERS + * *msg Pointer to the message describing the error + * + * *ptr Pointer to aassociated data. Can be NULL. + * + * error The error code encountered. + * + * OUTPUT PARAMETERS + * none + * + * RETURN VALUE + * none + * + * ALSO SEE + * set_str_constraint_handler_s() + */ +constraint_handler_t +set_mem_constraint_handler_s (constraint_handler_t handler) +{ + constraint_handler_t prev_handler = mem_handler; + if (NULL == handler) { + mem_handler = sl_default_handler; + } else { + mem_handler = handler; + } + return prev_handler; +} +EXPORT_SYMBOL(set_mem_constraint_handler_s) + + +/** + * NAME + * invoke_safe_mem_constraint_handler + * + * SYNOPSIS + * #include "safe_mem_constraint.h" + * void + * invoke_safe_mem_constraint_handler(const char *msg, + * void *ptr, + * errno_t error) + * + * DESCRIPTION + * Invokes the currently set constraint handler or the default. + * + * INPUT PARAMETERS + * *msg Pointer to the message describing the error + * + * *ptr Pointer to aassociated data. Can be NULL. + * + * error The error code encountered. + * + * OUTPUT PARAMETERS + * none + * + * RETURN VALUE + * none + * + */ +void +invoke_safe_mem_constraint_handler (const char *msg, + void *ptr, + errno_t error) +{ + if (NULL != mem_handler) { + mem_handler(msg, ptr, error); + } else { + sl_default_handler(msg, ptr, error); + } +} diff --git a/src/backend/columnar/safe_mem_constraint.h b/src/backend/columnar/safe_mem_constraint.h new file mode 100644 index 000000000..7ec898e1f --- /dev/null +++ b/src/backend/columnar/safe_mem_constraint.h @@ -0,0 +1,46 @@ +/*------------------------------------------------------------------ + * safe_mem_constraint.h + * + * October 2008, Bo Berry + * + * Copyright (c) 2008, 2009 by Cisco Systems, Inc. + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + *------------------------------------------------------------------ + */ + +#ifndef __SAFE_MEM_CONSTRAINT_H__ +#define __SAFE_MEM_CONSTRAINT_H__ + +#include "safeclib_private.h" + +/* + * Function used by the libraries to invoke the registered + * runtime-constraint handler. Always needed. + */ +extern void invoke_safe_mem_constraint_handler( + const char *msg, + void *ptr, + errno_t error); + +#endif /* __SAFE_MEM_CONSTRAINT_H__ */ diff --git a/src/backend/columnar/safe_str_constraint.c b/src/backend/columnar/safe_str_constraint.c new file mode 100644 index 000000000..d57058f93 --- /dev/null +++ b/src/backend/columnar/safe_str_constraint.c @@ -0,0 +1,146 @@ +/*------------------------------------------------------------------ + * safe_str_constraint.c + * + * October 2008, Bo Berry + * 2012, Jonathan Toppins + * + * Copyright (c) 2008, 2009, 2012 Cisco Systems + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + *------------------------------------------------------------------ + */ + +#include "safeclib_private.h" +#include "safe_str_constraint.h" +#include "safe_str_lib.h" + + +static constraint_handler_t str_handler = NULL; + + +/** + * NAME + * set_str_constraint_handler_s + * + * SYNOPSIS + * #include "safe_str_lib.h" + * constraint_handler_t + * set_str_constraint_handler_s(constraint_handler_t handler) + * + * DESCRIPTION + * The set_str_constraint_handler_s function sets the runtime-constraint + * handler to be handler. The runtime-constraint handler is the function to + * be called when a library function detects a runtime-constraint + * violation. Only the most recent handler registered with + * set_str_constraint_handler_s is called when a runtime-constraint + * violation occurs. + * When the handler is called, it is passed the following arguments in + * the following order: + * 1. A pointer to a character string describing the + * runtime-constraint violation. + * 2. A null pointer or a pointer to an implementation defined + * object. + * 3. If the function calling the handler has a return type declared + * as errno_t, the return value of the function is passed. + * Otherwise, a positive value of type errno_t is passed. + * The implementation has a default constraint handler that is used if no + * calls to the set_constraint_handler_s function have been made. The + * behavior of the default handler is implementation-defined, and it may + * cause the program to exit or abort. If the handler argument to + * set_constraint_handler_s is a null pointer, the implementation default + * handler becomes the current constraint handler. + * + * SPECIFIED IN + * ISO/IEC JTC1 SC22 WG14 N1172, Programming languages, environments + * and system software interfaces, Extensions to the C Library, + * Part I: Bounds-checking interfaces + * + * INPUT PARAMETERS + * *msg Pointer to the message describing the error + * + * *ptr Pointer to aassociated data. Can be NULL. + * + * error The error code encountered. + * + * OUTPUT PARAMETERS + * none + * + * RETURN VALUE + * none + * + * ALSO SEE + * set_str_constraint_handler_s() + */ +constraint_handler_t +set_str_constraint_handler_s (constraint_handler_t handler) +{ + constraint_handler_t prev_handler = str_handler; + if (NULL == handler) { + str_handler = sl_default_handler; + } else { + str_handler = handler; + } + return prev_handler; +} +EXPORT_SYMBOL(set_str_constraint_handler_s) + + +/** + * NAME + * invoke_safe_str_constraint_handler + * + * SYNOPSIS + * #include "safe_str_constraint.h" + * void + * invoke_safe_str_constraint_handler (const char *msg, + * void *ptr, + * errno_t error) + * + * DESCRIPTION + * Invokes the currently set constraint handler or the default. + * + * INPUT PARAMETERS + * *msg Pointer to the message describing the error + * + * *ptr Pointer to aassociated data. Can be NULL. + * + * error The error code encountered. + * + * OUTPUT PARAMETERS + * none + * + * RETURN VALUE + * none + * + */ +void +invoke_safe_str_constraint_handler (const char *msg, + void *ptr, + errno_t error) +{ + if (NULL != str_handler) { + str_handler(msg, ptr, error); + } else { + sl_default_handler(msg, ptr, error); + } +} diff --git a/src/backend/columnar/safe_str_constraint.h b/src/backend/columnar/safe_str_constraint.h new file mode 100644 index 000000000..a1fba3e7e --- /dev/null +++ b/src/backend/columnar/safe_str_constraint.h @@ -0,0 +1,78 @@ +/*------------------------------------------------------------------ + * safe_str_constraint.h + * + * October 2008, Bo Berry + * + * Copyright (c) 2008-2011 Cisco Systems + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + *------------------------------------------------------------------ + */ + +#ifndef __SAFE_STR_CONSTRAINT_H__ +#define __SAFE_STR_CONSTRAINT_H__ + +#include "safeclib_private.h" + +/* + * Function used by the libraries to invoke the registered + * runtime-constraint handler. Always needed. + */ +extern void invoke_safe_str_constraint_handler( + const char *msg, + void *ptr, + errno_t error); + + +/* + * Safe C Lib internal string routine to consolidate error handling + */ +static inline void handle_error(char *orig_dest, rsize_t orig_dmax, + char *err_msg, errno_t err_code) +{ +#ifdef SAFECLIB_STR_NULL_SLACK + /* null string to eliminate partial copy */ + while (orig_dmax) { *orig_dest = '\0'; orig_dmax--; orig_dest++; } +#else + *orig_dest = '\0'; +#endif + + invoke_safe_str_constraint_handler(err_msg, NULL, err_code); + return; +} + +static inline void handle_wc_error(wchar_t *orig_dest, rsize_t orig_dmax, + char *err_msg, errno_t err_code) +{ +#ifdef SAFECLIB_STR_NULL_SLACK + /* null string to eliminate partial copy */ + while (orig_dmax) { *orig_dest = L'\0'; orig_dmax--; orig_dest++; } +#else + *orig_dest = L'\0'; +#endif + + invoke_safe_str_constraint_handler(err_msg, NULL, err_code); + return; +} + +#endif /* __SAFE_STR_CONSTRAINT_H__ */ diff --git a/src/backend/columnar/safeclib_private.h b/src/backend/columnar/safeclib_private.h new file mode 100644 index 000000000..89ee97727 --- /dev/null +++ b/src/backend/columnar/safeclib_private.h @@ -0,0 +1,94 @@ +/*------------------------------------------------------------------ + * safeclib_private.h - Internal library references + * + * 2012, Jonathan Toppins + * + * Copyright (c) 2012, 2013 by Cisco Systems, Inc + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + *------------------------------------------------------------------ + */ + +#ifndef __SAFECLIB_PRIVATE_H__ +#define __SAFECLIB_PRIVATE_H__ + +#include "citus_config.h" +#ifdef __KERNEL__ +/* linux kernel environment */ + +#include +#include +#include + +#define RCNEGATE(x) ( -(x) ) + +#define slprintf(...) printk(KERN_EMERG __VA_ARGS__) +#define slabort() +#ifdef DEBUG +#define sldebug_printf(...) printk(KERN_DEBUG __VA_ARGS__) +#endif + +#else /* !__KERNEL__ */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#ifdef STDC_HEADERS +# include +# include +# include +#else +# ifdef HAVE_STDLIB_H +# include +# endif +#endif +#ifdef HAVE_STRING_H +# if !defined STDC_HEADERS && defined HAVE_MEMORY_H +# include +# endif +# include +#endif +#ifdef HAVE_LIMITS_H +# include +#endif + +#define EXPORT_SYMBOL(sym) +#define RCNEGATE(x) (x) + +#define slprintf(...) fprintf(stderr, __VA_ARGS__) +#define slabort() abort() +#ifdef DEBUG +#define sldebug_printf(...) printf(__VA_ARGS__) +#endif + +#endif /* __KERNEL__ */ + +#ifndef sldebug_printf +#define sldebug_printf(...) +#endif + +#include "safe_lib.h" + +#endif /* __SAFECLIB_PRIVATE_H__ */ diff --git a/src/backend/columnar/sql/columnar--11.0-1.sql b/src/backend/columnar/sql/columnar--11.0-1.sql new file mode 100644 index 000000000..0e1c8bb07 --- /dev/null +++ b/src/backend/columnar/sql/columnar--11.0-1.sql @@ -0,0 +1,332 @@ +-- columnar--9.5-1--10.0-1.sql + +CREATE SCHEMA columnar; +SET search_path TO columnar; + + +CREATE SEQUENCE storageid_seq MINVALUE 10000000000 NO CYCLE; + +CREATE TABLE options ( + regclass regclass NOT NULL PRIMARY KEY, + chunk_group_row_limit int NOT NULL, + stripe_row_limit int NOT NULL, + compression_level int NOT NULL, + compression name NOT NULL +) WITH (user_catalog_table = true); + +COMMENT ON TABLE options IS 'columnar table specific options, maintained by alter_columnar_table_set'; + +CREATE TABLE stripe ( + storage_id bigint NOT NULL, + stripe_num bigint NOT NULL, + file_offset bigint NOT NULL, + data_length bigint NOT NULL, + column_count int NOT NULL, + chunk_row_count int NOT NULL, + row_count bigint NOT NULL, + chunk_group_count int NOT NULL, + PRIMARY KEY (storage_id, stripe_num) +) WITH (user_catalog_table = true); + +COMMENT ON TABLE stripe IS 'Columnar per stripe metadata'; + +CREATE TABLE chunk_group ( + storage_id bigint NOT NULL, + stripe_num bigint NOT NULL, + chunk_group_num int NOT NULL, + row_count bigint NOT NULL, + PRIMARY KEY (storage_id, stripe_num, chunk_group_num), + FOREIGN KEY (storage_id, stripe_num) REFERENCES stripe(storage_id, stripe_num) ON DELETE CASCADE +); + +COMMENT ON TABLE chunk_group IS 'Columnar chunk group metadata'; + +CREATE TABLE chunk ( + storage_id bigint NOT NULL, + stripe_num bigint NOT NULL, + attr_num int NOT NULL, + chunk_group_num int NOT NULL, + minimum_value bytea, + maximum_value bytea, + value_stream_offset bigint NOT NULL, + value_stream_length bigint NOT NULL, + exists_stream_offset bigint NOT NULL, + exists_stream_length bigint NOT NULL, + value_compression_type int NOT NULL, + value_compression_level int NOT NULL, + value_decompressed_length bigint NOT NULL, + value_count bigint NOT NULL, + PRIMARY KEY (storage_id, stripe_num, attr_num, chunk_group_num), + FOREIGN KEY (storage_id, stripe_num, chunk_group_num) REFERENCES chunk_group(storage_id, stripe_num, chunk_group_num) ON DELETE CASCADE +) WITH (user_catalog_table = true); + +COMMENT ON TABLE chunk IS 'Columnar per chunk metadata'; + +DO $proc$ +BEGIN + +-- from version 12 and up we have support for tableam's if installed on pg11 we can't +-- create the objects here. Instead we rely on citus_finish_pg_upgrade to be called by the +-- user instead to add the missing objects +IF substring(current_Setting('server_version'), '\d+')::int >= 12 THEN + EXECUTE $$ +--#include "udfs/columnar_handler/10.0-1.sql" +CREATE OR REPLACE FUNCTION columnar.columnar_handler(internal) + RETURNS table_am_handler + LANGUAGE C +AS 'MODULE_PATHNAME', 'columnar_handler'; +COMMENT ON FUNCTION columnar.columnar_handler(internal) + IS 'internal function returning the handler for columnar tables'; + +-- postgres 11.8 does not support the syntax for table am, also it is seemingly trying +-- to parse the upgrade file and erroring on unknown syntax. +-- normally this section would not execute on postgres 11 anyway. To trick it to pass on +-- 11.8 we wrap the statement in a plpgsql block together with an EXECUTE. This is valid +-- syntax on 11.8 and will execute correctly in 12 +DO $create_table_am$ +BEGIN +EXECUTE 'CREATE ACCESS METHOD columnar TYPE TABLE HANDLER columnar.columnar_handler'; +END $create_table_am$; + +--#include "udfs/alter_columnar_table_set/10.0-1.sql" +CREATE OR REPLACE FUNCTION pg_catalog.alter_columnar_table_set( + table_name regclass, + chunk_group_row_limit int DEFAULT NULL, + stripe_row_limit int DEFAULT NULL, + compression name DEFAULT null, + compression_level int DEFAULT NULL) + RETURNS void + LANGUAGE C +AS 'MODULE_PATHNAME', 'alter_columnar_table_set'; + +COMMENT ON FUNCTION pg_catalog.alter_columnar_table_set( + table_name regclass, + chunk_group_row_limit int, + stripe_row_limit int, + compression name, + compression_level int) +IS 'set one or more options on a columnar table, when set to NULL no change is made'; + + +--#include "udfs/alter_columnar_table_reset/10.0-1.sql" +CREATE OR REPLACE FUNCTION pg_catalog.alter_columnar_table_reset( + table_name regclass, + chunk_group_row_limit bool DEFAULT false, + stripe_row_limit bool DEFAULT false, + compression bool DEFAULT false, + compression_level bool DEFAULT false) + RETURNS void + LANGUAGE C +AS 'MODULE_PATHNAME', 'alter_columnar_table_reset'; + +COMMENT ON FUNCTION pg_catalog.alter_columnar_table_reset( + table_name regclass, + chunk_group_row_limit bool, + stripe_row_limit bool, + compression bool, + compression_level bool) +IS 'reset on or more options on a columnar table to the system defaults'; + + $$; +END IF; +END$proc$; + +-- dropped in 10.0.3#include "udfs/columnar_ensure_objects_exist/10.0-1.sql" + +-- citus_internal.columnar_ensure_objects_exist is an internal helper function to create +-- missing objects, anything related to the table access methods. +-- Since the API for table access methods is only available in PG12 we can't create these +-- objects when Citus is installed in PG11. Once citus is installed on PG11 the user can +-- upgrade their database to PG12. Now they require the table access method objects that +-- we couldn't create before. +-- This internal function is called from `citus_finish_pg_upgrade` which the user is +-- required to call after a PG major upgrade. +CREATE OR REPLACE FUNCTION columnar_ensure_objects_exist() + RETURNS void + LANGUAGE plpgsql + SET search_path = pg_catalog +AS $ceoe$ +BEGIN + +-- when postgres is version 12 or above we need to create the tableam. If the tableam +-- exist we assume all objects have been created. +--IF substring(current_Setting('server_version'), '\d+')::int >= 12 THEN +IF NOT EXISTS (SELECT 1 FROM pg_am WHERE amname = 'columnar') THEN + +--#include "../columnar_handler/10.0-1.sql" + +--#include "../alter_columnar_table_set/10.0-1.sql" + +--#include "../alter_columnar_table_reset/10.0-1.sql" + +-- Need change extension name to columnar ??? + -- add the missing objects to the extension + ALTER EXTENSION citus ADD FUNCTION columnar.columnar_handler(internal); + ALTER EXTENSION citus ADD ACCESS METHOD columnar; + ALTER EXTENSION citus ADD FUNCTION pg_catalog.alter_columnar_table_set( + table_name regclass, + chunk_group_row_limit int, + stripe_row_limit int, + compression name, + compression_level int); + ALTER EXTENSION citus ADD FUNCTION pg_catalog.alter_columnar_table_reset( + table_name regclass, + chunk_group_row_limit bool, + stripe_row_limit bool, + compression bool, + compression_level bool); + +END IF; +END IF; +END; +$ceoe$; + +COMMENT ON FUNCTION columnar_ensure_objects_exist() + IS 'internal function to be called by pg_catalog.citus_finish_pg_upgrade responsible for creating the columnar objects'; + + +RESET search_path; + +-- columnar--10.0.-1 --10.0.2 +GRANT USAGE ON SCHEMA columnar TO PUBLIC; +GRANT SELECT ON ALL tables IN SCHEMA columnar TO PUBLIC ; + +-- columnar--10.0-3--10.1-1.sql + +-- Drop foreign keys between columnar metadata tables. +-- Postgres assigns different names to those foreign keys in PG11, so act accordingly. +DO $proc$ +BEGIN +IF substring(current_Setting('server_version'), '\d+')::int >= 12 THEN + EXECUTE $$ +ALTER TABLE columnar.chunk DROP CONSTRAINT chunk_storage_id_stripe_num_chunk_group_num_fkey; +ALTER TABLE columnar.chunk_group DROP CONSTRAINT chunk_group_storage_id_stripe_num_fkey; + $$; +ELSE + EXECUTE $$ +ALTER TABLE columnar.chunk DROP CONSTRAINT chunk_storage_id_fkey; +ALTER TABLE columnar.chunk_group DROP CONSTRAINT chunk_group_storage_id_fkey; + $$; +END IF; +END$proc$; + +--10.1-1 -- 10.2-1 + +-- columnar--10.1-1--10.2-1.sql + +-- For a proper mapping between tid & (stripe, row_num), add a new column to +-- columnar.stripe and define a BTREE index on this column. +-- Also include storage_id column for per-relation scans. +ALTER TABLE columnar.stripe ADD COLUMN first_row_number bigint; +CREATE INDEX stripe_first_row_number_idx ON columnar.stripe USING BTREE(storage_id, first_row_number); + +-- Populate first_row_number column of columnar.stripe table. +-- +-- For simplicity, we calculate MAX(row_count) value across all the stripes +-- of all the columanar tables and then use it to populate first_row_number +-- column. This would introduce some gaps however we are okay with that since +-- it's already the case with regular INSERT/COPY's. +DO $$ +DECLARE + max_row_count bigint; + -- this should be equal to columnar_storage.h/COLUMNAR_FIRST_ROW_NUMBER + COLUMNAR_FIRST_ROW_NUMBER constant bigint := 1; +BEGIN + SELECT MAX(row_count) INTO max_row_count FROM columnar.stripe; + UPDATE columnar.stripe SET first_row_number = COLUMNAR_FIRST_ROW_NUMBER + + (stripe_num - 1) * max_row_count; +END; +$$; + +--#include "udfs/upgrade_columnar_storage/10.2-1.sql" +CREATE OR REPLACE FUNCTION upgrade_columnar_storage(rel regclass) + RETURNS VOID + STRICT + LANGUAGE c AS 'MODULE_PATHNAME', $$upgrade_columnar_storage$$; + +COMMENT ON FUNCTION upgrade_columnar_storage(regclass) + IS 'function to upgrade the columnar storage, if necessary'; + + +--#include "udfs/downgrade_columnar_storage/10.2-1.sql" + +CREATE OR REPLACE FUNCTION downgrade_columnar_storage(rel regclass) + RETURNS VOID + STRICT + LANGUAGE c AS 'MODULE_PATHNAME', $$downgrade_columnar_storage$$; + +COMMENT ON FUNCTION downgrade_columnar_storage(regclass) + IS 'function to downgrade the columnar storage, if necessary'; + +-- upgrade storage for all columnar relations +SELECT upgrade_columnar_storage(c.oid) FROM pg_class c, pg_am a + WHERE c.relam = a.oid AND amname = 'columnar'; + +-- columnar--10.2-1--10.2-2.sql + +-- revoke read access for columnar.chunk from unprivileged +-- user as it contains chunk min/max values +REVOKE SELECT ON columnar.chunk FROM PUBLIC; + + +-- columnar--10.2-2--10.2-3.sql + +-- Since stripe_first_row_number_idx is required to scan a columnar table, we +-- need to make sure that it is created before doing anything with columnar +-- tables during pg upgrades. +-- +-- However, a plain btree index is not a dependency of a table, so pg_upgrade +-- cannot guarantee that stripe_first_row_number_idx gets created when +-- creating columnar.stripe, unless we make it a unique "constraint". +-- +-- To do that, drop stripe_first_row_number_idx and create a unique +-- constraint with the same name to keep the code change at minimum. +DROP INDEX columnar.stripe_first_row_number_idx; +ALTER TABLE columnar.stripe ADD CONSTRAINT stripe_first_row_number_idx +UNIQUE (storage_id, first_row_number); + +-- columnar--10.2-3--10.2-4.sql + +CREATE OR REPLACE FUNCTION columnar_ensure_am_depends_catalog() + RETURNS void + LANGUAGE plpgsql + SET search_path = pg_catalog +AS $func$ +BEGIN + INSERT INTO pg_depend + SELECT -- Define a dependency edge from "columnar table access method" .. + 'pg_am'::regclass::oid as classid, + (select oid from pg_am where amname = 'columnar') as objid, + 0 as objsubid, + -- ... to each object that is registered to pg_class and that lives + -- in "columnar" schema. That contains catalog tables, indexes + -- created on them and the sequences created in "columnar" schema. + -- + -- Given the possibility of user might have created their own objects + -- in columnar schema, we explicitly specify list of objects that we + -- are interested in. + 'pg_class'::regclass::oid as refclassid, + columnar_schema_members.relname::regclass::oid as refobjid, + 0 as refobjsubid, + 'n' as deptype + FROM (VALUES ('columnar.chunk'), + ('columnar.chunk_group'), + ('columnar.chunk_group_pkey'), + ('columnar.chunk_pkey'), + ('columnar.options'), + ('columnar.options_pkey'), + ('columnar.storageid_seq'), + ('columnar.stripe'), + ('columnar.stripe_first_row_number_idx'), + ('columnar.stripe_pkey') + ) columnar_schema_members(relname) + -- Avoid inserting duplicate entries into pg_depend. + EXCEPT TABLE pg_depend; +END; +$func$; +COMMENT ON FUNCTION columnar_ensure_am_depends_catalog() + IS 'internal function responsible for creating dependencies from columnar ' + 'table access method to the rel objects in columnar schema'; + + +SELECT columnar_ensure_am_depends_catalog();