[jOOQ/jOOQ#18787] XMLDatabase has O(N^2) complexity in column /

attribute / parameter lookups
This commit is contained in:
Lukas Eder 2025-07-16 14:51:30 +02:00
parent a21b1aaf63
commit 54cfb82bee
3 changed files with 98 additions and 77 deletions

View File

@ -121,10 +121,12 @@ import org.jooq.tools.jdbc.JDBCUtils;
import org.jooq.util.jaxb.tools.MiniJAXB;
import org.jooq.util.xml.XmlUtils;
import org.jooq.util.xml.jaxb.CheckConstraint;
import org.jooq.util.xml.jaxb.Column;
import org.jooq.util.xml.jaxb.Index;
import org.jooq.util.xml.jaxb.IndexColumnUsage;
import org.jooq.util.xml.jaxb.InformationSchema;
import org.jooq.util.xml.jaxb.KeyColumnUsage;
import org.jooq.util.xml.jaxb.Parameter;
import org.jooq.util.xml.jaxb.ReferentialConstraint;
import org.jooq.util.xml.jaxb.Routine;
import org.jooq.util.xml.jaxb.Schema;
@ -147,6 +149,8 @@ public class XMLDatabase extends AbstractDatabase {
private static final JooqLogger log = JooqLogger.getLogger(XMLDatabase.class);
InformationSchema info;
Map<Name, List<Column>> columnsByTableName;
Map<Name, List<Parameter>> parametersByRoutineName;
private InformationSchema info() {
if (info == null) {
@ -747,4 +751,34 @@ public class XMLDatabase extends AbstractDatabase {
static long unbox(Long l) {
return l == null ? 0L : l.longValue();
}
List<Column> getColumnsByTableName(Name tableName) {
if (columnsByTableName == null) {
columnsByTableName = new LinkedHashMap<>();
for (Column column : info().getColumns()) {
columnsByTableName.computeIfAbsent(
name(column.getTableCatalog(), column.getTableSchema(), column.getTableName()),
n -> new ArrayList<>()
).add(column);
}
}
return columnsByTableName.get(tableName);
}
List<Parameter> getParametersByRoutineName(Name specificName) {
if (parametersByRoutineName == null) {
parametersByRoutineName = new LinkedHashMap<>();
for (Parameter parameter : info().getParameters()) {
parametersByRoutineName.computeIfAbsent(
name(parameter.getSpecificCatalog(), parameter.getSpecificSchema(), parameter.getSpecificPackage(), parameter.getSpecificName()),
n -> new ArrayList<>()
).add(parameter);
}
}
return parametersByRoutineName.get(specificName);
}
}

View File

@ -50,6 +50,7 @@ import org.jooq.meta.PackageDefinition;
import org.jooq.meta.ParameterDefinition;
import org.jooq.meta.SchemaDefinition;
import org.jooq.tools.StringUtils;
import org.jooq.util.xml.jaxb.Column;
import org.jooq.util.xml.jaxb.InformationSchema;
import org.jooq.util.xml.jaxb.Parameter;
import org.jooq.util.xml.jaxb.Routine;
@ -130,47 +131,38 @@ public class XMLRoutineDefinition extends AbstractRoutineDefinition {
@Override
protected void init0() {
for (Parameter parameter : info.getParameters()) {
Name parameterRoutineName = name(
parameter.getSpecificCatalog(),
parameter.getSpecificSchema(),
parameter.getSpecificPackage(),
parameter.getSpecificName()
for (Parameter parameter : ((XMLDatabase) getDatabase()).getParametersByRoutineName(specificName)) {
DataTypeDefinition type = new DefaultDataTypeDefinition(
getDatabase(),
getSchema(),
parameter.getDataType(),
parameter.getCharacterMaximumLength(),
parameter.getNumericPrecision(),
parameter.getNumericScale(),
null,
parameter.getParameterDefault()
);
if (specificName.equals(parameterRoutineName)) {
DataTypeDefinition type = new DefaultDataTypeDefinition(
getDatabase(),
getSchema(),
parameter.getDataType(),
parameter.getCharacterMaximumLength(),
parameter.getNumericPrecision(),
parameter.getNumericScale(),
null,
parameter.getParameterDefault()
);
ParameterDefinition p = new DefaultParameterDefinition(
this,
parameter.getParameterName(),
parameter.getOrdinalPosition(),
type,
!StringUtils.isBlank(parameter.getParameterDefault()),
StringUtils.isBlank(parameter.getParameterName()),
parameter.getComment()
);
ParameterDefinition p = new DefaultParameterDefinition(
this,
parameter.getParameterName(),
parameter.getOrdinalPosition(),
type,
!StringUtils.isBlank(parameter.getParameterDefault()),
StringUtils.isBlank(parameter.getParameterName()),
parameter.getComment()
);
switch (parameter.getParameterMode()) {
case IN:
addParameter(InOutDefinition.IN, p);
break;
case INOUT:
addParameter(InOutDefinition.INOUT, p);
break;
case OUT:
addParameter(InOutDefinition.OUT, p);
break;
}
switch (parameter.getParameterMode()) {
case IN:
addParameter(InOutDefinition.IN, p);
break;
case INOUT:
addParameter(InOutDefinition.INOUT, p);
break;
case OUT:
addParameter(InOutDefinition.OUT, p);
break;
}
}
}

View File

@ -38,10 +38,10 @@
package org.jooq.meta.xml;
import static java.lang.Boolean.TRUE;
import static org.jooq.impl.DSL.name;
import static org.jooq.impl.QOM.GenerationOption.STORED;
import static org.jooq.impl.QOM.GenerationOption.VIRTUAL;
import static org.jooq.meta.xml.XMLDatabase.unbox;
import static org.jooq.tools.StringUtils.defaultIfNull;
import java.sql.SQLException;
import java.util.ArrayList;
@ -50,11 +50,9 @@ import java.util.List;
import org.jooq.TableOptions.TableType;
import org.jooq.meta.AbstractTableDefinition;
import org.jooq.meta.ColumnDefinition;
import org.jooq.meta.DataTypeDefinition;
import org.jooq.meta.DefaultColumnDefinition;
import org.jooq.meta.DefaultDataTypeDefinition;
import org.jooq.meta.SchemaDefinition;
import org.jooq.tools.StringUtils;
import org.jooq.util.xml.jaxb.Column;
import org.jooq.util.xml.jaxb.InformationSchema;
import org.jooq.util.xml.jaxb.Table;
@ -86,44 +84,41 @@ public class XMLTableDefinition extends AbstractTableDefinition {
protected List<ColumnDefinition> getElements0() throws SQLException {
List<ColumnDefinition> result = new ArrayList<>();
for (Column column : info.getColumns()) {
if (StringUtils.equals(defaultIfNull(table.getTableCatalog(), ""), defaultIfNull(column.getTableCatalog(), "")) &&
StringUtils.equals(defaultIfNull(table.getTableSchema(), ""), defaultIfNull(column.getTableSchema(), "")) &&
StringUtils.equals(defaultIfNull(table.getTableName(), ""), defaultIfNull(column.getTableName(), ""))) {
for (Column column : ((XMLDatabase) getDatabase()).getColumnsByTableName(
name(table.getTableCatalog(), table.getTableSchema(), table.getTableName())
)) {
SchemaDefinition schema = getDatabase().getSchema(column.getTableSchema());
SchemaDefinition schema = getDatabase().getSchema(column.getTableSchema());
DefaultDataTypeDefinition type = new DefaultDataTypeDefinition(
getDatabase(),
schema,
column.getDataType(),
unbox(column.getCharacterMaximumLength()),
unbox(column.getNumericPrecision()),
unbox(column.getNumericScale()),
column.isIsNullable(),
column.getColumnDefault()
)
.generatedAlwaysAs(TRUE.equals(column.isIsGenerated()) ? column.getGenerationExpression() : null)
.generationOption(TRUE.equals(column.isIsGenerated())
? "STORED".equalsIgnoreCase(column.getGenerationOption())
? STORED
: "VIRTUAL".equalsIgnoreCase(column.getGenerationOption())
? VIRTUAL
: null
: null)
.hidden(TRUE.equals(column.isHidden()));
DefaultDataTypeDefinition type = new DefaultDataTypeDefinition(
getDatabase(),
schema,
column.getDataType(),
unbox(column.getCharacterMaximumLength()),
unbox(column.getNumericPrecision()),
unbox(column.getNumericScale()),
column.isIsNullable(),
column.getColumnDefault()
)
.generatedAlwaysAs(TRUE.equals(column.isIsGenerated()) ? column.getGenerationExpression() : null)
.generationOption(TRUE.equals(column.isIsGenerated())
? "STORED".equalsIgnoreCase(column.getGenerationOption())
? STORED
: "VIRTUAL".equalsIgnoreCase(column.getGenerationOption())
? VIRTUAL
: null
: null)
.hidden(TRUE.equals(column.isHidden()));
result.add(new DefaultColumnDefinition(
this,
column.getColumnName(),
unbox(column.getOrdinalPosition()),
type,
column.getIdentityGeneration() != null,
TRUE.equals(column.isHidden()),
TRUE.equals(column.isReadonly()),
column.getComment()
));
}
result.add(new DefaultColumnDefinition(
this,
column.getColumnName(),
unbox(column.getOrdinalPosition()),
type,
column.getIdentityGeneration() != null,
TRUE.equals(column.isHidden()),
TRUE.equals(column.isReadonly()),
column.getComment()
));
}
return result;