Age Owner Branch data TLA Line data Source code
1 : : /*-------------------------------------------------------------------------
2 : : *
3 : : * pg_subscription.c
4 : : * replication subscriptions
5 : : *
6 : : * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
7 : : * Portions Copyright (c) 1994, Regents of the University of California
8 : : *
9 : : * IDENTIFICATION
10 : : * src/backend/catalog/pg_subscription.c
11 : : *
12 : : *-------------------------------------------------------------------------
13 : : */
14 : :
15 : : #include "postgres.h"
16 : :
17 : : #include "access/genam.h"
18 : : #include "access/heapam.h"
19 : : #include "access/htup_details.h"
20 : : #include "access/tableam.h"
21 : : #include "catalog/indexing.h"
22 : : #include "catalog/pg_subscription.h"
23 : : #include "catalog/pg_subscription_rel.h"
24 : : #include "catalog/pg_type.h"
25 : : #include "miscadmin.h"
26 : : #include "storage/lmgr.h"
27 : : #include "utils/array.h"
28 : : #include "utils/builtins.h"
29 : : #include "utils/fmgroids.h"
30 : : #include "utils/lsyscache.h"
31 : : #include "utils/pg_lsn.h"
32 : : #include "utils/rel.h"
33 : : #include "utils/syscache.h"
34 : :
35 : : static List *textarray_to_stringlist(ArrayType *textarray);
36 : :
37 : : /*
38 : : * Fetch the subscription from the syscache.
39 : : */
40 : : Subscription *
2642 peter_e@gmx.net 41 :CBC 727 : GetSubscription(Oid subid, bool missing_ok)
42 : : {
43 : : HeapTuple tup;
44 : : Subscription *sub;
45 : : Form_pg_subscription subform;
46 : : Datum datum;
47 : : bool isnull;
48 : :
49 : 727 : tup = SearchSysCache1(SUBSCRIPTIONOID, ObjectIdGetDatum(subid));
50 : :
51 [ - + ]: 727 : if (!HeapTupleIsValid(tup))
52 : : {
2642 peter_e@gmx.net 53 [ # # ]:UBC 0 : if (missing_ok)
54 : 0 : return NULL;
55 : :
56 [ # # ]: 0 : elog(ERROR, "cache lookup failed for subscription %u", subid);
57 : : }
58 : :
2642 peter_e@gmx.net 59 :CBC 727 : subform = (Form_pg_subscription) GETSTRUCT(tup);
60 : :
61 : 727 : sub = (Subscription *) palloc(sizeof(Subscription));
62 : 727 : sub->oid = subid;
63 : 727 : sub->dbid = subform->subdbid;
738 akapila@postgresql.o 64 : 727 : sub->skiplsn = subform->subskiplsn;
2642 peter_e@gmx.net 65 : 727 : sub->name = pstrdup(NameStr(subform->subname));
66 : 727 : sub->owner = subform->subowner;
67 : 727 : sub->enabled = subform->subenabled;
1366 tgl@sss.pgh.pa.us 68 : 727 : sub->binary = subform->subbinary;
1319 akapila@postgresql.o 69 : 727 : sub->stream = subform->substream;
1005 70 : 727 : sub->twophasestate = subform->subtwophasestate;
762 71 : 727 : sub->disableonerr = subform->subdisableonerr;
381 rhaas@postgresql.org 72 : 727 : sub->passwordrequired = subform->subpasswordrequired;
376 73 : 727 : sub->runasowner = subform->subrunasowner;
75 akapila@postgresql.o 74 :GNC 727 : sub->failover = subform->subfailover;
75 : :
76 : : /* Get conninfo */
386 dgustafsson@postgres 77 :CBC 727 : datum = SysCacheGetAttrNotNull(SUBSCRIPTIONOID,
78 : : tup,
79 : : Anum_pg_subscription_subconninfo);
2557 peter_e@gmx.net 80 : 727 : sub->conninfo = TextDatumGetCString(datum);
81 : :
82 : : /* Get slotname */
2642 83 : 727 : datum = SysCacheGetAttr(SUBSCRIPTIONOID,
84 : : tup,
85 : : Anum_pg_subscription_subslotname,
86 : : &isnull);
2532 87 [ + + ]: 727 : if (!isnull)
88 : 694 : sub->slotname = pstrdup(NameStr(*DatumGetName(datum)));
89 : : else
90 : 33 : sub->slotname = NULL;
91 : :
92 : : /* Get synccommit */
386 dgustafsson@postgres 93 : 727 : datum = SysCacheGetAttrNotNull(SUBSCRIPTIONOID,
94 : : tup,
95 : : Anum_pg_subscription_subsynccommit);
2557 peter_e@gmx.net 96 : 727 : sub->synccommit = TextDatumGetCString(datum);
97 : :
98 : : /* Get publications */
386 dgustafsson@postgres 99 : 727 : datum = SysCacheGetAttrNotNull(SUBSCRIPTIONOID,
100 : : tup,
101 : : Anum_pg_subscription_subpublications);
2642 peter_e@gmx.net 102 : 727 : sub->publications = textarray_to_stringlist(DatumGetArrayTypeP(datum));
103 : :
104 : : /* Get origin */
386 dgustafsson@postgres 105 : 727 : datum = SysCacheGetAttrNotNull(SUBSCRIPTIONOID,
106 : : tup,
107 : : Anum_pg_subscription_suborigin);
633 akapila@postgresql.o 108 : 727 : sub->origin = TextDatumGetCString(datum);
109 : :
110 : : /* Is the subscription owner a superuser? */
180 akapila@postgresql.o 111 :GNC 727 : sub->ownersuperuser = superuser_arg(sub->owner);
112 : :
2642 peter_e@gmx.net 113 :CBC 727 : ReleaseSysCache(tup);
114 : :
115 : 727 : return sub;
116 : : }
117 : :
118 : : /*
119 : : * Return number of subscriptions defined in given database.
120 : : * Used by dropdb() to check if database can indeed be dropped.
121 : : */
122 : : int
123 : 30 : CountDBSubscriptions(Oid dbid)
124 : : {
2524 bruce@momjian.us 125 : 30 : int nsubs = 0;
126 : : Relation rel;
127 : : ScanKeyData scankey;
128 : : SysScanDesc scan;
129 : : HeapTuple tup;
130 : :
1910 andres@anarazel.de 131 : 30 : rel = table_open(SubscriptionRelationId, RowExclusiveLock);
132 : :
2642 peter_e@gmx.net 133 : 30 : ScanKeyInit(&scankey,
134 : : Anum_pg_subscription_subdbid,
135 : : BTEqualStrategyNumber, F_OIDEQ,
136 : : ObjectIdGetDatum(dbid));
137 : :
138 : 30 : scan = systable_beginscan(rel, InvalidOid, false,
139 : : NULL, 1, &scankey);
140 : :
141 [ - + ]: 30 : while (HeapTupleIsValid(tup = systable_getnext(scan)))
2642 peter_e@gmx.net 142 :UBC 0 : nsubs++;
143 : :
2642 peter_e@gmx.net 144 :CBC 30 : systable_endscan(scan);
145 : :
1910 andres@anarazel.de 146 : 30 : table_close(rel, NoLock);
147 : :
2642 peter_e@gmx.net 148 : 30 : return nsubs;
149 : : }
150 : :
151 : : /*
152 : : * Free memory allocated by subscription struct.
153 : : */
154 : : void
155 : 34 : FreeSubscription(Subscription *sub)
156 : : {
157 : 34 : pfree(sub->name);
158 : 34 : pfree(sub->conninfo);
2532 159 [ + - ]: 34 : if (sub->slotname)
160 : 34 : pfree(sub->slotname);
2642 161 : 34 : list_free_deep(sub->publications);
162 : 34 : pfree(sub);
163 : 34 : }
164 : :
165 : : /*
166 : : * Disable the given subscription.
167 : : */
168 : : void
762 akapila@postgresql.o 169 : 4 : DisableSubscription(Oid subid)
170 : : {
171 : : Relation rel;
172 : : bool nulls[Natts_pg_subscription];
173 : : bool replaces[Natts_pg_subscription];
174 : : Datum values[Natts_pg_subscription];
175 : : HeapTuple tup;
176 : :
177 : : /* Look up the subscription in the catalog */
178 : 4 : rel = table_open(SubscriptionRelationId, RowExclusiveLock);
179 : 4 : tup = SearchSysCacheCopy1(SUBSCRIPTIONOID, ObjectIdGetDatum(subid));
180 : :
181 [ - + ]: 4 : if (!HeapTupleIsValid(tup))
762 akapila@postgresql.o 182 [ # # ]:UBC 0 : elog(ERROR, "cache lookup failed for subscription %u", subid);
183 : :
762 akapila@postgresql.o 184 :CBC 4 : LockSharedObject(SubscriptionRelationId, subid, 0, AccessShareLock);
185 : :
186 : : /* Form a new tuple. */
187 : 4 : memset(values, 0, sizeof(values));
188 : 4 : memset(nulls, false, sizeof(nulls));
189 : 4 : memset(replaces, false, sizeof(replaces));
190 : :
191 : : /* Set the subscription to disabled. */
192 : 4 : values[Anum_pg_subscription_subenabled - 1] = BoolGetDatum(false);
193 : 4 : replaces[Anum_pg_subscription_subenabled - 1] = true;
194 : :
195 : : /* Update the catalog */
196 : 4 : tup = heap_modify_tuple(tup, RelationGetDescr(rel), values, nulls,
197 : : replaces);
198 : 4 : CatalogTupleUpdate(rel, &tup->t_self, tup);
199 : 4 : heap_freetuple(tup);
200 : :
201 : 4 : table_close(rel, NoLock);
202 : 4 : }
203 : :
204 : : /*
205 : : * Convert text array to list of strings.
206 : : *
207 : : * Note: the resulting list of strings is pallocated here.
208 : : */
209 : : static List *
2642 peter_e@gmx.net 210 : 727 : textarray_to_stringlist(ArrayType *textarray)
211 : : {
212 : : Datum *elems;
213 : : int nelems,
214 : : i;
2524 bruce@momjian.us 215 : 727 : List *res = NIL;
216 : :
653 peter@eisentraut.org 217 : 727 : deconstruct_array_builtin(textarray, TEXTOID, &elems, NULL, &nelems);
218 : :
2642 peter_e@gmx.net 219 [ - + ]: 727 : if (nelems == 0)
2642 peter_e@gmx.net 220 :UBC 0 : return NIL;
221 : :
2642 peter_e@gmx.net 222 [ + + ]:CBC 1789 : for (i = 0; i < nelems; i++)
2557 223 : 1062 : res = lappend(res, makeString(TextDatumGetCString(elems[i])));
224 : :
2642 225 : 727 : return res;
226 : : }
227 : :
228 : : /*
229 : : * Add new state record for a subscription table.
230 : : *
231 : : * If retain_lock is true, then don't release the locks taken in this function.
232 : : * We normally release the locks at the end of transaction but in binary-upgrade
233 : : * mode, we expect to release those immediately.
234 : : */
235 : : void
2200 236 : 175 : AddSubscriptionRelState(Oid subid, Oid relid, char state,
237 : : XLogRecPtr sublsn, bool retain_lock)
238 : : {
239 : : Relation rel;
240 : : HeapTuple tup;
241 : : bool nulls[Natts_pg_subscription_rel];
242 : : Datum values[Natts_pg_subscription_rel];
243 : :
2477 244 : 175 : LockSharedObject(SubscriptionRelationId, subid, 0, AccessShareLock);
245 : :
1910 andres@anarazel.de 246 : 175 : rel = table_open(SubscriptionRelRelationId, RowExclusiveLock);
247 : :
248 : : /* Try finding existing mapping. */
2579 peter_e@gmx.net 249 : 175 : tup = SearchSysCacheCopy2(SUBSCRIPTIONRELMAP,
250 : : ObjectIdGetDatum(relid),
251 : : ObjectIdGetDatum(subid));
2200 252 [ - + ]: 175 : if (HeapTupleIsValid(tup))
2200 peter_e@gmx.net 253 [ # # ]:UBC 0 : elog(ERROR, "subscription table %u in subscription %u already exists",
254 : : relid, subid);
255 : :
256 : : /* Form the tuple. */
2200 peter_e@gmx.net 257 :CBC 175 : memset(values, 0, sizeof(values));
258 : 175 : memset(nulls, false, sizeof(nulls));
259 : 175 : values[Anum_pg_subscription_rel_srsubid - 1] = ObjectIdGetDatum(subid);
260 : 175 : values[Anum_pg_subscription_rel_srrelid - 1] = ObjectIdGetDatum(relid);
261 : 175 : values[Anum_pg_subscription_rel_srsubstate - 1] = CharGetDatum(state);
262 [ + + ]: 175 : if (sublsn != InvalidXLogRecPtr)
2200 peter_e@gmx.net 263 :GBC 1 : values[Anum_pg_subscription_rel_srsublsn - 1] = LSNGetDatum(sublsn);
264 : : else
2200 peter_e@gmx.net 265 :CBC 174 : nulls[Anum_pg_subscription_rel_srsublsn - 1] = true;
266 : :
267 : 175 : tup = heap_form_tuple(RelationGetDescr(rel), values, nulls);
268 : :
269 : : /* Insert tuple into catalog. */
1972 andres@anarazel.de 270 : 175 : CatalogTupleInsert(rel, tup);
271 : :
2200 peter_e@gmx.net 272 : 175 : heap_freetuple(tup);
273 : :
274 : : /* Cleanup. */
103 akapila@postgresql.o 275 [ + + ]:GNC 175 : if (retain_lock)
276 : : {
277 : 173 : table_close(rel, NoLock);
278 : : }
279 : : else
280 : : {
281 : 2 : table_close(rel, RowExclusiveLock);
282 : 2 : UnlockSharedObject(SubscriptionRelationId, subid, 0, AccessShareLock);
283 : : }
2200 peter_e@gmx.net 284 :CBC 175 : }
285 : :
286 : : /*
287 : : * Update the state of a subscription table.
288 : : */
289 : : void
290 : 647 : UpdateSubscriptionRelState(Oid subid, Oid relid, char state,
291 : : XLogRecPtr sublsn)
292 : : {
293 : : Relation rel;
294 : : HeapTuple tup;
295 : : bool nulls[Natts_pg_subscription_rel];
296 : : Datum values[Natts_pg_subscription_rel];
297 : : bool replaces[Natts_pg_subscription_rel];
298 : :
299 : 647 : LockSharedObject(SubscriptionRelationId, subid, 0, AccessShareLock);
300 : :
1910 andres@anarazel.de 301 : 647 : rel = table_open(SubscriptionRelRelationId, RowExclusiveLock);
302 : :
303 : : /* Try finding existing mapping. */
2200 peter_e@gmx.net 304 : 647 : tup = SearchSysCacheCopy2(SUBSCRIPTIONRELMAP,
305 : : ObjectIdGetDatum(relid),
306 : : ObjectIdGetDatum(subid));
307 [ - + ]: 647 : if (!HeapTupleIsValid(tup))
2200 peter_e@gmx.net 308 [ # # ]:UBC 0 : elog(ERROR, "subscription table %u in subscription %u does not exist",
309 : : relid, subid);
310 : :
311 : : /* Update the tuple. */
2200 peter_e@gmx.net 312 :CBC 647 : memset(values, 0, sizeof(values));
313 : 647 : memset(nulls, false, sizeof(nulls));
314 : 647 : memset(replaces, false, sizeof(replaces));
315 : :
316 : 647 : replaces[Anum_pg_subscription_rel_srsubstate - 1] = true;
317 : 647 : values[Anum_pg_subscription_rel_srsubstate - 1] = CharGetDatum(state);
318 : :
319 : 647 : replaces[Anum_pg_subscription_rel_srsublsn - 1] = true;
320 [ + + ]: 647 : if (sublsn != InvalidXLogRecPtr)
321 : 318 : values[Anum_pg_subscription_rel_srsublsn - 1] = LSNGetDatum(sublsn);
322 : : else
323 : 329 : nulls[Anum_pg_subscription_rel_srsublsn - 1] = true;
324 : :
325 : 647 : tup = heap_modify_tuple(tup, RelationGetDescr(rel), values, nulls,
326 : : replaces);
327 : :
328 : : /* Update the catalog. */
329 : 647 : CatalogTupleUpdate(rel, &tup->t_self, tup);
330 : :
331 : : /* Cleanup. */
1910 andres@anarazel.de 332 : 647 : table_close(rel, NoLock);
2579 peter_e@gmx.net 333 : 647 : }
334 : :
335 : : /*
336 : : * Get state of subscription table.
337 : : *
338 : : * Returns SUBREL_STATE_UNKNOWN when the table is not in the subscription.
339 : : */
340 : : char
1277 alvherre@alvh.no-ip. 341 : 4074 : GetSubscriptionRelState(Oid subid, Oid relid, XLogRecPtr *sublsn)
342 : : {
343 : : HeapTuple tup;
344 : : char substate;
345 : : bool isnull;
346 : : Datum d;
347 : : Relation rel;
348 : :
349 : : /*
350 : : * This is to avoid the race condition with AlterSubscription which tries
351 : : * to remove this relstate.
352 : : */
1157 akapila@postgresql.o 353 : 4074 : rel = table_open(SubscriptionRelRelationId, AccessShareLock);
354 : :
355 : : /* Try finding the mapping. */
2579 peter_e@gmx.net 356 : 4074 : tup = SearchSysCache2(SUBSCRIPTIONRELMAP,
357 : : ObjectIdGetDatum(relid),
358 : : ObjectIdGetDatum(subid));
359 : :
360 [ + + ]: 4074 : if (!HeapTupleIsValid(tup))
361 : : {
1144 akapila@postgresql.o 362 : 25 : table_close(rel, AccessShareLock);
1277 alvherre@alvh.no-ip. 363 : 25 : *sublsn = InvalidXLogRecPtr;
364 : 25 : return SUBREL_STATE_UNKNOWN;
365 : : }
366 : :
367 : : /* Get the state. */
368 : 4049 : substate = ((Form_pg_subscription_rel) GETSTRUCT(tup))->srsubstate;
369 : :
370 : : /* Get the LSN */
2579 peter_e@gmx.net 371 : 4049 : d = SysCacheGetAttr(SUBSCRIPTIONRELMAP, tup,
372 : : Anum_pg_subscription_rel_srsublsn, &isnull);
373 [ + + ]: 4049 : if (isnull)
374 : 3572 : *sublsn = InvalidXLogRecPtr;
375 : : else
376 : 477 : *sublsn = DatumGetLSN(d);
377 : :
378 : : /* Cleanup */
379 : 4049 : ReleaseSysCache(tup);
380 : :
1157 akapila@postgresql.o 381 : 4049 : table_close(rel, AccessShareLock);
382 : :
2579 peter_e@gmx.net 383 : 4049 : return substate;
384 : : }
385 : :
386 : : /*
387 : : * Drop subscription relation mapping. These can be for a particular
388 : : * subscription, or for a particular relation, or both.
389 : : */
390 : : void
391 : 21144 : RemoveSubscriptionRel(Oid subid, Oid relid)
392 : : {
393 : : Relation rel;
394 : : TableScanDesc scan;
395 : : ScanKeyData skey[2];
396 : : HeapTuple tup;
397 : 21144 : int nkeys = 0;
398 : :
1910 andres@anarazel.de 399 : 21144 : rel = table_open(SubscriptionRelRelationId, RowExclusiveLock);
400 : :
2579 peter_e@gmx.net 401 [ + + ]: 21144 : if (OidIsValid(subid))
402 : : {
403 : 105 : ScanKeyInit(&skey[nkeys++],
404 : : Anum_pg_subscription_rel_srsubid,
405 : : BTEqualStrategyNumber,
406 : : F_OIDEQ,
407 : : ObjectIdGetDatum(subid));
408 : : }
409 : :
410 [ + + ]: 21144 : if (OidIsValid(relid))
411 : : {
412 : 21057 : ScanKeyInit(&skey[nkeys++],
413 : : Anum_pg_subscription_rel_srrelid,
414 : : BTEqualStrategyNumber,
415 : : F_OIDEQ,
416 : : ObjectIdGetDatum(relid));
417 : : }
418 : :
419 : : /* Do the search and delete what we found. */
1861 andres@anarazel.de 420 : 21144 : scan = table_beginscan_catalog(rel, nkeys, skey);
2579 peter_e@gmx.net 421 [ + + ]: 21230 : while (HeapTupleIsValid(tup = heap_getnext(scan, ForwardScanDirection)))
422 : : {
423 : : Form_pg_subscription_rel subrel;
424 : :
1157 akapila@postgresql.o 425 : 86 : subrel = (Form_pg_subscription_rel) GETSTRUCT(tup);
426 : :
427 : : /*
428 : : * We don't allow to drop the relation mapping when the table
429 : : * synchronization is in progress unless the caller updates the
430 : : * corresponding subscription as well. This is to ensure that we don't
431 : : * leave tablesync slots or origins in the system when the
432 : : * corresponding table is dropped.
433 : : */
434 [ + + - + ]: 86 : if (!OidIsValid(subid) && subrel->srsubstate != SUBREL_STATE_READY)
435 : : {
1157 akapila@postgresql.o 436 [ # # ]:UBC 0 : ereport(ERROR,
437 : : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
438 : : errmsg("could not drop relation mapping for subscription \"%s\"",
439 : : get_subscription_name(subrel->srsubid, false)),
440 : : errdetail("Table synchronization for relation \"%s\" is in progress and is in state \"%c\".",
441 : : get_rel_name(relid), subrel->srsubstate),
442 : :
443 : : /*
444 : : * translator: first %s is a SQL ALTER command and second %s is a
445 : : * SQL DROP command
446 : : */
447 : : errhint("Use %s to enable subscription if not already enabled or use %s to drop the subscription.",
448 : : "ALTER SUBSCRIPTION ... ENABLE",
449 : : "DROP SUBSCRIPTION ...")));
450 : : }
451 : :
2496 tgl@sss.pgh.pa.us 452 :CBC 86 : CatalogTupleDelete(rel, &tup->t_self);
453 : : }
1861 andres@anarazel.de 454 : 21144 : table_endscan(scan);
455 : :
1910 456 : 21144 : table_close(rel, RowExclusiveLock);
2579 peter_e@gmx.net 457 : 21144 : }
458 : :
459 : : /*
460 : : * Does the subscription have any relations?
461 : : *
462 : : * Use this function only to know true/false, and when you have no need for the
463 : : * List returned by GetSubscriptionRelations.
464 : : */
465 : : bool
1005 akapila@postgresql.o 466 : 205 : HasSubscriptionRelations(Oid subid)
467 : : {
468 : : Relation rel;
469 : : ScanKeyData skey[1];
470 : : SysScanDesc scan;
471 : : bool has_subrels;
472 : :
473 : 205 : rel = table_open(SubscriptionRelRelationId, AccessShareLock);
474 : :
475 : 205 : ScanKeyInit(&skey[0],
476 : : Anum_pg_subscription_rel_srsubid,
477 : : BTEqualStrategyNumber, F_OIDEQ,
478 : : ObjectIdGetDatum(subid));
479 : :
480 : 205 : scan = systable_beginscan(rel, InvalidOid, false,
481 : : NULL, 1, skey);
482 : :
483 : : /* If even a single tuple exists then the subscription has tables. */
484 : 205 : has_subrels = HeapTupleIsValid(systable_getnext(scan));
485 : :
486 : : /* Cleanup */
487 : 205 : systable_endscan(scan);
488 : 205 : table_close(rel, AccessShareLock);
489 : :
490 : 205 : return has_subrels;
491 : : }
492 : :
493 : : /*
494 : : * Get the relations for the subscription.
495 : : *
496 : : * If not_ready is true, return only the relations that are not in a ready
497 : : * state, otherwise return all the relations of the subscription. The
498 : : * returned list is palloc'ed in the current memory context.
499 : : */
500 : : List *
627 michael@paquier.xyz 501 : 851 : GetSubscriptionRelations(Oid subid, bool not_ready)
502 : : {
2579 peter_e@gmx.net 503 : 851 : List *res = NIL;
504 : : Relation rel;
505 : : HeapTuple tup;
506 : 851 : int nkeys = 0;
507 : : ScanKeyData skey[2];
508 : : SysScanDesc scan;
509 : :
1910 andres@anarazel.de 510 : 851 : rel = table_open(SubscriptionRelRelationId, AccessShareLock);
511 : :
2579 peter_e@gmx.net 512 : 851 : ScanKeyInit(&skey[nkeys++],
513 : : Anum_pg_subscription_rel_srsubid,
514 : : BTEqualStrategyNumber, F_OIDEQ,
515 : : ObjectIdGetDatum(subid));
516 : :
627 michael@paquier.xyz 517 [ + + ]: 851 : if (not_ready)
518 : 823 : ScanKeyInit(&skey[nkeys++],
519 : : Anum_pg_subscription_rel_srsubstate,
520 : : BTEqualStrategyNumber, F_CHARNE,
521 : : CharGetDatum(SUBREL_STATE_READY));
522 : :
2579 peter_e@gmx.net 523 : 851 : scan = systable_beginscan(rel, InvalidOid, false,
524 : : NULL, nkeys, skey);
525 : :
526 [ + + ]: 2145 : while (HeapTupleIsValid(tup = systable_getnext(scan)))
527 : : {
528 : : Form_pg_subscription_rel subrel;
529 : : SubscriptionRelState *relstate;
530 : : Datum d;
531 : : bool isnull;
532 : :
533 : 1294 : subrel = (Form_pg_subscription_rel) GETSTRUCT(tup);
534 : :
2524 bruce@momjian.us 535 : 1294 : relstate = (SubscriptionRelState *) palloc(sizeof(SubscriptionRelState));
2579 peter_e@gmx.net 536 : 1294 : relstate->relid = subrel->srrelid;
537 : 1294 : relstate->state = subrel->srsubstate;
1364 tgl@sss.pgh.pa.us 538 : 1294 : d = SysCacheGetAttr(SUBSCRIPTIONRELMAP, tup,
539 : : Anum_pg_subscription_rel_srsublsn, &isnull);
540 [ + + ]: 1294 : if (isnull)
541 : 1053 : relstate->lsn = InvalidXLogRecPtr;
542 : : else
543 : 241 : relstate->lsn = DatumGetLSN(d);
544 : :
2579 peter_e@gmx.net 545 : 1294 : res = lappend(res, relstate);
546 : : }
547 : :
548 : : /* Cleanup */
549 : 851 : systable_endscan(scan);
1910 andres@anarazel.de 550 : 851 : table_close(rel, AccessShareLock);
551 : :
2579 peter_e@gmx.net 552 : 851 : return res;
553 : : }
|