Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support all 'spanner.*' options in pg_settings #2229

Open
wants to merge 6 commits into
base: postgresql-dialect
Choose a base branch
from
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 @@ -95,7 +95,7 @@ String getSqlValue() {
private final String minVal;
private final String maxVal;
private final String[] enumVals;
private final ImmutableList upperCaseEnumVals;
private final ImmutableList<String> upperCaseEnumVals;

private String setting;
private String unit;
Expand Down Expand Up @@ -258,77 +258,111 @@ static Context tryParseContext(String value) {
}
}

/** Returns this setting as a SELECT statement that can be used in a query or CTE. */
String getSelectStatement() {
/**
* Returns a SELECT statement that can be used in a query or CTE to select jsonb-generated
* settings.
*/
static String getSelectJsonbSetting() {
return "select "
+ toSelectExpression(getCasePreservingKey())
+ " as name, "
+ toSelectExpression(setting)
+ " as setting, "
+ toSelectExpression(unit)
+ " as unit, "
+ toSelectExpression(category)
+ " as category, "
+ toSelectExpression((String) null)
+ " as short_desc, "
+ toSelectExpression((String) null)
+ " as extra_desc, "
+ toSelectExpression(context.getSqlValue())
+ " as context, "
+ toSelectExpression(vartype)
+ " as vartype, "
+ toSelectExpression(minVal)
+ " as min_val, "
+ toSelectExpression(maxVal)
+ " as max_val, "
+ toSelectExpression(enumVals)
+ " as enumvals, "
+ toSelectExpression(bootVal)
+ " as boot_val, "
+ toSelectExpression(resetVal)
+ " as reset_val, "
+ toSelectExpression(source)
+ " as source, "
+ toSelectExpression((String) null)
+ " as sourcefile, "
+ toSelectExpression((Integer) null)
+ "::bigint as sourceline, "
+ toSelectExpression(pendingRestart)
+ "::boolean as pending_restart";
+ "t->>'name' as name, "
+ "t->>'setting' as setting, "
+ "t->>'unit' as unit, "
+ "t->>'category' as category, "
+ "t->>'short_desc' as short_desc, "
+ "t->>'extra_desc' as extra_desc, "
+ "t->>'context' as context, "
+ "t->>'vartype' as vartype, "
+ "t->>'min_val' as min_val, "
+ "t->>'max_val' as max_val, "
+ "case when t->>'enumvals' is null then null::text[] else spanner.string_array((t->>'enumvals')::jsonb) end as enumvals, "
+ "t->>'boot_val' as boot_val, "
+ "t->>'reset_val' as reset_val, "
+ "t->>'source' as source, "
+ "(t->>'sourcefile')::varchar as sourcefile, "
+ "(t->>'sourceline')::bigint as sourceline, "
+ "(t->>'pending_restart')::boolean as pending_restart\n";
}

/** Returns this setting as a jsonb literal expression that can be used in a query or CTE. */
String getJsonbLiteral() {
return "'{"
+ toJsonbElement("name", getCasePreservingKey())
+ ","
+ toJsonbElement("setting", setting)
+ ","
+ toJsonbElement("unit", unit)
+ ","
+ toJsonbElement("category", category)
+ ","
+ toJsonbElement("short_desc", (String) null)
+ ","
+ toJsonbElement("extra_desc", (String) null)
+ ","
+ toJsonbElement("context", context.getSqlValue())
+ ","
+ toJsonbElement("vartype", vartype)
+ ","
+ toJsonbElement("min_val", minVal)
+ ","
+ toJsonbElement("max_val", maxVal)
+ ","
+ toJsonbElement("enum_vals", enumVals)
+ ","
+ toJsonbElement("boot_val", bootVal)
+ ","
+ toJsonbElement("reset_val", resetVal)
+ ","
+ toJsonbElement("source", source)
+ ","
+ toJsonbElement("sourcefile", (String) null)
+ ","
+ toJsonbElement("sourceline", (Integer) null)
+ ","
+ toJsonbElement("pending_restart", pendingRestart)
+ "}'::jsonb";
}

/** Returns the column names of the pg_settings table. */
static ImmutableList<String> getColumnNames() {
return COLUMN_NAMES;
}

/** Converts a string to a SQL literal expression that can be used in a select statement. */
String toSelectExpression(String value) {
return value == null ? "null" : "'" + value + "'";
String toJsonbElement(String name, String value) {
return "\"" + name + "\":" + toJsonbExpression(value);
}

/**
* Converts a string array to a SQL literal expression that can be used in a select statement. The
* expression is cast to text[].
*/
String toSelectExpression(String[] value) {
return value == null
? "null::text[]"
: "'{"
+ Arrays.stream(value)
.map(s -> s.startsWith("\"") ? s : "\"" + s + "\"")
.collect(Collectors.joining(", "))
+ "}'::text[]";
String toJsonbElement(String name, Integer value) {
return "\"" + name + "\":" + toJsonbExpression(value);
}

/** Converts an Integer to a SQL literal expression that can be used in a select statement. */
String toSelectExpression(Integer value) {
String toJsonbElement(String name, Boolean value) {
return "\"" + name + "\":" + toJsonbExpression(value);
}

String toJsonbElement(String name, String[] value) {
return "\"" + name + "\":" + toJsonbExpression(value);
}

String toJsonbExpression(String value) {
return value == null ? "null" : "\"" + value + "\"";
}

String toJsonbExpression(Integer value) {
return value == null ? "null" : value.toString();
}

String toJsonbExpression(Boolean value) {
return value == null ? "null" : value.toString();
}

/** Converts a Boolean to a SQL literal expression that can be used in a select statement. */
String toSelectExpression(Boolean value) {
return value == null ? "null" : (value ? "'t'" : "'f'");
String toJsonbExpression(String[] value) {
return value == null
? "null"
: "["
+ Arrays.stream(value)
.map(s -> s.startsWith("\"") ? s : "\"" + s + "\"")
.collect(Collectors.joining(", "))
+ "]";
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,9 +70,7 @@ public class SessionState {
"server_version_num",
"TimeZone",
"transaction_isolation",
"transaction_read_only",
"spanner.ddl_transaction_mode",
"spanner.replace_pg_catalog_tables");
"transaction_read_only");

static final Map<String, PGSetting> SERVER_SETTINGS = new HashMap<>();

Expand Down Expand Up @@ -138,10 +136,16 @@ void initSettingValue(String key, String value) {
*/
public String generatePGSettingsCte() {
return "pg_settings_inmem_ as (\n"
+ PGSetting.getSelectJsonbSetting()
+ "from unnest(array[\n"
+ getAll().stream()
.filter(setting -> SUPPORTED_PG_SETTINGS_KEYS.contains(setting.getCasePreservingKey()))
.map(PGSetting::getSelectStatement)
.collect(Collectors.joining("\nunion all\n"))
.filter(
setting ->
setting.getName().toLowerCase().startsWith("spanner.")
|| SUPPORTED_PG_SETTINGS_KEYS.contains(setting.getCasePreservingKey()))
.map(PGSetting::getJsonbLiteral)
.collect(Collectors.joining(",\n"))
+ "\n]) t"
+ "\n),\n"
+ "pg_settings_names_ as (\n"
+ "select name from pg_settings_inmem_\n"
Expand Down
19 changes: 18 additions & 1 deletion src/test/java/com/google/cloud/spanner/pgadapter/ITJdbcTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -1112,7 +1112,7 @@ public void testPGSettings() throws SQLException {
assertTrue(resultSet.next());
originalDateStyle = resultSet.getString("setting");
assertTrue(
originalDateStyle,
"Original value: " + originalDateStyle,
"ISO".equals(originalDateStyle) || "ISO, MDY".equals(originalDateStyle));
assertFalse(resultSet.next());
}
Expand Down Expand Up @@ -1171,6 +1171,23 @@ public void testPGSettings() throws SQLException {
assertEquals(originalDateStyle, resultSet.getString("setting"));
assertFalse(resultSet.next());
}

// Verify that we can get all pg_settings and that the number of setting is equal to the
// expected value.
int numExpectedSettings = 30;
int rowCount = 0;
try (ResultSet resultSet =
connection.createStatement().executeQuery("select * from pg_settings order by name")) {
while (resultSet.next()) {
for (int col = 1; col <= resultSet.getMetaData().getColumnCount(); col++) {
// Just verify that we can get the value.
resultSet.getObject(col);
}
assertNotNull(resultSet.getString("name"));
rowCount++;
}
}
assertEquals(numExpectedSettings, rowCount);
}
}

Expand Down
Loading
Loading