2006-07-04 00:45:41 +02:00
|
|
|
/*-------------------------------------------------------------------------
|
|
|
|
*
|
|
|
|
* reloptions.h
|
2010-01-05 22:54:00 +01:00
|
|
|
* Core support for relation and tablespace options (pg_class.reloptions
|
|
|
|
* and pg_tablespace.spcoptions)
|
2006-07-04 00:45:41 +02:00
|
|
|
*
|
|
|
|
* Note: the functions dealing with text-array reloptions values declare
|
|
|
|
* them as Datum, not ArrayType *, to avoid needing to include array.h
|
|
|
|
* into a lot of low-level code.
|
|
|
|
*
|
|
|
|
*
|
2019-01-02 18:44:25 +01:00
|
|
|
* Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
|
2006-07-04 00:45:41 +02:00
|
|
|
* Portions Copyright (c) 1994, Regents of the University of California
|
|
|
|
*
|
2010-09-20 22:08:53 +02:00
|
|
|
* src/include/access/reloptions.h
|
2006-07-04 00:45:41 +02:00
|
|
|
*
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
#ifndef RELOPTIONS_H
|
|
|
|
#define RELOPTIONS_H
|
|
|
|
|
Restructure index access method API to hide most of it at the C level.
This patch reduces pg_am to just two columns, a name and a handler
function. All the data formerly obtained from pg_am is now provided
in a C struct returned by the handler function. This is similar to
the designs we've adopted for FDWs and tablesample methods. There
are multiple advantages. For one, the index AM's support functions
are now simple C functions, making them faster to call and much less
error-prone, since the C compiler can now check function signatures.
For another, this will make it far more practical to define index access
methods in installable extensions.
A disadvantage is that SQL-level code can no longer see attributes
of index AMs; in particular, some of the crosschecks in the opr_sanity
regression test are no longer possible from SQL. We've addressed that
by adding a facility for the index AM to perform such checks instead.
(Much more could be done in that line, but for now we're content if the
amvalidate functions more or less replace what opr_sanity used to do.)
We might also want to expose some sort of reporting functionality, but
this patch doesn't do that.
Alexander Korotkov, reviewed by Petr Jelínek, and rather heavily
editorialized on by me.
2016-01-18 01:36:59 +01:00
|
|
|
#include "access/amapi.h"
|
2009-01-26 20:41:06 +01:00
|
|
|
#include "access/htup.h"
|
2012-08-30 22:15:44 +02:00
|
|
|
#include "access/tupdesc.h"
|
2006-07-04 00:45:41 +02:00
|
|
|
#include "nodes/pg_list.h"
|
2015-08-14 15:19:28 +02:00
|
|
|
#include "storage/lock.h"
|
2006-07-04 00:45:41 +02:00
|
|
|
|
2009-01-05 18:14:28 +01:00
|
|
|
/* types supported by reloptions */
|
|
|
|
typedef enum relopt_type
|
|
|
|
{
|
|
|
|
RELOPT_TYPE_BOOL,
|
|
|
|
RELOPT_TYPE_INT,
|
|
|
|
RELOPT_TYPE_REAL,
|
|
|
|
RELOPT_TYPE_STRING
|
|
|
|
} relopt_type;
|
|
|
|
|
|
|
|
/* kinds supported by reloptions */
|
|
|
|
typedef enum relopt_kind
|
|
|
|
{
|
2009-06-11 16:49:15 +02:00
|
|
|
RELOPT_KIND_HEAP = (1 << 0),
|
|
|
|
RELOPT_KIND_TOAST = (1 << 1),
|
|
|
|
RELOPT_KIND_BTREE = (1 << 2),
|
|
|
|
RELOPT_KIND_HASH = (1 << 3),
|
|
|
|
RELOPT_KIND_GIN = (1 << 4),
|
|
|
|
RELOPT_KIND_GIST = (1 << 5),
|
2010-01-22 17:40:19 +01:00
|
|
|
RELOPT_KIND_ATTRIBUTE = (1 << 6),
|
|
|
|
RELOPT_KIND_TABLESPACE = (1 << 7),
|
2011-12-17 22:41:16 +01:00
|
|
|
RELOPT_KIND_SPGIST = (1 << 8),
|
2011-12-22 22:15:57 +01:00
|
|
|
RELOPT_KIND_VIEW = (1 << 9),
|
BRIN: Block Range Indexes
BRIN is a new index access method intended to accelerate scans of very
large tables, without the maintenance overhead of btrees or other
traditional indexes. They work by maintaining "summary" data about
block ranges. Bitmap index scans work by reading each summary tuple and
comparing them with the query quals; all pages in the range are returned
in a lossy TID bitmap if the quals are consistent with the values in the
summary tuple, otherwise not. Normal index scans are not supported
because these indexes do not store TIDs.
As new tuples are added into the index, the summary information is
updated (if the block range in which the tuple is added is already
summarized) or not; in the latter case, a subsequent pass of VACUUM or
the brin_summarize_new_values() function will create the summary
information.
For data types with natural 1-D sort orders, the summary info consists
of the maximum and the minimum values of each indexed column within each
page range. This type of operator class we call "Minmax", and we
supply a bunch of them for most data types with B-tree opclasses.
Since the BRIN code is generalized, other approaches are possible for
things such as arrays, geometric types, ranges, etc; even for things
such as enum types we could do something different than minmax with
better results. In this commit I only include minmax.
Catalog version bumped due to new builtin catalog entries.
There's more that could be done here, but this is a good step forwards.
Loosely based on ideas from Simon Riggs; code mostly by Álvaro Herrera,
with contribution by Heikki Linnakangas.
Patch reviewed by: Amit Kapila, Heikki Linnakangas, Robert Haas.
Testing help from Jeff Janes, Erik Rijkers, Emanuel Calvo.
PS:
The research leading to these results has received funding from the
European Union's Seventh Framework Programme (FP7/2007-2013) under
grant agreement n° 318633.
2014-11-07 20:38:14 +01:00
|
|
|
RELOPT_KIND_BRIN = (1 << 10),
|
2017-03-31 22:28:30 +02:00
|
|
|
RELOPT_KIND_PARTITIONED = (1 << 11),
|
2009-01-05 18:14:28 +01:00
|
|
|
/* if you add a new kind, make sure you update "last_default" too */
|
2017-03-31 22:28:30 +02:00
|
|
|
RELOPT_KIND_LAST_DEFAULT = RELOPT_KIND_PARTITIONED,
|
2009-05-25 00:22:44 +02:00
|
|
|
/* some compilers treat enums as signed ints, so we can't use 1 << 31 */
|
|
|
|
RELOPT_KIND_MAX = (1 << 30)
|
2009-01-05 18:14:28 +01:00
|
|
|
} relopt_kind;
|
|
|
|
|
2009-02-02 20:31:40 +01:00
|
|
|
/* reloption namespaces allowed for heaps -- currently only TOAST */
|
|
|
|
#define HEAP_RELOPT_NAMESPACES { "toast", NULL }
|
|
|
|
|
2009-01-05 18:14:28 +01:00
|
|
|
/* generic struct to hold shared data */
|
|
|
|
typedef struct relopt_gen
|
|
|
|
{
|
2009-06-11 16:49:15 +02:00
|
|
|
const char *name; /* must be first (used as list termination
|
|
|
|
* marker) */
|
2009-01-05 18:14:28 +01:00
|
|
|
const char *desc;
|
2009-04-04 02:45:02 +02:00
|
|
|
bits32 kinds;
|
2015-08-14 15:19:28 +02:00
|
|
|
LOCKMODE lockmode;
|
2009-01-05 18:14:28 +01:00
|
|
|
int namelen;
|
2009-06-11 16:49:15 +02:00
|
|
|
relopt_type type;
|
2009-01-05 18:14:28 +01:00
|
|
|
} relopt_gen;
|
|
|
|
|
|
|
|
/* holds a parsed value */
|
|
|
|
typedef struct relopt_value
|
|
|
|
{
|
|
|
|
relopt_gen *gen;
|
|
|
|
bool isset;
|
|
|
|
union
|
|
|
|
{
|
2009-06-11 16:49:15 +02:00
|
|
|
bool bool_val;
|
|
|
|
int int_val;
|
|
|
|
double real_val;
|
|
|
|
char *string_val; /* allocated separately */
|
|
|
|
} values;
|
2009-01-05 18:14:28 +01:00
|
|
|
} relopt_value;
|
|
|
|
|
|
|
|
/* reloptions records for specific variable types */
|
|
|
|
typedef struct relopt_bool
|
|
|
|
{
|
|
|
|
relopt_gen gen;
|
|
|
|
bool default_val;
|
|
|
|
} relopt_bool;
|
2009-01-12 22:02:15 +01:00
|
|
|
|
2009-01-05 18:14:28 +01:00
|
|
|
typedef struct relopt_int
|
|
|
|
{
|
|
|
|
relopt_gen gen;
|
|
|
|
int default_val;
|
|
|
|
int min;
|
|
|
|
int max;
|
|
|
|
} relopt_int;
|
|
|
|
|
|
|
|
typedef struct relopt_real
|
|
|
|
{
|
|
|
|
relopt_gen gen;
|
|
|
|
double default_val;
|
|
|
|
double min;
|
|
|
|
double max;
|
|
|
|
} relopt_real;
|
|
|
|
|
2009-01-12 22:02:15 +01:00
|
|
|
/* validation routines for strings */
|
2017-10-31 15:34:31 +01:00
|
|
|
typedef void (*validate_string_relopt) (const char *value);
|
2009-01-08 20:34:41 +01:00
|
|
|
|
2009-01-05 18:14:28 +01:00
|
|
|
typedef struct relopt_string
|
|
|
|
{
|
|
|
|
relopt_gen gen;
|
|
|
|
int default_len;
|
|
|
|
bool default_isnull;
|
2009-06-11 16:49:15 +02:00
|
|
|
validate_string_relopt validate_cb;
|
2011-08-09 14:25:44 +02:00
|
|
|
char *default_val;
|
2009-01-05 18:14:28 +01:00
|
|
|
} relopt_string;
|
|
|
|
|
2009-03-23 17:36:27 +01:00
|
|
|
/* This is the table datatype for fillRelOptions */
|
2009-01-12 22:02:15 +01:00
|
|
|
typedef struct
|
|
|
|
{
|
2009-03-23 17:36:27 +01:00
|
|
|
const char *optname; /* option's name */
|
2009-06-11 16:49:15 +02:00
|
|
|
relopt_type opttype; /* option's datatype */
|
2009-03-23 17:36:27 +01:00
|
|
|
int offset; /* offset of field in result struct */
|
2009-01-12 22:02:15 +01:00
|
|
|
} relopt_parse_elt;
|
|
|
|
|
|
|
|
|
2009-01-05 18:14:28 +01:00
|
|
|
/*
|
2009-01-12 22:02:15 +01:00
|
|
|
* These macros exist for the convenience of amoptions writers (but consider
|
|
|
|
* using fillRelOptions, which is a lot simpler). Beware of multiple
|
|
|
|
* evaluation of arguments!
|
2009-01-06 15:47:37 +01:00
|
|
|
*
|
|
|
|
* The last argument in the HANDLE_*_RELOPTION macros allows the caller to
|
|
|
|
* determine whether the option was set (true), or its value acquired from
|
|
|
|
* defaults (false); it can be passed as (char *) NULL if the caller does not
|
|
|
|
* need this information.
|
2009-01-12 22:02:15 +01:00
|
|
|
*
|
|
|
|
* optname is the option name (a string), var is the variable
|
|
|
|
* on which the value should be stored (e.g. StdRdOptions->fillfactor), and
|
|
|
|
* option is a relopt_value pointer.
|
|
|
|
*
|
|
|
|
* The normal way to use this is to loop on the relopt_value array returned by
|
|
|
|
* parseRelOptions:
|
|
|
|
* for (i = 0; options[i].gen->name; i++)
|
|
|
|
* {
|
2009-06-11 16:49:15 +02:00
|
|
|
* if (HAVE_RELOPTION("fillfactor", options[i])
|
|
|
|
* {
|
|
|
|
* HANDLE_INT_RELOPTION("fillfactor", rdopts->fillfactor, options[i], &isset);
|
|
|
|
* continue;
|
|
|
|
* }
|
|
|
|
* if (HAVE_RELOPTION("default_row_acl", options[i])
|
|
|
|
* {
|
|
|
|
* ...
|
|
|
|
* }
|
|
|
|
* ...
|
|
|
|
* if (validate)
|
|
|
|
* ereport(ERROR,
|
|
|
|
* (errmsg("unknown option")));
|
|
|
|
* }
|
2009-01-12 22:02:15 +01:00
|
|
|
*
|
2009-06-11 16:49:15 +02:00
|
|
|
* Note that this is more or less the same that fillRelOptions does, so only
|
|
|
|
* use this if you need to do something non-standard within some option's
|
|
|
|
* code block.
|
2009-01-05 18:14:28 +01:00
|
|
|
*/
|
|
|
|
#define HAVE_RELOPTION(optname, option) \
|
Avoid unnecessary use of pg_strcasecmp for already-downcased identifiers.
We have a lot of code in which option names, which from the user's
viewpoint are logically keywords, are passed through the grammar as plain
identifiers, and then matched to string literals during command execution.
This approach avoids making words into lexer keywords unnecessarily. Some
places matched these strings using plain strcmp, some using pg_strcasecmp.
But the latter should be unnecessary since identifiers would have been
downcased on their way through the parser. Aside from any efficiency
concerns (probably not a big factor), the lack of consistency in this area
creates a hazard of subtle bugs due to different places coming to different
conclusions about whether two option names are the same or different.
Hence, standardize on using strcmp() to match any option names that are
expected to have been fed through the parser.
This does create a user-visible behavioral change, which is that while
formerly all of these would work:
alter table foo set (fillfactor = 50);
alter table foo set (FillFactor = 50);
alter table foo set ("fillfactor" = 50);
alter table foo set ("FillFactor" = 50);
now the last case will fail because that double-quoted identifier is
different from the others. However, none of our documentation says that
you can use a quoted identifier in such contexts at all, and we should
discourage doing so since it would break if we ever decide to parse such
constructs as true lexer keywords rather than poor man's substitutes.
So this shouldn't create a significant compatibility issue for users.
Daniel Gustafsson, reviewed by Michael Paquier, small changes by me
Discussion: https://postgr.es/m/29405B24-564E-476B-98C0-677A29805B84@yesql.se
2018-01-27 00:25:02 +01:00
|
|
|
(strncmp(option.gen->name, optname, option.gen->namelen + 1) == 0)
|
2009-01-05 18:14:28 +01:00
|
|
|
|
2009-01-12 22:02:15 +01:00
|
|
|
#define HANDLE_INT_RELOPTION(optname, var, option, wasset) \
|
|
|
|
do { \
|
|
|
|
if (option.isset) \
|
2009-06-11 16:49:15 +02:00
|
|
|
var = option.values.int_val; \
|
2009-01-12 22:02:15 +01:00
|
|
|
else \
|
2009-06-11 16:49:15 +02:00
|
|
|
var = ((relopt_int *) option.gen)->default_val; \
|
2009-01-12 22:02:15 +01:00
|
|
|
(wasset) != NULL ? *(wasset) = option.isset : (dummyret)NULL; \
|
2009-01-05 18:14:28 +01:00
|
|
|
} while (0)
|
|
|
|
|
2009-01-06 15:47:37 +01:00
|
|
|
#define HANDLE_BOOL_RELOPTION(optname, var, option, wasset) \
|
2009-01-05 18:14:28 +01:00
|
|
|
do { \
|
2009-01-12 22:02:15 +01:00
|
|
|
if (option.isset) \
|
2009-06-11 16:49:15 +02:00
|
|
|
var = option.values.bool_val; \
|
2009-01-12 22:02:15 +01:00
|
|
|
else \
|
|
|
|
var = ((relopt_bool *) option.gen)->default_val; \
|
|
|
|
(wasset) != NULL ? *(wasset) = option.isset : (dummyret) NULL; \
|
2009-01-05 18:14:28 +01:00
|
|
|
} while (0)
|
|
|
|
|
2009-06-11 16:49:15 +02:00
|
|
|
#define HANDLE_REAL_RELOPTION(optname, var, option, wasset) \
|
2009-01-12 22:02:15 +01:00
|
|
|
do { \
|
|
|
|
if (option.isset) \
|
2009-06-11 16:49:15 +02:00
|
|
|
var = option.values.real_val; \
|
2009-01-12 22:02:15 +01:00
|
|
|
else \
|
|
|
|
var = ((relopt_real *) option.gen)->default_val; \
|
|
|
|
(wasset) != NULL ? *(wasset) = option.isset : (dummyret) NULL; \
|
2009-01-05 18:14:28 +01:00
|
|
|
} while (0)
|
|
|
|
|
2009-01-06 15:47:37 +01:00
|
|
|
/*
|
|
|
|
* Note that this assumes that the variable is already allocated at the tail of
|
2009-01-12 22:02:15 +01:00
|
|
|
* reloptions structure (StdRdOptions or equivalent).
|
2009-01-06 15:47:37 +01:00
|
|
|
*
|
|
|
|
* "base" is a pointer to the reloptions structure, and "offset" is an integer
|
|
|
|
* variable that must be initialized to sizeof(reloptions structure). This
|
|
|
|
* struct must have been allocated with enough space to hold any string option
|
2014-05-06 18:12:18 +02:00
|
|
|
* present, including terminating \0 for every option. SET_VARSIZE() must be
|
2009-01-06 15:47:37 +01:00
|
|
|
* called on the struct with this offset as the second argument, after all the
|
|
|
|
* string options have been processed.
|
|
|
|
*/
|
2009-06-11 16:49:15 +02:00
|
|
|
#define HANDLE_STRING_RELOPTION(optname, var, option, base, offset, wasset) \
|
2009-01-08 20:34:41 +01:00
|
|
|
do { \
|
2009-01-12 22:02:15 +01:00
|
|
|
relopt_string *optstring = (relopt_string *) option.gen;\
|
|
|
|
char *string_val; \
|
|
|
|
if (option.isset) \
|
|
|
|
string_val = option.values.string_val; \
|
|
|
|
else if (!optstring->default_isnull) \
|
|
|
|
string_val = optstring->default_val; \
|
|
|
|
else \
|
|
|
|
string_val = NULL; \
|
|
|
|
(wasset) != NULL ? *(wasset) = option.isset : (dummyret) NULL; \
|
|
|
|
if (string_val == NULL) \
|
|
|
|
var = 0; \
|
|
|
|
else \
|
|
|
|
{ \
|
|
|
|
strcpy(((char *)(base)) + (offset), string_val); \
|
|
|
|
var = (offset); \
|
|
|
|
(offset) += strlen(string_val) + 1; \
|
|
|
|
} \
|
2009-01-05 18:14:28 +01:00
|
|
|
} while (0)
|
|
|
|
|
2009-01-08 20:34:41 +01:00
|
|
|
/*
|
|
|
|
* For use during amoptions: get the strlen of a string option
|
|
|
|
* (either default or the user defined value)
|
|
|
|
*/
|
|
|
|
#define GET_STRING_RELOPTION_LEN(option) \
|
|
|
|
((option).isset ? strlen((option).values.string_val) : \
|
|
|
|
((relopt_string *) (option).gen)->default_len)
|
|
|
|
|
|
|
|
/*
|
|
|
|
* For use by code reading options already parsed: get a pointer to the string
|
|
|
|
* value itself. "optstruct" is the StdRdOption struct or equivalent, "member"
|
|
|
|
* is the struct member corresponding to the string option
|
|
|
|
*/
|
|
|
|
#define GET_STRING_RELOPTION(optstruct, member) \
|
|
|
|
((optstruct)->member == 0 ? NULL : \
|
2009-01-12 22:02:15 +01:00
|
|
|
(char *)(optstruct) + (optstruct)->member)
|
2009-01-08 20:34:41 +01:00
|
|
|
|
|
|
|
|
2009-04-04 02:45:02 +02:00
|
|
|
extern relopt_kind add_reloption_kind(void);
|
2017-10-31 15:34:31 +01:00
|
|
|
extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc,
|
2019-05-22 19:04:48 +02:00
|
|
|
bool default_val);
|
2017-10-31 15:34:31 +01:00
|
|
|
extern void add_int_reloption(bits32 kinds, const char *name, const char *desc,
|
2019-05-22 19:04:48 +02:00
|
|
|
int default_val, int min_val, int max_val);
|
2017-10-31 15:34:31 +01:00
|
|
|
extern void add_real_reloption(bits32 kinds, const char *name, const char *desc,
|
2019-05-22 19:04:48 +02:00
|
|
|
double default_val, double min_val, double max_val);
|
2017-10-31 15:34:31 +01:00
|
|
|
extern void add_string_reloption(bits32 kinds, const char *name, const char *desc,
|
2019-05-22 19:04:48 +02:00
|
|
|
const char *default_val, validate_string_relopt validator);
|
2009-01-12 22:02:15 +01:00
|
|
|
|
2006-07-04 00:45:41 +02:00
|
|
|
extern Datum transformRelOptions(Datum oldOptions, List *defList,
|
2019-05-22 19:04:48 +02:00
|
|
|
const char *namspace, char *validnsps[],
|
|
|
|
bool acceptOidsOff, bool isReset);
|
2007-12-02 00:44:44 +01:00
|
|
|
extern List *untransformRelOptions(Datum options);
|
2009-01-26 20:41:06 +01:00
|
|
|
extern bytea *extractRelOptions(HeapTuple tuple, TupleDesc tupdesc,
|
2019-05-22 19:04:48 +02:00
|
|
|
amoptions_function amoptions);
|
2009-01-05 18:14:28 +01:00
|
|
|
extern relopt_value *parseRelOptions(Datum options, bool validate,
|
2019-05-22 19:04:48 +02:00
|
|
|
relopt_kind kind, int *numrelopts);
|
2009-01-12 22:02:15 +01:00
|
|
|
extern void *allocateReloptStruct(Size base, relopt_value *options,
|
2019-05-22 19:04:48 +02:00
|
|
|
int numoptions);
|
2009-03-23 17:36:27 +01:00
|
|
|
extern void fillRelOptions(void *rdopts, Size basesize,
|
2019-05-22 19:04:48 +02:00
|
|
|
relopt_value *options, int numoptions,
|
|
|
|
bool validate,
|
|
|
|
const relopt_parse_elt *elems, int nelems);
|
2006-07-04 00:45:41 +02:00
|
|
|
|
|
|
|
extern bytea *default_reloptions(Datum reloptions, bool validate,
|
2019-05-22 19:04:48 +02:00
|
|
|
relopt_kind kind);
|
2006-07-04 00:45:41 +02:00
|
|
|
extern bytea *heap_reloptions(char relkind, Datum reloptions, bool validate);
|
2014-07-14 23:24:40 +02:00
|
|
|
extern bytea *view_reloptions(Datum reloptions, bool validate);
|
Restructure index access method API to hide most of it at the C level.
This patch reduces pg_am to just two columns, a name and a handler
function. All the data formerly obtained from pg_am is now provided
in a C struct returned by the handler function. This is similar to
the designs we've adopted for FDWs and tablesample methods. There
are multiple advantages. For one, the index AM's support functions
are now simple C functions, making them faster to call and much less
error-prone, since the C compiler can now check function signatures.
For another, this will make it far more practical to define index access
methods in installable extensions.
A disadvantage is that SQL-level code can no longer see attributes
of index AMs; in particular, some of the crosschecks in the opr_sanity
regression test are no longer possible from SQL. We've addressed that
by adding a facility for the index AM to perform such checks instead.
(Much more could be done in that line, but for now we're content if the
amvalidate functions more or less replace what opr_sanity used to do.)
We might also want to expose some sort of reporting functionality, but
this patch doesn't do that.
Alexander Korotkov, reviewed by Petr Jelínek, and rather heavily
editorialized on by me.
2016-01-18 01:36:59 +01:00
|
|
|
extern bytea *index_reloptions(amoptions_function amoptions, Datum reloptions,
|
2019-05-22 19:04:48 +02:00
|
|
|
bool validate);
|
2010-01-22 17:40:19 +01:00
|
|
|
extern bytea *attribute_reloptions(Datum reloptions, bool validate);
|
2010-01-05 22:54:00 +01:00
|
|
|
extern bytea *tablespace_reloptions(Datum reloptions, bool validate);
|
2015-08-14 15:19:28 +02:00
|
|
|
extern LOCKMODE AlterTableGetRelOptionsLockLevel(List *defList);
|
2006-07-04 00:45:41 +02:00
|
|
|
|
Phase 2 of pgindent updates.
Change pg_bsd_indent to follow upstream rules for placement of comments
to the right of code, and remove pgindent hack that caused comments
following #endif to not obey the general rule.
Commit e3860ffa4dd0dad0dd9eea4be9cc1412373a8c89 wasn't actually using
the published version of pg_bsd_indent, but a hacked-up version that
tried to minimize the amount of movement of comments to the right of
code. The situation of interest is where such a comment has to be
moved to the right of its default placement at column 33 because there's
code there. BSD indent has always moved right in units of tab stops
in such cases --- but in the previous incarnation, indent was working
in 8-space tab stops, while now it knows we use 4-space tabs. So the
net result is that in about half the cases, such comments are placed
one tab stop left of before. This is better all around: it leaves
more room on the line for comment text, and it means that in such
cases the comment uniformly starts at the next 4-space tab stop after
the code, rather than sometimes one and sometimes two tabs after.
Also, ensure that comments following #endif are indented the same
as comments following other preprocessor commands such as #else.
That inconsistency turns out to have been self-inflicted damage
from a poorly-thought-through post-indent "fixup" in pgindent.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:18:54 +02:00
|
|
|
#endif /* RELOPTIONS_H */
|