提交 12082887 authored 作者: Noel Grandin's avatar Noel Grandin 提交者: GitHub

Merge pull request #640 from stumc/Issue#628

Issue#628 NPE in CTE 
...@@ -143,6 +143,7 @@ import org.h2.table.Table; ...@@ -143,6 +143,7 @@ import org.h2.table.Table;
import org.h2.table.TableFilter; import org.h2.table.TableFilter;
import org.h2.table.TableFilter.TableFilterVisitor; import org.h2.table.TableFilter.TableFilterVisitor;
import org.h2.table.TableView; import org.h2.table.TableView;
import org.h2.util.ColumnNamer;
import org.h2.util.MathUtils; import org.h2.util.MathUtils;
import org.h2.util.New; import org.h2.util.New;
import org.h2.util.StatementBuilder; import org.h2.util.StatementBuilder;
...@@ -5268,23 +5269,16 @@ public class Parser { ...@@ -5268,23 +5269,16 @@ public class Parser {
// array of length 1 to receive extra 'output' field in addition to // array of length 1 to receive extra 'output' field in addition to
// return value // return value
querySQLOutput[0] = StringUtils.cache(theQuery.getPlanSQL()); querySQLOutput[0] = StringUtils.cache(theQuery.getPlanSQL());
ColumnNamer columnNamer = new ColumnNamer(theQuery.getSession());
ArrayList<Expression> withExpressions = theQuery.getExpressions(); ArrayList<Expression> withExpressions = theQuery.getExpressions();
for (int i = 0; i < withExpressions.size(); ++i) { for (int i = 0; i < withExpressions.size(); ++i) {
Expression columnExp = withExpressions.get(i); Expression columnExp = withExpressions.get(i);
/* // use the passed in column name if supplied, otherwise use alias (if found) otherwise use column name
* Use the passed in column name if supplied, otherwise use alias // derived from column expression
* (if found) otherwise use column name derived from column String columnName = columnNamer.getColumnName(columnExp,i,cols);
* expression. columnTemplateList.add(new Column(columnName,
*/ columnExp.getType()));
String columnName;
if (cols != null) {
columnName = cols[i];
} else if (columnExp.getAlias() != null) {
columnName = columnExp.getAlias();
} else {
columnName = columnExp.getColumnName();
}
columnTemplateList.add(new Column(columnName, columnExp.getType()));
} }
return columnTemplateList; return columnTemplateList;
} }
...@@ -5300,6 +5294,7 @@ public class Parser { ...@@ -5300,6 +5294,7 @@ public class Parser {
parameters, columnTemplateList.toArray(new Column[0]), session, parameters, columnTemplateList.toArray(new Column[0]), session,
allowRecursiveQueryDetection, false); allowRecursiveQueryDetection, false);
if (!view.isRecursiveQueryDetected() && allowRecursiveQueryDetection) { if (!view.isRecursiveQueryDetected() && allowRecursiveQueryDetection) {
session.removeLocalTempTable(view);
view = new TableView(schema, id, tempViewName, querySQL, parameters, view = new TableView(schema, id, tempViewName, querySQL, parameters,
columnTemplateList.toArray(new Column[0]), session, columnTemplateList.toArray(new Column[0]), session,
false/* recursive */, false); false/* recursive */, false);
......
...@@ -23,6 +23,7 @@ import org.h2.schema.Sequence; ...@@ -23,6 +23,7 @@ import org.h2.schema.Sequence;
import org.h2.table.Column; import org.h2.table.Column;
import org.h2.table.IndexColumn; import org.h2.table.IndexColumn;
import org.h2.table.Table; import org.h2.table.Table;
import org.h2.util.ColumnNamer;
import org.h2.util.New; import org.h2.util.New;
import org.h2.value.DataType; import org.h2.value.DataType;
import org.h2.value.Value; import org.h2.value.Value;
...@@ -230,10 +231,11 @@ public class CreateTable extends SchemaCommand { ...@@ -230,10 +231,11 @@ public class CreateTable extends SchemaCommand {
private void generateColumnsFromQuery() { private void generateColumnsFromQuery() {
int columnCount = asQuery.getColumnCount(); int columnCount = asQuery.getColumnCount();
ArrayList<Expression> expressions = asQuery.getExpressions(); ArrayList<Expression> expressions = asQuery.getExpressions();
ColumnNamer columnNamer= new ColumnNamer(session);
for (int i = 0; i < columnCount; i++) { for (int i = 0; i < columnCount; i++) {
Expression expr = expressions.get(i); Expression expr = expressions.get(i);
int type = expr.getType(); int type = expr.getType();
String name = expr.getAlias(); String name = columnNamer.getColumnName(expr,i,expr.getAlias());
long precision = expr.getPrecision(); long precision = expr.getPrecision();
int displaySize = expr.getDisplaySize(); int displaySize = expr.getDisplaySize();
DataType dt = DataType.getDataType(type); DataType dt = DataType.getDataType(type);
......
...@@ -16,6 +16,7 @@ import org.h2.engine.Constants; ...@@ -16,6 +16,7 @@ import org.h2.engine.Constants;
import org.h2.engine.Database; import org.h2.engine.Database;
import org.h2.engine.Session; import org.h2.engine.Session;
import org.h2.engine.SysProperties; import org.h2.engine.SysProperties;
import org.h2.expression.Alias;
import org.h2.expression.Comparison; import org.h2.expression.Comparison;
import org.h2.expression.ConditionAndOr; import org.h2.expression.ConditionAndOr;
import org.h2.expression.Expression; import org.h2.expression.Expression;
...@@ -40,6 +41,7 @@ import org.h2.table.JoinBatch; ...@@ -40,6 +41,7 @@ import org.h2.table.JoinBatch;
import org.h2.table.Table; import org.h2.table.Table;
import org.h2.table.TableFilter; import org.h2.table.TableFilter;
import org.h2.table.TableView; import org.h2.table.TableView;
import org.h2.util.ColumnNamer;
import org.h2.util.New; import org.h2.util.New;
import org.h2.util.StatementBuilder; import org.h2.util.StatementBuilder;
import org.h2.util.StringUtils; import org.h2.util.StringUtils;
...@@ -838,8 +840,15 @@ public class Select extends Query { ...@@ -838,8 +840,15 @@ public class Select extends Query {
sort = prepareOrder(orderList, expressions.size()); sort = prepareOrder(orderList, expressions.size());
orderList = null; orderList = null;
} }
ColumnNamer columnNamer= new ColumnNamer(session);
for (int i = 0; i < expressions.size(); i++) { for (int i = 0; i < expressions.size(); i++) {
Expression e = expressions.get(i); Expression e = expressions.get(i);
String proposedColumnName = e.getAlias();
String columnName = columnNamer.getColumnName(e,i,proposedColumnName);
// if the name changed, create an alias
if(!columnName.equals(proposedColumnName)){
e = new Alias(e,columnName,true);
}
expressions.set(i, e.optimize(session)); expressions.set(i, e.optimize(session));
} }
if (condition != null) { if (condition != null) {
......
...@@ -11,6 +11,7 @@ import org.h2.expression.ExpressionColumn; ...@@ -11,6 +11,7 @@ import org.h2.expression.ExpressionColumn;
import org.h2.table.Column; import org.h2.table.Column;
import org.h2.table.ColumnResolver; import org.h2.table.ColumnResolver;
import org.h2.table.TableFilter; import org.h2.table.TableFilter;
import org.h2.util.ColumnNamer;
import org.h2.value.Value; import org.h2.value.Value;
/** /**
...@@ -35,9 +36,11 @@ public class SelectListColumnResolver implements ColumnResolver { ...@@ -35,9 +36,11 @@ public class SelectListColumnResolver implements ColumnResolver {
columns = new Column[columnCount]; columns = new Column[columnCount];
expressions = new Expression[columnCount]; expressions = new Expression[columnCount];
ArrayList<Expression> columnList = select.getExpressions(); ArrayList<Expression> columnList = select.getExpressions();
ColumnNamer columnNamer= new ColumnNamer(select.getSession());
for (int i = 0; i < columnCount; i++) { for (int i = 0; i < columnCount; i++) {
Expression expr = columnList.get(i); Expression expr = columnList.get(i);
Column column = new Column(expr.getAlias(), Value.NULL); String columnName = columnNamer.getColumnName(expr, i, expr.getAlias());
Column column = new Column(columnName, Value.NULL);
column.setTable(null, i); column.setTable(null, i);
columns[i] = column; columns[i] = column;
expressions[i] = expr.getNonAliasExpression(); expressions[i] = expr.getNonAliasExpression();
......
...@@ -26,6 +26,7 @@ import org.h2.table.Column; ...@@ -26,6 +26,7 @@ import org.h2.table.Column;
import org.h2.table.ColumnResolver; import org.h2.table.ColumnResolver;
import org.h2.table.Table; import org.h2.table.Table;
import org.h2.table.TableFilter; import org.h2.table.TableFilter;
import org.h2.util.ColumnNamer;
import org.h2.util.New; import org.h2.util.New;
import org.h2.util.StringUtils; import org.h2.util.StringUtils;
import org.h2.value.Value; import org.h2.value.Value;
...@@ -329,6 +330,7 @@ public class SelectUnion extends Query { ...@@ -329,6 +330,7 @@ public class SelectUnion extends Query {
expressions = New.arrayList(); expressions = New.arrayList();
ArrayList<Expression> le = left.getExpressions(); ArrayList<Expression> le = left.getExpressions();
ArrayList<Expression> re = right.getExpressions(); ArrayList<Expression> re = right.getExpressions();
ColumnNamer columnNamer= new ColumnNamer(session);
for (int i = 0; i < len; i++) { for (int i = 0; i < len; i++) {
Expression l = le.get(i); Expression l = le.get(i);
Expression r = re.get(i); Expression r = re.get(i);
...@@ -336,7 +338,8 @@ public class SelectUnion extends Query { ...@@ -336,7 +338,8 @@ public class SelectUnion extends Query {
long prec = Math.max(l.getPrecision(), r.getPrecision()); long prec = Math.max(l.getPrecision(), r.getPrecision());
int scale = Math.max(l.getScale(), r.getScale()); int scale = Math.max(l.getScale(), r.getScale());
int displaySize = Math.max(l.getDisplaySize(), r.getDisplaySize()); int displaySize = Math.max(l.getDisplaySize(), r.getDisplaySize());
Column col = new Column(l.getAlias(), type, prec, scale, displaySize); String columnName = columnNamer.getColumnName(l,i,l.getAlias());
Column col = new Column(columnName, type, prec, scale, displaySize);
Expression e = new ExpressionColumn(session.getDatabase(), col); Expression e = new ExpressionColumn(session.getDatabase(), col);
expressions.add(e); expressions.add(e);
} }
......
...@@ -341,6 +341,7 @@ public class Set extends Prepared { ...@@ -341,6 +341,7 @@ public class Set extends Prepared {
if (database.getMode() != mode) { if (database.getMode() != mode) {
session.getUser().checkAdmin(); session.getUser().checkAdmin();
database.setMode(mode); database.setMode(mode);
session.getColumnNamerConfiguration().configure(mode.getEnum());
} }
break; break;
case SetTypes.MULTI_THREADED: { case SetTypes.MULTI_THREADED: {
...@@ -534,6 +535,13 @@ public class Set extends Prepared { ...@@ -534,6 +535,13 @@ public class Set extends Prepared {
database.setAllowBuiltinAliasOverride(value == 1); database.setAllowBuiltinAliasOverride(value == 1);
break; break;
} }
case SetTypes.COLUMN_NAME_RULES: {
session.getUser().checkAdmin();
session.getColumnNamerConfiguration().configure(expression.getColumnName());
break;
}
default: default:
DbException.throwInternalError("type="+type); DbException.throwInternalError("type="+type);
} }
......
...@@ -247,6 +247,11 @@ public class SetTypes { ...@@ -247,6 +247,11 @@ public class SetTypes {
* The type of SET BUILTIN_ALIAS_OVERRIDE statement. * The type of SET BUILTIN_ALIAS_OVERRIDE statement.
*/ */
public static final int BUILTIN_ALIAS_OVERRIDE = 47; public static final int BUILTIN_ALIAS_OVERRIDE = 47;
/**
* The type of a SET COLUMN_NAME_RULES statement.
*/
public static final int COLUMN_NAME_RULES = 48;
private static final ArrayList<String> TYPES = New.arrayList(); private static final ArrayList<String> TYPES = New.arrayList();
...@@ -304,6 +309,8 @@ public class SetTypes { ...@@ -304,6 +309,8 @@ public class SetTypes {
list.add(FORCE_JOIN_ORDER, "FORCE_JOIN_ORDER"); list.add(FORCE_JOIN_ORDER, "FORCE_JOIN_ORDER");
list.add(LAZY_QUERY_EXECUTION, "LAZY_QUERY_EXECUTION"); list.add(LAZY_QUERY_EXECUTION, "LAZY_QUERY_EXECUTION");
list.add(BUILTIN_ALIAS_OVERRIDE, "BUILTIN_ALIAS_OVERRIDE"); list.add(BUILTIN_ALIAS_OVERRIDE, "BUILTIN_ALIAS_OVERRIDE");
list.add(COLUMN_NAME_RULES, "COLUMN_NAME_RULES");
} }
/** /**
......
...@@ -17,11 +17,15 @@ import org.h2.util.StringUtils; ...@@ -17,11 +17,15 @@ import org.h2.util.StringUtils;
* PostgreSQL, MySQL). Each mode has different settings. * PostgreSQL, MySQL). Each mode has different settings.
*/ */
public class Mode { public class Mode {
public enum ModeEnum {
REGULAR, DB2, Derby, MSSQLServer, HSQLDB, MySQL, Oracle, PostgreSQL, Ignite,
}
/** /**
* The name of the default mode. * The name of the default mode.
*/ */
static final String REGULAR = "REGULAR"; static final String REGULAR = ModeEnum.REGULAR.name();
private static final HashMap<String, Mode> MODES = New.hashMap(); private static final HashMap<String, Mode> MODES = New.hashMap();
...@@ -180,12 +184,14 @@ public class Mode { ...@@ -180,12 +184,14 @@ public class Mode {
private final String name; private final String name;
private ModeEnum modeEnum;
static { static {
Mode mode = new Mode(REGULAR); Mode mode = new Mode(ModeEnum.REGULAR.name());
mode.nullConcatIsNull = true; mode.nullConcatIsNull = true;
add(mode); add(mode);
mode = new Mode("DB2"); mode = new Mode(ModeEnum.DB2.name());
mode.aliasColumnName = true; mode.aliasColumnName = true;
mode.supportOffsetFetch = true; mode.supportOffsetFetch = true;
mode.sysDummy1 = true; mode.sysDummy1 = true;
...@@ -200,7 +206,7 @@ public class Mode { ...@@ -200,7 +206,7 @@ public class Mode {
mode.allowDB2TimestampFormat = true; mode.allowDB2TimestampFormat = true;
add(mode); add(mode);
mode = new Mode("Derby"); mode = new Mode(ModeEnum.Derby.name());
mode.aliasColumnName = true; mode.aliasColumnName = true;
mode.uniqueIndexSingleNull = true; mode.uniqueIndexSingleNull = true;
mode.supportOffsetFetch = true; mode.supportOffsetFetch = true;
...@@ -210,7 +216,7 @@ public class Mode { ...@@ -210,7 +216,7 @@ public class Mode {
mode.supportedClientInfoPropertiesRegEx = null; mode.supportedClientInfoPropertiesRegEx = null;
add(mode); add(mode);
mode = new Mode("HSQLDB"); mode = new Mode(ModeEnum.HSQLDB.name());
mode.aliasColumnName = true; mode.aliasColumnName = true;
mode.convertOnlyToSmallerScale = true; mode.convertOnlyToSmallerScale = true;
mode.nullConcatIsNull = true; mode.nullConcatIsNull = true;
...@@ -223,7 +229,7 @@ public class Mode { ...@@ -223,7 +229,7 @@ public class Mode {
mode.supportedClientInfoPropertiesRegEx = null; mode.supportedClientInfoPropertiesRegEx = null;
add(mode); add(mode);
mode = new Mode("MSSQLServer"); mode = new Mode(ModeEnum.MSSQLServer.name());
mode.aliasColumnName = true; mode.aliasColumnName = true;
mode.squareBracketQuotedNames = true; mode.squareBracketQuotedNames = true;
mode.uniqueIndexSingleNull = true; mode.uniqueIndexSingleNull = true;
...@@ -235,7 +241,7 @@ public class Mode { ...@@ -235,7 +241,7 @@ public class Mode {
mode.supportedClientInfoPropertiesRegEx = null; mode.supportedClientInfoPropertiesRegEx = null;
add(mode); add(mode);
mode = new Mode("MySQL"); mode = new Mode(ModeEnum.MySQL.name());
mode.convertInsertNullToZero = true; mode.convertInsertNullToZero = true;
mode.indexDefinitionInCreateTable = true; mode.indexDefinitionInCreateTable = true;
mode.lowerCaseIdentifiers = true; mode.lowerCaseIdentifiers = true;
...@@ -249,7 +255,7 @@ public class Mode { ...@@ -249,7 +255,7 @@ public class Mode {
mode.prohibitEmptyInPredicate = true; mode.prohibitEmptyInPredicate = true;
add(mode); add(mode);
mode = new Mode("Oracle"); mode = new Mode(ModeEnum.Oracle.name());
mode.aliasColumnName = true; mode.aliasColumnName = true;
mode.convertOnlyToSmallerScale = true; mode.convertOnlyToSmallerScale = true;
mode.uniqueIndexSingleNullExceptAllColumnsAreNull = true; mode.uniqueIndexSingleNullExceptAllColumnsAreNull = true;
...@@ -262,7 +268,7 @@ public class Mode { ...@@ -262,7 +268,7 @@ public class Mode {
mode.prohibitEmptyInPredicate = true; mode.prohibitEmptyInPredicate = true;
add(mode); add(mode);
mode = new Mode("PostgreSQL"); mode = new Mode(ModeEnum.PostgreSQL.name());
mode.aliasColumnName = true; mode.aliasColumnName = true;
mode.nullConcatIsNull = true; mode.nullConcatIsNull = true;
mode.supportOffsetFetch = true; mode.supportOffsetFetch = true;
...@@ -285,7 +291,7 @@ public class Mode { ...@@ -285,7 +291,7 @@ public class Mode {
mode.disallowedTypes = disallowedTypes; mode.disallowedTypes = disallowedTypes;
add(mode); add(mode);
mode = new Mode("Ignite"); mode = new Mode(ModeEnum.Ignite.name());
mode.nullConcatIsNull = true; mode.nullConcatIsNull = true;
mode.allowAffinityKey = true; mode.allowAffinityKey = true;
mode.indexDefinitionInCreateTable = true; mode.indexDefinitionInCreateTable = true;
...@@ -294,6 +300,7 @@ public class Mode { ...@@ -294,6 +300,7 @@ public class Mode {
private Mode(String name) { private Mode(String name) {
this.name = name; this.name = name;
this.modeEnum = ModeEnum.valueOf(name);
} }
private static void add(Mode mode) { private static void add(Mode mode) {
...@@ -311,15 +318,19 @@ public class Mode { ...@@ -311,15 +318,19 @@ public class Mode {
} }
public static Mode getMySQL() { public static Mode getMySQL() {
return getInstance("MySQL"); return getInstance(ModeEnum.MySQL.name());
} }
public static Mode getOracle() { public static Mode getOracle() {
return getInstance("Oracle"); return getInstance(ModeEnum.Oracle.name());
} }
public String getName() { public String getName() {
return name; return name;
} }
public ModeEnum getEnum() {
return this.modeEnum;
}
} }
...@@ -42,6 +42,7 @@ import org.h2.table.SubQueryInfo; ...@@ -42,6 +42,7 @@ import org.h2.table.SubQueryInfo;
import org.h2.table.Table; import org.h2.table.Table;
import org.h2.table.TableFilter; import org.h2.table.TableFilter;
import org.h2.table.TableType; import org.h2.table.TableType;
import org.h2.util.ColumnNamerConfiguration;
import org.h2.util.New; import org.h2.util.New;
import org.h2.util.SmallLRUCache; import org.h2.util.SmallLRUCache;
import org.h2.value.Value; import org.h2.value.Value;
...@@ -126,6 +127,7 @@ public class Session extends SessionWithState { ...@@ -126,6 +127,7 @@ public class Session extends SessionWithState {
private boolean joinBatchEnabled; private boolean joinBatchEnabled;
private boolean forceJoinOrder; private boolean forceJoinOrder;
private boolean lazyQueryExecution; private boolean lazyQueryExecution;
private ColumnNamerConfiguration columnNamerConfiguration;
/** /**
* Tables marked for ANALYZE after the current transaction is committed. * Tables marked for ANALYZE after the current transaction is committed.
* Prevents us calling ANALYZE repeatedly in large transactions. * Prevents us calling ANALYZE repeatedly in large transactions.
...@@ -162,6 +164,7 @@ public class Session extends SessionWithState { ...@@ -162,6 +164,7 @@ public class Session extends SessionWithState {
this.lockTimeout = setting == null ? this.lockTimeout = setting == null ?
Constants.INITIAL_LOCK_TIMEOUT : setting.getIntValue(); Constants.INITIAL_LOCK_TIMEOUT : setting.getIntValue();
this.currentSchemaName = Constants.SCHEMA_MAIN; this.currentSchemaName = Constants.SCHEMA_MAIN;
this.columnNamerConfiguration = ColumnNamerConfiguration.getDefault();
} }
public void setLazyQueryExecution(boolean lazyQueryExecution) { public void setLazyQueryExecution(boolean lazyQueryExecution) {
...@@ -373,6 +376,8 @@ public class Session extends SessionWithState { ...@@ -373,6 +376,8 @@ public class Session extends SessionWithState {
* @param table the table * @param table the table
*/ */
public void removeLocalTempTable(Table table) { public void removeLocalTempTable(Table table) {
// Exception thrown in org.h2.engine.Database.removeMeta if line below is missing with TestGeneralCommonTableQueries
database.lockMeta(this);
modificationId++; modificationId++;
localTempTables.remove(table.getName()); localTempTables.remove(table.getName());
synchronized (database) { synchronized (database) {
...@@ -974,6 +979,8 @@ public class Session extends SessionWithState { ...@@ -974,6 +979,8 @@ public class Session extends SessionWithState {
modificationId++; modificationId++;
table.setModified(); table.setModified();
it.remove(); it.remove();
// Exception thrown in org.h2.engine.Database.removeMeta if line below is missing with TestDeadlock
database.lockMeta(this);
table.removeChildrenAndResources(this); table.removeChildrenAndResources(this);
if (closeSession) { if (closeSession) {
// need to commit, otherwise recovery might // need to commit, otherwise recovery might
...@@ -1747,4 +1754,12 @@ public class Session extends SessionWithState { ...@@ -1747,4 +1754,12 @@ public class Session extends SessionWithState {
} }
} }
public ColumnNamerConfiguration getColumnNamerConfiguration() {
return columnNamerConfiguration;
}
public void setColumnNamerConfiguration(ColumnNamerConfiguration columnNamerConfiguration) {
this.columnNamerConfiguration = columnNamerConfiguration;
}
} }
...@@ -30,6 +30,7 @@ import org.h2.result.ResultInterface; ...@@ -30,6 +30,7 @@ import org.h2.result.ResultInterface;
import org.h2.result.Row; import org.h2.result.Row;
import org.h2.result.SortOrder; import org.h2.result.SortOrder;
import org.h2.schema.Schema; import org.h2.schema.Schema;
import org.h2.util.ColumnNamer;
import org.h2.util.New; import org.h2.util.New;
import org.h2.util.StatementBuilder; import org.h2.util.StatementBuilder;
import org.h2.util.StringUtils; import org.h2.util.StringUtils;
...@@ -162,6 +163,7 @@ public class TableView extends Table { ...@@ -162,6 +163,7 @@ public class TableView extends Table {
tables = New.arrayList(query.getTables()); tables = New.arrayList(query.getTables());
ArrayList<Expression> expressions = query.getExpressions(); ArrayList<Expression> expressions = query.getExpressions();
ArrayList<Column> list = New.arrayList(); ArrayList<Column> list = New.arrayList();
ColumnNamer columnNamer= new ColumnNamer(session);
for (int i = 0, count = query.getColumnCount(); i < count; i++) { for (int i = 0, count = query.getColumnCount(); i < count; i++) {
Expression expr = expressions.get(i); Expression expr = expressions.get(i);
String name = null; String name = null;
...@@ -173,6 +175,7 @@ public class TableView extends Table { ...@@ -173,6 +175,7 @@ public class TableView extends Table {
if (name == null) { if (name == null) {
name = expr.getAlias(); name = expr.getAlias();
} }
name = columnNamer.getColumnName(expr,i,name);
if (type == Value.UNKNOWN) { if (type == Value.UNKNOWN) {
type = expr.getType(); type = expr.getType();
} }
...@@ -441,7 +444,7 @@ public class TableView extends Table { ...@@ -441,7 +444,7 @@ public class TableView extends Table {
@Override @Override
public String getSQL() { public String getSQL() {
if (isTemporary()) { if (isTemporary() && querySQL!=null) {
return "(\n" + StringUtils.indent(querySQL) + ")"; return "(\n" + StringUtils.indent(querySQL) + ")";
} }
return super.getSQL(); return super.getSQL();
......
package org.h2.util;
import java.util.HashSet;
import java.util.Set;
import java.util.regex.Matcher;
import org.h2.engine.Session;
import org.h2.expression.Expression;
public class ColumnNamer {
private static final String DEFAULT_COLUMN_NAME = "DEFAULT";
private ColumnNamerConfiguration configuration;
private Session session;
private Set<String> existingColumnNames = new HashSet<String>();
public ColumnNamer(Session session) {
this.session = session;
if(this.session!=null && this.session.getColumnNamerConfiguration()!=null){
// use original from session
this.configuration = this.session.getColumnNamerConfiguration();
}
else{
// detached namer, create new
this.configuration = ColumnNamerConfiguration.getDefault();
if(session!=null){
session.setColumnNamerConfiguration(this.configuration);
}
}
}
/**
* Create a standardized column name that isn't null and doesn't have a CR/LF in it.
* @param columnExp the column expression
* @param indexOfColumn index of column in below array
* @return
*/
public String getColumnName(Expression expr, int indexOfColumn) {
return getColumnName(expr,indexOfColumn,(String) null);
}
/**
* Create a standardized column name that isn't null and doesn't have a CR/LF in it.
* @param columnExp the column expression
* @param indexOfColumn index of column in below array
* @param columnNameOverides array of overriding column names
* @return the new column name
*/
public String getColumnName(Expression columnExp, int indexOfColumn, String[] columnNameOverides){
String columnNameOverride = null;
if (columnNameOverides != null && columnNameOverides.length > indexOfColumn){
columnNameOverride = columnNameOverides[indexOfColumn];
}
return getColumnName(columnExp, indexOfColumn, columnNameOverride);
}
/**
* Create a standardized column name that isn't null and doesn't have a CR/LF in it.
* @param columnExp the column expression
* @param indexOfColumn index of column in below array
* @param columnNameOverride single overriding column name
* @return the new column name
*/
public String getColumnName(Expression columnExp, int indexOfColumn, String columnNameOverride) {
// try a name from the column name override
String columnName = null;
if (columnNameOverride != null){
columnName = columnNameOverride;
if(!isAllowableColumnName(columnName)){
columnName = fixColumnName(columnName);
}
if(!isAllowableColumnName(columnName)){
columnName = null;
}
}
// try a name from the column alias
if (columnName==null && columnExp.getAlias()!=null && !DEFAULT_COLUMN_NAME.equals(columnExp.getAlias())){
columnName = columnExp.getAlias();
if(!isAllowableColumnName(columnName)){
columnName = fixColumnName(columnName);
}
if(!isAllowableColumnName(columnName)){
columnName = null;
}
}
// try a name derived from the column expression SQL
if (columnName==null && columnExp.getColumnName()!=null && !DEFAULT_COLUMN_NAME.equals(columnExp.getColumnName())){
columnName = columnExp.getColumnName();
if(!isAllowableColumnName(columnName)){
columnName = fixColumnName(columnName);
}
if(!isAllowableColumnName(columnName)){
columnName = null;
}
}
// try a name derived from the column expression plan SQL
if (columnName==null && columnExp.getSQL()!=null && !DEFAULT_COLUMN_NAME.equals(columnExp.getSQL())){
columnName = columnExp.getSQL();
if(!isAllowableColumnName(columnName)){
columnName = fixColumnName(columnName);
}
if(!isAllowableColumnName(columnName)){
columnName = null;
}
}
// go with a innocuous default name pattern
if (columnName==null){
columnName = configuration.getDefaultColumnNamePattern().replace("$$", ""+(indexOfColumn+1));
}
if(existingColumnNames.contains(columnName) && configuration.isGenerateUniqueColumnNames()){
columnName = generateUniqueName(columnName);
}
existingColumnNames.add(columnName);
return columnName;
}
private String generateUniqueName(String columnName) {
String newColumnName = columnName;
int loopCount = 2;
while(existingColumnNames.contains(newColumnName)){
String loopCountString = "_"+loopCount;
newColumnName = columnName.substring(0,Math.min(columnName.length(), configuration.getMaxIdentiferLength()-loopCountString.length()))+loopCountString;
loopCount++;
}
return newColumnName;
}
public boolean isAllowableColumnName(String proposedName){
// check null
if (proposedName == null){
return false;
}
// check size limits
if (proposedName.length() > configuration.getMaxIdentiferLength() || proposedName.length()==0){
return false;
}
Matcher match = configuration.getCompiledRegularExpressionMatchAllowed().matcher(proposedName);
if(!match.matches()){
return false;
}
return true;
}
private String fixColumnName(String proposedName) {
Matcher match = configuration.getCompiledRegularExpressionMatchDisallowed().matcher(proposedName);
proposedName = match.replaceAll("");
// check size limits - then truncate
if (proposedName.length() > configuration.getMaxIdentiferLength()){
proposedName=proposedName.substring(0, configuration.getMaxIdentiferLength());
}
return proposedName;
}
public ColumnNamerConfiguration getConfiguration() {
return configuration;
}
}
package org.h2.util;
import java.util.regex.Pattern;
import org.h2.engine.Mode.ModeEnum;
import static org.h2.engine.Mode.ModeEnum.*;
import org.h2.message.DbException;
public class ColumnNamerConfiguration {
private static final String DEFAULT_COMMAND = "DEFAULT";
private static final String REGULAR_EXPRESSION_MATCH_DISALLOWED = "REGULAR_EXPRESSION_MATCH_DISALLOWED = ";
private static final String REGULAR_EXPRESSION_MATCH_ALLOWED = "REGULAR_EXPRESSION_MATCH_ALLOWED = ";
private static final String DEFAULT_COLUMN_NAME_PATTERN = "DEFAULT_COLUMN_NAME_PATTERN = ";
private static final String MAX_IDENTIFIER_LENGTH = "MAX_IDENTIFIER_LENGTH = ";
private static final String EMULATE_COMMAND = "EMULATE = ";
private static final String GENERATE_UNIQUE_COLUMN_NAMES = "GENERATE_UNIQUE_COLUMN_NAMES = ";
private int maxIdentiferLength;
private String regularExpressionMatchAllowed;
private String regularExpressionMatchDisallowed;
private String defaultColumnNamePattern;
private boolean generateUniqueColumnNames;
private Pattern compiledRegularExpressionMatchAllowed;
private Pattern compiledRegularExpressionMatchDisallowed;
public ColumnNamerConfiguration(int maxIdentiferLength, String regularExpressionMatchAllowed,
String regularExpressionMatchDisallowed, String defaultColumnNamePattern, boolean generateUniqueColumnNames) {
this.maxIdentiferLength = maxIdentiferLength;
this.regularExpressionMatchAllowed = regularExpressionMatchAllowed;
this.regularExpressionMatchDisallowed = regularExpressionMatchDisallowed;
this.defaultColumnNamePattern = defaultColumnNamePattern;
this.generateUniqueColumnNames = generateUniqueColumnNames;
compiledRegularExpressionMatchAllowed = Pattern.compile(regularExpressionMatchAllowed);
compiledRegularExpressionMatchDisallowed = Pattern.compile(regularExpressionMatchDisallowed);
}
public int getMaxIdentiferLength() {
return maxIdentiferLength;
}
public void setMaxIdentiferLength(int maxIdentiferLength) {
this.maxIdentiferLength = Math.max(30,maxIdentiferLength);
if(maxIdentiferLength!=getMaxIdentiferLength()){
throw DbException.getInvalidValueException("Illegal value (<30) in SET COLUMN_NAME_RULES","MAX_IDENTIFIER_LENGTH="+maxIdentiferLength);
}
}
public String getRegularExpressionMatchAllowed() {
return regularExpressionMatchAllowed;
}
public void setRegularExpressionMatchAllowed(String regularExpressionMatchAllowed) {
this.regularExpressionMatchAllowed = regularExpressionMatchAllowed;
}
public String getRegularExpressionMatchDisallowed() {
return regularExpressionMatchDisallowed;
}
public void setRegularExpressionMatchDisallowed(String regularExpressionMatchDisallowed) {
this.regularExpressionMatchDisallowed = regularExpressionMatchDisallowed;
}
public String getDefaultColumnNamePattern() {
return defaultColumnNamePattern;
}
public void setDefaultColumnNamePattern(String defaultColumnNamePattern) {
this.defaultColumnNamePattern = defaultColumnNamePattern;
}
public Pattern getCompiledRegularExpressionMatchAllowed() {
return compiledRegularExpressionMatchAllowed;
}
public void setCompiledRegularExpressionMatchAllowed(Pattern compiledRegularExpressionMatchAllowed) {
this.compiledRegularExpressionMatchAllowed = compiledRegularExpressionMatchAllowed;
}
public Pattern getCompiledRegularExpressionMatchDisallowed() {
return compiledRegularExpressionMatchDisallowed;
}
public void setCompiledRegularExpressionMatchDisallowed(Pattern compiledRegularExpressionMatchDisallowed) {
this.compiledRegularExpressionMatchDisallowed = compiledRegularExpressionMatchDisallowed;
}
public void configure(String stringValue) {
try{
if(stringValue.equalsIgnoreCase(DEFAULT_COMMAND)){
configure(REGULAR);
} else if(stringValue.startsWith(EMULATE_COMMAND)){
configure(ModeEnum.valueOf(unquoteString(stringValue.substring(EMULATE_COMMAND.length()))));
} else if(stringValue.startsWith(MAX_IDENTIFIER_LENGTH)){
int maxLength = Integer.parseInt(stringValue.substring(MAX_IDENTIFIER_LENGTH.length()));
setMaxIdentiferLength(maxLength);
} else if(stringValue.startsWith(GENERATE_UNIQUE_COLUMN_NAMES)){
setGenerateUniqueColumnNames(Integer.parseInt(stringValue.substring(GENERATE_UNIQUE_COLUMN_NAMES.length()))==1);
} else if(stringValue.startsWith(DEFAULT_COLUMN_NAME_PATTERN)){
setDefaultColumnNamePattern(unquoteString(stringValue.substring(DEFAULT_COLUMN_NAME_PATTERN.length())));
} else if(stringValue.startsWith(REGULAR_EXPRESSION_MATCH_ALLOWED)){
setRegularExpressionMatchAllowed(unquoteString(stringValue.substring(REGULAR_EXPRESSION_MATCH_ALLOWED.length())));
} else if(stringValue.startsWith(REGULAR_EXPRESSION_MATCH_DISALLOWED)){
setRegularExpressionMatchDisallowed(unquoteString(stringValue.substring(REGULAR_EXPRESSION_MATCH_DISALLOWED.length())));
}
else
{
throw DbException.getInvalidValueException("SET COLUMN_NAME_RULES: unknown id:"+stringValue,
stringValue);
}
recompilePatterns();
}
//Including NumberFormatException|PatternSyntaxException
catch(RuntimeException e){
throw DbException.getInvalidValueException("SET COLUMN_NAME_RULES:"+e.getMessage(),
stringValue);
}
}
private void recompilePatterns() {
try{
// recompile RE patterns
setCompiledRegularExpressionMatchAllowed(Pattern.compile(getRegularExpressionMatchAllowed()));
setCompiledRegularExpressionMatchDisallowed(Pattern.compile(getRegularExpressionMatchDisallowed()));
}
catch(Exception e){
configure(REGULAR);
throw e;
}
}
public static ColumnNamerConfiguration getDefault(){
return new ColumnNamerConfiguration(Integer.MAX_VALUE, "(?m)(?s).+", "(?m)(?s)[\\x00]", "_UNNAMED_$$",false);
}
private static String unquoteString(String s){
if(s.startsWith("'") && s.endsWith("'")){
s = s.substring(1, s.length()-1);
return s;
}
return s;
}
public boolean isGenerateUniqueColumnNames() {
return generateUniqueColumnNames;
}
public void setGenerateUniqueColumnNames(boolean generateUniqueColumnNames) {
this.generateUniqueColumnNames = generateUniqueColumnNames;
}
public void configure(ModeEnum modeEnum) {
switch(modeEnum){
case Oracle:
// Nonquoted identifiers can contain only alphanumeric characters
// from your database character set and the underscore (_), dollar sign ($), and pound sign (#).
setMaxIdentiferLength(128);
setRegularExpressionMatchAllowed("(?m)(?s)\"?[A-Za-z0-9_\\$#]+\"?");
setRegularExpressionMatchDisallowed("(?m)(?s)[^A-Za-z0-9_\"\\$#]");
setDefaultColumnNamePattern("_UNNAMED_$$");
setGenerateUniqueColumnNames(false);
break;
case MSSQLServer:
// https://docs.microsoft.com/en-us/sql/sql-server/maximum-capacity-specifications-for-sql-server
setMaxIdentiferLength(128);
setRegularExpressionMatchAllowed("(?m)(?s)[A-Za-z0-9_\\[\\]]+");// allows [] around names
setRegularExpressionMatchDisallowed("(?m)(?s)[^A-Za-z0-9_\\[\\]]");
setDefaultColumnNamePattern("_UNNAMED_$$");
setGenerateUniqueColumnNames(false);
break;
case PostgreSQL:
setMaxIdentiferLength(63);// this default can be changed to 128 by postgres config
setRegularExpressionMatchAllowed("(?m)(?s)[A-Za-z0-9_\\$]+");
setRegularExpressionMatchDisallowed("(?m)(?s)[^A-Za-z0-9_\\$]");
setDefaultColumnNamePattern("_UNNAMED_$$");
setGenerateUniqueColumnNames(false);
break;
case MySQL:
//https://dev.mysql.com/doc/refman/5.7/en/identifiers.html
setMaxIdentiferLength(64);
setRegularExpressionMatchAllowed("(?m)(?s)`?[A-Za-z0-9_`\\$]+`?");
setRegularExpressionMatchDisallowed("(?m)(?s)[^A-Za-z0-9_`\\$]");
setDefaultColumnNamePattern("_UNNAMED_$$");
setGenerateUniqueColumnNames(false);
break;
default:
case REGULAR:
case DB2:
case Derby:
case HSQLDB:
case Ignite:
setMaxIdentiferLength(Integer.MAX_VALUE);
setRegularExpressionMatchAllowed("(?m)(?s).+");
setRegularExpressionMatchDisallowed("(?m)(?s)[\\x00]");
setDefaultColumnNamePattern("_UNNAMED_$$");
setGenerateUniqueColumnNames(false);
break;
}
recompilePatterns();
}
}
\ No newline at end of file
...@@ -230,6 +230,7 @@ import org.h2.test.utils.SelfDestructor; ...@@ -230,6 +230,7 @@ import org.h2.test.utils.SelfDestructor;
import org.h2.tools.DeleteDbFiles; import org.h2.tools.DeleteDbFiles;
import org.h2.tools.Server; import org.h2.tools.Server;
import org.h2.util.AbbaLockingDetector; import org.h2.util.AbbaLockingDetector;
import org.h2.util.TestColumnNamer;
import org.h2.util.New; import org.h2.util.New;
import org.h2.util.Profiler; import org.h2.util.Profiler;
import org.h2.util.StringUtils; import org.h2.util.StringUtils;
...@@ -782,6 +783,8 @@ kill -9 `jps -l | grep "org.h2.test." | cut -d " " -f 1` ...@@ -782,6 +783,8 @@ kill -9 `jps -l | grep "org.h2.test." | cut -d " " -f 1`
addTest(new TestViewDropView()); addTest(new TestViewDropView());
addTest(new TestReplace()); addTest(new TestReplace());
addTest(new TestSynonymForTable()); addTest(new TestSynonymForTable());
addTest(new TestColumnNamer());
// jaqu // jaqu
addTest(new AliasMapTest()); addTest(new AliasMapTest());
......
...@@ -9,7 +9,6 @@ import java.sql.Connection; ...@@ -9,7 +9,6 @@ import java.sql.Connection;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.Statement; import java.sql.Statement;
import org.h2.jdbc.JdbcSQLException; import org.h2.jdbc.JdbcSQLException;
import org.h2.test.TestBase; import org.h2.test.TestBase;
...@@ -42,6 +41,7 @@ public class TestGeneralCommonTableQueries extends TestBase { ...@@ -42,6 +41,7 @@ public class TestGeneralCommonTableQueries extends TestBase {
testMerge(); testMerge();
testCreateTable(); testCreateTable();
testNestedSQL(); testNestedSQL();
testRecursiveTable();
} }
private void testSimpleSelect() throws Exception { private void testSimpleSelect() throws Exception {
...@@ -469,4 +469,80 @@ public class TestGeneralCommonTableQueries extends TestBase { ...@@ -469,4 +469,80 @@ public class TestGeneralCommonTableQueries extends TestBase {
conn.close(); conn.close();
deleteDb("commonTableExpressionQueries"); deleteDb("commonTableExpressionQueries");
} }
private void testRecursiveTable() throws Exception {
String[] expectedRowData =new String[]{"|meat|null","|fruit|3","|veg|2"};
String[] expectedColumnNames =new String[]{"VAL",
"SUM(SELECT\n X\nFROM PUBLIC.\"\" BB\n /* SELECT\n SUM(1) AS X,\n A\n FROM PUBLIC.B\n /++ PUBLIC.B.tableScan ++/\n /++ WHERE A IS ?1\n ++/\n /++ scanCount: 4 ++/\n INNER JOIN PUBLIC.C\n /++ PUBLIC.C.tableScan ++/\n ON 1=1\n WHERE (A IS ?1)\n AND (B.VAL = C.B)\n GROUP BY A: A IS A.VAL\n */\n /* scanCount: 1 */\nWHERE BB.A IS A.VAL)"};
deleteDb("commonTableExpressionQueries");
Connection conn = getConnection("commonTableExpressionQueries");
PreparedStatement prep;
ResultSet rs;
String SETUP_SQL =
"DROP TABLE IF EXISTS A; "
+"DROP TABLE IF EXISTS B; "
+"DROP TABLE IF EXISTS C; "
+"CREATE TABLE A(VAL VARCHAR(255)); "
+"CREATE TABLE B(A VARCHAR(255), VAL VARCHAR(255)); "
+"CREATE TABLE C(B VARCHAR(255), VAL VARCHAR(255)); "
+" "
+"INSERT INTO A VALUES('fruit'); "
+"INSERT INTO B VALUES('fruit','apple'); "
+"INSERT INTO B VALUES('fruit','banana'); "
+"INSERT INTO C VALUES('apple', 'golden delicious');"
+"INSERT INTO C VALUES('apple', 'granny smith'); "
+"INSERT INTO C VALUES('apple', 'pippin'); "
+"INSERT INTO A VALUES('veg'); "
+"INSERT INTO B VALUES('veg', 'carrot'); "
+"INSERT INTO C VALUES('carrot', 'nantes'); "
+"INSERT INTO C VALUES('carrot', 'imperator'); "
+"INSERT INTO C VALUES(null, 'banapple'); "
+"INSERT INTO A VALUES('meat'); "
;
String WITH_QUERY =
"WITH BB as (SELECT \n"
+"sum(1) as X, \n"
+"a \n"
+"FROM B \n"
+"JOIN C ON B.val=C.b \n"
+"GROUP BY a) \n"
+"SELECT \n"
+"A.val, \n"
+"sum(SELECT X FROM BB WHERE BB.a IS A.val)\n"//AS SUM_X
+"FROM A \n"
+"GROUP BY A.val";
for(int queryRunTries=1;queryRunTries<4;queryRunTries++){
Statement stat = conn.createStatement();
stat.execute(SETUP_SQL);
stat.close();
prep = conn.prepareStatement(WITH_QUERY);
rs = prep.executeQuery();
for(int columnIndex = 1; columnIndex <= rs.getMetaData().getColumnCount(); columnIndex++){
// previously the column label was null or had \n or \r in the string
assertTrue(rs.getMetaData().getColumnLabel(columnIndex)!=null);
assertEquals(expectedColumnNames[columnIndex-1],rs.getMetaData().getColumnLabel(columnIndex));
}
int rowNdx=0;
while (rs.next()) {
StringBuffer buf = new StringBuffer();
for(int columnIndex = 1; columnIndex <= rs.getMetaData().getColumnCount(); columnIndex++){
buf.append("|"+rs.getString(columnIndex));
}
assertEquals(expectedRowData[rowNdx], buf.toString());
rowNdx++;
}
assertEquals(3,rowNdx);
rs.close();
prep.close();
}
conn.close();
deleteDb("commonTableExpressionQueries");
}
} }
\ No newline at end of file
...@@ -11,6 +11,8 @@ import java.io.InputStream; ...@@ -11,6 +11,8 @@ import java.io.InputStream;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.io.LineNumberReader; import java.io.LineNumberReader;
import java.io.PrintStream; import java.io.PrintStream;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.sql.Connection; import java.sql.Connection;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
import java.sql.ResultSet; import java.sql.ResultSet;
...@@ -72,7 +74,7 @@ public class TestScript extends TestBase { ...@@ -72,7 +74,7 @@ public class TestScript extends TestBase {
} }
@Override @Override
public void test() throws Exception { public void test() throws Exception {
if (config.networked && config.big) { if (config.networked && config.big) {
return; return;
} }
......
...@@ -2,3 +2,81 @@ ...@@ -2,3 +2,81 @@
-- and the EPL 1.0 (http://h2database.com/html/license.html). -- and the EPL 1.0 (http://h2database.com/html/license.html).
-- Initial Developer: H2 Group -- Initial Developer: H2 Group
-- --
-- Try a custom column naming rules setup
SET COLUMN_NAME_RULES=MAX_IDENTIFIER_LENGTH = 30;
> ok
SET COLUMN_NAME_RULES=REGULAR_EXPRESSION_MATCH_ALLOWED = '[A-Za-z0-9_]+';
> ok
SET COLUMN_NAME_RULES=REGULAR_EXPRESSION_MATCH_DISALLOWED = '[^A-Za-z0-9_]+';
> ok
SET COLUMN_NAME_RULES=DEFAULT_COLUMN_NAME_PATTERN = 'noName$$';
> ok
SET COLUMN_NAME_RULES=GENERATE_UNIQUE_COLUMN_NAMES = 1;
> ok
SELECT 1 AS VERY_VERY_VERY_LONG_ID_VERY_VERY_VERY_LONG_ID, SUM(X)+1 AS _123456789012345, SUM(X)+1 , SUM(X)+1
+47, 'x' , '!!!' , '!!!!' FROM SYSTEM_RANGE(1,2);
> VERY_VERY_VERY_LONG_ID_VERY_VE _123456789012345 SUMX1 SUMX147 x noName6 noName7
> ------------------------------ ---------------- ----- ------- - ------- -------
> 1 4 4 51 x !!! !!!!
SET COLUMN_NAME_RULES=EMULATE='Oracle';
> ok
SELECT 1 AS VERY_VERY_VERY_LONG_ID, SUM(X)+1 AS _123456789012345, SUM(X)+1 , SUM(X)+1
+47, 'x' , '!!!' , '!!!!' FROM SYSTEM_RANGE(1,2);
> VERY_VERY_VERY_LONG_ID _123456789012345 SUMX1 SUMX147 x _UNNAMED_6 _UNNAMED_7
> ---------------------- ---------------- ----- ------- - ---------- ----------
> 1 4 4 51 x !!! !!!!
SET COLUMN_NAME_RULES=EMULATE='Oracle';
> ok
SELECT 1 AS VERY_VERY_VERY_LONG_ID, SUM(X)+1 AS _123456789012345, SUM(X)+1 , SUM(X)+1
+47, 'x' , '!!!' , '!!!!', 'Very Long' AS _23456789012345678901234567890XXX FROM SYSTEM_RANGE(1,2);
> VERY_VERY_VERY_LONG_ID _123456789012345 SUMX1 SUMX147 x _UNNAMED_6 _UNNAMED_7 _23456789012345678901234567890XXX
> ---------------------- ---------------- ----- ------- - ---------- ---------- ---------------------------------
> 1 4 4 51 x !!! !!!! Very Long
SET COLUMN_NAME_RULES=EMULATE='PostgreSQL';
> ok
SELECT 1 AS VERY_VERY_VERY_LONG_ID, SUM(X)+1 AS _123456789012345, SUM(X)+1 , SUM(X)+1
+47, 'x' , '!!!' , '!!!!', 999 AS "QuotedColumnId" FROM SYSTEM_RANGE(1,2);
> VERY_VERY_VERY_LONG_ID _123456789012345 SUMX1 SUMX147 x _UNNAMED_6 _UNNAMED_7 QuotedColumnId
> ---------------------- ---------------- ----- ------- - ---------- ---------- --------------
> 1 4 4 51 x !!! !!!! 999
SET COLUMN_NAME_RULES=DEFAULT;
> ok
-- Test all MODES of database:
-- DB2, Derby, MSSQLServer, HSQLDB, MySQL, Oracle, PostgreSQL, Ignite
SET COLUMN_NAME_RULES=EMULATE='DB2';
> ok
SET COLUMN_NAME_RULES=EMULATE='Derby';
> ok
SET COLUMN_NAME_RULES=EMULATE='MSSQLServer';
> ok
SET COLUMN_NAME_RULES=EMULATE='MySQL';
> ok
SET COLUMN_NAME_RULES=EMULATE='Oracle';
> ok
SET COLUMN_NAME_RULES=EMULATE='PostgreSQL';
> ok
SET COLUMN_NAME_RULES=EMULATE='Ignite';
> ok
SET COLUMN_NAME_RULES=EMULATE='REGULAR';
> ok
package org.h2.util;
import org.h2.expression.Expression;
import org.h2.expression.ValueExpression;
import org.h2.test.TestBase;
public class TestColumnNamer extends TestBase {
private String[] ids = new String[]{
"ABC"
,"123"
,"a\n2"
,"a$c%d#e@f!."
,null
,"VERYVERYVERYVERYVERYVERYLONGVERYVERYVERYVERYVERYVERYLONGVERYVERYVERYVERYVERYVERYLONG"
,"'!!!'"
,"'!!!!'"
,"3.1415"
,"\r"
,"col1"
,"col1"
,"col1"
,"col2col2col2col2col2col2col2col2col2col2col2col2col2col2col2col2col2col2col2col2col2col2col2col2"
,"col2col2col2col2col2col2col2col2col2col2col2col2col2col2col2col2col2col2col2col2col2col2col2col2"
};
private String[] expectedColumnName= {"ABC"
,"123"
,"a2"
,"acdef"
,"colName6"
,"VERYVERYVERYVERYVERYVERYLONGVE"
,"colName8"
,"colName9"
,"31415"
,"colName11"
,"col1"
,"col1_2"
,"col1_3"
,"col2col2col2col2col2col2col2co"
,"col2col2col2col2col2col2col2_2"};
public static void main(String[] args){
new TestColumnNamer().test();
}
public void test() {
ColumnNamer columnNamer = new ColumnNamer(null);
columnNamer.getConfiguration().configure("MAX_IDENTIFIER_LENGTH = 30");
columnNamer.getConfiguration().configure("REGULAR_EXPRESSION_MATCH_ALLOWED = '[A-Za-z0-9_]+'");
columnNamer.getConfiguration().configure("REGULAR_EXPRESSION_MATCH_DISALLOWED = '[^A-Za-z0-9_]+'");
columnNamer.getConfiguration().configure("DEFAULT_COLUMN_NAME_PATTERN = 'colName$$'");
columnNamer.getConfiguration().configure("GENERATE_UNIQUE_COLUMN_NAMES = 1");
int index =0;
for(String id : ids){
Expression columnExp = ValueExpression.getDefault();
String newColumnName = columnNamer.getColumnName(columnExp , index+1, id);
assertTrue(newColumnName!=null);
assertTrue(newColumnName.length()<=30);
assertTrue(newColumnName.length()>=1);
assertEquals(newColumnName,expectedColumnName[index]);
index++;
}
}
}
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论