Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import static com.google.cloud.teleport.spanner.AvroUtil.SPANNER_DYNAMIC_PROPERTIES;
import static com.google.cloud.teleport.spanner.AvroUtil.SPANNER_EDGE_TABLE;
import static com.google.cloud.teleport.spanner.AvroUtil.SPANNER_ENTITY;
import static com.google.cloud.teleport.spanner.AvroUtil.SPANNER_ENTITY_LOCALITY_GROUP;
import static com.google.cloud.teleport.spanner.AvroUtil.SPANNER_ENTITY_MODEL;
import static com.google.cloud.teleport.spanner.AvroUtil.SPANNER_ENTITY_PLACEMENT;
import static com.google.cloud.teleport.spanner.AvroUtil.SPANNER_ENTITY_PROPERTY_GRAPH;
Expand Down Expand Up @@ -73,6 +74,7 @@
import com.google.cloud.teleport.spanner.ddl.Ddl;
import com.google.cloud.teleport.spanner.ddl.GraphElementTable;
import com.google.cloud.teleport.spanner.ddl.GraphElementTable.Kind;
import com.google.cloud.teleport.spanner.ddl.LocalityGroup;
import com.google.cloud.teleport.spanner.ddl.Model;
import com.google.cloud.teleport.spanner.ddl.NamedSchema;
import com.google.cloud.teleport.spanner.ddl.Placement;
Expand Down Expand Up @@ -126,6 +128,8 @@ public Ddl toDdl(Collection<Schema> avroSchemas) {
builder.addSchema(toSchema(null, schema));
} else if (SPANNER_ENTITY_PLACEMENT.equals(schema.getProp(SPANNER_ENTITY))) {
builder.addPlacement(toPlacement(null, schema));
} else if (SPANNER_ENTITY_LOCALITY_GROUP.equals(schema.getProp(SPANNER_ENTITY))) {
builder.addLocalityGroup(toLocalityGroup(null, schema));
} else if (SPANNER_ENTITY_PROPERTY_GRAPH.equals(schema.getProp(SPANNER_ENTITY))) {
builder.addPropertyGraph(toPropertyGraph(null, schema));
} else {
Expand Down Expand Up @@ -579,6 +583,18 @@ public Placement toPlacement(String placementName, Schema schema) {
return builder.build();
}

public LocalityGroup toLocalityGroup(String localityGroupName, Schema schema) {
if (localityGroupName == null) {
localityGroupName = getSpannerObjectName(schema);
}
LOG.debug("Converting to Ddl localityGroupName {}", localityGroupName);

LocalityGroup.Builder builder = LocalityGroup.builder(dialect).name(localityGroupName);
builder.options(getNumberedPropsWithPrefix(schema, SPANNER_OPTION));

return builder.build();
}

public Table toTable(String tableName, Schema schema) {
if (tableName == null) {
tableName = getSpannerObjectName(schema);
Expand Down Expand Up @@ -691,6 +707,8 @@ public Table toTable(String tableName, Schema schema) {

table.checkConstraints(getNumberedPropsWithPrefix(schema, SPANNER_CHECK_CONSTRAINT));

table.options(getNumberedPropsWithPrefix(schema, SPANNER_OPTION));

// Table parent options.
String spannerParent = schema.getProp(SPANNER_PARENT);
if (!Strings.isNullOrEmpty(spannerParent)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ private AvroUtil() {}
public static final String SPANNER_ENTITY_MODEL = "Model";
public static final String SPANNER_ENTITY_PROPERTY_GRAPH = "PropertyGraph";
public static final String SPANNER_ENTITY_PLACEMENT = "Placement";
public static final String SPANNER_ENTITY_LOCALITY_GROUP = "LocalityGroup";
public static final String SPANNER_FOREIGN_KEY = "spannerForeignKey_";
public static final String SPANNER_INDEX = "spannerIndex_";
public static final String SPANNER_ON_DELETE_ACTION = "spannerOnDeleteAction";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import static com.google.cloud.teleport.spanner.AvroUtil.SPANNER_DYNAMIC_PROPERTIES;
import static com.google.cloud.teleport.spanner.AvroUtil.SPANNER_EDGE_TABLE;
import static com.google.cloud.teleport.spanner.AvroUtil.SPANNER_ENTITY;
import static com.google.cloud.teleport.spanner.AvroUtil.SPANNER_ENTITY_LOCALITY_GROUP;
import static com.google.cloud.teleport.spanner.AvroUtil.SPANNER_ENTITY_MODEL;
import static com.google.cloud.teleport.spanner.AvroUtil.SPANNER_ENTITY_PLACEMENT;
import static com.google.cloud.teleport.spanner.AvroUtil.SPANNER_ENTITY_PROPERTY_GRAPH;
Expand Down Expand Up @@ -73,6 +74,7 @@
import com.google.cloud.teleport.spanner.ddl.Ddl;
import com.google.cloud.teleport.spanner.ddl.GraphElementTable;
import com.google.cloud.teleport.spanner.ddl.IndexColumn;
import com.google.cloud.teleport.spanner.ddl.LocalityGroup;
import com.google.cloud.teleport.spanner.ddl.Model;
import com.google.cloud.teleport.spanner.ddl.ModelColumn;
import com.google.cloud.teleport.spanner.ddl.NamedSchema;
Expand Down Expand Up @@ -206,6 +208,11 @@ public Collection<Schema> convert(Ddl ddl) {
for (int i = 0; i < table.checkConstraints().size(); i++) {
recordBuilder.prop(SPANNER_CHECK_CONSTRAINT + i, table.checkConstraints().get(i));
}
if (table.options() != null) {
for (int i = 0; i < table.options().size(); i++) {
recordBuilder.prop(SPANNER_OPTION + i, table.options().get(i));
}
}
SchemaBuilder.FieldAssembler<Schema> fieldsAssembler = recordBuilder.fields();
int columnOrdinal = 0;
for (Column cm : table.columns()) {
Expand Down Expand Up @@ -426,6 +433,23 @@ public Collection<Schema> convert(Ddl ddl) {
}
schemas.add(recordBuilder.fields().endRecord());
}

for (LocalityGroup localityGroup : ddl.localityGroups()) {
LOG.info("DdlToAvro localityGroup {}", localityGroup.name());
SchemaBuilder.RecordBuilder<Schema> recordBuilder =
SchemaBuilder.record(generateAvroSchemaName(localityGroup.name()))
.namespace(this.namespace);
recordBuilder.prop(SPANNER_NAME, localityGroup.name());
recordBuilder.prop(GOOGLE_FORMAT_VERSION, version);
recordBuilder.prop(GOOGLE_STORAGE, "CloudSpanner");
recordBuilder.prop(SPANNER_ENTITY, SPANNER_ENTITY_LOCALITY_GROUP);
if (localityGroup.options() != null) {
for (int i = 0; i < localityGroup.options().size(); i++) {
recordBuilder.prop(SPANNER_OPTION + i, localityGroup.options().get(i));
}
}
schemas.add(recordBuilder.fields().endRecord());
}
return schemas;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import com.google.cloud.spanner.TimestampBound;
import com.google.cloud.teleport.spanner.ddl.ChangeStream;
import com.google.cloud.teleport.spanner.ddl.Ddl;
import com.google.cloud.teleport.spanner.ddl.LocalityGroup;
import com.google.cloud.teleport.spanner.ddl.Model;
import com.google.cloud.teleport.spanner.ddl.NamedSchema;
import com.google.cloud.teleport.spanner.ddl.Placement;
Expand Down Expand Up @@ -435,6 +436,21 @@ public void processElement(ProcessContext c) {
}
}));

PCollection<String> allLocalityGroupNames =
ddl.apply(
"List all locality group names",
ParDo.of(
new DoFn<Ddl, String>() {

@ProcessElement
public void processElement(ProcessContext c) {
Ddl ddl = c.element();
for (LocalityGroup localityGroup : ddl.localityGroups()) {
c.output(localityGroup.name());
}
}
}));

PCollection<String> allUdfNames =
ddl.apply(
"List all user-defined function names",
Expand Down Expand Up @@ -675,6 +691,24 @@ public void processElement(ProcessContext c) {
}
}));

PCollection<KV<String, Iterable<String>>> localityGroups =
allLocalityGroupNames.apply(
"Export locality groups",
ParDo.of(
new DoFn<String, KV<String, Iterable<String>>>() {

@ProcessElement
public void processElement(ProcessContext c) {
String localityGroupName = c.element();
LOG.info("Exporting locality group: " + localityGroupName);
// This file will contain the schema definition for the locality group.
c.output(
KV.of(
localityGroupName,
Collections.singleton(localityGroupName + ".avro-00000-of-00001")));
}
}));

PCollection<KV<String, Iterable<String>>> udfs =
allUdfNames.apply(
"Export user-defined functions",
Expand All @@ -700,6 +734,7 @@ public void processElement(ProcessContext c) {
.and(sequences)
.and(namedSchemas)
.and(placements)
.and(localityGroups)
.and(udfs)
.and(propertyGraphs)
.apply("Combine all empty schema files", Flatten.pCollections());
Expand Down Expand Up @@ -1046,6 +1081,8 @@ public void processElement(
exportManifest.addSequences(obj);
} else if (ddl.placement(obj.getName()) != null) {
exportManifest.addPlacements(obj);
} else if (ddl.localityGroup(obj.getName()) != null) {
exportManifest.addLocalityGroups(obj);
} else if (ddl.udf(obj.getName()) != null) {
exportManifest.addUdfs(obj);
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import com.google.cloud.spanner.Mutation;
import com.google.cloud.teleport.spanner.ddl.ChangeStream;
import com.google.cloud.teleport.spanner.ddl.Ddl;
import com.google.cloud.teleport.spanner.ddl.LocalityGroup;
import com.google.cloud.teleport.spanner.ddl.NamedSchema;
import com.google.cloud.teleport.spanner.ddl.Placement;
import com.google.cloud.teleport.spanner.ddl.PropertyGraph;
Expand Down Expand Up @@ -519,6 +520,7 @@ public void processElement(ProcessContext c) {
List<KV<String, Schema>> missingSequences = new ArrayList<>();
List<KV<String, Schema>> missingUdfs = new ArrayList<>();
List<KV<String, Schema>> missingPlacements = new ArrayList<>();
List<KV<String, Schema>> missingLocalityGroups = new ArrayList<>();
List<KV<String, Schema>> missingPropertyGraphs = new ArrayList<>();
for (KV<String, String> kv : avroSchemas) {
if (informationSchemaDdl.schema(kv.getKey()) == null
Expand All @@ -529,6 +531,7 @@ public void processElement(ProcessContext c) {
&& informationSchemaDdl.udf(kv.getKey()) == null
&& informationSchemaDdl.sequence(kv.getKey()) == null
&& informationSchemaDdl.placement(kv.getKey()) == null
&& informationSchemaDdl.localityGroup(kv.getKey()) == null
&& informationSchemaDdl.propertyGraph(kv.getKey()) == null) {
Schema schema = parser.parse(kv.getValue());
if (schema.getProp(AvroUtil.SPANNER_CHANGE_STREAM_FOR_CLAUSE)
Expand All @@ -548,6 +551,9 @@ public void processElement(ProcessContext c) {
missingNamedSchemas.add(KV.of(kv.getKey(), schema));
} else if ("Placement".equals(schema.getProp("spannerEntity"))) {
missingPlacements.add(KV.of(kv.getKey(), schema));
} else if (AvroUtil.SPANNER_ENTITY_LOCALITY_GROUP.equals(
schema.getProp("spannerEntity"))) {
missingLocalityGroups.add(KV.of(kv.getKey(), schema));
} else if (AvroUtil.SPANNER_ENTITY_PROPERTY_GRAPH.equals(
schema.getProp("spannerEntity"))) {
missingPropertyGraphs.add(KV.of(kv.getKey(), schema));
Expand Down Expand Up @@ -640,6 +646,18 @@ public void processElement(ProcessContext c) {
ddlStatements.addAll(newDdl.createPlacementStatements());
}

if (!missingLocalityGroups.isEmpty()) {
Ddl.Builder builder = Ddl.builder(dialect);
for (KV<String, Schema> kv : missingLocalityGroups) {
LocalityGroup localityGroup =
converter.toLocalityGroup(kv.getKey(), kv.getValue());
builder.addLocalityGroup(localityGroup);
mergedDdl.addLocalityGroup(localityGroup);
}
Ddl newDdl = builder.build();
ddlStatements.addAll(newDdl.createLocalityGroupStatements());
}

if (!missingTables.isEmpty()
|| !missingModels.isEmpty()
|| !missingViews.isEmpty()
Expand Down Expand Up @@ -855,6 +873,12 @@ public void processElement(ProcessContext c) {
c.output(KV.of(placement.getName(), fullPath));
}
}
for (Export.Table localityGroup : proto.getLocalityGroupsList()) {
for (String f : localityGroup.getDataFilesList()) {
String fullPath = GcsUtil.joinPath(importDirectory.get(), f);
c.output(KV.of(localityGroup.getName(), fullPath));
}
}
}
}));

Expand Down Expand Up @@ -892,6 +916,11 @@ public void processElement(ProcessContext c) {
c.output(KV.of(placement.getName(), placement.getManifestFile()));
}
}
for (Export.Table localityGroup : proto.getLocalityGroupsList()) {
if (!Strings.isNullOrEmpty(localityGroup.getManifestFile())) {
c.output(KV.of(localityGroup.getName(), localityGroup.getManifestFile()));
}
}
}
}));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -160,12 +160,30 @@ public void prettyPrint(Appendable appendable) throws IOException {
if (isHidden()) {
appendable.append(" HIDDEN");
}
if (columnOptions() == null) {
if (columnOptions() == null || columnOptions().isEmpty()) {
return;
}
String optionsString = String.join(",", columnOptions());
if (!optionsString.isEmpty()) {
appendable.append(" OPTIONS (").append(optionsString).append(")");
if (dialect() == Dialect.POSTGRESQL) {
for (String option : columnOptions()) {
String[] parts = option.split("=", 2);
if (parts.length == 2 && parts[0].trim().equalsIgnoreCase("locality_group")) {
String lgName = parts[1].trim();
if (lgName.length() >= 2
&& ((lgName.startsWith("'") && lgName.endsWith("'"))
|| (lgName.startsWith("\"") && lgName.endsWith("\"")))) {
lgName = lgName.substring(1, lgName.length() - 1);
}
appendable
.append(" LOCALITY GROUP ")
.append(
"NULL".equalsIgnoreCase(lgName) ? "NULL" : quoteIdentifier(lgName, dialect()));
}
}
} else {
String optionsString = String.join(",", columnOptions());
if (!optionsString.isEmpty()) {
appendable.append(" OPTIONS (").append(optionsString).append(")");
}
}
}

Expand Down
Loading
Loading