Database build
Published 14 February 2018
Analogous to checking that code compiles, a database build will check that the database can be created from scratch. Failures should be rare as changes have in theory originated from a working development instance linked to version control using Source Control for Oracle. However, SQL errors could be introduced in specific circumstances.
- A user chooses to make a change "offline" by editing the SQL creation scripts directly, rather than making a "connected" change on their development instance and using Source Control for Oracle to do the check-in.
- A poorly executed code merge could result in invalid SQL.
Note that Oracle will not prevent a database from building if it contains invalid objects. These need to be detected independently.
Other benefits
Other than failing fast when either of the above scenarios occurs, running a database build has additional benefits:
- It builds a database on which further testing can happen, such as unit testing and static analysis checks.
- A report of all objects in the database can be generated as a build artifact for documentation or audit purposes.
- A database creation script can be generated as a build artifact, which is can be run to easily provision dev and test instances.
Worked example:
- Runs DropAllObjects.sql (code included below) to empty the TEST schema, which is a schema whose sole function is to serve the Build and Test continuous integration process.
- Runs the Schema Compare for Oracle command line, sco.exe, to build the database from the State folder, where the creation scripts are stored.
- As part of the same command line invocation we also output the .sql creation script and the changes report to save as build artifacts.
- We output a warning to the console if there are no changes, which probably means the schema has no objects
- If, as expected, we detect differences (sco.exe exit code 61) we set the ERRORLEVEL to 0 to prevent the build from recognizing this as a failure.
CI Build
rem First we run a previously saved script Tools/DropAllObjects.sql to drop all objects from the TEST schema
echo on
Call exit | sqlplus SOCO_TEST/demopassword@(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(Host=localhost)(Port=1521))(CONNECT_DATA=(SID=XE))) @Tools/DropAllObjects.sql
echo off
rem Build the database with the objects and generate a creation script and a report listing all objects.
"C:\Program Files\Red Gate\Schema Compare for Oracle 4\sco.exe" /deploy /i:sdwgvac /source State{SOCO_DEV} /target SOCO_TEST/demopassword@localhost/XE{SOCO_TEST} /sf:Artifacts/database_creation_script.sql /report:Artifacts/all_objects_report.html
echo Build database from state:%ERRORLEVEL%
rem IF ERRORLEVEL is 0 then there are no changes.
IF %ERRORLEVEL% EQU 0 (
echo ========================================================================================================
echo == Warning - No schema changes detected. Does the database have any schema objects?
echo ========================================================================================================
)
rem IF ERRORLEVEL is 61 there are differences, which we expect.
IF %ERRORLEVEL% EQU 61 (
echo ========================================================================================================
echo == Objects were found and built. Change report all_objects_report.html saved as an artifact
echo ========================================================================================================
rem Reset the ERRORLEVEL to 0 so the build doesn't fail
SET ERRORLEVEL=0
)
DropAllObjects.sql
SET SERVEROUTPUT ON SIZE 1000000
BEGIN
FOR cur_rec IN (SELECT object_name, object_type
FROM user_objects
WHERE object_type IN ('TABLE', 'VIEW', 'PACKAGE', 'PROCEDURE', 'FUNCTION', 'SEQUENCE')) LOOP
BEGIN
IF cur_rec.object_type = 'TABLE' THEN
EXECUTE IMMEDIATE 'DROP ' || cur_rec.object_type || ' "' || cur_rec.object_name || '" CASCADE CONSTRAINTS';
ELSE
EXECUTE IMMEDIATE 'DROP ' || cur_rec.object_type || ' "' || cur_rec.object_name || '"';
END IF;
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.put_line('FAILED: DROP ' || cur_rec.object_type || ' "' || cur_rec.object_name || '"');
END;
END LOOP;
END;
/