All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.google.code.plsqlmaven.oraddl.helpers.TableHelper.groovy Maven / Gradle / Ivy

package com.google.code.plsqlmaven.oraddl.helpers

/*
 * Copyright 2001-2005 The Apache Software Foundation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import groovy.sql.Sql
import java.sql.SQLException

class TableHelper extends OraDdlHelper
{
      private static tempColIndex= 99999999999999999999999999;
      
      public TableHelper(sql,log,username)
      {
          super(sql,log,username);
      }

      public boolean extract(name,xml)
      {
          if (name.toUpperCase()==~'JAVA\\$.*')
            return false
            
          def constraints= getConstraints(name)
		  def dbconstraints= constraints.clone()
		  
          xml.table('name': xid(name))
          {
			  def comment= sql.firstRow("select comments from user_tab_comments where table_name = ${name}")?.comments
			  
			  if (comment)
			    xml.comment('')
				{
					out.print("")
			    }
			  
              xml.columns()
              {
                  sql.eachRow("select * from user_tab_columns a where table_name = ${name} order by column_id")
                  {
                     def col= it.toRowResult()
                     def p= col.data_type.indexOf('(')
				 	 def colComment= sql.firstRow("select comments from user_col_comments where table_name = ${name} and column_name= ${col.column_name}")?.comments
					 
                     xml.column('name':          xid(col.column_name),
                                'type':          col.data_type.toLowerCase().substring(0,(p==-1?col.data_type.length():p)),
                                'precision':     col.data_precision,
                                'scale':         col.data_scale,
                                'length':        rd(col.char_length+(col.char_used==null ? 0 : ' '+(col.char_used=='B' ? 'byte' : 'char')),0),
                                'default':       (col.data_default?.trim()?.toLowerCase()=='null' ? null : col.data_default?.trim()),
                                'primary':       simpleKey(col.column_name,constraints, 'P'),
                                'unique':        simpleKey(col.column_name,constraints, 'U'),
                                'check':         simpleCheck(col.column_name,constraints),
                                'not-null':      simpleNotNull(col.column_name,constraints,dbconstraints),
                                'references':    simpleForeignKey(col.column_name,constraints))
					 {
					    if (colComment)
						  xml.comment('')
						  {
							 out.print("")
						  }
				     }
                  }
              }
              
              if (constraints.size()>0)
                  xml.constraints()
                  {
                      constraints.each
                      {
                          constraint ->
                          
                          xml.constraint('name': xid(constraint.constraint_name),
                                         'type': constraintType(constraint.constraint_type),
                                         'expression': constraint.search_condition,
                                         'on-delete': (constraint.delete_rule!='NO ACTION' ? constraint.delete_rule?.toLowerCase() : null))
                          {
                              xml.columns()
                              {
                                  constraint.columns.each
                                  {
                                     column ->
                                     
                                     xml.column('name': xid(column.column_name))
                                  }
                              }
                              
                              if (constraint.constraint_type=='R')
                              {
                                  
                                  xml.references('table': xid(constraint.rcolumns[0].table_name),
                                                 'owner': xid(constraint.rcolumns[0].owner)==xid(username) ? null : xid(constraint.rcolumns[0].owner))
                                  {
                                      constraint.rcolumns.each
                                      {
                                         column ->
                                         
                                         xml.column('name': xid(column.column_name))
                                      }
                                  }
                              }
                              
                          }
                      }
                  }
                  
               def triggers= sql.rows("select trigger_name from user_triggers a where table_name = ${name}");
               
               if (triggers.size()>0)   
                   xml.triggers()
                   {
                       triggers.each
                       {
                          trigger ->
                          
                          xml.trigger('name': xid(trigger.trigger_name))
                       }
                   }
              
          }
          
          return true;
      }
      
      private getConstraints(tableName)
      {
          def constraints= []
          
          sql.eachRow("select * from user_constraints a where table_name = upper(${tableName}) order by decode(constraint_type,'P',1,'U',2,'R',3,4)")
          {
             def cons= it.toRowResult()
             cons['columns']= []
             
             sql.eachRow("select * from user_cons_columns where constraint_name= ${cons.constraint_name} order by position")
             {
                cons.columns << it.toRowResult()
             }
             
             if (cons.constraint_type=='R')
             {
                 cons['rcolumns']= []
                 
                 sql.eachRow("select * from all_cons_columns where constraint_name= ${cons.r_constraint_name} and owner= ${cons.r_owner} order by position")
                 {
                     def rcol= it.toRowResult()
                     cons.rcolumns << rcol
                 }
             }
             
             constraints << cons
          }
          
          return constraints 
      }
      
      private constraintType(type)
      {
          switch (type)
          {
              case 'P':
               return 'primary'
              case 'U':
               return 'unique'
              case 'C':
               return 'check'
              case 'R':
               return 'foreign'
          }
      }
      
      private simpleKey(columnName,constraints,type)
      {
          def constraint= constraints.find{ constraint -> (constraint.constraint_type==type
                                   &&constraint.constraint_name.startsWith('SYS_C')
                                   &&constraint.columns.size()==1
                                   &&constraint.columns.find{ column -> (column.column_name==columnName) }) } 
          
          constraints.remove constraint
          
          return constraint ? 'true' : null
      }
      
      private simpleForeignKey(columnName,constraints)
      {
          def fk= constraints.find{ constraint -> (constraint.constraint_type=='R'
                                           &&constraint.constraint_name.startsWith('SYS_C')
                                           &&constraint.columns.size()==1
                                           &&constraint.columns.find{ column -> (column.column_name==columnName) }) }
          
          if (fk)
          {          
             constraints.remove fk
             def rcol= fk.rcolumns[0]             
             return ((xid(username)!=xid(rcol.owner) ? xid(rcol.owner)+'.' : '')+xid(rcol.table_name)+(rcol.column_name!= columnName ? '.'+xid(rcol.column_name) : ''))
          }
          
          return null
      }

      private simpleCheck(columnName,constraints)
      {
          def checks= constraints.findAll{ constraint -> (constraint.constraint_type=='C'
                                                     && constraint.columns.find{ column -> (column.column_name==columnName) }
                                                     && constraint.columns.size()==1
                                                     && constraint.constraint_name.startsWith('SYS_C') 
                                                     && !isNotNullSearchCondition(constraint.search_condition,columnName)) }
          
          def r
          
          if (checks)
          {
              constraints.removeAll checks
              r= checks?.collect{ constraint -> constraint.search_condition }?.join(' and ')
          }
                                                    
          return r ? r : null                                                     
      }
      
      private isNotNullSearchCondition(dbSearchCondition,columnName)
      {
          return cmp(dbSearchCondition.toLowerCase().replaceAll('"',''),(columnName+' IS NOT NULL').toLowerCase())
      }
      
      private simpleNotNull(columnName,constraints,dbconstraints)
      {
          def colInPk= (boolean)dbconstraints.find{ constraint -> (constraint.constraint_type=='P'
                                                                 &&constraint.columns.find{ column -> (column.column_name==columnName) }) }
          
          def constraint= constraints.findAll{ constraint -> (cmp(constraint.constraint_type,'C')
                                                 && constraint.columns.find{ column -> cmp(column.column_name,columnName) }
                                                 && cmp(constraint.columns.size(),1)
                                                 && constraint.constraint_name.startsWith('SYS_C') 
                                                 && isNotNullSearchCondition(constraint.search_condition,columnName)) } 
          
          if (constraint.size()>0)
          {
            constraint.each { c -> constraints.remove c } // it is possible to find doubled check not null constraint on the same column
            return colInPk ? null : 'true'
          }
          else
            return null
           
      }
      
      public boolean exists(table)
      {
           def exists= false;
           sql.eachRow("select 1 from user_tables where table_name= ${oid(table.'@name',false)}")
           { exists= true }
           
           return exists
      }
      
      public create(table)
      {
          def changes= []
		  
		  def maxLength= 0;
		  
		  table.columns.column.each
		  { 
			  col -> 
			  
			  def l=oid(col.'@name').length() 
			  
			  if (l>maxLength)
			    maxLength= l
		  }
		  
		  def spaces= 
		  {
		      col ->
			  
			  def sp= ''
			  
			  (maxLength-oid(col.'@name').length()+2).times{ sp+=' ' }
			  
			  return sp
		  }
          
          changes << [
                              type: 'create_table',
                               ddl: 'create table '+oid(table.'@name')+'\n(\n'+INDENT+table.columns.column.collect{ col-> oid(col.'@name')+spaces(col)+getColumnType(col) }.join(',\n'+INDENT)+'\n)',
                       privMessage: "You need to: grant create table to ${username}"         
                     ]
          
		  if (table.comment)
   		    changes << set_table_comment(table)

          table.columns.column.each
          {
              column ->
			  
			  if (column.comment)
	    		    changes << set_column_comment(table,column)
              
              if (column.'@primary'=='true')
                changes << add_constraint(table,col_to_primary(column))

              if (column.'@not-null'=='true')
                changes << add_constraint(table,col_to_notnull(column))

              if (column.'@unique'=='true')
                changes << add_constraint(table,col_to_unique(column))
                
              if (column.'@check')
                changes << add_constraint(table,col_to_check(column,column.'@check'))
                
              if (column.'@references')
                changes << add_constraint(table,col_to_foreign(column))

          }
          
          table.constraints.constraint.each
          {
              constraint ->
              
              changes << add_constraint(table,constraint)
          }
		  
          return changes
      }
      
      public detectChanges(source,target)
      {
          def changes= [];
          
		  if (source.comment?.text()!=target.comment?.text())
		    changes << set_table_comment(target)
			
		 log.debug 'source: '+source.toString()
			
          target.columns.column.each
          {
                targetCol ->
                
                def sourceCol= source.columns.column.find({ col -> cmp(col.'@name',targetCol.'@name') })
				
				log.debug 'sourceCol: '+sourceCol.toString()
                
                if (!sourceCol)
                {
                      changes << add_column(target,targetCol)
                    
					  if (targetCol.comment)
						changes << set_column_comment(target,targetCol)
	
	                  if (targetCol.'@primary'=='true')
	                    changes << add_constraint(target,col_to_primary(targetCol))
	    
	                  if (targetCol.'@not-null'=='true')
	                    changes << add_constraint(target,col_to_notnull(targetCol))
	    
	                  if (targetCol.'@unique'=='true')
	                    changes << add_constraint(target,col_to_unique(targetCol))
	                    
	                  if (targetCol.'@check')
	                    changes << add_constraint(target,col_to_check(targetCol,targetCol.'@check'))
	                    
	                  if (targetCol.'@references')
	                    changes << add_constraint(target,col_to_foreign(targetCol))
    
                }
                else
                {
					if (sourceCol.comment?.text()!=targetCol.comment?.text())
		   			   changes << set_column_comment(target,targetCol)
		
                    if (  !cmp(sourceCol,targetCol,'type')
                        ||!cmp(sourceCol,targetCol,'precision')
                        ||!cmp(sourceCol,targetCol,'scale')
                        ||!cmp(sourceCol,targetCol,'length')
                        ||!cmp(sourceCol,targetCol,'default'))
                      changes += modify_column(target,targetCol,sourceCol)
                    
                    if (!cmp(sourceCol,targetCol,'primary','false'))
                      modify_simple_primary(changes,target,targetCol,sourceCol)

                    if (!cmp(sourceCol,targetCol,'unique','false'))
                      modify_simple_unique(changes,target,targetCol,sourceCol)

                    if (!cmp(sourceCol,targetCol,'not-null','false'))
                      modify_simple_notnull(changes,target,targetCol,sourceCol)
					  
                    if (!cmp(sourceCol,targetCol,'check'))
                      modify_simple_check(changes,target,targetCol,sourceCol)
                      
                    if (!cmp(sourceCol,targetCol,'references'))
                      modify_simple_foreign(changes,target,targetCol,sourceCol)
                }
          }

          def renamedConstraints= []
          
          source.constraints.constraint.findAll{ c -> (!(c.'@name' in target.constraints.constraint*.'@name')) }.each
          {
                constraint ->

                def rename= false;
                def targetCons;
                
                if (constraint.'@type'=='primary') 
                {
                    targetCons= target.constraints.constraint.find{ c -> (c.'@type'=='primary') }
                    
                    if (targetCons)
                    try
                    {
                        if (constraint.columns.column.size()!=targetCons.columns.column.size())
                                throw new ContextException('column count differs')
                        else
                            targetCons.columns.column.eachWithIndex
                            {
                                targetCol, index ->
                                
                                def sourceCol= constraint.columns.column[index];
                                
                                if (!cmp(sourceCol,targetCol,'name'))
                                  throw new ContextException('columns differs')
                            }
                            
                        rename= true;
                    }
                    catch (ContextException cex)
                    {}
                }
                
                if (rename)
                {
                  renamedConstraints << targetCons.'@name'
                  changes << rename_constraint(target,constraint,targetCons);
                }
                else                
                  changes << drop_constraint(target,constraint);
          }
              
          source.columns.column.findAll{ col -> (!(col.'@name' in target.columns.column*.'@name')) }.each
          {
              column ->
              
              changes << drop_column(target,column)
          }
          
          target.constraints.constraint.each
          {
                 targetCons ->
				 
                 def sourceCons= source.constraints.constraint.find{ c-> (c.'@name'==targetCons.'@name') }

				 if (!sourceCons)
                 {
                     if (!(targetCons.'@name' in renamedConstraints))
                       changes << add_constraint(target,targetCons)
				 }
                 else
                 {
                     try
                     {
                        if (  !cmp(sourceCons,targetCons,'type')
                            ||!cmp(sourceCons,targetCons,'on-delete','no action')
                            ||!cmp(sourceCons,targetCons,'expression')
                            ||!cmp(sourceCons.references[0]?.'@owner',targetCons.references[0]?.'@owner')
                            ||!cmp(sourceCons.references[0]?.'@table',targetCons.references[0]?.'@table') )
                            throw new ContextException('base metadata differs')
                        else
                        if (targetCons.'@type'!='check')
                        {
                            if (sourceCons.columns.column.size()!=targetCons.columns.column.size())
                                throw new ContextException('column count differs')
                            else      
                                targetCons.columns.column.eachWithIndex
                                {
                                    targetCol, index -> 
                                    
                                    def sourceCol= sourceCons.columns.column[index];
                                    
                                    if (!cmp(sourceCol,targetCol,'name'))
                                      throw new ContextException('columns differs')
                                }
                              
                            if (targetCons.'@type'=='foreign')
                            {
                                if (sourceCons.references.column.size()!=targetCons.references.column.size())
                                    throw new ContextException('referenced column count differs')
                                else
                                    targetCons.references.column.eachWithIndex
                                    {
                                        targetCol, index ->
                                        
                                        def sourceCol= sourceCons.references.column[index];
                                        
                                        if (!cmp(sourceCol,targetCol,'name'))
                                          throw new ContextException('referenced columns differs')
                                    }
                             }
                        }
                     }
                     catch (ContextException ex)
                     {
                         changes += modify_constraint(target,targetCons,ex.context)
                     }
                  }
                     
          }
          
          source.triggers.trigger.each
          {
              sourceTrigger ->
              
              def targetTrigger= target.triggers.trigger.find{ t-> (t.'@name'==sourceTrigger.'@name')}
              
              if (!targetTrigger)
                changes << drop_trigger(source,sourceTrigger)
          }
          
          return changes
      }
   
      
      /*   CHANGES    */
      
      public drop_trigger(table,trigger)
      {
           return [
                            type: 'drop_trigger',
                             ddl: "drop trigger ${oid(trigger.'@name')}",
                     privMessage: "You need to: grant alter table to ${username}"
                  ]
      }
      
      public drop_column(table,column)
      {
           return [
                            type: 'drop_column',
                             ddl: "alter table ${oid(table.'@name')} drop column ${oid(column.'@name')}",
                     privMessage: "You need to: grant alter table to ${username}"
                  ]
      }
   
      public modify_column(table,targetCol,sourceCol)
      {
          def changes= []
          
          if (targetCol.'@type'=='varchar2'&&sourceCol.'@type'=='clob')
          {
              changes+= column_clob_to_varchar2(table,targetCol);
          }
          else
          if (targetCol.'@type'=='varchar2'&&sourceCol.'@type'=='number')
          {
              changes+= column_number_to_varchar2(table,targetCol);
          }
          else
          if (targetCol.'@type'=='number'&&sourceCol.'@type'=='number'&&
              ((!cmp(sourceCol,targetCol,'precision')
                  &&(!(dv(targetCol.'@precision'?.toInteger(),9999999)>dv(sourceCol.'@precision'?.toInteger(),9999999))))
              ||!cmp(sourceCol,targetCol,'scale',0)))
          {
              changes+= column_number_reduce_precision(table,targetCol);
          }
          else
          {
             def columnType= getColumnType(targetCol)
			 
             changes+= [
                                 type: 'modify_column',
                                  ddl: "alter table ${oid(table.'@name')} modify (${oid(targetCol.'@name')} ${columnType})",
                          privMessage: "You need to: grant alter table to ${username}"
                       ]
          }
          
          return changes
      }
   
      public add_column(table,column)
      {
          def columnType= getColumnType(column)
          
          return [
                                 type: 'add_column',
                                  ddl: "alter table ${oid(table.'@name')} add (${oid(column.'@name')} ${columnType})",
                          privMessage: "You need to: grant alter table to ${username}"
                 ]
          
      }
      
      public add_constraint(table,constraint)
      {
		  def ddl= "alter table ${oid(table.'@name')} "
		  
		  if (constraint.'@type'=='not-null')
              ddl+= "modify (${constraint.columns.column[0].'@name'} not null)"
          else
		  {
			  ddl+= "add "+(constraint.'@name' ? "constraint ${oid(constraint.'@name')}\n" : '')
			  
	          if (constraint.'@type'=='primary')
	              ddl+="primary key ("+constraint.columns.column*.'@name'.join(',')+")"
	          else
	          if (constraint.'@type'=='foreign')
	          {
	              ddl+="foreign key ("+constraint.columns.column*.'@name'.join(',')+")\n"
	              def owner= constraint.references[0].'@owner'
	              ddl+="references "+( owner&&owner!=username ? owner+'.' : '' )+constraint.references[0].'@table'
	              ddl+='('+constraint.references.column*.'@name'.join(',')+')'
	              
	              if (dv(constraint.'@on-delete','no action')!='no action')
	                ddl+='\non delete '+constraint.'@on-delete'
	          }
	          else
	          if (constraint.'@type'=='check')
	              ddl+="check ("+constraint.'@expression'+")"
	          else
	          if (constraint.'@type'=='unique')
	              ddl+="unique ("+constraint.columns.column*.'@name'.join(',')+")"
		  }
          
          return [
                         type: 'add_constraint',
                          ddl: ddl,
                  privMessage: "You need to: grant alter table to ${username}",
                   constraint: [type: constraint.'@type']
                 ]

      }
   
      public rename_constraint(table,sourceCons,targetCons)
      {
		  def position=1;		  
		  def positionQuery= targetCons.columns.column.collect{ """select constraint_name from user_cons_columns where column_name= '${oid(it.'@name',false)}' and position= ${position++} and table_name= v_table""" }.join(' intersect ')
		  
          return [
                              type: 'rename_constraint',
                             //  ddl: "alter table ${oid(table.'@name')} rename constraint ${oid(sourceCons.'@name')} to ${oid(targetCons.'@name')}",
							   ddl: """-- rename ${targetCons.'@type'} constraint on ${oid(table.'@name')}(${targetCons.columns.column.collect{ oid(it.'@name') }.join(',')}) to ${targetCons.'@name'}  
                                       declare
                                         v_table       varchar2(30):= '${oid(table.'@name',false)}';
                                         v_constraint  varchar2(30):= '${oid(sourceCons.'@name',false)}';
                                       begin
                                         
                                         if v_constraint= 'null' then
	                                         select constraint_name
	                                           into v_constraint
	                                           from user_constraints
	                                          where constraint_name in (${positionQuery})
	                                            and constraint_type= 'P'
	                                            and constraint_name like 'SYS\\_C%' escape '\\';
                                         end if;
                                         
                                         execute immediate 'alter table "'||v_table||'" rename constraint "'||v_constraint||'" to ${oid(targetCons.'@name')}';
                                       
                                       end;""",
                       privMessage: "You need to: grant alter table to ${username}"
                 ]
      }
	  
	  public drop_primary_constraint(table,constraint)
	  {
		  return [
							  type: 'drop_constraint',
							   ddl: "alter table ${oid(table.'@name')} drop primary key cascade",
					   privMessage: "You need to: grant alter table to ${username}"
				 ]
	  }

	  public drop_unique_constraint(table,constraint)
	  {

		  def position=1;		  
		  def positionQuery= constraint.columns.column.collect{ """select constraint_name from user_cons_columns where column_name= '${oid(it.'@name',false)}' and position= ${position++} and table_name= v_table""" }.join(' intersect ')
		  
          return [
                              type: 'drop_constraint',
                               ddl: """-- drop unique constraint on ${oid(table.'@name')}(${constraint.columns.column.collect{ oid(it.'@name') }.join(',')})
                                       declare
                                         v_table       varchar2(30):= '${oid(table.'@name',false)}';
                                         v_constraint  varchar2(30);
                                       begin
                                         
                                         select constraint_name
                                           into v_constraint
                                           from user_constraints
                                          where constraint_name in (${positionQuery})
                                            and constraint_type= 'U'
                                            and constraint_name like 'SYS\\_C%' escape '\\';
                                         
                                         execute immediate 'alter table "'||v_table||'" drop constraint "'||v_constraint||'" cascade';
                                       
                                       end;""",
                       privMessage: "You need to: grant alter table to ${username}"
                 ]
	  }

	  public drop_check_constraint(table,constraint)
	  {

		  def position=1;		  
		  def columnNames= constraint.columns.column.collect{ "'"+oid(it.'@name',false)+"'" }.join(',')
		  
          return [
                              type: 'drop_constraint',
                               ddl: """-- drop check constraint (${constraint.'@expression'}) on ${oid(table.'@name')}
                                       declare
                                         v_table             varchar2(30):= '${oid(table.'@name',false)}';
                                         v_constraint        varchar2(30);
                                         v_search_condition  varchar2(32767):= '${constraint.'@expression'}';
                                       begin
                                         
                                             for c_cur in (select constraint_name,
                                                                  search_condition
                                                             from user_constraints
                                                            where constraint_name in (select distinct constraint_name
                                                                                        from user_cons_columns a
                                                                                       where column_name in (${columnNames})
                                                                                         and position is null
                                                                                         and table_name= v_table) 
                                                              and constraint_name like 'SYS\\_C%' escape '\\'
                                                              and constraint_type= 'C')
                                             loop
                                              if c_cur.search_condition= v_search_condition then
                                                execute immediate 'alter table "'||v_table||'" drop constraint "'||c_cur.constraint_name||'"';
                                              end if;
                                             end loop;
                                         
                                       end;""",
                       privMessage: "You need to: grant alter table to ${username}"
                 ]
	  }
	  
	  public drop_foreign_constraint(table,constraint)
	  {

		  def position=1;		  
		  def positionQuery= constraint.columns.column.collect{ """select constraint_name from user_cons_columns where column_name= '${oid(it.'@name',false)}' and position= ${position++} and table_name= v_table""" }.join(' intersect ')
		  position=1;
		  def rPositionQuery= constraint.references.column.collect{ """select constraint_name from all_cons_columns where column_name= '${oid(it.'@name',false)}' and position= ${position++} and table_name= v_r_table and owner= v_r_owner""" }.join(' intersect ')
		  
          return [
                              type: 'drop_constraint',
                               ddl: """-- drop foreign constraint on ${oid(table.'@name')}(${constraint.columns.column.collect{ oid(it.'@name') }.join(',')}) to ${oid(constraint.references.'@table'[0])}(${constraint.references.column.collect{ oid(it.'@name') }.join(',')}) 
                                       declare
                                         v_table       varchar2(30):= '${oid(table.'@name',false)}';
                                         v_r_table     varchar2(30):= '${oid(constraint.references.'@table'[0],false)}';
                                         v_r_owner     varchar2(30):= nvl('${oid(constraint.references.'@owner'[0],false)}','null');
                                         v_constraint  varchar2(30);
                                       begin
                                       
                                         if v_r_owner = 'null' then
                                           v_r_owner:= user;
                                         end if;
                                         
                                         select constraint_name
                                           into v_constraint
                                           from user_constraints
                                          where constraint_name in (${positionQuery})
                                            and constraint_type= 'R'
                                            and constraint_name like 'SYS\\_C%' escape '\\'
                                            and r_constraint_name = (select constraint_name
                                                                       from all_constraints
                                                                      where constraint_name in (select constraint_name
										                                                         from all_cons_columns a
										                                                        where constraint_name in (${rPositionQuery})
										                                                          and owner = v_r_owner)
										                               and constraint_type in ('P','U')
										                               and owner = v_r_owner);
                           
                                         
                                         execute immediate 'alter table "'||v_table||'" drop constraint "'||v_constraint||'"';
                                       
                                       end;""",
                       privMessage: "You need to: grant alter table to ${username}"
                 ]
	  }

	  public drop_constraint(table,constraint)
      {
		  if (constraint.'@name')
	          return [
	                              type: 'drop_constraint',
	                               ddl: "alter table ${oid(table.'@name')} drop constraint ${oid(constraint.'@name')} cascade",
	                       privMessage: "You need to: grant alter table to ${username}"
	                 ]
		  else
			  return "drop_${constraint.'@type'}_constraint"(table,constraint)
      }
      
      public modify_constraint(table,constraint,cause=null)
      {
          return [drop_constraint(table,constraint),
                  add_constraint(table,constraint)]
      }
	  
	  public col_to_primary(column)
	  {
		  return parser.parseText('')
      }
	  
	  public col_to_unique(column)
	  {
		  return parser.parseText('')
	  }

	  public col_to_check(column,expression)
	  {
		  return parser.parseText('')
	  }

	  public col_to_notnull(column)
	  {
		  return parser.parseText('')
	  }
	  
	  public col_to_foreign(column)
	  {
		  def ref= column.'@references'.split('\\.')
		  def rowner= ''
		  def rtable= ''
		  def rcolumn= ''
		  
		  if (ref.length==3)
		  {
		      rowner= ref[0]
		      rtable= ref[1]
		      rcolumn= ref[2]
		  }
		  else
		  if (ref.length==2)
		  {
		      rtable= ref[0]
		      rcolumn= ref[1]
	      }
		  else
		  {
		      rtable= ref[0]
		      rcolumn= column.'@name'
		  }
		  
		  return parser.parseText('')
	  }
	  
	  public modify_simple_primary(changes,table,targetCol,sourceCol)
      {
          if (sourceCol.'@primary'=='true')
            changes << drop_constraint(table,col_to_primary(sourceCol))
          
          if (targetCol.'@primary'=='true')
            changes << add_constraint(table,col_to_primary(targetCol))
      }

      public modify_simple_unique(changes,table,targetCol,sourceCol)
      {
          if (sourceCol.'@unique'=='true')
            changes << drop_constraint(table,col_to_unique(sourceCol))
            
           if (targetCol.'@unique'=='true')
            changes << add_constraint(table,col_to_unique(targetCol))
      }

      public modify_simple_check(changes,table,targetCol,sourceCol)
      {
          if (sourceCol.'@check')
            changes << drop_constraint(table,col_to_check(sourceCol,sourceCol.'@check'))
            
          if (targetCol.'@check')
            changes << add_constraint(table,col_to_check(targetCol,targetCol.'@check'))
      }

      public modify_simple_notnull(changes,table,targetCol,sourceCol)
      {
          if (sourceCol.'@not-null'=='true')
            changes << drop_constraint(table,col_to_check(sourceCol,sourceCol.'@name'+' is not null'))
            
          if (targetCol.'@not-null'=='true')
            changes << add_constraint(table,col_to_notnull(targetCol))
      }

      public modify_simple_foreign(changes,table,targetCol,sourceCol)
      {
          if (sourceCol.'@references')
            changes << drop_constraint(table,col_to_foreign(sourceCol))
            
          if (targetCol.'@references')
            changes << add_constraint(table,col_to_foreign(targetCol))
      }
      
      public column_clob_to_varchar2(table,column)
      {
          def changes= [];
          def tempIndex= tempColIndex--;
          def columnType= getColumnType(column);
          
          changes << [
	                         type: 'drop_maven_temporary_column',
	                     mainType: 'modify_column',
	                    tempIndex: tempIndex,
	                          ddl: "alter table ${oid(table.'@name')} drop column mvn_${tempIndex}",
	                     failSafe: true
                     ]
          
          changes << [
                              type: 'add_maven_temporary_column',
                          mainType: 'modify_column',
                         tempIndex: tempIndex,
                               ddl: "alter table ${oid(table.'@name')} add (mvn_${tempIndex} ${columnType})",
                       privMessage: "You need to: grant alter table to ${username}"
                     ]
          
          def target_length= column.'@length'.split(' ')[0];

          changes << [
                              type: 'maven_translate_values_clob_to_varchar2',
                          mainType: 'modify_column',
                         tempIndex: tempIndex,
                               ddl: """declare
                                          v_value ${columnType};
                                          
                                          function to_varchar2(p_old clob, p_length number, p_rowid varchar2)
                                          return varchar2
                                          as
                                             v_length number:= dbms_lob.getlength(p_old);
                                          begin
                                          
                                             if v_length > p_length then
                                               raise_application_error(-20001,'Found a value longer than target column length: '||to_char(v_value)||' at rowid: '||p_rowid);
                                             end if;
                                             
                                             return dbms_lob.substr(p_old,v_length,1);
                                             
                                          end;
                                     begin
                                          for c_cur in (select rowid rwid, ${oid(column.'@name')} from ${oid(table.'@name')}) loop
                                             v_value:= to_varchar2(c_cur.${oid(column.'@name')},${target_length},c_cur.rwid);
                                             update ${oid(table.'@name')}
                                                set mvn_${tempIndex}= v_value
                                              where rowid= c_cur.rwid;
                                          end loop;
                                          commit;
                                     end;
                                   """
                     ]
          
          changes << [
                              type: 'maven_drop_column_after_data_migration',
                          mainType: 'modify_column',
                         tempIndex: tempIndex,
                               ddl: "alter table ${oid(table.'@name')} drop column ${oid(column.'@name')}",
                       privMessage: "You need to: grant alter table to ${username}"
                     ]

          changes << [
                              type: 'maven_rename_temporary_column',
                          mainType: 'modify_column',
                         tempIndex: tempIndex,
                               ddl: "alter table ${oid(table.'@name')} rename column mvn_${tempIndex} to ${oid(column.'@name')}",
                       privMessage: "You need to: grant alter table to ${username}"
                     ]
          
          return changes;
      }
      
      private column_number_to_varchar2(table,column)
      {
          def changes= [];
          def tempIndex= tempColIndex--;
          def columnType= getColumnType(column);
          
          try
          {
             changes << [
                             type: 'drop_maven_temporary_column',
                         mainType: 'modify_column',
                        tempIndex: tempIndex,
                              ddl: "alter table ${oid(table.'@name')} drop column mvn_${tempIndex}",
                         failSafe: true
                        ]
          }
          catch (Exception ex)
          {}
          
          changes << [
                              type: 'add_maven_temporary_column',
                          mainType: 'modify_column',
                         tempIndex: tempIndex,
                               ddl: "alter table ${oid(table.'@name')} add (mvn_${tempIndex} ${columnType})",
                       privMessage: "You need to: grant alter table to ${username}"
                     ]
          
          def target_length= column.'@length'.split(' ')[0];

          changes << [
                              type: 'maven_translate_values_number_to_varchar2',
                          mainType: 'modify_column',
                         tempIndex: tempIndex,
                               ddl: """declare
                                          v_value ${columnType};
                                          
                                          function to_varchar2(p_old number, p_length number, p_rowid varchar2)
                                          return varchar2
                                          as 
                                             v_value varchar2(2000):= to_char(p_old);
                                          begin
                                          
                                             if length(v_value) > p_length then
                                               raise_application_error(-20001,'Found a value longer than target column length: '||to_char(v_value)||' at rowid: '||p_rowid);
                                             end if;
                                             
                                             return v_value;
                                             
                                          end;
                                     begin
                                          for c_cur in (select rowid rwid, ${oid(column.'@name')} from ${oid(table.'@name')}) loop
                                             v_value:= to_varchar2(c_cur.${oid(column.'@name')},${target_length},c_cur.rwid);
                                             update ${oid(table.'@name')}
                                                set mvn_${tempIndex}= v_value
                                              where rowid= c_cur.rwid;
                                          end loop;
                                          commit;
                                     end;
                                   """
                     ]
          
          changes << [
                              type: 'maven_drop_column_after_data_migration',
                          mainType: 'modify_column',
                         tempIndex: tempIndex,
                               ddl: "alter table ${oid(table.'@name')} drop column ${oid(column.'@name')}",
                       privMessage: "You need to: grant alter table to ${username}"
                     ]

          changes << [
                              type: 'maven_rename_temporary_column',
                          mainType: 'modify_column',
                         tempIndex: tempIndex,
                               ddl: "alter table ${oid(table.'@name')} rename column mvn_${tempIndex} to ${oid(column.'@name')}",
                       privMessage: "You need to: grant alter table to ${username}"
                     ]
          
          return changes;
      }
      
      
      private column_number_reduce_precision(table,column)
      {
          def changes= [];
          def tempIndex= tempColIndex--;
          def columnType= getColumnType(column);
          
          try
          {
             changes << [
                             type: 'drop_maven_temporary_column',
                         mainType: 'modify_column',
                        tempIndex: tempIndex,
                              ddl: "alter table ${oid(table.'@name')} drop column mvn_${tempIndex}",
                         failSafe: true
                        ]
          }
          catch (Exception ex)
          {}
          
          changes << [
                              type: 'add_maven_temporary_column',
                          mainType: 'modify_column',
                         tempIndex: tempIndex,
                               ddl: "alter table ${oid(table.'@name')} add (mvn_${tempIndex} ${columnType})",
                       privMessage: "You need to: grant alter table to ${username}"
                     ]
          
          changes << [
                              type: 'maven_column_reduce_number_precision',
                          mainType: 'modify_column',
                         tempIndex: tempIndex,
                               ddl: """declare
                                          v_value ${columnType};
                                          
                                          function reduce_precision(p_old number, p_rowid varchar2)
                                          return number
                                          as
                                             v_value ${columnType};
                                          begin
                                          
                                             v_value:= p_old;
                                             return v_value;
                                          
                                          exception
                                           when others then
                                             raise_application_error(-20001,'Found value incompatible with target column precision: '||to_char(p_old)||' at rowid: '||p_rowid);
                                          end;
                                     begin
                                          for c_cur in (select rowid rwid, ${oid(column.'@name')} from ${oid(table.'@name')}) loop
                                             v_value:= reduce_precision(c_cur.${oid(column.'@name')},c_cur.rwid);
                                             update ${oid(table.'@name')}
                                                set mvn_${tempIndex}= v_value
                                              where rowid= c_cur.rwid;
                                          end loop;
                                          commit;
                                     end;
                                   """
                     ]
          
          changes << [
                              type: 'maven_drop_column_after_data_migration',
                          mainType: 'modify_column',
                         tempIndex: tempIndex,
                               ddl: "alter table ${oid(table.'@name')} drop column ${oid(column.'@name')}",
                       privMessage: "You need to: grant alter table to ${username}"
                     ]

          changes << [
                              type: 'maven_rename_temporary_column',
                          mainType: 'modify_column',
                         tempIndex: tempIndex,
                               ddl: "alter table ${oid(table.'@name')} rename column mvn_${tempIndex} to ${oid(column.'@name')}",
                       privMessage: "You need to: grant alter table to ${username}"
                     ]
          
          return changes;
      }
	  
	  public set_table_comment(table)
	  {
		  def escapedComment= table.comment?.text()?.replace("'","''")
		  
		  return [
					  type: 'table_comment',
					   ddl: "comment on table ${oid(table.'@name')} is '${escapedComment}'",
			   privMessage: "You need to: grant alter table to ${username}"
                 ]
      }
      
	  public set_column_comment(table,column)
	  {
		  def escapedComment= column.comment?.text()?.replace("'","''")
		  
		  return [
					  type: 'column_comment',
					   ddl: "comment on column ${oid(table.'@name')}.${oid(column.'@name')} is '${escapedComment}'",
			   privMessage: "You need to: grant alter table to ${username}"
                 ]
      }
	  
      public reorder(changes)
      {
          def reordered= changes.clone()
          
          changes.each
          {
              change ->
              
              if (change&&change.type=='add_constraint'&&change.constraint.type=='foreign')
              {
                  reordered.remove(change)
                  reordered << change
              }
          }
          
          return reordered
      }
      
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy