Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit5564c11

Browse files
committed
Clone extended stats in CREATE TABLE (LIKE INCLUDING ALL)
The LIKE INCLUDING ALL clause to CREATE TABLE intuitively indicatescloning of extended statistics on the source table, but it failed to doso. Patch it up so that it does. Also include an INCLUDING STATISTICSoption to the LIKE clause, so that the behavior can be requestedindividually, or excluded individually.While at it, reorder the INCLUDING options, both in code and in docs, inalphabetical order which makes more sense than feature-implementationorder that was previously used.Backpatch this to Postgres 10, where extended statistics wereintroduced, because this is seen as an oversight in a fresh featurewhich is better to get consistent from the get-go instead of changingonly in pg11.In pg11, comments on statistics objects are cloned too. In pg10 theyare not, because I (Álvaro) was too coward to change the parse node asrequired to support it. Also, in pg10 I chose not to renumber theparser symbols for the various INCLUDING options in LIKE, for the samereason. Any corresponding user-visible changes (docs) are backpatched,though.Reported-by: Stephen FroehlichAuthor: David RowleyReviewed-by: Álvaro Herrera, Tomas VondraDiscussion:https://postgr.es/m/CY1PR0601MB1927315B45667A1B679D0FD5E5EF0@CY1PR0601MB1927.namprd06.prod.outlook.com
1 parentc2c537c commit5564c11

File tree

11 files changed

+323
-37
lines changed

11 files changed

+323
-37
lines changed

‎doc/src/sgml/ref/create_table.sgml

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } | UNLOGGED ] TABLE [ IF NOT EXI
8282

8383
<phrase>and <replaceable class="parameter">like_option</replaceable> is:</phrase>
8484

85-
{ INCLUDING | EXCLUDING } {DEFAULTS | CONSTRAINTS | IDENTITY | INDEXES |STORAGE |COMMENTS | ALL }
85+
{ INCLUDING | EXCLUDING } {COMMENTS | CONSTRAINTS |DEFAULTS |IDENTITY | INDEXES |STATISTICS |STORAGE | ALL }
8686

8787
<phrase>and <replaceable class="parameter">partition_bound_spec</replaceable> is:</phrase>
8888

@@ -591,6 +591,10 @@ WITH ( MODULUS <replaceable class="parameter">numeric_literal</replaceable>, REM
591591
No distinction is made between column constraints and table
592592
constraints.
593593
</para>
594+
<para>
595+
Extended statistics are copied to the new table if
596+
<literal>INCLUDING STATISTICS</literal> is specified.
597+
</para>
594598
<para>
595599
Indexes, <literal>PRIMARY KEY</literal>, <literal>UNIQUE</literal>,
596600
and <literal>EXCLUDE</literal> constraints on the original table will be
@@ -616,7 +620,7 @@ WITH ( MODULUS <replaceable class="parameter">numeric_literal</replaceable>, REM
616620
</para>
617621
<para>
618622
<literal>INCLUDING ALL</literal> is an abbreviated form of
619-
<literal>INCLUDINGDEFAULTS INCLUDINGIDENTITY INCLUDINGCONSTRAINTS INCLUDING INDEXES INCLUDINGSTORAGE INCLUDINGCOMMENTS</literal>.
623+
<literal>INCLUDINGCOMMENTS INCLUDINGCONSTRAINTS INCLUDINGDEFAULTS INCLUDINGIDENTITY INCLUDINGINDEXES INCLUDINGSTATISTICS INCLUDINGSTORAGE</literal>.
620624
</para>
621625
<para>
622626
Note that unlike <literal>INHERITS</literal>, columns and

‎src/backend/commands/indexcmds.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1805,7 +1805,8 @@ GetDefaultOpClass(Oid type_id, Oid am_id)
18051805
/*
18061806
*makeObjectName()
18071807
*
1808-
*Create a name for an implicitly created index, sequence, constraint, etc.
1808+
*Create a name for an implicitly created index, sequence, constraint,
1809+
*extended statistics, etc.
18091810
*
18101811
*The parameters are typically: the original table name, the original field
18111812
*name, and a "type" string (such as "seq" or "pkey"). The field name
@@ -1981,6 +1982,8 @@ ChooseIndexName(const char *tabname, Oid namespaceId,
19811982
*
19821983
* We know that less than NAMEDATALEN characters will actually be used,
19831984
* so we can truncate the result once we've generated that many.
1985+
*
1986+
* XXX See also ChooseExtendedStatisticNameAddition.
19841987
*/
19851988
staticchar*
19861989
ChooseIndexNameAddition(List*colnames)

‎src/backend/commands/statscmds.c

Lines changed: 142 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include"catalog/namespace.h"
2121
#include"catalog/pg_namespace.h"
2222
#include"catalog/pg_statistic_ext.h"
23+
#include"commands/comment.h"
2324
#include"commands/defrem.h"
2425
#include"miscadmin.h"
2526
#include"statistics/statistics.h"
@@ -31,6 +32,11 @@
3132
#include"utils/typcache.h"
3233

3334

35+
staticchar*ChooseExtendedStatisticName(constchar*name1,constchar*name2,
36+
constchar*label,Oidnamespaceid);
37+
staticchar*ChooseExtendedStatisticNameAddition(List*exprs);
38+
39+
3440
/* qsort comparator for the attnums in CreateStatistics */
3541
staticint
3642
compare_int16(constvoid*a,constvoid*b)
@@ -51,7 +57,6 @@ CreateStatistics(CreateStatsStmt *stmt)
5157
int16attnums[STATS_MAX_DIMENSIONS];
5258
intnumcols=0;
5359
char*namestr;
54-
NameDatastxname;
5560
Oidstatoid;
5661
OidnamespaceId;
5762
Oidstxowner=GetUserId();
@@ -75,31 +80,6 @@ CreateStatistics(CreateStatsStmt *stmt)
7580

7681
Assert(IsA(stmt,CreateStatsStmt));
7782

78-
/* resolve the pieces of the name (namespace etc.) */
79-
namespaceId=QualifiedNameGetCreationNamespace(stmt->defnames,&namestr);
80-
namestrcpy(&stxname,namestr);
81-
82-
/*
83-
* Deal with the possibility that the statistics object already exists.
84-
*/
85-
if (SearchSysCacheExists2(STATEXTNAMENSP,
86-
NameGetDatum(&stxname),
87-
ObjectIdGetDatum(namespaceId)))
88-
{
89-
if (stmt->if_not_exists)
90-
{
91-
ereport(NOTICE,
92-
(errcode(ERRCODE_DUPLICATE_OBJECT),
93-
errmsg("statistics object \"%s\" already exists, skipping",
94-
namestr)));
95-
returnInvalidObjectAddress;
96-
}
97-
98-
ereport(ERROR,
99-
(errcode(ERRCODE_DUPLICATE_OBJECT),
100-
errmsg("statistics object \"%s\" already exists",namestr)));
101-
}
102-
10383
/*
10484
* Examine the FROM clause. Currently, we only allow it to be a single
10585
* simple table, but later we'll probably allow multiple tables and JOIN
@@ -148,6 +128,45 @@ CreateStatistics(CreateStatsStmt *stmt)
148128
Assert(rel);
149129
relid=RelationGetRelid(rel);
150130

131+
/*
132+
* If the node has a name, split it up and determine creation namespace.
133+
* If not (a possibility not considered by the grammar, but one which can
134+
* occur via the "CREATE TABLE ... (LIKE)" command), then we put the
135+
* object in the same namespace as the relation, and cons up a name for it.
136+
*/
137+
if (stmt->defnames)
138+
namespaceId=QualifiedNameGetCreationNamespace(stmt->defnames,&namestr);
139+
else
140+
{
141+
namespaceId=RelationGetNamespace(rel);
142+
namestr=ChooseExtendedStatisticName(RelationGetRelationName(rel),
143+
ChooseExtendedStatisticNameAddition(stmt->exprs),
144+
"stat",
145+
namespaceId);
146+
}
147+
148+
/*
149+
* Deal with the possibility that the statistics object already exists.
150+
*/
151+
if (SearchSysCacheExists2(STATEXTNAMENSP,
152+
CStringGetDatum(namestr),
153+
ObjectIdGetDatum(namespaceId)))
154+
{
155+
if (stmt->if_not_exists)
156+
{
157+
ereport(NOTICE,
158+
(errcode(ERRCODE_DUPLICATE_OBJECT),
159+
errmsg("statistics object \"%s\" already exists, skipping",
160+
namestr)));
161+
relation_close(rel,NoLock);
162+
returnInvalidObjectAddress;
163+
}
164+
165+
ereport(ERROR,
166+
(errcode(ERRCODE_DUPLICATE_OBJECT),
167+
errmsg("statistics object \"%s\" already exists",namestr)));
168+
}
169+
151170
/*
152171
* Currently, we only allow simple column references in the expression
153172
* list. That will change someday, and again the grammar already supports
@@ -288,7 +307,7 @@ CreateStatistics(CreateStatsStmt *stmt)
288307
memset(values,0,sizeof(values));
289308
memset(nulls, false,sizeof(nulls));
290309
values[Anum_pg_statistic_ext_stxrelid-1]=ObjectIdGetDatum(relid);
291-
values[Anum_pg_statistic_ext_stxname-1]=NameGetDatum(&stxname);
310+
values[Anum_pg_statistic_ext_stxname-1]=CStringGetDatum(namestr);
292311
values[Anum_pg_statistic_ext_stxnamespace-1]=ObjectIdGetDatum(namespaceId);
293312
values[Anum_pg_statistic_ext_stxowner-1]=ObjectIdGetDatum(stxowner);
294313
values[Anum_pg_statistic_ext_stxkeys-1]=PointerGetDatum(stxkeys);
@@ -340,6 +359,11 @@ CreateStatistics(CreateStatsStmt *stmt)
340359
* STATISTICS, which is more work than it seems worth.
341360
*/
342361

362+
/* Add any requested comment */
363+
if (stmt->stxcomment!=NULL)
364+
CreateComments(statoid,StatisticExtRelationId,0,
365+
stmt->stxcomment);
366+
343367
/* Return stats object's address */
344368
returnmyself;
345369
}
@@ -405,3 +429,94 @@ UpdateStatisticsForTypeChange(Oid statsOid, Oid relationOid, int attnum,
405429
* Future types of extended stats will likely require us to work harder.
406430
*/
407431
}
432+
433+
/*
434+
* Select a nonconflicting name for a new statistics.
435+
*
436+
* name1, name2, and label are used the same way as for makeObjectName(),
437+
* except that the label can't be NULL; digits will be appended to the label
438+
* if needed to create a name that is unique within the specified namespace.
439+
*
440+
* Returns a palloc'd string.
441+
*
442+
* Note: it is theoretically possible to get a collision anyway, if someone
443+
* else chooses the same name concurrently. This is fairly unlikely to be
444+
* a problem in practice, especially if one is holding a share update
445+
* exclusive lock on the relation identified by name1. However, if choosing
446+
* multiple names within a single command, you'd better create the new object
447+
* and do CommandCounterIncrement before choosing the next one!
448+
*/
449+
staticchar*
450+
ChooseExtendedStatisticName(constchar*name1,constchar*name2,
451+
constchar*label,Oidnamespaceid)
452+
{
453+
intpass=0;
454+
char*stxname=NULL;
455+
charmodlabel[NAMEDATALEN];
456+
457+
/* try the unmodified label first */
458+
StrNCpy(modlabel,label,sizeof(modlabel));
459+
460+
for (;;)
461+
{
462+
Oidexistingstats;
463+
464+
stxname=makeObjectName(name1,name2,modlabel);
465+
466+
existingstats=GetSysCacheOid2(STATEXTNAMENSP,
467+
PointerGetDatum(stxname),
468+
ObjectIdGetDatum(namespaceid));
469+
if (!OidIsValid(existingstats))
470+
break;
471+
472+
/* found a conflict, so try a new name component */
473+
pfree(stxname);
474+
snprintf(modlabel,sizeof(modlabel),"%s%d",label,++pass);
475+
}
476+
477+
returnstxname;
478+
}
479+
480+
/*
481+
* Generate "name2" for a new statistics given the list of column names for it
482+
* This will be passed to ChooseExtendedStatisticName along with the parent
483+
* table name and a suitable label.
484+
*
485+
* We know that less than NAMEDATALEN characters will actually be used,
486+
* so we can truncate the result once we've generated that many.
487+
*
488+
* XXX see also ChooseIndexNameAddition.
489+
*/
490+
staticchar*
491+
ChooseExtendedStatisticNameAddition(List*exprs)
492+
{
493+
charbuf[NAMEDATALEN*2];
494+
intbuflen=0;
495+
ListCell*lc;
496+
497+
buf[0]='\0';
498+
foreach(lc,exprs)
499+
{
500+
ColumnRef*cref= (ColumnRef*)lfirst(lc);
501+
constchar*name;
502+
503+
/* It should be one of these, but just skip if it happens not to be */
504+
if (!IsA(cref,ColumnRef))
505+
continue;
506+
507+
name=strVal((Value*)linitial(cref->fields));
508+
509+
if (buflen>0)
510+
buf[buflen++]='_';/* insert _ between names */
511+
512+
/*
513+
* At this point we have buflen <= NAMEDATALEN. name should be less
514+
* than NAMEDATALEN already, but use strlcpy for paranoia.
515+
*/
516+
strlcpy(buf+buflen,name,NAMEDATALEN);
517+
buflen+=strlen(buf+buflen);
518+
if (buflen >=NAMEDATALEN)
519+
break;
520+
}
521+
returnpstrdup(buf);
522+
}

‎src/backend/nodes/copyfuncs.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3424,6 +3424,7 @@ _copyCreateStatsStmt(const CreateStatsStmt *from)
34243424
COPY_NODE_FIELD(stat_types);
34253425
COPY_NODE_FIELD(exprs);
34263426
COPY_NODE_FIELD(relations);
3427+
COPY_STRING_FIELD(stxcomment);
34273428
COPY_SCALAR_FIELD(if_not_exists);
34283429

34293430
returnnewnode;

‎src/backend/nodes/equalfuncs.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1363,6 +1363,7 @@ _equalCreateStatsStmt(const CreateStatsStmt *a, const CreateStatsStmt *b)
13631363
COMPARE_NODE_FIELD(stat_types);
13641364
COMPARE_NODE_FIELD(exprs);
13651365
COMPARE_NODE_FIELD(relations);
1366+
COMPARE_STRING_FIELD(stxcomment);
13661367
COMPARE_SCALAR_FIELD(if_not_exists);
13671368

13681369
return true;

‎src/backend/nodes/outfuncs.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2687,6 +2687,7 @@ _outCreateStatsStmt(StringInfo str, const CreateStatsStmt *node)
26872687
WRITE_NODE_FIELD(stat_types);
26882688
WRITE_NODE_FIELD(exprs);
26892689
WRITE_NODE_FIELD(relations);
2690+
WRITE_STRING_FIELD(stxcomment);
26902691
WRITE_BOOL_FIELD(if_not_exists);
26912692
}
26922693

‎src/backend/parser/gram.y

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3636,12 +3636,13 @@ TableLikeOptionList:
36363636
;
36373637

36383638
TableLikeOption:
3639-
DEFAULTS{$$ =CREATE_TABLE_LIKE_DEFAULTS; }
3639+
COMMENTS{$$ =CREATE_TABLE_LIKE_COMMENTS; }
36403640
|CONSTRAINTS{$$ = CREATE_TABLE_LIKE_CONSTRAINTS; }
3641+
|DEFAULTS{$$ = CREATE_TABLE_LIKE_DEFAULTS; }
36413642
|IDENTITY_P{$$ = CREATE_TABLE_LIKE_IDENTITY; }
36423643
|INDEXES{$$ = CREATE_TABLE_LIKE_INDEXES; }
3644+
|STATISTICS{$$ = CREATE_TABLE_LIKE_STATISTICS; }
36433645
|STORAGE{$$ = CREATE_TABLE_LIKE_STORAGE; }
3644-
|COMMENTS{$$ = CREATE_TABLE_LIKE_COMMENTS; }
36453646
|ALL{$$ = CREATE_TABLE_LIKE_ALL; }
36463647
;
36473648

@@ -3980,6 +3981,7 @@ CreateStatsStmt:
39803981
n->stat_types =$4;
39813982
n->exprs =$6;
39823983
n->relations =$8;
3984+
n->stxcomment =NULL;
39833985
n->if_not_exists =false;
39843986
$$ = (Node *)n;
39853987
}
@@ -3991,6 +3993,7 @@ CreateStatsStmt:
39913993
n->stat_types =$7;
39923994
n->exprs =$9;
39933995
n->relations =$11;
3996+
n->stxcomment =NULL;
39943997
n->if_not_exists =true;
39953998
$$ = (Node *)n;
39963999
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp