Chapter 01 · Oracle AI Database Foundations, Editions, Deployment Models, and Lab Setup

Build a Safe Course Environment with Users, Tablespaces, Sample Schemas, and Baseline Backups

Create a safe reusable Oracle course environment with least-privilege owner/runtime users, deterministic ServiceHub data, storage assumptions, reset scripts, and a Data Pump baseline export.

Intermediate115–140 minutesSchema + security + export labOracle AI Database Free 26aiFREEPDB1 + Data PumpLast reviewed: August 24, 2026

Learning outcomes

The ServiceHub Oracle lab now connects reliably. The final foundation task is to make it safe to reuse. A single SYSTEM session that owns tables, runs the application, and performs destructive resets would teach the wrong operational habits. Instead, this lesson establishes a disposable schema boundary, separate owner/runtime identities, deterministic seed data, explicit storage assumptions, a logical baseline export, and a cleanup procedure.

01

Create a disposable application owner and runtime user inside FREEPDB1 with bounded privileges and quota.

02

Record tablespace/storage assumptions rather than hard-coding a datafile path copied from another machine.

03

Create deterministic relational and JSON sample data that later Oracle chapters can extend consistently.

04

Prove least privilege with a deliberate negative test and avoid broad DBA grants to the application.

05

Create and verify a baseline Data Pump schema export while understanding that logical export is not a substitute for RMAN/DR.

Safety boundary

Every command in this lesson targets the local Free lab PDB. Before user/tablespace DDL, run SHOW CON_NAME and confirm FREEPDB1. Do not reuse production-like account names/passwords, and do not run the cleanup script against any database whose data matters.

1. Decide the identity boundaries before creating objects

Use two local users: SERVICEHUB_OWNER owns tables and later PL/SQL APIs; SERVICEHUB_APP represents the runtime application and receives only the object privileges it needs. This prevents the application from modifying schema structure simply because it can query and update business data. Administrative setup remains a separate privileged session.

In Oracle, a user and its schema are tightly related: a user owns a same-named schema namespace. That differs from database engines where schemas are independent namespaces assignable to principals. The owner/runtime split is therefore an identity design, not a request to create a second schema object manually.

2. Record storage assumptions before creating a dedicated tablespace

First inspect the PDB’s default/temporary tablespaces and whether Oracle Managed Files (OMF) has a configured destination. Do not paste a Linux datafile path into a Windows installation or a container and hope it exists.

sql · inspect PDB storage defaults
SHOW CON_NAMESELECT property_name, property_valueFROM   database_propertiesWHERE  property_name IN ('DEFAULT_PERMANENT_TABLESPACE','DEFAULT_TEMP_TABLESPACE');SELECT name, valueFROM   v$parameterWHERE  name = 'db_create_file_dest';SELECT tablespace_name, status, contentsFROM   dba_tablespacesORDER  BY tablespace_name;

The mandatory course path can safely use the existing USERS tablespace with a small explicit quota. If your lab has OMF configured and you want a dedicated learning tablespace, create it with an intentionally bounded size. If OMF is not configured, do not invent a file path; stay on USERS until Chapter 03 teaches datafiles and storage layout.

sql · optional OMF-only dedicated learning tablespace
-- OPTIONAL: run only if DB_CREATE_FILE_DEST is non-null and this is disposable.CREATE TABLESPACE servicehub_data  DATAFILE SIZE 100M  AUTOEXTEND ON NEXT 50M MAXSIZE 1G;-- Verify rather than assume.SELECT tablespace_name, status, contentsFROM   dba_tablespacesWHERE  tablespace_name = 'SERVICEHUB_DATA';

3. Create owner and runtime users without hard-coded passwords

SQLcl/SQL*Plus substitution variables let the lesson avoid embedding a real credential. Enter temporary strong lab passwords when prompted. The owner receives session creation and a bounded quota; the runtime user initially receives only session creation. If you created SERVICEHUB_DATA, substitute that name for USERS deliberately and record the decision.

sqlcl / sql*plus + sql · create local lab users in FREEPDB1
SHOW CON_NAME-- Stop if this is not FREEPDB1.ACCEPT owner_password CHAR PROMPT 'Temporary SERVICEHUB_OWNER password: ' HIDEACCEPT app_password   CHAR PROMPT 'Temporary SERVICEHUB_APP password: ' HIDECREATE USER servicehub_owner IDENTIFIED BY "&owner_password"  DEFAULT TABLESPACE users  TEMPORARY TABLESPACE temp  QUOTA 200M ON users;CREATE USER servicehub_app IDENTIFIED BY "&app_password"  DEFAULT TABLESPACE users  TEMPORARY TABLESPACE temp  QUOTA 0 ON users;GRANT CREATE SESSION, CREATE TABLE, CREATE VIEW, CREATE SEQUENCE,      CREATE PROCEDURE, CREATE TRIGGER TO servicehub_owner;GRANT CREATE SESSION TO servicehub_app;UNDEFINE owner_passwordUNDEFINE app_password

The exact owner privileges will evolve with the course. Do not pre-grant broad capabilities “just in case.” For example, the application does not need DBA, CREATE ANY TABLE, or unlimited tablespace to run ordinary DML.

4. Build deterministic ServiceHub seed data

Connect as SERVICEHUB_OWNER to FREEPDB1. The seed schema is intentionally small: regions, technicians, and work orders. It uses relational keys for core integrity and one native JSON column for a device payload. Later lessons can add indexes, PL/SQL APIs, partitioning demonstrations, spatial data, and vectors without replacing the domain.

sql · create the seed schema
CREATE TABLE service_regions (  region_id    NUMBER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,  region_code  VARCHAR2(12) NOT NULL UNIQUE,  region_name  VARCHAR2(100) NOT NULL);CREATE TABLE technicians (  technician_id NUMBER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,  region_id     NUMBER NOT NULL,  display_name  VARCHAR2(100) NOT NULL,  skill_level   NUMBER(1) DEFAULT 1 NOT NULL,  active_flag   CHAR(1) DEFAULT 'Y' NOT NULL,  CONSTRAINT technicians_region_fk    FOREIGN KEY (region_id) REFERENCES service_regions(region_id),  CONSTRAINT technicians_skill_ck CHECK (skill_level BETWEEN 1 AND 5),  CONSTRAINT technicians_active_ck CHECK (active_flag IN ('Y','N')));CREATE TABLE work_orders (  work_order_id NUMBER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,  region_id     NUMBER NOT NULL,  technician_id NUMBER,  status_code   VARCHAR2(20) NOT NULL,  priority_no   NUMBER(1) NOT NULL,  opened_at     TIMESTAMP WITH TIME ZONE NOT NULL,  closed_at     TIMESTAMP WITH TIME ZONE,  payload_json  JSON,  CONSTRAINT work_orders_region_fk    FOREIGN KEY (region_id) REFERENCES service_regions(region_id),  CONSTRAINT work_orders_tech_fk    FOREIGN KEY (technician_id) REFERENCES technicians(technician_id),  CONSTRAINT work_orders_status_ck    CHECK (status_code IN ('OPEN','ASSIGNED','DONE','CANCELLED')),  CONSTRAINT work_orders_priority_ck CHECK (priority_no BETWEEN 1 AND 5),  CONSTRAINT work_orders_dates_ck CHECK (closed_at IS NULL OR closed_at >= opened_at));INSERT INTO service_regions(region_code, region_name) VALUES ('NORTH','North Service Zone');INSERT INTO service_regions(region_code, region_name) VALUES ('CENTRAL','Central Service Zone');INSERT INTO service_regions(region_code, region_name) VALUES ('SOUTH','South Service Zone');INSERT INTO technicians(region_id, display_name, skill_level)SELECT region_id, 'Ari Rahimi', 4 FROM service_regions WHERE region_code='NORTH';INSERT INTO technicians(region_id, display_name, skill_level)SELECT region_id, 'Nora Chen', 5 FROM service_regions WHERE region_code='CENTRAL';INSERT INTO technicians(region_id, display_name, skill_level)SELECT region_id, 'Mina Costa', 3 FROM service_regions WHERE region_code='SOUTH';INSERT INTO work_orders(region_id, technician_id, status_code, priority_no, opened_at, payload_json)SELECT r.region_id, t.technician_id, 'ASSIGNED', 2,       TIMESTAMP '2026-08-20 09:00:00 +00:00',       JSON('{"source":"mobile","asset":"pump-17","temperature_c":72.4}')FROM service_regions r JOIN technicians t ON t.region_id=r.region_idWHERE r.region_code='NORTH';INSERT INTO work_orders(region_id, status_code, priority_no, opened_at, payload_json)SELECT region_id, 'OPEN', 1,       TIMESTAMP '2026-08-21 14:30:00 +00:00',       JSON('{"source":"api","asset":"compressor-4","alarm":"pressure"}')FROM service_regions WHERE region_code='CENTRAL';COMMIT;

The timestamps and values are fixed so query examples are reproducible. Identity values may differ after repeated reset/reseed cycles, so later assertions should join by stable business codes unless the lab explicitly resets the schema.

5. Grant runtime access—and prove the boundary with a failure

As the owner, grant only the DML needed by the ServiceHub runtime. Then connect as the runtime user and verify both a successful business query and a failed schema-creation attempt.

sql · owner grants object privileges
GRANT SELECT ON service_regions TO servicehub_app;GRANT SELECT ON technicians TO servicehub_app;GRANT SELECT, INSERT, UPDATE ON work_orders TO servicehub_app;
sql · runtime positive and negative tests
-- Connect as SERVICEHUB_APP to //localhost:1521/FREEPDB1SELECT r.region_code,       COUNT(*) AS work_order_countFROM   servicehub_owner.work_orders wJOIN   servicehub_owner.service_regions r ON r.region_id = w.region_idGROUP  BY r.region_codeORDER  BY r.region_code;-- Deliberately forbidden: the runtime identity should not own schema objects.CREATE TABLE should_not_work(id NUMBER);

The first query should succeed. The second should fail with insufficient-privilege behavior (commonly ORA-01031) because SERVICEHUB_APP has no CREATE TABLE privilege and no tablespace quota. That failure is a positive security test. Do not “fix” it with GRANT DBA; preserve the boundary.

6. Record a baseline manifest before backup/export

A reproducible lab needs more than SQL files. Record the database and client versions, current PDB/service, object counts, and storage assumptions. Statistics such as NUM_ROWS can be stale or null until statistics are gathered, so use direct counts for seed verification.

sql · lab manifest and deterministic counts
SELECT banner_full FROM v$version;SELECT value AS compatible FROM v$parameter WHERE name='compatible';SELECT sys_context('USERENV','CON_NAME') AS con_name,       sys_context('USERENV','SERVICE_NAME') AS service_nameFROM dual;SELECT username, default_tablespace, temporary_tablespaceFROM   dba_usersWHERE  username IN ('SERVICEHUB_OWNER','SERVICEHUB_APP')ORDER  BY username;SELECT 'SERVICE_REGIONS' AS object_name, COUNT(*) AS row_count FROM servicehub_owner.service_regionsUNION ALLSELECT 'TECHNICIANS', COUNT(*) FROM servicehub_owner.techniciansUNION ALLSELECT 'WORK_ORDERS', COUNT(*) FROM servicehub_owner.work_orders;

For the seed above the expected counts are 3 regions, 3 technicians, and 2 work orders. If they differ, fix the seed/reset process before taking the baseline export.

7. Baseline logical export with Data Pump

Oracle Data Pump creates a logical export that is excellent for a small disposable schema baseline. It is not a physical RMAN backup and does not establish a point-in-time recovery or disaster-recovery strategy. Chapter 15 will build those mechanisms. For this foundation lab, export SERVICEHUB_OWNER to a directory object that the server can access.

sql · inspect Data Pump directory objects
SELECT directory_name, directory_pathFROM   dba_directoriesWHERE  directory_name = 'DATA_PUMP_DIR';
shell / expdp · run schema export from a host with Oracle Data Pump client
# Omit the password so expdp prompts rather than exposing it in shell history.expdp system@//localhost:1521/FREEPDB1 \  schemas=SERVICEHUB_OWNER \  directory=DATA_PUMP_DIR \  dumpfile=servicehub_ch01_baseline.dmp \  logfile=servicehub_ch01_baseline.log \  reuse_dumpfiles=NO

Read the log and require a successful completion status. Store the dump and log outside an ephemeral container layer if you use containers. To make this a real recovery confidence check, later import the dump into a separate disposable schema/PDB and validate row counts and application behavior; an export command returning successfully is not the same as a restore drill.

8. Reset and cleanup are part of the lab design

The chapter’s reset operation is intentionally simple: drop the two local users with owned objects, then rerun the setup script. If you created the optional dedicated tablespace, drop it only after confirming no unrelated segments use it. Never make cleanup “smart” enough to guess a production target.

sql · explicit destructive reset—FREEPDB1 lab only
SHOW CON_NAME-- STOP unless this reports FREEPDB1 and you intend to destroy the lab schema.DROP USER servicehub_app CASCADE;DROP USER servicehub_owner CASCADE;-- OPTIONAL and only if you created the dedicated course tablespace:-- DROP TABLESPACE servicehub_data INCLUDING CONTENTS AND DATAFILES;

Before running reset, verify that the baseline export exists if you need to preserve the state. After reset/reseed, rerun the manifest counts and negative privilege test. A reset script that cannot prove its target container is not production-safe.

9. Production judgment

Production identity design should go beyond this small lab: use managed secrets or external identity patterns where appropriate, enforce password/account lifecycle policy, avoid shared administrator credentials, grant directly where stored-code semantics require it, and test privileges from the actual application driver. Dedicated tablespaces, quotas, encryption, backup retention, and key management belong to a documented storage/security design rather than a copied setup script.

Likewise, a Data Pump export is a migration/logical-recovery artifact, not a replacement for physical backup, archived redo, RMAN recovery, Data Guard, or tested RPO/RTO. The lab’s purpose is to establish a known-good starting point and a reversible learning environment.

10. Chapter checkpoint and bridge to Chapter 02

Chapter 01 began with boundaries and ends with an operationally useful baseline. You can identify the instance/database/CDB/PDB/service layers, distinguish product branding/RU/COMPATIBLE/licensing, choose a deployment model consciously, verify listener connectivity, and create a least-privilege disposable schema with deterministic data and a logical export. Chapter 02 now opens the running instance: SGA, PGA, server/background processes, session models, initialization parameters, startup/shutdown states, and ADR diagnostics.

Check your understanding

  1. Why does SERVICEHUB_APP have zero tablespace quota even though it can insert into SERVICEHUB_OWNER.WORK_ORDERS?
  2. Why is ORA-01031 from the runtime CREATE TABLE test a successful lab outcome?
  3. What should you do if DB_CREATE_FILE_DEST is null instead of inventing a datafile path?
  4. What does a successful Data Pump schema export prove, and what does it not prove?
  5. What must be checked immediately before running the DROP USER reset script?
Review the answers

The runtime user does not need to allocate its own segments to modify objects owned by another schema when it has the required object privileges. Zero quota reinforces that it is not a schema owner.

It proves the runtime identity lacks schema-creation privilege as intended. Granting DBA to remove that error would destroy the least-privilege boundary.

Use the existing USERS tablespace for the mandatory lab and record that choice, or design a correct platform-specific datafile/OMF layout after learning storage. Do not copy an arbitrary host path.

It proves Data Pump completed a logical export operation according to its log. It does not prove physical recoverability, point-in-time recovery, disaster recovery, or that an import/application verification will succeed.

Confirm the current container is the disposable FREEPDB1 lab, confirm the usernames are the course users, and confirm any state you need has been exported/backed up. Never rely on filename or connection-history assumptions.

Authoritative references

Keep knowledge open

Help the academy stay free and grow.

If these tutorials save you time, a small donation supports new lessons, technical review, diagrams, examples, and long-term maintenance.

ETHEthereum / ERC-20 only
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0

Send only Ethereum or ERC-20 compatible assets to this address.