From aae64f181c4c33be994bfad6cb920f1b959f7b05 Mon Sep 17 00:00:00 2001 From: Jan Bartel Date: Wed, 27 May 2020 13:42:01 +0200 Subject: [PATCH] Issue #4894 use schema and/or catalog name when creating sessions table (#4908) Signed-off-by: Jan Bartel --- .../sessions/session-configuration-jdbc.adoc | 22 ++++++- .../etc/sessions/jdbc/session-store.xml | 6 ++ .../config/modules/session-store-jdbc.mod | 11 ++++ .../server/session/JDBCSessionDataStore.java | 61 +++++++++++++++---- 4 files changed, 86 insertions(+), 14 deletions(-) diff --git a/jetty-documentation/src/main/asciidoc/administration/sessions/session-configuration-jdbc.adoc b/jetty-documentation/src/main/asciidoc/administration/sessions/session-configuration-jdbc.adoc index e02c04ca5e2..533cc88e061 100644 --- a/jetty-documentation/src/main/asciidoc/administration/sessions/session-configuration-jdbc.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/sessions/session-configuration-jdbc.adoc @@ -85,6 +85,16 @@ db-connection-type=datasource #jetty.session.jdbc.schema.maxIntervalColumn=maxInterval #jetty.session.jdbc.schema.mapColumn=map #jetty.session.jdbc.schema.table=JettySessions +# Optional name of the schema used to identify where the session table is defined in the database: +# "" - empty string, no schema name +# "INFERRED" - special string meaning infer from the current db connection +# name - a string defined by the user +#jetty.session.jdbc.schema.schemaName +# Optional name of the catalog used to identify where the session table is defined in the database: +# "" - empty string, no catalog name +# "INFERRED" - special string meaning infer from the current db connection +# name - a string defined by the user +#jetty.session.jdbc.schema.catalogName ---- jetty.session.gracePeriod.seconds:: @@ -111,4 +121,14 @@ jetty.session.jdbc.driverUrl:: Url of the database which includes the driver type, host name and port, service name and any specific attributes unique to the database, such as a username. As an example, here is a mysql connection with the username appended: `jdbc:mysql://127.0.0.1:3306/sessions?user=sessionsadmin`. -The `jetty.sessionTableSchema` values represent the names for the columns in the JDBC database and can be changed to suit your environment. +The `jetty.session.jdbc.schema.*` values represent the names of the table and columns in the JDBC database used to store sessions and can be changed to suit your environment. + +There are also two special, optional properties: `jetty.session.jdbc.schema.schemaName` and `jetty.session.jdbc.schema.catalogName`. +The exact meaning of these two properties is dependent on your database vendor, but can broadly be described as further scoping for the session table name. +See https://en.wikipedia.org/wiki/Database_schema and https://en.wikipedia.org/wiki/Database_catalog. +These extra scoping names can come into play at startup time when jetty determines if the session table already exists, or otherwise creates it on-the-fly. +If you have employed either of these concepts when you pre-created the session table, or you want to ensure that jetty uses them when it auto-creates the session table, then you have two options: either set them explicitly, or let jetty infer them from a database connection (obtained using either a Datasource or Driver according to the `db-connection-type` you have configured). +To set them explicitly, uncomment and supply appropriate values for the `jetty.session.jdbc.schema.schemaName` and/or `jetty.session.jdbc.schema.catalogName` properties. +To allow jetty to infer them from a database connection, use the special string `INFERRED` instead. +If you leave them blank or commented out, then the sessions table will not be scoped by schema or catalog name. + diff --git a/jetty-server/src/main/config/etc/sessions/jdbc/session-store.xml b/jetty-server/src/main/config/etc/sessions/jdbc/session-store.xml index 2bc8295ec5b..6a96d65f167 100644 --- a/jetty-server/src/main/config/etc/sessions/jdbc/session-store.xml +++ b/jetty-server/src/main/config/etc/sessions/jdbc/session-store.xml @@ -54,6 +54,12 @@ + + + + + + diff --git a/jetty-server/src/main/config/modules/session-store-jdbc.mod b/jetty-server/src/main/config/modules/session-store-jdbc.mod index e97457d0781..b367e364309 100644 --- a/jetty-server/src/main/config/modules/session-store-jdbc.mod +++ b/jetty-server/src/main/config/modules/session-store-jdbc.mod @@ -55,3 +55,14 @@ db-connection-type=datasource #jetty.session.jdbc.schema.maxIntervalColumn=maxInterval #jetty.session.jdbc.schema.mapColumn=map #jetty.session.jdbc.schema.table=JettySessions +# Optional name of the schema used to identify where the session table is defined in the database: +# "" - empty string, no schema name +# "INFERRED" - special string meaning infer from the current db connection +# name - a string defined by the user +#jetty.session.jdbc.schema.schemaName +# Optional name of the catalog used to identify where the session table is defined in the database: +# "" - empty string, no catalog name +# "INFERRED" - special string meaning infer from the current db connection +# name - a string defined by the user +#jetty.session.jdbc.schema.catalogName + diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/session/JDBCSessionDataStore.java b/jetty-server/src/main/java/org/eclipse/jetty/server/session/JDBCSessionDataStore.java index 54e6b5354a7..0fb2f3830f8 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/session/JDBCSessionDataStore.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/session/JDBCSessionDataStore.java @@ -66,9 +66,11 @@ public class JDBCSessionDataStore extends AbstractSessionDataStore public static class SessionTableSchema { public static final int MAX_INTERVAL_NOT_SET = -999; + public static final String INFERRED = "INFERRED"; protected DatabaseAdaptor _dbAdaptor; protected String _schemaName = null; + protected String _catalogName = null; protected String _tableName = "JettySessions"; protected String _idColumn = "sessionId"; protected String _contextPathColumn = "contextPath"; @@ -87,7 +89,20 @@ public class JDBCSessionDataStore extends AbstractSessionDataStore { _dbAdaptor = dbadaptor; } + + public void setCatalogName(String catalogName) + { + if (catalogName != null && StringUtil.isBlank(catalogName)) + _catalogName = null; + else + _catalogName = catalogName; + } + public String getCatalogName() + { + return _catalogName; + } + public String getSchemaName() { return _schemaName; @@ -95,8 +110,10 @@ public class JDBCSessionDataStore extends AbstractSessionDataStore public void setSchemaName(String schemaName) { - checkNotNull(schemaName); - _schemaName = schemaName; + if (schemaName != null && StringUtil.isBlank(schemaName)) + _schemaName = null; + else + _schemaName = schemaName; } public String getTableName() @@ -484,28 +501,48 @@ public class JDBCSessionDataStore extends AbstractSessionDataStore //make the session table if necessary String tableName = _dbAdaptor.convertIdentifier(getTableName()); + String schemaName = _dbAdaptor.convertIdentifier(getSchemaName()); - try (ResultSet result = metaData.getTables(null, schemaName, tableName, null)) + if (INFERRED.equalsIgnoreCase(schemaName)) + { + //use the value from the connection - + //NOTE that this value will also now be prepended to ALL + //table names in queries/updates. + schemaName = connection.getSchema(); + setSchemaName(schemaName); + } + String catalogName = _dbAdaptor.convertIdentifier(getCatalogName()); + if (INFERRED.equalsIgnoreCase(catalogName)) + { + //use the value from the connection + catalogName = connection.getCatalog(); + setCatalogName(catalogName); + } + + try (ResultSet result = metaData.getTables(catalogName, schemaName, tableName, null)) { if (!result.next()) { + if (LOG.isDebugEnabled()) + LOG.debug("Creating table {} schema={} catalog={}", tableName, schemaName, catalogName); //table does not exist, so create it statement.executeUpdate(getCreateStatementAsString()); } else { + if (LOG.isDebugEnabled()) + LOG.debug("Not creating table {} schema={} catalog={}", tableName, schemaName, catalogName); //session table exists, check it has maxinterval column ResultSet colResult = null; try { - colResult = metaData.getColumns(null, schemaName, tableName, + colResult = metaData.getColumns(catalogName, schemaName, tableName, _dbAdaptor.convertIdentifier(getMaxIntervalColumn())); } catch (SQLException sqlEx) { - LOG.warn("Problem checking if " + getTableName() + - " table contains " + getMaxIntervalColumn() + " column. Ensure table contains column definition: \"" + - getMaxIntervalColumn() + " long not null default -999\""); + LOG.warn("Problem checking if {} table contains {} column. Ensure table contains column with definition: long not null default -999", + getTableName(), getMaxIntervalColumn()); throw sqlEx; } try @@ -519,9 +556,7 @@ public class JDBCSessionDataStore extends AbstractSessionDataStore } catch (SQLException sqlEx) { - LOG.warn("Problem adding " + getMaxIntervalColumn() + - " column. Ensure table contains column definition: \"" + getMaxIntervalColumn() + - " long not null default -999\""); + LOG.warn("Problem adding {} column. Ensure table contains column definition: long not null default -999", getMaxIntervalColumn()); throw sqlEx; } } @@ -538,7 +573,7 @@ public class JDBCSessionDataStore extends AbstractSessionDataStore boolean index1Exists = false; boolean index2Exists = false; - try (ResultSet result = metaData.getIndexInfo(null, schemaName, tableName, false, true)) + try (ResultSet result = metaData.getIndexInfo(catalogName, schemaName, tableName, false, true)) { while (result.next()) { @@ -559,8 +594,8 @@ public class JDBCSessionDataStore extends AbstractSessionDataStore @Override public String toString() { - return String.format("%s[%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s]", super.toString(), - _schemaName, _tableName, _idColumn, _contextPathColumn, _virtualHostColumn, _cookieTimeColumn, _createTimeColumn, + return String.format("%s[%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s]", super.toString(), + _catalogName, _schemaName, _tableName, _idColumn, _contextPathColumn, _virtualHostColumn, _cookieTimeColumn, _createTimeColumn, _expiryTimeColumn, _accessTimeColumn, _lastAccessTimeColumn, _lastNodeColumn, _lastSavedTimeColumn, _maxIntervalColumn); } }