Skip to content

Commit

Permalink
Merge pull request #4895 from greenplum-db/external-table-ddl-creatio…
Browse files Browse the repository at this point in the history
…n-162776271

GP: Add DDL generation for Greenplum's concept of external tables
  • Loading branch information
serge-rider committed Jan 3, 2019
2 parents 66ddfc3 + 2f1ad6d commit e51a49a
Show file tree
Hide file tree
Showing 9 changed files with 643 additions and 13 deletions.
@@ -0,0 +1,171 @@
/*
* DBeaver - Universal Database Manager
* Copyright (C) 2010-2017 Serge Rider (serge@jkiss.org)
* Copyright (C) 2019 Dmitriy Dubson (ddubson@pivotal.io)
* Copyright (C) 2019 Gavin Shaw (gshaw@pivotal.io)
* Copyright (C) 2019 Zach Marcin (zmarcin@pivotal.io)
* Copyright (C) 2019 Nikhil Pawar (npawar@pivotal.io)
*
* 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.
*/
package org.jkiss.dbeaver.ext.greenplum.model;

import org.jkiss.dbeaver.DBException;
import org.jkiss.dbeaver.ext.postgresql.model.PostgreSchema;
import org.jkiss.dbeaver.ext.postgresql.model.PostgreTableColumn;
import org.jkiss.dbeaver.ext.postgresql.model.PostgreTableRegular;
import org.jkiss.dbeaver.model.impl.jdbc.JDBCUtils;
import org.jkiss.dbeaver.model.runtime.DBRProgressMonitor;

import java.sql.ResultSet;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class GreenplumExternalTable extends PostgreTableRegular {
public enum FormatType {
c("CSV"),
t("TEXT");

private String formatType;

FormatType(String formatTypeString) {
this.formatType = formatTypeString;
}

public String getValue() {
return formatType;
}
}

public enum RejectLimitType {
r("ROWS");

private String rejectLimitType;

RejectLimitType(String rejectLimitTypeString) {
this.rejectLimitType = rejectLimitTypeString;
}

public String getValue() {
return rejectLimitType;
}
}

private final List<String> uriLocations;
private final String execLocation;
private final FormatType formatType;
private final String formatOptions;
private final String encoding;
private final RejectLimitType rejectLimitType;
private final int rejectLimit;

public GreenplumExternalTable(PostgreSchema catalog, ResultSet dbResult) {
super(catalog, dbResult);
this.uriLocations = Arrays.asList(JDBCUtils.safeGetString(dbResult, "urilocation")
.trim().split(","));
this.execLocation = JDBCUtils.safeGetString(dbResult, "execlocation");
this.formatType = FormatType.valueOf(JDBCUtils.safeGetString(dbResult, "fmttype"));
this.formatOptions = JDBCUtils.safeGetString(dbResult, "fmtopts");
this.encoding = JDBCUtils.safeGetString(dbResult, "encoding");

this.rejectLimit = JDBCUtils.safeGetInt(dbResult, "rejectlimit");
String rejectlimittype = JDBCUtils.safeGetString(dbResult, "rejectlimittype");
if (rejectlimittype != null && rejectlimittype.length() > 0) {
this.rejectLimitType = RejectLimitType.valueOf(rejectlimittype);
} else {
this.rejectLimitType = null;
}

}

public List<String> getUriLocations() {
return uriLocations;
}

public String getExecLocation() {
return execLocation;
}

public FormatType getFormatType() {
return formatType;
}

public String getFormatOptions() {
return formatOptions;
}

public String getEncoding() {
return encoding;
}

public RejectLimitType getRejectLimitType() {
return rejectLimitType;
}

public int getRejectLimit() {
return rejectLimit;
}

public String generateDDL(DBRProgressMonitor monitor) throws DBException {
StringBuilder ddlBuilder = new StringBuilder("CREATE EXTERNAL TABLE " + this.getDatabase().getName()
+ "." + this.getSchema().getName() + "." + this.getName() + " (\n");

List<PostgreTableColumn> tableColumns = this.getAttributes(monitor)
.stream()
.filter(field -> field.getOrdinalPosition() >= 0)
.collect(Collectors.toList());

if (tableColumns.size() == 1) {
PostgreTableColumn column = tableColumns.get(0);
ddlBuilder.append("\t" + column.getName() + " " + column.getTypeName() + "\n)\n");
} else {
ddlBuilder.append(tableColumns
.stream()
.map(field -> "\t" + field.getName() + " " + field.getTypeName())
.collect(Collectors.joining(",\n")));
ddlBuilder.append("\n)\n");
}

if (this.getUriLocations() != null && !this.getUriLocations().isEmpty()) {
ddlBuilder.append("LOCATION (\n");

ddlBuilder.append(this.getUriLocations()
.stream()
.map(location -> "\t'" + location + "'")
.collect(Collectors.joining(",\n")));

ddlBuilder.append("\n) " + determineExecutionLocation() + "\n");
}

ddlBuilder.append("FORMAT '" + this.getFormatType().getValue() + "' ( " + this.getFormatOptions() + " )");

if (this.getEncoding() != null && this.getEncoding().length() > 0) {
ddlBuilder.append("\nENCODING '" + this.getEncoding() + "'");
}

if (this.getRejectLimit() > 0 && this.getRejectLimitType() != null) {
ddlBuilder.append("\nSEGMENT REJECT LIMIT " + this.getRejectLimit() + " " + this.getRejectLimitType().getValue());
}

return ddlBuilder.toString();
}

private String determineExecutionLocation() {
if (this.getExecLocation() != null && this.getExecLocation().equalsIgnoreCase("MASTER_ONLY")) {
return "ON MASTER";
}

return "ON ALL";
}
}
@@ -1,9 +1,28 @@
/*
* DBeaver - Universal Database Manager
* Copyright (C) 2010-2017 Serge Rider (serge@jkiss.org)
* Copyright (C) 2019 Dmitriy Dubson (ddubson@pivotal.io)
* Copyright (C) 2019 Gavin Shaw (gshaw@pivotal.io)
* Copyright (C) 2019 Zach Marcin (zmarcin@pivotal.io)
* Copyright (C) 2019 Nikhil Pawar (npawar@pivotal.io)
*
* 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.
*/
package org.jkiss.dbeaver.ext.greenplum.model;

import org.jkiss.code.NotNull;
import org.jkiss.code.Nullable;
import org.jkiss.dbeaver.DBException;
import org.jkiss.dbeaver.Log;
import org.jkiss.dbeaver.ext.postgresql.model.PostgreDatabase;
import org.jkiss.dbeaver.ext.postgresql.model.PostgreSchema;
import org.jkiss.dbeaver.ext.postgresql.model.PostgreTableBase;
Expand All @@ -18,9 +37,9 @@
import java.util.ArrayList;
import java.util.Collection;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class GreenplumSchema extends PostgreSchema {
private static final Log log = Log.getLog(GreenplumSchema.class);
private GreenplumTableCache greenplumTableCache = new GreenplumTableCache();

public GreenplumSchema(PostgreDatabase owner, String name, JDBCResultSet resultSet) throws SQLException {
Expand All @@ -29,10 +48,12 @@ public GreenplumSchema(PostgreDatabase owner, String name, JDBCResultSet resultS

@Override
public Collection<? extends JDBCTable> getTables(DBRProgressMonitor monitor) throws DBException {
return greenplumTableCache.getTypedObjects(monitor, this, GreenplumTable.class)
.stream()
.filter(table -> !table.isPartition())
.collect(Collectors.toCollection(ArrayList::new));
return Stream.concat(
greenplumTableCache.getTypedObjects(monitor, this, GreenplumExternalTable.class).stream(),
greenplumTableCache.getTypedObjects(monitor, this, GreenplumTable.class)
.stream()
.filter(table -> !table.isPartition())
).collect(Collectors.toCollection(ArrayList::new));
}

public class GreenplumTableCache extends TableCache {
Expand All @@ -42,13 +63,25 @@ protected GreenplumTableCache() {

@NotNull
@Override
public JDBCStatement prepareLookupStatement(@NotNull JDBCSession session, @NotNull PostgreSchema postgreSchema, @Nullable PostgreTableBase object, @Nullable String objectName) throws SQLException {
String sqlQuery = "SELECT c.oid,d.description, c.*\n" +
public JDBCStatement prepareLookupStatement(@NotNull JDBCSession session,
@NotNull PostgreSchema postgreSchema,
@Nullable PostgreTableBase object,
@Nullable String objectName) throws SQLException {
String sqlQuery = "SELECT c.oid,d.description, c.*,\n" +
"CASE WHEN x.urilocation IS NOT NULL THEN array_to_string(x.urilocation, ',') ELSE '' END AS urilocation,\n" +
"x.fmttype, x.fmtopts,\n" +
"coalesce(x.rejectlimit, 0) AS rejectlimit,\n" +
"coalesce(x.rejectlimittype, '') AS rejectlimittype,\n" +
"array_to_string(x.execlocation, ',') AS execlocation,\n" +
"pg_encoding_to_char(x.encoding) AS encoding,\n" +
"case when c.relstorage = 'x' then true else false end as \"is_ext_table\"\n" +
"FROM pg_catalog.pg_class c\n" +
"inner join pg_catalog.pg_namespace ns\n" +
"\ton ns.oid = c.relnamespace\n" +
"LEFT OUTER JOIN pg_catalog.pg_description d\n" +
"\tON d.objoid=c.oid AND d.objsubid=0\n" +
"left outer join pg_catalog.pg_exttable x\n" +
"\ton x.reloid = c.oid\n" +
"left outer join pg_catalog.pg_partitions p\n" +
"\ton c.relname = p.partitiontablename and ns.nspname = p.schemaname\n" +
"WHERE c.relnamespace= ? AND c.relkind not in ('i','c') AND p.partitiontablename is null "
Expand Down
@@ -1,3 +1,23 @@
/*
* DBeaver - Universal Database Manager
* Copyright (C) 2010-2017 Serge Rider (serge@jkiss.org)
* Copyright (C) 2019 Dmitriy Dubson (ddubson@pivotal.io)
* Copyright (C) 2019 Gavin Shaw (gshaw@pivotal.io)
* Copyright (C) 2019 Zach Marcin (zmarcin@pivotal.io)
* Copyright (C) 2019 Nikhil Pawar (npawar@pivotal.io)
*
* 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.
*/
package org.jkiss.dbeaver.ext.greenplum.model;

import org.jkiss.code.NotNull;
Expand Down
@@ -1,3 +1,23 @@
/*
* DBeaver - Universal Database Manager
* Copyright (C) 2010-2017 Serge Rider (serge@jkiss.org)
* Copyright (C) 2019 Dmitriy Dubson (ddubson@pivotal.io)
* Copyright (C) 2019 Gavin Shaw (gshaw@pivotal.io)
* Copyright (C) 2019 Zach Marcin (zmarcin@pivotal.io)
* Copyright (C) 2019 Nikhil Pawar (npawar@pivotal.io)
*
* 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.
*/
package org.jkiss.dbeaver.ext.greenplum.model;

import org.jkiss.dbeaver.ext.postgresql.model.PostgreTableBase;
Expand Down
@@ -1,6 +1,10 @@
/*
* DBeaver - Universal Database Manager
* Copyright (C) 2010-2017 Serge Rider (serge@jkiss.org)
* Copyright (C) 2019 Dmitriy Dubson (ddubson@pivotal.io)
* Copyright (C) 2019 Gavin Shaw (gshaw@pivotal.io)
* Copyright (C) 2019 Zach Marcin (zmarcin@pivotal.io)
* Copyright (C) 2019 Nikhil Pawar (npawar@pivotal.io)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -16,9 +20,12 @@
*/
package org.jkiss.dbeaver.ext.greenplum.model;

import org.jkiss.dbeaver.DBException;
import org.jkiss.dbeaver.ext.postgresql.model.*;
import org.jkiss.dbeaver.ext.postgresql.model.impls.PostgreServerExtensionBase;
import org.jkiss.dbeaver.model.exec.jdbc.JDBCResultSet;
import org.jkiss.dbeaver.model.impl.jdbc.JDBCUtils;
import org.jkiss.dbeaver.model.runtime.DBRProgressMonitor;

/**
* PostgreServerGreenplum
Expand Down Expand Up @@ -52,11 +59,18 @@ public boolean supportsClientInfo() {
@Override
public PostgreTableBase createRelationOfClass(PostgreSchema schema, PostgreClass.RelKind kind, JDBCResultSet dbResult) {
if (kind == PostgreClass.RelKind.r) {
if (isExternal(dbResult)) {
return new GreenplumExternalTable(schema, dbResult);
}
return new GreenplumTable(schema, dbResult);
}
return super.createRelationOfClass(schema, kind, dbResult);
}

private boolean isExternal(JDBCResultSet dbResult) {
return JDBCUtils.safeGetBoolean(dbResult, "is_ext_table");
}

@Override
public PostgreDatabase.SchemaCache createSchemaCache(PostgreDatabase database) {
return new GreenplumSchemaCache();
Expand All @@ -71,4 +85,13 @@ public void configureDialect(PostgreDialect dialect) {
public String createWithClause(PostgreTableRegular table, PostgreTableBase tableBase) {
return GreenplumWithClauseBuilder.generateWithClause(table, tableBase);
}

@Override
public String readTableDDL(DBRProgressMonitor monitor, PostgreTableBase table) throws DBException {
if (table instanceof GreenplumExternalTable) {
return ((GreenplumExternalTable) table).generateDDL(monitor);
} else {
return super.readTableDDL(monitor, table);
}
}
}

0 comments on commit e51a49a

Please sign in to comment.