|
33 | 33 | #include "optimizer/optimizer.h"
|
34 | 34 | #include "statistics/statistics.h"
|
35 | 35 | #include "utils/builtins.h"
|
| 36 | +#include "utils/lsyscache.h" |
36 | 37 | #include "utils/fmgroids.h"
|
37 | 38 | #include "utils/inval.h"
|
38 | 39 | #include "utils/memutils.h"
|
@@ -210,13 +211,15 @@ CreateStatistics(CreateStatsStmt *stmt)
|
210 | 211 | /*
|
211 | 212 | * Convert the expression list to a simple array of attnums, but also keep
|
212 | 213 | * a list of more complex expressions. While at it, enforce some
|
213 |
| - * constraints. |
| 214 | + * constraints - we don't allow extended statistics on system attributes, |
| 215 | + * and we require the data type to have less-than operator. |
214 | 216 | *
|
215 |
| - * XXX We do only the bare minimum to separate simple attribute and |
216 |
| - * complex expressions - for example "(a)" will be treated as a complex |
217 |
| - * expression. No matter how elaborate the check is, there'll always be a |
218 |
| - * way around it, if the user is determined (consider e.g. "(a+0)"), so |
219 |
| - * it's not worth protecting against it. |
| 217 | + * There are many ways how to "mask" a simple attribute refenrece as an |
| 218 | + * expression, for example "(a+0)" etc. We can't possibly detect all of |
| 219 | + * them, but we handle at least the simple case with attribute in parens. |
| 220 | + * There'll always be a way around this, if the user is determined (like |
| 221 | + * the "(a+0)" example), but this makes it somewhat consistent with how |
| 222 | + * indexes treat attributes/expressions. |
220 | 223 | */
|
221 | 224 | foreach(cell, stmt->exprs)
|
222 | 225 | {
|
@@ -257,6 +260,28 @@ CreateStatistics(CreateStatsStmt *stmt)
|
257 | 260 | nattnums++;
|
258 | 261 | ReleaseSysCache(atttuple);
|
259 | 262 | }
|
| 263 | + else if (IsA(selem->expr, Var)) /* column reference in parens */ |
| 264 | + { |
| 265 | + Var *var = (Var *) selem->expr; |
| 266 | + TypeCacheEntry *type; |
| 267 | + |
| 268 | + /* Disallow use of system attributes in extended stats */ |
| 269 | + if (var->varattno <= 0) |
| 270 | + ereport(ERROR, |
| 271 | + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), |
| 272 | + errmsg("statistics creation on system columns is not supported"))); |
| 273 | + |
| 274 | + /* Disallow data types without a less-than operator */ |
| 275 | + type = lookup_type_cache(var->vartype, TYPECACHE_LT_OPR); |
| 276 | + if (type->lt_opr == InvalidOid) |
| 277 | + ereport(ERROR, |
| 278 | + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), |
| 279 | + errmsg("column \"%s\" cannot be used in statistics because its type %s has no default btree operator class", |
| 280 | + get_attname(relid, var->varattno, false), format_type_be(var->vartype)))); |
| 281 | + |
| 282 | + attnums[nattnums] = var->varattno; |
| 283 | + nattnums++; |
| 284 | + } |
260 | 285 | else /* expression */
|
261 | 286 | {
|
262 | 287 | Node *expr = selem->expr;
|
|
0 commit comments