blob: 89a546c55bf4d108c1b8054837e85f6f4ac576a8 [file] [log] [blame]
/* Copyright (c) 2001-2010, The HSQL Development Group
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of the HSQL Development Group nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL HSQL DEVELOPMENT GROUP, HSQLDB.ORG,
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.hsqldb;
import org.hsqldb.HsqlNameManager.HsqlName;
import org.hsqldb.error.Error;
import org.hsqldb.error.ErrorCode;
import org.hsqldb.lib.ArrayUtil;
import org.hsqldb.lib.HsqlArrayList;
import org.hsqldb.lib.OrderedHashSet;
import org.hsqldb.rights.Grantee;
import org.hsqldb.types.NumberType;
import org.hsqldb.types.Type;
/**
* Implementation of SQL procedure and functions
*
* @author Fred Toussi (fredt@users dot sourceforge.net)
*
* @version 1.9.0
* @since 1.9.0
*/
public class RoutineSchema implements SchemaObject {
Routine[] routines = Routine.emptyArray;
int routineType;
private HsqlName name;
public RoutineSchema(int type, HsqlName name) {
routineType = type;
this.name = name;
}
public int getType() {
return routineType;
}
public HsqlName getCatalogName() {
return name.schema.schema;
}
public HsqlName getSchemaName() {
return name.schema;
}
public HsqlName getName() {
return name;
}
public Grantee getOwner() {
return name.schema.owner;
}
public OrderedHashSet getReferences() {
OrderedHashSet set = new OrderedHashSet();
for (int i = 0; i < routines.length; i++) {
set.addAll(routines[i].getReferences());
}
return set;
}
public OrderedHashSet getComponents() {
OrderedHashSet set = new OrderedHashSet();
set.addAll(routines);
return set;
}
public void compile(Session session, SchemaObject parentObject) {}
public String getSQL() {
return null;
}
public long getChangeTimestamp() {
return 0;
}
public String[] getSQLArray() {
HsqlArrayList list = new HsqlArrayList();
for (int i = 0; i < routines.length; i++) {
list.add(routines[i].getSQL());
}
String[] array = new String[list.size()];
list.toArray(array);
return array;
}
public void addSpecificRoutine(Database database, Routine routine) {
int signature = routine.getParameterSignature();
Type[] types = routine.getParameterTypes();
for (int i = 0; i < this.routines.length; i++) {
if (routines[i].parameterTypes.length == types.length) {
if (routineType == SchemaObject.PROCEDURE) {
throw Error.error(ErrorCode.X_42605);
}
if (routines[i].isAggregate() != routine.isAggregate()) {
throw Error.error(ErrorCode.X_42605);
}
boolean match = true;
for (int j = 0; j < types.length; j++) {
if (!routines[i].parameterTypes[j].equals(types[j])) {
match = false;
break;
}
}
if (match) {
throw Error.error(ErrorCode.X_42605);
}
}
}
if (routine.getSpecificName() == null) {
HsqlName specificName =
database.nameManager.newSpecificRoutineName(name);
routine.setSpecificName(specificName);
} else {
routine.getSpecificName().parent = name;
routine.getSpecificName().schema = name.schema;
}
routine.setName(name);
routine.routineSchema = this;
routines = (Routine[]) ArrayUtil.resizeArray(routines,
routines.length + 1);
routines[routines.length - 1] = routine;
}
public void removeSpecificRoutine(Routine routine) {
for (int i = 0; i < this.routines.length; i++) {
if (routines[i] == routine) {
routines = (Routine[]) ArrayUtil.toAdjustedArray(routines,
null, i, -1);
break;
}
}
}
public Routine[] getSpecificRoutines() {
return routines;
}
public Routine getSpecificRoutine(Type[] types) {
int matchIndex = -1;
outerLoop:
for (int i = 0; i < this.routines.length; i++) {
int matchCount = 0;
if (routines[i].isAggregate()) {
if (types.length == 1) {
if (types[0] == null) {
return routines[i];
}
int typeDifference = types[0].precedenceDegree(
routines[i].parameterTypes[0]);
if (typeDifference < -NumberType.DOUBLE_WIDTH) {
if (matchIndex == -1) {
continue;
}
int oldDiff = types[0].precedenceDegree(
routines[matchIndex].parameterTypes[0]);
int newDiff = types[0].precedenceDegree(
routines[i].parameterTypes[0]);
if (oldDiff == newDiff) {
continue outerLoop;
}
if (newDiff < oldDiff) {
matchIndex = i;
}
continue outerLoop;
} else if (typeDifference == 0) {
return routines[i];
} else {
matchIndex = i;
continue outerLoop;
}
}
// treat routine as non-aggregate
}
if (routines[i].parameterTypes.length != types.length) {
continue;
}
if (types.length == 0) {
return this.routines[i];
}
for (int j = 0; j < types.length; j++) {
int typeDifference;
// parameters
if (types[j] == null) {
continue;
}
typeDifference =
types[j].precedenceDegree(routines[i].parameterTypes[j]);
if (typeDifference < -NumberType.DOUBLE_WIDTH) {
// accept numeric type narrowing
continue outerLoop;
} else if (typeDifference == 0) {
if (matchCount == j) {
matchCount = j + 1;
}
}
}
if (matchCount == types.length) {
return routines[i];
}
if (matchIndex == -1) {
matchIndex = i;
continue;
}
for (int j = 0; j < types.length; j++) {
if (types[j] == null) {
continue;
}
int oldDiff = types[j].precedenceDegree(
routines[matchIndex].parameterTypes[j]);
int newDiff =
types[j].precedenceDegree(routines[i].parameterTypes[j]);
if (oldDiff == newDiff) {
continue;
}
if (newDiff < oldDiff) {
matchIndex = i;
}
continue outerLoop;
}
}
if (matchIndex < 0) {
StringBuffer sb = new StringBuffer();
sb.append(name.getSchemaQualifiedStatementName());
sb.append(Tokens.T_OPENBRACKET);
for (int i = 0; i < types.length; i++) {
if (i != 0) {
sb.append(Tokens.T_COMMA);
}
sb.append(types[i].getNameString());
}
sb.append(Tokens.T_CLOSEBRACKET);
throw Error.error(ErrorCode.X_42609, sb.toString());
}
return routines[matchIndex];
}
public Routine getSpecificRoutine(int paramCount) {
for (int i = 0; i < this.routines.length; i++) {
if (routines[i].parameterTypes.length == paramCount) {
return routines[i];
}
}
throw Error.error(ErrorCode.X_42501);
}
public boolean isAggregate() {
return routines[0].isAggregate;
}
}