/* * Create a new logical slot, with invalid LSN and xid, directly. This does not * use the snapshot builder or logical decoding machinery. It's only intended * for creating a slot on a replica that mirrors the state of a slot on an * upstream master. * * Note that this is test harness code. You shouldn't expose slot internals * to SQL like this for any real world usage. See the README. */ Datum test_slot_timelines_create_logical_slot(PG_FUNCTION_ARGS) { char *slotname = text_to_cstring(PG_GETARG_TEXT_P(0)); char *plugin = text_to_cstring(PG_GETARG_TEXT_P(1)); CheckSlotRequirements(); ReplicationSlotCreate(slotname, true, RS_PERSISTENT); /* register the plugin name with the slot */ StrNCpy(NameStr(MyReplicationSlot->data.plugin), plugin, NAMEDATALEN); /* * Initialize persistent state to placeholders to be set by * test_slot_timelines_advance_logical_slot . */ MyReplicationSlot->data.xmin = InvalidTransactionId; MyReplicationSlot->data.catalog_xmin = InvalidTransactionId; MyReplicationSlot->data.restart_lsn = InvalidXLogRecPtr; MyReplicationSlot->data.confirmed_flush = InvalidXLogRecPtr; clear_slot_transient_state(); ReplicationSlotRelease(); PG_RETURN_VOID(); }
/* * SQL function for creating a new physical (streaming replication) * replication slot. */ Datum pg_create_physical_replication_slot(PG_FUNCTION_ARGS) { Name name = PG_GETARG_NAME(0); Datum values[2]; bool nulls[2]; TupleDesc tupdesc; HeapTuple tuple; Datum result; Assert(!MyReplicationSlot); if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) elog(ERROR, "return type must be a row type"); check_permissions(); CheckSlotRequirements(); /* acquire replication slot, this will check for conflicting names */ ReplicationSlotCreate(NameStr(*name), false, RS_PERSISTENT); values[0] = NameGetDatum(&MyReplicationSlot->data.name); nulls[0] = false; nulls[1] = true; tuple = heap_form_tuple(tupdesc, values, nulls); result = HeapTupleGetDatum(tuple); ReplicationSlotRelease(); PG_RETURN_DATUM(result); }
/* * SQL function for creating a new logical replication slot. */ Datum pg_create_logical_replication_slot(PG_FUNCTION_ARGS) { Name name = PG_GETARG_NAME(0); Name plugin = PG_GETARG_NAME(1); LogicalDecodingContext *ctx = NULL; TupleDesc tupdesc; HeapTuple tuple; Datum result; Datum values[2]; bool nulls[2]; Assert(!MyReplicationSlot); if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) elog(ERROR, "return type must be a row type"); check_permissions(); CheckLogicalDecodingRequirements(); /* * Acquire a logical decoding slot, this will check for conflicting names. * Initially create it as ephemeral - that allows us to nicely handle * errors during initialization because it'll get dropped if this * transaction fails. We'll make it persistent at the end. */ ReplicationSlotCreate(NameStr(*name), true, RS_EPHEMERAL); /* * Create logical decoding context, to build the initial snapshot. */ ctx = CreateInitDecodingContext( NameStr(*plugin), NIL, logical_read_local_xlog_page, NULL, NULL); /* build initial snapshot, might take a while */ DecodingContextFindStartpoint(ctx); values[0] = CStringGetTextDatum(NameStr(MyReplicationSlot->data.name)); values[1] = LSNGetDatum(MyReplicationSlot->data.confirmed_flush); /* don't need the decoding context anymore */ FreeDecodingContext(ctx); memset(nulls, 0, sizeof(nulls)); tuple = heap_form_tuple(tupdesc, values, nulls); result = HeapTupleGetDatum(tuple); /* ok, slot is now fully created, mark it as persistent */ ReplicationSlotPersist(); ReplicationSlotRelease(); PG_RETURN_DATUM(result); }
/* * SQL function for creating a new physical (streaming replication) * replication slot. */ Datum pg_create_physical_replication_slot(PG_FUNCTION_ARGS) { Name name = PG_GETARG_NAME(0); bool immediately_reserve = PG_GETARG_BOOL(1); Datum values[2]; bool nulls[2]; TupleDesc tupdesc; HeapTuple tuple; Datum result; Assert(!MyReplicationSlot); if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) elog(ERROR, "return type must be a row type"); check_permissions(); CheckSlotRequirements(); /* acquire replication slot, this will check for conflicting names */ ReplicationSlotCreate(NameStr(*name), false, RS_PERSISTENT); values[0] = NameGetDatum(&MyReplicationSlot->data.name); nulls[0] = false; if (immediately_reserve) { /* Reserve WAL as the user asked for it */ ReplicationSlotReserveWal(); /* Write this slot to disk */ ReplicationSlotMarkDirty(); ReplicationSlotSave(); values[1] = LSNGetDatum(MyReplicationSlot->data.restart_lsn); nulls[1] = false; } else { values[0] = NameGetDatum(&MyReplicationSlot->data.name); nulls[1] = true; } tuple = heap_form_tuple(tupdesc, values, nulls); result = HeapTupleGetDatum(tuple); ReplicationSlotRelease(); PG_RETURN_DATUM(result); }