Add SQL schema for DelegationSignerData (#713)

* Add SQL schema for DelegationSignerData

* Remove join table

* Rebased on HEAD

* Rebase on head
This commit is contained in:
Shicong Huang 2020-10-09 10:22:31 -04:00 committed by GitHub
parent 035431c90d
commit 89cc3e576d
11 changed files with 242 additions and 30 deletions

View file

@ -67,6 +67,7 @@ import google.registry.model.domain.DomainCommand.Update.AddRemove;
import google.registry.model.domain.DomainCommand.Update.Change; import google.registry.model.domain.DomainCommand.Update.Change;
import google.registry.model.domain.fee.FeeUpdateCommandExtension; import google.registry.model.domain.fee.FeeUpdateCommandExtension;
import google.registry.model.domain.metadata.MetadataExtension; import google.registry.model.domain.metadata.MetadataExtension;
import google.registry.model.domain.secdns.DelegationSignerData;
import google.registry.model.domain.secdns.SecDnsUpdateExtension; import google.registry.model.domain.secdns.SecDnsUpdateExtension;
import google.registry.model.domain.superuser.DomainUpdateSuperuserExtension; import google.registry.model.domain.superuser.DomainUpdateSuperuserExtension;
import google.registry.model.eppcommon.AuthInfo; import google.registry.model.eppcommon.AuthInfo;
@ -238,10 +239,16 @@ public final class DomainUpdateFlow implements TransactionalFlow {
DomainBase.Builder domainBuilder = DomainBase.Builder domainBuilder =
domain domain
.asBuilder() .asBuilder()
// Handle the secDNS extension. // Handle the secDNS extension. As dsData in secDnsUpdate is read from EPP input and
// does not have domainRepoId set, we create a copy of the existing dsData without
// domainRepoId for comparison.
.setDsData( .setDsData(
secDnsUpdate.isPresent() secDnsUpdate.isPresent()
? updateDsData(domain.getDsData(), secDnsUpdate.get()) ? updateDsData(
domain.getDsData().stream()
.map(DelegationSignerData::cloneWithoutDomainRepoId)
.collect(toImmutableSet()),
secDnsUpdate.get())
: domain.getDsData()) : domain.getDsData())
.setLastEppUpdateTime(now) .setLastEppUpdateTime(now)
.setLastEppUpdateClientId(clientId) .setLastEppUpdateClientId(clientId)

View file

@ -19,6 +19,7 @@ import google.registry.model.EppResource;
import google.registry.model.EppResource.ForeignKeyedEppResource; import google.registry.model.EppResource.ForeignKeyedEppResource;
import google.registry.model.annotations.ExternalMessagingName; import google.registry.model.annotations.ExternalMessagingName;
import google.registry.model.annotations.ReportedOn; import google.registry.model.annotations.ReportedOn;
import google.registry.model.domain.secdns.DelegationSignerData;
import google.registry.model.host.HostResource; import google.registry.model.host.HostResource;
import google.registry.persistence.VKey; import google.registry.persistence.VKey;
import google.registry.persistence.WithStringVKey; import google.registry.persistence.WithStringVKey;
@ -113,6 +114,32 @@ public class DomainBase extends DomainContent
restoreOfyKeys(getRepoId()); restoreOfyKeys(getRepoId());
} }
/**
* Returns the set of {@link DelegationSignerData} associated with the domain.
*
* <p>This is the getter method specific for Hibernate to access the field so it is set to
* private. The caller can use the public {@link #getDsData()} to get the DS data.
*
* <p>Note that we need to set `insertable = false, updatable = false` for @JoinColumn, otherwise
* Hibernate would try to set the foreign key to null(through an UPDATE TABLE sql) instead of
* deleting the whole entry from the table when the {@link DelegationSignerData} is removed from
* the set.
*/
@Access(AccessType.PROPERTY)
@OneToMany(
cascade = {CascadeType.ALL},
fetch = FetchType.EAGER,
orphanRemoval = true)
@JoinColumn(
name = "domainRepoId",
referencedColumnName = "repoId",
insertable = false,
updatable = false)
@SuppressWarnings("UnusedMethod")
private Set<DelegationSignerData> getInternalDelegationSignerData() {
return dsData;
}
@Override @Override
public VKey<DomainBase> createVKey() { public VKey<DomainBase> createVKey() {
return VKey.create(DomainBase.class, getRepoId(), Key.create(this)); return VKey.create(DomainBase.class, getRepoId(), Key.create(this));

View file

@ -317,6 +317,10 @@ public class DomainContent extends EppResource
autorenewPollMessageHistoryId = getHistoryId(autorenewPollMessage); autorenewPollMessageHistoryId = getHistoryId(autorenewPollMessage);
autorenewBillingEventHistoryId = getHistoryId(autorenewBillingEvent); autorenewBillingEventHistoryId = getHistoryId(autorenewBillingEvent);
deletePollMessageHistoryId = getHistoryId(deletePollMessage); deletePollMessageHistoryId = getHistoryId(deletePollMessage);
dsData =
nullToEmptyImmutableCopy(dsData).stream()
.map(dsData -> dsData.cloneWithDomainRepoId(getRepoId()))
.collect(toImmutableSet());
} }
/** /**
@ -469,6 +473,12 @@ public class DomainContent extends EppResource
this.gracePeriods = gracePeriods; this.gracePeriods = gracePeriods;
} }
// Hibernate needs this in order to populate dsData but no one else should ever use it
@SuppressWarnings("UnusedMethod")
private void setInternalDelegationSignerData(Set<DelegationSignerData> dsData) {
this.dsData = dsData;
}
public final String getCurrentSponsorClientId() { public final String getCurrentSponsorClientId() {
return getPersistedCurrentSponsorClientId(); return getPersistedCurrentSponsorClientId();
} }
@ -791,10 +801,16 @@ public class DomainContent extends EppResource
instance.tld = getTldFromDomainName(instance.fullyQualifiedDomainName); instance.tld = getTldFromDomainName(instance.fullyQualifiedDomainName);
T newDomain = super.build(); T newDomain = super.build();
// Hibernate throws exception if gracePeriods is null because we enabled all cascadable // Hibernate throws exception if gracePeriods or dsData is null because we enabled all
// operations and orphan removal. // cascadable operations and orphan removal.
newDomain.gracePeriods = newDomain.gracePeriods =
newDomain.gracePeriods == null ? ImmutableSet.of() : newDomain.gracePeriods; newDomain.gracePeriods == null ? ImmutableSet.of() : newDomain.gracePeriods;
newDomain.dsData =
newDomain.dsData == null
? ImmutableSet.of()
: newDomain.dsData.stream()
.map(ds -> ds.cloneWithDomainRepoId(instance.getRepoId()))
.collect(toImmutableSet());
return newDomain; return newDomain;
} }

View file

@ -14,11 +14,22 @@
package google.registry.model.domain.secdns; package google.registry.model.domain.secdns;
import static google.registry.util.PreconditionsUtils.checkArgumentNotNull;
import com.googlecode.objectify.annotation.Embed; import com.googlecode.objectify.annotation.Embed;
import com.googlecode.objectify.annotation.Ignore;
import google.registry.model.ImmutableObject; import google.registry.model.ImmutableObject;
import google.registry.model.domain.secdns.DelegationSignerData.DelegationSignerDataId;
import google.registry.schema.replay.DatastoreAndSqlEntity; import google.registry.schema.replay.DatastoreAndSqlEntity;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.IdClass;
import javax.persistence.Index;
import javax.persistence.Table;
import javax.xml.bind.DatatypeConverter; import javax.xml.bind.DatatypeConverter;
import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlTransient;
import javax.xml.bind.annotation.XmlType; import javax.xml.bind.annotation.XmlType;
import javax.xml.bind.annotation.adapters.HexBinaryAdapter; import javax.xml.bind.annotation.adapters.HexBinaryAdapter;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
@ -31,19 +42,26 @@ import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
*/ */
@Embed @Embed
@XmlType(name = "dsData") @XmlType(name = "dsData")
@javax.persistence.Entity @Entity
@Table(indexes = @Index(columnList = "domainRepoId"))
@IdClass(DelegationSignerDataId.class)
public class DelegationSignerData extends ImmutableObject implements DatastoreAndSqlEntity { public class DelegationSignerData extends ImmutableObject implements DatastoreAndSqlEntity {
private DelegationSignerData() {} private DelegationSignerData() {}
@Ignore @XmlTransient @javax.persistence.Id String domainRepoId;
/** The identifier for this particular key in the domain. */ /** The identifier for this particular key in the domain. */
@javax.persistence.Id int keyTag; @javax.persistence.Id
@Column(nullable = false)
int keyTag;
/** /**
* The algorithm used by this key. * The algorithm used by this key.
* *
* @see <a href="http://tools.ietf.org/html/rfc4034#appendix-A.1">RFC 4034 Appendix A.1</a> * @see <a href="http://tools.ietf.org/html/rfc4034#appendix-A.1">RFC 4034 Appendix A.1</a>
*/ */
@Column(nullable = false)
@XmlElement(name = "alg") @XmlElement(name = "alg")
int algorithm; int algorithm;
@ -52,6 +70,7 @@ public class DelegationSignerData extends ImmutableObject implements DatastoreAn
* *
* @see <a href="http://tools.ietf.org/html/rfc4034#appendix-A.2">RFC 4034 Appendix A.2</a> * @see <a href="http://tools.ietf.org/html/rfc4034#appendix-A.2">RFC 4034 Appendix A.2</a>
*/ */
@Column(nullable = false)
int digestType; int digestType;
/** /**
@ -59,6 +78,7 @@ public class DelegationSignerData extends ImmutableObject implements DatastoreAn
* *
* @see <a href="http://tools.ietf.org/html/rfc4034#section-5.1.4">RFC 4034 Section 5.1.4</a> * @see <a href="http://tools.ietf.org/html/rfc4034#section-5.1.4">RFC 4034 Section 5.1.4</a>
*/ */
@Column(nullable = false)
@XmlJavaTypeAdapter(HexBinaryAdapter.class) @XmlJavaTypeAdapter(HexBinaryAdapter.class)
byte[] digest; byte[] digest;
@ -82,16 +102,34 @@ public class DelegationSignerData extends ImmutableObject implements DatastoreAn
return digest == null ? "" : DatatypeConverter.printHexBinary(digest); return digest == null ? "" : DatatypeConverter.printHexBinary(digest);
} }
public DelegationSignerData cloneWithDomainRepoId(String domainRepoId) {
DelegationSignerData clone = clone(this);
clone.domainRepoId = checkArgumentNotNull(domainRepoId);
return clone;
}
public DelegationSignerData cloneWithoutDomainRepoId() {
DelegationSignerData clone = clone(this);
clone.domainRepoId = null;
return clone;
}
public static DelegationSignerData create( public static DelegationSignerData create(
int keyTag, int algorithm, int digestType, byte[] digest) { int keyTag, int algorithm, int digestType, byte[] digest, String domainRepoId) {
DelegationSignerData instance = new DelegationSignerData(); DelegationSignerData instance = new DelegationSignerData();
instance.keyTag = keyTag; instance.keyTag = keyTag;
instance.algorithm = algorithm; instance.algorithm = algorithm;
instance.digestType = digestType; instance.digestType = digestType;
instance.digest = digest; instance.digest = digest;
instance.domainRepoId = domainRepoId;
return instance; return instance;
} }
public static DelegationSignerData create(
int keyTag, int algorithm, int digestType, byte[] digest) {
return create(keyTag, algorithm, digestType, digest, null);
}
public static DelegationSignerData create( public static DelegationSignerData create(
int keyTag, int algorithm, int digestType, String digestAsHex) { int keyTag, int algorithm, int digestType, String digestAsHex) {
return create(keyTag, algorithm, digestType, DatatypeConverter.parseHexBinary(digestAsHex)); return create(keyTag, algorithm, digestType, DatatypeConverter.parseHexBinary(digestAsHex));
@ -107,4 +145,20 @@ public class DelegationSignerData extends ImmutableObject implements DatastoreAn
"%d %d %d %s", "%d %d %d %s",
this.keyTag, this.algorithm, this.digestType, DatatypeConverter.printHexBinary(digest)); this.keyTag, this.algorithm, this.digestType, DatatypeConverter.printHexBinary(digest));
} }
static class DelegationSignerDataId extends ImmutableObject implements Serializable {
String domainRepoId;
int keyTag;
private DelegationSignerDataId() {}
private DelegationSignerDataId(String domainRepoId, int keyTag) {
this.domainRepoId = domainRepoId;
this.keyTag = keyTag;
}
public static DelegationSignerDataId create(String domainRepoId, int keyTag) {
return new DelegationSignerDataId(checkArgumentNotNull(domainRepoId), keyTag);
}
}
} }

View file

@ -821,10 +821,12 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
setEppInput("domain_create_dsdata_no_maxsiglife.xml"); setEppInput("domain_create_dsdata_no_maxsiglife.xml");
persistContactsAndHosts("tld"); // For some reason this sample uses "tld". persistContactsAndHosts("tld"); // For some reason this sample uses "tld".
doSuccessfulTest("tld"); doSuccessfulTest("tld");
DomainBase domain = reloadResourceByForeignKey();
assertAboutDomains() assertAboutDomains()
.that(reloadResourceByForeignKey()) .that(domain)
.hasExactlyDsData( .hasExactlyDsData(
DelegationSignerData.create(12345, 3, 1, base16().decode("49FD46E6C4B45C55D4AC"))); DelegationSignerData.create(12345, 3, 1, base16().decode("49FD46E6C4B45C55D4AC"))
.cloneWithDomainRepoId(domain.getRepoId()));
} }
@Test @Test

View file

@ -14,6 +14,7 @@
package google.registry.flows.domain; package google.registry.flows.domain;
import static com.google.common.collect.ImmutableSet.toImmutableSet;
import static com.google.common.collect.Sets.union; import static com.google.common.collect.Sets.union;
import static com.google.common.io.BaseEncoding.base16; import static com.google.common.io.BaseEncoding.base16;
import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat;
@ -470,7 +471,11 @@ class DomainUpdateFlowTest extends ResourceFlowTestCase<DomainUpdateFlow, Domain
.that(resource) .that(resource)
.hasOnlyOneHistoryEntryWhich() .hasOnlyOneHistoryEntryWhich()
.hasType(HistoryEntry.Type.DOMAIN_UPDATE); .hasType(HistoryEntry.Type.DOMAIN_UPDATE);
assertThat(resource.getDsData()).isEqualTo(expectedDsData); assertThat(resource.getDsData())
.isEqualTo(
expectedDsData.stream()
.map(ds -> ds.cloneWithDomainRepoId(resource.getRepoId()))
.collect(toImmutableSet()));
assertDnsTasksEnqueued("example.tld"); assertDnsTasksEnqueued("example.tld");
} }

View file

@ -25,6 +25,7 @@ import static org.joda.time.DateTimeZone.UTC;
import static org.junit.jupiter.api.Assertions.fail; import static org.junit.jupiter.api.Assertions.fail;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;
import com.googlecode.objectify.Key; import com.googlecode.objectify.Key;
import google.registry.model.billing.BillingEvent; import google.registry.model.billing.BillingEvent;
import google.registry.model.billing.BillingEvent.Flag; import google.registry.model.billing.BillingEvent.Flag;
@ -342,6 +343,50 @@ public class DomainBaseSqlTest {
}); });
} }
@Test
void testModifyDsData_addThenRemoveSuccessfully() {
persistDomain();
DelegationSignerData extraDsData =
DelegationSignerData.create(2, 2, 3, new byte[] {0, 1, 2}, "4-COM");
ImmutableSet<DelegationSignerData> unionDsData =
Sets.union(domain.getDsData(), ImmutableSet.of(extraDsData)).immutableCopy();
// Add an extra DelegationSignerData to dsData set.
jpaTm()
.transact(
() -> {
DomainBase persisted = jpaTm().load(domain.createVKey());
assertThat(persisted.getDsData()).containsExactlyElementsIn(domain.getDsData());
DomainBase modified = persisted.asBuilder().setDsData(unionDsData).build();
jpaTm().put(modified);
});
// Verify that the persisted domain entity contains both DelegationSignerData records.
jpaTm()
.transact(
() -> {
DomainBase persisted = jpaTm().load(domain.createVKey());
assertThat(persisted.getDsData()).containsExactlyElementsIn(unionDsData);
assertEqualDomainExcept(persisted, "dsData");
});
// Remove the extra DelegationSignerData record from dsData set.
jpaTm()
.transact(
() -> {
DomainBase persisted = jpaTm().load(domain.createVKey());
jpaTm().put(persisted.asBuilder().setDsData(domain.getDsData()).build());
});
// Verify that the persisted domain is equal to the original domain.
jpaTm()
.transact(
() -> {
DomainBase persisted = jpaTm().load(domain.createVKey());
assertEqualDomainExcept(persisted);
});
}
@Test @Test
void testUpdates() { void testUpdates() {
jpaTm() jpaTm()
@ -358,16 +403,6 @@ public class DomainBaseSqlTest {
.transact( .transact(
() -> { () -> {
DomainBase result = jpaTm().load(domain.createVKey()); DomainBase result = jpaTm().load(domain.createVKey());
// Fix DS data, since we can't persist that yet.
result =
result
.asBuilder()
.setDsData(
ImmutableSet.of(
DelegationSignerData.create(1, 2, 3, new byte[] {0, 1, 2})))
.build();
assertAboutImmutableObjects() assertAboutImmutableObjects()
.that(result) .that(result)
.isEqualExceptFields(domain, "updateTimestamp", "creationTime"); .isEqualExceptFields(domain, "updateTimestamp", "creationTime");
@ -572,13 +607,6 @@ public class DomainBaseSqlTest {
} }
private void assertEqualDomainExcept(DomainBase thatDomain, String... excepts) { private void assertEqualDomainExcept(DomainBase thatDomain, String... excepts) {
// Fix DS data, since we can't persist it yet.
thatDomain =
thatDomain
.asBuilder()
.setDsData(ImmutableSet.of(DelegationSignerData.create(1, 2, 3, new byte[] {0, 1, 2})))
.build();
// Fix the original creation timestamp (this gets initialized on first write) // Fix the original creation timestamp (this gets initialized on first write)
DomainBase org = domain.asBuilder().setCreationTime(thatDomain.getCreationTime()).build(); DomainBase org = domain.asBuilder().setCreationTime(thatDomain.getCreationTime()).build();

View file

@ -60,3 +60,4 @@ V59__use_composite_primary_key_for_contact_and_host_history_table.sql
V60__remove_pollmessage_sequence.sql V60__remove_pollmessage_sequence.sql
V61__domain_hist_columns.sql V61__domain_hist_columns.sql
V62__disable_key_auto_generation_for_history_tables.sql V62__disable_key_auto_generation_for_history_tables.sql
V63__add_schema_for_ds_data.sql

View file

@ -0,0 +1,29 @@
-- Copyright 2020 The Nomulus Authors. All Rights Reserved.
--
-- Licensed under the Apache License, Version 2.0 (the "License");
-- you may not use this file except in compliance with the License.
-- You may obtain a copy of the License at
--
-- http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- See the License for the specific language governing permissions and
-- limitations under the License.
create table "DelegationSignerData" (
domain_repo_id text not null,
key_tag int4 not null,
algorithm int4 not null,
digest bytea not null,
digest_type int4 not null,
primary key (domain_repo_id, key_tag)
);
create index IDXhlqqd5uy98cjyos72d81x9j95 on "DelegationSignerData" (domain_repo_id);
alter table if exists "DelegationSignerData"
add constraint FKtr24j9v14ph2mfuw2gsmt12kq
foreign key (domain_repo_id)
references "Domain";

View file

@ -227,11 +227,12 @@
); );
create table "DelegationSignerData" ( create table "DelegationSignerData" (
domain_repo_id text not null,
key_tag int4 not null, key_tag int4 not null,
algorithm int4 not null, algorithm int4 not null,
digest bytea, digest bytea not null,
digest_type int4 not null, digest_type int4 not null,
primary key (key_tag) primary key (domain_repo_id, key_tag)
); );
create table "Domain" ( create table "Domain" (
@ -668,6 +669,7 @@ create index IDXo1xdtpij2yryh0skxe9v91sep on "ContactHistory" (creation_time);
create index IDXhp33wybmb6tbpr1bq7ttwk8je on "ContactHistory" (history_registrar_id); create index IDXhp33wybmb6tbpr1bq7ttwk8je on "ContactHistory" (history_registrar_id);
create index IDX9q53px6r302ftgisqifmc6put on "ContactHistory" (history_type); create index IDX9q53px6r302ftgisqifmc6put on "ContactHistory" (history_type);
create index IDXsudwswtwqnfnx2o1hx4s0k0g5 on "ContactHistory" (history_modification_time); create index IDXsudwswtwqnfnx2o1hx4s0k0g5 on "ContactHistory" (history_modification_time);
create index IDXhlqqd5uy98cjyos72d81x9j95 on "DelegationSignerData" (domain_repo_id);
create index IDX8nr0ke9mrrx4ewj6pd2ag4rmr on "Domain" (creation_time); create index IDX8nr0ke9mrrx4ewj6pd2ag4rmr on "Domain" (creation_time);
create index IDXhsjqiy2lyobfymplb28nm74lm on "Domain" (current_sponsor_registrar_id); create index IDXhsjqiy2lyobfymplb28nm74lm on "Domain" (current_sponsor_registrar_id);
create index IDX5mnf0wn20tno4b9do88j61klr on "Domain" (deletion_time); create index IDX5mnf0wn20tno4b9do88j61klr on "Domain" (deletion_time);
@ -705,6 +707,11 @@ create index spec11threatmatch_check_date_idx on "Spec11ThreatMatch" (check_date
foreign key (revision_id) foreign key (revision_id)
references "ClaimsList"; references "ClaimsList";
alter table if exists "DelegationSignerData"
add constraint FKtr24j9v14ph2mfuw2gsmt12kq
foreign key (domain_repo_id)
references "Domain";
alter table if exists "DomainHistoryHost" alter table if exists "DomainHistoryHost"
add constraint FKa9woh3hu8gx5x0vly6bai327n add constraint FKa9woh3hu8gx5x0vly6bai327n
foreign key (domain_history_domain_repo_id, domain_history_history_revision_id) foreign key (domain_history_domain_repo_id, domain_history_history_revision_id)

View file

@ -303,6 +303,19 @@ CREATE TABLE public."Cursor" (
); );
--
-- Name: DelegationSignerData; Type: TABLE; Schema: public; Owner: -
--
CREATE TABLE public."DelegationSignerData" (
domain_repo_id text NOT NULL,
key_tag integer NOT NULL,
algorithm integer NOT NULL,
digest bytea NOT NULL,
digest_type integer NOT NULL
);
-- --
-- Name: Domain; Type: TABLE; Schema: public; Owner: - -- Name: Domain; Type: TABLE; Schema: public; Owner: -
-- --
@ -1059,6 +1072,14 @@ ALTER TABLE ONLY public."Cursor"
ADD CONSTRAINT "Cursor_pkey" PRIMARY KEY (scope, type); ADD CONSTRAINT "Cursor_pkey" PRIMARY KEY (scope, type);
--
-- Name: DelegationSignerData DelegationSignerData_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public."DelegationSignerData"
ADD CONSTRAINT "DelegationSignerData_pkey" PRIMARY KEY (domain_repo_id, key_tag);
-- --
-- Name: DomainHistory DomainHistory_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- Name: DomainHistory DomainHistory_pkey; Type: CONSTRAINT; Schema: public; Owner: -
-- --
@ -1372,6 +1393,13 @@ CREATE INDEX idxeokttmxtpq2hohcioe5t2242b ON public."BillingCancellation" USING
CREATE INDEX idxfg2nnjlujxo6cb9fha971bq2n ON public."HostHistory" USING btree (creation_time); CREATE INDEX idxfg2nnjlujxo6cb9fha971bq2n ON public."HostHistory" USING btree (creation_time);
--
-- Name: idxhlqqd5uy98cjyos72d81x9j95; Type: INDEX; Schema: public; Owner: -
--
CREATE INDEX idxhlqqd5uy98cjyos72d81x9j95 ON public."DelegationSignerData" USING btree (domain_repo_id);
-- --
-- Name: idxhmv411mdqo5ibn4vy7ykxpmlv; Type: INDEX; Schema: public; Owner: - -- Name: idxhmv411mdqo5ibn4vy7ykxpmlv; Type: INDEX; Schema: public; Owner: -
-- --
@ -1985,6 +2013,14 @@ ALTER TABLE ONLY public."PremiumEntry"
ADD CONSTRAINT fko0gw90lpo1tuee56l0nb6y6g5 FOREIGN KEY (revision_id) REFERENCES public."PremiumList"(revision_id); ADD CONSTRAINT fko0gw90lpo1tuee56l0nb6y6g5 FOREIGN KEY (revision_id) REFERENCES public."PremiumList"(revision_id);
--
-- Name: DelegationSignerData fktr24j9v14ph2mfuw2gsmt12kq; Type: FK CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public."DelegationSignerData"
ADD CONSTRAINT fktr24j9v14ph2mfuw2gsmt12kq FOREIGN KEY (domain_repo_id) REFERENCES public."Domain"(repo_id);
-- --
-- PostgreSQL database dump complete -- PostgreSQL database dump complete
-- --