On 04/11/16 14:00, Andres Freund wrote:
> Hi,
> 
> + <sect1 id="catalog-pg-publication-rel">
> +  <title><structname>pg_publication_rel</structname></title>
> +
> +  <indexterm zone="catalog-pg-publication-rel">
> +   <primary>pg_publication_rel</primary>
> +  </indexterm>
> +
> +  <para>
> +   The <structname>pg_publication_rel</structname> catalog contains
> +   mapping between tables and publications in the database. This is many to
> +   many mapping.
> +  </para>
> 
> I wonder if we shouldn't abstract this a bit away from relations to
> allow other objects to be exported to. Could structure it a bit more
> like pg_depend.
> 

Honestly, let's not overdesign this. Change like that can be made in the
future if we need it and I am quite unconvinced we do given that
anything we might want to replicate will be relation. I understand that
it might be useful to know what's on downstream in terms of objects at
some point for some future functionality,  but I am don't have idea how
that functionality will look like so it's premature to guess what
catalog structure it will need.

> 
> +ALTER PUBLICATION <replaceable class="PARAMETER">name</replaceable> [ [ WITH 
> ] <replaceable class="PARAMETER">option</replaceable> [ ... ] ]
> +
> +<phrase>where <replaceable class="PARAMETER">option</replaceable> can 
> be:</phrase>
> +
> +      PuBLISH_INSERT | NOPuBLISH_INSERT
> +    | PuBLISH_UPDATE | NOPuBLISH_UPDATE
> +    | PuBLISH_DELETE | NOPuBLISH_DELETE
> 
> That's odd casing.
> 
> 
> +   <varlistentry>
> +    <term><literal>PuBLISH_INSERT</literal></term>
> +    <term><literal>NOPuBLISH_INSERT</literal></term>
> +    <term><literal>PuBLISH_UPDATE</literal></term>
> +    <term><literal>NOPuBLISH_UPDATE</literal></term>
> +    <term><literal>PuBLISH_DELETE</literal></term>
> +    <term><literal>NOPuBLISH_DELETE</literal></term>
> 

Ah typo in my sed script, fun.

> More odd casing.
> 
> +   <varlistentry>
> +    <term><literal>FOR TABLE</literal></term>
> +    <listitem>
> +     <para>
> +      Specifies optional list of tables to add to the publication.
> +     </para>
> +    </listitem>
> +   </varlistentry>
> +
> +   <varlistentry>
> +    <term><literal>FOR TABLE ALL IN SCHEMA</literal></term>
> +    <listitem>
> +     <para>
> +      Specifies optional schema for which all logged tables will be added to
> +      publication.
> +     </para>
> +    </listitem>
> +   </varlistentry>
> 
> "FOR TABLE ALL IN SCHEMA" sounds weird.
> 

I actually removed support for this at some point, forgot to remove
docs. I might add this feature again in the future but I reckon we can
live without it in v1.


> +  <para>
> +   This operation does not reserve any resources on the server. It only
> +   defines grouping and filtering logic for future subscribers.
> +  </para>
> 
> That's strictly speaking not true, maybe rephrase a bit?
> 

Sure, this basically is supposed to mean that it does not really start
replication or keep wal or anything like that as opposed what for
example slots do.

> +/*
> + * Check if relation can be in given publication and throws appropriate
> + * error if not.
> + */
> +static void
> +check_publication_add_relation(Relation targetrel)
> +{
> +     /* Must be table */
> +     if (RelationGetForm(targetrel)->relkind != RELKIND_RELATION)
> +             ereport(ERROR,
> +                             (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
> +                              errmsg("only tables can be added to 
> publication"),
> +                              errdetail("%s is not a table",
> +                                                
> RelationGetRelationName(targetrel))));
> +
> +     /* Can't be system table */
> +     if (IsCatalogRelation(targetrel))
> +             ereport(ERROR,
> +                             (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
> +                              errmsg("only user tables can be added to 
> publication"),
> +                              errdetail("%s is a system table",
> +                                                
> RelationGetRelationName(targetrel))));
> +
> +     /* UNLOGGED and TEMP relations cannot be part of publication. */
> +     if (!RelationNeedsWAL(targetrel))
> +             ereport(ERROR,
> +                             (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
> +                              errmsg("UNLOGGED and TEMP relations cannot be 
> replicated")));
> +}
> 
> This probably means we need a check in the ALTER TABLE ... SET UNLOGGED
> path.
> 

Good point.

> 
> +/*
> + * Returns if relation represented by oid and Form_pg_class entry
> + * is publishable.
> + *
> + * Does same checks as the above, but does not need relation to be opened
> + * and also does not throw errors.
> + */
> +static bool
> +is_publishable_class(Oid relid, Form_pg_class reltuple)
> +{
> +     return reltuple->relkind == RELKIND_RELATION &&
> +             !IsCatalogClass(relid, reltuple) &&
> +             reltuple->relpersistence == RELPERSISTENCE_PERMANENT &&
> +             /* XXX needed to exclude information_schema tables */
> +             relid >= FirstNormalObjectId;
> +}
> 
> Shouldn't that be IsCatalogRelation() instead?
> 

Well IsCatalogRelation just calls IsCatalogClass and we call
IsCatalogClass here as well. The problem with IsCatalogClass is that it
does not consider tables in information_schema that were created as part
of initdb to be system catalogs because it first does negative check on
pg_catalog and toast schemas and only then considers
FirstNormalObjectId. I was actually wondering if that might be a bug in
IsCatalogClass.

> 
> +/*
> + * Create new publication.
> + * TODO ACL check
> + */
> 

That was meant for future enhancements, but I think I'll don't do
detailed ACLs in v1 so I'll remove that TODO.

> +
> +/*
> + * Drop publication by OID
> + */
> +void
> +DropPublicationById(Oid pubid)
> +
> +/*
> + * Remove relation from publication by mapping OID.
> + */
> +void
> +RemovePublicationRelById(Oid proid)
> +{
> 
> Permission checks?
> 
> +}
> 
> Hm. Neither of these does dependency checking, wonder if that can be
> argued to be problematic.
> 

As PeterE said, that's done by caller, none of the Drop...ById does
dependency checks.

> +publication_opt_item:
> +                     IDENT
> +                             {
> +                                     /*
> +                                      * We handle identifiers that aren't 
> parser keywords with
> +                                      * the following special-case codes, to 
> avoid bloating the
> +                                      * size of the main parser.
> +                                      */
> +                                     if (strcmp($1, "publish_insert") == 0)
> +                                             $$ = 
> makeDefElem("publish_insert",
> +                                                                             
>  (Node *)makeInteger(TRUE), @1);
> +                                     else if (strcmp($1, "nopublish_insert") 
> == 0)
> +                                             $$ = 
> makeDefElem("publish_insert",
> +                                                                             
>  (Node *)makeInteger(FALSE), @1);
> +                                     else if (strcmp($1, "publish_update") 
> == 0)
> +                                             $$ = 
> makeDefElem("publish_update",
> +                                                                             
>  (Node *)makeInteger(TRUE), @1);
> +                                     else if (strcmp($1, "nopublish_update") 
> == 0)
> +                                             $$ = 
> makeDefElem("publish_update",
> +                                                                             
>  (Node *)makeInteger(FALSE), @1);
> +                                     else if (strcmp($1, "publish_delete") 
> == 0)
> +                                             $$ = 
> makeDefElem("publish_delete",
> +                                                                             
>  (Node *)makeInteger(TRUE), @1);
> +                                     else if (strcmp($1, "nopublish_delete") 
> == 0)
> +                                             $$ = 
> makeDefElem("publish_delete",
> +                                                                             
>  (Node *)makeInteger(FALSE), @1);
> +                                     else
> +                                             ereport(ERROR,
> +                                                             
> (errcode(ERRCODE_SYNTAX_ERROR),
> +                                                              
> errmsg("unrecognized publication option \"%s\"", $1),
> +                                                                      
> parser_errposition(@1)));
> +                             }
> +             ;
> 
> I still would very much like to move this outside of gram.y and just use
> IDENTs here. Like how COPY options are handled.
> 

Well, I looked into it and it means some loss of info in the error
messages - mainly the error position in the query because utility
statements don't get ParseState (unlike COPY). It might be worth the
flexibility though.

> 
> 
> +CATALOG(pg_publication,6104)
> +{
> +     NameData        pubname;                        /* name of the 
> publication */
> +
> +     /*
> +      * indicates that this is special publication which should encompass
> +      * all tables in the database (except for the unlogged and temp ones)
> +      */
> +     bool            puballtables;
> +
> +     /* true if inserts are published */
> +     bool            pubinsert;
> +
> +     /* true if updates are published */
> +     bool            pubupdate;
> +
> +     /* true if deletes are published */
> +     bool            pubdelete;
> +
> +} FormData_pg_publication;
> 
> Shouldn't this have an owner? 

Probably, I wanted to do that as follow-up patch originally, but looks
like it should be in initial version.

>  I also wonder if we want an easier to
> extend form of pubinsert/update/delete (say to add pubddl, pubtruncate,
> pub ... without changing the schema).
> 

So like, text array that's then parsed everywhere (I am not doing
bitmask/int definitely)?

> 
> +/* ----------------
> + *           pg_publication_rel definition.  cpp turns this into
> + *           typedef struct FormData_pg_publication_rel
> + *
> + * ----------------
> + */
> +#define PublicationRelRelationId                             6106
> +
> +CATALOG(pg_publication_rel,6106)
> +{
> +     Oid             prpubid;                                /* Oid of the 
> publication */
> +     Oid             prrelid;                                /* Oid of the 
> relation */
> +} FormData_pg_publication_rel;
> 
> To me it seems like a good idea to have objclassid/objsubid here.
> 

You said that in the beginning, but again I am not quite convinced of
that yet. i guess if PeterE will move the sequence patches all the way
and we might lose the notion that sequences are relation (not sure if
that's where he is ultimately going though), that might make sense,
otherwise, don't really think this we need that.


-- 
  Petr Jelinek                  http://www.2ndQuadrant.com/
  PostgreSQL Development, 24x7 Support, Training & Services


-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to