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 Toggle source code
- 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 Toggle source code
- 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;
- /