提交 b7083e42 编写于 作者: S Serge Rider 提交者: GitHub

Merge pull request #11182 from dbeaver/postgresql-escape-string#11173

#11173 PostgreSQL escape string

Former-commit-id: c31cef0b
......@@ -303,6 +303,12 @@ meta.org.jkiss.dbeaver.ext.postgresql.model.PostgreLanguage.userDefined.name=Use
meta.org.jkiss.dbeaver.ext.postgresql.model.PostgreLanguage.userDefined.description=
meta.org.jkiss.dbeaver.ext.postgresql.model.PostgreLanguage.validatorId.name=Validator Id
meta.org.jkiss.dbeaver.ext.postgresql.model.PostgreLanguage.validatorId.description=
meta.org.jkiss.dbeaver.ext.postgresql.model.PostgreSetting.name.name=Name
meta.org.jkiss.dbeaver.ext.postgresql.model.PostgreSetting.name.description=
meta.org.jkiss.dbeaver.ext.postgresql.model.PostgreSetting.value.name=Value
meta.org.jkiss.dbeaver.ext.postgresql.model.PostgreSetting.value.description=
meta.org.jkiss.dbeaver.ext.postgresql.model.PostgreSetting.unit.name=Unit
meta.org.jkiss.dbeaver.ext.postgresql.model.PostgreSetting.unit.description=
meta.org.jkiss.dbeaver.ext.postgresql.model.PostgreProcedure.kind.name=Type
meta.org.jkiss.dbeaver.ext.postgresql.model.PostgreProcedure.objectId.name=Object ID
meta.org.jkiss.dbeaver.ext.postgresql.model.PostgreProcedure.aggregate.name=Aggregate
......@@ -628,6 +634,8 @@ tree.information.node.name=System Info
tree.information.node.tip=Information
tree.language.node.name=Language
tree.languages.node.name=Languages
tree.setting.node.name=Setting
tree.settings.node.name=Settings
tree.mview.node.name=Materialized View
tree.mviews.node.name=Materialized Views
tree.mviews.node.tip=Materialized views
......
......@@ -268,6 +268,12 @@ meta.org.jkiss.dbeaver.ext.postgresql.model.PostgreLanguage.userDefined.descript
meta.org.jkiss.dbeaver.ext.postgresql.model.PostgreLanguage.userDefined.name = \u041E\u043F\u0440\u0435\u0434\u0435\u043B\u0451\u043D \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u0435\u043C
meta.org.jkiss.dbeaver.ext.postgresql.model.PostgreLanguage.validatorId.description = Validator Id
meta.org.jkiss.dbeaver.ext.postgresql.model.PostgreLanguage.validatorId.name = \u041A\u043E\u0434 \u0432\u0430\u043B\u0438\u0434\u0430\u0442\u043E\u0440\u0430
meta.org.jkiss.dbeaver.ext.postgresql.model.PostgreSetting.name.name = \u041D\u0430\u0437\u0432\u0430\u043D\u0438\u0435
meta.org.jkiss.dbeaver.ext.postgresql.model.PostgreSetting.name.description =
meta.org.jkiss.dbeaver.ext.postgresql.model.PostgreSetting.value.name = \u0417\u043D\u0430\u0447\u0435\u043D\u0438\u0435
meta.org.jkiss.dbeaver.ext.postgresql.model.PostgreSetting.value.description =
meta.org.jkiss.dbeaver.ext.postgresql.model.PostgreSetting.unit.name = \u0415\u0434. \u0438\u0437\u043C.
meta.org.jkiss.dbeaver.ext.postgresql.model.PostgreSetting.unit.description =
meta.org.jkiss.dbeaver.ext.postgresql.model.PostgreMaterializedView.tablespace.description = \u0422\u0430\u0431\u043B\u0438\u0447\u043D\u043E\u0435 \u043F\u0440\u043E\u0441\u0442\u0440\u0430\u043D\u0441\u0442\u0432\u043E \u043C\u0430\u0442\u0435\u0440\u0438\u0430\u043B\u0438\u0437\u043E\u0432\u0430\u043D\u043D\u043E\u0433\u043E \u043F\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043B\u0435\u043D\u0438\u044F
meta.org.jkiss.dbeaver.ext.postgresql.model.PostgreMaterializedView.tablespace.name = \u0422\u0430\u0431\u043B\u0438\u0447\u043D\u043E\u0435 \u043F\u0440\u043E\u0441\u0442\u0440\u0430\u043D\u0441\u0442\u0432\u043E
meta.org.jkiss.dbeaver.ext.postgresql.model.PostgreMaterializedView.withData.name = \u041D\u0430\u043F\u043E\u043B\u043D\u0435\u043D\u043E
......@@ -599,6 +605,8 @@ tree.information.node.name = \u0421\u0438\u0441\u0442\u0435\u043C\u043D\u044B\u0
tree.information.node.tip = \u0418\u043D\u0444\u043E\u0440\u043C\u0430\u0446\u0438\u044F
tree.language.node.name = \u042F\u0437\u044B\u043A
tree.languages.node.name = \u042F\u0437\u044B\u043A\u0438
tree.setting.node.name = \u041D\u0430\u0441\u0442\u0440\u043E\u0439\u043A\u0430
tree.settings.node.name = \u041D\u0430\u0441\u0442\u0440\u043E\u0439\u043A\u0438
tree.locks.node.name = \u0411\u043B\u043E\u043A\u0438\u0440\u043E\u0432\u043A\u0438
tree.locks.node.tip = \u0414\u0438\u0441\u043F\u0435\u0442\u0447\u0435\u0440 \u0431\u043B\u043E\u043A\u0438\u0440\u043E\u0432\u043E\u043A \u0441\u0435\u0440\u0432\u0435\u0440\u0430
tree.mview.node.name = \u041C\u0430\u0442. \u043F\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043B\u0435\u043D\u0438\u0435
......
......@@ -261,7 +261,10 @@
</folder>
<folder type="org.jkiss.dbeaver.ext.postgresql.model.PostgreAvailableExtension" label="%tree.avalextensions.node.name" icon="#extensions" description="%tree.extensions.node.tip" visibleIf="object.dataSource.serverType.supportsExtensions()">
<items label="%tree.avalextension.node.name" path="extension" property="availableExtensions" icon="#extension"/>
</folder>
</folder>
<folder type="org.jkiss.dbeaver.ext.postgresql.model.PostgreSetting" label="%tree.settings.node.name" icon="#settings" description="Settings">
<items label="%tree.setting.node.name" path="setting" property="settings" icon="#setting"/>
</folder>
</folder>
</items>
......
......@@ -75,6 +75,9 @@ public class PostgreConstants {
public static final String TEMP_SCHEMA_PREFIX = "pg_temp_";
public static final String PUBLIC_SCHEMA_NAME = "public";
// Settings names from 'pg_options' view
public static final String OPTION_STANDARD_CONFORMING_STRINGS = "standard_conforming_strings";
public static final String PG_OBJECT_CLASS = "org.postgresql.util.PGobject";
public static final String PG_ARRAY_CLASS = "org.postgresql.jdbc.PgArray";
public static final String PG_INTERVAL_CLASS = "org.postgresql.util.PGInterval";
......
......@@ -68,6 +68,7 @@ public class PostgreDataSource extends JDBCDataSource implements DBSInstanceCont
private static final Log log = Log.getLog(PostgreDataSource.class);
private DatabaseCache databaseCache;
private SettingCache settingCache;
private String activeDatabaseName;
private PostgreServerExtension serverExtension;
private String serverVersion;
......@@ -95,7 +96,7 @@ public class PostgreDataSource extends JDBCDataSource implements DBSInstanceCont
this,
activeDatabaseName);
databaseCache.setCache(Collections.singletonList(defDatabase));
settingCache = new SettingCache();
}
@Override
......@@ -119,7 +120,7 @@ public class PostgreDataSource extends JDBCDataSource implements DBSInstanceCont
activeDatabaseName = PostgreConstants.DEFAULT_DATABASE;
}
databaseCache = new DatabaseCache();
settingCache = new SettingCache();
DBPConnectionConfiguration configuration = getContainer().getActualConnectionConfiguration();
final boolean showNDD = CommonUtils.getBoolean(configuration.getProviderProperty(PostgreConstants.PROP_SHOW_NON_DEFAULT_DB), false);
List<PostgreDatabase> dbList = new ArrayList<>();
......@@ -132,6 +133,12 @@ public class PostgreDataSource extends JDBCDataSource implements DBSInstanceCont
databaseCache.setCache(dbList);
// Initiate default context
getDefaultInstance().checkInstanceConnection(monitor, false);
try {
// Preload some settings, if available
settingCache.getObject(monitor, this, PostgreConstants.OPTION_STANDARD_CONFORMING_STRINGS);
} catch (DBException e) {
// ignore
}
}
private void loadAvailableDatabases(@NotNull DBRProgressMonitor monitor, DBPConnectionConfiguration configuration, List<PostgreDatabase> dbList) throws DBException {
......@@ -280,6 +287,18 @@ public class PostgreDataSource extends JDBCDataSource implements DBSInstanceCont
return databaseCache.getCachedObject(name);
}
public SettingCache getSettingCache() {
return settingCache;
}
public Collection<PostgreSetting> getSettings() {
return settingCache.getCachedObjects();
}
public PostgreSetting getSetting(String name) {
return settingCache.getCachedObject(name);
}
@Override
public void initialize(@NotNull DBRProgressMonitor monitor)
throws DBException
......@@ -611,6 +630,27 @@ public class PostgreDataSource extends JDBCDataSource implements DBSInstanceCont
}
}
static class SettingCache extends JDBCObjectLookupCache<PostgreDataSource, PostgreSetting> {
@NotNull
@Override
public JDBCStatement prepareLookupStatement(@NotNull JDBCSession session, @NotNull PostgreDataSource owner, @Nullable PostgreSetting object, @Nullable String objectName) throws SQLException {
if (object != null || objectName != null) {
final JDBCPreparedStatement dbStat = session.prepareStatement("select * from pg_catalog.pg_settings where name=?");
dbStat.setString(1, object != null ? object.getName() : objectName);
return dbStat;
}
return session.prepareStatement("select * from pg_catalog.pg_settings");
}
@Nullable
@Override
protected PostgreSetting fetchObject(@NotNull JDBCSession session, @NotNull PostgreDataSource owner, @NotNull JDBCResultSet dbResult) throws SQLException, DBException {
return new PostgreSetting(owner, dbResult);
}
}
private final Pattern ERROR_POSITION_PATTERN = Pattern.compile("\\n\\s*\\p{L}+\\s*: ([0-9]+)");
@Nullable
......
......@@ -440,6 +440,12 @@ public class PostgreDatabase extends JDBCRemoteInstance
return languageCache.getAllObjects(monitor, this);
}
@Association
public Collection<PostgreSetting> getSettings(DBRProgressMonitor monitor) throws DBException {
checkInstanceConnection(monitor);
return getDataSource().getSettingCache().getAllObjects(monitor, getDataSource());
}
@Association
public Collection<PostgreCharset> getEncodings(DBRProgressMonitor monitor) throws DBException {
if (!getDataSource().getServerType().supportsEncodings()) {
......
......@@ -22,6 +22,7 @@ import org.jkiss.dbeaver.ext.postgresql.PostgreConstants;
import org.jkiss.dbeaver.ext.postgresql.edit.PostgreTableColumnManager;
import org.jkiss.dbeaver.ext.postgresql.model.data.PostgreBinaryFormatter;
import org.jkiss.dbeaver.ext.postgresql.sql.PostgreDollarQuoteRule;
import org.jkiss.dbeaver.ext.postgresql.sql.PostgreEscapeStringRule;
import org.jkiss.dbeaver.model.DBPDataKind;
import org.jkiss.dbeaver.model.DBPDataSource;
import org.jkiss.dbeaver.model.DBPDataSourceContainer;
......@@ -745,7 +746,6 @@ public class PostgreDialect extends JDBCSQLDialect implements TPRuleProvider {
removeSQLKeyword("LENGTH");
if (dataSource instanceof PostgreDataSource) {
((PostgreDataSource) dataSource).getServerType().configureDialect(this);
serverExtension = ((PostgreDataSource) dataSource).getServerType();
serverExtension.configureDialect(this);
}
......@@ -876,6 +876,7 @@ public class PostgreDialect extends JDBCSQLDialect implements TPRuleProvider {
public void extendRules(@Nullable DBPDataSourceContainer dataSource, @NotNull List<TPRule> rules, @NotNull RulePosition position) {
if (position == RulePosition.INITIAL || position == RulePosition.PARTITION) {
rules.add(new PostgreDollarQuoteRule(dataSource, position == RulePosition.PARTITION));
rules.add(new PostgreEscapeStringRule());
}
}
}
/*
* DBeaver - Universal Database Manager
* Copyright (C) 2010-2021 DBeaver Corp and others
*
* 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.postgresql.model;
import org.jkiss.code.NotNull;
import org.jkiss.code.Nullable;
import org.jkiss.dbeaver.model.DBPDataSource;
import org.jkiss.dbeaver.model.impl.jdbc.JDBCUtils;
import org.jkiss.dbeaver.model.meta.Property;
import org.jkiss.dbeaver.model.struct.DBSObject;
import java.sql.ResultSet;
public class PostgreSetting implements DBSObject {
private final PostgreDataSource database;
private final String name;
private final String value;
private final String unit;
private final String description;
protected PostgreSetting(PostgreDataSource database, ResultSet dbResult) {
this.database = database;
this.name = JDBCUtils.safeGetString(dbResult, "name");
this.value = JDBCUtils.safeGetString(dbResult, "setting");
this.unit = JDBCUtils.safeGetString(dbResult, "unit");
this.description = JDBCUtils.safeGetString(dbResult, "short_desc");
}
@NotNull
@Property(viewable = true, order = 1)
@Override
public String getName() {
return name;
}
@Nullable
@Property(viewable = true, order = 2)
public String getValue() {
return value;
}
@Nullable
@Property(viewable = true, order = 3)
public String getUnit() {
return unit;
}
@Nullable
@Override
public String getDescription() {
return description;
}
@Override
public boolean isPersisted() {
return true;
}
@Nullable
@Override
public DBSObject getParentObject() {
return database;
}
@NotNull
@Override
public DBPDataSource getDataSource() {
return database.getDataSource();
}
}
......@@ -16,7 +16,9 @@
*/
package org.jkiss.dbeaver.ext.postgresql.model.impls;
import org.jkiss.dbeaver.ext.postgresql.PostgreConstants;
import org.jkiss.dbeaver.ext.postgresql.model.PostgreDataSource;
import org.jkiss.dbeaver.ext.postgresql.model.PostgreSetting;
/**
* PostgreServerPostgreSQL
......@@ -53,4 +55,10 @@ public class PostgreServerPostgreSQL extends PostgreServerExtensionBase {
public boolean supportsDatabaseSize() {
return true;
}
@Override
public boolean supportsBackslashStringEscape() {
final PostgreSetting setting = dataSource.getSetting(PostgreConstants.OPTION_STANDARD_CONFORMING_STRINGS);
return setting != null && "off".equals(setting.getValue());
}
}
/*
* DBeaver - Universal Database Manager
* Copyright (C) 2010-2021 DBeaver Corp and others
*
* 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.postgresql.sql;
import org.jkiss.dbeaver.model.sql.parser.tokens.SQLTokenType;
import org.jkiss.dbeaver.model.text.parser.*;
/**
* This rule matches string literals with C-Style escapes, as
* described in <b>4.1.2.2</b> chapter of PostgreSQL documentation.
*
* @see <a href="https://www.postgresql.org/docs/current/sql-syntax-lexical.html#SQL-SYNTAX-STRINGS-ESCAPE">4.1.2.2. String Constants with C-Style Escapes</a>
*/
public class PostgreEscapeStringRule implements TPPredicateRule {
private final TPToken stringToken = new TPTokenDefault(SQLTokenType.T_STRING);
@Override
public TPToken getSuccessToken() {
return stringToken;
}
@Override
public TPToken evaluate(TPCharacterScanner scanner, boolean resume) {
int ch = scanner.read();
int chRead = 1;
if (ch != 'e' && ch != 'E') {
scanner.unread();
return TPTokenAbstract.UNDEFINED;
}
ch = scanner.read();
chRead++;
if (ch != '\'') {
scanner.unread();
scanner.unread();
return TPTokenAbstract.UNDEFINED;
}
do {
ch = scanner.read();
chRead++;
if (ch == '\\' && (ch = scanner.read()) == '\'') {
// Don't care about other escape sequences
continue;
}
if (ch == '\'') {
return stringToken;
}
} while (ch != TPCharacterScanner.EOF);
while (chRead-- > 0) {
scanner.unread();
}
return TPTokenAbstract.UNDEFINED;
}
@Override
public TPToken evaluate(TPCharacterScanner scanner) {
return evaluate(scanner, false);
}
}
......@@ -124,20 +124,21 @@ public class SQLPartitionScanner extends RuleBasedPartitionScanner implements TP
boolean hasDoubleQuoteRule = false;
String[][] identifierQuoteStrings = dialect.getIdentifierQuoteStrings();
String[][] stringQuoteStrings = dialect.getStringQuoteStrings();
char stringEscapeCharacter = dialect.getStringEscapeCharacter();
if (identifierQuoteStrings != null) {
for (String[] quoteString : identifierQuoteStrings) {
rules.add(new MultiLineRule(quoteString[0], quoteString[1], sqlQuotedToken, dialect.getStringEscapeCharacter()));
rules.add(new MultiLineRule(quoteString[0], quoteString[1], sqlQuotedToken, stringEscapeCharacter));
if (quoteString[1].equals(SQLConstants.STR_QUOTE_DOUBLE) && quoteString[0].equals(quoteString[1])) {
hasDoubleQuoteRule = true;
}
}
}
if (!hasDoubleQuoteRule) {
rules.add(new MultiLineRule(SQLConstants.STR_QUOTE_DOUBLE, SQLConstants.STR_QUOTE_DOUBLE, sqlQuotedToken, dialect.getStringEscapeCharacter()));
rules.add(new MultiLineRule(SQLConstants.STR_QUOTE_DOUBLE, SQLConstants.STR_QUOTE_DOUBLE, sqlQuotedToken, stringEscapeCharacter));
}
if (!ArrayUtils.isEmpty(stringQuoteStrings)) {
for (String[] quotes : stringQuoteStrings) {
rules.add(new MultiLineRule(quotes[0], quotes[1], sqlStringToken, dialect.getStringEscapeCharacter()));
rules.add(new MultiLineRule(quotes[0], quotes[1], sqlStringToken, stringEscapeCharacter));
}
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册