Click here to Skip to main content
15,897,291 members
Articles / Programming Languages / SQL

Schema Compare Tool for Oracle

Rate me:
Please Sign up or sign in to vote.
4.48/5 (18 votes)
20 Jul 20043 min read 151.2K   1.8K   42  
This small VB.NET application allows you to compare Oracle database schemas against one another. This is very helpful when making sure your development instance is the same as your production instance; especially when implementing front-end changes.
Imports System.Data.OracleClient
Imports System.IO

Public Class OracleCompare

    Private mConn As OracleConnection
    Private LogFileName As String
    Private MissingTables As DataTable

    Public Sub New()
        MissingTables = New DataTable("MISSING_TABLES")
        MissingTables.Columns.Add("NAME")
    End Sub

    Public Function BuildSchemaInfo(ByVal ConnString As String, ByVal ConnUser As String) As DataSet
        mConn = New OracleConnection(ConnString)
        mConn.Open()

        Dim ds As New DataSet("SchemaInfo")
        ds.Clear()
        AddDSInfo(ds, ConnUser)

        AddSchemaItem(ConnString, "TABLE", "SELECT TABLE_NAME FROM USER_TABLES ORDER BY TABLE_NAME", ds)
        AddSchemaItem(ConnString, "VIEW", "SELECT VIEW_NAME,TEXT_LENGTH,VIEW_NAME TABLE_NAME FROM user_views", ds)
        AddSchemaItem(ConnString, "COLUMN", "SELECT TABLE_NAME||'.'||COLUMN_NAME COLUMN_NAME,DATA_TYPE,DATA_LENGTH,NULLABLE,TABLE_NAME FROM USER_TAB_COLUMNS ORDER BY TABLE_NAME,COLUMN_ID", ds)
        AddSchemaItem(ConnString, "SEQUENCE", "SELECT SEQUENCE_NAME,MIN_VALUE,MAX_VALUE,INCREMENT_BY,CYCLE_FLAG FROM USER_SEQUENCES ORDER BY 1", ds)
        AddSchemaItem(ConnString, "TRIGGER", "SELECT TABLE_NAME||'.'||TRIGGER_NAME TRIGGER_NAME,TRIGGER_TYPE,TRIGGERING_EVENT,TABLE_NAME FROM USER_TRIGGERS ORDER BY TABLE_NAME", ds)
        AddSchemaItem(ConnString, "CONSTRAINT", "SELECT TABLE_NAME||'.'||CONSTRAINT_NAME CONSTRAINT_NAME,CONSTRAINT_TYPE,TABLE_NAME, NVL(R_CONSTRAINT_NAME,'NULL') R_CONSTRAINT_NAME,NVL(DELETE_RULE,'NULL') DELETE_RULE FROM USER_CONSTRAINTS WHERE GENERATED = 'USER NAME' UNION SELECT C.TABLE_NAME||'.'||DECODE(C.CONSTRAINT_TYPE,'C','CHECK','?')||'_'||CLM.COLUMN_NAME,CONSTRAINT_TYPE,C.TABLE_NAME, NVL(R_CONSTRAINT_NAME,'NULL') R_CONSTRAINT_NAME,NVL(DELETE_RULE,'NULL') DELETE_RULE FROM USER_CONSTRAINTS C, USER_CONS_COLUMNS CLM WHERE C.CONSTRAINT_NAME=CLM.CONSTRAINT_NAME AND C.GENERATED='GENERATED NAME' ORDER BY 3", ds)
        AddSchemaItem(ConnString, "INDEX", "SELECT TABLE_NAME||'.'||INDEX_NAME INDEX_NAME,TABLE_NAME,UNIQUENESS FROM USER_INDEXES", ds)
        AddSchemaItem(ConnString, "JOB", "SELECT WHAT,INTERVAL FROM USER_JOBS", ds)
        AddSchemaItem(ConnString, "PROCEDURE", "SELECT OBJECT_NAME NAME FROM USER_OBJECTS WHERE OBJECT_TYPE IN ('FUNCTION','PROCEDURE') ORDER BY 1", ds)
        AddSchemaItem(ConnString, "PACKAGE", "SELECT OBJECT_NAME||' '||OBJECT_TYPE NAME, T.LINE_COUNT FROM USER_OBJECTS O, (SELECT NAME,COUNT(*) LINE_COUNT FROM USER_SOURCE GROUP BY NAME) T WHERE O.OBJECT_TYPE IN ('PACKAGE','PACKAGE BODY') AND (T.NAME = O.OBJECT_NAME) ORDER BY 1", ds)

        mConn.Close()
        Return ds

    End Function
    Private Sub AddDSInfo(ByVal ds As DataSet, ByVal ConnUser As String)
        Dim tblInfo As New DataTable("INFO")
        tblInfo.Columns.Add("NAME")
        tblInfo.Columns.Add("VALUE")
        Dim dr As DataRow = tblInfo.NewRow
        dr("NAME") = "Source"
        dr("VALUE") = ConnUser
        tblInfo.Rows.Add(dr)
        dr = tblInfo.NewRow
        dr("NAME") = "Date"
        dr("VALUE") = Now()
        tblInfo.Rows.Add(dr)

        ds.Tables.Add(tblInfo)
    End Sub
    Private Sub AddSchemaItem(ByVal connString As String, ByVal tableName As String, ByVal sqlQuery As String, ByVal ds As DataSet)
        Dim rdr As OracleDataReader
        Try
            rdr = ExecuteReader(sqlQuery)
            Dim tbl As New DataTable(tableName)
            Dim i As Integer
            For i = 0 To rdr.FieldCount - 1
                tbl.Columns.Add(rdr.GetName(i))
            Next
            While rdr.Read()
                Dim dr As DataRow = tbl.NewRow()
                For i = 0 To rdr.FieldCount - 1
                    dr(i) = rdr(i)
                Next
                tbl.Rows.Add(dr)
            End While
            rdr.Close()
            rdr = Nothing
            ds.Tables.Add(tbl)
        Catch ex As Exception
            Throw New Exception("AddSchemaItem failed for: " & vbCrLf & vbCrLf & sqlQuery & vbCrLf & vbCrLf & ex.Message)
        End Try
    End Sub
    Private Function ExecuteReader(ByVal sqlQuery As String) As OracleDataReader
        Dim rdr As OracleDataReader
        Dim cmd As New OracleCommand(sqlQuery, mConn)
        Try
            rdr = cmd.ExecuteReader(CommandBehavior.Default)
        Catch ex As Exception

        Finally
            cmd.Dispose()
        End Try
        Return rdr
    End Function
    Public Sub Compare(ByVal dsBaseline As DataSet, ByVal dsCompare As DataSet, ByVal LogFileName As String)
        Me.LogFileName = LogFileName
        File.Delete(LogFileName)
        Log("DATABASE RECONCILE REPORT - " & Now())
        Log("------------------------------------------------")
        Log("")
        Log("BASELINE INFORMATION")
        Log("--------------------")
        MissingTables.Rows.Clear()
        For Each dr As DataRow In dsBaseline.Tables("INFO").Rows
            Log(dr("NAME") & " = " & dr("VALUE"))
        Next
        Log("")
        Log("TARGET INFORMATION")
        Log("------------------")
        For Each dr As DataRow In dsCompare.Tables("INFO").Rows
            Log(dr("NAME") & " = " & dr("VALUE"))
        Next
        Log("")
        Log("RECONCILE RESULTS")
        Log("-----------------")
        Dim num As Integer = dsBaseline.Tables.Count - 1
        Dim thisTab As Integer = 0
        For Each tbl As DataTable In dsBaseline.Tables
            Dim f As Integer = (thisTab / num) * 100
            If tbl.TableName <> "INFO" Then
                CompareTable(tbl.TableName, dsBaseline, dsCompare)
                thisTab += 1
            End If
        Next
        Log("")
        Log("-------------")
        Log("END OF REPORT")
        Log("-------------")
    End Sub
    Private Sub CompareTable(ByVal tableName As String, ByVal dsBaseline As DataSet, ByVal dsCompare As DataSet)
        dsCompare.Tables(tableName).AcceptChanges()
        Dim bResult As Boolean = True
        For Each dr As DataRow In dsBaseline.Tables(tableName).Rows
            Dim colName As String
            colName = dsBaseline.Tables(tableName).Columns(0).ColumnName
            Dim testRow As DataRow() = dsCompare.Tables(tableName).Select(colName & " = '" & Replace(dr(colName), "'", "''") & "'")
            If testRow.Length = 0 Then
                If tableName = "VIEW" Or tableName = "TABLE" Then
                    Log(tableName & ":  " & dr(0) & " not found.")
                    bResult = False
                    Dim drTbl As DataRow = MissingTables.NewRow
                    drTbl("NAME") = dr(0)
                    MissingTables.Rows.Add(drTbl)
                Else
                    Dim thisTable As String
                    Try
                        thisTable = dr("TABLE_NAME")
                        Dim isMissing As DataRow() = MissingTables.Select("NAME = '" & thisTable & "'")
                        If isMissing.Length = 0 Then
                            Log(tableName & ":  " & dr(0) & " not found.")
                            bResult = False
                        End If
                    Catch ex As Exception
                    End Try
                End If

            Else
                Dim i As Integer = 0
                For Each c As String In dr.ItemArray
                    If testRow(0)(i) <> c Then
                        Log(tableName & ":  " & dr(0) & ". " & dsBaseline.Tables(tableName).Columns(i).ColumnName & " is " & testRow(0)(i) & ". Should be " & c & ".")
                        bResult = False
                    End If
                    i += 1
                Next
                testRow(0).BeginEdit()
                testRow(0).EndEdit()
            End If
        Next
        If Not dsCompare.Tables(tableName).GetChanges(DataRowState.Unchanged) Is Nothing Then
            For Each dr As DataRow In dsCompare.Tables(tableName).GetChanges(DataRowState.Unchanged).Rows
                Try
                    Dim thisTable As String = dr("TABLE_NAME")
                    Dim isMissing As DataRow() = MissingTables.Select("NAME = '" & thisTable & "'")
                    If isMissing.Length = 0 Then
                        Dim drTbl As DataRow = MissingTables.NewRow
                        drTbl("NAME") = dr(0)
                        MissingTables.Rows.Add(drTbl)
                        Log(tableName & ":  Found unknown " & tableName & ": " & dr(0) & ".")
                        bResult = False
                    End If
                Catch
                    Log(tableName & ":  Found unknown " & tableName & ": " & dr(0) & ".")
                    bResult = False
                End Try

            Next
        End If

        dsCompare.Tables(tableName).AcceptChanges()
        If bResult Then
            Log(tableName & ": Reconcile OK.")
        End If
    End Sub
    Private Sub Log(ByVal messageText As String)
        Dim wFile As New StreamWriter(LogFileName, True)
        wFile.WriteLine(messageText)
        wFile.Flush()
        wFile.Close()
    End Sub
End Class

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions