Schema.kt 13.14 KiB
package unibz.cs.semint.kprime.domain.ddl
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement
@JacksonXmlRootElement(localName = "schema")
class Schema () {
@JacksonXmlProperty(isAttribute = true)
var name: String =""
@JacksonXmlProperty(isAttribute = true)
var id: String=""
var tables: ArrayList<Table>? = ArrayList<Table>()
var constraints: MutableList<Constraint>? = ArrayList<Constraint>()
fun table(name: String): Table? {
if (tables().isEmpty()) return null
return tables().filter { t -> t.name==name }.firstOrNull()
}
fun constraints(): MutableList<Constraint> {
if (constraints!=null) return constraints as MutableList<Constraint>
return ArrayList()
}
fun tables():ArrayList<Table> {
if (tables!=null) return tables as ArrayList<Table>
return ArrayList()
}
fun constraint(name: String): Constraint? {
if (constraints().isEmpty()) return null
return constraints().filter { c -> c.name==name}.firstOrNull()
}
fun key(tableName: String): Set<Column> {
var resultCols = mutableSetOf<Column>()
val first = constraints().filter { c ->
c.type == Constraint.TYPE.PRIMARY_KEY.name &&
c.name == "primaryKey.${tableName}"
}.toList()
if (first.isEmpty()) return mutableSetOf()
return first[0].source.columns.toSet()
}
fun functionalLHS(tableName: String): Set<Column> {
var resultCols = mutableSetOf<Column>()
val first = constraints().filter { c ->
c.type == Constraint.TYPE.FUNCTIONAL.name &&
c.name == "functional.${tableName}"
}.toList()
if (first.isEmpty()) return mutableSetOf()
return first[0].source.columns.toSet()
}
fun functionals(): Set<Constraint> {
var resultCols = mutableSetOf<Column>()
return constraints().filter { c ->
c.type == Constraint.TYPE.FUNCTIONAL.name }.toSet()
}
fun functionalRHS(tableName: String): Set<Column> {
var resultCols = mutableSetOf<Column>()
val first = constraints().filter { c ->
c.type == Constraint.TYPE.FUNCTIONAL.name &&
c.name == "functional.${tableName}"
}.toList()
if (first.isEmpty()) return mutableSetOf()
return first[0].target.columns.toSet()
}
fun key(tableName:String,k:Set<Column>) {
val primaryConstraint = Constraint()
primaryConstraint.name="primaryKey.$tableName"
primaryConstraint.source.table="$tableName"
primaryConstraint.source.columns.addAll(k)
primaryConstraint.target.columns.addAll(k)
primaryConstraint.type= Constraint.TYPE.PRIMARY_KEY.name
constraints().add(primaryConstraint)
}
fun functional(tableName:String, lhs:Set<Column>, rhs:Set<Column>){
val functionalConstraint = Constraint()
functionalConstraint.name="functional.$tableName"
functionalConstraint.source.table="$tableName"
functionalConstraint.source.columns.addAll(lhs)
functionalConstraint.target.table="$tableName"
functionalConstraint.target.columns.addAll(rhs)
functionalConstraint.type= Constraint.TYPE.FUNCTIONAL.name
constraints().add(functionalConstraint)
}
fun addFunctionals(tableName:String, setExpression: String): Schema {
val constraintsToAdd = Constraint.set(setExpression)
for (constraint in constraintsToAdd) {
constraint.name=tableName+".functional"
constraint.type=Constraint.TYPE.FUNCTIONAL.name
constraint.source.table=tableName
constraint.target.table=tableName
}
constraints().addAll(constraintsToAdd)
return this
}
companion object {
private fun <T> reducedPowerSet(originalSet: Set<T>): Set<Set<T>> {
var result = powerSet(originalSet)
result = result.minus(HashSet<T>()) as Set<Set<T>>
return result
}
fun <T> powerSet(originalSet: Set<T>): Set<Set<T>> {
val sets = HashSet<Set<T>>()
if (originalSet.isEmpty()) {
sets.add(HashSet<T>())
return sets
}
val list = ArrayList<T>(originalSet)
val head = list.get(0)
val rest = HashSet<T>(list.subList(1,list.size))
for (set in powerSet(rest)) {
val newSet = HashSet<T>()
newSet.add(head)
newSet.addAll(set)
sets.add(newSet)
sets.add(set)
}
return sets
}
fun superkeys(attrs: Set<Column>, fds:Set<Constraint>): Set<Set<Column>> {
val keys = HashSet<Set<Column>>()
val powerset = reducedPowerSet(attrs)
for (sa in powerset) {
if (closure(sa, fds).equals(attrs)) {
keys.add(sa)
}
}
return keys
}
fun closure(attrs: Set<Column>, fds:Set<Constraint>): Set<Column> {
val result = HashSet<Column>(attrs)
//println("RESULT X = $result")
var found = true
while(found) {
found= false
for (fd in fds) {
//println("FD ${fd.left()} == ${fd.right()}")
if (result.containsAll(fd.left())
&& !result.containsAll(fd.right())) {
result.addAll(fd.right())
found = true
//println("FOUND")
}
}
}
return result
}
fun keys(attrs: Set<Column>, fds:Set<Constraint>): Set<Set<Column>> {
var superkeys = superkeys(attrs, fds)
var toremove = HashSet<Set<Column>>()
for (key in superkeys) {
for (col in key) {
var remaining = HashSet<Column>(key)
remaining.remove(col)
if (superkeys.contains(remaining)) {
toremove.add(key)
break
}
}
}
superkeys = superkeys.minus(toremove)
return superkeys
}
fun removeTrivial(fds : Set<Constraint>): HashSet<Constraint> {
val toRemove = HashSet<Constraint>()
val toAdd = HashSet<Constraint>()
for (fd in fds) {
if (fd.left().containsAll(fd.right())) {
toRemove.add(fd)
}
else {
val toRemoveFromRight = HashSet<Column>()
for (a in fd.right()) {
if (fd.left().contains(a)) {
toRemoveFromRight.add(a)
}
}
if (toRemoveFromRight.isNotEmpty()) {
var right = fd.right()
right = right.minus(toRemoveFromRight) as Collection<Column>
toRemove.add(fd)
toAdd.add(Constraint.of(fd.left(),right))
}
}
}
val result = HashSet<Constraint>(fds)
result.addAll(toAdd)
result.removeAll(toRemove)
return result
}
fun equivalent(a: Set<Constraint>, b: Set<Constraint>): Boolean {
val names = HashSet<Column>()
for (fd in a) {
names.addAll(fd.left())
names.addAll(fd.right())
}
for (fd in b) {
names.addAll(fd.left())
names.addAll(fd.right())
}
val reducedPowerSet = reducedPowerSet(names)
for (set in reducedPowerSet) {
val closureInA = closure(set,a)
val closureInB = closure(set,b)
if (!closureInA.equals(closureInB)) return false
}
return true
}
fun removeUnnecessaryEntireFD(fds: Set<Constraint>): HashSet<Constraint> {
var temp = HashSet<Constraint>(fds)
var count = 0
while(true) {
lateinit var toRemove : Constraint
var found = false
for (fd in temp) {
val remaining = HashSet<Constraint>(temp)
remaining.remove(fd)
//println("REMOVE ")
if (equivalent(remaining, temp)) {
//println("EQUIVALENT $count")
++count
found = true
toRemove = fd
break;
}
}
if(!found) { break; }
else {
if (toRemove!=null)
temp = temp.minus(toRemove) as HashSet<Constraint>
}
}
return temp
}
fun splitRight(fds: Set<Constraint>): HashSet<Constraint> {
val result = HashSet<Constraint>(fds)
val toRemove = HashSet<Constraint>()
val toAdd = HashSet<Constraint>()
for(fd in fds) {
if (fd.right().size > 1) {
for (a in fd.right()) {
toAdd.add(Constraint.of(fd.left(), listOf(a)))
}
toRemove.add(fd)
}
}
result.addAll(toAdd)
result.removeAll(toRemove)
return result
}
fun projection(attrs: Set<Column>, fds: Set<Constraint>): Set<Constraint> {
val appeared = HashSet<Column>()
for (fd in fds) {
appeared.addAll(fd.left())
appeared.addAll(fd.right())
}
if (attrs.containsAll(appeared)) {
return HashSet<Constraint>(fds)
}
val notin = HashSet<Column>(appeared)
notin.removeAll(attrs)
val reducedPowerSet = reducedPowerSet(attrs)
val result = HashSet<Constraint>()
for (sa in reducedPowerSet) {
var closure = closure(sa, fds)
closure = closure.minus(notin)
result.add(Constraint.of(sa, closure))
}
return minimalBasis(result)
}
fun minimalBasis(fds: Set<Constraint>): Set<Constraint> {
var result = HashSet<Constraint>(fds)
result = splitRight(result)
result = removeTrivial(result)
var count = 1
while (count > 0) {
val before_remove = result.size
result = removeUnnecessaryEntireFD(result)
result = removeUnnecessaryLeftSide(result)
count = before_remove - result.size
}
return result
}
private fun removeUnnecessaryLeftSide(fds: HashSet<Constraint>): HashSet<Constraint> {
var count = 0
while (true) {
var found = false
lateinit var toRemove: Constraint
lateinit var toAdd: Constraint
var loop = 0
for (fd in fds) {
val left = fd.left()
val right = fd.right()
if (left.size > 1) {
for (a in left) {
val remaining: MutableSet<Column> = HashSet<Column>(left)
remaining.remove(a)
val alternative: MutableSet<Constraint> = HashSet<Constraint>(fds)
alternative.remove(fd)
toAdd = Constraint.of(remaining,right)
alternative.add(toAdd)
if (equivalent(alternative, fds)) {
found = true
toRemove = fd
++count
break
}
}
}
if (found) {
break
}
++loop
}
if (found) {
fds.remove(toRemove)
fds.add(toAdd)
}
if (loop == fds.size) {
break
}
}
return fds
}
fun combineRight(fds: Set<Constraint>): Set<Constraint> {
val result = HashSet<Constraint>(fds)
val map = HashMap<Collection<Column>, MutableCollection<Column>>()
for (fd in result) {
if(map.containsKey(fd.left())) {
map.get(fd.left())?.addAll(fd.right())
} else {
map.put(fd.left(), fd.right() as MutableCollection<Column>)
}
}
result.clear()
for (left in map.keys) {
result.add(Constraint.of(left,map.get(left) as MutableCollection))
}
return result
}
}
}